Skip to content
Source
Sign inSign up
Open History to see the last commit

textarea.tsx

58 lines1.9 KB

1import { Field as FieldPrimitive } from "@base-ui/react/field";
2import { mergeProps } from "@base-ui/react/merge-props";
3import type * as React from "react";
4​
5import { cn } from "~/lib/utils";
6​
7type TextareaProps = React.ComponentProps<"textarea"> & {
8 size?: "sm" | "default" | number;
9 unstyled?: boolean;
10};
11​
12function Textarea({
13 className,
14 size = "default",
15 unstyled = false,
16 rows,
17 ...props
18}: TextareaProps) {
19 return (
20 <span
21 className={
22 cn(
23 !unstyled &&
24 "surface-well relative inline-flex w-full rounded-[var(--control-radius)] text-prompt text-foreground has-focus-visible:surface-focus has-aria-invalid:surface-invalid has-focus-visible:has-aria-invalid:surface-invalid-focus has-disabled:opacity-64",
25 className,
26 ) || undefined
27 }
28 data-size={size}
29 data-slot="textarea-control"
30 >
31 <FieldPrimitive.Control
32 render={(defaultProps) => (
33 <textarea
34 className={cn(
35 "field-sizing-content max-h-64 w-full rounded-[inherit] px-[calc(--spacing(3)-1px)] py-[calc(--spacing(1.5)-1px)] outline-none wrap-anywhere",
36 rows === undefined && "min-h-17.5 max-sm:min-h-20.5",
37 size === "sm" && "px-[calc(--spacing(2.5)-1px)] py-[calc(--spacing(1)-1px)]",
38 size === "sm" && rows === undefined && "min-h-16.5 max-sm:min-h-19.5",
39 )}
40 // field-sizing: content ignores `rows`, so an explicit row count sets the minimum height.
41 style={
42 rows === undefined
43 ? undefined
44 : {
45 minHeight: `calc(${rows}lh + 2 * (var(--spacing) * ${size === "sm" ? 1 : 1.5} - 1px))`,
46 }
47 }
48 data-slot="textarea"
49 rows={rows}
50 {...mergeProps(defaultProps, props)}
51 />
52 )}
53 />
54 </span>
55 );
57​
58export { Textarea, type TextareaProps };