vultus-core 0.5.3 → 0.5.5

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 (42) hide show
  1. package/README.md +121 -3
  2. package/dist/FieldContext.d.ts +37 -1
  3. package/dist/FieldContext.d.ts.map +1 -1
  4. package/dist/FieldContext.js +68 -11
  5. package/dist/FieldContext.js.map +1 -1
  6. package/dist/fieldGroupValues.d.ts +63 -0
  7. package/dist/fieldGroupValues.d.ts.map +1 -0
  8. package/dist/fieldGroupValues.js +119 -0
  9. package/dist/fieldGroupValues.js.map +1 -0
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +1 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/kindHooks.d.ts +23 -0
  15. package/dist/kindHooks.d.ts.map +1 -0
  16. package/dist/kindHooks.js +38 -0
  17. package/dist/kindHooks.js.map +1 -0
  18. package/dist/tree.d.ts +5 -2
  19. package/dist/tree.d.ts.map +1 -1
  20. package/dist/tree.js +3 -3
  21. package/dist/tree.js.map +1 -1
  22. package/dist/useArg.d.ts +6 -0
  23. package/dist/useArg.d.ts.map +1 -1
  24. package/dist/useArg.js +6 -2
  25. package/dist/useArg.js.map +1 -1
  26. package/dist/useFieldGroup.d.ts +80 -0
  27. package/dist/useFieldGroup.d.ts.map +1 -0
  28. package/dist/useFieldGroup.js +266 -0
  29. package/dist/useFieldGroup.js.map +1 -0
  30. package/dist/useStoredField.d.ts +8 -0
  31. package/dist/useStoredField.d.ts.map +1 -1
  32. package/dist/useStoredField.js +4 -2
  33. package/dist/useStoredField.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/FieldContext.tsx +73 -11
  36. package/src/fieldGroupValues.ts +169 -0
  37. package/src/index.ts +1 -0
  38. package/src/kindHooks.ts +52 -0
  39. package/src/tree.ts +8 -5
  40. package/src/useArg.ts +6 -2
  41. package/src/useFieldGroup.ts +346 -0
  42. package/src/useStoredField.ts +4 -2
