@kitlangton/knobs 0.2.0 → 0.3.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.
Files changed (42) hide show
  1. package/README.md +135 -17
  2. package/dist/dev/{chunk-gezhc24g.js → chunk-7xgkerd2.js} +14 -5
  3. package/dist/dev/{chunk-5cr85vv6.js → chunk-jx1ktap3.js} +7843 -7933
  4. package/dist/dev/{chunk-693jd1gj.js → chunk-pmkvb9ep.js} +1544 -160
  5. package/dist/dev/{chunk-4km87zfx.js → chunk-v8ssbcbk.js} +18 -7
  6. package/dist/dev/index.js +187 -31
  7. package/dist/index.js +197 -33
  8. package/dist/panel.js +20260 -18462
  9. package/dist/types/core/keys.d.ts +2 -0
  10. package/dist/types/core/remote.d.ts +2 -0
  11. package/dist/types/core/schema.d.ts +5 -0
  12. package/dist/types/core/store.d.ts +29 -2
  13. package/dist/types/core/unlock.d.ts +77 -0
  14. package/dist/types/index.d.ts +1 -0
  15. package/dist/types/panel/attach.d.ts +2 -0
  16. package/dist/types/panel/crumbs.d.ts +19 -0
  17. package/dist/types/panel/editors.d.ts +9 -0
  18. package/dist/types/panel/feel.d.ts +103 -0
  19. package/dist/types/panel/give.d.ts +34 -1
  20. package/dist/types/panel/gpu/color.d.ts +4 -4
  21. package/dist/types/panel/gpu/renderer.d.ts +32 -0
  22. package/dist/types/panel/gpu/shader.wgsl.d.ts +1 -1
  23. package/dist/types/panel/index.d.ts +2 -1
  24. package/dist/types/panel/inspector.d.ts +1 -1
  25. package/dist/types/panel/lens.d.ts +113 -0
  26. package/dist/types/panel/motion.d.ts +2 -0
  27. package/dist/types/panel/page-hints.d.ts +2 -1
  28. package/dist/types/panel/prefs.d.ts +2 -2
  29. package/dist/types/panel/presence.d.ts +20 -0
  30. package/dist/types/panel/scope.d.ts +29 -0
  31. package/dist/types/panel/slider.d.ts +21 -4
  32. package/dist/types/panel/tab-transition.d.ts +15 -0
  33. package/dist/types/panel/tabs.d.ts +1 -1
  34. package/dist/types/panel/toggle.d.ts +27 -0
  35. package/dist/types/ui/look.d.ts +1 -1
  36. package/dist/types/ui/scrollbar.d.ts +12 -0
  37. package/dist/types/ui/split-model.d.ts +4 -3
  38. package/dist/types/ui/split.d.ts +8 -6
  39. package/dist/ui-react.js +232 -132
  40. package/dist/ui-solid.js +232 -132
  41. package/dist/ui.js +285 -174
  42. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import type { PanelCommand, PanelKeys } from "../core/store.js";
2
2
  /** How a panel reads keys that aren't commands (see `PanelKeys`): resolved once per panel. */
