@conform-to/dom 1.0.6 → 1.1.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 +1 -1
- package/form.d.ts +6 -2
- package/form.js +59 -20
- package/form.mjs +61 -22
- package/formdata.d.ts +5 -1
- package/formdata.js +8 -0
- package/formdata.mjs +8 -1
- package/package.json +1 -1
- package/submission.d.ts +10 -0
- package/submission.js +2 -6
- package/submission.mjs +3 -7
package/README
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
╚══════╝ ╚═════╝ ╚═╝ ╚══╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
Version 1.0
|
|
11
|
+
Version 1.1.0 / License MIT / Copyright (c) 2024 Edmund Hung
|
|
12
12
|
|
|
13
13
|
A type-safe form validation library utilizing web fundamentals to progressively enhance HTML Forms with full support for server frameworks like Remix and Next.js.
|
|
14
14
|
|
package/form.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export type Constraint = {
|
|
|
33
33
|
pattern?: string;
|
|
34
34
|
};
|
|
35
35
|
export type FormMeta<FormError> = {
|
|
36
|
+
formId: string;
|
|
37
|
+
isValueUpdated: boolean;
|
|
36
38
|
submissionStatus?: 'error' | 'success';
|
|
37
39
|
defaultValue: Record<string, unknown>;
|
|
38
40
|
initialValue: Record<string, unknown>;
|
|
@@ -42,7 +44,7 @@ export type FormMeta<FormError> = {
|
|
|
42
44
|
key: Record<string, string | undefined>;
|
|
43
45
|
validated: Record<string, boolean>;
|
|
44
46
|
};
|
|
45
|
-
export type FormState<FormError> = FormMeta<FormError> & {
|
|
47
|
+
export type FormState<FormError> = Omit<FormMeta<FormError>, 'formId' | 'isValueUpdated'> & {
|
|
46
48
|
valid: Record<string, boolean>;
|
|
47
49
|
dirty: Record<string, boolean>;
|
|
48
50
|
};
|
|
@@ -94,6 +96,7 @@ export type FormOptions<Schema, FormError = string[], FormValue = Schema> = {
|
|
|
94
96
|
export type SubscriptionSubject = {
|
|
95
97
|
[key in 'error' | 'initialValue' | 'value' | 'key' | 'valid' | 'dirty']?: SubscriptionScope;
|
|
96
98
|
} & {
|
|
99
|
+
formId?: boolean;
|
|
97
100
|
status?: boolean;
|
|
98
101
|
};
|
|
99
102
|
export type SubscriptionScope = {
|
|
@@ -107,7 +110,7 @@ export type ControlButtonProps = {
|
|
|
107
110
|
formNoValidate: boolean;
|
|
108
111
|
};
|
|
109
112
|
export type FormContext<Schema extends Record<string, any> = any, FormError = string[], FormValue = Schema> = {
|
|
110
|
-
|
|
113
|
+
getFormId(): string;
|
|
111
114
|
submit(event: SubmitEvent): {
|
|
112
115
|
formData: FormData;
|
|
113
116
|
action: ReturnType<typeof getFormAction>;
|
|
@@ -119,6 +122,7 @@ export type FormContext<Schema extends Record<string, any> = any, FormError = st
|
|
|
119
122
|
onInput(event: Event): void;
|
|
120
123
|
onBlur(event: Event): void;
|
|
121
124
|
onUpdate(options: Partial<FormOptions<Schema, FormError, FormValue>>): void;
|
|
125
|
+
observe(): () => void;
|
|
122
126
|
subscribe(callback: () => void, getSubject?: () => SubscriptionSubject | undefined): () => void;
|
|
123
127
|
getState(): FormState<FormError>;
|
|
124
128
|
getSerializedState(): string;
|
package/form.js
CHANGED
|
@@ -14,6 +14,8 @@ function createFormMeta(options, initialized) {
|
|
|
14
14
|
var defaultValue = options.defaultValue ? submission.serialize(options.defaultValue) : {};
|
|
15
15
|
var initialValue = (_lastResult$initialVa = lastResult === null || lastResult === void 0 ? void 0 : lastResult.initialValue) !== null && _lastResult$initialVa !== void 0 ? _lastResult$initialVa : defaultValue;
|
|
16
16
|
var result = {
|
|
17
|
+
formId: options.formId,
|
|
18
|
+
isValueUpdated: false,
|
|
17
19
|
submissionStatus: lastResult === null || lastResult === void 0 ? void 0 : lastResult.status,
|
|
18
20
|
defaultValue,
|
|
19
21
|
initialValue,
|
|
@@ -37,7 +39,7 @@ function getDefaultKey(defaultValue, prefix) {
|
|
|
37
39
|
var [key, value] = _ref2;
|
|
38
40
|
if (Array.isArray(value)) {
|
|
39
41
|
for (var i = 0; i < value.length; i++) {
|
|
40
|
-
result[formdata.
|
|
42
|
+
result[formdata.formatName(key, i)] = util.generateId();
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
return result;
|
|
@@ -66,10 +68,10 @@ function handleIntent(meta, intent, fields, initialized) {
|
|
|
66
68
|
case 'update':
|
|
67
69
|
{
|
|
68
70
|
var {
|
|
69
|
-
name: _name2,
|
|
70
71
|
validated,
|
|
71
72
|
value
|
|
72
73
|
} = intent.payload;
|
|
74
|
+
var _name2 = formdata.formatName(intent.payload.name, intent.payload.index);
|
|
73
75
|
if (typeof value !== 'undefined') {
|
|
74
76
|
updateValue(meta, _name2 !== null && _name2 !== void 0 ? _name2 : '', submission.serialize(value));
|
|
75
77
|
}
|
|
@@ -98,8 +100,7 @@ function handleIntent(meta, intent, fields, initialized) {
|
|
|
98
100
|
}
|
|
99
101
|
case 'reset':
|
|
100
102
|
{
|
|
101
|
-
var
|
|
102
|
-
var _name3 = (_intent$payload$name = intent.payload.name) !== null && _intent$payload$name !== void 0 ? _intent$payload$name : '';
|
|
103
|
+
var _name3 = formdata.formatName(intent.payload.name, intent.payload.index);
|
|
103
104
|
var _value = formdata.getValue(meta.defaultValue, _name3);
|
|
104
105
|
updateValue(meta, _name3, _value);
|
|
105
106
|
if (_name3) {
|
|
@@ -323,7 +324,7 @@ function createFormContext(options) {
|
|
|
323
324
|
for (var subscriber of subscribers) {
|
|
324
325
|
var _subscriber$getSubjec;
|
|
325
326
|
var subject = (_subscriber$getSubjec = subscriber.getSubject) === null || _subscriber$getSubjec === void 0 ? void 0 : _subscriber$getSubjec.call(subscriber);
|
|
326
|
-
if (!subject || subject.status && prevState.submissionStatus !== nextState.submissionStatus || shouldNotify(prevState.error, nextState.error, cache.error, subject.error) || shouldNotify(prevState.initialValue, nextState.initialValue, cache.initialValue, subject.initialValue) || shouldNotify(prevState.key, nextState.key, cache.key, subject.key, (prev, next) => prev !== next) || shouldNotify(prevState.valid, nextState.valid, cache.valid, subject.valid, compareBoolean) || shouldNotify(prevState.dirty, nextState.dirty, cache.dirty, subject.dirty, compareBoolean) || shouldNotify(prevState.value, nextState.value, cache.value, subject.value)) {
|
|
327
|
+
if (!subject || subject.formId && prevMeta.formId !== nextMeta.formId || subject.status && prevState.submissionStatus !== nextState.submissionStatus || shouldNotify(prevState.error, nextState.error, cache.error, subject.error) || shouldNotify(prevState.initialValue, nextState.initialValue, cache.initialValue, subject.initialValue) || shouldNotify(prevState.key, nextState.key, cache.key, subject.key, (prev, next) => prev !== next) || shouldNotify(prevState.valid, nextState.valid, cache.valid, subject.valid, compareBoolean) || shouldNotify(prevState.dirty, nextState.dirty, cache.dirty, subject.dirty, compareBoolean) || shouldNotify(prevState.value, nextState.value, cache.value, subject.value)) {
|
|
327
328
|
subscriber.callback();
|
|
328
329
|
}
|
|
329
330
|
}
|
|
@@ -357,8 +358,11 @@ function createFormContext(options) {
|
|
|
357
358
|
formData,
|
|
358
359
|
submitter
|
|
359
360
|
});
|
|
360
|
-
if (submission.status
|
|
361
|
-
|
|
361
|
+
if (submission.status === 'success' || submission.error !== null) {
|
|
362
|
+
var _result2 = submission.reply();
|
|
363
|
+
report(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, _result2), {}, {
|
|
364
|
+
status: _result2.status !== 'success' ? _result2.status : undefined
|
|
365
|
+
}));
|
|
362
366
|
}
|
|
363
367
|
return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, result), {}, {
|
|
364
368
|
submission
|
|
@@ -378,7 +382,15 @@ function createFormContext(options) {
|
|
|
378
382
|
shouldRevalidate = shouldValidate
|
|
379
383
|
} = latestOptions;
|
|
380
384
|
var validated = meta.validated[element.name];
|
|
381
|
-
return validated ? shouldRevalidate === eventName : shouldValidate === eventName;
|
|
385
|
+
return validated ? shouldRevalidate === eventName && (eventName === 'onInput' || meta.isValueUpdated) : shouldValidate === eventName;
|
|
386
|
+
}
|
|
387
|
+
function updateFormValue(form) {
|
|
388
|
+
var formData = new FormData(form);
|
|
389
|
+
var result = submission.getSubmissionContext(formData);
|
|
390
|
+
updateFormMeta(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, meta), {}, {
|
|
391
|
+
isValueUpdated: true,
|
|
392
|
+
value: result.payload
|
|
393
|
+
}));
|
|
382
394
|
}
|
|
383
395
|
function onInput(event) {
|
|
384
396
|
var element = resolveTarget(event);
|
|
@@ -386,11 +398,7 @@ function createFormContext(options) {
|
|
|
386
398
|
return;
|
|
387
399
|
}
|
|
388
400
|
if (event.defaultPrevented || !willValidate(element, 'onInput')) {
|
|
389
|
-
|
|
390
|
-
var result = submission.getSubmissionContext(formData);
|
|
391
|
-
updateFormMeta(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, meta), {}, {
|
|
392
|
-
value: result.payload
|
|
393
|
-
}));
|
|
401
|
+
updateFormValue(element.form);
|
|
394
402
|
} else {
|
|
395
403
|
dispatch({
|
|
396
404
|
type: 'validate',
|
|
@@ -412,18 +420,21 @@ function createFormContext(options) {
|
|
|
412
420
|
}
|
|
413
421
|
});
|
|
414
422
|
}
|
|
423
|
+
function reset() {
|
|
424
|
+
updateFormMeta(createFormMeta(latestOptions, true));
|
|
425
|
+
}
|
|
415
426
|
function onReset(event) {
|
|
416
427
|
var element = getFormElement();
|
|
417
428
|
if (event.type !== 'reset' || event.target !== element || event.defaultPrevented) {
|
|
418
429
|
return;
|
|
419
430
|
}
|
|
420
|
-
|
|
431
|
+
reset();
|
|
421
432
|
}
|
|
422
433
|
function report(result) {
|
|
423
434
|
var _result$error, _result$state;
|
|
424
435
|
var formElement = getFormElement();
|
|
425
436
|
if (!result.initialValue) {
|
|
426
|
-
|
|
437
|
+
reset();
|
|
427
438
|
return;
|
|
428
439
|
}
|
|
429
440
|
var error = Object.entries((_result$error = result.error) !== null && _result$error !== void 0 ? _result$error : {}).reduce((result, _ref5) => {
|
|
@@ -435,6 +446,7 @@ function createFormContext(options) {
|
|
|
435
446
|
return result;
|
|
436
447
|
}, {});
|
|
437
448
|
var update = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, meta), {}, {
|
|
449
|
+
isValueUpdated: false,
|
|
438
450
|
submissionStatus: result.status,
|
|
439
451
|
value: result.initialValue,
|
|
440
452
|
validated: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, meta.validated), (_result$state = result.state) === null || _result$state === void 0 ? void 0 : _result$state.validated),
|
|
@@ -458,8 +470,7 @@ function createFormContext(options) {
|
|
|
458
470
|
// Merge new options with the latest options
|
|
459
471
|
Object.assign(latestOptions, options);
|
|
460
472
|
if (latestOptions.formId !== currentFormId) {
|
|
461
|
-
|
|
462
|
-
(_getFormElement = getFormElement()) === null || _getFormElement === void 0 || _getFormElement.reset();
|
|
473
|
+
reset();
|
|
463
474
|
} else if (options.lastResult && options.lastResult !== currentResult) {
|
|
464
475
|
report(options.lastResult);
|
|
465
476
|
}
|
|
@@ -515,9 +526,36 @@ function createFormContext(options) {
|
|
|
515
526
|
}
|
|
516
527
|
});
|
|
517
528
|
}
|
|
529
|
+
function observe() {
|
|
530
|
+
var observer = new MutationObserver(mutations => {
|
|
531
|
+
var form = getFormElement();
|
|
532
|
+
if (!form) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
for (var mutation of mutations) {
|
|
536
|
+
var nodes = mutation.type === 'childList' ? [...mutation.addedNodes, ...mutation.removedNodes] : [mutation.target];
|
|
537
|
+
for (var node of nodes) {
|
|
538
|
+
var element = dom.isFieldElement(node) ? node : node instanceof HTMLElement ? node.querySelector('input,select,textarea') : null;
|
|
539
|
+
if ((element === null || element === void 0 ? void 0 : element.form) === form) {
|
|
540
|
+
updateFormValue(form);
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
observer.observe(document, {
|
|
547
|
+
subtree: true,
|
|
548
|
+
childList: true,
|
|
549
|
+
attributes: true,
|
|
550
|
+
attributeFilter: ['form', 'name']
|
|
551
|
+
});
|
|
552
|
+
return () => {
|
|
553
|
+
observer.disconnect();
|
|
554
|
+
};
|
|
555
|
+
}
|
|
518
556
|
return {
|
|
519
|
-
|
|
520
|
-
return
|
|
557
|
+
getFormId() {
|
|
558
|
+
return meta.formId;
|
|
521
559
|
},
|
|
522
560
|
submit,
|
|
523
561
|
onReset,
|
|
@@ -532,7 +570,8 @@ function createFormContext(options) {
|
|
|
532
570
|
reorder: createFormControl('reorder'),
|
|
533
571
|
subscribe,
|
|
534
572
|
getState,
|
|
535
|
-
getSerializedState
|
|
573
|
+
getSerializedState,
|
|
574
|
+
observe
|
|
536
575
|
};
|
|
537
576
|
}
|
|
538
577
|
|
package/form.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs';
|
|
2
|
-
import { flatten,
|
|
2
|
+
import { flatten, formatName, getValue, isPlainObject, setValue, normalize, getFormData, getPaths, formatPaths, isPrefix } from './formdata.mjs';
|
|
3
3
|
import { getFormAction, getFormEncType, getFormMethod, isFieldElement, requestSubmit } from './dom.mjs';
|
|
4
4
|
import { generateId, clone, invariant } from './util.mjs';
|
|
5
|
-
import { serialize, setListState, setListValue, setState,
|
|
5
|
+
import { serialize, setListState, setListValue, setState, INTENT, serializeIntent, root, getSubmissionContext } from './submission.mjs';
|
|
6
6
|
|
|
7
7
|
function createFormMeta(options, initialized) {
|
|
8
8
|
var _lastResult$initialVa, _options$constraint, _lastResult$state$val, _lastResult$state, _ref;
|
|
@@ -10,6 +10,8 @@ function createFormMeta(options, initialized) {
|
|
|
10
10
|
var defaultValue = options.defaultValue ? serialize(options.defaultValue) : {};
|
|
11
11
|
var initialValue = (_lastResult$initialVa = lastResult === null || lastResult === void 0 ? void 0 : lastResult.initialValue) !== null && _lastResult$initialVa !== void 0 ? _lastResult$initialVa : defaultValue;
|
|
12
12
|
var result = {
|
|
13
|
+
formId: options.formId,
|
|
14
|
+
isValueUpdated: false,
|
|
13
15
|
submissionStatus: lastResult === null || lastResult === void 0 ? void 0 : lastResult.status,
|
|
14
16
|
defaultValue,
|
|
15
17
|
initialValue,
|
|
@@ -33,7 +35,7 @@ function getDefaultKey(defaultValue, prefix) {
|
|
|
33
35
|
var [key, value] = _ref2;
|
|
34
36
|
if (Array.isArray(value)) {
|
|
35
37
|
for (var i = 0; i < value.length; i++) {
|
|
36
|
-
result[
|
|
38
|
+
result[formatName(key, i)] = generateId();
|
|
37
39
|
}
|
|
38
40
|
}
|
|
39
41
|
return result;
|
|
@@ -62,10 +64,10 @@ function handleIntent(meta, intent, fields, initialized) {
|
|
|
62
64
|
case 'update':
|
|
63
65
|
{
|
|
64
66
|
var {
|
|
65
|
-
name: _name2,
|
|
66
67
|
validated,
|
|
67
68
|
value
|
|
68
69
|
} = intent.payload;
|
|
70
|
+
var _name2 = formatName(intent.payload.name, intent.payload.index);
|
|
69
71
|
if (typeof value !== 'undefined') {
|
|
70
72
|
updateValue(meta, _name2 !== null && _name2 !== void 0 ? _name2 : '', serialize(value));
|
|
71
73
|
}
|
|
@@ -94,8 +96,7 @@ function handleIntent(meta, intent, fields, initialized) {
|
|
|
94
96
|
}
|
|
95
97
|
case 'reset':
|
|
96
98
|
{
|
|
97
|
-
var
|
|
98
|
-
var _name3 = (_intent$payload$name = intent.payload.name) !== null && _intent$payload$name !== void 0 ? _intent$payload$name : '';
|
|
99
|
+
var _name3 = formatName(intent.payload.name, intent.payload.index);
|
|
99
100
|
var _value = getValue(meta.defaultValue, _name3);
|
|
100
101
|
updateValue(meta, _name3, _value);
|
|
101
102
|
if (_name3) {
|
|
@@ -319,7 +320,7 @@ function createFormContext(options) {
|
|
|
319
320
|
for (var subscriber of subscribers) {
|
|
320
321
|
var _subscriber$getSubjec;
|
|
321
322
|
var subject = (_subscriber$getSubjec = subscriber.getSubject) === null || _subscriber$getSubjec === void 0 ? void 0 : _subscriber$getSubjec.call(subscriber);
|
|
322
|
-
if (!subject || subject.status && prevState.submissionStatus !== nextState.submissionStatus || shouldNotify(prevState.error, nextState.error, cache.error, subject.error) || shouldNotify(prevState.initialValue, nextState.initialValue, cache.initialValue, subject.initialValue) || shouldNotify(prevState.key, nextState.key, cache.key, subject.key, (prev, next) => prev !== next) || shouldNotify(prevState.valid, nextState.valid, cache.valid, subject.valid, compareBoolean) || shouldNotify(prevState.dirty, nextState.dirty, cache.dirty, subject.dirty, compareBoolean) || shouldNotify(prevState.value, nextState.value, cache.value, subject.value)) {
|
|
323
|
+
if (!subject || subject.formId && prevMeta.formId !== nextMeta.formId || subject.status && prevState.submissionStatus !== nextState.submissionStatus || shouldNotify(prevState.error, nextState.error, cache.error, subject.error) || shouldNotify(prevState.initialValue, nextState.initialValue, cache.initialValue, subject.initialValue) || shouldNotify(prevState.key, nextState.key, cache.key, subject.key, (prev, next) => prev !== next) || shouldNotify(prevState.valid, nextState.valid, cache.valid, subject.valid, compareBoolean) || shouldNotify(prevState.dirty, nextState.dirty, cache.dirty, subject.dirty, compareBoolean) || shouldNotify(prevState.value, nextState.value, cache.value, subject.value)) {
|
|
323
324
|
subscriber.callback();
|
|
324
325
|
}
|
|
325
326
|
}
|
|
@@ -353,8 +354,11 @@ function createFormContext(options) {
|
|
|
353
354
|
formData,
|
|
354
355
|
submitter
|
|
355
356
|
});
|
|
356
|
-
if (submission.status
|
|
357
|
-
|
|
357
|
+
if (submission.status === 'success' || submission.error !== null) {
|
|
358
|
+
var _result2 = submission.reply();
|
|
359
|
+
report(_objectSpread2(_objectSpread2({}, _result2), {}, {
|
|
360
|
+
status: _result2.status !== 'success' ? _result2.status : undefined
|
|
361
|
+
}));
|
|
358
362
|
}
|
|
359
363
|
return _objectSpread2(_objectSpread2({}, result), {}, {
|
|
360
364
|
submission
|
|
@@ -374,7 +378,15 @@ function createFormContext(options) {
|
|
|
374
378
|
shouldRevalidate = shouldValidate
|
|
375
379
|
} = latestOptions;
|
|
376
380
|
var validated = meta.validated[element.name];
|
|
377
|
-
return validated ? shouldRevalidate === eventName : shouldValidate === eventName;
|
|
381
|
+
return validated ? shouldRevalidate === eventName && (eventName === 'onInput' || meta.isValueUpdated) : shouldValidate === eventName;
|
|
382
|
+
}
|
|
383
|
+
function updateFormValue(form) {
|
|
384
|
+
var formData = new FormData(form);
|
|
385
|
+
var result = getSubmissionContext(formData);
|
|
386
|
+
updateFormMeta(_objectSpread2(_objectSpread2({}, meta), {}, {
|
|
387
|
+
isValueUpdated: true,
|
|
388
|
+
value: result.payload
|
|
389
|
+
}));
|
|
378
390
|
}
|
|
379
391
|
function onInput(event) {
|
|
380
392
|
var element = resolveTarget(event);
|
|
@@ -382,11 +394,7 @@ function createFormContext(options) {
|
|
|
382
394
|
return;
|
|
383
395
|
}
|
|
384
396
|
if (event.defaultPrevented || !willValidate(element, 'onInput')) {
|
|
385
|
-
|
|
386
|
-
var result = getSubmissionContext(formData);
|
|
387
|
-
updateFormMeta(_objectSpread2(_objectSpread2({}, meta), {}, {
|
|
388
|
-
value: result.payload
|
|
389
|
-
}));
|
|
397
|
+
updateFormValue(element.form);
|
|
390
398
|
} else {
|
|
391
399
|
dispatch({
|
|
392
400
|
type: 'validate',
|
|
@@ -408,18 +416,21 @@ function createFormContext(options) {
|
|
|
408
416
|
}
|
|
409
417
|
});
|
|
410
418
|
}
|
|
419
|
+
function reset() {
|
|
420
|
+
updateFormMeta(createFormMeta(latestOptions, true));
|
|
421
|
+
}
|
|
411
422
|
function onReset(event) {
|
|
412
423
|
var element = getFormElement();
|
|
413
424
|
if (event.type !== 'reset' || event.target !== element || event.defaultPrevented) {
|
|
414
425
|
return;
|
|
415
426
|
}
|
|
416
|
-
|
|
427
|
+
reset();
|
|
417
428
|
}
|
|
418
429
|
function report(result) {
|
|
419
430
|
var _result$error, _result$state;
|
|
420
431
|
var formElement = getFormElement();
|
|
421
432
|
if (!result.initialValue) {
|
|
422
|
-
|
|
433
|
+
reset();
|
|
423
434
|
return;
|
|
424
435
|
}
|
|
425
436
|
var error = Object.entries((_result$error = result.error) !== null && _result$error !== void 0 ? _result$error : {}).reduce((result, _ref5) => {
|
|
@@ -431,6 +442,7 @@ function createFormContext(options) {
|
|
|
431
442
|
return result;
|
|
432
443
|
}, {});
|
|
433
444
|
var update = _objectSpread2(_objectSpread2({}, meta), {}, {
|
|
445
|
+
isValueUpdated: false,
|
|
434
446
|
submissionStatus: result.status,
|
|
435
447
|
value: result.initialValue,
|
|
436
448
|
validated: _objectSpread2(_objectSpread2({}, meta.validated), (_result$state = result.state) === null || _result$state === void 0 ? void 0 : _result$state.validated),
|
|
@@ -454,8 +466,7 @@ function createFormContext(options) {
|
|
|
454
466
|
// Merge new options with the latest options
|
|
455
467
|
Object.assign(latestOptions, options);
|
|
456
468
|
if (latestOptions.formId !== currentFormId) {
|
|
457
|
-
|
|
458
|
-
(_getFormElement = getFormElement()) === null || _getFormElement === void 0 || _getFormElement.reset();
|
|
469
|
+
reset();
|
|
459
470
|
} else if (options.lastResult && options.lastResult !== currentResult) {
|
|
460
471
|
report(options.lastResult);
|
|
461
472
|
}
|
|
@@ -511,9 +522,36 @@ function createFormContext(options) {
|
|
|
511
522
|
}
|
|
512
523
|
});
|
|
513
524
|
}
|
|
525
|
+
function observe() {
|
|
526
|
+
var observer = new MutationObserver(mutations => {
|
|
527
|
+
var form = getFormElement();
|
|
528
|
+
if (!form) {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
for (var mutation of mutations) {
|
|
532
|
+
var nodes = mutation.type === 'childList' ? [...mutation.addedNodes, ...mutation.removedNodes] : [mutation.target];
|
|
533
|
+
for (var node of nodes) {
|
|
534
|
+
var element = isFieldElement(node) ? node : node instanceof HTMLElement ? node.querySelector('input,select,textarea') : null;
|
|
535
|
+
if ((element === null || element === void 0 ? void 0 : element.form) === form) {
|
|
536
|
+
updateFormValue(form);
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
observer.observe(document, {
|
|
543
|
+
subtree: true,
|
|
544
|
+
childList: true,
|
|
545
|
+
attributes: true,
|
|
546
|
+
attributeFilter: ['form', 'name']
|
|
547
|
+
});
|
|
548
|
+
return () => {
|
|
549
|
+
observer.disconnect();
|
|
550
|
+
};
|
|
551
|
+
}
|
|
514
552
|
return {
|
|
515
|
-
|
|
516
|
-
return
|
|
553
|
+
getFormId() {
|
|
554
|
+
return meta.formId;
|
|
517
555
|
},
|
|
518
556
|
submit,
|
|
519
557
|
onReset,
|
|
@@ -528,7 +566,8 @@ function createFormContext(options) {
|
|
|
528
566
|
reorder: createFormControl('reorder'),
|
|
529
567
|
subscribe,
|
|
530
568
|
getState,
|
|
531
|
-
getSerializedState
|
|
569
|
+
getSerializedState,
|
|
570
|
+
observe
|
|
532
571
|
};
|
|
533
572
|
}
|
|
534
573
|
|
package/formdata.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export declare function getFormData(form: HTMLFormElement, submitter?: HTMLInput
|
|
|
13
13
|
* const paths = getPaths('todos[0].content'); // ['todos', 0, 'content']
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
|
-
export declare function getPaths(name: string): Array<string | number>;
|
|
16
|
+
export declare function getPaths(name: string | undefined): Array<string | number>;
|
|
17
17
|
/**
|
|
18
18
|
* Returns a formatted name from the paths based on the JS syntax convention
|
|
19
19
|
* @example
|
|
@@ -22,6 +22,10 @@ export declare function getPaths(name: string): Array<string | number>;
|
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
24
|
export declare function formatPaths(paths: Array<string | number>): string;
|
|
25
|
+
/**
|
|
26
|
+
* Format based on a prefix and a path
|
|
27
|
+
*/
|
|
28
|
+
export declare function formatName(prefix: string | undefined, path?: string | number): string;
|
|
25
29
|
/**
|
|
26
30
|
* Check if a name match the prefix paths
|
|
27
31
|
*/
|
package/formdata.js
CHANGED
|
@@ -65,6 +65,13 @@ function formatPaths(paths) {
|
|
|
65
65
|
}, '');
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Format based on a prefix and a path
|
|
70
|
+
*/
|
|
71
|
+
function formatName(prefix, path) {
|
|
72
|
+
return typeof path !== 'undefined' ? formatPaths([...getPaths(prefix), path]) : prefix !== null && prefix !== void 0 ? prefix : '';
|
|
73
|
+
}
|
|
74
|
+
|
|
68
75
|
/**
|
|
69
76
|
* Check if a name match the prefix paths
|
|
70
77
|
*/
|
|
@@ -215,6 +222,7 @@ function flatten(data, options) {
|
|
|
215
222
|
}
|
|
216
223
|
|
|
217
224
|
exports.flatten = flatten;
|
|
225
|
+
exports.formatName = formatName;
|
|
218
226
|
exports.formatPaths = formatPaths;
|
|
219
227
|
exports.getFormData = getFormData;
|
|
220
228
|
exports.getPaths = getPaths;
|
package/formdata.mjs
CHANGED
|
@@ -61,6 +61,13 @@ function formatPaths(paths) {
|
|
|
61
61
|
}, '');
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Format based on a prefix and a path
|
|
66
|
+
*/
|
|
67
|
+
function formatName(prefix, path) {
|
|
68
|
+
return typeof path !== 'undefined' ? formatPaths([...getPaths(prefix), path]) : prefix !== null && prefix !== void 0 ? prefix : '';
|
|
69
|
+
}
|
|
70
|
+
|
|
64
71
|
/**
|
|
65
72
|
* Check if a name match the prefix paths
|
|
66
73
|
*/
|
|
@@ -210,4 +217,4 @@ function flatten(data, options) {
|
|
|
210
217
|
return result;
|
|
211
218
|
}
|
|
212
219
|
|
|
213
|
-
export { flatten, formatPaths, getFormData, getPaths, getValue, isFile, isPlainObject, isPrefix, normalize, setValue };
|
|
220
|
+
export { flatten, formatName, formatPaths, getFormData, getPaths, getValue, isFile, isPlainObject, isPrefix, normalize, setValue };
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "A set of opinionated helpers built on top of the Constraint Validation API",
|
|
4
4
|
"homepage": "https://conform.guide",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "1.0
|
|
6
|
+
"version": "1.1.0",
|
|
7
7
|
"main": "index.js",
|
|
8
8
|
"module": "index.mjs",
|
|
9
9
|
"types": "index.d.ts",
|
package/submission.d.ts
CHANGED
|
@@ -78,14 +78,24 @@ export type ResetIntent<Schema = any> = {
|
|
|
78
78
|
type: 'reset';
|
|
79
79
|
payload: {
|
|
80
80
|
name?: FieldName<Schema>;
|
|
81
|
+
index?: never;
|
|
82
|
+
} | {
|
|
83
|
+
name: FieldName<Schema>;
|
|
84
|
+
index: Schema extends Array<unknown> ? number : never;
|
|
81
85
|
};
|
|
82
86
|
};
|
|
83
87
|
export type UpdateIntent<Schema = unknown> = {
|
|
84
88
|
type: 'update';
|
|
85
89
|
payload: {
|
|
86
90
|
name?: FieldName<Schema>;
|
|
91
|
+
index?: never;
|
|
87
92
|
value?: NonNullable<DefaultValue<Schema>>;
|
|
88
93
|
validated?: boolean;
|
|
94
|
+
} | {
|
|
95
|
+
name: FieldName<Schema>;
|
|
96
|
+
index: Schema extends Array<unknown> ? number : never;
|
|
97
|
+
value?: NonNullable<DefaultValue<Schema extends Array<infer Item> ? Item : unknown>>;
|
|
98
|
+
validated?: boolean;
|
|
89
99
|
};
|
|
90
100
|
};
|
|
91
101
|
export type RemoveIntent<Schema extends Array<any> = any> = {
|
package/submission.js
CHANGED
|
@@ -54,9 +54,7 @@ function parse(payload, options) {
|
|
|
54
54
|
switch (intent.type) {
|
|
55
55
|
case 'update':
|
|
56
56
|
{
|
|
57
|
-
var
|
|
58
|
-
name
|
|
59
|
-
} = intent.payload;
|
|
57
|
+
var name = formdata.formatName(intent.payload.name, intent.payload.index);
|
|
60
58
|
var _value = serialize(intent.payload.value);
|
|
61
59
|
if (typeof _value !== 'undefined') {
|
|
62
60
|
if (name) {
|
|
@@ -70,9 +68,7 @@ function parse(payload, options) {
|
|
|
70
68
|
}
|
|
71
69
|
case 'reset':
|
|
72
70
|
{
|
|
73
|
-
var
|
|
74
|
-
name: _name
|
|
75
|
-
} = intent.payload;
|
|
71
|
+
var _name = formdata.formatName(intent.payload.name, intent.payload.index);
|
|
76
72
|
if (_name) {
|
|
77
73
|
formdata.setValue(context.payload, _name, () => undefined);
|
|
78
74
|
} else {
|
package/submission.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs';
|
|
2
|
-
import { setValue, isPlainObject, getValue, normalize, flatten, isPrefix } from './formdata.mjs';
|
|
2
|
+
import { formatName, setValue, isPlainObject, getValue, normalize, flatten, isPrefix } from './formdata.mjs';
|
|
3
3
|
import { invariant } from './util.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -50,9 +50,7 @@ function parse(payload, options) {
|
|
|
50
50
|
switch (intent.type) {
|
|
51
51
|
case 'update':
|
|
52
52
|
{
|
|
53
|
-
var
|
|
54
|
-
name
|
|
55
|
-
} = intent.payload;
|
|
53
|
+
var name = formatName(intent.payload.name, intent.payload.index);
|
|
56
54
|
var _value = serialize(intent.payload.value);
|
|
57
55
|
if (typeof _value !== 'undefined') {
|
|
58
56
|
if (name) {
|
|
@@ -66,9 +64,7 @@ function parse(payload, options) {
|
|
|
66
64
|
}
|
|
67
65
|
case 'reset':
|
|
68
66
|
{
|
|
69
|
-
var
|
|
70
|
-
name: _name
|
|
71
|
-
} = intent.payload;
|
|
67
|
+
var _name = formatName(intent.payload.name, intent.payload.index);
|
|
72
68
|
if (_name) {
|
|
73
69
|
setValue(context.payload, _name, () => undefined);
|
|
74
70
|
} else {
|