@dimaan/ui 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
- import { HTMLAttributes, ReactNode, ReactElement, ButtonHTMLAttributes, InputHTMLAttributes, ChangeEvent, FieldsetHTMLAttributes, AnchorHTMLAttributes, Ref } from 'react';
3
+ import { HTMLAttributes, ReactNode, ReactElement, ButtonHTMLAttributes, InputHTMLAttributes, ChangeEvent, FieldsetHTMLAttributes, AnchorHTMLAttributes, Ref, TextareaHTMLAttributes } from 'react';
4
+ import { FieldValues, FieldPath, Control } from 'react-hook-form';
4
5
  import { ClassValue } from 'clsx';
5
6
 
6
7
  interface DashboardLayoutContextValue {
@@ -124,6 +125,81 @@ interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'typ
124
125
  }
125
126
  declare const Checkbox: react.ForwardRefExoticComponent<CheckboxProps & react.RefAttributes<HTMLInputElement>>;
126
127
 
128
+ interface FieldRHFProps<TValues extends FieldValues = FieldValues, TName extends FieldPath<TValues> = FieldPath<TValues>> {
129
+ /**
130
+ * RHF `Control` returned from `useForm()`. Optional when `Field` is rendered
131
+ * inside a `<FormProvider>` — the control is read from context automatically.
132
+ */
133
+ control?: Control<TValues>;
134
+ /** Path to the field within the form values. */
135
+ name: TName;
136
+ }
137
+ interface FieldLayoutProps {
138
+ /** Label rendered above the control. */
139
+ label?: ReactNode;
140
+ /** Helper text rendered under the control when there's no error. */
141
+ description?: ReactNode;
142
+ /** Marks the field as required (visual `*` + native `required`). */
143
+ required?: boolean;
144
+ /** Disables the wrapped control. */
145
+ disabled?: boolean;
146
+ /** Stretch the wrapper to fill its parent. Defaults to `true`. */
147
+ fullWidth?: boolean;
148
+ /** Class applied to the outer wrapper. */
149
+ className?: string;
150
+ /** The single control element to wrap. Receives id + aria + (in RHF mode) field props. */
151
+ children: ReactElement;
152
+ }
153
+ interface FieldManualProps extends FieldLayoutProps {
154
+ control?: never;
155
+ name?: never;
156
+ /** Error message to display. Pass falsy when valid. */
157
+ error?: ReactNode;
158
+ /** Override `aria-invalid`. Defaults to `!!error` when omitted. */
159
+ invalid?: boolean;
160
+ }
161
+ interface FieldRHFOnlyProps<TValues extends FieldValues, TName extends FieldPath<TValues>> extends FieldLayoutProps, FieldRHFProps<TValues, TName> {
162
+ error?: never;
163
+ invalid?: never;
164
+ }
165
+ type FieldProps<TValues extends FieldValues = FieldValues, TName extends FieldPath<TValues> = FieldPath<TValues>> = FieldManualProps | FieldRHFOnlyProps<TValues, TName>;
166
+ /**
167
+ * `Field` wraps a single form control with a label, description, and error
168
+ * message. It works in three modes:
169
+ *
170
+ * 1. **FormProvider context mode** (recommended): pass only `name`. The
171
+ * `control` is pulled from the surrounding `<FormProvider>`.
172
+ * 2. **Explicit control mode**: pass both `control` and `name` (useful when you
173
+ * don't want a `FormProvider`, or when you have multiple forms on the page).
174
+ * 3. **Manual mode**: omit `name`. Provide `error` / `invalid` yourself.
175
+ *
176
+ * @example FormProvider mode
177
+ * ```tsx
178
+ * <FormProvider {...form}>
179
+ * <form onSubmit={form.handleSubmit(onSubmit)}>
180
+ * <Field name="email" label="Email" description="…">
181
+ * <Input type="email" />
182
+ * </Field>
183
+ * </form>
184
+ * </FormProvider>
185
+ * ```
186
+ *
187
+ * @example Explicit control mode
188
+ * ```tsx
189
+ * <Field control={form.control} name="email" label="Email">
190
+ * <Input type="email" />
191
+ * </Field>
192
+ * ```
193
+ *
194
+ * @example Manual mode
195
+ * ```tsx
196
+ * <Field label="Email" error={errorMessage}>
197
+ * <Input value={email} onChange={(e) => setEmail(e.target.value)} />
198
+ * </Field>
199
+ * ```
200
+ */
201
+ declare function Field<TValues extends FieldValues = FieldValues, TName extends FieldPath<TValues> = FieldPath<TValues>>(props: FieldProps<TValues, TName>): ReactElement;
202
+
127
203
  type DashboardHeaderProps = HTMLAttributes<HTMLElement>;
