@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.
Files changed (39) hide show
  1. package/dist/FormStateApp.d.ts +2 -3
  2. package/dist/FormStateApp.js +8 -47
  3. package/dist/FormStateApp.test.js +14 -14
  4. package/dist/config.d.ts +6 -6
  5. package/dist/fields/fragmentField.js +3 -3
  6. package/dist/fields/listField.js +12 -12
  7. package/dist/fields/objectField.d.ts +4 -4
  8. package/dist/fields/objectField.js +10 -10
  9. package/dist/fields/valueField.d.ts +13 -0
  10. package/dist/fields/valueField.js +49 -14
  11. package/dist/formState.stories.d.ts +2 -4
  12. package/dist/formState.stories.js +1 -1
  13. package/dist/formState.test.js +171 -77
  14. package/dist/formStateDomain.js +1 -1
  15. package/dist/index.d.ts +3 -4
  16. package/dist/index.js +0 -11
  17. package/dist/proxies.d.ts +5 -0
  18. package/dist/proxies.js +21 -0
  19. package/dist/rules.d.ts +1 -1
  20. package/dist/rules.js +1 -1
  21. package/dist/setupTests.js +2 -2
  22. package/dist/useFormState.d.ts +4 -4
  23. package/dist/useFormState.js +13 -17
  24. package/dist/useFormState.test.js +141 -198
  25. package/dist/useFormStates.d.ts +3 -3
  26. package/dist/useFormStates.js +7 -11
  27. package/dist/useFormStates.test.js +56 -89
  28. package/dist/utils.d.ts +3 -3
  29. package/dist/utils.js +8 -8
  30. package/dist/utils.test.js +49 -49
  31. package/package.json +44 -39
  32. package/dist/AutoSaveStatus/AutoSaveStatusProvider.d.ts +0 -24
  33. package/dist/AutoSaveStatus/AutoSaveStatusProvider.js +0 -91
  34. package/dist/AutoSaveStatus/index.d.ts +0 -2
  35. package/dist/AutoSaveStatus/index.js +0 -9
  36. package/dist/AutoSaveStatus/useAutoSaveStatus.d.ts +0 -1
  37. package/dist/AutoSaveStatus/useAutoSaveStatus.js +0 -9
  38. package/dist/AutoSaveStatus/useAutoSaveStatus.test.d.ts +0 -1
  39. package/dist/AutoSaveStatus/useAutoSaveStatus.test.js +0 -152
@@ -1,7 +1,7 @@
1
1
  import { ObjectConfig } from "./config";
2
2
  import { ObjectState } from "./fields/objectField";
