@dimaan/ui 0.0.9 → 0.0.10

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
@@ -2,6 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { HTMLAttributes, ReactNode, ReactElement, ButtonHTMLAttributes, InputHTMLAttributes, ChangeEvent, FieldsetHTMLAttributes, AnchorHTMLAttributes, Ref, TextareaHTMLAttributes } from 'react';
4
4
  import { FieldValues, FieldPath, Control } from 'react-hook-form';
5
+ import * as RadixRadioGroup from '@radix-ui/react-radio-group';
5
6
  import { ClassValue } from 'clsx';
6
7
 
7
8
  interface DashboardLayoutContextValue {
@@ -314,47 +315,45 @@ declare const inputBaseClass = "group/input relative inline-flex w-full items-ce
314
315
  interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix'> {
315
316
  variant?: InputVariant;
316
317
  inputSize?: InputSize;
317
- /** Optional label rendered above the field. */
318
- label?: ReactNode;
319
- /** Helper text rendered under the field when not in an error state. */
320
- helperText?: ReactNode;
321
- /** Error message — renders in destructive style and sets aria-invalid. */
322
- error?: ReactNode;
323
318
  /** Element rendered before the input (icon, prefix text, etc.). */
324
319
  leadingIcon?: ReactNode;
325
320
  /** Element rendered after the input (icon, suffix text, etc.). */
326
321
  trailingIcon?: ReactNode;
327
- /** Stretch the wrapper to fill the parent's inline width. Defaults to `true`. */
328
- fullWidth?: boolean;
329
322
  /** Class applied to the outer wrapper that holds the icons + input. */
330
323
  wrapperClassName?: string;
331
- /** Class applied to the field container (`<label>` block). */
332
- containerClassName?: string;
333
324
  }
334
325
  /**
335
- * Text input with optional label, helper text, error message, and leading/trailing icons.
336
- * Works standalone (uses `label`/`helperText`/`error` props) OR wrapped inside `<Field>`
337
- * (id and aria-* are injected by Field via `cloneElement`).
326
+ * Bare text input renders the wrapper + native `<input>` + optional leading /
327
+ * trailing icons. **No label/helperText/error props by design** (per ADR-007:
328
+ * Field owns all form layout). Wrap in `<Field label="…">` for label, helper,
329
+ * error rendering and full a11y wiring.
338
330
  *
339
- * @example Standalone with label + helper
331
+ * @example Inside a Field (RHF + Zod)
340
332
  * ```tsx
341
- * <Input label="Email" helperText="We'll never share it." type="email" />
333
+ * <Field name="email" label="Email" description="" required>
334
+ * <Input type="email" />
335
+ * </Field>
342
336
  * ```
343
337
  *
344
338
  * @example With icons
345
339
  * ```tsx
346
- * <Input
347
- * label="Search"
348
- * leadingIcon={<Search />}
349
- * trailingIcon={<X onClick={clear} />}
350
- * />
340
+ * <Field label="Search">
341
+ * <Input
342
+ * leadingIcon={<Search />}
343
+ * trailingIcon={<X onClick={clear} />}
344
+ * placeholder="Type to search…"
345
+ * />
346
+ * </Field>
351
347
  * ```
352
348
  *
353
- * @example Inside a Field (RHF + Zod)
349
+ * @example Bare in a filter bar (no Field)
354
350
  * ```tsx
355
- * <Field name="email" label="Email" required>
356
- * <Input type="email" />
357
- * </Field>
351
+ * <Input
352
+ * value={search}
353
+ * onChange={(e) => setSearch(e.target.value)}
354
+ * placeholder="Search…"
355
+ * aria-label="Search products"
356
+ * />
358
357
  * ```
359
358
  */
360
359
  declare const Input: react.ForwardRefExoticComponent<InputProps & react.RefAttributes<HTMLInputElement>>;
