mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add textarea component (#17465)
This adds the shadcn textarea component along with storybook stories Figma: https://www.figma.com/design/WfqIgsTFXN2BscBSSyXWF8/Coder-kit?node-id=1949-13239&t=NSt5S88hAsE4Q9di-1 <img width="612" alt="Screenshot 2025-04-18 at 12 16 57" src="https://github.com/user-attachments/assets/dcd0281f-5d80-4047-9ba4-e456290ceb61" />
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { expect, userEvent, within } from "@storybook/test";
|
||||
import { useState } from "react";
|
||||
import { Textarea } from "./Textarea";
|
||||
|
||||
const meta: Meta<typeof Textarea> = {
|
||||
title: "components/Textarea",
|
||||
component: Textarea,
|
||||
args: {},
|
||||
argTypes: {
|
||||
value: {
|
||||
control: "text",
|
||||
description: "The controlled value of the textarea",
|
||||
},
|
||||
defaultValue: {
|
||||
control: "text",
|
||||
description: "The default value when initially rendered",
|
||||
},
|
||||
disabled: {
|
||||
control: "boolean",
|
||||
description:
|
||||
"When true, prevents the user from interacting with the textarea",
|
||||
},
|
||||
placeholder: {
|
||||
control: "text",
|
||||
description: "Placeholder text displayed when the textarea is empty",
|
||||
},
|
||||
rows: {
|
||||
control: "number",
|
||||
description: "The number of rows to display",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Textarea>;
|
||||
|
||||
export const WithPlaceholder: Story = {
|
||||
args: {
|
||||
placeholder: "Enter your message here...",
|
||||
},
|
||||
};
|
||||
|
||||
export const Disabled: Story = {
|
||||
args: {
|
||||
disabled: true,
|
||||
placeholder: "Placeholder",
|
||||
},
|
||||
};
|
||||
|
||||
export const WithDefaultValue: Story = {
|
||||
args: {
|
||||
defaultValue: "This is some default text in the textarea.",
|
||||
},
|
||||
};
|
||||
|
||||
export const Large: Story = {
|
||||
args: {
|
||||
rows: 8,
|
||||
placeholder: "Placeholder: A larger textarea with more rows",
|
||||
},
|
||||
};
|
||||
|
||||
const ControlledTextarea = () => {
|
||||
const [value, setValue] = useState("This is a controlled textarea.");
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<Textarea
|
||||
value={value}
|
||||
placeholder="Type something..."
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
/>
|
||||
<div className="text-sm text-content-secondary">
|
||||
Character count: {value.length}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Controlled: Story = {
|
||||
render: () => <ControlledTextarea />,
|
||||
};
|
||||
|
||||
export const TypeText: Story = {
|
||||
args: {
|
||||
placeholder: "Type something here...",
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const textarea = canvas.getByRole("textbox");
|
||||
await userEvent.type(
|
||||
textarea,
|
||||
"Hello, this is some example text being typed into the textarea!",
|
||||
);
|
||||
expect(textarea).toHaveValue(
|
||||
"Hello, this is some example text being typed into the textarea!",
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copied from shadc/ui on 04/18/2025
|
||||
* @see {@link https://ui.shadcn.com/docs/components/textarea}
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "utils/cn";
|
||||
|
||||
export const Textarea = React.forwardRef<
|
||||
HTMLTextAreaElement,
|
||||
React.ComponentProps<"textarea">
|
||||
>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
`flex min-h-[60px] w-full px-3 py-2 text-sm shadow-sm text-content-primary
|
||||
rounded-md border border-border bg-transparent placeholder:text-content-secondary
|
||||
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-content-link
|
||||
disabled:cursor-not-allowed disabled:opacity-50 disabled:text-content-disabled md:text-sm`,
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user