@datum-cloud/datum-ui 0.5.0 → 0.6.0-alpha.a9a8815

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 (154) hide show
  1. package/README.md +78 -40
  2. package/dist/adapter-context-rWveHhDd.mjs +25 -0
  3. package/dist/combobox/index.mjs +2 -0
  4. package/dist/combobox-cKTFK4uN.mjs +96 -0
  5. package/dist/components/features/combobox/combobox.d.ts +27 -0
  6. package/dist/components/features/combobox/combobox.d.ts.map +1 -0
  7. package/dist/components/features/combobox/index.d.ts +3 -0
  8. package/dist/components/features/combobox/index.d.ts.map +1 -0
  9. package/dist/components/features/combobox/types.d.ts +78 -0
  10. package/dist/components/features/combobox/types.d.ts.map +1 -0
  11. package/dist/components/features/date-time-picker/date-time-picker.d.ts +9 -0
  12. package/dist/components/features/date-time-picker/date-time-picker.d.ts.map +1 -0
  13. package/dist/components/features/date-time-picker/index.d.ts +3 -0
  14. package/dist/components/features/date-time-picker/index.d.ts.map +1 -0
  15. package/dist/components/features/date-time-picker/types.d.ts +53 -0
  16. package/dist/components/features/date-time-picker/types.d.ts.map +1 -0
  17. package/dist/components/features/date-time-picker/utils/format.d.ts +13 -0
  18. package/dist/components/features/date-time-picker/utils/format.d.ts.map +1 -0
  19. package/dist/components/features/date-time-picker/utils/index.d.ts +3 -0
  20. package/dist/components/features/date-time-picker/utils/index.d.ts.map +1 -0
  21. package/dist/components/features/date-time-picker/utils/timezone.d.ts +23 -0
  22. package/dist/components/features/date-time-picker/utils/timezone.d.ts.map +1 -0
  23. package/dist/components/features/form/adapter-context.d.ts +17 -0
  24. package/dist/components/features/form/adapter-context.d.ts.map +1 -0
  25. package/dist/components/features/form/adapter-types.d.ts +120 -0
  26. package/dist/components/features/form/adapter-types.d.ts.map +1 -0
  27. package/dist/components/features/form/adapters/conform/conform-adapter.d.ts +9 -0
  28. package/dist/components/features/form/adapters/conform/conform-adapter.d.ts.map +1 -0
  29. package/dist/components/features/form/adapters/conform/conform-provider.d.ts +22 -0
  30. package/dist/components/features/form/adapters/conform/conform-provider.d.ts.map +1 -0
  31. package/dist/components/features/form/adapters/conform/index.d.ts +3 -0
  32. package/dist/components/features/form/adapters/conform/index.d.ts.map +1 -0
  33. package/dist/components/features/form/adapters/rhf/index.d.ts +3 -0
  34. package/dist/components/features/form/adapters/rhf/index.d.ts.map +1 -0
  35. package/dist/components/features/form/adapters/rhf/rhf-adapter.d.ts +10 -0
  36. package/dist/components/features/form/adapters/rhf/rhf-adapter.d.ts.map +1 -0
  37. package/dist/components/features/form/adapters/rhf/rhf-provider.d.ts +22 -0
  38. package/dist/components/features/form/adapters/rhf/rhf-provider.d.ts.map +1 -0
  39. package/dist/components/features/form/components/form-autocomplete.d.ts.map +1 -1
  40. package/dist/components/features/form/components/form-autosearch.d.ts +25 -0
  41. package/dist/components/features/form/components/form-autosearch.d.ts.map +1 -0
  42. package/dist/components/features/form/components/form-checkbox.d.ts.map +1 -1
  43. package/dist/components/features/form/components/form-combobox.d.ts +76 -0
  44. package/dist/components/features/form/components/form-combobox.d.ts.map +1 -0
  45. package/dist/components/features/form/components/form-copy-box.d.ts.map +1 -1
  46. package/dist/components/features/form/components/form-custom.d.ts.map +1 -1
  47. package/dist/components/features/form/components/form-date-picker.d.ts +38 -0
  48. package/dist/components/features/form/components/form-date-picker.d.ts.map +1 -0
  49. package/dist/components/features/form/components/form-date-time-picker.d.ts +37 -0
  50. package/dist/components/features/form/components/form-date-time-picker.d.ts.map +1 -0
  51. package/dist/components/features/form/components/form-field-array.d.ts +5 -17
  52. package/dist/components/features/form/components/form-field-array.d.ts.map +1 -1
  53. package/dist/components/features/form/components/form-field.d.ts +7 -21
  54. package/dist/components/features/form/components/form-field.d.ts.map +1 -1
  55. package/dist/components/features/form/components/form-input-group.d.ts +4 -4
  56. package/dist/components/features/form/components/form-input-group.d.ts.map +1 -1
  57. package/dist/components/features/form/components/form-input.d.ts.map +1 -1
  58. package/dist/components/features/form/components/form-radio-group.d.ts.map +1 -1
  59. package/dist/components/features/form/components/form-root.d.ts +5 -25
  60. package/dist/components/features/form/components/form-root.d.ts.map +1 -1
  61. package/dist/components/features/form/components/form-select.d.ts.map +1 -1
  62. package/dist/components/features/form/components/form-switch.d.ts.map +1 -1
  63. package/dist/components/features/form/components/form-textarea.d.ts.map +1 -1
  64. package/dist/components/features/form/components/form-time-picker.d.ts +21 -0
  65. package/dist/components/features/form/components/form-time-picker.d.ts.map +1 -0
  66. package/dist/components/features/form/components/form-transfer.d.ts +37 -0
  67. package/dist/components/features/form/components/form-transfer.d.ts.map +1 -0
  68. package/dist/components/features/form/components/index.d.ts +6 -1
  69. package/dist/components/features/form/components/index.d.ts.map +1 -1
  70. package/dist/components/features/form/components/stepper/form-stepper.d.ts.map +1 -1
  71. package/dist/components/features/form/context/form-context.d.ts +2 -2
  72. package/dist/components/features/form/context/form-context.d.ts.map +1 -1
  73. package/dist/components/features/form/hooks/index.d.ts +1 -1
  74. package/dist/components/features/form/hooks/index.d.ts.map +1 -1
  75. package/dist/components/features/form/hooks/use-field.d.ts +12 -18
  76. package/dist/components/features/form/hooks/use-field.d.ts.map +1 -1
  77. package/dist/components/features/form/hooks/use-form-state.d.ts +36 -0
  78. package/dist/components/features/form/hooks/use-form-state.d.ts.map +1 -0
  79. package/dist/components/features/form/hooks/use-watch.d.ts +9 -20
  80. package/dist/components/features/form/hooks/use-watch.d.ts.map +1 -1
  81. package/dist/components/features/form/index.d.ts +69 -44
  82. package/dist/components/features/form/index.d.ts.map +1 -1
  83. package/dist/components/features/form/stepper/index.d.ts +17 -0
  84. package/dist/components/features/form/stepper/index.d.ts.map +1 -0
  85. package/dist/components/features/form/types/index.d.ts +68 -32
  86. package/dist/components/features/form/types/index.d.ts.map +1 -1
  87. package/dist/components/features/form/utils/get-field-constraints.d.ts +43 -0
  88. package/dist/components/features/form/utils/get-field-constraints.d.ts.map +1 -0
  89. package/dist/components/features/form/utils/get-schema-defaults.d.ts +24 -0
  90. package/dist/components/features/form/utils/get-schema-defaults.d.ts.map +1 -0
  91. package/dist/components/features/time-picker/index.d.ts +3 -0
  92. package/dist/components/features/time-picker/index.d.ts.map +1 -0
  93. package/dist/components/features/time-picker/time-picker.d.ts +22 -0
  94. package/dist/components/features/time-picker/time-picker.d.ts.map +1 -0
  95. package/dist/components/features/time-picker/types.d.ts +31 -0
  96. package/dist/components/features/time-picker/types.d.ts.map +1 -0
  97. package/dist/components/features/transfer/components/index.d.ts +9 -0
  98. package/dist/components/features/transfer/components/index.d.ts.map +1 -0
  99. package/dist/components/features/transfer/components/transfer-group.d.ts +7 -0
  100. package/dist/components/features/transfer/components/transfer-group.d.ts.map +1 -0
  101. package/dist/components/features/transfer/components/transfer-item.d.ts +10 -0
  102. package/dist/components/features/transfer/components/transfer-item.d.ts.map +1 -0
  103. package/dist/components/features/transfer/components/transfer-panel.d.ts +18 -0
  104. package/dist/components/features/transfer/components/transfer-panel.d.ts.map +1 -0
  105. package/dist/components/features/transfer/components/transfer-search.d.ts +9 -0
  106. package/dist/components/features/transfer/components/transfer-search.d.ts.map +1 -0
  107. package/dist/components/features/transfer/hooks/use-transfer-dnd.d.ts +26 -0
  108. package/dist/components/features/transfer/hooks/use-transfer-dnd.d.ts.map +1 -0
  109. package/dist/components/features/transfer/hooks/use-transfer-state.d.ts +20 -0
  110. package/dist/components/features/transfer/hooks/use-transfer-state.d.ts.map +1 -0
  111. package/dist/components/features/transfer/index.d.ts +3 -0
  112. package/dist/components/features/transfer/index.d.ts.map +1 -0
  113. package/dist/components/features/transfer/transfer.d.ts +6 -0
  114. package/dist/components/features/transfer/transfer.d.ts.map +1 -0
  115. package/dist/components/features/transfer/types.d.ts +69 -0
  116. package/dist/components/features/transfer/types.d.ts.map +1 -0
  117. package/dist/date-picker/index.mjs +1 -1
  118. package/dist/date-time-picker/index.mjs +2 -0
  119. package/dist/date-time-picker-Bx_n4nEJ.mjs +177 -0
  120. package/dist/form/adapters/conform/index.mjs +326 -0
  121. package/dist/form/adapters/rhf/index.mjs +275 -0
  122. package/dist/form/index.mjs +3 -2
  123. package/dist/form/stepper/index.mjs +542 -0
  124. package/dist/form-context-Ccxm-wqL.mjs +17 -0
  125. package/dist/form-zf5QOnAk.mjs +1611 -0
  126. package/dist/get-field-constraints-CxfZ753o.mjs +49 -0
  127. package/dist/grid/index.mjs +1 -1
  128. package/dist/hooks/index.mjs +2 -2
  129. package/dist/index.mjs +14 -13
  130. package/dist/input-number/index.mjs +1 -1
  131. package/dist/map/index.mjs +1 -1
  132. package/dist/{map-ClxB41Hg.mjs → map-CWIQ-eql.mjs} +1 -1
  133. package/dist/more-actions/index.mjs +1 -1
  134. package/dist/page-title/index.mjs +1 -1
  135. package/dist/stepper/index.mjs +1 -320
  136. package/dist/stepper-DvIOp0hh.mjs +321 -0
  137. package/dist/tag-input/index.mjs +1 -1
  138. package/dist/task-queue/index.mjs +1 -1
  139. package/dist/time-picker/index.mjs +2 -0
  140. package/dist/time-picker-BoF7pZZ2.mjs +43 -0
  141. package/dist/transfer/index.mjs +2 -0
  142. package/dist/transfer-C55XfEXy.mjs +243 -0
  143. package/package.json +58 -2
  144. package/dist/form-Co3fM4B7.mjs +0 -2114
  145. /package/dist/{col-q-J99UHe.mjs → col-1T0Q3SlH.mjs} +0 -0
  146. /package/dist/{hooks-Cb7YlxN4.mjs → hooks-D8r2M2U6.mjs} +0 -0
  147. /package/dist/{input-number-mDB-5M5C.mjs → input-number-a7uydAsw.mjs} +0 -0
  148. /package/dist/{map-leaflet-imports-CaMm_rdF.mjs → map-leaflet-imports-CRSKA79m.mjs} +0 -0
  149. /package/dist/{more-actions-CGagbIDT.mjs → more-actions-ILnEZq_E.mjs} +0 -0
  150. /package/dist/{page-title-R7QbfbWp.mjs → page-title-ChsnpBiH.mjs} +0 -0
  151. /package/dist/{tag-input-BVSwNcRd.mjs → tag-input-T9cUX9-G.mjs} +0 -0
  152. /package/dist/{task-queue-dropdown-DyM5R8KF.mjs → task-queue-dropdown-Wcbj-f0V.mjs} +0 -0
  153. /package/dist/{to-api-format-BnbRFYQI.mjs → to-api-format-Bh3c01gr.mjs} +0 -0
  154. /package/dist/{use-copy-to-clipboard-BGdTmkFV.mjs → use-copy-to-clipboard-uNeeVHC4.mjs} +0 -0