@@ -1 +1 @@
1
- {"version":3,"file":"useStoredField.js","sourceRoot":"","sources":["../src/useStoredField.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useStoredField.js","sourceRoot":"","sources":["../src/useStoredField.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vultus-core",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Framework-neutral action model + hooks for vultus (antd-free by design)",
6
6
  "repository": {
@@ -31,25 +31,46 @@ function isProbe(key: string): boolean {
31
31
  return PROBED_KEYS.has(key) || key.startsWith('@@');
32
32
  }
33
33
 
34
- /** What the guard throws for a key no provider gave, so readingContext can tell it from the function's own errors. */
35
- class MissingKeyError extends Error {}
34
+ /**
35
+ * What the guard throws for a key no provider gave, so readingContext can tell it from the
36
+ * function's own errors. Exported for the field group (fieldGroupValues), whose own reads that
37
+ * fail (an id not in the group, `values` read from `initialValue`) get the field and option in
38
+ * front the same way; not part of the package's API.
39
+ */
40
+ export class MissingKeyError extends Error {}
36
41
 
37
42
  /**
38
- * The context value as the definitions' functions receive it: reading a key that no provider
39
- * gave throws, naming it and the keys present, so a forgotten value fails loudly instead of
40
- * passing `undefined` along. A key provided with the value `undefined` is fine.
43
+ * `raw` guarded against reading a key it lacks: such a read throws a MissingKeyError with
44
+ * `missing(key)` as its message, which readingContext puts the field and the option in front
45
+ * of. `has` says whether `raw` has the key; by default inherited members (`toString`) count,
46
+ * and `Object.hasOwn` makes them missing too. Probes and symbol keys read as usual. Exported for
47
+ * the field group's `values` (an id not in the group); not part of the package's API.
41
48
  */
42
- function guard(raw: object): object {
49
+ export function guardKeys(
50
+ raw: object,
51
+ missing: (key: string) => string,
52
+ has: (target: object, key: string) => boolean = (target, key) => key in target,
53
+ ): object {
43
54
  return new Proxy(raw, {
44
55
  get(target, key, receiver) {
45
- if (typeof key === 'string' && !isProbe(key) && !(key in target)) {
46
- throw new MissingKeyError(`Field context: '${key}' was never provided (provided: ${Object.keys(target).join(', ')})`);
47
- }
56
+ if (typeof key === 'string' && !isProbe(key) && !has(target, key)) throw new MissingKeyError(missing(key));
48
57
  return Reflect.get(target, key, receiver);
49
58
  },
50
59
  });
51
60
  }
52
61
 
62
+ /**
63
+ * The context value as the definitions' functions receive it: reading a key that no provider
64
+ * gave throws, naming it and the keys present, so a forgotten value fails loudly instead of
65
+ * passing `undefined` along. A key provided with the value `undefined` is fine. `values` is the
66
+ * key a field group adds (extendFieldContext), so reading it from any other context says so.
67
+ */
68
+ function guard(raw: object): object {
69
+ return guardKeys(raw, (key) => (key === 'values'
70
+ ? 'ctx.values is only available inside a field group'
71
+ : `Field context: '${key}' was never provided (provided: ${Object.keys(raw).join(', ')})`));
72
+ }
73
+
53
74
  /**
54
75
  * Runs `read`, a call of a definition's function with the field context. A key it reads that
55
76
  * no provider gave throws with `where` (`Field '<id>': option '<name>'`) in front of the
@@ -92,7 +113,48 @@ export function createFieldContext<Ctx extends object>(): {
92
113
  return { Provider: FieldContextProvider };
93
114
  }
94
115
 
95
- /** The field context the hooks resolve functions with: the guarded value, or NO_FIELD_CONTEXT. */
116
+ /**
117
+ * A field context with `base`'s keys (none for NO_FIELD_CONTEXT) and `extra`'s, guarded as a
118
+ * provider's value is: how a field group gives its fields' functions `values` beside the app's
119
+ * own keys. `extra`'s properties are copied as defined, so a getter among them runs when its
120
+ * key is read, not here. A key of `extra` that `base` already has throws, `where` in front,
121
+ * instead of shadowing the app's value; every key the copy takes is checked (non-enumerable
122
+ * and symbol keys too).
123
+ */
124
+ export function extendFieldContext(base: FieldCtx, extra: Record<string, unknown>, where: string): object {
125
+ const raw: object = base === NO_FIELD_CONTEXT ? {} : { ...base };
126
+ for (const key of Reflect.ownKeys(extra)) {
127
+ if (Object.hasOwn(raw, key)) throw new Error(`${where}: the field context already has '${String(key)}'; a field group provides it`);
128
+ }
129
+ return guard(Object.defineProperties(raw, Object.getOwnPropertyDescriptors(extra)));
130
+ }
131
+
132
+ /** The context withFieldContext gives the hooks it is running, if any. */
133
+ let override: FieldCtx | undefined;
134
+
135
+ /**
136
+ * Runs `run` with `ctx` as the field context: a hook it calls gets `ctx` from useFieldContext
137
+ * instead of the providers' value. It is for a hook that calls other hooks in its own render,
138
+ * each with its own context (a field group runs each field's kind hook with the group's); the
139
+ * components rendered below do not see it. `run` must be synchronous: the previous context
140
+ * comes back when it returns or throws. Calls nest.
141
+ */
142
+ export function withFieldContext<T>(ctx: FieldCtx, run: () => T): T {
143
+ const previous = override;
144
+ override = ctx;
145
+ try {
146
+ return run();
147
+ } finally {
148
+ override = previous;
149
+ }
150
+ }
151
+
152
+ /**
153
+ * The field context the hooks resolve functions with: the one withFieldContext gives while it
154
+ * runs, else the providers' guarded value, or NO_FIELD_CONTEXT.
155
+ */
96
156
  export function useFieldContext(): FieldCtx {
97
- return useContext(FieldContext)?.guarded ?? NO_FIELD_CONTEXT;
157
+ // Called under an override too, so that the hooks' order never depends on one.
158
+ const provided = useContext(FieldContext);
159
+ return override ?? provided?.guarded ?? NO_FIELD_CONTEXT;
98
160
  }
@@ -0,0 +1,169 @@
1
+ import { extendFieldContext, guardKeys, MissingKeyError, type FieldCtx } from './FieldContext.js';
2
+ import { initialValueOf, sanitizeStored, type FieldDefinition } from './kinds.js';
3
+
4
+ /**
5
+ * One render's values of a field group (see useFieldGroup): each field's shown value and
6
+ * default, computed on demand by id from the kept values, with the definitions' options
7
+ * evaluated in the group's context, and each computed once.
8
+ */
9
+ export interface GroupValues {
10
+ /**
11
+ * The field context the group's option functions receive: the app's own keys (guarded as a
12
+ * provider's value is) and `values`, the fields' shown values by id.
13
+ */
14
+ ctx: object;
15
+ /**
16
+ * A field's shown value: its kept value, else its current default, made fit for its options
17
+ * as they are now (sanitizeStored); one that no longer fits shows the field's fallback. The
18
+ * kept value itself is never touched, so it shows again once it fits again.
19
+ */
20
+ valueOf(id: string): unknown;
21
+ /**
22
+ * A field's default: its `initialValue` (which cannot read `values`), else its kind's
23
+ * implicit initial value from its options as they are now (the first enabled choice, `min`,
24
+ * ...), so it moves with the fields those options read.
25
+ */
26
+ defaultOf(id: string): unknown;
27
+ /** The shown values by id, each computed when first read; `ctx.values` is the same object. */
28
+ values: Readonly<Record<string, unknown>>;
29
+ }
30
+
31
+ /** What createGroupValues computes the values from. */
32
+ export interface GroupValuesParams {
33
+ /** The group's fields, as data: unique ids, no mixed-boolean. */
34
+ definitions: readonly FieldDefinition[];
35
+ /** The app's field context (useFieldContext), which `values` is added to. */
36
+ appCtx: FieldCtx;
37
+ /** A field's kept value; `undefined` when none is kept, so the field shows its current default. */
38
+ kept(id: string): unknown | undefined;
39
+ /**
40
+ * Where a kept value's sanitizing warnings go, with the field's id: the caller decides whether
41
+ * to show them (and how often). A default made fit is the definer's, not kept input, so it
42
+ * never warns.
43
+ */
44
+ warn(id: string, message: string): void;
45
+ }
46
+
47
+ const WHERE = 'Field group';
48
+ const INITIAL_VALUE_READS_VALUES = "initialValue cannot read other fields' values";
49
+ const NOT_IN_A_GROUP = 'a mixed-boolean field shows an aggregate of other data, not a value of its own, so it cannot be in a field group';
50
+
51
+ function silently(_message: string): void {}
52
+
53
+ /**
54
+ * A definition as its values are computed from it. Its `initialValue` function receives
55
+ * `initialCtx`, whose `values` throws: a default cannot depend on other fields' values. A
56
+ * number's or range's display options (`step`, `unit`, `format`) are left out, because resolving
57
+ * its bounds (resolveNumeric) resolves them too, and an option that never affects the value
58
+ * (`unit: (ctx) => ctx.values.copies === 1 ? ...`) must not count as a dependency, nor form a
59
+ * cycle.
60
+ */
61
+ function forComputingValues(definition: FieldDefinition, initialCtx: object): FieldDefinition {
62
+ const computing = { ...definition };
63
+ const { initialValue } = definition;
64
+ if (typeof initialValue === 'function') {
65
+ Object.assign(computing, { initialValue: () => (initialValue as (ctx: object) => unknown)(initialCtx) });
66
+ }
67
+ if (computing.kind === 'numeric' || computing.kind === 'range') {
68
+ delete computing.step;
69
+ delete computing.unit;
70
+ delete computing.format;
71
+ }
72
+ return computing;
73
+ }
74
+
75
+ /**
76
+ * The values of a field group for one render, computed from its definitions and kept values.
77
+ *
78
+ * Every option function of the definitions receives `ctx`: the app's field context and
79
+ * `values`, the fields' shown values by id. A field's value is computed when an option (or the
80
+ * caller) first reads it, and kept for the rest of this snapshot; a new render makes a new one.
81
+ * The shown value is the kept value (else the current default) checked against the field's
82
+ * options as they are now, as a store's value is (sanitizeStored); one that no longer fits
83
+ * shows the fallback, which the other fields see too.
84
+ *
85
+ * Throws here for two definitions with the same id and for a mixed-boolean definition (naming
86
+ * the field), and for an app context that already has `values`. Throws when read, naming the
87
+ * field and the option, for an option reading an id not in the group and for `initialValue`
88
+ * reading `values`. Fields whose values depend on each other throw when read, naming the cycle
89
+ * (`Fields 'a' -> 'b' -> 'a' depend on each other's values`): a field's value and default are in
90
+ * progress while its options run, and reading one in progress is a cycle. Options that never
91
+ * affect a value (`visible`, `label`, `unit`, ...) are not run here, so they cannot form one.
92
+ */
93
+ export function createGroupValues({ definitions, appCtx, kept, warn }: GroupValuesParams): GroupValues {
94
+ const ids = definitions.map((definition) => definition.id);
95
+ for (const definition of definitions) {
96
+ if (ids.indexOf(definition.id) !== ids.lastIndexOf(definition.id)) {
97
+ throw new Error(`Field '${definition.id}': another field in the group has the same id`);
98
+ }
99
+ if (definition.kind === 'mixed-boolean') throw new Error(`Field '${definition.id}': ${NOT_IN_A_GROUP}`);
100
+ }
101
+ const noField = (id: string) => `no field '${id}' in the group (fields: ${ids.join(', ')})`;
102
+
103
+ const getters: Record<string, unknown> = {};
104
+ for (const id of ids) Object.defineProperty(getters, id, { get: () => valueOf(id), enumerable: true });
105
+ // Own keys only: `values.toString` is a typo for an id, not Object's member. `constructor`
106
+ // reads as usual, as the probes do, because printers (vitest's) name an object by it.
107
+ const values = guardKeys(getters, noField, (target, key) => key === 'constructor' || Object.hasOwn(target, key)) as
108
+ Readonly<Record<string, unknown>>;
109
+ const ctx = extendFieldContext(appCtx, { values }, WHERE);
110
+ // `values` not enumerable: a missing key's message lists the keys provided, and this one only throws.
111
+ const initialCtx = extendFieldContext(appCtx, Object.defineProperty<Record<string, unknown>>({}, 'values', {
112
+ get(): never {
113
+ throw new MissingKeyError(INITIAL_VALUE_READS_VALUES);
114
+ },
115
+ }), WHERE);
116
+ const computingDefinitions = new Map(definitions.map((definition) => [definition.id, forComputingValues(definition, initialCtx)]));
117
+
118
+ const shown = new Map<string, unknown>();
119
+ const defaults = new Map<string, unknown>();
120
+ /** The fields whose value or default is being computed, outermost first. */
121
+ const inProgress: string[] = [];
122
+
123
+ function definitionOf(id: string): FieldDefinition {
124
+ const definition = computingDefinitions.get(id);
125
+ if (definition === undefined) throw new MissingKeyError(noField(id));
126
+ return definition;
127
+ }
128
+
129
+ /** Runs `compute` with `id` in progress; reading `id` again before it returns is a cycle. */
130
+ function computing<T>(id: string, compute: () => T): T {
131
+ const at = inProgress.indexOf(id);
132
+ if (at !== -1) {
133
+ const cycle = [...inProgress.slice(at), id].map((each) => `'${each}'`).join(' -> ');
134
+ throw new Error(`Fields ${cycle} depend on each other's values`);
135
+ }
136
+ inProgress.push(id);
137
+ try {
138
+ return compute();
139
+ } finally {
140
+ inProgress.pop();
141
+ }
142
+ }
143
+
144
+ /** The default, computed as part of `id`'s own value or default (already in progress). */
145
+ function ownDefault(id: string): unknown {
146
+ if (!defaults.has(id)) defaults.set(id, initialValueOf(definitionOf(id), ctx));
147
+ return defaults.get(id);
148
+ }
149
+
150
+ function defaultOf(id: string): unknown {
151
+ definitionOf(id);
152
+ return defaults.has(id) ? defaults.get(id) : computing(id, () => ownDefault(id));
153
+ }
154
+
155
+ function valueOf(id: string): unknown {
156
+ const definition = definitionOf(id);
157
+ if (!shown.has(id)) {
158
+ shown.set(id, computing(id, () => {
159
+ const value = kept(id);
160
+ return value === undefined
161
+ ? sanitizeStored(definition, ownDefault(id), ctx, silently)
162
+ : sanitizeStored(definition, value, ctx, (message) => warn(id, message));
163
+ }));
164
+ }
165
+ return shown.get(id);
166
+ }
167
+
168
+ return { ctx, valueOf, defaultOf, values };
169
+ }
package/src/index.ts CHANGED
@@ -72,6 +72,7 @@ export {
72
72
  export {
73
73
  argOf, useStoredField, useStoredFields, type StoredField, type StoredFields,
74
74
  } from './useStoredField.js';
75
+ export { useFieldGroup, type FieldGroup } from './useFieldGroup.js';
75
76
  export { InternalLinkContext, useInternalLink, type InternalLinkComponent } from './LinkContext.js';
76
77
  export { MessageSinkContext, useMessageSink, type MessageSink } from './MessageSink.js';
77
78
  export {
@@ -0,0 +1,52 @@
1
+ import type { FieldControls, FieldKind } from './field.js';
2
+ import type { FieldDefinition } from './kinds.js';
3
+ import { useBoolField } from './useBoolField.js';
4
+ import { useManyOfField } from './useManyOfField.js';
5
+ import { useManyOfTreeField } from './useManyOfTreeField.js';
6
+ import { useMixedBoolField } from './useMixedBoolField.js';
7
+ import { useNumericField } from './useNumericField.js';
8
+ import { useOneOfField } from './useOneOfField.js';
9
+ import { useOneOfTreeField } from './useOneOfTreeField.js';
10
+ import { useRangeField } from './useRangeField.js';
11
+ import { useTextField } from './useTextField.js';
12
+
13
+ /**
14
+ * A definition in its outside form, as its kind's hook takes it: without `initialValue` (whoever
15
+ * keeps the value keeps its default too), with the value, its writer, and the link a value
16
+ * amounts to where whoever keeps it has one.
17
+ */
18
+ export type KindFieldOptions = OutsideForm<FieldDefinition>;
19
+
20
+ /** The outside form of a definition, member by member for a union (the conditional type distributes). */
21
+ type OutsideForm<D> = D extends FieldDefinition
22
+ ? Omit<D, 'initialValue'> & { value: unknown; onChange(value: any): void; hrefFor?(value: any): string | undefined }
23
+ : never;
24
+
25
+ /**
26
+ * Each kind's hook. Its options are checked against the definition in kinds.ts
27
+ * (DefinitionsFitTheirHooks); the mapped type makes leaving a kind out a compile error.
28
+ */
29
+ const KIND_HOOKS: { [K in FieldKind]: (options: any) => FieldControls<any, any> } = {
30
+ boolean: useBoolField,
31
+ 'mixed-boolean': useMixedBoolField,
32
+ oneOf: useOneOfField,
33
+ manyOf: useManyOfField,
34
+ numeric: useNumericField,
35
+ range: useRangeField,
36
+ manyOfTree: useManyOfTreeField,
37
+ oneOfTree: useOneOfTreeField,
38
+ text: useTextField,
39
+ };
40
+
41
+ /**
42
+ * Runs the hook of `definition`'s kind with `options` and returns its controls, exactly as that
43
+ * hook returns them. The hook called depends on the kind, so a caller running several fields
44
+ * (useFieldGroup) keeps each field's kind the same across renders. A kind that is none of
45
+ * FieldKind's (plain data can carry anything) throws, naming the field.
46
+ */
47
+ export function useKindField(definition: FieldDefinition, options: KindFieldOptions): FieldControls<any, any> {
48
+ const { id, kind } = definition;
49
+ if (!Object.hasOwn(KIND_HOOKS, kind)) throw new Error(`Field '${id}': unknown kind '${String(kind)}'`);
50
+ const useHook = KIND_HOOKS[kind];
51
+ return useHook(options);
52
+ }
package/src/tree.ts CHANGED
@@ -40,9 +40,12 @@ export type TreeSelection = 'topmost' | 'all' | 'leaves' | 'independent';
40
40
  /**
41
41
  * Which nodes a tree widget opens at first: `'top'` (the default), the roots with children;
42
42
  * `'none'`; `'selected'` (moxb's `expandValues`), the ancestors of the value's nodes; `'all'`,
43
- * every node with children.
43
+ * every node with children; or a list of node values, those of them with children and, as
44
+ * `'selected'`, the ancestors of the value's nodes (a book's printed table of contents: its
45
+ * chapters open, its sections folded, the current section shown). A listed leaf, or a value
46
+ * naming no node, opens nothing.
44
47
  */
45
- export type TreeExpand = 'top' | 'none' | 'selected' | 'all';
48
+ export type TreeExpand = 'top' | 'none' | 'selected' | 'all' | readonly string[];
46
49
 
47
50
  function hasChildren(node: { children?: unknown[] }): boolean {
48
51
  return (node.children?.length ?? 0) > 0;
@@ -196,11 +199,11 @@ export function expandedTreeKeys<T extends string>(nodes: TreeNode<T>[], value:
196
199
  if (expand === 'top') return nodes.filter(hasChildren).map((node) => node.value);
197
200
  const { order, parent } = indexTree(nodes);
198
201
  if (expand === 'all') return order.filter(hasChildren).map((node) => node.value);
199
- const ancestors = new Set<T>();
202
+ const open = new Set<string>(typeof expand === 'string' ? [] : expand);
200
203
  for (const v of value) {
201
- for (let up = parent.get(v); up !== undefined; up = parent.get(up)) ancestors.add(up);
204
+ for (let up = parent.get(v); up !== undefined; up = parent.get(up)) open.add(up);
202
205
  }
203
- return order.filter((node) => ancestors.has(node.value)).map((node) => node.value);
206
+ return order.filter((node) => hasChildren(node) && open.has(node.value)).map((node) => node.value);
204
207
  }
205
208
 
206
209
  /**
package/src/useArg.ts CHANGED
@@ -22,8 +22,12 @@ export interface ArgControls<T> {
22
22
  hrefFor(value: T): string | undefined;
23
23
  }
24
24
 
25
- /** The raw value a write needs for `value`: `undefined` (removes the key) when it equals the default, else its formatted form. */
26
- function rawFor<T>(value: T, defaultValue: T, valueType: ValueType<T>): string | undefined {
25
+ /**
26
+ * The raw value a write needs for `value`: `undefined` (removes the key) when it equals the
27
+ * default, else its formatted form. Exported for the field group (useFieldGroup), which writes a
28
+ * store by the same rule; not part of the package's API.
29
+ */
30
+ export function rawFor<T>(value: T, defaultValue: T, valueType: ValueType<T>): string | undefined {
27
31
  return valueType.isEqual(value, defaultValue) ? undefined : valueType.format(value);
28
32
  }
29
33