@xh/hoist 73.0.0-SNAPSHOT.1745690606180 → 73.0.0-SNAPSHOT.1745976013413
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/CHANGELOG.md +2 -0
- package/build/types/cmp/form/FormModel.d.ts +13 -2
- package/cmp/form/FormModel.ts +84 -2
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,8 @@ Requires `hoist-core >= 30.0` with new APIs to support the consolidated Admin Co
|
|
|
10
10
|
|
|
11
11
|
* Added a new "Clients" Admin Console tab- a consolidated view of all websocket-connected clients
|
|
12
12
|
across all instances in the cluster.
|
|
13
|
+
* Updated `FormModel` to support `persistWith` for storing and recalling its values, including
|
|
14
|
+
developer options to persist all or a provided subset of fields.
|
|
13
15
|
|
|
14
16
|
### 🐞 Bug Fixes
|
|
15
17
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HoistModel, PlainObject } from '@xh/hoist/core';
|
|
1
|
+
import { HoistModel, PersistOptions, PlainObject } from '@xh/hoist/core';
|
|
2
2
|
import { ValidationState } from '@xh/hoist/data';
|
|
3
3
|
import { BaseFieldConfig, BaseFieldModel } from './field/BaseFieldModel';
|
|
4
4
|
import { SubformsFieldConfig, SubformsFieldModel } from './field/SubformsFieldModel';
|
|
@@ -9,11 +9,19 @@ export interface FormConfig {
|
|
|
9
9
|
fields?: Array<BaseFieldModel | BaseFieldConfig | SubformsFieldConfig | SubformsFieldModel>;
|
|
10
10
|
/** Map of initial values for fields in this model. */
|
|
11
11
|
initialValues?: PlainObject;
|
|
12
|
+
/** Options governing persistence of the form state. */
|
|
13
|
+
persistWith?: FormPersistOptions;
|
|
12
14
|
disabled?: boolean;
|
|
13
15
|
readonly?: boolean;
|
|
14
16
|
/** @internal */
|
|
15
17
|
xhImpl?: boolean;
|
|
16
18
|
}
|
|
19
|
+
export interface FormPersistOptions extends PersistOptions {
|
|
20
|
+
/** If persisting only a subset of all fields, provide an array of field names. */
|
|
21
|
+
includeFields?: string[];
|
|
22
|
+
/** If excluding a subset of all fields, provide an array of field names. */
|
|
23
|
+
excludeFields?: string[];
|
|
24
|
+
}
|
|
17
25
|
/**
|
|
18
26
|
* FormModel is the main entry point for Form specification. This Model's `fields` collection holds
|
|
19
27
|
* multiple FieldModel instances, which in turn hold the state of user edited data and the
|
|
@@ -57,7 +65,7 @@ export declare class FormModel extends HoistModel {
|
|
|
57
65
|
* See {@link getData} instead if you need to get or react to the values of *any/all* fields.
|
|
58
66
|
*/
|
|
59
67
|
get values(): PlainObject;
|
|
60
|
-
constructor({ fields, initialValues, disabled, readonly, xhImpl }?: FormConfig);
|
|
68
|
+
constructor({ fields, initialValues, disabled, persistWith, readonly, xhImpl }?: FormConfig);
|
|
61
69
|
getField(fieldName: string): BaseFieldModel;
|
|
62
70
|
/**
|
|
63
71
|
* Snapshot of current field values, keyed by field name.
|
|
@@ -127,4 +135,7 @@ export declare class FormModel extends HoistModel {
|
|
|
127
135
|
/** Trigger the display of validation errors (if any) by bound FormField components. */
|
|
128
136
|
displayValidation(): void;
|
|
129
137
|
private createValuesProxy;
|
|
138
|
+
private initPersist;
|
|
139
|
+
private serialize;
|
|
140
|
+
private deserialize;
|
|
130
141
|
}
|
package/cmp/form/FormModel.ts
CHANGED
|
@@ -4,14 +4,37 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2025 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
HoistModel,
|
|
9
|
+
managed,
|
|
10
|
+
PersistableState,
|
|
11
|
+
PersistenceProvider,
|
|
12
|
+
PersistOptions,
|
|
13
|
+
PlainObject
|
|
14
|
+
} from '@xh/hoist/core';
|
|
8
15
|
import {ValidationState} from '@xh/hoist/data';
|
|
9
16
|
import {action, bindable, computed, makeObservable, observable} from '@xh/hoist/mobx';
|
|
10
17
|
import {throwIf} from '@xh/hoist/utils/js';
|
|
11
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
flatMap,
|
|
20
|
+
forEach,
|
|
21
|
+
forOwn,
|
|
22
|
+
isArray,
|
|
23
|
+
isDate,
|
|
24
|
+
isObject,
|
|
25
|
+
isString,
|
|
26
|
+
map,
|
|
27
|
+
mapValues,
|
|
28
|
+
pick,
|
|
29
|
+
pickBy,
|
|
30
|
+
some,
|
|
31
|
+
values,
|
|
32
|
+
without
|
|
33
|
+
} from 'lodash';
|
|
12
34
|
import {BaseFieldConfig, BaseFieldModel} from './field/BaseFieldModel';
|
|
13
35
|
import {FieldModel} from './field/FieldModel';
|
|
14
36
|
import {SubformsFieldConfig, SubformsFieldModel} from './field/SubformsFieldModel';
|
|
37
|
+
import {isLocalDate, LocalDate} from '@xh/hoist/utils/datetime';
|
|
15
38
|
|
|
16
39
|
export interface FormConfig {
|
|
17
40
|
/**
|
|
@@ -22,6 +45,9 @@ export interface FormConfig {
|
|
|
22
45
|
/** Map of initial values for fields in this model. */
|
|
23
46
|
initialValues?: PlainObject;
|
|
24
47
|
|
|
48
|
+
/** Options governing persistence of the form state. */
|
|
49
|
+
persistWith?: FormPersistOptions;
|
|
50
|
+
|
|
25
51
|
disabled?: boolean;
|
|
26
52
|
readonly?: boolean;
|
|
27
53
|
|
|
@@ -29,6 +55,13 @@ export interface FormConfig {
|
|
|
29
55
|
xhImpl?: boolean;
|
|
30
56
|
}
|
|
31
57
|
|
|
58
|
+
export interface FormPersistOptions extends PersistOptions {
|
|
59
|
+
/** If persisting only a subset of all fields, provide an array of field names. */
|
|
60
|
+
includeFields?: string[];
|
|
61
|
+
/** If excluding a subset of all fields, provide an array of field names. */
|
|
62
|
+
excludeFields?: string[];
|
|
63
|
+
}
|
|
64
|
+
|
|
32
65
|
/**
|
|
33
66
|
* FormModel is the main entry point for Form specification. This Model's `fields` collection holds
|
|
34
67
|
* multiple FieldModel instances, which in turn hold the state of user edited data and the
|
|
@@ -87,6 +120,7 @@ export class FormModel extends HoistModel {
|
|
|
87
120
|
fields = [],
|
|
88
121
|
initialValues = {},
|
|
89
122
|
disabled = false,
|
|
123
|
+
persistWith = null,
|
|
90
124
|
readonly = false,
|
|
91
125
|
xhImpl = false
|
|
92
126
|
}: FormConfig = {}) {
|
|
@@ -97,6 +131,7 @@ export class FormModel extends HoistModel {
|
|
|
97
131
|
this.disabled = disabled;
|
|
98
132
|
this.readonly = readonly;
|
|
99
133
|
const models = {};
|
|
134
|
+
|
|
100
135
|
fields.forEach((f: any) => {
|
|
101
136
|
const model =
|
|
102
137
|
f instanceof BaseFieldModel
|
|
@@ -111,6 +146,7 @@ export class FormModel extends HoistModel {
|
|
|
111
146
|
this.fields = models;
|
|
112
147
|
|
|
113
148
|
this.init(initialValues);
|
|
149
|
+
if (persistWith) this.initPersist(persistWith);
|
|
114
150
|
|
|
115
151
|
// Set the owning formModel *last* after all fields in place with data.
|
|
116
152
|
// This (currently) kicks off the validation and other reactivity.
|
|
@@ -274,4 +310,50 @@ export class FormModel extends HoistModel {
|
|
|
274
310
|
}
|
|
275
311
|
);
|
|
276
312
|
}
|
|
313
|
+
|
|
314
|
+
private initPersist({
|
|
315
|
+
includeFields = null,
|
|
316
|
+
excludeFields = null,
|
|
317
|
+
path = 'formValues',
|
|
318
|
+
...rootPersistWith
|
|
319
|
+
}: FormPersistOptions) {
|
|
320
|
+
const allFields = Object.keys(this.fields);
|
|
321
|
+
const fieldNamesToPersist = excludeFields
|
|
322
|
+
? without(allFields, ...excludeFields)
|
|
323
|
+
: (includeFields ?? allFields);
|
|
324
|
+
|
|
325
|
+
PersistenceProvider.create({
|
|
326
|
+
persistOptions: {
|
|
327
|
+
path,
|
|
328
|
+
...rootPersistWith
|
|
329
|
+
},
|
|
330
|
+
target: {
|
|
331
|
+
getPersistableState: () =>
|
|
332
|
+
new PersistableState(this.serialize(pick(this.getData(), fieldNamesToPersist))),
|
|
333
|
+
setPersistableState: ({value: formValues}) =>
|
|
334
|
+
this.setValues(this.deserialize(pick(formValues, fieldNamesToPersist)))
|
|
335
|
+
},
|
|
336
|
+
owner: this
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
private serialize = (formValue: unknown) => {
|
|
341
|
+
if (isArray(formValue)) return formValue.map(this.serialize);
|
|
342
|
+
if (isDate(formValue)) return {_xhType: 'date', value: formValue.toJSON()};
|
|
343
|
+
if (isLocalDate(formValue)) return {_xhType: 'localDate', value: formValue.toJSON()};
|
|
344
|
+
if (isObject(formValue)) return mapValues(formValue, this.serialize);
|
|
345
|
+
return formValue;
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
private deserialize = (formValue: unknown) => {
|
|
349
|
+
if (isArray(formValue)) return formValue.map(this.deserialize);
|
|
350
|
+
if (isObject(formValue)) {
|
|
351
|
+
if ('_xhType' in formValue && 'value' in formValue && isString(formValue.value)) {
|
|
352
|
+
if (formValue._xhType === 'date') return new Date(formValue.value);
|
|
353
|
+
if (formValue._xhType === 'localDate') return LocalDate.get(formValue.value);
|
|
354
|
+
}
|
|
355
|
+
return mapValues(formValue, this.deserialize);
|
|
356
|
+
}
|
|
357
|
+
return formValue;
|
|
358
|
+
};
|
|
277
359
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "73.0.0-SNAPSHOT.
|
|
3
|
+
"version": "73.0.0-SNAPSHOT.1745976013413",
|
|
4
4
|
"description": "Hoist add-on for building and deploying React Applications.",
|
|
5
5
|
"repository": "github:xh/hoist-react",
|
|
6
6
|
"homepage": "https://xh.io",
|