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

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