@kitlangton/knobs 0.4.0-next.12 → 0.4.0-next.14
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/README.md +43 -15
- package/dist/dev/{chunk-nwfm1bfj.js → chunk-bejz4qcg.js} +15 -7
- package/dist/dev/{chunk-ab7vfghg.js → chunk-f0e5tkqg.js} +2 -2
- package/dist/dev/{chunk-9qtvxa6k.js → chunk-s7d5a8vb.js} +271 -163
- package/dist/dev/{chunk-7kns3qe6.js → chunk-v2g91mrm.js} +9 -1
- package/dist/dev/index.js +166 -57
- package/dist/index.js +170 -54
- package/dist/panel.js +339 -181
- package/dist/review-react.js +5 -3
- package/dist/review-solid.js +5 -3
- package/dist/review.js +5 -3
- package/dist/types/core/remote.d.ts +5 -1
- package/dist/types/core/schema.d.ts +12 -1
- package/dist/types/core/store.d.ts +62 -12
- package/dist/types/core/variants.d.ts +3 -1
- package/dist/types/panel/gpu/renderer.d.ts +8 -0
- package/dist/types/panel/presets.d.ts +14 -4
- package/dist/types/ui/index.d.ts +1 -1
- package/dist/types/ui/palette.d.ts +15 -0
- package/dist/types/ui/tree-model.d.ts +5 -2
- package/dist/ui-react.js +5 -3
- package/dist/ui-solid.js +5 -3
- package/dist/ui.js +28 -6
- package/package.json +1 -1
package/dist/review-react.js
CHANGED
|
@@ -5046,7 +5046,8 @@ function ancestors(index, id) {
|
|
|
5046
5046
|
out.push(p);
|
|
5047
5047
|
return out;
|
|
5048
5048
|
}
|
|
5049
|
-
function navigate(rows, active,
|
|
5049
|
+
function navigate(rows, active, pressed, page = 10, dir = "ltr") {
|
|
5050
|
+
const key = dir === "rtl" && (pressed === "ArrowLeft" || pressed === "ArrowRight") ? pressed === "ArrowLeft" ? "ArrowRight" : "ArrowLeft" : pressed;
|
|
5050
5051
|
if (rows.length === 0)
|
|
5051
5052
|
return { active: null };
|
|
5052
5053
|
const i = active === null ? -1 : rows.findIndex((r) => r.id === active);
|
|
@@ -5929,7 +5930,8 @@ function tree(container, options) {
|
|
|
5929
5930
|
options.onMove(move);
|
|
5930
5931
|
} else if (nav.includes(e.key) && !e.metaKey && !e.ctrlKey) {
|
|
5931
5932
|
const page = Math.max(1, Math.floor(viewport() / h) - 1);
|
|
5932
|
-
const
|
|
5933
|
+
const dir = win.getComputedStyle(root).direction === "rtl" ? "rtl" : "ltr";
|
|
5934
|
+
const r = navigate(rows, active, e.key, page, dir);
|
|
5933
5935
|
if (r.toggle)
|
|
5934
5936
|
toggle(r.toggle.id, r.toggle.expanded);
|
|
5935
5937
|
else if (r.active) {
|
|
@@ -7643,7 +7645,7 @@ function presence(el, o = {}) {
|
|
|
7643
7645
|
});
|
|
7644
7646
|
const tune = (seconds, zeta) => {
|
|
7645
7647
|
const reduced = reducedMotion(win);
|
|
7646
|
-
spring.omega = 2 * Math.PI / (reduced ? FADE.duration : seconds);
|
|
7648
|
+
spring.omega = 2 * Math.PI / (reduced ? Math.min(FADE.duration, seconds) : seconds);
|
|
7647
7649
|
spring.zeta = reduced ? 1 : zeta;
|
|
7648
7650
|
};
|
|
7649
7651
|
render();
|
package/dist/review-solid.js
CHANGED
|
@@ -5045,7 +5045,8 @@ function ancestors(index, id) {
|
|
|
5045
5045
|
out.push(p);
|
|
5046
5046
|
return out;
|
|
5047
5047
|
}
|
|
5048
|
-
function navigate(rows, active,
|
|
5048
|
+
function navigate(rows, active, pressed, page = 10, dir = "ltr") {
|
|
5049
|
+
const key = dir === "rtl" && (pressed === "ArrowLeft" || pressed === "ArrowRight") ? pressed === "ArrowLeft" ? "ArrowRight" : "ArrowLeft" : pressed;
|
|
5049
5050
|
if (rows.length === 0)
|
|
5050
5051
|
return { active: null };
|
|
5051
5052
|
const i = active === null ? -1 : rows.findIndex((r) => r.id === active);
|
|
@@ -5928,7 +5929,8 @@ function tree(container, options) {
|
|
|
5928
5929
|
options.onMove(move);
|
|
5929
5930
|
} else if (nav.includes(e.key) && !e.metaKey && !e.ctrlKey) {
|
|
5930
5931
|
const page = Math.max(1, Math.floor(viewport() / h) - 1);
|
|
5931
|
-
const
|
|
5932
|
+
const dir = win.getComputedStyle(root).direction === "rtl" ? "rtl" : "ltr";
|
|
5933
|
+
const r = navigate(rows, active, e.key, page, dir);
|
|
5932
5934
|
if (r.toggle)
|
|
5933
5935
|
toggle(r.toggle.id, r.toggle.expanded);
|
|
5934
5936
|
else if (r.active) {
|
|
@@ -7642,7 +7644,7 @@ function presence(el, o = {}) {
|
|
|
7642
7644
|
});
|
|
7643
7645
|
const tune = (seconds, zeta) => {
|
|
7644
7646
|
const reduced = reducedMotion(win);
|
|
7645
|
-
spring.omega = 2 * Math.PI / (reduced ? FADE.duration : seconds);
|
|
7647
|
+
spring.omega = 2 * Math.PI / (reduced ? Math.min(FADE.duration, seconds) : seconds);
|
|
7646
7648
|
spring.zeta = reduced ? 1 : zeta;
|
|
7647
7649
|
};
|
|
7648
7650
|
render();
|
package/dist/review.js
CHANGED
|
@@ -3769,7 +3769,7 @@ function presence(el, o = {}) {
|
|
|
3769
3769
|
});
|
|
3770
3770
|
const tune = (seconds, zeta) => {
|
|
3771
3771
|
const reduced = reducedMotion(win);
|
|
3772
|
-
spring.omega = 2 * Math.PI / (reduced ? FADE.duration : seconds);
|
|
3772
|
+
spring.omega = 2 * Math.PI / (reduced ? Math.min(FADE.duration, seconds) : seconds);
|
|
3773
3773
|
spring.zeta = reduced ? 1 : zeta;
|
|
3774
3774
|
};
|
|
3775
3775
|
render();
|
|
@@ -10203,7 +10203,8 @@ function ancestors(index, id) {
|
|
|
10203
10203
|
out.push(p);
|
|
10204
10204
|
return out;
|
|
10205
10205
|
}
|
|
10206
|
-
function navigate(rows, active,
|
|
10206
|
+
function navigate(rows, active, pressed, page = 10, dir = "ltr") {
|
|
10207
|
+
const key = dir === "rtl" && (pressed === "ArrowLeft" || pressed === "ArrowRight") ? pressed === "ArrowLeft" ? "ArrowRight" : "ArrowLeft" : pressed;
|
|
10207
10208
|
if (rows.length === 0)
|
|
10208
10209
|
return { active: null };
|
|
10209
10210
|
const i = active === null ? -1 : rows.findIndex((r) => r.id === active);
|
|
@@ -11086,7 +11087,8 @@ function tree(container, options) {
|
|
|
11086
11087
|
options.onMove(move);
|
|
11087
11088
|
} else if (nav.includes(e.key) && !e.metaKey && !e.ctrlKey) {
|
|
11088
11089
|
const page = Math.max(1, Math.floor(viewport() / h) - 1);
|
|
11089
|
-
const
|
|
11090
|
+
const dir = win.getComputedStyle(root).direction === "rtl" ? "rtl" : "ltr";
|
|
11091
|
+
const r = navigate(rows, active, e.key, page, dir);
|
|
11090
11092
|
if (r.toggle)
|
|
11091
11093
|
toggle(r.toggle.id, r.toggle.expanded);
|
|
11092
11094
|
else if (r.active) {
|
|
@@ -136,8 +136,12 @@ export interface RemoteControlsOptions {
|
|
|
136
136
|
readonly nullDefaults?: boolean;
|
|
137
137
|
readonly values?: State;
|
|
138
138
|
readonly presets?: Readonly<Record<string, State>>;
|
|
139
|
+
/** Presets that belong to one tab or group (see `ControlsOptions.scopedPresets`). */
|
|
140
|
+
readonly scopedPresets?: Readonly<Record<string, Readonly<Record<string, State>>>>;
|
|
139
141
|
/** Groups pinned above the tab strip, outside the presets (see `ControlsOptions.pinned`). */
|
|
140
142
|
readonly pinned?: readonly string[];
|
|
143
|
+
/** Groups presets leave alone, in place (see `ControlsOptions.inPresets`). */
|
|
144
|
+
readonly inPresets?: Readonly<Record<string, boolean>>;
|
|
141
145
|
/** Numbered presets per group, e.g. the phone's preset sets (see `ControlsOptions.groupPresets`). */
|
|
142
146
|
readonly groupPresets?: Readonly<Record<string, readonly GroupPreset[]>>;
|
|
143
147
|
/** Display labels by group id, section id and preset id (see `ControlsOptions.groupLabels`). */
|
|
@@ -145,7 +149,7 @@ export interface RemoteControlsOptions {
|
|
|
145
149
|
readonly sectionLabels?: Readonly<Record<string, string>>;
|
|
146
150
|
readonly presetLabels?: Readonly<Record<string, string>>;
|
|
147
151
|
/** Shorthand for `presetLabels.default`, e.g. "Native". */
|
|
148
|
-
readonly defaultLabel?: string
|
|
152
|
+
readonly defaultLabel?: string | Readonly<Record<string, string>>;
|
|
149
153
|
/** How a page card shows its group presets (see `ControlsOptions.groupPresetDisplay`). */
|
|
150
154
|
readonly groupPresetDisplay?: GroupPresetDisplay;
|
|
151
155
|
/** One muted line under a group's card title or a section's heading on a page, by id. */
|
|
@@ -56,6 +56,11 @@ export interface FieldMeta {
|
|
|
56
56
|
* Panel presets and saved variants leave pinned fields alone. See `ControlsOptions.pinned`.
|
|
57
57
|
*/
|
|
58
58
|
readonly pinned?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* `false`: presets, scoped presets and variants leave the field alone, as they leave a pinned
|
|
61
|
+
* one, but its row stays where it is. See `ControlsOptions.inPresets` for a whole group.
|
|
62
|
+
*/
|
|
63
|
+
readonly inPresets?: false;
|
|
59
64
|
/**
|
|
60
65
|
* A collapsible sub-heading inside the field's group: a flat heading with a hairline, never a
|
|
61
66
|
* card inside the card. Consecutive fields that share it sit under one heading.
|
|
@@ -63,7 +68,7 @@ export interface FieldMeta {
|
|
|
63
68
|
readonly subsection?: string;
|
|
64
69
|
}
|
|
65
70
|
/** Meta keys copied from a field's options or a descriptor onto the field. */
|
|
66
|
-
export declare const META_KEYS: readonly ["label", "group", "groupLabel", "section", "sectionLabel", "groupDescription", "sectionDescription", "shortcut", "random", "disabled", "readOnly", "folded", "sectionFolded", "tab", "pinned", "subsection"];
|
|
71
|
+
export declare const META_KEYS: readonly ["label", "group", "groupLabel", "section", "sectionLabel", "groupDescription", "sectionDescription", "shortcut", "random", "disabled", "readOnly", "folded", "sectionFolded", "tab", "pinned", "inPresets", "subsection"];
|
|
67
72
|
/** The meta `source` gives, without undefined keys. */
|
|
68
73
|
export declare function pickMeta(source: FieldMeta | undefined, skip?: readonly string[]): FieldMeta;
|
|
69
74
|
/** Marks a knob as half of a flat spring: two number keys drawn as one spring card. */
|
|
@@ -365,6 +370,11 @@ export declare function variantsOf(schema: Schema, isPinned?: (key: string) => b
|
|
|
365
370
|
* or whose first field that gives `pinned` says `true`, and ungrouped fields that say so themselves.
|
|
366
371
|
*/
|
|
367
372
|
export declare function pinnedKeys(schema: Schema, groups?: readonly string[]): ReadonlySet<string>;
|
|
373
|
+
/**
|
|
374
|
+
* The keys presets leave alone: the pinned ones, fields that say `inPresets: false`, and every key
|
|
375
|
+
* of a group `groups` gives `false`.
|
|
376
|
+
*/
|
|
377
|
+
export declare function presetFreeKeys(schema: Schema, pinned: ReadonlySet<string>, groups?: Readonly<Record<string, boolean>>): ReadonlySet<string>;
|
|
368
378
|
export type FieldValue<F extends Field> = F extends Knob ? number : F extends Choice<infer T> ? T : F extends Toggle ? boolean : F extends SpringField ? SpringValue : F extends ColorField ? string : F extends PointField ? Point : F extends EasingField ? Bezier : F extends VecField<3> ? Vec3 : F extends VecField<2> ? Point : F extends RangeField ? readonly [number, number] : F extends AngleField | SeedField ? number : F extends KeybindField | TextField ? string : F extends GradientField ? readonly GradientStop[] : F extends CurveField ? readonly CurvePoint[] : never;
|
|
369
379
|
/** The keys of a schema's readouts (what `controls.watch` takes). */
|
|
370
380
|
export type ReadoutKeys<S extends Schema> = {
|
|
@@ -494,6 +504,7 @@ export declare function range(value: readonly [number, number], options: FieldMe
|
|
|
494
504
|
sectionFolded?: boolean;
|
|
495
505
|
tab?: string;
|
|
496
506
|
pinned?: boolean;
|
|
507
|
+
inPresets?: false;
|
|
497
508
|
subsection?: string;
|
|
498
509
|
};
|
|
499
510
|
/** Degrees on a dial (0–360 and wrapping by default): `angle(45)`, `angle(30, { min: -90, max: 90 })`. */
|
|
@@ -50,6 +50,19 @@ export interface PresetRef {
|
|
|
50
50
|
readonly kind: "preset" | "variant";
|
|
51
51
|
readonly id: string;
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* A preset strip that belongs to one tab or group (see `ControlsOptions.scopedPresets`): its
|
|
55
|
+
* presets and saved variants move only its own keys, and it keeps its own active preset.
|
|
56
|
+
*/
|
|
57
|
+
export interface PresetScope<V = State> {
|
|
58
|
+
/** The tab or group it's named for. */
|
|
59
|
+
readonly id: string;
|
|
60
|
+
/** The keys it moves: the tab's or group's, pinned ones aside. */
|
|
61
|
+
readonly keys: readonly string[];
|
|
62
|
+
/** By id, `default` first; keys outside the scope sit at their defaults. */
|
|
63
|
+
readonly presets: Readonly<Record<string, V>>;
|
|
64
|
+
readonly variants: Variants<V>;
|
|
65
|
+
}
|
|
53
66
|
export interface ControlAction<V = State> {
|
|
54
67
|
readonly id?: string;
|
|
55
68
|
readonly label: string;
|
|
@@ -76,8 +89,11 @@ export interface LabelOptions {
|
|
|
76
89
|
readonly sectionLabels?: Readonly<Record<string, string>>;
|
|
77
90
|
/** By preset id: what the preset strip shows, e.g. `{ default: "Native" }`. */
|
|
78
91
|
readonly presetLabels?: Readonly<Record<string, string>>;
|
|
79
|
-
/**
|
|
80
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Shorthand for `presetLabels.default`; by scope, `{ "": "Empty", Motion: "Shipped" }` names each
|
|
94
|
+
* strip's default chip on its own (`""` is the panel's, a tab or group's id one of `scopedPresets`).
|
|
95
|
+
*/
|
|
96
|
+
readonly defaultLabel?: string | Readonly<Record<string, string>>;
|
|
81
97
|
/** How a page card shows its group presets (see `GroupPresetDisplay`). */
|
|
82
98
|
readonly groupPresetDisplay?: GroupPresetDisplay;
|
|
83
99
|
/** By group id: one muted line under its card's title on a page, over fields' `groupDescription`. */
|
|
@@ -144,9 +160,14 @@ export interface MountPanelOptions extends LabelOptions {
|
|
|
144
160
|
* and knobs/ui piece on the page (and the host's `data-hint` elements), so pressed here or
|
|
145
161
|
* anywhere outside a text field it jumps across all of them; with nothing else on the page it's
|
|
146
162
|
* this panel's alone, as always. `"panel"`: `s` here labels only this panel's controls, and they
|
|
147
|
-
* don't join the page's. `keys: { hint: false }` turns hint mode off here either way.
|
|
163
|
+
* don't join the page's. `keys: { hint: false }` turns hint mode off here either way. As an
|
|
164
|
+
* object, `reach` is that choice and `digits: "always"` keeps the preset strips' digits on their
|
|
165
|
+
* chips all the time, quietly, rather than only while you use keys.
|
|
148
166
|
*/
|
|
149
|
-
readonly hints?: "page" | "panel"
|
|
167
|
+
readonly hints?: "page" | "panel" | {
|
|
168
|
+
readonly reach?: "page" | "panel";
|
|
169
|
+
readonly digits?: "keys" | "always";
|
|
170
|
+
};
|
|
150
171
|
/**
|
|
151
172
|
* The key that shows and hides every panel and chip on the page that listens for it, outside
|
|
152
173
|
* text fields and without modifiers; remembered per store. The store's `toggleKey` by default
|
|
@@ -169,8 +190,9 @@ export interface MountPanelOptions extends LabelOptions {
|
|
|
169
190
|
*/
|
|
170
191
|
readonly header?: boolean | HeaderOptions;
|
|
171
192
|
/**
|
|
172
|
-
* `
|
|
173
|
-
* `esc ↑ Shape` for where Esc goes).
|
|
193
|
+
* `true` shows a scope line beside the title (`Shape › Cohesion`, where keys go, and a faint
|
|
194
|
+
* `esc ↑ Shape` for where Esc goes). Off by default; the focus lens and the armed frame show
|
|
195
|
+
* either way.
|
|
174
196
|
*/
|
|
175
197
|
readonly crumbs?: boolean;
|
|
176
198
|
/**
|
|
@@ -355,12 +377,27 @@ export interface ControlsOptions<S extends Schema> extends LabelOptions {
|
|
|
355
377
|
/** An undo stack the host owns; undo and redo call it (see `HostHistory`). */
|
|
356
378
|
history?: HostHistory;
|
|
357
379
|
presets?: Readonly<Record<string, Partial<Values<S>>>>;
|
|
380
|
+
/**
|
|
381
|
+
* Presets that belong to one tab or group, keyed by its id: `{ Sidebars: { snappy: {…} } }`.
|
|
382
|
+
* Each shows its own strip on that tab (a tab without any shows none), moves only that tab's
|
|
383
|
+
* or group's keys, and has its own active preset, modified mark and saved variants. A variants
|
|
384
|
+
* choice on a tab adds its options to that tab's. `presets` then covers only the keys no scope
|
|
385
|
+
* holds; leave it out and only the scoped strips show.
|
|
386
|
+
*/
|
|
387
|
+
scopedPresets?: Readonly<Record<string, Readonly<Record<string, Partial<Values<S>>>>>>;
|
|
358
388
|
/**
|
|
359
389
|
* Groups pinned to the top of a panel, under the header and above the tab strip, on every tab
|
|
360
390
|
* (as fields' `pinned: true` pins theirs). Presets and saved variants leave them alone: applying
|
|
361
391
|
* one keeps their values, saving one keeps them out, and they're modified against their defaults.
|
|
362
392
|
*/
|
|
363
393
|
pinned?: readonly string[];
|
|
394
|
+
/**
|
|
395
|
+
* Groups presets leave alone, where they are: `{ Motion: false }`. As with pinned groups,
|
|
396
|
+
* applying a preset or variant keeps their values, saving one leaves them out, and a preset's chip
|
|
397
|
+
* doesn't drift when they change; but their rows stay in place. A field says it alone with
|
|
398
|
+
* `inPresets: false`.
|
|
399
|
+
*/
|
|
400
|
+
inPresets?: Readonly<Record<string, boolean>>;
|
|
364
401
|
/**
|
|
365
402
|
* Numbered presets per group, shown as 1, 2, 3… on the group's card in a page. A group's
|
|
366
403
|
* presets cover every key any of them names; keys a preset leaves out are at their defaults,
|
|
@@ -408,6 +445,13 @@ export interface Controls<S extends Schema = Schema> {
|
|
|
408
445
|
readonly persist: PersistMode;
|
|
409
446
|
readonly presets: Readonly<Record<string, Values<S>>>;
|
|
410
447
|
readonly variants: Variants<Values<S>>;
|
|
448
|
+
/** The tabs and groups with presets of their own, by id (see `ControlsOptions.scopedPresets`). */
|
|
449
|
+
readonly scopes: Readonly<Record<string, PresetScope<Values<S>>>>;
|
|
450
|
+
/**
|
|
451
|
+
* The scope `key`'s presets come from: a tab or group's id, `""` for `presets`, or undefined
|
|
452
|
+
* when presets leave it alone (pinned, `inPresets: false`).
|
|
453
|
+
*/
|
|
454
|
+
scopeOf(key: string): string | undefined;
|
|
411
455
|
readonly actions: readonly ControlAction<Values<S>>[];
|
|
412
456
|
/** Its panels' theme, as given (see `ControlsOptions.theme`). */
|
|
413
457
|
readonly theme: Theme | ThemeMode | undefined;
|
|
@@ -437,10 +481,12 @@ export interface Controls<S extends Schema = Schema> {
|
|
|
437
481
|
readonly groupFolded: Readonly<Record<string, boolean>> | undefined;
|
|
438
482
|
/** How a page's sections start (`sectionFolded`), as given. */
|
|
439
483
|
readonly sectionFolded: SectionFolded | undefined;
|
|
440
|
-
/** A preset's display label (`presetLabels`, `defaultLabel`), else its id
|
|
441
|
-
presetLabel(id: string): string;
|
|
484
|
+
/** A preset's display label (`presetLabels`, `defaultLabel`), else its id; `scope` as in `preset`. */
|
|
485
|
+
presetLabel(id: string, scope?: string): string;
|
|
442
486
|
/** Whether `key` is pinned (its group is, see `ControlsOptions.pinned`), outside the presets. */
|
|
443
487
|
isPinned(key: string): boolean;
|
|
488
|
+
/** Whether presets move `key`: false when it's pinned or says `inPresets: false` (or its group does). */
|
|
489
|
+
inPresets(key: string): boolean;
|
|
444
490
|
readonly error: string | null;
|
|
445
491
|
get(): Values<S>;
|
|
446
492
|
getServerSnapshot(): Values<S>;
|
|
@@ -555,17 +601,21 @@ export interface Controls<S extends Schema = Schema> {
|
|
|
555
601
|
readonly comparing: boolean;
|
|
556
602
|
/**
|
|
557
603
|
* Applies a preset and makes it the active one (`"default"` clears it); one undo step, or
|
|
558
|
-
* folded into the last with `coalesce` (a pan across the strip).
|
|
604
|
+
* folded into the last with `coalesce` (a pan across the strip). With `scope`, one of that tab
|
|
605
|
+
* or group's presets, which moves only its keys.
|
|
559
606
|
*/
|
|
560
607
|
preset(id: string, options?: {
|
|
561
608
|
coalesce?: boolean;
|
|
609
|
+
scope?: string;
|
|
562
610
|
}): void;
|
|
563
|
-
|
|
611
|
+
/** The preset the current values match (in `scope`, over its keys), else `"custom"`. */
|
|
612
|
+
matchingPreset(scope?: string): string;
|
|
564
613
|
/**
|
|
565
614
|
* The preset (or saved variant) last applied, which Reset returns to and Random explores
|
|
566
|
-
* around, or null. Kept with the values; forgotten by a reset to the defaults.
|
|
615
|
+
* around, or null. Kept with the values; forgotten by a reset to the defaults. With `scope`,
|
|
616
|
+
* that tab or group's.
|
|
567
617
|
*/
|
|
568
|
-
activePreset(): PresetRef | null;
|
|
618
|
+
activePreset(scope?: string): PresetRef | null;
|
|
569
619
|
/** The group preset last applied to `group` (0-based), or -1. */
|
|
570
620
|
activeGroupPreset(group: string): number;
|
|
571
621
|
/** The values Reset returns to first: the active presets over the defaults. */
|
|
@@ -22,4 +22,6 @@ export interface Variants<V> {
|
|
|
22
22
|
export(): string;
|
|
23
23
|
import(json: string): void;
|
|
24
24
|
}
|
|
25
|
-
export declare function createVariants<S extends Schema>(schema: () => S, id: string, key: string, storage: () => StoragePort | null, get: () => Values<S>, set: (v: Values<S>, id: string, coalesce: boolean) => void, notify: () => void, enabled: () => boolean
|
|
25
|
+
export declare function createVariants<S extends Schema>(schema: () => S, id: string, key: string, storage: () => StoragePort | null, get: () => Values<S>, set: (v: Values<S>, id: string, coalesce: boolean) => void, notify: () => void, enabled: () => boolean,
|
|
26
|
+
/** What the list starts as while storage holds none yet (it's kept once something's saved). */
|
|
27
|
+
seed?: () => readonly Variant<Values<S>>[]): Variants<Values<S>>;
|
|
@@ -434,6 +434,8 @@ export interface GpuPanelBinding {
|
|
|
434
434
|
/** Each locked-capable row's lock icon, by its label element; `data-on` says it's locked. */
|
|
435
435
|
readonly locks?: ReadonlyMap<HTMLElement, HTMLElement>;
|
|
436
436
|
readonly presetStrip: PresetStrip;
|
|
437
|
+
/** Groups' own preset strips, each at the top of its card (see `scopedPresets`). */
|
|
438
|
+
readonly groupStrips?: () => Iterable<PresetStrip>;
|
|
437
439
|
/** The tab strip under the header (hidden while the panel has no tabs). */
|
|
438
440
|
readonly tabs?: TabStrip;
|
|
439
441
|
readonly groups: readonly GpuGroupBinding[];
|
|
@@ -606,6 +608,12 @@ declare class GpuOverlayManager {
|
|
|
606
608
|
private initWebGpu;
|
|
607
609
|
private setAllPanelsActive;
|
|
608
610
|
private pushPrim;
|
|
611
|
+
/**
|
|
612
|
+
* A preset strip: its tray (`tray`: the panel's strip has one, a group card's sits on the card),
|
|
613
|
+
* the selected chip's pill on its springs, the chips' names and drift marks, and the save chip.
|
|
614
|
+
* True while anything in it moves.
|
|
615
|
+
*/
|
|
616
|
+
private drawPresetStrip;
|
|
609
617
|
/** --k-rim-width in CSS px, on whole device pixels (at least one), so hairlines stay crisp. */
|
|
610
618
|
private hairline;
|
|
611
619
|
/**
|
|
@@ -19,8 +19,11 @@ export interface ActivePresetState {
|
|
|
19
19
|
}
|
|
20
20
|
/** How strong the selection pill stays on the active preset once the values drift off it. */
|
|
21
21
|
export declare const DRIFTED_PILL = 0.5;
|
|
22
|
-
/**
|
|
23
|
-
|
|
22
|
+
/**
|
|
23
|
+
* The strip's id for the store's active preset (`p:` a preset, `v:` a saved variant), if any;
|
|
24
|
+
* `scope` as in `Controls.preset`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function activeEntryId(controls: Controls<any>, scope?: string): string | null;
|
|
24
27
|
/**
|
|
25
28
|
* Resolves which preset or variant is currently active.
|
|
26
29
|
* The store's active preset (`baseId`) holds the selection however far the values drift from it.
|
|
@@ -59,6 +62,8 @@ export interface PresetStrip {
|
|
|
59
62
|
select(index: number): void;
|
|
60
63
|
/** Lays the presets out as chips or a list (see `PresetDisplay`). */
|
|
61
64
|
display(mode: PresetDisplay): void;
|
|
65
|
+
/** Keeps each of the first nine chips' digit on it, quietly, before its name. */
|
|
66
|
+
digits(on: boolean): void;
|
|
62
67
|
selectById(id: string): void;
|
|
63
68
|
/** Saves the current values as "Variant N" and opens its name to typing; returns a status message. */
|
|
64
69
|
save(): string;
|
|
@@ -75,6 +80,11 @@ export interface PresetStrip {
|
|
|
75
80
|
}
|
|
76
81
|
export declare function createPresetStrip<S extends Schema>(doc: Document, controls: Controls<S>, showVariants: boolean, run: (action: () => unknown) => void, onAfterChange?: () => void,
|
|
77
82
|
/** What a preset's chip says (its id stays its identity); `controls.presetLabel` by default. */
|
|
78
|
-
presetLabel?: (id: string) => string,
|
|
83
|
+
presetLabel?: (id: string, scope: string) => string,
|
|
79
84
|
/** Whether these entries matter where the strip is shown (a tab they don't touch hides it). */
|
|
80
|
-
relevant?: (entries: readonly PresetEntry<any>[]) => boolean
|
|
85
|
+
relevant?: (entries: readonly PresetEntry<any>[]) => boolean,
|
|
86
|
+
/**
|
|
87
|
+
* Whose presets it shows: a tab or group's (see `ControlsOptions.scopedPresets`), `""` for the
|
|
88
|
+
* panel's own, or null for none (the strip hides).
|
|
89
|
+
*/
|
|
90
|
+
scopeOf?: () => string | null): PresetStrip;
|
package/dist/types/ui/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { confirm, type ConfirmOptions } from "./confirm.js";
|
|
|
4
4
|
export { overlayLook, type Anchor } from "./layer.js";
|
|
5
5
|
export { assignPageCodes, hints, pageHints, type HintPainter, type HintSourceOptions, type PageHints, type PageHintTarget, } from "../panel/page-hints.js";
|
|
6
6
|
export { fuzzy, inTriangle, marks, matchItem, place, safeTriangle, stepItem, rank, type Box, type FuzzyMatch, type Placed, type Placement, type Ranked, type Side, } from "./overlay-model.js";
|
|
7
|
-
export { commandPalette, type Command, type CommandPalette, type CommandPaletteOptions, } from "./palette.js";
|
|
7
|
+
export { commandPalette, type Command, type CommandPalette, type CommandPaletteOptions, type PalettePresence, } from "./palette.js";
|
|
8
8
|
export { contextMenu, menu, type ContextMenu, type ContextMenuOptions, type Menu, type MenuCloseReason, type MenuEntry, type MenuItem, type MenuOptions, } from "./menu.js";
|
|
9
9
|
export { popover, type Popover, type PopoverCloseReason, type PopoverOptions } from "./popover.js";
|
|
10
10
|
export { readout, type Readout } from "./readouts.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { UiLook } from "./look.js";
|
|
2
|
+
import { type PresenceOptions } from "./layer.js";
|
|
2
3
|
export interface Command {
|
|
3
4
|
/** Stable across sessions (recents remember it); the label by default. */
|
|
4
5
|
readonly id?: string;
|
|
@@ -25,9 +26,23 @@ export interface CommandPaletteOptions {
|
|
|
25
26
|
readonly placeholder?: string;
|
|
26
27
|
/** Recent commands are remembered under this key in localStorage; `false` remembers nothing. */
|
|
27
28
|
readonly recents?: string | false;
|
|
29
|
+
/**
|
|
30
|
+
* How it comes and goes: `"fade"` (opacity over about 80 ms, the default), `"none"` or `false`
|
|
31
|
+
* (at once), or a spring of your own. Fields you leave out are the full entrance: grows from
|
|
32
|
+
* .96, sharpens from 8 px, drops 8 px, over .34 s; it leaves in .2 s at most.
|
|
33
|
+
*/
|
|
34
|
+
readonly presence?: PalettePresence;
|
|
28
35
|
readonly look?: UiLook;
|
|
29
36
|
readonly doc?: Document;
|
|
30
37
|
}
|
|
38
|
+
export type PalettePresence = "fade" | "none" | false | {
|
|
39
|
+
readonly duration?: number;
|
|
40
|
+
readonly scale?: number;
|
|
41
|
+
readonly blur?: number;
|
|
42
|
+
readonly dy?: number;
|
|
43
|
+
};
|
|
44
|
+
/** The layer motion for a `presence` option; null for none. */
|
|
45
|
+
export declare function palettePresence(p?: PalettePresence): PresenceOptions | null;
|
|
31
46
|
export interface CommandPalette {
|
|
32
47
|
open(query?: string): void;
|
|
33
48
|
close(): void;
|
|
@@ -50,8 +50,11 @@ export interface NavResult {
|
|
|
50
50
|
readonly expanded: boolean;
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
|
-
/**
|
|
54
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Roving focus: ↑↓ move, ← closes or goes to the parent, → opens or goes to the first child.
|
|
55
|
+
* Right to left, ← and → swap.
|
|
56
|
+
*/
|
|
57
|
+
export declare function navigate<T>(rows: readonly FlatRow<T>[], active: string | null, pressed: NavKey | "PageUp" | "PageDown", page?: number, dir?: "ltr" | "rtl"): NavResult;
|
|
55
58
|
/**
|
|
56
59
|
* Type-ahead: the next row whose label starts with what's been typed, after the active one (or
|
|
57
60
|
* from it, once the word is longer than a letter, so typing on refines in place).
|
package/dist/ui-react.js
CHANGED
|
@@ -5046,7 +5046,8 @@ function ancestors(index, id) {
|
|
|
5046
5046
|
out.push(p);
|
|
5047
5047
|
return out;
|
|
5048
5048
|
}
|
|
5049
|
-
function navigate(rows, active,
|
|
5049
|
+
function navigate(rows, active, pressed, page = 10, dir = "ltr") {
|
|
5050
|
+
const key = dir === "rtl" && (pressed === "ArrowLeft" || pressed === "ArrowRight") ? pressed === "ArrowLeft" ? "ArrowRight" : "ArrowLeft" : pressed;
|
|
5050
5051
|
if (rows.length === 0)
|
|
5051
5052
|
return { active: null };
|
|
5052
5053
|
const i = active === null ? -1 : rows.findIndex((r) => r.id === active);
|
|
@@ -5929,7 +5930,8 @@ function tree(container, options) {
|
|
|
5929
5930
|
options.onMove(move);
|
|
5930
5931
|
} else if (nav.includes(e.key) && !e.metaKey && !e.ctrlKey) {
|
|
5931
5932
|
const page = Math.max(1, Math.floor(viewport() / h) - 1);
|
|
5932
|
-
const
|
|
5933
|
+
const dir = win.getComputedStyle(root).direction === "rtl" ? "rtl" : "ltr";
|
|
5934
|
+
const r = navigate(rows, active, e.key, page, dir);
|
|
5933
5935
|
if (r.toggle)
|
|
5934
5936
|
toggle(r.toggle.id, r.toggle.expanded);
|
|
5935
5937
|
else if (r.active) {
|
|
@@ -7643,7 +7645,7 @@ function presence(el, o = {}) {
|
|
|
7643
7645
|
});
|
|
7644
7646
|
const tune = (seconds, zeta) => {
|
|
7645
7647
|
const reduced = reducedMotion(win);
|
|
7646
|
-
spring.omega = 2 * Math.PI / (reduced ? FADE.duration : seconds);
|
|
7648
|
+
spring.omega = 2 * Math.PI / (reduced ? Math.min(FADE.duration, seconds) : seconds);
|
|
7647
7649
|
spring.zeta = reduced ? 1 : zeta;
|
|
7648
7650
|
};
|
|
7649
7651
|
render();
|
package/dist/ui-solid.js
CHANGED
|
@@ -5045,7 +5045,8 @@ function ancestors(index, id) {
|
|
|
5045
5045
|
out.push(p);
|
|
5046
5046
|
return out;
|
|
5047
5047
|
}
|
|
5048
|
-
function navigate(rows, active,
|
|
5048
|
+
function navigate(rows, active, pressed, page = 10, dir = "ltr") {
|
|
5049
|
+
const key = dir === "rtl" && (pressed === "ArrowLeft" || pressed === "ArrowRight") ? pressed === "ArrowLeft" ? "ArrowRight" : "ArrowLeft" : pressed;
|
|
5049
5050
|
if (rows.length === 0)
|
|
5050
5051
|
return { active: null };
|
|
5051
5052
|
const i = active === null ? -1 : rows.findIndex((r) => r.id === active);
|
|
@@ -5928,7 +5929,8 @@ function tree(container, options) {
|
|
|
5928
5929
|
options.onMove(move);
|
|
5929
5930
|
} else if (nav.includes(e.key) && !e.metaKey && !e.ctrlKey) {
|
|
5930
5931
|
const page = Math.max(1, Math.floor(viewport() / h) - 1);
|
|
5931
|
-
const
|
|
5932
|
+
const dir = win.getComputedStyle(root).direction === "rtl" ? "rtl" : "ltr";
|
|
5933
|
+
const r = navigate(rows, active, e.key, page, dir);
|
|
5932
5934
|
if (r.toggle)
|
|
5933
5935
|
toggle(r.toggle.id, r.toggle.expanded);
|
|
5934
5936
|
else if (r.active) {
|
|
@@ -7642,7 +7644,7 @@ function presence(el, o = {}) {
|
|
|
7642
7644
|
});
|
|
7643
7645
|
const tune = (seconds, zeta) => {
|
|
7644
7646
|
const reduced = reducedMotion(win);
|
|
7645
|
-
spring.omega = 2 * Math.PI / (reduced ? FADE.duration : seconds);
|
|
7647
|
+
spring.omega = 2 * Math.PI / (reduced ? Math.min(FADE.duration, seconds) : seconds);
|
|
7646
7648
|
spring.zeta = reduced ? 1 : zeta;
|
|
7647
7649
|
};
|
|
7648
7650
|
render();
|
package/dist/ui.js
CHANGED
|
@@ -3244,7 +3244,7 @@ function presence(el, o = {}) {
|
|
|
3244
3244
|
});
|
|
3245
3245
|
const tune = (seconds, zeta) => {
|
|
3246
3246
|
const reduced = reducedMotion(win);
|
|
3247
|
-
spring.omega = 2 * Math.PI / (reduced ? FADE.duration : seconds);
|
|
3247
|
+
spring.omega = 2 * Math.PI / (reduced ? Math.min(FADE.duration, seconds) : seconds);
|
|
3248
3248
|
spring.zeta = reduced ? 1 : zeta;
|
|
3249
3249
|
};
|
|
3250
3250
|
render();
|
|
@@ -4708,7 +4708,8 @@ function ancestors(index, id) {
|
|
|
4708
4708
|
out.push(p);
|
|
4709
4709
|
return out;
|
|
4710
4710
|
}
|
|
4711
|
-
function navigate(rows, active,
|
|
4711
|
+
function navigate(rows, active, pressed, page = 10, dir = "ltr") {
|
|
4712
|
+
const key = dir === "rtl" && (pressed === "ArrowLeft" || pressed === "ArrowRight") ? pressed === "ArrowLeft" ? "ArrowRight" : "ArrowLeft" : pressed;
|
|
4712
4713
|
if (rows.length === 0)
|
|
4713
4714
|
return { active: null };
|
|
4714
4715
|
const i = active === null ? -1 : rows.findIndex((r) => r.id === active);
|
|
@@ -10649,7 +10650,8 @@ function tree(container, options) {
|
|
|
10649
10650
|
options.onMove(move);
|
|
10650
10651
|
} else if (nav.includes(e.key) && !e.metaKey && !e.ctrlKey) {
|
|
10651
10652
|
const page = Math.max(1, Math.floor(viewport() / h) - 1);
|
|
10652
|
-
const
|
|
10653
|
+
const dir = win.getComputedStyle(root).direction === "rtl" ? "rtl" : "ltr";
|
|
10654
|
+
const r = navigate(rows, active, e.key, page, dir);
|
|
10653
10655
|
if (r.toggle)
|
|
10654
10656
|
toggle(r.toggle.id, r.toggle.expanded);
|
|
10655
10657
|
else if (r.active) {
|
|
@@ -13426,6 +13428,22 @@ function toast(message, options = {}) {
|
|
|
13426
13428
|
}
|
|
13427
13429
|
|
|
13428
13430
|
// src/ui/palette.ts
|
|
13431
|
+
var FADE_SECONDS = 0.08;
|
|
13432
|
+
function palettePresence(p = "fade") {
|
|
13433
|
+
if (p === false || p === "none")
|
|
13434
|
+
return null;
|
|
13435
|
+
if (p === "fade")
|
|
13436
|
+
return { scale: 1, blur: 0, dy: 0, duration: FADE_SECONDS, exit: FADE_SECONDS, bounce: 0 };
|
|
13437
|
+
const duration = p.duration ?? 0.34;
|
|
13438
|
+
return {
|
|
13439
|
+
scale: p.scale ?? 0.96,
|
|
13440
|
+
blur: p.blur ?? 8,
|
|
13441
|
+
dy: p.dy ?? -8,
|
|
13442
|
+
duration,
|
|
13443
|
+
exit: Math.min(0.2, duration),
|
|
13444
|
+
bounce: 0
|
|
13445
|
+
};
|
|
13446
|
+
}
|
|
13429
13447
|
var idOf = (c) => c.id ?? c.label;
|
|
13430
13448
|
var MAX_RECENT = 5;
|
|
13431
13449
|
var MAX_SHOWN = 200;
|
|
@@ -13433,6 +13451,7 @@ function commandPalette(options) {
|
|
|
13433
13451
|
const doc = options.doc ?? document;
|
|
13434
13452
|
const win = doc.defaultView;
|
|
13435
13453
|
const hotkey = options.hotkey === undefined ? "Mod+K" : options.hotkey;
|
|
13454
|
+
const motionOptions = palettePresence(options.presence);
|
|
13436
13455
|
const storeKey = options.recents === false ? null : `knobs-palette:${options.recents ?? "recent"}`;
|
|
13437
13456
|
const readRecents = () => {
|
|
13438
13457
|
if (!storeKey)
|
|
@@ -13662,7 +13681,7 @@ function commandPalette(options) {
|
|
|
13662
13681
|
const layer = el;
|
|
13663
13682
|
const giveBack = focusReturn(doc, layer);
|
|
13664
13683
|
const commands = typeof options.commands === "function" ? options.commands() : options.commands;
|
|
13665
|
-
const motion = presence(layer,
|
|
13684
|
+
const motion = motionOptions ? presence(layer, motionOptions) : null;
|
|
13666
13685
|
state = {
|
|
13667
13686
|
input,
|
|
13668
13687
|
list,
|
|
@@ -13700,7 +13719,7 @@ function commandPalette(options) {
|
|
|
13700
13719
|
runAt(state.active);
|
|
13701
13720
|
}
|
|
13702
13721
|
});
|
|
13703
|
-
motion
|
|
13722
|
+
motion?.show();
|
|
13704
13723
|
input.focus({ preventScroll: true });
|
|
13705
13724
|
input.select();
|
|
13706
13725
|
};
|
|
@@ -13713,7 +13732,10 @@ function commandPalette(options) {
|
|
|
13713
13732
|
el = null;
|
|
13714
13733
|
s.unstack();
|
|
13715
13734
|
s.giveBack();
|
|
13716
|
-
s.motion
|
|
13735
|
+
if (s.motion)
|
|
13736
|
+
s.motion.hide().then(() => layer.remove());
|
|
13737
|
+
else
|
|
13738
|
+
layer.remove();
|
|
13717
13739
|
};
|
|
13718
13740
|
const onKey = (e) => {
|
|
13719
13741
|
if (!hotkey || !matchesCombo(hotkey, e))
|