@datum-cloud/datum-ui 0.6.0-alpha.b817c77 → 0.6.0-alpha.b8a44ac

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 (126) hide show
  1. package/README.md +3 -0
  2. package/dist/combobox/index.mjs +2 -0
  3. package/dist/combobox-cKTFK4uN.mjs +96 -0
  4. package/dist/components/features/combobox/combobox.d.ts +27 -0
  5. package/dist/components/features/combobox/combobox.d.ts.map +1 -0
  6. package/dist/components/features/combobox/index.d.ts +3 -0
  7. package/dist/components/features/combobox/index.d.ts.map +1 -0
  8. package/dist/components/features/combobox/types.d.ts +78 -0
  9. package/dist/components/features/combobox/types.d.ts.map +1 -0
  10. package/dist/components/features/date-time-picker/date-time-picker.d.ts +9 -0
  11. package/dist/components/features/date-time-picker/date-time-picker.d.ts.map +1 -0
  12. package/dist/components/features/date-time-picker/index.d.ts +3 -0
  13. package/dist/components/features/date-time-picker/index.d.ts.map +1 -0
  14. package/dist/components/features/date-time-picker/types.d.ts +53 -0
  15. package/dist/components/features/date-time-picker/types.d.ts.map +1 -0
  16. package/dist/components/features/date-time-picker/utils/format.d.ts +13 -0
  17. package/dist/components/features/date-time-picker/utils/format.d.ts.map +1 -0
  18. package/dist/components/features/date-time-picker/utils/index.d.ts +3 -0
  19. package/dist/components/features/date-time-picker/utils/index.d.ts.map +1 -0
  20. package/dist/components/features/date-time-picker/utils/timezone.d.ts +23 -0
  21. package/dist/components/features/date-time-picker/utils/timezone.d.ts.map +1 -0
  22. package/dist/components/features/form/adapter-types.d.ts +20 -0
  23. package/dist/components/features/form/adapter-types.d.ts.map +1 -1
  24. package/dist/components/features/form/adapters/conform/conform-adapter.d.ts.map +1 -1
  25. package/dist/components/features/form/adapters/rhf/rhf-adapter.d.ts.map +1 -1
  26. package/dist/components/features/form/components/form-autosearch.d.ts +25 -0
  27. package/dist/components/features/form/components/form-autosearch.d.ts.map +1 -0
  28. package/dist/components/features/form/components/form-combobox.d.ts +76 -0
  29. package/dist/components/features/form/components/form-combobox.d.ts.map +1 -0
  30. package/dist/components/features/form/components/form-copy-box.d.ts +3 -0
  31. package/dist/components/features/form/components/form-copy-box.d.ts.map +1 -1
  32. package/dist/components/features/form/components/form-custom.d.ts.map +1 -1
  33. package/dist/components/features/form/components/form-date-picker.d.ts +38 -0
  34. package/dist/components/features/form/components/form-date-picker.d.ts.map +1 -0
  35. package/dist/components/features/form/components/form-date-time-picker.d.ts +37 -0
  36. package/dist/components/features/form/components/form-date-time-picker.d.ts.map +1 -0
  37. package/dist/components/features/form/components/form-dialog.d.ts.map +1 -1
  38. package/dist/components/features/form/components/form-radio-group.d.ts.map +1 -1
  39. package/dist/components/features/form/components/form-root.d.ts.map +1 -1
  40. package/dist/components/features/form/components/form-time-picker.d.ts +21 -0
  41. package/dist/components/features/form/components/form-time-picker.d.ts.map +1 -0
  42. package/dist/components/features/form/components/form-transfer.d.ts +37 -0
  43. package/dist/components/features/form/components/form-transfer.d.ts.map +1 -0
  44. package/dist/components/features/form/components/index.d.ts +7 -1
  45. package/dist/components/features/form/components/index.d.ts.map +1 -1
  46. package/dist/components/features/form/components/stepper/form-stepper.d.ts.map +1 -1
  47. package/dist/components/features/form/hooks/index.d.ts +1 -1
  48. package/dist/components/features/form/hooks/index.d.ts.map +1 -1
  49. package/dist/components/features/form/hooks/use-form-state.d.ts +36 -0
  50. package/dist/components/features/form/hooks/use-form-state.d.ts.map +1 -0
  51. package/dist/components/features/form/index.d.ts +39 -21
  52. package/dist/components/features/form/index.d.ts.map +1 -1
  53. package/dist/components/features/form/stepper/index.d.ts +17 -0
  54. package/dist/components/features/form/stepper/index.d.ts.map +1 -0
  55. package/dist/components/features/form/types/index.d.ts +36 -0
  56. package/dist/components/features/form/types/index.d.ts.map +1 -1
  57. package/dist/components/features/form/utils/get-field-constraints.d.ts +23 -1
  58. package/dist/components/features/form/utils/get-field-constraints.d.ts.map +1 -1
  59. package/dist/components/features/form/utils/get-schema-defaults.d.ts +24 -0
  60. package/dist/components/features/form/utils/get-schema-defaults.d.ts.map +1 -0
  61. package/dist/components/features/form/utils/zod-helpers.d.ts +12 -0
  62. package/dist/components/features/form/utils/zod-helpers.d.ts.map +1 -0
  63. package/dist/components/features/time-picker/index.d.ts +3 -0
  64. package/dist/components/features/time-picker/index.d.ts.map +1 -0
  65. package/dist/components/features/time-picker/time-picker.d.ts +22 -0
  66. package/dist/components/features/time-picker/time-picker.d.ts.map +1 -0
  67. package/dist/components/features/time-picker/types.d.ts +31 -0
  68. package/dist/components/features/time-picker/types.d.ts.map +1 -0
  69. package/dist/components/features/transfer/components/index.d.ts +9 -0
  70. package/dist/components/features/transfer/components/index.d.ts.map +1 -0
  71. package/dist/components/features/transfer/components/transfer-group.d.ts +7 -0
  72. package/dist/components/features/transfer/components/transfer-group.d.ts.map +1 -0
  73. package/dist/components/features/transfer/components/transfer-item.d.ts +10 -0
  74. package/dist/components/features/transfer/components/transfer-item.d.ts.map +1 -0
  75. package/dist/components/features/transfer/components/transfer-panel.d.ts +18 -0
  76. package/dist/components/features/transfer/components/transfer-panel.d.ts.map +1 -0
  77. package/dist/components/features/transfer/components/transfer-search.d.ts +9 -0
  78. package/dist/components/features/transfer/components/transfer-search.d.ts.map +1 -0
  79. package/dist/components/features/transfer/hooks/use-transfer-dnd.d.ts +26 -0
  80. package/dist/components/features/transfer/hooks/use-transfer-dnd.d.ts.map +1 -0
  81. package/dist/components/features/transfer/hooks/use-transfer-state.d.ts +20 -0
  82. package/dist/components/features/transfer/hooks/use-transfer-state.d.ts.map +1 -0
  83. package/dist/components/features/transfer/index.d.ts +3 -0
  84. package/dist/components/features/transfer/index.d.ts.map +1 -0
  85. package/dist/components/features/transfer/transfer.d.ts +6 -0
  86. package/dist/components/features/transfer/transfer.d.ts.map +1 -0
  87. package/dist/components/features/transfer/types.d.ts +69 -0
  88. package/dist/components/features/transfer/types.d.ts.map +1 -0
  89. package/dist/date-picker/index.mjs +1 -1
  90. package/dist/date-time-picker/index.mjs +2 -0
  91. package/dist/date-time-picker-Dy2jrJoN.mjs +175 -0
  92. package/dist/form/adapters/conform/index.mjs +102 -12
  93. package/dist/form/adapters/rhf/index.mjs +112 -26
  94. package/dist/form/index.mjs +3 -3
  95. package/dist/form/stepper/index.mjs +541 -0
  96. package/dist/form-context-Ccxm-wqL.mjs +17 -0
  97. package/dist/{form-BE1xBne4.mjs → form-mlNLKaB5.mjs} +350 -592
  98. package/dist/{get-field-constraints-BPMW8VvY.mjs → get-field-constraints-BicgDkfH.mjs} +19 -16
  99. package/dist/grid/index.mjs +1 -1
  100. package/dist/hooks/index.mjs +2 -2
  101. package/dist/index.mjs +14 -14
  102. package/dist/input-number/index.mjs +1 -1
  103. package/dist/map/index.mjs +1 -1
  104. package/dist/{map-Cw7u8r6E.mjs → map-CWIQ-eql.mjs} +1 -1
  105. package/dist/more-actions/index.mjs +1 -1
  106. package/dist/page-title/index.mjs +1 -1
  107. package/dist/stepper/index.mjs +1 -320
  108. package/dist/stepper-DvIOp0hh.mjs +321 -0
  109. package/dist/tag-input/index.mjs +1 -1
  110. package/dist/task-queue/index.mjs +1 -1
  111. package/dist/time-picker/index.mjs +2 -0
  112. package/dist/time-picker-BoF7pZZ2.mjs +43 -0
  113. package/dist/transfer/index.mjs +2 -0
  114. package/dist/transfer-B2n8pgEQ.mjs +260 -0
  115. package/package.json +37 -1
  116. /package/dist/{adapter-context-B7L2ucTr.mjs → adapter-context-rWveHhDd.mjs} +0 -0
  117. /package/dist/{col-YBbQ5wlb.mjs → col-1T0Q3SlH.mjs} +0 -0
  118. /package/dist/{hooks-DYjN7lvC.mjs → hooks-D8r2M2U6.mjs} +0 -0
  119. /package/dist/{input-number-DEjXG2I6.mjs → input-number-a7uydAsw.mjs} +0 -0
  120. /package/dist/{map-leaflet-imports-D6nTEOIh.mjs → map-leaflet-imports-CRSKA79m.mjs} +0 -0
  121. /package/dist/{more-actions-BNQ2yfWZ.mjs → more-actions-ILnEZq_E.mjs} +0 -0
  122. /package/dist/{page-title-CNiRNZ7p.mjs → page-title-ChsnpBiH.mjs} +0 -0
  123. /package/dist/{tag-input-BKed-cul.mjs → tag-input-T9cUX9-G.mjs} +0 -0
  124. /package/dist/{task-queue-dropdown-Di_Wjspz.mjs → task-queue-dropdown-Wcbj-f0V.mjs} +0 -0
  125. /package/dist/{to-api-format-Cq4prffn.mjs → to-api-format-Bh3c01gr.mjs} +0 -0
  126. /package/dist/{use-copy-to-clipboard-BGdTmkFV.mjs → use-copy-to-clipboard-uNeeVHC4.mjs} +0 -0
