atlas-react-kit 0.13.0 → 1.1.0

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.
Files changed (103) hide show
  1. package/COMPONENTS.md +144 -120
  2. package/DESIGN_RULES.md +53 -32
  3. package/README.md +12 -53
  4. package/dist/accordion.d.ts +1 -0
  5. package/dist/avatar.d.ts +1 -0
  6. package/dist/badge.d.ts +2 -3
  7. package/dist/breadcrumb.d.ts +2 -3
  8. package/dist/button.d.ts +2 -3
  9. package/dist/calendar.d.ts +2 -0
  10. package/dist/card.d.ts +3 -0
  11. package/dist/chart.d.ts +152 -0
  12. package/dist/chart.js +177 -0
  13. package/dist/color-legend.d.ts +8 -0
  14. package/dist/combobox.d.ts +13 -4
  15. package/dist/combobox.js +1 -8
  16. package/dist/date-picker.d.ts +26 -3
  17. package/dist/date-picker.js +37 -31
  18. package/dist/date-time-picker.d.ts +5 -2
  19. package/dist/date-time-picker.js +25 -38
  20. package/dist/dialog.d.ts +1 -0
  21. package/dist/dialog.js +4 -2
  22. package/dist/dropdown-menu.d.ts +9 -8
  23. package/dist/empty-panel.d.ts +8 -2
  24. package/dist/empty-panel.js +2 -2
  25. package/dist/error-boundary.d.ts +6 -1
  26. package/dist/field.d.ts +3 -0
  27. package/dist/field.js +1 -1
  28. package/dist/form/checkbox-field.d.ts +45 -0
  29. package/dist/form/checkbox-field.js +39 -0
  30. package/dist/form/combobox-field.d.ts +13 -0
  31. package/dist/form/combobox-field.js +14 -0
  32. package/dist/form/control-field.d.ts +6 -7
  33. package/dist/form/date-picker-field.d.ts +12 -21
  34. package/dist/form/date-picker-field.js +5 -4
  35. package/dist/form/date-time-picker-field.d.ts +7 -22
  36. package/dist/form/date-time-picker-field.js +4 -3
  37. package/dist/form/feedback-field.d.ts +2 -0
  38. package/dist/form/field-error.d.ts +35 -3
  39. package/dist/form/field-shell.d.ts +35 -6
  40. package/dist/form/field-shell.js +1 -1
  41. package/dist/form/focus-first-invalid.d.ts +28 -0
  42. package/dist/form/focus-first-invalid.js +29 -0
  43. package/dist/form/markdown-field.d.ts +4 -16
  44. package/dist/form/select-field.d.ts +13 -7
  45. package/dist/form/select-field.js +3 -2
  46. package/dist/form/text-field.d.ts +29 -10
  47. package/dist/form/text-field.js +4 -0
  48. package/dist/form/toggle-group-field.d.ts +30 -0
  49. package/dist/form/toggle-group-field.js +19 -0
  50. package/dist/info-tip.d.ts +10 -1
  51. package/dist/internal/as-child.d.ts +8 -0
  52. package/dist/internal/as-child.js +1 -0
  53. package/dist/internal/form-control.d.ts +3 -2
  54. package/dist/internal/form-control.js +3 -2
  55. package/dist/internal/kanban-layout.d.ts +55 -0
  56. package/dist/internal/kanban-layout.js +80 -0
  57. package/dist/internal/kanban-plugins.d.ts +17 -0
  58. package/dist/internal/kanban-plugins.js +17 -0
  59. package/dist/internal/listbox-navigation.d.ts +0 -11
  60. package/dist/internal/listbox-navigation.js +2 -2
  61. package/dist/internal/listbox-option.d.ts +0 -15
  62. package/dist/internal/listbox-option.js +1 -1
  63. package/dist/internal/use-drag-scroll.d.ts +17 -0
  64. package/dist/internal/use-drag-scroll.js +98 -0
  65. package/dist/internal/use-media-query.d.ts +4 -2
  66. package/dist/internal/use-media-query.js +11 -15
  67. package/dist/kanban.d.ts +84 -0
  68. package/dist/kanban.js +197 -0
  69. package/dist/markdown.d.ts +2 -0
  70. package/dist/meter.d.ts +7 -0
  71. package/dist/nav-link.d.ts +15 -6
  72. package/dist/nav-link.js +14 -4
  73. package/dist/next/nav-link.d.ts +6 -3
  74. package/dist/next/nav-link.js +8 -6
  75. package/dist/next/period-stepper.d.ts +11 -0
  76. package/dist/next/period-stepper.js +16 -0
  77. package/dist/next/tabs-nav-link.d.ts +6 -0
  78. package/dist/next/tabs-nav-link.js +8 -3
  79. package/dist/page-header.d.ts +19 -0
  80. package/dist/page-header.js +11 -0
  81. package/dist/pagination.d.ts +2 -0
  82. package/dist/period-stepper.d.ts +32 -0
  83. package/dist/period-stepper.js +27 -0
  84. package/dist/picker-shell.d.ts +33 -18
  85. package/dist/picker-shell.js +12 -10
  86. package/dist/progress.d.ts +1 -0
  87. package/dist/search-picker.d.ts +12 -0
  88. package/dist/select.d.ts +1 -0
  89. package/dist/skip-link.d.ts +7 -0
  90. package/dist/skip-link.js +10 -0
  91. package/dist/slider.d.ts +11 -0
  92. package/dist/sortable-table-head.d.ts +2 -0
  93. package/dist/stat-tile.d.ts +5 -0
  94. package/dist/table-body-skeleton.d.ts +2 -0
  95. package/dist/table.d.ts +1 -0
  96. package/dist/tabs.d.ts +27 -12
  97. package/dist/tabs.js +23 -10
  98. package/dist/toast.d.ts +7 -1
  99. package/dist/toggle-group.d.ts +9 -2
  100. package/dist/toggle-group.js +2 -1
  101. package/package.json +72 -6
  102. package/skills/atlas-react-kit/SKILL.md +46 -40
  103. package/theme.css +13 -0
