@conform-to/react 1.18.0 → 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.js +6 -2
- package/dist/future/dom.mjs +6 -2
- package/dist/future/forms.d.ts +1157 -26
- package/dist/future/forms.js +152 -23
- package/dist/future/forms.mjs +150 -26
- package/dist/future/hooks.d.ts +25 -164
- package/dist/future/hooks.js +34 -355
- package/dist/future/hooks.mjs +39 -352
- package/dist/future/index.d.ts +3 -3
- package/dist/future/index.js +5 -6
- package/dist/future/index.mjs +2 -2
- package/dist/future/intent.js +24 -12
- package/dist/future/intent.mjs +24 -12
- 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 +8 -12
- package/dist/future/state.js +24 -27
- package/dist/future/state.mjs +25 -28
- package/dist/future/types.d.ts +66 -111
- package/dist/future/util.d.ts +6 -10
- package/dist/future/util.js +17 -20
- package/dist/future/util.mjs +16 -19
- package/dist/helpers.d.ts +14 -10
- package/dist/helpers.js +14 -10
- package/dist/helpers.mjs +14 -10
- package/package.json +2 -2
package/dist/future/hooks.js
CHANGED
|
@@ -13,41 +13,19 @@ var dom = require('./dom.js');
|
|
|
13
13
|
var reactDom = require('react-dom');
|
|
14
14
|
var jsxRuntime = require('react/jsx-runtime');
|
|
15
15
|
|
|
16
|
-
var _excluded = ["
|
|
17
|
-
_excluded2 = ["
|
|
18
|
-
_excluded3 = ["defaultValue", "
|
|
19
|
-
_excluded4 = ["defaultValue", "hidden"],
|
|
20
|
-
_excluded5 = ["defaultValue", "
|
|
21
|
-
_excluded6 = ["defaultValue", "hidden"];
|
|
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"];
|
|
22
21
|
var INITIAL_KEY = 'INITIAL_KEY';
|
|
23
|
-
var
|
|
24
|
-
intentName: future.DEFAULT_INTENT_NAME,
|
|
25
|
-
observer: future.createGlobalFormsObserver(),
|
|
26
|
-
serialize: future.serialize,
|
|
27
|
-
shouldValidate: 'onSubmit'
|
|
28
|
-
});
|
|
29
|
-
var FormContextContext = /*#__PURE__*/react.createContext([]);
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Provides form context to child components.
|
|
33
|
-
* Stacks contexts to support nested forms, with latest context taking priority.
|
|
34
|
-
*/
|
|
35
|
-
function FormProvider(props) {
|
|
36
|
-
var stack = react.useContext(FormContextContext);
|
|
37
|
-
var value = react.useMemo(
|
|
38
|
-
// Put the latest form context first to ensure that to be the first one found
|
|
39
|
-
() => [props.context].concat(stack), [stack, props.context]);
|
|
40
|
-
return /*#__PURE__*/jsxRuntime.jsx(FormContextContext.Provider, {
|
|
41
|
-
value: value,
|
|
42
|
-
children: props.children
|
|
43
|
-
});
|
|
44
|
-
}
|
|
22
|
+
var GlobalFormsObserverContext = /*#__PURE__*/react.createContext(future.createGlobalFormsObserver());
|
|
45
23
|
|
|
46
24
|
/**
|
|
47
25
|
* Preserves form field values when its contents are unmounted.
|
|
48
26
|
* Useful for multi-step forms and virtualized lists.
|
|
49
27
|
*
|
|
50
|
-
*
|
|
28
|
+
* See https://conform.guide/api/react/future/PreserveBoundary
|
|
51
29
|
*/
|
|
52
30
|
function PreserveBoundary(props) {
|
|
53
31
|
// name is used as key so React properly unmounts/remounts when switching
|
|
@@ -84,30 +62,6 @@ function PreserveBoundaryImpl(props) {
|
|
|
84
62
|
});
|
|
85
63
|
}
|
|
86
64
|
|
|
87
|
-
/**
|
|
88
|
-
* @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`.
|
|
89
|
-
*/
|
|
90
|
-
function FormOptionsProvider(props) {
|
|
91
|
-
var {
|
|
92
|
-
children
|
|
93
|
-
} = props,
|
|
94
|
-
providedOptions = _rollupPluginBabelHelpers.objectWithoutProperties(props, _excluded);
|
|
95
|
-
var defaultOptions = react.useContext(GlobalFormOptionsContext);
|
|
96
|
-
var options = react.useMemo(() => _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, defaultOptions), providedOptions), [defaultOptions, providedOptions]);
|
|
97
|
-
return /*#__PURE__*/jsxRuntime.jsx(GlobalFormOptionsContext.Provider, {
|
|
98
|
-
value: options,
|
|
99
|
-
children: children
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
function useFormContext(formId) {
|
|
103
|
-
var contexts = react.useContext(FormContextContext);
|
|
104
|
-
var context = formId ? contexts.find(context => formId === context.formId) : contexts[0];
|
|
105
|
-
if (!context) {
|
|
106
|
-
throw new Error('No form context found; Have you render a <FormProvider /> with the corresponding form context?');
|
|
107
|
-
}
|
|
108
|
-
return context;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
65
|
/**
|
|
112
66
|
* Core form hook that manages form state, validation, and submission.
|
|
113
67
|
* Handles both sync and async validation, intent dispatching, and DOM updates.
|
|
@@ -150,8 +104,11 @@ function useConform(formRef, options) {
|
|
|
150
104
|
var abortControllerRef = react.useRef(null);
|
|
151
105
|
var handleSubmission = react.useCallback(function (type, result) {
|
|
152
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
|
+
});
|
|
153
110
|
var intent$1 = result.submission.intent ? intent.deserializeIntent(result.submission.intent) : null;
|
|
154
|
-
var finalResult = intent.applyIntent(
|
|
111
|
+
var finalResult = intent.applyIntent(normalizedResult, intent$1, {
|
|
155
112
|
handlers: intent.intentHandlers
|
|
156
113
|
});
|
|
157
114
|
var formElement = dom.getFormElement(formRef);
|
|
@@ -163,7 +120,7 @@ function useConform(formRef, options) {
|
|
|
163
120
|
intent: intent$1,
|
|
164
121
|
ctx: {
|
|
165
122
|
handlers: intent.intentHandlers,
|
|
166
|
-
cancelled: finalResult !==
|
|
123
|
+
cancelled: finalResult !== normalizedResult,
|
|
167
124
|
reset(defaultValue) {
|
|
168
125
|
return state.initializeState({
|
|
169
126
|
defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : options.defaultValue
|
|
@@ -173,11 +130,11 @@ function useConform(formRef, options) {
|
|
|
173
130
|
})));
|
|
174
131
|
|
|
175
132
|
// TODO: move on error handler to a new effect
|
|
176
|
-
if (formElement &&
|
|
133
|
+
if (formElement && finalResult.error) {
|
|
177
134
|
var _optionsRef$current$o, _optionsRef$current;
|
|
178
135
|
(_optionsRef$current$o = (_optionsRef$current = optionsRef.current).onError) === null || _optionsRef$current$o === void 0 || _optionsRef$current$o.call(_optionsRef$current, {
|
|
179
136
|
formElement,
|
|
180
|
-
error:
|
|
137
|
+
error: finalResult.error,
|
|
181
138
|
intent: intent$1
|
|
182
139
|
});
|
|
183
140
|
}
|
|
@@ -275,7 +232,7 @@ function useConform(formRef, options) {
|
|
|
275
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, {
|
|
276
233
|
payload: value,
|
|
277
234
|
error: {
|
|
278
|
-
formErrors:
|
|
235
|
+
formErrors: null,
|
|
279
236
|
fieldErrors: {}
|
|
280
237
|
},
|
|
281
238
|
intent: submission.intent ? intent.deserializeIntent(submission.intent) : null,
|
|
@@ -368,279 +325,12 @@ function useConform(formRef, options) {
|
|
|
368
325
|
return [state$1, handleSubmit];
|
|
369
326
|
}
|
|
370
327
|
|
|
371
|
-
/**
|
|
372
|
-
* The main React hook for form management. Handles form state, validation, and submission
|
|
373
|
-
* while providing access to form metadata, field objects, and form actions.
|
|
374
|
-
*
|
|
375
|
-
* It can be called in two ways:
|
|
376
|
-
* - **Schema first**: Pass a schema as the first argument for automatic validation with type inference
|
|
377
|
-
* - **Manual configuration**: Pass options with custom `onValidate` handler for manual validation
|
|
378
|
-
*
|
|
379
|
-
* @see https://conform.guide/api/react/future/useForm
|
|
380
|
-
* @example Schema first setup with zod:
|
|
381
|
-
*
|
|
382
|
-
* ```tsx
|
|
383
|
-
* const { form, fields } = useForm(zodSchema, {
|
|
384
|
-
* lastResult,
|
|
385
|
-
* shouldValidate: 'onBlur',
|
|
386
|
-
* });
|
|
387
|
-
*
|
|
388
|
-
* return (
|
|
389
|
-
* <form {...form.props}>
|
|
390
|
-
* <input name={fields.email.name} defaultValue={fields.email.defaultValue} />
|
|
391
|
-
* <div>{fields.email.errors}</div>
|
|
392
|
-
* </form>
|
|
393
|
-
* );
|
|
394
|
-
* ```
|
|
395
|
-
*
|
|
396
|
-
* @example Manual configuration setup with custom validation:
|
|
397
|
-
*
|
|
398
|
-
* ```tsx
|
|
399
|
-
* const { form, fields } = useForm({
|
|
400
|
-
* onValidate({ payload, error }) {
|
|
401
|
-
* if (!payload.email) {
|
|
402
|
-
* error.fieldErrors.email = ['Required'];
|
|
403
|
-
* }
|
|
404
|
-
* return error;
|
|
405
|
-
* }
|
|
406
|
-
* });
|
|
407
|
-
*
|
|
408
|
-
* return (
|
|
409
|
-
* <form {...form.props}>
|
|
410
|
-
* <input name={fields.email.name} defaultValue={fields.email.defaultValue} />
|
|
411
|
-
* <div>{fields.email.errors}</div>
|
|
412
|
-
* </form>
|
|
413
|
-
* );
|
|
414
|
-
* ```
|
|
415
|
-
*/
|
|
416
|
-
|
|
417
|
-
/**
|
|
418
|
-
* @deprecated Use `useForm(schema, options)` instead for better type inference.
|
|
419
|
-
*/
|
|
420
|
-
|
|
421
|
-
function useForm(schemaOrOptions, maybeOptions) {
|
|
422
|
-
var _options$onError;
|
|
423
|
-
var schema;
|
|
424
|
-
var options;
|
|
425
|
-
if (maybeOptions) {
|
|
426
|
-
schema = schemaOrOptions;
|
|
427
|
-
options = maybeOptions;
|
|
428
|
-
} else {
|
|
429
|
-
var fullOptions = schemaOrOptions;
|
|
430
|
-
options = fullOptions;
|
|
431
|
-
schema = fullOptions.schema;
|
|
432
|
-
}
|
|
433
|
-
var {
|
|
434
|
-
id,
|
|
435
|
-
constraint
|
|
436
|
-
} = options;
|
|
437
|
-
var globalOptions = react.useContext(GlobalFormOptionsContext);
|
|
438
|
-
var optionsRef = useLatest(options);
|
|
439
|
-
var globalOptionsRef = useLatest(globalOptions);
|
|
440
|
-
var fallbackId = react.useId();
|
|
441
|
-
var formId = id !== null && id !== void 0 ? id : "form-".concat(fallbackId);
|
|
442
|
-
var [state$1, handleSubmit] = useConform(formId, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, options), {}, {
|
|
443
|
-
serialize: globalOptions.serialize,
|
|
444
|
-
intentName: globalOptions.intentName,
|
|
445
|
-
onError: (_options$onError = options.onError) !== null && _options$onError !== void 0 ? _options$onError : dom.focusFirstInvalidField,
|
|
446
|
-
onValidate(ctx) {
|
|
447
|
-
var _options$onValidate, _options$onValidate2, _options;
|
|
448
|
-
if (schema) {
|
|
449
|
-
var standardResult = schema['~standard'].validate(ctx.payload);
|
|
450
|
-
if (standardResult instanceof Promise) {
|
|
451
|
-
return standardResult.then(actualStandardResult => {
|
|
452
|
-
if (typeof options.onValidate === 'function') {
|
|
453
|
-
throw new Error('The "onValidate" handler is not supported when used with asynchronous schema validation.');
|
|
454
|
-
}
|
|
455
|
-
return util.resolveStandardSchemaResult(actualStandardResult);
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
var resolvedResult = util.resolveStandardSchemaResult(standardResult);
|
|
459
|
-
if (!options.onValidate) {
|
|
460
|
-
return resolvedResult;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// Update the schema error in the context
|
|
464
|
-
if (resolvedResult.error) {
|
|
465
|
-
ctx.error = resolvedResult.error;
|
|
466
|
-
}
|
|
467
|
-
ctx.schemaValue = resolvedResult.value;
|
|
468
|
-
var validateResult = util.resolveValidateResult(options.onValidate(ctx));
|
|
469
|
-
if (validateResult.syncResult) {
|
|
470
|
-
var _validateResult$syncR, _validateResult$syncR2;
|
|
471
|
-
(_validateResult$syncR2 = (_validateResult$syncR = validateResult.syncResult).value) !== null && _validateResult$syncR2 !== void 0 ? _validateResult$syncR2 : _validateResult$syncR.value = resolvedResult.value;
|
|
472
|
-
}
|
|
473
|
-
if (validateResult.asyncResult) {
|
|
474
|
-
validateResult.asyncResult = validateResult.asyncResult.then(result => {
|
|
475
|
-
var _result$value;
|
|
476
|
-
(_result$value = result.value) !== null && _result$value !== void 0 ? _result$value : result.value = resolvedResult.value;
|
|
477
|
-
return result;
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
return [validateResult.syncResult, validateResult.asyncResult];
|
|
481
|
-
}
|
|
482
|
-
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 : {
|
|
483
|
-
// To avoid conform falling back to server validation,
|
|
484
|
-
// if neither schema nor validation handler is provided,
|
|
485
|
-
// we just treat it as a valid client submission
|
|
486
|
-
error: null
|
|
487
|
-
};
|
|
488
|
-
}
|
|
489
|
-
}));
|
|
490
|
-
var intent = useIntent(formId);
|
|
491
|
-
var context = react.useMemo(() => ({
|
|
492
|
-
formId,
|
|
493
|
-
state: state$1,
|
|
494
|
-
constraint: constraint !== null && constraint !== void 0 ? constraint : null,
|
|
495
|
-
handleSubmit,
|
|
496
|
-
handleInput(event) {
|
|
497
|
-
var _optionsRef$current$o4, _optionsRef$current4, _globalOptionsRef$cur;
|
|
498
|
-
if (!future.isFieldElement(event.target) || event.target.name === '' || event.target.form === null || event.target.form !== dom.getFormElement(formId)) {
|
|
499
|
-
return;
|
|
500
|
-
}
|
|
501
|
-
(_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), {}, {
|
|
502
|
-
target: event.target,
|
|
503
|
-
currentTarget: event.target.form
|
|
504
|
-
}));
|
|
505
|
-
if (event.defaultPrevented) {
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
var {
|
|
509
|
-
shouldValidate = globalOptionsRef.current.shouldValidate,
|
|
510
|
-
shouldRevalidate = (_globalOptionsRef$cur = globalOptionsRef.current.shouldRevalidate) !== null && _globalOptionsRef$cur !== void 0 ? _globalOptionsRef$cur : shouldValidate
|
|
511
|
-
} = optionsRef.current;
|
|
512
|
-
if (state.isTouched(state$1, event.target.name) ? shouldRevalidate === 'onInput' : shouldValidate === 'onInput') {
|
|
513
|
-
intent.validate(event.target.name);
|
|
514
|
-
}
|
|
515
|
-
},
|
|
516
|
-
handleBlur(event) {
|
|
517
|
-
var _optionsRef$current$o5, _optionsRef$current5, _globalOptionsRef$cur2;
|
|
518
|
-
if (!future.isFieldElement(event.target) || event.target.name === '' || event.target.form === null || event.target.form !== dom.getFormElement(formId)) {
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
521
|
-
(_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), {}, {
|
|
522
|
-
target: event.target,
|
|
523
|
-
currentTarget: event.target.form
|
|
524
|
-
}));
|
|
525
|
-
if (event.defaultPrevented) {
|
|
526
|
-
return;
|
|
527
|
-
}
|
|
528
|
-
var {
|
|
529
|
-
shouldValidate = globalOptionsRef.current.shouldValidate,
|
|
530
|
-
shouldRevalidate = (_globalOptionsRef$cur2 = globalOptionsRef.current.shouldRevalidate) !== null && _globalOptionsRef$cur2 !== void 0 ? _globalOptionsRef$cur2 : shouldValidate
|
|
531
|
-
} = optionsRef.current;
|
|
532
|
-
if (state.isTouched(state$1, event.target.name) ? shouldRevalidate === 'onBlur' : shouldValidate === 'onBlur') {
|
|
533
|
-
intent.validate(event.target.name);
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
}), [formId, state$1, constraint, handleSubmit, intent, optionsRef, globalOptionsRef]);
|
|
537
|
-
var form = react.useMemo(() => state.getFormMetadata(context, {
|
|
538
|
-
serialize: globalOptions.serialize,
|
|
539
|
-
extendFieldMetadata: globalOptions.defineCustomMetadata
|
|
540
|
-
}), [context, globalOptions.serialize, globalOptions.defineCustomMetadata]);
|
|
541
|
-
var fields = react.useMemo(() => state.getFieldset(context, {
|
|
542
|
-
serialize: globalOptions.serialize,
|
|
543
|
-
extendFieldMetadata: globalOptions.defineCustomMetadata
|
|
544
|
-
}), [context, globalOptions.serialize, globalOptions.defineCustomMetadata]);
|
|
545
|
-
return {
|
|
546
|
-
form,
|
|
547
|
-
fields,
|
|
548
|
-
intent
|
|
549
|
-
};
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
/**
|
|
553
|
-
* A React hook that provides access to form-level metadata and state.
|
|
554
|
-
* Requires `FormProvider` context when used in child components.
|
|
555
|
-
*
|
|
556
|
-
* @see https://conform.guide/api/react/future/useFormMetadata
|
|
557
|
-
* @example
|
|
558
|
-
* ```tsx
|
|
559
|
-
* function ErrorSummary() {
|
|
560
|
-
* const form = useFormMetadata();
|
|
561
|
-
*
|
|
562
|
-
* if (form.valid) return null;
|
|
563
|
-
*
|
|
564
|
-
* return (
|
|
565
|
-
* <div>Please fix {Object.keys(form.fieldErrors).length} errors</div>
|
|
566
|
-
* );
|
|
567
|
-
* }
|
|
568
|
-
* ```
|
|
569
|
-
*/
|
|
570
|
-
function useFormMetadata() {
|
|
571
|
-
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
572
|
-
var globalOptions = react.useContext(GlobalFormOptionsContext);
|
|
573
|
-
var context = useFormContext(options.formId);
|
|
574
|
-
var formMetadata = react.useMemo(() => state.getFormMetadata(context, {
|
|
575
|
-
serialize: globalOptions.serialize,
|
|
576
|
-
extendFieldMetadata: globalOptions.defineCustomMetadata
|
|
577
|
-
}), [context, globalOptions.serialize, globalOptions.defineCustomMetadata]);
|
|
578
|
-
return formMetadata;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
/**
|
|
582
|
-
* A React hook that provides access to a specific field's metadata and state.
|
|
583
|
-
* Requires `FormProvider` context when used in child components.
|
|
584
|
-
*
|
|
585
|
-
* @see https://conform.guide/api/react/future/useField
|
|
586
|
-
* @example
|
|
587
|
-
* ```tsx
|
|
588
|
-
* function FormField({ name, label }) {
|
|
589
|
-
* const field = useField(name);
|
|
590
|
-
*
|
|
591
|
-
* return (
|
|
592
|
-
* <div>
|
|
593
|
-
* <label htmlFor={field.id}>{label}</label>
|
|
594
|
-
* <input id={field.id} name={field.name} defaultValue={field.defaultValue} />
|
|
595
|
-
* {field.errors && <div>{field.errors.join(', ')}</div>}
|
|
596
|
-
* </div>
|
|
597
|
-
* );
|
|
598
|
-
* }
|
|
599
|
-
* ```
|
|
600
|
-
*/
|
|
601
|
-
function useField(name) {
|
|
602
|
-
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
603
|
-
var globalOptions = react.useContext(GlobalFormOptionsContext);
|
|
604
|
-
var context = useFormContext(options.formId);
|
|
605
|
-
var field = react.useMemo(() => state.getField(context, {
|
|
606
|
-
name,
|
|
607
|
-
serialize: globalOptions.serialize,
|
|
608
|
-
extendFieldMetadata: globalOptions.defineCustomMetadata
|
|
609
|
-
}), [context, name, globalOptions.serialize, globalOptions.defineCustomMetadata]);
|
|
610
|
-
return field;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
/**
|
|
614
|
-
* A React hook that provides an intent dispatcher for programmatic form actions.
|
|
615
|
-
* Intent dispatchers allow you to trigger form operations like validation, field updates,
|
|
616
|
-
* and array manipulations without manual form submission.
|
|
617
|
-
*
|
|
618
|
-
* @see https://conform.guide/api/react/future/useIntent
|
|
619
|
-
* @example
|
|
620
|
-
* ```tsx
|
|
621
|
-
* function ResetButton() {
|
|
622
|
-
* const buttonRef = useRef<HTMLButtonElement>(null);
|
|
623
|
-
* const intent = useIntent(buttonRef);
|
|
624
|
-
*
|
|
625
|
-
* return (
|
|
626
|
-
* <button type="button" ref={buttonRef} onClick={() => intent.reset()}>
|
|
627
|
-
* Reset Form
|
|
628
|
-
* </button>
|
|
629
|
-
* );
|
|
630
|
-
* }
|
|
631
|
-
* ```
|
|
632
|
-
*/
|
|
633
|
-
function useIntent(formRef) {
|
|
634
|
-
var globalOptions = react.useContext(GlobalFormOptionsContext);
|
|
635
|
-
return react.useMemo(() => dom.createIntentDispatcher(() => dom.getFormElement(formRef), globalOptions.intentName), [formRef, globalOptions.intentName]);
|
|
636
|
-
}
|
|
637
|
-
|
|
638
328
|
/**
|
|
639
329
|
* A React hook that lets you sync the state of an input and dispatch native form events from it.
|
|
640
330
|
* This is useful when emulating native input behavior — typically by rendering a hidden base control
|
|
641
331
|
* and syncing it with a custom input.
|
|
642
332
|
*
|
|
643
|
-
*
|
|
333
|
+
* **Example:**
|
|
644
334
|
* ```ts
|
|
645
335
|
* const control = useControl(options);
|
|
646
336
|
* ```
|
|
@@ -648,9 +338,7 @@ function useIntent(formRef) {
|
|
|
648
338
|
|
|
649
339
|
function useControl() {
|
|
650
340
|
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
651
|
-
var
|
|
652
|
-
observer
|
|
653
|
-
} = react.useContext(GlobalFormOptionsContext);
|
|
341
|
+
var observer = react.useContext(GlobalFormsObserverContext);
|
|
654
342
|
var inputRef = react.useRef(null);
|
|
655
343
|
var formRef = react.useMemo(() => ({
|
|
656
344
|
get current() {
|
|
@@ -715,8 +403,8 @@ function useControl() {
|
|
|
715
403
|
eventDispatched.current[listener] = undefined;
|
|
716
404
|
});
|
|
717
405
|
if (listener === 'focus') {
|
|
718
|
-
var _optionsRef$
|
|
719
|
-
(_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);
|
|
720
408
|
}
|
|
721
409
|
}
|
|
722
410
|
};
|
|
@@ -806,7 +494,7 @@ function useControl() {
|
|
|
806
494
|
if (element.type === 'checkbox' || element.type === 'radio') {
|
|
807
495
|
// React set the value as empty string incorrectly when the value is undefined
|
|
808
496
|
// This make sure the checkbox value falls back to the default value "on" properly
|
|
809
|
-
//
|
|
497
|
+
// See https://github.com/facebook/react/issues/17590
|
|
810
498
|
var value = 'value' in optionsRef.current && optionsRef.current.value ? optionsRef.current.value : 'on';
|
|
811
499
|
element.value = value;
|
|
812
500
|
}
|
|
@@ -824,10 +512,10 @@ function useControl() {
|
|
|
824
512
|
inputRef.current = inputs;
|
|
825
513
|
if ('defaultValue' in optionsRef.current) {
|
|
826
514
|
for (var input of inputs) {
|
|
827
|
-
var _optionsRef$
|
|
515
|
+
var _optionsRef$current5;
|
|
828
516
|
dom.initializeField(input, {
|
|
829
517
|
// We will not be uitlizing defaultChecked / value on checkbox / radio group
|
|
830
|
-
defaultValue: (_optionsRef$
|
|
518
|
+
defaultValue: (_optionsRef$current5 = optionsRef.current) === null || _optionsRef$current5 === void 0 ? void 0 : _optionsRef$current5.defaultValue
|
|
831
519
|
});
|
|
832
520
|
}
|
|
833
521
|
}
|
|
@@ -893,8 +581,9 @@ function useControl() {
|
|
|
893
581
|
* Returns `undefined` when the form element is not available (e.g., on SSR or initial client render),
|
|
894
582
|
* unless a `fallback` is provided.
|
|
895
583
|
*
|
|
896
|
-
*
|
|
897
|
-
*
|
|
584
|
+
* See https://conform.guide/api/react/future/useFormData
|
|
585
|
+
*
|
|
586
|
+
* **Example:**
|
|
898
587
|
* ```ts
|
|
899
588
|
* const value = useFormData(
|
|
900
589
|
* formRef,
|
|
@@ -904,9 +593,7 @@ function useControl() {
|
|
|
904
593
|
*/
|
|
905
594
|
|
|
906
595
|
function useFormData(formRef, select, options) {
|
|
907
|
-
var
|
|
908
|
-
observer
|
|
909
|
-
} = react.useContext(GlobalFormOptionsContext);
|
|
596
|
+
var observer = react.useContext(GlobalFormsObserverContext);
|
|
910
597
|
var valueRef = react.useRef();
|
|
911
598
|
var formDataRef = react.useRef();
|
|
912
599
|
var value = react.useSyncExternalStore(react.useCallback(callback => {
|
|
@@ -966,7 +653,7 @@ function useLatest(value) {
|
|
|
966
653
|
* A component that renders hidden base control(s) based on the shape of defaultValue.
|
|
967
654
|
* Used with useControl to sync complex values with form data.
|
|
968
655
|
*
|
|
969
|
-
*
|
|
656
|
+
* **Example:**
|
|
970
657
|
* ```tsx
|
|
971
658
|
* const control = useControl<{ street: string; city: string }>({
|
|
972
659
|
* defaultValue: { street: '123 Main St', city: 'Anytown' },
|
|
@@ -996,7 +683,7 @@ function useLatest(value) {
|
|
|
996
683
|
*/
|
|
997
684
|
var BaseControl = /*#__PURE__*/react.forwardRef(function BaseControl(props, ref) {
|
|
998
685
|
function formatValue(value) {
|
|
999
|
-
var serialized = future.
|
|
686
|
+
var serialized = future.defaultSerialize(value);
|
|
1000
687
|
if (typeof serialized === 'string') {
|
|
1001
688
|
return serialized;
|
|
1002
689
|
}
|
|
@@ -1027,7 +714,7 @@ var BaseControl = /*#__PURE__*/react.forwardRef(function BaseControl(props, ref)
|
|
|
1027
714
|
defaultValue: _defaultValue,
|
|
1028
715
|
hidden: _hidden = true
|
|
1029
716
|
} = props,
|
|
1030
|
-
fieldsetProps = _rollupPluginBabelHelpers.objectWithoutProperties(props,
|
|
717
|
+
fieldsetProps = _rollupPluginBabelHelpers.objectWithoutProperties(props, _excluded);
|
|
1031
718
|
return /*#__PURE__*/jsxRuntime.jsx("fieldset", _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, fieldsetProps), {}, {
|
|
1032
719
|
ref: ref,
|
|
1033
720
|
name: name,
|
|
@@ -1042,7 +729,7 @@ var BaseControl = /*#__PURE__*/react.forwardRef(function BaseControl(props, ref)
|
|
|
1042
729
|
multiple = Array.isArray(_defaultValue2),
|
|
1043
730
|
hidden: _hidden2 = true
|
|
1044
731
|
} = props,
|
|
1045
|
-
selectProps = _rollupPluginBabelHelpers.objectWithoutProperties(props,
|
|
732
|
+
selectProps = _rollupPluginBabelHelpers.objectWithoutProperties(props, _excluded2);
|
|
1046
733
|
if (multiple) {
|
|
1047
734
|
var defaultOptions = Array.isArray(_defaultValue2) ? _defaultValue2.map(formatValue) : [formatValue(_defaultValue2)];
|
|
1048
735
|
return /*#__PURE__*/jsxRuntime.jsx("select", _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, selectProps), {}, {
|
|
@@ -1072,7 +759,7 @@ var BaseControl = /*#__PURE__*/react.forwardRef(function BaseControl(props, ref)
|
|
|
1072
759
|
defaultValue: _defaultValue3,
|
|
1073
760
|
hidden: _hidden3 = true
|
|
1074
761
|
} = props,
|
|
1075
|
-
textareaProps = _rollupPluginBabelHelpers.objectWithoutProperties(props,
|
|
762
|
+
textareaProps = _rollupPluginBabelHelpers.objectWithoutProperties(props, _excluded3);
|
|
1076
763
|
return /*#__PURE__*/jsxRuntime.jsx("textarea", _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, textareaProps), {}, {
|
|
1077
764
|
defaultValue: formatValue(_defaultValue3),
|
|
1078
765
|
ref: ref,
|
|
@@ -1085,7 +772,7 @@ var BaseControl = /*#__PURE__*/react.forwardRef(function BaseControl(props, ref)
|
|
|
1085
772
|
value = _defaultValue4,
|
|
1086
773
|
hidden: _hidden4 = true
|
|
1087
774
|
} = props,
|
|
1088
|
-
_inputProps = _rollupPluginBabelHelpers.objectWithoutProperties(props,
|
|
775
|
+
_inputProps = _rollupPluginBabelHelpers.objectWithoutProperties(props, _excluded4);
|
|
1089
776
|
return /*#__PURE__*/jsxRuntime.jsx("input", _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, _inputProps), {}, {
|
|
1090
777
|
ref: ref,
|
|
1091
778
|
value: value,
|
|
@@ -1096,7 +783,7 @@ var BaseControl = /*#__PURE__*/react.forwardRef(function BaseControl(props, ref)
|
|
|
1096
783
|
defaultValue,
|
|
1097
784
|
hidden = true
|
|
1098
785
|
} = props,
|
|
1099
|
-
inputProps = _rollupPluginBabelHelpers.objectWithoutProperties(props,
|
|
786
|
+
inputProps = _rollupPluginBabelHelpers.objectWithoutProperties(props, _excluded5);
|
|
1100
787
|
return /*#__PURE__*/jsxRuntime.jsx("input", _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, inputProps), {}, {
|
|
1101
788
|
ref: ref,
|
|
1102
789
|
defaultValue: defaultValue !== undefined ? formatValue(defaultValue) : undefined,
|
|
@@ -1105,19 +792,11 @@ var BaseControl = /*#__PURE__*/react.forwardRef(function BaseControl(props, ref)
|
|
|
1105
792
|
});
|
|
1106
793
|
|
|
1107
794
|
exports.BaseControl = BaseControl;
|
|
1108
|
-
exports.
|
|
1109
|
-
exports.FormOptionsProvider = FormOptionsProvider;
|
|
1110
|
-
exports.FormProvider = FormProvider;
|
|
1111
|
-
exports.GlobalFormOptionsContext = GlobalFormOptionsContext;
|
|
795
|
+
exports.GlobalFormsObserverContext = GlobalFormsObserverContext;
|
|
1112
796
|
exports.INITIAL_KEY = INITIAL_KEY;
|
|
1113
797
|
exports.PreserveBoundary = PreserveBoundary;
|
|
1114
798
|
exports.useConform = useConform;
|
|
1115
799
|
exports.useControl = useControl;
|
|
1116
|
-
exports.useField = useField;
|
|
1117
|
-
exports.useForm = useForm;
|
|
1118
|
-
exports.useFormContext = useFormContext;
|
|
1119
800
|
exports.useFormData = useFormData;
|
|
1120
|
-
exports.useFormMetadata = useFormMetadata;
|
|
1121
|
-
exports.useIntent = useIntent;
|
|
1122
801
|
exports.useLatest = useLatest;
|
|
1123
802
|
exports.useSafeLayoutEffect = useSafeLayoutEffect;
|