128
204
  declare function DashboardHeader({ className, children, ...props }: DashboardHeaderProps): react_jsx_runtime.JSX.Element;
129
205
 
@@ -355,9 +431,37 @@ interface TableProps<T> {
355
431
 
356
432
  declare function Table<T>(props: TableProps<T>): react_jsx_runtime.JSX.Element;
357
433
 
434
+ type TextareaVariant = 'default' | 'filled' | 'ghost';
435
+ type TextareaSize = 'sm' | 'md' | 'lg';
436
+ type TextareaResize = 'none' | 'vertical' | 'horizontal' | 'both';
437
+ declare const textareaVariantClass: Record<TextareaVariant, string>;
438
+ declare const textareaSizeClass: Record<TextareaSize, string>;
439
+ declare const textareaResizeClass: Record<TextareaResize, string>;
440
+ declare const textareaBaseClass = "group/textarea relative flex w-full text-foreground outline-none transition-[background-color,border-color,box-shadow] focus-within:ring-2 focus-within:ring-ring/40 focus-within:ring-offset-1 focus-within:ring-offset-background aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-within:ring-destructive/40 has-[textarea:disabled]:pointer-events-none has-[textarea:disabled]:opacity-50";
441
+
442
+ interface TextareaProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'> {
443
+ variant?: TextareaVariant;
444
+ textareaSize?: TextareaSize;
445
+ /** Controls the native CSS `resize` behaviour. Defaults to `'vertical'`. */
446
+ resize?: TextareaResize;
447
+ /** Optional label rendered above the field. */
448
+ label?: ReactNode;
449
+ /** Helper text rendered under the field when not in an error state. */
450
+ helperText?: ReactNode;
451
+ /** Error message — renders in destructive style and sets aria-invalid. */
452
+ error?: ReactNode;
453
+ /** Stretch the wrapper to fill the parent's inline width. Defaults to `true`. */
454
+ fullWidth?: boolean;
455
+ /** Class applied to the outer wrapper that frames the textarea. */
456
+ wrapperClassName?: string;
457
+ /** Class applied to the field container (`<label>` block). */
458
+ containerClassName?: string;
459
+ }
460
+ declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.RefAttributes<HTMLTextAreaElement>>;
461
+
358
462
  type Direction = 'ltr' | 'rtl';
359
463
  declare function useDirection(): Direction;
360
464
 
361
465
  declare function cn(...inputs: ClassValue[]): string;
362
466
 