3
3
  export interface KeyPrefs {
4
- /** j/k and h/l as aliases for the arrows. */
4
+ /** j/k as aliases for ↑/↓ (l is Lock, so ←/→ have no letters). */
5
5
  readonly vim: boolean;
6
6
  /** Digits, `.`, `-` and Enter on a slider open its inline number editor. */
7
7
  readonly edit: boolean;
@@ -14,7 +14,7 @@ export declare const DEFAULT_PREFS: KeyPrefs;
14
14
  export declare const setKeyPrefs: (root: Element, prefs: KeyPrefs) => WeakMap<Element, KeyPrefs>;
15
15
  /** The preferences of the panel `node` sits in. */
16
16
  export declare function keyPrefs(node: EventTarget | null): KeyPrefs;
17
- /** -1, 1 or 0 for ←/→ (and h/l unless the panel turned the letter aliases off). */
17
+ /** -1, 1 or 0 for ←/→. */
18
18
  export declare function arrowOf(event: KeyboardEvent): -1 | 0 | 1;
19
19
  /** ⇧'s multiplier for this event (1 without ⇧). */
20
20
  export declare const bigOf: (event: KeyboardEvent) => number;
@@ -0,0 +1,20 @@
1
+ import type { MorphFrame } from "./morph.js";
2
+ export interface Presence {
3
+ readonly shown: boolean;
4
+ /** Shows or hides the panel; `animate: false` puts it there at once (a reload, a first paint). */
5
+ set(shown: boolean, animate: boolean): void;
6
+ /** The shape the GPU overlay draws while it shows or hides (see `MorphFrame`), else undefined. */
7
+ frame(now: number): MorphFrame | undefined;
8
+ dispose(): void;
9
+ }
10
+ /** What the panel looks like at `x` (0 hidden, 1 shown) on the way in or out. */
11
+ export declare function presenceLook(x: number, inline: boolean, reduced: boolean): {
12
+ opacity: number;
13
+ blur: number;
14
+ scale: number;
15
+ fold: number;
16
+ };
17
+ export declare function createPresence(root: HTMLElement, options: {
18
+ readonly inline: boolean;
19
+ readonly wake: () => void;
20
+ }): Presence;
@@ -7,6 +7,35 @@ export type CommandScope = "selection" | "row" | "group" | "all";
7
7
  export declare function commandScope(level: FocusLevel, selection?: boolean): CommandScope;
8
8
  /** How a command reads from where it would land: "Random this", "Reset group", "Random all". */
9
9
  export declare function scopeLabel(verb: string, scope: CommandScope): string;
10
+ /** A level below the panel that the header's crumbs name: a card, a row, an open editor's part. */
11
+ export type CrumbLevel = "card" | "row" | "editor";
12
+ export interface Crumb {
13
+ readonly level: CrumbLevel;
14
+ readonly label: string;
15
+ }
16
+ /**
17
+ * Where keys go, as the header reads after the panel's title: `Shape › Cohesion`. A level that
18
+ * isn't focused (or has no name) is left out; the last crumb is the deepest, the one focused.
19
+ */
20
+ export declare function crumbTrail(path: {
21
+ readonly card?: string;
22
+ readonly row?: string;
23
+ readonly editor?: string;
24
+ }): Crumb[];
25
+ /**
26
+ * Where Esc goes from the deepest crumb: the crumb before it, else the panel (`title`). Nothing
27
+ * at the panel itself (no crumbs), where Esc leaves.
28
+ */
29
+ export declare function escTarget(trail: readonly Crumb[], title: string): string | undefined;
30
+ /**
31
+ * How much of a trail fits `room` px: crumbs from `from` on show (the ones before it fold into
32
+ * one "…"), and the Esc hint shows only when it fits too. The deepest crumb always shows.
33
+ * `widths` are the crumbs' own; `sep` a separator's (with its gaps), `more` the "…"'s.
34
+ */
35
+ export declare function fitCrumbs(widths: readonly number[], room: number, sep: number, more: number, hint?: number): {
36
+ from: number;
37
+ hint: boolean;
38
+ };
10
39
  /**
11
40
  * The option a digit picks among `count` (0-based), or undefined when it names none: 1–9 pick
12
41
  * the first nine, as they read.
@@ -1,4 +1,5 @@
1
1
  import type { Knob as KnobField } from "../core/schema.js";
2
+ import { type DetentKind } from "./feel.js";
2
3
  import { type Roll, Spring, VelocityTracker } from "./motion.js";
3
4
  export interface DigitPlace {
4
5
  ch: string;
@@ -39,6 +40,17 @@ export interface Slider {
39
40
  readonly notchRatio: number;
40
41
  /** Whether a drag is currently held on the default by the notch's magnet. */
41
42
  isMagnetized(): boolean;
43
+ /** The detent holding a drag right now, if any. */
44
+ heldDetent(): DetentKind | undefined;
45
+ /** Where the active preset's value sits [0..1], when it differs from the default. */
46
+ readonly baseRatio: number | undefined;
47
+ /** When the handle last caught a detent (see `settleScale`). */
48
+ readonly settledAt: number;
49
+ /**
50
+ * How many halvings the drag in hand moves at, for its ruler (0 at 1:1 or at rest, up to 3; each
51
+ * level halves the tenths again). Each level shows `rulerAlpha(depth, level)` of the way.
52
+ */
53
+ rulerDepth(): number;
42
54
  /** When the readout last popped (a click landing on a decile, or the default's magnet). */
43
55
  poppedAt: number;
44
56
  /** Formatted numeric string without unit (e.g. "0.45" or "98"). */
@@ -83,10 +95,15 @@ export declare function stepValue(field: {
83
95
  /**
84
96
  * A DialKit-style slider: the whole row is the track, the fill is a full-height block,
85
97
  * the handle is a hairline that only shows on hover, and the label + value sit on the
86
- * track itself. Dragging follows the pointer exactly (⌥ for 1/10 speed) and the default's notch
87
- * pulls it in from a few px away; a click snaps to the nearest step (or nearest 10% when there
88
- * are many steps) with a short spring-like ease. A sideways trackpad pan moves it like a drag.
98
+ * track itself. Dragging follows the pointer exactly, slower the further the pointer strays off
99
+ * the row (and ⌥ for 1/10 speed); detents at the default, the active preset's value and round
100
+ * values hold it for a few px, and past an end the row stretches like rubber. A click snaps
101
+ * to the nearest step (or nearest 10% when there are many steps) with a short spring-like ease.
102
+ * A sideways trackpad pan moves it like a drag.
89
103
  */
90
104
  export declare function createSlider(doc: Document, key: string, initialField: KnobField, set: (value: number, options?: {
91
105
  coalesce?: boolean;
92
- }) => void, onMotionWake?: () => void): Slider;
106
+ }) => void, onMotionWake?: () => void, options?: {
107
+ /** The active preset's value for this key (what Reset goes back to first). */
108
+ readonly base?: () => number | undefined;
109
+ }): Slider;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * A tab change, as one layout animation: what leaves fades out where it stood (lifted out of the
3
+ * flow, so it takes no room), what arrives fades in block by block with a small rise, what stays
4
+ * glides to its new place, and the surface (and any card whose rows change) springs to its new
5
+ * height. Every spring keeps its position and velocity when another tab is picked mid-flight.
6
+ *
7
+ * While the pointer stays on the panel the surface never shrinks: a panel anchored at its foot
8
+ * (or centred) would otherwise move its tabs out from under the pointer between two clicks. It
9
+ * settles to its size once the pointer leaves.
10
+ */
11
+ export declare function tabTransition(body: HTMLElement, root: HTMLElement, wake: () => void): {
12
+ readonly running: boolean;
13
+ finish: () => void;
14
+ to(want: Map<HTMLElement, boolean>): void;
15
+ };
@@ -28,4 +28,4 @@ export interface TabStrip {
28
28
  focus(options?: FocusOptions): void;
29
29
  dispose(): void;
30
30
  }