@@ -1,11 +1,17 @@
1
- import { t as FormAdapterProvider } from "../../../adapter-context-B7L2ucTr.mjs";
2
- import { t as getFieldConstraints } from "../../../get-field-constraints-BPMW8VvY.mjs";
1
+ import { t as FormAdapterProvider } from "../../../adapter-context-rWveHhDd.mjs";
2
+ import { t as getFieldConstraints } from "../../../get-field-constraints-BicgDkfH.mjs";
3
3
  import * as React$1 from "react";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  import { FormProvider, getFormProps, getInputProps, useForm, useFormMetadata, useInputControl } from "@conform-to/react";
6
+ import { isDirty, useFormData } from "@conform-to/react/future";
6
7
  import { getZodConstraint, parseWithZod } from "@conform-to/zod/v4";
7
8
  //#region src/components/features/form/adapters/conform/conform-adapter.tsx
8
9
  /**
10
+ * Shared context for the touched fields set.
11
+ * Created in useConformCreateForm and consumed by useConformField.
12
+ */
13
+ const TouchedFieldsContext = React$1.createContext({ current: /* @__PURE__ */ new Set() });
14
+ /**
9
15
  * Resolve a Conform field metadata object by dot-notation path.
10
16
  *
11
17
  * Handles:
@@ -35,13 +41,18 @@ function resolveConformField(fields, name) {
35
41
  function convertFromString(value) {
36
42
  if (value === void 0) return void 0;
37
43
  if (Array.isArray(value)) return value[0];
38
- if (value === "on" || value === "true") return true;
39
- if (value === "" || value === "false") return false;
44
+ if (value === "on") return true;
45
+ if (value.startsWith("[") && value.endsWith("]")) try {
46
+ return JSON.parse(value);
47
+ } catch {
48
+ return value;
49
+ }
40
50
  return value;
41
51
  }
42
52
  function convertToString(value) {
43
53
  if (typeof value === "boolean") return value ? "on" : "";
44
54
  if (value === null || value === void 0) return "";
55
+ if (Array.isArray(value)) return JSON.stringify(value);
45
56
  return String(value);
46
57
  }
47
58
  /** Create a Conform form instance and normalize it to the adapter interface. */
