@homebound/form-state 2.18.1 → 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 +49 -14
- package/dist/formState.stories.d.ts +2 -4
- package/dist/formState.stories.js +1 -1
- package/dist/formState.test.js +171 -77
- package/dist/formStateDomain.js +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.js +0 -11
- 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 -17
- package/dist/useFormState.test.js +141 -198
- package/dist/useFormStates.d.ts +3 -3
- package/dist/useFormStates.js +7 -11
- package/dist/useFormStates.test.js +56 -89
- 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/AutoSaveStatus/AutoSaveStatusProvider.d.ts +0 -24
- package/dist/AutoSaveStatus/AutoSaveStatusProvider.js +0 -91
- package/dist/AutoSaveStatus/index.d.ts +0 -2
- package/dist/AutoSaveStatus/index.js +0 -9
- package/dist/AutoSaveStatus/useAutoSaveStatus.d.ts +0 -1
- package/dist/AutoSaveStatus/useAutoSaveStatus.js +0 -9
- package/dist/AutoSaveStatus/useAutoSaveStatus.test.d.ts +0 -1
- package/dist/AutoSaveStatus/useAutoSaveStatus.test.js +0 -152
package/dist/formStateDomain.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +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";
|
|
8
|
-
export * from "./AutoSaveStatus/index";
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
-
}) : (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
o[k2] = m[k];
|
|
8
|
-
}));
|
|
9
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
-
};
|
|
12
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
3
|
exports.useFormStates = exports.useFormState = exports.required = exports.createObjectState = void 0;
|
|
14
4
|
var objectField_1 = require("./fields/objectField");
|
|
@@ -19,4 +9,3 @@ var useFormState_1 = require("./useFormState");
|
|
|
19
9
|
Object.defineProperty(exports, "useFormState", { enumerable: true, get: function () { return useFormState_1.useFormState; } });
|
|
20
10
|
var useFormStates_1 = require("./useFormStates");
|
|
21
11
|
Object.defineProperty(exports, "useFormStates", { enumerable: true, get: function () { return useFormStates_1.useFormStates; } });
|
|
22
|
-
__exportStar(require("./AutoSaveStatus/index"), exports);
|
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
|
@@ -4,7 +4,6 @@ exports.useFormState = void 0;
|
|
|
4
4
|
const is_plain_object_1 = require("is-plain-object");
|
|
5
5
|
const react_1 = require("react");
|
|
6
6
|
const objectField_1 = require("./fields/objectField");
|
|
7
|
-
const AutoSaveStatus_1 = require("./AutoSaveStatus/index");
|
|
8
7
|
const utils_1 = require("./utils");
|
|
9
8
|
// If the user's autoSave hook makes some last-minute `.set` calls to sneak
|
|
10
9
|
// in some business logic right before their GraphQL mutation call, ignore it
|
|
@@ -18,17 +17,16 @@ let pendingAutoSave = false;
|
|
|
18
17
|
*/
|
|
19
18
|
function useFormState(opts) {
|
|
20
19
|
const { config, init, addRules, readOnly = false, loading, autoSave } = opts;
|
|
21
|
-
const autoSaveStatusContext = AutoSaveStatus_1.useAutoSaveStatus();
|
|
22
20
|
// Use a ref so our memo'ized `onBlur` always see the latest value
|
|
23
|
-
const autoSaveRef = react_1.useRef(autoSave);
|
|
21
|
+
const autoSaveRef = (0, react_1.useRef)(autoSave);
|
|
24
22
|
autoSaveRef.current = autoSave;
|
|
25
|
-
const firstRunRef = react_1.useRef(true);
|
|
23
|
+
const firstRunRef = (0, react_1.useRef)(true);
|
|
26
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
|
|
27
|
-
const [firstInitValue] = react_1.useState(() => utils_1.initValue(config, init));
|
|
28
|
-
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);
|
|
29
27
|
// If they're using init.input, useMemo on it (and it might be an array), otherwise allow the identity of init be unstable
|
|
30
|
-
const dep = utils_1.isInput(init) ? makeArray(init.input) : utils_1.isQuery(init) ? [init.query.data, init.query.loading] : [];
|
|
31
|
-
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)(() => {
|
|
32
30
|
function maybeAutoSave() {
|
|
33
31
|
if (isAutoSaving === "in-flight") {
|
|
34
32
|
pendingAutoSave = true;
|
|
@@ -47,7 +45,6 @@ function useFormState(opts) {
|
|
|
47
45
|
// user's autoSave function itself wants to call a .set.
|
|
48
46
|
const promise = autoSaveRef.current(form);
|
|
49
47
|
isAutoSaving = "in-flight";
|
|
50
|
-
autoSaveStatusContext.triggerAutoSave();
|
|
51
48
|
await promise;
|
|
52
49
|
}
|
|
53
50
|
catch (e) {
|
|
@@ -56,7 +53,6 @@ function useFormState(opts) {
|
|
|
56
53
|
}
|
|
57
54
|
finally {
|
|
58
55
|
isAutoSaving = false;
|
|
59
|
-
autoSaveStatusContext.resolveAutoSave(maybeError === null || maybeError === void 0 ? void 0 : maybeError.toString());
|
|
60
56
|
if (pendingAutoSave) {
|
|
61
57
|
pendingAutoSave = false;
|
|
62
58
|
// Push out the follow-up by 1 tick to allow refreshes to happen to potentially
|
|
@@ -68,8 +64,8 @@ function useFormState(opts) {
|
|
|
68
64
|
}, 0);
|
|
69
65
|
}
|
|
70
66
|
}
|
|
71
|
-
const value = firstRunRef.current ? firstInitValue : utils_1.initValue(config, init);
|
|
72
|
-
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 });
|
|
73
69
|
form.readOnly = readOnly;
|
|
74
70
|
setLoading(form, opts);
|
|
75
71
|
// The identity of `addRules` is not stable, but assume that it is for better UX.
|
|
@@ -82,7 +78,7 @@ function useFormState(opts) {
|
|
|
82
78
|
[config, ...(isWrappingMobxProxy ? dep : [])]);
|
|
83
79
|
// We use useEffect so that any mutations to the proxies, which will call `setState`s on any observers to
|
|
84
80
|
// queue their components' render), don't happen during our render, per https://fb.me/setstate-in-render.
|
|
85
|
-
react_1.useEffect(() => {
|
|
81
|
+
(0, react_1.useEffect)(() => {
|
|
86
82
|
// Ignore the 1st run b/c our 1st useMemo already initialized `form` with the current `init` value.
|
|
87
83
|
// Also for mobx proxies, we recreate a new form-state every time init changes, so that our
|
|
88
84
|
// fields fundamentally pointing to the right proxy. So just defer to the ^ useMemo.
|
|
@@ -97,10 +93,10 @@ function useFormState(opts) {
|
|
|
97
93
|
// rows in the table that our side panel's form has open/is focused on" (which ideally would
|
|
98
94
|
// be treated as a full component remount by having an `key` field somewhere in the parent
|
|
99
95
|
// component, but it's unlikely the user will always remember to do this).
|
|
100
|
-
form.set(utils_1.initValue(config, init), { refreshing: true });
|
|
96
|
+
form.set((0, utils_1.initValue)(config, init), { refreshing: true });
|
|
101
97
|
}, [form, ...dep]);
|
|
102
98
|
// Use useEffect so that we don't touch the form.init proxy during a render
|
|
103
|
-
react_1.useEffect(() => {
|
|
99
|
+
(0, react_1.useEffect)(() => {
|
|
104
100
|
form.readOnly = readOnly;
|
|
105
101
|
if (loading !== undefined) {
|
|
106
102
|
form.loading = loading;
|
|
@@ -115,11 +111,11 @@ function setLoading(form, opts) {
|
|
|
115
111
|
// Prefer the explicit/top-level opts.loading if it's set
|
|
116
112
|
form.loading = loading;
|
|
117
113
|
}
|
|
118
|
-
else if (utils_1.isInput(init) && !init.ifUndefined) {
|
|
114
|
+
else if ((0, utils_1.isInput)(init) && !init.ifUndefined) {
|
|
119
115
|
// Otherwise, check for `init.input`
|
|
120
116
|
form.loading = init.input === undefined;
|
|
121
117
|
}
|
|
122
|
-
else if (utils_1.isQuery(init)) {
|
|
118
|
+
else if ((0, utils_1.isQuery)(init)) {
|
|
123
119
|
// Or `query.loading`
|
|
124
120
|
form.loading = init.query.loading;
|
|
125
121
|
}
|