3
- export declare type ObjectStateCache<T, I> = Record<string, [ObjectState<T>, I]>;
4
- declare type UseFormStatesOpts<T, I> = {
3
+ export type ObjectStateCache<T, I> = Record<string, [ObjectState<T>, I]>;
4
+ type UseFormStatesOpts<T, I> = {
5
5
  /**
6
6
  * The config to use for each form state.
7
7
  *
@@ -40,7 +40,7 @@ declare type UseFormStatesOpts<T, I> = {
40
40
  */
41
41
  readOnly?: boolean;
42
42
  };
43
- declare type UseFormStatesHook<T, I> = {
43
+ type UseFormStatesHook<T, I> = {
44
44
  getFormState: (input: I, opts?: {
45
45
  readOnly?: boolean;
46
46
  }) => ObjectState<T>;
@@ -4,23 +4,21 @@ exports.useFormStates = void 0;
4
4
  const react_1 = require("react");
5
5
  const objectField_1 = require("./fields/objectField");
6
6
  const utils_1 = require("./utils");
7
- const AutoSaveStatus_1 = require("./AutoSaveStatus/index");
8
7
  function useFormStates(opts) {
9
8
  const { config, autoSave, getId, map, addRules, readOnly = false } = opts;
10
- const objectStateCache = react_1.useMemo(() => ({}),
9
+ const objectStateCache = (0, react_1.useMemo)(() => ({}),
11
10
  // Force resetting the cache if config changes
12
11
  // eslint-disable-next-line react-hooks/exhaustive-deps
13
12
  [config]);
14
13
  // Keep track of ObjectStates that triggered auto-save when a save was already in progress.
15
- const pendingAutoSaves = react_1.useRef(new Set());
14
+ const pendingAutoSaves = (0, react_1.useRef)(new Set());
16
15
  // Use a ref so our memo'ized `autoSave` always see the latest value
17
- const autoSaveRef = react_1.useRef(autoSave);
16
+ const autoSaveRef = (0, react_1.useRef)(autoSave);
18
17
  autoSaveRef.current = autoSave;
19
18
  // Use a ref b/c we're memod
20
- const readOnlyRef = react_1.useRef(readOnly);
19
+ const readOnlyRef = (0, react_1.useRef)(readOnly);
21
20
  readOnlyRef.current = readOnly;
22
- const autoSaveStatusContext = AutoSaveStatus_1.useAutoSaveStatus();
23
- const getFormState = react_1.useCallback((input, opts = {}) => {
21
+ const getFormState = (0, react_1.useCallback)((input, opts = {}) => {
24
22
  const existing = objectStateCache[getId(input)];
25
23
  let form = existing === null || existing === void 0 ? void 0 : existing[0];
26
24
  async function maybeAutoSave(form) {
@@ -34,7 +32,6 @@ function useFormStates(opts) {
34
32
  let maybeError;
35
33
  try {
36
34
  isAutoSaving = true;
37
- autoSaveStatusContext.triggerAutoSave();
38
35
  // See if we have any reactions that want to run (i.e. added by addRules hooks)
39
36
  await new Promise((resolve) => setTimeout(resolve, 0));
40
37
  // If a reaction re-queued our form during the ^ wait, remove it
@@ -47,7 +44,6 @@ function useFormStates(opts) {
47
44
  }
48
45
  finally {
49
46
  isAutoSaving = false;
50
- autoSaveStatusContext.resolveAutoSave(maybeError);
51
47
  if (pending.size > 0) {
52
48
  const first = pending.values().next().value;
53
49
  pending.delete(first);
@@ -58,7 +54,7 @@ function useFormStates(opts) {
58
54
  }
59
55
  // If it didn't exist, then add to the cache.
60
56
  if (!form) {
61
- form = objectField_1.createObjectState(config, utils_1.initValue(config, map ? { map, input } : input), {
57
+ form = (0, objectField_1.createObjectState)(config, (0, utils_1.initValue)(config, map ? { map, input } : input), {
62
58
  maybeAutoSave: () => maybeAutoSave(form),
63
59
  });
64
60
  if (addRules) {
@@ -68,7 +64,7 @@ function useFormStates(opts) {
68
64
  }
69
65
  // If the source of truth changed, then update the existing state and return it.
70
66
  if (existing && existing[1] !== input) {
71
- form.set(utils_1.initValue(config, map ? { map, input } : input), { refreshing: true });
67
+ form.set((0, utils_1.initValue)(config, map ? { map, input } : input), { refreshing: true });
72
68
  existing[1] = input;
73
69
  }
74
70
  form.readOnly = readOnlyRef.current || !!opts.readOnly;
@@ -2,59 +2,53 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const jsx_runtime_1 = require("react/jsx-runtime");
4
4
  const rtl_utils_1 = require("@homebound/rtl-utils");
5
- const react_hooks_1 = require("@testing-library/react-hooks");
6
5
  const mobx_1 = require("mobx");
7
- const mobx_react_1 = require("mobx-react");
8
6
  const react_1 = require("react");
9
7
  const FormStateApp_1 = require("./FormStateApp");
10
8
  const rules_1 = require("./rules");
11
9
  const useFormStates_1 = require("./useFormStates");
12
- const AutoSaveStatus_1 = require("./AutoSaveStatus/index");
13
- const AutoSaveStatusProvider_1 = require("./AutoSaveStatus/AutoSaveStatusProvider");
14
10
  describe("useFormStates", () => {
15
11
  it("can lazily create form states", async () => {
16
12
  const autoSave = jest.fn();
17
13
  // Given a parent and child component, where the formState is created only for the child component.
18
14
  function ChildComponent({ os }) {
19
- return jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "firstName" }, { children: os.firstName.value }), void 0);
15
+ return (0, jsx_runtime_1.jsx)("div", { "data-testid": "firstName", children: os.firstName.value });
20
16
  }
21
17
  function TestComponent() {
22
18
  const config = { id: { type: "value" }, firstName: { type: "value" } };
23
- const { getFormState } = useFormStates_1.useFormStates({
19
+ const { getFormState } = (0, useFormStates_1.useFormStates)({
24
20
  config,
25
21
  autoSave,
26
22
  getId: (o) => o.id,
27
23
  });
28
- return (jsx_runtime_1.jsx("div", { children: jsx_runtime_1.jsx(ChildComponent, { os: getFormState({ id: "a:1", firstName: "Brandon" }) }, void 0) }, void 0));
24
+ return ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(ChildComponent, { os: getFormState({ id: "a:1", firstName: "Brandon" }) }) }));
29
25
  }
30
- const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}, void 0));
26
+ const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
31
27
  // And the child component has defined state
32
- expect(r.firstName()).toHaveTextContent("Brandon");
28
+ expect(r.firstName).toHaveTextContent("Brandon");
33
29
  });
34
30
  it("can update existing object state from cache with new values", async () => {
35
31
  const autoSave = jest.fn();
36
32
  const config = { id: { type: "value" }, firstName: { type: "value" } };
37
33
  // Given a component using `getFormState` for lazily creating ObjectStates
38
34
  function TestComponent() {
39
- const [apiData, setApiData] = react_1.useState({ id: "a:1", firstName: "Brandon" });
40
- const { getFormState } = useFormStates_1.useFormStates({ config, autoSave, getId: (o) => o.id });
35
+ const [apiData, setApiData] = (0, react_1.useState)({ id: "a:1", firstName: "Brandon" });
36
+ const { getFormState } = (0, useFormStates_1.useFormStates)({ config, autoSave, getId: (o) => o.id });
41
37
  // Memoize an original for comparing the update against.
42
- const originalState = react_1.useMemo(() => getFormState(apiData), [getFormState]);
38
+ const originalState = (0, react_1.useMemo)(() => getFormState(apiData), [getFormState]);
43
39
  const state = getFormState(apiData);
44
- return (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "firstName" }, { children: state.firstName.value }), void 0),
45
- jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "statesEqual" }, { children: JSON.stringify(state === originalState) }), void 0),
46
- jsx_runtime_1.jsx("button", { "data-testid": "updateApiData", onClick: () => setApiData((prevState) => ({ ...prevState, firstName: "Bob" })) }, void 0)] }, void 0));
40
+ return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { "data-testid": "firstName", children: state.firstName.value }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "statesEqual", children: JSON.stringify(state === originalState) }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "updateApiData", onClick: () => setApiData((prevState) => ({ ...prevState, firstName: "Bob" })) })] }));
47
41
  }
