Can you summarise the release notes for 0.62?
theme.register() and ships its own [data-theme] block. Foundations
Typography
Heading level 1
Heading level 2
Heading level 3
Heading level 4
Body — the default reading text. Label — form labels & field captions. Caption — small meta text. Code — monospace inline.
default muted faint accent success warn danger
normal medium semibold bold
numeric 1234.50% default 1234.50%
eyebrow italic nowrap text uppercase leading none scale=false 13px
Font-scale slider vs a pinned run — only the first line follows the picker: size="lg" scales with --fs-scale size="lg" scale=false stays pinned
measure="40ch" — a paragraph capped at forty characters wide so long lines stay readable. Truncated heading that runs past its container
Theme tokens
The picker on the right passes
auto: it adds a row that follows the system
light/dark setting, remembering one light and one dark palette (dashed swatches). --bg
--bg-elevated
--bg-elevated-2
--surface
--border
--border-strong
--text
--text-muted
--text-faint
--accent
--link
--ok
--warn
--danger
--info
Text scaling opt-in
Optional in-app text-size control (drives
--fs-scale, text tokens only).
Most apps should rely on browser zoom and the user's OS/browser font-size instead —
the kit is rem-based and never resets the root size, so both are respected
out of the box. Reach for this only in reading-dense apps (chat, docs) that want to grow
body text while keeping chrome compact.Style hooks
Your scoped CSS cannot reach inside a kit component, and its internal class names
are private. Each component instead publishes CSS custom properties named
--<prefix>-<axis> (bg, fg, border, size, radius) that you set from style or any ancestor rule. Reaching in with :global() is
unsupported. The README lists every published property. --badge-bg --txt-fg
Badge size axis — numeric reserves and centres the box, --badge-min-size squares it, --badge-fs / --badge-fw set the typography: 7 7 42
A pill Popover trigger sitting in a row of Toggles — pill + size="sm" + the --pop-trigger-* hooks, no :global(): Layout
Layout: Stack · Cluster · AutoGrid
Cluster — wraps, never overflows: AutoGrid — columns adapt to available width (resize the window): AutoGrid — capped column width (max), left-packed instead of stretching:
alpha beta gamma delta epsilon zeta
Cluster stackAt="md" — buttons stack full-width when the cluster is under 40rem: Cell 1
Cell 2
Cell 3
Cell 4
Cell 5
Cell 6
Fixed 1
Fixed 2
Fixed 3
Card
Static card
An elevated surface with token-driven padding, border and radius.Stacked card
Looks like a pile — two layers peek out bottom-right.Stacked (info)
Back layers tinted with the info/blue hue.tone info
tone ok
tone warn
tone danger
tone attention
Dashed card
An empty-slot / drop-target frame.Dashed (danger)
Border style and tone compose.Borderless card
Frame dropped; the surface fill carries the shape.Dashed stack
The back layers pick up the dashed frame too.Interactive card
Enter/Space activate; the nested button stays independent.maxWidth 22rem
Fills its row up to the cap.Divider
Horizontal tones — default, strong, faint: Above the rule. Between two rules. Below the strong rule. Faint, tighter spacing.
or
Vertical — stretches to the row's cross size: MasterDetail
Two columns above its own 48rem breakpoint; below it one pane at a time with a sticky back
header. Drive Same component boxed at 22rem — the mobile regime on desktop:
selected from the URL to make each pane a route. Alice
Alice
Detail pane for Alice.Nothing selected
Pick someone on the left.
gap spaces the columns and divider="none" drops the seam — or
override --md-gap / --md-divider from the consumer: Bob
Detail pane for Bob.Actions
Button
as="a" / as="button" keep the same chrome and focus ring: Hit area — hitArea="compact" drops the 44px touch slab (outlined box shows the real hit box on touch): count hides at 0, caps at countMax (99+), and the exact number joins the accessible name: layout="stacked" puts glyph over the label; shortcut is a corner hint and aria-keyshortcuts: npm i @dorsk/tsumikit
Icon & IconButton
filled forwards to Icon, so a two-state toggle can paint its
"on" state with the filled glyph — and quote/reply head a
quote-reply action: All registry glyphs (sized at 1em — they scale with text):
back
arrow-right
arrow-up
arrow-down
chevron-up
chevron-down
chevron-left
chevron-right
menu
more
external
log-out
plus
minus
check
x
search
filter
copy
edit
trash
save
download
upload
send
share
reply
quote
retry
recycle
settings
play
pause
stop
music
tv
film
disc
file
file-text
folder
archive
image
markdown
list
grid
link
unlink
text-cursor
tag
bookmark
star
heart
fork
live
eye
eye-off
lock
unlock
bell
mail
calendar
clock
home
user
users
sun
moon
flame
zap
loader
info
warning
help
check-circle
x-circle
alert-circle
Toggle · OptionButton · SelectButton
Choice cards with
description and onfocuschange driving a preview pane (hover or arrow through them): The agent writes a step-by-step plan and waits for approval.
SelectButton (native select over a glyph button): selected: a
SegmentedControl
SplitButton
A primary action fused with a caret menu: one outer radius, a single divider, two tab stops. ArrowDown on the primary opens the menu. Pick a recipient first
Forms
Form atoms & Field
Helper text below the control.
This field is required.
Control K Shift Enter Control Alt Escape Up arrow
On
Checkbox & RadioGroup
Preview: The agent writes a step-by-step plan and waits for approval.
Fieldset
Drag a card between pools (HTML5 DnD); buttons are the keyboard path.
dragPayload feeds accepts while hovering, so the source pool stays unhighlighted. FileButton & Dropzone
native picker, keyboard-focusable
Drop files here or click to browse
overlay mode — wraps content, drop UI shows only while dragging a file over it Drawer-like surface
Buttons and content stay clickable. Drag a file anywhere over this card.EmojiPicker
Search the built-in EN+FR catalogue or browse it by group; pass your own
groups to replace it. Arrow keys walk the grid, Enter picks.Combobox
Autocomplete: you render the field, the kit floats the listbox under it, keeps
aria-activedescendant on the input and consumes Arrow / Enter / Tab / Escape. Mention: the consumer detects the trigger with
findTrigger and replaces the
token with applyTrigger; anchor="caret" pins the listbox under
the text cursor. Type @ to try it. InputGroup
Input + trailing Button: the field spans the whole group and draws the one border and ring;
the controls fuse with its edge, so a phone never zooms to a narrow field. Textarea (autoresize, top grip) + leading FileButton + trailing SplitButton (send + schedule menu);
past one row the adornments drop into a bar under the text, so every line runs full width
and the scrollbar stays clear of them: A trailing label whose width changes re-pads the field (click it): Sizes (sm · md · lg), disabled and error:
AttachmentList
Chips when the list is wider than 30rem; square tiles below that (resize the window or the box).
A tile's Popover carries the full name, the size and Remove:
Forced tiles; image attachments show their thumbnail:
numbered badges each position; onopen makes the chip name a button and adds a preview + Open to the tile popover: Data display
Badge · Link · Dot
neutral ok warn danger info success sm 12
~/path/to/file removable typescript trash glyph removed API_KEY
uppercase stable
soft ok warn danger 3
accent muted violet color dot icon text · 12:34
xs 8 128 a very long account name that clips
active stale dead hibernated custom ring
Swatch
Sizes and shapes; a label makes it an image, without one it is decorative.
A
Interactive palette: buttons with aria-pressed. var(--accent)
Metric · StatTile
Tracks
1284
Size
42.7 GB
Quality
FLAC
lossless · 16-bit
Added
37 this week
+12% vs last week
Surface variants — tiles (via Metric) and panels (via Card) opt into the same theme-aware shade by prop, no
:global override: Base
base
Raised
raised
Sunken
sunken
surface base
surface raised
surface sunken
SectionHeader · KeyValue · LoadMore
Recent sessions
12 last 24h 4
Group rows render here while open.
Failed
2 live
sakura
7Host
sakura- Running
- 3
- Queued
- 0
- Image
- cctui-worker:0.7.3 pulled 2h ago
- Load
- 1.42
- Tokens
- 128000
- Cost
- $0.42
Failed to load
No more items
DataTable generic <T>
| Name | Role | Status |
|---|---|---|
| api-gateway | service | ok |
| worker-02 | worker | warn |
| cache-01 | cache | danger |
layout="fixed" + truncate, hideBelow on the role column, rowTone accent bar, hover-revealed rowActions, size="sm". | Role | Status | Actions | |
|---|---|---|---|
| api-gateway | service | ok | |
| worker-02 | worker | warn | |
| cache-01 | cache | danger |
responsive="stack" in a 22rem-wide box: rows become cards via Column.role (title / detail / meta / hidden), actions stay on the title line. | Name | Role | Status | Id | Actions |
|---|---|---|---|---|
| api-gateway | service | ok | 1 | |
| worker-02 | worker | warn | 2 | |
| cache-01 | cache | danger | 3 |
stackLabel: false on the meta columns: no labels, the metas join on one · line under the title. | Name | Role | Status | Id |
|---|---|---|---|
| api-gateway | service | ok | #1 |
| worker-02 | worker | warn | #2 |
| cache-01 | cache | danger | #3 |
· separators; stackActions="end" closes every card with its actions. | Name | Role | Status | Id | Actions |
|---|---|---|---|---|
| api-gateway-with-a-long-unbroken-name | ok | #1 | ||
| worker-02 | worker | warn | #2 |
headerSnippets replaces a header cell — here a select-all checkbox over a
checkbox column. | Name | Role | |
|---|---|---|
| api-gateway | service | |
| worker-02 | worker | |
| cache-01 | cache |
stackBelow="30rem": it stays tabular in this 34rem box and stacks
once the box drops under 30rem. | Name | Role | Status | Id |
|---|---|---|---|
| api-gateway | service | ok | 1 |
| worker-02 | worker | warn | 2 |
| cache-01 | cache | danger | 3 |
SortableList
Drag the grip (long-press anywhere on a row withhandle="row"), use the arrows,
or focus a grip and press Space, then ↑/↓/Home/End and Space again. Alt+↑/↓ moves a row in
one step. The first row is locked and canMove keeps it on top. SwipeRow
Swipe a row sideways to reveal an action; past 35% of the width it fires on release. Vertical drags scroll as usual. Tab into a row to reach the same actions as buttons.- Behemoth Odin — 2 min ago
- Fafnir Hyperion — 9 min ago
- Ixion Zalera — 14 min ago
PullToRefresh
Touch or pen: pull down from the top of the list to prepend a row.Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12
Row 13
Row 14
Row 15
Row 16
Row 17
Row 18
Row 19
Row 20
SeekSlider · VolumeSlider · TimeDisplay
oninput previews while dragging; onchange fires once per release or key
step, so the player seeks only there. The bottom slider is a live stream (no duration). seeks: 0
FilterSearchBar organism
YouTrack-style structured search. Typerole:worker, status=ok, or
free text — drive it from the dropdown or type the query language by hand. The bar owns the
query (emits an AST); the host runs it and renders results. | Name | Role | Status |
|---|---|---|
| api-gateway | service | ok |
| worker-02 | worker | warn |
| cache-01 | cache | danger |
SELECT * FROM nodes
WHERE TRUE;FilterInput is the headless primitive underneath — same schema-driven dropdown, but
single-field with no below-bar chips. Its inline snippet renders custom nodes inside
the bar (here, a badge per parsed filter): size="sm" shape="pill" surface="sunken" with hotkey="/" — press / anywhere outside a field to focus it. key="cwd" is single-key mode: the box holds the bare value, so there is no cwd: prefix to mirror back and forth, the placeholder shows while
empty, and completion still comes from that field's provider. The inline snippet
keeps working — here a machine picker sitting inside the field's own box: display snippet renders the value over the input while the field is blurred
and non-empty — here a WorkingDir, so a long path abbreviates fish-style instead
of clipping. Focus it (click, Tab) and the raw editable string comes back. It
composes with inline, adds no tab stop and does not change the bar's height: Timestamp subdued · click for UTC / epoch / zone
Renders an instant in one of six modes (date, time, datetime, relative, iso, short-iso), subdued
by default. The
date/time/datetime modes follow
the viewer's zone unless you pass utc. Click it for a read-only popover
with the same instant as UTC, relative, your time zone and the unix epoch. Opt into selectable to let viewers switch the inline mode. datetime: date: date (utc): iso: short-iso: time: relative: mono: selectable: no popover:
GitRef branch · PR · ±diff
Branch chip, pull-request link and +/− diff stats in one inline row; every part is
optional. The PR state picks its tone (open ok, merged accent, closed danger, draft
muted).
collapse="auto" keeps only the glyphs when the nearest .cq container is narrower than 18rem; glyph forces it. branch: feat/wave-1-new-components-with-a-long-name pr: DorskFR/tsumikit#77 all three: fix/resizable-panel #78 +128 −42 glyph: fix/resizable-panel DorskFR/tsumikit#79 +3 −1
WorkingDir fish-style · degrades with width
Drag the handle: ancestors abbreviate one at a time left to right, then only the leaf
stays, then the leaf ellipsises down to
minLeaf chars. The full path is always
in the tooltip. Truncate char-count · hover reveal
Character-count truncation (the counterpart to
<Text truncate>'s CSS
ellipsis). Hover or focus a truncated value to reveal the full text. middle: 0x71C765…6d8976F
0x71C7656EC7ab88b098defB751B7401B5f6d8976F
end: a-very-long-resourc… a-very-long-resource-identifier-that-keeps-going
start: …/14/request-trace.log /srv/app/var/logs/2026/06/14/request-trace.log
fits (no tooltip): shortCodeBlock BYO highlighter
// install and use
import { Button, theme } from '@dorsk/tsumikit';
function greet(name) {
return `Hello, ${name}!`;
}git clone …
npm install
npm run devConversationPanel · ConversationFeed · ChatBubble · StatusBar
A full chat column: header, a feed that sticks to the bottom (scroll up, then append → "Jump to latest"), a "Load older" pill that keeps the viewport still, a live status row and a Composer with a toolbar row.Sure. Highlights:
renderMarkdownhelper, zero depsConversationFeed+ConversationPanelorganismsComposertoolbar row
| Area | Change |
|---|---|
| ChatBubble | timestamp, footer, markdown |
| StatusBar | new |
Read src/lib/index.ts (220 lines)
Links are scheme-checked: docs works, [x](javascript:alert(1)) stays text.
const html = renderMarkdown(text);Context compacted
Snippet body via Prose + renderMarkdown: bold, em, gone
Feedback
EmptyState
No results
No albums match your filters. Try broadening the search or clearing filters.
Your library is empty
Add an artist or album to start building your collection.
Nothing here yet
This section hasn't been set up.
Loading sessions…
No results
Try a different query.
Skeleton:
Callout
Auto-search runs in the background and links matches as it goes.
Linked
12 releases matched and were linked to this collection.
Some matches need review
3 releases had several candidates and were left unlinked.
Search failed
The provider returned 503. Try again in a minute.
Searching MusicBrainz for 48 releases…
Narrow container
Wraps its body and actions instead of overflowing.
Toasts
Progress
- conforming 412
- nonconforming 12
- blocked 0
- done 300
- skipped 120
Gauge
CapBar
Overlays
Tooltip
Tooltips appear on hover and keyboard focus, dismiss with Escape.
Also works on icon buttons.
- service
- api-gateway
- region
- ap-northeast-1
- build
7f3c9e2
Modal
Accessible dialog in the native top layer — Escape to close, click-outside to close, focus
trapped inside and restored to the trigger on close. Drag the right edge to resize (persisted).
ConfirmModal
Drawer
Side panel on the native
<dialog>: Escape, scrim click and the close
button close it; focus is trapped; body scroll is locked. A nav snippet
becomes a 150px page column beside the content on wide viewports and a horizontal strip
above it under 48rem, where the panel goes full-screen.