@@ -372,6 +371,126 @@ interface LanguageSwitcherProps<TCode extends string = string> extends Omit<Fiel
372
371
  }
373
372
  declare function LanguageSwitcher<TCode extends string = string>({ languages, value, onChange, ariaLabel, className, ...props }: LanguageSwitcherProps<TCode>): react_jsx_runtime.JSX.Element;
374
373
 
374
+ type RadioGroupSize = 'sm' | 'md' | 'lg';
375
+ /** Outer circle (radio button itself) — sized + bordered. */
376
+ declare const radioItemSizeClass: Record<RadioGroupSize, string>;
377
+ /** Inner indicator (the filled dot when selected). Centred via flex on the parent. */
378
+ declare const radioIndicatorSizeClass: Record<RadioGroupSize, string>;
379
+ /** Label text size that pairs naturally with each radio size. */
380
+ declare const radioLabelSizeClass: Record<RadioGroupSize, string>;
381
+ declare const radioItemBaseClass = "aspect-square shrink-0 rounded-full border border-input bg-background text-primary outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:ring-offset-2 focus-visible:ring-offset-background hover:border-ring disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-visible:ring-destructive/40 data-[state=checked]:border-primary";
382
+ declare const radioIndicatorBaseClass = "flex h-full w-full items-center justify-center";
383
+ declare const radioIndicatorDotClass = "rounded-full bg-primary";
384
+ /** Each option row: radio + label + optional description. */
385
+ declare const radioOptionRowClass = "flex cursor-pointer items-start gap-2 has-[button:disabled]:cursor-not-allowed";
386
+ /** The group container — vertical stack by default, horizontal row when orientation="horizontal". */
387
+ declare const radioGroupBaseClass = "flex gap-3";
388
+ declare const radioGroupOrientationClass: {
389
+ readonly vertical: "flex-col";
390
+ readonly horizontal: "flex-row flex-wrap";
391
+ };
392
+
393
+ interface RadioGroupOption {
394
+ value: string;
395
+ /** Visible label rendered next to the radio button. */
396
+ label: ReactNode;
397
+ /** Optional secondary text rendered below the label (e.g. plan description). */
398
+ description?: ReactNode;
399
+ disabled?: boolean;
400
+ }
401
+ type RadioGroupOrientation = 'vertical' | 'horizontal';
402
+ interface RadioGroupProps {
403
+ /** Visual size of each radio + label. */
404
+ radioSize?: RadioGroupSize;
405
+ /** Layout direction within the group. `'vertical'` (default) stacks options; `'horizontal'` lays them out in a row. */
406
+ orientation?: RadioGroupOrientation;
407
+ /** Controlled selected value (Radix-style). */
408
+ value?: string;
409
+ /** Initial selected value for uncontrolled usage. */
410
+ defaultValue?: string;
411
+ /** Radix-style change handler — receives the new value directly. */
412
+ onValueChange?: (value: string) => void;
413
+ /** Synthetic-event handler for `react-hook-form`'s `field.onChange` and other consumers. */
414
+ onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
415
+ /** Called when focus leaves the group. */
416
+ onBlur?: () => void;
417
+ /** Form name (for native form submission). */
418
+ name?: string;
419
+ /** Disables the entire group. */
420
+ disabled?: boolean;
421
+ /** Marks the group as required. */
422
+ required?: boolean;
423
+ /** Override id (otherwise auto-generated via useId). */
424
+ id?: string;
425
+ /** Declarative options. When `children` is provided it wins (escape hatch for custom content). */
426
+ options?: RadioGroupOption[];
427
+ /** Class on the outer group container. */
428
+ className?: string;
429
+ 'aria-label'?: string;
430
+ 'aria-labelledby'?: string;
431
+ 'aria-describedby'?: string;
432
+ 'aria-invalid'?: boolean | 'true' | 'false';
433
+ /** Radix children — used for advanced composition (custom RadioGroupItem layouts). */
434
+ children?: ReactNode;
435
+ }
436
+ /**
437
+ * Group of mutually-exclusive radio buttons built on `@radix-ui/react-radio-group`.
438
+ * Use for **3–5 options** where Select would be overkill (pricing tier, privacy
439
+ * level, single-choice settings). Bare component — wrap in `<Field label="…">`
440
+ * for the GROUP label, helper, and error rendering.
441
+ *
442
+ * Each option carries its own per-radio `label` (and optional `description`).
443
+ * The Field's outer label names the group; the option labels name each choice.
444
+ *
445
+ * @example Inside a Field (RHF + Zod)
446
+ * ```tsx
447
+ * <Field name="plan" label="Subscription plan" description="You can change anytime.">
448
+ * <RadioGroup
449
+ * options={[
450
+ * { value: 'free', label: 'Free', description: 'Up to 3 projects' },
451
+ * { value: 'pro', label: 'Pro', description: 'Unlimited projects' },
452
+ * { value: 'enterprise', label: 'Enterprise', description: 'Custom limits' },
453
+ * ]}
454
+ * />
455
+ * </Field>
456
+ * ```
457
+ *
458
+ * @example Horizontal row in a settings card
459
+ * ```tsx
460
+ * <Field label="Visibility" orientation="horizontal">
461
+ * <RadioGroup
462
+ * orientation="horizontal"
463
+ * value={visibility}
464
+ * onValueChange={setVisibility}
465
+ * options={[
466
+ * { value: 'public', label: 'Public' },
467
+ * { value: 'private', label: 'Private' },
468
+ * ]}
469
+ * />
470
+ * </Field>
471
+ * ```
472
+ */
473
+ declare const RadioGroup: react.ForwardRefExoticComponent<RadioGroupProps & react.RefAttributes<HTMLDivElement>>;
474
+ /**
475
+ * `<RadioGroupItem>` — re-exported for consumers building custom option layouts
476
+ * (icons, badges, etc.) via the `children` escape hatch.
477
+ *
478
+ * @example
479
+ * ```tsx
480
+ * <RadioGroup value={plan} onValueChange={setPlan}>
481
+ * {plans.map((p) => (
482
+ * <label key={p.value} htmlFor={p.value} className="flex items-center gap-2">
483
+ * <RadioGroupItem id={p.value} value={p.value} />
484
+ * <PlanCard {...p} />
485
+ * </label>
486
+ * ))}
487
+ * </RadioGroup>
488
+ * ```
489
+ */
490
+ declare const RadioGroupItem: react.ForwardRefExoticComponent<Omit<RadixRadioGroup.RadioGroupItemProps & react.RefAttributes<HTMLButtonElement>, "ref"> & {
491
+ radioSize?: RadioGroupSize;
492
+ } & react.RefAttributes<HTMLButtonElement>>;
493
+
375
494
  type SelectVariant = 'default' | 'filled' | 'ghost';
