Skip to content

feat: add textarea component #17465

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat: add textarea component
  • Loading branch information
jaaydenh committed Apr 18, 2025
commit 33a01027f5c6937a5237dd5781de3b597f1f3df7
99 changes: 99 additions & 0 deletions site/src/components/Textarea/Textarea.stories.tsx
Original file line number Diff line number Diff line change
@@ -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!",
);
},
};
26 changes: 26 additions & 0 deletions site/src/components/Textarea/Textarea.tsx
Original file line number Diff line number Diff line change
@@ -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}
/>
);
});
Loading