@axenstudio/axen-form 0.1.16 → 0.1.18

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 (128) 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 +127 -39
  10. package/dist/core/formStore.d.ts +2 -1
  11. package/dist/core/formStore.js +127 -39
  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 +69 -0
  16. package/dist/core/semanticValidation.d.ts +5 -0
  17. package/dist/core/semanticValidation.js +69 -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.d.ts +1 -2
  61. package/dist/react/AxenField.d.ts +1 -2
  62. package/dist/react/AxenForm.cjs +33 -23
  63. package/dist/react/AxenForm.d.ts +0 -1
  64. package/dist/react/AxenForm.js +34 -24
  65. package/dist/react/FormContext.d.ts +0 -1
  66. package/dist/react/useAxenForm.cjs +11 -4
  67. package/dist/react/useAxenForm.d.ts +1 -2
  68. package/dist/react/useAxenForm.js +11 -4
  69. package/dist/react/useField.cjs +3 -0
  70. package/dist/react/useField.d.ts +0 -1
  71. package/dist/react/useField.js +3 -0
  72. package/dist/react/useFieldArray.cjs +19 -13
  73. package/dist/react/useFieldArray.d.ts +0 -1
  74. package/dist/react/useFieldArray.js +19 -13
  75. package/dist/react/useFormState.cjs +18 -0
  76. package/dist/react/useFormState.d.ts +5 -0
  77. package/dist/react/useFormState.js +18 -0
  78. package/dist/types.d.ts +19 -2
  79. package/package.json +5 -2
  80. package/dist/adapters/yupAdapter.d.ts.map +0 -1
  81. package/dist/adapters/zodAdapter.d.ts.map +0 -1
  82. package/dist/core/dateUtils.d.ts.map +0 -1
  83. package/dist/core/formStore.d.ts.map +0 -1
  84. package/dist/core/numberUtils.d.ts.map +0 -1
  85. package/dist/core/pathUtils.d.ts.map +0 -1
  86. package/dist/core/payloadUtils.d.ts.map +0 -1
  87. package/dist/core/validation.d.ts.map +0 -1
  88. package/dist/fields/AutocompleteField/AutocompleteField.d.ts.map +0 -1
  89. package/dist/fields/AutocompleteMultiField/AutocompleteMultiField.d.ts.map +0 -1
  90. package/dist/fields/AutocompletePredictField/AutocompletePredictField.d.ts.map +0 -1
  91. package/dist/fields/CheckboxField/CheckboxField.d.ts.map +0 -1
  92. package/dist/fields/ColorField/ColorField.d.ts.map +0 -1
  93. package/dist/fields/CurrencyField/CurrencyField.d.ts.map +0 -1
  94. package/dist/fields/DateField/DateField.d.ts.map +0 -1
  95. package/dist/fields/DateField/DatePicker.d.ts.map +0 -1
  96. package/dist/fields/DateTimeField/DateTimeField.d.ts.map +0 -1
  97. package/dist/fields/EmailField/EmailField.d.ts.map +0 -1
  98. package/dist/fields/NumberField/NumberField.d.ts.map +0 -1
  99. package/dist/fields/PasswordField/PasswordField.d.ts.map +0 -1
  100. package/dist/fields/PhoneField/PhoneField.d.ts.map +0 -1
  101. package/dist/fields/RadioField/RadioField.d.ts.map +0 -1
  102. package/dist/fields/SelectField/SelectField.d.ts.map +0 -1
  103. package/dist/fields/SliderField/SliderField.d.ts.map +0 -1
  104. package/dist/fields/SwitchField/SwitchField.d.ts.map +0 -1
  105. package/dist/fields/TextField/TextField.d.ts.map +0 -1
  106. package/dist/fields/TextareaField/TextareaField.d.ts.map +0 -1
  107. package/dist/fields/TimeField/TimeField.d.ts.map +0 -1
  108. package/dist/fields/TimeField/TimePicker.d.ts.map +0 -1
  109. package/dist/fields/defaultComponentMap.d.ts.map +0 -1
  110. package/dist/fields/defaultPlaceholders.d.ts.map +0 -1
  111. package/dist/fields/fieldUtils.d.ts.map +0 -1
  112. package/dist/fields/iconUtils.d.ts.map +0 -1
  113. package/dist/fields/icons.d.ts.map +0 -1
  114. package/dist/index.d.ts.map +0 -1
  115. package/dist/layout/Box/Box.d.ts.map +0 -1
  116. package/dist/layout/Divider/Divider.d.ts.map +0 -1
  117. package/dist/layout/Grid/Grid.d.ts.map +0 -1
  118. package/dist/layout/Spacer/Spacer.d.ts.map +0 -1
  119. package/dist/layout/Stack/Stack.d.ts.map +0 -1
  120. package/dist/layout/index.d.ts.map +0 -1
  121. package/dist/react/AxenArrayField.d.ts.map +0 -1
  122. package/dist/react/AxenField.d.ts.map +0 -1
  123. package/dist/react/AxenForm.d.ts.map +0 -1
  124. package/dist/react/FormContext.d.ts.map +0 -1
  125. package/dist/react/useAxenForm.d.ts.map +0 -1
  126. package/dist/react/useField.d.ts.map +0 -1
  127. package/dist/react/useFieldArray.d.ts.map +0 -1
  128. package/dist/types.d.ts.map +0 -1