376
495
  type SelectSize = 'sm' | 'md' | 'lg';
377
496
  declare const selectVariantClass: Record<SelectVariant, string>;
@@ -719,41 +838,26 @@ interface TextareaProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>
719
838
  textareaSize?: TextareaSize;
720
839
  /** Controls the native CSS `resize` behaviour. Defaults to `'vertical'`. */
721
840
  resize?: TextareaResize;
722
- /** Optional label rendered above the field. */
723
- label?: ReactNode;
724
- /** Helper text rendered under the field when not in an error state. */
725
- helperText?: ReactNode;
726
- /** Error message — renders in destructive style and sets aria-invalid. */
727
- error?: ReactNode;
728
- /** Stretch the wrapper to fill the parent's inline width. Defaults to `true`. */
729
- fullWidth?: boolean;
730
841
  /** Class applied to the outer wrapper that frames the textarea. */
731
842
  wrapperClassName?: string;
732
- /** Class applied to the field container (`<label>` block). */
733
- containerClassName?: string;
734
843
  }
735
844
  /**
736
- * Multi-line text input with the same label/helper/error/aria contract as `<Input>`.
737
- * Works standalone OR wrapped inside `<Field>`.
845
+ * Bare multi-line text input renders the wrapper + native `<textarea>`. **No
846
+ * label/helperText/error props by design** (per ADR-007: Field owns all form
847
+ * layout). Wrap in `<Field label="…">` for label, helper, error rendering and
848
+ * full a11y wiring.
738
849
  *
739
- * @example Standalone
740
- * ```tsx
741
- * <Textarea label="Bio" helperText="Up to 280 characters." rows={4} />
742
- * ```
743
- *
744
- * @example With error + custom resize
850
+ * @example Inside a Field (RHF + Zod)
745
851
  * ```tsx
746
- * <Textarea
747
- * label="Notes"
748
- * error={errors.notes?.message}
749
- * resize="vertical"
750
- * />
852
+ * <Field name="bio" label="Bio" description="Up to 280 characters.">
853
+ * <Textarea rows={4} />
854
+ * </Field>
751
855
  * ```
752
856
  *
753
- * @example Inside a Field (RHF + Zod)
857
+ * @example Custom resize behaviour
754
858
  * ```tsx
755
- * <Field name="bio" label="Bio">
756
- * <Textarea rows={4} />
859
+ * <Field label="Notes">
860
+ * <Textarea resize="none" rows={6} />
757
861
  * </Field>
758
862
  * ```
759
863
  */
