@weasel-js/prefs 1.10.0 → 1.11.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/index.d.ts CHANGED
@@ -1,7 +1,11 @@
1
- import { P as PrefLeaf, a as PrefGroup, b as PrefSection, c as PrefNumber, d as PrefList, e as PrefMap, f as PrefCondition, g as PrefConditionReader, h as PrefAlias, i as PrefObject, j as PrefKind } from './open-BEY-aOGe.js';
2
- export { B as BuiltinPref, k as PREF_KINDS, l as PrefAction, m as PrefActionContext, n as PrefActionControl, o as PrefAtPath, p as PrefBase, q as PrefBoolean, r as PrefBooleanControl, s as PrefBooleanEncoding, t as PrefChange, u as PrefColor, v as PrefConditionValue, w as PrefCustom, x as PrefEnum, y as PrefEnumBase, z as PrefEnumControl, A as PrefEnumEncoding, C as PrefField, D as PrefFunctionUnit, E as PrefGroupAs, F as PrefLabel, G as PrefLinearUnit, H as PrefNumberControl, I as PrefNumberUnit, J as PrefPaint, K as PrefPair, L as PrefPath, M as PrefSectionAs, N as PrefSeparator, O as PrefString, Q as PrefStringControl, R as PrefTest, S as PrefUnion, T as PrefValidator, U as PrefValueAt, V as PrefValueOf, W as PrefsMigration, X as PrefsOptions, Y as PrefsStore, Z as ResolvedPrefUnit, _ as isBuiltinPref, $ as isPrefCondition, a0 as isPrefLinearUnit, a1 as mapPrefConditionPaths, a2 as openPrefs, a3 as openPrefsSync, a4 as pairRowsOf, a5 as prefAliasName, a6 as prefAliasTarget, a7 as prefAliasedLeaf, a8 as prefConditionHolds, a9 as prefConditionPaths, aa as prefConditionReadsItem, ab as prefGroupIsPage, ac as prefIsEnabled, ad as prefIsShown, ae as prefUnit, af as prefVariantDefault, ag as prefVariantOf, ah as repairPrefValue, ai as resolvePrefUnit } from './open-BEY-aOGe.js';
1
+ import { Endless } from '@weasel-js/quantity';
2
+ import { P as PrefLeaf, a as PrefGroup, b as PrefSection, c as PrefNumber, d as PrefList, e as PrefMap, f as PrefCondition, g as PrefConditionReader, h as PrefBoolean, i as PrefString, j as PrefColor, k as PrefEnumBase, l as PrefAction, m as PrefActions, n as PrefLabel, o as PrefSeparator, p as PrefAlias, q as PrefObject, r as PrefKind } from './groups-BDZC-ywb.js';
3
+ export { B as BuiltinPref, s as PREF_KINDS, t as PrefActionContext, u as PrefActionControl, v as PrefBarLead, w as PrefBarOverflow, x as PrefBase, y as PrefBooleanControl, z as PrefBooleanEncoding, A as PrefBoundAt, C as PrefBoundReader, D as PrefConditionValue, E as PrefCustom, F as PrefEnum, G as PrefEnumControl, H as PrefEnumEncoding, I as PrefField, J as PrefFunctionUnit, K as PrefGroupAs, L as PrefLinearUnit, M as PrefLocus, N as PrefNumberBase, O as PrefNumberControl, Q as PrefNumberUnit, R as PrefPaint, S as PrefPair, T as PrefSectionAs, U as PrefSelection, V as PrefStringControl, W as PrefTest, X as PrefUnion, Y as PrefValueBase, Z as PrefWeighted, _ as PrefWeights, $ as ResolvedPrefUnit, a0 as isBuiltinPref, a1 as isPrefCondition, a2 as isPrefLinearUnit, a3 as isPrefLocus, a4 as mapPrefConditionPaths, a5 as pairRowsOf, a6 as prefAliasName, a7 as prefAliasTarget, a8 as prefAliasedLeaf, a9 as prefAsBox, aa as prefClampNumber, ab as prefConditionHolds, ac as prefConditionPaths, ad as prefConditionReadsItem, ae as prefGroupIsPage, af as prefIsEnabled, ag as prefIsShown, ah as prefLocusMember, ai as prefLocusSelectors, aj as prefNumberAt, ak as prefUnit, al as prefUnitAccepts, am as prefVariantDefault, an as prefVariantOf, ao as resolvePrefUnit } from './groups-BDZC-ywb.js';
4
+ export { P as PREF_BLENDS, a as PrefAtPath, b as PrefBlend, c as PrefChange, d as PrefPath, e as PrefValidator, f as PrefValueAt, g as PrefValueOf, h as PrefsMigration, i as PrefsOptions, j as PrefsStore, o as openPrefs, k as openPrefsSync, r as repairPrefValue } from './open-VJ1zlFJz.js';
5
+ import { P as PrefsCssSource, a as PrefsCssOptions } from './css-v-LpmTll.js';
6
+ export { p as prefsCss, b as prefsCssAttributes } from './css-v-LpmTll.js';
7
+ import '@weasel-js/icons';
3
8
  import '@weasel-js/storage';