@@ -2,15 +2,23 @@ import type * as React from "react";
2
2
  export type ColorLegendItem = {
3
3
  /** CSS color from the app (map bins, status scales). The kit does not own it. */
4
4
  color: string;
5
+ /** Value range for the swatch, such as `0–10`, shown before the label. */
5
6
  range?: string;
7
+ /** What the color means. */
6
8
  label: string;
7
9
  };
8
10
  export type ColorLegendProps = Omit<React.ComponentProps<"figure">, "children" | "title"> & {
11
+ /** Heading above the list, drawn as the figure's caption. */
9
12
  title?: string;
13
+ /** One row per color, in display order. */
10
14
  items: ColorLegendItem[];
15
+ /** A small muted note under the list, such as the data source. */
11
16
  caption?: React.ReactNode;
17
+ /** Extra content after the caption. */
12
18
  children?: React.ReactNode;
19
+ /** Names the legend when there is no `title`. */
13
20
  "aria-label"?: string;
21
+ /** Classes for the figure, e.g. overlay position and card fill. */
14
22
  className?: string;
15
23
  };
16
24
  /**
@@ -1,29 +1,38 @@
1
1
  import * as React from "react";
2
+ import type { SearchPickerProps } from "./search-picker.js";
2
3
  export type ComboboxOption = {
4
+ /** What `onValueChange` reports and `value` matches; unique in the list. */
3
5
  value: string;
6
+ /** The visible text, on the trigger when selected and in the list. */
4
7
  label: string;
5
8
  };
6
9
  type ComboboxProps = {
10
+ /** Every choice, in display order. */
7
11
  options: ComboboxOption[];
12
+ /** The selected option's value; the trigger shows its label. */
8
13
  value?: string;
14
+ /** Called with the chosen (or created) value; the popover then closes. */
9
15
  onValueChange: (value: string) => void;
16
+ /** Trigger text when nothing is selected. Default `"Select"`. */
10
17
  placeholder?: string;
18
+ /** Placeholder and accessible name for the search input. Default `"Search"`. */
11
19
  searchPlaceholder?: string;
12
- emptyText?: string;
20
+ /** Disables the trigger, so the list cannot open. */
13
21
  disabled?: boolean;
22
+ /** Goes on the trigger, so a `<Label htmlFor>` names it. Generated when omitted. */
14
23
  id?: string;
15
24
  /** Classes for the trigger, e.g. its width; the list matches it. */
16
25
  className?: string;
17
- /** Classes for the listbox, e.g. its height. Defaults to `max-h-60`. */
18
- listClassName?: string;
19
26
  /**
20
27
  * Classes for the popover panel, e.g. a width other than the trigger's.
21
28
  * Defaults to the trigger width.
22
29
  */
23
30
  contentClassName?: string;
31
+ /** Marks the trigger invalid, drawing the error border. */
24
32
  "aria-invalid"?: boolean;
25
33
  /** Name the trigger when there is no `<Label htmlFor={id}>`. */
26
34
  "aria-label"?: string;
35
+ /** Id of the element that names the trigger and the list. */
27
36
  "aria-labelledby"?: string;
28
37
  /**
29
38
  * Offer creating the current query when it is not already an option.
@@ -41,7 +50,7 @@ type ComboboxProps = {
41
50
  * `Create "{value}"`.
42
51
  */
43
52
  createLabel?: (value: string) => string;
44
- } & Omit<React.ComponentProps<"button">, "value" | "defaultValue" | "children" | "type" | "role" | "aria-expanded" | "aria-controls" | "onKeyDown">;
53
+ } & Pick<SearchPickerProps<ComboboxOption>, "emptyText" | "listClassName"> & Omit<React.ComponentProps<"button">, "value" | "defaultValue" | "children" | "type" | "role" | "aria-expanded" | "aria-controls" | "onKeyDown">;
45
54
  /**
46
55
  * Searchable single-select built from Button, Popover, and Input.
47
56
  * The trigger uses the same form-control chrome as Input and SelectTrigger.
package/dist/combobox.js CHANGED
@@ -53,7 +53,6 @@ export function Combobox({ options, value, onValueChange, placeholder = "Select"
53
53
  const [open, setOpen] = React.useState(false);
54
54
  const [query, setQuery] = React.useState("");
55
55
  const [highlight, setHighlight] = React.useState(0);
56
- const inputRef = React.useRef(null);
57
56
  const listId = React.useId();
58
57
  const generatedId = React.useId();
59
58
  const triggerId = id ?? generatedId;
@@ -101,12 +100,6 @@ export function Combobox({ options, value, onValueChange, placeholder = "Select"
101
100
  const selectedIndex = resolvedOptions.findIndex((option) => option.value === value);
102
101
  setHighlight(selectedIndex >= 0 ? selectedIndex : 0);
103
102
  };
104
- React.useEffect(() => {
105
- if (!open)
106
- return;
107
- const frame = window.requestAnimationFrame(() => inputRef.current?.focus());
108
- return () => window.cancelAnimationFrame(frame);
109
- }, [open]);
110
103
  const onQueryChange = onInputChange((next) => {
111
104
  setQuery(next);
112
105
  setHighlight(0);
@@ -141,7 +134,7 @@ export function Combobox({ options, value, onValueChange, placeholder = "Select"
141
134
  },
142
135
  });
143
136
  };
144
- return (_jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { ...props, id: triggerId, type: "button", variant: "outline", role: "combobox", "aria-expanded": open, "aria-controls": listId, "aria-invalid": ariaInvalid, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, disabled: disabled, onKeyDown: onTriggerKeyDown, className: cn(formControlTriggerClassName, "justify-between", !selected && "text-muted-foreground", className), children: [_jsx("span", { className: "truncate", children: selected?.label ?? placeholder }), _jsx(ChevronDownIcon, { "data-icon": "inline-end", className: "opacity-50" })] }) }), _jsxs(PopoverContent, { align: "start", className: cn("w-[var(--radix-popover-trigger-width)] gap-0 rounded-none p-0", contentClassName), children: [_jsx("div", { "data-slot": "combobox-search", className: "border-b p-2", children: _jsx(Input, { ref: inputRef, value: query, onChange: onQueryChange, onKeyDown: onSearchKeyDown, placeholder: searchPlaceholder, "aria-label": searchPlaceholder, "aria-autocomplete": "list", "aria-controls": listId, "aria-activedescendant": activeOption ? listboxOptionId(listId, highlight) : undefined }) }), _jsx("ul", { id: listId, role: "listbox", "data-slot": "combobox-list", "aria-label": ariaLabelledBy ? undefined : ariaLabel, "aria-labelledby": ariaLabelledBy ?? (ariaLabel ? undefined : triggerId), className: empty
137
+ return (_jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { ...props, id: triggerId, type: "button", variant: "outline", role: "combobox", "aria-expanded": open, "aria-controls": listId, "aria-invalid": ariaInvalid, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, disabled: disabled, onKeyDown: onTriggerKeyDown, className: cn(formControlTriggerClassName, "justify-between", !selected && "text-muted-foreground", className), children: [_jsx("span", { className: "truncate", children: selected?.label ?? placeholder }), _jsx(ChevronDownIcon, { "data-icon": "inline-end", className: "opacity-50" })] }) }), _jsxs(PopoverContent, { align: "start", className: cn("w-[var(--radix-popover-trigger-width)] gap-0 rounded-none p-0", contentClassName), children: [_jsx("div", { "data-slot": "combobox-search", className: "border-b p-2", children: _jsx(Input, { value: query, onChange: onQueryChange, onKeyDown: onSearchKeyDown, placeholder: searchPlaceholder, "aria-label": searchPlaceholder, "aria-autocomplete": "list", "aria-controls": listId, "aria-activedescendant": activeOption ? listboxOptionId(listId, highlight) : undefined }) }), _jsx("ul", { id: listId, role: "listbox", "data-slot": "combobox-list", "aria-label": ariaLabelledBy ? undefined : ariaLabel, "aria-labelledby": ariaLabelledBy ?? (ariaLabel ? undefined : triggerId), className: empty
145
138
  ? "sr-only"
146
139
  : cn("max-h-60 overflow-y-auto p-1", listClassName), children: list.map((option, index) => {
147
140
  const isCreate = createOption != null && option === createOption;
@@ -5,7 +5,9 @@ export type { DateLike, DateMatcher, DateRange };
5
5
  export { toDate };
6
6
  /** From/to value for `DatePickerButton` in range mode; each side is `DateLike`. */