363
- export { AppShell, type AppShellBrand, type AppShellNavGroup, type AppShellNavItem, type AppShellProps, Avatar, type AvatarProps, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Checkbox, type CheckboxProps, type CheckboxSize, type Column, type ColumnAlign, DashboardContent, type DashboardContentProps, DashboardHeader, type DashboardHeaderProps, DashboardLayout, type DashboardLayoutContextValue, type DashboardLayoutProps, DashboardMain, type DashboardMainProps, type Direction, HeaderActions, type HeaderActionsProps, HeaderCollapseTrigger, type HeaderCollapseTriggerProps, HeaderMobileTrigger, type HeaderMobileTriggerProps, HeaderSearch, type HeaderSearchProps, HeaderTitle, type HeaderTitleProps, Input, type InputProps, type InputSize, type InputVariant, type LanguageOption, LanguageSwitcher, type LanguageSwitcherProps, type PaginationState, type RowSelectionState, Sidebar, SidebarFooter, type SidebarFooterProps, SidebarGroup, type SidebarGroupProps, SidebarHeader, type SidebarHeaderProps, SidebarNav, SidebarNavGroup, type SidebarNavGroupProps, SidebarNavItem, type SidebarNavItemProps, type SidebarNavItemRenderProps, type SidebarNavProps, type SidebarProps, type SortDirection, type SortState, type SortableValue, Table, type TableProps, type TableSize, type TableSizeClasses, buttonBaseClass, buttonSizeClass, buttonVariantClass, cn, inputBaseClass, inputSizeClass, inputVariantClass, alignClass as tableAlignClass, tableBaseClass, selectedRowClass as tableSelectedRowClass, tableSizeClass, sortIconClass as tableSortIconClass, useDashboardLayout, useDirection };
467
+ export { AppShell, type AppShellBrand, type AppShellNavGroup, type AppShellNavItem, type AppShellProps, Avatar, type AvatarProps, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Checkbox, type CheckboxProps, type CheckboxSize, type Column, type ColumnAlign, DashboardContent, type DashboardContentProps, DashboardHeader, type DashboardHeaderProps, DashboardLayout, type DashboardLayoutContextValue, type DashboardLayoutProps, DashboardMain, type DashboardMainProps, type Direction, Field, type FieldProps, type FieldRHFProps, HeaderActions, type HeaderActionsProps, HeaderCollapseTrigger, type HeaderCollapseTriggerProps, HeaderMobileTrigger, type HeaderMobileTriggerProps, HeaderSearch, type HeaderSearchProps, HeaderTitle, type HeaderTitleProps, Input, type InputProps, type InputSize, type InputVariant, type LanguageOption, LanguageSwitcher, type LanguageSwitcherProps, type PaginationState, type RowSelectionState, Sidebar, SidebarFooter, type SidebarFooterProps, SidebarGroup, type SidebarGroupProps, SidebarHeader, type SidebarHeaderProps, SidebarNav, SidebarNavGroup, type SidebarNavGroupProps, SidebarNavItem, type SidebarNavItemProps, type SidebarNavItemRenderProps, type SidebarNavProps, type SidebarProps, type SortDirection, type SortState, type SortableValue, Table, type TableProps, type TableSize, type TableSizeClasses, Textarea, type TextareaProps, type TextareaResize, type TextareaSize, type TextareaVariant, buttonBaseClass, buttonSizeClass, buttonVariantClass, cn, inputBaseClass, inputSizeClass, inputVariantClass, alignClass as tableAlignClass, tableBaseClass, selectedRowClass as tableSelectedRowClass, tableSizeClass, sortIconClass as tableSortIconClass, textareaBaseClass, textareaResizeClass, textareaSizeClass, textareaVariantClass, useDashboardLayout, useDirection };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
- import { HTMLAttributes, ReactNode, ReactElement, ButtonHTMLAttributes, InputHTMLAttributes, ChangeEvent, FieldsetHTMLAttributes, AnchorHTMLAttributes, Ref } from 'react';
3
+ import { HTMLAttributes, ReactNode, ReactElement, ButtonHTMLAttributes, InputHTMLAttributes, ChangeEvent, FieldsetHTMLAttributes, AnchorHTMLAttributes, Ref, TextareaHTMLAttributes } from 'react';
4
+ import { FieldValues, FieldPath, Control } from 'react-hook-form';
4
5
  import { ClassValue } from 'clsx';
5
6
 
6
7
  interface DashboardLayoutContextValue {
@@ -124,6 +125,81 @@ interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'typ
124
125
  }
125
126
  declare const Checkbox: react.ForwardRefExoticComponent<CheckboxProps & react.RefAttributes<HTMLInputElement>>;
126
127
 
