@axenstudio/axen-form 0.1.17 → 0.1.19

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 (132) hide show
  1. package/README.md +34 -3
  2. package/dist/adapters/yupAdapter.cjs +29 -10
  3. package/dist/adapters/yupAdapter.d.ts +1 -2
  4. package/dist/adapters/yupAdapter.js +29 -10
  5. package/dist/adapters/zodAdapter.cjs +29 -10
  6. package/dist/adapters/zodAdapter.d.ts +1 -2
  7. package/dist/adapters/zodAdapter.js +29 -10
  8. package/dist/core/dateUtils.d.ts +0 -1
  9. package/dist/core/formStore.cjs +214 -47
  10. package/dist/core/formStore.d.ts +5 -2
  11. package/dist/core/formStore.js +214 -47
  12. package/dist/core/numberUtils.d.ts +0 -1
  13. package/dist/core/pathUtils.d.ts +0 -1
  14. package/dist/core/payloadUtils.d.ts +0 -1
  15. package/dist/core/semanticValidation.cjs +82 -0
  16. package/dist/core/semanticValidation.d.ts +5 -0
  17. package/dist/core/semanticValidation.js +82 -0
  18. package/dist/core/validation.cjs +4 -3
  19. package/dist/core/validation.d.ts +0 -1
  20. package/dist/core/validation.js +4 -3
  21. package/dist/fields/AutocompleteField/AutocompleteField.d.ts +1 -2
  22. package/dist/fields/AutocompleteMultiField/AutocompleteMultiField.d.ts +1 -2
  23. package/dist/fields/AutocompletePredictField/AutocompletePredictField.d.ts +1 -2
  24. package/dist/fields/CheckboxField/CheckboxField.d.ts +1 -2
  25. package/dist/fields/ColorField/ColorField.d.ts +1 -2
  26. package/dist/fields/CurrencyField/CurrencyField.d.ts +1 -2
  27. package/dist/fields/DateField/DateField.d.ts +1 -2
  28. package/dist/fields/DateField/DatePicker.d.ts +1 -2
  29. package/dist/fields/DateTimeField/DateTimeField.d.ts +1 -2
  30. package/dist/fields/EmailField/EmailField.d.ts +1 -2
  31. package/dist/fields/NumberField/NumberField.d.ts +1 -2
  32. package/dist/fields/PasswordField/PasswordField.d.ts +1 -2
  33. package/dist/fields/PhoneField/PhoneField.d.ts +1 -2
  34. package/dist/fields/RadioField/RadioField.d.ts +1 -2
  35. package/dist/fields/SelectField/SelectField.d.ts +1 -2
  36. package/dist/fields/SliderField/SliderField.d.ts +1 -2
  37. package/dist/fields/SwitchField/SwitchField.d.ts +1 -2
  38. package/dist/fields/TextField/TextField.d.ts +1 -2
  39. package/dist/fields/TextareaField/TextareaField.d.ts +1 -2
  40. package/dist/fields/TimeField/TimeField.d.ts +1 -2
  41. package/dist/fields/TimeField/TimePicker.d.ts +1 -2
  42. package/dist/fields/defaultComponentMap.cjs +3 -0
  43. package/dist/fields/defaultComponentMap.d.ts +0 -1
  44. package/dist/fields/defaultComponentMap.js +3 -0
  45. package/dist/fields/defaultPlaceholders.d.ts +0 -1
  46. package/dist/fields/fieldBase.module.css.cjs +92 -70
  47. package/dist/fields/fieldBase.module.css.js +92 -70
  48. package/dist/fields/fieldUtils.d.ts +0 -1
  49. package/dist/fields/iconUtils.d.ts +0 -1
  50. package/dist/fields/icons.d.ts +3 -4
  51. package/dist/index.cjs +31 -22
  52. package/dist/index.d.ts +3 -2
  53. package/dist/index.js +32 -23
  54. package/dist/layout/Box/Box.d.ts +1 -2
  55. package/dist/layout/Divider/Divider.d.ts +1 -2
  56. package/dist/layout/Grid/Grid.d.ts +1 -2
  57. package/dist/layout/Spacer/Spacer.d.ts +1 -2
  58. package/dist/layout/Stack/Stack.d.ts +1 -2
  59. package/dist/layout/index.d.ts +0 -1
  60. package/dist/react/AxenArrayField.cjs +2 -0
  61. package/dist/react/AxenArrayField.d.ts +1 -2
  62. package/dist/react/AxenArrayField.js +2 -0
  63. package/dist/react/AxenField.cjs +2 -0
  64. package/dist/react/AxenField.d.ts +1 -2
  65. package/dist/react/AxenField.js +2 -0
  66. package/dist/react/AxenForm.cjs +29 -23
  67. package/dist/react/AxenForm.d.ts +0 -1
  68. package/dist/react/AxenForm.js +30 -24
  69. package/dist/react/FormContext.d.ts +0 -1
  70. package/dist/react/useAxenForm.cjs +17 -4
  71. package/dist/react/useAxenForm.d.ts +1 -2
  72. package/dist/react/useAxenForm.js +17 -4
  73. package/dist/react/useField.cjs +3 -0
  74. package/dist/react/useField.d.ts +0 -1
  75. package/dist/react/useField.js +3 -0
  76. package/dist/react/useFieldArray.cjs +19 -13
  77. package/dist/react/useFieldArray.d.ts +0 -1
  78. package/dist/react/useFieldArray.js +19 -13
  79. package/dist/react/useFormState.cjs +18 -0
  80. package/dist/react/useFormState.d.ts +5 -0
  81. package/dist/react/useFormState.js +18 -0
  82. package/dist/types.d.ts +28 -3
  83. package/package.json +5 -2
  84. package/dist/adapters/yupAdapter.d.ts.map +0 -1
  85. package/dist/adapters/zodAdapter.d.ts.map +0 -1
  86. package/dist/core/dateUtils.d.ts.map +0 -1
  87. package/dist/core/formStore.d.ts.map +0 -1
  88. package/dist/core/numberUtils.d.ts.map +0 -1
  89. package/dist/core/pathUtils.d.ts.map +0 -1
  90. package/dist/core/payloadUtils.d.ts.map +0 -1
  91. package/dist/core/validation.d.ts.map +0 -1
  92. package/dist/fields/AutocompleteField/AutocompleteField.d.ts.map +0 -1
  93. package/dist/fields/AutocompleteMultiField/AutocompleteMultiField.d.ts.map +0 -1
  94. package/dist/fields/AutocompletePredictField/AutocompletePredictField.d.ts.map +0 -1
  95. package/dist/fields/CheckboxField/CheckboxField.d.ts.map +0 -1
  96. package/dist/fields/ColorField/ColorField.d.ts.map +0 -1
  97. package/dist/fields/CurrencyField/CurrencyField.d.ts.map +0 -1
  98. package/dist/fields/DateField/DateField.d.ts.map +0 -1
  99. package/dist/fields/DateField/DatePicker.d.ts.map +0 -1
  100. package/dist/fields/DateTimeField/DateTimeField.d.ts.map +0 -1
  101. package/dist/fields/EmailField/EmailField.d.ts.map +0 -1
  102. package/dist/fields/NumberField/NumberField.d.ts.map +0 -1
  103. package/dist/fields/PasswordField/PasswordField.d.ts.map +0 -1
  104. package/dist/fields/PhoneField/PhoneField.d.ts.map +0 -1
  105. package/dist/fields/RadioField/RadioField.d.ts.map +0 -1
  106. package/dist/fields/SelectField/SelectField.d.ts.map +0 -1
  107. package/dist/fields/SliderField/SliderField.d.ts.map +0 -1
  108. package/dist/fields/SwitchField/SwitchField.d.ts.map +0 -1
  109. package/dist/fields/TextField/TextField.d.ts.map +0 -1
  110. package/dist/fields/TextareaField/TextareaField.d.ts.map +0 -1
  111. package/dist/fields/TimeField/TimeField.d.ts.map +0 -1
  112. package/dist/fields/TimeField/TimePicker.d.ts.map +0 -1
  113. package/dist/fields/defaultComponentMap.d.ts.map +0 -1
  114. package/dist/fields/defaultPlaceholders.d.ts.map +0 -1
  115. package/dist/fields/fieldUtils.d.ts.map +0 -1
  116. package/dist/fields/iconUtils.d.ts.map +0 -1
  117. package/dist/fields/icons.d.ts.map +0 -1
  118. package/dist/index.d.ts.map +0 -1
  119. package/dist/layout/Box/Box.d.ts.map +0 -1
  120. package/dist/layout/Divider/Divider.d.ts.map +0 -1
  121. package/dist/layout/Grid/Grid.d.ts.map +0 -1
  122. package/dist/layout/Spacer/Spacer.d.ts.map +0 -1
  123. package/dist/layout/Stack/Stack.d.ts.map +0 -1
  124. package/dist/layout/index.d.ts.map +0 -1
  125. package/dist/react/AxenArrayField.d.ts.map +0 -1
  126. package/dist/react/AxenField.d.ts.map +0 -1
  127. package/dist/react/AxenForm.d.ts.map +0 -1
  128. package/dist/react/FormContext.d.ts.map +0 -1
  129. package/dist/react/useAxenForm.d.ts.map +0 -1
  130. package/dist/react/useField.d.ts.map +0 -1
  131. package/dist/react/useFieldArray.d.ts.map +0 -1
  132. package/dist/types.d.ts.map +0 -1
