remix-validated-form 4.5.0-beta.1 → 4.5.0
Sign up to get free protection for your applications and to get access to all the features.
- package/.turbo/turbo-build.log +8 -8
- package/browser/internal/logic/nestedObjectToPathObject.d.ts +1 -0
- package/browser/internal/logic/nestedObjectToPathObject.js +47 -0
- package/browser/internal/state/arrayUtil.d.ts +6 -0
- package/browser/internal/state/arrayUtil.js +108 -0
- package/browser/internal/state/fieldArray.d.ts +21 -0
- package/browser/internal/state/fieldArray.js +50 -0
- package/browser/internal/state/types.d.ts +0 -0
- package/browser/internal/state/types.js +0 -0
- package/package.json +1 -1
package/.turbo/turbo-build.log
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
[2K[1G[2m$ vite build[22m
|
2
2
|
[36mvite v2.9.5 [32mbuilding for production...[36m[39m
|
3
3
|
transforming...
|
4
|
-
[32m✓[39m
|
4
|
+
[32m✓[39m 320 modules transformed.
|
5
5
|
rendering chunks...
|
6
|
-
[90m[37m[2mdist/[22m[90m[39m[36mremix-validated-form.cjs.js [39m [
|
7
|
-
[90m[37m[2mdist/[22m[90m[39m[90mremix-validated-form.cjs.js.map[39m [
|
8
|
-
[90m[37m[2mdist/[22m[90m[39m[36mremix-validated-form.es.js [39m [
|
9
|
-
[90m[37m[2mdist/[22m[90m[39m[90mremix-validated-form.es.js.map[39m [
|
10
|
-
[90m[37m[2mdist/[22m[90m[39m[36mremix-validated-form.umd.js [39m [
|
11
|
-
[90m[37m[2mdist/[22m[90m[39m[90mremix-validated-form.umd.js.map[39m [
|
6
|
+
[90m[37m[2mdist/[22m[90m[39m[36mremix-validated-form.cjs.js [39m [2m47.23 KiB / gzip: 17.41 KiB[22m
|
7
|
+
[90m[37m[2mdist/[22m[90m[39m[90mremix-validated-form.cjs.js.map[39m [2m265.34 KiB[22m
|
8
|
+
[90m[37m[2mdist/[22m[90m[39m[36mremix-validated-form.es.js [39m [2m104.23 KiB / gzip: 24.22 KiB[22m
|
9
|
+
[90m[37m[2mdist/[22m[90m[39m[90mremix-validated-form.es.js.map[39m [2m273.50 KiB[22m
|
10
|
+
[90m[37m[2mdist/[22m[90m[39m[36mremix-validated-form.umd.js [39m [2m47.48 KiB / gzip: 17.53 KiB[22m
|
11
|
+
[90m[37m[2mdist/[22m[90m[39m[90mremix-validated-form.umd.js.map[39m [2m265.31 KiB[22m
|
12
12
|
[32m[39m
|
13
13
|
[32m[36m[vite:dts][39m[32m Start generate declaration files...[39m
|
14
|
-
[32m[36m[vite:dts][39m[32m Declaration files built in
|
14
|
+
[32m[36m[vite:dts][39m[32m Declaration files built in 1961ms.[39m
|
15
15
|
[32m[39m
|
16
16
|
No name was provided for external module 'react' in output.globals – guessing 'React'
|
17
17
|
No name was provided for external module '@remix-run/react' in output.globals – guessing 'react'
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const nestedObjectToPathObject: (val: any, acc: Record<string, any>, path: string) => any;
|
@@ -0,0 +1,47 @@
|
|
1
|
+
export const nestedObjectToPathObject = (val, acc, path) => {
|
2
|
+
if (Array.isArray(val)) {
|
3
|
+
val.forEach((v, index) => nestedObjectToPathObject(v, acc, `${path}[${index}]`));
|
4
|
+
return acc;
|
5
|
+
}
|
6
|
+
if (typeof val === "object") {
|
7
|
+
Object.entries(val).forEach(([key, value]) => {
|
8
|
+
const nextPath = path ? `${path}.${key}` : key;
|
9
|
+
nestedObjectToPathObject(value, acc, nextPath);
|
10
|
+
});
|
11
|
+
return acc;
|
12
|
+
}
|
13
|
+
if (val !== undefined) {
|
14
|
+
acc[path] = val;
|
15
|
+
}
|
16
|
+
return acc;
|
17
|
+
};
|
18
|
+
if (import.meta.vitest) {
|
19
|
+
const { describe, expect, it } = import.meta.vitest;
|
20
|
+
describe("nestedObjectToPathObject", () => {
|
21
|
+
it("should return an object with the correct path", () => {
|
22
|
+
const result = nestedObjectToPathObject({
|
23
|
+
a: 1,
|
24
|
+
b: 2,
|
25
|
+
c: { foo: "bar", baz: [true, false] },
|
26
|
+
d: [
|
27
|
+
{ foo: "bar", baz: [true, false] },
|
28
|
+
{ e: true, f: "hi" },
|
29
|
+
],
|
30
|
+
g: undefined,
|
31
|
+
}, {}, "");
|
32
|
+
expect(result).toEqual({
|
33
|
+
a: 1,
|
34
|
+
b: 2,
|
35
|
+
"c.foo": "bar",
|
36
|
+
"c.baz[0]": true,
|
37
|
+
"c.baz[1]": false,
|
38
|
+
"d[0].foo": "bar",
|
39
|
+
"d[0].baz[0]": true,
|
40
|
+
"d[0].baz[1]": false,
|
41
|
+
"d[1].e": true,
|
42
|
+
"d[1].f": "hi",
|
43
|
+
});
|
44
|
+
expect(Object.keys(result)).toHaveLength(10);
|
45
|
+
});
|
46
|
+
});
|
47
|
+
}
|
@@ -0,0 +1,6 @@
|
|
1
|
+
export declare const getArray: (values: any, field: string) => unknown[];
|
2
|
+
export declare const swap: (array: unknown[], indexA: number, indexB: number) => void;
|
3
|
+
export declare const move: (array: unknown[], from: number, to: number) => void;
|
4
|
+
export declare const insert: (array: unknown[], index: number, value: unknown) => void;
|
5
|
+
export declare const remove: (array: unknown[], index: number) => void;
|
6
|
+
export declare const replace: (array: unknown[], index: number, value: unknown) => void;
|
@@ -0,0 +1,108 @@
|
|
1
|
+
import lodashGet from "lodash/get";
|
2
|
+
import lodashSet from "lodash/set";
|
3
|
+
import invariant from "tiny-invariant";
|
4
|
+
////
|
5
|
+
// All of these array helpers are written in a way that mutates the original array.
|
6
|
+
// This is because we're working with immer.
|
7
|
+
////
|
8
|
+
export const getArray = (values, field) => {
|
9
|
+
const value = lodashGet(values, field);
|
10
|
+
if (value === undefined || value === null) {
|
11
|
+
const newValue = [];
|
12
|
+
lodashSet(values, field, newValue);
|
13
|
+
return newValue;
|
14
|
+
}
|
15
|
+
invariant(Array.isArray(value), `FieldArray: defaultValue value for ${field} must be an array, null, or undefined`);
|
16
|
+
return value;
|
17
|
+
};
|
18
|
+
export const swap = (array, indexA, indexB) => {
|
19
|
+
const itemA = array[indexA];
|
20
|
+
const itemB = array[indexB];
|
21
|
+
array[indexA] = itemB;
|
22
|
+
array[indexB] = itemA;
|
23
|
+
};
|
24
|
+
export const move = (array, from, to) => {
|
25
|
+
const [item] = array.splice(from, 1);
|
26
|
+
array.splice(to, 0, item);
|
27
|
+
};
|
28
|
+
export const insert = (array, index, value) => {
|
29
|
+
array.splice(index, 0, value);
|
30
|
+
};
|
31
|
+
export const remove = (array, index) => {
|
32
|
+
array.splice(index, 1);
|
33
|
+
};
|
34
|
+
export const replace = (array, index, value) => {
|
35
|
+
array.splice(index, 1, value);
|
36
|
+
};
|
37
|
+
if (import.meta.vitest) {
|
38
|
+
const { describe, expect, it } = import.meta.vitest;
|
39
|
+
describe("getArray", () => {
|
40
|
+
it("shoud get a deeply nested array that can be mutated to update the nested value", () => {
|
41
|
+
const values = {
|
42
|
+
d: [
|
43
|
+
{ foo: "bar", baz: [true, false] },
|
44
|
+
{ e: true, f: "hi" },
|
45
|
+
],
|
46
|
+
};
|
47
|
+
const result = getArray(values, "d[0].baz");
|
48
|
+
const finalValues = {
|
49
|
+
d: [
|
50
|
+
{ foo: "bar", baz: [true, false, true] },
|
51
|
+
{ e: true, f: "hi" },
|
52
|
+
],
|
53
|
+
};
|
54
|
+
expect(result).toEqual([true, false]);
|
55
|
+
result.push(true);
|
56
|
+
expect(values).toEqual(finalValues);
|
57
|
+
});
|
58
|
+
it("should return an empty array that can be mutated if result is null or undefined", () => {
|
59
|
+
const values = {};
|
60
|
+
const result = getArray(values, "a.foo[0].bar");
|
61
|
+
const finalValues = {
|
62
|
+
a: { foo: [{ bar: ["Bob ross"] }] },
|
63
|
+
};
|
64
|
+
expect(result).toEqual([]);
|
65
|
+
result.push("Bob ross");
|
66
|
+
expect(values).toEqual(finalValues);
|
67
|
+
});
|
68
|
+
it("should throw if the value is defined and not an array", () => {
|
69
|
+
const values = { foo: "foo" };
|
70
|
+
expect(() => getArray(values, "foo")).toThrow();
|
71
|
+
});
|
72
|
+
});
|
73
|
+
describe("swap", () => {
|
74
|
+
it("should swap two items", () => {
|
75
|
+
const array = [1, 2, 3];
|
76
|
+
swap(array, 0, 1);
|
77
|
+
expect(array).toEqual([2, 1, 3]);
|
78
|
+
});
|
79
|
+
});
|
80
|
+
describe("move", () => {
|
81
|
+
it("should move an item to a new index", () => {
|
82
|
+
const array = [1, 2, 3];
|
83
|
+
move(array, 0, 1);
|
84
|
+
expect(array).toEqual([2, 1, 3]);
|
85
|
+
});
|
86
|
+
});
|
87
|
+
describe("insert", () => {
|
88
|
+
it("should insert an item at a new index", () => {
|
89
|
+
const array = [1, 2, 3];
|
90
|
+
insert(array, 1, 4);
|
91
|
+
expect(array).toEqual([1, 4, 2, 3]);
|
92
|
+
});
|
93
|
+
});
|
94
|
+
describe("remove", () => {
|
95
|
+
it("should remove an item at a given index", () => {
|
96
|
+
const array = [1, 2, 3];
|
97
|
+
remove(array, 1);
|
98
|
+
expect(array).toEqual([1, 3]);
|
99
|
+
});
|
100
|
+
});
|
101
|
+
describe("replace", () => {
|
102
|
+
it("should replace an item at a given index", () => {
|
103
|
+
const array = [1, 2, 3];
|
104
|
+
replace(array, 1, 4);
|
105
|
+
expect(array).toEqual([1, 4, 3]);
|
106
|
+
});
|
107
|
+
});
|
108
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import React from "react";
|
2
|
+
export declare const FieldArrayContext: React.Context<{
|
3
|
+
defaultValues: any[];
|
4
|
+
name: string;
|
5
|
+
} | null>;
|
6
|
+
export declare type FieldArrayHelpers = {
|
7
|
+
push: (item: any) => void;
|
8
|
+
swap: (indexA: number, indexB: number) => void;
|
9
|
+
move: (from: number, to: number) => void;
|
10
|
+
insert: (index: number, value: any) => void;
|
11
|
+
unshift: () => void;
|
12
|
+
remove: (index: number) => void;
|
13
|
+
pop: () => void;
|
14
|
+
replace: (index: number, value: any) => void;
|
15
|
+
};
|
16
|
+
export declare type FieldArrayProps = {
|
17
|
+
name: string;
|
18
|
+
children: (itemDefaults: any[], helpers: FieldArrayHelpers) => React.ReactNode;
|
19
|
+
formId?: string;
|
20
|
+
};
|
21
|
+
export declare const FieldArray: ({ name, children, formId }: FieldArrayProps) => JSX.Element;
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
+
import { useMemo, createContext } from "react";
|
3
|
+
import invariant from "tiny-invariant";
|
4
|
+
import { useInternalFormContext } from "../hooks";
|
5
|
+
import { useControllableValue } from "./controlledFields";
|
6
|
+
import { useFormStore } from "./storeHooks";
|
7
|
+
const useFieldArray = (context, field) => {
|
8
|
+
// TODO: Fieldarrays need to handle/update these things, too:
|
9
|
+
// - touchedFields & fieldErrors should be updated when fields are added/removed
|
10
|
+
// - Could probably move some of these callbacks into the store
|
11
|
+
// - There's a bug where adding a new field to the fieldarray validates the new field.
|
12
|
+
// - For some reason this only happens in the test-app, but not in the docs app.
|
13
|
+
const [value] = useControllableValue(context, field);
|
14
|
+
const arr = useFormStore(context.formId, (state) => state.controlledFields.array);
|
15
|
+
const helpers = useMemo(() => ({
|
16
|
+
push: (item) => {
|
17
|
+
arr.push(field, item);
|
18
|
+
},
|
19
|
+
swap: (indexA, indexB) => {
|
20
|
+
arr.swap(field, indexA, indexB);
|
21
|
+
},
|
22
|
+
move: (from, to) => {
|
23
|
+
arr.move(field, from, to);
|
24
|
+
},
|
25
|
+
insert: (index, value) => {
|
26
|
+
arr.insert(field, index, value);
|
27
|
+
},
|
28
|
+
unshift: () => {
|
29
|
+
arr.unshift(field);
|
30
|
+
},
|
31
|
+
remove: (index) => {
|
32
|
+
arr.remove(field, index);
|
33
|
+
},
|
34
|
+
pop: () => {
|
35
|
+
arr.pop(field);
|
36
|
+
},
|
37
|
+
replace: (index, value) => {
|
38
|
+
arr.replace(field, index, value);
|
39
|
+
},
|
40
|
+
}), [arr, field]);
|
41
|
+
return [value, helpers];
|
42
|
+
};
|
43
|
+
export const FieldArrayContext = createContext(null);
|
44
|
+
export const FieldArray = ({ name, children, formId }) => {
|
45
|
+
const context = useInternalFormContext(formId, "FieldArray");
|
46
|
+
const [value, helpers] = useFieldArray(context, name);
|
47
|
+
invariant(value === undefined || value === null || Array.isArray(value), `FieldArray: defaultValue value for ${name} must be an array, null, or undefined`);
|
48
|
+
const contextValue = useMemo(() => ({ defaultValues: value !== null && value !== void 0 ? value : [], name }), [name, value]);
|
49
|
+
return (_jsx(FieldArrayContext.Provider, { value: contextValue, children: children(contextValue.defaultValues, helpers) }, void 0));
|
50
|
+
};
|
File without changes
|
File without changes
|
package/package.json
CHANGED