@deepseek-ai/dsh-client-ui-primitives 0.0.1-rc.1 → 0.0.1-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +5 -1
- package/README.zh.md +6 -2
- package/lib/index.js +200 -25
- package/lib/invariant.js +1 -1
- package/lib/types/Menu.d.ts +5 -1
- package/lib/types/Toast.d.ts +24 -0
- package/lib/types/Tooltip.d.ts +7 -3
- package/lib/types/icons/index.d.ts +6 -0
- package/lib/types/index.d.ts +1 -0
- package/package.json +5 -5
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/client/ui-primitives/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: f96e931472a0946bd023b97b034643f079a67e44
|
|
6
|
+
README.zh.md: bf47fa2bca6f685fc52ca6ff786439a8d51230fc
|
package/README.md
CHANGED
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
English | [中文](README.zh.md)
|
|
4
4
|
|
|
5
|
-
Pure React atoms (zero cordis): StateDot, DisclosureRow, ic_ds_* icons, Button/Pill/Menu/Modal/Input, 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), TerminalBlock, DiffBlock, ReadBlock, SearchBlock, and WebBlock.
|
|
5
|
+
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), TerminalBlock, DiffBlock, ReadBlock, SearchBlock, and WebBlock.
|
|
6
6
|
|
|
7
7
|
## Hover cards
|
|
8
8
|
|
|
9
9
|
`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](../../../.agents/notes/archived/feature/2026-07-31-hover-card-click-copy.md).
|
|
10
10
|
|
|
11
|
+
## Toast
|
|
12
|
+
|
|
13
|
+
`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.
|
|
14
|
+
|
|
11
15
|
## Markdown rendering
|
|
12
16
|
|
|
13
17
|
`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](../../../.agents/notes/implemented/architecture/2026-08-06-web-markdown-incremental-ast-renderer.md)). `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).
|
package/README.zh.md
CHANGED
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | 中文
|
|
4
4
|
|
|
5
|
-
纯 React 原子组件(零 cordis):StateDot、DisclosureRow、ic_ds_* 图标、Button/Pill/Menu/Modal/Input、OnboardingSurface 首次使用接管层(portal 到 body 的遮罩加不透明展示层,在且仅在自身生命周期内保持 `#root` 为 `inert`)、markdown 家族(MessageText/MarkdownText/JsonBlock)、只读 JsonTree 检查器、`useAnchoredMaxHeight` 钩子(把底部锚定的浮层高度收敛到锚点上方的视口空间,并在 resize、scroll 与调用方提供的依赖变化时重新测量)、TerminalBlock、DiffBlock、ReadBlock、SearchBlock,以及 WebBlock。
|
|
5
|
+
纯 React 原子组件(零 cordis):StateDot、DisclosureRow、ic_ds_* 图标、Button/Pill/Menu/Modal/Input、Toast 短时横幅、OnboardingSurface 首次使用接管层(portal 到 body 的遮罩加不透明展示层,在且仅在自身生命周期内保持 `#root` 为 `inert`)、markdown 家族(MessageText/MarkdownText/JsonBlock)、只读 JsonTree 检查器、`useAnchoredMaxHeight` 钩子(把底部锚定的浮层高度收敛到锚点上方的视口空间,并在 resize、scroll 与调用方提供的依赖变化时重新测量)、TerminalBlock、DiffBlock、ReadBlock、SearchBlock,以及 WebBlock。
|
|
6
6
|
|
|
7
7
|
## 悬浮卡片
|
|
8
8
|
|
|
9
9
|
`HoverCard` 通过指针离开宽限期,使采用 portal 渲染的预览在跨过与锚点之间的间隙时仍可触及。消费方还可传入 `copyText`:此时卡片为指针与键盘激活提供按钮语义,其无障碍名称会在 `copyLabel` 前缀后包含该值,通过包内剪贴板辅助函数原样写入该值,并且只有宿主接受写入后,才会临时将内容替换为 `copiedLabel`。与卡片相交的非折叠文本选区会阻止指针点击激活;成功反馈保持卡片原有高度,并随卡片关闭或在一秒后清除。`copyLabel` 和 `copiedLabel` 采用 label prop,是因为这个 zero-cordis 原子组件无法读取应用 locale;省略 `copyText` 时,卡片维持只读且可选择文本的行为。历史依据见[已归档的悬浮卡片复制 Agent Note](../../../.agents/notes/archived/feature/2026-07-31-hover-card-click-copy.md)。
|
|
10
10
|
|
|
11
|
+
## Toast
|
|
12
|
+
|
|
13
|
+
`Toast` 是顶部的短时横幅:滑入后满不透明度停留三秒,再用一秒淡出,随后调用 `onDone` 由持有方卸载。它渲染 `role="alert"`,带可选的前置图标插槽,文案是必填 prop(零 cordis,由持有方本地化)。它经 body portal 渲染且 `pointer-events: none`,距视口顶部 120px,水平中心跟随可选的 `anchor` 元素(窗口尺寸变化时重测)——composer 传入自己的卡片,横幅因此在聊天列而非整个窗口上居中——不传则回退到视口居中。重复展示同一条消息需要重新挂载,持有方用每次展示递增的序号作为 key,让相同文案重新走完停留与淡出,而不是静默复用已淡出的横幅。`prefers-reduced-motion: reduce` 下去掉滑入,只保留延迟淡出。它的层级高于 ui-attachment 的图片灯箱,预览打开时报出的失败仍然可读。
|
|
14
|
+
|
|
11
15
|
## Markdown 渲染
|
|
12
16
|
|
|
13
17
|
`MarkdownText` 通过 React 元素渲染来自不受信任 assistant 输出的 GFM 与 `$…$`、`$$…$$`、`\(…\)` 和 `\[…\]` TeX 公式,公式由 KaTeX 排版并禁用受信任命令;块级同一行 `$$…$$` 是显示公式并支持 `\tag{}`。一个小范围的 micromark 扩展允许由星号标记、以标点结尾的粗体在紧邻的 CJK 文本前闭合,以适应 CJK 文本通常省略 CommonMark 所要求空格的写法;单星号强调、紧邻非 CJK 文本的情况、转义、代码与数学公式仍沿用上游解析行为。它会省略原始 HTML,使相对链接及非 HTTP(S)/mailto 链接失效,以安全的外部链接属性打开 HTTP(S) 链接,并在不发送 referrer 的情况下渲染采用绝对 HTTP(S) URL 的图片;相对路径、绝对本地路径、`file:` URL 与不受支持的 scheme 会保留其 alt 文本。完整内容为绝对 HTTP(S) URL 的行内代码会保留代码样式,并获得同样安全的外部链接;命令、非完整 URL、其他 scheme 与围栏代码仍不会成为链接。可选的 `fileMentions` 解析器让持有该组件的视图为命名真实文件的行内代码添加可点击入口:token 保留代码样式,并获得一个连接到解析所得 opener 的按钮,按钮带有解析器提供的无障碍标签和以完整路径为值的 `title`。渲染器绝不猜测哪些内容像路径:未解析的 token 保持不可交互;文件提及仅应用于已定稿的渲染(流式缓存不得固化可能过期的 handler);锚点内的 token 也保持不可交互,因为按钮不能嵌套其中。回复流式输出期间,`MarkdownText` 增量解析:除末尾两个块外全部冻结为缓存的 React 元素,每个分片只重新解析其后的源文本尾部,因此每分片的工作量跟随尾部而非整个回复([机制与 DOM 一致性约定](../../../.agents/notes/implemented/architecture/2026-08-06-web-markdown-incremental-ast-renderer.md))。`MessageText` 仍是用户创作内容使用的字面文本原语。`extractMarkdownPlainText` 会移除 Markdown 呈现标记以用于紧凑标签,同时将原始 HTML 保留为字面文本。元素间距、响应式图片、表格、链接与行内代码使用与 deepsuite `@deepseek/md` 相同的 `--dsw-alias-markdown-*` / `--dsw-font-markdown-*` token。围栏代码块通过 `CodeBlock` 渲染(语言横幅、复制控件,以及对已注册语法使用 shiki)。
|
|
@@ -34,7 +38,7 @@
|
|
|
34
38
|
|
|
35
39
|
## 模型体验
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
无。该包在浏览器中渲染纯 React 原子组件;这里没有任何内容进入模型请求。
|
|
38
42
|
|
|
39
43
|
#### KV Cache 影响
|
|
40
44
|
|
package/lib/index.js
CHANGED
|
@@ -102,6 +102,21 @@ const IconSearchOutline16 = ({ size = 16, className }) => jsxs("svg", {
|
|
|
102
102
|
fill: "currentColor"
|
|
103
103
|
})]
|
|
104
104
|
});
|
|
105
|
+
/** ic_ds_globe_outline_14 — meridian globe (harness-only figma extract). */
|
|
106
|
+
const IconGlobeOutline14 = ({ size = 14, className }) => jsx("svg", {
|
|
107
|
+
width: size,
|
|
108
|
+
height: size,
|
|
109
|
+
className,
|
|
110
|
+
viewBox: "0 0 14 14",
|
|
111
|
+
fill: "none",
|
|
112
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
113
|
+
children: jsx("path", {
|
|
114
|
+
fillRule: "evenodd",
|
|
115
|
+
clipRule: "evenodd",
|
|
116
|
+
d: "M7.00018 0.353516C10.6708 0.353535 13.6468 3.32958 13.6469 7.00018C13.6468 10.6708 10.6708 13.6468 7.00018 13.6469C3.32957 13.6468 0.353535 10.6708 0.353516 7.00018C0.353535 3.32957 3.32957 0.353531 7.00018 0.353516ZM5.44643 7.59661C5.49463 8.97506 5.70762 10.191 6.02136 11.0793C6.20141 11.5891 6.40328 11.9585 6.59898 12.1889C6.79501 12.4196 6.93213 12.454 7.00018 12.454C7.06822 12.454 7.20533 12.4197 7.40138 12.1889C7.59708 11.9585 7.79895 11.589 7.979 11.0793C8.29274 10.191 8.50574 8.97506 8.55394 7.59661H5.44643ZM1.57861 7.59661C1.80785 9.70467 3.2386 11.4509 5.1715 12.1388C5.07135 11.9317 4.97972 11.7098 4.89746 11.477C4.53084 10.4391 4.30224 9.0828 4.25357 7.59661H1.57861ZM9.74679 7.59661C9.69813 9.0828 9.46952 10.4391 9.1029 11.477C9.0206 11.7099 8.92818 11.9316 8.82797 12.1388C10.7613 11.4511 12.1925 9.70496 12.4218 7.59661H9.74679ZM5.1706 1.8616C3.23814 2.54963 1.80876 4.29604 1.5795 6.40376H4.25357C4.30224 4.91756 4.53083 3.56129 4.89746 2.5234C4.97968 2.29066 5.07051 2.0686 5.1706 1.8616ZM7.00018 1.54637C6.93213 1.54638 6.79503 1.5807 6.59898 1.81145C6.40332 2.04177 6.20139 2.41058 6.02136 2.92012C5.70754 3.80851 5.49461 5.02499 5.44643 6.40376H8.55394C8.50575 5.025 8.29282 3.80851 7.979 2.92012C7.79898 2.41059 7.59705 2.04177 7.40138 1.81145C7.20531 1.58067 7.06823 1.54637 7.00018 1.54637ZM8.82887 1.8616C8.92902 2.0687 9.02064 2.29053 9.1029 2.5234C9.46953 3.56129 9.69812 4.91756 9.74679 6.40376H12.4209C12.1916 4.29575 10.7618 2.54943 8.82887 1.8616Z",
|
|
117
|
+
fill: "currentColor"
|
|
118
|
+
})
|
|
119
|
+
});
|
|
105
120
|
/** ic_ds_settings_outline_14 */
|
|
106
121
|
const IconSettingsOutline14 = ({ size = 14, className }) => jsxs("svg", {
|
|
107
122
|
width: size,
|
|
@@ -499,6 +514,67 @@ const IconThinkOutline16 = ({ size = 16, className }) => jsxs("svg", {
|
|
|
499
514
|
fill: "currentColor"
|
|
500
515
|
})]
|
|
501
516
|
});
|
|
517
|
+
/** ic_ds_agent_preset_outline_16 (figma extract): node interiors knock out to transparency via mask, so the glyph sits on any fill. */
|
|
518
|
+
const IconAgentPresetOutline16 = ({ size = 16, className }) => jsxs("svg", {
|
|
519
|
+
width: size,
|
|
520
|
+
height: size,
|
|
521
|
+
className,
|
|
522
|
+
viewBox: "0 0 16 16",
|
|
523
|
+
fill: "none",
|
|
524
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
525
|
+
children: [
|
|
526
|
+
jsxs("mask", {
|
|
527
|
+
id: "mask0_agent_preset_16",
|
|
528
|
+
maskUnits: "userSpaceOnUse",
|
|
529
|
+
x: "0",
|
|
530
|
+
y: "0",
|
|
531
|
+
width: "16",
|
|
532
|
+
height: "16",
|
|
533
|
+
children: [
|
|
534
|
+
jsx("rect", {
|
|
535
|
+
width: "16",
|
|
536
|
+
height: "16",
|
|
537
|
+
fill: "white"
|
|
538
|
+
}),
|
|
539
|
+
jsx("circle", {
|
|
540
|
+
cx: "7.9995",
|
|
541
|
+
cy: "3.28319",
|
|
542
|
+
r: "1.712",
|
|
543
|
+
fill: "black"
|
|
544
|
+
}),
|
|
545
|
+
jsx("circle", {
|
|
546
|
+
cx: "3.51122",
|
|
547
|
+
cy: "11.3855",
|
|
548
|
+
r: "1.712",
|
|
549
|
+
fill: "black"
|
|
550
|
+
}),
|
|
551
|
+
jsx("circle", {
|
|
552
|
+
cx: "12.4878",
|
|
553
|
+
cy: "11.3855",
|
|
554
|
+
r: "1.712",
|
|
555
|
+
fill: "black"
|
|
556
|
+
})
|
|
557
|
+
]
|
|
558
|
+
}),
|
|
559
|
+
jsx("path", {
|
|
560
|
+
mask: "url(#mask0_agent_preset_16)",
|
|
561
|
+
d: "M12.2881 11.0425C12.6002 11.3723 13.0413 11.5786 13.5312 11.5786L13.5342 11.5776C13.1476 12.3233 12.6119 12.9785 11.9639 13.5005C10.9327 14.3309 9.6199 14.8286 8.19336 14.8286C7.29864 14.8285 6.45056 14.6313 5.6875 14.2808C6.08309 14.0281 6.36707 13.6189 6.45215 13.1392C6.99022 13.3561 7.57767 13.476 8.19336 13.4761C9.30019 13.4761 10.3157 13.0915 11.1152 12.4478C11.5935 12.0626 11.9924 11.5848 12.2881 11.0425ZM4.14746 4.36475C4.25569 4.83228 4.55488 5.2247 4.95898 5.4585C4.07956 6.30639 3.53144 7.49605 3.53125 8.81396C3.53125 9.69534 3.77613 10.5202 4.20117 11.2231C3.74959 11.3817 3.38395 11.7232 3.19531 12.1597C2.5541 11.2032 2.17969 10.052 2.17969 8.81396C2.17989 7.05087 2.93868 5.4646 4.14746 4.36475ZM8.19336 2.80029C8.85717 2.80029 9.49784 2.90834 10.0967 3.10791C12.3237 3.85044 13.9725 5.86061 14.1846 8.28369C13.9832 8.20048 13.7627 8.15382 13.5312 8.15381C13.2802 8.15381 13.042 8.20907 12.8271 8.30615C12.6281 6.47264 11.3666 4.95616 9.66895 4.39014C9.2063 4.236 8.70989 4.15186 8.19336 4.15186C7.96112 4.15189 7.7329 4.16981 7.50977 4.20264C7.51947 4.12886 7.52637 4.05348 7.52637 3.97705C7.52628 3.56604 7.3811 3.18914 7.13965 2.89404C7.48183 2.83352 7.83381 2.80033 8.19336 2.80029Z",
|
|
562
|
+
fill: "currentColor"
|
|
563
|
+
}),
|
|
564
|
+
jsx("path", {
|
|
565
|
+
d: "M9.1123 3.28271C9.11205 2.66858 8.61322 2.17041 7.99902 2.17041C7.38504 2.17067 6.88697 2.66874 6.88672 3.28271C6.88672 3.89691 7.38489 4.39574 7.99902 4.396C8.61338 4.396 9.1123 3.89707 9.1123 3.28271ZM10.3115 3.28271C10.3115 4.55981 9.27612 5.59521 7.99902 5.59521C6.72214 5.59496 5.6875 4.55965 5.6875 3.28271C5.68776 2.00599 6.7223 0.971447 7.99902 0.971191C9.27596 0.971191 10.3113 2.00584 10.3115 3.28271Z",
|
|
566
|
+
fill: "currentColor"
|
|
567
|
+
}),
|
|
568
|
+
jsx("path", {
|
|
569
|
+
d: "M4.62402 11.385C4.62377 10.7709 4.12494 10.2727 3.51074 10.2727C2.89676 10.273 2.39869 10.771 2.39844 11.385C2.39844 11.9992 2.89661 12.498 3.51074 12.4983C4.1251 12.4983 4.62402 11.9994 4.62402 11.385ZM5.82324 11.385C5.82324 12.6621 4.78784 13.6975 3.51074 13.6975C2.23386 13.6973 1.19922 12.6619 1.19922 11.385C1.19947 10.1083 2.23402 9.07374 3.51074 9.07349C4.78768 9.07349 5.82299 10.1081 5.82324 11.385Z",
|
|
570
|
+
fill: "currentColor"
|
|
571
|
+
}),
|
|
572
|
+
jsx("path", {
|
|
573
|
+
d: "M13.6006 11.385C13.6003 10.7709 13.1015 10.2727 12.4873 10.2727C11.8733 10.273 11.3753 10.771 11.375 11.385C11.375 11.9992 11.8732 12.498 12.4873 12.4983C13.1017 12.4983 13.6006 11.9994 13.6006 11.385ZM14.7998 11.385C14.7998 12.6621 13.7644 13.6975 12.4873 13.6975C11.2104 13.6973 10.1758 12.6619 10.1758 11.385C10.176 10.1083 11.2106 9.07374 12.4873 9.07349C13.7642 9.07349 14.7995 10.1081 14.7998 11.385Z",
|
|
574
|
+
fill: "currentColor"
|
|
575
|
+
})
|
|
576
|
+
]
|
|
577
|
+
});
|
|
502
578
|
/** ic_ds_browse_outline_16 */
|
|
503
579
|
const IconBrowseOutline16 = ({ size = 16, className }) => jsxs("svg", {
|
|
504
580
|
width: size,
|
|
@@ -794,6 +870,35 @@ const IconCodeOutline16 = ({ size = 16, className }) => jsx("svg", {
|
|
|
794
870
|
fill: "currentColor"
|
|
795
871
|
})
|
|
796
872
|
});
|
|
873
|
+
/** ic_ds_cordis_plugin_outline_14 */
|
|
874
|
+
const IconCordisPluginOutline14 = ({ size = 14, className }) => jsxs("svg", {
|
|
875
|
+
width: size,
|
|
876
|
+
height: size,
|
|
877
|
+
className,
|
|
878
|
+
viewBox: "0 0 14 14",
|
|
879
|
+
fill: "none",
|
|
880
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
881
|
+
children: [jsxs("g", {
|
|
882
|
+
clipPath: "url(#clip0_1840_45990)",
|
|
883
|
+
children: [jsx("path", {
|
|
884
|
+
d: "M3.03426 5.66661L1.70084 7.00003L3.0315 8.33069L2.14762 9.21457L-0.0669245 7.00003L2.15038 4.78273L3.03426 5.66661ZM7 14.067L4.77924 11.8462L5.66313 10.9623L7 12.2992L8.33342 10.9658L9.2173 11.8496L7 14.067ZM11.8489 9.21803L10.965 8.33414L12.2992 7.00003L10.9623 5.66316L11.8462 4.77927L14.0669 7.00003L11.8489 9.21803ZM8.33066 3.03153L7 1.70087L5.66589 3.03498L4.782 2.1511L7 -0.0668945L9.21454 2.14765L8.33066 3.03153Z",
|
|
885
|
+
fill: "currentColor"
|
|
886
|
+
}), jsx("rect", {
|
|
887
|
+
x: "5.98535",
|
|
888
|
+
y: "5.98535",
|
|
889
|
+
width: "2.02942",
|
|
890
|
+
height: "2.02942",
|
|
891
|
+
fill: "currentColor"
|
|
892
|
+
})]
|
|
893
|
+
}), jsx("defs", { children: jsx("clipPath", {
|
|
894
|
+
id: "clip0_1840_45990",
|
|
895
|
+
children: jsx("rect", {
|
|
896
|
+
width: "14",
|
|
897
|
+
height: "14",
|
|
898
|
+
fill: "currentColor"
|
|
899
|
+
})
|
|
900
|
+
}) })]
|
|
901
|
+
});
|
|
797
902
|
/** ic_ds_api_outline (figma extract) */
|
|
798
903
|
const IconApiOutline14 = ({ size = 14, className }) => jsxs("svg", {
|
|
799
904
|
width: size,
|
|
@@ -1392,6 +1497,7 @@ const MEASURE_STYLE = {
|
|
|
1392
1497
|
* @param props.anchor - the trigger element (rendered in place).
|
|
1393
1498
|
* @param props.items - selectable rows and optional separators.
|
|
1394
1499
|
* @param props.selectedId - row shown as selected.
|
|
1500
|
+
* @param props.selectedIds - rows shown as selected when a menu contains independent option groups.
|
|
1395
1501
|
* @param props.onSelect - row click callback (not called for disabled rows or submenu parents that only open children).
|
|
1396
1502
|
* @param props.onClose - invoked on outside click or Escape.
|
|
1397
1503
|
* @param props.align - list alignment against the anchor (default 'start').
|
|
@@ -1404,6 +1510,7 @@ const MEASURE_STYLE = {
|
|
|
1404
1510
|
* both trigger and list for the pointer grace (default false keeps it open
|
|
1405
1511
|
* until outside click/Escape/selection). The grace makes the 4px trigger->list
|
|
1406
1512
|
* gap and a brief overshoot survivable; coming back cancels the close.
|
|
1513
|
+
* @param props.dense - reduce vertical row spacing without changing the standard typography or card width.
|
|
1407
1514
|
* @param props.compact - use reduced menu typography and spacing.
|
|
1408
1515
|
* @param props.getAnchorRect - portal mode only: supply the anchor rect
|
|
1409
1516
|
* directly (e.g. from a host-owned trigger button) instead of measuring the
|
|
@@ -1415,7 +1522,7 @@ const MEASURE_STYLE = {
|
|
|
1415
1522
|
* by a hairline; they stay visible while the items above scroll.
|
|
1416
1523
|
* @returns anchor wrapper with the conditional list.
|
|
1417
1524
|
*/
|
|
1418
|
-
function Menu({ open, anchor, items, selectedId, onSelect, onClose, align = "start", side = "bottom", portal = false, closeOnPointerLeave = false, compact = false, getAnchorRect, footer, className }) {
|
|
1525
|
+
function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose, align = "start", side = "bottom", portal = false, closeOnPointerLeave = false, dense = false, compact = false, getAnchorRect, footer, className }) {
|
|
1419
1526
|
const rootRef = useRef(null);
|
|
1420
1527
|
const listRef = useRef(null);
|
|
1421
1528
|
const [openSubmenuId, setOpenSubmenuId] = useState(null);
|
|
@@ -1509,6 +1616,7 @@ function Menu({ open, anchor, items, selectedId, onSelect, onClose, align = "sta
|
|
|
1509
1616
|
}, entry.id);
|
|
1510
1617
|
const hasSub = entry.submenu !== void 0 && entry.submenu.length > 0;
|
|
1511
1618
|
const subOpen = hasSub && openSubmenuId === entry.id;
|
|
1619
|
+
const selected = entry.id === selectedId || selectedIds?.includes(entry.id) === true;
|
|
1512
1620
|
return jsxs("div", {
|
|
1513
1621
|
className: Menu_module_css_default.itemWrap,
|
|
1514
1622
|
onMouseEnter: () => {
|
|
@@ -1520,7 +1628,7 @@ function Menu({ open, anchor, items, selectedId, onSelect, onClose, align = "sta
|
|
|
1520
1628
|
children: [jsxs("button", {
|
|
1521
1629
|
type: "button",
|
|
1522
1630
|
role: "menuitem",
|
|
1523
|
-
className: clsx(Menu_module_css_default.item,
|
|
1631
|
+
className: clsx(Menu_module_css_default.item, selected && Menu_module_css_default.selected, entry.danger === true && Menu_module_css_default.danger),
|
|
1524
1632
|
disabled: entry.disabled,
|
|
1525
1633
|
"aria-haspopup": hasSub ? "menu" : void 0,
|
|
1526
1634
|
"aria-expanded": hasSub ? subOpen : void 0,
|
|
@@ -1543,7 +1651,7 @@ function Menu({ open, anchor, items, selectedId, onSelect, onClose, align = "sta
|
|
|
1543
1651
|
className: Menu_module_css_default.itemLabel,
|
|
1544
1652
|
children: entry.label
|
|
1545
1653
|
}),
|
|
1546
|
-
|
|
1654
|
+
selected && jsx(IconCheckOutline16, { className: Menu_module_css_default.check })
|
|
1547
1655
|
]
|
|
1548
1656
|
}), subOpen && entry.submenu !== void 0 && jsx("div", {
|
|
1549
1657
|
className: clsx(Menu_module_css_default.submenu, compact && Menu_module_css_default.compactList),
|
|
@@ -1569,7 +1677,7 @@ function Menu({ open, anchor, items, selectedId, onSelect, onClose, align = "sta
|
|
|
1569
1677
|
};
|
|
1570
1678
|
const list = open && jsxs("div", {
|
|
1571
1679
|
ref: listRef,
|
|
1572
|
-
className: clsx(Menu_module_css_default.list, compact && Menu_module_css_default.compactList, scrollable && Menu_module_css_default.scrollable, portal && Menu_module_css_default.portal, side === "top" && !portal && Menu_module_css_default.sideTop, align === "end" && !portal && Menu_module_css_default.alignEnd),
|
|
1680
|
+
className: clsx(Menu_module_css_default.list, dense && Menu_module_css_default.denseList, compact && Menu_module_css_default.compactList, scrollable && Menu_module_css_default.scrollable, portal && Menu_module_css_default.portal, side === "top" && !portal && Menu_module_css_default.sideTop, align === "end" && !portal && Menu_module_css_default.alignEnd),
|
|
1573
1681
|
style: portal ? fixedPos ?? MEASURE_STYLE : void 0,
|
|
1574
1682
|
role: "menu",
|
|
1575
1683
|
onClick: (e) => {
|
|
@@ -2180,15 +2288,17 @@ var Tooltip_module_css_default = {};
|
|
|
2180
2288
|
//#region lib/types/Tooltip.js
|
|
2181
2289
|
/**
|
|
2182
2290
|
* Attach a hover/focus tooltip to an anchor element.
|
|
2183
|
-
* @param props.label - bubble text.
|
|
2291
|
+
* @param props.label - bubble text, or a resolver evaluated only while the bubble is visible.
|
|
2184
2292
|
* @param props.side - placement relative to the anchor (default 'right').
|
|
2185
2293
|
* @param props.delayMs - hover delay in milliseconds; keyboard focus remains immediate.
|
|
2186
2294
|
* @param props.disabled - suppress the bubble while true; the anchor renders identically so
|
|
2187
2295
|
* toggling never remounts it (which would cut its CSS transitions).
|
|
2296
|
+
* @param props.maxWidth - bubble width cap in pixels, for labels long enough that the default
|
|
2297
|
+
* half-viewport cap would render a slab wider than the surface the anchor sits on.
|
|
2188
2298
|
* @param props.children - a single anchor element; its own ref (callback or object) is forwarded alongside the tooltip's.
|
|
2189
2299
|
* @returns the cloned anchor plus a fixed-position bubble while hovered/focused.
|
|
2190
2300
|
*/
|
|
2191
|
-
function Tooltip({ label, side = "right", delayMs = 0, disabled = false, children }) {
|
|
2301
|
+
function Tooltip({ label, side = "right", delayMs = 0, disabled = false, maxWidth, children }) {
|
|
2192
2302
|
const anchor = useRef(null);
|
|
2193
2303
|
const childRef = children.ref;
|
|
2194
2304
|
const mergedRef = useCallback((el) => {
|
|
@@ -2197,27 +2307,40 @@ function Tooltip({ label, side = "right", delayMs = 0, disabled = false, childre
|
|
|
2197
2307
|
else if (childRef != null) childRef.current = el;
|
|
2198
2308
|
}, [childRef]);
|
|
2199
2309
|
const [pos, setPos] = useState(null);
|
|
2310
|
+
const [placement, setPlacement] = useState(side);
|
|
2200
2311
|
const bubble = useRef(null);
|
|
2312
|
+
const resolvedLabel = pos === null ? null : typeof label === "function" ? label() : label;
|
|
2313
|
+
const y = pos === null ? 0 : placement === "right" ? pos.top + (pos.bottom - pos.top) / 2 : placement === "top" ? pos.top - 8 : pos.bottom + 8;
|
|
2314
|
+
const EDGE_MARGIN = 12;
|
|
2201
2315
|
useLayoutEffect(() => {
|
|
2202
2316
|
if (pos === null) return;
|
|
2203
|
-
const
|
|
2317
|
+
const fit = () => {
|
|
2204
2318
|
const el = bubble.current;
|
|
2205
2319
|
/* v8 ignore next -- pos is set only while the bubble is mounted. */
|
|
2206
2320
|
if (el === null) return;
|
|
2207
|
-
const EDGE_MARGIN = 12;
|
|
2208
2321
|
el.style.left = `${pos.x}px`;
|
|
2209
2322
|
const r = el.getBoundingClientRect();
|
|
2210
2323
|
let dx = 0;
|
|
2211
2324
|
if (r.right > window.innerWidth - EDGE_MARGIN) dx = window.innerWidth - EDGE_MARGIN - r.right;
|
|
2212
2325
|
if (r.left + dx < EDGE_MARGIN) dx = EDGE_MARGIN - r.left;
|
|
2213
2326
|
el.style.left = `${pos.x + dx}px`;
|
|
2327
|
+
if (side === "right") return;
|
|
2328
|
+
const fitsBelow = pos.bottom + 8 + r.height <= window.innerHeight - EDGE_MARGIN;
|
|
2329
|
+
const fitsAbove = pos.top - 8 - r.height >= EDGE_MARGIN;
|
|
2330
|
+
if (placement === "bottom" && !fitsBelow && fitsAbove) setPlacement("top");
|
|
2331
|
+
if (placement === "top" && !fitsAbove && fitsBelow) setPlacement("bottom");
|
|
2214
2332
|
};
|
|
2215
|
-
|
|
2216
|
-
window.addEventListener("resize",
|
|
2333
|
+
fit();
|
|
2334
|
+
window.addEventListener("resize", fit);
|
|
2217
2335
|
return () => {
|
|
2218
|
-
window.removeEventListener("resize",
|
|
2336
|
+
window.removeEventListener("resize", fit);
|
|
2219
2337
|
};
|
|
2220
|
-
}, [
|
|
2338
|
+
}, [
|
|
2339
|
+
placement,
|
|
2340
|
+
pos,
|
|
2341
|
+
resolvedLabel,
|
|
2342
|
+
side
|
|
2343
|
+
]);
|
|
2221
2344
|
const showTimer = useRef(null);
|
|
2222
2345
|
const triggers = useRef({
|
|
2223
2346
|
hover: false,
|
|
@@ -2245,15 +2368,11 @@ function Tooltip({ label, side = "right", delayMs = 0, disabled = false, childre
|
|
|
2245
2368
|
/* v8 ignore next -- the ref is attached by event time: events fire on the cloned anchor. */
|
|
2246
2369
|
if (el === null) return;
|
|
2247
2370
|
const r = el.getBoundingClientRect();
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
y: r.top - 8
|
|
2254
|
-
} : {
|
|
2255
|
-
x: r.left + r.width / 2,
|
|
2256
|
-
y: r.bottom + 8
|
|
2371
|
+
setPlacement(side);
|
|
2372
|
+
setPos({
|
|
2373
|
+
x: side === "right" ? r.right + 10 : r.left + r.width / 2,
|
|
2374
|
+
top: r.top,
|
|
2375
|
+
bottom: r.bottom
|
|
2257
2376
|
});
|
|
2258
2377
|
};
|
|
2259
2378
|
const showAfterHoverDelay = () => {
|
|
@@ -2298,16 +2417,72 @@ function Tooltip({ label, side = "right", delayMs = 0, disabled = false, childre
|
|
|
2298
2417
|
}), pos !== null && jsx("span", {
|
|
2299
2418
|
ref: bubble,
|
|
2300
2419
|
className: Tooltip_module_css_default.bubble,
|
|
2301
|
-
"data-side":
|
|
2420
|
+
"data-side": placement,
|
|
2302
2421
|
style: {
|
|
2303
2422
|
left: pos.x,
|
|
2304
|
-
top:
|
|
2423
|
+
top: y,
|
|
2424
|
+
...maxWidth === void 0 ? {} : { maxWidth }
|
|
2305
2425
|
},
|
|
2306
2426
|
role: "tooltip",
|
|
2307
|
-
children:
|
|
2427
|
+
children: resolvedLabel
|
|
2308
2428
|
})] });
|
|
2309
2429
|
}
|
|
2310
2430
|
//#endregion
|
|
2431
|
+
//#region \0dsh-css-stub:./Toast.module.css.mjs
|
|
2432
|
+
var Toast_module_css_default = {};
|
|
2433
|
+
//#endregion
|
|
2434
|
+
//#region lib/types/Toast.js
|
|
2435
|
+
/**
|
|
2436
|
+
* Transient top-center banner: slides in, holds at full opacity, fades out,
|
|
2437
|
+
* then reports done so the owner can unmount it. Re-showing the same text
|
|
2438
|
+
* restarts the cycle when the owner remounts the component (key it by a
|
|
2439
|
+
* per-show sequence). Rendered through a body portal so an owner inside a
|
|
2440
|
+
* transformed or filtered ancestor cannot trap the fixed banner in that
|
|
2441
|
+
* ancestor's box.
|
|
2442
|
+
*
|
|
2443
|
+
* @param props.text - resolved banner copy; the owner passes localized text.
|
|
2444
|
+
* @param props.icon - optional leading glyph (e.g. a warning icon).
|
|
2445
|
+
* @param props.anchor - optional element whose horizontal center the banner
|
|
2446
|
+
* follows (e.g. the composer card, so the banner centers over the chat column
|
|
2447
|
+
* rather than the whole window); omitted, it centers on the viewport.
|
|
2448
|
+
* @param props.onDone - called once the fade completes; unmount the toast here.
|
|
2449
|
+
* @returns the floating banner.
|
|
2450
|
+
*/
|
|
2451
|
+
function Toast({ text, icon, anchor, onDone }) {
|
|
2452
|
+
useEffect(() => {
|
|
2453
|
+
const timer = setTimeout(onDone, 4e3);
|
|
2454
|
+
return () => {
|
|
2455
|
+
clearTimeout(timer);
|
|
2456
|
+
};
|
|
2457
|
+
}, [onDone]);
|
|
2458
|
+
const [left, setLeft] = useState(null);
|
|
2459
|
+
useLayoutEffect(() => {
|
|
2460
|
+
if (anchor == null) return;
|
|
2461
|
+
const measure = () => {
|
|
2462
|
+
const rect = anchor.getBoundingClientRect();
|
|
2463
|
+
setLeft(rect.left + rect.width / 2);
|
|
2464
|
+
};
|
|
2465
|
+
measure();
|
|
2466
|
+
window.addEventListener("resize", measure);
|
|
2467
|
+
return () => {
|
|
2468
|
+
window.removeEventListener("resize", measure);
|
|
2469
|
+
};
|
|
2470
|
+
}, [anchor]);
|
|
2471
|
+
return createPortal(jsxs("div", {
|
|
2472
|
+
className: Toast_module_css_default.toast,
|
|
2473
|
+
role: "alert",
|
|
2474
|
+
style: left === null ? void 0 : { left },
|
|
2475
|
+
children: [icon !== void 0 && jsx("span", {
|
|
2476
|
+
className: Toast_module_css_default.icon,
|
|
2477
|
+
"aria-hidden": true,
|
|
2478
|
+
children: icon
|
|
2479
|
+
}), jsx("span", {
|
|
2480
|
+
className: Toast_module_css_default.text,
|
|
2481
|
+
children: text
|
|
2482
|
+
})]
|
|
2483
|
+
}), document.body);
|
|
2484
|
+
}
|
|
2485
|
+
//#endregion
|
|
2311
2486
|
//#region \0dsh-css-stub:./JsonTree.module.css.mjs
|
|
2312
2487
|
var JsonTree_module_css_default = {};
|
|
2313
2488
|
//#endregion
|
|
@@ -5677,4 +5852,4 @@ function extractMarkdownPlainText(markdown, options = {}) {
|
|
|
5677
5852
|
}
|
|
5678
5853
|
}
|
|
5679
5854
|
//#endregion
|
|
5680
|
-
export { BrandWordmark, Button, CodeBlock, ConnectionBanner, DEFAULT_DIFF_MAX_LINES, DEFAULT_READ_MAX_LINES, DEFAULT_SEARCH_MAX_LINES, DEFAULT_TERMINAL_MAX_LINES, DiffBlock, DisclosureRow, FishLogo, HoverCard, IconApiOutline14, IconArchiveOutline20, IconBranchOutline16, IconBrowseOutline16, IconCheckOutline14, IconCheckOutline16, IconChecklistOutline14, IconChevronDownOutline14, IconChevronLeftOutline14, IconChevronRightOutline14, IconChevronUpOutline14, IconCloseFill14, IconCloseOutline16, IconCodeOutline16, IconCopyOutline16, IconDarkOutline16, IconDataOutline16, IconDislikeFill16, IconDislikeOutline16, IconDownloadOutline16, IconEditOutline16, IconEllipsisOutline16, IconEnhanceOutline16, IconFolderClose16, IconFolderOpen16, IconFolderOpenOutline16, IconFollowsystemOutline16, IconFullscreenOutline16, IconGoalOutline16, IconInspectOutline12, IconLightOutline16, IconLikeFill16, IconLikeOutline16, IconLinkOutline14, IconLinkOutline16, IconListPenOutline16, IconLoadingOutline16, IconNewChatOutline16, IconPanelLeftOutline16, IconPaperclipOutline16, IconPauseOutline16, IconPersonalizationOutline16, IconPlayOutline16, IconPlusOutline16, IconProjectAddOutline16, IconQuestionOutline14, IconQueueOutline14, IconRefreshOutline14, IconRefreshOutline16, IconRightUpOutline14, IconRightUpOutline16, IconSearchOutline16, IconSendOutline14, IconSendOutline16, IconSettingsOutline14, IconSettingsOutline16, IconShareOutline16, IconSkillOutline16, IconSparkle16, IconStopFill16, IconThinkOutline14, IconThinkOutline16, IconTrashOutline16, IconTreeCorner8x10, IconTriangleRightFill14, IconUserOutline16, IconWarningOutline16, Input, JsonBlock, JsonTree, MarkdownText, Menu, MessageText, Modal, OnboardingSurface, Pill, ReadBlock, RiskConfirmation, SearchBlock, StateDot, TerminalBlock, Tooltip, WebBlock, extractMarkdownPlainText, useAnchoredMaxHeight, writeClipboard };
|
|
5855
|
+
export { BrandWordmark, Button, CodeBlock, ConnectionBanner, DEFAULT_DIFF_MAX_LINES, DEFAULT_READ_MAX_LINES, DEFAULT_SEARCH_MAX_LINES, DEFAULT_TERMINAL_MAX_LINES, DiffBlock, DisclosureRow, FishLogo, HoverCard, IconAgentPresetOutline16, IconApiOutline14, IconArchiveOutline20, IconBranchOutline16, IconBrowseOutline16, IconCheckOutline14, IconCheckOutline16, IconChecklistOutline14, IconChevronDownOutline14, IconChevronLeftOutline14, IconChevronRightOutline14, IconChevronUpOutline14, IconCloseFill14, IconCloseOutline16, IconCodeOutline16, IconCopyOutline16, IconCordisPluginOutline14, IconDarkOutline16, IconDataOutline16, IconDislikeFill16, IconDislikeOutline16, IconDownloadOutline16, IconEditOutline16, IconEllipsisOutline16, IconEnhanceOutline16, IconFolderClose16, IconFolderOpen16, IconFolderOpenOutline16, IconFollowsystemOutline16, IconFullscreenOutline16, IconGlobeOutline14, IconGoalOutline16, IconInspectOutline12, IconLightOutline16, IconLikeFill16, IconLikeOutline16, IconLinkOutline14, IconLinkOutline16, IconListPenOutline16, IconLoadingOutline16, IconNewChatOutline16, IconPanelLeftOutline16, IconPaperclipOutline16, IconPauseOutline16, IconPersonalizationOutline16, IconPlayOutline16, IconPlusOutline16, IconProjectAddOutline16, IconQuestionOutline14, IconQueueOutline14, IconRefreshOutline14, IconRefreshOutline16, IconRightUpOutline14, IconRightUpOutline16, IconSearchOutline16, IconSendOutline14, IconSendOutline16, IconSettingsOutline14, IconSettingsOutline16, IconShareOutline16, IconSkillOutline16, IconSparkle16, IconStopFill16, IconThinkOutline14, IconThinkOutline16, IconTrashOutline16, IconTreeCorner8x10, IconTriangleRightFill14, IconUserOutline16, IconWarningOutline16, Input, JsonBlock, JsonTree, MarkdownText, Menu, MessageText, Modal, OnboardingSurface, Pill, ReadBlock, RiskConfirmation, SearchBlock, StateDot, TerminalBlock, Toast, Tooltip, WebBlock, extractMarkdownPlainText, useAnchoredMaxHeight, writeClipboard };
|
package/lib/invariant.js
CHANGED
|
@@ -9,7 +9,7 @@ const name = "client-ui-primitives-invariant";
|
|
|
9
9
|
/** Service required before the companion can reserve package ownership. */
|
|
10
10
|
const inject = ["invariants"];
|
|
11
11
|
/**
|
|
12
|
-
* No runtime invariant: pure props-in React atoms with
|
|
12
|
+
* No runtime invariant: pure props-in React atoms with no Cordis API —
|
|
13
13
|
* no events, no services, no mutable cross-plugin state; rendering contracts
|
|
14
14
|
* are asserted directly by this package's component specs.
|
|
15
15
|
*/
|
package/lib/types/Menu.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ export type MenuEntry = MenuItem | MenuSeparator | MenuLabel;
|
|
|
30
30
|
* @param props.anchor - the trigger element (rendered in place).
|
|
31
31
|
* @param props.items - selectable rows and optional separators.
|
|
32
32
|
* @param props.selectedId - row shown as selected.
|
|
33
|
+
* @param props.selectedIds - rows shown as selected when a menu contains independent option groups.
|
|
33
34
|
* @param props.onSelect - row click callback (not called for disabled rows or submenu parents that only open children).
|
|
34
35
|
* @param props.onClose - invoked on outside click or Escape.
|
|
35
36
|
* @param props.align - list alignment against the anchor (default 'start').
|
|
@@ -42,6 +43,7 @@ export type MenuEntry = MenuItem | MenuSeparator | MenuLabel;
|
|
|
42
43
|
* both trigger and list for the pointer grace (default false keeps it open
|
|
43
44
|
* until outside click/Escape/selection). The grace makes the 4px trigger->list
|
|
44
45
|
* gap and a brief overshoot survivable; coming back cancels the close.
|
|
46
|
+
* @param props.dense - reduce vertical row spacing without changing the standard typography or card width.
|
|
45
47
|
* @param props.compact - use reduced menu typography and spacing.
|
|
46
48
|
* @param props.getAnchorRect - portal mode only: supply the anchor rect
|
|
47
49
|
* directly (e.g. from a host-owned trigger button) instead of measuring the
|
|
@@ -53,18 +55,20 @@ export type MenuEntry = MenuItem | MenuSeparator | MenuLabel;
|
|
|
53
55
|
* by a hairline; they stay visible while the items above scroll.
|
|
54
56
|
* @returns anchor wrapper with the conditional list.
|
|
55
57
|
*/
|
|
56
|
-
export declare function Menu({ open, anchor, items, selectedId, onSelect, onClose, align, side, portal, closeOnPointerLeave, compact, getAnchorRect, footer, className }: {
|
|
58
|
+
export declare function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose, align, side, portal, closeOnPointerLeave, dense, compact, getAnchorRect, footer, className }: {
|
|
57
59
|
open: boolean;
|
|
58
60
|
anchor: ReactNode;
|
|
59
61
|
items: readonly MenuEntry[];
|
|
60
62
|
footer?: readonly MenuEntry[];
|
|
61
63
|
selectedId?: string | undefined;
|
|
64
|
+
selectedIds?: readonly string[] | undefined;
|
|
62
65
|
onSelect: (id: string) => void;
|
|
63
66
|
onClose: () => void;
|
|
64
67
|
align?: 'start' | 'end';
|
|
65
68
|
side?: 'bottom' | 'top' | 'right';
|
|
66
69
|
portal?: boolean;
|
|
67
70
|
closeOnPointerLeave?: boolean;
|
|
71
|
+
dense?: boolean;
|
|
68
72
|
compact?: boolean;
|
|
69
73
|
getAnchorRect?: () => DOMRect | null;
|
|
70
74
|
className?: string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Transient top-center banner: slides in, holds at full opacity, fades out,
|
|
4
|
+
* then reports done so the owner can unmount it. Re-showing the same text
|
|
5
|
+
* restarts the cycle when the owner remounts the component (key it by a
|
|
6
|
+
* per-show sequence). Rendered through a body portal so an owner inside a
|
|
7
|
+
* transformed or filtered ancestor cannot trap the fixed banner in that
|
|
8
|
+
* ancestor's box.
|
|
9
|
+
*
|
|
10
|
+
* @param props.text - resolved banner copy; the owner passes localized text.
|
|
11
|
+
* @param props.icon - optional leading glyph (e.g. a warning icon).
|
|
12
|
+
* @param props.anchor - optional element whose horizontal center the banner
|
|
13
|
+
* follows (e.g. the composer card, so the banner centers over the chat column
|
|
14
|
+
* rather than the whole window); omitted, it centers on the viewport.
|
|
15
|
+
* @param props.onDone - called once the fade completes; unmount the toast here.
|
|
16
|
+
* @returns the floating banner.
|
|
17
|
+
*/
|
|
18
|
+
export declare function Toast({ text, icon, anchor, onDone }: {
|
|
19
|
+
text: string;
|
|
20
|
+
icon?: ReactNode;
|
|
21
|
+
anchor?: HTMLElement | null;
|
|
22
|
+
onDone: () => void;
|
|
23
|
+
}): import("react").ReactPortal;
|
|
24
|
+
//# sourceMappingURL=Toast.d.ts.map
|
package/lib/types/Tooltip.d.ts
CHANGED
|
@@ -9,21 +9,25 @@ interface AnchorProps {
|
|
|
9
9
|
onFocus?: FocusEventHandler | undefined;
|
|
10
10
|
onBlur?: FocusEventHandler | undefined;
|
|
11
11
|
}
|
|
12
|
+
type TooltipLabel = string | (() => string);
|
|
12
13
|
/**
|
|
13
14
|
* Attach a hover/focus tooltip to an anchor element.
|
|
14
|
-
* @param props.label - bubble text.
|
|
15
|
+
* @param props.label - bubble text, or a resolver evaluated only while the bubble is visible.
|
|
15
16
|
* @param props.side - placement relative to the anchor (default 'right').
|
|
16
17
|
* @param props.delayMs - hover delay in milliseconds; keyboard focus remains immediate.
|
|
17
18
|
* @param props.disabled - suppress the bubble while true; the anchor renders identically so
|
|
18
19
|
* toggling never remounts it (which would cut its CSS transitions).
|
|
20
|
+
* @param props.maxWidth - bubble width cap in pixels, for labels long enough that the default
|
|
21
|
+
* half-viewport cap would render a slab wider than the surface the anchor sits on.
|
|
19
22
|
* @param props.children - a single anchor element; its own ref (callback or object) is forwarded alongside the tooltip's.
|
|
20
23
|
* @returns the cloned anchor plus a fixed-position bubble while hovered/focused.
|
|
21
24
|
*/
|
|
22
|
-
export declare function Tooltip({ label, side, delayMs, disabled, children }: {
|
|
23
|
-
label:
|
|
25
|
+
export declare function Tooltip({ label, side, delayMs, disabled, maxWidth, children }: {
|
|
26
|
+
label: TooltipLabel;
|
|
24
27
|
side?: TooltipSide;
|
|
25
28
|
delayMs?: number;
|
|
26
29
|
disabled?: boolean;
|
|
30
|
+
maxWidth?: number;
|
|
27
31
|
children: ReactElement<AnchorProps>;
|
|
28
32
|
}): import("react").JSX.Element;
|
|
29
33
|
export {};
|
|
@@ -9,6 +9,8 @@ export type { IconProps } from './props.ts';
|
|
|
9
9
|
export declare const IconNewChatOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
10
10
|
/** ic_ds_search_outline_16 */
|
|
11
11
|
export declare const IconSearchOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
12
|
+
/** ic_ds_globe_outline_14 — meridian globe (harness-only figma extract). */
|
|
13
|
+
export declare const IconGlobeOutline14: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
12
14
|
/** ic_ds_settings_outline_14 */
|
|
13
15
|
export declare const IconSettingsOutline14: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
14
16
|
/** ic_ds_settings_outline_16 */
|
|
@@ -61,6 +63,8 @@ export declare const IconEditOutline16: ({ size, className }: IconProps) => impo
|
|
|
61
63
|
export declare const IconThinkOutline14: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
62
64
|
/** ic_ds_think_outline_16 */
|
|
63
65
|
export declare const IconThinkOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
66
|
+
/** ic_ds_agent_preset_outline_16 (figma extract): node interiors knock out to transparency via mask, so the glyph sits on any fill. */
|
|
67
|
+
export declare const IconAgentPresetOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
64
68
|
/** ic_ds_browse_outline_16 */
|
|
65
69
|
export declare const IconBrowseOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
66
70
|
/** ic_ds_link_outline_14 */
|
|
@@ -97,6 +101,8 @@ export declare const IconPauseOutline16: ({ size, className }: IconProps) => imp
|
|
|
97
101
|
export declare const IconFullscreenOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
98
102
|
/** ic_ds_code_outline_16 */
|
|
99
103
|
export declare const IconCodeOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
104
|
+
/** ic_ds_cordis_plugin_outline_14 */
|
|
105
|
+
export declare const IconCordisPluginOutline14: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
100
106
|
/** ic_ds_api_outline (figma extract) */
|
|
101
107
|
export declare const IconApiOutline14: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
102
108
|
/** ic_ds_personalization_outline_16 (figma extract) */
|
package/lib/types/index.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export { FishLogo } from './FishLogo.tsx';
|
|
|
22
22
|
export { BrandWordmark } from './BrandWordmark.tsx';
|
|
23
23
|
export { Tooltip } from './Tooltip.tsx';
|
|
24
24
|
export type { TooltipSide } from './Tooltip.tsx';
|
|
25
|
+
export { Toast } from './Toast.tsx';
|
|
25
26
|
export { writeClipboard } from './clipboard.ts';
|
|
26
27
|
export { JsonTree } from './JsonTree.tsx';
|
|
27
28
|
export type { JsonTreeProps, JsonTreeLabels } from './JsonTree.tsx';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-ui-primitives",
|
|
3
3
|
"description": "Pure React atoms for the dsh web UI: controls, icons, markdown, and JSON inspectors (zero cordis)",
|
|
4
|
-
"version": "0.0.1-rc.
|
|
4
|
+
"version": "0.0.1-rc.3",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "restricted"
|
|
7
7
|
},
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/react": "~18.3.1",
|
|
53
53
|
"@types/react-dom": "~18.3.0",
|
|
54
|
-
"@deepseek-ai/
|
|
55
|
-
"@deepseek-ai/
|
|
54
|
+
"@deepseek-ai/dsh-invariants": "^0.0.1-rc.3",
|
|
55
|
+
"@deepseek-ai/cordis": "^4.0.1-rc.1"
|
|
56
56
|
},
|
|
57
57
|
"files": [
|
|
58
58
|
"lib/index.js",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"lib/types/**/*.d.ts"
|
|
61
61
|
],
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"@deepseek-ai/
|
|
64
|
-
"@deepseek-ai/
|
|
63
|
+
"@deepseek-ai/cordis": "^4.0.1-rc.1",
|
|
64
|
+
"@deepseek-ai/dsh-invariants": "^0.0.1-rc.3"
|
|
65
65
|
}
|
|
66
66
|
}
|