7
7
  export type DatePickerRangeValue = {
8
+ /** First day of the range. */
8
9
  from?: DateLike;
10
+ /** Last day of the range; missing while only the start is picked. */
9
11
  to?: DateLike;
10
12
  };
11
13
  /** Format a Date as a timezone-safe calendar date (`yyyy-MM-dd`). */
@@ -20,21 +22,42 @@ type DatePickerSharedProps = PickerTriggerProps & {
20
22
  numberOfMonths?: number;
21
23
  };
22
24
  export type DatePickerSingleProps = DatePickerSharedProps & {
25
+ /** Pick one day. Default `"single"`. */
23
26
  mode?: "single";
27
+ /** Controlled day, as a `Date` or `yyyy-MM-dd`. Omitted is empty. */
24
28
  value?: DateLike;
25
- onChange: (date: Date | undefined) => void;
29
+ /**
30
+ * Called with the picked day. With `clearable`, Clear calls it with
31
+ * `undefined`; without, a second click on the selected day does.
32
+ */
33
+ onValueChange?: (date: Date | undefined) => void;
34
+ /** @deprecated Use `onValueChange`; `onChange` keeps working until 2.0. */
35
+ onChange?: (date: Date | undefined) => void;
36
+ /**
37
+ * Shows a Clear row under the calendar, which emits `undefined` and
38
+ * closes the popover. A click on the selected day then keeps it instead
39
+ * of clearing it, so Clear is the one way to empty the field. Default
40
+ * `false`.
41
+ */
42
+ clearable?: boolean;
26
43
  };
27
44
  export type DatePickerRangeProps = DatePickerSharedProps & {
45
+ /** Pick a from/to range of days. */
28
46
  mode: "range";
47
+ /** Controlled range; each side is a `Date` or `yyyy-MM-dd`. Omitted is empty. */
29
48
  value?: DatePickerRangeValue;
30
- onChange: (range: DateRange | undefined) => void;
49
+ /** Called on every range click, or with `undefined` on Clear. */
50
+ onValueChange?: (range: DateRange | undefined) => void;
51
+ /** @deprecated Use `onValueChange`; `onChange` keeps working until 2.0. */
52
+ onChange?: (range: DateRange | undefined) => void;
31
53
  };
32
54
  export type DatePickerButtonProps = DatePickerSingleProps | DatePickerRangeProps;
33
55
  /**
34
56
  * Calendar popover trigger styled as a form control (same chrome as Input
35
57
  * and SelectTrigger). `mode="single"` (default) accepts `Date` or
36
58
  * `yyyy-MM-dd` and emits `Date | undefined`. `mode="range"` accepts
37
- * `{ from, to }` and emits `DateRange | undefined`. Range mode shows one
59
+ * `{ from, to }` and emits `DateRange | undefined`. Range mode always has a
60
+ * Clear row; single mode shows one with `clearable`. Range mode shows one
38
61
  * month below `md` and two at `md+` unless `numberOfMonths` is set. The
39
62
  * popover clamps to the viewport (`side` is overridable). `className` styles
40
63
  * the trigger, `contentClassName` the popover, and `calendarProps` reaches
@@ -1,11 +1,10 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { format, isSameDay } from "date-fns";
5
5
  import { toDate, } from "./internal/date-like.js";
6
6
  import { MD_MEDIA_QUERY, useMediaQuery } from "./internal/use-media-query.js";
7
- import { LazyCalendar } from "./lazy-calendar.js";
8
- import { PickerClearFooter, PickerShell, limitCalendarProps, } from "./picker-shell.js";
7
+ import { PickerShell, } from "./picker-shell.js";
9
8
  export { toDate };
10
9
  /** Format a Date as a timezone-safe calendar date (`yyyy-MM-dd`). */
