cross-state 1.5.1 → 1.6.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/dist/react/index.cjs +124 -46
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +40 -22
- package/dist/react/index.d.ts +40 -22
- package/dist/react/index.js +125 -47
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
package/dist/react/index.cjs
CHANGED
|
@@ -59,8 +59,8 @@ function useClosestForm() {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
//#endregion
|
|
62
|
-
//#region src/react/form/
|
|
63
|
-
function
|
|
62
|
+
//#region src/react/form/legacyFormField.tsx
|
|
63
|
+
function LegacyFormField({ name = "", component, commitOnBlur, commitDebounce, inputFilter, defaultValue, serialize, deserialize = (x) => x, onChange, onBlur,...restProps }) {
|
|
64
64
|
const form = this.useForm();
|
|
65
65
|
const getFormState = () => ({
|
|
66
66
|
...form,
|
|
@@ -110,10 +110,6 @@ function FormField({ name = "", component, commitOnBlur, commitDebounce, render,
|
|
|
110
110
|
...form.getField(name),
|
|
111
111
|
hasTriggeredValidations
|
|
112
112
|
}, form);
|
|
113
|
-
if (render) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: render(props, {
|
|
114
|
-
...form.getField(name),
|
|
115
|
-
hasTriggeredValidations
|
|
116
|
-
}, form) ?? null });
|
|
117
113
|
if (component) return (0, react.createElement)(component, {
|
|
118
114
|
...restProps,
|
|
119
115
|
...props
|
|
@@ -121,6 +117,63 @@ function FormField({ name = "", component, commitOnBlur, commitDebounce, render,
|
|
|
121
117
|
return null;
|
|
122
118
|
}
|
|
123
119
|
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/react/form/formField.tsx
|
|
122
|
+
function FormField({ name = "", commitOnBlur, commitDebounce, children, render = children, includeNestedErrors }) {
|
|
123
|
+
const form = this.useForm();
|
|
124
|
+
const field = this.useField(name);
|
|
125
|
+
const hasTriggeredValidations = this.useFormState((form$1) => form$1.hasTriggeredValidations);
|
|
126
|
+
const renderProps = useFormFieldProps.call(this, {
|
|
127
|
+
name,
|
|
128
|
+
commitOnBlur,
|
|
129
|
+
commitDebounce,
|
|
130
|
+
includeNestedErrors
|
|
131
|
+
});
|
|
132
|
+
if (render) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: render(renderProps, {
|
|
133
|
+
...field,
|
|
134
|
+
hasTriggeredValidations
|
|
135
|
+
}, form) });
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
function useFormFieldProps({ name = "", commitOnBlur, commitDebounce, includeNestedErrors }) {
|
|
139
|
+
const form = this.useForm();
|
|
140
|
+
const field = this.useField(name, { includeNestedErrors });
|
|
141
|
+
const hasTriggeredValidations = this.useFormState((form$1) => form$1.hasTriggeredValidations);
|
|
142
|
+
const [localValue, setLocalValue] = (0, react.useState)();
|
|
143
|
+
const commitDebounceMs = commitDebounce !== void 0 ? require_store.calcDuration(commitDebounce) : void 0;
|
|
144
|
+
const commitLocalValue = require_storeMethods.useLatestFunction(() => {
|
|
145
|
+
field.setValue(localValue);
|
|
146
|
+
setLocalValue(void 0);
|
|
147
|
+
});
|
|
148
|
+
(0, react.useEffect)(() => {
|
|
149
|
+
if (localValue === void 0 || commitDebounceMs === void 0 || commitDebounceMs <= 0) return;
|
|
150
|
+
const timeout = setTimeout(commitLocalValue, commitDebounceMs);
|
|
151
|
+
return () => clearTimeout(timeout);
|
|
152
|
+
}, [
|
|
153
|
+
localValue,
|
|
154
|
+
commitDebounceMs,
|
|
155
|
+
commitLocalValue
|
|
156
|
+
]);
|
|
157
|
+
let props = {
|
|
158
|
+
name,
|
|
159
|
+
value: localValue ?? field.value,
|
|
160
|
+
onChange: require_storeMethods.useLatestFunction((event) => {
|
|
161
|
+
const value = typeof event === "object" && event !== null && "target" in event ? event.target.value : event;
|
|
162
|
+
if (commitOnBlur || commitDebounceMs !== void 0 && commitDebounceMs > 0) setLocalValue(value);
|
|
163
|
+
else field.setValue(value);
|
|
164
|
+
}),
|
|
165
|
+
onBlur: require_storeMethods.useLatestFunction(() => {
|
|
166
|
+
if (localValue !== void 0) commitLocalValue();
|
|
167
|
+
}),
|
|
168
|
+
"data-invalid": field.errors.length > 0 ? true : void 0
|
|
169
|
+
};
|
|
170
|
+
if (this.options.transformFieldProps) props = this.options.transformFieldProps(props, {
|
|
171
|
+
...field,
|
|
172
|
+
hasTriggeredValidations
|
|
173
|
+
}, form);
|
|
174
|
+
return props;
|
|
175
|
+
}
|
|
176
|
+
|
|
124
177
|
//#endregion
|
|
125
178
|
//#region src/react/form/formForEach.tsx
|
|
126
179
|
function FormForEach({ name, renderElement, renderAdditionalElement, filter, children }) {
|
|
@@ -221,25 +274,12 @@ function useFormAutosave(form) {
|
|
|
221
274
|
|
|
222
275
|
//#endregion
|
|
223
276
|
//#region src/react/form/form.tsx
|
|
224
|
-
function FormContainer({ form,...formProps }) {
|
|
277
|
+
const FormContainer = (0, react.forwardRef)(function FormContainer$1({ form,...formProps }, ref) {
|
|
225
278
|
const formInstance = form.useForm();
|
|
226
279
|
const hasTriggeredValidations = form.useFormState((state) => state.hasTriggeredValidations);
|
|
227
280
|
const hasErrors = form.useFormState((state) => hasTriggeredValidations && state.errors.size > 0);
|
|
228
|
-
const formRef = (0, react.useRef)(null);
|
|
229
|
-
const updateValidity = require_storeMethods.useLatestFunction((errors, buttonElement) => {
|
|
230
|
-
const formElement = formRef.current;
|
|
231
|
-
if (!formElement) return;
|
|
232
|
-
for (const element of Array.from(formElement.elements)) if ("name" in element && "setCustomValidity" in element) element.setCustomValidity(errors.get(element.name)?.join("\n") ?? "");
|
|
233
|
-
if (buttonElement && "setCustomValidity" in buttonElement) {
|
|
234
|
-
const errorString = [...errors.values()].flat().join("\n");
|
|
235
|
-
buttonElement.setCustomValidity(errorString);
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
(0, react.useEffect)(() => {
|
|
239
|
-
return formInstance.formState.map(() => formInstance.getErrors()).subscribe((errors) => updateValidity(errors));
|
|
240
|
-
}, [formInstance, updateValidity]);
|
|
241
281
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("form", {
|
|
242
|
-
ref
|
|
282
|
+
ref,
|
|
243
283
|
noValidate: true,
|
|
244
284
|
...formProps,
|
|
245
285
|
className: [formProps.className, hasTriggeredValidations ? formInstance.options.validatedClass ?? "validated" : void 0].filter(Boolean).join(" "),
|
|
@@ -250,11 +290,8 @@ function FormContainer({ form,...formProps }) {
|
|
|
250
290
|
try {
|
|
251
291
|
formInstance.formState.set("saveInProgress", true);
|
|
252
292
|
event.preventDefault();
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
updateValidity(formInstance.getErrors(), buttonElement);
|
|
256
|
-
if (formInstance.options.reportValidity) formElement.reportValidity();
|
|
257
|
-
if (formInstance.validate()) await formProps.onSubmit?.(event, {
|
|
293
|
+
const button = event.nativeEvent instanceof SubmitEvent && event.nativeEvent.submitter instanceof HTMLButtonElement ? event.nativeEvent.submitter : void 0;
|
|
294
|
+
if (formInstance.validate({ button })) await formProps.onSubmit?.(event, {
|
|
258
295
|
...formInstance,
|
|
259
296
|
...getDerivedState(formInstance)
|
|
260
297
|
});
|
|
@@ -263,30 +300,32 @@ function FormContainer({ form,...formProps }) {
|
|
|
263
300
|
}
|
|
264
301
|
}
|
|
265
302
|
});
|
|
266
|
-
}
|
|
267
|
-
function getField(form,
|
|
303
|
+
});
|
|
304
|
+
function getField(form, name, { includeNestedErrors } = {}) {
|
|
268
305
|
return {
|
|
269
306
|
get originalValue() {
|
|
270
|
-
return form.original !== void 0 ? require_propAccess.get(form.original,
|
|
307
|
+
return form.original !== void 0 ? require_propAccess.get(form.original, name) : void 0;
|
|
271
308
|
},
|
|
272
309
|
get value() {
|
|
273
|
-
return require_propAccess.get(form.getDraft() ?? form.original ?? form.options.defaultValue,
|
|
310
|
+
return require_propAccess.get(form.getDraft() ?? form.original ?? form.options.defaultValue, name);
|
|
274
311
|
},
|
|
275
312
|
setValue(update) {
|
|
276
313
|
form.formState.set("draft", (draft = form.original ?? form.options.defaultValue) => {
|
|
277
|
-
if (update instanceof Function) update = update(require_propAccess.get(draft,
|
|
278
|
-
return require_propAccess.set(draft,
|
|
314
|
+
if (update instanceof Function) update = update(require_propAccess.get(draft, name));
|
|
315
|
+
return require_propAccess.set(draft, name, update);
|
|
279
316
|
});
|
|
280
317
|
},
|
|
281
318
|
get hasChange() {
|
|
282
319
|
return !require_propAccess.deepEqual(this.originalValue, this.value, { undefinedEqualsAbsent: true });
|
|
283
320
|
},
|
|
284
321
|
get errors() {
|
|
285
|
-
|
|
322
|
+
const errors = form.getErrors();
|
|
323
|
+
if (includeNestedErrors) return Array.from(errors.entries()).filter(([key]) => key === name || key.startsWith(`${name}.`)).flatMap(([, value]) => value);
|
|
324
|
+
else return errors.get(name) ?? [];
|
|
286
325
|
},
|
|
287
326
|
get names() {
|
|
288
327
|
const { value } = this;
|
|
289
|
-
if (require_propAccess.isObject(value)) return Object.keys(value).map((key) => require_propAccess.join(
|
|
328
|
+
if (require_propAccess.isObject(value)) return Object.keys(value).map((key) => require_propAccess.join(name, key));
|
|
290
329
|
return [];
|
|
291
330
|
},
|
|
292
331
|
add(...args) {
|
|
@@ -382,12 +421,18 @@ var Form = class Form {
|
|
|
382
421
|
...getDerivedState(form)
|
|
383
422
|
}), useStoreOptions);
|
|
384
423
|
}
|
|
385
|
-
useField(
|
|
424
|
+
useField(name, { includeNestedErrors,...useStoreOptions } = {}) {
|
|
386
425
|
const form = this.useForm();
|
|
387
|
-
this.useFormState((form$1) => [form$1.getField(
|
|
388
|
-
return form.getField(
|
|
426
|
+
this.useFormState((form$1) => [form$1.getField(name).value, form$1.original], useStoreOptions);
|
|
427
|
+
return form.getField(name, { includeNestedErrors });
|
|
428
|
+
}
|
|
429
|
+
useFieldProps(name, options) {
|
|
430
|
+
return useFormFieldProps.call(this, {
|
|
431
|
+
name,
|
|
432
|
+
...options
|
|
433
|
+
});
|
|
389
434
|
}
|
|
390
|
-
Form({ defaultValue, validations, localizeError, autoSave, transform, validatedClass, original, onSubmit, reportValidity, transformFieldProps,...formProps }) {
|
|
435
|
+
Form({ defaultValue, validations, initiallyTriggerValidations, localizeError, autoSave, transform, validatedClass, original, onSubmit, reportValidity, transformFieldProps,...formProps }) {
|
|
391
436
|
const options = {
|
|
392
437
|
defaultValue: {
|
|
393
438
|
...this.options.defaultValue,
|
|
@@ -403,16 +448,17 @@ var Form = class Form {
|
|
|
403
448
|
validatedClass: validatedClass ?? this.options.validatedClass,
|
|
404
449
|
original: original ?? this.options.original,
|
|
405
450
|
onSubmit: onSubmit ?? this.options.onSubmit,
|
|
406
|
-
reportValidity: reportValidity ?? this.options.reportValidity ??
|
|
451
|
+
reportValidity: reportValidity ?? this.options.reportValidity ?? "browser",
|
|
407
452
|
transformFieldProps: transformFieldProps ?? this.options.transformFieldProps
|
|
408
453
|
};
|
|
409
454
|
const formState = (0, react.useMemo)(() => {
|
|
410
455
|
return require_store.createStore({
|
|
411
456
|
draft: void 0,
|
|
412
|
-
hasTriggeredValidations: false,
|
|
457
|
+
hasTriggeredValidations: initiallyTriggerValidations ?? false,
|
|
413
458
|
saveInProgress: false
|
|
414
459
|
});
|
|
415
460
|
}, []);
|
|
461
|
+
const formRef = (0, react.useRef)(null);
|
|
416
462
|
let lastDraft;
|
|
417
463
|
const cache = /* @__PURE__ */ new Map();
|
|
418
464
|
function lazy(key, fn) {
|
|
@@ -446,6 +492,9 @@ var Form = class Form {
|
|
|
446
492
|
flushAutosave() {
|
|
447
493
|
return autosave.flush();
|
|
448
494
|
},
|
|
495
|
+
cancelAutosave() {
|
|
496
|
+
return autosave.cancel();
|
|
497
|
+
},
|
|
449
498
|
hasChanges() {
|
|
450
499
|
return lazy("hasChanges", () => !require_propAccess.deepEqual(this.getDraft(), options.original ?? options.defaultValue, { undefinedEqualsAbsent: true }));
|
|
451
500
|
},
|
|
@@ -455,8 +504,27 @@ var Form = class Form {
|
|
|
455
504
|
isValid() {
|
|
456
505
|
return lazy("isValid", () => this.getErrors().size === 0);
|
|
457
506
|
},
|
|
458
|
-
validate() {
|
|
507
|
+
validate({ reportValidity: reportValidity$1 = options.reportValidity, button } = {}) {
|
|
459
508
|
formState.set("hasTriggeredValidations", true);
|
|
509
|
+
updateValidity(this.getErrors(), button);
|
|
510
|
+
switch (reportValidity$1) {
|
|
511
|
+
case "browser":
|
|
512
|
+
formRef.current?.reportValidity();
|
|
513
|
+
break;
|
|
514
|
+
case true:
|
|
515
|
+
case "scrollTo":
|
|
516
|
+
{
|
|
517
|
+
const invalidElement = document.querySelector(":invalid, [data-invalid=\"true\"]");
|
|
518
|
+
if (invalidElement && invalidElement instanceof HTMLElement) {
|
|
519
|
+
invalidElement.scrollIntoView({
|
|
520
|
+
behavior: "smooth",
|
|
521
|
+
block: "center"
|
|
522
|
+
});
|
|
523
|
+
invalidElement.focus({ preventScroll: true });
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
break;
|
|
527
|
+
}
|
|
460
528
|
return this.isValid();
|
|
461
529
|
},
|
|
462
530
|
reset() {
|
|
@@ -464,7 +532,7 @@ var Form = class Form {
|
|
|
464
532
|
formState.set("hasTriggeredValidations", false);
|
|
465
533
|
}
|
|
466
534
|
};
|
|
467
|
-
context.getField = (path) => lazy(path
|
|
535
|
+
context.getField = (path, options$1) => lazy(`${path}:${options$1?.includeNestedErrors}`, () => getField(context, path, options$1));
|
|
468
536
|
(0, react.useEffect)(() => {
|
|
469
537
|
const transform$1 = options.transform;
|
|
470
538
|
if (!transform$1) return;
|
|
@@ -474,6 +542,18 @@ var Form = class Form {
|
|
|
474
542
|
if (!require_propAccess.deepEqual(result, value)) context.formState.set("draft", result);
|
|
475
543
|
});
|
|
476
544
|
});
|
|
545
|
+
function updateValidity(errors, buttonElement) {
|
|
546
|
+
const formElement = formRef.current;
|
|
547
|
+
if (!formElement) return;
|
|
548
|
+
for (const element of Array.from(formElement.elements)) if ("name" in element && "setCustomValidity" in element) element.setCustomValidity(errors.get(element.name)?.join("\n") ?? "");
|
|
549
|
+
if (buttonElement && "setCustomValidity" in buttonElement) {
|
|
550
|
+
const errorString = [...errors.values()].flat().join("\n");
|
|
551
|
+
buttonElement.setCustomValidity(errorString);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
(0, react.useEffect)(() => {
|
|
555
|
+
return formState.map(() => context.getErrors()).subscribe((errors) => updateValidity(errors));
|
|
556
|
+
});
|
|
477
557
|
const autosave = useFormAutosave(context);
|
|
478
558
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GeneralFormContext.Provider, {
|
|
479
559
|
value: this,
|
|
@@ -491,10 +571,8 @@ var Form = class Form {
|
|
|
491
571
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: children(this.useFormState(selector)) });
|
|
492
572
|
}
|
|
493
573
|
Field(props) {
|
|
494
|
-
return Reflect.apply(
|
|
495
|
-
|
|
496
|
-
...props
|
|
497
|
-
}]);
|
|
574
|
+
if (props.component) return Reflect.apply(LegacyFormField, this, [props]);
|
|
575
|
+
return Reflect.apply(FormField, this, [props]);
|
|
498
576
|
}
|
|
499
577
|
ForEach(props) {
|
|
500
578
|
return Reflect.apply(FormForEach, this, [props]);
|