48
- const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}, void 0));
42
+ const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
49
43
  // And the initial values for the form state display
50
- expect(r.firstName()).toHaveTextContent("Brandon");
51
- expect(r.statesEqual()).toHaveTextContent("true");
44
+ expect(r.firstName).toHaveTextContent("Brandon");
45
+ expect(r.statesEqual).toHaveTextContent("true");
52
46
  // When updating the API data
53
- await rtl_utils_1.clickAndWait(r.updateApiData());
47
+ await (0, rtl_utils_1.clickAndWait)(r.updateApiData);
54
48
  // Then the new value is shown in the component
55
- expect(r.firstName()).toHaveTextContent("Bob");
49
+ expect(r.firstName).toHaveTextContent("Bob");
56
50
  // And the two states are using the same reference
57
- expect(r.statesEqual()).toHaveTextContent("true");
51
+ expect(r.statesEqual).toHaveTextContent("true");
58
52
  });
59
53
  it("can queue up changes for auto save if a save is already in progress - works across multiple states", async () => {
60
54
  const autoSaveStub = jest.fn();
@@ -65,9 +59,9 @@ describe("useFormStates", () => {
65
59
  };
66
60
  // Given a component using `getFormState` for lazily creating ObjectStates
67
61
  function TestComponent() {
68
- const [apiData, setApiData] = react_1.useState({ id: "a:1", firstName: "Tony", lastName: "Stark" });
69
- const [apiData2, setApiData2] = react_1.useState({ id: "a:2", firstName: "Steve", lastName: "Rogers" });
70
- const { getFormState } = useFormStates_1.useFormStates({ config, autoSave, getId: (o) => o.id });
62
+ const [apiData, setApiData] = (0, react_1.useState)({ id: "a:1", firstName: "Tony", lastName: "Stark" });
63
+ const [apiData2, setApiData2] = (0, react_1.useState)({ id: "a:2", firstName: "Steve", lastName: "Rogers" });
64
+ const { getFormState } = (0, useFormStates_1.useFormStates)({ config, autoSave, getId: (o) => o.id });
71
65
  const state = getFormState(apiData);
72
66
  const state2 = getFormState(apiData2);
73
67
  async function autoSave(form) {
@@ -81,30 +75,27 @@ describe("useFormStates", () => {
81
75
  }
82
76
  await Promise.resolve(1);
83
77
  }
84
- return (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "firstName" }, { children: state.firstName.value }), void 0),
85
- jsx_runtime_1.jsx("button", { "data-testid": "focusSetAndSaveField", onClick: () => {
78
+ return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { "data-testid": "firstName", children: state.firstName.value }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "focusSetAndSaveField", onClick: () => {
86
79
  state.firstName.focus();
87
80
  state.firstName.set("Foo");
88
81
  state.firstName.maybeAutoSave();
89
- } }, void 0),
90
- jsx_runtime_1.jsx("button", { "data-testid": "focusSetAndSaveFieldLastName", onClick: () => {
82
+ } }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "focusSetAndSaveFieldLastName", onClick: () => {
91
83
  state.lastName.focus();
92
84
  state.lastName.set("Bar");
93
85
  state.lastName.maybeAutoSave();
94
- } }, void 0),
95
- jsx_runtime_1.jsx("button", { "data-testid": "focusSetAndSaveField2", onClick: () => {
86
+ } }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "focusSetAndSaveField2", onClick: () => {
96
87
  state2.lastName.focus();
97
88
  state2.lastName.set("Bar");
98
89
  state2.lastName.maybeAutoSave();
99
- } }, void 0)] }, void 0));
90
+ } })] }));
100
91
  }
