@conform-to/react 1.17.1 → 1.19.0
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.
- package/README.md +1 -1
- package/dist/future/dom.d.ts +4 -17
- package/dist/future/dom.js +81 -124
- package/dist/future/dom.mjs +81 -121
- package/dist/future/forms.d.ts +1157 -26
- package/dist/future/forms.js +154 -25
- package/dist/future/forms.mjs +152 -28
- package/dist/future/hooks.d.ts +61 -186
- package/dist/future/hooks.js +336 -433
- package/dist/future/hooks.mjs +340 -430
- package/dist/future/index.d.ts +3 -3
- package/dist/future/index.js +6 -6
- package/dist/future/index.mjs +2 -2
- package/dist/future/intent.js +47 -35
- package/dist/future/intent.mjs +49 -37
- package/dist/future/memoize.d.ts +1 -1
- package/dist/future/memoize.js +1 -1
- package/dist/future/memoize.mjs +1 -1
- package/dist/future/state.d.ts +10 -14
- package/dist/future/state.js +58 -68
- package/dist/future/state.mjs +59 -70
- package/dist/future/types.d.ts +207 -139
- package/dist/future/util.d.ts +8 -12
- package/dist/future/util.js +27 -30
- package/dist/future/util.mjs +24 -27
- package/dist/helpers.d.ts +14 -10
- package/dist/helpers.js +14 -10
- package/dist/helpers.mjs +14 -10
- package/package.json +4 -3
package/dist/future/hooks.js
CHANGED
|
@@ -10,40 +10,22 @@ var util = require('./util.js');
|
|
|
10
10
|
var state = require('./state.js');
|
|
11
11
|
var intent = require('./intent.js');
|
|
12
12
|
var dom = require('./dom.js');
|
|
13
|
+
var reactDom = require('react-dom');
|
|
13
14
|
var jsxRuntime = require('react/jsx-runtime');
|
|
14
15
|
|
|
15
|
-
var _excluded = ["
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
var _excluded = ["name", "form", "defaultValue", "hidden"],
|
|
17
|
+
_excluded2 = ["defaultValue", "multiple", "hidden"],
|
|
18
|
+
_excluded3 = ["defaultValue", "hidden"],
|
|
19
|
+
_excluded4 = ["defaultValue", "value", "hidden"],
|
|
20
|
+
_excluded5 = ["defaultValue", "hidden"];
|
|
18
21
|
var INITIAL_KEY = 'INITIAL_KEY';
|
|
19
|
-
var
|
|
20
|
-
intentName: future.DEFAULT_INTENT_NAME,
|
|
21
|
-
observer: future.createGlobalFormsObserver(),
|
|
22
|
-
serialize: future.serialize,
|
|
23
|
-
shouldValidate: 'onSubmit'
|
|
24
|
-
});
|
|
25
|
-
var FormContextContext = /*#__PURE__*/react.createContext([]);
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Provides form context to child components.
|
|
29
|
-
* Stacks contexts to support nested forms, with latest context taking priority.
|
|
30
|
-
*/
|
|
31
|
-
function FormProvider(props) {
|
|
32
|
-
var stack = react.useContext(FormContextContext);
|
|
33
|
-
var value = react.useMemo(
|
|
34
|
-
// Put the latest form context first to ensure that to be the first one found
|
|
35
|
-
() => [props.context].concat(stack), [stack, props.context]);
|
|
36
|
-
return /*#__PURE__*/jsxRuntime.jsx(FormContextContext.Provider, {
|
|
37
|
-
value: value,
|
|
38
|
-
children: props.children
|
|
39
|
-
});
|
|
40
|
-
}
|
|
22
|
+
var GlobalFormsObserverContext = /*#__PURE__*/react.createContext(future.createGlobalFormsObserver());
|
|
41
23
|
|
|
42
24
|
/**
|
|
43
25
|
* Preserves form field values when its contents are unmounted.
|
|
44
26
|
* Useful for multi-step forms and virtualized lists.
|
|
45
27
|
*
|
|
46
|
-
*
|
|
28
|
+
* See https://conform.guide/api/react/future/PreserveBoundary
|
|
47
29
|
*/
|
|
48
30
|
function PreserveBoundary(props) {
|
|
49
31
|
// name is used as key so React properly unmounts/remounts when switching
|
|
@@ -80,30 +62,6 @@ function PreserveBoundaryImpl(props) {
|
|
|
80
62
|
});
|
|
81
63
|
}
|
|
82
64
|
|
|
83
|
-
/**
|
|
84
|
-
* @deprecated Replaced by the `configureForms` factory API. This will be removed in the next minor version. If you are not ready to migrate, please pin to `v1.16.0`.
|
|
85
|
-
*/
|
|
86
|
-
function FormOptionsProvider(props) {
|
|
87
|
-
var {
|
|
88
|
-
children
|
|
89
|
-
} = props,
|
|
90
|
-
providedOptions = _rollupPluginBabelHelpers.objectWithoutProperties(props, _excluded);
|
|
91
|
-
var defaultOptions = react.useContext(GlobalFormOptionsContext);
|
|
92
|
-
var options = react.useMemo(() => _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, defaultOptions), providedOptions), [defaultOptions, providedOptions]);
|
|
93
|
-
return /*#__PURE__*/jsxRuntime.jsx(GlobalFormOptionsContext.Provider, {
|
|
94
|
-
value: options,
|
|
95
|
-
children: children
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
function useFormContext(formId) {
|
|
99
|
-
var contexts = react.useContext(FormContextContext);
|
|
100
|
-
var context = formId ? contexts.find(context => formId === context.formId) : contexts[0];
|
|
101
|
-
if (!context) {
|
|
102
|
-
throw new Error('No form context found; Have you render a <FormProvider /> with the corresponding form context?');
|
|
103
|
-
}
|
|
104
|
-
return context;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
65
|
/**
|
|
108
66
|
* Core form hook that manages form state, validation, and submission.
|
|
109
67
|
* Handles both sync and async validation, intent dispatching, and DOM updates.
|
|
@@ -146,16 +104,23 @@ function useConform(formRef, options) {
|
|
|
146
104
|
var abortControllerRef = react.useRef(null);
|
|
147
105
|
var handleSubmission = react.useCallback(function (type, result) {
|
|
148
106
|
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : optionsRef.current;
|
|
107
|
+
var normalizedResult = !result.error ? result : _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, result), {}, {
|
|
108
|
+
error: future.normalizeFormError(result.error)
|
|
109
|
+
});
|
|
149
110
|
var intent$1 = result.submission.intent ? intent.deserializeIntent(result.submission.intent) : null;
|
|
150
|
-
var finalResult = intent.applyIntent(
|
|
111
|
+
var finalResult = intent.applyIntent(normalizedResult, intent$1, {
|
|
151
112
|
handlers: intent.intentHandlers
|
|
152
113
|
});
|
|
114
|
+
var formElement = dom.getFormElement(formRef);
|
|
115
|
+
if (formElement && (finalResult.reset || typeof finalResult.targetValue !== 'undefined')) {
|
|
116
|
+
future.dispatchInternalUpdateEvent(formElement);
|
|
117
|
+
}
|
|
153
118
|
setState(state$1 => state.updateState(state$1, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, finalResult), {}, {
|
|
154
119
|
type,
|
|
155
120
|
intent: intent$1,
|
|
156
121
|
ctx: {
|
|
157
122
|
handlers: intent.intentHandlers,
|
|
158
|
-
cancelled: finalResult !==
|
|
123
|
+
cancelled: finalResult !== normalizedResult,
|
|
159
124
|
reset(defaultValue) {
|
|
160
125
|
return state.initializeState({
|
|
161
126
|
defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : options.defaultValue
|
|
@@ -165,12 +130,11 @@ function useConform(formRef, options) {
|
|
|
165
130
|
})));
|
|
166
131
|
|
|
167
132
|
// TODO: move on error handler to a new effect
|
|
168
|
-
|
|
169
|
-
if (formElement && result.error) {
|
|
133
|
+
if (formElement && finalResult.error) {
|
|
170
134
|
var _optionsRef$current$o, _optionsRef$current;
|
|
171
135
|
(_optionsRef$current$o = (_optionsRef$current = optionsRef.current).onError) === null || _optionsRef$current$o === void 0 || _optionsRef$current$o.call(_optionsRef$current, {
|
|
172
136
|
formElement,
|
|
173
|
-
error:
|
|
137
|
+
error: finalResult.error,
|
|
174
138
|
intent: intent$1
|
|
175
139
|
});
|
|
176
140
|
}
|
|
@@ -178,6 +142,10 @@ function useConform(formRef, options) {
|
|
|
178
142
|
}, [formRef, optionsRef]);
|
|
179
143
|
if (options.key !== keyRef.current) {
|
|
180
144
|
keyRef.current = options.key;
|
|
145
|
+
var formElement = dom.getFormElement(formRef);
|
|
146
|
+
if (formElement) {
|
|
147
|
+
future.dispatchInternalUpdateEvent(formElement);
|
|
148
|
+
}
|
|
181
149
|
setState(state.initializeState({
|
|
182
150
|
defaultValue: options.defaultValue
|
|
183
151
|
}));
|
|
@@ -204,52 +172,56 @@ function useConform(formRef, options) {
|
|
|
204
172
|
}, [formRef, state$1.resetKey, state$1.defaultValue, optionsRef]);
|
|
205
173
|
useSafeLayoutEffect(() => {
|
|
206
174
|
if (state$1.targetValue) {
|
|
207
|
-
var
|
|
208
|
-
if (!
|
|
175
|
+
var _formElement = dom.getFormElement(formRef);
|
|
176
|
+
if (!_formElement) {
|
|
209
177
|
// eslint-disable-next-line no-console
|
|
210
178
|
console.error('Failed to update form value; No form element found');
|
|
211
179
|
return;
|
|
212
180
|
}
|
|
213
|
-
dom.updateFormValue(
|
|
181
|
+
dom.updateFormValue(_formElement, state$1.targetValue, optionsRef.current.serialize);
|
|
214
182
|
}
|
|
215
183
|
pendingValueRef.current = undefined;
|
|
216
184
|
}, [formRef, state$1.targetValue, optionsRef]);
|
|
217
185
|
var handleSubmit = react.useCallback(event => {
|
|
218
|
-
var _abortControllerRef$c2
|
|
186
|
+
var _abortControllerRef$c2;
|
|
219
187
|
var abortController = new AbortController();
|
|
220
188
|
|
|
221
189
|
// Keep track of the abort controller so we can cancel the previous request if a new one is made
|
|
222
190
|
(_abortControllerRef$c2 = abortControllerRef.current) === null || _abortControllerRef$c2 === void 0 || _abortControllerRef$c2.abort('A new submission is made');
|
|
223
191
|
abortControllerRef.current = abortController;
|
|
224
|
-
var formData;
|
|
225
192
|
var result;
|
|
226
193
|
var resolvedValue;
|
|
194
|
+
var formElement = event.currentTarget;
|
|
195
|
+
var submitEvent = dom.getSubmitEvent(event);
|
|
196
|
+
var formData = future.getFormData(formElement, submitEvent.submitter);
|
|
197
|
+
var submission = future.parseSubmission(formData, {
|
|
198
|
+
intentName: optionsRef.current.intentName
|
|
199
|
+
});
|
|
227
200
|
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
resolvedValue = lastAsyncResultRef.current.resolvedValue;
|
|
233
|
-
} else {
|
|
234
|
-
var _optionsRef$current$o2, _optionsRef$current2;
|
|
235
|
-
var formElement = event.currentTarget;
|
|
236
|
-
var submitEvent = dom.getSubmitEvent(event);
|
|
237
|
-
formData = future.getFormData(formElement, submitEvent.submitter);
|
|
238
|
-
var submission = future.parseSubmission(formData, {
|
|
239
|
-
intentName: optionsRef.current.intentName
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
// Patch missing fields in the submission object
|
|
243
|
-
for (var element of formElement.elements) {
|
|
244
|
-
if (future.isFieldElement(element) && element.name) {
|
|
245
|
-
submission.fields = util.appendUniqueItem(submission.fields, element.name);
|
|
246
|
-
}
|
|
201
|
+
// Patch missing fields in the submission object
|
|
202
|
+
for (var element of formElement.elements) {
|
|
203
|
+
if (future.isFieldElement(element) && element.name) {
|
|
204
|
+
submission.fields = util.appendUniqueItem(submission.fields, element.name);
|
|
247
205
|
}
|
|
206
|
+
}
|
|
248
207
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
208
|
+
// Override submission value if the pending value is not applied yet (i.e. batch updates)
|
|
209
|
+
if (pendingValueRef.current !== undefined) {
|
|
210
|
+
submission.payload = pendingValueRef.current;
|
|
211
|
+
}
|
|
212
|
+
var lastAsyncResult = lastAsyncResultRef.current;
|
|
213
|
+
|
|
214
|
+
// Clear the last async result so it won't affect the next submission
|
|
215
|
+
lastAsyncResultRef.current = null;
|
|
216
|
+
if (lastAsyncResult &&
|
|
217
|
+
// Only default submission will be re-submitted after async validation
|
|
218
|
+
!submission.intent &&
|
|
219
|
+
// Ensure the submission payload is the same as the one being validated
|
|
220
|
+
future.deepEqual(submission.payload, lastAsyncResult.result.submission.payload)) {
|
|
221
|
+
result = lastAsyncResult.result;
|
|
222
|
+
resolvedValue = lastAsyncResult.resolvedValue;
|
|
223
|
+
} else {
|
|
224
|
+
var _optionsRef$current$o2, _optionsRef$current2;
|
|
253
225
|
var value = intent.resolveIntent(submission);
|
|
254
226
|
var submissionResult = future.report(submission, {
|
|
255
227
|
keepFiles: true,
|
|
@@ -260,7 +232,7 @@ function useConform(formRef, options) {
|
|
|
260
232
|
value !== undefined ? (_optionsRef$current$o2 = (_optionsRef$current2 = optionsRef.current).onValidate) === null || _optionsRef$current$o2 === void 0 ? void 0 : _optionsRef$current$o2.call(_optionsRef$current2, {
|
|
261
233
|
payload: value,
|
|
262
234
|
error: {
|
|
263
|
-
formErrors:
|
|
235
|
+
formErrors: null,
|
|
264
236
|
fieldErrors: {}
|
|
265
237
|
},
|
|
266
238
|
intent: submission.intent ? intent.deserializeIntent(submission.intent) : null,
|
|
@@ -294,16 +266,20 @@ function useConform(formRef, options) {
|
|
|
294
266
|
|
|
295
267
|
// If the form is meant to be submitted and there is no error
|
|
296
268
|
if (submissionResult.error === null && !submission.intent) {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
//
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
269
|
+
// Keep track of the validated payload and resume submission on the next task.
|
|
270
|
+
// Calling requestSubmit() directly from the async callback, or from a
|
|
271
|
+
// microtask, can still be ignored before the native submission lifecycle
|
|
272
|
+
// has fully settled.
|
|
273
|
+
setTimeout(() => {
|
|
274
|
+
if (abortController.signal.aborted) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
lastAsyncResultRef.current = {
|
|
278
|
+
resolvedValue: value,
|
|
279
|
+
result: submissionResult
|
|
280
|
+
};
|
|
281
|
+
future.requestSubmit(formElement, submitEvent.submitter);
|
|
282
|
+
}, 0);
|
|
307
283
|
}
|
|
308
284
|
}
|
|
309
285
|
});
|
|
@@ -349,287 +325,20 @@ function useConform(formRef, options) {
|
|
|
349
325
|
return [state$1, handleSubmit];
|
|
350
326
|
}
|
|
351
327
|
|
|
352
|
-
/**
|
|
353
|
-
* The main React hook for form management. Handles form state, validation, and submission
|
|
354
|
-
* while providing access to form metadata, field objects, and form actions.
|
|
355
|
-
*
|
|
356
|
-
* It can be called in two ways:
|
|
357
|
-
* - **Schema first**: Pass a schema as the first argument for automatic validation with type inference
|
|
358
|
-
* - **Manual configuration**: Pass options with custom `onValidate` handler for manual validation
|
|
359
|
-
*
|
|
360
|
-
* @see https://conform.guide/api/react/future/useForm
|
|
361
|
-
* @example Schema first setup with zod:
|
|
362
|
-
*
|
|
363
|
-
* ```tsx
|
|
364
|
-
* const { form, fields } = useForm(zodSchema, {
|
|
365
|
-
* lastResult,
|
|
366
|
-
* shouldValidate: 'onBlur',
|
|
367
|
-
* });
|
|
368
|
-
*
|
|
369
|
-
* return (
|
|
370
|
-
* <form {...form.props}>
|
|
371
|
-
* <input name={fields.email.name} defaultValue={fields.email.defaultValue} />
|
|
372
|
-
* <div>{fields.email.errors}</div>
|
|
373
|
-
* </form>
|
|
374
|
-
* );
|
|
375
|
-
* ```
|
|
376
|
-
*
|
|
377
|
-
* @example Manual configuration setup with custom validation:
|
|
378
|
-
*
|
|
379
|
-
* ```tsx
|
|
380
|
-
* const { form, fields } = useForm({
|
|
381
|
-
* onValidate({ payload, error }) {
|
|
382
|
-
* if (!payload.email) {
|
|
383
|
-
* error.fieldErrors.email = ['Required'];
|
|
384
|
-
* }
|
|
385
|
-
* return error;
|
|
386
|
-
* }
|
|
387
|
-
* });
|
|
388
|
-
*
|
|
389
|
-
* return (
|
|
390
|
-
* <form {...form.props}>
|
|
391
|
-
* <input name={fields.email.name} defaultValue={fields.email.defaultValue} />
|
|
392
|
-
* <div>{fields.email.errors}</div>
|
|
393
|
-
* </form>
|
|
394
|
-
* );
|
|
395
|
-
* ```
|
|
396
|
-
*/
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* @deprecated Use `useForm(schema, options)` instead for better type inference.
|
|
400
|
-
*/
|
|
401
|
-
|
|
402
|
-
function useForm(schemaOrOptions, maybeOptions) {
|
|
403
|
-
var _options$onError;
|
|
404
|
-
var schema;
|
|
405
|
-
var options;
|
|
406
|
-
if (maybeOptions) {
|
|
407
|
-
schema = schemaOrOptions;
|
|
408
|
-
options = maybeOptions;
|
|
409
|
-
} else {
|
|
410
|
-
var fullOptions = schemaOrOptions;
|
|
411
|
-
options = fullOptions;
|
|
412
|
-
schema = fullOptions.schema;
|
|
413
|
-
}
|
|
414
|
-
var {
|
|
415
|
-
id,
|
|
416
|
-
constraint
|
|
417
|
-
} = options;
|
|
418
|
-
var globalOptions = react.useContext(GlobalFormOptionsContext);
|
|
419
|
-
var optionsRef = useLatest(options);
|
|
420
|
-
var globalOptionsRef = useLatest(globalOptions);
|
|
421
|
-
var fallbackId = react.useId();
|
|
422
|
-
var formId = id !== null && id !== void 0 ? id : "form-".concat(fallbackId);
|
|
423
|
-
var [state$1, handleSubmit] = useConform(formId, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, options), {}, {
|
|
424
|
-
serialize: globalOptions.serialize,
|
|
425
|
-
intentName: globalOptions.intentName,
|
|
426
|
-
onError: (_options$onError = options.onError) !== null && _options$onError !== void 0 ? _options$onError : dom.focusFirstInvalidField,
|
|
427
|
-
onValidate(ctx) {
|
|
428
|
-
var _options$onValidate, _options$onValidate2, _options;
|
|
429
|
-
if (schema) {
|
|
430
|
-
var standardResult = schema['~standard'].validate(ctx.payload);
|
|
431
|
-
if (standardResult instanceof Promise) {
|
|
432
|
-
return standardResult.then(actualStandardResult => {
|
|
433
|
-
if (typeof options.onValidate === 'function') {
|
|
434
|
-
throw new Error('The "onValidate" handler is not supported when used with asynchronous schema validation.');
|
|
435
|
-
}
|
|
436
|
-
return util.resolveStandardSchemaResult(actualStandardResult);
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
var resolvedResult = util.resolveStandardSchemaResult(standardResult);
|
|
440
|
-
if (!options.onValidate) {
|
|
441
|
-
return resolvedResult;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// Update the schema error in the context
|
|
445
|
-
if (resolvedResult.error) {
|
|
446
|
-
ctx.error = resolvedResult.error;
|
|
447
|
-
}
|
|
448
|
-
ctx.schemaValue = resolvedResult.value;
|
|
449
|
-
var validateResult = util.resolveValidateResult(options.onValidate(ctx));
|
|
450
|
-
if (validateResult.syncResult) {
|
|
451
|
-
var _validateResult$syncR, _validateResult$syncR2;
|
|
452
|
-
(_validateResult$syncR2 = (_validateResult$syncR = validateResult.syncResult).value) !== null && _validateResult$syncR2 !== void 0 ? _validateResult$syncR2 : _validateResult$syncR.value = resolvedResult.value;
|
|
453
|
-
}
|
|
454
|
-
if (validateResult.asyncResult) {
|
|
455
|
-
validateResult.asyncResult = validateResult.asyncResult.then(result => {
|
|
456
|
-
var _result$value;
|
|
457
|
-
(_result$value = result.value) !== null && _result$value !== void 0 ? _result$value : result.value = resolvedResult.value;
|
|
458
|
-
return result;
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
return [validateResult.syncResult, validateResult.asyncResult];
|
|
462
|
-
}
|
|
463
|
-
return (_options$onValidate = (_options$onValidate2 = (_options = options).onValidate) === null || _options$onValidate2 === void 0 ? void 0 : _options$onValidate2.call(_options, ctx)) !== null && _options$onValidate !== void 0 ? _options$onValidate : {
|
|
464
|
-
// To avoid conform falling back to server validation,
|
|
465
|
-
// if neither schema nor validation handler is provided,
|
|
466
|
-
// we just treat it as a valid client submission
|
|
467
|
-
error: null
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
}));
|
|
471
|
-
var intent = useIntent(formId);
|
|
472
|
-
var context = react.useMemo(() => ({
|
|
473
|
-
formId,
|
|
474
|
-
state: state$1,
|
|
475
|
-
constraint: constraint !== null && constraint !== void 0 ? constraint : null,
|
|
476
|
-
handleSubmit,
|
|
477
|
-
handleInput(event) {
|
|
478
|
-
var _optionsRef$current$o4, _optionsRef$current4, _globalOptionsRef$cur;
|
|
479
|
-
if (!future.isFieldElement(event.target) || event.target.name === '' || event.target.form === null || event.target.form !== dom.getFormElement(formId)) {
|
|
480
|
-
return;
|
|
481
|
-
}
|
|
482
|
-
(_optionsRef$current$o4 = (_optionsRef$current4 = optionsRef.current).onInput) === null || _optionsRef$current$o4 === void 0 || _optionsRef$current$o4.call(_optionsRef$current4, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, event), {}, {
|
|
483
|
-
target: event.target,
|
|
484
|
-
currentTarget: event.target.form
|
|
485
|
-
}));
|
|
486
|
-
if (event.defaultPrevented) {
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
var {
|
|
490
|
-
shouldValidate = globalOptionsRef.current.shouldValidate,
|
|
491
|
-
shouldRevalidate = (_globalOptionsRef$cur = globalOptionsRef.current.shouldRevalidate) !== null && _globalOptionsRef$cur !== void 0 ? _globalOptionsRef$cur : shouldValidate
|
|
492
|
-
} = optionsRef.current;
|
|
493
|
-
if (state.isTouched(state$1, event.target.name) ? shouldRevalidate === 'onInput' : shouldValidate === 'onInput') {
|
|
494
|
-
intent.validate(event.target.name);
|
|
495
|
-
}
|
|
496
|
-
},
|
|
497
|
-
handleBlur(event) {
|
|
498
|
-
var _optionsRef$current$o5, _optionsRef$current5, _globalOptionsRef$cur2;
|
|
499
|
-
if (!future.isFieldElement(event.target) || event.target.name === '' || event.target.form === null || event.target.form !== dom.getFormElement(formId)) {
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
(_optionsRef$current$o5 = (_optionsRef$current5 = optionsRef.current).onBlur) === null || _optionsRef$current$o5 === void 0 || _optionsRef$current$o5.call(_optionsRef$current5, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, event), {}, {
|
|
503
|
-
target: event.target,
|
|
504
|
-
currentTarget: event.target.form
|
|
505
|
-
}));
|
|
506
|
-
if (event.defaultPrevented) {
|
|
507
|
-
return;
|
|
508
|
-
}
|
|
509
|
-
var {
|
|
510
|
-
shouldValidate = globalOptionsRef.current.shouldValidate,
|
|
511
|
-
shouldRevalidate = (_globalOptionsRef$cur2 = globalOptionsRef.current.shouldRevalidate) !== null && _globalOptionsRef$cur2 !== void 0 ? _globalOptionsRef$cur2 : shouldValidate
|
|
512
|
-
} = optionsRef.current;
|
|
513
|
-
if (state.isTouched(state$1, event.target.name) ? shouldRevalidate === 'onBlur' : shouldValidate === 'onBlur') {
|
|
514
|
-
intent.validate(event.target.name);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
}), [formId, state$1, constraint, handleSubmit, intent, optionsRef, globalOptionsRef]);
|
|
518
|
-
var form = react.useMemo(() => state.getFormMetadata(context, {
|
|
519
|
-
serialize: globalOptions.serialize,
|
|
520
|
-
extendFieldMetadata: globalOptions.defineCustomMetadata
|
|
521
|
-
}), [context, globalOptions.serialize, globalOptions.defineCustomMetadata]);
|
|
522
|
-
var fields = react.useMemo(() => state.getFieldset(context, {
|
|
523
|
-
serialize: globalOptions.serialize,
|
|
524
|
-
extendFieldMetadata: globalOptions.defineCustomMetadata
|
|
525
|
-
}), [context, globalOptions.serialize, globalOptions.defineCustomMetadata]);
|
|
526
|
-
return {
|
|
527
|
-
form,
|
|
528
|
-
fields,
|
|
529
|
-
intent
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
/**
|
|
534
|
-
* A React hook that provides access to form-level metadata and state.
|
|
535
|
-
* Requires `FormProvider` context when used in child components.
|
|
536
|
-
*
|
|
537
|
-
* @see https://conform.guide/api/react/future/useFormMetadata
|
|
538
|
-
* @example
|
|
539
|
-
* ```tsx
|
|
540
|
-
* function ErrorSummary() {
|
|
541
|
-
* const form = useFormMetadata();
|
|
542
|
-
*
|
|
543
|
-
* if (form.valid) return null;
|
|
544
|
-
*
|
|
545
|
-
* return (
|
|
546
|
-
* <div>Please fix {Object.keys(form.fieldErrors).length} errors</div>
|
|
547
|
-
* );
|
|
548
|
-
* }
|
|
549
|
-
* ```
|
|
550
|
-
*/
|
|
551
|
-
function useFormMetadata() {
|
|
552
|
-
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
553
|
-
var globalOptions = react.useContext(GlobalFormOptionsContext);
|
|
554
|
-
var context = useFormContext(options.formId);
|
|
555
|
-
var formMetadata = react.useMemo(() => state.getFormMetadata(context, {
|
|
556
|
-
serialize: globalOptions.serialize,
|
|
557
|
-
extendFieldMetadata: globalOptions.defineCustomMetadata
|
|
558
|
-
}), [context, globalOptions.serialize, globalOptions.defineCustomMetadata]);
|
|
559
|
-
return formMetadata;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
/**
|
|
563
|
-
* A React hook that provides access to a specific field's metadata and state.
|
|
564
|
-
* Requires `FormProvider` context when used in child components.
|
|
565
|
-
*
|
|
566
|
-
* @see https://conform.guide/api/react/future/useField
|
|
567
|
-
* @example
|
|
568
|
-
* ```tsx
|
|
569
|
-
* function FormField({ name, label }) {
|
|
570
|
-
* const field = useField(name);
|
|
571
|
-
*
|
|
572
|
-
* return (
|
|
573
|
-
* <div>
|
|
574
|
-
* <label htmlFor={field.id}>{label}</label>
|
|
575
|
-
* <input id={field.id} name={field.name} defaultValue={field.defaultValue} />
|
|
576
|
-
* {field.errors && <div>{field.errors.join(', ')}</div>}
|
|
577
|
-
* </div>
|
|
578
|
-
* );
|
|
579
|
-
* }
|
|
580
|
-
* ```
|
|
581
|
-
*/
|
|
582
|
-
function useField(name) {
|
|
583
|
-
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
584
|
-
var globalOptions = react.useContext(GlobalFormOptionsContext);
|
|
585
|
-
var context = useFormContext(options.formId);
|
|
586
|
-
var field = react.useMemo(() => state.getField(context, {
|
|
587
|
-
name,
|
|
588
|
-
serialize: globalOptions.serialize,
|
|
589
|
-
extendFieldMetadata: globalOptions.defineCustomMetadata
|
|
590
|
-
}), [context, name, globalOptions.serialize, globalOptions.defineCustomMetadata]);
|
|
591
|
-
return field;
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
/**
|
|
595
|
-
* A React hook that provides an intent dispatcher for programmatic form actions.
|
|
596
|
-
* Intent dispatchers allow you to trigger form operations like validation, field updates,
|
|
597
|
-
* and array manipulations without manual form submission.
|
|
598
|
-
*
|
|
599
|
-
* @see https://conform.guide/api/react/future/useIntent
|
|
600
|
-
* @example
|
|
601
|
-
* ```tsx
|
|
602
|
-
* function ResetButton() {
|
|
603
|
-
* const buttonRef = useRef<HTMLButtonElement>(null);
|
|
604
|
-
* const intent = useIntent(buttonRef);
|
|
605
|
-
*
|
|
606
|
-
* return (
|
|
607
|
-
* <button type="button" ref={buttonRef} onClick={() => intent.reset()}>
|
|
608
|
-
* Reset Form
|
|
609
|
-
* </button>
|
|
610
|
-
* );
|
|
611
|
-
* }
|
|
612
|
-
* ```
|
|
613
|
-
*/
|
|
614
|
-
function useIntent(formRef) {
|
|
615
|
-
var globalOptions = react.useContext(GlobalFormOptionsContext);
|
|
616
|
-
return react.useMemo(() => dom.createIntentDispatcher(() => dom.getFormElement(formRef), globalOptions.intentName), [formRef, globalOptions.intentName]);
|
|
617
|
-
}
|
|
618
|
-
|
|
619
328
|
/**
|
|
620
329
|
* A React hook that lets you sync the state of an input and dispatch native form events from it.
|
|
621
|
-
* This is useful when emulating native input behavior — typically by rendering a hidden base
|
|
330
|
+
* This is useful when emulating native input behavior — typically by rendering a hidden base control
|
|
622
331
|
* and syncing it with a custom input.
|
|
623
332
|
*
|
|
624
|
-
*
|
|
333
|
+
* **Example:**
|
|
625
334
|
* ```ts
|
|
626
335
|
* const control = useControl(options);
|
|
627
336
|
* ```
|
|
628
337
|
*/
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
338
|
+
|
|
339
|
+
function useControl() {
|
|
340
|
+
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
341
|
+
var observer = react.useContext(GlobalFormsObserverContext);
|
|
633
342
|
var inputRef = react.useRef(null);
|
|
634
343
|
var formRef = react.useMemo(() => ({
|
|
635
344
|
get current() {
|
|
@@ -641,29 +350,40 @@ function useControl(options) {
|
|
|
641
350
|
return Array.isArray(input) ? (_input$0$form = (_input$ = input[0]) === null || _input$ === void 0 ? void 0 : _input$.form) !== null && _input$0$form !== void 0 ? _input$0$form : null : input.form;
|
|
642
351
|
}
|
|
643
352
|
}), []);
|
|
353
|
+
var [defaultValue, setDefaultValue] = react.useState(() => dom.deriveDefaultPayload(options));
|
|
354
|
+
var pendingDefaultValueSyncRef = react.useRef(false);
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Keep defaultValue in sync with external option updates during render.
|
|
358
|
+
* This is required for structural controls where hidden descendants must be
|
|
359
|
+
* rendered in the same cycle as form state updates (e.g. update intents).
|
|
360
|
+
*/
|
|
361
|
+
if (pendingDefaultValueSyncRef.current && inputRef.current && future.isGlobalInstance(inputRef.current, 'HTMLFieldSetElement')) {
|
|
362
|
+
pendingDefaultValueSyncRef.current = false;
|
|
363
|
+
setDefaultValue(() => dom.deriveDefaultPayload(options));
|
|
364
|
+
}
|
|
644
365
|
var eventDispatched = react.useRef({});
|
|
645
|
-
var
|
|
646
|
-
var snapshotRef = react.useRef(defaultSnapshot);
|
|
366
|
+
var snapshotRef = react.useRef(defaultValue);
|
|
647
367
|
var optionsRef = react.useRef(options);
|
|
648
368
|
react.useEffect(() => {
|
|
649
369
|
optionsRef.current = options;
|
|
650
370
|
});
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
371
|
+
react.useEffect(() => observer.onInternalUpdate(event => {
|
|
372
|
+
var input = inputRef.current;
|
|
373
|
+
if (input && input instanceof HTMLFieldSetElement && event.target === input.form) {
|
|
374
|
+
pendingDefaultValueSyncRef.current = true;
|
|
375
|
+
}
|
|
376
|
+
}), [observer]);
|
|
377
|
+
var payloadSnapshot = react.useSyncExternalStore(react.useCallback(callback => observer.onFieldUpdate(event => {
|
|
378
|
+
var _inputRef$current;
|
|
656
379
|
var input = event.target;
|
|
657
|
-
if (Array.isArray(inputRef.current) ? inputRef.current.some(item => item === input) : inputRef.current === input) {
|
|
380
|
+
if (Array.isArray(inputRef.current) ? inputRef.current.some(item => item === input) : (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.contains(input)) {
|
|
658
381
|
callback();
|
|
659
382
|
}
|
|
660
383
|
}), [observer]), () => {
|
|
661
384
|
var input = inputRef.current;
|
|
662
385
|
var prev = snapshotRef.current;
|
|
663
|
-
var next =
|
|
664
|
-
value: dom.getRadioGroupValue(input),
|
|
665
|
-
options: dom.getCheckboxGroupValue(input)
|
|
666
|
-
} : dom.getInputSnapshot(input);
|
|
386
|
+
var next = input ? dom.resolveControlPayload(input) : defaultValue;
|
|
667
387
|
if (future.deepEqual(prev, next)) {
|
|
668
388
|
return prev;
|
|
669
389
|
}
|
|
@@ -673,7 +393,8 @@ function useControl(options) {
|
|
|
673
393
|
react.useEffect(() => {
|
|
674
394
|
var createEventListener = listener => {
|
|
675
395
|
return event => {
|
|
676
|
-
|
|
396
|
+
var _inputRef$current2;
|
|
397
|
+
if (Array.isArray(inputRef.current) ? inputRef.current.some(item => item === event.target) : event.target instanceof Node && ((_inputRef$current2 = inputRef.current) === null || _inputRef$current2 === void 0 ? void 0 : _inputRef$current2.contains(event.target))) {
|
|
677
398
|
var timer = eventDispatched.current[listener];
|
|
678
399
|
if (timer) {
|
|
679
400
|
clearTimeout(timer);
|
|
@@ -682,8 +403,8 @@ function useControl(options) {
|
|
|
682
403
|
eventDispatched.current[listener] = undefined;
|
|
683
404
|
});
|
|
684
405
|
if (listener === 'focus') {
|
|
685
|
-
var _optionsRef$
|
|
686
|
-
(_optionsRef$
|
|
406
|
+
var _optionsRef$current4, _optionsRef$current4$;
|
|
407
|
+
(_optionsRef$current4 = optionsRef.current) === null || _optionsRef$current4 === void 0 || (_optionsRef$current4$ = _optionsRef$current4.onFocus) === null || _optionsRef$current4$ === void 0 || _optionsRef$current4$.call(_optionsRef$current4);
|
|
687
408
|
}
|
|
688
409
|
}
|
|
689
410
|
};
|
|
@@ -701,10 +422,62 @@ function useControl(options) {
|
|
|
701
422
|
};
|
|
702
423
|
}, []);
|
|
703
424
|
return {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
425
|
+
defaultValue,
|
|
426
|
+
get payload() {
|
|
427
|
+
if (payloadSnapshot != null && 'parse' in options) {
|
|
428
|
+
try {
|
|
429
|
+
return options.parse(payloadSnapshot);
|
|
430
|
+
} catch (error) {
|
|
431
|
+
var payloadText = '';
|
|
432
|
+
try {
|
|
433
|
+
payloadText = JSON.stringify(payloadSnapshot, null, 2);
|
|
434
|
+
} catch (_unused) {
|
|
435
|
+
payloadText = '<unserializable payload>';
|
|
436
|
+
}
|
|
437
|
+
throw new Error("Failed to parse the payload. Received ".concat(payloadText, "."), {
|
|
438
|
+
cause: error
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return payloadSnapshot;
|
|
443
|
+
},
|
|
444
|
+
get value() {
|
|
445
|
+
if (payloadSnapshot === null) {
|
|
446
|
+
return '';
|
|
447
|
+
}
|
|
448
|
+
if (typeof payloadSnapshot === 'string') {
|
|
449
|
+
return payloadSnapshot;
|
|
450
|
+
}
|
|
451
|
+
return undefined;
|
|
452
|
+
},
|
|
453
|
+
get checked() {
|
|
454
|
+
if (payloadSnapshot === null) {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
var value = 'value' in options && options.value ? options.value : 'on';
|
|
458
|
+
if (payloadSnapshot === value) {
|
|
459
|
+
return true;
|
|
460
|
+
}
|
|
461
|
+
return undefined;
|
|
462
|
+
},
|
|
463
|
+
get options() {
|
|
464
|
+
if (payloadSnapshot === null) {
|
|
465
|
+
return [];
|
|
466
|
+
}
|
|
467
|
+
if (Array.isArray(payloadSnapshot) && payloadSnapshot.every(item => typeof item === 'string')) {
|
|
468
|
+
return payloadSnapshot;
|
|
469
|
+
}
|
|
470
|
+
return undefined;
|
|
471
|
+
},
|
|
472
|
+
get files() {
|
|
473
|
+
if (payloadSnapshot === null) {
|
|
474
|
+
return [];
|
|
475
|
+
}
|
|
476
|
+
if (Array.isArray(payloadSnapshot) && payloadSnapshot.every(item => future.isGlobalInstance(item, 'File'))) {
|
|
477
|
+
return payloadSnapshot;
|
|
478
|
+
}
|
|
479
|
+
return undefined;
|
|
480
|
+
},
|
|
708
481
|
formRef,
|
|
709
482
|
register: react.useCallback(element => {
|
|
710
483
|
if (!element) {
|
|
@@ -718,17 +491,16 @@ function useControl(options) {
|
|
|
718
491
|
element.hidden = true;
|
|
719
492
|
element.removeAttribute('type');
|
|
720
493
|
}
|
|
721
|
-
if (shouldHandleFocus) {
|
|
722
|
-
dom.makeInputFocusable(element);
|
|
723
|
-
}
|
|
724
494
|
if (element.type === 'checkbox' || element.type === 'radio') {
|
|
725
|
-
var _optionsRef$current$v, _optionsRef$current7;
|
|
726
495
|
// React set the value as empty string incorrectly when the value is undefined
|
|
727
496
|
// This make sure the checkbox value falls back to the default value "on" properly
|
|
728
|
-
//
|
|
729
|
-
|
|
497
|
+
// See https://github.com/facebook/react/issues/17590
|
|
498
|
+
var value = 'value' in optionsRef.current && optionsRef.current.value ? optionsRef.current.value : 'on';
|
|
499
|
+
element.value = value;
|
|
730
500
|
}
|
|
731
501
|
dom.initializeField(element, optionsRef.current);
|
|
502
|
+
} else if (element instanceof HTMLFieldSetElement) {
|
|
503
|
+
inputRef.current = element;
|
|
732
504
|
} else {
|
|
733
505
|
var _inputs$0$name, _inputs$, _inputs$0$type, _inputs$2;
|
|
734
506
|
var inputs = Array.from(element);
|
|
@@ -738,39 +510,36 @@ function useControl(options) {
|
|
|
738
510
|
throw new Error('You can only register a checkbox or radio group with the same name');
|
|
739
511
|
}
|
|
740
512
|
inputRef.current = inputs;
|
|
741
|
-
|
|
742
|
-
var
|
|
743
|
-
|
|
744
|
-
dom.
|
|
513
|
+
if ('defaultValue' in optionsRef.current) {
|
|
514
|
+
for (var input of inputs) {
|
|
515
|
+
var _optionsRef$current5;
|
|
516
|
+
dom.initializeField(input, {
|
|
517
|
+
// We will not be uitlizing defaultChecked / value on checkbox / radio group
|
|
518
|
+
defaultValue: (_optionsRef$current5 = optionsRef.current) === null || _optionsRef$current5 === void 0 ? void 0 : _optionsRef$current5.defaultValue
|
|
519
|
+
});
|
|
745
520
|
}
|
|
746
|
-
dom.initializeField(input, {
|
|
747
|
-
// We will not be uitlizing defaultChecked / value on checkbox / radio group
|
|
748
|
-
defaultValue: (_optionsRef$current8 = optionsRef.current) === null || _optionsRef$current8 === void 0 ? void 0 : _optionsRef$current8.defaultValue
|
|
749
|
-
});
|
|
750
521
|
}
|
|
751
522
|
}
|
|
752
|
-
}, [
|
|
523
|
+
}, []),
|
|
753
524
|
change: react.useCallback(value => {
|
|
754
525
|
if (!eventDispatched.current.change) {
|
|
755
|
-
var
|
|
756
|
-
var
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
// So we will pick the first element that should be checked
|
|
767
|
-
return isChecked;
|
|
768
|
-
default:
|
|
769
|
-
return false;
|
|
770
|
-
}
|
|
771
|
-
}) : inputRef.current;
|
|
526
|
+
var element = inputRef.current;
|
|
527
|
+
var isFieldset = element instanceof HTMLFieldSetElement;
|
|
528
|
+
var serializedValue = value == null ? value : 'serialize' in optionsRef.current && optionsRef.current.serialize ? optionsRef.current.serialize(value) : value;
|
|
529
|
+
if (isFieldset) {
|
|
530
|
+
// Fieldset mode renders hidden descendant inputs from defaultValue.
|
|
531
|
+
// Flush this update before dispatching events so listeners see the
|
|
532
|
+
// latest form structure in the same input/change cycle.
|
|
533
|
+
reactDom.flushSync(() => {
|
|
534
|
+
setDefaultValue(serializedValue);
|
|
535
|
+
});
|
|
536
|
+
}
|
|
772
537
|
if (element) {
|
|
773
|
-
future.change(element,
|
|
538
|
+
future.change(element, serializedValue, {
|
|
539
|
+
// Sometimes no change is made on the inputs but done through DOM mutation.
|
|
540
|
+
// But we still want to dispatch the event to notify listeners.
|
|
541
|
+
forceDispatch: isFieldset
|
|
542
|
+
});
|
|
774
543
|
}
|
|
775
544
|
}
|
|
776
545
|
if (eventDispatched.current.change) {
|
|
@@ -812,8 +581,9 @@ function useControl(options) {
|
|
|
812
581
|
* Returns `undefined` when the form element is not available (e.g., on SSR or initial client render),
|
|
813
582
|
* unless a `fallback` is provided.
|
|
814
583
|
*
|
|
815
|
-
*
|
|
816
|
-
*
|
|
584
|
+
* See https://conform.guide/api/react/future/useFormData
|
|
585
|
+
*
|
|
586
|
+
* **Example:**
|
|
817
587
|
* ```ts
|
|
818
588
|
* const value = useFormData(
|
|
819
589
|
* formRef,
|
|
@@ -823,9 +593,7 @@ function useControl(options) {
|
|
|
823
593
|
*/
|
|
824
594
|
|
|
825
595
|
function useFormData(formRef, select, options) {
|
|
826
|
-
var
|
|
827
|
-
observer
|
|
828
|
-
} = react.useContext(GlobalFormOptionsContext);
|
|
596
|
+
var observer = react.useContext(GlobalFormsObserverContext);
|
|
829
597
|
var valueRef = react.useRef();
|
|
830
598
|
var formDataRef = react.useRef();
|
|
831
599
|
var value = react.useSyncExternalStore(react.useCallback(callback => {
|
|
@@ -881,19 +649,154 @@ function useLatest(value) {
|
|
|
881
649
|
return ref;
|
|
882
650
|
}
|
|
883
651
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
652
|
+
/**
|
|
653
|
+
* A component that renders hidden base control(s) based on the shape of defaultValue.
|
|
654
|
+
* Used with useControl to sync complex values with form data.
|
|
655
|
+
*
|
|
656
|
+
* **Example:**
|
|
657
|
+
* ```tsx
|
|
658
|
+
* const control = useControl<{ street: string; city: string }>({
|
|
659
|
+
* defaultValue: { street: '123 Main St', city: 'Anytown' },
|
|
660
|
+
* parse(payload) {
|
|
661
|
+
* if (
|
|
662
|
+
* typeof payload === 'object' &&
|
|
663
|
+
* payload !== null &&
|
|
664
|
+
* 'street' in payload &&
|
|
665
|
+
* 'city' in payload &&
|
|
666
|
+
* typeof payload.street === 'string' &&
|
|
667
|
+
* typeof payload.city === 'string'
|
|
668
|
+
* ) {
|
|
669
|
+
* return payload;
|
|
670
|
+
* }
|
|
671
|
+
*
|
|
672
|
+
* throw new Error('Unexpected payload shape');
|
|
673
|
+
* },
|
|
674
|
+
* });
|
|
675
|
+
*
|
|
676
|
+
* <BaseControl
|
|
677
|
+
* type="fieldset"
|
|
678
|
+
* name="address"
|
|
679
|
+
* ref={control.register}
|
|
680
|
+
* defaultValue={control.defaultValue}
|
|
681
|
+
* />
|
|
682
|
+
* ```
|
|
683
|
+
*/
|
|
684
|
+
var BaseControl = /*#__PURE__*/react.forwardRef(function BaseControl(props, ref) {
|
|
685
|
+
function formatValue(value) {
|
|
686
|
+
var serialized = future.defaultSerialize(value);
|
|
687
|
+
if (typeof serialized === 'string') {
|
|
688
|
+
return serialized;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// null, undefined, File, or array - fallback to empty string
|
|
692
|
+
return '';
|
|
693
|
+
}
|
|
694
|
+
function renderInput(name, value, form) {
|
|
695
|
+
if (Array.isArray(value)) {
|
|
696
|
+
return value.map((item, index) => renderInput("".concat(name, "[").concat(index, "]"), item, form));
|
|
697
|
+
}
|
|
698
|
+
if (future.isPlainObject(value)) {
|
|
699
|
+
return Object.entries(value).map(_ref5 => {
|
|
700
|
+
var [key, val] = _ref5;
|
|
701
|
+
return renderInput("".concat(name, ".").concat(key), val, form);
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
return /*#__PURE__*/jsxRuntime.jsx("input", {
|
|
705
|
+
name: name,
|
|
706
|
+
defaultValue: formatValue(value),
|
|
707
|
+
form: form
|
|
708
|
+
}, name);
|
|
709
|
+
}
|
|
710
|
+
if (props.type === 'fieldset') {
|
|
711
|
+
var {
|
|
712
|
+
name,
|
|
713
|
+
form,
|
|
714
|
+
defaultValue: _defaultValue,
|
|
715
|
+
hidden: _hidden = true
|
|
716
|
+
} = props,
|
|
717
|
+
fieldsetProps = _rollupPluginBabelHelpers.objectWithoutProperties(props, _excluded);
|
|
718
|
+
return /*#__PURE__*/jsxRuntime.jsx("fieldset", _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, fieldsetProps), {}, {
|
|
719
|
+
ref: ref,
|
|
720
|
+
name: name,
|
|
721
|
+
form: form,
|
|
722
|
+
hidden: _hidden,
|
|
723
|
+
children: _defaultValue != null ? renderInput(name, _defaultValue, form) : null
|
|
724
|
+
}));
|
|
725
|
+
}
|
|
726
|
+
if (props.type === 'select') {
|
|
727
|
+
var {
|
|
728
|
+
defaultValue: _defaultValue2,
|
|
729
|
+
multiple = Array.isArray(_defaultValue2),
|
|
730
|
+
hidden: _hidden2 = true
|
|
731
|
+
} = props,
|
|
732
|
+
selectProps = _rollupPluginBabelHelpers.objectWithoutProperties(props, _excluded2);
|
|
733
|
+
if (multiple) {
|
|
734
|
+
var defaultOptions = Array.isArray(_defaultValue2) ? _defaultValue2.map(formatValue) : [formatValue(_defaultValue2)];
|
|
735
|
+
return /*#__PURE__*/jsxRuntime.jsx("select", _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, selectProps), {}, {
|
|
736
|
+
ref: ref,
|
|
737
|
+
defaultValue: defaultOptions,
|
|
738
|
+
hidden: _hidden2,
|
|
739
|
+
multiple: true,
|
|
740
|
+
children: defaultOptions.map((option, index) => /*#__PURE__*/jsxRuntime.jsx("option", {
|
|
741
|
+
value: option,
|
|
742
|
+
children: option
|
|
743
|
+
}, index))
|
|
744
|
+
}));
|
|
745
|
+
}
|
|
746
|
+
var defaultOption = formatValue(_defaultValue2);
|
|
747
|
+
return /*#__PURE__*/jsxRuntime.jsx("select", _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, selectProps), {}, {
|
|
748
|
+
ref: ref,
|
|
749
|
+
defaultValue: defaultOption,
|
|
750
|
+
hidden: _hidden2,
|
|
751
|
+
children: [defaultOption].map((option, index) => /*#__PURE__*/jsxRuntime.jsx("option", {
|
|
752
|
+
value: option,
|
|
753
|
+
children: option
|
|
754
|
+
}, index))
|
|
755
|
+
}));
|
|
756
|
+
}
|
|
757
|
+
if (props.type === 'textarea') {
|
|
758
|
+
var {
|
|
759
|
+
defaultValue: _defaultValue3,
|
|
760
|
+
hidden: _hidden3 = true
|
|
761
|
+
} = props,
|
|
762
|
+
textareaProps = _rollupPluginBabelHelpers.objectWithoutProperties(props, _excluded3);
|
|
763
|
+
return /*#__PURE__*/jsxRuntime.jsx("textarea", _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, textareaProps), {}, {
|
|
764
|
+
defaultValue: formatValue(_defaultValue3),
|
|
765
|
+
ref: ref,
|
|
766
|
+
hidden: _hidden3
|
|
767
|
+
}));
|
|
768
|
+
}
|
|
769
|
+
if (props.type === 'checkbox' || props.type === 'radio') {
|
|
770
|
+
var {
|
|
771
|
+
defaultValue: _defaultValue4 = 'on',
|
|
772
|
+
value = _defaultValue4,
|
|
773
|
+
hidden: _hidden4 = true
|
|
774
|
+
} = props,
|
|
775
|
+
_inputProps = _rollupPluginBabelHelpers.objectWithoutProperties(props, _excluded4);
|
|
776
|
+
return /*#__PURE__*/jsxRuntime.jsx("input", _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, _inputProps), {}, {
|
|
777
|
+
ref: ref,
|
|
778
|
+
value: value,
|
|
779
|
+
hidden: _hidden4
|
|
780
|
+
}));
|
|
781
|
+
}
|
|
782
|
+
var {
|
|
783
|
+
defaultValue,
|
|
784
|
+
hidden = true
|
|
785
|
+
} = props,
|
|
786
|
+
inputProps = _rollupPluginBabelHelpers.objectWithoutProperties(props, _excluded5);
|
|
787
|
+
return /*#__PURE__*/jsxRuntime.jsx("input", _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, inputProps), {}, {
|
|
788
|
+
ref: ref,
|
|
789
|
+
defaultValue: defaultValue !== undefined ? formatValue(defaultValue) : undefined,
|
|
790
|
+
hidden: hidden
|
|
791
|
+
}));
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
exports.BaseControl = BaseControl;
|
|
795
|
+
exports.GlobalFormsObserverContext = GlobalFormsObserverContext;
|
|
888
796
|
exports.INITIAL_KEY = INITIAL_KEY;
|
|
889
797
|
exports.PreserveBoundary = PreserveBoundary;
|
|
890
798
|
exports.useConform = useConform;
|
|
891
799
|
exports.useControl = useControl;
|
|
892
|
-
exports.useField = useField;
|
|
893
|
-
exports.useForm = useForm;
|
|
894
|
-
exports.useFormContext = useFormContext;
|
|
895
800
|
exports.useFormData = useFormData;
|
|
896
|
-
exports.useFormMetadata = useFormMetadata;
|
|
897
|
-
exports.useIntent = useIntent;
|
|
898
801
|
exports.useLatest = useLatest;
|
|
899
802
|
exports.useSafeLayoutEffect = useSafeLayoutEffect;
|