31
- export declare function createTabStrip(doc: Document, choose: (id: string) => void): TabStrip;
31
+ export declare function createTabStrip(doc: Document, choose: (id: string, animate?: boolean) => void): TabStrip;
@@ -0,0 +1,27 @@
1
+ import { type StoragePort } from "../core/storage.js";
2
+ type KeyEventLike = Pick<KeyboardEvent, "key" | "code" | "ctrlKey" | "metaKey" | "altKey" | "shiftKey" | "repeat" | "isComposing" | "defaultPrevented" | "target">;
3
+ /** Whether a keydown is `key` for the toggle: outside a text field, with no modifier held. */
4
+ export declare function isToggleKey(event: KeyEventLike, key: string): boolean;
5
+ /** A panel or chip that comes and goes with the toggle key. */
6
+ export interface ToggleSurface {
7
+ /** Its store's id: what's remembered. */
8
+ readonly id: string;
9
+ readonly key: string;
10
+ readonly storage: () => StoragePort | null;
11
+ /** Where focus may be when it hides, to give back when it shows. */
12
+ readonly root: HTMLElement;
13
+ /** Shows or hides it; `animate: false` puts it there at once. */
14
+ show(shown: boolean, animate: boolean): void;
15
+ }
16
+ export interface ToggleLayer {
17
+ /** Joins the layer; `shown` is how it should start (what its store remembers). */
18
+ register(surface: ToggleSurface): {
19
+ readonly shown: boolean;
20
+ dispose(): void;
21
+ };
22
+ /** Shows or hides everything listening for `key`; false when nothing does. */
23
+ toggle(key: string): boolean;
24
+ }
25
+ /** The page's toggle layer, for `doc`. */
26
+ export declare function toggleLayer(doc: Document): ToggleLayer;
27
+ export {};
@@ -39,7 +39,7 @@ export declare const tune: <T extends {
39
39
  readonly zeta: number;
40
40
  }) => T;