101
- const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}, void 0));
92
+ const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
102
93
  // And triggering the auto save behavior before awaiting the initial promise to resolve so we have pending changes.
103
- rtl_utils_1.click(r.focusSetAndSaveField());
104
- rtl_utils_1.click(r.focusSetAndSaveFieldLastName());
105
- rtl_utils_1.click(r.focusSetAndSaveField2());
94
+ (0, rtl_utils_1.click)(r.focusSetAndSaveField);
95
+ (0, rtl_utils_1.click)(r.focusSetAndSaveFieldLastName);
96
+ (0, rtl_utils_1.click)(r.focusSetAndSaveField2);
106
97
  // Awaits the promises for all methods triggered above
107
- await rtl_utils_1.wait();
98
+ await (0, rtl_utils_1.wait)();
108
99
  // Then expect the auto save to only have been called two times. Once with each set of changedValues.
109
100
  expect(autoSaveStub).toBeCalledTimes(2);
110
101
  expect(autoSaveStub).toBeCalledWith({ id: "a:1", firstName: "Foo", lastName: "Bar" });
@@ -121,39 +112,37 @@ describe("useFormStates", () => {
121
112
  firstName: { type: "value", rules: [rules_1.required] },
122
113
  };
123
114
  function TestComponent() {
124
- const [config, setConfig] = react_1.useState(originalConfig);
125
- const { getFormState } = useFormStates_1.useFormStates({ config, autoSave, getId: (o) => o.id });
115
+ const [config, setConfig] = (0, react_1.useState)(originalConfig);
116
+ const { getFormState } = (0, useFormStates_1.useFormStates)({ config, autoSave, getId: (o) => o.id });
126
117
  // Memoize an original for comparing the update against.
127
118
  // eslint-disable-next-line react-hooks/exhaustive-deps
128
- const originalState = react_1.useMemo(() => getFormState(apiData), []);
119
+ const originalState = (0, react_1.useMemo)(() => getFormState(apiData), []);
129
120
  const state = getFormState(apiData);
130
- return (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "statesEqual" }, { children: JSON.stringify(state === originalState) }), void 0),
131
- jsx_runtime_1.jsx("button", { "data-testid": "updateConfig", onClick: () => setConfig(updatedConfig) }, void 0)] }, void 0));
121
+ return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { "data-testid": "statesEqual", children: JSON.stringify(state === originalState) }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "updateConfig", onClick: () => setConfig(updatedConfig) })] }));
132
122
  }
133
123
  // When rendered with the original configuration
134
- const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}, void 0));
124
+ const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
135
125
  // Then the two form-states generated are equal
