mirror of
https://github.com/makeplane/plane.git
synced 2025-12-22 22:59:33 +01:00
[WEB-4731] feat: add baseui input component to propel package (#7769)
* ✨ feat: add input component to propel package * 🚨 fix: lint * 🚨 fix: lint * fix: add aria-invalid attribute to Input component for better accessibility * chore: fix formatting in package.json and reorder imports in popover-menu stories
This commit is contained in:
@@ -100,6 +100,10 @@
|
||||
"import": "./dist/icons/index.mjs",
|
||||
"require": "./dist/icons/index.js"
|
||||
},
|
||||
"./input": {
|
||||
"import": "./dist/input/index.mjs",
|
||||
"require": "./dist/input/index.js"
|
||||
},
|
||||
"./menu": {
|
||||
"import": "./dist/menu/index.mjs",
|
||||
"require": "./dist/menu/index.js"
|
||||
|
||||
1
packages/propel/src/input/index.ts
Normal file
1
packages/propel/src/input/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./input";
|
||||
153
packages/propel/src/input/input.stories.tsx
Normal file
153
packages/propel/src/input/input.stories.tsx
Normal file
@@ -0,0 +1,153 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import { Input } from "./index";
|
||||
|
||||
const meta: Meta<typeof Input> = {
|
||||
title: "Components/Input",
|
||||
component: Input,
|
||||
parameters: {
|
||||
layout: "centered",
|
||||
},
|
||||
tags: ["autodocs"],
|
||||
argTypes: {
|
||||
mode: {
|
||||
control: "select",
|
||||
options: ["primary", "transparent", "true-transparent"],
|
||||
},
|
||||
inputSize: {
|
||||
control: "select",
|
||||
options: ["xs", "sm", "md"],
|
||||
},
|
||||
hasError: {
|
||||
control: "boolean",
|
||||
},
|
||||
type: {
|
||||
control: "select",
|
||||
options: ["text", "email", "password", "number", "tel", "url", "search"],
|
||||
},
|
||||
autoComplete: {
|
||||
control: "select",
|
||||
options: ["on", "off"],
|
||||
},
|
||||
disabled: {
|
||||
control: "boolean",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Input>;
|
||||
|
||||
const createStory = (args: Partial<React.ComponentProps<typeof Input>>): Story => ({
|
||||
args: { placeholder: "Enter text...", className: "w-[400px]", ...args },
|
||||
});
|
||||
|
||||
const createShowcaseStory = (
|
||||
title: string,
|
||||
sections: Array<{ label: string; props: Partial<React.ComponentProps<typeof Input>> }>
|
||||
): Story => ({
|
||||
render: () => (
|
||||
<div className="space-y-4 w-[400px]">
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-sm font-medium">{title}</h3>
|
||||
<div className="space-y-2">
|
||||
{sections.map(({ label, props }, index) => (
|
||||
<div key={index} className="w-full">
|
||||
<label className="text-xs text-gray-500">{label}</label>
|
||||
<Input className="w-full" {...props} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
||||
export const Default = createStory({});
|
||||
|
||||
export const Primary = createStory({
|
||||
mode: "primary",
|
||||
placeholder: "Primary input",
|
||||
});
|
||||
|
||||
export const Transparent = createStory({
|
||||
mode: "transparent",
|
||||
placeholder: "Transparent input",
|
||||
});
|
||||
|
||||
export const TrueTransparent = createStory({
|
||||
mode: "true-transparent",
|
||||
placeholder: "True transparent input",
|
||||
});
|
||||
|
||||
export const ExtraSmall = createStory({
|
||||
inputSize: "xs",
|
||||
placeholder: "Extra small input",
|
||||
});
|
||||
|
||||
export const Small = createStory({
|
||||
inputSize: "sm",
|
||||
placeholder: "Small input",
|
||||
});
|
||||
|
||||
export const Medium = createStory({
|
||||
inputSize: "md",
|
||||
placeholder: "Medium input",
|
||||
});
|
||||
|
||||
export const WithError = createStory({
|
||||
hasError: true,
|
||||
placeholder: "Input with error",
|
||||
defaultValue: "Invalid input",
|
||||
});
|
||||
|
||||
export const Disabled = createStory({
|
||||
disabled: true,
|
||||
placeholder: "Disabled input",
|
||||
defaultValue: "Cannot edit this",
|
||||
});
|
||||
|
||||
export const WithValue = createStory({
|
||||
defaultValue: "Pre-filled value",
|
||||
placeholder: "Input with value",
|
||||
});
|
||||
|
||||
export const Email = createStory({
|
||||
type: "email",
|
||||
placeholder: "Enter your email",
|
||||
autoComplete: "on",
|
||||
});
|
||||
|
||||
export const Password = createStory({
|
||||
type: "password",
|
||||
placeholder: "Enter your password",
|
||||
autoComplete: "off",
|
||||
});
|
||||
|
||||
export const Number = createStory({
|
||||
type: "number",
|
||||
placeholder: "Enter a number",
|
||||
});
|
||||
|
||||
export const Search = createStory({
|
||||
type: "search",
|
||||
placeholder: "Search...",
|
||||
});
|
||||
|
||||
export const AllModes = createShowcaseStory("Input Modes", [
|
||||
{ label: "Primary", props: { mode: "primary", placeholder: "Primary input" } },
|
||||
{ label: "Transparent", props: { mode: "transparent", placeholder: "Transparent input" } },
|
||||
{ label: "True Transparent", props: { mode: "true-transparent", placeholder: "True transparent input" } },
|
||||
]);
|
||||
|
||||
export const AllSizes = createShowcaseStory("Input Sizes", [
|
||||
{ label: "Extra Small (xs)", props: { inputSize: "xs", placeholder: "Extra small input" } },
|
||||
{ label: "Small (sm)", props: { inputSize: "sm", placeholder: "Small input" } },
|
||||
{ label: "Medium (md)", props: { inputSize: "md", placeholder: "Medium input" } },
|
||||
]);
|
||||
|
||||
export const AllStates = createShowcaseStory("Input States", [
|
||||
{ label: "Normal", props: { placeholder: "Normal input" } },
|
||||
{ label: "With Error", props: { hasError: true, placeholder: "Input with error" } },
|
||||
{ label: "Disabled", props: { disabled: true, placeholder: "Disabled input" } },
|
||||
{ label: "With Value", props: { defaultValue: "Pre-filled value", placeholder: "Input with value" } },
|
||||
]);
|
||||
54
packages/propel/src/input/input.tsx
Normal file
54
packages/propel/src/input/input.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import * as React from "react";
|
||||
import { Input as BaseInput } from "@base-ui-components/react/input";
|
||||
// helpers
|
||||
import { cn } from "../utils";
|
||||
|
||||
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
||||
mode?: "primary" | "transparent" | "true-transparent";
|
||||
inputSize?: "xs" | "sm" | "md";
|
||||
hasError?: boolean;
|
||||
}
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>((props, ref) => {
|
||||
const {
|
||||
id,
|
||||
type,
|
||||
name,
|
||||
mode = "primary",
|
||||
inputSize = "sm",
|
||||
hasError = false,
|
||||
className = "",
|
||||
autoComplete = "off",
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<BaseInput
|
||||
id={id}
|
||||
ref={ref}
|
||||
type={type}
|
||||
name={name}
|
||||
className={cn(
|
||||
"block rounded-md bg-transparent text-sm placeholder-custom-text-400 focus:outline-none",
|
||||
{
|
||||
"rounded-md border-[0.5px] border-custom-border-200": mode === "primary",
|
||||
"rounded border-none bg-transparent ring-0 transition-all focus:ring-1 focus:ring-custom-primary":
|
||||
mode === "transparent",
|
||||
"rounded border-none bg-transparent ring-0": mode === "true-transparent",
|
||||
"border-red-500": hasError,
|
||||
"px-1.5 py-1": inputSize === "xs",
|
||||
"px-3 py-2": inputSize === "sm",
|
||||
"p-3": inputSize === "md",
|
||||
},
|
||||
className
|
||||
)}
|
||||
aria-invalid={hasError || undefined}
|
||||
autoComplete={autoComplete}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
Input.displayName = "form-input-field";
|
||||
|
||||
export { Input };
|
||||
@@ -18,6 +18,7 @@ export default defineConfig({
|
||||
"src/emoji-reaction/index.ts",
|
||||
"src/emoji-reaction-picker/index.ts",
|
||||
"src/icons/index.ts",
|
||||
"src/input/index.ts",
|
||||
"src/menu/index.ts",
|
||||
"src/pill/index.ts",
|
||||
"src/popover/index.ts",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import React from "react";
|
||||
import { PopoverMenu } from "./popover-menu";
|
||||
|
||||
type TPopoverMenu = {
|
||||
|
||||
Reference in New Issue
Block a user