@homebound/form-state 2.33.0 → 3.0.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 (57) hide show
  1. package/dist/index.d.ts +437 -9
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +1109 -14
  4. package/dist/index.js.map +1 -0
  5. package/package.json +32 -35
  6. package/dist/FormStateApp.d.ts +0 -5
  7. package/dist/FormStateApp.js +0 -54
  8. package/dist/FormStateApp.test.d.ts +0 -1
  9. package/dist/FormStateApp.test.js +0 -26
  10. package/dist/config.d.ts +0 -78
  11. package/dist/config.js +0 -2
  12. package/dist/configBuilders.d.ts +0 -67
  13. package/dist/configBuilders.js +0 -115
  14. package/dist/configBuilders.test.d.ts +0 -1
  15. package/dist/configBuilders.test.js +0 -65
  16. package/dist/fields/deepEquals.d.ts +0 -7
  17. package/dist/fields/deepEquals.js +0 -53
  18. package/dist/fields/fragmentField.d.ts +0 -4
  19. package/dist/fields/fragmentField.js +0 -58
  20. package/dist/fields/listField.d.ts +0 -11
  21. package/dist/fields/listField.js +0 -355
  22. package/dist/fields/objectField.d.ts +0 -63
  23. package/dist/fields/objectField.js +0 -277
  24. package/dist/fields/valueField.d.ts +0 -81
  25. package/dist/fields/valueField.js +0 -244
  26. package/dist/formState.stories.d.ts +0 -4
  27. package/dist/formState.stories.js +0 -12
  28. package/dist/formState.test.d.ts +0 -11
  29. package/dist/formState.test.js +0 -2109
  30. package/dist/formStateDomain.d.ts +0 -47
  31. package/dist/formStateDomain.js +0 -28
  32. package/dist/mobx-behavior.test.d.ts +0 -1
  33. package/dist/mobx-behavior.test.js +0 -51
  34. package/dist/proxies.d.ts +0 -5
  35. package/dist/proxies.js +0 -20
  36. package/dist/rules.d.ts +0 -10
  37. package/dist/rules.js +0 -11
  38. package/dist/setupTests.d.ts +0 -1
  39. package/dist/setupTests.js +0 -15
  40. package/dist/stackoverlfow.d.ts +0 -17
  41. package/dist/stackoverlfow.js +0 -17
  42. package/dist/temporal.d.ts +0 -6
  43. package/dist/temporal.js +0 -34
  44. package/dist/temporal.test.d.ts +0 -1
  45. package/dist/temporal.test.js +0 -97
  46. package/dist/useFormState.d.ts +0 -82
  47. package/dist/useFormState.js +0 -158
  48. package/dist/useFormState.test.d.ts +0 -1
  49. package/dist/useFormState.test.js +0 -787
  50. package/dist/useFormStates.d.ts +0 -68
  51. package/dist/useFormStates.js +0 -101
  52. package/dist/useFormStates.test.d.ts +0 -1
  53. package/dist/useFormStates.test.js +0 -223
  54. package/dist/utils.d.ts +0 -52
  55. package/dist/utils.js +0 -198
  56. package/dist/utils.test.d.ts +0 -1
  57. package/dist/utils.test.js +0 -102