@@ -65,25 +76,84 @@ function useConformCreateForm(props) {
65
76
  } : void 0
66
77
  });
67
78
  const constraints = React$1.useMemo(() => getFieldConstraints(schema), [schema]);
79
+ const formIsDirty = useFormData(formRef, (formData) => isDirty(formData, { defaultValue: defaultValues }) ?? false) ?? false;
80
+ const dirtyFields = useFormData(formRef, (formData) => {
81
+ const result = {};
82
+ const defaults = defaultValues ?? {};
83
+ for (const key of Object.keys(defaults)) {
84
+ const current = formData.get(key);
85
+ const defaultVal = defaults[key];
86
+ result[key] = current !== (defaultVal === true ? "on" : defaultVal === false || defaultVal === null || defaultVal === void 0 ? "" : String(defaultVal));
87
+ }
88
+ for (const key of formData.keys()) if (!(key in result) && !key.startsWith("$")) {
89
+ const current = formData.get(key);
90
+ result[key] = current !== "" && current !== null;
91
+ }
92
+ const dirty = {};
93
+ for (const [key, value] of Object.entries(result)) if (value) dirty[key] = true;
94
+ return dirty;
95
+ }) ?? {};
96
+ const isValid = useFormData(formRef, (formData) => {
97
+ return parseWithZod(formData, { schema })?.status === "success";
98
+ }) ?? false;
99
+ const touchedFieldsRef = React$1.useRef(/* @__PURE__ */ new Set());
100
+ const [touchedFields, setTouchedFields] = React$1.useState({});
101
+ React$1.useEffect(() => {
102
+ const formEl = formRef?.current;
103
+ if (!formEl) return;
104
+ const handleFocusOut = (event) => {
105
+ const target = event.target;
106
+ if (target instanceof HTMLInputElement || target instanceof HTMLSelectElement || target instanceof HTMLTextAreaElement) {
107
+ const name = target.name;
108
+ if (name && !touchedFieldsRef.current.has(name)) {
109
+ touchedFieldsRef.current.add(name);
110
+ setTouchedFields((prev) => ({
111
+ ...prev,
112
+ [name]: true
113
+ }));
114
+ }
115
+ }
116
+ };
117
+ formEl.addEventListener("focusout", handleFocusOut);
118
+ return () => formEl.removeEventListener("focusout", handleFocusOut);
119
+ }, [formRef]);
120
+ const formState = React$1.useMemo(() => ({
121
+ isDirty: formIsDirty,
122
+ isValid,
123
+ isSubmitted: false,
124
+ submitCount: 0,
125
+ dirtyFields,
126
+ touchedFields
127
+ }), [
128
+ formIsDirty,
129
+ isValid,
130
+ dirtyFields,
131
+ touchedFields
132
+ ]);
68
133
  const normalizedFields = React$1.useMemo(() => {
69
134
  const result = {};
70
135
  for (const [key, fieldMeta] of Object.entries(fields)) result[key] = {
71
136
  id: fieldMeta.id ?? `${id ?? form.id}-${key}`,
72
137
  errors: fieldMeta.errors ?? [],
73
- required: constraints[key]?.required ?? false
138
+ required: constraints[key]?.required ?? false,
139
+ isDirty: dirtyFields[key] ?? false,
140
+ isTouched: touchedFields[key] ?? false
74
141
  };
75
142
  return result;
76
143
  }, [
77
144
  fields,
78
145
  id,
79
146
  form.id,
80
- constraints
147
+ constraints,
148
+ dirtyFields,
149
+ touchedFields
81
150
  ]);