@@ -764,4 +868,4 @@ declare function useDirection(): Direction;
764
868
 
765
869
  declare function cn(...inputs: ClassValue[]): string;
766
870
 
767
- 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 FieldOrientation, 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, Select, type SelectOption, type SelectProps, type SelectSize, type SelectVariant, 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, Switch, type SwitchProps, type SwitchSize, Table, type TableProps, type TableSize, type TableSizeClasses, Textarea, type TextareaProps, type TextareaResize, type TextareaSize, type TextareaVariant, buttonBaseClass, buttonSizeClass, buttonVariantClass, cn, inputBaseClass, inputSizeClass, inputVariantClass, selectBaseClass, selectSizeClass, selectVariantClass, switchThumbBaseClass, switchThumbClass, switchTrackBaseClass, switchTrackClass, alignClass as tableAlignClass, tableBaseClass, selectedRowClass as tableSelectedRowClass, tableSizeClass, sortIconClass as tableSortIconClass, textareaBaseClass, textareaResizeClass, textareaSizeClass, textareaVariantClass, useDashboardLayout, useDirection };
871
+ 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 FieldOrientation, 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, RadioGroup, RadioGroupItem, type RadioGroupOption, type RadioGroupOrientation, type RadioGroupProps, type RadioGroupSize, type RowSelectionState, Select, type SelectOption, type SelectProps, type SelectSize, type SelectVariant, 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, Switch, type SwitchProps, type SwitchSize, Table, type TableProps, type TableSize, type TableSizeClasses, Textarea, type TextareaProps, type TextareaResize, type TextareaSize, type TextareaVariant, buttonBaseClass, buttonSizeClass, buttonVariantClass, cn, inputBaseClass, inputSizeClass, inputVariantClass, radioGroupBaseClass, radioGroupOrientationClass, radioIndicatorBaseClass, radioIndicatorDotClass, radioIndicatorSizeClass, radioItemBaseClass, radioItemSizeClass, radioLabelSizeClass, radioOptionRowClass, selectBaseClass, selectSizeClass, selectVariantClass, switchThumbBaseClass, switchThumbClass, switchTrackBaseClass, switchTrackClass, alignClass as tableAlignClass, tableBaseClass, selectedRowClass as tableSelectedRowClass, tableSizeClass, sortIconClass as tableSortIconClass, textareaBaseClass, textareaResizeClass, textareaSizeClass, textareaVariantClass, useDashboardLayout, useDirection };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { HTMLAttributes, ReactNode, ReactElement, ButtonHTMLAttributes, InputHTMLAttributes, ChangeEvent, FieldsetHTMLAttributes, AnchorHTMLAttributes, Ref, TextareaHTMLAttributes } from 'react';
4
4
  import { FieldValues, FieldPath, Control } from 'react-hook-form';
