@kitlangton/knobs 0.4.0-next.11 → 0.4.0-next.13
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 +117 -21
- package/dist/dev/{chunk-75gbzbyd.js → chunk-44r02asc.js} +2 -5
- package/dist/dev/{chunk-mjdgzad5.js → chunk-7kns3qe6.js} +29 -25
- package/dist/dev/{chunk-bnhzf1tj.js → chunk-mbhy4jg5.js} +1453 -1097
- package/dist/dev/{chunk-j57rhjtm.js → chunk-pdf3zy95.js} +95 -42
- package/dist/dev/index.js +188 -63
- package/dist/index.js +211 -60
- package/dist/panel.js +2699 -2149
- package/dist/review-react.js +8 -4
- package/dist/review-solid.js +10 -5
- package/dist/review.js +8 -4
- package/dist/types/core/remote.d.ts +10 -2
- package/dist/types/core/schema.d.ts +52 -4
- package/dist/types/core/store.d.ts +45 -8
- package/dist/types/core/variants.d.ts +3 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/panel/dock.d.ts +9 -0
- package/dist/types/panel/gpu/renderer.d.ts +11 -1
- package/dist/types/panel/inspector.d.ts +11 -3
- package/dist/types/panel/presets.d.ts +26 -4
- package/dist/types/panel/scope.d.ts +15 -4
- package/dist/types/ui/canvas-css.d.ts +1 -0
- package/dist/types/ui/canvas-model.d.ts +116 -0
- package/dist/types/ui/canvas.d.ts +66 -0
- package/dist/types/ui/index.d.ts +2 -0
- package/dist/types/ui/react.d.ts +12 -0
- package/dist/types/ui/solid.d.ts +9 -0
- package/dist/ui-react.js +1020 -17
- package/dist/ui-solid.js +1032 -25
- package/dist/ui.js +986 -4
- package/package.json +1 -1
package/dist/review-react.js
CHANGED
|
@@ -2965,13 +2965,17 @@ var css2 = `
|
|
|
2965
2965
|
.knobs-tree-row[aria-expanded="true"]>.knobs-tree-caret{transform:rotate(90deg)}
|
|
2966
2966
|
.knobs-tree-row:not([aria-expanded])>.knobs-tree-caret{visibility:hidden}
|
|
2967
2967
|
.knobs-tree-icon{flex:none;display:flex;align-items:center;justify-content:center;width:14px;margin-right:6px;color:var(--_k-fg-3);font-size:calc(var(--_k-font-size) - 1px)}
|
|
2968
|
-
|
|
2968
|
+
/* The label wins the room: it keeps its width while the detail (which only takes what's left)
|
|
2969
|
+
fades out at its end, and gives way only once the detail is gone. Each fades where it's cut. */
|
|
2970
|
+
.knobs-tree-label{position:relative;flex:0 1 auto;min-width:0;overflow:hidden;font-weight:var(--_k-weight)}
|
|
2971
|
+
.knobs-tree-row[data-editing]>.knobs-tree-label{flex-grow:1}
|
|
2969
2972
|
.knobs-tree-row[data-ancestor] .knobs-tree-label{color:var(--_k-fg-2)}
|
|
2970
2973
|
.knobs-tree-label .knobs-tree-mark{color:var(--_k-accent)}
|
|
2971
2974
|
.knobs-tree-row[data-off~="visible"] :is(.knobs-tree-label,.knobs-tree-icon){opacity:.45}
|
|
2972
2975
|
.knobs-tree-row[data-off~="locked"] .knobs-tree-label{color:var(--_k-fg-2)}
|
|
2973
|
-
.knobs-tree-detail{flex:
|
|
2974
|
-
.knobs-tree-
|
|
2976
|
+
.knobs-tree-detail{flex:1 1 0;min-width:0;overflow:hidden;padding-left:6px;text-align:right;color:var(--_k-fg-3);font-variant-numeric:tabular-nums}
|
|
2977
|
+
.knobs-tree-row[data-editing]>.knobs-tree-detail{flex-grow:0;visibility:hidden}
|
|
2978
|
+
.knobs-tree-tools{flex:none;display:flex;align-items:center;gap:1px;margin-left:auto;padding-left:4px}
|
|
2975
2979
|
.knobs-ui .knobs-tree-toggle{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:calc(var(--_k-radius) * 999);color:var(--_k-fg-3);cursor:pointer;opacity:0;transition:opacity .12s,color .12s,background .12s}
|
|
2976
2980
|
.knobs-ui .knobs-tree-toggle svg{width:12px;height:12px}
|
|
2977
2981
|
.knobs-tree-row:is(:hover,[data-active],[aria-selected="true"]) .knobs-tree-toggle,.knobs-ui .knobs-tree-toggle[aria-pressed="false"]{opacity:1}
|
|
@@ -5327,7 +5331,7 @@ function tree(container, options) {
|
|
|
5327
5331
|
text.className = "knobs-tree-text";
|
|
5328
5332
|
label.append(text);
|
|
5329
5333
|
const detail = doc.createElement("span");
|
|
5330
|
-
detail.className = "knobs-tree-detail";
|
|
5334
|
+
detail.className = "knobs-tree-detail knobs-scroll-fade-x";
|
|
5331
5335
|
const tools = doc.createElement("span");
|
|
5332
5336
|
tools.className = "knobs-tree-tools";
|
|
5333
5337
|
el.append(caret, icon, label, detail, tools);
|
package/dist/review-solid.js
CHANGED
|
@@ -2964,13 +2964,17 @@ var css2 = `
|
|
|
2964
2964
|
.knobs-tree-row[aria-expanded="true"]>.knobs-tree-caret{transform:rotate(90deg)}
|
|
2965
2965
|
.knobs-tree-row:not([aria-expanded])>.knobs-tree-caret{visibility:hidden}
|
|
2966
2966
|
.knobs-tree-icon{flex:none;display:flex;align-items:center;justify-content:center;width:14px;margin-right:6px;color:var(--_k-fg-3);font-size:calc(var(--_k-font-size) - 1px)}
|
|
2967
|
-
|
|
2967
|
+
/* The label wins the room: it keeps its width while the detail (which only takes what's left)
|
|
2968
|
+
fades out at its end, and gives way only once the detail is gone. Each fades where it's cut. */
|
|
2969
|
+
.knobs-tree-label{position:relative;flex:0 1 auto;min-width:0;overflow:hidden;font-weight:var(--_k-weight)}
|
|
2970
|
+
.knobs-tree-row[data-editing]>.knobs-tree-label{flex-grow:1}
|
|
2968
2971
|
.knobs-tree-row[data-ancestor] .knobs-tree-label{color:var(--_k-fg-2)}
|
|
2969
2972
|
.knobs-tree-label .knobs-tree-mark{color:var(--_k-accent)}
|
|
2970
2973
|
.knobs-tree-row[data-off~="visible"] :is(.knobs-tree-label,.knobs-tree-icon){opacity:.45}
|
|
2971
2974
|
.knobs-tree-row[data-off~="locked"] .knobs-tree-label{color:var(--_k-fg-2)}
|
|
2972
|
-
.knobs-tree-detail{flex:
|
|
2973
|
-
.knobs-tree-
|
|
2975
|
+
.knobs-tree-detail{flex:1 1 0;min-width:0;overflow:hidden;padding-left:6px;text-align:right;color:var(--_k-fg-3);font-variant-numeric:tabular-nums}
|
|
2976
|
+
.knobs-tree-row[data-editing]>.knobs-tree-detail{flex-grow:0;visibility:hidden}
|
|
2977
|
+
.knobs-tree-tools{flex:none;display:flex;align-items:center;gap:1px;margin-left:auto;padding-left:4px}
|
|
2974
2978
|
.knobs-ui .knobs-tree-toggle{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:calc(var(--_k-radius) * 999);color:var(--_k-fg-3);cursor:pointer;opacity:0;transition:opacity .12s,color .12s,background .12s}
|
|
2975
2979
|
.knobs-ui .knobs-tree-toggle svg{width:12px;height:12px}
|
|
2976
2980
|
.knobs-tree-row:is(:hover,[data-active],[aria-selected="true"]) .knobs-tree-toggle,.knobs-ui .knobs-tree-toggle[aria-pressed="false"]{opacity:1}
|
|
@@ -5326,7 +5330,7 @@ function tree(container, options) {
|
|
|
5326
5330
|
text.className = "knobs-tree-text";
|
|
5327
5331
|
label.append(text);
|
|
5328
5332
|
const detail = doc.createElement("span");
|
|
5329
|
-
detail.className = "knobs-tree-detail";
|
|
5333
|
+
detail.className = "knobs-tree-detail knobs-scroll-fade-x";
|
|
5330
5334
|
const tools = doc.createElement("span");
|
|
5331
5335
|
tools.className = "knobs-tree-tools";
|
|
5332
5336
|
el.append(caret, icon, label, detail, tools);
|
|
@@ -12702,11 +12706,12 @@ var init_player = __esm(() => {
|
|
|
12702
12706
|
|
|
12703
12707
|
// src/ui/solid.ts
|
|
12704
12708
|
import {
|
|
12705
|
-
children,
|
|
12706
12709
|
createEffect,
|
|
12710
|
+
createMemo,
|
|
12707
12711
|
createRoot,
|
|
12708
12712
|
getOwner,
|
|
12709
12713
|
onCleanup,
|
|
12714
|
+
splitProps,
|
|
12710
12715
|
untrack
|
|
12711
12716
|
} from "solid-js";
|
|
12712
12717
|
import { insert } from "solid-js/web";
|
package/dist/review.js
CHANGED
|
@@ -3006,13 +3006,17 @@ var css2 = `
|
|
|
3006
3006
|
.knobs-tree-row[aria-expanded="true"]>.knobs-tree-caret{transform:rotate(90deg)}
|
|
3007
3007
|
.knobs-tree-row:not([aria-expanded])>.knobs-tree-caret{visibility:hidden}
|
|
3008
3008
|
.knobs-tree-icon{flex:none;display:flex;align-items:center;justify-content:center;width:14px;margin-right:6px;color:var(--_k-fg-3);font-size:calc(var(--_k-font-size) - 1px)}
|
|
3009
|
-
|
|
3009
|
+
/* The label wins the room: it keeps its width while the detail (which only takes what's left)
|
|
3010
|
+
fades out at its end, and gives way only once the detail is gone. Each fades where it's cut. */
|
|
3011
|
+
.knobs-tree-label{position:relative;flex:0 1 auto;min-width:0;overflow:hidden;font-weight:var(--_k-weight)}
|
|
3012
|
+
.knobs-tree-row[data-editing]>.knobs-tree-label{flex-grow:1}
|
|
3010
3013
|
.knobs-tree-row[data-ancestor] .knobs-tree-label{color:var(--_k-fg-2)}
|
|
3011
3014
|
.knobs-tree-label .knobs-tree-mark{color:var(--_k-accent)}
|
|
3012
3015
|
.knobs-tree-row[data-off~="visible"] :is(.knobs-tree-label,.knobs-tree-icon){opacity:.45}
|
|
3013
3016
|
.knobs-tree-row[data-off~="locked"] .knobs-tree-label{color:var(--_k-fg-2)}
|
|
3014
|
-
.knobs-tree-detail{flex:
|
|
3015
|
-
.knobs-tree-
|
|
3017
|
+
.knobs-tree-detail{flex:1 1 0;min-width:0;overflow:hidden;padding-left:6px;text-align:right;color:var(--_k-fg-3);font-variant-numeric:tabular-nums}
|
|
3018
|
+
.knobs-tree-row[data-editing]>.knobs-tree-detail{flex-grow:0;visibility:hidden}
|
|
3019
|
+
.knobs-tree-tools{flex:none;display:flex;align-items:center;gap:1px;margin-left:auto;padding-left:4px}
|
|
3016
3020
|
.knobs-ui .knobs-tree-toggle{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:calc(var(--_k-radius) * 999);color:var(--_k-fg-3);cursor:pointer;opacity:0;transition:opacity .12s,color .12s,background .12s}
|
|
3017
3021
|
.knobs-ui .knobs-tree-toggle svg{width:12px;height:12px}
|
|
3018
3022
|
.knobs-tree-row:is(:hover,[data-active],[aria-selected="true"]) .knobs-tree-toggle,.knobs-ui .knobs-tree-toggle[aria-pressed="false"]{opacity:1}
|
|
@@ -10484,7 +10488,7 @@ function tree(container, options) {
|
|
|
10484
10488
|
text.className = "knobs-tree-text";
|
|
10485
10489
|
label.append(text);
|
|
10486
10490
|
const detail = doc.createElement("span");
|
|
10487
|
-
detail.className = "knobs-tree-detail";
|
|
10491
|
+
detail.className = "knobs-tree-detail knobs-scroll-fade-x";
|
|
10488
10492
|
const tools = doc.createElement("span");
|
|
10489
10493
|
tools.className = "knobs-tree-tools";
|
|
10490
10494
|
el.append(caret, icon, label, detail, tools);
|
|
@@ -45,6 +45,8 @@ export interface ToolbarDescriptor extends DescriptorMeta {
|
|
|
45
45
|
readonly global?: boolean;
|
|
46
46
|
readonly disabled?: boolean;
|
|
47
47
|
}[];
|
|
48
|
+
/** `false`: icons only (see `toolbar`). */
|
|
49
|
+
readonly labels?: boolean;
|
|
48
50
|
readonly default?: undefined;
|
|
49
51
|
readonly bind?: undefined;
|
|
50
52
|
}
|
|
@@ -77,11 +79,11 @@ export interface ReadoutDescriptor extends DescriptorMeta {
|
|
|
77
79
|
export type ControlDescriptor = ValueDescriptor | SpringBindingDescriptor | ActionDescriptor | ToolbarDescriptor | ReadoutDescriptor;
|
|
78
80
|
export interface ValueDescriptor extends DescriptorMeta {
|
|
79
81
|
readonly bind?: undefined;
|
|
80
|
-
readonly kind: "knob" | "number" | "choice" | "toggle" | "bool" | "spring" | "color" | "point" | "easing" | "vec2" | "vec3" | "range" | "angle" | "seed" | "keybind" | "gradient" | "curve";
|
|
82
|
+
readonly kind: "knob" | "number" | "choice" | "toggle" | "bool" | "spring" | "color" | "point" | "easing" | "vec2" | "vec3" | "range" | "angle" | "seed" | "keybind" | "text" | "gradient" | "curve";
|
|
81
83
|
/**
|
|
82
84
|
* Springs take `{ duration, bounce }`, colours a CSS string, points and vec2 `{ x, y }`, vec3
|
|
83
85
|
* `{ x, y, z }`, easings `[x1, y1, x2, y2]`, ranges `[low, high]`, keybinds a combination
|
|
84
|
-
* string (`"Meta+K"`), gradients `[{ at, color }]` and curves `[{ x, y }]`.
|
|
86
|
+
* string (`"Meta+K"`), text a string, gradients `[{ at, color }]` and curves `[{ x, y }]`.
|
|
85
87
|
*/
|
|
86
88
|
readonly default: Value;
|
|
87
89
|
readonly min?: number;
|
|
@@ -103,6 +105,10 @@ export interface ValueDescriptor extends DescriptorMeta {
|
|
|
103
105
|
readonly axes?: readonly string[];
|
|
104
106
|
/** Angles: carry past the ends a whole turn (on for a full turn by default). */
|
|
105
107
|
readonly wrap?: boolean;
|
|
108
|
+
/** Text: lines in a box that grows with them (see `text`). */
|
|
109
|
+
readonly multiline?: boolean;
|
|
110
|
+
/** Text: shown in the empty field. */
|
|
111
|
+
readonly placeholder?: string;
|
|
106
112
|
/** Gradients: blend in `oklab` (default) or `srgb`. */
|
|
107
113
|
readonly space?: GradientSpace;
|
|
108
114
|
/** Curves: the y range, `[0, 1]` by default (`min` and `max` work too). */
|
|
@@ -130,6 +136,8 @@ export interface RemoteControlsOptions {
|
|
|
130
136
|
readonly nullDefaults?: boolean;
|
|
131
137
|
readonly values?: State;
|
|
132
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>>>>;
|
|
133
141
|
/** Groups pinned above the tab strip, outside the presets (see `ControlsOptions.pinned`). */
|
|
134
142
|
readonly pinned?: readonly string[];
|
|
135
143
|
/** Numbered presets per group, e.g. the phone's preset sets (see `ControlsOptions.groupPresets`). */
|
|
@@ -101,6 +101,12 @@ export interface Choice<T extends string = string> extends FieldMeta {
|
|
|
101
101
|
* spare and there are at most four options, and a menu otherwise, switching as the width changes.
|
|
102
102
|
*/
|
|
103
103
|
readonly display?: "menu" | "segmented";
|
|
104
|
+
/**
|
|
105
|
+
* The options are versions of the design: each is a preset in the panel's top strip (the
|
|
106
|
+
* default option is the default preset), which is where you switch them, and the choice gets no
|
|
107
|
+
* row of its own. See `choice`.
|
|
108
|
+
*/
|
|
109
|
+
readonly variants?: true;
|
|
104
110
|
}
|
|
105
111
|
export interface Toggle extends FieldMeta {
|
|
106
112
|
readonly kind: "toggle";
|
|
@@ -215,6 +221,15 @@ export interface KeybindField extends FieldMeta {
|
|
|
215
221
|
readonly kind: "keybind";
|
|
216
222
|
readonly value: string;
|
|
217
223
|
}
|
|
224
|
+
/** Words: a name, a caption, a prompt. Typed into a field; `multiline` for a box of lines. */
|
|
225
|
+
export interface TextField extends FieldMeta {
|
|
226
|
+
readonly kind: "text";
|
|
227
|
+
readonly value: string;
|
|
228
|
+
/** Lines (Enter starts a new one) in a box that grows with them; one line otherwise. */
|
|
229
|
+
readonly multiline?: boolean;
|
|
230
|
+
/** Shown in the empty field. */
|
|
231
|
+
readonly placeholder?: string;
|
|
232
|
+
}
|
|
218
233
|
/**
|
|
219
234
|
* A toolbar button's key and where it presses the button: while the panel has focus (`"panel"`),
|
|
220
235
|
* anywhere on the page but a text field (`"page"`), or nowhere (`"none"`: the chip only, for a
|
|
@@ -245,8 +260,10 @@ export interface ToolbarItem {
|
|
|
245
260
|
export interface ToolbarField extends FieldMeta {
|
|
246
261
|
readonly kind: "toolbar";
|
|
247
262
|
readonly items: readonly ToolbarItem[];
|
|
263
|
+
/** `false`: icons only, each label in its tooltip (see `toolbar`). */
|
|
264
|
+
readonly labels?: boolean;
|
|
248
265
|
}
|
|
249
|
-
export type ValueField = Knob | Choice | Toggle | SpringField | ColorField | PointField | EasingField | VecField | RangeField | AngleField | SeedField | KeybindField | GradientField | CurveField;
|
|
266
|
+
export type ValueField = Knob | Choice | Toggle | SpringField | ColorField | PointField | EasingField | VecField | RangeField | AngleField | SeedField | KeybindField | TextField | GradientField | CurveField;
|
|
250
267
|
/** A readout's own: polled while its row shows, instead of pushed with `controls.watch`. */
|
|
251
268
|
interface ReadoutMeta extends FieldMeta {
|
|
252
269
|
/** Read each frame while the row is on screen (pushing with `controls.watch` is the other way). */
|
|
@@ -335,12 +352,20 @@ export declare const isReadout: (field: {
|
|
|
335
352
|
/** Whether a field holds a value (actions, toolbars and readouts don't). */
|
|
336
353
|
export declare const hasValue: (field: Field) => field is ValueField;
|
|
337
354
|
export type Schema = Readonly<Record<string, Field>>;
|
|
355
|
+
/**
|
|
356
|
+
* The schema's variants choice (`choice(…, { variants: true })`), if it has one. A pinned choice
|
|
357
|
+
* (`isPinned`) is never the variants choice: pinned wins, and it stays an ordinary choice.
|
|
358
|
+
*/
|
|
359
|
+
export declare function variantsOf(schema: Schema, isPinned?: (key: string) => boolean): {
|
|
360
|
+
key: string;
|
|
361
|
+
field: Choice;
|
|
362
|
+
} | undefined;
|
|
338
363
|
/**
|
|
339
364
|
* The schema's pinned keys (values, actions and readouts alike): every key of a group in `groups`,
|
|
340
365
|
* or whose first field that gives `pinned` says `true`, and ungrouped fields that say so themselves.
|
|
341
366
|
*/
|
|
342
367
|
export declare function pinnedKeys(schema: Schema, groups?: readonly string[]): ReadonlySet<string>;
|
|
343
|
-
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 ? string : F extends GradientField ? readonly GradientStop[] : F extends CurveField ? readonly CurvePoint[] : never;
|
|
368
|
+
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;
|
|
344
369
|
/** The keys of a schema's readouts (what `controls.watch` takes). */
|
|
345
370
|
export type ReadoutKeys<S extends Schema> = {
|
|
346
371
|
[K in keyof S]: [S[K] & ReadoutField] extends [never] ? never : K;
|
|
@@ -371,9 +396,17 @@ export declare function valueKeys(schema: Schema): string[];
|
|
|
371
396
|
export declare function knob(value: number, options: Omit<Knob, "kind" | "value" | "step"> & {
|
|
372
397
|
step?: number;
|
|
373
398
|
}): Knob;
|
|
399
|
+
/**
|
|
400
|
+
* `choice("glass", ["glass", "solid", "flat"])`: one of a set of options, as segments or a menu.
|
|
401
|
+
* With `variants: true` the options are versions of the design instead: each becomes a preset in
|
|
402
|
+
* the panel's top strip (the default option is the default preset, the others follow in order),
|
|
403
|
+
* the choice has no row, and Random leaves it be. The store's `presets` add values to a variant
|
|
404
|
+
* by its option (`{ Roll: { speed: 0.8 } }`).
|
|
405
|
+
*/
|
|
374
406
|
export declare function choice<const T extends readonly [string, ...string[]]>(value: T[number], options: T, meta?: FieldMeta & {
|
|
375
407
|
readonly labels?: Readonly<Partial<Record<T[number], string>>>;
|
|
376
408
|
readonly display?: "menu" | "segmented";
|
|
409
|
+
readonly variants?: boolean;
|
|
377
410
|
}): Choice<T[number]>;
|
|
378
411
|
/**
|
|
379
412
|
* `action("Replay", { run, shortcut: "Shift+K", global: true, rebind: true })`: a button row. Its
|
|
@@ -477,6 +510,15 @@ export declare function seed(value: number, options?: FieldMeta & {
|
|
|
477
510
|
}): SeedField;
|
|
478
511
|
/** A key combination captured by pressing it (`"Meta+Shift+K"`, `""` for none). */
|
|
479
512
|
export declare function keybind(value?: string, meta?: FieldMeta): KeybindField;
|
|
513
|
+
/**
|
|
514
|
+
* Words typed into a field: `text("Hello")`, `text("", { multiline: true, placeholder: "Notes" })`.
|
|
515
|
+
* One line unless `multiline` (a line break typed or set there becomes a space). Out of Random
|
|
516
|
+
* and Mutate.
|
|
517
|
+
*/
|
|
518
|
+
export declare function text(value?: string, options?: FieldMeta & {
|
|
519
|
+
multiline?: boolean;
|
|
520
|
+
placeholder?: string;
|
|
521
|
+
}): TextField;
|
|
480
522
|
/**
|
|
481
523
|
* Colour over a 0…1 parameter: `gradient([{ at: 0, color: "#fff4d6" }, { at: 1, color: "#20242c" }])`.
|
|
482
524
|
* Colours take what `color` takes and are kept as `oklch()` strings. `space` blends in `oklab`
|
|
@@ -515,8 +557,14 @@ type ResolvedShortcut = {
|
|
|
515
557
|
export declare function toolbarShortcut(item: ToolbarItem): ResolvedShortcut | undefined;
|
|
516
558
|
/** An action row's shortcut as `{ key, scope }`, or undefined without one. */
|
|
517
559
|
export declare function actionShortcut(field: ActionField): ResolvedShortcut | undefined;
|
|
518
|
-
/**
|
|
519
|
-
|
|
560
|
+
/**
|
|
561
|
+
* A wrapping row of buttons with icons and shortcut chips; holds no value. When every item has an
|
|
562
|
+
* icon and the labels don't fit on one row, it's one row of icons, each label in its tooltip;
|
|
563
|
+
* `labels: false` always shows icons only, `labels: true` always shows the labels.
|
|
564
|
+
*/
|
|
565
|
+
export declare function toolbar(items: readonly ToolbarItem[], meta?: FieldMeta & {
|
|
566
|
+
readonly labels?: boolean;
|
|
567
|
+
}): ToolbarField;
|
|
520
568
|
type ReadoutOptions = Omit<ReadoutMeta, "shortcut" | "random" | "readOnly">;
|
|
521
569
|
/** A live value: `watch({ label: "FPS", decimals: 0 })`, then `controls.watch("fps", 59.9)`. */
|
|
522
570
|
export declare function watch(options?: ReadoutOptions): WatchField;
|
|
@@ -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;
|
|
@@ -169,8 +182,9 @@ export interface MountPanelOptions extends LabelOptions {
|
|
|
169
182
|
*/
|
|
170
183
|
readonly header?: boolean | HeaderOptions;
|
|
171
184
|
/**
|
|
172
|
-
* `
|
|
173
|
-
* `esc ↑ Shape` for where Esc goes).
|
|
185
|
+
* `true` shows a scope line beside the title (`Shape › Cohesion`, where keys go, and a faint
|
|
186
|
+
* `esc ↑ Shape` for where Esc goes). Off by default; the focus lens and the armed frame show
|
|
187
|
+
* either way.
|
|
174
188
|
*/
|
|
175
189
|
readonly crumbs?: boolean;
|
|
176
190
|
/**
|
|
@@ -243,6 +257,13 @@ export interface MountPanelOptions extends LabelOptions {
|
|
|
243
257
|
readonly density?: DensityMode;
|
|
244
258
|
readonly renderer?: RendererMode;
|
|
245
259
|
readonly variants?: boolean;
|
|
260
|
+
/**
|
|
261
|
+
* The presets as chips in a tray (`"chips"`) or as rows like a menu's (`"list"`). `"auto"` (the
|
|
262
|
+
* default) shows chips while they fit on two lines and the list once they'd take more.
|
|
263
|
+
*/
|
|
264
|
+
readonly presetDisplay?: "auto" | "list" | "chips";
|
|
265
|
+
/** Shown in the panel's quiet style while it has no rows (`"This story has no controls"`). */
|
|
266
|
+
readonly empty?: string;
|
|
246
267
|
readonly history?: boolean;
|
|
247
268
|
readonly footer?: boolean;
|
|
248
269
|
readonly actions?: readonly ControlAction<any>[];
|
|
@@ -348,6 +369,14 @@ export interface ControlsOptions<S extends Schema> extends LabelOptions {
|
|
|
348
369
|
/** An undo stack the host owns; undo and redo call it (see `HostHistory`). */
|
|
349
370
|
history?: HostHistory;
|
|
350
371
|
presets?: Readonly<Record<string, Partial<Values<S>>>>;
|
|
372
|
+
/**
|
|
373
|
+
* Presets that belong to one tab or group, keyed by its id: `{ Sidebars: { snappy: {…} } }`.
|
|
374
|
+
* Each shows its own strip on that tab (a tab without any shows none), moves only that tab's
|
|
375
|
+
* or group's keys, and has its own active preset, modified mark and saved variants. A variants
|
|
376
|
+
* choice on a tab adds its options to that tab's. `presets` then covers only the keys no scope
|
|
377
|
+
* holds; leave it out and only the scoped strips show.
|
|
378
|
+
*/
|
|
379
|
+
scopedPresets?: Readonly<Record<string, Readonly<Record<string, Partial<Values<S>>>>>>;
|
|
351
380
|
/**
|
|
352
381
|
* Groups pinned to the top of a panel, under the header and above the tab strip, on every tab
|
|
353
382
|
* (as fields' `pinned: true` pins theirs). Presets and saved variants leave them alone: applying
|
|
@@ -401,6 +430,10 @@ export interface Controls<S extends Schema = Schema> {
|
|
|
401
430
|
readonly persist: PersistMode;
|
|
402
431
|
readonly presets: Readonly<Record<string, Values<S>>>;
|
|
403
432
|
readonly variants: Variants<Values<S>>;
|
|
433
|
+
/** The tabs and groups with presets of their own, by id (see `ControlsOptions.scopedPresets`). */
|
|
434
|
+
readonly scopes: Readonly<Record<string, PresetScope<Values<S>>>>;
|
|
435
|
+
/** The scope `key`'s presets come from: a tab or group's id, `""` for `presets`, or undefined when pinned. */
|
|
436
|
+
scopeOf(key: string): string | undefined;
|
|
404
437
|
readonly actions: readonly ControlAction<Values<S>>[];
|
|
405
438
|
/** Its panels' theme, as given (see `ControlsOptions.theme`). */
|
|
406
439
|
readonly theme: Theme | ThemeMode | undefined;
|
|
@@ -430,8 +463,8 @@ export interface Controls<S extends Schema = Schema> {
|
|
|
430
463
|
readonly groupFolded: Readonly<Record<string, boolean>> | undefined;
|
|
431
464
|
/** How a page's sections start (`sectionFolded`), as given. */
|
|
432
465
|
readonly sectionFolded: SectionFolded | undefined;
|
|
433
|
-
/** A preset's display label (`presetLabels`, `defaultLabel`), else its id
|
|
434
|
-
presetLabel(id: string): string;
|
|
466
|
+
/** A preset's display label (`presetLabels`, `defaultLabel`), else its id; `scope` as in `preset`. */
|
|
467
|
+
presetLabel(id: string, scope?: string): string;
|
|
435
468
|
/** Whether `key` is pinned (its group is, see `ControlsOptions.pinned`), outside the presets. */
|
|
436
469
|
isPinned(key: string): boolean;
|
|
437
470
|
readonly error: string | null;
|
|
@@ -548,17 +581,21 @@ export interface Controls<S extends Schema = Schema> {
|
|
|
548
581
|
readonly comparing: boolean;
|
|
549
582
|
/**
|
|
550
583
|
* Applies a preset and makes it the active one (`"default"` clears it); one undo step, or
|
|
551
|
-
* folded into the last with `coalesce` (a pan across the strip).
|
|
584
|
+
* folded into the last with `coalesce` (a pan across the strip). With `scope`, one of that tab
|
|
585
|
+
* or group's presets, which moves only its keys.
|
|
552
586
|
*/
|
|
553
587
|
preset(id: string, options?: {
|
|
554
588
|
coalesce?: boolean;
|
|
589
|
+
scope?: string;
|
|
555
590
|
}): void;
|
|
556
|
-
|
|
591
|
+
/** The preset the current values match (in `scope`, over its keys), else `"custom"`. */
|
|
592
|
+
matchingPreset(scope?: string): string;
|
|
557
593
|
/**
|
|
558
594
|
* The preset (or saved variant) last applied, which Reset returns to and Random explores
|
|
559
|
-
* around, or null. Kept with the values; forgotten by a reset to the defaults.
|
|
595
|
+
* around, or null. Kept with the values; forgotten by a reset to the defaults. With `scope`,
|
|
596
|
+
* that tab or group's.
|
|
560
597
|
*/
|
|
561
|
-
activePreset(): PresetRef | null;
|
|
598
|
+
activePreset(scope?: string): PresetRef | null;
|
|
562
599
|
/** The group preset last applied to `group` (0-based), or -1. */
|
|
563
600
|
activeGroupPreset(group: string): number;
|
|
564
601
|
/** 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>>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { knob, choice, toggle, spring, color, point, easing, action, flatSpring, vec2, vec3, range, angle, seed, keybind, gradient, curve, toolbar, toolbarShortcut, actionShortcut, watch, sparkline, graph, meter, table, log, hasValue, isReadout, wrapAngle, SPRING, type FieldMeta, type ActionField, type SpringPart, type ValueField, type Knob, type Choice, type Toggle, type SpringField, type ColorField, type PointField, type EasingField, type VecField, type Vec3, type RangeField, type AngleField, type SeedField, type KeybindField, type GradientField, type CurveField, type ToolbarField, type ToolbarItem, type ToolbarShortcut, type WatchField, type SparklineField, type GraphField, type GraphSeries, type GraphThreshold, type MeterField, type TableField, type LogField, type ReadoutField, type ReadoutKeys, type ReadoutInput, type Point, type Field, type Schema, type Values, type Value, type State, } from "./core/schema.js";
|
|
1
|
+
export { knob, choice, toggle, spring, color, point, easing, action, flatSpring, vec2, vec3, range, angle, seed, keybind, text, gradient, curve, toolbar, toolbarShortcut, actionShortcut, watch, sparkline, graph, meter, table, log, hasValue, isReadout, wrapAngle, SPRING, type FieldMeta, type ActionField, type SpringPart, type ValueField, type Knob, type Choice, type Toggle, type SpringField, type ColorField, type PointField, type EasingField, type VecField, type Vec3, type RangeField, type AngleField, type SeedField, type KeybindField, type TextField, type GradientField, type CurveField, type ToolbarField, type ToolbarItem, type ToolbarShortcut, type WatchField, type SparklineField, type GraphField, type GraphSeries, type GraphThreshold, type MeterField, type TableField, type LogField, type ReadoutField, type ReadoutKeys, type ReadoutInput, type Point, type Field, type Schema, type Values, type Value, type State, } from "./core/schema.js";
|
|
2
2
|
export { springCss, springMotion, type SpringValue } from "./core/spring.js";
|
|
3
3
|
export { reducedSpring, SPRINGS, type SpringName } from "./core/motion.js";
|
|
4
4
|
export { colorHex, parseColor, type Oklch } from "./core/color.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The header of the knobs/ui split pane `host` sits in, when the pane has one (a title) and no
|
|
3
|
+
* panel's buttons have joined it yet. A panel there with no title of its own puts its buttons in
|
|
4
|
+
* it (after the pane's actions, before its collapse button) rather than drawing a header row
|
|
5
|
+
* that would hold only them: one header per surface.
|
|
6
|
+
*/
|
|
7
|
+
export declare function paneHeadOf(host: HTMLElement): HTMLElement | undefined;
|
|
8
|
+
/** Moves `actions` into the pane header `head`; the returned function takes them back out. */
|
|
9
|
+
export declare function dock(actions: HTMLElement, head: HTMLElement): () => void;
|
|
@@ -333,6 +333,16 @@ export interface GpuKeybindRow {
|
|
|
333
333
|
readonly wave: RowWave;
|
|
334
334
|
isModified(): boolean;
|
|
335
335
|
}
|
|
336
|
+
/** A text row: the canvas draws its label; the field itself is the DOM's, above the canvas. */
|
|
337
|
+
export interface GpuTextRow {
|
|
338
|
+
readonly kind: "text";
|
|
339
|
+
readonly key: string;
|
|
340
|
+
readonly display: string;
|
|
341
|
+
readonly row: HTMLElement;
|
|
342
|
+
readonly labelEl: HTMLElement;
|
|
343
|
+
readonly wave: RowWave;
|
|
344
|
+
isModified(): boolean;
|
|
345
|
+
}
|
|
336
346
|
export interface GpuToolbarRow {
|
|
337
347
|
readonly kind: "toolbar";
|
|
338
348
|
readonly key: string;
|
|
@@ -370,7 +380,7 @@ export interface GpuSubheadRow {
|
|
|
370
380
|
readonly wave: RowWave;
|
|
371
381
|
isModified(): boolean;
|
|
372
382
|
}
|
|
373
|
-
export type GpuRowBinding = GpuReadoutRow | GpuVecRow | GpuRangeRow | GpuAngleRow | GpuSeedRow | GpuKeybindRow | GpuToolbarRow | GpuSubheadRow | GpuActionRow | GpuKnobRow | GpuChoiceRow | GpuToggleRow | GpuSpringRow | GpuColorRow | GpuPointRow | GpuEasingRow | GpuGradientRow | GpuCurveRow;
|
|
383
|
+
export type GpuRowBinding = GpuReadoutRow | GpuVecRow | GpuRangeRow | GpuAngleRow | GpuSeedRow | GpuKeybindRow | GpuTextRow | GpuToolbarRow | GpuSubheadRow | GpuActionRow | GpuKnobRow | GpuChoiceRow | GpuToggleRow | GpuSpringRow | GpuColorRow | GpuPointRow | GpuEasingRow | GpuGradientRow | GpuCurveRow;
|
|
374
384
|
export interface GpuGroupBinding {
|
|
375
385
|
readonly element: HTMLElement;
|
|
376
386
|
readonly labelEl: HTMLElement;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toolbarShortcut, type AngleField, type KeybindField, type Point, type RangeField, type SeedField, type ToolbarField, type ToolbarItem, type Vec3, type VecField } from "../core/schema.js";
|
|
1
|
+
import { toolbarShortcut, type AngleField, type KeybindField, type Point, type TextField, type RangeField, type SeedField, type ToolbarField, type ToolbarItem, type Vec3, type VecField } from "../core/schema.js";
|
|
2
2
|
import { type EditorRow, type RowContext } from "./editors.js";
|
|
3
3
|
type Vec = Point & {
|
|
4
4
|
readonly z?: number;
|
|
@@ -30,6 +30,12 @@ export declare function keyCap(o: {
|
|
|
30
30
|
wake(): void;
|
|
31
31
|
}): KeyCap;
|
|
32
32
|
export declare function keybindRow(c: RowContext<KeybindField>): EditorRow;
|
|
33
|
+
/**
|
|
34
|
+
* Words in a field: one line beside the label, or (`multiline`) a box under it that grows with
|
|
35
|
+
* its lines. Each keystroke sets the value; one focus's typing is one undo step. Enter (⌘Enter in
|
|
36
|
+
* a box) or Esc lets go of it.
|
|
37
|
+
*/
|
|
38
|
+
export declare function textRow(c: RowContext<TextField>): EditorRow;
|
|
33
39
|
export interface ToolbarRow extends EditorRow {
|
|
34
40
|
readonly field: ToolbarField;
|
|
35
41
|
/** The item a keydown presses, if any (`global` says whether it's a page-wide shortcut). */
|
|
@@ -42,8 +48,10 @@ export interface ToolbarRow extends EditorRow {
|
|
|
42
48
|
type Shortcut = ReturnType<typeof toolbarShortcut>;
|
|
43
49
|
/**
|
|
44
50
|
* A toolbar: its buttons in equal columns, as many as fit and balanced across the rows (see
|
|
45
|
-
* `toolbarColumns`), each with its icon and label at the start and its shortcut at the end.
|
|
46
|
-
*
|
|
51
|
+
* `toolbarColumns`), each with its icon and label at the start and its shortcut at the end. When
|
|
52
|
+
* every button has an icon and the labels don't fit on one row (or `labels: false`), it's one row
|
|
53
|
+
* of icons, each label and shortcut in its tooltip. `keyOf` is each item's shortcut as it is now
|
|
54
|
+
* (the store's rebinding, else its own).
|
|
47
55
|
*/
|
|
48
56
|
export declare function toolbarRow(c: RowContext<ToolbarField>, press: (item: ToolbarItem) => void, keyOf?: (item: ToolbarItem) => Shortcut): ToolbarRow;
|
|
49
57
|
/** The value a vector shows, as `{ x, y }` or `{ x, y, z }`. */
|
|
@@ -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.
|
|
@@ -28,9 +31,19 @@ export declare function activeEntryId(controls: Controls<any>): string | null;
|
|
|
28
31
|
* cycling never gets stuck when a saved variant has the exact same values as a built-in preset.
|
|
29
32
|
*/
|
|
30
33
|
export declare function resolveActivePresetEntry<V extends Record<string, any>>(entries: readonly PresetEntry<V>[], currentValues: V, lastAppliedId: string | null, baseId?: string | null): ActivePresetState;
|
|
34
|
+
/**
|
|
35
|
+
* How many lines `count` chips take in `avail` px, at least `min` px each with `gap` between (as
|
|
36
|
+
* the strip's auto-fit grid lays them); 1 before there's room to measure.
|
|
37
|
+
*/
|
|
38
|
+
export declare function presetLines(count: number, min: number, avail: number, gap: number): number;
|
|
31
39
|
/** Whether any entry but the defaults gives one of `keys` a value other than its default. */
|
|
32
40
|
export declare function presetsTouch(entries: readonly PresetEntry<any>[], keys: readonly string[], defaults: Readonly<Record<string, unknown>>): boolean;
|
|
33
41
|
export declare function nextPresetIndex(count: number, activeIndex: number, direction: number): number;
|
|
42
|
+
/**
|
|
43
|
+
* How the strip lays out its presets: `"chips"` in a tray of equal columns, `"list"` as rows like a
|
|
44
|
+
* menu's, or `"auto"` (the default): chips while they fit on two lines, else the list.
|
|
45
|
+
*/
|
|
46
|
+
export type PresetDisplay = "auto" | "list" | "chips";
|
|
34
47
|
export interface PresetStrip {
|
|
35
48
|
readonly element: HTMLElement;
|
|
36
49
|
readonly track: HTMLElement;
|
|
@@ -45,6 +58,10 @@ export interface PresetStrip {
|
|
|
45
58
|
getButtons(): readonly HTMLButtonElement[];
|
|
46
59
|
getActiveState(): ActivePresetState;
|
|
47
60
|
cycle(direction: -1 | 1): void;
|
|
61
|
+
/** Applies the nth chip (0-based), as a click on it does. */
|
|
62
|
+
select(index: number): void;
|
|
63
|
+
/** Lays the presets out as chips or a list (see `PresetDisplay`). */
|
|
64
|
+
display(mode: PresetDisplay): void;
|
|
48
65
|
selectById(id: string): void;
|
|
49
66
|
/** Saves the current values as "Variant N" and opens its name to typing; returns a status message. */
|
|
50
67
|
save(): string;
|
|
@@ -61,6 +78,11 @@ export interface PresetStrip {
|
|
|
61
78
|
}
|
|
62
79
|
export declare function createPresetStrip<S extends Schema>(doc: Document, controls: Controls<S>, showVariants: boolean, run: (action: () => unknown) => void, onAfterChange?: () => void,
|
|
63
80
|
/** What a preset's chip says (its id stays its identity); `controls.presetLabel` by default. */
|
|
64
|
-
presetLabel?: (id: string) => string,
|
|
81
|
+
presetLabel?: (id: string, scope: string) => string,
|
|
65
82
|
/** Whether these entries matter where the strip is shown (a tab they don't touch hides it). */
|
|
66
|
-
relevant?: (entries: readonly PresetEntry<any>[]) => boolean
|
|
83
|
+
relevant?: (entries: readonly PresetEntry<any>[]) => boolean,
|
|
84
|
+
/**
|
|
85
|
+
* Whose presets it shows: a tab or group's (see `ControlsOptions.scopedPresets`), `""` for the
|
|
86
|
+
* panel's own, or null for none (the strip hides).
|
|
87
|
+
*/
|
|
88
|
+
scopeOf?: () => string | null): PresetStrip;
|
|
@@ -28,11 +28,12 @@ export declare function crumbTrail(path: {
|
|
|
28
28
|
*/
|
|
29
29
|
export declare function escTarget(trail: readonly Crumb[], title: string): string | undefined;
|
|
30
30
|
/**
|
|
31
|
-
* How much of a trail fits `room` px: crumbs from `from` on show
|
|
32
|
-
*
|
|
33
|
-
* `
|
|
31
|
+
* How much of a trail fits `room` px: crumbs from `from` on show, the ones before it dropped, and
|
|
32
|
+
* the Esc hint shows only when it fits too. Without room for the deepest crumb, none show
|
|
33
|
+
* (`from` is the trail's length): the line never runs past the title's room into the buttons.
|
|
34
|
+
* `widths` are the crumbs' own; `sep` a separator's (with its gaps).
|
|
34
35
|
*/
|
|
35
|
-
export declare function fitCrumbs(widths: readonly number[], room: number, sep: number,
|
|
36
|
+
export declare function fitCrumbs(widths: readonly number[], room: number, sep: number, hint?: number): {
|
|
36
37
|
from: number;
|
|
37
38
|
hint: boolean;
|
|
38
39
|
};
|
|
@@ -41,6 +42,16 @@ export declare function fitCrumbs(widths: readonly number[], room: number, sep:
|
|
|
41
42
|
* the first nine, as they read.
|
|
42
43
|
*/
|
|
43
44
|
export declare function digitOption(key: string, count: number): number | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Where a digit goes in a panel: a focused row's options take 1–9 (even past the last), a number
|
|
47
|
+
* row and a page card's numbered presets keep theirs, and anywhere else 1–9 pick the preset
|
|
48
|
+
* strip's chips (the design's variants) while the strip has that many. Undefined leaves the key.
|
|
49
|
+
*/
|
|
50
|
+
export declare function digitRoute(key: string, at: {
|
|
51
|
+
options: boolean;
|
|
52
|
+
keeps: boolean;
|
|
53
|
+
presets: number;
|
|
54
|
+
}): "options" | "presets" | undefined;
|
|
44
55
|
/**
|
|
45
56
|
* The digit hints for a row's options: one per option that shows (up to nine), or, while they
|
|
46
57
|
* don't (a menu, a folded editor), one standing for them all ("1–5").
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const canvasCss = "\n.knobs-ui.knobs-canvas{--_kc-radius:var(--k-ui-canvas-radius,var(--_k-radius-panel));--_kc-fade:var(--k-ui-canvas-fade,16px);\n position:relative;width:100%;height:100%;overflow:hidden;outline:none;background:var(--k-ui-canvas-bg,var(--_k-bg-page));contain:strict;\n touch-action:none;overscroll-behavior:none;user-select:none;-webkit-user-select:none;cursor:default;\n font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}\n:where(.knobs-canvas-stage,.knobs-canvas-stage *,.knobs-canvas-zoom,.knobs-canvas-zoom *){box-sizing:border-box}\n/* No hard edges: what slides out of view fades over the last few px. */\n.knobs-canvas-stage{position:absolute;inset:0;overflow:hidden;\n -webkit-mask-image:linear-gradient(to right,transparent,#000 var(--_kc-fade),#000 calc(100% - var(--_kc-fade)),transparent),linear-gradient(to bottom,transparent,#000 var(--_kc-fade),#000 calc(100% - var(--_kc-fade)),transparent);\n -webkit-mask-composite:source-in;mask-image:linear-gradient(to right,transparent,#000 var(--_kc-fade),#000 calc(100% - var(--_kc-fade)),transparent),linear-gradient(to bottom,transparent,#000 var(--_kc-fade),#000 calc(100% - var(--_kc-fade)),transparent);mask-composite:intersect}\n.knobs-canvas-dots{position:absolute;left:-128px;top:-128px;right:-128px;bottom:-128px;pointer-events:none;will-change:transform;\n background-image:radial-gradient(circle,var(--k-ui-canvas-dot,color-mix(in srgb,var(--_k-fg) 22%,transparent)) 1px,transparent 1.25px)}\n.knobs-canvas-world{position:absolute;left:0;top:0;width:0;height:0;transform-origin:0 0}\n.knobs-canvas[data-moving] .knobs-canvas-world{will-change:transform}\n.knobs-canvas:is([data-panning],[data-space]) .knobs-canvas-world{pointer-events:none}\n.knobs-canvas[data-space]{cursor:grab}\n.knobs-canvas[data-grabbing]{cursor:grabbing}\n.knobs-canvas-tile{position:absolute;left:0;top:0;display:flex;flex-direction:column;width:max-content;transform-origin:50% 50%}\n.knobs-canvas-title{flex:none;contain:inline-size;height:24px;padding:0 2px 8px;overflow:hidden;white-space:nowrap;color:var(--_k-fg-2);\n font-size:var(--_k-type-small,12px);line-height:16px;-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 16px),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 16px),transparent)}\n.knobs-canvas-card{position:relative;flex:none;padding:var(--k-ui-canvas-pad,16px);border-radius:var(--_kc-radius);background:var(--k-ui-canvas-card,var(--_k-bg));\n overflow:hidden;user-select:text;-webkit-user-select:text}\n.knobs-canvas-card::after{content:\"\";position:absolute;inset:0;border-radius:inherit;box-shadow:inset 0 0 0 1px var(--_k-border);pointer-events:none}\n/* The readout: how far, and the way back to the whole set or 100%. */\n.knobs-canvas-zoom{position:absolute;right:10px;bottom:10px;z-index:1;display:flex;align-items:center;gap:2px;height:28px;padding:0 4px;border-radius:999px;\n background:var(--_k-bg);box-shadow:inset 0 0 0 1px var(--_k-border);color:var(--_k-fg-2);font-size:var(--_k-type-small,12px);\n font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";white-space:nowrap}\n:where(.knobs-ui) .knobs-canvas-btn{all:revert;box-sizing:border-box;font:inherit;letter-spacing:inherit;margin:0;border:0;outline:none;box-shadow:none;\n display:inline-flex;align-items:center;justify-content:center;height:20px;min-width:20px;padding:0 6px;border-radius:999px;background:transparent;color:inherit;cursor:default;\n transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}\n:where(.knobs-ui) .knobs-canvas-btn:is(:hover,:focus-visible){background:var(--_k-fill-hover);color:var(--_k-fg);transition-duration:0ms}\n:where(.knobs-ui) .knobs-canvas-btn:focus-visible{box-shadow:0 0 0 1.5px var(--_k-accent)}\n.knobs-canvas-pct{min-width:46px}\n.knobs-canvas-btn svg{width:13px;height:13px}\n";
|