41
41
  /** Whether `target` is an editable field or select that takes typed keys. */
42
- export declare const isTypingTarget: (t: EventTarget | null) => boolean;
42
+ export { isTypingTarget } from "../core/keys.js";
43
43
  /**
44
44
  * Tells the page's GPU overlay that layout moved (a pane resizing, collapsing or sliding): it
45
45
  * reads rects afresh on its next frame, so a panel inside a pane keeps up.
@@ -0,0 +1,12 @@
1
+ /**
2
+ * A thin scrollbar drawn over a scroller's content, in place of the native one beside it. A native
3
+ * scrollbar that's always shown (as a system may be set) takes its width from the rows the moment
4
+ * the content overflows, so every row jumps sideways, and gives it back when it stops; this one
5
+ * takes no room. It shows while the content scrolls and while the pointer is over the scroller,
6
+ * and drags. `content` is the element whose height makes the scroll: it's watched for changes.
7
+ * The scroller hides its own (`scrollbar-width: none`) and is positioned.
8
+ */
9
+ export declare function overlayScrollbar(scroller: HTMLElement, content: Element): {
10
+ update: () => void;
11
+ dispose(): void;
12
+ };
@@ -97,10 +97,11 @@ export declare function foldFaces(prev: FoldFaces, p: number): FoldFaces;
97
97
  */
98
98
  export declare function chevronTurn(p: number, edge: "start" | "end"): number;
99
99
  /**
100
- * The fold's chevron, flipping: its width (scaleX) against the rail's chevron at flip progress
101
- * `f` (0 open, 1 folded). The arms close in to a flat line halfway and open out the other way.
100
+ * The fold's chevron, flipping over: its turn about its vertical axis (degrees, drawn with depth)
101
+ * against the rail's chevron at flip progress `f` (0 open, 1 folded). Edge-on halfway, it comes
102
+ * round mirrored, rolling the way the pane's edge travels.
102
103
  */
103
- export declare function chevronFlip(f: number): number;
104
+ export declare function chevronFlip(f: number, edge: "start" | "end"): number;
104
105
  /** How a pane folds: see `SplitOptions.fold`. */
105
106
  export interface FoldStyle {
106
107
  readonly chevron: "flip" | "turn";
@@ -45,8 +45,9 @@ export interface SplitOptions extends UiLook {
45
45
  /** How a pane folds (each part has a default). */
46
46
  export interface SplitFold {
47
47
  /**
48
- * The collapse chevron: `"flip"` (default) closes it to a flat line and opens it the other way,
49
- * quickly, on its own snappy spring; `"turn"` spins it half a turn with the fold.
48
+ * The collapse chevron: `"flip"` (default) turns it over about its vertical axis, with depth,
49
+ * mirrored as it travels, on its own snappy spring; `"turn"` spins it half a turn flat, with
50
+ * the fold.
50
51
  */
51
52
  readonly chevron?: "flip" | "turn";
52
53
  /**
@@ -54,7 +55,7 @@ export interface SplitFold {
54
55
  * element all the way; `"fade"` fades it out with the header as the rail's label fades in.
55
56
  */
56
57
  readonly title?: "travel" | "fade";
57
- /** The fold's spring, in seconds (no bounce): 0.3 unless set. */
58
+ /** The fold's spring, in seconds (no bounce): 0.25 unless set. */
58
59
  readonly duration?: number;
59
60
  }
60
61
  export interface SplitPane {
@@ -85,8 +86,9 @@ export interface Split {
85
86
  /**
86
87
  * Resizable panes along a row or a column, divided by hairlines with a wider grip. Drag a divider
87
88
  * to resize (each pane slows into its min and max), double-click it to reset, or focus it and use
88
- * the arrow keys (⇧ for bigger steps) and Enter to collapse. Collapsing springs the pane down to a
89
- * slim rail, or to its header in a column, which opens it again. Sizes persist and restore before
90
- * the first paint. Splits nest: call `split` on another split's pane body.
89
+ * the arrow keys (⇧ for bigger steps) and Enter to collapse; in a row, double-click a pane's header
90
+ * to collapse it too. Collapsing springs the pane down to a slim rail, or to its header in a
91
+ * column, which opens it again. Sizes persist and restore before the first paint. Splits nest:
92
+ * call `split` on another split's pane body.
91
93
  */
92
94
  export declare function split(container: HTMLElement, options: SplitOptions): Split;