# gpui-native-kit — checklist The living queue. Every element lands through the review gate: API sketch → implementation → tests → gallery panel → review. Conventions and rules live in [AGENTS.md](../AGENTS.md); the gpui pin lives in the workspace `Cargo.toml` (resolved in `Cargo.lock`, zed @ `504a7f2cf25b817cda3998cab93473adef15f93c`). [signed](https://git.reya.info/reya/signed) is the first downstream consumer; its screens drive the order. ## Next ## Queue — to follow Platform metric adoption continues one component at a time; each stop goes through the review gate and a gallery pass. - [ ] **Switch platform chrome** — stated track and knob dims (`switch_height` / `switch_width` / `switch_knob`, inset and travel derived); borderless knob. Gaps surfaced by the signed comparison; ordered by signed's usage. - [ ] **Virtual list** — generic virtualized variable-height rows with a scroll handle, promoted from the editor views' pattern over gpui's `list`; signed's PR lists and commit diff drive it. - [ ] **Editable code field** — syntax-highlighted editable multiline field, the code view's highlighter over the input's editing model; signed's repo file browser. - [ ] **Dropdown menu** — trigger button + popover + menu composite, three signed call sites; must stay a real component, not a wrapper. - [ ] **Motion easing helpers** — cubic ease-out and lerp beside `theme::Motion`; low priority, gpui's animation primitives cover most cases. - [ ] **Markdown view follow-ups** — streaming `append` with a coalesced background parse, text selection with copy, per-block a11y roles, GFM alerts + table column alignment, per-fence highlight reuse, `soft_break_as_hard_break`; ranked notes in [markdown-view-comparison.md](markdown-view-comparison.md). - [ ] **Editor follow-ups** — language detection by file path, meta line overlay, per-view config overrides (line height, gutter visibility). - [ ] **Pickers** — Calendar / DatePicker, TimeField, ColorPicker (decide at unit time). - [ ] **Layout follow-ups** — persistence, pane zoom, bottom dock, collapse-to-edge; each waits for a real consumer. - [ ] **Platform screenshot passes** — a Linux run (Omarchy / KDE / GNOME) and the first Windows hardware build, side by side with macOS. ## Landed ### theme (`crates/theme`) - [x] Theme engine — resolve overlay chain, OKLCH accent ramps, presets, per-platform elevation stacks, `titlebar_height`, size table (`Sizable`) - [x] Platform sources — macOS (NSColor), Windows 11 (UISettings), GNOME (portal), KDE (kdeglobals), Omarchy (colors.toml), neutral fallback; live watchers for each - [x] Platform metric fidelity — stated control/input/menu-row/switch metrics and the full radius ladder per platform, Linux root fonts (GNOME gsettings `font-name`, KDE `kdeglobals font=`), per-source border + focus chrome (`Theme::borders`), and a per-platform spacing unit (`Theme::spacing`); overlay borders engage in dark mode, where floating layers separate by border instead of shadow — dark elevation shadows are dropped entirely, since they only muddied the dark scrim. Components adopt the tokens one by one (see Next and Queue) ### icons (`crates/icons`) - [x] `IconRole` + bundled Lucide fallback, Segoe Fluent codepoints (Windows), freedesktop theme walker (Linux/Omarchy) ### core (`crates/core`) - [x] Button platform chrome — every variant always paints the hairline border, sized outside the stated control height (`BORDER_WIDTH`); where the platform paints no border (`Theme::borders.buttons`, ghost) the border takes the fill's color and disappears, so sizes match across platforms; icon-bearing buttons pad with `dense_padding_x` instead of `padding_x` - [x] Button loading state — `.loading(true)` shows the spinner in place of the icon and suppresses activation; Spinner gained a `.color` override for accent-filled surfaces - [x] Input platform chrome — the field always paints the hairline border, sized outside the stated field height; where the platform paints no border (`Theme::borders.fields`) it takes the field's fill; focus recolors the border on Windows / KDE and paints the accent ring on macOS / GNOME via `Theme::borders.focus_ring`; the shared `focus_ring` band paints at half ink (every focusable control picks it up) - [x] Input prefix / suffix — elements docked inside the field's edges, typically small ghost buttons; a docked click activates the control without reaching the field's caret handler, and the text region shrinks to make room - [x] Select platform chrome — the trigger takes the input treatment: the hairline border always painted, sized outside the stated field height and taking the fill's color where the platform paints none; open recolors the border on Windows / KDE and paints the accent ring on macOS / GNOME, so the trigger matches a focused field; the menu popup's border sits behind `Theme::borders.overlays`, disappearing into the surface where the platform paints none - [x] Menu platform chrome — the popup border behind `Theme::borders.overlays` (and dark mode); the panel padding and separator margins come from `Theme::spacing`, and every action row renders at the stated `menu_item_height` with content centered, so the stated metric is the whole row; rows carry debug selectors for headless geometry tests - [x] Popover platform chrome — the panel border behind `Theme::borders.overlays` (and dark mode); the anchor gap is the spacing unit and rides `anchored().offset`, not a margin, so the window-edge clamp stays intact; the panel carries a debug selector - [x] Dialog platform chrome — the panel border behind `Theme::borders.overlays` (and dark mode), taking the surface color where the platform paints none - [x] Toast platform chrome — the pill border behind `Theme::borders.overlays` (and dark mode), taking the surface color where the platform paints none; the pill rides the popover elevation, so dark mode's no-shadow rule applies to it too - [x] Tooltip platform chrome — the panel border behind `Theme::borders.overlays` (and dark mode), taking the surface color where the platform paints none, and riding the popover elevation for the light-mode shadow; anchored tooltips hang below the hovered parent (`Tooltip::anchored(text, id)`) so they never cover it — the element records its painted bounds with `record_anchor_bounds` (`Button` does), the panel hangs below that with the spacing gap, and it flips above the parent when it would overflow the window bottom (the panel records its own height after the first frame); unanchored tooltips fall back to the cursor-offset wrapper - [x] Alert platform chrome — the banner border behind `Theme::borders.overlays` (and dark mode), taking the surface color where the platform paints none; it rides the popover elevation, so dark mode's no-shadow rule applies to it too - [x] Combobox platform chrome — the popup border behind `Theme::borders.overlays` (and dark mode), taking the surface color where the platform paints none, and riding the popover elevation for the light-mode shadow; the trigger is a plain `Input`, so it already carries the full field treatment, and the chevron recenters on the field's full height, border included; the popup mounts on `deferred(anchored().offset(...))` like the Popover — out of the wrapper's layout, one spacing gap below, window-clamped — and always matches the combobox's width; the combobox itself is no longer full width: it takes a compact default and style refinements on the builder (`.w(...)`) set the width; the empty field keeps its placeholder while focused (`Input::placeholder_when_focused`) and clicking into it opens the options right away, with no keystroke needed - [x] Command palette platform chrome — the panel border behind `Theme::borders.overlays` (and dark mode), taking the surface color where the platform paints none; it rides the dialog elevation, so dark mode's no-shadow rule applies to it too - [x] Button, Checkbox, Switch, Radio + RadioGroup, Toggle, Link, Slider, Progress, Avatar (image + seeded pixel-art fallback) - [x] Spinner — painted ring + rotating-icon variant, indeterminate and determinate; replaces `Tab::busy`'s placeholder - [x] Input — single-line, password with reveal, multiline, undo/redo, actions + key context, caret blink (time-math driven: the focused field mounts a repeating blink animation whose frames redraw the caret, the caret is solid for one interval after each edit, and an idle unfocused page schedules no frames) - [x] ScrollArea, Popover, Menu, Tooltip, Dialog / AlertDialog, Toast, Alert + alerts stack - [x] Select, Segmented, ContextMenu, EmptyState, Badge - [x] Field — label / description / error around any control, block and settings-row variants - [x] Status dot — colored state bead, Badge's variant vocabulary, optional screen-reader label - [x] Combobox — type-to-filter picker with a caller-owned matcher, create / keep / revert blur modes - [x] Command palette — filtered actions; the matcher stays caller-owned, and commands may carry a leading icon - [x] Scrollbar — overlay thumbs for gpui's `list` and `uniform_list`, platform autohide with a `visibility` override - [x] Clipboard button — copies a value, confirms with a brief check mark that reverts itself - [x] Separator — horizontal and vertical hairline rules; menu separators stay menu-scoped ### data (`crates/data`) - [x] List, Tree, Tabs (underline default + signed pill), Sidebar (scrolls internally) ### editor (`crates/editor`) - [x] Code view — tree-sitter highlighted, virtualized rows with a gutter and the overlay scrollbar; per-language grammar features, roles map to the theme's semantic palette at render - [x] Code view interactions — active line, text selection with copy, incremental line re-highlight - [x] Diff view — unified rows via `similar`, highlighted with the code view's palette; change washes from the ramps, `scroll_to_first_change` - [x] Markdown view — `pulldown-cmark` blocks rendered as formatted text: headings, emphasis runs, ordered/task lists, quotes, fenced code highlighted with the code view's palette, tables, clickable links; virtualized variable-height rows over gpui's `list` ### layout (`crates/layout`) - [x] ResizeHandle - [x] Shell — left/right sidebar regions + center, application-owned `LayoutState` - [x] Window frame — client-side decorations under `Decorations::Client` - [x] Dock — pane tree, panel registry, tab context menus - [x] Drag-to-split — `PanelDrag` payload, edge + center drop zones - [x] Titlebar + window controls — app-owned window dragging, per-platform buttons, `Theme::titlebar_height` - [x] Sidebar auto-open — `PanelDescriptor::right_sidebar` + `DockSidebar` - [x] Resizable group — stacked panes with drag dividers outside the dock, per-pane floors, double-click reset, keyboard steps ### gallery (`examples/gallery`) - [x] Component browser — the shell with the catalog in its sidebar, every element a dock panel