128
+ interface FieldRHFProps<TValues extends FieldValues = FieldValues, TName extends FieldPath<TValues> = FieldPath<TValues>> {
129
+ /**
130
+ * RHF `Control` returned from `useForm()`. Optional when `Field` is rendered
131
+ * inside a `<FormProvider>` — the control is read from context automatically.
132
+ */
133
+ control?: Control<TValues>;
134
+ /** Path to the field within the form values. */
135
+ name: TName;
136
+ }
137
+ interface FieldLayoutProps {
138
+ /** Label rendered above the control. */
139
+ label?: ReactNode;
140
+ /** Helper text rendered under the control when there's no error. */
141
+ description?: ReactNode;
142
+ /** Marks the field as required (visual `*` + native `required`). */
143
+ required?: boolean;
144
+ /** Disables the wrapped control. */
145
+ disabled?: boolean;
146
+ /** Stretch the wrapper to fill its parent. Defaults to `true`. */
147
+ fullWidth?: boolean;
148
+ /** Class applied to the outer wrapper. */
149
+ className?: string;
150
+ /** The single control element to wrap. Receives id + aria + (in RHF mode) field props. */
151
+ children: ReactElement;
152
+ }
153
+ interface FieldManualProps extends FieldLayoutProps {
154
+ control?: never;
155
+ name?: never;
156
+ /** Error message to display. Pass falsy when valid. */
157
+ error?: ReactNode;
158
+ /** Override `aria-invalid`. Defaults to `!!error` when omitted. */
159
+ invalid?: boolean;
160
+ }
161
+ interface FieldRHFOnlyProps<TValues extends FieldValues, TName extends FieldPath<TValues>> extends FieldLayoutProps, FieldRHFProps<TValues, TName> {
162
+ error?: never;
163
+ invalid?: never;
164
+ }
165
+ type FieldProps<TValues extends FieldValues = FieldValues, TName extends FieldPath<TValues> = FieldPath<TValues>> = FieldManualProps | FieldRHFOnlyProps<TValues, TName>;
166
+ /**
167
+ * `Field` wraps a single form control with a label, description, and error
168
+ * message. It works in three modes:
169
+ *
170
+ * 1. **FormProvider context mode** (recommended): pass only `name`. The
171
+ * `control` is pulled from the surrounding `<FormProvider>`.
172
+ * 2. **Explicit control mode**: pass both `control` and `name` (useful when you
173
+ * don't want a `FormProvider`, or when you have multiple forms on the page).
174
+ * 3. **Manual mode**: omit `name`. Provide `error` / `invalid` yourself.
175
+ *
176
+ * @example FormProvider mode
177
+ * ```tsx
178
+ * <FormProvider {...form}>
179
+ * <form onSubmit={form.handleSubmit(onSubmit)}>
180
+ * <Field name="email" label="Email" description="…">
181
+ * <Input type="email" />
182
+ * </Field>
183
+ * </form>
184
+ * </FormProvider>
185
+ * ```
186
+ *
187
+ * @example Explicit control mode
188
+ * ```tsx
189
+ * <Field control={form.control} name="email" label="Email">
190
+ * <Input type="email" />
191
+ * </Field>
192
+ * ```
193
+ *
194
+ * @example Manual mode
195
+ * ```tsx
196
+ * <Field label="Email" error={errorMessage}>
197
+ * <Input value={email} onChange={(e) => setEmail(e.target.value)} />
198
+ * </Field>
199
+ * ```
200
+ */
201
+ declare function Field<TValues extends FieldValues = FieldValues, TName extends FieldPath<TValues> = FieldPath<TValues>>(props: FieldProps<TValues, TName>): ReactElement;
202
+
127
203
  type DashboardHeaderProps = HTMLAttributes<HTMLElement>;
128
204
  declare function DashboardHeader({ className, children, ...props }: DashboardHeaderProps): react_jsx_runtime.JSX.Element;
129
205
 
