remix-validated-form 4.1.0 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -2
- package/browser/ValidatedForm.d.ts +1 -1
- package/browser/ValidatedForm.js +3 -2
- package/browser/internal/MultiValueMap.js +3 -3
- package/browser/internal/logic/getCheckboxChecked copy.d.ts +1 -0
- package/browser/internal/logic/getCheckboxChecked copy.js +9 -0
- package/browser/internal/logic/getCheckboxChecked.d.ts +1 -0
- package/browser/internal/logic/getCheckboxChecked.js +9 -0
- package/browser/internal/logic/getRadioChecked.d.ts +1 -0
- package/browser/internal/logic/getRadioChecked.js +5 -0
- package/browser/internal/logic/setFieldValue.d.ts +1 -0
- package/browser/internal/logic/setFieldValue.js +40 -0
- package/browser/internal/util.d.ts +1 -0
- package/browser/internal/util.js +12 -1
- package/build/ValidatedForm.d.ts +1 -1
- package/build/ValidatedForm.js +2 -1
- package/build/internal/MultiValueMap.js +2 -2
- package/build/internal/logic/getCheckboxChecked.d.ts +1 -0
- package/build/internal/logic/getCheckboxChecked.js +13 -0
- package/build/internal/logic/getRadioChecked.d.ts +1 -0
- package/build/internal/logic/getRadioChecked.js +9 -0
- package/build/internal/logic/setFieldValue.d.ts +1 -0
- package/build/internal/logic/setFieldValue.js +47 -0
- package/build/internal/util.d.ts +1 -0
- package/build/internal/util.js +13 -1
- package/package.json +1 -1
- package/src/ValidatedForm.tsx +3 -1
- package/src/internal/MultiValueMap.ts +3 -3
- package/src/internal/util.ts +13 -1
package/.turbo/turbo-build.log
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
[2K[1G[2m$ npm run build:browser && npm run build:main[22m
|
2
2
|
|
3
|
-
> remix-validated-form@4.0
|
3
|
+
> remix-validated-form@4.1.0 build:browser
|
4
4
|
> tsc --module ESNext --outDir ./browser
|
5
5
|
|
6
6
|
|
7
|
-
> remix-validated-form@4.0
|
7
|
+
> remix-validated-form@4.1.0 build:main
|
8
8
|
> tsc --module CommonJS --outDir ./build
|
9
9
|
|
@@ -47,4 +47,4 @@ export declare type FormProps<DataType> = {
|
|
47
47
|
/**
|
48
48
|
* The primary form component of `remix-validated-form`.
|
49
49
|
*/
|
50
|
-
export declare function ValidatedForm<DataType>({ validator, onSubmit, children, fetcher, action, defaultValues:
|
50
|
+
export declare function ValidatedForm<DataType>({ validator, onSubmit, children, fetcher, action, defaultValues: unMemoizedDefaults, formRef: formRefProp, onReset, subaction, resetAfterSubmit, disableFocusOnError, method, replace, id, ...rest }: FormProps<DataType>): JSX.Element;
|
package/browser/ValidatedForm.js
CHANGED
@@ -10,7 +10,7 @@ import { useDefaultValuesFromLoader, useErrorResponseForForm, useFormUpdateAtom,
|
|
10
10
|
import { useMultiValueMap } from "./internal/MultiValueMap";
|
11
11
|
import { addErrorAtom, clearErrorAtom, endSubmitAtom, formRegistry, resetAtom, setFieldErrorsAtom, startSubmitAtom, syncFormContextAtom, } from "./internal/state";
|
12
12
|
import { useSubmitComplete } from "./internal/submissionCallbacks";
|
13
|
-
import { mergeRefs, useIsomorphicLayoutEffect as useLayoutEffect, } from "./internal/util";
|
13
|
+
import { mergeRefs, useDeepEqualsMemo, useIsomorphicLayoutEffect as useLayoutEffect, } from "./internal/util";
|
14
14
|
const getDataFromForm = (el) => new FormData(el);
|
15
15
|
function nonNull(value) {
|
16
16
|
return value !== null;
|
@@ -99,10 +99,11 @@ const useFormAtom = (formId) => {
|
|
99
99
|
/**
|
100
100
|
* The primary form component of `remix-validated-form`.
|
101
101
|
*/
|
102
|
-
export function ValidatedForm({ validator, onSubmit, children, fetcher, action, defaultValues:
|
102
|
+
export function ValidatedForm({ validator, onSubmit, children, fetcher, action, defaultValues: unMemoizedDefaults, formRef: formRefProp, onReset, subaction, resetAfterSubmit = false, disableFocusOnError, method, replace, id, ...rest }) {
|
103
103
|
var _a;
|
104
104
|
const formId = useFormId(id);
|
105
105
|
const formAtom = useFormAtom(formId);
|
106
|
+
const providedDefaultValues = useDeepEqualsMemo(unMemoizedDefaults);
|
106
107
|
const contextValue = useMemo(() => ({
|
107
108
|
formId,
|
108
109
|
action,
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { useRef } from "react";
|
1
|
+
import { useCallback, useRef } from "react";
|
2
2
|
export class MultiValueMap {
|
3
3
|
constructor() {
|
4
4
|
this.dict = new Map();
|
@@ -30,10 +30,10 @@ export class MultiValueMap {
|
|
30
30
|
}
|
31
31
|
export const useMultiValueMap = () => {
|
32
32
|
const ref = useRef(null);
|
33
|
-
return () => {
|
33
|
+
return useCallback(() => {
|
34
34
|
if (ref.current)
|
35
35
|
return ref.current;
|
36
36
|
ref.current = new MultiValueMap();
|
37
37
|
return ref.current;
|
38
|
-
};
|
38
|
+
}, []);
|
39
39
|
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const getCheckboxChecked: (checkboxValue: string | undefined, newValue: unknown) => boolean | undefined;
|
@@ -0,0 +1,9 @@
|
|
1
|
+
export const getCheckboxChecked = (checkboxValue = "on", newValue) => {
|
2
|
+
if (Array.isArray(newValue))
|
3
|
+
return newValue.includes(checkboxValue);
|
4
|
+
if (typeof newValue === "boolean")
|
5
|
+
return newValue;
|
6
|
+
if (typeof newValue === "string")
|
7
|
+
return newValue === checkboxValue;
|
8
|
+
return undefined;
|
9
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const getCheckboxChecked: (checkboxValue: string | undefined, newValue: unknown) => boolean | undefined;
|
@@ -0,0 +1,9 @@
|
|
1
|
+
export const getCheckboxChecked = (checkboxValue = "on", newValue) => {
|
2
|
+
if (Array.isArray(newValue))
|
3
|
+
return newValue.includes(checkboxValue);
|
4
|
+
if (typeof newValue === "boolean")
|
5
|
+
return newValue;
|
6
|
+
if (typeof newValue === "string")
|
7
|
+
return newValue === checkboxValue;
|
8
|
+
return undefined;
|
9
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const getRadioChecked: (radioValue: string | undefined, newValue: unknown) => boolean | undefined;
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const setFieldValue: (formElement: HTMLFormElement, name: string, value: unknown) => void;
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import invariant from "tiny-invariant";
|
2
|
+
import { getCheckboxChecked } from "./getCheckboxChecked";
|
3
|
+
import { getRadioChecked } from "./getRadioChecked";
|
4
|
+
const setElementValue = (element, value, name) => {
|
5
|
+
if (element instanceof HTMLSelectElement && element.multiple) {
|
6
|
+
invariant(Array.isArray(value), "Must specify an array to set the value for a multi-select");
|
7
|
+
for (const option of element.options) {
|
8
|
+
option.selected = value.includes(option.value);
|
9
|
+
}
|
10
|
+
return;
|
11
|
+
}
|
12
|
+
if (element instanceof HTMLInputElement && element.type === "checkbox") {
|
13
|
+
const newChecked = getCheckboxChecked(element.value, value);
|
14
|
+
invariant(newChecked !== undefined, `Unable to determine if checkbox should be checked. Provided value was ${value} for checkbox ${name}.`);
|
15
|
+
element.checked = newChecked;
|
16
|
+
return;
|
17
|
+
}
|
18
|
+
if (element instanceof HTMLInputElement && element.type === "radio") {
|
19
|
+
const newChecked = getRadioChecked(element.value, value);
|
20
|
+
invariant(newChecked !== undefined, `Unable to determine if radio should be checked. Provided value was ${value} for radio ${name}.`);
|
21
|
+
element.checked = newChecked;
|
22
|
+
return;
|
23
|
+
}
|
24
|
+
invariant(typeof value === "string", `Invalid value for field "${name}" which is an ${element.constructor.name}. Expected string but received ${typeof value}`);
|
25
|
+
const input = element;
|
26
|
+
input.value = value;
|
27
|
+
};
|
28
|
+
export const setFieldValue = (formElement, name, value) => {
|
29
|
+
const controlElement = formElement.elements.namedItem(name);
|
30
|
+
if (!controlElement)
|
31
|
+
return;
|
32
|
+
if (controlElement instanceof RadioNodeList) {
|
33
|
+
for (const element of controlElement) {
|
34
|
+
setElementValue(element, value, name);
|
35
|
+
}
|
36
|
+
}
|
37
|
+
else {
|
38
|
+
setElementValue(controlElement, value, name);
|
39
|
+
}
|
40
|
+
};
|
@@ -2,3 +2,4 @@ import type React from "react";
|
|
2
2
|
export declare const omit: (obj: any, ...keys: string[]) => any;
|
3
3
|
export declare const mergeRefs: <T = any>(refs: (React.MutableRefObject<T> | React.LegacyRef<T> | undefined)[]) => (instance: T | null) => void;
|
4
4
|
export declare const useIsomorphicLayoutEffect: typeof React.useEffect;
|
5
|
+
export declare const useDeepEqualsMemo: <T>(item: T) => T;
|
package/browser/internal/util.js
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
import {
|
1
|
+
import { isEqual } from "lodash";
|
2
|
+
import { useEffect, useLayoutEffect, useRef } from "react";
|
2
3
|
export const omit = (obj, ...keys) => {
|
3
4
|
const result = { ...obj };
|
4
5
|
for (const key of keys) {
|
@@ -19,3 +20,13 @@ export const mergeRefs = (refs) => {
|
|
19
20
|
};
|
20
21
|
};
|
21
22
|
export const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
23
|
+
export const useDeepEqualsMemo = (item) => {
|
24
|
+
const ref = useRef(item);
|
25
|
+
const areEqual = ref.current === item || isEqual(ref.current, item);
|
26
|
+
useEffect(() => {
|
27
|
+
if (!areEqual) {
|
28
|
+
ref.current = item;
|
29
|
+
}
|
30
|
+
});
|
31
|
+
return areEqual ? ref.current : item;
|
32
|
+
};
|
package/build/ValidatedForm.d.ts
CHANGED
@@ -47,4 +47,4 @@ export declare type FormProps<DataType> = {
|
|
47
47
|
/**
|
48
48
|
* The primary form component of `remix-validated-form`.
|
49
49
|
*/
|
50
|
-
export declare function ValidatedForm<DataType>({ validator, onSubmit, children, fetcher, action, defaultValues:
|
50
|
+
export declare function ValidatedForm<DataType>({ validator, onSubmit, children, fetcher, action, defaultValues: unMemoizedDefaults, formRef: formRefProp, onReset, subaction, resetAfterSubmit, disableFocusOnError, method, replace, id, ...rest }: FormProps<DataType>): JSX.Element;
|
package/build/ValidatedForm.js
CHANGED
@@ -124,10 +124,11 @@ const useFormAtom = (formId) => {
|
|
124
124
|
/**
|
125
125
|
* The primary form component of `remix-validated-form`.
|
126
126
|
*/
|
127
|
-
function ValidatedForm({ validator, onSubmit, children, fetcher, action, defaultValues:
|
127
|
+
function ValidatedForm({ validator, onSubmit, children, fetcher, action, defaultValues: unMemoizedDefaults, formRef: formRefProp, onReset, subaction, resetAfterSubmit = false, disableFocusOnError, method, replace, id, ...rest }) {
|
128
128
|
var _a;
|
129
129
|
const formId = useFormId(id);
|
130
130
|
const formAtom = useFormAtom(formId);
|
131
|
+
const providedDefaultValues = (0, util_1.useDeepEqualsMemo)(unMemoizedDefaults);
|
131
132
|
const contextValue = (0, react_2.useMemo)(() => ({
|
132
133
|
formId,
|
133
134
|
action,
|
@@ -34,11 +34,11 @@ class MultiValueMap {
|
|
34
34
|
exports.MultiValueMap = MultiValueMap;
|
35
35
|
const useMultiValueMap = () => {
|
36
36
|
const ref = (0, react_1.useRef)(null);
|
37
|
-
return () => {
|
37
|
+
return (0, react_1.useCallback)(() => {
|
38
38
|
if (ref.current)
|
39
39
|
return ref.current;
|
40
40
|
ref.current = new MultiValueMap();
|
41
41
|
return ref.current;
|
42
|
-
};
|
42
|
+
}, []);
|
43
43
|
};
|
44
44
|
exports.useMultiValueMap = useMultiValueMap;
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const getCheckboxChecked: (checkboxValue: string | undefined, newValue: unknown) => boolean | undefined;
|
@@ -0,0 +1,13 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.getCheckboxChecked = void 0;
|
4
|
+
const getCheckboxChecked = (checkboxValue = "on", newValue) => {
|
5
|
+
if (Array.isArray(newValue))
|
6
|
+
return newValue.includes(checkboxValue);
|
7
|
+
if (typeof newValue === "boolean")
|
8
|
+
return newValue;
|
9
|
+
if (typeof newValue === "string")
|
10
|
+
return newValue === checkboxValue;
|
11
|
+
return undefined;
|
12
|
+
};
|
13
|
+
exports.getCheckboxChecked = getCheckboxChecked;
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const getRadioChecked: (radioValue: string | undefined, newValue: unknown) => boolean | undefined;
|
@@ -0,0 +1,9 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.getRadioChecked = void 0;
|
4
|
+
const getRadioChecked = (radioValue = "on", newValue) => {
|
5
|
+
if (typeof newValue === "string")
|
6
|
+
return newValue === radioValue;
|
7
|
+
return undefined;
|
8
|
+
};
|
9
|
+
exports.getRadioChecked = getRadioChecked;
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const setFieldValue: (formElement: HTMLFormElement, name: string, value: unknown) => void;
|
@@ -0,0 +1,47 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.setFieldValue = void 0;
|
7
|
+
const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
|
8
|
+
const getCheckboxChecked_1 = require("./getCheckboxChecked");
|
9
|
+
const getRadioChecked_1 = require("./getRadioChecked");
|
10
|
+
const setElementValue = (element, value, name) => {
|
11
|
+
if (element instanceof HTMLSelectElement && element.multiple) {
|
12
|
+
(0, tiny_invariant_1.default)(Array.isArray(value), "Must specify an array to set the value for a multi-select");
|
13
|
+
for (const option of element.options) {
|
14
|
+
option.selected = value.includes(option.value);
|
15
|
+
}
|
16
|
+
return;
|
17
|
+
}
|
18
|
+
if (element instanceof HTMLInputElement && element.type === "checkbox") {
|
19
|
+
const newChecked = (0, getCheckboxChecked_1.getCheckboxChecked)(element.value, value);
|
20
|
+
(0, tiny_invariant_1.default)(newChecked, `Unable to determine if checkbox should be checked. Provided value was ${value} for checkbox ${name}.`);
|
21
|
+
element.checked = newChecked;
|
22
|
+
return;
|
23
|
+
}
|
24
|
+
if (element instanceof HTMLInputElement && element.type === "radio") {
|
25
|
+
const newChecked = (0, getRadioChecked_1.getRadioChecked)(element.value, value);
|
26
|
+
(0, tiny_invariant_1.default)(newChecked, `Unable to determine if radio should be checked. Provided value was ${value} for radio ${name}.`);
|
27
|
+
element.checked = newChecked;
|
28
|
+
return;
|
29
|
+
}
|
30
|
+
(0, tiny_invariant_1.default)(typeof value === "string", `Must specify a string to set the value of ${element.constructor.name}`);
|
31
|
+
const input = element;
|
32
|
+
input.value = value;
|
33
|
+
};
|
34
|
+
const setFieldValue = (formElement, name, value) => {
|
35
|
+
const controlElement = formElement.elements.namedItem(name);
|
36
|
+
if (!controlElement)
|
37
|
+
return;
|
38
|
+
if (controlElement instanceof RadioNodeList) {
|
39
|
+
for (const element of controlElement) {
|
40
|
+
setElementValue(element, value, name);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
else {
|
44
|
+
setElementValue(controlElement, value, name);
|
45
|
+
}
|
46
|
+
};
|
47
|
+
exports.setFieldValue = setFieldValue;
|
package/build/internal/util.d.ts
CHANGED
@@ -2,3 +2,4 @@ import type React from "react";
|
|
2
2
|
export declare const omit: (obj: any, ...keys: string[]) => any;
|
3
3
|
export declare const mergeRefs: <T = any>(refs: (React.MutableRefObject<T> | React.LegacyRef<T> | undefined)[]) => (instance: T | null) => void;
|
4
4
|
export declare const useIsomorphicLayoutEffect: typeof React.useEffect;
|
5
|
+
export declare const useDeepEqualsMemo: <T>(item: T) => T;
|
package/build/internal/util.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.useIsomorphicLayoutEffect = exports.mergeRefs = exports.omit = void 0;
|
3
|
+
exports.useDeepEqualsMemo = exports.useIsomorphicLayoutEffect = exports.mergeRefs = exports.omit = void 0;
|
4
|
+
const lodash_1 = require("lodash");
|
4
5
|
const react_1 = require("react");
|
5
6
|
const omit = (obj, ...keys) => {
|
6
7
|
const result = { ...obj };
|
@@ -24,3 +25,14 @@ const mergeRefs = (refs) => {
|
|
24
25
|
};
|
25
26
|
exports.mergeRefs = mergeRefs;
|
26
27
|
exports.useIsomorphicLayoutEffect = typeof window !== "undefined" ? react_1.useLayoutEffect : react_1.useEffect;
|
28
|
+
const useDeepEqualsMemo = (item) => {
|
29
|
+
const ref = (0, react_1.useRef)(item);
|
30
|
+
const areEqual = ref.current === item || (0, lodash_1.isEqual)(ref.current, item);
|
31
|
+
(0, react_1.useEffect)(() => {
|
32
|
+
if (!areEqual) {
|
33
|
+
ref.current = item;
|
34
|
+
}
|
35
|
+
});
|
36
|
+
return areEqual ? ref.current : item;
|
37
|
+
};
|
38
|
+
exports.useDeepEqualsMemo = useDeepEqualsMemo;
|
package/package.json
CHANGED
package/src/ValidatedForm.tsx
CHANGED
@@ -38,6 +38,7 @@ import {
|
|
38
38
|
import { useSubmitComplete } from "./internal/submissionCallbacks";
|
39
39
|
import {
|
40
40
|
mergeRefs,
|
41
|
+
useDeepEqualsMemo,
|
41
42
|
useIsomorphicLayoutEffect as useLayoutEffect,
|
42
43
|
} from "./internal/util";
|
43
44
|
import { FieldErrors, Validator } from "./validation/types";
|
@@ -206,7 +207,7 @@ export function ValidatedForm<DataType>({
|
|
206
207
|
children,
|
207
208
|
fetcher,
|
208
209
|
action,
|
209
|
-
defaultValues:
|
210
|
+
defaultValues: unMemoizedDefaults,
|
210
211
|
formRef: formRefProp,
|
211
212
|
onReset,
|
212
213
|
subaction,
|
@@ -219,6 +220,7 @@ export function ValidatedForm<DataType>({
|
|
219
220
|
}: FormProps<DataType>) {
|
220
221
|
const formId = useFormId(id);
|
221
222
|
const formAtom = useFormAtom(formId);
|
223
|
+
const providedDefaultValues = useDeepEqualsMemo(unMemoizedDefaults);
|
222
224
|
const contextValue = useMemo<InternalFormContextValue>(
|
223
225
|
() => ({
|
224
226
|
formId,
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { useRef } from "react";
|
1
|
+
import { useCallback, useRef } from "react";
|
2
2
|
|
3
3
|
export class MultiValueMap<Key, Value> {
|
4
4
|
private dict: Map<Key, Value[]> = new Map();
|
@@ -30,9 +30,9 @@ export class MultiValueMap<Key, Value> {
|
|
30
30
|
|
31
31
|
export const useMultiValueMap = <Key, Value>() => {
|
32
32
|
const ref = useRef<MultiValueMap<Key, Value> | null>(null);
|
33
|
-
return () => {
|
33
|
+
return useCallback(() => {
|
34
34
|
if (ref.current) return ref.current;
|
35
35
|
ref.current = new MultiValueMap();
|
36
36
|
return ref.current;
|
37
|
-
};
|
37
|
+
}, []);
|
38
38
|
};
|
package/src/internal/util.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
+
import { isEqual } from "lodash";
|
1
2
|
import type React from "react";
|
2
|
-
import { useEffect, useLayoutEffect } from "react";
|
3
|
+
import { useEffect, useLayoutEffect, useRef } from "react";
|
3
4
|
|
4
5
|
export const omit = (obj: any, ...keys: string[]) => {
|
5
6
|
const result = { ...obj };
|
@@ -25,3 +26,14 @@ export const mergeRefs = <T = any>(
|
|
25
26
|
|
26
27
|
export const useIsomorphicLayoutEffect =
|
27
28
|
typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
29
|
+
|
30
|
+
export const useDeepEqualsMemo = <T>(item: T): T => {
|
31
|
+
const ref = useRef<T>(item);
|
32
|
+
const areEqual = ref.current === item || isEqual(ref.current, item);
|
33
|
+
useEffect(() => {
|
34
|
+
if (!areEqual) {
|
35
|
+
ref.current = item;
|
36
|
+
}
|
37
|
+
});
|
38
|
+
return areEqual ? ref.current : item;
|
39
|
+
};
|