dsh-client-ui-primitives/packages/client/ui-primitives官方

175.3kStar19.0kFork0Issue752Watching

纯React原子组件库,为dsh web UI提供Button、Modal、Input等控件和ic_ds_*图标,以及MarkdownText/JsonTree等渲染器和Toast、OnboardingSurface等交互组件

机审证据安装命令仓库已核验dsh-plugin Topic许可证READMEAI 百科

此插件是大仓库 deepseek-ai/deepseek-harness 的子包,星数与活跃度统计的是整个仓库。

语言
TypeScript
License
MIT
分支
master
ai-agentscordisdshdsh-plugin

安装

$ dsh plugin --profile web add npm:@deepseek-ai/dsh-client-ui-primitives

在终端中运行以上命令,通过 dsh CLI 安装此插件。可在右上角切换 Profile。 第一次用 dsh?看这篇新手教程

对话式安装

帮我安装 DeepSeek Harness 插件 deepseek-ai/deepseek-harness/packages/client/ui-primitives:先查看仓库 https://github.com/deepseek-ai/deepseek-harness 确认安全性,然后执行安装命令并验证插件加载成功。

把这段指令粘贴给 DSH Web GUI 里的助手,由它代你完成安装与验证。

English | 中文

Pure React atoms (zero cordis): StateDot, DisclosureRow, ic_ds_* icons, Button/Pill/Menu/Modal/Input, the Toast transient banner, the OnboardingSurface first-run takeover (body-portaled mask + opaque stage that holds #root inert for exactly its own lifetime), the markdown family (MessageText/MarkdownText/JsonBlock), the read-only JsonTree inspector, the useAnchoredMaxHeight hook that clamps a bottom-anchored overlay to the viewport space above its anchor (re-measured on resize, scroll, and a caller-supplied dependency), the useAnchoredPosition hook that holds a fixed-position floating panel under its anchor (measure, offset, clamp inside the viewport margin, re-placed on capture-phase scroll, window resize, and the panel's own size changes), TerminalBlock, DiffBlock, ReadBlock, SearchBlock, and WebBlock.

Hover cards

HoverCard keeps its portaled preview reachable across the anchor gap with a pointer-leave grace. A consumer may also pass copyText: the card then exposes button semantics for pointer and keyboard activation, includes that value after the copyLabel prefix in its accessible name, writes the exact value through the package clipboard helper, and temporarily replaces its content with copiedLabel only after the host accepts the write. A non-collapsed text selection intersecting the card suppresses pointer-click activation, while success feedback retains the original card height and clears when the card closes or after one second. copyLabel and copiedLabel are label props because this zero-cordis atom cannot read the application locale; omitting copyText preserves the read/select-only card. Historical rationale: the archived hover-card copy note.

Toast

Toast is the transient top banner: it slides in, holds at full opacity for three seconds, fades over one second, then calls onDone so the owner can unmount it. It renders role="alert" with an optional leading icon slot and takes its copy as a required prop (zero-cordis: the owner localizes). It body-portals with pointer-events: none, sits 120px from the viewport top, and centers horizontally over the optional anchor element (re-measured on window resizes) — the composer passes its card so the banner centers over the chat column rather than the whole window — falling back to the viewport center without one. Re-showing the same message requires a remount — owners key the element by a per-show sequence so an identical repeated message restarts the hold-and-fade cycle instead of silently reusing the faded banner. Under prefers-reduced-motion: reduce the slide-in is dropped and only the delayed fade remains. It layers above the ui-attachment image lightbox so a failure reported during a preview stays readable.

Markdown rendering

MarkdownText renders GFM and $…$, $$…$$, \(…\), and \[…\] TeX math from untrusted assistant output through React elements, with math typeset by KaTeX and trusted commands disabled; block-level same-line $$…$$ is display math, including \tag{}. A narrow micromark extension lets asterisk strong emphasis ending in punctuation close before adjacent CJK text, where prose normally omits the whitespace CommonMark requires; single-asterisk emphasis, non-CJK adjacency, escapes, code, and math retain upstream parsing. It omits raw HTML, neutralizes relative and non-HTTP(S)/mailto links, opens HTTP(S) links with safe external-link attributes, and renders absolute HTTP(S) images without a referrer; relative paths, absolute local paths, file: URLs, and unsupported schemes retain their alt text. Inline code whose complete value is an absolute HTTP(S) URL keeps its code styling and gains the same safe external anchor; commands, partial URLs, other schemes, and fenced code remain inert. An optional fileMentions resolver lets the owning view link inline code that names a real file: the token keeps code styling and gains a button wired to the resolved opener, with the resolver's accessible label and full-path title. The renderer never guesses at what looks like a path — an unresolved token stays inert, mentions apply to settled renders only (the streaming cache must not bake in handlers that could go stale), and a token inside an anchor stays inert because a button cannot nest there. While a reply streams, MarkdownText parses incrementally: all but the trailing two blocks freeze as cached React elements and only the source tail behind them re-parses per chunk, so per-chunk work tracks the tail instead of the whole reply (mechanism and DOM-parity contract). MessageText remains the literal-text primitive for user-authored content. extractMarkdownPlainText removes Markdown presentation markup for compact labels while preserving raw HTML as literal text. Element spacing, responsive images, tables, links, and inline code use the same --dsw-alias-markdown-* / --dsw-font-markdown-* tokens as deepsuite @deepseek/md. Fenced blocks render through CodeBlock (language banner, copy control, shiki for the registered grammars).

Terminal output

TerminalBlock renders a shell command as a terminal surface: one prompt row per line of the command (the shortened cwd label on the first row only, since the view knows one working directory and a cd moves later lines elsewhere, then that line), the command's output, a status pill for a non-zero exit code or a terminating signal, and a copy control that writes the raw output prop. A run-state StateDot marks the call once, on the first row, out of flow in a gutter the card reserves as its own left padding, so the dot sits inside the card box yet left of the prompt text. It reaches three of StateDot's states — the chase while running, red for the same exit status that renders the pill, green otherwise — so a card states whether its command is still running rather than leaving that to be inferred from the presence of output; it carries one visually hidden text label because StateDot is aria-hidden. One dot regardless of line count is deliberate: the exit status is the whole call's, so a dot per line would claim a per-line outcome the view does not carry. Command text is white-space: pre, so repeated spaces, tabs, and an indented continuation render verbatim while the row stays single-line and ellipsizes. ANSI escape sequences are parsed with anser (bundled into this package's browser artifact) into React spans; cursor movements replay into a per-line column buffer before inert controls are stripped, since carriage return and backspace only MOVE the cursor: 100% + CR + OK alone shows OK0%, while the \x1b[K a spinner writes with its redraw erases the tail so 100%\r\x1b[KOK shows OK. Erase-in-line is honored in all three parameter forms, the cursor advances by terminal columns (8-column tab stops, two for emoji and CJK, none for a combining mark), and SGR state is normalized per cell as a terminal stores it, threading across lines and closing at the state the line ended in; basic-16 foreground colors map onto --dsw-* tokens, while 256-palette and truecolor values pass through as literal rgb. Output keeps white-space: pre with horizontal scrolling, so column-aligned output holds its alignment instead of soft-wrapping, and collapses to a head slice plus a tail slice past maxLines (default 16) behind an expand button. Rationale: the web terminal card note.

Read rendering

ReadBlock renders a returned file window as a line-numbered, syntax-highlighted code surface: a bold path (or presenter-supplied title) banner with a copy control, then the content lines with their file line numbers in a gutter (a windowed read keeps the file's own numbering, so a read past an offset starts above 1). A totalLines exceeding the window count draws a showing N of M note, and the body collapses to a head slice plus a tail slice past maxLines (default 16, the TerminalBlock split arithmetic) behind an expand button. Highlighting runs through the same shiki path as CodeBlock. Rationale: the web read card note.

Diff rendering

DiffBlock renders a file mutation as an inline diff surface: one bold path header per file, the removed lines (- , error token) above the added lines (+ , success token), a gap before a same-file second hunk, and a dim └ +A -R · N file(s) footer. Lines are white-space: pre with horizontal scrolling, so a source line holds its indentation instead of soft-wrapping, and the body collapses to a head slice plus a tail slice past maxLines (default 16, TerminalBlock's split arithmetic) behind an expand button. A create (oldText: null) has no removed side. The copy control writes the prefixed diff text (path headers, - /+ lines, the gap) so a multi-file copy stays attributable, and floats in the top-right corner rather than on a banner row of its own. Geometry mirrors CodeBlock/TerminalBlock. Rationale: the web diff card note.

Search results

SearchBlock renders a completed search, one component for both kinds (discriminated by kind). A matches (grep) shows each file as a bold path header with its lineNumber: line rows, the per-file group collapsible; a paths (glob) shows a flat path list. Both flatten to one row list the height cap slices head/tail over (default 16, the TerminalBlock split arithmetic), and neither soft-wraps — a long match line or path scrolls horizontally instead of folding. The banner summary folds the pre-cap total in when the tool capped the result (显示 X / 共 N 处匹配 · K 个文件 for grep, 显示 X / 共 N 个路径 for glob), so the card never presents a capped result as complete; a copy control writes the whole structured result regardless of the cap or which groups are collapsed. Geometry mirrors CodeBlock/TerminalBlock. Rationale: the web search card note.

Web retrieval

WebBlock renders a completed web retrieval, one component for both kinds of the web render intent (discriminated by kind). A search shows an optional provider answer (through MarkdownText) above an ordered citation list: each source is a safe external link labelled by its title, or its hostname, falling back to the raw URL when the URL does not parse or has no hostname (a file:/data: URL) so a label is never blank; its snippet and publication date render below it. Only http(s) URLs become anchors (target/rel set) — the http(s) subset of the allowlist MarkdownText applies to untrusted links (it also permits mailto:, excluded here); any other URL renders as plain text. The whole list renders in one fixed-height scroll container (max-height: 320px, overflow-y: auto), so a list taller than that scrolls vertically in place instead of growing the card; <li value> pins each source's citation number, contiguous from 1, rather than leaving it to the <ol>'s implicit count. When a search legitimately returns no answer and no sources, the card shows an explicit empty-state note rather than a blank <ol> (the chat row does not surface the raw result content). A fetch shows a compact summary: the linked final URL and its HTTP status. Both mark a capped retrieval. Rationale: the web result card note and the source scroll note.

Model Experience

None, as the package renders pure React atoms in the browser; nothing here reaches a model request.

KV Cache effect

None; this package neither assembles nor sends a provider request.

Known Limitations and Deferred Work

  • 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. Inline links and references resolved within one parse are unaffected.
  • Glyph-level icons are redrawn approximations — the fish logo (and the sparkle held by ui-conversation) 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.
  • 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.
  • No Active StateDot variant — the supported states are done, warning, ongoing, and error.
  • User-facing copy localizes through label props, defaulting to the original Chinese literals — the atoms are zero-cordis and cannot reach ctx.locale, so HoverCard (copyLabel/copiedLabel), TerminalBlock (labels), JsonTree (labels), CodeBlock (copyLabel/copiedLabel), MarkdownText (codeLabels), JsonBlock (truncatedLabel), ConnectionBanner (label), and Modal (closeLabel) take their copy as optional props. Localized plugins pass dictionary-driven labels from their own t seat; a consumer that passes nothing gets those defaults. WebBlock does not yet follow this pattern: its source-list and fetch truncation notes and its empty-search note stay inline Chinese, pending the same label-prop treatment.
  • TerminalBlock is not a terminal emulator — it renders settled or still-running command output, not an interactive session: SGR color and attributes are honored, and so are the in-line cursor movements a progress line uses — carriage return, backspace, erase-in-line, tab stops and character width. Absolute cursor positioning, screen clearing, and alternate-screen sequences are stripped. Basic-16 magenta and cyan have no token equivalent and stay literal rgb.

收录徽章

Listed on deepseek-plugin.org
[![Listed on deepseek-plugin.org](https://img.shields.io/badge/listed_on-deepseek--plugin.org-007EC6)](https://deepseek-plugin.org/plugins/deepseek-ai/deepseek-harness/packages/client/ui-primitives)

把这段 markdown 粘贴到你的 GitHub README,链接回本插件详情页。徽章只声明已被本站收录,不代表安全认证。

返回插件目录
dsh-client-ui-primitives/packages/client/ui-primitives — DeepSeek Harness 插件 | deepseek-plugin.org