@@ -355,9 +431,37 @@ interface TableProps<T> {
355
431
 
356
432
  declare function Table<T>(props: TableProps<T>): react_jsx_runtime.JSX.Element;
357
433
 
434
+ type TextareaVariant = 'default' | 'filled' | 'ghost';
435
+ type TextareaSize = 'sm' | 'md' | 'lg';
436
+ type TextareaResize = 'none' | 'vertical' | 'horizontal' | 'both';
437
+ declare const textareaVariantClass: Record<TextareaVariant, string>;
438
+ declare const textareaSizeClass: Record<TextareaSize, string>;
439
+ declare const textareaResizeClass: Record<TextareaResize, string>;
440
+ declare const textareaBaseClass = "group/textarea relative flex w-full text-foreground outline-none transition-[background-color,border-color,box-shadow] focus-within:ring-2 focus-within:ring-ring/40 focus-within:ring-offset-1 focus-within:ring-offset-background aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-within:ring-destructive/40 has-[textarea:disabled]:pointer-events-none has-[textarea:disabled]:opacity-50";
441
+
442
+ interface TextareaProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'> {
443
+ variant?: TextareaVariant;
444
+ textareaSize?: TextareaSize;
445
+ /** Controls the native CSS `resize` behaviour. Defaults to `'vertical'`. */
446
+ resize?: TextareaResize;
447
+ /** Optional label rendered above the field. */
448
+ label?: ReactNode;
449
+ /** Helper text rendered under the field when not in an error state. */
450
+ helperText?: ReactNode;
451
+ /** Error message — renders in destructive style and sets aria-invalid. */
452
+ error?: ReactNode;
453
+ /** Stretch the wrapper to fill the parent's inline width. Defaults to `true`. */
454
+ fullWidth?: boolean;
455
+ /** Class applied to the outer wrapper that frames the textarea. */
456
+ wrapperClassName?: string;
457
+ /** Class applied to the field container (`<label>` block). */
458
+ containerClassName?: string;
459
+ }
460
+ declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.RefAttributes<HTMLTextAreaElement>>;
461
+
358
462
  type Direction = 'ltr' | 'rtl';
359
463
  declare function useDirection(): Direction;
360
464
 
361
465
  declare function cn(...inputs: ClassValue[]): string;
362
466
 
363
- export { AppShell, type AppShellBrand, type AppShellNavGroup, type AppShellNavItem, type AppShellProps, Avatar, type AvatarProps, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Checkbox, type CheckboxProps, type CheckboxSize, type Column, type ColumnAlign, DashboardContent, type DashboardContentProps, DashboardHeader, type DashboardHeaderProps, DashboardLayout, type DashboardLayoutContextValue, type DashboardLayoutProps, DashboardMain, type DashboardMainProps, type Direction, HeaderActions, type HeaderActionsProps, HeaderCollapseTrigger, type HeaderCollapseTriggerProps, HeaderMobileTrigger, type HeaderMobileTriggerProps, HeaderSearch, type HeaderSearchProps, HeaderTitle, type HeaderTitleProps, Input, type InputProps, type InputSize, type InputVariant, type LanguageOption, LanguageSwitcher, type LanguageSwitcherProps, type PaginationState, type RowSelectionState, Sidebar, SidebarFooter, type SidebarFooterProps, SidebarGroup, type SidebarGroupProps, SidebarHeader, type SidebarHeaderProps, SidebarNav, SidebarNavGroup, type SidebarNavGroupProps, SidebarNavItem, type SidebarNavItemProps, type SidebarNavItemRenderProps, type SidebarNavProps, type SidebarProps, type SortDirection, type SortState, type SortableValue, Table, type TableProps, type TableSize, type TableSizeClasses, buttonBaseClass, buttonSizeClass, buttonVariantClass, cn, inputBaseClass, inputSizeClass, inputVariantClass, alignClass as tableAlignClass, tableBaseClass, selectedRowClass as tableSelectedRowClass, tableSizeClass, sortIconClass as tableSortIconClass, useDashboardLayout, useDirection };
467
+ export { AppShell, type AppShellBrand, type AppShellNavGroup, type AppShellNavItem, type AppShellProps, Avatar, type AvatarProps, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Checkbox, type CheckboxProps, type CheckboxSize, type Column, type ColumnAlign, DashboardContent, type DashboardContentProps, DashboardHeader, type DashboardHeaderProps, DashboardLayout, type DashboardLayoutContextValue, type DashboardLayoutProps, DashboardMain, type DashboardMainProps, type Direction, Field, type FieldProps, type FieldRHFProps, HeaderActions, type HeaderActionsProps, HeaderCollapseTrigger, type HeaderCollapseTriggerProps, HeaderMobileTrigger, type HeaderMobileTriggerProps, HeaderSearch, type HeaderSearchProps, HeaderTitle, type HeaderTitleProps, Input, type InputProps, type InputSize, type InputVariant, type LanguageOption, LanguageSwitcher, type LanguageSwitcherProps, type PaginationState, type RowSelectionState, Sidebar, SidebarFooter, type SidebarFooterProps, SidebarGroup, type SidebarGroupProps, SidebarHeader, type SidebarHeaderProps, SidebarNav, SidebarNavGroup, type SidebarNavGroupProps, SidebarNavItem, type SidebarNavItemProps, type SidebarNavItemRenderProps, type SidebarNavProps, type SidebarProps, type SortDirection, type SortState, type SortableValue, Table, type TableProps, type TableSize, type TableSizeClasses, Textarea, type TextareaProps, type TextareaResize, type TextareaSize, type TextareaVariant, buttonBaseClass, buttonSizeClass, buttonVariantClass, cn, inputBaseClass, inputSizeClass, inputVariantClass, alignClass as tableAlignClass, tableBaseClass, selectedRowClass as tableSelectedRowClass, tableSizeClass, sortIconClass as tableSortIconClass, textareaBaseClass, textareaResizeClass, textareaSizeClass, textareaVariantClass, useDashboardLayout, useDirection };
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { clsx } from 'clsx';
3
3
  import { twMerge } from 'tailwind-merge';
