@conform-to/react 1.8.2 → 1.9.1

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.
@@ -0,0 +1,57 @@
1
+ import { type ValidationAttributes, type Serialize } from '@conform-to/dom/future';
2
+ import type { DefaultFieldMetadata, Field, FieldName, Fieldset, FormContext, FormMetadata, FormState, FormAction, UnknownIntent, ActionHandler } from './types';
3
+ export declare function initializeState<ErrorShape>(): FormState<ErrorShape>;
4
+ /**
5
+ * Updates form state based on action type:
6
+ * - Client actions: update intended value and client errors
7
+ * - Server actions: update server errors and clear client errors
8
+ * - Initialize: set initial intended value
9
+ */
10
+ export declare function updateState<ErrorShape>(state: FormState<ErrorShape>, action: FormAction<ErrorShape, UnknownIntent | null, {
11
+ handlers: Record<string, ActionHandler>;
12
+ reset: () => FormState<ErrorShape>;
13
+ }>): FormState<ErrorShape>;
14
+ export declare function getDefaultValue(context: FormContext<any>, name: string, serialize?: Serialize): string | undefined;
15
+ export declare function getDefaultOptions(context: FormContext<any>, name: string, serialize?: Serialize): string[] | undefined;
16
+ export declare function isDefaultChecked(context: FormContext<any>, name: string, serialize?: Serialize): boolean;
17
+ /**
18
+ * Determine if the field is touched
19
+ *
20
+ * This checks if the field is in the list of touched fields,
21
+ * or if there is any child field that is touched, i.e. form / fieldset
22
+ */
23
+ export declare function isTouched(state: FormState<any>, name?: string): boolean;
24
+ export declare function getDefaultListKey(prefix: string, initialValue: Record<string, unknown> | null, name: string): string[];
25
+ export declare function getListKey(context: FormContext<any>, name: string): string[];
26
+ export declare function getErrors<ErrorShape>(state: FormState<ErrorShape>, name?: string): ErrorShape[] | undefined;
27
+ export declare function getFieldErrors<ErrorShape>(state: FormState<ErrorShape>, name?: string): Record<string, ErrorShape[]>;
28
+ /**
29
+ * Gets validation constraint for a field, with fallback to parent array patterns.
30
+ * e.g. "array[0].key" falls back to "array[].key" if specific constraint not found.
31
+ */
32
+ export declare function getConstraint(context: FormContext<any>, name: string): ValidationAttributes | undefined;
33
+ export declare function getFormMetadata<ErrorShape>(context: FormContext<ErrorShape>, options: {
34
+ serialize: Serialize;
35
+ }): FormMetadata<ErrorShape, DefaultFieldMetadata<ErrorShape>>;
36
+ export declare function getField<FieldShape, ErrorShape = string>(context: FormContext<ErrorShape>, options: {
37
+ name: FieldName<FieldShape>;
38
+ serialize: Serialize;
39
+ key?: string;
40
+ }): Field<FieldShape, DefaultFieldMetadata<ErrorShape>>;
41
+ /**
42
+ * Creates a proxy that dynamically generates field objects when properties are accessed.
43
+ */
44
+ export declare function getFieldset<FieldShape = Record<string, any>, ErrorShape = string>(context: FormContext<ErrorShape>, options: {
45
+ name?: FieldName<FieldShape>;
46
+ serialize: Serialize;
47
+ }): Fieldset<FieldShape, DefaultFieldMetadata<ErrorShape>>;
48
+ /**
49
+ * Creates an array of field objects for list/array inputs
50
+ */
51
+ export declare function getFieldList<FieldShape = Array<any>, ErrorShape = string>(context: FormContext<ErrorShape>, options: {
52
+ name: FieldName<FieldShape>;
53
+ serialize: Serialize;
54
+ }): Field<[
55
+ FieldShape
56
+ ] extends [Array<infer ItemShape> | null | undefined] ? ItemShape : unknown, DefaultFieldMetadata<ErrorShape>>[];
57
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1,318 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _rollupPluginBabelHelpers = require('../_virtual/_rollupPluginBabelHelpers.js');
6
+ var future = require('@conform-to/dom/future');
7
+ var util = require('./util.js');
8
+
9
+ function initializeState() {
10
+ return {
11
+ resetKey: util.generateUniqueKey(),
12
+ listKeys: {},
13
+ intendedValue: null,
14
+ serverValidatedValue: null,
15
+ serverError: null,
16
+ clientError: null,
17
+ touchedFields: []
18
+ };
19
+ }
20
+
21
+ /**
22
+ * Updates form state based on action type:
23
+ * - Client actions: update intended value and client errors
24
+ * - Server actions: update server errors and clear client errors
25
+ * - Initialize: set initial intended value
26
+ */
27
+ function updateState(state, action) {
28
+ var _action$intendedValue, _action$intendedValue2;
29
+ if (action.intendedValue === null) {
30
+ return action.ctx.reset();
31
+ }
32
+ var value = (_action$intendedValue = action.intendedValue) !== null && _action$intendedValue !== void 0 ? _action$intendedValue : action.submission.payload;
33
+
34
+ // Apply the form error and intended value from the result first
35
+ state = action.type === 'client' ? util.merge(state, {
36
+ intendedValue: !action.intent ? value : (_action$intendedValue2 = action.intendedValue) !== null && _action$intendedValue2 !== void 0 ? _action$intendedValue2 : state.intendedValue,
37
+ // Update client error only if the error is different from the previous one to minimize unnecessary re-renders
38
+ clientError: typeof action.error !== 'undefined' && !future.deepEqual(state.clientError, action.error) ? action.error : state.clientError,
39
+ // Reset server error if form value is changed
40
+ serverError: typeof action.error !== 'undefined' && !future.deepEqual(state.serverValidatedValue, value) ? null : state.serverError
41
+ }) : util.merge(state, {
42
+ intendedValue: action.type === 'initialize' ? value : state.intendedValue,
43
+ // Clear client error to avoid showing stale errors
44
+ clientError: null,
45
+ // Update server error if the error is defined.
46
+ // There is no need to check if the error is different as we are updating other states as well
47
+ serverError: typeof action.error !== 'undefined' ? action.error : state.serverError,
48
+ // Keep track of the value that the serverError is based on
49
+ serverValidatedValue: typeof action.error !== 'undefined' ? value : state.serverValidatedValue
50
+ });
51
+ if (action.type !== 'server' && typeof action.intent !== 'undefined') {
52
+ var _action$intent, _action$ctx$handlers;
53
+ // Validate the whole form if no intent is provided (default submission)
54
+ var intent = (_action$intent = action.intent) !== null && _action$intent !== void 0 ? _action$intent : {
55
+ type: 'validate'
56
+ };
57
+ var handler = (_action$ctx$handlers = action.ctx.handlers) === null || _action$ctx$handlers === void 0 ? void 0 : _action$ctx$handlers[intent.type];
58
+ if (typeof (handler === null || handler === void 0 ? void 0 : handler.onUpdate) === 'function') {
59
+ var _handler$validatePayl, _handler$validatePayl2;
60
+ if ((_handler$validatePayl = (_handler$validatePayl2 = handler.validatePayload) === null || _handler$validatePayl2 === void 0 ? void 0 : _handler$validatePayl2.call(handler, intent.payload)) !== null && _handler$validatePayl !== void 0 ? _handler$validatePayl : true) {
61
+ return handler.onUpdate(state, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, action), {}, {
62
+ intent: {
63
+ type: intent.type,
64
+ payload: intent.payload
65
+ }
66
+ }));
67
+ }
68
+ }
69
+ }
70
+ return state;
71
+ }
72
+ function getDefaultValue(context, name) {
73
+ var _ref, _context$state$intend;
74
+ var serialize = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : future.serialize;
75
+ var value = future.getValueAtPath((_ref = (_context$state$intend = context.state.intendedValue) !== null && _context$state$intend !== void 0 ? _context$state$intend : context.defaultValue) !== null && _ref !== void 0 ? _ref : {}, name);
76
+ var serializedValue = serialize(value);
77
+ if (typeof serializedValue === 'string') {
78
+ return serializedValue;
79
+ }
80
+ }
81
+ function getDefaultOptions(context, name) {
82
+ var _ref2, _context$state$intend2;
83
+ var serialize = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : future.serialize;
84
+ var value = future.getValueAtPath((_ref2 = (_context$state$intend2 = context.state.intendedValue) !== null && _context$state$intend2 !== void 0 ? _context$state$intend2 : context.defaultValue) !== null && _ref2 !== void 0 ? _ref2 : {}, name);
85
+ var serializedValue = typeof value !== 'undefined' ? serialize(value) : undefined;
86
+ if (Array.isArray(serializedValue) && serializedValue.every(item => typeof item === 'string')) {
87
+ return serializedValue;
88
+ }
89
+ if (typeof serializedValue === 'string') {
90
+ return [serializedValue];
91
+ }
92
+ }
93
+ function isDefaultChecked(context, name) {
94
+ var _ref3, _context$state$intend3;
95
+ var serialize = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : future.serialize;
96
+ var value = future.getValueAtPath((_ref3 = (_context$state$intend3 = context.state.intendedValue) !== null && _context$state$intend3 !== void 0 ? _context$state$intend3 : context.defaultValue) !== null && _ref3 !== void 0 ? _ref3 : {}, name);
97
+ var serializedValue = typeof value !== 'undefined' ? serialize(value) : undefined;
98
+ return serializedValue === 'on';
99
+ }
100
+
101
+ /**
102
+ * Determine if the field is touched
103
+ *
104
+ * This checks if the field is in the list of touched fields,
105
+ * or if there is any child field that is touched, i.e. form / fieldset
106
+ */
107
+ function isTouched(state) {
108
+ var name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
109
+ if (state.touchedFields.includes(name)) {
110
+ return true;
111
+ }
112
+ var paths = future.getPathSegments(name);
113
+ return state.touchedFields.some(field => field !== name && future.getRelativePath(field, paths) !== null);
114
+ }
115
+ function getDefaultListKey(prefix, initialValue, name) {
116
+ return util.getArrayAtPath(initialValue, name).map((_, index) => "".concat(prefix, "-").concat(future.appendPathSegment(name, index)));
117
+ }
118
+ function getListKey(context, name) {
119
+ var _context$state$listKe, _context$state$listKe2, _context$state$intend4;
120
+ return (_context$state$listKe = (_context$state$listKe2 = context.state.listKeys) === null || _context$state$listKe2 === void 0 ? void 0 : _context$state$listKe2[name]) !== null && _context$state$listKe !== void 0 ? _context$state$listKe : getDefaultListKey(context.state.resetKey, (_context$state$intend4 = context.state.intendedValue) !== null && _context$state$intend4 !== void 0 ? _context$state$intend4 : context.defaultValue, name);
121
+ }
122
+ function getErrors(state, name) {
123
+ var _state$serverError;
124
+ var error = (_state$serverError = state.serverError) !== null && _state$serverError !== void 0 ? _state$serverError : state.clientError;
125
+ if (!error || !isTouched(state, name)) {
126
+ return;
127
+ }
128
+ var errors = name ? error.fieldErrors[name] : error.formErrors;
129
+ if (errors && errors.length > 0) {
130
+ return errors;
131
+ }
132
+ }
133
+ function getFieldErrors(state, name) {
134
+ var result = {};
135
+ var basePath = future.getPathSegments(name);
136
+ for (var field of state.touchedFields) {
137
+ var relativePath = future.getRelativePath(field, basePath);
138
+ if (!relativePath || relativePath.length === 0) {
139
+ continue;
140
+ }
141
+ var error = getErrors(state, field);
142
+ if (typeof error !== 'undefined') {
143
+ result[future.formatPathSegments(relativePath)] = error;
144
+ }
145
+ }
146
+ return result;
147
+ }
148
+
149
+ /**
150
+ * Gets validation constraint for a field, with fallback to parent array patterns.
151
+ * e.g. "array[0].key" falls back to "array[].key" if specific constraint not found.
152
+ */
153
+ function getConstraint(context, name) {
154
+ var _context$constraint;
155
+ var constraint = (_context$constraint = context.constraint) === null || _context$constraint === void 0 ? void 0 : _context$constraint[name];
156
+ if (!constraint) {
157
+ var path = future.getPathSegments(name);
158
+ for (var i = path.length - 1; i >= 0; i--) {
159
+ var segment = path[i];
160
+ // Try searching a less specific path for the constraint
161
+ // e.g. `array[0].anotherArray[1].key` -> `array[0].anotherArray[].key` -> `array[].anotherArray[].key`
162
+ if (typeof segment === 'number') {
163
+ // This overrides the current number segment with an empty string
164
+ // which will be treated as an empty bracket
165
+ path[i] = '';
166
+ break;
167
+ }
168
+ }
169
+ var alternative = future.formatPathSegments(path);
170
+ if (name !== alternative) {
171
+ constraint = getConstraint(context, alternative);
172
+ }
173
+ }
174
+ return constraint;
175
+ }
176
+ function getFormMetadata(context, options) {
177
+ return {
178
+ key: context.state.resetKey,
179
+ id: context.formId,
180
+ errorId: "".concat(context.formId, "-form-error"),
181
+ descriptionId: "".concat(context.formId, "-form-description"),
182
+ get errors() {
183
+ return getErrors(context.state);
184
+ },
185
+ get fieldErrors() {
186
+ return getFieldErrors(context.state);
187
+ },
188
+ get touched() {
189
+ return isTouched(context.state);
190
+ },
191
+ get valid() {
192
+ return typeof getErrors(context.state) === 'undefined';
193
+ },
194
+ get invalid() {
195
+ return !this.valid;
196
+ },
197
+ props: {
198
+ id: context.formId,
199
+ onSubmit: context.handleSubmit,
200
+ onInput: context.handleInput,
201
+ onBlur: context.handleBlur,
202
+ noValidate: true
203
+ },
204
+ context,
205
+ getField(name) {
206
+ return getField(context, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, options), {}, {
207
+ name
208
+ }));
209
+ },
210
+ getFieldset(name) {
211
+ return getFieldset(context, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, options), {}, {
212
+ name
213
+ }));
214
+ },
215
+ getFieldList(name) {
216
+ return getFieldList(context, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, options), {}, {
217
+ name
218
+ }));
219
+ }
220
+ };
221
+ }
222
+ function getField(context, options) {
223
+ var id = "".concat(context.formId, "-field-").concat(options.name.replace(/[^a-zA-Z0-9._-]/g, '_'));
224
+ var constraint = getConstraint(context, options.name);
225
+ var metadata = {
226
+ id: id,
227
+ descriptionId: "".concat(id, "-description"),
228
+ errorId: "".concat(id, "-error"),
229
+ formId: context.formId,
230
+ required: constraint === null || constraint === void 0 ? void 0 : constraint.required,
231
+ minLength: constraint === null || constraint === void 0 ? void 0 : constraint.minLength,
232
+ maxLength: constraint === null || constraint === void 0 ? void 0 : constraint.maxLength,
233
+ pattern: constraint === null || constraint === void 0 ? void 0 : constraint.pattern,
234
+ min: constraint === null || constraint === void 0 ? void 0 : constraint.min,
235
+ max: constraint === null || constraint === void 0 ? void 0 : constraint.max,
236
+ step: constraint === null || constraint === void 0 ? void 0 : constraint.step,
237
+ multiple: constraint === null || constraint === void 0 ? void 0 : constraint.multiple,
238
+ get defaultValue() {
239
+ return getDefaultValue(context, options.name, options.serialize);
240
+ },
241
+ get defaultOptions() {
242
+ return getDefaultOptions(context, options.name, options.serialize);
243
+ },
244
+ get defaultChecked() {
245
+ return isDefaultChecked(context, options.name, options.serialize);
246
+ },
247
+ get touched() {
248
+ return isTouched(context.state, options.name);
249
+ },
250
+ get valid() {
251
+ return typeof getErrors(context.state, options.name) === 'undefined';
252
+ },
253
+ get invalid() {
254
+ return !this.valid;
255
+ },
256
+ get errors() {
257
+ return getErrors(context.state, options.name);
258
+ },
259
+ get fieldErrors() {
260
+ return getFieldErrors(context.state, options.name);
261
+ }
262
+ };
263
+ return Object.assign(metadata, {
264
+ key: options.key,
265
+ name: options.name,
266
+ getFieldset() {
267
+ return getFieldset(context, options);
268
+ },
269
+ getFieldList() {
270
+ return getFieldList(context, options);
271
+ }
272
+ });
273
+ }
274
+
275
+ /**
276
+ * Creates a proxy that dynamically generates field objects when properties are accessed.
277
+ */
278
+ function getFieldset(context, options) {
279
+ return new Proxy({}, {
280
+ get(target, name, receiver) {
281
+ if (typeof name === 'string') {
282
+ return getField(context, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, options), {}, {
283
+ name: future.appendPathSegment(options === null || options === void 0 ? void 0 : options.name, name)
284
+ }));
285
+ }
286
+ return Reflect.get(target, name, receiver);
287
+ }
288
+ });
289
+ }
290
+
291
+ /**
292
+ * Creates an array of field objects for list/array inputs
293
+ */
294
+ function getFieldList(context, options) {
295
+ var keys = getListKey(context, options.name);
296
+ return keys.map((key, index) => {
297
+ return getField(context, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, options), {}, {
298
+ name: future.appendPathSegment(options.name, index),
299
+ key
300
+ }));
301
+ });
302
+ }
303
+
304
+ exports.getConstraint = getConstraint;
305
+ exports.getDefaultListKey = getDefaultListKey;
306
+ exports.getDefaultOptions = getDefaultOptions;
307
+ exports.getDefaultValue = getDefaultValue;
308
+ exports.getErrors = getErrors;
309
+ exports.getField = getField;
310
+ exports.getFieldErrors = getFieldErrors;
311
+ exports.getFieldList = getFieldList;
312
+ exports.getFieldset = getFieldset;
313
+ exports.getFormMetadata = getFormMetadata;
314
+ exports.getListKey = getListKey;
315
+ exports.initializeState = initializeState;
316
+ exports.isDefaultChecked = isDefaultChecked;
317
+ exports.isTouched = isTouched;
318
+ exports.updateState = updateState;
@@ -0,0 +1,300 @@
1
+ import { objectSpread2 as _objectSpread2 } from '../_virtual/_rollupPluginBabelHelpers.mjs';
2
+ import { getPathSegments, getRelativePath, appendPathSegment, deepEqual, getValueAtPath, formatPathSegments, serialize } from '@conform-to/dom/future';
3
+ import { generateUniqueKey, merge, getArrayAtPath } from './util.mjs';
4
+
5
+ function initializeState() {
6
+ return {
7
+ resetKey: generateUniqueKey(),
8
+ listKeys: {},
9
+ intendedValue: null,
10
+ serverValidatedValue: null,
11
+ serverError: null,
12
+ clientError: null,
13
+ touchedFields: []
14
+ };
15
+ }
16
+
17
+ /**
18
+ * Updates form state based on action type:
19
+ * - Client actions: update intended value and client errors
20
+ * - Server actions: update server errors and clear client errors
21
+ * - Initialize: set initial intended value
22
+ */
23
+ function updateState(state, action) {
24
+ var _action$intendedValue, _action$intendedValue2;
25
+ if (action.intendedValue === null) {
26
+ return action.ctx.reset();
27
+ }
28
+ var value = (_action$intendedValue = action.intendedValue) !== null && _action$intendedValue !== void 0 ? _action$intendedValue : action.submission.payload;
29
+
30
+ // Apply the form error and intended value from the result first
31
+ state = action.type === 'client' ? merge(state, {
32
+ intendedValue: !action.intent ? value : (_action$intendedValue2 = action.intendedValue) !== null && _action$intendedValue2 !== void 0 ? _action$intendedValue2 : state.intendedValue,
33
+ // Update client error only if the error is different from the previous one to minimize unnecessary re-renders
34
+ clientError: typeof action.error !== 'undefined' && !deepEqual(state.clientError, action.error) ? action.error : state.clientError,
35
+ // Reset server error if form value is changed
36
+ serverError: typeof action.error !== 'undefined' && !deepEqual(state.serverValidatedValue, value) ? null : state.serverError
37
+ }) : merge(state, {
38
+ intendedValue: action.type === 'initialize' ? value : state.intendedValue,
39
+ // Clear client error to avoid showing stale errors
40
+ clientError: null,
41
+ // Update server error if the error is defined.
42
+ // There is no need to check if the error is different as we are updating other states as well
43
+ serverError: typeof action.error !== 'undefined' ? action.error : state.serverError,
44
+ // Keep track of the value that the serverError is based on
45
+ serverValidatedValue: typeof action.error !== 'undefined' ? value : state.serverValidatedValue
46
+ });
47
+ if (action.type !== 'server' && typeof action.intent !== 'undefined') {
48
+ var _action$intent, _action$ctx$handlers;
49
+ // Validate the whole form if no intent is provided (default submission)
50
+ var intent = (_action$intent = action.intent) !== null && _action$intent !== void 0 ? _action$intent : {
51
+ type: 'validate'
52
+ };
53
+ var handler = (_action$ctx$handlers = action.ctx.handlers) === null || _action$ctx$handlers === void 0 ? void 0 : _action$ctx$handlers[intent.type];
54
+ if (typeof (handler === null || handler === void 0 ? void 0 : handler.onUpdate) === 'function') {
55
+ var _handler$validatePayl, _handler$validatePayl2;
56
+ if ((_handler$validatePayl = (_handler$validatePayl2 = handler.validatePayload) === null || _handler$validatePayl2 === void 0 ? void 0 : _handler$validatePayl2.call(handler, intent.payload)) !== null && _handler$validatePayl !== void 0 ? _handler$validatePayl : true) {
57
+ return handler.onUpdate(state, _objectSpread2(_objectSpread2({}, action), {}, {
58
+ intent: {
59
+ type: intent.type,
60
+ payload: intent.payload
61
+ }
62
+ }));
63
+ }
64
+ }
65
+ }
66
+ return state;
67
+ }
68
+ function getDefaultValue(context, name) {
69
+ var _ref, _context$state$intend;
70
+ var serialize$1 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : serialize;
71
+ var value = getValueAtPath((_ref = (_context$state$intend = context.state.intendedValue) !== null && _context$state$intend !== void 0 ? _context$state$intend : context.defaultValue) !== null && _ref !== void 0 ? _ref : {}, name);
72
+ var serializedValue = serialize$1(value);
73
+ if (typeof serializedValue === 'string') {
74
+ return serializedValue;
75
+ }
76
+ }
77
+ function getDefaultOptions(context, name) {
78
+ var _ref2, _context$state$intend2;
79
+ var serialize$1 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : serialize;
80
+ var value = getValueAtPath((_ref2 = (_context$state$intend2 = context.state.intendedValue) !== null && _context$state$intend2 !== void 0 ? _context$state$intend2 : context.defaultValue) !== null && _ref2 !== void 0 ? _ref2 : {}, name);
81
+ var serializedValue = typeof value !== 'undefined' ? serialize$1(value) : undefined;
82
+ if (Array.isArray(serializedValue) && serializedValue.every(item => typeof item === 'string')) {
83
+ return serializedValue;
84
+ }
85
+ if (typeof serializedValue === 'string') {
86
+ return [serializedValue];
87
+ }
88
+ }
89
+ function isDefaultChecked(context, name) {
90
+ var _ref3, _context$state$intend3;
91
+ var serialize$1 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : serialize;
92
+ var value = getValueAtPath((_ref3 = (_context$state$intend3 = context.state.intendedValue) !== null && _context$state$intend3 !== void 0 ? _context$state$intend3 : context.defaultValue) !== null && _ref3 !== void 0 ? _ref3 : {}, name);
93
+ var serializedValue = typeof value !== 'undefined' ? serialize$1(value) : undefined;
94
+ return serializedValue === 'on';
95
+ }
96
+
97
+ /**
98
+ * Determine if the field is touched
99
+ *
100
+ * This checks if the field is in the list of touched fields,
101
+ * or if there is any child field that is touched, i.e. form / fieldset
102
+ */
103
+ function isTouched(state) {
104
+ var name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
105
+ if (state.touchedFields.includes(name)) {
106
+ return true;
107
+ }
108
+ var paths = getPathSegments(name);
109
+ return state.touchedFields.some(field => field !== name && getRelativePath(field, paths) !== null);
110
+ }
111
+ function getDefaultListKey(prefix, initialValue, name) {
112
+ return getArrayAtPath(initialValue, name).map((_, index) => "".concat(prefix, "-").concat(appendPathSegment(name, index)));
113
+ }
114
+ function getListKey(context, name) {
115
+ var _context$state$listKe, _context$state$listKe2, _context$state$intend4;
116
+ return (_context$state$listKe = (_context$state$listKe2 = context.state.listKeys) === null || _context$state$listKe2 === void 0 ? void 0 : _context$state$listKe2[name]) !== null && _context$state$listKe !== void 0 ? _context$state$listKe : getDefaultListKey(context.state.resetKey, (_context$state$intend4 = context.state.intendedValue) !== null && _context$state$intend4 !== void 0 ? _context$state$intend4 : context.defaultValue, name);
117
+ }
118
+ function getErrors(state, name) {
119
+ var _state$serverError;
120
+ var error = (_state$serverError = state.serverError) !== null && _state$serverError !== void 0 ? _state$serverError : state.clientError;
121
+ if (!error || !isTouched(state, name)) {
122
+ return;
123
+ }
124
+ var errors = name ? error.fieldErrors[name] : error.formErrors;
125
+ if (errors && errors.length > 0) {
126
+ return errors;
127
+ }
128
+ }
129
+ function getFieldErrors(state, name) {
130
+ var result = {};
131
+ var basePath = getPathSegments(name);
132
+ for (var field of state.touchedFields) {
133
+ var relativePath = getRelativePath(field, basePath);
134
+ if (!relativePath || relativePath.length === 0) {
135
+ continue;
136
+ }
137
+ var error = getErrors(state, field);
138
+ if (typeof error !== 'undefined') {
139
+ result[formatPathSegments(relativePath)] = error;
140
+ }
141
+ }
142
+ return result;
143
+ }
144
+
145
+ /**
146
+ * Gets validation constraint for a field, with fallback to parent array patterns.
147
+ * e.g. "array[0].key" falls back to "array[].key" if specific constraint not found.
148
+ */
149
+ function getConstraint(context, name) {
150
+ var _context$constraint;
151
+ var constraint = (_context$constraint = context.constraint) === null || _context$constraint === void 0 ? void 0 : _context$constraint[name];
152
+ if (!constraint) {
153
+ var path = getPathSegments(name);
154
+ for (var i = path.length - 1; i >= 0; i--) {
155
+ var segment = path[i];
156
+ // Try searching a less specific path for the constraint
157
+ // e.g. `array[0].anotherArray[1].key` -> `array[0].anotherArray[].key` -> `array[].anotherArray[].key`
158
+ if (typeof segment === 'number') {
159
+ // This overrides the current number segment with an empty string
160
+ // which will be treated as an empty bracket
161
+ path[i] = '';
162
+ break;
163
+ }
164
+ }
165
+ var alternative = formatPathSegments(path);
166
+ if (name !== alternative) {
167
+ constraint = getConstraint(context, alternative);
168
+ }
169
+ }
170
+ return constraint;
171
+ }
172
+ function getFormMetadata(context, options) {
173
+ return {
174
+ key: context.state.resetKey,
175
+ id: context.formId,
176
+ errorId: "".concat(context.formId, "-form-error"),
177
+ descriptionId: "".concat(context.formId, "-form-description"),
178
+ get errors() {
179
+ return getErrors(context.state);
180
+ },
181
+ get fieldErrors() {
182
+ return getFieldErrors(context.state);
183
+ },
184
+ get touched() {
185
+ return isTouched(context.state);
186
+ },
187
+ get valid() {
188
+ return typeof getErrors(context.state) === 'undefined';
189
+ },
190
+ get invalid() {
191
+ return !this.valid;
192
+ },
193
+ props: {
194
+ id: context.formId,
195
+ onSubmit: context.handleSubmit,
196
+ onInput: context.handleInput,
197
+ onBlur: context.handleBlur,
198
+ noValidate: true
199
+ },
200
+ context,
201
+ getField(name) {
202
+ return getField(context, _objectSpread2(_objectSpread2({}, options), {}, {
203
+ name
204
+ }));
205
+ },
206
+ getFieldset(name) {
207
+ return getFieldset(context, _objectSpread2(_objectSpread2({}, options), {}, {
208
+ name
209
+ }));
210
+ },
211
+ getFieldList(name) {
212
+ return getFieldList(context, _objectSpread2(_objectSpread2({}, options), {}, {
213
+ name
214
+ }));
215
+ }
216
+ };
217
+ }
218
+ function getField(context, options) {
219
+ var id = "".concat(context.formId, "-field-").concat(options.name.replace(/[^a-zA-Z0-9._-]/g, '_'));
220
+ var constraint = getConstraint(context, options.name);
221
+ var metadata = {
222
+ id: id,
223
+ descriptionId: "".concat(id, "-description"),
224
+ errorId: "".concat(id, "-error"),
225
+ formId: context.formId,
226
+ required: constraint === null || constraint === void 0 ? void 0 : constraint.required,
227
+ minLength: constraint === null || constraint === void 0 ? void 0 : constraint.minLength,
228
+ maxLength: constraint === null || constraint === void 0 ? void 0 : constraint.maxLength,
229
+ pattern: constraint === null || constraint === void 0 ? void 0 : constraint.pattern,
230
+ min: constraint === null || constraint === void 0 ? void 0 : constraint.min,
231
+ max: constraint === null || constraint === void 0 ? void 0 : constraint.max,
232
+ step: constraint === null || constraint === void 0 ? void 0 : constraint.step,
233
+ multiple: constraint === null || constraint === void 0 ? void 0 : constraint.multiple,
234
+ get defaultValue() {
235
+ return getDefaultValue(context, options.name, options.serialize);
236
+ },
237
+ get defaultOptions() {
238
+ return getDefaultOptions(context, options.name, options.serialize);
239
+ },
240
+ get defaultChecked() {
241
+ return isDefaultChecked(context, options.name, options.serialize);
242
+ },
243
+ get touched() {
244
+ return isTouched(context.state, options.name);
245
+ },
246
+ get valid() {
247
+ return typeof getErrors(context.state, options.name) === 'undefined';
248
+ },
249
+ get invalid() {
250
+ return !this.valid;
251
+ },
252
+ get errors() {
253
+ return getErrors(context.state, options.name);
254
+ },
255
+ get fieldErrors() {
256
+ return getFieldErrors(context.state, options.name);
257
+ }
258
+ };
259
+ return Object.assign(metadata, {
260
+ key: options.key,
261
+ name: options.name,
262
+ getFieldset() {
263
+ return getFieldset(context, options);
264
+ },
265
+ getFieldList() {
266
+ return getFieldList(context, options);
267
+ }
268
+ });
269
+ }
270
+
271
+ /**
272
+ * Creates a proxy that dynamically generates field objects when properties are accessed.
273
+ */
274
+ function getFieldset(context, options) {
275
+ return new Proxy({}, {
276
+ get(target, name, receiver) {
277
+ if (typeof name === 'string') {
278
+ return getField(context, _objectSpread2(_objectSpread2({}, options), {}, {
279
+ name: appendPathSegment(options === null || options === void 0 ? void 0 : options.name, name)
280
+ }));
281
+ }
282
+ return Reflect.get(target, name, receiver);
283
+ }
284
+ });
285
+ }
286
+
287
+ /**
288
+ * Creates an array of field objects for list/array inputs
289
+ */
290
+ function getFieldList(context, options) {
291
+ var keys = getListKey(context, options.name);
292
+ return keys.map((key, index) => {
293
+ return getField(context, _objectSpread2(_objectSpread2({}, options), {}, {
294
+ name: appendPathSegment(options.name, index),
295
+ key
296
+ }));
297
+ });
298
+ }
299
+
300
+ export { getConstraint, getDefaultListKey, getDefaultOptions, getDefaultValue, getErrors, getField, getFieldErrors, getFieldList, getFieldset, getFormMetadata, getListKey, initializeState, isDefaultChecked, isTouched, updateState };