11
10
  export function formatLocalDate(date) {
@@ -22,49 +21,56 @@ function formatRangeTriggerLabel(from, to, placeholder) {
22
21
  return format(from, "PPP");
23
22
  return `${format(from, "PPP")} – ${format(to, "PPP")}`;
24
23
  }
25
- function DatePickerSingleButton({ value, onChange, placeholder = "Pick a date", numberOfMonths, defaultMonth, calendarProps, minDate, maxDate, ...shell }) {
24
+ function DatePickerSingleButton({ value, onValueChange, onChange, placeholder = "Pick a date", numberOfMonths, defaultMonth, clearable = false, ...shell }) {
26
25
  const [open, setOpen] = React.useState(false);
26
+ const emit = onValueChange ?? onChange;
27
27
  const date = toDate(value);
28
- return (_jsx(PickerShell, { ...shell, empty: !date, label: date ? format(date, "PPP") : placeholder, dialogLabel: "Choose date", open: open, onOpenChange: setOpen, children: _jsx(LazyCalendar, { ...limitCalendarProps(calendarProps, minDate, maxDate), mode: "single", autoFocus: true, selected: date, defaultMonth: defaultMonth ?? date, numberOfMonths: numberOfMonths, onSelect: (next) => {
29
- onChange(next);
30
- setOpen(false);
31
- } }) }));
28
+ const onSelect = (next) => {
29
+ emit?.(next);
30
+ setOpen(false);
31
+ };
32
+ return (_jsx(PickerShell, { ...shell, empty: !date, label: date ? format(date, "PPP") : placeholder, dialogLabel: "Choose date", open: open, onOpenChange: setOpen, defaultMonth: defaultMonth ?? date, calendar: clearable
33
+ ? // Day Picker's `required` keeps the day on a second click, so
34
+ // Clear is the one way out; its type needs the literal `true`.
35
+ {
36
+ mode: "single",
37
+ required: true,
38
+ selected: date,
39
+ numberOfMonths,
40
+ onSelect,
41
+ }
42
+ : { mode: "single", selected: date, numberOfMonths, onSelect }, onClear: clearable ? () => emit?.(undefined) : undefined, clearDisabled: !date }));
32
43
  }
33
- function DatePickerRangeButton({ value, onChange, placeholder = "Pick a date range", numberOfMonths, defaultMonth, calendarProps, minDate, maxDate, ...shell }) {
44
+ function DatePickerRangeButton({ value, onValueChange, onChange, placeholder = "Pick a date range", numberOfMonths, defaultMonth, ...shell }) {
34
45
  const [open, setOpen] = React.useState(false);
46
+ const emit = onValueChange ?? onChange;
35
47
  const mdUp = useMediaQuery(MD_MEDIA_QUERY);
36
48
  const months = numberOfMonths ?? (mdUp ? 2 : 1);
37
49
  const from = toDate(value?.from);
38
50
  const to = toDate(value?.to);
39
51
  const selected = from || to ? { from, to } : undefined;
40
- // Opening on a complete range means the next click starts a new one.
41
- // Without this, Day Picker extends the old range and the popover closes
42
- // on that first click, so a fresh range needs Clear first.
43
- const restartRef = React.useRef(false);
44
- const onOpenChange = (next) => {
45
- if (next)
46
- restartRef.current = Boolean(from && to);
47
- setOpen(next);
48
- };
49
- return (_jsxs(PickerShell, { ...shell, empty: !from, label: formatRangeTriggerLabel(from, to, placeholder), dialogLabel: "Choose dates", open: open, onOpenChange: onOpenChange, children: [_jsx(LazyCalendar, { ...limitCalendarProps(calendarProps, minDate, maxDate), mode: "range", autoFocus: true, selected: selected, defaultMonth: defaultMonth ?? from ?? to, numberOfMonths: months, onSelect: (next, day) => {
50
- const range = restartRef.current ? { from: day, to: day } : next;
51
- restartRef.current = false;
52
- onChange(range);
53
- // First click is a same-day range; keep the popover open so the
54
- // user can set `to`. Close once the ends differ.
55
- if (range?.from && range.to && !isSameDay(range.from, range.to)) {
56
- setOpen(false);
57
- }
58
- } }), _jsx(PickerClearFooter, { disabled: !from && !to, onClear: () => {
59
- onChange(undefined);
52
+ return (_jsx(PickerShell, { ...shell, empty: !from, label: formatRangeTriggerLabel(from, to, placeholder), dialogLabel: "Choose dates", open: open, onOpenChange: setOpen, defaultMonth: defaultMonth ?? from ?? to, calendar: {
53
+ mode: "range",
54
+ // A click on a complete range (or on none) starts a new one, so a
55
+ // fresh range never needs Clear first. The start emits `to: undefined`.
56
+ resetOnSelect: true,
57
+ selected,
58
+ numberOfMonths: months,
59
+ onSelect: (range) => {
60
+ emit?.(range);
61
+ // Close once the ends differ; a start or a one-day range stays open.
62
+ if (range?.from && range.to && !isSameDay(range.from, range.to)) {
60
63
  setOpen(false);
61
- } })] }));
64
+ }
65
+ },
66
+ }, onClear: () => emit?.(undefined), clearDisabled: !from && !to }));
62
67
  }
63
68
  /**
64
69
  * Calendar popover trigger styled as a form control (same chrome as Input
65
70
  * and SelectTrigger). `mode="single"` (default) accepts `Date` or
66
71
  * `yyyy-MM-dd` and emits `Date | undefined`. `mode="range"` accepts
67
- * `{ from, to }` and emits `DateRange | undefined`. Range mode shows one
72
+ * `{ from, to }` and emits `DateRange | undefined`. Range mode always has a
73
+ * Clear row; single mode shows one with `clearable`. Range mode shows one
68
74
  * month below `md` and two at `md+` unless `numberOfMonths` is set. The
69
75
  * popover clamps to the viewport (`side` is overridable). `className` styles
70
76
  * the trigger, `contentClassName` the popover, and `calendarProps` reaches
@@ -5,7 +5,10 @@ export declare const DEFAULT_TIME_STEP = 15;
5
5
  export type DateTimePickerButtonProps = PickerTriggerProps & {
6
6
  /** Controlled instant. `null` or omitted is empty. */
7
7
  value?: Date | null;
8
- onChange: (date: Date | null) => void;
8
+ /** Called with the picked instant, or `null` on Clear. */
9
+ onValueChange?: (date: Date | null) => void;
10
+ /** @deprecated Use `onValueChange`; `onChange` keeps working until 2.0. */
11
+ onChange?: (date: Date | null) => void;
9
12
  /**
10
13
  * Minute increment for the time selects (1, 5, 15, 30, or 60).
11
14
  * Values that do not divide 60 fall back to 15 so the list stays even.
@@ -25,4 +28,4 @@ export declare function resolveTimeStep(step: number | undefined): number;
25
28
  * stays on-screen at a 390px width. `className` styles the trigger,
26
29
  * `contentClassName` the popover, and `calendarProps` reaches Day Picker.
27
30
  */
28
- export declare function DateTimePickerButton({ value, onChange, timeStep, placeholder, defaultMonth, calendarProps, minDate, maxDate, ...shell }: DateTimePickerButtonProps): React.JSX.Element;
31
+ export declare function DateTimePickerButton({ value, onValueChange, onChange, timeStep, placeholder, defaultMonth, ...shell }: DateTimePickerButtonProps): React.JSX.Element;
@@ -2,8 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { format } from "date-fns";
5
- import { LazyCalendar } from "./lazy-calendar.js";
6
- import { PickerClearFooter, PickerShell, limitCalendarProps, } from "./picker-shell.js";
5
+ import { PickerShell } from "./picker-shell.js";
7
6
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "./select.js";
8
7
  /** Default clock increment, in minutes. Must divide 60. */
9
8
  export const DEFAULT_TIME_STEP = 15;
@@ -48,18 +47,6 @@ function minuteOptions(step, current) {
48
47
  return minutes;
49
48
  }
50
49
  const HOUR_OPTIONS = Array.from({ length: 24 }, (_, hour) => padTimePart(hour));
51
- /**
52
- * Keep the date-time popover open when a portaled Select option is clicked.
53
- * Select content renders outside the popover, so Radix would otherwise treat
54
- * that pointer down as an outside dismiss.
55
- */
56
- function preventDismissForPortaledSelect(event) {
57
- const target = event.target;
58
- if (target instanceof Element &&
59
- target.closest("[data-slot=select-content]")) {
60
- event.preventDefault();
61
- }
62
- }
63
50
  /**
64
51
  * Calendar plus hour/minute popover trigger styled as a form control (same
65
52
  * chrome as Input, SelectTrigger, and DatePickerButton). `value` is a `Date`
@@ -68,32 +55,32 @@ function preventDismissForPortaledSelect(event) {
68
55
  * stays on-screen at a 390px width. `className` styles the trigger,
69
56
  * `contentClassName` the popover, and `calendarProps` reaches Day Picker.
70
57
  */
71
- export function DateTimePickerButton({ value, onChange, timeStep, placeholder = "Pick a date and time", defaultMonth, calendarProps, minDate, maxDate, ...shell }) {
58
+ export function DateTimePickerButton({ value, onValueChange, onChange, timeStep, placeholder = "Pick a date and time", defaultMonth, ...shell }) {
72
59
  const [open, setOpen] = React.useState(false);
60
+ const emit = onValueChange ?? onChange;
73
61
  const date = value ?? null;
74
62
  const step = resolveTimeStep(timeStep);
75
63
  const empty = date == null;
76
- const hourId = React.useId();
77
- const minuteId = React.useId();
78
- return (_jsxs(PickerShell, { ...shell, empty: empty, label: date ? format(date, "PPP p") : placeholder, dialogLabel: "Choose date and time", open: open, onOpenChange: setOpen, onInteractOutside: preventDismissForPortaledSelect, children: [_jsx(LazyCalendar, { ...limitCalendarProps(calendarProps, minDate, maxDate), mode: "single", autoFocus: true, selected: date ?? undefined, defaultMonth: defaultMonth ?? date ?? undefined, onSelect: (next) => {
79
- // Re-clicking a selected day would clear it; require Clear instead
80
- // so a time already set is not dropped by an accidental second tap.
81
- if (!next)
82
- return;
83
- onChange(combineDateAndTime(next, date?.getHours() ?? 0, date?.getMinutes() ?? 0));
84
- } }), _jsxs("div", { role: "group", "aria-label": "Time", "data-slot": "date-time-picker-time", className: "flex min-w-0 flex-col gap-2 border-t p-3", children: [_jsx("p", { className: "text-xs font-semibold tracking-wide uppercase", children: "Time" }), _jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsxs(Select, { value: date ? padTimePart(date.getHours()) : undefined, onValueChange: (nextHour) => {
85
- if (!date)
86
- return;
87
- onChange(combineDateAndTime(date, Number(nextHour), date.getMinutes()));
88
- }, disabled: empty, children: [_jsx(SelectTrigger, { id: hourId, "aria-label": "Hour", className: "min-w-0 flex-1", children: _jsx(SelectValue, { placeholder: "\u2013\u2013" }) }), _jsx(SelectContent, { children: HOUR_OPTIONS.map((hour) => (_jsx(SelectItem, { value: hour, children: hour }, hour))) })] }), _jsx("span", { className: "text-muted-foreground", "aria-hidden": "true", children: ":" }), _jsxs(Select, { value: date ? padTimePart(date.getMinutes()) : undefined, onValueChange: (nextMinute) => {
89
- if (!date)
90
- return;
91
- onChange(combineDateAndTime(date, date.getHours(), Number(nextMinute)));
92
- }, disabled: empty, children: [_jsx(SelectTrigger, { id: minuteId, "aria-label": "Minute", className: "min-w-0 flex-1", children: _jsx(SelectValue, { placeholder: "\u2013\u2013" }) }), _jsx(SelectContent, { children: minuteOptions(step, date?.getMinutes()).map((minute) => {
93
- const value = padTimePart(minute);
94
- return (_jsx(SelectItem, { value: value, children: value }, value));
95
- }) })] })] })] }), _jsx(PickerClearFooter, { disabled: empty, onClear: () => {
96
- onChange(null);
97
- setOpen(false);
98
- } })] }));
64
+ return (_jsx(PickerShell, { ...shell, empty: empty, label: date ? format(date, "PPP p") : placeholder, dialogLabel: "Choose date and time", open: open, onOpenChange: setOpen, defaultMonth: defaultMonth ?? date ?? undefined, calendar: {
65
+ mode: "single",
66
+ selected: date ?? undefined,
67
+ onSelect: (next) => {
68
+ // Re-clicking a selected day would clear it; require Clear instead
69
+ // so a time already set is not dropped by an accidental second tap.
70
+ if (!next)
71
+ return;
72
+ emit?.(combineDateAndTime(next, date?.getHours() ?? 0, date?.getMinutes() ?? 0));
73
+ },
74
+ }, onClear: () => emit?.(null), clearDisabled: empty, children: _jsxs("div", { role: "group", "aria-label": "Time", "data-slot": "date-time-picker-time", className: "flex min-w-0 flex-col gap-2 border-t p-3", children: [_jsx("p", { className: "text-xs font-semibold tracking-wide uppercase", children: "Time" }), _jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsxs(Select, { value: date ? padTimePart(date.getHours()) : undefined, onValueChange: (nextHour) => {
75
+ if (!date)
76
+ return;
77
+ emit?.(combineDateAndTime(date, Number(nextHour), date.getMinutes()));
78
+ }, disabled: empty, children: [_jsx(SelectTrigger, { "aria-label": "Hour", className: "min-w-0 flex-1", children: _jsx(SelectValue, { placeholder: "\u2013\u2013" }) }), _jsx(SelectContent, { children: HOUR_OPTIONS.map((hour) => (_jsx(SelectItem, { value: hour, children: hour }, hour))) })] }), _jsx("span", { className: "text-muted-foreground", "aria-hidden": "true", children: ":" }), _jsxs(Select, { value: date ? padTimePart(date.getMinutes()) : undefined, onValueChange: (nextMinute) => {
79
+ if (!date)
80
+ return;
81
+ emit?.(combineDateAndTime(date, date.getHours(), Number(nextMinute)));
82
+ }, disabled: empty, children: [_jsx(SelectTrigger, { "aria-label": "Minute", className: "min-w-0 flex-1", children: _jsx(SelectValue, { placeholder: "\u2013\u2013" }) }), _jsx(SelectContent, { children: minuteOptions(step, date?.getMinutes()).map((minute) => {
83
+ const value = padTimePart(minute);
84
+ return (_jsx(SelectItem, { value: value, children: value }, value));
85
+ }) })] })] })] }) }));
99
86
  }