82
151
  const conformFormProps = React$1.useMemo(() => getFormProps(form), [form]);
83
152
  return React$1.useMemo(() => ({
84
153
  id: form.id,
85
154
  fields: normalizedFields,
86
155
  formProps: conformFormProps,
156
+ formState,
87
157
  submit: () => formRef?.current?.requestSubmit(),
88
158
  reset: () => form.reset(),
89
159
  getValues: () => {
@@ -95,36 +165,51 @@ function useConformCreateForm(props) {
95
165
  },
96
166
  raw: {
97
167
  form,
98
- fields
168
+ fields,
169
+ touchedFieldsRef
99
170
  }
100
171
  }), [
101
172
  form,
102
173
  fields,
103
174
  normalizedFields,
104
175
  conformFormProps,
176
+ formState,
105
177
  formRef
106
178
  ]);
107
179
  }
108
180
  /** Resolve a field by dot-notation path and return its normalized state. */
109
181
  function useConformField(name) {
110
182
  const fieldMeta = resolveConformField(useFormMetadata().getFieldset(), name);
183
+ const touchedFieldsRef = React$1.use(TouchedFieldsContext);
111
184
  const control = useInputControl(fieldMeta ?? {
112
185
  name,
113
186
  key: void 0,
114
187
  id: name
115
188
  });
116
189
  if (!fieldMeta) throw new Error(`[Conform Adapter] Field "${name}" not found. Make sure the field name matches your schema.`);
190
+ const currentValue = convertFromString(control.value);
191
+ const defaultValue = convertFromString(fieldMeta.initialValue);
192
+ const fieldIsDirty = currentValue !== (defaultValue === void 0 ? "" : defaultValue);
193
+ const fieldIsTouched = touchedFieldsRef.current.has(name);
117
194
  return React$1.useMemo(() => ({
118
195
  name: fieldMeta.name,
119
196
  id: fieldMeta.id,
120
197
  errors: fieldMeta.errors ?? [],
121
198
  required: fieldMeta.required ?? false,
122
- value: convertFromString(control.value),
199
+ isDirty: fieldIsDirty,
200
+ isTouched: fieldIsTouched,
201
+ value: currentValue,
123
202
  change: (value) => control.change(convertToString(value)),
124
203
  blur: () => control.blur(),
125
204
  focus: () => control.focus(),
126
205
  inputProps: getInputProps(fieldMeta, { type: "text" })
127
- }), [fieldMeta, control]);
206
+ }), [
207
+ fieldMeta,
208
+ control,
209
+ currentValue,
210
+ fieldIsDirty,
211
+ fieldIsTouched
212
+ ]);
128
213
  }
