forked from
slices.network/slices
Highly ambitious ATProtocol AppView service and sdks
1import type { JSX } from "preact";
2import { cn } from "../../utils/cn.ts";
3
4type TextareaSize = "sm" | "md" | "lg";
5
6export interface TextareaProps
7 extends Omit<JSX.IntrinsicElements['textarea'], 'size'> {
8 label?: string;
9 error?: string;
10 size?: TextareaSize;
11}
12
13export function Textarea(props: TextareaProps): JSX.Element {
14 const { class: classProp, label, error, size = "lg", ...rest } = props;
15
16 const sizeClasses = {
17 sm: "px-2.5 py-0.5 text-xs",
18 md: "px-3 py-1 text-sm",
19 lg: "px-4 py-2 text-sm",
20 };
21
22 const className = cn(
23 "block w-full border border-zinc-200 dark:border-zinc-700 rounded-md bg-white dark:bg-zinc-900 text-zinc-900 dark:text-white placeholder:text-zinc-500 dark:placeholder:text-zinc-400 focus:outline-none focus:ring-2 focus:border-transparent",
24 sizeClasses[size],
25 error
26 ? "border-red-500 dark:border-red-400 focus:ring-red-500 dark:focus:ring-red-400"
27 : "focus:ring-blue-500 dark:focus:ring-blue-400",
28 props.disabled && "bg-zinc-50 dark:bg-zinc-800 text-zinc-500 dark:text-zinc-400 cursor-not-allowed",
29 classProp,
30 );
31
32 return (
33 <div>
34 {label && (
35 <label className="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-2">
36 {label}
37 {props.required && <span className="text-red-500 dark:text-red-400 ml-1">*</span>}
38 </label>
39 )}
40 <textarea class={className} {...rest} />
41 {error && <p className="mt-1 text-sm text-red-600 dark:text-red-400">{error}</p>}
42 </div>
43 );
44}