@kitlangton/knobs 0.0.0-stage → 0.1.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 (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1270 -2
  3. package/dist/dev/chunk-e13znr7c.js +155 -0
  4. package/dist/dev/chunk-kdewv0mt.js +1334 -0
  5. package/dist/dev/chunk-ktsn42p7.js +15668 -0
  6. package/dist/dev/chunk-qtt698hp.js +1118 -0
  7. package/dist/dev/index.js +1389 -0
  8. package/dist/index.js +2367 -0
  9. package/dist/panel.js +23635 -0
  10. package/dist/react.js +326 -0
  11. package/dist/solid.js +336 -0
  12. package/dist/themes.js +235 -0
  13. package/dist/types/core/adapter.d.ts +21 -0
  14. package/dist/types/core/code.d.ts +3 -0
  15. package/dist/types/core/color.d.ts +27 -0
  16. package/dist/types/core/easing.d.ts +21 -0
  17. package/dist/types/core/internal.d.ts +18 -0
  18. package/dist/types/core/keys.d.ts +21 -0
  19. package/dist/types/core/mutate.d.ts +21 -0
  20. package/dist/types/core/ramp.d.ts +150 -0
  21. package/dist/types/core/random.d.ts +2 -0
  22. package/dist/types/core/readout.d.ts +73 -0
  23. package/dist/types/core/remote.d.ts +258 -0
  24. package/dist/types/core/schema.d.ts +526 -0
  25. package/dist/types/core/spring.d.ts +38 -0
  26. package/dist/types/core/storage.d.ts +8 -0
  27. package/dist/types/core/store.d.ts +474 -0
  28. package/dist/types/core/theme.d.ts +27 -0
  29. package/dist/types/core/variants.d.ts +17 -0
  30. package/dist/types/index.d.ts +13 -0
  31. package/dist/types/panel/attach.d.ts +5 -0
  32. package/dist/types/panel/choice.d.ts +56 -0
  33. package/dist/types/panel/die.d.ts +121 -0
  34. package/dist/types/panel/editors.d.ts +159 -0
  35. package/dist/types/panel/folds.d.ts +14 -0
  36. package/dist/types/panel/give.d.ts +73 -0
  37. package/dist/types/panel/gpu/atlas.d.ts +40 -0
  38. package/dist/types/panel/gpu/color.d.ts +128 -0
  39. package/dist/types/panel/gpu/die.wgsl.d.ts +1 -0
  40. package/dist/types/panel/gpu/renderer.d.ts +712 -0
  41. package/dist/types/panel/gpu/shader.wgsl.d.ts +2 -0
  42. package/dist/types/panel/haptics.d.ts +8 -0
  43. package/dist/types/panel/has.d.ts +14 -0
  44. package/dist/types/panel/hints.d.ts +45 -0
  45. package/dist/types/panel/icons.d.ts +30 -0
  46. package/dist/types/panel/index.d.ts +10 -0
  47. package/dist/types/panel/inspector.d.ts +20 -0
  48. package/dist/types/panel/measure.d.ts +6 -0
  49. package/dist/types/panel/menu.d.ts +38 -0
  50. package/dist/types/panel/morph.d.ts +38 -0
  51. package/dist/types/panel/motion.d.ts +77 -0
  52. package/dist/types/panel/page-hints.d.ts +82 -0
  53. package/dist/types/panel/page.d.ts +423 -0
  54. package/dist/types/panel/panel.d.ts +43 -0
  55. package/dist/types/panel/position.d.ts +5 -0
  56. package/dist/types/panel/prefs.d.ts +28 -0
  57. package/dist/types/panel/presets.d.ts +48 -0
  58. package/dist/types/panel/ramps.d.ts +14 -0
  59. package/dist/types/panel/readout-row.d.ts +21 -0
  60. package/dist/types/panel/reveal.d.ts +15 -0
  61. package/dist/types/panel/rolling-css.d.ts +2 -0
  62. package/dist/types/panel/search.d.ts +36 -0
  63. package/dist/types/panel/seg.d.ts +15 -0
  64. package/dist/types/panel/session.d.ts +21 -0
  65. package/dist/types/panel/slider.d.ts +92 -0
  66. package/dist/types/panel/smear.d.ts +7 -0
  67. package/dist/types/panel/spin.d.ts +13 -0
  68. package/dist/types/panel/styles.d.ts +11 -0
  69. package/dist/types/panel/swipe.d.ts +114 -0
  70. package/dist/types/panel/switcher.d.ts +20 -0
  71. package/dist/types/panel/tabs.d.ts +31 -0
  72. package/dist/types/panel/thumb.d.ts +36 -0
  73. package/dist/types/react/Knobs.d.ts +15 -0
  74. package/dist/types/react/VariantSwitcher.d.ts +10 -0
  75. package/dist/types/react/index.d.ts +3 -0
  76. package/dist/types/react/useControls.d.ts +11 -0
  77. package/dist/types/solid/index.d.ts +50 -0
  78. package/dist/types/themes/index.d.ts +1 -0
  79. package/dist/types/ui/bento-css.d.ts +1 -0
  80. package/dist/types/ui/bento-model.d.ts +96 -0
  81. package/dist/types/ui/bento.d.ts +77 -0
  82. package/dist/types/ui/commands.d.ts +11 -0
  83. package/dist/types/ui/confirm.d.ts +13 -0
  84. package/dist/types/ui/index.d.ts +20 -0
  85. package/dist/types/ui/layer.d.ts +70 -0
  86. package/dist/types/ui/look.d.ts +53 -0
  87. package/dist/types/ui/menu.d.ts +63 -0
  88. package/dist/types/ui/overlay-css.d.ts +1 -0
  89. package/dist/types/ui/overlay-model.d.ts +87 -0
  90. package/dist/types/ui/palette.d.ts +38 -0
  91. package/dist/types/ui/popover.d.ts +35 -0
  92. package/dist/types/ui/react.d.ts +45 -0
  93. package/dist/types/ui/readout-css.d.ts +1 -0
  94. package/dist/types/ui/readout-model.d.ts +137 -0
  95. package/dist/types/ui/readouts.d.ts +85 -0
  96. package/dist/types/ui/rgba.d.ts +6 -0
  97. package/dist/types/ui/solid.d.ts +40 -0
  98. package/dist/types/ui/split-model.d.ts +81 -0
  99. package/dist/types/ui/split.d.ts +75 -0
  100. package/dist/types/ui/timeline-model.d.ts +83 -0
  101. package/dist/types/ui/timeline.d.ts +76 -0
  102. package/dist/types/ui/toast.d.ts +19 -0
  103. package/dist/types/ui/tooltip.d.ts +19 -0
  104. package/dist/types/ui/tree-model.d.ts +125 -0
  105. package/dist/types/ui/tree.d.ts +95 -0
  106. package/dist/ui-react.js +6558 -0
  107. package/dist/ui-solid.js +6511 -0
  108. package/dist/ui.js +9238 -0
  109. package/package.json +99 -4
@@ -0,0 +1,423 @@
1
+ import type { StoragePort } from "../core/storage.js";
2
+ import type { MountPanelOptions, SectionFolded } from "../core/store.js";
3
+ import type { Panel } from "./panel.js";
4
+ /** What a folded card's or section's summary is made of (see `MountPageOptions.groupSummary`). */
5
+ export interface FoldSummaryInfo {
6
+ /** The group preset its values match (its name), "Custom" when none does; null without any. */
7
+ readonly preset: string | null;
8
+ /** How many of its rows differ from their defaults (a spring's two keys count once). */
9
+ readonly changed: number;
10
+ /** Its value keys. */
11
+ readonly keys: readonly string[];
12
+ }
13
+ export interface MountPageOptions extends MountPanelOptions {
14
+ /** Section order; sections not listed follow in the order they first appear. */
15
+ readonly sections?: readonly string[];
16
+ /** The narrowest a column may get before the page drops one (px). Default 300. */
17
+ readonly columnWidth?: number;
18
+ /** `/` filters rows by label, live. Default true. */
19
+ readonly filter?: boolean;
20
+ /**
21
+ * Sections that start folded to their heading: `true` for all of them, or by section id (over
22
+ * the store's `sectionFolded` and fields' `sectionFolded`). A section that says either way
23
+ * folds: its heading toggles it (a click, or Enter where it's focused). What the user last
24
+ * chose is remembered (see `foldStorage`) and wins over this.
25
+ */
26
+ readonly sectionFolded?: SectionFolded;
27
+ /**
28
+ * Where the page keeps what the user folds and opens (sections and group cards), under
29
+ * `knobs:<id>:folds:v1` as `{ sections, groups }`. By default the store's own storage, unless
30
+ * it has `persist: "none"` (then nothing). Given, it always wins and keeps folds only (never
31
+ * values, locks or variants), so a store with `storage: null` can still remember its folds.
32
+ * `null` keeps none. Folds made for context (`remember: false`) and by the filter are never
33
+ * written.
34
+ */
35
+ readonly foldStorage?: StoragePort | null;
36
+ /**
37
+ * A strip of section chips in the sticky header: the section in view is marked as the page
38
+ * scrolls, each chip counts its changed rows, and a chip (or ⌥↑ / ⌥↓) glides to its section,
39
+ * opening it if it's folded.
40
+ */
41
+ readonly nav?: boolean;
42
+ /**
43
+ * What a folded group card's header says. By default "<matching preset, or Custom> · N
44
+ * changed", leaving out what doesn't apply. `null` shows nothing.
45
+ */
46
+ readonly groupSummary?: (group: string, info: FoldSummaryInfo) => string | Node | null;
47
+ /** What a folded section's heading says ("N changed · M cards" by default; `preset` is null). */
48
+ readonly sectionSummary?: (section: string, info: FoldSummaryInfo) => string | Node | null;
49
+ }
50
+ export interface PageCardOptions {
51
+ readonly title?: string;
52
+ /** The section the card sits in; a new one is added after the others. */
53
+ readonly section?: string;
54
+ /** Any content, placed in the card's body (more can follow with `card.body.append`). */
55
+ readonly element?: HTMLElement;
56
+ /**
57
+ * Makes the card collapsible, starting folded (`true`) or open (`false`): its header toggles it
58
+ * (a click, or Enter where it's focused) and shows a caret. What the user last chose comes back
59
+ * after a reload in the same tab, over this.
60
+ */
61
+ readonly collapsed?: boolean;
62
+ /** One quiet line on the right of a folded card's header, e.g. "iPhone · 0.142.4 · connected". */
63
+ readonly summary?: string | Node;
64
+ /** One muted line under the title (the whole of it on hover). */
65
+ readonly description?: string;
66
+ }
67
+ export interface PageItem {
68
+ readonly label: string;
69
+ readonly detail?: string;
70
+ onSelect?(): void;
71
+ }
72
+ export interface PageAction {
73
+ readonly label: string;
74
+ run(): void;
75
+ readonly disabled?: boolean;
76
+ }
77
+ /** A control in a custom card; `set` shows a value that arrived from elsewhere (no `onChange`). */
78
+ export interface PageControl<T> {
79
+ readonly element: HTMLElement;
80
+ get(): T;
81
+ set(value: T): void;
82
+ }
83
+ export interface PageCard {
84
+ /** The card itself. */
85
+ readonly element: HTMLElement;
86
+ /** Where content goes. */
87
+ readonly body: HTMLElement;
88
+ /** Right side of the card's header, for a badge or a small button. */
89
+ readonly accessory: HTMLElement;
90
+ /**
91
+ * A choice row, like a choice field (no `label` spans the card): segmented while the labels fit
92
+ * and there are at most four, a drop-down menu otherwise; `display` fixes one or the other.
93
+ */
94
+ choice<T extends string>(options: {
95
+ readonly label?: string;
96
+ readonly options: readonly (T | {
97
+ readonly value: T;
98
+ readonly label: string;
99
+ })[];
100
+ readonly value: T;
101
+ readonly display?: "menu" | "segmented";
102
+ onChange(value: T): void;
103
+ }): PageControl<T>;
104
+ /** A switch row. */
105
+ toggle(options: {
106
+ readonly label: string;
107
+ readonly value: boolean;
108
+ onChange(value: boolean): void;
109
+ }): PageControl<boolean>;
110
+ /**
111
+ * A row of buttons; `set` swaps them, keyed by label: buttons that stay glide to their place,
112
+ * the rest cross-fade, and the row folds away while it's empty.
113
+ */
114
+ actions(items: readonly PageAction[]): {
115
+ readonly element: HTMLElement;
116
+ set(items: readonly PageAction[]): void;
117
+ };
118
+ /** A list row: a label, a quieter detail and, with `onSelect`, a keyboard stop (Enter). */
119
+ item(options: PageItem): HTMLElement;
120
+ /**
121
+ * Rows kept by key: `set` updates the ones that stay, folds new ones open and removed ones
122
+ * shut, so the card's height eases and the cards below glide.
123
+ */
124
+ list(items?: readonly (PageItem & {
125
+ readonly key: string;
126
+ })[]): {
127
+ readonly element: HTMLElement;
128
+ set(items: readonly (PageItem & {
129
+ readonly key: string;
130
+ })[]): void;
131
+ };
132
+ /** Folds a row (or anything in the card) open or shut. */
133
+ show(element: HTMLElement, visible: boolean): void;
134
+ /**
135
+ * Folds the card down to its header (or back open, with `false`); the cards below in its
136
+ * column glide. Makes a card collapsible if it wasn't.
137
+ */
138
+ collapse(collapsed?: boolean): void;
139
+ /** Whether the card is folded to its header. */
140
+ readonly collapsed: boolean;
141
+ /** Replaces the folded header's summary (`null` clears it). */
142
+ summary(content: string | Node | null): void;
143
+ /** Empties the body. */
144
+ clear(): void;
145
+ remove(): void;
146
+ }
147
+ /**
148
+ * What's on screen elsewhere (a phone's current screen): group ids (or custom card titles) and
149
+ * section ids. `null` clears it.
150
+ */
151
+ export interface PageHighlight {
152
+ readonly groups?: readonly string[];
153
+ readonly sections?: readonly string[];
154
+ }
155
+ export interface Page extends Panel {
156
+ /** A card of your own in the page's grid, styled by the same tokens. */
157
+ card(options: PageCardOptions): PageCard;
158
+ /**
159
+ * Emphasizes what's on screen: highlighted cards and sections keep full strength, with a small
160
+ * dot by the title of each highlighted section (or of a card highlighted on its own); the rest
161
+ * dims a little, readable and fully interactive (a dimmed card you focus comes back up). Every
162
+ * change glides on the panel spring and can be interrupted. `null` clears it.
163
+ *
164
+ * `reveal: true` glides the first highlighted card (or its section's heading) into view when
165
+ * it's off screen, unless the user scrolled, pressed a key or touched the page in the last two
166
+ * seconds, or is dragging.
167
+ *
168
+ * `expand: true` opens the folded sections and cards it highlights. What it opened folds again
169
+ * once a later highlight moves away from it, unless the user worked in it meanwhile (it's
170
+ * theirs then). Opening it this way isn't remembered: the user's own folds are.
171
+ */
172
+ highlight(target: PageHighlight | null, options?: {
173
+ readonly reveal?: boolean;
174
+ readonly expand?: boolean;
175
+ }): void;
176
+ /**
177
+ * Folds a foldable group's card to its header (or opens it, with `false`; toggles without
178
+ * `folded`). Remembered as the user's choice unless `remember: false`; `reveal` glides the card
179
+ * into view.
180
+ */
181
+ fold(group: string, folded?: boolean, options?: PageFoldOptions): void;
182
+ /**
183
+ * Folds a section to its heading (or opens it, with `false`; toggles without `folded`). Its
184
+ * cards fold away and the columns re-balance, gliding. Remembered as the user's choice unless
185
+ * `remember: false`; `reveal` glides the heading into view. Makes the section foldable if it
186
+ * wasn't.
187
+ */
188
+ foldSection(section: string, folded?: boolean, options?: PageFoldOptions): void;
189
+ /** Whether a section is folded to its heading (its own state; the filter's opening aside). */
190
+ sectionFolded(section: string): boolean;
191
+ /**
192
+ * Opens a section, or a group's card and its section, and glides it into view. By default
193
+ * it's for context (what's on another screen) and isn't remembered; a jump the user asked for
194
+ * passes `remember: true` so it stays open after a reload.
195
+ */
196
+ reveal(target: {
197
+ readonly section: string;
198
+ } | {
199
+ readonly group: string;
200
+ }, options?: {
201
+ readonly remember?: boolean;
202
+ }): void;
203
+ /** The page's sections in reading order, with their groups, for a navigation of your own. */
204
+ sections(): readonly PageSectionInfo[];
205
+ /**
206
+ * The section filling most of the window below the header, as the page scrolls; after a
207
+ * `reveal` (or a jump), that section until the user scrolls.
208
+ */
209
+ activeSection(): string | undefined;
210
+ /**
211
+ * Calls `listener` (after a microtask) whenever `sections()` would say something new: a fold,
212
+ * a changed count, a label or description, sections and groups coming or going. Returns an
213
+ * unsubscribe. `source` says what folded or opened something (see `PageFoldSource`); it's null
214
+ * for the first call and for changes that aren't folds (a value, a label).
215
+ */
216
+ onSections(listener: (sections: readonly PageSectionInfo[], source: PageFoldSource | null) => void): () => void;
217
+ /** Calls `listener` when `activeSection()` changes. Returns an unsubscribe. */
218
+ onActiveSection(listener: (section: string | undefined) => void): () => void;
219
+ }
220
+ /**
221
+ * What a change `onSections` reports came from: `"user"` a click or key on a heading or card
222
+ * header; `"code"` the page's methods (`fold`, `foldSection`, `reveal`, `highlight`'s expand);
223
+ * `"search"` the filter opening matches while it runs (`folded` keeps the saved state; the list
224
+ * shows what the filter shows); `"restore"` the filter clearing, everything back as it was.
225
+ */
226
+ export type PageFoldSource = "user" | "code" | "search" | "restore";
227
+ export interface PageFoldOptions {
228
+ /**
229
+ * `true` (the default) keeps it as the user's choice, across reloads (see `MountPageOptions.foldStorage`);
230
+ * `false` is for context and leaves what's remembered alone.
231
+ */
232
+ readonly remember?: boolean;
233
+ /** Glides the card or heading into view. */
234
+ readonly reveal?: boolean;
235
+ }
236
+ /** A group's card, as `page.sections()` describes it. */
237
+ export interface PageGroupInfo {
238
+ readonly id: string;
239
+ /** Its title as the card shows it. */
240
+ readonly label: string;
241
+ /** Folded to its header (false for a group that doesn't fold). */
242
+ readonly folded: boolean;
243
+ /** How many of its rows differ from their defaults. */
244
+ readonly changed: number;
245
+ /** The group preset its values match, "Custom" when none does; null without presets. */
246
+ readonly preset: string | null;
247
+ }
248
+ /** A section, as `page.sections()` describes it. */
249
+ export interface PageSectionInfo {
250
+ readonly id: string;
251
+ /** Its heading as the page shows it. */
252
+ readonly label: string;
253
+ readonly description?: string;
254
+ /** Folded to its heading (its own state: a running filter's opening doesn't count). */
255
+ readonly folded: boolean;
256
+ /** Changed rows across its groups. */
257
+ readonly changed: number;
258
+ /** Its group cards in reading order (custom cards aren't listed). */
259
+ readonly groups: readonly PageGroupInfo[];
260
+ }
261
+ export interface PageLayout {
262
+ /** Each showing section's label (the overlay draws their text). */
263
+ readonly sections: readonly PageSectionView[];
264
+ add(tile: HTMLElement, section: string): void;
265
+ /**
266
+ * Folds a section to its heading or opens it (making it foldable): its cards fold away or grow
267
+ * back, and the columns re-balance, gliding from wherever the last change had them.
268
+ */
269
+ foldSection(name: string, folded: boolean, animate?: boolean): void;
270
+ /** Whether a section is folded to its heading (while folds hold; see `openFolds`). */
271
+ isFolded(name: string): boolean;
272
+ /** Whether a section's heading toggles it. */
273
+ isFoldable(name: string): boolean;
274
+ /** While on (a filter runs), folded sections show their cards; call inside `change`. */
275
+ openFolds(open: boolean): void;
276
+ /** Sections with something in them, in reading order. */
277
+ sectionList(): readonly {
278
+ readonly name: string;
279
+ readonly label: HTMLElement | null;
280
+ readonly tiles: readonly HTMLElement[];
281
+ readonly folded: boolean;
282
+ }[];
283
+ /** The section a card sits in. */
284
+ sectionOf(tile: HTMLElement): string | undefined;
285
+ /** Re-reads each heading's label and description (the schema changed). */
286
+ relabel(): void;
287
+ /** Where a node lands once the glide has settled (its rect less its glide offset). */
288
+ settled(node: HTMLElement): {
289
+ top: number;
290
+ bottom: number;
291
+ };
292
+ /** Folds the card away, then takes it out of the page. */
293
+ remove(tile: HTMLElement): void;
294
+ /** Re-balances the columns when their count changed (or always, with `force`). */
295
+ pack(force?: boolean): void;
296
+ /**
297
+ * Applies a structural change (the filter, cards shown or hidden) and animates the result:
298
+ * `rows` whose `hidden` changed fold open or shut, cards glide to their new places.
299
+ */
300
+ change(mutate: () => void, rows?: readonly HTMLElement[], instant?: boolean): void;
301
+ /** Steps the motion now, at the start of the overlay's frame (`now` from requestAnimationFrame). */
302
+ frame(now: number): void;
303
+ /** A card's content changed at once (it was drawn `from` px tall): its height eases there. */
304
+ resize(tile: HTMLElement, from: number): void;
305
+ /** Emphasizes the cards and sections in `target` and dims the rest (see `Page.highlight`). */
306
+ highlight(target: PageHighlight | null): void;
307
+ /** Highlighted cards and section headings that show, top to bottom. */
308
+ highlighted(): HTMLElement[];
309
+ /**
310
+ * How a card or section heading is emphasized right now: `dim` (0 full … the token's
311
+ * `--k-page-dim`) and its dot (`mark` 0…1), as the DOM draws them.
312
+ */
313
+ emphasis(node: HTMLElement): {
314
+ readonly dim: number;
315
+ readonly mark: number;
316
+ readonly dot?: HTMLElement;
317
+ } | undefined;
318
+ /** While cards glide or change height, or something folds inside them. */
319
+ readonly moving: boolean;
320
+ readonly version: number;
321
+ dispose(): void;
322
+ }
323
+ /**
324
+ * Splits `heights` into at most `n` contiguous runs whose tallest is as short as possible, so
325
+ * reading down a column and on to the next follows the original order.
326
+ */
327
+ export declare function balancedRuns(heights: readonly number[], n: number, gap?: number): number[];
328
+ export interface PageColumnItem {
329
+ readonly height: number;
330
+ /** Cards of a section are contiguous; sections are numbered in reading order. */
331
+ readonly section: number;
332
+ /**
333
+ * A folded section's heading, standing for the whole section (whose `label` is 0): it gets
334
+ * `space` above it when it follows another section in a column.
335
+ */
336
+ readonly head?: boolean;
337
+ }
338
+ export type PageColumnEntry = {
339
+ readonly kind: "label";
340
+ readonly section: number;
341
+ readonly continued: boolean;
342
+ } | {
343
+ readonly kind: "card";
344
+ readonly index: number;
345
+ };
346
+ export interface PageColumn {
347
+ /** The column holds items `start` to `end - 1`. */
348
+ readonly start: number;
349
+ readonly end: number;
350
+ readonly height: number;
351
+ /** Top to bottom: a label over each section's first card here, then the cards. */
352
+ readonly entries: readonly PageColumnEntry[];
353
+ }
354
+ /**
355
+ * Lays a page's cards into `n` independent columns that keep their reading order (down a
356
+ * column, then the next). A column holds part of one section (a long section takes several
357
+ * adjacent columns) or several whole sections stacked; it never ends one section and starts
358
+ * another midway. The tallest column is as short as possible, and the rest as even as they can
359
+ * be. Each column opens with its section's label (`continued` when the section began in the
360
+ * column before); a section stacked below another gets a label and `space` above it.
361
+ */
362
+ export declare function pageColumns(items: readonly PageColumnItem[], n: number, options?: {
363
+ readonly gap?: number;
364
+ /** A section's label height (0 for none). */
365
+ readonly label?: (section: number) => number;
366
+ readonly space?: number;
367
+ }): PageColumn[];
368
+ /** A disclosure chevron: it points right while folded and down while open (see .knobs-caret). */
369
+ export declare function caretIcon(doc: Document): SVGSVGElement;
370
+ /** A section's heading as the GPU overlay draws it. */
371
+ export interface PageSectionView {
372
+ readonly element: HTMLElement;
373
+ readonly head: HTMLElement | null;
374
+ readonly name?: HTMLElement;
375
+ readonly summary?: HTMLElement;
376
+ readonly desc?: HTMLElement;
377
+ readonly caret?: SVGElement;
378
+ }
379
+ export declare function createPageLayout(doc: Document, host: HTMLElement, options: {
380
+ order: readonly string[];
381
+ columnWidth: number;
382
+ /** What a section's heading says (its name by default). */
383
+ sectionLabel?(name: string): string;
384
+ /** The muted line under a section's heading, if any. */
385
+ sectionDescription?(name: string): string | undefined;
386
+ /** How a section starts: folded or open, or undefined when it doesn't fold. */
387
+ sectionFold?(name: string): boolean | undefined;
388
+ /** Cards moved in the DOM (re-sort anything kept in page order). */
389
+ onLayout(): void;
390
+ /** Motion started or settled (the overlay re-reads rects). */
391
+ wake(): void;
392
+ }): PageLayout;
393
+ /**
394
+ * A card's title without its section's name repeated in front: "Transcript · Arrivals" under
395
+ * Transcript reads "Arrivals". `prefixes` are what the section is called (its id and label); the
396
+ * name has to be followed by a separator (· • : / | › » or a dash), and something has to remain.
397
+ */
398
+ export declare function cardTitle(title: string, prefixes: readonly string[]): string;
399
+ /** Whether a field, group or card answers the filter: every word appears somewhere in `text`. */
400
+ export declare function matchesFilter(query: string, ...text: (string | undefined)[]): boolean;
401
+ /** A custom card's fold, as the page drives it (see `Page.highlight`'s `expand`). */
402
+ export interface CustomCardFold {
403
+ readonly tile: HTMLElement;
404
+ readonly folded: boolean;
405
+ readonly collapsible: boolean;
406
+ /** Folds or opens it, remembering it as the user's choice only with `remember`. */
407
+ fold(folded: boolean, remember: boolean): void;
408
+ }
409
+ export declare function createCustomCard(doc: Document, options: PageCardOptions, hooks: {
410
+ wake(): void;
411
+ remove(tile: HTMLElement): void;
412
+ /** What the header shows for `title` (a repeated section prefix dropped). */
413
+ title?(title: string): string;
414
+ /** The card's content changed at once (it was `from` px tall): its height eases there. */
415
+ resize?(tile: HTMLElement, from: number): void;
416
+ /** Where a collapsible card's state is remembered, by title. */
417
+ folded?: {
418
+ get(title: string): boolean | undefined;
419
+ set(title: string, folded: boolean): void;
420
+ };
421
+ /** Hands the page a way to fold the card without remembering it (a highlight's expand). */
422
+ register?(card: CustomCardFold): void;
423
+ }): PageCard;
@@ -0,0 +1,43 @@
1
+ import { type Schema } from "../core/schema.js";
2
+ import type { Controls, MountPanelOptions } from "../core/store.js";
3
+ import { type MountPageOptions, type Page } from "./page.js";
4
+ import { type PresetStrip } from "./presets.js";
5
+ export interface Panel {
6
+ element: HTMLElement;
7
+ presetStrip: PresetStrip;
8
+ focus(): void;
9
+ /** Collapses the panel into its chip (or fades it out), then disposes it. */
10
+ dismiss(): void;
11
+ /** Reverses a collapse still in flight; false once there's none to reverse. */
12
+ reopen(): boolean;
13
+ /** Asks `rowAccessory` again for every row, e.g. after a pin changed elsewhere. */
14
+ updateAccessories(): void;
15
+ /** Folds (`true`) or opens a foldable group's card; toggles without `folded`. */
16
+ fold(group: string, folded?: boolean): void;
17
+ /** Shows tab `id` (when given) and returns the tab shown, if the panel has tabs. */
18
+ tab(id?: string): string | undefined;
19
+ /**
20
+ * Searches for `query` (when given) with exactly `chips` on (when given), as typing and clicking
21
+ * would, and returns what the search holds now; undefined without `search`.
22
+ */
23
+ search(query?: string, chips?: readonly string[]): PanelSearch | undefined;
24
+ dispose(): void;
25
+ }
26
+ /** A panel's search: the query as typed and the chips that are on. */
27
+ export interface PanelSearch {
28
+ readonly query: string;
29
+ readonly chips: readonly string[];
30
+ }
31
+ /** "synth-voice" → "Synth voice", "knobsTokens" → "Knobs tokens"; titles with spaces are kept. */
32
+ export declare function readableTitle(id: string): string;
33
+ export declare function createPanel<S extends Schema>(controls: Controls<S>, anchor: HTMLElement, close: () => void, options?: MountPanelOptions & {
34
+ readonly restored?: boolean;
35
+ readonly chip?: HTMLElement;
36
+ }): Panel;
37
+ export declare function mountPanel<S extends Schema>(controls: Controls<S>, container: HTMLElement, options?: MountPanelOptions): Panel;
38
+ /**
39
+ * A full page of controls: sections of group cards in balanced columns under a sticky header
40
+ * (title, presets, Random, Reset, Copy, undo and redo). Groups show their numbered presets;
41
+ * `page.card()` adds cards of your own.
42
+ */
43
+ export declare function mountPage<S extends Schema>(controls: Controls<S>, container: HTMLElement, options?: MountPageOptions): Page;
@@ -0,0 +1,5 @@
1
+ import { type StoragePort } from "../core/storage.js";
2
+ export declare function positionPanel(panel: HTMLElement, header: HTMLElement, anchor: HTMLElement, id: string, storage: () => StoragePort | null): {
3
+ constrain: () => void;
4
+ dispose(): void;
5
+ };
@@ -0,0 +1,28 @@
1
+ import type { PanelCommand, PanelKeys } from "../core/store.js";
2
+ /** How a panel reads keys that aren't commands (see `PanelKeys`): resolved once per panel. */
3
+ export interface KeyPrefs {
4
+ /** j/k and h/l as aliases for the arrows. */
5
+ readonly vim: boolean;
6
+ /** Digits, `.`, `-` and Enter on a slider open its inline number editor. */
7
+ readonly edit: boolean;
8
+ /** What ⇧ multiplies a step by. */
9
+ readonly bigStep: number;
10
+ /** ↑/↓ wrap from the last row to the first. */
11
+ readonly wrap: boolean;
12
+ }
13
+ export declare const DEFAULT_PREFS: KeyPrefs;
14
+ export declare const setKeyPrefs: (root: Element, prefs: KeyPrefs) => WeakMap<Element, KeyPrefs>;
15
+ /** The preferences of the panel `node` sits in. */
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). */
18
+ export declare function arrowOf(event: KeyboardEvent): -1 | 0 | 1;
19
+ /** ⇧'s multiplier for this event (1 without ⇧). */
20
+ export declare const bigOf: (event: KeyboardEvent) => number;
21
+ /**
22
+ * The keys each command answers to. An explicit binding wins: a default that collides with one
23
+ * is dropped (`{ hint: "f" }` takes `f` from "first row"). `presets` takes two characters, back
24
+ * then forward (`"[]"`).
25
+ */
26
+ export declare function resolveKeys(given: PanelKeys | undefined, page?: boolean): Record<PanelCommand, string[]>;
27
+ /** How a key reads in the shortcuts popover. */
28
+ export declare function keyLabel(key: string, alt?: boolean): string;
@@ -0,0 +1,48 @@
1
+ import { type Schema } from "../core/schema.js";
2
+ import type { Controls } from "../core/store.js";
3
+ import { Edges, Spring } from "./motion.js";
4
+ export interface PresetEntry<V = Record<string, unknown>> {
5
+ readonly id: string;
6
+ readonly kind: "preset" | "variant";
7
+ readonly rawId: string;
8
+ readonly label: string;
9
+ readonly values: V;
10
+ apply(): void;
11
+ }
12
+ export interface ActivePresetState {
13
+ readonly activeId: string;
14
+ readonly activeIndex: number;
15
+ readonly isCustom: boolean;
16
+ }
17
+ /**
18
+ * Resolves which preset or variant is currently active.
19
+ * Honors `lastAppliedId` when its values still match `currentValues`, so cycling never gets
20
+ * stuck when a saved variant has the exact same values as a built-in preset.
21
+ */
22
+ export declare function resolveActivePresetEntry<V extends Record<string, any>>(entries: readonly PresetEntry<V>[], currentValues: V, lastAppliedId: string | null): ActivePresetState;
23
+ export declare function nextPresetIndex(count: number, activeIndex: number, direction: number): number;
24
+ export interface PresetStrip {
25
+ readonly element: HTMLElement;
26
+ readonly track: HTMLElement;
27
+ readonly pill: HTMLElement;
28
+ /** Trailing "+" chip that saves the current values as a new variant (absent when variants are off). */
29
+ readonly saveButton: HTMLButtonElement | null;
30
+ /** The selected pill's left and right edges (track px); the edge facing the move leads. */
31
+ readonly pillEdges: Edges;
32
+ readonly pillY: Spring;
33
+ readonly pillAlpha: Spring;
34
+ getEntries(): readonly PresetEntry<any>[];
35
+ getButtons(): readonly HTMLButtonElement[];
36
+ getActiveState(): ActivePresetState;
37
+ cycle(direction: -1 | 1): void;
38
+ selectById(id: string): void;
39
+ /** Saves the current values as "Variant N"; returns a status message. */
40
+ save(): string;
41
+ /** Deletes the selected chip when it's a saved variant; returns a status message. */
42
+ deleteActive(): string | undefined;
43
+ update(): void;
44
+ dispose(): void;
45
+ }
46
+ export declare function createPresetStrip<S extends Schema>(doc: Document, controls: Controls<S>, showVariants: boolean, run: (action: () => unknown) => void, onAfterChange?: () => void,
47
+ /** What a preset's chip says (its id stays its identity); `controls.presetLabel` by default. */
48
+ presetLabel?: (id: string) => string): PresetStrip;
@@ -0,0 +1,14 @@
1
+ import type { CurveField, GradientField } from "../core/schema.js";
2
+ import { type EditorRow, type RowContext } from "./editors.js";
3
+ /** The custom properties a gradient strip's samples ride on (registered, so they transition). */
4
+ export declare const GRADIENT_VARS: string[];
5
+ /**
6
+ * A gradient: a swatch strip with stop ticks in the head; a wide strip with a handle per stop, the
7
+ * selected stop's colour strips and any presets in the body.
8
+ */
9
+ export declare function gradientRow(c: RowContext<GradientField>): EditorRow;
10
+ /**
11
+ * A curve: its name (when it's a preset) and a mini curve in the head; a graph with a grid,
12
+ * draggable points and a hover crosshair, and shape chips, in the body.
13
+ */
14
+ export declare function curveRow(c: RowContext<CurveField>): EditorRow;
@@ -0,0 +1,21 @@
1
+ import type { ReadoutState } from "../core/readout.js";
2
+ import type { ReadoutField } from "../core/schema.js";
3
+ import { type ReadoutView } from "../ui/readouts.js";
4
+ import type { EditorRow } from "./editors.js";
5
+ import type { RowWave } from "./gpu/renderer.js";
6
+ export interface ReadoutRow extends EditorRow {
7
+ readonly view: ReadoutView;
8
+ /** Something new arrived for this key. */
9
+ notify(): void;
10
+ swap(field: ReadoutField, display: string): void;
11
+ }
12
+ export declare function readoutRow(c: {
13
+ doc: Document;
14
+ key: string;
15
+ display: string;
16
+ field: ReadoutField;
17
+ state: ReadoutState;
18
+ wave: RowWave;
19
+ wake(): void;
20
+ gpu(): boolean;
21
+ }): ReadoutRow;
@@ -0,0 +1,15 @@
1
+ export declare const isAnyRevealing: () => boolean;
2
+ export declare const isRevealingIn: (root: HTMLElement) => boolean;
3
+ export declare const getRevealVersion: () => number;
4
+ export declare const isRevealing: (node: HTMLElement) => boolean;
5
+ /**
6
+ * Eases an in-flow element from height `from` to the height it has now, after its content
7
+ * changed, so what's below glides. Read `from` before the change (mid-flight is fine).
8
+ */
9
+ export declare function resize(node: HTMLElement, from: number): void;
10
+ /**
11
+ * Shows or hides an in-flow element by animating its height (and margins/padding) open or shut,
12
+ * so the content below glides instead of jumping. Interruptible: reversing mid-flight continues
13
+ * from the current height.
14
+ */
15
+ export declare function reveal(node: HTMLElement, show: boolean, after?: () => void, delay?: number): void;
@@ -0,0 +1,2 @@
1
+ declare const _default: ".rn-root {\n display: inline-block;\n position: relative;\n white-space: pre;\n unicode-bidi: isolate;\n vertical-align: baseline;\n}\n.rn-root > .rn-measure,\n.rn-root > .rn-visual { display: none; }\n.rn-root[data-rn-measuring] > .rn-measure {\n display: inline-flex;\n position: relative;\n visibility: hidden;\n white-space: pre;\n padding: 0;\n border: 0;\n}\n.rn-token { display: inline-block; padding: 0; border: 0; }\n.rn-root[data-rn-measuring] > .rn-value,\n.rn-react[data-rn-hydrated] > .rn-semantic,\n.rn-solid[data-rn-hydrated] > .rn-semantic {\n position: absolute;\n inset: 0;\n padding: 0;\n margin: 0;\n color: transparent;\n z-index: 1;\n}\n/* A single native text layer is selectable; decorative reels never enter a copy. */\n.rn-value::selection, .rn-semantic::selection {\n color: HighlightText;\n background: Highlight;\n}\n.rn-root[data-rn-ready] > .rn-visual {\n display: block;\n position: absolute;\n inset: 0;\n pointer-events: none;\n user-select: none;\n}\n.rn-slot {\n position: absolute;\n left: 0;\n overflow: hidden;\n /* Space for italic overhang without changing the measured advance width. */\n box-sizing: content-box;\n padding-inline: 0.15em;\n margin-inline-start: -0.15em;\n -webkit-mask-image: var(--rn-mask, linear-gradient(\n to bottom,\n transparent,\n #000 var(--rn-edge-fade, 0.12em),\n #000 calc(100% - var(--rn-edge-fade, 0.12em)),\n transparent\n ));\n mask-image: var(--rn-mask, linear-gradient(\n to bottom,\n transparent,\n #000 var(--rn-edge-fade, 0.12em),\n #000 calc(100% - var(--rn-edge-fade, 0.12em)),\n transparent\n ));\n -webkit-mask-repeat: no-repeat;\n mask-repeat: no-repeat;\n}\n@supports (overflow: clip) {\n .rn-slot { overflow-x: visible; overflow-y: clip; }\n}\n.rn-slot:not([data-rn-wheel]) {\n overflow: visible;\n -webkit-mask-image: none;\n mask-image: none;\n}\n.rn-enter, .rn-reel, .rn-face { display: block; }\n.rn-reel { position: relative; }\n.rn-ink { display: block; position: absolute; inset: 0; will-change: transform; }\n/* Safari's SVG filter must rasterize the smear's descendants into its input. */\n.rn-smear .rn-ink { will-change: auto; }\n/* Each turning half carries its own perspective transform, not a shared 3D scene. */\n/* The slot acts as the bezel: the card stays vertically framed while it hinges. */\n.rn-slot[data-rn-flap] { -webkit-mask-image: none; mask-image: none; }\n/* Hinged faces must occlude the cards behind them, including with default CSS. */\n:where(.rn-slot[data-rn-flap]) .rn-face { background: var(--rn-flap-background, Canvas); }\n.rn-flap { position: absolute; inset: 0; transform-origin: 50% 50%; backface-visibility: hidden; }\n/* --rn-crease is the visible hinge gap between the two halves. */\n.rn-flap-top { clip-path: inset(0 0 calc(50% + var(--rn-crease, 1px) / 2) 0); }\n.rn-flap-bottom { clip-path: inset(calc(50% + var(--rn-crease, 1px) / 2) 0 0 0); }\n.rn-sharp, .rn-smear { display: block; }\n.rn-smear { position: absolute; inset: 0; pointer-events: none; }\n.rn-blur-defs { position: absolute; width: 0; height: 0; overflow: hidden; }\n.rn-face { text-align: center; white-space: pre; }\n.rn-react, .rn-solid { display: inline-block; position: relative; white-space: pre; unicode-bidi: isolate; }\n.rn-mount { display: inline-block; user-select: none; }\n.rn-mount .rn-value { pointer-events: none; }\n.rn-react:not([data-rn-hydrated]) > .rn-mount,\n.rn-solid:not([data-rn-hydrated]) > .rn-mount { display: none; }\n";
2
+ export default _default;
@@ -0,0 +1,36 @@
1
+ export interface SearchChipSpec {
2
+ readonly id: string;
3
+ readonly label: string;
4
+ readonly count?: boolean;
5
+ }
6
+ /**
7
+ * A panel's search field: a text field that filters rows as you type, and filter chips beside it
8
+ * ("Modified 3") that narrow them further. It's drawn by the DOM in both renderers.
9
+ */
10
+ export interface SearchBar {
11
+ readonly element: HTMLElement;
12
+ readonly input: HTMLInputElement;
13
+ readonly chips: readonly HTMLButtonElement[];
14
+ /** The trimmed query, lower-cased. */
15
+ query(): string;
16
+ /** The chips that are on. */
17
+ active(): ReadonlySet<string>;
18
+ /** Whether anything narrows the rows (a query or a chip). */
19
+ filtering(): boolean;
20
+ /** Shows each counted chip's number. */
21
+ counts(counts: ReadonlyMap<string, number>): void;
22
+ /** Empties the query and turns the chips off. */
23
+ clear(): void;
24
+ /** Sets the query as typed, and (when given) exactly which chips are on. */
25
+ set(query: string | undefined, chips?: readonly string[]): void;
26
+ focus(): void;
27
+ }
28
+ export declare function createSearch(doc: Document, options: {
29
+ placeholder: string;
30
+ chips: readonly SearchChipSpec[];
31
+ change(): void;
32
+ }): SearchBar;
33
+ /** Where `query` matches in `text` (case-insensitive), as [start, end), or undefined. */
34
+ export declare function matchSpan(text: string, query: string): [number, number] | undefined;
35
+ /** Writes `text` into `label`, with the matched span wrapped in `<mark class="knobs-match">`. */
36
+ export declare function markLabel(label: HTMLElement, text: string, span: [number, number] | undefined): void;