d4551/deepseek-harness--packages-client-ui-primitives ↗★ 4
@deepseek-ai/dsh-client-ui-primitives
Pure React atoms for the dsh web UI: controls, icons, markdown, and JSON inspectors (zero cordis) 适合构建 Web 功能插件的开发者,零 Cordis 依赖,供各插件组合界面
Other repositories with this package name
- deepseek-ai/deepseek-harness--packages-client-ui-primitives
- whitelonng/dshcode--packages-client-ui-primitives
- fufankeji/deepseek-harness-studio--packages-client-ui-primitives
- op7418/pilot-harness--packages-client-ui-primitives
- See-Sol-Lab/DeepSeekGUI--packages-client-ui-primitives
- peiyuwang54/deepseek-harness-cli--packages-client-ui-primitives
Install
This plugin has no verified bundle, or compatibility checks failed. Read the repository notes first. Read the full README ↗
README
Read the full README ↗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)." kind: "package-library"
@deepseek-ai/dsh-client-ui-primitives
English | 中文
Summary
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 banners), 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.
Table of Contents
- Use this package
- Understand the implementation
- Further Exploration
- Model Experience
- Known Limitations and Deferred Work
- Dev Note
Use this package
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.
Controls and icons
Button, Pill, Input, Menu, Modal, Tooltip, DisclosureRow, StateDot, HoverCard, Toast, ConnectionBanner, RiskConfirmation, and the OnboardingSurface first-run takeover cover the common interaction shapes. The ic_ds_* icon set and the FishLogo/CatLogo/BrandWordmark marks fill brand and inline-icon slots. 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. Menu walks its rows with the arrows once the focus is on one of them, and its autoFocus prop takes the focus into the list on open and returns it on close — a portaled list sits at the end of the document, so a caller that opened it from the keyboard must send the focus after it. Its rows stay out of the tab sequence and Tab closes the list instead of walking past the rest of the document, and ariaLabel names the list, which nothing else can do once it is portaled away from its trigger. A disabled row carries aria-disabled rather than the native attribute, so the arrows still reach it and a reader still announces it; the row refuses its own activation instead, and opens no submenu.
Within a menu, Up/Down and Home/End move among that menu's rows. Right, Enter, or Space opens a submenu and focuses its first row; Left or Escape returns to its parent row. Submenus take their accessible name from that row. Pointer movement outside a submenu does not dismiss it while it contains keyboard focus.
Input displays shared focus and validation styling from its native aria-invalid attribute. Associate field guidance through aria-describedby, including password inputs. Markdown links remain underlined without hovering, and the reconnecting banner announces its status to assistive technology.
Conversation flow rows
PanelTable presents related records with localized column headers and an accessible table name. Consumers supply native body rows and row headers; the primitive owns shared spacing, borders, and typography.
FlowRow is the 24px line a conversation row sits on: it anchors and clips a row-wide overlay and moves its height with the Settings font-size delta. DisclosureRow draws the leading glyph, title, and disclosure behaviour on one; its callers fill the rest of the line with RowSeparator, the meta dot, and RowSummary, the summary text that takes the remaining width and truncates to one line. InspectPill is the hover-revealed jump to a call's trajectory record — it rests transparent and the owning card's own hover rule reveals it — and ResultText renders a call's flattened result as a code panel. GlyphButton is the icon-only button on a transparent fill; its surface prop names the box and ink it takes, because the sidebar, panel-header, dock-bar, and message-row instances are four geometries the design has not reconciled, and each owner keeps its own hover, focus, and disabled rules on the class it passes.
Rendering agent output
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 and highlights a growing fence from saved Shiki grammar state; the final render uses the same span tree (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 MessageText remains the literal-text primitive for user-authored content.
Localizing copy
Code fences and file-read cards retain readable code if a syntax grammar cannot load. The card displays a localized failure message and a Reload page button; only activating that button reloads the document and retries the download. A failed import stays recorded because browsers cache module failures for the document. Re-rendering or streaming more code does not repeat the failed request or its browser error report.
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, ConnectionBanner, Modal, DiffBlock, ReadBlock, SearchBlock, and WebBlock accept complete localized labels, including grammar-failure and reload copy. Omission fails typechecking, and each feature maps its typed t seat into the primitive's label interface.
Understand the implementation
Implementation internals — click to expand
The package is one separation: presentational React atoms with zero Cordis and zero slot knowledge, styled only through --dsw-* tokens, while every feature-specific concern (locale, session data, composition) stays in the composing plugin.
Source map
| File | Role |
|---|---|
src/index.ts | Public atom exports |
src/markdown/ | Markdown and math pipeline: micromark parsing, KaTeX typesetting, incremental streaming renderer, CodeBlock/JsonBlock |
src/TerminalBlock.tsx | ANSI escape parsing (anser) and terminal card rendering |
src/ReadBlock.tsx / src/DiffBlock.tsx | Read and diff cards |
src/SearchBlock.tsx / src/WebBlock.tsx | Search and web-retrieval cards |
src/icons/ | ic_ds_* glyph components and brand marks |
src/useAnchoredPosition.ts / src/useAnchoredMaxHeight.ts | Floating-panel and overlay geometry hooks |
Streaming markdown
While a reply streams, MarkdownText parses incrementally: all but the trailing two blocks freeze as cached React elements and only the source tail re-parses per chunk, so per-chunk work tracks the tail instead of the whole reply. A growing fenced block tokenizes completed text from saved Shiki grammar state plus the unfinished last line; completed lines retain their DOM, and the settled render uses the same span tree. The settled full parse at finalize also resolves references that crossed the freeze boundary (incremental renderer, streaming fence highlighting).
Geometry and overflow
Portaled Menu lists and message-feedback panels use useAnchoredPosition. The hook returns a data-anchored-position identity and owns a constructed stylesheet containing only measured left and top coordinates; closing removes that sheet without changing other adopted sheets. Placement follows scrolling, viewport changes, portal remounts, and panel resizing. Button-anchored menus try the opposite edge before clamping, so an overflowing menu does not cover its trigger. An unavailable external anchor keeps the menu hidden and inert until it can be measured.
The output cards share one geometry model: white-space: pre with horizontal scrolling so column-aligned content keeps its alignment, and a head-plus-tail slice behind an expand button past maxLines (default 16) so a long body never stretches the card. TerminalBlock parses ANSI into React spans with a per-line column buffer for cursor movement, honoring erase-in-line, tab stops, and character width.
Further Exploration
These pages place the atoms in the client stack and the design system.
- ui-renderer — the React renderer that mounts the assembled application and binds slot data.
- ui-tool — the tool-call presentation layer that composes these output cards.
- ui-conversation — the chat surface that renders markdown replies and tool cards.
- ui-theme — the
--dsw-*token system these atoms style through. - Web styling — the authoritative styling rules for web client components.
Model Experience
None, as the package is a browser-side UI plugin layer that registers nothing model-facing.
KV Cache effect
None; this package neither assembles nor sends a provider request.
Known Limitations and Deferred Work
These limits define how the atoms behave at the edges; they are current package constraints, not a component roadmap.
- Streaming defers cross-boundary reference resolution — a reference-style link or footnote whose definition sits on the other side of the incremental freeze boundary renders as literal text while the reply streams; the settled full parse at finalize resolves it.
- Glyph-level icons are redrawn approximations — the fish logo and the sparkle mark come from font glyphs whose vector geometry is not exportable from the local design data; hand-authored recreations stand in until an exact export path exists.
PillandInputhave 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.- No
ActiveStateDotvariant — the supported states are done, warning, ongoing, and error. - User-facing copy is required at the render site — the atoms are zero-Cordis and cannot reach
ctx.locale; each feature must supply complete localized labels through the primitive's typed props (decision). TerminalBlockis 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.
Dev Note
Working context for maintainers — click to expand
Native Safari 26.4 does not implement the typed CSS attr() expressions previously used for menu coordinates and anchor identifiers. A newer Playwright WebKit build can support those expressions, so passing WebKit automation alone does not establish installed Safari behavior. Menu positioning now uses the standard constructed stylesheet API, with no inline style attributes. Validate coordinates, pointer and keyboard journeys in both automated browsers and the installed browser.
Menu and anchored-panel interaction suites run in the native browser lane, where adopted stylesheets, layout and ResizeObserver execute directly. The canonical GUI and coverage commands include these suites. Focus returns during layout cleanup when the menu closes; selecting an item in a controlled menu that stays open retains focus within that menu. Sidebar checks cover macOS Control-click, repeated secondary presses, pointer travel, keyboard reopening, dialog focus and real session actions.