@golemui/core 1.3.0-rc.0 → 1.4.0-rc.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/CHANGELOG.md +8 -0
- package/index.d.ts +3 -1
- package/index.js +1249 -1128
- package/index.umd.cjs +8 -8
- package/lib/context/form.context.d.ts +0 -1
- package/lib/errors.d.ts +2 -0
- package/lib/shared.d.ts +5 -0
- package/lib/store/actions.d.ts +1 -25
- package/lib/store/model.d.ts +21 -21
- package/lib/store/reducers/apply-default-values.d.ts +14 -0
- package/lib/store/reducers/calculate-current-state.d.ts +7 -1
- package/lib/store/reducers/calculate-widget-flags.d.ts +7 -1
- package/lib/store/reducers/calculate-widget-props.d.ts +7 -1
- package/lib/store/reducers/drop-removed-widget-entries.d.ts +13 -0
- package/lib/store/reducers/fill-calculated-widgets.d.ts +12 -0
- package/lib/store/reducers/index.d.ts +3 -3
- package/lib/store/reducers/override-widget-prop.d.ts +6 -0
- package/lib/store/reducers/set-widget-data.d.ts +2 -2
- package/lib/store/reducers/utils.d.ts +5 -27
- package/lib/store/selectors.d.ts +0 -22
- package/lib/store/view-model.d.ts +92 -0
- package/lib/utils/form.d.ts +19 -6
- package/lib/utils/justin.d.ts +10 -0
- package/lib/utils/object.d.ts +37 -18
- package/lib/utils/repeater.d.ts +43 -2
- package/package.json +1 -1
- package/lib/store/reducers/add-widget.d.ts +0 -3
- package/lib/store/reducers/materialize-repeater-items.d.ts +0 -10
- package/lib/store/reducers/remove-widget.d.ts +0 -3
- package/lib/utils/function.d.ts +0 -71
|
@@ -1,30 +1,8 @@
|
|
|
1
|
-
import { State } from '../model';
|
|
2
|
-
/**
|
|
3
|
-
* Conditionally applies a reducer function based on a predicate
|
|
4
|
-
*
|
|
5
|
-
* This higher-order reducer creates a new reducer that only applies the given
|
|
6
|
-
* reducer function when the predicate function returns true for the current state.
|
|
7
|
-
* If the predicate returns false, the state is returned unchanged.
|
|
8
|
-
*
|
|
9
|
-
* @param predicate - A function that takes the current state and returns a boolean
|
|
10
|
-
* indicating whether the reducer should be applied
|
|
11
|
-
* @param reducerFn - The reducer function to apply when the predicate returns true
|
|
12
|
-
*
|
|
13
|
-
* @returns A new reducer function that conditionally applies the given reducer
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```typescript
|
|
17
|
-
* // Only increment if count is less than 10
|
|
18
|
-
* const conditionalIncrement = reduceIf(
|
|
19
|
-
* (state: { count: number }) => state.count < 10,
|
|
20
|
-
* (state) => ({ ...state, count: state.count + 1 })
|
|
21
|
-
* );
|
|
22
|
-
*
|
|
23
|
-
* conditionalIncrement({ count: 5 }); // returns { count: 6 }
|
|
24
|
-
* conditionalIncrement({ count: 10 }); // returns { count: 10 } (unchanged)
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
export declare const reduceIf: (predicate: (state: State) => boolean, reducerFn: (state: State) => State) => (state: State) => State;
|
|
28
1
|
export declare const hasWhen: (val: unknown) => val is {
|
|
29
2
|
when: string;
|
|
30
3
|
};
|
|
4
|
+
/**
|
|
5
|
+
* Compares arrays by their elements and plain objects by their properties,
|
|
6
|
+
* everything else is comppared by reference using `===`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function deepEqual(a: unknown, b: unknown): boolean;
|
package/lib/store/selectors.d.ts
CHANGED
|
@@ -1,25 +1,3 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
|
-
import { LayoutWidget } from '../form-widget';
|
|
3
|
-
import { DotPath, Uid } from '../shared';
|
|
4
2
|
import { State } from './model';
|
|
5
|
-
export declare const dataByPath$: <T = any>(path: DotPath) => import('rxjs').UnaryFunction<Observable<State>, Observable<T>>;
|
|
6
|
-
export declare const validationByPath$: (path: DotPath) => import('rxjs').UnaryFunction<Observable<State>, Observable<import('../shared').ValidationStatus>>;
|
|
7
|
-
export declare const injectedValidationByPath$: (path: DotPath) => import('rxjs').UnaryFunction<Observable<State>, Observable<import('../shared').ValidationStatus>>;
|
|
8
|
-
/**
|
|
9
|
-
* Emits the current calculated widget for the given uid
|
|
10
|
-
* Re triggers on widget changes OR store.lang changes
|
|
11
|
-
*/
|
|
12
|
-
export declare const calculatedWidgetsByUid$: (uid: Uid) => (state$: Observable<State>) => Observable<import('../form-widget').NonFunctionWidget<string, any, any>>;
|
|
13
|
-
export declare const calculatedLayoutChildrenByUid$: (uid: Uid) => import('rxjs').UnaryFunction<Observable<State>, Observable<(import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, /*elided*/ any> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]>>;
|
|
14
|
-
export declare const selectWidgetFlags: import('rxjs').UnaryFunction<Observable<State>, Observable<Record<string, {
|
|
15
|
-
hidden?: boolean;
|
|
16
|
-
readonly?: boolean;
|
|
17
|
-
disabled?: boolean;
|
|
18
|
-
}>>>;
|
|
19
|
-
export declare const widgetFlagsByUid$: (uid: Uid) => import('rxjs').UnaryFunction<Observable<State>, Observable<{
|
|
20
|
-
hidden?: boolean;
|
|
21
|
-
readonly?: boolean;
|
|
22
|
-
disabled?: boolean;
|
|
23
|
-
}>>;
|
|
24
|
-
export declare const touchedControlsByPath$: (path: DotPath) => import('rxjs').UnaryFunction<Observable<State>, Observable<boolean>>;
|
|
25
3
|
export declare const formHealth: (store: Observable<State>) => Observable<import('./model').FormHealth>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { FormWidget, NonFunctionWidget } from '../form-widget';
|
|
3
|
+
import { Uid } from '../shared';
|
|
4
|
+
import { State } from './model';
|
|
5
|
+
/**
|
|
6
|
+
* One render-ready snapshot of everything a widget component needs from the store, so a binding
|
|
7
|
+
* can serve a widget from a single subscription (or a single snapshot read) instead of one
|
|
8
|
+
* subscription per store slice.
|
|
9
|
+
*
|
|
10
|
+
* Hidden widgets are reported as they are: `widget` is `undefined` and `hidden` is `true`. This
|
|
11
|
+
* differs from the calculated-widget lookup, which holds no entry for a hidden widget and
|
|
12
|
+
* therefore leaves subscribers holding the last visible value.
|
|
13
|
+
*/
|
|
14
|
+
export type WidgetViewModel<T = unknown> = {
|
|
15
|
+
uid: Uid;
|
|
16
|
+
/**
|
|
17
|
+
* The fully calculated widget (`calculatedWidgets[uid].current`), `undefined` while the widget
|
|
18
|
+
* is hidden or absent from the current derive.
|
|
19
|
+
*/
|
|
20
|
+
widget: NonFunctionWidget<string> | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* A layout widget's visible children, with repeater row indexes already applied to each child's
|
|
23
|
+
* `uid` and `path`. Empty for non-layout widgets and while hidden. Bindings can hand these nodes
|
|
24
|
+
* straight to their widget renderer without applying the indexes themselves.
|
|
25
|
+
*/
|
|
26
|
+
children: FormWidget<string>[];
|
|
27
|
+
/**
|
|
28
|
+
* For a repeater input, one fully indexed row layout node per row of its array value, ready to
|
|
29
|
+
* render. Empty for non-repeater widgets and while hidden. Row order matches the data array, so
|
|
30
|
+
* a row's position in this list is also its index in the value. The one exception is an errored
|
|
31
|
+
* derive, where a row the failed derive never resolved is left out until the form recovers.
|
|
32
|
+
*/
|
|
33
|
+
rows: NonFunctionWidget<string>[];
|
|
34
|
+
/** The BCP 47 language tag of the current locale. */
|
|
35
|
+
lang: string;
|
|
36
|
+
/** The form data at the widget's path, `undefined` for widgets without a path. */
|
|
37
|
+
value: T | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Schema and injected validation messages merged into one list. Empty until the form has been
|
|
40
|
+
* touched, so nothing shows before the user interacts.
|
|
41
|
+
*/
|
|
42
|
+
errors: string[];
|
|
43
|
+
/** Whether this control has been touched and may display its errors. */
|
|
44
|
+
touched: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* True when the form has been touched and is currently invalid. This is what action widgets
|
|
47
|
+
* (submit buttons) render as their `invalid` state.
|
|
48
|
+
*/
|
|
49
|
+
formInvalid: boolean;
|
|
50
|
+
/** The widget's `hidden` flag for the current derive. */
|
|
51
|
+
hidden: boolean;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Reads one widget's view model out of a state snapshot. Pure and uncached: every call builds
|
|
55
|
+
* fresh objects. Use {@link createWidgetViewModelReader} when reference stability across calls
|
|
56
|
+
* matters (change detection, `distinctUntilChanged`, React's `useSyncExternalStore`).
|
|
57
|
+
*
|
|
58
|
+
* @param state - A store state snapshot (`store.getState()`).
|
|
59
|
+
* @param uid - The widget's uid, including repeater row indexes when the widget lives inside a
|
|
60
|
+
* repeater row (e.g. `firstName[0]`).
|
|
61
|
+
* @returns The widget's view model.
|
|
62
|
+
* @example
|
|
63
|
+
* const vm = widgetViewModel<string>(store.getState(), 'firstName');
|
|
64
|
+
* vm.value; // the data at the widget's path
|
|
65
|
+
* vm.errors; // [] until the form is touched
|
|
66
|
+
*/
|
|
67
|
+
export declare function widgetViewModel<T = unknown>(state: State, uid: Uid): WidgetViewModel<T>;
|
|
68
|
+
/**
|
|
69
|
+
* Creates a memoizing reader over {@link widgetViewModel}: for a given uid it returns the exact
|
|
70
|
+
* same object until one of that widget's state slices changes, and reuses the `children` / `rows`
|
|
71
|
+
* / `errors` arrays while their own inputs are unchanged. Create one reader per store and keep it
|
|
72
|
+
* for the store's lifetime.
|
|
73
|
+
*
|
|
74
|
+
* @returns A reader function over a state snapshot and a uid.
|
|
75
|
+
* @example
|
|
76
|
+
* const readViewModel = createWidgetViewModelReader();
|
|
77
|
+
* const a = readViewModel(store.getState(), 'firstName');
|
|
78
|
+
* // ... an unrelated widget changes ...
|
|
79
|
+
* const b = readViewModel(store.getState(), 'firstName');
|
|
80
|
+
* a === b; // true
|
|
81
|
+
*/
|
|
82
|
+
export declare function createWidgetViewModelReader(): <T = unknown>(state: State, uid: Uid) => WidgetViewModel<T>;
|
|
83
|
+
/**
|
|
84
|
+
* RxJS operator form of {@link widgetViewModel} for subscribe-based bindings: maps the store's
|
|
85
|
+
* `state$` to the widget's view model and emits only when the view model actually changed.
|
|
86
|
+
*
|
|
87
|
+
* @param uid - The widget's uid, row indexes included when it lives inside a repeater row.
|
|
88
|
+
* @returns An operator from a state stream to a view model stream.
|
|
89
|
+
* @example
|
|
90
|
+
* store.state$.pipe(widgetViewModel$('firstName')).subscribe((vm) => { ... });
|
|
91
|
+
*/
|
|
92
|
+
export declare const widgetViewModel$: <T = unknown>(uid: Uid) => (state$: Observable<State>) => Observable<WidgetViewModel<T>>;
|
package/lib/utils/form.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FormWidget } from '../form-widget';
|
|
2
|
-
import { $Errors } from '../shared';
|
|
2
|
+
import { $Errors, DotPath } from '../shared';
|
|
3
3
|
import { State } from '../store/model';
|
|
4
4
|
/**
|
|
5
5
|
* Flattens the hierarchical form structure into a single-level array of form widgets.
|
|
@@ -21,16 +21,29 @@ import { State } from '../store/model';
|
|
|
21
21
|
*/
|
|
22
22
|
export declare function flattenForm(widgets: FormWidget[]): FormWidget[];
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
25
|
-
* e.g. `{ invalidAge: '!!$errors.age' }` or { disabled { when: '$formIsInvalid' } }
|
|
24
|
+
* The validation variables reactive expressions can read.
|
|
26
25
|
*/
|
|
27
|
-
export
|
|
26
|
+
export type ValidationVariables = {
|
|
28
27
|
$formIsInvalid: boolean;
|
|
29
28
|
$errors: $Errors;
|
|
30
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* Calculates validation variables to be used in reactive expressions
|
|
32
|
+
* e.g. `{ invalidAge: '!!$errors.age' }` or { disabled { when: '$formIsInvalid' } }
|
|
33
|
+
*/
|
|
34
|
+
export declare function calculateValidationVariables(state: State): ValidationVariables;
|
|
35
|
+
/**
|
|
36
|
+
* The data path a widget owns: an input widget's `path`, or a function widget's `path` when it
|
|
37
|
+
* returns a control. A function widget is stored as the callable itself, so `isInputWidget` is
|
|
38
|
+
* false for it and its path is the one the decoder stamped on the function object.
|
|
39
|
+
*
|
|
40
|
+
* @param widget - A `resolvedSources` entry, or a `calculatedWidgets` `current` / `source`.
|
|
41
|
+
* @returns The path, or `undefined` for a widget that owns none.
|
|
42
|
+
*/
|
|
43
|
+
export declare function inputPath(widget: FormWidget<string> | undefined): DotPath | undefined;
|
|
31
44
|
/**
|
|
32
45
|
* Returns a copy of the form data with values for currently-hidden input widgets removed.
|
|
33
|
-
* Paths
|
|
34
|
-
*
|
|
46
|
+
* Paths come from `resolvedSources`, so hidden repeater row inputs are pruned too and hidden
|
|
47
|
+
* widgets absent from calculatedWidgets are still covered.
|
|
35
48
|
*/
|
|
36
49
|
export declare function pruneHiddenData(state: State): Record<string, any>;
|
package/lib/utils/justin.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Evaluator } from 'subscript/justin';
|
|
1
2
|
import { $Errors, ExpressionFunctions, ReactiveExpression } from '../shared';
|
|
2
3
|
import { State } from '../store/model';
|
|
3
4
|
/**
|
|
@@ -13,5 +14,14 @@ export type RepeaterItemExpressionScope = {
|
|
|
13
14
|
export type ExpressionExtraScope = RepeaterItemExpressionScope & {
|
|
14
15
|
$fn?: ExpressionFunctions;
|
|
15
16
|
};
|
|
17
|
+
export declare const COMPILED_EXPRESSION_CACHE_LIMIT = 2000;
|
|
18
|
+
/**
|
|
19
|
+
* Returns the compiled evaluator for an expression, compiling on the first call.
|
|
20
|
+
*
|
|
21
|
+
* Row-rewritten `when` expressions are distinct per row, so the cache grows with the row
|
|
22
|
+
* count and is cleared when it reaches the limit. The next call recompiles. A failed parse
|
|
23
|
+
* is never cached, so an invalid expression throws the same error on every call.
|
|
24
|
+
*/
|
|
25
|
+
export declare function compileExpression(expression: string): Evaluator;
|
|
16
26
|
export declare function expressionIsTrue(expression: ReactiveExpression, $form: State['data'], $meta: State['meta'], $errors: $Errors, $formIsInvalid: boolean, extraScope?: ExpressionExtraScope): boolean;
|
|
17
27
|
export declare function normalizeArrayIndexes(expression: string): string;
|
package/lib/utils/object.d.ts
CHANGED
|
@@ -48,6 +48,25 @@ import { DotPath } from '../shared';
|
|
|
48
48
|
* ```
|
|
49
49
|
*/
|
|
50
50
|
export declare const get: <T = any>(obj: Record<string, any>, path: DotPath) => T;
|
|
51
|
+
/**
|
|
52
|
+
* Tells whether every segment of a dot-separated path is present in the object.
|
|
53
|
+
*
|
|
54
|
+
* Unlike `get`, a leaf that is present but holds `undefined` counts as existing, which is
|
|
55
|
+
* what distinguishes "the value was never written" from "the value was cleared".
|
|
56
|
+
*
|
|
57
|
+
* @param object - The object to look the path up in
|
|
58
|
+
* @param path - A dot-separated path (e.g. "user.profile.name" or "users.0.name").
|
|
59
|
+
* An empty path returns false.
|
|
60
|
+
* @returns True when every segment exists, false otherwise
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* pathExists({ user: { name: undefined } }, 'user.name'); // true
|
|
65
|
+
* pathExists({ user: {} }, 'user.name'); // false
|
|
66
|
+
* pathExists({ users: [{ name: 'Alice' }] }, 'users.1'); // false
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare const pathExists: (object: Record<string, any>, path: DotPath) => boolean;
|
|
51
70
|
/**
|
|
52
71
|
* Sets the value at path of object by mutation.
|
|
53
72
|
* If a portion of path doesn't exist, it's created.
|
|
@@ -119,10 +138,25 @@ export declare const get: <T = any>(obj: Record<string, any>, path: DotPath) =>
|
|
|
119
138
|
* ```
|
|
120
139
|
*/
|
|
121
140
|
export declare const set: (object: Record<string, any>, path: DotPath, value: any) => Record<string, any>;
|
|
141
|
+
/**
|
|
142
|
+
* Returns a copy of `object` with `value` set at `path`, copying only the containers along
|
|
143
|
+
* the path. Untouched siblings keep their references and `object` is never modified, so the
|
|
144
|
+
* result can be compared to the input by reference at any level. Missing containers are
|
|
145
|
+
* created like {@link set}: an array when the next key is an index, an object otherwise.
|
|
146
|
+
* @param object - The object to copy and write into.
|
|
147
|
+
* @param path - Dot-separated path, array indexes as numeric segments.
|
|
148
|
+
* @param value - The value to set at the path.
|
|
149
|
+
* @returns A new root object with the value set.
|
|
150
|
+
* @example
|
|
151
|
+
* const next = copyOnWriteSet({ a: { b: 1 }, c: { d: 2 } }, 'a.b', 3);
|
|
152
|
+
* next.a.b; // 3
|
|
153
|
+
* next.c; // the input's c, by reference
|
|
154
|
+
*/
|
|
155
|
+
export declare const copyOnWriteSet: (object: Record<string, any>, path: DotPath, value: any) => Record<string, any>;
|
|
122
156
|
/**
|
|
123
157
|
* Removes the property at the given dot-path from object by mutation.
|
|
124
158
|
* After deletion, any ancestor plain objects that become empty are also removed.
|
|
125
|
-
* Ancestor arrays that become empty are left in place
|
|
159
|
+
* Ancestor arrays that become empty are left in place, upward pruning stops as
|
|
126
160
|
* soon as an array boundary is encountered.
|
|
127
161
|
*
|
|
128
162
|
* @param object - The object to modify
|
|
@@ -144,7 +178,7 @@ export declare const set: (object: Record<string, any>, path: DotPath, value: an
|
|
|
144
178
|
* ```typescript
|
|
145
179
|
* const obj = { a: { b: { c: 1 } } };
|
|
146
180
|
* unset(obj, 'a.b.c');
|
|
147
|
-
* // Result: {}
|
|
181
|
+
* // Result: {} ('b' and 'a' are pruned because they became empty objects)
|
|
148
182
|
* ```
|
|
149
183
|
*
|
|
150
184
|
* @example
|
|
@@ -152,25 +186,10 @@ export declare const set: (object: Record<string, any>, path: DotPath, value: an
|
|
|
152
186
|
* ```typescript
|
|
153
187
|
* const obj = { items: [{ name: 'Alice' }] };
|
|
154
188
|
* unset(obj, 'items.0.name');
|
|
155
|
-
* // Result: { items: [{}] }
|
|
189
|
+
* // Result: { items: [{}] } (the empty object is kept inside the array)
|
|
156
190
|
* ```
|
|
157
191
|
*/
|
|
158
192
|
export declare const unset: <T extends Record<string, any>>(object: T, path: DotPath) => T;
|
|
159
|
-
/**
|
|
160
|
-
* Deletes a key from an object and returns the same mutated object.
|
|
161
|
-
*
|
|
162
|
-
* @param object - The object to remove the key from.
|
|
163
|
-
* @param key - The property name to delete.
|
|
164
|
-
* @returns The same object, with the specified key removed.
|
|
165
|
-
*
|
|
166
|
-
* @example
|
|
167
|
-
* ```ts
|
|
168
|
-
* const obj = { a: 1, b: 2, c: 3 };
|
|
169
|
-
* deleteKey(obj, "b");
|
|
170
|
-
* console.log(obj); // { a: 1, c: 3 }
|
|
171
|
-
* ```
|
|
172
|
-
*/
|
|
173
|
-
export declare const deleteKey: (object: Record<string, any>, key: string) => Record<string, any>;
|
|
174
193
|
/**
|
|
175
194
|
* Deep-clones plain objects and arrays while preserving function references
|
|
176
195
|
* (and other non-plain values) by reference. Functions are stateless widget
|
package/lib/utils/repeater.d.ts
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
|
-
import { FormWidget, NonFunctionWidget } from '../form-widget';
|
|
1
|
+
import { FormWidget, InputWidget, LayoutWidget, NonFunctionWidget } from '../form-widget';
|
|
2
2
|
import { Uid } from '../shared';
|
|
3
|
+
import { RepeaterItemScope, State } from '../store/model';
|
|
4
|
+
/**
|
|
5
|
+
* A repeater input widget as the core reads it: an input with a layout template under `props.template`.
|
|
6
|
+
*/
|
|
7
|
+
export type RepeaterTemplateWidget = InputWidget<string> & {
|
|
8
|
+
type: 'repeater';
|
|
9
|
+
props: {
|
|
10
|
+
template: LayoutWidget<string>;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export declare const isRepeaterWidget: (widget: FormWidget<string>) => widget is RepeaterTemplateWidget;
|
|
14
|
+
/** `"abc[0][1]"` -> `[0, 1]`, `"abc"` -> `[]`. */
|
|
15
|
+
export declare const extractRepeaterIndexes: (uid: string) => number[];
|
|
16
|
+
/**
|
|
17
|
+
* The two maps `expandSources` builds from the form and the data.
|
|
18
|
+
*/
|
|
19
|
+
export type ExpandedSources = {
|
|
20
|
+
resolvedSources: Record<Uid, FormWidget<string>>;
|
|
21
|
+
repeaterItemScopes: Record<Uid, RepeaterItemScope>;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Walks the flat form and the current data and returns every widget that exists for that data.
|
|
25
|
+
*
|
|
26
|
+
* `resolvedSources` holds the `flatForm` widgets by reference plus, for every repeater row, one entry
|
|
27
|
+
* per template widget (the row layout node included) with the row indexes written into `uid` and `path`.
|
|
28
|
+
* Nested repeater containers are entries too and are recursed with their concrete path. Function widgets
|
|
29
|
+
* stay callable (see {@link makeRepeaterItemConfig}), `when` expressions are not rewritten here.
|
|
30
|
+
*
|
|
31
|
+
* `repeaterItemScopes` maps every row widget uid to the innermost item that owns it.
|
|
32
|
+
*
|
|
33
|
+
* @param flatForm - The flattened form definition keyed by uid.
|
|
34
|
+
* @param data - The current form data the repeater arrays are read from.
|
|
35
|
+
* @returns Both maps, rebuilt from scratch.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* const { resolvedSources, repeaterItemScopes } = expandSources(flatForm, { users: [{}, {}] });
|
|
39
|
+
* resolvedSources['name[1]'].path; // 'users.1.name'
|
|
40
|
+
* repeaterItemScopes['name[1]']; // { itemPath: 'users.1', index: 1 }
|
|
41
|
+
*/
|
|
42
|
+
export declare function expandSources(flatForm: State['flatForm'], data: Record<string, any>): ExpandedSources;
|
|
3
43
|
/**
|
|
4
44
|
* Derives a concrete widget config for a specific repeater item by materializing the provided indexes into the
|
|
5
45
|
* widget's `uid` (and `path` for input widgets).
|
|
@@ -46,7 +86,8 @@ export declare function transformRepeaterItemWhenExpression(expression: string,
|
|
|
46
86
|
*
|
|
47
87
|
* @param widget - A widget already materialized for a repeater item (see {@link makeRepeaterItemConfig}).
|
|
48
88
|
* @param repeaterIndexes - Ordered list of indexes for each nesting level.
|
|
49
|
-
* @returns A new widget config with item-concrete `when` expressions
|
|
89
|
+
* @returns A new widget config with item-concrete `when` expressions, or the input widget by
|
|
90
|
+
* reference when no flag field has a `when` expression. The original is never mutated.
|
|
50
91
|
*
|
|
51
92
|
* @example
|
|
52
93
|
* // repeaterIndexes = [1]
|
package/package.json
CHANGED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { State } from '../model';
|
|
2
|
-
/**
|
|
3
|
-
* Walks every repeater's live array data and derives, per item, the same concrete widgets the renderer mounts for that item.
|
|
4
|
-
* Produces two maps keyed by materialized uid, both rebuilt from scratch on every run:
|
|
5
|
-
* - `repeaterItemScopes`: which item owns each widget (binds `$item` / `$index`).
|
|
6
|
-
* - `materializedRepeaterWidgets`: the item-concrete widget configs, with uid and path baked, `when` expressions rewritten for the item's row, and function widgets resolved.
|
|
7
|
-
*
|
|
8
|
-
* `calculateWidgetFlags` and `calculateWidgetProps` consume these maps, so this stage must run before them in the pipeline.
|
|
9
|
-
*/
|
|
10
|
-
export declare const materializeRepeaterItems: (state: State) => State;
|
package/lib/utils/function.d.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A function type that transforms a value of type A to type B
|
|
3
|
-
*/
|
|
4
|
-
type Func<A, B> = (arg: A) => B;
|
|
5
|
-
/**
|
|
6
|
-
* Performs left-to-right function composition (pipeline).
|
|
7
|
-
* The output of each function is passed as input to the next function.
|
|
8
|
-
*
|
|
9
|
-
* @typeParam A - The initial value type
|
|
10
|
-
* @param value - The initial value to pipe through the functions
|
|
11
|
-
* @param fns - Functions to apply in sequence
|
|
12
|
-
* @returns The result after applying all functions
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```typescript
|
|
16
|
-
* const addOne = (x: number) => x + 1;
|
|
17
|
-
* const double = (x: number) => x * 2;
|
|
18
|
-
* const toString = (x: number) => `Result: ${x}`;
|
|
19
|
-
*
|
|
20
|
-
* const result = pipe(5, addOne, double, toString); // 5 -> 6 -> 12 -> "Result: 12"
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
declare function pipe<A>(value: A): A;
|
|
24
|
-
/** @see {@link pipe} */
|
|
25
|
-
declare function pipe<A, B>(value: A, fn1: Func<A, B>): B;
|
|
26
|
-
/** @see {@link pipe} */
|
|
27
|
-
declare function pipe<A, B, C>(value: A, fn1: Func<A, B>, fn2: Func<B, C>): C;
|
|
28
|
-
/** @see {@link pipe} */
|
|
29
|
-
declare function pipe<A, B, C, D>(value: A, fn1: Func<A, B>, fn2: Func<B, C>, fn3: Func<C, D>): D;
|
|
30
|
-
/** @see {@link pipe} */
|
|
31
|
-
declare function pipe<A, B, C, D, E>(value: A, fn1: Func<A, B>, fn2: Func<B, C>, fn3: Func<C, D>, fn4: Func<D, E>): E;
|
|
32
|
-
/** @see {@link pipe} */
|
|
33
|
-
declare function pipe<A, B, C, D, E, F>(value: A, fn1: Func<A, B>, fn2: Func<B, C>, fn3: Func<C, D>, fn4: Func<D, E>, fn5: Func<E, F>): F;
|
|
34
|
-
/** @see {@link pipe} */
|
|
35
|
-
declare function pipe<A, B, C, D, E, F, G>(value: A, fn1: Func<A, B>, fn2: Func<B, C>, fn3: Func<C, D>, fn4: Func<D, E>, fn5: Func<E, F>, fn6: Func<F, G>): G;
|
|
36
|
-
/** @see {@link pipe} */
|
|
37
|
-
declare function pipe<A, B, C, D, E, F, G, H>(value: A, fn1: Func<A, B>, fn2: Func<B, C>, fn3: Func<C, D>, fn4: Func<D, E>, fn5: Func<E, F>, fn6: Func<F, G>, fn7: Func<G, H>): H;
|
|
38
|
-
/**
|
|
39
|
-
* Performs right-to-left function composition.
|
|
40
|
-
* The output of each function is passed as input to the previous function.
|
|
41
|
-
*
|
|
42
|
-
* @typeParam A - The input type of the composed function
|
|
43
|
-
* @returns A new function that applies all the given functions from right to left
|
|
44
|
-
*
|
|
45
|
-
* @example
|
|
46
|
-
* Basic composition
|
|
47
|
-
* ```typescript
|
|
48
|
-
* const addOne = (x: number) => x + 1;
|
|
49
|
-
* const double = (x: number) => x * 2;
|
|
50
|
-
* const toString = (x: number) => `Result: ${x}`;
|
|
51
|
-
*
|
|
52
|
-
* const transform = compose(toString, double, addOne); // Applies: addOne -> double -> toString
|
|
53
|
-
* console.log(transform(5)); // "Result: 12"
|
|
54
|
-
* ```
|
|
55
|
-
*/
|
|
56
|
-
declare function compose<A>(fn1: Func<A, A>): Func<A, A>;
|
|
57
|
-
/** @see {@link compose} */
|
|
58
|
-
declare function compose<A, B>(fn1: Func<A, B>, fn2: Func<B, A>): Func<B, B>;
|
|
59
|
-
/** @see {@link compose} */
|
|
60
|
-
declare function compose<A, B, C>(fn1: Func<B, C>, fn2: Func<A, B>): Func<A, C>;
|
|
61
|
-
/** @see {@link compose} */
|
|
62
|
-
declare function compose<A, B, C, D>(fn1: Func<C, D>, fn2: Func<B, C>, fn3: Func<A, B>): Func<A, D>;
|
|
63
|
-
/** @see {@link compose} */
|
|
64
|
-
declare function compose<A, B, C, D, E>(fn1: Func<D, E>, fn2: Func<C, D>, fn3: Func<B, C>, fn4: Func<A, B>): Func<A, E>;
|
|
65
|
-
/** @see {@link compose} */
|
|
66
|
-
declare function compose<A, B, C, D, E, F>(fn1: Func<E, F>, fn2: Func<D, E>, fn3: Func<C, D>, fn4: Func<B, C>, fn5: Func<A, B>): Func<A, F>;
|
|
67
|
-
/** @see {@link compose} */
|
|
68
|
-
declare function compose<A, B, C, D, E, F, G>(fn1: Func<F, G>, fn2: Func<E, F>, fn3: Func<D, E>, fn4: Func<C, D>, fn5: Func<B, C>, fn6: Func<A, B>): Func<A, G>;
|
|
69
|
-
/** @see {@link compose} */
|
|
70
|
-
declare function compose<A, B, C, D, E, F, G, H>(fn1: Func<G, H>, fn2: Func<F, G>, fn3: Func<E, F>, fn4: Func<D, E>, fn5: Func<C, D>, fn6: Func<B, C>, fn7: Func<A, B>): Func<A, H>;
|
|
71
|
-
export { compose, pipe };
|