package/dist/dialog.d.ts CHANGED
@@ -6,6 +6,7 @@ declare function DialogPortal({ ...props }: React.ComponentProps<typeof DialogPr
6
6
  declare function DialogClose({ ...props }: React.ComponentProps<typeof DialogPrimitive.Close>): React.JSX.Element;
7
7
  declare function DialogOverlay({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Overlay>): React.JSX.Element;
8
8
  declare function DialogContent({ className, children, showCloseButton, overlayClassName, closeButtonClassName, ...props }: React.ComponentProps<typeof DialogPrimitive.Content> & {
9
+ /** Show the X close button in the top-right corner. Default `true`. */
9
10
  showCloseButton?: boolean;
10
11
  /** Classes for the backdrop, e.g. a darker scrim. */
11
12
  overlayClassName?: string;
package/dist/dialog.js CHANGED
@@ -22,7 +22,9 @@ function DialogOverlay({ className, ...props }) {
22
22
  return (_jsx(DialogPrimitive.Overlay, { "data-slot": "dialog-overlay", className: cn(overlayFade, "fixed inset-0 isolate z-50 bg-black/20 supports-backdrop-filter:backdrop-blur-sm", className), ...props }));
23
23
  }
24
24
  function DialogContent({ className, children, showCloseButton = true, overlayClassName, closeButtonClassName, ...props }) {
25
- return (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, { className: overlayClassName }), _jsxs(DialogPrimitive.Content, { "data-slot": "dialog-content", className: cn(overlaySurface, overlayFadeZoom, "fixed top-1/2 left-1/2 z-50 grid max-h-[90dvh] w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-6 overflow-y-auto p-6 text-sm outline-none", className), ...props, children: [children, showCloseButton && (_jsx(DialogPrimitive.Close, { "data-slot": "dialog-close-button", asChild: true, children: _jsxs(Button, { variant: "ghost", size: "icon-sm", className: cn("absolute top-4 right-4 text-muted-foreground hover:text-foreground", closeButtonClassName), children: [_jsx(XIcon, {}), _jsx("span", { className: "sr-only", children: "Close" })] }) }))] })] }));
25
+ return (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, { className: overlayClassName }), _jsxs(DialogPrimitive.Content, { "data-slot": "dialog-content", className: cn(overlaySurface, overlayFadeZoom, "fixed top-1/2 left-1/2 z-50 grid max-h-[90dvh] w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-6 overflow-y-auto p-6 text-sm outline-none", showCloseButton
26
+ ? "[--dialog-close-gutter:--spacing(10)]"
27
+ : "[--dialog-close-gutter:0px]", className), ...props, children: [children, showCloseButton && (_jsx(DialogPrimitive.Close, { "data-slot": "dialog-close-button", asChild: true, children: _jsxs(Button, { variant: "ghost", size: "icon-sm", className: cn("absolute top-4 right-4 text-muted-foreground hover:text-foreground", closeButtonClassName), children: [_jsx(XIcon, {}), _jsx("span", { className: "sr-only", children: "Close" })] }) }))] })] }));
26
28
  }