@@ -27,13 +27,14 @@ export declare function createFormStore<TValues extends Record<string, unknown>>
27
27
  setFieldError: (name: string, error: string | undefined) => void;
28
28
  setValues: (values: TValues) => void;
29
29
  setErrors: (errors: Record<string, string>) => void;
30
+ setFieldArrayValue: (name: string, items: unknown[], origins: Array<number | null>) => void;
30
31
  resetForm: (nextValues?: Partial<TValues>) => void;
31
32
  validateForm: () => Promise<Record<string, string>>;
32
33
  validateField: (name: string) => Promise<string | undefined>;
33
34
  submitForm: (onSubmit?: (values: TValues) => void | Promise<void>) => Promise<void>;
35
+ touchAllFields: () => void;
34
36
  getFieldValue: (name: string) => unknown;
35
37
  getFieldError: (name: string) => string | undefined;
36
38
  getFieldTouched: (name: string) => boolean;
37
39
  };
38
40
  export type FormStore<TValues extends Record<string, unknown> = Record<string, unknown>> = ReturnType<typeof createFormStore<TValues>>;
39
- //# sourceMappingURL=formStore.d.ts.map
@@ -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,
@@ -18,6 +29,9 @@ function createFormStore(options) {
18
29
  const subscribers = /* @__PURE__ */ new Set();
19
30
  const fieldSubscribers = /* @__PURE__ */ new Map();
20
31
  let validationSchema = options.validationSchema;
32
+ let valuesRevision = 0;
33
+ let formRequest = 0;
34
+ const fieldRequests = /* @__PURE__ */ new Map();
21
35
  if (validationAdapter && options.fields && !validationSchema) {
22
36
  validationSchema = validationAdapter.buildSchema(options.fields);
23
37
  }
@@ -46,16 +60,30 @@ function createFormStore(options) {
46
60
  var _a;
47
61
  (_a = fieldSubscribers.get(name)) == null ? void 0 : _a.forEach((fn) => fn());
48
62
  }
49
- function setFieldValue(name, value) {
50
- state = {
51
- ...state,
52
- values: set(state.values, name, value),
53
- dirty: true
54
- };
55
- notifyField(name);
63
+ function notifyAllFields() {
64
+ for (const name of fieldSubscribers.keys()) notifyField(name);
56
65
  notify();
66
+ }
67
+ function notifyValuePath(path) {
68
+ const related = (key) => key === path || key.startsWith(`${path}.`) || key.startsWith(`${path}[`) || path.startsWith(`${key}.`) || path.startsWith(`${key}[`);
69
+ for (const key of fieldSubscribers.keys()) if (related(key)) notifyField(key);
70
+ notify();
71
+ }
72
+ function setFieldValue(name, value) {
73
+ const nextValues = set(state.values, name, value);
74
+ valuesRevision += 1;
75
+ state = { ...state, values: nextValues, dirty: !valuesEqual(nextValues, state.initialValues) };
76
+ for (const field of options.fields ?? []) {
77
+ if (field.hidden && state.errors[field.name] && (typeof field.hidden === "function" ? field.hidden(nextValues) : field.hidden)) {
78
+ setFieldError(field.name, void 0);
79
+ }
80
+ }
81
+ notifyValuePath(name);
57
82
  if (validateOnChange && validationAdapter && validationSchema) {
58
- runFieldValidation(name);
83
+ const revision = valuesRevision;
84
+ void runFieldValidation(name).catch((error) => {
85
+ if (revision === valuesRevision) setFieldError(name, error instanceof Error ? error.message : "Validation failed");
86
+ });
59
87
  }
60
88
  }
61
89
  function setFieldTouched(name, touched = true) {
@@ -66,7 +94,10 @@ function createFormStore(options) {
66
94
  notifyField(name);
67
95
  notify();
68
96
  if (validateOnBlur && touched && validationAdapter && validationSchema) {
69
- runFieldValidation(name);
97
+ const revision = valuesRevision;
98
+ void runFieldValidation(name).catch((error) => {
99
+ if (revision === valuesRevision) setFieldError(name, error instanceof Error ? error.message : "Validation failed");
100
+ });
70
101
  }
71
102
  }
72
103
  function setFieldError(name, error) {
@@ -81,13 +112,47 @@ function createFormStore(options) {
81
112
  notify();
82
113
  }
83
114
  function setValues(values) {
84
- state = { ...state, values, dirty: true };
85
- notify();
86
- subscribers.forEach((fn) => fn());
115
+ valuesRevision += 1;
116
+ state = { ...state, values, dirty: !valuesEqual(values, state.initialValues) };
117
+ notifyAllFields();
87
118
  }
88
119
  function setErrors(errors) {
89
120
  state = { ...state, errors };
90
- notify();
121
+ notifyAllFields();
122
+ }
123
+ function setFieldArrayValue(name, items, origins) {
124
+ const remap = (entries) => {
125
+ const result = {};
126
+ for (const [path, value] of Object.entries(entries)) {
127
+ if (!path.startsWith(name)) {
128
+ result[path] = value;
129
+ continue;
130
+ }
131
+ const suffix = path.slice(name.length);
132
+ const match = /^(?:\.(\d+)|\[(\d+)\])(?=\.|\[|$)/.exec(suffix);
133
+ if (!match) {
134
+ result[path] = value;
135
+ continue;
136
+ }
137
+ const oldIndex = Number(match[1] ?? match[2]);
138
+ const tail = suffix.slice(match[0].length);
139
+ for (let i = 0; i < origins.length; i++) {
140
+ if (origins[i] !== oldIndex) continue;
141
+ result[`${name}${match[1] !== void 0 ? `.${i}` : `[${i}]`}${tail}`] = value;
142
+ }
143
+ }
144
+ return result;
145
+ };
146
+ const values = set(state.values, name, items);
147
+ valuesRevision += 1;
148
+ state = {
149
+ ...state,
150
+ values,
151
+ dirty: !valuesEqual(values, state.initialValues),
152
+ errors: remap(state.errors),
153
+ touched: remap(state.touched)
154
+ };
155
+ notifyValuePath(name);
91
156
  }
92
157
  function resetForm(nextValues) {
93
158
  const newValues = nextValues ? { ...state.initialValues, ...nextValues } : structuredClone(state.initialValues);
@@ -98,23 +163,40 @@ function createFormStore(options) {
98
163
  dirty: false,
99
164
  isSubmitting: false,
100
165
  submitCount: state.submitCount,
101
- initialValues: state.initialValues
166
+ initialValues: nextValues ? structuredClone(newValues) : state.initialValues
102
167
  };
103
- notify();
168
+ valuesRevision += 1;
169
+ notifyAllFields();
104
170
  }
105
171
  async function validateForm() {
106
172
  if (!validationAdapter || !validationSchema) return {};
173
+ const revision = valuesRevision;
174
+ const request = ++formRequest;
107
175
  const errors = await validationAdapter.validate(validationSchema, state.values);
176
+ if (revision !== valuesRevision || request !== formRequest) return state.errors;
108
177
  state = { ...state, errors };
109
178
  notify();
179
+ for (const name of fieldSubscribers.keys()) notifyField(name);
110
180
  return errors;
111
181
  }
112
182
  async function validateField(name) {
183
+ var _a;
113
184
  if (!(validationAdapter == null ? void 0 : validationAdapter.validateField) || !validationSchema) return void 0;
185
+ const revision = valuesRevision;
186
+ const request = (fieldRequests.get(name) ?? 0) + 1;
187
+ fieldRequests.set(name, request);
188
+ const config = (_a = options.fields) == null ? void 0 : _a.find((field) => field.name === name);
189
+ if ((config == null ? void 0 : config.hidden) && (typeof config.hidden === "function" ? config.hidden(state.values) : config.hidden)) {
190
+ setFieldError(name, void 0);
191
+ return void 0;
192
+ }
114
193
  const fieldValue = get(state.values, name);
115
194
  const error = await validationAdapter.validateField(validationSchema, name, fieldValue);
116
- setFieldError(name, error);
117
- return error;
195
+ if (revision === valuesRevision && request === fieldRequests.get(name)) {
196
+ setFieldError(name, error);
197
+ return error;
198
+ }
199
+ return state.errors[name];
118
200
  }
119
201
  async function runFieldValidation(name) {
120
202
  if (validationAdapter == null ? void 0 : validationAdapter.validateField) {
@@ -124,30 +206,18 @@ function createFormStore(options) {
124
206
  }
125
207
  }
126
208
  async function submitForm(onSubmit) {
209
+ if (state.isSubmitting) return;
127
210
  state = { ...state, isSubmitting: true, submitCount: state.submitCount + 1 };
128
211
  notify();
129
- const allTouched = {};
130
- if (options.fields) {
131
- for (const field of options.fields) {
132
- allTouched[field.name] = true;
133
- }
134
- }
135
- state = { ...state, touched: { ...state.touched, ...allTouched } };
136
- const errors = await validateForm();
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 {
212
+ try {
213
+ touchAllFields();
214
+ const revision = valuesRevision;
215
+ const errors = await validateForm();
216
+ for (const name of Object.keys(state.touched)) notifyField(name);
217
+ if (revision !== valuesRevision || Object.keys(errors).length > 0) return;
218
+ const handler = onSubmit ?? options.onSubmit;
219
+ if (handler) await handler(state.values);
220
+ } finally {
151
221
  state = { ...state, isSubmitting: false };
152
222
  notify();
153
223
  }
@@ -161,6 +231,22 @@ function createFormStore(options) {
161
231
  function getFieldTouched(name) {
162
232
  return state.touched[name] ?? false;
163
233
  }
234
+ function touchAllFields() {
235
+ const allTouched = {};
236
+ if (options.fields) {
237
+ for (const field of options.fields) {
238
+ allTouched[field.name] = true;
239
+ }
240
+ }
241
+ for (const name of fieldSubscribers.keys()) {
242
+ allTouched[name] = true;
243
+ }
244
+ state = { ...state, touched: { ...state.touched, ...allTouched } };
245
+ for (const name of Object.keys(allTouched)) {
246
+ notifyField(name);
247
+ }
248
+ notify();
249
+ }
164
250
  return {
165
251
  getState,
166
252
  subscribe,
@@ -170,10 +256,12 @@ function createFormStore(options) {
170
256
  setFieldError,
171
257
  setValues,
172
258
  setErrors,
259
+ setFieldArrayValue,
173
260
  resetForm,
174
261
  validateForm,
175
262
  validateField,
176
263
  submitForm,
264
+ touchAllFields,
177
265
  getFieldValue,
178
266
  getFieldError,
179
267
  getFieldTouched
@@ -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,69 @@
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) {
8
+ var _a;
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 country = ((rules == null ? void 0 : rules.country) ?? "").toUpperCase();
33
+ const patterns = {
34
+ ID: /^\d{5}$/u,
35
+ US: /^\d{5}(?:-\d{4})?$/u,
36
+ SG: /^\d{6}$/u
37
+ };
38
+ valid = Boolean((_a = patterns[country]) == null ? void 0 : _a.test(input));
39
+ }
40
+ return valid ? void 0 : (rules == null ? void 0 : rules.message) ?? `Invalid ${format}`;
41
+ }
42
+ function withValidationPolicy(adapter, policy) {
43
+ return {
44
+ buildSchema(fields) {
45
+ return { base: adapter.buildSchema(fields), fields };
46
+ },
47
+ async validate(schema, values) {
48
+ const { base, fields } = schema;
49
+ const errors = { ...await adapter.validate(base, values) };
50
+ for (const field of fields) {
51
+ if (isHidden(field, values)) {
52
+ delete errors[field.name];
53
+ } else if (!errors[field.name]) {
54
+ const error = validateSemanticValue(field, pathUtils.get(values, field.name), policy);
55
+ if (error) errors[field.name] = error;
56
+ }
57
+ }
58
+ return errors;
59
+ },
60
+ async validateField(schema, name, value) {
61
+ var _a;
62
+ const { base, fields } = schema;
63
+ const error = await ((_a = adapter.validateField) == null ? void 0 : _a.call(adapter, base, name, value));
64
+ return error ?? validateSemanticValue(fields.find((f) => f.name === name) ?? { type: "text" }, value, policy);
65
+ }
66
+ };
67
+ }
68
+ exports.validateSemanticValue = validateSemanticValue;
69
+ 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): 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,69 @@
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) {
6
+ var _a;
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 country = ((rules == null ? void 0 : rules.country) ?? "").toUpperCase();
31
+ const patterns = {
32
+ ID: /^\d{5}$/u,
33
+ US: /^\d{5}(?:-\d{4})?$/u,
34
+ SG: /^\d{6}$/u
35
+ };
36
+ valid = Boolean((_a = patterns[country]) == null ? void 0 : _a.test(input));
37
+ }
38
+ return valid ? void 0 : (rules == null ? void 0 : rules.message) ?? `Invalid ${format}`;
39
+ }
40
+ function withValidationPolicy(adapter, policy) {
41
+ return {
42
+ buildSchema(fields) {
43
+ return { base: adapter.buildSchema(fields), fields };
44
+ },
45
+ async validate(schema, values) {
46
+ const { base, fields } = schema;
47
+ const errors = { ...await adapter.validate(base, values) };
48
+ for (const field of fields) {
49
+ if (isHidden(field, values)) {
50
+ delete errors[field.name];
51
+ } else if (!errors[field.name]) {
52
+ const error = validateSemanticValue(field, get(values, field.name), policy);
53
+ if (error) errors[field.name] = error;
54
+ }
55
+ }
56
+ return errors;
57
+ },
58
+ async validateField(schema, name, value) {
59
+ var _a;
60
+ const { base, fields } = schema;
61
+ const error = await ((_a = adapter.validateField) == null ? void 0 : _a.call(adapter, base, name, value));
62
+ return error ?? validateSemanticValue(fields.find((f) => f.name === name) ?? { type: "text" }, value, policy);
63
+ }
64
+ };
65
+ }
66
+ export {
67
+ validateSemanticValue,
68
+ withValidationPolicy
69
+ };
@@ -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;
@@ -6,5 +6,4 @@ export declare function NumberField({ name, value, onChange: _onChange, onBlur,
6
6
  prefix?: string;
7
7
  suffix?: string;
8
8
  locale?: string;
9
- }): import("react/jsx-runtime").JSX.Element;
10
- //# sourceMappingURL=NumberField.d.ts.map
9
+ }): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function PasswordField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=PasswordField.d.ts.map
2
+ export declare function PasswordField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function PhoneField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=PhoneField.d.ts.map
2
+ export declare function PhoneField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function RadioField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, options, form, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=RadioField.d.ts.map
2
+ export declare function RadioField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, options, form, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function SelectField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, options, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=SelectField.d.ts.map
2
+ export declare function SelectField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, options, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -3,5 +3,4 @@ export declare function SliderField({ name, value, onChange: _onChange, onBlur,
3
3
  min?: number;
4
4
  max?: number;
5
5
  step?: number;
6
- }): import("react/jsx-runtime").JSX.Element;
7
- //# sourceMappingURL=SliderField.d.ts.map
6
+ }): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function SwitchField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, form, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=SwitchField.d.ts.map
2
+ export declare function SwitchField({ 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 TextField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=TextField.d.ts.map
2
+ export declare function TextField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -1,5 +1,4 @@
1
1
  import { FieldComponentProps } from '../../types';
2
2
  export declare function TextareaField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, rows, }: FieldComponentProps & {
3
3
  rows?: number;
4
- }): import("react/jsx-runtime").JSX.Element;
5
- //# sourceMappingURL=TextareaField.d.ts.map
4
+ }): import("react").JSX.Element;
@@ -3,5 +3,4 @@ export declare function TimeField({ name, value, onChange, onBlur, error, helper
3
3
  locale?: string;
4
4
  ampm?: boolean;
5
5
  showSeconds?: boolean;
6
- }>): import("react/jsx-runtime").JSX.Element;
7
- //# sourceMappingURL=TimeField.d.ts.map
6
+ }>): import("react").JSX.Element;
@@ -6,6 +6,5 @@ interface TimePickerProps {
6
6
  onApply: (isoTime: string) => void;
7
7
  onClose: () => void;
8
8
  }
9
- export declare function TimePicker({ value, showSeconds, ampm, pickerId, onApply, onClose, }: Readonly<TimePickerProps>): import("react/jsx-runtime").JSX.Element;
9
+ export declare function TimePicker({ value, showSeconds, ampm, pickerId, onApply, onClose, }: Readonly<TimePickerProps>): import("react").JSX.Element;
10
10
  export {};
11
- //# sourceMappingURL=TimePicker.d.ts.map