@@ -1,67 +0,0 @@
1
- import { FragmentFieldConfig, ListFieldConfig, ObjectConfig, ObjectFieldConfig, ValueFieldConfig } from "./config";
2
- import { Fragment, ObjectState } from "./fields/objectField";
3
- import { Rule } from "./rules";
4
- import { Builtin, OmitIf } from "./utils";
5
- /**
6
- * Provides a Zod-ish API for building form configs.
7
- */
8
- export declare const f: {
9
- /** Creates the top-level config for a form, like an author or book. */
10
- config<T>(fields: ObjectConfigBuilderFields<T>): ObjectConfig<T>;
11
- /** Creates the config DSL for an object, like an author or book. */
12
- object<T>(fields: ObjectConfigBuilderFields<T>): ObjectConfigBuilder<T>;
13
- /** Creates the config DSL for an list of objects, like an author's list of books. */
14
- list<U>(fields: ObjectConfigBuilderFields<U>): ListFieldConfigBuilder<U>;
15
- /** Creates the config DSL for a primitive value, like a first name or phone number. */
16
- value<V>(): ValueFieldConfigBuilder<V>;
17
- /** A shortcut for creating a child object with a single `id` key. */
18
- reference<V extends {
19
- id?: unknown;
20
- }>(fields?: ObjectConfigBuilderFields<V>): ObjectConfigBuilder<V>;
21
- /** A shorthand for creating a computed value. */
22
- computed<V>(): ValueFieldConfigBuilder<V>;
23
- };
24
- /**
25
- * Defines the fields that should be passed into `f.object({ ... })` for fhe form type `T`.
26
- *
27
- * This is basically a map of `key` in `T` to `f.value()`, `f.list()`, or `f.object()`
28
- * DSL objects that define the runtime structure/fields of the form.
29
- */
30
- export type ObjectConfigBuilderFields<T> = {
31
- [P in keyof OmitIf<T, Function>]: T[P] extends Fragment<infer V> ? FragmentFieldConfigBuilder : T[P] extends Array<infer U> | null | undefined ? U extends Builtin ? ValueFieldConfigBuilder<T[P]> : ListFieldConfigBuilder<U> : ValueFieldConfigBuilder<T[P]> | ObjectConfigBuilder<T[P]>;
32
- };
33
- export interface FragmentFieldConfigBuilder {
34
- build(): FragmentFieldConfig;
35
- }
36
- /** Provides a fluent DSL for building up an object's config. */
37
- export declare class ObjectConfigBuilder<T> {
38
- private config;
39
- constructor(fields: ObjectConfigBuilderFields<T>);
40
- ref(): this;
41
- build(): ObjectFieldConfig<T>;
42
- }
43
- /** Provides a fluent DSL for building up a value's config. */
44
- export declare class ValueFieldConfigBuilder<V> {
45
- private config;
46
- /** Marks the field as required. */
47
- req(): this;
48
- /** Marks the field as read only. */
49
- readOnly(): this;
50
- /** Marks the field as local only. */
51
- localOnly(): this;
52
- /** Appends `rules` to the field's validation rules. */
53
- rules(rules: Rule<V | null | undefined>[]): this;
54
- /** Marks the field as computed. */
55
- computed(): this;
56
- build(): ValueFieldConfig<V>;
57
- }
58
- /** Provides a fluent DSL for building up a list's config. */
59
- export declare class ListFieldConfigBuilder<U> {
60
- private config;
61
- constructor(fields: ObjectConfigBuilderFields<U>);
62
- /** Appends `rule` to the field's validation rules. */
63
- rule(rule: Rule<readonly ObjectState<U>[]>): this;
64
- /** Appends `rules` to the field's validation rules. */
65
- rules(rules: Rule<readonly ObjectState<U>[]>[]): this;
66
- build(): ListFieldConfig<U>;
67
- }
@@ -1,115 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ListFieldConfigBuilder = exports.ValueFieldConfigBuilder = exports.ObjectConfigBuilder = exports.f = void 0;
4
- const rules_1 = require("./rules");
5
- /**
6
- * Provides a Zod-ish API for building form configs.
7
- */
8
- exports.f = {
9
- /** Creates the top-level config for a form, like an author or book. */
10
- config(fields) {
11
- return new ObjectConfigBuilder(fields).build().config;
12
- },
13
- /** Creates the config DSL for an object, like an author or book. */
14
- object(fields) {
15
- return new ObjectConfigBuilder(fields);
16
- },
17
- /** Creates the config DSL for an list of objects, like an author's list of books. */
18
- list(fields) {
19
- return new ListFieldConfigBuilder(fields);
20
- },
21
- /** Creates the config DSL for a primitive value, like a first name or phone number. */
22
- value() {
23
- return new ValueFieldConfigBuilder();
24
- },
25
- /** A shortcut for creating a child object with a single `id` key. */
26
- reference(fields) {
27
- return exports.f.object({ id: exports.f.value(), ...fields }).ref();
28
- },
29
- /** A shorthand for creating a computed value. */
30
- computed() {
31
- return this.value().computed();
32
- },
33
- };
34
- /** Provides a fluent DSL for building up an object's config. */
35
- class ObjectConfigBuilder {
36
- constructor(fields) {
37
- this.config = { type: "object", config: {} };
38
- for (const [key, value] of Object.entries(fields)) {
39
- this.config.config[key] = value.build();
40
- }
41
- }
42
- ref() {
43
- this.config.reference = true;
44
- return this;
45
- }
46
- build() {
47
- return this.config;
48
- }
49
- }
50
- exports.ObjectConfigBuilder = ObjectConfigBuilder;
51
- /** Provides a fluent DSL for building up a value's config. */
52
- class ValueFieldConfigBuilder {
53
- constructor() {
54
- this.config = { type: "value", rules: [] };
55
- }
56
- /** Marks the field as required. */
57
- req() {
58
- this.config.rules = [rules_1.required];
59
- return this;
60
- }
61
- /** Marks the field as read only. */
62
- readOnly() {
63
- this.config.readOnly = true;
64
- return this;
65
- }
66
- /** Marks the field as local only. */
67
- localOnly() {
68
- this.config.isLocalOnly = true;
69
- return this;
70
- }
71
- /** Appends `rules` to the field's validation rules. */
72
- rules(rules) {
73
- var _a;
74
- var _b;
75
- ((_a = (_b = this.config).rules) !== null && _a !== void 0 ? _a : (_b.rules = [])).push(...rules);
76
- return this;
77
- }
78
- /** Marks the field as computed. */
79
- computed() {
80
- this.config.computed = true;
81
- return this;
82
- }
83
- build() {
84
- return this.config;
85
- }
86
- }
87
- exports.ValueFieldConfigBuilder = ValueFieldConfigBuilder;
88
- /** Provides a fluent DSL for building up a list's config. */
89
- class ListFieldConfigBuilder {
90
- constructor(fields) {
91
- const config = {};
92
- for (const [key, value] of Object.entries(fields)) {
93
- config[key] = value.build();
94
- }
95
- this.config = { type: "list", rules: [], config };
96
- }
97
- /** Appends `rule` to the field's validation rules. */
98
- rule(rule) {
99
- var _a;
100
- var _b;
101
- ((_a = (_b = this.config).rules) !== null && _a !== void 0 ? _a : (_b.rules = [])).push(rule);
102
- return this;
103
- }
104
- /** Appends `rules` to the field's validation rules. */
105
- rules(rules) {
106
- var _a;
107
- var _b;
108
- ((_a = (_b = this.config).rules) !== null && _a !== void 0 ? _a : (_b.rules = [])).push(...rules);
109
- return this;
110
- }
111
- build() {
112
- return this.config;
113
- }
114
- }
115
- exports.ListFieldConfigBuilder = ListFieldConfigBuilder;
@@ -1 +0,0 @@
1
- export {};
@@ -1,65 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const configBuilders_1 = require("./configBuilders");
4
- describe("config", () => {
5
- it("supports observable objects with helper methods in the config DSL", () => {
6
- const config = configBuilders_1.f.config({
7
- firstName: configBuilders_1.f.value(),
8
- lastName: configBuilders_1.f.value(),
9
- fullName: configBuilders_1.f.computed(),
10
- });
11
- // Throw away assertion, test is making sure ^ line compiles
12
- expect(config).toBeDefined();
13
- });
14
- it("supports nested objects", () => {
15
- const config = configBuilders_1.f.config({
16
- id: configBuilders_1.f.value(),
17
- address: configBuilders_1.f.object({ id: configBuilders_1.f.value() }),
18
- });
19
- expect(config).toMatchInlineSnapshot(`
20
- {
21
- "address": {
22
- "config": {
23
- "id": {
24
- "rules": [],
25
- "type": "value",
26
- },
27
- },
28
- "type": "object",
29
- },
30
- "id": {
31
- "rules": [],
32
- "type": "value",
33
- },
34
- }
35
- `);
36
- });
37
- it("supports Reference alias", () => {
38
- const config = configBuilders_1.f.config({
39
- id: configBuilders_1.f.value(),
40
- address: configBuilders_1.f.reference({ name: configBuilders_1.f.value() }),
41
- });
42
- expect(config).toMatchInlineSnapshot(`
43
- {
44
- "address": {
45
- "config": {
46
- "id": {
47
- "rules": [],
48
- "type": "value",
49
- },
50
- "name": {
51
- "rules": [],
52
- "type": "value",
53
- },
54
- },
55
- "reference": true,
56
- "type": "object",
57
- },
58
- "id": {
59
- "rules": [],
60
- "type": "value",
61
- },
62
- }
63
- `);
64
- });
65
- });
@@ -1,7 +0,0 @@
1
- /**
2
- * Our own `deepEquals` because either `fast-deep-equals` or `dequal` or etc actually
3
- * handle cyclic data structures, despite ChatGTP's assertions/hallucinations.
4
- *
5
- * Ported from https://github.com/KoryNunn/cyclic-deep-equal which is ISC.
6
- */
7
- export declare function deepEquals(a: any, b: any, visited?: Set<any>): boolean;
@@ -1,53 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deepEquals = deepEquals;
4
- const temporal_1 = require("../temporal");
5
- /**
6
- * Our own `deepEquals` because either `fast-deep-equals` or `dequal` or etc actually
7
- * handle cyclic data structures, despite ChatGTP's assertions/hallucinations.
8
- *
9
- * Ported from https://github.com/KoryNunn/cyclic-deep-equal which is ISC.
10
- */
11
- function deepEquals(a, b, visited = new Set()) {
12
- const temporalEquals = (0, temporal_1.areSupportedTemporalValuesEqual)(a, b);
13
- if (temporalEquals !== undefined)
14
- return temporalEquals;
15
- const aType = typeof a;
16
- if (aType !== typeof b)
17
- return false;
18
- if (a == null || b == null || !(aType === "object" || aType === "function")) {
19
- if (aType === "number" && isNaN(a) && isNaN(b))
20
- return true;
21
- return a === b;
22
- }
23
- if (hasToJSON(a) || hasToJSON(b)) {
24
- const a1 = hasToJSON(a) ? a.toJSON() : a;
25
- const b1 = hasToJSON(b) ? b.toJSON() : b;
26
- return deepEquals(a1, b1, visited);
27
- }
28
- if (Array.isArray(a) !== Array.isArray(b))
29
- return false;
30
- const aKeys = Object.keys(a), bKeys = Object.keys(b);
31
- if (aKeys.length !== bKeys.length)
32
- return false;
33
- let equal = true;
34
- for (const key of aKeys) {
35
- if (!(key in b)) {
36
- equal = false;
37
- break;
38
- }
39
- if (a[key] && a[key] instanceof Object) {
40
- if (visited.has(a[key]))
41
- break;
42
- visited.add(a[key]);
43
- }
44
- if (!deepEquals(a[key], b[key], visited)) {
45
- equal = false;
46
- break;
47
- }
48
- }
49
- return equal;
50
- }
51
- function hasToJSON(o) {
52
- return !!(o && typeof o === "object" && "toJSON" in o);
53
- }
@@ -1,4 +0,0 @@
1
- export interface FragmentField<V> {
2
- value: V;
3
- }
4
- export declare function newFragmentField<T extends object, K extends keyof T & string>(parentInstance: T, key: K): FragmentField<T[K]>;
@@ -1,58 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.newFragmentField = newFragmentField;
4
- const mobx_1 = require("mobx");
5
- const utils_1 = require("../utils");
6
- function newFragmentField(parentInstance, key) {
7
- // We always return the same `instance` field from our `value` method, but
8
- // we want to pretend that it's observable, so use a tick to force it.
9
- const _tick = (0, mobx_1.observable)({ value: 1 });
10
- // We steal the fragment from our parent, so that it doesn't
11
- // accidentally end up on the wire
12
- let value = parentInstance[key];
13
- delete parentInstance[key];
14
- const obj = {
15
- key,
16
- _isIdKey: false,
17
- _isDeleteKey: false,
18
- _isReadOnlyKey: false,
19
- _isLocalOnly: false,
20
- touched: false,
21
- valid: true,
22
- readOnly: true,
23
- required: false,
24
- loading: false,
25
- dirty: false,
26
- focused: false,
27
- originalValue: undefined,
28
- changedValue: undefined,
29
- errors: [],
30
- rules: [],
31
- isNewEntity: false,
32
- focus: () => { },
33
- blur: () => { },
34
- maybeAutoSave: () => { },
35
- commitChanges: () => { },
36
- revertChanges: () => { },
37
- get value() {
38
- // Watch for our parentInstance changing
39
- if (key in parentInstance) {
40
- value = parentInstance[key];
41
- delete parentInstance[key];
42
- }
43
- _tick.value > 0 || (0, utils_1.fail)();
44
- return value;
45
- },
46
- set value(v) {
47
- value = v;
48
- _tick.value++;
49
- },
50
- set(value) {
51
- this.value = value;
52
- },
53
- adapt(value) {
54
- throw new Error("FragmentField does not support adapt");
55
- },
56
- };
57
- return (0, mobx_1.makeAutoObservable)(obj, { value: false });
58
- }
@@ -1,11 +0,0 @@
1
- import { ListFieldConfig, ObjectFieldConfig } from "../config";
2
- import { ObjectState } from "./objectField";
3
- import { FieldState } from "./valueField";
4
- import { Rule } from "../rules";
5
- /** Form state for list of children, i.e. `U` is a `Book` in a form with a `books: Book[]`. */
6
- export interface ListFieldState<U> extends FieldState<U[]> {
7
- readonly rows: ReadonlyArray<ObjectState<U>>;
8
- add(value: U, index?: number): void;
9
- remove(indexOrValue: number | U): void;
10
- }
11
- export declare function newListFieldState<T, K extends keyof T, U>(parentCopy: T, parentInstance: T, parentState: () => ObjectState<T>, key: K, rules: Rule<readonly ObjectState<U>[]>[], listConfig: ListFieldConfig<U>, config: ObjectFieldConfig<U>, strictOrder: boolean, maybeAutoSave: () => void, deepExhaustive: boolean): ListFieldState<U>;