27
29
  function DialogHeader({ className, ...props }) {
28
30
  return (_jsx("div", { "data-slot": "dialog-header", className: cn("flex flex-col gap-2", className), ...props }));
@@ -31,7 +33,7 @@ function DialogFooter({ className, children, ...props }) {
31
33
  return (_jsx("div", { "data-slot": "dialog-footer", className: cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className), ...props, children: children }));
32
34
  }
33
35
  function DialogTitle({ className, ...props }) {
34
- return (_jsx(DialogPrimitive.Title, { "data-slot": "dialog-title", className: cn("font-heading text-lg leading-none font-semibold tracking-wider uppercase", className), ...props }));
36
+ return (_jsx(DialogPrimitive.Title, { "data-slot": "dialog-title", className: cn("pr-[var(--dialog-close-gutter,0px)] font-heading text-lg leading-none font-semibold tracking-wider uppercase", className), ...props }));
35
37
  }
36
38
  function DialogDescription({ className, ...props }) {
37
39
  return (_jsx(DialogPrimitive.Description, { "data-slot": "dialog-description", className: cn("mt-0.5 text-sm leading-relaxed text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground", className), ...props }));
@@ -1,26 +1,27 @@
1
1
  import * as React from "react";
2
2
  import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
3
+ /** Props for menu rows that can line up with checkbox and radio items. */
4
+ type MenuInsetProps = {
5
+ /** Indent the row to line up with checkbox and radio item text. */
6
+ inset?: boolean;
7
+ };
3
8
  /** Action menu for commands (row actions, overflow menus). Use `Select` to pick a value. */
4
9
  declare function DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>): React.JSX.Element;