5
+ import * as RadixRadioGroup from '@radix-ui/react-radio-group';
5
6
  import { ClassValue } from 'clsx';
6
7
 
7
8
  interface DashboardLayoutContextValue {
@@ -314,47 +315,45 @@ declare const inputBaseClass = "group/input relative inline-flex w-full items-ce
314
315
  interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix'> {
315
316
  variant?: InputVariant;
316
317
  inputSize?: InputSize;
317
- /** Optional label rendered above the field. */
318
- label?: ReactNode;
319
- /** Helper text rendered under the field when not in an error state. */
320
- helperText?: ReactNode;
321
- /** Error message — renders in destructive style and sets aria-invalid. */
322
- error?: ReactNode;
323
318
  /** Element rendered before the input (icon, prefix text, etc.). */
324
319
  leadingIcon?: ReactNode;
325
320
  /** Element rendered after the input (icon, suffix text, etc.). */
326
321
  trailingIcon?: ReactNode;
327
- /** Stretch the wrapper to fill the parent's inline width. Defaults to `true`. */
328
- fullWidth?: boolean;
329
322
  /** Class applied to the outer wrapper that holds the icons + input. */
330
323
  wrapperClassName?: string;
331
- /** Class applied to the field container (`<label>` block). */
332
- containerClassName?: string;
333
324
  }
334
325
  /**
335
- * Text input with optional label, helper text, error message, and leading/trailing icons.
336
- * Works standalone (uses `label`/`helperText`/`error` props) OR wrapped inside `<Field>`
337
- * (id and aria-* are injected by Field via `cloneElement`).
326
+ * Bare text input renders the wrapper + native `<input>` + optional leading /
327
+ * trailing icons. **No label/helperText/error props by design** (per ADR-007:
328
+ * Field owns all form layout). Wrap in `<Field label="…">` for label, helper,
329
+ * error rendering and full a11y wiring.
338
330
  *
339
- * @example Standalone with label + helper
331
+ * @example Inside a Field (RHF + Zod)
340
332
  * ```tsx
341
- * <Input label="Email" helperText="We'll never share it." type="email" />
333
+ * <Field name="email" label="Email" description="" required>
334
+ * <Input type="email" />
335
+ * </Field>
342
336
  * ```
343
337
  *
344
338
  * @example With icons
345
339
  * ```tsx
346
- * <Input
347
- * label="Search"
348
- * leadingIcon={<Search />}
349
- * trailingIcon={<X onClick={clear} />}
350
- * />
340
+ * <Field label="Search">
341
+ * <Input
342
+ * leadingIcon={<Search />}
343
+ * trailingIcon={<X onClick={clear} />}
344
+ * placeholder="Type to search…"
345
+ * />
346
+ * </Field>
351
347
  * ```
352
348
  *
353
- * @example Inside a Field (RHF + Zod)
349
+ * @example Bare in a filter bar (no Field)
354
350
  * ```tsx
355
- * <Field name="email" label="Email" required>
356
- * <Input type="email" />
357
- * </Field>
351
+ * <Input
352
+ * value={search}
353
+ * onChange={(e) => setSearch(e.target.value)}
354
+ * placeholder="Search…"
355
+ * aria-label="Search products"
356
+ * />
358
357
  * ```
359
358
  */
360
359
  declare const Input: react.ForwardRefExoticComponent<InputProps & react.RefAttributes<HTMLInputElement>>;
@@ -372,6 +371,126 @@ interface LanguageSwitcherProps<TCode extends string = string> extends Omit<Fiel
372
371
  }
