Tags from the tagger are added after a comma and the caption is never reworded. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpnF7GwNGMbngU11wjym7P
15 KiB
UI kit reference
The kit is called the Composer: app/ui/composer/. It is the only code that styles or builds raw DOM. For when to use which element, read UI design guidelines. This page is the reference.
How elements work
import { composer } from "../../composer/composer.js";
const save = composer.button.md({ label: "Save", tone: "primary", onClick: save });
host.appendChild(save.node);
save.setBusy(true);
// later
save.destroy();
- An element is
composer.<group>.<variant>(props). It returns a handle:{ node, destroy, ...methods }. nodeis the DOM node to place.destroy()removes listeners and the node. A feature that creates elements aftersetupreturns must destroy them itself.- Methods differ by element. The common ones are
setValue,get,setText,setItems,setDisabled,setBusy,setPressed,openandclose. Read the factory incomposer/elements/<file>.jsfor the exact set. - Content is text. Every string prop goes through
asText(internals/text.js) and is shown as text, never parsed. A prop that would take HTML does not exist. - Containers take handles, not nodes or markup:
panel.default({ children: [handleA, handleB] }). - Unknown elements throw
UnknownElement.composer.button.huge(...)fails with the list of known variants. A feature that asks for an element that does not exist therefore hides itself instead of showing something approximate. - The kit's own CSS classes start with
cx-. App frame classes start withfp-(app/ui/frame.css) and belong to the shell. Never use either from a feature; the feature rule test fails on acx-orfp-string.
Where each group lives
| File | Groups |
|---|---|
text.js |
brand, code, header, hint (low: true hides it first when the row runs short), label, text |
button.js |
button, buttonGroup, iconButton |
input.js |
filterList, input, number, search, stepper, textarea |
choice.js |
checkbox, checkboxRow, checklist, color, radioGroup, segmented, select, toggle |
slider.js |
range, slider |
layout.js |
actionBar, card, collapsible, field, frame, group, hero, list, panel, region, settingsRow, sidebar, splitPane, tabs, toolbar, workspace |
tile.js |
grid, tile |
stage.js |
stage |
chart.js |
chart |
tags.js |
tags |
captioned.js |
captioned |
status.js |
banner, chip, dot, dropzone, emptyState, inlineError, progress, skeleton, spinner, toast |
modal.js |
modal |
popover.js |
autocomplete, menu, popover, splitButton, tooltip |
floating.js |
floating (window, corner), overlay, slideOver |
gallery.js |
gallery, ruler, viewer (media, cover) |
track.js, nle.js |
track, timeline |
wheel.js |
wheel |
Elements
Variants are listed after the group. Props shown are the ones every use needs; the catalogue (catalogue/elements.html) and catalogue/demos.js show each element with a working set.
Text
| Element | Variants | Main props |
|---|---|---|
header |
display, xl, lg, md, sm |
text |
text |
lg, md, sm, xs |
text. Has setText. |
hint |
default |
text |
label |
field, section |
text, for |
code |
inline, block |
text, label (block) |
brand |
default |
name |
Actions
| Element | Variants | Main props |
|---|---|---|
button |
xl, lg, md, sm, menu |
label, onClick, tone (neutral, primary, danger, ghost, render), icon, disabled, busy, type, title, pressed. Methods setBusy, setDisabled, setPressed, setLabel. |
iconButton |
md, sm, micro |
icon, label (required), onClick, tone, disabled, pressed |
buttonGroup |
md |
label, value, items |
splitButton |
md |
label, items, onClick |
Inputs and choices
| Element | Variants | Main props |
|---|---|---|
input |
md, sm |
value, placeholder, label, onCommit |
search |
md |
placeholder, label |
textarea |
md |
value, rows, label |
number |
md |
value, min, max, step, precision, unit, snap, onChange, disabled, id, label |
stepper |
md |
value, min, max, step, label |
slider |
md, sm, readout, macro |
value, min, max, step, label, onChange, onCommit. .setMax(n) changes the top and redraws the fill. |
range |
md |
from, to, min, max, step, label |
toggle |
default |
label, hint, checked, onChange |
checkbox |
default |
checked, label |
checkboxRow |
default |
label, hint, checked |
checklist |
default |
label, values, items |
radioGroup |
default |
label, value, options |
segmented |
md, sm |
label, value, options, onChange |
select |
md, sm |
label, value, options, onChange |
filterList |
md |
value, items |
autocomplete |
default |
anchored to an input; sits above modals |
color |
swatch |
label, value |
wheel |
picker, half |
edge, items |
dropzone |
default |
label, hint |
options is a list of { value, label }. Changes are reported as the value, not as an event.
Layout
| Element | Variants | Notes |
|---|---|---|
frame |
app |
The page frame. Owned by the shell. |
workspace |
docked |
Docked areas around a centre. |
splitPane |
h, v |
Two children with a draggable divider. |
region |
stack |
children, gap, label, fill. .set(children) replaces them. |
panel |
default, zone |
A titled card. |
group |
default |
A quiet sub-block. |
field |
default, row |
A label, a control and a hint. |
settingsRow |
default |
The row the Settings window uses. .setHint(text) changes its hint later. |
card |
default |
children. Related fields on one rounded card (a region.stack with a background). |
grid |
pair, cards |
children. Tiles in two columns, or as many columns as fit (at least 190 wide). |
tile |
action, node, add |
title, sub, onClick. node also takes state (ready, needs, skipped) and draws a dot. add is the dashed empty slot. |
hero |
default |
title, hint. The mark, a big title and one line (the top of About). |
collapsible |
default |
|
tabs |
underline, dock |
value, tabs. |
sidebar |
rail |
value, items. |
toolbar, actionBar |
default, sticky |
Toolbars wrap; an action bar sticks to the bottom of its scroll area. |
list |
rows |
Grouped rows. |
Status and feedback
| Element | Variants | Main props |
|---|---|---|
banner |
info, warn, danger |
text |
chip |
neutral, good, warn, danger, info |
label |
dot |
default |
tone, label |
inlineError |
default |
text |
toast |
info, good, warn, danger |
text, action, duration (default 3200 ms) |
progress |
bar, indeterminate, inline |
value, max, label. inline is a short bar with a line of text beside it: .setValue, .setText, .setHidden. |
spinner |
md, sm |
label |
skeleton |
line, block, grid |
count, label |
emptyState |
default |
icon, title, hint |
Overlays
| Element | Variants | Main props |
|---|---|---|
modal |
generic, stacked, dialogue, prompt, choice |
generic: title, subtitle, size (sm, md, lg, xl), body, actions, onClose, closeOnOutside, closeOnEsc. dialogue: title, message, tone, confirmLabel, cancelLabel, onResult, and a .result promise. |
popover |
anchored |
Positioned by internals/anchor.js, flips at an edge. |
menu |
dropdown, context |
A context menu is anchored to a point, not an element. |
tooltip |
default |
|
floating |
window, corner |
window is a draggable window (the Settings and Sampler windows). corner is a small button pinned inside the bottom-right corner of anchor (a handle or a node); it follows the box and calls onGone when the box leaves. |
slideOver |
md |
A panel that slides in from the side. |
overlay |
blocking |
message. Blocks the page while something runs. |
All overlays use the portal, the z-ladder and the dismiss stack.
Charts, tags and captioned media
| Element | Variants | Main props |
|---|---|---|
chart |
line |
series ({ name, values } or { name, points: [{x, y}] }, plus tone accent/good/warn/muted, faint for a raw noisy line under a smoothed one, dashed), xLabel, yLabel, height (sm, md, lg), logY, empty, label. Points that are not numbers are skipped; long series are cut to a few hundred drawn points keeping highs and lows. Hover reads the nearest values. Methods setSeries, setEmpty. |
tags |
editor |
value (list of strings), suggestions, placeholder, label, maxTags, onChange(list). Enter or comma adds, Backspace on an empty box removes the last, chips drag to reorder, Tab takes the first suggestion. Methods get, setValue (does not call onChange), focus. |
tags |
cloud |
items ({ tag, count }), selected, onPick(tag), onRemove(tag) (adds a remove button), label, empty. Draws the first 300 and says how many more. Methods setItems, setSelected. |
captioned |
cell, side |
A picture or clip with its caption: preview, name, a badge and a text box for the caption in one card. cell stacks the picture over the caption (for grids), side puts them side by side (for one at a time). src (a picture URL; a clip passes its still), kind (image or video, a clip gets a play mark), title, caption (free text, kept as typed), badge and tone (neutral, good, bad, warn), selected and onSelect(on) (adds a tick box), onChange(caption) (as it is typed), onOpen() (makes the picture a button). Methods getCaption, setCaption (does not call onChange), setSelected, setBadge, setPicture, focus. |
Media and time
| Element | Variants | Main props |
|---|---|---|
gallery |
adaptive, icons, list, rows, cards, strip |
id, cols, items. Density through internals/density.js. |
viewer |
media, cover |
media: src, empty; .setLook({ transform, filter, fit, opacity }) changes how the picture is drawn (kept across sources). cover is a layer over its parent that shows a picture, clip or sound with a close button: .show({ src, kind }), .close(), onClose. |
stage |
overlay |
A transparent layer over a picture holding text and pictures that can be dragged and resized. Gives data (items: position as 0..1, size in picture pixels, colours, text); onMove(id, {x, y}) and onResize(id, factor) report numbers, never styles. .fit(w, h) sizes it to the picture inside its parent, .setItems(items) draws, .busy is true during a gesture. |
ruler |
default |
label, total, marks |
track |
default |
label, pxPerSecond, playhead, selection, items |
timeline |
stage |
pxPerSecond, lanes. Methods setLanes, setPlayhead, setZoom. |
Internals
Used by elements. A feature does not import them. They exist in composer/internals/:
| File | Does |
|---|---|
register.js |
define, UnknownElement, lookups. |
el.js, text.js |
Safe DOM building, asText, setText. |
ids.js |
Unique ids for label and control pairs. |
zlayer.js |
The z-ladder. The only place a z-index is written. |
portal.js |
Where overlays are drawn. |
dismiss.js |
One Escape and outside-click stack. |
focus.js |
trap and roving. |
anchor.js |
Pure placement (measure, flip, clamp) plus anchorTo. |
drag.js, dragReorder.js, snap.js, swapping.js |
Dragging, reordering and snapping. |
density.js |
Grid columns 0 to 4, saved per id. |
motion.js |
Reduced motion check and shared timings. |
Adding an element
- Write it in the right file under
composer/elements/(or a new file). Calldefine(group, variant, factory)once per variant. The factory takes props and returns a handle. Use onlyel,asTextand the internals. Never writeinnerHTML. - Register the file. A new file is imported in
elements/index.jsand its stylesheet is added tocomposer.cssbeforepolish.css. - Style it with tokens only, using
cx-class names. Cover both themes and reduced motion. - Add a demo to
catalogue/demos.jsunder"<group>.<variant>". A registered element with no demo fails the suite. A demo is a props object, or a function that receivescomposerwhen the props need other handles. - Teach the content test any new string prop name.
composer/tests/rule_content_is_data.test.jsattacks every string under the names inCONTENT_KEYSwith a markup payload and proves it comes back as text. If your prop name is not in the set (for examplecaptionorempty), add it, or the test fails with a message naming the demo. - Test behaviour in
composer/tests/elements_behaviour.test.jsor a new*.test.jsbeside it: what the element does when used, not only that it renders. - Look at it in
catalogue/elements.htmlin dark and light.
Rule tests that run over the whole kit
| Test | Proves |
|---|---|
rule_content_is_data.test.js |
Every string prop of every demo is shown as text. |
rule_unknown_element_hides.test.js |
Asking for a missing element throws and hides the feature. |
rule_features_use_the_kit.test.js |
Every file in app/ui/features/ passes FEATURE_RULES (no document, window, style, class names, literal colours or sizes). |
rule_kit_never_interprets.test.js |
tools/kit_lint finds no markup parsing or eval in the kit and the shell, and still catches a bad example. |
register.test.js |
Duplicate definitions are refused. |
overlays.test.js, dismiss.test.js, zlayer.test.js, portal.test.js |
Layering, Escape and portal behaviour. |
panel_schema.test.js |
panel.js draws every setting type. |
panel.js and the catalogue
composer/panel.js renders a module's SETTINGS as a panel with the allowed ui renderers. The live app does not use it for Settings (it uses features/settings/field.js); the catalogue and the tests do. So a ui value changes what the catalogue shows, not what Settings > Engine draws. See Module reference.
The catalogue
Open /funpack/app/ui/catalogue/ with the devserver running (python tools/devserver.py 8199).
| Page | Shows |
|---|---|
index.html |
Tokens: type, colour, spacing, radius, motion. |
elements.html |
Every registered element in both themes. |
hide.html |
What happens when a module is broken or missing. |
log.html |
The Log view. |