129
214
  /** Watch a single field's value reactively. */
130
215
  function useConformWatch(name) {
@@ -135,6 +220,7 @@ function useConformWatch(name) {
135
220
  /** Watch multiple fields' values reactively. */
136
221
  function useConformWatchAll(names) {
137
222
  const allFields = useFormMetadata().getFieldset();
223
+ const namesKey = names.join(",");
138
224
  return React$1.useMemo(() => {
139
225
  const result = {};
140
226
  for (const name of names) {
@@ -142,7 +228,7 @@ function useConformWatchAll(names) {
142
228
  if (fieldMeta) result[name] = convertFromString(fieldMeta.value);
143
229
  }
144
230
  return result;
145
- }, [allFields, names]);
231
+ }, [allFields, namesKey]);
146
232
  }
147
233
  /** Get field array helpers for a given array field name. */
148
234
  function useConformFieldArray(name) {
@@ -186,12 +272,16 @@ function useConformFieldArray(name) {
186
272
  /**
187
273
  * Wraps children in Conform's FormProvider so that useFormMetadata() and
188
274
  * useInputControl() work inside field components.
275
+ * Also provides the touched fields ref via context for useConformField.
189
276
  */
190
277
  function ConformFormProviderWrapper({ instance, children }) {
191
- const { form } = instance.raw;
278
+ const { form, touchedFieldsRef } = instance.raw;
192
279
  return /* @__PURE__ */ jsx(FormProvider, {
193
280
  context: form.context,
194
- children
281
+ children: /* @__PURE__ */ jsx(TouchedFieldsContext, {
282
+ value: touchedFieldsRef,
283
+ children
284
+ })
195
285
  });
196
286
  }
197
287
  /**
@@ -1,41 +1,119 @@
1
- import { t as FormAdapterProvider } from "../../../adapter-context-B7L2ucTr.mjs";
2
- import { t as getFieldConstraints } from "../../../get-field-constraints-BPMW8VvY.mjs";
1
+ import { t as FormAdapterProvider } from "../../../adapter-context-rWveHhDd.mjs";
2
+ import { n as getObjectShape, t as getFieldConstraints } from "../../../get-field-constraints-BicgDkfH.mjs";
3
3
  import * as React$1 from "react";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  import { zodResolver } from "@hookform/resolvers/zod";
6
6
  import { FormProvider, useController, useFieldArray, useForm, useFormContext, useWatch } from "react-hook-form";
7
+ //#region src/components/features/form/utils/get-schema-defaults.ts
8
+ /**
9
+ * Derive default values from a Zod schema that match what React Hook Form's
10
+ * `useController` will produce when fields register.
11
+ *
12
+ * This is critical for RHF's `isDirty` tracking: RHF compares current values
13
+ * against `_defaultValues`. Without explicit defaults, RHF uses `{}` as the
14
+ * baseline, so when `useController` registers fields (e.g. `username: ''`),
15
+ * the form is immediately considered dirty.
16
+ *
17
+ * By passing these schema-derived defaults to `useForm({ defaultValues })`,
18
+ * the baseline matches the registered values and `isDirty` starts as `false`.
19
+ *
20
+ * Maps Zod field types to their `useController` registration values:
21
+ * - string -> `''`
22
+ * - number -> `undefined`
23
+ * - boolean -> `false`
24
+ * - array -> `[]`
25
+ * - object -> `{}` (recursive)
26
+ * - optional/nullable wrappers -> unwrap and derive inner default
27
+ * - `.default()` -> use the provided default value
28
+ */
29
+ function getSchemaDefaults(schema) {
30
+ const shape = getObjectShape(schema);
31
+ if (!shape) return {};
32
+ const defaults = {};
33
+ for (const [key, fieldSchema] of Object.entries(shape)) defaults[key] = getFieldDefault(fieldSchema);
34
+ return defaults;
35
+ }
36
+ /**
37
+ * Get the default value for a Zod field type that matches what RHF's
38
+ * `useController` will produce when registering the field.
39
+ *
40
+ * Unwraps optional/nullable/default wrappers to find the inner type,
41
+ * then returns the natural "empty" value for that type.
42
+ */
43
+ function getFieldDefault(schema) {
44
+ const { type } = schema.def;
45
+ if (type === "default") return schema.def.defaultValue;
46
+ if (type === "optional" || type === "nullable") {
47
+ const innerDef = schema.def;
48
+ return getFieldDefault(innerDef.innerType);
49
+ }
50
+ if (type === "pipe") {
51
+ const pipeDef = schema.def;
52
+ return getFieldDefault(pipeDef.in);
53
+ }
54
+ if (type === "string") return "";
55
+ if (type === "number" || type === "bigint" || type === "nan") return void 0;
56
+ if (type === "boolean") return false;
57
+ if (type === "array") return [];
58
+ if (type === "object") return getSchemaDefaults(schema);
59
+ }
60
+ //#endregion
7
61
  //#region src/components/features/form/adapters/rhf/rhf-adapter.tsx
62
+ const RHFFormIdContext = React$1.createContext("form");
8
63
  /** Create a React Hook Form instance and normalize it to the adapter interface. */
9
64
  function useRHFCreateForm(props) {
10
65
  const { schema, defaultValues, mode, id, onSubmit, formRef } = props;
66
+ const modeMap = {
67
+ onBlur: "onBlur",
68
+ onChange: "onChange",
69
+ onSubmit: "onSubmit"
70
+ };
71
+ const schemaDefaults = React$1.useMemo(() => getSchemaDefaults(schema), [schema]);
72
+ const mergedDefaults = React$1.useMemo(() => ({
73
+ ...schemaDefaults,
74
+ ...defaultValues
75
+ }), [schemaDefaults, defaultValues]);
11
76
  const form = useForm({
12
77
  resolver: zodResolver(schema),
13
- defaultValues,
14
- mode: {
15
- onBlur: "onBlur",
16
- onChange: "onChange",
17
- onSubmit: "onSubmit"
18
- }[mode]
78
+ defaultValues: mergedDefaults,
79
+ mode: modeMap[mode]
19
80
  });
81
+ const { errors, isDirty, isValid, dirtyFields, touchedFields } = form.formState;
20
82
  const constraints = React$1.useMemo(() => getFieldConstraints(schema), [schema]);
21
83
  const onSubmitRef = React$1.useRef(onSubmit);
22
84
  onSubmitRef.current = onSubmit;
23
85
  const normalizedFields = React$1.useMemo(() => {
24
86
  const result = {};
25
- const errors = form.formState.errors;
26
87
  for (const [key, constraint] of Object.entries(constraints)) {
27
88
  const fieldError = errors[key];
28
89
  result[key] = {
29
90
  id: `${id ?? "form"}-${key}`,
30
91
  errors: fieldError?.message ? [String(fieldError.message)] : [],
31
- required: constraint.required
92
+ required: constraint.required,
93
+ isDirty: Boolean(dirtyFields[key]),
94
+ isTouched: Boolean(touchedFields[key])
32
95
  };
33
96
  }
34
97
  return result;
35
98
  }, [
36
99
  constraints,
37
- form.formState.errors,
38
- id
100
+ errors,
101
+ id,
102
+ dirtyFields,
103
+ touchedFields
104
+ ]);
105
+ const formState = React$1.useMemo(() => ({
106
+ isDirty,
107
+ isValid,
108
+ isSubmitted: false,
109
+ submitCount: 0,
110
+ dirtyFields: Object.fromEntries(Object.entries(dirtyFields).map(([k, v]) => [k, Boolean(v)])),
111
+ touchedFields: Object.fromEntries(Object.entries(touchedFields).map(([k, v]) => [k, Boolean(v)]))
112
+ }), [
113
+ isDirty,
114
+ isValid,
115
+ dirtyFields,
116
+ touchedFields
39
117
  ]);
40
118
  const handleSubmit = React$1.useMemo(() => form.handleSubmit((data) => {
41
119
  onSubmitRef.current?.(data);
@@ -49,6 +127,7 @@ function useRHFCreateForm(props) {
49
127
  id: id ?? "form",
50
128
  fields: normalizedFields,
51
129
  formProps,
130
+ formState,
52
131
  submit: () => formRef?.current?.requestSubmit(),
53
132
  reset: () => form.reset(),
54
133
  getValues: () => form.getValues(),
@@ -57,29 +136,36 @@ function useRHFCreateForm(props) {
57
136
  id,
58
137
  normalizedFields,
59
138
  formProps,
139
+ formState,
60
140
  form,
61
141
  formRef
62
142
  ]);
63
143
  }
64
144
  /** Resolve a field by name and return its normalized state. */
65
145
  function useRHFField(name) {
146
+ const form = useFormContext();
147
+ const formId = React$1.use(RHFFormIdContext);
66
148
  const { field, fieldState } = useController({
67
149
  name,
68
- control: useFormContext().control
150
+ control: form.control
69
151
  });
70
152
  return React$1.useMemo(() => ({
71
153
  name: field.name,
72
- id: name,
154
+ id: `${formId}-${name}`,
73
155
  errors: fieldState.error?.message ? [String(fieldState.error.message)] : [],
74
156
  required: false,
157
+ isDirty: fieldState.isDirty,
158
+ isTouched: fieldState.isTouched,
75
159
  value: field.value,
76
160
  change: (value) => field.onChange(value),
77
161
  blur: () => field.onBlur(),
78
- focus: () => {}
162
+ focus: () => form.setFocus(name)
79
163
  }), [
80
164
  field,
81
165
  fieldState,
82
- name
166
+ name,
167
+ formId,
168
+ form
83
169
  ]);
84
170
  }
85
171
  /** Watch a single field's value reactively. */
@@ -95,13 +181,14 @@ function useRHFWatchAllHook(names) {
95
181
  name: names,
96
182
  control: useFormContext().control
97
183
  });
184
+ const namesKey = names.join(",");
98
185
  return React$1.useMemo(() => {
99
186
  const result = {};
100
187
  names.forEach((n, index) => {
101
188
  result[n] = values[index];
102
189
  });
103
190
  return result;
104
- }, [names, values]);
191
+ }, [namesKey, values]);
105
192
  }
106
193
  /** Get field array helpers for a given array field name. */
107
194
  function useRHFFieldArrayHook(name) {
@@ -118,12 +205,8 @@ function useRHFFieldArrayHook(name) {
118
205
  append: React$1.useCallback((defaultValue) => {
119
206
  append(defaultValue ?? {});
120
207
  }, [append]),
121
- remove: React$1.useCallback((index) => {
122
- remove(index);
123
- }, [remove]),
124
- move: React$1.useCallback((from, to) => {
125
- move(from, to);
126
- }, [move])
208
+ remove,
209
+ move
127
210
  };
128
211
  }
129
212
  /**
@@ -132,9 +215,12 @@ function useRHFFieldArrayHook(name) {
132
215
  */
133
216
  function RHFFormProviderWrapper({ instance, children }) {
134
217
  const form = instance.raw;
135
- return /* @__PURE__ */ jsx(FormProvider, {
136
- ...form,
137
- children
218
+ return /* @__PURE__ */ jsx(RHFFormIdContext, {
219
+ value: instance.id,
220
+ children: /* @__PURE__ */ jsx(FormProvider, {
221
+ ...form,
222
+ children
223
+ })
138
224
  });
139
225
  }
140
226
  /**
@@ -1,3 +1,3 @@
1
- import { A as FormButton, C as FormField, D as FormCustom, E as FormDescription, O as FormCopyBox, S as FormFieldArray, T as FormDialog, _ as FormSelectItem, a as useField, b as FormRadioItem, c as FormStep, d as useWatch, f as useWatchAll, g as FormSelect, h as FormSubmit, i as useFieldContext, j as FormAutocomplete, k as FormCheckbox, l as FormStepper, m as FormSwitch, n as useStepper, o as StepperNavigation, p as FormTextarea, r as useFormContext, s as StepperControls, t as Form, u as FormWhen, v as FormRoot, w as FormError, x as FormInput, y as FormRadioGroup } from "../form-BE1xBne4.mjs";
2
- import { n as useAdapter, t as FormAdapterProvider } from "../adapter-context-B7L2ucTr.mjs";
3
- export { Form, FormAdapterProvider, FormAutocomplete, FormButton, FormCheckbox, FormCopyBox, FormCustom, FormDescription, FormDialog, FormError, FormField, FormFieldArray, FormInput, FormRadioGroup, FormRadioItem, FormRoot, FormSelect, FormSelectItem, FormStep, FormStepper, FormSubmit, FormSwitch, FormTextarea, FormWhen, StepperControls, StepperNavigation, useAdapter, useField, useFieldContext, useFormContext, useStepper, useWatch, useWatchAll };
1
+ import { A as FormCheckbox, C as FormDialog, D as FormCustom, E as FormDatePicker, M as FormAutosearch, N as FormAutocomplete, O as FormCopyBox, S as FormError, T as FormDateTimePicker, _ as FormRadioGroup, a as useField, b as FormFieldArray, c as useWatchAll, d as FormTextarea, f as FormSwitch, g as FormRoot, h as FormSelectItem, i as useFieldContext, j as FormButton, k as FormCombobox, l as FormTransfer, m as FormSelect, n as useFormState, o as FormWhen, p as FormSubmit, r as useFormContext, s as useWatch, t as Form, u as FormTimePicker, v as FormRadioItem, w as FormDescription, x as FormField, y as FormInput } from "../form-mlNLKaB5.mjs";
2
+ import { n as useAdapter, t as FormAdapterProvider } from "../adapter-context-rWveHhDd.mjs";
3
+ export { Form, FormAdapterProvider, FormAutocomplete, FormAutosearch, FormButton, FormCheckbox, FormCombobox, FormCopyBox, FormCustom, FormDatePicker, FormDateTimePicker, FormDescription, FormDialog, FormError, FormField, FormFieldArray, FormInput, FormRadioGroup, FormRadioItem, FormRoot, FormSelect, FormSelectItem, FormSubmit, FormSwitch, FormTextarea, FormTimePicker, FormTransfer, FormWhen, useAdapter, useField, useFieldContext, useFormContext, useFormState, useWatch, useWatchAll };