136
- expect(r.statesEqual()).toHaveTextContent("true");
126
+ expect(r.statesEqual).toHaveTextContent("true");
137
127
  // When updating the configuration object
138
- rtl_utils_1.click(r.updateConfig);
128
+ (0, rtl_utils_1.click)(r.updateConfig);
139
129
  // Then the two form-states are no longer equal.
140
- expect(r.statesEqual()).toHaveTextContent("false");
130
+ expect(r.statesEqual).toHaveTextContent("false");
141
131
  });
142
132
  it("calls addRules once per form state", async () => {
143
133
  // Given a user wants to use addRules
144
134
  const addRules = jest.fn();
145
135
  function TestComponent() {
146
136
  const config = { id: { type: "value" }, firstName: { type: "value" } };
147
- const { getFormState } = useFormStates_1.useFormStates({
137
+ const { getFormState } = (0, useFormStates_1.useFormStates)({
148
138
  config,
149
139
  addRules,
150
140
  getId: (o) => o.id,
151
141
  });
152
- return (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsx(ChildComponent, { os: getFormState({ id: "a:1", firstName: "Brandon" }) }, void 0),
153
- jsx_runtime_1.jsx(ChildComponent, { os: getFormState({ id: "a:1", firstName: "Brandon" }) }, void 0)] }, void 0));
142
+ return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(ChildComponent, { os: getFormState({ id: "a:1", firstName: "Brandon" }) }), (0, jsx_runtime_1.jsx)(ChildComponent, { os: getFormState({ id: "a:1", firstName: "Brandon" }) })] }));
154
143
  }
155
144
  // When we render
156
- await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}, void 0));
145
+ await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
157
146
  // Then addRules was only called once
158
147
  expect(addRules).toHaveBeenCalledTimes(1);
159
148
  });