373
372
  declare function LanguageSwitcher<TCode extends string = string>({ languages, value, onChange, ariaLabel, className, ...props }: LanguageSwitcherProps<TCode>): react_jsx_runtime.JSX.Element;
374
373
 
374
+ type RadioGroupSize = 'sm' | 'md' | 'lg';
375
+ /** Outer circle (radio button itself) — sized + bordered. */
376
+ declare const radioItemSizeClass: Record<RadioGroupSize, string>;
377
+ /** Inner indicator (the filled dot when selected). Centred via flex on the parent. */
378
+ declare const radioIndicatorSizeClass: Record<RadioGroupSize, string>;
379
+ /** Label text size that pairs naturally with each radio size. */
380
+ declare const radioLabelSizeClass: Record<RadioGroupSize, string>;
381
+ declare const radioItemBaseClass = "aspect-square shrink-0 rounded-full border border-input bg-background text-primary outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:ring-offset-2 focus-visible:ring-offset-background hover:border-ring disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-visible:ring-destructive/40 data-[state=checked]:border-primary";
382
+ declare const radioIndicatorBaseClass = "flex h-full w-full items-center justify-center";
383
+ declare const radioIndicatorDotClass = "rounded-full bg-primary";
384
+ /** Each option row: radio + label + optional description. */
385
+ declare const radioOptionRowClass = "flex cursor-pointer items-start gap-2 has-[button:disabled]:cursor-not-allowed";
386
+ /** The group container — vertical stack by default, horizontal row when orientation="horizontal". */
387
+ declare const radioGroupBaseClass = "flex gap-3";
388
+ declare const radioGroupOrientationClass: {
389
+ readonly vertical: "flex-col";
390
+ readonly horizontal: "flex-row flex-wrap";
391
+ };
392
+
393
+ interface RadioGroupOption {
394
+ value: string;
395
+ /** Visible label rendered next to the radio button. */
396
+ label: ReactNode;
397
+ /** Optional secondary text rendered below the label (e.g. plan description). */
398
+ description?: ReactNode;
399
+ disabled?: boolean;
400
+ }
401
+ type RadioGroupOrientation = 'vertical' | 'horizontal';
402
+ interface RadioGroupProps {
403
+ /** Visual size of each radio + label. */
404
+ radioSize?: RadioGroupSize;
405
+ /** Layout direction within the group. `'vertical'` (default) stacks options; `'horizontal'` lays them out in a row. */
406
+ orientation?: RadioGroupOrientation;
407
+ /** Controlled selected value (Radix-style). */
408
+ value?: string;
409
+ /** Initial selected value for uncontrolled usage. */
410
+ defaultValue?: string;
411
+ /** Radix-style change handler — receives the new value directly. */
412
+ onValueChange?: (value: string) => void;
413
+ /** Synthetic-event handler for `react-hook-form`'s `field.onChange` and other consumers. */
414
+ onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
415
+ /** Called when focus leaves the group. */
416
+ onBlur?: () => void;
417
+ /** Form name (for native form submission). */
418
+ name?: string;
419
+ /** Disables the entire group. */
420
+ disabled?: boolean;
421
+ /** Marks the group as required. */
422
+ required?: boolean;
423
+ /** Override id (otherwise auto-generated via useId). */
424
+ id?: string;
425
+ /** Declarative options. When `children` is provided it wins (escape hatch for custom content). */
426
+ options?: RadioGroupOption[];
427
+ /** Class on the outer group container. */
428
+ className?: string;
429
+ 'aria-label'?: string;
430
+ 'aria-labelledby'?: string;
431
+ 'aria-describedby'?: string;
432
+ 'aria-invalid'?: boolean | 'true' | 'false';
433
+ /** Radix children — used for advanced composition (custom RadioGroupItem layouts). */
434
+ children?: ReactNode;
435
+ }
436
+ /**
437
+ * Group of mutually-exclusive radio buttons built on `@radix-ui/react-radio-group`.
438
+ * Use for **3–5 options** where Select would be overkill (pricing tier, privacy
439
+ * level, single-choice settings). Bare component — wrap in `<Field label="…">`
440
+ * for the GROUP label, helper, and error rendering.
441
+ *
442
+ * Each option carries its own per-radio `label` (and optional `description`).
443
+ * The Field's outer label names the group; the option labels name each choice.
444
+ *
445
+ * @example Inside a Field (RHF + Zod)
446
+ * ```tsx
447
+ * <Field name="plan" label="Subscription plan" description="You can change anytime.">
448
+ * <RadioGroup
449
+ * options={[
450
+ * { value: 'free', label: 'Free', description: 'Up to 3 projects' },
451
+ * { value: 'pro', label: 'Pro', description: 'Unlimited projects' },
452
+ * { value: 'enterprise', label: 'Enterprise', description: 'Custom limits' },
453
+ * ]}
454
+ * />
455
+ * </Field>
456
+ * ```
457
+ *
458
+ * @example Horizontal row in a settings card
459
+ * ```tsx
460
+ * <Field label="Visibility" orientation="horizontal">
461
+ * <RadioGroup
462
+ * orientation="horizontal"
463
+ * value={visibility}
464
+ * onValueChange={setVisibility}
465
+ * options={[
466
+ * { value: 'public', label: 'Public' },
467
+ * { value: 'private', label: 'Private' },
468
+ * ]}
469
+ * />
470
+ * </Field>
471
+ * ```
472
+ */
473
+ declare const RadioGroup: react.ForwardRefExoticComponent<RadioGroupProps & react.RefAttributes<HTMLDivElement>>;
474
+ /**
475
+ * `<RadioGroupItem>` — re-exported for consumers building custom option layouts
476
+ * (icons, badges, etc.) via the `children` escape hatch.
477
+ *
478
+ * @example
479
+ * ```tsx
480
+ * <RadioGroup value={plan} onValueChange={setPlan}>
481
+ * {plans.map((p) => (
482
+ * <label key={p.value} htmlFor={p.value} className="flex items-center gap-2">
483
+ * <RadioGroupItem id={p.value} value={p.value} />
484
+ * <PlanCard {...p} />
485
+ * </label>
486
+ * ))}
487
+ * </RadioGroup>
488
+ * ```
489
+ */
490
+ declare const RadioGroupItem: react.ForwardRefExoticComponent<Omit<RadixRadioGroup.RadioGroupItemProps & react.RefAttributes<HTMLButtonElement>, "ref"> & {
491
+ radioSize?: RadioGroupSize;
492
+ } & react.RefAttributes<HTMLButtonElement>>;
493
+
375
494
  type SelectVariant = 'default' | 'filled' | 'ghost';