@@ -0,0 +1,1611 @@
1
+ import { t as cn } from "./cn-D2KYQ917.mjs";
2
+ import { t as Button } from "./button-BllvE9Lm.mjs";
3
+ import { t as Icon } from "./icon-wrapper-DuLp3RM1.mjs";
4
+ import { t as Checkbox } from "./checkbox-I5BvrMPe.mjs";
5
+ import { t as Dialog } from "./dialog-Bm2H9lrx.mjs";
6
+ import { t as Input } from "./input-FKGqZypx.mjs";
7
+ import { t as Label } from "./label-cnAhY-ej.mjs";
8
+ import { n as RadioGroupItem, t as RadioGroup } from "./radio-group-CiITR0LO.mjs";
9
+ import { i as SelectItem, l as SelectTrigger, n as SelectContent, t as Select, u as SelectValue } from "./select-CiLR_DiQ.mjs";
10
+ import { t as Tooltip } from "./tooltip-Cruvl5F6.mjs";
11
+ import { t as Switch } from "./switch-DQJQhPIQ.mjs";
12
+ import { t as Textarea } from "./textarea-BwD-MmTV.mjs";
13
+ import { t as Autocomplete } from "./autocomplete-V5-qslzS.mjs";
14
+ import { t as CalendarDatePicker } from "./calendar-date-picker-DWK94_DC.mjs";
15
+ import { t as toast } from "./toast-BWnN5fax.mjs";
16
+ import { n as useFormContext$1, t as FormProvider } from "./form-context-Ccxm-wqL.mjs";
17
+ import { t as Combobox } from "./combobox-cKTFK4uN.mjs";
18
+ import { t as useCopyToClipboard } from "./use-copy-to-clipboard-uNeeVHC4.mjs";
19
+ import { t as DateTimePicker } from "./date-time-picker-Bx_n4nEJ.mjs";
20
+ import { n as useAdapter } from "./adapter-context-rWveHhDd.mjs";
21
+ import { t as TimePicker } from "./time-picker-BoF7pZZ2.mjs";
22
+ import { t as Transfer } from "./transfer-C55XfEXy.mjs";
23
+ import { InputWithAddons } from "./input-with-addons/index.mjs";
24
+ import { CheckIcon, CircleHelp, CopyIcon } from "lucide-react";
25
+ import * as React$1 from "react";
26
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
27
+ //#region src/components/features/form/context/field-context.tsx
28
+ const FieldContext = React$1.createContext(null);
29
+ function FieldProvider({ children, value }) {
30
+ return /* @__PURE__ */ jsx(FieldContext, {
31
+ value,
32
+ children
33
+ });
34
+ }
35
+ function useFieldContext$1() {
36
+ const context = React$1.use(FieldContext);
37
+ if (!context) throw new Error("useFieldContext must be used within a Form.Field component. Make sure your input component is wrapped with Form.Field.");
38
+ return context;
39
+ }
40
+ /**
41
+ * Optional field context - returns null if not within a Form.Field
42
+ * Useful for components that can work both inside and outside Form.Field
43
+ */
44
+ function useOptionalFieldContext() {
45
+ return React$1.use(FieldContext);
46
+ }
47
+ //#endregion
48
+ //#region src/components/features/form/components/form-autocomplete.tsx
49
+ /**
50
+ * Form.Autocomplete - Searchable select component
51
+ *
52
+ * Automatically wired to the parent Form.Field context.
53
+ * Supports flat/grouped options, virtualization, custom rendering, and async search.
54
+ *
55
+ * @example Basic usage
56
+ * ```tsx
57
+ * <Form.Field name="timezone" label="Timezone" required>
58
+ * <Form.Autocomplete
59
+ * options={timezones}
60
+ * placeholder="Select timezone..."
61
+ * />
62
+ * </Form.Field>
63
+ * ```
64
+ *
65
+ * @example Async search
66
+ * ```tsx
67
+ * <Form.Field name="userId" label="User">
68
+ * <Form.Autocomplete
69
+ * options={users ?? []}
70
+ * onSearchChange={setSearch}
71
+ * loading={isLoading}
72
+ * placeholder="Search users..."
73
+ * />
74
+ * </Form.Field>
75
+ * ```
76
+ *
77
+ * @example Grouped options
78
+ * ```tsx
79
+ * <Form.Field name="role" label="Role" required>
80
+ * <Form.Autocomplete
81
+ * options={roleGroups}
82
+ * placeholder="Select a role..."
83
+ * />
84
+ * </Form.Field>
85
+ * ```
86
+ */
87
+ function FormAutocomplete({ disabled, className, ...props }) {
88
+ const { id, errors, disabled: fieldDisabled, fieldState } = useFieldContext$1();
89
+ const isDisabled = disabled ?? fieldDisabled;
90
+ const hasErrors = errors && errors.length > 0;
91
+ const value = fieldState?.value != null ? String(fieldState.value) : "";
92
+ return /* @__PURE__ */ jsx(Autocomplete, {
93
+ ...props,
94
+ name: fieldState?.name,
95
+ id,
96
+ value,
97
+ onValueChange: (val) => fieldState?.change(val),
98
+ disabled: isDisabled,
99
+ triggerClassName: cn(hasErrors && "border-destructive", props.triggerClassName),
100
+ className
101
+ });
102
+ }
103
+ FormAutocomplete.displayName = "Form.Autocomplete";
104
+ //#endregion
105
+ //#region src/components/features/form/components/form-autosearch.tsx
106
+ /**
107
+ * Form.Autosearch - Alias to Form.Autocomplete with search-first focus
108
+ *
109
+ * This is a convenience wrapper around Form.Autocomplete that emphasizes
110
+ * the search functionality. It's functionally identical to Form.Autocomplete.
111
+ *
112
+ * @example Basic usage
113
+ * ```tsx
114
+ * <Form.Field name="search" label="Search">
115
+ * <Form.Autosearch
116
+ * options={options}
117
+ * placeholder="Type to search..."
118
+ * />
119
+ * </Form.Field>
120
+ * ```
121
+ */
122
+ function FormAutosearch(props) {
123
+ return /* @__PURE__ */ jsx(FormAutocomplete, { ...props });
124
+ }
125
+ FormAutosearch.displayName = "Form.Autosearch";
126
+ //#endregion
127
+ //#region src/components/features/form/components/form-button.tsx
128
+ /**
129
+ * Form.Button - A button for non-submit actions within a form
130
+ *
131
+ * Automatically gets disabled when the form is submitting.
132
+ * Use this for cancel buttons, reset buttons, or other actions.
133
+ *
134
+ * @example
135
+ * ```tsx
136
+ * <Form.Button onClick={() => navigate(-1)}>
137
+ * Cancel
138
+ * </Form.Button>
139
+ *
140
+ * <Form.Button onClick={() => form.reset()} type="secondary">
141
+ * Reset
142
+ * </Form.Button>
143
+ * ```
144
+ */
145
+ function FormButton({ children, onClick, type = "quaternary", theme = "borderless", size, disabled, className, disableOnSubmit = true }) {
146
+ const { isSubmitting } = useFormContext$1();
147
+ return /* @__PURE__ */ jsx(Button, {
148
+ htmlType: "button",
149
+ type,
150
+ theme,
151
+ size,
152
+ disabled: disabled || disableOnSubmit && isSubmitting,
153
+ className,
154
+ onClick,
155
+ children
156
+ });
157
+ }
158
+ FormButton.displayName = "Form.Button";
159
+ //#endregion
160
+ //#region src/components/features/form/components/form-checkbox.tsx
161
+ /**
162
+ * Form.Checkbox - Checkbox input component
163
+ *
164
+ * Automatically wired to the parent Form.Field context.
165
+ *
166
+ * @example
167
+ * ```tsx
168
+ * <Form.Field name="terms">
169
+ * <Form.Checkbox label="I agree to the terms and conditions" />
170
+ * </Form.Field>
171
+ * ```
172
+ */
173
+ function FormCheckbox({ label, disabled, className }) {
174
+ const { id, errors, disabled: fieldDisabled, fieldState } = useFieldContext$1();
175
+ const isDisabled = disabled ?? fieldDisabled;
176
+ const hasErrors = errors && errors.length > 0;
177
+ const checked = Boolean(fieldState?.value);
178
+ return /* @__PURE__ */ jsxs("div", {
179
+ className: cn("flex items-center space-x-2", className),
180
+ children: [/* @__PURE__ */ jsx(Checkbox, {
181
+ id,
182
+ checked,
183
+ onCheckedChange: (value) => fieldState?.change(Boolean(value)),
184
+ disabled: isDisabled,
185
+ "aria-invalid": hasErrors || void 0,
186
+ "aria-describedby": hasErrors ? `${id}-error` : void 0
187
+ }), label && /* @__PURE__ */ jsx(Label, {
188
+ htmlFor: id,
189
+ className: cn("cursor-pointer text-sm font-normal", isDisabled && "cursor-not-allowed opacity-70"),
190
+ children: label
191
+ })]
192
+ });
193
+ }
194
+ FormCheckbox.displayName = "Form.Checkbox";
195
+ //#endregion
196
+ //#region src/components/features/form/components/form-combobox.tsx
197
+ function FormCombobox({ options, placeholder, searchPlaceholder, emptyMessage, disabled, className, triggerClassName, contentClassName, searchable = true, showDropdownArrow = true, clearable = false, "data-testid": testId }) {
198
+ const { id, errors, disabled: fieldDisabled, fieldState } = useFieldContext$1();
199
+ const isDisabled = disabled ?? fieldDisabled;
200
+ const hasErrors = errors && errors.length > 0;
201
+ const handleChange = React$1.useCallback((value) => {
202
+ fieldState?.change(value ?? "");
203
+ }, [fieldState]);
204
+ return /* @__PURE__ */ jsx(Combobox, {
205
+ id,
206
+ options,
207
+ value: fieldState?.value ?? "",
208
+ onChange: handleChange,
209
+ placeholder,
210
+ searchPlaceholder,
211
+ emptyMessage,
212
+ disabled: isDisabled,
213
+ searchable,
214
+ showDropdownArrow,
215
+ clearable,
216
+ className,
217
+ triggerClassName: cn(hasErrors && "border-destructive", triggerClassName),
218
+ contentClassName,
219
+ "data-testid": testId
220
+ });
221
+ }
222
+ FormCombobox.displayName = "FormCombobox";
223
+ //#endregion
224
+ //#region src/components/features/form/components/form-copy-box.tsx
225
+ /**
226
+ * Form.CopyBox - Read-only field with copy-to-clipboard functionality
227
+ *
228
+ * Displays field value in a read-only box with a copy button.
229
+ * Automatically gets value from Form.Field context.
230
+ *
231
+ * @example Basic usage
232
+ * ```tsx
233
+ * <Form.Field name="organizationId" label="Organization ID">
234
+ * <Form.CopyBox />
235
+ * </Form.Field>
236
+ * ```
237
+ *
238
+ * @example With icon-only button
239
+ * ```tsx
240
+ * <Form.Field name="apiKey" label="API Key">
241
+ * <Form.CopyBox variant="icon-only" />
242
+ * </Form.Field>
243
+ * ```
244
+ *
245
+ * @example With placeholder
246
+ * ```tsx
247
+ * <Form.Field name="webhookUrl" label="Webhook URL">
248
+ * <Form.CopyBox placeholder="Not configured" />
249
+ * </Form.Field>
250
+ * ```
251
+ */
252
+ function FormCopyBox({ variant = "default", className, contentClassName, buttonClassName, placeholder = "" }) {
253
+ const { fieldState } = useFieldContext$1();
254
+ const [copied, copy] = useCopyToClipboard();
255
+ const value = fieldState?.value != null ? String(fieldState.value) : "";
256
+ const displayValue = value || placeholder;
257
+ const copyToClipboard = () => {
258
+ if (!value) return;
259
+ copy(value).then(() => {
260
+ toast.success("Copied to clipboard");
261
+ });
262
+ };
263
+ return /* @__PURE__ */ jsxs("div", {
264
+ className: cn("group border-input flex h-10 w-full overflow-hidden rounded-lg border bg-[#F6F6F580] text-xs focus-within:outline-hidden", className),
265
+ children: [/* @__PURE__ */ jsx("div", {
266
+ className: cn("flex w-full items-center overflow-hidden px-3 py-2 text-xs opacity-50", contentClassName),
267
+ children: /* @__PURE__ */ jsx("span", {
268
+ className: "truncate",
269
+ children: displayValue
270
+ })
271
+ }), /* @__PURE__ */ jsx("div", {
272
+ className: "flex items-center py-2 pr-3",
273
+ children: variant === "icon-only" ? /* @__PURE__ */ jsx("button", {
274
+ type: "button",
275
+ className: cn("text-muted-foreground hover:text-foreground flex size-7 items-center justify-center rounded-sm transition-colors", buttonClassName),
276
+ onClick: copyToClipboard,
277
+ children: copied ? /* @__PURE__ */ jsx(CheckIcon, { className: "size-4" }) : /* @__PURE__ */ jsx(CopyIcon, { className: "size-4" })
278
+ }) : /* @__PURE__ */ jsxs(Button, {
279
+ type: "quaternary",
280
+ theme: "outline",
281
+ size: "small",
282
+ className: cn("h-7 w-fit gap-1 px-2 text-xs", buttonClassName),
283
+ onClick: copyToClipboard,
284
+ children: [/* @__PURE__ */ jsx(CopyIcon, { className: "size-3!" }), copied ? "Copied" : "Copy"]
285
+ })
286
+ })]
287
+ });
288
+ }
289
+ //#endregion
290
+ //#region src/components/features/form/components/form-custom.tsx
291
+ /**
292
+ * Form.Custom - Escape hatch for custom implementations
293
+ *
294
+ * Provides access to the underlying form context for complex use cases
295
+ * that don't fit the standard component patterns.
296
+ *
297
+ * @example
298
+ * ```tsx
299
+ * <Form.Custom>
300
+ * {({ form, fields, submit, reset }) => (
301
+ * <MyCustomComponent
302
+ * fields={fields}
303
+ * onCustomAction={() => {
304
+ * // Do something custom
305
+ * submit();
306
+ * }}
307
+ * />
308
+ * )}
309
+ * </Form.Custom>
310
+ * ```
311
+ */
312
+ function FormCustom({ children }) {
313
+ const ctx = useFormContext$1();
314
+ return /* @__PURE__ */ jsx(Fragment$1, { children: children({
315
+ form: ctx.form,
316
+ fields: ctx.fields,
317
+ isSubmitting: ctx.isSubmitting,
318
+ isDirty: ctx.isDirty,
319
+ isValid: ctx.isValid,
320
+ isSubmitted: ctx.isSubmitted,
321
+ submitCount: ctx.submitCount,
322
+ dirtyFields: ctx.dirtyFields,
323
+ touchedFields: ctx.touchedFields,
324
+ submit: ctx.submit,
325
+ reset: ctx.reset
326
+ }) });
327
+ }
328
+ FormCustom.displayName = "Form.Custom";
329
+ //#endregion
330
+ //#region src/components/features/form/components/form-date-picker.tsx
331
+ function FormDatePicker({ placeholder, disabled, className, triggerClassName, numberOfMonths = 1, minDate: minDateProp, maxDate: maxDateProp, disableFuture, disablePast }) {
332
+ const { id, errors, disabled: fieldDisabled, fieldState } = useFieldContext$1();
333
+ const isDisabled = disabled ?? fieldDisabled;
334
+ const hasErrors = errors && errors.length > 0;
335
+ const currentValue = React$1.useMemo(() => {
336
+ const val = fieldState?.value;
337
+ if (!val) return {
338
+ from: void 0,
339
+ to: void 0
340
+ };
341
+ if (val instanceof Date) return {
342
+ from: val,
343
+ to: val
344
+ };
345
+ if (typeof val === "string") {
346
+ const date = new Date(val);
347
+ return {
348
+ from: date,
349
+ to: date
350
+ };
351
+ }
352
+ if (typeof val === "object" && "from" in val) return val;
353
+ return {
354
+ from: void 0,
355
+ to: void 0
356
+ };
357
+ }, [fieldState?.value]);
358
+ const minDate = minDateProp;
359
+ const maxDate = maxDateProp;
360
+ return /* @__PURE__ */ jsx(CalendarDatePicker, {
361
+ id,
362
+ date: currentValue,
363
+ onDateSelect: React$1.useCallback((range) => {
364
+ if (!range) {
365
+ fieldState?.change(void 0);
366
+ return;
367
+ }
368
+ if (numberOfMonths === 1) fieldState?.change(range.from.toISOString());
369
+ else fieldState?.change({
370
+ from: range.from.toISOString(),
371
+ to: range.to.toISOString()
372
+ });
373
+ }, [fieldState, numberOfMonths]),
374
+ numberOfMonths,
375
+ placeholder,
376
+ disabled: isDisabled,
377
+ minDate,
378
+ maxDate,
379
+ disableFuture,
380
+ disablePast,
381
+ variant: "outline",
382
+ className: cn(className),
383
+ triggerClassName: cn(triggerClassName),
384
+ "aria-invalid": hasErrors || void 0,
385
+ "aria-describedby": hasErrors ? `${id}-error` : void 0
386
+ });
387
+ }
388
+ FormDatePicker.displayName = "Form.DatePicker";
389
+ //#endregion
390
+ //#region src/components/features/form/components/form-date-time-picker.tsx
391
+ function FormDateTimePicker({ minDate: minDateProp, maxDate: maxDateProp, disabledDates, timezone, showTimezoneIndicator, placeholder, disabled, className }) {
392
+ const { id, errors, disabled: fieldDisabled, fieldState } = useFieldContext$1();
393
+ const isDisabled = disabled ?? fieldDisabled;
394
+ const hasErrors = errors && errors.length > 0;
395
+ const currentValue = React$1.useMemo(() => {
396
+ const val = fieldState?.value;
397
+ if (!val) return void 0;
398
+ if (typeof val === "string") return val;
399
+ }, [fieldState?.value]);
400
+ const minDate = minDateProp;
401
+ const maxDate = maxDateProp;
402
+ return /* @__PURE__ */ jsx(DateTimePicker, {
403
+ value: currentValue,
404
+ onChange: React$1.useCallback((value) => {
405
+ fieldState?.change(value);
406
+ }, [fieldState]),
407
+ minDate,
408
+ maxDate,
409
+ disabledDates,
410
+ timezone,
411
+ showTimezoneIndicator,
412
+ placeholder,
413
+ disabled: isDisabled,
414
+ className: cn(className),
415
+ "aria-invalid": hasErrors || void 0,
416
+ "aria-describedby": hasErrors ? `${id}-error` : void 0
417
+ });
418
+ }
419
+ FormDateTimePicker.displayName = "Form.DateTimePicker";
420
+ //#endregion
421
+ //#region src/components/features/form/components/form-description.tsx
422
+ /**
423
+ * Form.Description - Display field description/helper text
424
+ *
425
+ * @example
426
+ * ```tsx
427
+ * <Form.Field name="password">
428
+ * <Form.Input type="password" />
429
+ * <Form.Description>
430
+ * Must be at least 8 characters with one uppercase letter
431
+ * </Form.Description>
432
+ * </Form.Field>
433
+ * ```
434
+ */
435
+ function FormDescription({ children, className }) {
436
+ const fieldContext = useOptionalFieldContext();
437
+ return /* @__PURE__ */ jsx("p", {
438
+ id: fieldContext ? `${fieldContext.id}-description` : void 0,
439
+ className: cn("text-muted-foreground text-xs text-wrap", className),
440
+ children
441
+ });
442
+ }
443
+ FormDescription.displayName = "Form.Description";
444
+ //#endregion
445
+ //#region src/components/features/form/components/form-dialog.tsx
446
+ /**
447
+ * Form.Dialog - A dialog with an integrated form
448
+ *
449
+ * Combines Dialog and Form.Root into a single component with:
450
+ * - Automatic dialog state management (controlled or uncontrolled)
451
+ * - Built-in header with title and description
452
+ * - Built-in footer with submit and cancel buttons
453
+ * - Auto-close on successful submission
454
+ * - Prevents accidental close during submission
455
+ * - Supports render function pattern for form state access
456
+ *
457
+ * @example Basic usage
458
+ * ```tsx
459
+ * <Form.Dialog
460
+ * title="Add User"
461
+ * description="Enter user details"
462
+ * schema={userSchema}
463
+ * onSubmit={handleSubmit}
464
+ * trigger={<Button>Add User</Button>}
465
+ * >
466
+ * <Form.Field name="name" label="Name" required>
467
+ * <Form.Input />
468
+ * </Form.Field>
469
+ * <Form.Field name="email" label="Email" required>
470
+ * <Form.Input type="email" />
471
+ * </Form.Field>
472
+ * </Form.Dialog>
473
+ * ```
474
+ *
475
+ * @example With render function for form state access
476
+ * ```tsx
477
+ * <Form.Dialog
478
+ * title="Edit User"
479
+ * schema={userSchema}
480
+ * defaultValues={user}
481
+ * onSubmit={handleSubmit}
482
+ * trigger={<Button>Edit</Button>}
483
+ * >
484
+ * {({ form, fields, isSubmitting, reset }) => (
485
+ * <>
486
+ * <Form.Field name="name" label="Name">
487
+ * <Form.Input />
488
+ * </Form.Field>
489
+ * <Button variant="ghost" onClick={reset} disabled={isSubmitting}>
490
+ * Reset
491
+ * </Button>
492
+ * </>
493
+ * )}
494
+ * </Form.Dialog>
495
+ * ```
496
+ */
497
+ function FormDialog({ open, onOpenChange, defaultOpen, title, description, trigger, schema, defaultValues, onSubmit, onSuccess, onError, submitText = "Submit", submitTextLoading = "Submitting...", cancelText = "Cancel", showCancel = true, submitType = "primary", loading, formComponent, telemetry, className, formClassName, children }) {
498
+ const [internalOpen, setInternalOpen] = React$1.useState(defaultOpen ?? false);
499
+ const [internalIsSubmitting, setInternalIsSubmitting] = React$1.useState(false);
500
+ const isSubmitting = loading ?? internalIsSubmitting;
501
+ const isControlled = open !== void 0;
502
+ const isOpen = isControlled ? open : internalOpen;
503
+ const handleOpenChange = React$1.useCallback((value) => {
504
+ if (!value && isSubmitting) return;
505
+ if (!isControlled) setInternalOpen(value);
506
+ onOpenChange?.(value);
507
+ }, [
508
+ isControlled,
509
+ isSubmitting,
510
+ onOpenChange
511
+ ]);
512
+ const handleSubmit = React$1.useCallback(async (data) => {
513
+ if (loading === void 0) setInternalIsSubmitting(true);
514
+ try {
515
+ await onSubmit?.(data);
516
+ onSuccess?.(data);
517
+ } catch (error) {
518
+ console.error("Form submission error:", error);
519
+ throw error;
520
+ } finally {
521
+ if (loading === void 0) setInternalIsSubmitting(false);
522
+ }
523
+ }, [
524
+ onSubmit,
525
+ onSuccess,
526
+ loading
527
+ ]);
528
+ const handleCancel = React$1.useCallback(() => {
529
+ handleOpenChange(false);
530
+ }, [handleOpenChange]);
531
+ return /* @__PURE__ */ jsxs(Dialog, {
532
+ open: isOpen,
533
+ onOpenChange: handleOpenChange,
534
+ children: [trigger && /* @__PURE__ */ jsx(Dialog.Trigger, { children: trigger }), /* @__PURE__ */ jsx(Dialog.Content, {
535
+ className,
536
+ children: /* @__PURE__ */ jsx(Form.Root, {
537
+ schema,
538
+ defaultValues,
539
+ onSubmit: handleSubmit,
540
+ onError,
541
+ isSubmitting,
542
+ mode: "onSubmit",
543
+ formComponent,
544
+ telemetry,
545
+ className: cn("space-y-0", formClassName),
546
+ children: (renderProps) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
547
+ /* @__PURE__ */ jsx(Dialog.Header, {
548
+ title,
549
+ description,
550
+ onClose: handleCancel,
551
+ className: "border-b",
552
+ descriptionClassName: "text-foreground/80"
553
+ }),
554
+ /* @__PURE__ */ jsx(Dialog.Body, {
555
+ className: "space-y-0",
556
+ children: typeof children === "function" ? children(renderProps) : children
557
+ }),
558
+ /* @__PURE__ */ jsxs(Dialog.Footer, {
559
+ className: "border-t",
560
+ children: [showCancel && /* @__PURE__ */ jsx(Form.Button, {
561
+ type: "quaternary",
562
+ theme: "outline",
563
+ onClick: handleCancel,
564
+ disableOnSubmit: true,
565
+ children: cancelText
566
+ }), /* @__PURE__ */ jsx(Form.Submit, {
567
+ type: submitType,
568
+ children: isSubmitting ? submitTextLoading : submitText
569
+ })]
570
+ })
571
+ ] })
572
+ })
573
+ })]
574
+ });
575
+ }
576
+ FormDialog.displayName = "Form.Dialog";
577
+ //#endregion
578
+ //#region src/components/features/form/components/form-error.tsx
579
+ /**
580
+ * Form.Error - Display field errors
581
+ *
582
+ * Can be used inside Form.Field to display errors automatically,
583
+ * or standalone with custom rendering.
584
+ *
585
+ * @example
586
+ * ```tsx
587
+ * // Inside Form.Field - displays field errors automatically
588
+ * <Form.Field name="email">
589
+ * <Form.Input />
590
+ * <Form.Error />
591
+ * </Form.Field>
592
+ *
593
+ * // Custom rendering
594
+ * <Form.Field name="email">
595
+ * <Form.Input />
596
+ * <Form.Error>
597
+ * {(errors) => errors.map(e => <span key={e}>{e}</span>)}
598
+ * </Form.Error>
599
+ * </Form.Field>
600
+ * ```
601
+ */
602
+ function FormError({ children, className }) {
603
+ const errors = useOptionalFieldContext()?.errors;
604
+ if (!errors || errors.length === 0) return null;
605
+ if (typeof children === "function") return /* @__PURE__ */ jsx(Fragment$1, { children: children(errors) });
606
+ return /* @__PURE__ */ jsx("ul", {
607
+ className: cn("text-destructive space-y-1 text-sm font-medium", errors.length > 1 && "list-disc pl-4", className),
608
+ role: "alert",
609
+ "aria-live": "polite",
610
+ children: errors.map((error) => /* @__PURE__ */ jsx("li", {
611
+ className: "text-wrap",
612
+ children: error
613
+ }, error))
614
+ });
615
+ }
616
+ FormError.displayName = "Form.Error";
617
+ //#endregion
618
+ //#region src/components/features/form/components/form-field.tsx
619
+ function FieldLabel({ htmlFor, label, hasErrors, required, tooltip, className }) {
620
+ const [isTooltipVisible, setIsTooltipVisible] = React$1.useState(false);
621
+ return /* @__PURE__ */ jsxs("div", {
622
+ className: "relative flex w-fit items-center space-x-2",
623
+ children: [/* @__PURE__ */ jsxs(Label, {
624
+ htmlFor,
625
+ className: cn("text-foreground/80 gap-0 text-xs font-semibold", hasErrors && "text-destructive", className),
626
+ children: [label, required && /* @__PURE__ */ jsx("span", {
627
+ className: "text-destructive/80 align-super text-sm leading-0",
628
+ "aria-hidden": "true",
629
+ children: "*"
630
+ })]
631
+ }), tooltip && /* @__PURE__ */ jsx(Tooltip, {
632
+ message: tooltip,
633
+ open: isTooltipVisible,
634
+ onOpenChange: setIsTooltipVisible,
635
+ side: "bottom",
636
+ contentClassName: "max-w-xs text-wrap",
637
+ children: /* @__PURE__ */ jsx(Icon, {
638
+ icon: CircleHelp,
639
+ className: cn("text-ring absolute top-0.5 -right-3 size-3.5 cursor-pointer transition-opacity duration-400")
640
+ })
641
+ })]
642
+ });
643
+ }
644
+ /**
645
+ * Form.Field - Field wrapper that provides label, errors, and description.
646
+ * Uses the active adapter to resolve field state by name.
647
+ *
648
+ * @example Standard usage
649
+ * ```tsx
650
+ * <Form.Field name="email" label="Email" required>
651
+ * <Form.Input type="email" />
652
+ * </Form.Field>
653
+ * ```
654
+ *
655
+ * @example Render function for custom components
656
+ * ```tsx
657
+ * <Form.Field name="role" label="Role">
658
+ * {({ control, meta }) => (
659
+ * <CustomSelect value={control.value} onChange={control.change} />
660
+ * )}
661
+ * </Form.Field>
662
+ * ```
663
+ */
664
+ function FormField({ name, children, label, description, tooltip, required = false, disabled = false, className, labelClassName }) {
665
+ const adapter = useAdapter();
666
+ const { fields, isSubmitting, form } = useFormContext$1();
667
+ const fieldState = adapter.useField(name);
668
+ const errors = fieldState.errors;
669
+ const hasErrors = errors.length > 0;
670
+ const fieldId = fieldState.id;
671
+ const descriptionId = description ? `${fieldId}-description` : void 0;
672
+ const errorId = hasErrors ? `${fieldId}-error` : void 0;
673
+ const fieldRequired = required || fieldState.required;
674
+ const contextValue = React$1.useMemo(() => ({
675
+ name,
676
+ id: fieldId,
677
+ errors,
678
+ required: fieldRequired,
679
+ disabled,
680
+ fieldState
681
+ }), [
682
+ name,
683
+ fieldId,
684
+ errors,
685
+ fieldRequired,
686
+ disabled,
687
+ fieldState
688
+ ]);
689
+ const isRenderFunction = typeof children === "function";
690
+ const renderContent = () => {
691
+ if (isRenderFunction) return children({
692
+ field: fieldState,
693
+ control: {
694
+ value: fieldState.value,
695
+ change: fieldState.change,
696
+ blur: fieldState.blur,
697
+ focus: fieldState.focus
698
+ },
699
+ meta: {
700
+ name,
701
+ id: fieldId,
702
+ errors,
703
+ required: fieldRequired,
704
+ disabled
705
+ },
706
+ fields,
707
+ form,
708
+ isSubmitting
709
+ });
710
+ return children;
711
+ };
712
+ return /* @__PURE__ */ jsx(FieldProvider, {
713
+ value: contextValue,
714
+ children: /* @__PURE__ */ jsxs("div", {
715
+ className: cn("flex flex-col space-y-2", className),
716
+ children: [
717
+ label && /* @__PURE__ */ jsx(FieldLabel, {
718
+ htmlFor: fieldId,
719
+ label,
720
+ hasErrors,
721
+ required: fieldRequired,
722
+ tooltip,
723
+ className: labelClassName
724
+ }),
725
+ renderContent(),
726
+ description && /* @__PURE__ */ jsx("p", {
727
+ id: descriptionId,
728
+ className: "text-ring text-xs text-wrap",
729
+ children: description
730
+ }),
731
+ hasErrors && /* @__PURE__ */ jsx("ul", {
732
+ id: errorId,
733
+ className: cn("text-destructive space-y-1 text-xs font-medium", errors.length > 1 && "list-disc pl-4"),
734
+ role: "alert",
735
+ "aria-live": "polite",
736
+ children: errors.map((error) => /* @__PURE__ */ jsx("li", {
737
+ className: "text-wrap",
738
+ children: error
739
+ }, error))
740
+ })
741
+ ]
742
+ })
743
+ });
744
+ }
745
+ FormField.displayName = "Form.Field";
746
+ //#endregion
747
+ //#region src/components/features/form/components/form-field-array.tsx
748
+ /**
749
+ * Form.FieldArray - Dynamic array of fields with append/remove/move helpers.
750
+ *
751
+ * @example
752
+ * ```tsx
753
+ * <Form.FieldArray name="members">
754
+ * {({ fields, append, remove }) => (
755
+ * <>
756
+ * {fields.map((field, index) => (
757
+ * <div key={field.key}>
758
+ * <Form.Field name={`members.${index}.email`} label="Email">
759
+ * <Form.Input type="email" />
760
+ * </Form.Field>
761
+ * <button onClick={() => remove(index)}>Remove</button>
762
+ * </div>
763
+ * ))}
764
+ * <button onClick={() => append({})}>Add Member</button>
765
+ * </>
766
+ * )}
767
+ * </Form.FieldArray>
768
+ * ```
769
+ */
770
+ function FormFieldArray({ name, children }) {
771
+ const fieldArray = useAdapter().useFieldArray(name);
772
+ return /* @__PURE__ */ jsx(Fragment$1, { children: children({
773
+ fields: fieldArray.items,
774
+ append: fieldArray.append,
775
+ remove: fieldArray.remove,
776
+ move: fieldArray.move
777
+ }) });
778
+ }
779
+ FormFieldArray.displayName = "Form.FieldArray";
780
+ //#endregion
781
+ //#region src/components/features/form/components/form-input.tsx
782
+ /**
783
+ * Form.Input - Text input component
784
+ *
785
+ * Automatically wired to the parent Form.Field context.
786
+ *
787
+ * @example
788
+ * ```tsx
789
+ * <Form.Field name="email" label="Email" required>
790
+ * <Form.Input type="email" placeholder="john@example.com" />
791
+ * </Form.Field>
792
+ * ```
793
+ */
794
+ function FormInput({ ref, type = "text", className, disabled, ...props }) {
795
+ const { id, errors, disabled: fieldDisabled, fieldState } = useFieldContext$1();
796
+ const isDisabled = disabled ?? fieldDisabled;
797
+ const hasErrors = errors && errors.length > 0;
798
+ return /* @__PURE__ */ jsx(Input, {
799
+ ...props,
800
+ ref,
801
+ id,
802
+ name: fieldState?.name,
803
+ type,
804
+ value: fieldState?.value ?? "",
805
+ onChange: (e) => fieldState?.change(e.target.value),
806
+ onBlur: () => fieldState?.blur(),
807
+ className: cn("!text-xs", className),
808
+ disabled: isDisabled,
809
+ "aria-invalid": hasErrors || void 0,
810
+ "aria-describedby": hasErrors ? `${id}-error` : void 0
811
+ });
812
+ }
813
+ FormInput.displayName = "Form.Input";
814
+ //#endregion
815
+ //#region src/components/features/form/components/form-radio-group.tsx
816
+ /**
817
+ * Form.RadioGroup - Radio button group component
818
+ *
819
+ * Automatically wired to the parent Form.Field context.
820
+ *
821
+ * @example
822
+ * ```tsx
823
+ * <Form.Field name="plan" label="Select Plan" required>
824
+ * <Form.RadioGroup orientation="vertical">
825
+ * <Form.RadioItem value="free" label="Free" description="Basic features" />
826
+ * <Form.RadioItem value="pro" label="Pro" description="Advanced features" />
827
+ * <Form.RadioItem value="enterprise" label="Enterprise" description="Custom solutions" />
828
+ * </Form.RadioGroup>
829
+ * </Form.Field>
830
+ * ```
831
+ */
832
+ function FormRadioGroup({ orientation = "vertical", disabled, className, children }) {
833
+ const { id, errors, disabled: fieldDisabled, fieldState } = useFieldContext$1();
834
+ const isDisabled = disabled ?? fieldDisabled;
835
+ const hasErrors = errors && errors.length > 0;
836
+ return /* @__PURE__ */ jsx(RadioGroup, {
837
+ value: fieldState?.value != null ? String(fieldState.value) : void 0,
838
+ onValueChange: (val) => fieldState?.change(val),
839
+ disabled: isDisabled,
840
+ "aria-invalid": hasErrors || void 0,
841
+ "aria-describedby": hasErrors ? `${id}-error` : void 0,
842
+ className: cn(orientation === "horizontal" ? "flex flex-row space-x-4" : "flex flex-col space-y-2", className),
843
+ children
844
+ });
845
+ }
846
+ FormRadioGroup.displayName = "Form.RadioGroup";
847
+ /**
848
+ * Form.RadioItem - Individual radio button option
849
+ *
850
+ * @example
851
+ * ```tsx
852
+ * <Form.RadioItem value="option1" label="Option 1" />
853
+ * ```
854
+ */
855
+ function FormRadioItem({ value, label, description, disabled }) {
856
+ const radioId = `radio-${value}`;
857
+ return /* @__PURE__ */ jsxs("div", {
858
+ className: "flex items-start space-x-2",
859
+ children: [/* @__PURE__ */ jsx(RadioGroupItem, {
860
+ id: radioId,
861
+ value,
862
+ disabled,
863
+ className: "mt-1"
864
+ }), /* @__PURE__ */ jsxs("div", {
865
+ className: "flex flex-col",
866
+ children: [/* @__PURE__ */ jsx(Label, {
867
+ htmlFor: radioId,
868
+ className: cn("cursor-pointer text-sm font-normal", disabled && "cursor-not-allowed opacity-70"),
869
+ children: label
870
+ }), description && /* @__PURE__ */ jsx("span", {
871
+ className: "text-muted-foreground text-xs",
872
+ children: description
873
+ })]
874
+ })]
875
+ });
876
+ }
877
+ FormRadioItem.displayName = "Form.RadioItem";
878
+ //#endregion
879
+ //#region src/components/features/form/components/form-root.tsx
880
+ /**
881
+ * Form.Root - Root form container that integrates with the active adapter.
882
+ *
883
+ * @example Standard usage
884
+ * ```tsx
885
+ * <Form.Root schema={schema} onSubmit={handleSubmit}>
886
+ * <Form.Field name="email" label="Email">
887
+ * <Form.Input type="email" />
888
+ * </Form.Field>
889
+ * <Form.Submit>Save</Form.Submit>
890
+ * </Form.Root>
891
+ * ```
892
+ *
893
+ * @example Render function for form state access
894
+ * ```tsx
895
+ * <Form.Root schema={schema}>
896
+ * {({ form, fields, isSubmitting }) => (
897
+ * <Form.Field name="email"><Form.Input /></Form.Field>
898
+ * )}
899
+ * </Form.Root>
900
+ * ```
901
+ */
902
+ function FormRoot({ schema, children, onSubmit, action, method = "POST", formComponent: FormComp = "form", id, name, defaultValues, mode = "onBlur", isSubmitting: externalIsSubmitting, onError, onSuccess, telemetry, className }) {
903
+ const adapter = useAdapter();
904
+ const [internalIsSubmitting, setInternalIsSubmitting] = React$1.useState(false);
905
+ const isSubmitting = externalIsSubmitting ?? internalIsSubmitting;
906
+ const [isSubmitted, setIsSubmitted] = React$1.useState(false);
907
+ const [submitCount, setSubmitCount] = React$1.useState(0);
908
+ const formRef = React$1.useRef(null);
909
+ const wrappedOnSubmit = React$1.useCallback(async (data) => {
910
+ setInternalIsSubmitting(true);
911
+ setIsSubmitted(true);
912
+ setSubmitCount((prev) => prev + 1);
913
+ try {
914
+ await onSubmit?.(data);
915
+ telemetry?.onSuccess?.({
916
+ formName: name ?? "",
917
+ formId: id
918
+ });
919
+ onSuccess?.(data);
920
+ } catch (error) {
921
+ const err = error instanceof Error ? error : new Error(String(error));
922
+ telemetry?.onError?.({
923
+ formName: name ?? "",
924
+ formId: id,
925
+ error: err
926
+ });
927
+ telemetry?.captureError?.(err, {
928
+ formName: name ?? "",
929
+ formId: id
930
+ });
931
+ onError?.(error);
932
+ } finally {
933
+ setInternalIsSubmitting(false);
934
+ }
935
+ }, [
936
+ onSubmit,
937
+ onSuccess,
938
+ onError,
939
+ telemetry,
940
+ name,
941
+ id
942
+ ]);
943
+ const instance = adapter.useCreateForm({
944
+ schema,
945
+ defaultValues,
946
+ mode,
947
+ id,
948
+ onSubmit: onSubmit ? wrappedOnSubmit : void 0,
949
+ formRef
950
+ });
951
+ const { formState } = instance;
952
+ const contextValue = React$1.useMemo(() => ({
953
+ form: instance,
954
+ fields: instance.fields,
955
+ isSubmitting,
956
+ isDirty: formState.isDirty,
957
+ isValid: formState.isValid,
958
+ isSubmitted,
959
+ submitCount,
960
+ dirtyFields: formState.dirtyFields,
961
+ touchedFields: formState.touchedFields,
962
+ submit: () => formRef.current?.requestSubmit(),
963
+ reset: () => instance.reset(),
964
+ formId: instance.id
965
+ }), [
966
+ instance,
967
+ isSubmitting,
968
+ formState,
969
+ isSubmitted,
970
+ submitCount
971
+ ]);
972
+ const isRenderFunction = typeof children === "function";
973
+ const renderProps = {
974
+ form: instance,
975
+ fields: instance.fields,
976
+ isSubmitting,
977
+ isDirty: formState.isDirty,
978
+ isValid: formState.isValid,
979
+ isSubmitted,
980
+ submitCount,
981
+ dirtyFields: formState.dirtyFields,
982
+ touchedFields: formState.touchedFields,
983
+ submit: () => formRef.current?.requestSubmit(),
984
+ reset: () => instance.reset()
985
+ };
986
+ const renderChildren = () => {
987
+ if (isRenderFunction) return children(renderProps);
988
+ return children;
989
+ };
990
+ return /* @__PURE__ */ jsx(FormProvider, {
991
+ value: contextValue,
992
+ children: /* @__PURE__ */ jsx(adapter.FormProvider, {
993
+ instance,
994
+ children: /* @__PURE__ */ jsx(FormComp, {
995
+ ref: formRef,
996
+ ...instance.formProps,
997
+ method,
998
+ action,
999
+ className: cn("space-y-6", className),
1000
+ autoComplete: "off",
1001
+ noValidate: true,
1002
+ onSubmit: (e) => {
1003
+ e.stopPropagation();
1004
+ telemetry?.onSubmit?.({
1005
+ formName: name ?? "",
1006
+ formId: id
1007
+ });
1008
+ const adapterSubmit = instance.formProps.onSubmit;
1009
+ adapterSubmit?.(e);
1010
+ },
1011
+ children: renderChildren()
1012
+ })
1013
+ })
1014
+ });
1015
+ }
1016
+ FormRoot.displayName = "Form.Root";
1017
+ //#endregion
1018
+ //#region src/components/features/form/components/form-select.tsx
1019
+ /**
1020
+ * Form.Select - Select dropdown component
1021
+ *
1022
+ * Automatically wired to the parent Form.Field context.
1023
+ *
1024
+ * @example
1025
+ * ```tsx
1026
+ * <Form.Field name="country" label="Country" required>
1027
+ * <Form.Select placeholder="Select a country">
1028
+ * <Form.SelectItem value="us">United States</Form.SelectItem>
1029
+ * <Form.SelectItem value="uk">United Kingdom</Form.SelectItem>
1030
+ * <Form.SelectItem value="ca">Canada</Form.SelectItem>
1031
+ * </Form.Select>
1032
+ * </Form.Field>
1033
+ * ```
1034
+ */
1035
+ function FormSelect({ placeholder, disabled, className, children }) {
1036
+ const { id, errors, disabled: fieldDisabled, fieldState } = useFieldContext$1();
1037
+ const isDisabled = disabled ?? fieldDisabled;
1038
+ const hasErrors = errors && errors.length > 0;
1039
+ return /* @__PURE__ */ jsxs(Select, {
1040
+ value: fieldState?.value != null ? String(fieldState.value) : void 0,
1041
+ onValueChange: (val) => fieldState?.change(val),
1042
+ disabled: isDisabled,
1043
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
1044
+ id,
1045
+ className: cn(className),
1046
+ "aria-invalid": hasErrors || void 0,
1047
+ "aria-describedby": hasErrors ? `${id}-error` : void 0,
1048
+ onBlur: () => fieldState?.blur(),
1049
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder })
1050
+ }), /* @__PURE__ */ jsx(SelectContent, { children })]
1051
+ });
1052
+ }
1053
+ FormSelect.displayName = "Form.Select";
1054
+ /**
1055
+ * Form.SelectItem - Individual select option
1056
+ *
1057
+ * @example
1058
+ * ```tsx
1059
+ * <Form.SelectItem value="option1">Option 1</Form.SelectItem>
1060
+ * ```
1061
+ */
1062
+ function FormSelectItem({ value, children, disabled }) {
1063
+ return /* @__PURE__ */ jsx(SelectItem, {
1064
+ value,
1065
+ disabled,
1066
+ children
1067
+ });
1068
+ }
1069
+ FormSelectItem.displayName = "Form.SelectItem";
1070
+ //#endregion
1071
+ //#region src/components/features/form/components/form-submit.tsx
1072
+ /**
1073
+ * Form.Submit - Submit button with automatic loading state
1074
+ *
1075
+ * @example
1076
+ * ```tsx
1077
+ * <Form.Submit loadingText="Saving...">
1078
+ * Save Changes
1079
+ * </Form.Submit>
1080
+ * ```
1081
+ */
1082
+ function FormSubmit({ children, loadingText, loading = false, ...props }) {
1083
+ const { isSubmitting } = useFormContext$1();
1084
+ const isLoading = loading || isSubmitting;
1085
+ return /* @__PURE__ */ jsx(Button, {
1086
+ htmlType: "submit",
1087
+ disabled: props.disabled || isLoading,
1088
+ loading: isLoading,
1089
+ ...props,
1090
+ children: isLoading && loadingText ? loadingText : children
1091
+ });
1092
+ }
1093
+ FormSubmit.displayName = "Form.Submit";
1094
+ //#endregion
1095
+ //#region src/components/features/form/components/form-switch.tsx
1096
+ /**
1097
+ * Form.Switch - Toggle switch component
1098
+ *
1099
+ * Automatically wired to the parent Form.Field context.
1100
+ *
1101
+ * @example
1102
+ * ```tsx
1103
+ * <Form.Field name="notifications">
1104
+ * <Form.Switch label="Enable email notifications" />
1105
+ * </Form.Field>
1106
+ * ```
1107
+ */
1108
+ function FormSwitch({ label, disabled, className }) {
1109
+ const { id, errors, disabled: fieldDisabled, fieldState } = useFieldContext$1();
1110
+ const isDisabled = disabled ?? fieldDisabled;
1111
+ const hasErrors = errors && errors.length > 0;
1112
+ const checked = Boolean(fieldState?.value);
1113
+ return /* @__PURE__ */ jsxs("div", {
1114
+ className: cn("flex items-center space-x-2", className),
1115
+ children: [/* @__PURE__ */ jsx(Switch, {
1116
+ id,
1117
+ checked,
1118
+ onCheckedChange: (value) => fieldState?.change(Boolean(value)),
1119
+ disabled: isDisabled,
1120
+ "aria-invalid": hasErrors || void 0,
1121
+ "aria-describedby": hasErrors ? `${id}-error` : void 0
1122
+ }), label && /* @__PURE__ */ jsx(Label, {
1123
+ htmlFor: id,
1124
+ className: cn("cursor-pointer text-sm font-normal", isDisabled && "cursor-not-allowed opacity-70"),
1125
+ children: label
1126
+ })]
1127
+ });
1128
+ }
1129
+ FormSwitch.displayName = "Form.Switch";
1130
+ //#endregion
1131
+ //#region src/components/features/form/components/form-textarea.tsx
1132
+ /**
1133
+ * Form.Textarea - Multi-line text input component
1134
+ *
1135
+ * Automatically wired to the parent Form.Field context.
1136
+ *
1137
+ * @example
1138
+ * ```tsx
1139
+ * <Form.Field name="bio" label="Bio">
1140
+ * <Form.Textarea rows={4} placeholder="Tell us about yourself..." />
1141
+ * </Form.Field>
1142
+ * ```
1143
+ */
1144
+ function FormTextarea({ ref, className, disabled, rows = 3, ...props }) {
1145
+ const { id, errors, disabled: fieldDisabled, fieldState } = useFieldContext$1();
1146
+ const isDisabled = disabled ?? fieldDisabled;
1147
+ const hasErrors = errors && errors.length > 0;
1148
+ return /* @__PURE__ */ jsx(Textarea, {
1149
+ ...props,
1150
+ ref,
1151
+ id,
1152
+ name: fieldState?.name,
1153
+ value: fieldState?.value ?? "",
1154
+ onChange: (e) => fieldState?.change(e.target.value),
1155
+ onBlur: () => fieldState?.blur(),
1156
+ rows,
1157
+ className: cn(className),
1158
+ disabled: isDisabled,
1159
+ "aria-invalid": hasErrors || void 0,
1160
+ "aria-describedby": hasErrors ? `${id}-error` : void 0
1161
+ });
1162
+ }
1163
+ FormTextarea.displayName = "Form.Textarea";
1164
+ //#endregion
1165
+ //#region src/components/features/form/components/form-time-picker.tsx
1166
+ function FormTimePicker({ min, max, step, placeholder, disabled, className }) {
1167
+ const { id, errors, disabled: fieldDisabled, fieldState } = useFieldContext$1();
1168
+ const isDisabled = disabled ?? fieldDisabled;
1169
+ const hasErrors = errors && errors.length > 0;
1170
+ return /* @__PURE__ */ jsx(TimePicker, {
1171
+ id,
1172
+ value: fieldState?.value ?? "",
1173
+ onChange: React$1.useCallback((value) => {
1174
+ fieldState?.change(value || void 0);
1175
+ }, [fieldState]),
1176
+ min,
1177
+ max,
1178
+ step,
1179
+ placeholder,
1180
+ disabled: isDisabled,
1181
+ className: cn(className),
1182
+ "aria-invalid": hasErrors || void 0,
1183
+ "aria-describedby": hasErrors ? `${id}-error` : void 0
1184
+ });
1185
+ }
1186
+ FormTimePicker.displayName = "Form.TimePicker";
1187
+ //#endregion
1188
+ //#region src/components/features/form/components/form-transfer.tsx
1189
+ /**
1190
+ * Form.Transfer - Transfer list component for selecting multiple items
1191
+ *
1192
+ * Automatically wired to the parent Form.Field context.
1193
+ * Displays minItems/maxItems constraints when provided.
1194
+ *
1195
+ * @example
1196
+ * ```tsx
1197
+ * <Form.Field name="teams" label="Select Teams">
1198
+ * <Form.Transfer
1199
+ * items={teams}
1200
+ * itemKey="id"
1201
+ * itemLabel="name"
1202
+ * minItems={2}
1203
+ * maxItems={5}
1204
+ * />
1205
+ * </Form.Field>
1206
+ * ```
1207
+ */
1208
+ function FormTransfer({ disabled, minItems, maxItems, ...props }) {
1209
+ const { disabled: fieldDisabled, fieldState } = useFieldContext$1();
1210
+ const isDisabled = disabled ?? fieldDisabled;
1211
+ const value = Array.isArray(fieldState?.value) ? fieldState.value : [];
1212
+ const handleChange = (newValue) => {
1213
+ fieldState?.change(newValue);
1214
+ };
1215
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Transfer, {
1216
+ ...props,
1217
+ value,
1218
+ onChange: handleChange,
1219
+ disabled: isDisabled
1220
+ }), (minItems != null || maxItems != null) && /* @__PURE__ */ jsx("p", {
1221
+ className: "text-sm text-muted-foreground mt-2",
1222
+ children: minItems != null && maxItems != null ? `Select between ${minItems} and ${maxItems} items (minimum: ${minItems}, maximum: ${maxItems})` : minItems != null ? `Select at least ${minItems} items (minimum: ${minItems})` : `Select up to ${maxItems} items (maximum: ${maxItems})`
1223
+ })] });
1224
+ }
1225
+ FormTransfer.displayName = "Form.Transfer";
1226
+ //#endregion
1227
+ //#region src/components/features/form/hooks/use-watch.ts
1228
+ /**
1229
+ * Hook to watch a field's value reactively.
1230
+ * Delegates to the active adapter's useWatch implementation.
1231
+ *
1232
+ * @example
1233
+ * ```tsx
1234
+ * function ConditionalField() {
1235
+ * const contactMethod = useWatch('contactMethod')
1236
+ * if (contactMethod === 'email') {
1237
+ * return <Form.Field name="email"><Form.Input type="email" /></Form.Field>
1238
+ * }
1239
+ * return null
1240
+ * }
1241
+ * ```
1242
+ */
1243
+ function useWatch(name) {
1244
+ return useAdapter().useWatch(name);
1245
+ }
1246
+ /**
1247
+ * Hook to watch multiple fields at once.
1248
+ * Delegates to the active adapter's useWatchAll implementation.
1249
+ *
1250
+ * @example
1251
+ * ```tsx
1252
+ * function Summary() {
1253
+ * const values = useWatchAll(['firstName', 'lastName', 'email'])
1254
+ * return <div>Name: {values.firstName} {values.lastName}</div>
1255
+ * }
1256
+ * ```
1257
+ */
1258
+ function useWatchAll(names) {
1259
+ return useAdapter().useWatchAll(names);
1260
+ }
1261
+ //#endregion
1262
+ //#region src/components/features/form/components/form-when.tsx
1263
+ /**
1264
+ * Form.When - Conditional rendering based on field values
1265
+ *
1266
+ * Renders children only when the specified field matches the condition.
1267
+ *
1268
+ * @example
1269
+ * ```tsx
1270
+ * // Render when field equals value
1271
+ * <Form.When field="contactMethod" is="email">
1272
+ * <Form.Field name="email"><Form.Input type="email" /></Form.Field>
1273
+ * </Form.When>
1274
+ *
1275
+ * // Render when field does not equal value
1276
+ * <Form.When field="contactMethod" isNot="none">
1277
+ * <Form.Field name="contact"><Form.Input /></Form.Field>
1278
+ * </Form.When>
1279
+ *
1280
+ * // Render when field value is in array
1281
+ * <Form.When field="role" in={['admin', 'moderator']}>
1282
+ * <Form.Field name="permissions"><Form.Input /></Form.Field>
1283
+ * </Form.When>
1284
+ *
1285
+ * // Render when field value is not in array
1286
+ * <Form.When field="status" notIn={['archived', 'deleted']}>
1287
+ * <Form.Field name="actions"><Form.Input /></Form.Field>
1288
+ * </Form.When>
1289
+ * ```
1290
+ */
1291
+ function FormWhen({ field, is, isNot, in: inArray, notIn, children }) {
1292
+ const value = useWatch(field);
1293
+ let shouldRender = true;
1294
+ if (is !== void 0) shouldRender = value === is;
1295
+ if (isNot !== void 0 && shouldRender) shouldRender = value !== isNot;
1296
+ if (inArray !== void 0 && shouldRender) shouldRender = inArray.includes(value);
1297
+ if (notIn !== void 0 && shouldRender) shouldRender = !notIn.includes(value);
1298
+ if (!shouldRender) return null;
1299
+ return /* @__PURE__ */ jsx(Fragment$1, { children });
1300
+ }
1301
+ FormWhen.displayName = "Form.When";
1302
+ //#endregion
1303
+ //#region src/components/features/form/components/form-input-group.tsx
1304
+ /**
1305
+ * Form.InputGroup - Input with leading/trailing addons
1306
+ *
1307
+ * Automatically wired to the parent Form.Field context.
1308
+ *
1309
+ * @example
1310
+ * ```tsx
1311
+ * <Form.Field name="website" label="Website" required>
1312
+ * <Form.InputGroup leading="https://" placeholder="example.com" />
1313
+ * </Form.Field>
1314
+ * ```
1315
+ */
1316
+ function FormInputGroup({ ref, className, disabled, ...props }) {
1317
+ const { id, errors, disabled: fieldDisabled, fieldState } = useFieldContext$1();
1318
+ const isDisabled = disabled ?? fieldDisabled;
1319
+ const hasErrors = errors && errors.length > 0;
1320
+ return /* @__PURE__ */ jsx(InputWithAddons, {
1321
+ ...props,
1322
+ ref,
1323
+ id,
1324
+ name: fieldState?.name,
1325
+ value: fieldState?.value ?? "",
1326
+ onChange: (e) => fieldState?.change(e.target.value),
1327
+ onBlur: () => fieldState?.blur(),
1328
+ className: cn("text-xs!", className),
1329
+ disabled: isDisabled,
1330
+ "aria-invalid": hasErrors || void 0,
1331
+ "aria-describedby": hasErrors ? `${id}-error` : void 0
1332
+ });
1333
+ }
1334
+ FormInputGroup.displayName = "Form.InputGroup";
1335
+ //#endregion
1336
+ //#region src/components/features/form/hooks/use-field.ts
1337
+ /**
1338
+ * Hook to access and control a specific field.
1339
+ * Delegates to the active adapter's useField implementation.
1340
+ *
1341
+ * @example
1342
+ * ```tsx
1343
+ * function MyCustomInput({ name }: { name: string }) {
1344
+ * const { field, control, meta, errors } = useField(name)
1345
+ * return (
1346
+ * <input
1347
+ * name={meta.name}
1348
+ * id={meta.id}
1349
+ * value={control.value ?? ''}
1350
+ * onChange={(e) => control.change(e.target.value)}
1351
+ * onBlur={control.blur}
1352
+ * aria-invalid={!!errors?.length}
1353
+ * />
1354
+ * )
1355
+ * }
1356
+ * ```
1357
+ */
1358
+ function useField(name) {
1359
+ const fieldState = useAdapter().useField(name);
1360
+ return {
1361
+ field: fieldState,
1362
+ control: {
1363
+ value: fieldState.value,
1364
+ change: fieldState.change,
1365
+ blur: fieldState.blur,
1366
+ focus: fieldState.focus
1367
+ },
1368
+ meta: {
1369
+ name: fieldState.name,
1370
+ id: fieldState.id,
1371
+ errors: fieldState.errors,
1372
+ required: fieldState.required,
1373
+ disabled: false
1374
+ },
1375
+ errors: fieldState.errors
1376
+ };
1377
+ }
1378
+ //#endregion
1379
+ //#region src/components/features/form/hooks/use-field-context.ts
1380
+ /**
1381
+ * Hook to access the current field context
1382
+ * Must be used within a Form.Field component
1383
+ *
1384
+ * @example
1385
+ * ```tsx
1386
+ * function MyInput() {
1387
+ * const { name, id, errors, required, disabled, fieldMeta } = useFieldContext();
1388
+ *
1389
+ * return (
1390
+ * <input
1391
+ * name={name}
1392
+ * id={id}
1393
+ * required={required}
1394
+ * disabled={disabled}
1395
+ * aria-invalid={!!errors?.length}
1396
+ * />
1397
+ * );
1398
+ * }
1399
+ * ```
1400
+ */
1401
+ function useFieldContext() {
1402
+ return useFieldContext$1();
1403
+ }
1404
+ //#endregion
1405
+ //#region src/components/features/form/hooks/use-form-context.ts
1406
+ /**
1407
+ * Hook to access the form context
1408
+ *
1409
+ * @example
1410
+ * ```tsx
1411
+ * function MyComponent() {
1412
+ * const { form, fields, isSubmitting, submit, reset } = useFormContext();
1413
+ *
1414
+ * return (
1415
+ * <button onClick={submit} disabled={isSubmitting}>
1416
+ * Submit
1417
+ * </button>
1418
+ * );
1419
+ * }
1420
+ * ```
1421
+ */
1422
+ function useFormContext() {
1423
+ return useFormContext$1();
1424
+ }
1425
+ //#endregion
1426
+ //#region src/components/features/form/hooks/use-form-state.ts
1427
+ /**
1428
+ * Hook to access form-level state (dirty, valid, submitted, etc.)
1429
+ *
1430
+ * @example
1431
+ * ```tsx
1432
+ * function SaveButton() {
1433
+ * const { isDirty, isSubmitting, isValid } = useFormState()
1434
+ *
1435
+ * return (
1436
+ * <button
1437
+ * type="submit"
1438
+ * disabled={!isDirty || isSubmitting || !isValid}
1439
+ * >
1440
+ * Save Changes
1441
+ * </button>
1442
+ * )
1443
+ * }
1444
+ * ```
1445
+ */
1446
+ function useFormState() {
1447
+ const ctx = useFormContext$1();
1448
+ return {
1449
+ isDirty: ctx.isDirty,
1450
+ isValid: ctx.isValid,
1451
+ isSubmitting: ctx.isSubmitting,
1452
+ isSubmitted: ctx.isSubmitted,
1453
+ submitCount: ctx.submitCount,
1454
+ dirtyFields: ctx.dirtyFields,
1455
+ touchedFields: ctx.touchedFields
1456
+ };
1457
+ }
1458
+ //#endregion
1459
+ //#region src/components/features/form/index.ts
1460
+ /**
1461
+ * Datum Form Library
1462
+ *
1463
+ * A compound component pattern form library with pluggable adapter support.
1464
+ * Choose between Conform.js or React Hook Form as your form backend,
1465
+ * with Zod for schema validation.
1466
+ *
1467
+ * ## Adapter Setup
1468
+ *
1469
+ * Wrap your app with an adapter provider:
1470
+ *
1471
+ * ```tsx
1472
+ * // Conform adapter
1473
+ * import { ConformAdapter } from '@datum-cloud/datum-ui/form/adapters/conform'
1474
+ * <ConformAdapter><App /></ConformAdapter>
1475
+ *
1476
+ * // React Hook Form adapter
1477
+ * import { RHFAdapter } from '@datum-cloud/datum-ui/form/adapters/rhf'
1478
+ * <RHFAdapter><App /></RHFAdapter>
1479
+ * ```
1480
+ *
1481
+ * @example Basic Usage
1482
+ * ```tsx
1483
+ * import { Form } from '@datum-cloud/datum-ui/form';
1484
+ * import { z } from 'zod';
1485
+ *
1486
+ * const userSchema = z.object({
1487
+ * name: z.string().min(2),
1488
+ * email: z.string().email(),
1489
+ * });
1490
+ *
1491
+ * function UserForm() {
1492
+ * return (
1493
+ * <Form.Root schema={userSchema} onSubmit={(data) => console.log(data)}>
1494
+ * <Form.Field name="name" label="Name" required>
1495
+ * <Form.Input />
1496
+ * </Form.Field>
1497
+ * <Form.Field name="email" label="Email" required>
1498
+ * <Form.Input type="email" />
1499
+ * </Form.Field>
1500
+ * <Form.Submit>Save</Form.Submit>
1501
+ * </Form.Root>
1502
+ * );
1503
+ * }
1504
+ * ```
1505
+ *
1506
+ * @example Multi-Step Form (separate import)
1507
+ * ```tsx
1508
+ * import { FormStepper, FormStep, StepperNavigation, StepperControls } from '@datum-cloud/datum-ui/form/stepper';
1509
+ *
1510
+ * const steps = [
1511
+ * { id: 'account', label: 'Account', schema: accountSchema },
1512
+ * { id: 'profile', label: 'Profile', schema: profileSchema },
1513
+ * ];
1514
+ *
1515
+ * <FormStepper steps={steps} onComplete={handleComplete}>
1516
+ * <StepperNavigation />
1517
+ * <FormStep id="account">...</FormStep>
1518
+ * <FormStep id="profile">...</FormStep>
1519
+ * <StepperControls />
1520
+ * </FormStepper>
1521
+ * ```
1522
+ *
1523
+ * @example Form State
1524
+ * ```tsx
1525
+ * <Form.Root schema={schema} onSubmit={handleSubmit}>
1526
+ * {({ isDirty, isValid, isSubmitted, submitCount }) => (
1527
+ * <>
1528
+ * <Form.Field name="name"><Form.Input /></Form.Field>
1529
+ * <Form.Submit disabled={!isDirty || !isValid}>Save</Form.Submit>
1530
+ * {isSubmitted && <p>Submitted {submitCount} time(s)</p>}
1531
+ * </>
1532
+ * )}
1533
+ * </Form.Root>
1534
+ * ```
1535
+ *
1536
+ * @example Conditional Fields
1537
+ * ```tsx
1538
+ * <Form.Field name="contactMethod">
1539
+ * <Form.Select>
1540
+ * <Form.SelectItem value="email">Email</Form.SelectItem>
1541
+ * <Form.SelectItem value="phone">Phone</Form.SelectItem>
1542
+ * </Form.Select>
1543
+ * </Form.Field>
1544
+ *
1545
+ * <Form.When field="contactMethod" is="email">
1546
+ * <Form.Field name="email"><Form.Input type="email" /></Form.Field>
1547
+ * </Form.When>
1548
+ * ```
1549
+ */
1550
+ /**
1551
+ * Form compound component
1552
+ *
1553
+ * Requires an adapter provider at the application root:
1554
+ * - `<ConformAdapter>` from `@datum-cloud/datum-ui/form/adapters/conform`
1555
+ * - `<RHFAdapter>` from `@datum-cloud/datum-ui/form/adapters/rhf`
1556
+ *
1557
+ * Components:
1558
+ * - Form.Root - Main form container
1559
+ * - Form.Field - Field wrapper with label and error handling
1560
+ * - Form.Input, Form.Textarea, Form.Select, Form.Checkbox, Form.Switch, Form.RadioGroup
1561
+ * - Form.Autocomplete, Form.CopyBox, Form.InputGroup
1562
+ * - Form.When - Conditional rendering
1563
+ * - Form.FieldArray - Dynamic array of fields
1564
+ * - Form.Custom - Escape hatch for custom implementations
1565
+ * - Form.Dialog - Form rendered inside a Dialog
1566
+ * - Form.Submit, Form.Button, Form.Error, Form.Description
1567
+ *
1568
+ * Stepper (separate import):
1569
+ * - `@datum-cloud/datum-ui/form/stepper` provides FormStepper, FormStep, StepperNavigation, StepperControls, useStepper
1570
+ *
1571
+ * Hooks:
1572
+ * - Form.useFormContext, Form.useFormState, Form.useFieldContext, Form.useField
1573
+ * - Form.useWatch, Form.useWatchAll
1574
+ */
1575
+ const Form = {
1576
+ Root: FormRoot,
1577
+ Field: FormField,
1578
+ Submit: FormSubmit,
1579
+ Button: FormButton,
1580
+ Error: FormError,
1581
+ Description: FormDescription,
1582
+ Input: FormInput,
1583
+ Textarea: FormTextarea,
1584
+ Select: FormSelect,
1585
+ SelectItem: FormSelectItem,
1586
+ Checkbox: FormCheckbox,
1587
+ Switch: FormSwitch,
1588
+ RadioGroup: FormRadioGroup,
1589
+ RadioItem: FormRadioItem,
1590
+ CopyBox: FormCopyBox,
1591
+ Autocomplete: FormAutocomplete,
1592
+ Autosearch: FormAutosearch,
1593
+ Combobox: FormCombobox,
1594
+ InputGroup: FormInputGroup,
1595
+ DatePicker: FormDatePicker,
1596
+ DateTimePicker: FormDateTimePicker,
1597
+ TimePicker: FormTimePicker,
1598
+ Transfer: FormTransfer,
1599
+ When: FormWhen,
1600
+ FieldArray: FormFieldArray,
1601
+ Custom: FormCustom,
1602
+ Dialog: FormDialog,
1603
+ useFormContext,
1604
+ useFormState,
1605
+ useFieldContext,
1606
+ useField,
1607
+ useWatch,
1608
+ useWatchAll
1609
+ };
1610
+ //#endregion
1611
+ export { FormCheckbox as A, FormDialog as C, FormCustom as D, FormDatePicker as E, FormAutosearch as M, FormAutocomplete as N, FormCopyBox as O, FormError as S, FormDateTimePicker as T, FormRadioGroup as _, useField as a, FormFieldArray as b, useWatchAll as c, FormTextarea as d, FormSwitch as f, FormRoot as g, FormSelectItem as h, useFieldContext as i, FormButton as j, FormCombobox as k, FormTransfer as l, FormSelect as m, useFormState as n, FormWhen as o, FormSubmit as p, useFormContext as r, useWatch as s, Form as t, FormTimePicker as u, FormRadioItem as v, FormDescription as w, FormField as x, FormInput as y };