@homebound/form-state 2.19.0 → 2.20.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/FormStateApp.d.ts +2 -3
- package/dist/FormStateApp.js +8 -47
- package/dist/FormStateApp.test.js +14 -14
- package/dist/config.d.ts +6 -6
- package/dist/fields/fragmentField.js +3 -3
- package/dist/fields/listField.js +12 -12
- package/dist/fields/objectField.d.ts +4 -4
- package/dist/fields/objectField.js +10 -10
- package/dist/fields/valueField.d.ts +13 -0
- package/dist/fields/valueField.js +48 -14
- package/dist/formState.stories.d.ts +2 -4
- package/dist/formState.stories.js +1 -1
- package/dist/formState.test.js +146 -79
- package/dist/formStateDomain.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/proxies.d.ts +5 -0
- package/dist/proxies.js +21 -0
- package/dist/rules.d.ts +1 -1
- package/dist/rules.js +1 -1
- package/dist/setupTests.js +2 -2
- package/dist/useFormState.d.ts +4 -4
- package/dist/useFormState.js +13 -13
- package/dist/useFormState.test.js +141 -169
- package/dist/useFormStates.d.ts +3 -3
- package/dist/useFormStates.js +7 -7
- package/dist/useFormStates.test.js +56 -63
- package/dist/utils.d.ts +3 -3
- package/dist/utils.js +8 -8
- package/dist/utils.test.js +49 -49
- package/package.json +44 -39
package/dist/formStateDomain.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { ObjectConfig } from "./config";
|
|
2
2
|
export { ListFieldState } from "./fields/listField";
|
|
3
|
-
export {
|
|
4
|
-
export { FieldState } from "./fields/valueField";
|
|
5
|
-
export {
|
|
3
|
+
export { ObjectState, createObjectState } from "./fields/objectField";
|
|
4
|
+
export { FieldState, ValueAdapter } from "./fields/valueField";
|
|
5
|
+
export { Rule, required } from "./rules";
|
|
6
6
|
export { useFormState } from "./useFormState";
|
|
7
7
|
export { useFormStates } from "./useFormStates";
|
package/dist/proxies.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.newDelegateProxy = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Creates a new combined object with keys in `overrides` taking precedence, and then
|
|
6
|
+
* any other keys falling back to `delegate`.
|
|
7
|
+
*/
|
|
8
|
+
function newDelegateProxy(delegate, overrides) {
|
|
9
|
+
function pickTarget(key) {
|
|
10
|
+
return Reflect.has(overrides, key) ? overrides : delegate;
|
|
11
|
+
}
|
|
12
|
+
return new Proxy(delegate, {
|
|
13
|
+
get(object, key) {
|
|
14
|
+
return Reflect.get(pickTarget(key), key);
|
|
15
|
+
},
|
|
16
|
+
set(object, key, value) {
|
|
17
|
+
return Reflect.set(pickTarget(key), key, value);
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
exports.newDelegateProxy = newDelegateProxy;
|
package/dist/rules.d.ts
CHANGED
package/dist/rules.js
CHANGED
|
@@ -5,7 +5,7 @@ const mobx_1 = require("mobx");
|
|
|
5
5
|
/** A rule that validates `value` is not `undefined`, `null`, or empty string. */
|
|
6
6
|
// We pre-emptively make this a mobx action so that it's identity doesn't change when proxied
|
|
7
7
|
// and breaks our ability to do `rules.some(r => r === required)`.
|
|
8
|
-
exports.required = mobx_1.action(({ value: v }) => {
|
|
8
|
+
exports.required = (0, mobx_1.action)(({ value: v }) => {
|
|
9
9
|
const isEmptyString = typeof v === "string" ? v.trim() === "" : false;
|
|
10
10
|
return v !== undefined && v !== null && !isEmptyString ? undefined : "Required";
|
|
11
11
|
});
|
package/dist/setupTests.js
CHANGED
|
@@ -3,9 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
require("@testing-library/jest-dom");
|
|
4
4
|
const mobx_1 = require("mobx");
|
|
5
5
|
// formState doesn't use actions
|
|
6
|
-
mobx_1.configure({ enforceActions: "never" });
|
|
6
|
+
(0, mobx_1.configure)({ enforceActions: "never" });
|
|
7
7
|
beforeEach(() => {
|
|
8
|
-
jest.useFakeTimers(
|
|
8
|
+
jest.useFakeTimers();
|
|
9
9
|
});
|
|
10
10
|
afterEach(() => {
|
|
11
11
|
jest.runOnlyPendingTimers();
|
package/dist/useFormState.d.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { ObjectConfig } from "./config";
|
|
2
2
|
import { ObjectState } from "./fields/objectField";
|
|
3
|
-
export
|
|
3
|
+
export type Query<I> = {
|
|
4
4
|
data: I;
|
|
5
5
|
loading: boolean;
|
|
6
6
|
error?: any;
|
|
7
7
|
};
|
|
8
|
-
export
|
|
8
|
+
export type InputAndMap<T, I> = {
|
|
9
9
|
input: I;
|
|
10
10
|
map: (input: Exclude<I, null | undefined>) => T;
|
|
11
11
|
ifUndefined?: T;
|
|
12
12
|
};
|
|
13
|
-
export
|
|
13
|
+
export type QueryAndMap<T, I> = {
|
|
14
14
|
query: Query<I>;
|
|
15
15
|
map: (input: Exclude<I, null | undefined>) => T;
|
|
16
16
|
ifUndefined?: T;
|
|
17
17
|
};
|
|
18
|
-
export
|
|
18
|
+
export type UseFormStateOpts<T, I> = {
|
|
19
19
|
/** The form configuration, should be a module-level const or useMemo'd. */
|
|
20
20
|
config: ObjectConfig<T>;
|
|
21
21
|
/**
|
package/dist/useFormState.js
CHANGED
|
@@ -18,15 +18,15 @@ let pendingAutoSave = false;
|
|
|
18
18
|
function useFormState(opts) {
|
|
19
19
|
const { config, init, addRules, readOnly = false, loading, autoSave } = opts;
|
|
20
20
|
// Use a ref so our memo'ized `onBlur` always see the latest value
|
|
21
|
-
const autoSaveRef = react_1.useRef(autoSave);
|
|
21
|
+
const autoSaveRef = (0, react_1.useRef)(autoSave);
|
|
22
22
|
autoSaveRef.current = autoSave;
|
|
23
|
-
const firstRunRef = react_1.useRef(true);
|
|
23
|
+
const firstRunRef = (0, react_1.useRef)(true);
|
|
24
24
|
// This is a little weird, but we need to know ahead of time, before the form useMemo, if we're working with classes/mobx proxies
|
|
25
|
-
const [firstInitValue] = react_1.useState(() => utils_1.initValue(config, init));
|
|
26
|
-
const isWrappingMobxProxy = !is_plain_object_1.isPlainObject(firstInitValue);
|
|
25
|
+
const [firstInitValue] = (0, react_1.useState)(() => (0, utils_1.initValue)(config, init));
|
|
26
|
+
const isWrappingMobxProxy = !(0, is_plain_object_1.isPlainObject)(firstInitValue);
|
|
27
27
|
// If they're using init.input, useMemo on it (and it might be an array), otherwise allow the identity of init be unstable
|
|
28
|
-
const dep = utils_1.isInput(init) ? makeArray(init.input) : utils_1.isQuery(init) ? [init.query.data, init.query.loading] : [];
|
|
29
|
-
const form = react_1.useMemo(() => {
|
|
28
|
+
const dep = (0, utils_1.isInput)(init) ? makeArray(init.input) : (0, utils_1.isQuery)(init) ? [init.query.data, init.query.loading] : [];
|
|
29
|
+
const form = (0, react_1.useMemo)(() => {
|
|
30
30
|
function maybeAutoSave() {
|
|
31
31
|
if (isAutoSaving === "in-flight") {
|
|
32
32
|
pendingAutoSave = true;
|
|
@@ -64,8 +64,8 @@ function useFormState(opts) {
|
|
|
64
64
|
}, 0);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
-
const value = firstRunRef.current ? firstInitValue : utils_1.initValue(config, init);
|
|
68
|
-
const form = objectField_1.createObjectState(config, value, { maybeAutoSave });
|
|
67
|
+
const value = firstRunRef.current ? firstInitValue : (0, utils_1.initValue)(config, init);
|
|
68
|
+
const form = (0, objectField_1.createObjectState)(config, value, { maybeAutoSave });
|
|
69
69
|
form.readOnly = readOnly;
|
|
70
70
|
setLoading(form, opts);
|
|
71
71
|
// The identity of `addRules` is not stable, but assume that it is for better UX.
|
|
@@ -78,7 +78,7 @@ function useFormState(opts) {
|
|
|
78
78
|
[config, ...(isWrappingMobxProxy ? dep : [])]);
|
|
79
79
|
// We use useEffect so that any mutations to the proxies, which will call `setState`s on any observers to
|
|
80
80
|
// queue their components' render), don't happen during our render, per https://fb.me/setstate-in-render.
|
|
81
|
-
react_1.useEffect(() => {
|
|
81
|
+
(0, react_1.useEffect)(() => {
|
|
82
82
|
// Ignore the 1st run b/c our 1st useMemo already initialized `form` with the current `init` value.
|
|
83
83
|
// Also for mobx proxies, we recreate a new form-state every time init changes, so that our
|
|
84
84
|
// fields fundamentally pointing to the right proxy. So just defer to the ^ useMemo.
|
|
@@ -93,10 +93,10 @@ function useFormState(opts) {
|
|
|
93
93
|
// rows in the table that our side panel's form has open/is focused on" (which ideally would
|
|
94
94
|
// be treated as a full component remount by having an `key` field somewhere in the parent
|
|
95
95
|
// component, but it's unlikely the user will always remember to do this).
|
|
96
|
-
form.set(utils_1.initValue(config, init), { refreshing: true });
|
|
96
|
+
form.set((0, utils_1.initValue)(config, init), { refreshing: true });
|
|
97
97
|
}, [form, ...dep]);
|
|
98
98
|
// Use useEffect so that we don't touch the form.init proxy during a render
|
|
99
|
-
react_1.useEffect(() => {
|
|
99
|
+
(0, react_1.useEffect)(() => {
|
|
100
100
|
form.readOnly = readOnly;
|
|
101
101
|
if (loading !== undefined) {
|
|
102
102
|
form.loading = loading;
|
|
@@ -111,11 +111,11 @@ function setLoading(form, opts) {
|
|
|
111
111
|
// Prefer the explicit/top-level opts.loading if it's set
|
|
112
112
|
form.loading = loading;
|
|
113
113
|
}
|
|
114
|
-
else if (utils_1.isInput(init) && !init.ifUndefined) {
|
|
114
|
+
else if ((0, utils_1.isInput)(init) && !init.ifUndefined) {
|
|
115
115
|
// Otherwise, check for `init.input`
|
|
116
116
|
form.loading = init.input === undefined;
|
|
117
117
|
}
|
|
118
|
-
else if (utils_1.isQuery(init)) {
|
|
118
|
+
else if ((0, utils_1.isQuery)(init)) {
|
|
119
119
|
// Or `query.loading`
|
|
120
120
|
form.loading = init.query.loading;
|
|
121
121
|
}
|