@@ -1,4 +1,15 @@
1
1
  import { get, set } from "./pathUtils.js";
2
+ function valuesEqual(a, b) {
3
+ if (Object.is(a, b)) return true;
4
+ if (a instanceof Date || b instanceof Date) return a instanceof Date && b instanceof Date && a.getTime() === b.getTime();
5
+ if (a === null || b === null || typeof a !== "object" || typeof b !== "object") return false;
6
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
7
+ const left = a;
8
+ const right = b;
9
+ const keys = Object.keys(left);
10
+ if (keys.length !== Object.keys(right).length) return false;
11
+ return keys.every((key) => Object.prototype.hasOwnProperty.call(right, key) && valuesEqual(left[key], right[key]));
12
+ }
2
13
  function createFormStore(options) {
3
14
  const {
4
15
  initialValues,
@@ -10,6 +21,9 @@ function createFormStore(options) {
10
21
  values: structuredClone(initialValues),
11
22
  errors: {},
12
23
  touched: {},
24
+ validationStatus: "unvalidated",
25
+ fieldValidationStatus: {},
26
+ isValidating: false,
13
27
  dirty: false,
14
28
  isSubmitting: false,
15
29
  submitCount: 0,
@@ -18,6 +32,9 @@ function createFormStore(options) {
18
32
  const subscribers = /* @__PURE__ */ new Set();
19
33
  const fieldSubscribers = /* @__PURE__ */ new Map();
20
34
  let validationSchema = options.validationSchema;
35
+ let valuesRevision = 0;
36
+ let formRequest = 0;
37
+ const fieldRequests = /* @__PURE__ */ new Map();
21
38
  if (validationAdapter && options.fields && !validationSchema) {
22
39
  validationSchema = validationAdapter.buildSchema(options.fields);
23
40
  }
@@ -46,16 +63,53 @@ function createFormStore(options) {
46
63
  var _a;
47
64
  (_a = fieldSubscribers.get(name)) == null ? void 0 : _a.forEach((fn) => fn());
48
65
  }
66
+ function notifyAllFields() {
67
+ for (const name of fieldSubscribers.keys()) notifyField(name);
68
+ notify();
69
+ }
70
+ function notifyValuePath(path) {
71
+ const related = (key) => key === path || key.startsWith(`${path}.`) || key.startsWith(`${path}[`) || path.startsWith(`${key}.`) || path.startsWith(`${key}[`);
72
+ for (const key of fieldSubscribers.keys()) if (related(key)) notifyField(key);
73
+ notify();
74
+ }
49
75
  function setFieldValue(name, value) {
76
+ const nextValues = set(state.values, name, value);
77
+ const statuses = { ...state.fieldValidationStatus, [name]: "unvalidated" };
78
+ const dependents = (options.fields ?? []).filter((field) => {
79
+ var _a;
80
+ return field.name !== name && ((_a = field.rules) == null ? void 0 : _a.countryField) === name;
81
+ });
82
+ const errors = { ...state.errors };
83
+ for (const field of dependents) {
84
+ statuses[field.name] = "unvalidated";
85
+ delete errors[field.name];
86
+ }
87
+ valuesRevision += 1;
50
88
  state = {
51
89
  ...state,
52
- values: set(state.values, name, value),
53
- dirty: true
90
+ values: nextValues,
91
+ errors,
92
+ dirty: !valuesEqual(nextValues, state.initialValues),
93
+ validationStatus: "unvalidated",
94
+ isValidating: false,
95
+ fieldValidationStatus: statuses
54
96
  };
55
- notifyField(name);
56
- notify();
97
+ for (const field of options.fields ?? []) {
98
+ if (field.hidden && state.errors[field.name] && (typeof field.hidden === "function" ? field.hidden(nextValues) : field.hidden)) {
99
+ setFieldError(field.name, void 0);
100
+ }
101
+ }
102
+ notifyValuePath(name);
103
+ for (const field of dependents) notifyField(field.name);
57
104
  if (validateOnChange && validationAdapter && validationSchema) {
58
- runFieldValidation(name);
105
+ const revision = valuesRevision;
106
+ for (const fieldName of [name, ...dependents.map((field) => field.name)]) {
107
+ void runFieldValidation(fieldName).catch((error) => {
108
+ if (revision === valuesRevision) {
109
+ setFieldError(fieldName, error instanceof Error ? error.message : "Validation failed");
110
+ }
111
+ });
112
+ }
59
113
  }
60
114
  }
61
115
  function setFieldTouched(name, touched = true) {
@@ -66,28 +120,84 @@ function createFormStore(options) {
66
120
  notifyField(name);
67
121
  notify();
68
122
  if (validateOnBlur && touched && validationAdapter && validationSchema) {
69
- runFieldValidation(name);
123
+ const revision = valuesRevision;
124
+ void runFieldValidation(name).catch((error) => {
125
+ if (revision === valuesRevision) setFieldError(name, error instanceof Error ? error.message : "Validation failed");
126
+ });
70
127
  }
71
128
  }
72
129
  function setFieldError(name, error) {
73
- const next = { ...state.errors };
74
- if (error) {
75
- next[name] = error;
76
- } else {
77
- delete next[name];
78
- }
79
- state = { ...state, errors: next };
130
+ const errors = { ...state.errors };
131
+ if (error) errors[name] = error;
132
+ else delete errors[name];
133
+ state = {
134
+ ...state,
135
+ errors,
136
+ validationStatus: Object.keys(errors).length ? "invalid" : "unvalidated",
137
+ isValidating: false,
138
+ fieldValidationStatus: { ...state.fieldValidationStatus, [name]: error ? "invalid" : "unvalidated" }
139
+ };
80
140
  notifyField(name);
81
141
  notify();
82
142
  }
83
143
  function setValues(values) {
84
- state = { ...state, values, dirty: true };
85
- notify();
86
- subscribers.forEach((fn) => fn());
144
+ valuesRevision += 1;
145
+ state = {
146
+ ...state,
147
+ values,
148
+ dirty: !valuesEqual(values, state.initialValues),
149
+ validationStatus: "unvalidated",
150
+ isValidating: false,
151
+ fieldValidationStatus: {}
152
+ };
153
+ notifyAllFields();
87
154
  }
88
155
  function setErrors(errors) {
89
- state = { ...state, errors };
90
- notify();
156
+ state = {
157
+ ...state,
158
+ errors,
159
+ validationStatus: Object.keys(errors).length ? "invalid" : "unvalidated",
160
+ isValidating: false,
161
+ fieldValidationStatus: {}
162
+ };
163
+ notifyAllFields();
164
+ }
165
+ function setFieldArrayValue(name, items, origins) {
166
+ const remap = (entries) => {
167
+ const result = {};
168
+ for (const [path, value] of Object.entries(entries)) {
169
+ if (!path.startsWith(name)) {
170
+ result[path] = value;
171
+ continue;
172
+ }
173
+ const suffix = path.slice(name.length);
174
+ const match = /^(?:\.(\d+)|\[(\d+)\])(?=\.|\[|$)/.exec(suffix);
175
+ if (!match) {
176
+ result[path] = value;
177
+ continue;
178
+ }
179
+ const oldIndex = Number(match[1] ?? match[2]);
180
+ const tail = suffix.slice(match[0].length);
181
+ for (let i = 0; i < origins.length; i++) {
182
+ if (origins[i] !== oldIndex) continue;
183
+ result[`${name}${match[1] !== void 0 ? `.${i}` : `[${i}]`}${tail}`] = value;
184
+ }
185
+ }
186
+ return result;
187
+ };
188
+ const values = set(state.values, name, items);
189
+ valuesRevision += 1;
190
+ state = {
191
+ ...state,
192
+ values,
193
+ dirty: !valuesEqual(values, state.initialValues),
194
+ errors: remap(state.errors),
195
+ touched: remap(state.touched),
196
+ validationStatus: "unvalidated",
197
+ isValidating: false,
198
+ fieldValidationStatus: remap(state.fieldValidationStatus)
199
+ };
200
+ notifyValuePath(name);
91
201
  }
92
202
  function resetForm(nextValues) {
93
203
  const newValues = nextValues ? { ...state.initialValues, ...nextValues } : structuredClone(state.initialValues);
@@ -95,29 +205,94 @@ function createFormStore(options) {
95
205
  values: newValues,
96
206
  errors: {},
97
207
  touched: {},
208
+ validationStatus: "unvalidated",
209
+ fieldValidationStatus: {},
210
+ isValidating: false,
98
211
  dirty: false,
99
212
  isSubmitting: false,
100
213
  submitCount: state.submitCount,
101
- initialValues: state.initialValues
214
+ initialValues: nextValues ? structuredClone(newValues) : state.initialValues
102
215
  };
103
- notify();
216
+ valuesRevision += 1;
217
+ notifyAllFields();
104
218
  }
105
219
  async function validateForm() {
106
220
  if (!validationAdapter || !validationSchema) return {};
107
- const errors = await validationAdapter.validate(validationSchema, state.values);
108
- state = { ...state, errors };
221
+ const revision = valuesRevision;
222
+ const request = ++formRequest;
223
+ state = { ...state, validationStatus: "validating", isValidating: true };
109
224
  notify();
110
- for (const name of fieldSubscribers.keys()) {
111
- notifyField(name);
225
+ try {
226
+ const errors = await validationAdapter.validate(validationSchema, state.values);
227
+ if (revision !== valuesRevision || request !== formRequest) return state.errors;
228
+ const statuses = { ...state.fieldValidationStatus };
229
+ for (const field of options.fields ?? []) statuses[field.name] = errors[field.name] ? "invalid" : "valid";
230
+ state = {
231
+ ...state,
232
+ errors,
233
+ validationStatus: Object.keys(errors).length ? "invalid" : "valid",
234
+ isValidating: false,
235
+ fieldValidationStatus: statuses
236
+ };
237
+ notify();
238
+ for (const name of fieldSubscribers.keys()) notifyField(name);
239
+ return errors;
240
+ } catch (error) {
241
+ if (revision === valuesRevision && request === formRequest) {
242
+ state = { ...state, validationStatus: "unvalidated", isValidating: false };
243
+ notify();
244
+ }
245
+ throw error;
112
246
  }
113
- return errors;
114
247
  }
115
248
  async function validateField(name) {
249
+ var _a;
116
250
  if (!(validationAdapter == null ? void 0 : validationAdapter.validateField) || !validationSchema) return void 0;
251
+ const revision = valuesRevision;
252
+ const request = (fieldRequests.get(name) ?? 0) + 1;
253
+ fieldRequests.set(name, request);
254
+ const config = (_a = options.fields) == null ? void 0 : _a.find((field) => field.name === name);
255
+ const hidden = (config == null ? void 0 : config.hidden) && (typeof config.hidden === "function" ? config.hidden(state.values) : config.hidden);
256
+ if (hidden) {
257
+ setFieldError(name, void 0);
258
+ state = { ...state, fieldValidationStatus: { ...state.fieldValidationStatus, [name]: "valid" } };
259
+ notifyField(name);
260
+ notify();
261
+ return void 0;
262
+ }
263
+ state = {
264
+ ...state,
265
+ fieldValidationStatus: { ...state.fieldValidationStatus, [name]: "validating" },
266
+ validationStatus: state.validationStatus === "validating" ? "validating" : "unvalidated"
267
+ };
268
+ notifyField(name);
269
+ notify();
117
270
  const fieldValue = get(state.values, name);
118
- const error = await validationAdapter.validateField(validationSchema, name, fieldValue);
119
- setFieldError(name, error);
120
- return error;
271
+ try {
272
+ const error = await validationAdapter.validateField(validationSchema, name, fieldValue, state.values);
273
+ if (revision === valuesRevision && request === fieldRequests.get(name)) {
274
+ const errors = { ...state.errors };
275
+ if (error) errors[name] = error;
276
+ else delete errors[name];
277
+ state = {
278
+ ...state,
279
+ errors,
280
+ validationStatus: state.validationStatus === "validating" ? "validating" : Object.keys(errors).length ? "invalid" : "unvalidated",
281
+ fieldValidationStatus: { ...state.fieldValidationStatus, [name]: error ? "invalid" : "valid" }
282
+ };
283
+ notifyField(name);
284
+ notify();
285
+ return error;
286
+ }
287
+ return state.errors[name];
288
+ } catch (error) {
289
+ if (revision === valuesRevision && request === fieldRequests.get(name)) {
290
+ state = { ...state, fieldValidationStatus: { ...state.fieldValidationStatus, [name]: "unvalidated" } };
291
+ notifyField(name);
292
+ notify();
293
+ }
294
+ throw error;
295
+ }
121
296
  }
122
297
  async function runFieldValidation(name) {
123
298
  if (validationAdapter == null ? void 0 : validationAdapter.validateField) {
@@ -127,27 +302,18 @@ function createFormStore(options) {
127
302
  }
128
303
  }
129
304
  async function submitForm(onSubmit) {
305
+ if (state.isSubmitting) return;
130
306
  state = { ...state, isSubmitting: true, submitCount: state.submitCount + 1 };
131
307
  notify();
132
- touchAllFields();
133
- const errors = await validateForm();
134
- for (const name of Object.keys(state.touched)) {
135
- notifyField(name);
136
- }
137
- if (Object.keys(errors).length > 0) {
138
- state = { ...state, isSubmitting: false };
139
- notify();
140
- return;
141
- }
142
- const handler = onSubmit ?? options.onSubmit;
143
- if (handler) {
144
- try {
145
- await handler(state.values);
146
- } finally {
147
- state = { ...state, isSubmitting: false };
148
- notify();
149
- }
150
- } else {
308
+ try {
309
+ touchAllFields();
310
+ const revision = valuesRevision;
311
+ const errors = await validateForm();
312
+ for (const name of Object.keys(state.touched)) notifyField(name);
313
+ if (revision !== valuesRevision || Object.keys(errors).length > 0) return;
314
+ const handler = onSubmit ?? options.onSubmit;
315
+ if (handler) await handler(state.values);
316
+ } finally {
151
317
  state = { ...state, isSubmitting: false };
152
318
  notify();
153
319
  }
@@ -186,6 +352,7 @@ function createFormStore(options) {
186
352
  setFieldError,
187
353
  setValues,
188
354
  setErrors,
355
+ setFieldArrayValue,
189
356
  resetForm,
190
357
  validateForm,
191
358
  validateField,
@@ -23,4 +23,3 @@ export declare function getGroupSeparator(locale?: string): string;
23
23
  * then finds the same position in the formatted string.
24
24
  */
25
25
  export declare function calculateCursorPosition(rawValue: string, formattedValue: string, cursorPos: number, locale?: string): number;
26
- //# sourceMappingURL=numberUtils.d.ts.map
@@ -12,4 +12,3 @@ export declare function set<T extends Record<string, unknown>>(obj: T, path: str
12
12
  export declare function toPathArray(path: string): string[];
13
13
  /** Convert path segments back to dot-path string */
14
14
  export declare function pathToString(segments: string[]): string;
15
- //# sourceMappingURL=pathUtils.d.ts.map
@@ -19,4 +19,3 @@ export declare function pickFields<T extends Record<string, unknown>>(values: T,
19
19
  * Useful for debugging / UI display.
20
20
  */
21
21
  export declare function getStrippedFields<T extends Record<string, unknown>>(values: T, fieldMap: string[] | Record<string, string[]>, discriminatorKey?: string): string[];
22
- //# sourceMappingURL=payloadUtils.d.ts.map
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const pathUtils = require("./pathUtils.cjs");
4
+ function isHidden(field, values) {
5
+ return typeof field.hidden === "function" ? Boolean(field.hidden(values)) : Boolean(field.hidden);
6
+ }
7
+ function validateSemanticValue(field, value, policy, values = {}) {
8
+ var _a, _b;
9
+ if (field.validation) return void 0;
10
+ const rules = field.rules;
11
+ const inferred = field.type === "tel" ? "phone" : field.type;
12
+ const format = (rules == null ? void 0 : rules.format) ?? ((policy == null ? void 0 : policy.mode) === "standard" && (inferred === "email" || inferred === "phone" || inferred === "url") ? inferred : void 0);
13
+ if (!format || value === void 0 || value === null || value === "") return void 0;
14
+ if (typeof value !== "string") return (rules == null ? void 0 : rules.message) ?? "Invalid value";
15
+ const input = value.trim();
16
+ if (!input) return void 0;
17
+ let valid = true;
18
+ if (format === "email") {
19
+ valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/u.test(input) && input.length <= 254;
20
+ } else if (format === "url") {
21
+ try {
22
+ const parsed = new URL(input);
23
+ valid = (parsed.protocol === "http:" || parsed.protocol === "https:") && Boolean(parsed.hostname);
24
+ } catch {
25
+ valid = false;
26
+ }
27
+ } else if (format === "phone") {
28
+ const clean = input.replace(/[().\s-]/g, "");
29
+ const region = ((rules == null ? void 0 : rules.region) ?? "").toUpperCase();
30
+ valid = region === "ID" ? /^(?:\+62|62|0)8\d{7,11}$/u.test(clean) : /^\+[1-9]\d{7,14}$/u.test(clean);
31
+ } else if (format === "postalCode") {
32
+ const resolved = ((_a = rules == null ? void 0 : rules.countryResolver) == null ? void 0 : _a.call(rules, values)) ?? ((rules == null ? void 0 : rules.countryField) ? pathUtils.get(values, rules.countryField) : void 0) ?? (rules == null ? void 0 : rules.country);
33
+ const country = typeof resolved === "string" ? resolved.trim().toUpperCase() : "";
34
+ if (!country && ((rules == null ? void 0 : rules.countryField) || (rules == null ? void 0 : rules.countryResolver))) return void 0;
35
+ const patterns = {
36
+ ID: /^\d{5}$/u,
37
+ US: /^\d{5}(?:-\d{4})?$/u,
38
+ SG: /^\d{6}$/u,
39
+ JP: /^\d{3}-?\d{4}$/u,
40
+ GB: /^(?:GIR\s?0AA|[A-Z]{1,2}\d[A-Z\d]?\s?\d[A-Z]{2})$/iu,
41
+ UK: /^(?:GIR\s?0AA|[A-Z]{1,2}\d[A-Z\d]?\s?\d[A-Z]{2})$/iu
42
+ };
43
+ const validator = ((_b = policy == null ? void 0 : policy.postalCodePatterns) == null ? void 0 : _b[country]) ?? patterns[country];
44
+ if (!validator) valid = (policy == null ? void 0 : policy.unknownCountry) === "ignore";
45
+ else if (validator instanceof RegExp) {
46
+ validator.lastIndex = 0;
47
+ valid = validator.test(input);
48
+ } else valid = Boolean(validator(input, values));
49
+ }
50
+ return valid ? void 0 : (rules == null ? void 0 : rules.message) ?? `Invalid ${format}`;
51
+ }
52
+ function withValidationPolicy(adapter, policy) {
53
+ return {
54
+ buildSchema(fields) {
55
+ return { base: adapter.buildSchema(fields), fields };
56
+ },
57
+ async validate(schema, values) {
58
+ const { base, fields } = schema;
59
+ const errors = { ...await adapter.validate(base, values) };
60
+ for (const field of fields) {
61
+ if (isHidden(field, values)) {
62
+ delete errors[field.name];
63
+ } else if (!errors[field.name]) {
64
+ const error = validateSemanticValue(field, pathUtils.get(values, field.name), policy, values);
65
+ if (error) errors[field.name] = error;
66
+ }
67
+ }
68
+ return errors;
69
+ },
70
+ async validateField(schema, name, value, values) {
71
+ var _a;
72
+ const { base, fields } = schema;
73
+ const context = values ?? { [name]: value };
74
+ const field = fields.find((f) => f.name === name) ?? { name, type: "text" };
75
+ if (isHidden(field, context)) return void 0;
76
+ const error = await ((_a = adapter.validateField) == null ? void 0 : _a.call(adapter, base, name, value, context));
77
+ return error ?? validateSemanticValue(field, value, policy, context);
78
+ }
79
+ };
80
+ }
81
+ exports.validateSemanticValue = validateSemanticValue;
82
+ exports.withValidationPolicy = withValidationPolicy;
@@ -0,0 +1,5 @@
1
+ import { FieldConfig, ValidationAdapter, ValidationPolicy } from '../types';
2
+ /** Optional semantics: custom Yup/Zod field schemas retain precedence. */
3
+ export declare function validateSemanticValue(field: FieldConfig, value: unknown, policy?: ValidationPolicy, values?: Record<string, unknown>): string | undefined;
4
+ /** Adapter-independent policy wrapper. No mandatory Yup, Zod, or UI dependencies. */
5
+ export declare function withValidationPolicy(adapter: ValidationAdapter, policy?: ValidationPolicy): ValidationAdapter;
@@ -0,0 +1,82 @@
1
+ import { get } from "./pathUtils.js";
2
+ function isHidden(field, values) {
3
+ return typeof field.hidden === "function" ? Boolean(field.hidden(values)) : Boolean(field.hidden);
4
+ }
5
+ function validateSemanticValue(field, value, policy, values = {}) {
6
+ var _a, _b;
7
+ if (field.validation) return void 0;
8
+ const rules = field.rules;
9
+ const inferred = field.type === "tel" ? "phone" : field.type;
10
+ const format = (rules == null ? void 0 : rules.format) ?? ((policy == null ? void 0 : policy.mode) === "standard" && (inferred === "email" || inferred === "phone" || inferred === "url") ? inferred : void 0);
11
+ if (!format || value === void 0 || value === null || value === "") return void 0;
12
+ if (typeof value !== "string") return (rules == null ? void 0 : rules.message) ?? "Invalid value";
13
+ const input = value.trim();
14
+ if (!input) return void 0;
15
+ let valid = true;
16
+ if (format === "email") {
17
+ valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/u.test(input) && input.length <= 254;
18
+ } else if (format === "url") {
19
+ try {
20
+ const parsed = new URL(input);
21
+ valid = (parsed.protocol === "http:" || parsed.protocol === "https:") && Boolean(parsed.hostname);
22
+ } catch {
23
+ valid = false;
24
+ }
25
+ } else if (format === "phone") {
26
+ const clean = input.replace(/[().\s-]/g, "");
27
+ const region = ((rules == null ? void 0 : rules.region) ?? "").toUpperCase();
28
+ valid = region === "ID" ? /^(?:\+62|62|0)8\d{7,11}$/u.test(clean) : /^\+[1-9]\d{7,14}$/u.test(clean);
29
+ } else if (format === "postalCode") {
30
+ const resolved = ((_a = rules == null ? void 0 : rules.countryResolver) == null ? void 0 : _a.call(rules, values)) ?? ((rules == null ? void 0 : rules.countryField) ? get(values, rules.countryField) : void 0) ?? (rules == null ? void 0 : rules.country);
31
+ const country = typeof resolved === "string" ? resolved.trim().toUpperCase() : "";
32
+ if (!country && ((rules == null ? void 0 : rules.countryField) || (rules == null ? void 0 : rules.countryResolver))) return void 0;
33
+ const patterns = {
34
+ ID: /^\d{5}$/u,
35
+ US: /^\d{5}(?:-\d{4})?$/u,
36
+ SG: /^\d{6}$/u,
37
+ JP: /^\d{3}-?\d{4}$/u,
38
+ GB: /^(?:GIR\s?0AA|[A-Z]{1,2}\d[A-Z\d]?\s?\d[A-Z]{2})$/iu,
39
+ UK: /^(?:GIR\s?0AA|[A-Z]{1,2}\d[A-Z\d]?\s?\d[A-Z]{2})$/iu
40
+ };
41
+ const validator = ((_b = policy == null ? void 0 : policy.postalCodePatterns) == null ? void 0 : _b[country]) ?? patterns[country];
42
+ if (!validator) valid = (policy == null ? void 0 : policy.unknownCountry) === "ignore";
43
+ else if (validator instanceof RegExp) {
44
+ validator.lastIndex = 0;
45
+ valid = validator.test(input);
46
+ } else valid = Boolean(validator(input, values));
47
+ }
48
+ return valid ? void 0 : (rules == null ? void 0 : rules.message) ?? `Invalid ${format}`;
49
+ }
50
+ function withValidationPolicy(adapter, policy) {
51
+ return {
52
+ buildSchema(fields) {
53
+ return { base: adapter.buildSchema(fields), fields };
54
+ },
55
+ async validate(schema, values) {
56
+ const { base, fields } = schema;
57
+ const errors = { ...await adapter.validate(base, values) };
58
+ for (const field of fields) {
59
+ if (isHidden(field, values)) {
60
+ delete errors[field.name];
61
+ } else if (!errors[field.name]) {
62
+ const error = validateSemanticValue(field, get(values, field.name), policy, values);
63
+ if (error) errors[field.name] = error;
64
+ }
65
+ }
66
+ return errors;
67
+ },
68
+ async validateField(schema, name, value, values) {
69
+ var _a;
70
+ const { base, fields } = schema;
71
+ const context = values ?? { [name]: value };
72
+ const field = fields.find((f) => f.name === name) ?? { name, type: "text" };
73
+ if (isHidden(field, context)) return void 0;
74
+ const error = await ((_a = adapter.validateField) == null ? void 0 : _a.call(adapter, base, name, value, context));
75
+ return error ?? validateSemanticValue(field, value, policy, context);
76
+ }
77
+ };
78
+ }
79
+ export {
80
+ validateSemanticValue,
81
+ withValidationPolicy
82
+ };
@@ -16,7 +16,7 @@ const simpleValidator = {
16
16
  const isHidden = typeof rule.hidden === "function" ? rule.hidden(values) : rule.hidden;
17
17
  if (isHidden) continue;
18
18
  const value = getNestedValue(values, rule.name);
19
- if (isEmpty(value)) {
19
+ if (isEmpty(value, rule.type)) {
20
20
  errors[rule.name] = rule.message;
21
21
  }
22
22
  }
@@ -26,10 +26,11 @@ const simpleValidator = {
26
26
  const rules = schema;
27
27
  const rule = rules.find((r) => r.name === name);
28
28
  if (!rule) return void 0;
29
- return isEmpty(value) ? rule.message : void 0;
29
+ return isEmpty(value, rule.type) ? rule.message : void 0;
30
30
  }
31
31
  };
32
- function isEmpty(value) {
32
+ function isEmpty(value, type) {
33
+ if (type === "checkbox" || type === "switch") return value !== true;
33
34
  if (value == null) return true;
34
35
  if (typeof value === "string") return value.trim() === "";
35
36
  if (Array.isArray(value)) return value.length === 0;
@@ -4,4 +4,3 @@ import { ValidationAdapter } from '../types';
4
4
  * No external library dependency.
5
5
  */
6
6
  export declare const simpleValidator: ValidationAdapter;
7
- //# sourceMappingURL=validation.d.ts.map
@@ -14,7 +14,7 @@ const simpleValidator = {
14
14
  const isHidden = typeof rule.hidden === "function" ? rule.hidden(values) : rule.hidden;
15
15
  if (isHidden) continue;
16
16
  const value = getNestedValue(values, rule.name);
17
- if (isEmpty(value)) {
17
+ if (isEmpty(value, rule.type)) {
18
18
  errors[rule.name] = rule.message;
19
19
  }
20
20
  }
@@ -24,10 +24,11 @@ const simpleValidator = {
24
24
  const rules = schema;
25
25
  const rule = rules.find((r) => r.name === name);
26
26
  if (!rule) return void 0;
27
- return isEmpty(value) ? rule.message : void 0;
27
+ return isEmpty(value, rule.type) ? rule.message : void 0;
28
28
  }
29
29
  };
30
- function isEmpty(value) {
30
+ function isEmpty(value, type) {
31
+ if (type === "checkbox" || type === "switch") return value !== true;
31
32
  if (value == null) return true;
32
33
  if (typeof value === "string") return value.trim() === "";
33
34
  if (Array.isArray(value)) return value.length === 0;
@@ -2,5 +2,4 @@ import { AutocompleteOption, FieldComponentProps } from '../../types';
2
2
  export declare function AutocompleteField({ name, value, onChange: _onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, options: staticOptions, fetchOptions, optionLabel, icon, form, }: FieldComponentProps & {
3
3
  fetchOptions?: (query: string, signal?: AbortSignal) => Promise<AutocompleteOption[]>;
4
4
  optionLabel?: string;
5
- }): import("react/jsx-runtime").JSX.Element;
6
- //# sourceMappingURL=AutocompleteField.d.ts.map
5
+ }): import("react").JSX.Element;
@@ -2,5 +2,4 @@ import { AutocompleteOption, FieldComponentProps } from '../../types';
2
2
  export declare function AutocompleteMultiField({ name, value, onChange: _onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, options: staticOptions, fetchOptions, optionLabel, icon, form, }: FieldComponentProps & {
3
3
  fetchOptions?: (query: string, signal?: AbortSignal) => Promise<AutocompleteOption[]>;
4
4
  optionLabel?: string;
5
- }): import("react/jsx-runtime").JSX.Element;
6
- //# sourceMappingURL=AutocompleteMultiField.d.ts.map
5
+ }): import("react").JSX.Element;
@@ -6,5 +6,4 @@ import { AutocompleteOption, FieldComponentProps } from '../../types';
6
6
  export declare function AutocompletePredictField({ name, value, onChange: _onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, options: staticOptions, fetchOptions, optionLabel, icon, form, }: FieldComponentProps & {
7
7
  fetchOptions?: (query: string, signal?: AbortSignal) => Promise<AutocompleteOption[]>;
8
8
  optionLabel?: string;
9
- }): import("react/jsx-runtime").JSX.Element;
10
- //# sourceMappingURL=AutocompletePredictField.d.ts.map
9
+ }): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function CheckboxField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, form, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=CheckboxField.d.ts.map
2
+ export declare function CheckboxField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, form, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function ColorField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, form, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=ColorField.d.ts.map
2
+ export declare function ColorField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, form, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -6,5 +6,4 @@ export declare function CurrencyField({ name, value, onChange: _onChange, onBlur
6
6
  suffix?: string;
7
7
  locale?: string;
8
8
  currency?: string;
9
- }): import("react/jsx-runtime").JSX.Element;
10
- //# sourceMappingURL=CurrencyField.d.ts.map
9
+ }): import("react").JSX.Element;
@@ -3,5 +3,4 @@ export declare function DateField({ name, value, onChange, onBlur, error, helper
3
3
  min?: string;
4
4
  max?: string;
5
5
  locale?: string;
6
- }>): import("react/jsx-runtime").JSX.Element;
7
- //# sourceMappingURL=DateField.d.ts.map
6
+ }>): import("react").JSX.Element;
@@ -6,6 +6,5 @@ interface DatePickerProps {
6
6
  onApply: (isoDate: string) => void;
7
7
  onClose: () => void;
8
8
  }
9
- export declare function DatePicker({ value, min, max, pickerId, onApply, onClose, }: Readonly<DatePickerProps>): import("react/jsx-runtime").JSX.Element;
9
+ export declare function DatePicker({ value, min, max, pickerId, onApply, onClose, }: Readonly<DatePickerProps>): import("react").JSX.Element;
10
10
  export {};
11
- //# sourceMappingURL=DatePicker.d.ts.map
@@ -5,5 +5,4 @@ export declare function DateTimeField({ name, value, onChange, onBlur, error, he
5
5
  locale?: string;
6
6
  ampm?: boolean;
7
7
  showSeconds?: boolean;
8
- }>): import("react/jsx-runtime").JSX.Element;
9
- //# sourceMappingURL=DateTimeField.d.ts.map
8
+ }>): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function EmailField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=EmailField.d.ts.map
2
+ export declare function EmailField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react").JSX.Element;