4
4
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
5
5
  import { Loader2, Check, Minus, ChevronLeft, Menu, ChevronDown, ChevronsUpDown, ChevronUp, ChevronRight } from 'lucide-react';
6
+ import { useFormContext, Controller } from 'react-hook-form';
6
7
 
7
8
  // src/components/dashboard-layout/context.ts
8
9
  var DashboardLayoutContext = createContext(null);
@@ -742,6 +743,125 @@ var Checkbox = forwardRef(function Checkbox2({
742
743
  )
743
744
  ] });
744
745
  });
746
+ function Field(props) {
747
+ const formContext = useFormContext();
748
+ if (props.name !== void 0) {
749
+ const { control: explicitControl, name, children: children2, ...layout2 } = props;
750
+ const control = explicitControl ?? formContext?.control;
751
+ if (!control) {
752
+ throw new Error(
753
+ '<Field name="..."> requires either a `control` prop OR being rendered inside <FormProvider>. Wrap your form with <FormProvider {...form}> from react-hook-form, or pass `control={form.control}` explicitly.'
754
+ );
755
+ }
756
+ return /* @__PURE__ */ jsx(
757
+ Controller,
758
+ {
759
+ control,
760
+ name,
761
+ render: ({ field, fieldState }) => /* @__PURE__ */ jsx(FieldShell, { ...layout2, error: fieldState.error?.message, invalid: fieldState.invalid, children: cloneFieldChild(children2, {
762
+ name: field.name,
763
+ value: field.value ?? "",
764
+ onChange: field.onChange,
765
+ onBlur: field.onBlur,
766
+ ref: field.ref,
767
+ disabled: layout2.disabled ?? field.disabled
768
+ }) })
769
+ }
770
+ );
771
+ }
772
+ const { children, error, invalid, ...layout } = props;
773
+ return /* @__PURE__ */ jsx(FieldShell, { ...layout, error, invalid: invalid ?? Boolean(error), children });
774
+ }
775
+ function FieldShell({
776
+ label,
777
+ description,
778
+ error,
779
+ invalid = false,
780
+ required = false,
781
+ disabled = false,
782
+ fullWidth = true,
783
+ className,
784
+ children
785
+ }) {
786
+ const reactId = useId();
787
+ if (!isValidElement(children)) {
788
+ throw new Error("<Field> requires a single React element as its child.");
789
+ }
790
+ const childProps = children.props;
791
+ const id = childProps.id ?? reactId;
792
+ const descriptionId = `${id}-description`;
793
+ const errorId = `${id}-error`;
794
+ const showError = invalid && error !== void 0 && error !== null && error !== false;
795
+ const showDescription = !showError && description !== void 0 && description !== null;
796
+ const userDescribedBy = childProps["aria-describedby"];
797
+ const describedBy = [userDescribedBy, showDescription ? descriptionId : null, showError ? errorId : null].filter(Boolean).join(" ") || void 0;
798
+ const enhancedChild = cloneFieldChild(children, {
799
+ id,
800
+ "aria-invalid": childProps["aria-invalid"] ?? (invalid || void 0),
801
+ "aria-describedby": describedBy,
802
+ disabled: childProps.disabled ?? disabled,
803
+ required: childProps.required ?? required
804
+ });
805
+ return /* @__PURE__ */ jsxs(
806
+ "div",
807
+ {
808
+ "data-invalid": invalid || void 0,
809
+ "data-disabled": disabled || void 0,
810
+ className: cn("flex flex-col gap-1.5", fullWidth && "w-full", className),
811
+ children: [
812
+ label !== void 0 && label !== null && /* @__PURE__ */ jsxs(
813
+ "label",
814
+ {
815
+ htmlFor: id,
816
+ className: cn(
817
+ "text-sm font-medium select-none text-foreground",
818
+ disabled && "opacity-50",
819
+ invalid && "text-destructive"
820
+ ),
821
+ children: [
822
+ label,
823
+ required && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ms-0.5 text-destructive", children: "*" })
824
+ ]
825
+ }
826
+ ),
827
+ enhancedChild,
828
+ showError ? /* @__PURE__ */ jsx(
829
+ "p",
830
+ {
831
+ id: errorId,
832
+ role: "alert",
833
+ "aria-live": "polite",
834
+ className: "text-xs font-medium text-destructive",
835
+ children: error
836
+ }
837
+ ) : showDescription ? /* @__PURE__ */ jsx("p", { id: descriptionId, className: "text-xs text-muted-foreground", children: description }) : null
838
+ ]
839
+ }
840
+ );
841
+ }
842
+ function cloneFieldChild(child, injected) {
843
+ const childProps = child.props;
844
+ const childRef = child.ref;
845
+ const merged = { ...injected };
846
+ for (const key of Object.keys(childProps)) {
847
+ const value = childProps[key];
848
+ if (value !== void 0) merged[key] = value;
849
+ }
850
+ if (injected.ref) {
851
+ merged.ref = mergeRefs(injected.ref, childRef);
852
+ } else if (childRef) {
853
+ merged.ref = childRef;
854
+ }
855
+ return cloneElement(child, merged);
856
+ }
857
+ function mergeRefs(...refs) {
858
+ return (instance) => {
859
+ for (const ref of refs) {
860
+ if (typeof ref === "function") ref(instance);
861
+ else if (ref && typeof ref === "object") ref.current = instance;
862
+ }
863
+ };
864
+ }
745
865
 
