description: "Shared React UI atoms for the dsh web client: controls, icons, markdown and math rendering, and the terminal/read/diff/search/web output cards (zero cordis)."
English | 中文
dsh-client-ui-primitives is the web client's shared React component library: every feature plugin composes its UI from these atoms, and nothing here depends on Cordis or the slot system. It provides the control set (buttons, pills, inputs, menus, modals, toast banners, disclosure rows, hover cards, connection indicators), the icon glyphs and brand marks, positioning hooks for anchored overlays, and the content renderers for agent output: markdown with TeX math, terminal output, file reads, diffs, search results, web retrieval, and JSON inspection. The renderers are built for untrusted model output — raw HTML is dropped, links are neutralized or opened safely, and ANSI escape sequences are parsed rather than passed through. User-facing copy is supplied through label props; the feature plugin that composes an atom owns localization.
Compose feature UI from these atoms whenever the web client needs a standard control or an agent-output renderer. They render through React only and take --dsw-* design tokens from the theme, so they fit any plugin without importing the theme or the slot system.
Button, Pill, Input, Menu, Modal, Tooltip, DisclosureRow, StateDot, HoverCard, Toast, ConnectionIndicator, RiskConfirmation, and the OnboardingSurface first-run takeover cover the common interaction shapes. The ic_ds_* icon set and FishLogo/BrandWordmark marks fill brand and inline-icon slots. LinkIcon draws the leading category glyph for clickable artifact links — globe, folder, code, image, document, or plain paper, all riding currentColor — and classifyLinkPath derives a file path's category from its extension. ConnectionIndicator renders a warning-colored disconnected action, a connecting label whose one-to-three dots advance every 500ms independently of retry timing, or a success-colored recovered status. Every state reserves the widest supplied label and uses fixed icon and text columns, so copy changes do not move or resize the control. Its owner supplies visibility, the recovery hold, localized labels, and the immediate-reconnect callback; the primitive uses no native title tooltip. useAnchoredPosition and useAnchoredMaxHeight keep floating panels and bottom-anchored overlays clamped to the viewport and following their anchor. HoverCard keeps its portaled preview reachable across the anchor gap and can expose a copy button through the copyText prop. Toast holds for the window its owner names through holdMs, because how long a banner has to stay depends on how much there is to read; the same value drives its unmount timer and the stylesheet's fade delay, so the two cannot disagree. rankByName is the / menu's shared candidate ranker for the command and skill sources: the query must be a case-insensitive ordered subsequence of the name; prefix hits rank first, then alignment score, then source order (ranking decision).
MarkdownText renders untrusted GFM and TeX math, blocks unsafe links and images, and can turn resolved file mentions into explicit controls. While a reply streams, it freezes completed blocks, advances a top-level open fence by completed lines, and highlights that fence from saved Shiki grammar state. Completed token lines enter fixed-size React groups, so later chunks reconcile only the growing group; an unchanged fence retains that DOM when the final full parse resolves cross-document syntax (incremental renderer, streaming fence highlighting). TerminalBlock, ReadBlock, DiffBlock, SearchBlock, and WebBlock render the matching tool-result intent with copy controls, overflow handling, and ANSI processing where applicable. JsonTree and JsonBlock inspect JSON values read-only, while projectUserText projects sent user text into inline plain runs and reference chips for the message bubble and queue rows.
The atoms cannot read the application locale, so every piece of user-facing copy arrives through required label props. HoverCard, TerminalBlock, JsonTree, CodeBlock, MarkdownText, JsonBlock, ConnectionIndicator, Modal, DiffBlock, ReadBlock, SearchBlock, and WebBlock accept complete localized labels. The package owns no language fallback; omission fails typechecking, and each feature maps its typed t seat into the primitive's label interface.
These pages place the atoms in the client stack and the design system.
--dsw-* token system these atoms style through.None, as the package is a browser-side UI plugin layer that registers nothing model-facing.
None; this package neither assembles nor sends a provider request.
These limits define how the atoms behave at the edges; they are current package constraints, not a component roadmap.
Pill and Input have no design source — both atoms are self-defined; the sidebar search field and view-tab strip that resemble them are consumer-owned compositions, not these atoms.Active StateDot variant — the supported states are done, warning, ongoing, and error.ctx.locale; each feature must supply complete localized labels through the primitive's typed props (decision).TerminalBlock is not a terminal emulator — it renders settled or still-running command output, not an interactive session: SGR colors, carriage return, backspace, erase-in-line, tab stops, and character width are honored; absolute cursor positioning, screen clearing, and alternate-screen sequences are stripped.Runtime invariant: No companion is published. Pure props-in React atoms with no Cordis API — no events, no services, no mutable cross-plugin state; rendering contracts are asserted directly by this package's component specs.