import type { ReactNode, Ref } from "react";
import React from "react";
import type { TextAreaProps as AriaTextAreaProps, TextFieldProps as AriaTextFieldProps } from "react-aria-components";
import { TextArea as AriaTextArea, TextField as AriaTextField } from "react-aria-components";
import { HintText } from "@/components/base/input/hint-text";
import { Label } from "@/components/base/input/label";
import { cx } from "@/utils/cx";
// Creates a data URL for an SVG resize handle with a given color.
const getResizeHandleBg = (color: string) => {
return `url(data:image/svg+xml;base64,${btoa(``)})`;
};
interface TextAreaBaseProps extends AriaTextAreaProps {
ref?: Ref;
}
export const TextAreaBase = ({ className, ...props }: TextAreaBaseProps) => {
return (
cx(
"w-full scroll-py-3 rounded-lg bg-primary px-3.5 py-3 text-md text-primary shadow-xs ring-1 ring-primary transition duration-100 ease-linear ring-inset placeholder:text-placeholder autofill:rounded-lg autofill:text-primary focus:outline-hidden",
// Resize handle
"[&::-webkit-resizer]:bg-(image:--resize-handle-bg) [&::-webkit-resizer]:bg-contain dark:[&::-webkit-resizer]:bg-(image:--resize-handle-bg-dark)",
state.isFocused && !state.isDisabled && "ring-2 ring-brand",
state.isDisabled && "cursor-not-allowed bg-disabled_subtle text-disabled ring-disabled",
state.isInvalid && "ring-error_subtle",
state.isInvalid && state.isFocused && "ring-2 ring-error",
typeof className === "function" ? className(state) : className,
)
}
/>
);
};
TextAreaBase.displayName = "TextAreaBase";
interface TextFieldProps extends AriaTextFieldProps {
/** Label text for the textarea */
label?: string;
/** Helper text displayed below the textarea */
hint?: ReactNode;
/** Tooltip message displayed after the label. */
tooltip?: string;
/** Class name for the textarea wrapper */
textAreaClassName?: TextAreaBaseProps["className"];
/** Ref for the textarea wrapper */
ref?: Ref;
/** Ref for the textarea */
textAreaRef?: TextAreaBaseProps["ref"];
/** Whether to hide required indicator from label. */
hideRequiredIndicator?: boolean;
/** Placeholder text. */
placeholder?: string;
/** Visible height of textarea in rows . */
rows?: number;
/** Visible width of textarea in columns. */
cols?: number;
}
export const TextArea = ({
label,
hint,
tooltip,
textAreaRef,
hideRequiredIndicator,
textAreaClassName,
placeholder,
className,
rows,
cols,
...props
}: TextFieldProps) => {
return (
cx("group flex h-max w-full flex-col items-start justify-start gap-1.5", typeof className === "function" ? className(state) : className)
}
>
{({ isInvalid, isRequired }) => (
<>
{label && (
)}
{hint && {hint}}
>
)}
);
};
TextArea.displayName = "TextArea";