746
866
  // src/components/input/inputVariants.ts
747
867
  var inputVariantClass = {
@@ -1384,6 +1504,91 @@ function SortIndicator({ active, direction }) {
1384
1504
  return direction === "asc" ? /* @__PURE__ */ jsx(ChevronUp, { "aria-hidden": "true", className }) : /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": "true", className });
1385
1505
  }
1386
1506
 
1387
- export { AppShell, Avatar, Button, Checkbox, DashboardContent, DashboardHeader, DashboardLayout, DashboardMain, HeaderActions, HeaderCollapseTrigger, HeaderMobileTrigger, HeaderSearch, HeaderTitle, Input, LanguageSwitcher, Sidebar, SidebarFooter, SidebarGroup, SidebarHeader, SidebarNav, SidebarNavGroup, SidebarNavItem, Table, buttonBaseClass, buttonSizeClass, buttonVariantClass, cn, inputBaseClass, inputSizeClass, inputVariantClass, alignClass as tableAlignClass, tableBaseClass, selectedRowClass as tableSelectedRowClass, tableSizeClass, sortIconClass as tableSortIconClass, useDashboardLayout, useDirection };
1507
+ // src/components/textarea/textareaVariants.ts
1508
+ var textareaVariantClass = {
1509
+ default: "border border-input bg-background hover:border-ring",
1510
+ filled: "border border-transparent bg-muted hover:bg-muted/80",
1511
+ ghost: "border border-transparent bg-transparent hover:bg-accent"
1512
+ };
1513
+ var textareaSizeClass = {
1514
+ sm: "rounded-md px-2.5 py-1.5 text-sm",
1515
+ md: "rounded-md px-3 py-2 text-sm",
1516
+ lg: "rounded-md px-4 py-2.5 text-base"
1517
+ };
1518
+ var textareaResizeClass = {
1519
+ none: "resize-none",
1520
+ vertical: "resize-y",
1521
+ horizontal: "resize-x",
1522
+ both: "resize"
1523
+ };
1524
+ var textareaBaseClass = "group/textarea relative flex w-full text-foreground outline-none transition-[background-color,border-color,box-shadow] focus-within:ring-2 focus-within:ring-ring/40 focus-within:ring-offset-1 focus-within:ring-offset-background aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-within:ring-destructive/40 has-[textarea:disabled]:pointer-events-none has-[textarea:disabled]:opacity-50";
1525
+ var Textarea = forwardRef(function Textarea2({
1526
+ variant = "default",
1527
+ textareaSize = "md",
1528
+ resize = "vertical",
1529
+ label,
1530
+ helperText,
1531
+ error,
1532
+ fullWidth = true,
1533
+ rows = 4,
1534
+ id,
1535
+ className,
1536
+ wrapperClassName,
1537
+ containerClassName,
1538
+ "aria-invalid": ariaInvalidProp,
1539
+ "aria-describedby": ariaDescribedByProp,
1540
+ disabled,
1541
+ ...props
1542
+ }, ref) {
1543
+ const generatedId = useId();
1544
+ const textareaId = id ?? generatedId;
1545
+ const helperId = `${textareaId}-helper`;
1546
+ const errorId = `${textareaId}-error`;
1547
+ const hasError = error !== void 0 && error !== null && error !== false;
1548
+ const ariaInvalid = ariaInvalidProp ?? (hasError ? true : void 0);
1549
+ const describedByIds = [
1550
+ ariaDescribedByProp,
1551
+ hasError ? errorId : null,
1552
+ !hasError && helperText ? helperId : null
1553
+ ].filter(Boolean).join(" ");
1554
+ const ariaDescribedBy = describedByIds.length > 0 ? describedByIds : void 0;
1555
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", fullWidth && "w-full", containerClassName), children: [
1556
+ label !== void 0 && label !== null && /* @__PURE__ */ jsx("label", { htmlFor: textareaId, className: "text-sm font-medium text-foreground select-none", children: label }),
1557
+ /* @__PURE__ */ jsx(
1558
+ "div",
1559
+ {
1560
+ "data-slot": "textarea-wrapper",
1561
+ className: cn(
1562
+ textareaBaseClass,
1563
+ textareaVariantClass[variant],
1564
+ textareaSizeClass[textareaSize],
1565
+ wrapperClassName
1566
+ ),
1567
+ "aria-invalid": ariaInvalid,
1568
+ "data-disabled": disabled ? "true" : void 0,
1569
+ children: /* @__PURE__ */ jsx(
1570
+ "textarea",
1571
+ {
1572
+ ref,
1573
+ id: textareaId,
1574
+ rows,
1575
+ disabled,
1576
+ "aria-invalid": ariaInvalid,
1577
+ "aria-describedby": ariaDescribedBy,
1578
+ className: cn(
1579
+ "w-full min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed",
1580
+ textareaResizeClass[resize],
1581
+ className
1582
+ ),
1583
+ ...props
1584
+ }
1585
+ )
1586
+ }
1587
+ ),
1588
+ hasError ? /* @__PURE__ */ jsx("p", { id: errorId, className: "text-xs text-destructive", children: error }) : helperText ? /* @__PURE__ */ jsx("p", { id: helperId, className: "text-xs text-muted-foreground", children: helperText }) : null
1589
+ ] });
1590
+ });
1591
+
1592
+ export { AppShell, Avatar, Button, Checkbox, DashboardContent, DashboardHeader, DashboardLayout, DashboardMain, Field, HeaderActions, HeaderCollapseTrigger, HeaderMobileTrigger, HeaderSearch, HeaderTitle, Input, LanguageSwitcher, Sidebar, SidebarFooter, SidebarGroup, SidebarHeader, SidebarNav, SidebarNavGroup, SidebarNavItem, Table, Textarea, buttonBaseClass, buttonSizeClass, buttonVariantClass, cn, inputBaseClass, inputSizeClass, inputVariantClass, alignClass as tableAlignClass, tableBaseClass, selectedRowClass as tableSelectedRowClass, tableSizeClass, sortIconClass as tableSortIconClass, textareaBaseClass, textareaResizeClass, textareaSizeClass, textareaVariantClass, useDashboardLayout, useDirection };
1388
1593
  //# sourceMappingURL=index.js.map
1389
1594
  //# sourceMappingURL=index.js.map