4
- import '@weasel-js/quantity';
5
9
 
6
10
  /**
7
11
  * A number leaf's bounds in the unit it is displayed in.
@@ -12,16 +16,17 @@ import '@weasel-js/quantity';
12
16
  * `max` are points, so they convert the way the value does; `step` is a
13
17
  * distance, and a unit with an offset maps zero somewhere else, so converting
14
18
  * it as a point would scale it wrong. A decreasing conversion swaps which end
15
- * is the lower one.
19
+ * is the lower one, and which end is `endless`.
16
20
  */
17
21
  declare function prefDisplayBounds(p: PrefNumber): {
18
22
  min?: number;
19
23
  max?: number;
20
24
  step: number;
25
+ endless?: Endless;
21
26
  };
22
27
  /** Distinguishes a leaf from a group or a section while walking a schema tree. */
23
28
  declare function isPrefLeaf(node: PrefLeaf | PrefGroup | PrefSection): node is PrefLeaf;
24
- /** Whether a leaf has a value to store: an `action` is a button and holds none, an `alias` shows another leaf's,
29
+ /** Whether a leaf has a value to store: an `action` is a button and holds none, nor does an `actions` run of them, an `alias` shows another leaf's,
25
30
  * and a `label` and a `separator` are text and a rule. */
26
31
  declare function prefHoldsValue(leaf: PrefLeaf): boolean;
27
32
  /** Distinguishes a section, whose key adds nothing to a path, from a group, whose key is a segment. */
@@ -59,7 +64,7 @@ declare function prefLeaves(schema: PrefGroup): Map<string, PrefLeaf>;
59
64
  declare function flattenPrefValues(schema: PrefGroup, tree: unknown): [string, unknown][];
60
65
  /**
61
66
  * Drop every leaf that does not answer to `query`, pruning groups left empty.
62
- * A group whose own name matches keeps all of its leaves. An empty or
67
+ * A group whose own name or tag matches keeps all of its leaves. An empty or
63
68
  * whitespace query matches everything.
64
69
  *
65
70
  * An alias answers as the row it draws: its target's name and description
@@ -82,13 +87,22 @@ type PrefTabRun<T> = {
82
87
  */
83
88
  declare function prefTabRuns<T>(items: readonly T[], isTab: (item: T) => boolean): PrefTabRun<T>[];
84
89
 
90
+ /** The leaves carrying `tag`, themselves or through a group above them, by
91
+ * path, in schema order. */
92
+ declare function prefLeavesTagged(schema: PrefGroup | PrefSection, tag: string): Map<string, PrefLeaf>;
93
+ /** The tags the leaf at `path` carries: each group's above it, outermost
94
+ * first, then its own. Empty for a path that names no leaf. */
95
+ declare function prefLeafTags(schema: PrefGroup | PrefSection, path: string): readonly string[];
96
+
85
97
  /** One thing wrong with a condition: it is not one, it reads a path no leaf
86
- * holds a value at, it compares a leaf against a value it never holds, it
98
+ * holds a value at, it compares a leaf against a value it never holds — an
99
+ * enum against a string none of its options is being `option`, which a
100
+ * surface may take as a test that never matches — it
87
101
  * never holds whatever the leaf does, as an `in` of no values, it is the
88
102
  * `showIf` of a list's or a map's item, which is drawn with each entry, or
89
103
  * it reads from the entry on a node that no list or map draws. */