376
495
  type SelectSize = 'sm' | 'md' | 'lg';
377
496
  declare const selectVariantClass: Record<SelectVariant, string>;
@@ -719,41 +838,26 @@ interface TextareaProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>
719
838
  textareaSize?: TextareaSize;
720
839
  /** Controls the native CSS `resize` behaviour. Defaults to `'vertical'`. */
721
840
  resize?: TextareaResize;
722
- /** Optional label rendered above the field. */
723
- label?: ReactNode;
724
- /** Helper text rendered under the field when not in an error state. */
725
- helperText?: ReactNode;
726
- /** Error message — renders in destructive style and sets aria-invalid. */
727
- error?: ReactNode;
728
- /** Stretch the wrapper to fill the parent's inline width. Defaults to `true`. */
729
- fullWidth?: boolean;
730
841
  /** Class applied to the outer wrapper that frames the textarea. */
731
842
  wrapperClassName?: string;
732
- /** Class applied to the field container (`<label>` block). */
733
- containerClassName?: string;
734
843
  }
735
844
  /**
736
- * Multi-line text input with the same label/helper/error/aria contract as `<Input>`.
737
- * Works standalone OR wrapped inside `<Field>`.
845
+ * Bare multi-line text input renders the wrapper + native `<textarea>`. **No
846
+ * label/helperText/error props by design** (per ADR-007: Field owns all form
847
+ * layout). Wrap in `<Field label="…">` for label, helper, error rendering and
848
+ * full a11y wiring.
738
849
  *
739
- * @example Standalone
740
- * ```tsx
741
- * <Textarea label="Bio" helperText="Up to 280 characters." rows={4} />
742
- * ```
743
- *
744
- * @example With error + custom resize
850
+ * @example Inside a Field (RHF + Zod)
745
851
  * ```tsx
746
- * <Textarea
747
- * label="Notes"
748
- * error={errors.notes?.message}
749
- * resize="vertical"
750
- * />
852
+ * <Field name="bio" label="Bio" description="Up to 280 characters.">
853
+ * <Textarea rows={4} />
854
+ * </Field>
751
855
  * ```
752
856
  *
753
- * @example Inside a Field (RHF + Zod)
857
+ * @example Custom resize behaviour
754
858
  * ```tsx
755
- * <Field name="bio" label="Bio">
756
- * <Textarea rows={4} />
859
+ * <Field label="Notes">
860
+ * <Textarea resize="none" rows={6} />
757
861
  * </Field>
758
862
  * ```
759
863
  */