@@ -161,12 +150,12 @@ describe("useFormStates", () => {
161
150
  // Given a user wants to use auto save
162
151
  const autoSave = jest.fn();
163
152
  function TestComponent() {
164
- const { getFormState } = useFormStates_1.useFormStates({
153
+ const { getFormState } = (0, useFormStates_1.useFormStates)({
165
154
  config,
166
155
  getId: (o) => o.id,
167
156
  addRules(fs) {
168
157
  // And they have a reactive true that calculates last name
169
- mobx_1.reaction(() => fs.firstName.value, (curr) => {
158
+ (0, mobx_1.reaction)(() => fs.firstName.value, (curr) => {
170
159
  fs.lastName.set(curr);
171
160
  });
172
161
  },
@@ -174,12 +163,12 @@ describe("useFormStates", () => {
174
163
  autoSave(fs.changedValue);
175
164
  },
176
165
  });
177
- return jsx_runtime_1.jsx(FormStateApp_1.TextField, { field: getFormState({ id: "a:1", firstName: "Brandon" }).firstName }, void 0);
166
+ return (0, jsx_runtime_1.jsx)(FormStateApp_1.TextField, { field: getFormState({ id: "a:1", firstName: "Brandon" }).firstName });
178
167
  }
179
168
  // When we render
180
- const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}, void 0));
169
+ const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
181
170
  // And update the firstName
182
- await rtl_utils_1.typeAndWait(r.firstName(), "first");
171
+ await (0, rtl_utils_1.typeAndWait)(r.firstName, "first");
183
172
  // Then autoSave was called once with both input+calc'd values
184
173
  expect(autoSave).toHaveBeenCalledTimes(1);
185
174
  expect(autoSave).toHaveBeenCalledWith({ id: "a:1", firstName: "first", lastName: "first" });
@@ -187,63 +176,41 @@ describe("useFormStates", () => {
187
176
  it("can set readOnly via the hook opt", async () => {
188
177
  // Given a test component
189
178
  function TestComponent({ readOnly }) {
190
- const { getFormState } = useFormStates_1.useFormStates({
179
+ const { getFormState } = (0, useFormStates_1.useFormStates)({
191
180
  config,
192
181
  getId: (o) => o.id,
193
182
  // And it passes readOnly directly to useFormStates
194
183
  readOnly,
195
184
  });
196
- return jsx_runtime_1.jsx(ChildComponent, { os: getFormState({ id: "a:1", firstName: "Brandon" }) }, void 0);
185
+ return (0, jsx_runtime_1.jsx)(ChildComponent, { os: getFormState({ id: "a:1", firstName: "Brandon" }) });
197
186
  }
198
187
  // When we render
199
- const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, { readOnly: true }, void 0));
188
+ const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, { readOnly: true }));
200
189
  // Then it's read only
201
- expect(r.firstName()).toHaveAttribute("data-readonly", "true");
190
+ expect(r.firstName).toHaveAttribute("data-readonly", "true");
202
191
  // And when we rerender
203
- await r.rerender(jsx_runtime_1.jsx(TestComponent, { readOnly: false }, void 0));
192
+ await r.rerender((0, jsx_runtime_1.jsx)(TestComponent, { readOnly: false }));
204
193
  // Then it's not read only
205
- expect(r.firstName()).toHaveAttribute("data-readonly", "false");
194
+ expect(r.firstName).toHaveAttribute("data-readonly", "false");
206
195
  });
207
196
  it("can set readOnly via the getFormState function", async () => {
208
197
  // Given a test component
209
198
  function TestComponent({ readOnly }) {
210
- const { getFormState } = useFormStates_1.useFormStates({
199
+ const { getFormState } = (0, useFormStates_1.useFormStates)({
211
200
  config,
212
201
  getId: (o) => o.id,
213
202
  });
214
203
  // And it passes readOnly directly to getFormState
215
- return jsx_runtime_1.jsx(ChildComponent, { os: getFormState({ id: "a:1", firstName: "Brandon" }, { readOnly }) }, void 0);
204
+ return (0, jsx_runtime_1.jsx)(ChildComponent, { os: getFormState({ id: "a:1", firstName: "Brandon" }, { readOnly }) });
216
205
  }
217
206
  // When we render
218
- const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, { readOnly: true }, void 0));
207
+ const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, { readOnly: true }));
219
208
  // Then it's read only
220
- expect(r.firstName()).toHaveAttribute("data-readonly", "true");
209
+ expect(r.firstName).toHaveAttribute("data-readonly", "true");
221
210
  // And when we rerender
222
- await r.rerender(jsx_runtime_1.jsx(TestComponent, { readOnly: false }, void 0));
211
+ await r.rerender((0, jsx_runtime_1.jsx)(TestComponent, { readOnly: false }));
223
212
  // Then it's not read only
224
- expect(r.firstName()).toHaveAttribute("data-readonly", "false");
225
- });
226
- it("notifies AutoSaveStatusProvider of updates", async () => {
227
- const { result } = react_hooks_1.renderHook(() => ({
228
- fs: useFormStates_1.useFormStates({ config, autoSave: async () => { }, getId: (o) => o.id }),
229
- autoSave: AutoSaveStatus_1.useAutoSaveStatus(),
230
- }), {
231
- wrapper: ({ children }) => (jsx_runtime_1.jsx(AutoSaveStatus_1.AutoSaveStatusProvider, { children: jsx_runtime_1.jsx(mobx_react_1.Observer, { children: () => jsx_runtime_1.jsx(jsx_runtime_1.Fragment, { children: children }, void 0) }, void 0) }, void 0)),
232
- });
233
- expect(result.current.autoSave.status).toBe(AutoSaveStatusProvider_1.AutoSaveStatus.IDLE);
234
- react_hooks_1.act(() => {
235
- result.current.fs.getFormState({ id: "a:1" }).set({ firstName: "test" });
236
- });
237
- react_hooks_1.act(() => {
238
- // useFormStates has a setTimeout(..., 0) that needs to trigger
239
- jest.advanceTimersToNextTimer();
240
- });
241
- expect(result.current.autoSave.status).toBe(AutoSaveStatusProvider_1.AutoSaveStatus.SAVING);
242
- await react_hooks_1.act(async () => {
243
- jest.runAllTimers();
244
- });
245
- expect(result.current.autoSave.status).toBe(AutoSaveStatusProvider_1.AutoSaveStatus.DONE);
246
- jest.clearAllTimers();
213
+ expect(r.firstName).toHaveAttribute("data-readonly", "false");
247
214
  });
248
215
  });
249
216
  const config = {
@@ -252,5 +219,5 @@ const config = {
252
219
  lastName: { type: "value" },
253
220
  };
254
221
  function ChildComponent({ os }) {
255
- return (jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "firstName", "data-readonly": os.firstName.readOnly }, { children: os.firstName.value }), void 0));
222
+ return ((0, jsx_runtime_1.jsx)("div", { "data-testid": "firstName", "data-readonly": os.firstName.readOnly, children: os.firstName.value }));
256
223
  }