90
104
  interface PrefConditionProblem {
91
- code: 'malformed' | 'no-leaf' | 'no-value' | 'value' | 'never' | 'item-show' | 'no-item';
105
+ code: 'malformed' | 'no-leaf' | 'no-value' | 'value' | 'option' | 'never' | 'item-show' | 'no-item';
92
106
  /** The path read, where the problem is with one. */
93
107
  path?: string;
94
108
  problem: string;
@@ -278,6 +292,69 @@ declare function prefShownValue(leaf: PrefLeaf, stored: unknown, siblings?: Reco
278
292
  */
279
293
  declare function prefShownReader(schema: PrefGroup | PrefSection, read: PrefConditionReader, item?: PrefLeaf, over?: PrefGroup | PrefSection): PrefConditionReader;
280
294
 
295
+ /** One thing wrong with a leaf's `splitBy`. */
296
+ interface PrefSplitProblem {
297
+ code: 'valueless' | 'no-leaf' | 'not-enum' | 'encoded' | 'clearable' | 'split' | 'twice' | 'default';
298
+ /** The path of the leaf whose `splitBy` it is. */
299
+ at: string;
300
+ /** The entry of `splitBy` the problem is with, where it is with one. */
301
+ path?: string;
302
+ problem: string;
303
+ }
304
+ /** Everything wrong with the `splitBy` lists of `schema`'s leaves, in schema order. */
305
+ declare function checkPrefSplits(schema: PrefGroup): PrefSplitProblem[];
306
+
307
+ /** What a builder takes after the leaf's name and default: any of the leaf's other fields. */
308
+ type Rest<L> = Partial<Omit<L, 'kind' | 'name' | 'default'>>;
309
+ /**
310
+ * Builders for a preferences schema, each returning what the literal would
311
+ * hold. `pref.group('View', { grid: pref.boolean('Grid', true) })` is
312
+ * `{ name: 'View', children: { grid: { kind: 'boolean', name: 'Grid', description: '', default: true } } }`,
313
+ * and its paths and value types are read from it the same way.
314
+ */
315
+ declare const pref: {
316
+ /** A group: `children` nest under its key, which is a segment of their paths. */
317
+ group<const C extends Record<string, PrefLeaf | PrefGroup>>(name: string, children: C, options?: Omit<PrefGroup, "name" | "children">): Omit<PrefGroup, "children"> & {
318
+ children: C;
319
+ };
320
+ /** A section: a heading over `members`, whose key adds nothing to their paths. */
321
+ section<const M extends Record<string, PrefLeaf | PrefSection>>(name: string, members: M, options?: Omit<PrefSection, "name" | "members">): Omit<PrefSection, "members"> & {
322
+ members: M;
323
+ };
324
+ number: (name: string, def: number, rest?: Rest<PrefNumber>) => PrefNumber & {
325
+ default: number;
326
+ };
327
+ boolean: (name: string, def: boolean, rest?: Rest<PrefBoolean>) => PrefBoolean;
328
+ string: (name: string, def: string, rest?: Rest<PrefString>) => PrefString;
329
+ color: (name: string, def: string, rest?: Rest<PrefColor>) => PrefColor;
330
+ /** A fixed set of choices. An option given as its value alone is labeled with that value, its first letter raised. */
331
+ enum<const T extends string>(name: string, def: NoInfer<T>, options: readonly (T | PrefEnumBase<T>["options"][number])[], rest?: Omit<Rest<PrefEnumBase<T>>, "options">): PrefEnumBase<T> & {
332
+ default: T;
333
+ clearable?: false;
334
+ };
335
+ /** A button firing the registered action `action` (`id` or `id:variant`). Its name defaults to empty, which shows the action's own label. */
336
+ action: (action: string, rest?: Partial<Omit<PrefAction, "kind" | "default" | "action">>) => PrefAction;
337
+ /** Every action registered in the action group `group`. */
338
+ actions: (group: string, rest?: Partial<Omit<PrefActions, "kind" | "default" | "group">>) => PrefActions;
339
+ label: (name: string, rest?: Rest<PrefLabel>) => PrefLabel;
340
+ separator: () => PrefSeparator;
341
+ };
342
+
343
+ /**
344
+ * A schema's defaults read the way a store at defaults reads them, a split
345
+ * default by its `defaultLocus` — what `prefsCss` needs to write a schema's
346
+ * stylesheet with no store and no storage, at build time say.
347
+ */
348
+ declare function prefsDefaultsSource(schema: PrefGroup): PrefsCssSource;
349
+
350
+ /**
351
+ * `prefsCss` names for the kit's own settings: `tree.typeaheadMs` writes as
352
+ * `--wzl-kit-tree-typeahead-ms`, clear of theme tokens. With `at`, only the
353
+ * leaves under it are written, each named from below it; a selector outside
354
+ * `at` keeps its whole path in its attribute name.
355
+ */
356
+ declare function kitSettingsCssOptions(at?: string): PrefsCssOptions;
357
+
281
358
  /**
282
359
  * The schema that answers for the value at `path`: `schema` where a leaf of
283
360
  * it describes that value, else `over`, the schema `schema` is drawn over.
@@ -345,6 +422,15 @@ declare function prefType<L extends PrefLeaf>(name: string, leaf: L): L & {
345
422
  type: string;
346
423
  };
347
424
 
425
+ /** Whether a leaf's control fits beside a heading's words: a built-in `boolean`'s or `enum`'s does. */
426
+ declare function prefFitsHeading(leaf: PrefLeaf): boolean;
427
+ /**
428
+ * The key of the leaf a group or a section draws in its heading: the first
429
+ * directly in it that is marked `heading` and whose control fits there.
430
+ * Undefined for a node with no name, which has no heading to draw it in.
431
+ */
432
+ declare function prefHeadingKey(node: PrefGroup | PrefSection): string | undefined;
433
+
348
434
  /** Neighboring items one row draws, in {@link pairRuns}' answer. */
349
435
  interface PairRun<T> {
350
436
  items: T[];
@@ -387,4 +473,12 @@ declare function prefDrawsSeveral(leaf: {
387
473
  kind: string;
388
474
  }): boolean;
389
475
 
390
- export { PREF_ENTRY, PREF_KIND_TRAITS, PREF_SCOPE, type PairRun, PrefAlias, type PrefAliasTargets, type PrefAliasTargetsOptions, PrefCondition, type PrefConditionField, type PrefConditionJudge, type PrefConditionProblem, PrefConditionReader, type PrefConditionSite, type PrefConditionsApplied, type PrefConditionsOptions, type PrefEntry, type PrefEntryApplied, PrefGroup, PrefKind, type PrefKindTraits, PrefLeaf, PrefList, PrefMap, PrefNumber, PrefObject, type PrefSchemaConditionProblem, type PrefScope, type PrefScopeAtOptions, PrefSection, type PrefTabRun, VERSION_RECORD, applyPrefConditions, applyPrefEntryConditions, checkPrefCondition, checkPrefConditions, filterPrefSubtree, flattenPrefValues, isPrefLeaf, isPrefSection, pairRuns, prefAliasTargets, prefDisplayBounds, prefDrawsSeveral, prefHoldsValue, prefIsCompound, prefJudge, prefLeafAt, prefLeaves, prefObjectBase, prefObjectWithField, prefReader, prefSchemaHolding, prefScopeAt, prefScopeUnder, prefSectionLeaves, prefShownReader, prefShownValue, prefTabRuns, prefType, prefValueAtPath, visiblePrefSubtree };
476
+ /**
477
+ * One group named `name` holding every child of `groups`. Groups at the same
478
+ * key merge, the first one's own fields kept; a leaf meeting anything at the
479
+ * same key throws. Composes schemas that each add to the same areas, such as
480
+ * the kit settings groups that `ui` and `core` both give a `targets` group.
481
+ */
482
+ declare function mergePrefGroups(name: string, ...groups: readonly PrefGroup[]): PrefGroup;
483
+
484
+ export { PREF_ENTRY, PREF_KIND_TRAITS, PREF_SCOPE, type PairRun, PrefAction, PrefActions, PrefAlias, type PrefAliasTargets, type PrefAliasTargetsOptions, PrefBoolean, PrefColor, PrefCondition, type PrefConditionField, type PrefConditionJudge, type PrefConditionProblem, PrefConditionReader, type PrefConditionSite, type PrefConditionsApplied, type PrefConditionsOptions, type PrefEntry, type PrefEntryApplied, PrefEnumBase, PrefGroup, PrefKind, type PrefKindTraits, PrefLabel, PrefLeaf, PrefList, PrefMap, PrefNumber, PrefObject, type PrefSchemaConditionProblem, type PrefScope, type PrefScopeAtOptions, PrefSection, PrefSeparator, type PrefSplitProblem, PrefString, type PrefTabRun, PrefsCssOptions, PrefsCssSource, VERSION_RECORD, applyPrefConditions, applyPrefEntryConditions, checkPrefCondition, checkPrefConditions, checkPrefSplits, filterPrefSubtree, flattenPrefValues, isPrefLeaf, isPrefSection, kitSettingsCssOptions, mergePrefGroups, pairRuns, pref, prefAliasTargets, prefDisplayBounds, prefDrawsSeveral, prefFitsHeading, prefHeadingKey, prefHoldsValue, prefIsCompound, prefJudge, prefLeafAt, prefLeafTags, prefLeaves, prefLeavesTagged, prefObjectBase, prefObjectWithField, prefReader, prefSchemaHolding, prefScopeAt, prefScopeUnder, prefSectionLeaves, prefShownReader, prefShownValue, prefTabRuns, prefType, prefValueAtPath, prefsDefaultsSource, visiblePrefSubtree };
package/dist/index.js CHANGED
@@ -1,5 +1,9 @@
1
- import { prefLeafHoldingIn, prefLeafHolding, prefSchemaHolding, UNSEEN, prefConditionHolds, prefValueAtPath, isPrefSection, prefSectionLeaves, isPrefLeaf, prefLeafAt, prefAliasTarget, prefAliasedLeaf, pairRowsOf, prefConditionReadsItem, visiblePrefSubtree } from './chunk-5KB3WBJZ.js';
2
- export { PREF_KINDS, VERSION_RECORD, checkPrefCondition, checkPrefConditions, filterPrefSubtree, flattenPrefValues, isBuiltinPref, isPrefCondition, isPrefLeaf, isPrefLinearUnit, isPrefSection, mapPrefConditionPaths, openPrefs, openPrefsSync, pairRowsOf, prefAliasName, prefAliasTarget, prefAliasedLeaf, prefConditionHolds, prefConditionPaths, prefConditionReadsItem, prefDisplayBounds, prefHoldsValue, prefIsEnabled, prefIsShown, prefLeafAt, prefLeaves, prefSchemaHolding, prefSectionLeaves, prefUnit, prefValueAtPath, prefVariantDefault, prefVariantOf, repairPrefValue, resolvePrefUnit, visiblePrefSubtree } from './chunk-5KB3WBJZ.js';
1
+ import { prefLeafHoldingIn, prefLeafHolding, prefSchemaHolding, UNSEEN, prefConditionHolds, isBuiltinPref, pairRowsOf, prefConditionReadsItem } from './chunk-WN6QQICK.js';
2
+ export { PREF_KINDS, checkPrefCondition, checkPrefConditions, isBuiltinPref, isPrefCondition, kitSettingsCssOptions, mapPrefConditionPaths, openPrefs, openPrefsSync, pairRowsOf, prefConditionHolds, prefConditionPaths, prefConditionReadsItem, prefIsEnabled, prefIsShown, prefSchemaHolding } from './chunk-WN6QQICK.js';
3
+ export { prefsDefaultsSource } from './chunk-ZLXZRX73.js';
4
+ import { prefValueAtPath, isPrefSection, prefSectionLeaves, isPrefLeaf, prefLeafAt, prefAliasTarget, prefAliasedLeaf, visiblePrefSubtree } from './chunk-OZFER7VN.js';
5
+ export { PREF_BLENDS, VERSION_RECORD, checkPrefSplits, filterPrefSubtree, flattenPrefValues, isPrefLeaf, isPrefLinearUnit, isPrefLocus, isPrefSection, prefAliasName, prefAliasTarget, prefAliasedLeaf, prefClampNumber, prefDisplayBounds, prefHoldsValue, prefLeafAt, prefLeaves, memberAt as prefLocusMember, locusSelectors as prefLocusSelectors, prefNumberAt, prefSectionLeaves, prefUnit, prefUnitAccepts, prefValueAtPath, prefVariantDefault, prefVariantOf, prefsCss, prefsCssAttributes, repairPrefValue, resolvePrefUnit, visiblePrefSubtree } from './chunk-OZFER7VN.js';
6
+ import { hasTag } from '@weasel-js/registry';
3
7
 
4
8
  // src/tabRuns.ts
5
9
  function prefTabRuns(items, isTab) {
@@ -17,11 +21,31 @@ function prefTabRuns(items, isTab) {
17
21
  }
18
22
  return out;
19
23
  }
24
+ function taggedLeaves(schema) {
25
+ const out = [];
26
+ const walk = (node, prefix, above) => {
27
+ const section = isPrefSection(node);
28
+ for (const [key, child] of Object.entries(section ? node.members : node.children)) {
29
+ const path = section || prefix === "" ? key : `${prefix}.${key}`;
30
+ const tags = child.tags ? [...above, ...child.tags] : above;
31
+ if (isPrefLeaf(child)) out.push([path, child, tags]);
32
+ else walk(child, section ? prefix : path, tags);
33
+ }
34
+ };
35
+ walk(schema, "", schema.tags ?? []);
36
+ return out;
37
+ }
38
+ function prefLeavesTagged(schema, tag) {
39
+ return new Map(taggedLeaves(schema).filter(([, , tags]) => hasTag(tags, tag)).map(([path, leaf2]) => [path, leaf2]));
40
+ }
41
+ function prefLeafTags(schema, path) {
42
+ return taggedLeaves(schema).find(([p]) => p === path)?.[2] ?? [];
43
+ }
20
44
 
21
45
  // src/shown.ts
22
- function prefShownValue(leaf, stored, siblings) {
23
- if (leaf.kind !== "boolean" && leaf.kind !== "enum") return stored;
24
- const { encoding } = leaf;
46
+ function prefShownValue(leaf2, stored, siblings) {
47
+ if (leaf2.kind !== "boolean" && leaf2.kind !== "enum") return stored;
48
+ const { encoding } = leaf2;
25
49
  return encoding ? encoding.read(stored, siblings) : stored;
26
50
  }
27
51
  function prefShownReader(schema, read, item, over) {
@@ -55,9 +79,9 @@ function prefReader(schema, values, over) {
55
79
  if (held !== void 0) return held;
56
80
  if (beyond && prefSchemaHolding(schema, path, over) === over) return beyond(path);
57
81
  if (isPrefSection(schema)) {
58
- for (const [key, leaf] of prefSectionLeaves(schema.members)) {
59
- if (path === key) return leaf.default;
60
- if (path.startsWith(`${key}.`)) return prefValueAtPath(leaf.default, path.slice(key.length + 1));
82
+ for (const [key, leaf2] of prefSectionLeaves(schema.members)) {
83
+ if (path === key) return leaf2.default;
84
+ if (path.startsWith(`${key}.`)) return prefValueAtPath(leaf2.default, path.slice(key.length + 1));
61
85
  }
62
86
  return void 0;
63
87
  }
@@ -91,18 +115,18 @@ function scopeAmong(held, rest, above, holds) {
91
115
  }
92
116
  return void 0;
93
117
  }
94
- function scopeInside(leaf, rest, scope, holds) {
95
- if (leaf.kind === "object") return scopeAmong(leaf.children, rest, scope, holds) ?? scope;
96
- if (leaf.kind === "list" || leaf.kind === "map") {
97
- const { item } = leaf;
118
+ function scopeInside(leaf2, rest, scope, holds) {
119
+ if (leaf2.kind === "object") return scopeAmong(leaf2.children, rest, scope, holds) ?? scope;
120
+ if (leaf2.kind === "list" || leaf2.kind === "map") {
121
+ const { item } = leaf2;
98
122
  if (item === void 0) return scope;
99
123
  const inItem = deferEntryConditions(holds);
100
124
  const entry = prefScopeUnder(scope, { enableIf: item.enableIf }, inItem);
101
125
  const dot = rest.indexOf(".");
102
126
  return dot < 0 ? entry : scopeInside(item, rest.slice(dot + 1), entry, inItem);
103
127
  }
104
- if (leaf.kind !== "union") return scope;
105
- for (const variant of Object.values(leaf.variants)) {
128
+ if (leaf2.kind !== "union") return scope;
129
+ for (const variant of Object.values(leaf2.variants)) {
106
130
  const found = scopeAmong(variant.children, rest, scope, holds);
107
131
  if (found) return found;
108
132
  }
@@ -133,8 +157,8 @@ function prefAliasScope(own, alias, over, holds) {
133
157
  }
134
158
  function prefScopeAt(schema, path, holds, { aliasOver, aliasHolds } = {}) {
135
159
  const own = scopeAt(schema, path, holds);
136
- const leaf = prefLeafAt(schema, path);
137
- return leaf?.kind === "alias" ? prefAliasScope(own, leaf, aliasOver ?? schema, aliasHolds ?? holds) : own;
160
+ const leaf2 = prefLeafAt(schema, path);
161
+ return leaf2?.kind === "alias" ? prefAliasScope(own, leaf2, aliasOver ?? schema, aliasHolds ?? holds) : own;
138
162
  }
139
163
 
140
164
  // src/scope.ts
@@ -142,7 +166,7 @@ var under = (prefix, key) => prefix === "" ? key : `${prefix}.${key}`;
142
166
  function leafWalk({ keepEmpty, keepHidden, inItem, aliasOver, aliasHolds }) {
143
167
  const disabled = /* @__PURE__ */ new Set();
144
168
  const hidden = /* @__PURE__ */ new Set();
145
- const leaf = (node, path, above, holds) => {
169
+ const leaf2 = (node, path, above, holds) => {
146
170
  const own = prefScopeUnder(above, node, holds);
147
171
  const scope = node.kind === "alias" && aliasOver ? prefAliasScope(own, node, aliasOver, aliasHolds ?? holds) : own;
148
172
  return scope.shown || keepHidden ? inside(node, path, scope, holds) : null;
@@ -175,7 +199,7 @@ function leafWalk({ keepEmpty, keepHidden, inItem, aliasOver, aliasHolds }) {
175
199
  let changed = false;
176
200
  const out = {};
177
201
  for (const [key, child] of Object.entries(held)) {
178
- const kept = isPrefLeaf(child) ? leaf(child, under(prefix, key), above, holds) : section(child, prefix, above, holds);
202
+ const kept = isPrefLeaf(child) ? leaf2(child, under(prefix, key), above, holds) : section(child, prefix, above, holds);
179
203
  changed ||= kept !== child;
180
204
  if (kept !== null) out[key] = kept;
181
205
  }
@@ -188,7 +212,7 @@ function leafWalk({ keepEmpty, keepHidden, inItem, aliasOver, aliasHolds }) {
188
212
  if (kept === node.members) return node;
189
213
  return Object.keys(kept).length === 0 && !keepEmpty ? null : { ...node, members: kept };
190
214
  };
191
- return { disabled, hidden, leaf, inside, members };
215
+ return { disabled, hidden, leaf: leaf2, inside, members };
192
216
  }
193
217
  function applyPrefConditions(schema, holds, { keepEmpty = false, keepHidden = false, aliasOver, aliasHolds } = {}) {
194
218
  const walk = leafWalk({ keepEmpty, keepHidden, inItem: deferEntryConditions(holds), aliasOver: aliasOver ?? schema, aliasHolds });
@@ -223,11 +247,40 @@ function applyPrefEntryConditions(item, path, holds, { keepEmpty = false, keepHi
223
247
  return { item: walk.inside(item, path, scope, asked), disabled: walk.disabled, hidden: walk.hidden };
224
248
  }
225
249
 
250
+ // src/build.ts
251
+ var leaf = (kind, name, def, rest) => ({ kind, name, description: "", default: def, ...rest });
252
+ var labeled = (value) => value === "" ? value : value[0].toUpperCase() + value.slice(1);
253
+ var pref = {
254
+ /** A group: `children` nest under its key, which is a segment of their paths. */
255
+ group(name, children, options) {
256
+ return { name, ...options, children };
257
+ },
258
+ /** A section: a heading over `members`, whose key adds nothing to their paths. */
259
+ section(name, members, options) {
260
+ return { name, ...options, members };
261
+ },
262
+ number: (name, def, rest) => leaf("number", name, def, rest),
263
+ boolean: (name, def, rest) => leaf("boolean", name, def, rest),
264
+ string: (name, def, rest) => leaf("string", name, def, rest),
265
+ color: (name, def, rest) => leaf("color", name, def, rest),
266
+ /** A fixed set of choices. An option given as its value alone is labeled with that value, its first letter raised. */
267
+ enum(name, def, options, rest) {
268
+ const full = options.map((option) => typeof option === "string" ? { value: option, label: labeled(option) } : option);
269
+ return { kind: "enum", name, description: "", default: def, ...rest, options: full };
270
+ },
271
+ /** A button firing the registered action `action` (`id` or `id:variant`). Its name defaults to empty, which shows the action's own label. */
272
+ action: (action, rest) => leaf("action", "", void 0, { action, ...rest }),
273
+ /** Every action registered in the action group `group`. */
274
+ actions: (group, rest) => leaf("actions", "", void 0, { group, ...rest }),
275
+ label: (name, rest) => leaf("label", name, void 0, rest),
276
+ separator: () => leaf("separator", "", void 0, void 0)
277
+ };
278
+
226
279
  // src/aliasTargets.ts
227
- function visibleFieldsOf(leaf) {
228
- if (leaf.kind !== "object") return leaf;
229
- const shown = visiblePrefSubtree({ ...leaf, hidden: false }, false, true);
230
- return { ...leaf, children: shown.children };
280
+ function visibleFieldsOf(leaf2) {
281
+ if (leaf2.kind !== "object") return leaf2;
282
+ const shown = visiblePrefSubtree({ ...leaf2, hidden: false }, false, true);
283
+ return { ...leaf2, children: shown.children };
231
284
  }
232
285
  function prefAliasTargets(over, judge, { showHidden = false, markHidden = false } = {}) {
233
286
  const holds = judge();
@@ -235,8 +288,8 @@ function prefAliasTargets(over, judge, { showHidden = false, markHidden = false
235
288
  const get = () => applied ??= applyPrefConditions(over, holds, { keepEmpty: true, keepHidden: markHidden });
236
289
  const leafAt = (path) => {
237
290
  const { shown } = get();
238
- const leaf = shown === null ? void 0 : prefLeafAt(shown, path);
239
- return leaf === void 0 || showHidden ? leaf : visibleFieldsOf(leaf);
291
+ const leaf2 = shown === null ? void 0 : prefLeafAt(shown, path);
292
+ return leaf2 === void 0 || showHidden ? leaf2 : visibleFieldsOf(leaf2);
240
293
  };
241
294
  return {
242
295
  holds,
@@ -253,27 +306,43 @@ function prefAliasTargets(over, judge, { showHidden = false, markHidden = false
253
306
 
254
307
  // src/object.ts
255
308
  var isObject = (v) => typeof v === "object" && v !== null;
256
- function prefObjectBase(pref, held) {
309
+ function prefObjectBase(pref2, held) {
257
310
  if (isObject(held)) return held;
258
- return pref.fromScalar?.(held) ?? (isObject(pref.default) ? pref.default : {});
311
+ return pref2.fromScalar?.(held) ?? (isObject(pref2.default) ? pref2.default : {});
259
312
  }
260
- function prefObjectWithField(pref, held, key, value) {
261
- const base = prefObjectBase(pref, held);
313
+ function prefObjectWithField(pref2, held, key, value) {
314
+ const base = prefObjectBase(pref2, held);
262
315
  if (value !== void 0) return { ...base, [key]: value };
263
316
  const { [key]: _dropped, ...rest } = base;
264
317
  return rest;
265
318
  }
266
319
 
267
320
  // src/type.ts
268
- function prefType(name, leaf) {
269
- return { ...leaf, type: name };
321
+ function prefType(name, leaf2) {
322
+ return { ...leaf2, type: name };
270
323
  }
271
324
 
272
325
  // src/groups.ts
326
+ function prefAsBox(as) {
327
+ return as === "panel" || as === "menu";
328
+ }
273
329
  function prefGroupIsPage(group) {
274
330
  return group.as === void 0 || group.as === "page";
275
331
  }
276
332
 
333
+ // src/heading.ts
334
+ function prefFitsHeading(leaf2) {
335
+ return (leaf2.kind === "boolean" || leaf2.kind === "enum") && isBuiltinPref(leaf2);
336
+ }
337
+ function prefHeadingKey(node) {
338
+ if (node.name === "") return void 0;
339
+ const held = "members" in node ? node.members : node.children;
340
+ for (const [key, child] of Object.entries(held)) {
341
+ if (isPrefLeaf(child) && child.heading === true && prefFitsHeading(child)) return key;
342
+ }
343
+ return void 0;
344
+ }
345
+
277
346
  // src/pair.ts
278
347
  function pairRuns(items, leafOf) {
279
348
  const leaves = items.map(leafOf);
@@ -306,18 +375,41 @@ var PREF_KIND_TRAITS = {
306
375
  union: MANY,
307
376
  field: ONE,
308
377
  action: { compound: false, several: true },
378
+ actions: { compound: false, several: true },
309
379
  alias: ONE,
310
380
  label: ONE,
311
381
  separator: ONE
312
382
  };
313
- var traitsOf = (leaf) => Object.hasOwn(PREF_KIND_TRAITS, leaf.kind) ? PREF_KIND_TRAITS[leaf.kind] : ONE;
314
- function prefIsCompound(leaf) {
315
- return traitsOf(leaf).compound;
383
+ var traitsOf = (leaf2) => Object.hasOwn(PREF_KIND_TRAITS, leaf2.kind) ? PREF_KIND_TRAITS[leaf2.kind] : ONE;
384
+ function prefIsCompound(leaf2) {
385
+ return traitsOf(leaf2).compound;
386
+ }
387
+ function prefDrawsSeveral(leaf2) {
388
+ return traitsOf(leaf2).several;
389
+ }
390
+
391
+ // src/merge.ts
392
+ function mergeChildren(into, from, at) {
393
+ for (const [key, child] of Object.entries(from)) {
394
+ const path = at === "" ? key : `${at}.${key}`;
395
+ const held = into[key];
396
+ if (held === void 0) {
397
+ into[key] = child;
398
+ } else if (!isPrefLeaf(held) && !isPrefLeaf(child)) {
399
+ const children = { ...held.children };
400
+ mergeChildren(children, child.children, path);
401
+ into[key] = { ...held, children };
402
+ } else {
403
+ throw new Error(`mergePrefGroups: two groups give "${path}", and one of them is a leaf`);
404
+ }
405
+ }
316
406
  }
317
- function prefDrawsSeveral(leaf) {
318
- return traitsOf(leaf).several;
407
+ function mergePrefGroups(name, ...groups) {
408
+ const children = {};
409
+ for (const group of groups) mergeChildren(children, group.children, "");
410
+ return { name, children };
319
411
  }
320
412
 
321
- export { PREF_ENTRY, PREF_KIND_TRAITS, PREF_SCOPE, applyPrefConditions, applyPrefEntryConditions, pairRuns, prefAliasTargets, prefDrawsSeveral, prefGroupIsPage, prefIsCompound, prefJudge, prefObjectBase, prefObjectWithField, prefReader, prefScopeAt, prefScopeUnder, prefShownReader, prefShownValue, prefTabRuns, prefType };
413
+ export { PREF_ENTRY, PREF_KIND_TRAITS, PREF_SCOPE, applyPrefConditions, applyPrefEntryConditions, mergePrefGroups, pairRuns, pref, prefAliasTargets, prefAsBox, prefDrawsSeveral, prefFitsHeading, prefGroupIsPage, prefHeadingKey, prefIsCompound, prefJudge, prefLeafTags, prefLeavesTagged, prefObjectBase, prefObjectWithField, prefReader, prefScopeAt, prefScopeUnder, prefShownReader, prefShownValue, prefTabRuns, prefType };
322
414
  //# sourceMappingURL=index.js.map
323
415
  //# sourceMappingURL=index.js.map