@@ -764,4 +868,4 @@ declare function useDirection(): Direction;
764
868
 
765
869
  declare function cn(...inputs: ClassValue[]): string;
766
870
 
767
- 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 FieldOrientation, 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, Select, type SelectOption, type SelectProps, type SelectSize, type SelectVariant, 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, Switch, type SwitchProps, type SwitchSize, Table, type TableProps, type TableSize, type TableSizeClasses, Textarea, type TextareaProps, type TextareaResize, type TextareaSize, type TextareaVariant, buttonBaseClass, buttonSizeClass, buttonVariantClass, cn, inputBaseClass, inputSizeClass, inputVariantClass, selectBaseClass, selectSizeClass, selectVariantClass, switchThumbBaseClass, switchThumbClass, switchTrackBaseClass, switchTrackClass, alignClass as tableAlignClass, tableBaseClass, selectedRowClass as tableSelectedRowClass, tableSizeClass, sortIconClass as tableSortIconClass, textareaBaseClass, textareaResizeClass, textareaSizeClass, textareaVariantClass, useDashboardLayout, useDirection };
871
+ 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 FieldOrientation, 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, RadioGroup, RadioGroupItem, type RadioGroupOption, type RadioGroupOrientation, type RadioGroupProps, type RadioGroupSize, type RowSelectionState, Select, type SelectOption, type SelectProps, type SelectSize, type SelectVariant, 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, Switch, type SwitchProps, type SwitchSize, Table, type TableProps, type TableSize, type TableSizeClasses, Textarea, type TextareaProps, type TextareaResize, type TextareaSize, type TextareaVariant, buttonBaseClass, buttonSizeClass, buttonVariantClass, cn, inputBaseClass, inputSizeClass, inputVariantClass, radioGroupBaseClass, radioGroupOrientationClass, radioIndicatorBaseClass, radioIndicatorDotClass, radioIndicatorSizeClass, radioItemBaseClass, radioItemSizeClass, radioLabelSizeClass, radioOptionRowClass, selectBaseClass, selectSizeClass, selectVariantClass, switchThumbBaseClass, switchThumbClass, switchTrackBaseClass, switchTrackClass, alignClass as tableAlignClass, tableBaseClass, selectedRowClass as tableSelectedRowClass, tableSizeClass, sortIconClass as tableSortIconClass, textareaBaseClass, textareaResizeClass, textareaSizeClass, textareaVariantClass, useDashboardLayout, useDirection };