@homebound/form-state 2.8.0 → 2.10.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 +4 -0
- package/dist/FormStateApp.js +2 -1
- package/dist/formState.js +13 -27
- package/dist/formState.test.js +36 -0
- package/dist/useFormState.js +1 -2
- package/dist/useFormState.test.js +29 -0
- package/dist/useFormStates.d.ts +9 -2
- package/dist/useFormStates.js +32 -20
- package/dist/useFormStates.test.js +77 -5
- package/package.json +1 -1
package/dist/FormStateApp.d.ts
CHANGED
package/dist/FormStateApp.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FormStateApp = void 0;
|
|
3
|
+
exports.TextField = exports.FormStateApp = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const mobx_react_1 = require("mobx-react");
|
|
6
6
|
const index_1 = require("./index");
|
|
@@ -91,3 +91,4 @@ function TextField(props) {
|
|
|
91
91
|
jsx_runtime_1.jsx("td", Object.assign({ "data-testid": `${field.key}_errors` }, { children: field.errors }), void 0),
|
|
92
92
|
jsx_runtime_1.jsx("td", Object.assign({ "data-testid": `${field.key}_original` }, { children: field.originalValue }), void 0)] }, void 0) }, void 0)] }), void 0)] }, void 0)) }, void 0));
|
|
93
93
|
}
|
|
94
|
+
exports.TextField = TextField;
|
package/dist/formState.js
CHANGED
|
@@ -24,10 +24,10 @@ exports.required = mobx_1.action(({ value: v }) => {
|
|
|
24
24
|
*/
|
|
25
25
|
function createObjectState(config, instance, opts = {}) {
|
|
26
26
|
const noop = () => { };
|
|
27
|
-
return newObjectState(config, undefined, instance, undefined, opts.maybeAutoSave || noop);
|
|
27
|
+
return newObjectState(config, undefined, undefined, instance, undefined, opts.maybeAutoSave || noop);
|
|
28
28
|
}
|
|
29
29
|
exports.createObjectState = createObjectState;
|
|
30
|
-
function newObjectState(config, parentState, instance, key, maybeAutoSave) {
|
|
30
|
+
function newObjectState(config, parentState, parentListState, instance, key, maybeAutoSave) {
|
|
31
31
|
// This is what we return, but we only know it's value until we call `observable`, so
|
|
32
32
|
// we create a mutable variable to capture it so that we can create fields/call their
|
|
33
33
|
// constructors and give them a way to access it later.
|
|
@@ -52,7 +52,7 @@ function newObjectState(config, parentState, instance, key, maybeAutoSave) {
|
|
|
52
52
|
if (!instance[key]) {
|
|
53
53
|
instance[key] = {};
|
|
54
54
|
}
|
|
55
|
-
field = newObjectState(config.config, getObjectState, instance[key], key, maybeAutoSave);
|
|
55
|
+
field = newObjectState(config.config, getObjectState, undefined, instance[key], key, maybeAutoSave);
|
|
56
56
|
}
|
|
57
57
|
else {
|
|
58
58
|
throw new Error("Unsupported");
|
|
@@ -93,12 +93,13 @@ function newObjectState(config, parentState, instance, key, maybeAutoSave) {
|
|
|
93
93
|
getFields(this).forEach((f) => (f.touched = touched));
|
|
94
94
|
},
|
|
95
95
|
get readOnly() {
|
|
96
|
-
return this._readOnly ||
|
|
96
|
+
return (this._readOnly ||
|
|
97
|
+
this._considerReadOnly() ||
|
|
98
|
+
(parentState && parentState().readOnly) ||
|
|
99
|
+
!!(parentListState === null || parentListState === void 0 ? void 0 : parentListState.readOnly));
|
|
97
100
|
},
|
|
98
101
|
set readOnly(readOnly) {
|
|
99
102
|
this._readOnly = readOnly;
|
|
100
|
-
// Use this.readOnly so we can _considerReadOnly
|
|
101
|
-
getFields(this).forEach((f) => (f.readOnly = this.readOnly));
|
|
102
103
|
},
|
|
103
104
|
get valid() {
|
|
104
105
|
return getFields(this).every((f) => f.valid);
|
|
@@ -197,8 +198,6 @@ function newValueFieldState(parentInstance, parentState, key, rules, isIdKey, is
|
|
|
197
198
|
const field = {
|
|
198
199
|
key,
|
|
199
200
|
touched: false,
|
|
200
|
-
/** Configuration readOnly state. Mostly used to determine original state. */
|
|
201
|
-
_configReadOnly: readOnly,
|
|
202
201
|
/** Current readOnly value. */
|
|
203
202
|
_readOnly: readOnly || false,
|
|
204
203
|
_focused: false,
|
|
@@ -219,25 +218,13 @@ function newValueFieldState(parentInstance, parentState, key, rules, isIdKey, is
|
|
|
219
218
|
get dirty() {
|
|
220
219
|
return !areEqual(this.originalValue, this.value);
|
|
221
220
|
},
|
|
221
|
+
/** Returns whether this field is readOnly, although if our parent is readOnly then it trumps. */
|
|
222
222
|
get readOnly() {
|
|
223
|
-
return this._readOnly;
|
|
223
|
+
return parentState().readOnly || this._readOnly;
|
|
224
224
|
},
|
|
225
|
-
/**
|
|
226
|
-
* Field readOnly is only opinionated when set.
|
|
227
|
-
* - When set to true from FormObject, accept change since true is higher priority.
|
|
228
|
-
* - When set to false from FormObject, use original (`_configReadOnly`) value.
|
|
229
|
-
*/
|
|
225
|
+
/** Sets the field readOnly, but `v` will still be or-d with the parent's readOnly state. */
|
|
230
226
|
set readOnly(v) {
|
|
231
|
-
|
|
232
|
-
this._readOnly = v;
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
if (v) {
|
|
236
|
-
this._readOnly = v;
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
this._readOnly = this._configReadOnly || false;
|
|
240
|
-
}
|
|
227
|
+
this._readOnly = v;
|
|
241
228
|
},
|
|
242
229
|
// For primitive fields, the changed value is just the value.
|
|
243
230
|
get changedValue() {
|
|
@@ -356,11 +343,10 @@ function newListFieldState(parentInstance, parentState, key, rules, listConfig,
|
|
|
356
343
|
_focused: false,
|
|
357
344
|
_readOnly: false,
|
|
358
345
|
get readOnly() {
|
|
359
|
-
return this._readOnly;
|
|
346
|
+
return this._readOnly || parentState().readOnly;
|
|
360
347
|
},
|
|
361
348
|
set readOnly(readOnly) {
|
|
362
349
|
this._readOnly = readOnly;
|
|
363
|
-
this.rows.forEach((r) => (r.readOnly = readOnly));
|
|
364
350
|
},
|
|
365
351
|
set value(v) {
|
|
366
352
|
this.set(v);
|
|
@@ -401,7 +387,7 @@ function newListFieldState(parentInstance, parentState, key, rules, listConfig,
|
|
|
401
387
|
// Because we're reading from this.value, child will be the proxy version
|
|
402
388
|
let childState = rowMap.get(child);
|
|
403
389
|
if (!childState) {
|
|
404
|
-
childState = newObjectState(config, parentState, child, undefined, maybeAutoSave);
|
|
390
|
+
childState = newObjectState(config, parentState, list, child, undefined, maybeAutoSave);
|
|
405
391
|
rowMap.set(child, childState);
|
|
406
392
|
}
|
|
407
393
|
return childState;
|
package/dist/formState.test.js
CHANGED
|
@@ -686,6 +686,42 @@ describe("formState", () => {
|
|
|
686
686
|
// Then expect form
|
|
687
687
|
expect(formState.title.readOnly).toBeTruthy();
|
|
688
688
|
});
|
|
689
|
+
it("has an object-level readOnly=true override field-level readOnly=false", () => {
|
|
690
|
+
// Given a top-level object
|
|
691
|
+
const a1 = createAuthorInputState({
|
|
692
|
+
firstName: "a1",
|
|
693
|
+
lastName: "aL1",
|
|
694
|
+
books: [{ title: "b1", classification: formStateDomain_1.dd100 }],
|
|
695
|
+
});
|
|
696
|
+
// And it is read-only
|
|
697
|
+
a1.readOnly = true;
|
|
698
|
+
// Then it's fields are read-only
|
|
699
|
+
const fields = [a1, a1.firstName, a1.books, a1.books.rows[0].title, a1.books.rows[0].classification];
|
|
700
|
+
fields.forEach((f) => expect(f.readOnly).toBeTruthy());
|
|
701
|
+
// And even if a specific field tries to _not_ be read-only,
|
|
702
|
+
// i.e. due to a more granular business rule that happens to
|
|
703
|
+
// be allowed right now
|
|
704
|
+
a1.firstName.readOnly = false;
|
|
705
|
+
// Then the field-level rule is ignored, and it's still treated as read-only
|
|
706
|
+
expect(a1.firstName.readOnly).toBeTruthy();
|
|
707
|
+
});
|
|
708
|
+
it("has an field-level readOnly=true override object-level readOnly=false", () => {
|
|
709
|
+
// Given a top-level object
|
|
710
|
+
const a1 = createAuthorInputState({
|
|
711
|
+
firstName: "a1",
|
|
712
|
+
lastName: "aL1",
|
|
713
|
+
books: [{ title: "b1", classification: formStateDomain_1.dd100 }],
|
|
714
|
+
});
|
|
715
|
+
// And the top-level form is explicitly set to read-only=false
|
|
716
|
+
a1.readOnly = false;
|
|
717
|
+
// Then it's fields are not read-only
|
|
718
|
+
const fields = [a1, a1.firstName, a1.books, a1.books.rows[0].title, a1.books.rows[0].classification];
|
|
719
|
+
fields.forEach((f) => expect(f.readOnly).toBeFalsy());
|
|
720
|
+
// But when one of the fields opts in to readOnly
|
|
721
|
+
a1.firstName.readOnly = true;
|
|
722
|
+
// Then the field-level rule is respected
|
|
723
|
+
expect(a1.firstName.readOnly).toBeTruthy();
|
|
724
|
+
});
|
|
689
725
|
it("canSave returns dirty and touches", () => {
|
|
690
726
|
const a1 = formState_1.createObjectState({
|
|
691
727
|
firstName: { type: "value", rules: [formState_1.required] },
|
package/dist/useFormState.js
CHANGED
|
@@ -12,7 +12,6 @@ let isAutoSaving = false;
|
|
|
12
12
|
// `pendingAutoSave` is a flag for determining if we need to immediately call `maybeAutoSave` again after the initial Promise finishes
|
|
13
13
|
// This could happen if a field triggers auto-save while another field's auto-save is already in progress.
|
|
14
14
|
let pendingAutoSave = false;
|
|
15
|
-
let timerId;
|
|
16
15
|
/**
|
|
17
16
|
* Creates a formState instance for editing in a form.
|
|
18
17
|
*/
|
|
@@ -39,7 +38,7 @@ function useFormState(opts) {
|
|
|
39
38
|
if (autoSaveRef.current && form.dirty && form.valid && !isAutoSaving) {
|
|
40
39
|
isAutoSaving = "queued";
|
|
41
40
|
// We use setTimeout as a cheap way to wait until the end of the current event listener
|
|
42
|
-
|
|
41
|
+
setTimeout(async () => {
|
|
43
42
|
try {
|
|
44
43
|
// We technically don't flip to in-flight until after the call in case the
|
|
45
44
|
// user's autoSave function itself wants to call a .set.
|
|
@@ -3,8 +3,10 @@ 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
5
|
const react_1 = require("@testing-library/react");
|
|
6
|
+
const mobx_1 = require("mobx");
|
|
6
7
|
const mobx_react_1 = require("mobx-react");
|
|
7
8
|
const react_2 = require("react");
|
|
9
|
+
const FormStateApp_1 = require("./FormStateApp");
|
|
8
10
|
const formState_1 = require("./formState");
|
|
9
11
|
const useFormState_1 = require("./useFormState");
|
|
10
12
|
describe("useFormState", () => {
|
|
@@ -425,6 +427,33 @@ describe("useFormState", () => {
|
|
|
425
427
|
expect(autoSaveStub).toBeCalledWith({ id: "a:1", firstName: "Foo" });
|
|
426
428
|
expect(autoSaveStub).toBeCalledWith({ id: "a:1", lastName: "Bar" });
|
|
427
429
|
});
|
|
430
|
+
it("calls autoSave with results of calculations in addRules", async () => {
|
|
431
|
+
const autoSaveStub = jest.fn();
|
|
432
|
+
const config = {
|
|
433
|
+
id: { type: "value" },
|
|
434
|
+
firstName: { type: "value" },
|
|
435
|
+
lastName: { type: "value" },
|
|
436
|
+
};
|
|
437
|
+
// Given a component that is using autoSave
|
|
438
|
+
function TestComponent() {
|
|
439
|
+
const fs = useFormState_1.useFormState({
|
|
440
|
+
config,
|
|
441
|
+
addRules(fs) {
|
|
442
|
+
// And also has calculated values
|
|
443
|
+
mobx_1.reaction(() => fs.firstName.value, (curr) => (fs.lastName.value = curr));
|
|
444
|
+
},
|
|
445
|
+
autoSave: (fs) => autoSaveStub(fs.changedValue),
|
|
446
|
+
init: { id: "a:1" },
|
|
447
|
+
});
|
|
448
|
+
return jsx_runtime_1.jsx(FormStateApp_1.TextField, { field: fs.firstName }, void 0);
|
|
449
|
+
}
|
|
450
|
+
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}, void 0));
|
|
451
|
+
// When the user sets one field
|
|
452
|
+
await rtl_utils_1.typeAndWait(r.firstName, "first");
|
|
453
|
+
// Then we only called autoSave once
|
|
454
|
+
expect(autoSaveStub).toBeCalledTimes(1);
|
|
455
|
+
expect(autoSaveStub).toBeCalledWith({ id: "a:1", firstName: "first", lastName: "first" });
|
|
456
|
+
});
|
|
428
457
|
});
|
|
429
458
|
const authorConfig = {
|
|
430
459
|
id: { type: "value" },
|
package/dist/useFormStates.d.ts
CHANGED
|
@@ -34,8 +34,15 @@ declare type UseFormStatesOpts<T, I> = {
|
|
|
34
34
|
* Does not need to be stable/useMemo'd.
|
|
35
35
|
*/
|
|
36
36
|
map?: (input: Exclude<I, null | undefined>) => T;
|
|
37
|
+
/**
|
|
38
|
+
* Sets all `ObjectState`s to readOnly.
|
|
39
|
+
*/
|
|
40
|
+
readOnly?: boolean;
|
|
37
41
|
};
|
|
38
|
-
|
|
39
|
-
getFormState: (input: I
|
|
42
|
+
declare type UseFormStatesHook<T, I> = {
|
|
43
|
+
getFormState: (input: I, opts?: {
|
|
44
|
+
readOnly?: boolean;
|
|
45
|
+
}) => ObjectState<T>;
|
|
40
46
|
};
|
|
47
|
+
export declare function useFormStates<T, I = T>(opts: UseFormStatesOpts<T, I>): UseFormStatesHook<T, I>;
|
|
41
48
|
export {};
|
package/dist/useFormStates.js
CHANGED
|
@@ -5,37 +5,48 @@ const react_1 = require("react");
|
|
|
5
5
|
const formState_1 = require("./formState");
|
|
6
6
|
const utils_1 = require("./utils");
|
|
7
7
|
function useFormStates(opts) {
|
|
8
|
-
const { config, autoSave, getId, map, addRules } = opts;
|
|
8
|
+
const { config, autoSave, getId, map, addRules, readOnly = false } = opts;
|
|
9
9
|
const objectStateCache = react_1.useMemo(() => ({}),
|
|
10
10
|
// Force resetting the cache if config changes
|
|
11
11
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
12
12
|
[config]);
|
|
13
13
|
// Keep track of ObjectStates that triggered auto-save when a save was already in progress.
|
|
14
|
-
const pendingAutoSaves = react_1.useRef(
|
|
14
|
+
const pendingAutoSaves = react_1.useRef(new Set());
|
|
15
15
|
// Use a ref so our memo'ized `autoSave` always see the latest value
|
|
16
16
|
const autoSaveRef = react_1.useRef(autoSave);
|
|
17
17
|
autoSaveRef.current = autoSave;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
18
|
+
// Use a ref b/c we're memod
|
|
19
|
+
const readOnlyRef = react_1.useRef(readOnly);
|
|
20
|
+
readOnlyRef.current = readOnly;
|
|
21
|
+
const getFormState = react_1.useCallback((input, opts = {}) => {
|
|
22
|
+
const existing = objectStateCache[getId(input)];
|
|
23
|
+
let form = existing === null || existing === void 0 ? void 0 : existing[0];
|
|
24
|
+
async function maybeAutoSave(form) {
|
|
25
|
+
// Don't use canSave() because we don't want to set touched for all the fields
|
|
26
|
+
if (autoSaveRef.current && form.dirty && form.valid) {
|
|
27
|
+
const { current: pending } = pendingAutoSaves;
|
|
28
|
+
if (isAutoSaving) {
|
|
29
|
+
pending.add(form);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
isAutoSaving = true;
|
|
34
|
+
// See if we have any reactions that want to run (i.e. added by addRules hooks)
|
|
35
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
36
|
+
// If a reaction re-queued our form during the ^ wait, remove it
|
|
37
|
+
pending.delete(form);
|
|
38
|
+
await autoSaveRef.current(form);
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
isAutoSaving = false;
|
|
42
|
+
if (pending.size > 0) {
|
|
43
|
+
const first = pending.values().next().value;
|
|
44
|
+
pending.delete(first);
|
|
45
|
+
await maybeAutoSave(first);
|
|
46
|
+
}
|
|
32
47
|
}
|
|
33
48
|
}
|
|
34
49
|
}
|
|
35
|
-
}
|
|
36
|
-
const getFormState = react_1.useCallback((input) => {
|
|
37
|
-
const existing = objectStateCache[getId(input)];
|
|
38
|
-
let form = existing === null || existing === void 0 ? void 0 : existing[0];
|
|
39
50
|
// If it didn't exist, then add to the cache.
|
|
40
51
|
if (!form) {
|
|
41
52
|
form = formState_1.createObjectState(config, utils_1.initValue(config, map ? { map, input } : input), {
|
|
@@ -51,6 +62,7 @@ function useFormStates(opts) {
|
|
|
51
62
|
form.set(utils_1.initValue(config, map ? { map, input } : input), { refreshing: true });
|
|
52
63
|
existing[1] = input;
|
|
53
64
|
}
|
|
65
|
+
form.readOnly = readOnlyRef.current || !!opts.readOnly;
|
|
54
66
|
return form;
|
|
55
67
|
},
|
|
56
68
|
// Allow the user to not stable-ize getId, map, addRules, and autoSave
|
|
@@ -2,8 +2,10 @@
|
|
|
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 mobx_1 = require("mobx");
|
|
5
6
|
const react_1 = require("react");
|
|
6
7
|
const formState_1 = require("./formState");
|
|
8
|
+
const FormStateApp_1 = require("./FormStateApp");
|
|
7
9
|
const useFormStates_1 = require("./useFormStates");
|
|
8
10
|
describe("useFormStates", () => {
|
|
9
11
|
it("can lazily create form states", async () => {
|
|
@@ -99,10 +101,9 @@ describe("useFormStates", () => {
|
|
|
99
101
|
rtl_utils_1.click(r.focusSetAndSaveField2());
|
|
100
102
|
// Awaits the promises for all methods triggered above
|
|
101
103
|
await rtl_utils_1.wait();
|
|
102
|
-
// Then expect the auto save to only have been called
|
|
103
|
-
expect(autoSaveStub).toBeCalledTimes(
|
|
104
|
-
expect(autoSaveStub).toBeCalledWith({ id: "a:1", firstName: "Foo" });
|
|
105
|
-
expect(autoSaveStub).toBeCalledWith({ id: "a:1", lastName: "Bar" });
|
|
104
|
+
// Then expect the auto save to only have been called two times. Once with each set of changedValues.
|
|
105
|
+
expect(autoSaveStub).toBeCalledTimes(2);
|
|
106
|
+
expect(autoSaveStub).toBeCalledWith({ id: "a:1", firstName: "Foo", lastName: "Bar" });
|
|
106
107
|
expect(autoSaveStub).toBeCalledWith({ id: "a:2", lastName: "Bar" });
|
|
107
108
|
});
|
|
108
109
|
it("clears out cache if configuration changes", async () => {
|
|
@@ -151,7 +152,78 @@ describe("useFormStates", () => {
|
|
|
151
152
|
// Then addRules was only called once
|
|
152
153
|
expect(addRules).toHaveBeenCalledTimes(1);
|
|
153
154
|
});
|
|
155
|
+
it("calls autoSave with results of calculations in addRules", async () => {
|
|
156
|
+
// Given a user wants to use auto save
|
|
157
|
+
const autoSave = jest.fn();
|
|
158
|
+
function TestComponent() {
|
|
159
|
+
const { getFormState } = useFormStates_1.useFormStates({
|
|
160
|
+
config,
|
|
161
|
+
getId: (o) => o.id,
|
|
162
|
+
addRules(fs) {
|
|
163
|
+
// And they have a reactive true that calculates last name
|
|
164
|
+
mobx_1.reaction(() => fs.firstName.value, (curr) => {
|
|
165
|
+
fs.lastName.set(curr);
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
async autoSave(fs) {
|
|
169
|
+
autoSave(fs.changedValue);
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
return jsx_runtime_1.jsx(FormStateApp_1.TextField, { field: getFormState({ id: "a:1", firstName: "Brandon" }).firstName }, void 0);
|
|
173
|
+
}
|
|
174
|
+
// When we render
|
|
175
|
+
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}, void 0));
|
|
176
|
+
// And update the firstName
|
|
177
|
+
await rtl_utils_1.typeAndWait(r.firstName(), "first");
|
|
178
|
+
// Then autoSave was called once with both input+calc'd values
|
|
179
|
+
expect(autoSave).toHaveBeenCalledTimes(1);
|
|
180
|
+
expect(autoSave).toHaveBeenCalledWith({ id: "a:1", firstName: "first", lastName: "first" });
|
|
181
|
+
});
|
|
182
|
+
it("can set readOnly via the hook opt", async () => {
|
|
183
|
+
// Given a test component
|
|
184
|
+
function TestComponent({ readOnly }) {
|
|
185
|
+
const { getFormState } = useFormStates_1.useFormStates({
|
|
186
|
+
config,
|
|
187
|
+
getId: (o) => o.id,
|
|
188
|
+
// And it passes readOnly directly to useFormStates
|
|
189
|
+
readOnly,
|
|
190
|
+
});
|
|
191
|
+
return jsx_runtime_1.jsx(ChildComponent, { os: getFormState({ id: "a:1", firstName: "Brandon" }) }, void 0);
|
|
192
|
+
}
|
|
193
|
+
// When we render
|
|
194
|
+
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, { readOnly: true }, void 0));
|
|
195
|
+
// Then it's read only
|
|
196
|
+
expect(r.firstName()).toHaveAttribute("data-readonly", "true");
|
|
197
|
+
// And when we rerender
|
|
198
|
+
await r.rerender(jsx_runtime_1.jsx(TestComponent, { readOnly: false }, void 0));
|
|
199
|
+
// Then it's not read only
|
|
200
|
+
expect(r.firstName()).toHaveAttribute("data-readonly", "false");
|
|
201
|
+
});
|
|
202
|
+
it("can set readOnly via the getFormState function", async () => {
|
|
203
|
+
// Given a test component
|
|
204
|
+
function TestComponent({ readOnly }) {
|
|
205
|
+
const { getFormState } = useFormStates_1.useFormStates({
|
|
206
|
+
config,
|
|
207
|
+
getId: (o) => o.id,
|
|
208
|
+
});
|
|
209
|
+
// And it passes readOnly directly to getFormState
|
|
210
|
+
return jsx_runtime_1.jsx(ChildComponent, { os: getFormState({ id: "a:1", firstName: "Brandon" }, { readOnly }) }, void 0);
|
|
211
|
+
}
|
|
212
|
+
// When we render
|
|
213
|
+
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, { readOnly: true }, void 0));
|
|
214
|
+
// Then it's read only
|
|
215
|
+
expect(r.firstName()).toHaveAttribute("data-readonly", "true");
|
|
216
|
+
// And when we rerender
|
|
217
|
+
await r.rerender(jsx_runtime_1.jsx(TestComponent, { readOnly: false }, void 0));
|
|
218
|
+
// Then it's not read only
|
|
219
|
+
expect(r.firstName()).toHaveAttribute("data-readonly", "false");
|
|
220
|
+
});
|
|
154
221
|
});
|
|
222
|
+
const config = {
|
|
223
|
+
id: { type: "value" },
|
|
224
|
+
firstName: { type: "value" },
|
|
225
|
+
lastName: { type: "value" },
|
|
226
|
+
};
|
|
155
227
|
function ChildComponent({ os }) {
|
|
156
|
-
return jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "firstName" }, { children: os.firstName.value }), void 0);
|
|
228
|
+
return (jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "firstName", "data-readonly": os.firstName.readOnly }, { children: os.firstName.value }), void 0));
|
|
157
229
|
}
|