@kitlangton/knobs 0.4.0-next.2 → 0.4.0-next.4
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 +62 -12
- package/dist/dev/{chunk-8mabjeyk.js → chunk-0w1xk9jc.js} +162 -1
- package/dist/dev/{chunk-1qzffbpa.js → chunk-76frnh2j.js} +78 -34
- package/dist/dev/{chunk-ayb292zj.js → chunk-rem3qrhz.js} +2 -2
- package/dist/dev/index.js +3 -3
- package/dist/panel.js +240 -34
- package/dist/themes.js +160 -0
- package/dist/types/tokens/schema.d.ts +180 -0
- package/dist/types/ui/compare-css.d.ts +1 -1
- package/dist/types/ui/compare-gpu.d.ts +0 -5
- package/dist/types/ui/compare-model.d.ts +31 -2
- package/dist/types/ui/compare.d.ts +17 -4
- package/dist/types/ui/history-css.d.ts +1 -0
- package/dist/types/ui/history-model.d.ts +236 -0
- package/dist/types/ui/history.d.ts +33 -0
- package/dist/types/ui/icons.d.ts +40 -0
- package/dist/types/ui/index.d.ts +4 -2
- package/dist/types/ui/selection-pill-css.d.ts +1 -0
- package/dist/types/ui/selection-pill.d.ts +103 -0
- package/dist/types/ui/timeline-model.d.ts +23 -0
- package/dist/types/ui/timeline.d.ts +11 -1
- package/dist/types/ui/tree.d.ts +3 -2
- package/dist/types/ui/walkthrough-blocks.d.ts +20 -1
- package/dist/types/ui/walkthrough-model.d.ts +59 -1
- package/dist/types/ui/walkthrough.d.ts +10 -2
- package/dist/ui-react.js +2027 -952
- package/dist/ui-solid.js +2027 -952
- package/dist/ui.js +2047 -952
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1095,7 +1095,7 @@ Scrolling pane bodies, trees and the command palette's list fade their content o
|
|
|
1095
1095
|
**`tree(container, options)`** is an outliner. Rows are virtualised, so 10,000 of them scroll at full speed with about 35 in the DOM. When a branch opens, its children slide out from under it as one block with the rows below, like a drawer, and closing folds them back. The tree takes items with `id`, `label` and `children` (or `getId`, `getLabel` and `getChildren` for your own shape; an array, even empty, makes a parent that takes drops). Options:
|
|
1096
1096
|
|
|
1097
1097
|
- `icon` and `detail` for a glyph and dimmed text (or nodes of your own), or `render` for your own row content
|
|
1098
|
-
- `glide: true` to show the selected row as one highlight that
|
|
1098
|
+
- `glide: true` to show the selected row as the selection pill (`selectionPill`): one highlight that slides to the next row picked on the state spring (.3 s, no bounce), the row's text bright under it, instead of each row lighting in place; several selected rows light in place
|
|
1099
1099
|
- `toggles` for row accessories such as `visible` and `locked`, which show at rest only in their unusual state
|
|
1100
1100
|
- `filter` for a query or a test; matching rows show with their ancestors, the match marked
|
|
1101
1101
|
- `selection`, `expanded` and `rowHeight` (`--k-row` by default)
|
|
@@ -1181,7 +1181,7 @@ const clock = timeline(dock, {
|
|
|
1181
1181
|
})
|
|
1182
1182
|
```
|
|
1183
1183
|
|
|
1184
|
-
**`timeline(container, options)`** is a scrubber for time-based work. The ruler counts in seconds or frames (`units`) with ticks that thin out as it zooms (`⌘` wheel, a pinch, `+`/`-`, `0` fits) and pans with the wheel or a trackpad. The playhead follows the hand 1:1, pulls softly toward markers and lands on frames (`snap`). Markers can be added (`M`), dragged, renamed (`Enter`) and removed, and `[`/`]` jump between them; `I` and `O` set a loop range. `Space` plays on one rAF clock that sleeps when nothing moves, and `←`/`→` step a frame (`⇧` ten; `arrows: { step: 0.5, shift: 2 }` makes them seconds, the playhead gliding there) and `,`/`.` always do
|
|
1184
|
+
**`timeline(container, options)`** is a scrubber for time-based work. The ruler counts in seconds or frames (`units`) with ticks that thin out as it zooms (`⌘` wheel, a pinch, `+`/`-`, `0` fits) and pans with the wheel or a trackpad. The playhead follows the hand 1:1, pulls softly toward markers and lands on frames (`snap`). Markers can be added (`M`), dragged, renamed (`Enter`) and removed, and `[`/`]` jump between them; `I` and `O` set a loop range. `Space` plays on one rAF clock that sleeps when nothing moves, and `←`/`→` step a frame (`⇧` ten; `arrows: { step: 0.5, shift: 2 }` makes them seconds, the playhead gliding there) and `,`/`.` always do. A jump the hand didn't make catches up: a marker's click, a loop's wrap, a press on the track away from the playhead, play from elsewhere and `seek(t, { glide: true })` all carry the playhead from where it is on a quick spring (.15 s, no bounce) while the time lands at once; a drag stays 1:1, and moves during a catch-up follow the hand while the rest settles. There's no clock beside play: the time shows under the pointer on the track, in seconds, while hovering or scrubbing. `variant: "lane"` makes it one slim lane (a compare's own): ticks without labels, markers as faint chapter ticks with the current one (the last at or before the playhead) in text colour, nothing to edit, and the wheel left to the page. A right-click on the ruler, a marker or a range opens a context menu. It reports `onSeek(time, source)` (`"scrub" | "key" | "marker" | "play" | "code"`), `onPlay`, `onMarkers`, `onRanges` and `onCross(marker)`. The handle has `time`, `playing`, `duration`, `fps`, `markers`, `ranges`, `view`, `seek`, `play`, `pause`, `toggle`, `update`, `fit`, `zoom`, `focus` and `dispose`. Pieces bound to a timeline hear it with `listen({ onSeek, onPlay, onView, onScrub, onRanges })` (it returns a stop), and `drive(clock)` makes playback follow another clock, such as a video's `currentTime`, so the two never drift. `Timeline` in `knobs/ui/react` and `knobs/ui/solid` follows its props. The Lab's scene clock and Boom retrigger run from one under the viewport.
|
|
1185
1185
|
|
|
1186
1186
|
### Compare
|
|
1187
1187
|
|
|
@@ -1192,8 +1192,8 @@ import { compare, compareStrip, timeline } from "knobs/ui"
|
|
|
1192
1192
|
const review = compare(el, {
|
|
1193
1193
|
before: { src: "/runs/41.mp4" },
|
|
1194
1194
|
after: { src: "/runs/42.mp4" },
|
|
1195
|
-
mode: "side", // the default
|
|
1196
|
-
timeline: true,
|
|
1195
|
+
mode: "side", // the default, or "wipe"
|
|
1196
|
+
timeline: true, // a slim lane of its own; its markers are chapter ticks
|
|
1197
1197
|
onView: ({ zoom, loop }) => log(zoom, loop), // { u, v, w, h }, { start, end } | null
|
|
1198
1198
|
})
|
|
1199
1199
|
review.seekBy(0.5)
|
|
@@ -1202,13 +1202,18 @@ review.setLoop(true) // around the playhead; drag its ends on the timeline
|
|
|
1202
1202
|
// A long page of them: each loads near the view and lets go well off it.
|
|
1203
1203
|
for (const step of steps) compare(step.el, { before: step.before, after: step.after, timeline: true })
|
|
1204
1204
|
|
|
1205
|
+
// The difference, opted in as a third mode; a chapter's click jumps with a catch-up.
|
|
1206
|
+
const diff = compare(el, { before, after, modes: ["side", "wipe", "difference"], timeline: true })
|
|
1207
|
+
diff.timeline?.update({ markers: [{ id: "a", time: 1.5, label: "The card moves" }] })
|
|
1208
|
+
diff.seek(1.5, { glide: true })
|
|
1209
|
+
|
|
1205
1210
|
// Or composed: the app places the pieces and binds them to one timeline.
|
|
1206
1211
|
const clock = timeline(dock, { duration: 6, fps: 30 })
|
|
1207
1212
|
compare(viewer, { before, after, timeline: clock })
|
|
1208
1213
|
compareStrip(strip, { before, after, timeline: clock })
|
|
1209
1214
|
```
|
|
1210
1215
|
|
|
1211
|
-
**`compare(container, options)`** is a before/after viewer for videos and images (by extension, or `kind`).
|
|
1216
|
+
**`compare(container, options)`** is a before/after viewer for videos and images (by extension, or `kind`). It offers two modes, side by side (the default `mode`: a split screen down the middle, each side filling its half) and a wipe; `modes: ["side", "wipe", "difference"]` adds a difference (changes above `threshold` in one accent, `--k-compare-diff`), and one mode hides the bar. The modes sit in a segmented control above the stage, the selection pill sliding to the one picked. It draws in one WebGPU pass that copies a frame in only when one arrives, and draws only when something changed; where there's no WebGPU, two `<video>`s with a clip-path wipe stand in. Pinch, `⌘`/ctrl-wheel or double-click zooms into either side and both zoom to the same part (the wheel and a drag pan it, both 1:1); a small glass pill in the corner shows how far, with a reset (`0`, a double-click, `Escape`), which glides back. Overlaid, the sides are letterboxed, never cropped. Both videos run from one clock: paused, scrubbed or stepped, each seeks to the frame's midpoint, coalesced while a seek is in flight; playing, After leads, Before's rate leans by up to 25% to stay on it (it seeks past 90 ms), and a bound timeline follows After's time, so only one clock ever moves it (`Space` resumes from the frame showing). Scrubbing answers at once even on raw screen recordings with a keyframe every 8–18 s: frames decoded in the background (WebCodecs where the file is a plain MP4, else a hidden `<video>`) sit in a small cache shared by every viewer and strip of the same source, and the nearest shows while the exact seek lands (mid-drag, far from any cached frame, `fastSeek` answers first; letting go seeks exactly). Encoding with a keyframe every 15 frames makes every seek exact and near instant: `COMPARE_FFMPEG` holds the command (`ffmpeg -i in.mov -vf fps=30 -fps_mode cfr -c:v libx264 -crf 18 -g 15 … out.mp4`). Sources load only near the view and are let go 3 s after leaving it (`lazy: false` keeps them), every viewer shares one GPU device, and in a container with no height of its own it takes the height its sides need, half its width in their shape, so the split has no margins (`aspect` before they load); with a height of its own (a card going full-window, say), the pair fits as a whole and refits as it resizes, keeping the zoom. On a card (`.knobs-surface`, a split's pane) or marked `data-nested`, its stage drops its fill, so one surface shows. Bind an existing `timeline()` (`timeline: clock`), or pass `timeline: true` for a slim lane of its own (`variant: "lane"`): there's no clock or frame readout anywhere, only the time under the pointer on the lane, and its markers (a walkthrough's chapters) are faint ticks, the current one in text colour. `seek(t, { glide: true })` is a chapter's jump: the videos land at once and the playhead catches up. Loop (`L`, the loop icon) sets a loop range around the playhead on the timeline, whose ends drag, and playback stays inside it. The wipe's line carries a raised 16×28 grip at the pointer's height; dragging it is 1:1, the cursor hides and the line and grip brighten, and a press elsewhere on the stage brings the line there on a quick catch-up (.15 s). Before and After ride either side of the seam while wiping, each fading as its side runs out of room. The wipe is a slider too (`←`/`→`, `⇧` 10%); a mode change glides. Keys when focused: `Space` plays, `←`/`→` seek half a second (`⇧` two), the playhead gliding there while the videos land at once, `,`/`.` step a frame, `1`–`3` pick the offered modes in order and `S` `W` (`D`, when offered) by name, `Z` held shows the loupe (or `loupe: true`), `L` loops, `=`/`-`/`0` zoom. It reports `onMode`, `onWipe` and `onView({ zoom, loop })`; the handle has `mode`, `modes`, `wipe`, `zoom`, `loop`, `time`, `playing`, `duration`, `renderer`, `timeline`, `strip`, `update`, `seek`, `seekBy`, `play`, `pause`, `toggle`, `step`, `setZoom`, `setLoop`, `focus` and `dispose`. A frame strip is off by default (`strip: true` puts one over the timeline); **`compareStrip(container, { before, after, timeline })`** is the same piece on its own: it draws Before over After along the timeline's view from the same frame cache, decoded only while it's on screen, with a bar for how much each column differs; a press scrubs. `Compare` and `CompareStrip` are in `knobs/ui/react` and `knobs/ui/solid`. The Lab's View switch shows one on its scene timeline.
|
|
1212
1217
|
|
|
1213
1218
|
### Activity
|
|
1214
1219
|
|
|
@@ -1291,13 +1296,13 @@ const diff = codeDiff(el, {
|
|
|
1291
1296
|
for (const step of steps) codeDiff(step.el, { ...look, patch: step.patch, height: "auto" })
|
|
1292
1297
|
```
|
|
1293
1298
|
|
|
1294
|
-
**`codeDiff(container, options)`** shows a code diff in a knobs card: a header with the file's path, its `+12 −3`, ‹ 2 of 5 › when there are several files (`nav: false` hides it), a wrap toggle and Split | Unified, over the diff. The diff itself is drawn by [`@pierre/diffs`](https://diffs.com) (Shiki highlighting, word-level changes, hunks that expand when whole files are known), an optional peer dependency: install it to use diffs (`npm i @pierre/diffs`). It loads on first use, so `knobs/ui` doesn't carry it. Its colours come from the pieces' tokens, so dark, light, presets and `restyle()` carry into it. `--k-diff-add`, `--k-diff-del` and `--k-diff-bg` tune it, and `syntax: { dark, light }` picks Shiki themes for the code. It takes `patch` (`git diff` or `git show` output, one file or many) or `files: [{ name, before, after, lang? }]`, plus `file`, `layout`, `wrap`, `onFile`, `onLayout`, `onWrap` and `onLines(lines, file)` (dragging over line numbers selects lines). Changing the file, the layout or the wrap fades the new view in over the old in place (.3 s in, .24 s out, a 3px blur while it fades; a .16 s fade under reduced motion). With `height: "fill"` the card fills its container and each file keeps its scroll. With `height: "auto"` it's a self-contained piece for a long page: it's as tall as the file's diff up to `maxHeight` (640, or 70% of the window when that's less) and scrolls inside past that, springing to each file's height (.4 s, no bounce). It holds the height the diff will take from the first frame, counted from the patch's rows before the renderer has loaded, so nothing below it jumps. It also draws only within a screen of the viewport (of the scroller it sits in) and lets go of its views four screens away, keeping its height; `lazy: false` draws it at once, and `lazy: true` does this with `height: "fill"`. Pass `viewed` (names) or `onViewed(viewed, file)` for a Viewed tick in the header. `stack: true` puts every file down one scroller, as GitHub's Files changed does: each under its own header (status, path, counts and their bar, Viewed) that sticks to the top until the next file's pushes it off: flush (square, no card around each file, a gap between files), opaque in the code's colour, with a hairline under it only while it's stuck. The card's header then sums the change, ‹ › and `show()` glide to a file (.4 s), the file on show follows the scroll, and each file draws only near the view.
|
|
1299
|
+
**`codeDiff(container, options)`** shows a code diff in a knobs card: a header with the file's path, its `+12 −3`, ‹ 2 of 5 › when there are several files (`nav: false` hides it), a wrap toggle and Split | Unified (a segmented control, the selection pill sliding to the one picked), over the diff. Its buttons are Phosphor icons. The diff itself is drawn by [`@pierre/diffs`](https://diffs.com) (Shiki highlighting, word-level changes, hunks that expand when whole files are known), an optional peer dependency: install it to use diffs (`npm i @pierre/diffs`). It loads on first use, so `knobs/ui` doesn't carry it. Its colours come from the pieces' tokens, so dark, light, presets and `restyle()` carry into it. `--k-diff-add`, `--k-diff-del` and `--k-diff-bg` tune it, and `syntax: { dark, light }` picks Shiki themes for the code. It takes `patch` (`git diff` or `git show` output, one file or many) or `files: [{ name, before, after, lang? }]`, plus `file`, `layout`, `wrap`, `onFile`, `onLayout`, `onWrap` and `onLines(lines, file)` (dragging over line numbers selects lines). Changing the file, the layout or the wrap fades the new view in over the old in place (.3 s in, .24 s out, a 3px blur while it fades; a .16 s fade under reduced motion). With `height: "fill"` the card fills its container and each file keeps its scroll. With `height: "auto"` it's a self-contained piece for a long page: it's as tall as the file's diff up to `maxHeight` (640, or 70% of the window when that's less) and scrolls inside past that, springing to each file's height (.4 s, no bounce). It holds the height the diff will take from the first frame, counted from the patch's rows before the renderer has loaded, so nothing below it jumps. It also draws only within a screen of the viewport (of the scroller it sits in) and lets go of its views four screens away, keeping its height; `lazy: false` draws it at once, and `lazy: true` does this with `height: "fill"`. Pass `viewed` (names) or `onViewed(viewed, file)` for a Viewed tick in the header. `stack: true` puts every file down one scroller, as GitHub's Files changed does: each under its own header (status, path, counts and their bar, Viewed) that sticks to the top until the next file's pushes it off: flush (square, no card around each file, a gap between files), opaque in the code's colour, with a hairline under it only while it's stuck. The card's header then sums the change, ‹ › and `show()` glide to a file (.4 s), the file on show follows the scroll, and each file draws only near the view.
|
|
1295
1300
|
|
|
1296
1301
|
Its scrollers fade their content out at an edge with more beyond it (a mask: at the top once scrolled, below a stuck header, and at the bottom while there's more below, `--k-diff-fade`, 20px), easing in and out on the .25 s spring. Its scrollbars are thin ones drawn over the code that take no room and stay hidden until the pointer is over the diff, or while you scroll or drag: `overlayScrollbar` up and down, and a bar per code column across, kept at the bottom of what shows of the column however far down a long file you are (the renderer's own, inside its shadow root, are hidden). One inset runs all round, `--k-diff-inset` (8px, the renderer's own gap): the header's controls sit it in from the top and right, the path, the separators and the line numbers it in from the left, and the code ends it above the bottom. Inner corners (separators, the header's controls) are the outer corner less that distance, so they're concentric with the card. On another surface the diff takes no inset across, so its header and code line up with the surface's own content (a walkthrough's caption), and its corners are measured from the surface's. The header's hairline shows only once the code has scrolled under it. The handle has `files`, `file`, `layout`, `wrap`, `viewed`, `show(name)`, `step(±1)`, `update({ patch?, files?, file?, layout?, wrap?, viewed?, height?, maxHeight? })`, `ready` (once drawn) and `dispose()`. `update({ height: "fill" | "auto" })` switches in place, keeping the views, their scroll and the sticky headers; the new height isn't sprung, so a container whose size is moving (a walkthrough card going full window) is followed, not fought.
|
|
1297
1302
|
|
|
1298
1303
|
**One surface.** Cards never nest. Whatever draws a card carries `.knobs-surface` (a walkthrough's step; put it on your own cards too), and a split's pane counts as one; a piece inside a surface draws no card of its own, so a diff in a step, a pane or your card shows no second fill or ring, and a `diffReview` inside one parts its panes on a hairline instead of drawing them as cards. The diff's code keeps an opaque fill under its sticky line numbers, the colour showing behind it, so it still matches.
|
|
1299
1304
|
|
|
1300
|
-
**`diffReview(container, options)`** pairs it with a file list in one card. The list is a drawer at the card's left that springs open and shut between 0 and 256px (`listSize`; .4 s, no bounce), from a button at the start of the diff's header or `⌘B` / `Ctrl+B` while you're working in the review; the diff reflows as it moves, the list slides out from under it, and with an `id` it stays as you left it (`listOpen: false` starts it shut). The list is built on `tree()` and laid out as GitHub's, Graphite's and VS Code's are: a filter field on top (every word must be in the path: `ui diff`; `Esc` clears it, `↓` or `Enter` goes to the list), then a compact tree (28px rows, `--k-diff-row`) with folders folded into paths (`src/ui` is one row when `src` holds nothing else). Each file shows its change as a coloured letter (M amber, A green, D red and struck through, R blue; `--k-diff-mod` and `--k-diff-move` tune the two new ones), its `+12 −3` and a five-square bar of the share added and removed, and a tick to mark it viewed (on a folder, everything in it). Viewed files dim, the list's title counts them (`2/5`), and with an `id` they're remembered until their change moves on (each is saved with a fingerprint of its diff). The file on show has one highlight that
|
|
1305
|
+
**`diffReview(container, options)`** pairs it with a file list in one card. The list is a drawer at the card's left that springs open and shut between 0 and 256px (`listSize`; .4 s, no bounce), from a button at the start of the diff's header or `⌘B` / `Ctrl+B` while you're working in the review; the diff reflows as it moves, the list slides out from under it, and with an `id` it stays as you left it (`listOpen: false` starts it shut). The list is built on `tree()` and laid out as GitHub's, Graphite's and VS Code's are: a filter field on top (every word must be in the path: `ui diff`; `Esc` clears it, `↓` or `Enter` goes to the list), then a compact tree (28px rows, `--k-diff-row`) with folders folded into paths (`src/ui` is one row when `src` holds nothing else). Each file shows its change as a coloured letter (M amber, A green, D red and struck through, R blue; `--k-diff-mod` and `--k-diff-move` tune the two new ones), its `+12 −3` and a five-square bar of the share added and removed, and a tick to mark it viewed (on a folder, everything in it). Viewed files dim, the list's title counts them (`2/5`), and with an `id` they're remembered until their change moves on (each is saved with a fingerprint of its diff). The file on show has the selection pill: one highlight that slides to the next on the state spring (.3 s, no bounce), its row's text sharp and bright under it while other rows stay as they are (the tree's `glide` option). Picking a file shows it. The handle has the pieces, `tree` and `diff`, plus `listOpen`, `toggleList(open?)`, `viewed`, `setViewed(names, on)`, `filter(query)` and `update()`; `viewed` and `onViewed(viewed, file)` seed and report the marks, and `search: false` drops the field. To place the tree and the diff yourself, `diffFiles({ patch })` lists the files with their counts in tree order, `diffTree(files)` makes the tree's items, and `diffCounts(file, doc, { bar })` and `diffStatus(file)` give a row's counts and letter (a tree's `detail` and `icon`). `CodeDiff` and `DiffReview` in `knobs/ui/react` and `knobs/ui/solid` follow `patch`, `files`, `file`, `layout`, `wrap`, `viewed`, `height` and `maxHeight`. The demo is `examples/lab-diff.html`.
|
|
1301
1306
|
|
|
1302
1307
|
### Ideas grid (bento)
|
|
1303
1308
|
|
|
@@ -1348,7 +1353,23 @@ const doc: WalkthroughDoc = {
|
|
|
1348
1353
|
const w = walkthrough(container, { doc, onFeedback: (fb) => send(fb) })
|
|
1349
1354
|
```
|
|
1350
1355
|
|
|
1351
|
-
**`walkthrough(container, { doc })`** is the page an agent writes to show its work: a plain document (JSON) of sections and steps, each step
|
|
1356
|
+
**`walkthrough(container, { doc })`** is the page an agent writes to show its work: a plain document (JSON) of sections and steps, each step a title, a caption, its media and what it asks (a note, or a pick between options). It reads as one calm column at a readable width (`--k-walkthrough-width`, 680px), the contents rail beside it on the right (`rail: "left"`, or `false`), on the page tokens: the intro, the updates and each section a section's room apart (`--k-space-section`, 96px, a hairline in the middle), the groups and steps inside a section a group's room apart (`--k-space-group`, 48px), prose at 68ch. Steps sit on the page with a hairline between them; `cards: true` puts each on a card of its own, the one surface its media sit on (nothing inside draws a fill and a ring of its own). Titles take inline Markdown (`` `code` ``, `[links](…)`); the contents read them as plain words.
|
|
1357
|
+
|
|
1358
|
+
A section's meta line leads with its **kicker** in text colour: `"PR 2 of 5"` by default where its `link` is a pull request (counted among the sections that link one). The doc's `kickers` counts with another noun, `{ noun: "Part" }` giving every section "Part 2 of 6", or none with `false`. A section's own `kicker: "Epilogue"` wins over its count and `kicker: false` hides it, without renumbering the rest. The contents rail isn't numbered. Its PR link, status and so on follow in faint, joined by `·`. Its title (20/28) outranks the page's (16/24) and its steps' (13/20). Steps aren't numbered on screen, but a ref still names one by its key, id or number (`"1.2"`): `step` on an update, a history event, a stack item or a table cell, and clicking goes there as `j` / `k` do.
|
|
1359
|
+
|
|
1360
|
+
Notes come from a launcher in the column's corner (`noteBar: "collapsed"`, the default) that opens into the bar on a click, `n`, a recording or ink, and folds back when it's empty; `"docked"` keeps the bar there, `"hidden"` drops it (`w.send()` still works). Typed, spoken or inked, each note carries what was on show (a video's time and chapter, a compare's loop and zoom, a diff's file) and a short log of what led up to it; `onFeedback`, `w.feedback` and `w.markdown()` hand it back. The page keeps the bar's height clear at its end and as its scroller's `scroll-padding-bottom`, so `j` / `k`, `go()` and the last step never land under it, and full window stops above it. `j` / `k` move between steps (`Home` / `End` to the first and last), `←` / `→` seek, `f` goes full window, `n` writes a note, `1`–`9` pick.
|
|
1361
|
+
|
|
1362
|
+
Media is a bare URL (a video or picture), or `compare`, `video`, `image`, `diff`, `code`, `terminal`, `metric`, `callout`, `text`, `history`, `stack`, `table`, or `mount` (your own, `(el) => cleanup`; the one that isn't JSON). A step's media sit one under another (a group's room apart); `columns: 2` sets them side by side where there's room, and `more: "More clips"` folds everything after the first under a quiet toggle. Only a picture's frame and a code block are bounded; a metric, a callout, a table, a stack and a history sit on the page.
|
|
1363
|
+
|
|
1364
|
+
**The feed** (`updates` and `qa`, newest first) is a calm list a group's room apart, a hairline between items and no boxes: a meta line (when · the step's PR · `status`), the question in text colour (or the update), its answer in dim prose, and its `trail` (what Kit did before asking, `"0:04 · Played the compare"`) folded under a small faint **Context** toggle whose height springs open on the state spring (.3 s) while the lines fade in place under a soft bottom edge. `status: "shipped"` reads Shipped, `"changes"` reads Changes queued.
|
|
1365
|
+
|
|
1366
|
+
```json
|
|
1367
|
+
{ "qa": [{ "at": "2026-10-19T12:10:00-07:00", "q": "Why is there no video for #57158?",
|
|
1368
|
+
"a": "It's the installer redirect: nothing to watch.", "step": "4.1", "status": "shipped",
|
|
1369
|
+
"trail": ["0:03 · Viewed TUI /connect", "0:11 · Played the compare at 0:04"] }] }
|
|
1370
|
+
```
|
|
1371
|
+
|
|
1372
|
+
The demo is `examples/walkthrough.html`.
|
|
1352
1373
|
|
|
1353
1374
|
**`history`**: dated events down a spine, a tone dot each (`good`, `warn`, `bad`, `info`, `dim`), under quiet group headings. `provenance` says whether an event was seen in the record (`"verified"`) or worked out from behaviour (`"inferred"`, a ring for a dot and a dashed tag), and `source` where (`"verified · git"`). `evidence` is small tags, linked or not; `type: "release"` draws a diamond, `"audit"` a square. Groups take `events` or `rows`; a bare `events` list is one group. In a narrow card the date goes over the event.
|
|
1354
1375
|
|
|
@@ -1371,7 +1392,7 @@ const w = walkthrough(container, { doc, onFeedback: (fb) => send(fb) })
|
|
|
1371
1392
|
"delta": { "add": 446, "del": 47 }, "status": "Stacked on #57146", "tone": "good", "summary": "Modal, notice and prompt recall." } ] }
|
|
1372
1393
|
```
|
|
1373
1394
|
|
|
1374
|
-
**`table`**: a real `<table>` for audits and matrices. Rows are cells by column key, bare or under `cells`; a cell is text, a number, or `{ text, href?, code?, badge?, tone?, step? }` (a `badge` is a tone chip). Columns take `mono` and `align` (number columns go right by themselves). Figures are tabular; a tall table keeps its head stuck, a
|
|
1395
|
+
**`table`**: a real `<table>` for audits and matrices. Rows are cells by column key, bare or under `cells`; a cell is text, a number, or `{ text, href?, code?, badge?, tone?, step? }` (a `badge` is a tone chip). Columns take `mono` and `align` (number columns go right by themselves). Figures are tabular; a tall table keeps its head stuck, and its bars show thin on hover. `caption` goes under it. Where the step is narrower than the columns' natural width (long text keeping a measure, code on one line), each row becomes a block: its `primary` cell (the first column by default) as its title with its badges at the end of the line, the rest as term and value under it, the blocks parted by hairlines. `stack: "always"` always stacks; `stack: "never"` scrolls across instead, edges fading where there's more.
|
|
1375
1396
|
|
|
1376
1397
|
```json
|
|
1377
1398
|
{ "kind": "table", "caption": "From a clean HOME, Oct 20", "columns": [
|
|
@@ -1382,7 +1403,7 @@ const w = walkthrough(container, { doc, onFeedback: (fb) => send(fb) })
|
|
|
1382
1403
|
{ "channel": "brew install …/opencode-v2", "days": 31, "state": { "text": "Pending", "badge": "info", "step": "4.6" } } ] }
|
|
1383
1404
|
```
|
|
1384
1405
|
|
|
1385
|
-
**`chapters`** on a `video` (or a `compare`):
|
|
1406
|
+
**`chapters`** on a `video` (or a `compare`): a readout list under it, a row each (number · label · start). A click selects the chapter at once while the media seeks there and plays, and goes in the note's log; the selection pill slides to the chapter playing (the last that started at or before the playhead) and fades out in place outside them, and a note's `media` names it (`chapter`). A chapter ends at `end`, else `start + duration`, else the next one's start. On a compare they're also its timeline's markers. A video's `captions` (or `captionsSrc`) is a WebVTT URL, shown by default.
|
|
1386
1407
|
|
|
1387
1408
|
```json
|
|
1388
1409
|
{ "kind": "video", "src": "journey.mp4", "poster": "journey.png", "captions": "captions.vtt", "chapters": [
|
|
@@ -1396,7 +1417,7 @@ Panels take a `theme`, an `appearance`, `density: "compact" | "default" | "comfo
|
|
|
1396
1417
|
|
|
1397
1418
|
### Themes and appearance
|
|
1398
1419
|
|
|
1399
|
-
Two themes ship in `knobs/themes`: **Knobs** (the default: a near-black glass panel, a white accent, alpha hairlines) and **Void** (true black and flat, solid hairlines, text capped at `#ededed`, a black stage behind compared media; for OLED screens and video review). Each has a dark and a light appearance.
|
|
1420
|
+
Two themes ship in `knobs/themes`: **Knobs** (the default: a near-black glass panel, a white accent, alpha hairlines) and **Void** (true black and flat, solid hairlines, text capped at `#ededed`, a black stage behind compared media; for OLED screens and video review). Each has a dark and a light appearance. `--k-before` and `--k-after` name a comparison's two sides, neutral by default (`fg-3` and `fg`).
|
|
1400
1421
|
|
|
1401
1422
|
```ts
|
|
1402
1423
|
import { defineTheme, themes } from "knobs/themes"
|
|
@@ -1463,6 +1484,8 @@ A reset that went back to the active preset rather than the defaults carries `ba
|
|
|
1463
1484
|
|
|
1464
1485
|
Generated from the token schema (`bun run scripts/tokens-table.ts`), with the Knobs theme's values. Inputs are the dials a theme turns, semantic tokens are what pieces read, hooks style one component.
|
|
1465
1486
|
|
|
1487
|
+
The page roles (**Space**: `--k-space-inside` 4 · `sibling` 8 · `title` 12 · `group` 48 · `section` 96 · `column` 24, `--k-pad-page` 24 (16 under 640px) and `--k-pad-card` 12; **Type**: `--k-type-heading` 20/28 · `title` 16/24 · `body` 13/20 · `label` 12/16 · `small` 11/16, with `--k-leading-*`) are what a page built from knobs/ui (a walkthrough) is laid out on. They don't scale with density: density sizes a panel's controls, and the panel doesn't read them. Two weights (400, 500), mono one size down from what's around it, tabular figures.
|
|
1488
|
+
|
|
1466
1489
|
<!-- tokens:start -->
|
|
1467
1490
|
|
|
1468
1491
|
### Accent
|
|
@@ -1504,6 +1527,16 @@ Generated from the token schema (`bun run scripts/tokens-table.ts`), with the Kn
|
|
|
1504
1527
|
|---|---|---|---|---|
|
|
1505
1528
|
| `--k-font` | input | `system-ui,-apple-system,"SF Pro Text",sans-serif` | `system-ui,-apple-system,"SF Pro Text",sans-serif` | UI font stack. |
|
|
1506
1529
|
| `--k-mono` | input | `"SF Mono",SFMono-Regular,ui-monospace,Menlo,monospace` | `"SF Mono",SFMono-Regular,ui-monospace,Menlo,monospace` | Monospace font stack. |
|
|
1530
|
+
| `--k-type-heading` | semantic | `20px` | `20px` | Section headings (a PR's title, under its kicker), weight 500. |
|
|
1531
|
+
| `--k-leading-heading` | semantic | `28px` | `28px` | Line height for type-heading. |
|
|
1532
|
+
| `--k-type-title` | semantic | `16px` | `16px` | A page's title, weight 500. |
|
|
1533
|
+
| `--k-leading-title` | semantic | `24px` | `24px` | Line height for type-title. |
|
|
1534
|
+
| `--k-type-body` | semantic | `13px` | `13px` | Prose, questions, list rows, step titles; 400, or 500 for emphasis. |
|
|
1535
|
+
| `--k-leading-body` | semantic | `20px` | `20px` | Line height for type-body. |
|
|
1536
|
+
| `--k-type-label` | semantic | `12px` | `12px` | Labels over media, weight 500; mono inside body text. |
|
|
1537
|
+
| `--k-leading-label` | semantic | `16px` | `16px` | Line height for type-label. |
|
|
1538
|
+
| `--k-type-small` | semantic | `11px` | `11px` | Meta, controls, keys, timestamps; mono inside labels. |
|
|
1539
|
+
| `--k-leading-small` | semantic | `16px` | `16px` | Line height for type-small. |
|
|
1507
1540
|
| `--k-font-size` | semantic | `round(calc(12px * (1 + (var(--k-density) - 1) * .5)),1px)` | `round(calc(12px * (1 + (var(--k-density) - 1) * .5)),1px)` | Body size; a 5-step scale derives privately. Derived: `round(calc(12px * (1 + (var(--k-density) - 1) * .5)),1px)`. |
|
|
1508
1541
|
| `--k-value-font` | semantic | `var(--k-font)` | `var(--k-font)` | Font for readouts and values (labPreset: mono). Derived: `var(--k-font)`. |
|
|
1509
1542
|
|
|
@@ -1570,6 +1603,8 @@ Generated from the token schema (`bun run scripts/tokens-table.ts`), with the Kn
|
|
|
1570
1603
|
| `--k-diff-add` | semantic | `#59d38c` | `#0a7e3a` | Added lines; line and word tints derive privately (12% / 38%). Derived: `var(--k-ok)`. |
|
|
1571
1604
|
| `--k-diff-del` | semantic | `#fa6863` | `#cc2827` | Deleted lines. Derived: `var(--k-danger)`. |
|
|
1572
1605
|
| `--k-diff-mod` | semantic | `#f7bc50` | `#b66c00` | Modified lines. Derived: `var(--k-warn)`. |
|
|
1606
|
+
| `--k-before` | semantic | `#9e9ea3` | `#96969b` | Before in a comparison, and only Before: its label and side of the seam. Neutral unless a theme gives it a colour. Derived: `var(--k-fg-3)`. |
|
|
1607
|
+
| `--k-after` | semantic | `#f4f5f9` | `#1a1a1d` | After in a comparison, and only After. Derived: `var(--k-fg)`. |
|
|
1573
1608
|
| `--k-series-1` | semantic | `#6db0f4` | `#2378c2` | Chart series 1. |
|
|
1574
1609
|
| `--k-series-2` | semantic | `#66c189` | `#008b4f` | Chart series 2. |
|
|
1575
1610
|
| `--k-series-3` | semantic | `#d79f4c` | `#9c6900` | Chart series 3. |
|
|
@@ -1577,6 +1612,19 @@ Generated from the token schema (`bun run scripts/tokens-table.ts`), with the Kn
|
|
|
1577
1612
|
| `--k-series-5` | semantic | `#bc97e8` | `#885cb5` | Chart series 5. |
|
|
1578
1613
|
| `--k-series-6` | semantic | `#25c2c2` | `#008686` | Chart series 6. |
|
|
1579
1614
|
|
|
1615
|
+
### Space
|
|
1616
|
+
|
|
1617
|
+
| Token | Tier | Dark | Light | |
|
|
1618
|
+
|---|---|---|---|---|
|
|
1619
|
+
| `--k-space-inside` | semantic | `var(--k-unit)` | `var(--k-unit)` | Parts of one thing: an icon and its label, a meta line and its title. Derived: `var(--k-unit)`. |
|
|
1620
|
+
| `--k-space-sibling` | semantic | `calc(var(--k-unit) * 2)` | `calc(var(--k-unit) * 2)` | Siblings in a group: buttons in a row, a list item's lines. Derived: `calc(var(--k-unit) * 2)`. |
|
|
1621
|
+
| `--k-space-title` | semantic | `calc(var(--k-unit) * 3)` | `calc(var(--k-unit) * 3)` | A heading and what it heads. Derived: `calc(var(--k-unit) * 3)`. |
|
|
1622
|
+
| `--k-space-group` | semantic | `calc(var(--k-unit) * 12)` | `calc(var(--k-unit) * 12)` | Groups inside a section (prose, video, diff), stacked media, feed items (a hairline in the middle). Derived: `calc(var(--k-unit) * 12)`. |
|
|
1623
|
+
| `--k-space-section` | semantic | `calc(var(--k-unit) * 24)` | `calc(var(--k-unit) * 24)` | Sections of a page (the intro, the updates, each PR), a hairline in the middle. Derived: `calc(var(--k-unit) * 24)`. |
|
|
1624
|
+
| `--k-space-column` | semantic | `calc(var(--k-unit) * 6)` | `calc(var(--k-unit) * 6)` | Columns: a contents rail and the page, media side by side. Derived: `calc(var(--k-unit) * 6)`. |
|
|
1625
|
+
| `--k-pad-page` | semantic | `calc(var(--k-unit) * 6)` | `calc(var(--k-unit) * 6)` | A page's edge; 16px under 640px wide. Derived: `calc(var(--k-unit) * 6)`. |
|
|
1626
|
+
| `--k-pad-card` | semantic | `calc(var(--k-unit) * 3)` | `calc(var(--k-unit) * 3)` | Inside a card or popover. Derived: `calc(var(--k-unit) * 3)`. |
|
|
1627
|
+
|
|
1580
1628
|
### Material
|
|
1581
1629
|
|
|
1582
1630
|
| Token | Tier | Dark | Light | |
|
|
@@ -1875,7 +1923,9 @@ The package has two core exports selected through the standard `development` con
|
|
|
1875
1923
|
| `toast(message, { tone?, linger?, action?, within? })` | A status pill at the bottom centre. |
|
|
1876
1924
|
| `menu(anchor, items, { placement?, label?, onSelect?, onClose? })` / `contextMenu(target, items, options?)` | Menus with icons, shortcut chips, checks, radios and submenus; a right-click or menu-key menu. |
|
|
1877
1925
|
| `timeline(container, { duration, time?, fps?, units?, markers?, ranges?, snap?, onSeek?, … })` | A zoomable ruler and playhead with markers, loop ranges and playback. |
|
|
1878
|
-
| `compare(container, { before, after, mode?, wipe?, timeline?, onMode?, onWipe?, onView?, … })` / `compareStrip(container, { before, after, timeline })` | A before/after viewer for videos and images (a split screen zoomed together, wipe
|
|
1926
|
+
| `compare(container, { before, after, mode?, modes?, wipe?, timeline?, onMode?, onWipe?, onView?, … })` / `compareStrip(container, { before, after, timeline })` | A before/after viewer for videos and images (a split screen zoomed together, or a wipe; a difference opted in) on one clock, with a loop; a frame strip with difference bars, on its own. |
|
|
1927
|
+
| `selectionPill(container, { selected, rows?, radius?, copy?, color? })` | The one highlight that travels between rows: a fill on the state spring taking each row's box and radius, with a bright copy of the rows clipped to it; `update({ snap? })`, `dispose()`. |
|
|
1928
|
+
| `icon(name, { small? })` / `ICON_NAMES` | Phosphor regular glyphs as SVG markup in `currentColor`, 16 px (12 px `small`). |
|
|
1879
1929
|
| `activity(container, { events, selected?, onSelect?, onActivate?, onToggle?, onPlay?, newest?, follow?, keys?, icons?, tints? })` | A rail of events on one continuous line, with groups that open in place; `{ set, add, select, expand, focus, destroy }`. |
|
|
1880
1930
|
| `optionPicker(container, { options, selected?, chosen?, onSelect?, onChoose?, body?, digits? })` | Options 1–n on a gliding card, the selected one's parameters (a panel) open under it. |
|
|
1881
1931
|
| `bento(container, { items, gap?, tolerance?, rowHeight?, fit?, blur?, picks?, onPick?, onZoom?, onActive? })` | An ideas grid: a bento of images and live content that zooms an item to fill the view; picks with Space. |
|
|
@@ -1194,6 +1194,22 @@ var theme = { from: "theme" }, css = (s) => ({ css: s }), value = (s) => ({ valu
|
|
|
1194
1194
|
source: css("var(--k-warn)"),
|
|
1195
1195
|
doc: "Modified lines."
|
|
1196
1196
|
},
|
|
1197
|
+
{
|
|
1198
|
+
name: "before",
|
|
1199
|
+
tier: "semantic",
|
|
1200
|
+
type: "color",
|
|
1201
|
+
group: "Data",
|
|
1202
|
+
source: css("var(--k-fg-3)"),
|
|
1203
|
+
doc: "Before in a comparison, and only Before: its label and side of the seam. Neutral unless a theme gives it a colour."
|
|
1204
|
+
},
|
|
1205
|
+
{
|
|
1206
|
+
name: "after",
|
|
1207
|
+
tier: "semantic",
|
|
1208
|
+
type: "color",
|
|
1209
|
+
group: "Data",
|
|
1210
|
+
source: css("var(--k-fg)"),
|
|
1211
|
+
doc: "After in a comparison, and only After."
|
|
1212
|
+
},
|
|
1197
1213
|
{
|
|
1198
1214
|
name: "series-1",
|
|
1199
1215
|
tier: "semantic",
|
|
@@ -1284,6 +1300,150 @@ var theme = { from: "theme" }, css = (s) => ({ css: s }), value = (s) => ({ valu
|
|
|
1284
1300
|
source: value("288px"),
|
|
1285
1301
|
doc: "Panel width."
|
|
1286
1302
|
},
|
|
1303
|
+
{
|
|
1304
|
+
name: "space-inside",
|
|
1305
|
+
tier: "semantic",
|
|
1306
|
+
type: "length",
|
|
1307
|
+
group: "Space",
|
|
1308
|
+
source: css("var(--k-unit)"),
|
|
1309
|
+
doc: "Parts of one thing: an icon and its label, a meta line and its title."
|
|
1310
|
+
},
|
|
1311
|
+
{
|
|
1312
|
+
name: "space-sibling",
|
|
1313
|
+
tier: "semantic",
|
|
1314
|
+
type: "length",
|
|
1315
|
+
group: "Space",
|
|
1316
|
+
source: css("calc(var(--k-unit) * 2)"),
|
|
1317
|
+
doc: "Siblings in a group: buttons in a row, a list item's lines."
|
|
1318
|
+
},
|
|
1319
|
+
{
|
|
1320
|
+
name: "space-title",
|
|
1321
|
+
tier: "semantic",
|
|
1322
|
+
type: "length",
|
|
1323
|
+
group: "Space",
|
|
1324
|
+
source: css("calc(var(--k-unit) * 3)"),
|
|
1325
|
+
doc: "A heading and what it heads."
|
|
1326
|
+
},
|
|
1327
|
+
{
|
|
1328
|
+
name: "space-group",
|
|
1329
|
+
tier: "semantic",
|
|
1330
|
+
type: "length",
|
|
1331
|
+
group: "Space",
|
|
1332
|
+
source: css("calc(var(--k-unit) * 12)"),
|
|
1333
|
+
doc: "Groups inside a section (prose, video, diff), stacked media, feed items (a hairline in the middle)."
|
|
1334
|
+
},
|
|
1335
|
+
{
|
|
1336
|
+
name: "space-section",
|
|
1337
|
+
tier: "semantic",
|
|
1338
|
+
type: "length",
|
|
1339
|
+
group: "Space",
|
|
1340
|
+
source: css("calc(var(--k-unit) * 24)"),
|
|
1341
|
+
doc: "Sections of a page (the intro, the updates, each PR), a hairline in the middle."
|
|
1342
|
+
},
|
|
1343
|
+
{
|
|
1344
|
+
name: "space-column",
|
|
1345
|
+
tier: "semantic",
|
|
1346
|
+
type: "length",
|
|
1347
|
+
group: "Space",
|
|
1348
|
+
source: css("calc(var(--k-unit) * 6)"),
|
|
1349
|
+
doc: "Columns: a contents rail and the page, media side by side."
|
|
1350
|
+
},
|
|
1351
|
+
{
|
|
1352
|
+
name: "pad-page",
|
|
1353
|
+
tier: "semantic",
|
|
1354
|
+
type: "length",
|
|
1355
|
+
group: "Space",
|
|
1356
|
+
source: css("calc(var(--k-unit) * 6)"),
|
|
1357
|
+
doc: "A page's edge; 16px under 640px wide."
|
|
1358
|
+
},
|
|
1359
|
+
{
|
|
1360
|
+
name: "pad-card",
|
|
1361
|
+
tier: "semantic",
|
|
1362
|
+
type: "length",
|
|
1363
|
+
group: "Space",
|
|
1364
|
+
source: css("calc(var(--k-unit) * 3)"),
|
|
1365
|
+
doc: "Inside a card or popover."
|
|
1366
|
+
},
|
|
1367
|
+
{
|
|
1368
|
+
name: "type-heading",
|
|
1369
|
+
tier: "semantic",
|
|
1370
|
+
type: "length",
|
|
1371
|
+
group: "Type",
|
|
1372
|
+
source: value("20px"),
|
|
1373
|
+
doc: "Section headings (a PR's title, under its kicker), weight 500."
|
|
1374
|
+
},
|
|
1375
|
+
{
|
|
1376
|
+
name: "leading-heading",
|
|
1377
|
+
tier: "semantic",
|
|
1378
|
+
type: "length",
|
|
1379
|
+
group: "Type",
|
|
1380
|
+
source: value("28px"),
|
|
1381
|
+
doc: "Line height for type-heading."
|
|
1382
|
+
},
|
|
1383
|
+
{
|
|
1384
|
+
name: "type-title",
|
|
1385
|
+
tier: "semantic",
|
|
1386
|
+
type: "length",
|
|
1387
|
+
group: "Type",
|
|
1388
|
+
source: value("16px"),
|
|
1389
|
+
doc: "A page's title, weight 500."
|
|
1390
|
+
},
|
|
1391
|
+
{
|
|
1392
|
+
name: "leading-title",
|
|
1393
|
+
tier: "semantic",
|
|
1394
|
+
type: "length",
|
|
1395
|
+
group: "Type",
|
|
1396
|
+
source: value("24px"),
|
|
1397
|
+
doc: "Line height for type-title."
|
|
1398
|
+
},
|
|
1399
|
+
{
|
|
1400
|
+
name: "type-body",
|
|
1401
|
+
tier: "semantic",
|
|
1402
|
+
type: "length",
|
|
1403
|
+
group: "Type",
|
|
1404
|
+
source: value("13px"),
|
|
1405
|
+
doc: "Prose, questions, list rows, step titles; 400, or 500 for emphasis."
|
|
1406
|
+
},
|
|
1407
|
+
{
|
|
1408
|
+
name: "leading-body",
|
|
1409
|
+
tier: "semantic",
|
|
1410
|
+
type: "length",
|
|
1411
|
+
group: "Type",
|
|
1412
|
+
source: value("20px"),
|
|
1413
|
+
doc: "Line height for type-body."
|
|
1414
|
+
},
|
|
1415
|
+
{
|
|
1416
|
+
name: "type-label",
|
|
1417
|
+
tier: "semantic",
|
|
1418
|
+
type: "length",
|
|
1419
|
+
group: "Type",
|
|
1420
|
+
source: value("12px"),
|
|
1421
|
+
doc: "Labels over media, weight 500; mono inside body text."
|
|
1422
|
+
},
|
|
1423
|
+
{
|
|
1424
|
+
name: "leading-label",
|
|
1425
|
+
tier: "semantic",
|
|
1426
|
+
type: "length",
|
|
1427
|
+
group: "Type",
|
|
1428
|
+
source: value("16px"),
|
|
1429
|
+
doc: "Line height for type-label."
|
|
1430
|
+
},
|
|
1431
|
+
{
|
|
1432
|
+
name: "type-small",
|
|
1433
|
+
tier: "semantic",
|
|
1434
|
+
type: "length",
|
|
1435
|
+
group: "Type",
|
|
1436
|
+
source: value("11px"),
|
|
1437
|
+
doc: "Meta, controls, keys, timestamps; mono inside labels."
|
|
1438
|
+
},
|
|
1439
|
+
{
|
|
1440
|
+
name: "leading-small",
|
|
1441
|
+
tier: "semantic",
|
|
1442
|
+
type: "length",
|
|
1443
|
+
group: "Type",
|
|
1444
|
+
source: value("16px"),
|
|
1445
|
+
doc: "Line height for type-small."
|
|
1446
|
+
},
|
|
1287
1447
|
{
|
|
1288
1448
|
name: "font-size",
|
|
1289
1449
|
tier: "semantic",
|
|
@@ -2141,8 +2301,9 @@ ${register(["width"], "<length-percentage>", "288px")}
|
|
|
2141
2301
|
@media(prefers-reduced-motion:reduce){:where(.knobs-chip,.knobs-ui){--k-token-t:0s}}`, aliased = (css) => css.replace(new RegExp(`var\\(--_k-(${ANIMATED.join("|")})\\)`, "g"), "var(--kv-$1)").replace(/var\(--k-blur\)/g, "var(--kv-blur)");
|
|
2142
2302
|
|
|
2143
2303
|
// src/core/root.ts
|
|
2144
|
-
var ROOT_CLASS = "knobs-root", extras = `:where(.${ROOT_CLASS}){--_k-shadow-k:calc(var(--k-shadow-strength,calc(.48 - .32 * var(--_k-light,0))) / .48);--_k-glass-tone:var(--k-glass-tone,calc(.5 + .58 * var(--_k-light,0)));--_k-fill-base:var(--k-fill-base,var(--_k-fill-selected));--_k-fill-hover-mix:var(--k-fill-hover-mix,var(--k-fill-rest-mix,20%));--_k-reveal-ease:var(--k-ease,cubic-bezier(.2,.8,.2,1))}`, spring = `:where(:root,:host){--k-fill-ease:${DEFAULT_LINEAR.easing};--k-fill-ms:${DEFAULT_LINEAR.ms}}`, rootCss = `${tokensCss(knobs)}
|
|
2304
|
+
var ROOT_CLASS = "knobs-root", extras = `:where(.${ROOT_CLASS}){--_k-shadow-k:calc(var(--k-shadow-strength,calc(.48 - .32 * var(--_k-light,0))) / .48);--_k-glass-tone:var(--k-glass-tone,calc(.5 + .58 * var(--_k-light,0)));--_k-fill-base:var(--k-fill-base,var(--_k-fill-selected));--_k-fill-hover-mix:var(--k-fill-hover-mix,var(--k-fill-rest-mix,20%));--_k-reveal-ease:var(--k-ease,cubic-bezier(.2,.8,.2,1))}`, narrow = `@media(max-width:639.98px){:where(.${ROOT_CLASS}){--_k-pad-page:var(--k-pad-page,calc(var(--_k-unit) * 4))}}`, spring = `:where(:root,:host){--k-fill-ease:${DEFAULT_LINEAR.easing};--k-fill-ms:${DEFAULT_LINEAR.ms}}`, rootCss = `${tokensCss(knobs)}
|
|
2145
2305
|
${extras}
|
|
2306
|
+
${narrow}
|
|
2146
2307
|
${spring}
|
|
2147
2308
|
${DRIVERS}
|
|
2148
2309
|
${motionCss}`;
|