package/dist/utils.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { ObjectConfig } from "./config";
2
2
  import { InputAndMap, QueryAndMap, UseFormStateOpts } from "./useFormState";
3
- export declare type Builtin = Date | Function | Uint8Array | string | number | boolean;
4
- export declare type Primitive = undefined | null | boolean | string | number | Function | Date | {
3
+ export type Builtin = Date | Function | Uint8Array | string | number | boolean;
4
+ export type Primitive = undefined | null | boolean | string | number | Function | Date | {
5
5
  toJSON(): any;
6
6
  };
7
7
  /** Makes the keys in `T` required while keeping the values undefined. */
8
- export declare type DeepRequired<T> = T extends Primitive ? T : {
8
+ export type DeepRequired<T> = T extends Primitive ? T : {
9
9
  [P in keyof Required<T>]: T[P] extends Array<infer U> ? Array<DeepRequired<U>> : T[P] extends ReadonlyArray<infer U2> ? ReadonlyArray<DeepRequired<U2>> : DeepRequired<T[P]>;
10
10
  };
11
11
  export declare function fail(message?: string): never;
package/dist/utils.js CHANGED
@@ -31,11 +31,11 @@ function initValue(config, init) {
31
31
  }
32
32
  exports.initValue = initValue;
33
33
  function isInput(init) {
34
- return !!init && "input" in init && "map" in init;
34
+ return !!init && typeof init === "object" && "input" in init && "map" in init;
35
35
  }
36
36
  exports.isInput = isInput;
37
37
  function isQuery(init) {
38
- return !!init && "query" in init && "map" in init;
38
+ return !!init && typeof init === "object" && "query" in init && "map" in init;
39
39
  }
40
40
  exports.isQuery = isQuery;
41
41
  /**
@@ -49,7 +49,7 @@ exports.isQuery = isQuery;
49
49
  */
50
50
  function pickFields(formConfig, instance) {
51
51
  // If the caller is using classes, i.e. with their own custom observable behavior, then just use as-is
52
- if (!is_plain_object_1.isPlainObject(instance)) {
52
+ if (!(0, is_plain_object_1.isPlainObject)(instance)) {
53
53
  return instance;
54
54
  }
55
55
  return Object.fromEntries(Object.entries(formConfig).map(([key, _keyConfig]) => {
@@ -64,7 +64,7 @@ function pickFields(formConfig, instance) {
64
64
  }
65
65
  }
66
66
  else if (keyConfig.type === "list") {
67
- if (mobx_1.isObservable(value)) {
67
+ if ((0, mobx_1.isObservable)(value)) {
68
68
  // If we hit an observable array, leave it as the existing proxy so the our
69
69
  // ListFieldState will react to changes in the original array.
70
70
  return [key, value];
@@ -103,17 +103,17 @@ exports.isEmpty = isEmpty;
103
103
  * - arrays
104
104
  */
105
105
  function areEqual(a, b, strictOrder) {
106
- if (is_plain_object_1.isPlainObject(a)) {
107
- return fast_deep_equal_1.default(mobx_1.toJS(a), mobx_1.toJS(b));
106
+ if ((0, is_plain_object_1.isPlainObject)(a)) {
107
+ return (0, fast_deep_equal_1.default)((0, mobx_1.toJS)(a), (0, mobx_1.toJS)(b));
108
108
  }
109
109
  if (hasToJSON(a) || hasToJSON(b)) {
110
110
  const a1 = hasToJSON(a) ? a.toJSON() : a;
111
111
  const b1 = hasToJSON(b) ? b.toJSON() : b;
112
- return fast_deep_equal_1.default(a1, b1);
112
+ return (0, fast_deep_equal_1.default)(a1, b1);
113
113
  }
114
114
  if (a && b && a instanceof Array && b instanceof Array) {
115
115
  if (strictOrder !== false) {
116
- return fast_deep_equal_1.default(a, b);
116
+ return (0, fast_deep_equal_1.default)(a, b);
117
117
  }
118
118
  if (a.length !== b.length)
119
119
  return false;
@@ -6,72 +6,72 @@ const utils_1 = require("./utils");
6
6
  describe("utils", () => {
7
7
  describe("pickFields", () => {
8
8
  it("can pick a value field", () => {
9
- const a = utils_1.pickFields(
9
+ const a = (0, utils_1.pickFields)(
10
10
  //
11
11
  { firstName: { type: "value" } }, { firstName: "a", b: "ignored" });
12
12
  expect(a).toMatchInlineSnapshot(`
13
- Object {
14
- "firstName": "a",
15
- }
16
- `);
13
+ {
14
+ "firstName": "a",
15
+ }
16
+ `);
17
17
  });
18
18
  it("can pick an unset object fields", () => {
19
- const a = utils_1.pickFields(authorWithAddressConfig, { firstName: "a", b: "ignored" });
19
+ const a = (0, utils_1.pickFields)(authorWithAddressConfig, { firstName: "a", b: "ignored" });
20
20
  expect(a).toMatchInlineSnapshot(`
21
- Object {
22
- "address": undefined,
23
- "firstName": "a",
24
- "id": undefined,
25
- "lastName": undefined,
26
- }
27
- `);
21
+ {
22
+ "address": undefined,
23
+ "firstName": "a",
24
+ "id": undefined,
25
+ "lastName": undefined,
26
+ }
27
+ `);
28
28
  });
29
29
  it("can pick a set object field", () => {
30
- const a = utils_1.pickFields(authorWithAddressConfig, { firstName: "a", b: "ignored", address: {} });
30
+ const a = (0, utils_1.pickFields)(authorWithAddressConfig, { firstName: "a", b: "ignored", address: {} });
31
31
  expect(a).toMatchInlineSnapshot(`
32
- Object {
33
- "address": Object {
34
- "city": undefined,
35
- "street": undefined,
36
- },
37
- "firstName": "a",
38
- "id": undefined,
39
- "lastName": undefined,
40
- }
41
- `);
32
+ {
33
+ "address": {
34
+ "city": undefined,
35
+ "street": undefined,
36
+ },
37
+ "firstName": "a",
38
+ "id": undefined,
39
+ "lastName": undefined,
40
+ }
41
+ `);
42
42
  });
43
43
  it("can pick an unset list field", () => {
44
- const a = utils_1.pickFields(authorWithBooksConfig, { firstName: "a", b: "ignored" });
44
+ const a = (0, utils_1.pickFields)(authorWithBooksConfig, { firstName: "a", b: "ignored" });
45
45
  expect(a).toMatchInlineSnapshot(`
46
- Object {
47
- "books": undefined,
48
- "firstName": "a",
49
- "id": undefined,
50
- "lastName": undefined,
51
- }
52
- `);
46
+ {
47
+ "books": undefined,
48
+ "firstName": "a",
49
+ "id": undefined,
50
+ "lastName": undefined,
51
+ }
52
+ `);
53
53
  });
54
54
  it("can pick a set list field", () => {
55
- const a = utils_1.pickFields(authorWithBooksConfig, { firstName: "a", b: "ignored", books: [{}] });
55
+ const a = (0, utils_1.pickFields)(authorWithBooksConfig, { firstName: "a", b: "ignored", books: [{}] });
56
56
  expect(a).toMatchInlineSnapshot(`
57
- Object {
58
- "books": Array [
59
- Object {
60
- "classification": undefined,
61
- "id": undefined,
62
- "title": undefined,
63
- },
64
- ],
65
- "firstName": "a",
66
- "id": undefined,
67
- "lastName": undefined,
68
- }
69
- `);
57
+ {
58
+ "books": [
59
+ {
60
+ "classification": undefined,
61
+ "id": undefined,
62
+ "title": undefined,
63
+ },
64
+ ],
65
+ "firstName": "a",
66
+ "id": undefined,
67
+ "lastName": undefined,
68
+ }
69
+ `);
70
70
  });
71
71
  it("can pick a set observable list field", () => {
72
- const books = mobx_1.observable([]);
73
- const a = utils_1.pickFields(authorWithBooksConfig, { firstName: "a", b: "ignored", books });
74
- expect(mobx_1.isObservable(a.books)).toEqual(true);
72
+ const books = (0, mobx_1.observable)([]);
73
+ const a = (0, utils_1.pickFields)(authorWithBooksConfig, { firstName: "a", b: "ignored", books });
74
+ expect((0, mobx_1.isObservable)(a.books)).toEqual(true);
75
75
  });
76
76
  });
77
77
  });