5
10
  declare function DropdownMenuPortal({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>): React.JSX.Element;
6
11
  declare function DropdownMenuTrigger({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>): React.JSX.Element;
7
12
  declare function DropdownMenuContent({ className, align, sideOffset, collisionPadding, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>): React.JSX.Element;
8
13
  declare function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>): React.JSX.Element;
9
- declare function DropdownMenuItem({ className, inset, variant, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
10
- inset?: boolean;
14
+ declare function DropdownMenuItem({ className, inset, variant, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & MenuInsetProps & {
15
+ /** `destructive` colors the row for a dangerous action. Default `default`. */
11
16
  variant?: "default" | "destructive";
12
17
  }): React.JSX.Element;
13
18
  declare function DropdownMenuCheckboxItem({ className, children, checked, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>): React.JSX.Element;
14
19
  declare function DropdownMenuRadioGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>): React.JSX.Element;
15
20
  declare function DropdownMenuRadioItem({ className, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>): React.JSX.Element;
16
- declare function DropdownMenuLabel({ className, inset, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
17
- inset?: boolean;
18
- }): React.JSX.Element;
21
+ declare function DropdownMenuLabel({ className, inset, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & MenuInsetProps): React.JSX.Element;
19
22
  declare function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>): React.JSX.Element;
20
23
  declare function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
21
24
  declare function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>): React.JSX.Element;
22
- declare function DropdownMenuSubTrigger({ className, inset, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
23
- inset?: boolean;
24
- }): React.JSX.Element;
25
+ declare function DropdownMenuSubTrigger({ className, inset, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & MenuInsetProps): React.JSX.Element;
25
26
  declare function DropdownMenuSubContent({ className, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>): React.JSX.Element;
26
27
  export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, };
@@ -1,9 +1,15 @@
1
1
  import type * as React from "react";
2
2
  type Props = React.ComponentProps<"div"> & {
3
3
  children: React.ReactNode;
4
- /** Tighter padding for compact widgets; default is standard form empty states. */
5
- size?: "sm" | "md" | "lg";
4
+ /**
5
+ * `sm` is tighter padding for compact widgets; `default` is standard form
6
+ * empty states; `lg` is roomier, for page-level states. `md` is a
7
+ * deprecated alias of `default`, kept until 2.0. Default `default`.
8
+ */
9
+ size?: "sm" | "default" | "lg" | "md";
10
+ /** Tinted muted background. Default `true`. */
6
11
  muted?: boolean;
12
+ /** Classes for the root `div`. */
7
13
  className?: string;
8
14
  };
9
15
  /** Dashed empty-state panel for lists, widgets, and form sections. Other props go to the root `div`. */
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { cn } from "./utils.js";
3
3
  /** Dashed empty-state panel for lists, widgets, and form sections. Other props go to the root `div`. */
4
- export function EmptyPanel({ children, size = "md", muted = true, className, ...props }) {
5
- return (_jsx("div", { "data-slot": "empty-panel", ...props, className: cn("rounded-none border border-dashed text-center text-sm text-muted-foreground", muted && "bg-muted/30", size === "sm" && "px-3 py-4", size === "md" && "px-4 py-6", size === "lg" && "px-4 py-8", className), children: children }));
4
+ export function EmptyPanel({ children, size = "default", muted = true, className, ...props }) {
5
+ return (_jsx("div", { "data-slot": "empty-panel", ...props, className: cn("rounded-none border border-dashed text-center text-sm text-muted-foreground", muted && "bg-muted/30", size === "sm" && "px-3 py-4", (size === "default" || size === "md") && "px-4 py-6", size === "lg" && "px-4 py-8", className), children: children }));
6
6
  }
@@ -1,9 +1,12 @@
1
1
  import { Component, type ErrorInfo, type ReactNode } from "react";
2
2
  type ErrorFallbackProps = {
3
- /** User-facing recovery copy. */
3
+ /** User-facing recovery copy. Default "Something went wrong.". */
4
4
  message?: string;
5
+ /** Shows a "Try again" button that calls this. Hidden when omitted. */
5
6
  onRetry?: () => void;
7
+ /** Shows a "Reload" button that calls this. Hidden when omitted. */
6
8
  onReload?: () => void;
9
+ /** Classes for the panel. */
7
10
  className?: string;
8
11
  };
9
12
  /**
@@ -13,9 +16,11 @@ type ErrorFallbackProps = {
13
16
  */
14
17
  export declare function ErrorFallback({ message, onRetry, onReload, className, }: ErrorFallbackProps): import("react").JSX.Element;
15
18
  type ErrorBoundaryProps = {
19
+ /** Content to render until it throws. */
16
20
  children: ReactNode;
17
21
  /** Overrides the default recovery message. */
18
22
  message?: string;
23
+ /** Called with the caught error and its component stack, e.g. to log it. */
19
24
  onError?: (error: Error, info: ErrorInfo) => void;
20
25
  };
21
26
  type ErrorBoundaryState = {
package/dist/field.d.ts CHANGED
@@ -2,6 +2,7 @@ import { type VariantProps } from "class-variance-authority";
2
2
  import { Label } from "./label.js";
3
3
  declare function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">): import("react").JSX.Element;
4
4
  declare function FieldLegend({ className, variant, ...props }: React.ComponentProps<"legend"> & {
5
+ /** `label` styles the legend like a field label. Default `legend`. */
5
6
  variant?: "legend" | "label";
6
7
  }): import("react").JSX.Element;
7
8
  /**
@@ -27,9 +28,11 @@ declare function FieldLabel({ className, ...props }: React.ComponentProps<typeof
27
28
  declare function FieldTitle({ className, ...props }: React.ComponentProps<"div">): import("react").JSX.Element;
28
29
  declare function FieldDescription({ className, ...props }: React.ComponentProps<"p">): import("react").JSX.Element;
29
30
  declare function FieldSeparator({ children, className, ...props }: React.ComponentProps<"div"> & {
31
+ /** Optional text shown in a gap in the middle of the line, e.g. "Or". */
30
32
  children?: React.ReactNode;
31
33
  }): import("react").JSX.Element;
32
34
  declare function FieldError({ className, children, errors, ...props }: React.ComponentProps<"div"> & {
35
+ /** Errors to list, deduplicated by message; `children` replaces them. */
33
36
  errors?: Array<{
34
37
  message?: string;
35
38
  } | undefined>;
package/dist/field.js CHANGED
@@ -71,7 +71,7 @@ function FieldError({ className, children, errors, ...props }) {
71
71
  if (uniqueErrors?.length == 1) {
72
72
  return uniqueErrors[0]?.message;
73
73
  }
74
- return (_jsx("ul", { className: "ml-4 flex list-disc flex-col gap-1", children: uniqueErrors.map((error, index) => error?.message && _jsx("li", { children: error.message }, index)) }));
74
+ return (_jsx("ul", { className: "ml-4 flex list-disc flex-col gap-1", children: uniqueErrors.map((error) => error?.message && _jsx("li", { children: error.message }, error.message)) }));
75
75
  }, [children, errors]);
76
76
  if (!content) {
77
77
  return null;
@@ -0,0 +1,45 @@
1
+ import { type FormFieldBaseProps, type FormFieldDescriptionProps, type FormFieldMetaProps } from "./field-error.js";
2
+ type CheckboxFieldProps = FormFieldBaseProps & FormFieldMetaProps & FormFieldDescriptionProps & {
3
+ /** Whether the box is checked. */
4
+ checked: boolean;
5
+ /** Called with the new checked state when the person toggles the box. */
6
+ onCheckedChange: (checked: boolean) => void;
7
+ /** Called when the checkbox loses focus; pass the field's blur handler. */
8
+ onBlur?: () => void;
9
+ /** Checkbox id the label points at. Defaults to a generated id. */
10
+ id?: string;
11
+ /** Sets `required` on the checkbox and marks the label. */
12
+ required?: boolean;
13
+ /** Disables the checkbox. */
14
+ disabled?: boolean;
15
+ /** Checkbox before the label (default) or after the label and hint. */
16
+ controlPosition?: "start" | "end";
17
+ /** Forwarded to the checkbox. */
18
+ className?: string;
19
+ };
20
+ /**
21
+ * One boolean as a labelled checkbox, with an optional hint and the same
22
+ * error text and timing as the other `form/*` fields.
23
+ */
24
+ export declare function FormCheckboxField({ checked, onCheckedChange, onBlur, label, description, id: idProp, meta, submitted, showError, required, disabled, controlPosition, className, fieldClassName, }: CheckboxFieldProps): import("react").JSX.Element;
25
+ export type CheckboxGroupOption<T extends string | number> = {
26
+ /** Value added to the group's `value` while this box is checked. */
27
+ value: T;
28
+ /** Text shown next to the box. */
29
+ label: string;
30
+ };
31
+ type CheckboxGroupFieldProps<T extends string | number> = FormFieldBaseProps & FormFieldMetaProps & FormFieldDescriptionProps & {
32
+ /** The boxes to show, in order. */
33
+ options: CheckboxGroupOption<T>[];
34
+ /** The checked values. */
35
+ value: T[];
36
+ /** Called with the checked values, in `options` order. */
37
+ onValueChange: (value: T[]) => void;
38
+ /** Disables every checkbox in the group. */
39
+ disabled?: boolean;
40
+ /** Layout of the options, e.g. a grid. Defaults to a wrapping row. */
41
+ className?: string;
42
+ };
43
+ /** Several values from a short list, as a labelled set of checkboxes. */
44
+ export declare function FormCheckboxGroupField<T extends string | number>({ label, description, options, value, onValueChange, meta, submitted, showError, disabled, className, fieldClassName, }: CheckboxGroupFieldProps<T>): import("react").JSX.Element;
45
+ export {};