@deepseek-ai/dsh-client-ui-primitives 0.1.7-rc.2 → 0.2.0-rc.1
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 +6 -6
- package/README.md +6 -5
- package/README.zh.md +6 -5
- package/lib/Menu.module.css +2 -2
- package/lib/Modal.module.css +5 -4
- package/lib/Switch.module.css +4 -0
- package/lib/TextShimmer.module.css +82 -21
- package/lib/Tooltip.module.css +1 -0
- package/lib/index.js +135 -58
- package/lib/types/DisclosureRow.d.ts +6 -2
- package/lib/types/TextShimmer.d.ts +14 -5
- package/lib/types/Tooltip.d.ts +10 -3
- package/lib/types/index.d.ts +1 -0
- package/lib/types/overlay-top-margin.d.ts +2 -8
- package/lib/types/useAnchoredMaxHeight.d.ts +2 -2
- package/lib/types/useAnchoredPosition.d.ts +1 -1
- package/package.json +4 -4
package/README.i18n.yaml
CHANGED
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
en: d152484eb41ac6b4
|
|
16
16
|
zh: 09388d293f9be9cb
|
|
17
17
|
/deepseek-ai-dsh-client-ui-primitives/use-this-package:
|
|
18
|
-
en:
|
|
19
|
-
zh:
|
|
18
|
+
en: 7bae72c97d0449f5
|
|
19
|
+
zh: 4589ecc2b216edc5
|
|
20
20
|
/deepseek-ai-dsh-client-ui-primitives/use-this-package/component-catalog:
|
|
21
|
-
en:
|
|
22
|
-
zh:
|
|
21
|
+
en: 91d4b79159aab5df
|
|
22
|
+
zh: 3a2d8461e836bb66
|
|
23
23
|
/deepseek-ai-dsh-client-ui-primitives/use-this-package/controls-and-icons:
|
|
24
|
-
en:
|
|
25
|
-
zh:
|
|
24
|
+
en: b4cd33720a6cf6b8
|
|
25
|
+
zh: 8db75bf633789c6d
|
|
26
26
|
/deepseek-ai-dsh-client-ui-primitives/use-this-package/rendering-agent-output:
|
|
27
27
|
en: d79e20306593c4bf
|
|
28
28
|
zh: 5c0f1100e2cd6fcc
|
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ Use `dsh-client-ui-primitives` to build web-client controls and render agent out
|
|
|
25
25
|
<a id="use-this-package"></a>
|
|
26
26
|
## Use this package
|
|
27
27
|
|
|
28
|
-
`Toast` uses the theme’s toast background and label colors in both light and dark modes. `Menu` data rows and `MenuItemButton` component rows accept owner-provided effective shortcuts and align their keys at the trailing edge as muted text without a background, including submenus. `ShortcutKeys` defaults to unboxed keys for menu and inline hints. Its `tooltip` variant uses lighter keycaps over the dark bubble and groups plus-separated combinations into one filled block. `Tooltip.shortcutKeys` vertically centers keycaps beside optional localized action text, or shows only keys when the label is empty. The optional `className` supplies owner interaction styles. `Modal` and the settings shell share top-layer Escape and Tab handling through `useModalLayer`, restoring the previous focus on close. `closeTopModal(document)` requests the foreground modal’s current close action; newer menus or unregistered dialogs block dismissal of the modal behind them. Components use `isBehindModal` to avoid moving focus behind a nested dialog. Menus consume their local Escape before modal dismissal. `observeComposition` supplies the same composition-end and legacy IME guard to local modal and recording handlers; callers dispose its document listeners with their interaction lifetime.
|
|
28
|
+
`Toast` uses the theme’s toast background and label colors in both light and dark modes. `Menu` data rows and `MenuItemButton` component rows accept owner-provided effective shortcuts and align their keys at the trailing edge as muted text without a background, including submenus. `ShortcutKeys` defaults to unboxed keys for menu and inline hints. Its `tooltip` variant uses lighter keycaps over the dark bubble and groups plus-separated combinations into one filled block. `Tooltip.shortcutKeys` vertically centers keycaps beside optional localized action text, or shows only keys when the label is empty. The optional `className` supplies owner interaction styles. `Modal` uses the frame’s shared overlay inset, with a minimum 24px viewport margin. Its mask leaves the Windows caption unpainted while the full-viewport layer blocks background clicks. `Modal` and the settings shell share top-layer Escape and Tab handling through `useModalLayer`, restoring the previous focus on close. `closeTopModal(document)` requests the foreground modal’s current close action; newer menus or unregistered dialogs block dismissal of the modal behind them. Components use `isBehindModal` to avoid moving focus behind a nested dialog. Menus consume their local Escape before modal dismissal. `observeComposition` supplies the same composition-end and legacy IME guard to local modal and recording handlers; callers dispose its document listeners with their interaction lifetime.
|
|
29
29
|
|
|
30
30
|
Automatic modal entry and modal/menu return focus, including after Escape and application close shortcuts, use `focusWithoutRing(element, options?)` to suppress the outline until Tab or directional navigation resumes normal focus styling. Dialog containers keep their outline-free styling. Existing borders, shadows, and error states remain intact. Mark a dialog's initial control with `data-modal-autofocus` so the modal captures its invoking control before moving focus. Controls mounted with the dialog must not use React `autoFocus`, which runs before that capture. Tab and Shift+Tab from the dialog container enter its first and last focusable controls.
|
|
31
31
|
|
|
@@ -41,7 +41,7 @@ Check this table before writing a control in a feature package. A plugin cannot
|
|
|
41
41
|
| Export | What it is |
|
|
42
42
|
|---|---|
|
|
43
43
|
| `Button` | Clickable action; `variant` selects `primary`, `ghost`, `outline`, or `toolbar`. Its ref targets the native button for focus and overlay anchoring. |
|
|
44
|
-
| `Switch` | Two-state toggle, 36×20. `label` is required, so the control cannot ship unnamed. |
|
|
44
|
+
| `Switch` | Two-state toggle, 36×20. The off-state thumb reads `--dsw-alias-switch-thumb` so it stays light in both themes, and the on-state thumb contrasts with the brand track. Disabled controls use half opacity. `label` is required, so the control cannot ship unnamed. |
|
|
45
45
|
| `SegmentedControl` | Tablist of two or more equal-width segments with one sliding indicator, for switching a card or panel between a few modes; the owner holds the selection and `label` names the list. `id` seeds each tab's id (`<id>-<value>`) and the panel it controls (`<id>-<value>-panel`), which the owner renders and points back at the tab with `aria-labelledby`; a segment may be `disabled` with a `title`, and `disabled` on the control locks every segment while the shown panel has work in flight. |
|
|
46
46
|
| `Checkbox` | Labeled native checkbox with controlled state, keyboard interaction, and disabled styling; the caller supplies localized `label` text. |
|
|
47
47
|
| `Input` | Single-line text entry for search boxes and inline forms. |
|
|
@@ -53,9 +53,10 @@ Check this table before writing a control in a feature package. A plugin cannot
|
|
|
53
53
|
| `StateDot` | Solid green `done`, amber `warning`, red `error`, and neutral-grey `idle` marks in a 10px slot, plus a tertiary-grey 14px rotating `ongoing` loader whose animations pin to document time zero so every visible loader rotates in phase. `aria-hidden`, so the render site owns the name. `appearance="step"` shows a filled check for completion and a hollow pending circle. |
|
|
54
54
|
| `ConnectionIndicator` | Inline connection-recovery control across outage, retry, and recovered states. |
|
|
55
55
|
| `DisclosureRow` | 24px compact disclosure that lays title and content side by side. Memoized with shallow prop comparison; keep callbacks and React-node props stable when their content is unchanged. |
|
|
56
|
+
| `TextShimmer` | One left-to-right highlight across a row’s title, separators, summary, and suffix, with a 300ms initial delay, a one-second sweep and a 500ms rest. The mask spans the content width, capped by the visible row and tilts 15° from vertical, with a flat peak and soft edges. The moving decoration stays clipped to the row without enlarging its scrollable area. Base text inherits the caller’s color, including hover changes; the theme supplies the translucent highlight. Place icons and chevrons outside `TextShimmer` so only text and separators receive the highlight. A string child uses the same retained text interface; nested `TextShimmer` instances share the outer animation. Composite children render twice while active and must have no effects or element ids. Mark separators with `data-shimmer-decoration` so their fill receives the highlight. `DisclosureRow` forwards `contentClassName` for the text area and `contentLayoutClassName` for its inner layout. The inert decorative copy is excluded from interaction, selection, and accessibility; text updates retain the animation, and reduced-motion mode keeps the static base. |
|
|
56
57
|
| `Modal` | Centered dialog over a page mask. A nested dialog can intercept keys with `onKeyDownCapture` before document Escape handlers. The tint and dialog fade in while backdrop blur stays fully applied, honoring reduced motion. Set `backdropBlur={false}` when the caller already blurs the source page. |
|
|
57
58
|
| `RiskConfirmation` | Sensitive action gated behind an explicit checkbox. |
|
|
58
|
-
| `Tooltip` | Hover text anchored to a cloned child; optional `portal` rendering escapes clipping containers and ancestor stacking contexts that cap the bubble's z-index. |
|
|
59
|
+
| `Tooltip` | Hover and keyboard-focus text anchored to a cloned child; optional `delayMs` controls hover delay and `focusDelayMs` controls keyboard-focus delay, both defaulting to 0 ms. Optional `portal` rendering escapes clipping containers and ancestor stacking contexts that cap the bubble's z-index. |
|
|
59
60
|
| `HoverCard` | Hover preview the pointer can rest on and select from; optional copy button. |
|
|
60
61
|
| `ImageLightbox` | Shared image modal with focus restoration and Escape dismissal. |
|
|
61
62
|
| `Toast` | Transient top-center banner held for the owner's `holdMs`. |
|
|
@@ -82,9 +83,9 @@ Writing your own component in your own package is fine when the need is genuinel
|
|
|
82
83
|
|
|
83
84
|
### Controls and icons
|
|
84
85
|
|
|
85
|
-
The catalog above lists what each export is for; this section covers the behavior that props alone do not show. Product icon names omit artboard sizes and end in `Regular` for the supplied one-pixel artwork or `Medium` for the same geometry at a 1.3px stroke; the `size` prop controls rendered dimensions ([decision](../../../.agents/notes/implemented/architecture/2026-09-16-size-neutral-product-icon-weights.md)). Each product, reference, link, and permission glyph intentionally keeps both weight exports even when the current product uses only one, so callers can choose emphasis without adding another API later; fill-only pairs render identically. `IconWarningOutlineRegular`/`Medium` use a circle; `IconWarningTriangleOutlineRegular`/`Medium` use a rounded triangle. `FishLogo` and `BrandWordmark` fill brand slots. `FileTypeIcon` renders the traditional 28px spreadsheet, folder, HTML, image, Markdown, generic, PDF, PPT, video, and Word glyphs, and uses the imported square technology artwork for the established 48 code and configuration categories. The import replaces artwork only: archive-only categories do not extend `CodeFileType`. `classifyFileType` applies exact filename, prefix, suffix, optional project-context, and extension rules in that order; React names win over TypeScript/JavaScript, Angular suffixes win over their base extension, and a Dart file becomes Flutter only when the supplied project files contain a `pubspec.yaml` with `flutter:`. Markdown and SVG remain traditional Markdown and image files. Spreadsheet mappings include CSV, TSV, Excel workbooks and templates, OpenDocument spreadsheets, and Numbers; KEY maps to slides, while RTF/ODT/Pages map to documents. `fileExtension` exposes the same basename and final-dot parsing for adjacent metadata labels. Traditional glyphs use a solid category-colored sheet with a white mark and translucent white corner; the generic code glyph uses angle brackets and a slash at the supplied 1.35px stroke; the generic file uses a grey sheet and darker grey corner. Callers may override the sheet color through `--dsh-file-type-icon-color`. The full-color technology artwork is the deliberate exception and retains its embedded palette. All glyphs are decorative and carry no label. `LinkIconMedium` is the leading glyph for clickable artifact links — globe, folder, code, image, document, or plain paper, and for a `url` link the mark of a well-known site named by its `href` — the developer sites a transcript usually cites (GitHub, GitLab, npm, PyPI, Stack Overflow, MDN, Wikipedia, Hacker News, YouTube, X, Bilibili, Zhihu, Juejin, CSDN) and mainstream search, video, social, shopping, and reference sites (Google, Baidu, DuckDuckGo, TikTok, Netflix, Spotify, Facebook, Instagram, Reddit, Telegram, WhatsApp, WeChat, QQ, Weibo, Taobao, AliExpress, eBay, Quora, V2EX, Apple) — while `classifyLinkPath` folds the shared file types into that existing six-category vocabulary. `ConnectionIndicator` renders a warning-colored disconnected action whose permanent retry glyph marks the retry action beside the owner-supplied outage label, the shared ongoing loader in the same warning color as its label whose one-to-three dots advance every 500ms independently of retry timing, or a success-colored recovered status. Clicking either warning state requests an immediate reconnect; no hover interaction changes the copy. The pill fades in on appearance, fades out for 150ms before unmounting, and sizes to its current label. 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;
|
|
86
|
+
The catalog above lists what each export is for; this section covers the behavior that props alone do not show. Product icon names omit artboard sizes and end in `Regular` for the supplied one-pixel artwork or `Medium` for the same geometry at a 1.3px stroke; the `size` prop controls rendered dimensions ([decision](../../../.agents/notes/implemented/architecture/2026-09-16-size-neutral-product-icon-weights.md)). Each product, reference, link, and permission glyph intentionally keeps both weight exports even when the current product uses only one, so callers can choose emphasis without adding another API later; fill-only pairs render identically. `IconWarningOutlineRegular`/`Medium` use a circle; `IconWarningTriangleOutlineRegular`/`Medium` use a rounded triangle. `FishLogo` and `BrandWordmark` fill brand slots. `FileTypeIcon` renders the traditional 28px spreadsheet, folder, HTML, image, Markdown, generic, PDF, PPT, video, and Word glyphs, and uses the imported square technology artwork for the established 48 code and configuration categories. The import replaces artwork only: archive-only categories do not extend `CodeFileType`. `classifyFileType` applies exact filename, prefix, suffix, optional project-context, and extension rules in that order; React names win over TypeScript/JavaScript, Angular suffixes win over their base extension, and a Dart file becomes Flutter only when the supplied project files contain a `pubspec.yaml` with `flutter:`. Markdown and SVG remain traditional Markdown and image files. Spreadsheet mappings include CSV, TSV, Excel workbooks and templates, OpenDocument spreadsheets, and Numbers; KEY maps to slides, while RTF/ODT/Pages map to documents. `fileExtension` exposes the same basename and final-dot parsing for adjacent metadata labels. Traditional glyphs use a solid category-colored sheet with a white mark and translucent white corner; the generic code glyph uses angle brackets and a slash at the supplied 1.35px stroke; the generic file uses a grey sheet and darker grey corner. Callers may override the sheet color through `--dsh-file-type-icon-color`. The full-color technology artwork is the deliberate exception and retains its embedded palette. All glyphs are decorative and carry no label. `LinkIconMedium` is the leading glyph for clickable artifact links — globe, folder, code, image, document, or plain paper, and for a `url` link the mark of a well-known site named by its `href` — the developer sites a transcript usually cites (GitHub, GitLab, npm, PyPI, Stack Overflow, MDN, Wikipedia, Hacker News, YouTube, X, Bilibili, Zhihu, Juejin, CSDN) and mainstream search, video, social, shopping, and reference sites (Google, Baidu, DuckDuckGo, TikTok, Netflix, Spotify, Facebook, Instagram, Reddit, Telegram, WhatsApp, WeChat, QQ, Weibo, Taobao, AliExpress, eBay, Quora, V2EX, Apple) — while `classifyLinkPath` folds the shared file types into that existing six-category vocabulary. `ConnectionIndicator` renders a warning-colored disconnected action whose permanent retry glyph marks the retry action beside the owner-supplied outage label, the shared ongoing loader in the same warning color as its label whose one-to-three dots advance every 500ms independently of retry timing, or a success-colored recovered status. Clicking either warning state requests an immediate reconnect; no hover interaction changes the copy. The pill fades in on appearance, fades out for 150ms before unmounting, and sizes to its current label. 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; anchored overlays and portalled `Menu` add 20px to the frame's published top clearance, or keep 20px in native fullscreen, while preserving their own minimum margins in ordinary browsers. `HoverCard` keeps its portaled preview reachable across the anchor gap and can expose a copy button through the `copyText` prop. Its `preview` variant uses the anchor or `widthAnchorRef` element’s width minus 48px, centers the panel with 24px side insets, and places it above or below the row within the viewport. The panel keeps the frame’s top clearance, caps its height at 420px, and follows content and anchor resizing; Escape or pointer and keyboard activation of the anchor dismisses it. The whole preview fades in and out over 100ms; a closing preview stops receiving pointer input and unmounts after the fade. Re-entering the anchor during the fade restores it. Reduced-motion preferences suppress the transition. Copy labels are required only when copying is enabled. A `Tooltip` nested in the anchor hides that preview while its own hover or focus label is visible; releasing, disabling, or unmounting the nested tooltip restores a still-open preview. `Toast` uses the owner's `holdMs` for both the fade delay and its hold-and-fade lifetime. Rerenders with unchanged `holdMs` do not restart that lifetime; completion uses the latest callback, and fully faded actions cannot receive input. A new component key restarts the banner. `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. Portalled `Menu` lists follow their anchor during dragging and CSS transforms, and stop tracking when closed. `Menu.autoFocus` focuses its first enabled item, supports Arrow Up/Down and Home/End navigation, and focuses the first button in the anchor on Escape; it is opt-in for action menus.
|
|
86
87
|
|
|
87
|
-
`Tooltip` reads the anchor on hover or keyboard focus and fits its bubble from `ResizeObserver` border-box sizes. The bubble stays hidden until its first fit, slides inside the horizontal viewport margin, and flips above or below only when the opposite side fits. Label-size and viewport changes reuse the anchor coordinates; fitting does not synchronously measure the bubble or trigger a React render.
|
|
88
|
+
`Tooltip` reads the anchor on hover or keyboard focus and fits its bubble from `ResizeObserver` border-box sizes. The bubble stays hidden until its first fit, slides inside the horizontal viewport margin, and flips above or below only when the opposite side fits. Label-size and viewport changes reuse the anchor coordinates; fitting does not synchronously measure the bubble or trigger a React render. Opt-in `openOnClick` also lets an informational button pin the same bubble for reading and associates it with the anchor description. Another click, Escape, Tab, or an outside pointerdown closes it; ordinary action tooltips still dismiss on click.
|
|
88
89
|
|
|
89
90
|
### Rendering agent output
|
|
90
91
|
|
package/README.zh.md
CHANGED
|
@@ -25,7 +25,7 @@ kind: "package-library"
|
|
|
25
25
|
<a id="use-this-package"></a>
|
|
26
26
|
## 使用本包
|
|
27
27
|
|
|
28
|
-
`Toast` 在浅色和深色模式下均使用主题的系统提示背景与文字颜色。`Menu` 数据条目与 `MenuItemButton` 组件条目接收功能 owner 提供的有效快捷键,并在末端以无背景的浅灰色文字对齐显示,子菜单也采用同一呈现。`ShortcutKeys` 默认以无方块的按键文字显示菜单和行内提示。`tooltip` 变体在深色气泡上使用稍浅的键帽,以加号连接的组合则共用一个填充色块。`Tooltip.shortcutKeys` 将键帽与可选的本地化操作文本垂直居中排列,标签为空时只显示按键。可选的 `className` 供调用方设置交互状态样式。`Modal` 与设置外壳通过 `useModalLayer` 共用顶层 Esc 和 Tab 处理,关闭时恢复先前焦点。`closeTopModal(document)` 请求前台弹窗当前的关闭操作;上层菜单或未注册的对话框会阻止关闭其后方弹窗。组件通过 `isBehindModal` 避免将焦点移到嵌套弹窗后方。菜单先消费自己的 Esc,再由模态层处理关闭。 `observeComposition` 为局部弹层和录键处理提供相同的 composition-end 与旧版 IME 保护;调用方随交互生命周期释放其 document 监听。
|
|
28
|
+
`Toast` 在浅色和深色模式下均使用主题的系统提示背景与文字颜色。`Menu` 数据条目与 `MenuItemButton` 组件条目接收功能 owner 提供的有效快捷键,并在末端以无背景的浅灰色文字对齐显示,子菜单也采用同一呈现。`ShortcutKeys` 默认以无方块的按键文字显示菜单和行内提示。`tooltip` 变体在深色气泡上使用稍浅的键帽,以加号连接的组合则共用一个填充色块。`Tooltip.shortcutKeys` 将键帽与可选的本地化操作文本垂直居中排列,标签为空时只显示按键。可选的 `className` 供调用方设置交互状态样式。`Modal` 使用框架共享的浮层起点,视口边距至少为 24px。其遮罩不绘制 Windows 顶栏区域,覆盖整个视口的模态层仍阻挡背景点击。`Modal` 与设置外壳通过 `useModalLayer` 共用顶层 Esc 和 Tab 处理,关闭时恢复先前焦点。`closeTopModal(document)` 请求前台弹窗当前的关闭操作;上层菜单或未注册的对话框会阻止关闭其后方弹窗。组件通过 `isBehindModal` 避免将焦点移到嵌套弹窗后方。菜单先消费自己的 Esc,再由模态层处理关闭。 `observeComposition` 为局部弹层和录键处理提供相同的 composition-end 与旧版 IME 保护;调用方随交互生命周期释放其 document 监听。
|
|
29
29
|
|
|
30
30
|
弹窗自动进入及弹窗、菜单回焦,包括通过 Esc 和应用关闭快捷键触发的回焦,均使用 `focusWithoutRing(element, options?)`,在 Tab 或方向键导航恢复正常焦点样式前抑制外轮廓线。弹窗容器仍不绘制焦点外框。原有边框、阴影和错误状态保持不变。用 `data-modal-autofocus` 标记弹窗的初始控件,让模态层先保存触发控件,再移动焦点。随弹窗挂载的控件不得使用 React `autoFocus`,因为它会在保存触发控件前执行。弹窗容器获得焦点时,Tab 和 Shift+Tab 分别进入第一个和最后一个可聚焦控件。
|
|
31
31
|
|
|
@@ -41,7 +41,7 @@ kind: "package-library"
|
|
|
41
41
|
| 导出 | 是什么 |
|
|
42
42
|
|---|---|
|
|
43
43
|
| `Button` | 可点击操作;`variant` 选择 `primary`、`ghost`、`outline` 或 `toolbar`。ref 指向原生按钮,供焦点控制与浮层锚定使用。 |
|
|
44
|
-
| `Switch` | 36×20
|
|
44
|
+
| `Switch` | 36×20 的双态开关。关闭态滑块读取 `--dsw-alias-switch-thumb`,在两种主题下均保持亮色;开启态滑块与品牌色轨道形成对比。禁用控件使用半透明样式。`label` 必填,控件不可能在没有名称的情况下发布。 |
|
|
45
45
|
| `SegmentedControl` | 两段或更多等宽分段加一个滑动指示块的 tablist,用于在几种模式间切换一张卡片或面板;选中项由调用方持有,`label` 为列表命名。`id` 派生每个 tab 的 id(`<id>-<value>`)及其控制的面板 id(`<id>-<value>-panel`),面板由调用方渲染并用 `aria-labelledby` 指回 tab;分段可 `disabled` 并带 `title`,控件级 `disabled` 在当前面板有进行中的操作时锁住全部分段。 |
|
|
46
46
|
| `Checkbox` | 带标签的原生复选框,支持受控状态、键盘交互和禁用样式;调用方提供本地化的 `label` 文本。 |
|
|
47
47
|
| `Input` | 单行文本输入,用于搜索框与行内表单。 |
|
|
@@ -53,9 +53,10 @@ kind: "package-library"
|
|
|
53
53
|
| `StateDot` | 10px 槽内的绿色 `done`、琥珀色 `warning`、红色 `error`、中性灰色 `idle` 圆点,以及 tertiary 灰色 14px 旋转 `ongoing` loading,其动画固定到文档时间零点,所以所有可见 loading 同相旋转。它是 `aria-hidden` 的,名称由渲染点提供。 `appearance="step"` 以实心勾表示完成、空心圆表示等待。 |
|
|
54
54
|
| `ConnectionIndicator` | 行内连接恢复控件,覆盖断线、重试与已恢复三种状态。 |
|
|
55
55
|
| `DisclosureRow` | 24px 紧凑折叠行,标题与内容左右排列。使用浅层 prop 比较进行 memo;内容未变时,保持回调与 React 节点 prop 的引用稳定。 |
|
|
56
|
+
| `TextShimmer` | 同一道高光从左到右扫过一行的标题、分隔符、摘要与后缀:首次等待 300ms,扫动一秒,再静止 500ms。遮罩覆盖内容宽度,并限制在可见行宽内,相对垂直方向倾斜 15°,峰值区域平坦,两侧柔和渐隐。移动的装饰层始终裁剪在行内,不会扩大可滚动区域。底色继承调用方的颜色,包括悬停变化;主题提供半透明高光。图标和箭头放在 `TextShimmer` 外,只有文字和分隔符参与扫光。字符串子节点沿用稳定的文字接口;嵌套的 `TextShimmer` 共用外层动画。活动期间组合子节点渲染两次,因此不得带副作用或元素 id。分隔符标记 `data-shimmer-decoration`,让填色参与扫光。`DisclosureRow` 将 `contentClassName` 传给文字区域,将 `contentLayoutClassName` 传给内部布局。惰性装饰副本不参与交互、选区和无障碍访问;文字更新保留动画,减少动态效果模式保留静态底色。 |
|
|
56
57
|
| `Modal` | 页面遮罩之上的居中对话框。嵌套对话框可通过 `onKeyDownCapture` 在文档级 Escape 处理器之前拦截按键。 色层与弹窗淡入,背景模糊始终完整生效,并遵循减少动态效果偏好。调用方已模糊源页面时设置 `backdropBlur={false}`。 |
|
|
57
58
|
| `RiskConfirmation` | 以显式复选框把关的敏感操作确认。 |
|
|
58
|
-
| `Tooltip` |
|
|
59
|
+
| `Tooltip` | 锚定在克隆子元素上的悬停与键盘聚焦提示;可选的 `delayMs` 控制悬停延迟,`focusDelayMs` 控制键盘聚焦延迟,均默认为 0 毫秒。可通过 `portal` 渲染到外层,避免被容器裁剪,或受祖先层叠上下文限制其 z-index。 |
|
|
59
60
|
| `HoverCard` | 指针可停留、可选中的悬停预览;可选带复制按钮。 |
|
|
60
61
|
| `ImageLightbox` | 共享图片浮层,支持焦点恢复与 Esc 关闭。 |
|
|
61
62
|
| `Toast` | 顶部居中的瞬时横幅,保持时长由所有者的 `holdMs` 决定。 |
|
|
@@ -82,9 +83,9 @@ kind: "package-library"
|
|
|
82
83
|
|
|
83
84
|
### 控件与图标
|
|
84
85
|
|
|
85
|
-
上面的目录说明每个导出的用途;本节讲 props 本身看不出来的行为。产品图标名称不含画板尺寸,以 `Regular` 表示原始 1px 图形,以 `Medium` 表示同一几何的 1.3px 描边;`size` prop 控制渲染尺寸([决定](../../../.agents/notes/implemented/architecture/2026-09-16-size-neutral-product-icon-weights.zh.md))。每个产品、引用、链接与权限图形都会有意保留两种线重导出,即使当前产品只使用其中一种,也让调用方无需再次扩展 API 就能选择强调程度;仅填充的成对图形外观相同。`IconWarningOutlineRegular`/`Medium` 使用圆形;`IconWarningTriangleOutlineRegular`/`Medium` 使用圆角三角形。`FishLogo` 与 `BrandWordmark` 填充品牌 slot。`FileTypeIcon` 渲染传统的 28px spreadsheet、folder、HTML、image、Markdown、generic、PDF、PPT、video 与 Word 图形,并为现有 48 个代码和配置类别使用导入的方形技术图形。该导入只替换图形:资源包中额外的类别不会扩展 `CodeFileType`。`classifyFileType` 按完整文件名、前缀、后缀、可选项目上下文、扩展名的顺序匹配;React 文件名优先于 TypeScript/JavaScript,Angular 后缀优先于基础扩展名,只有传入的项目文件包含带 `flutter:` 的 `pubspec.yaml` 时 Dart 文件才使用 Flutter。Markdown 与 SVG 仍分别使用传统 Markdown 与图片图形。表格映射包括 CSV、TSV、Excel 工作簿与模板、OpenDocument 表格和 Numbers;KEY 映射为幻灯片,RTF/ODT/Pages 映射为文档。`fileExtension` 为相邻元数据 label 暴露同一套 basename 与最终点号解析。传统图形使用实色分类底板、白色标记和半透明白色折角;通用代码图形使用尖括号与斜线,保留原图 1.35px 描边;通用文件使用灰色底板与较深灰色折角。调用方可通过 `--dsh-file-type-icon-color` 覆盖底板颜色。全彩技术图形是明确例外,会保留其内嵌调色板。所有图形都是装饰性的,不自带 label。`LinkIconMedium` 是可点击产物链接的前置图形——地球、文件夹、代码、图片、文档或纸张,`url` 链接的 `href` 指向已知站点时则改用该站点自己的标记——转写内容常引用的开发者站点(GitHub、GitLab、npm、PyPI、Stack Overflow、MDN、Wikipedia、Hacker News、YouTube、X、Bilibili、知乎、掘金、CSDN),以及主流搜索、视频、社交、购物与参考资料站点(Google、百度、DuckDuckGo、TikTok、Netflix、Spotify、Facebook、Instagram、Reddit、Telegram、WhatsApp、微信、QQ、微博、淘宝、速卖通、eBay、Quora、V2EX、Apple)——`classifyLinkPath` 把共享文件类型折叠进原有六类词汇。`ConnectionIndicator` 可渲染警告色的断联操作(常驻重试图形指明重试动作,断联文案由持有方提供)、与文案使用相同警告色的共享 ongoing loading 加一至三个点以独立于 retry 时序的 500ms 节奏推进的连接中状态,或成功色的恢复状态。点击任一警告状态都会请求立即重连;没有任何悬停交互会改变文案。药丸出现时淡入、卸载前淡出 150ms,宽度随当前 label 自适应。它的持有方提供可见性、恢复驻留时间、本地化 label 与立即重连回调;该原语不使用原生 title tooltip。`useAnchoredPosition` 与 `useAnchoredMaxHeight`
|
|
86
|
+
上面的目录说明每个导出的用途;本节讲 props 本身看不出来的行为。产品图标名称不含画板尺寸,以 `Regular` 表示原始 1px 图形,以 `Medium` 表示同一几何的 1.3px 描边;`size` prop 控制渲染尺寸([决定](../../../.agents/notes/implemented/architecture/2026-09-16-size-neutral-product-icon-weights.zh.md))。每个产品、引用、链接与权限图形都会有意保留两种线重导出,即使当前产品只使用其中一种,也让调用方无需再次扩展 API 就能选择强调程度;仅填充的成对图形外观相同。`IconWarningOutlineRegular`/`Medium` 使用圆形;`IconWarningTriangleOutlineRegular`/`Medium` 使用圆角三角形。`FishLogo` 与 `BrandWordmark` 填充品牌 slot。`FileTypeIcon` 渲染传统的 28px spreadsheet、folder、HTML、image、Markdown、generic、PDF、PPT、video 与 Word 图形,并为现有 48 个代码和配置类别使用导入的方形技术图形。该导入只替换图形:资源包中额外的类别不会扩展 `CodeFileType`。`classifyFileType` 按完整文件名、前缀、后缀、可选项目上下文、扩展名的顺序匹配;React 文件名优先于 TypeScript/JavaScript,Angular 后缀优先于基础扩展名,只有传入的项目文件包含带 `flutter:` 的 `pubspec.yaml` 时 Dart 文件才使用 Flutter。Markdown 与 SVG 仍分别使用传统 Markdown 与图片图形。表格映射包括 CSV、TSV、Excel 工作簿与模板、OpenDocument 表格和 Numbers;KEY 映射为幻灯片,RTF/ODT/Pages 映射为文档。`fileExtension` 为相邻元数据 label 暴露同一套 basename 与最终点号解析。传统图形使用实色分类底板、白色标记和半透明白色折角;通用代码图形使用尖括号与斜线,保留原图 1.35px 描边;通用文件使用灰色底板与较深灰色折角。调用方可通过 `--dsh-file-type-icon-color` 覆盖底板颜色。全彩技术图形是明确例外,会保留其内嵌调色板。所有图形都是装饰性的,不自带 label。`LinkIconMedium` 是可点击产物链接的前置图形——地球、文件夹、代码、图片、文档或纸张,`url` 链接的 `href` 指向已知站点时则改用该站点自己的标记——转写内容常引用的开发者站点(GitHub、GitLab、npm、PyPI、Stack Overflow、MDN、Wikipedia、Hacker News、YouTube、X、Bilibili、知乎、掘金、CSDN),以及主流搜索、视频、社交、购物与参考资料站点(Google、百度、DuckDuckGo、TikTok、Netflix、Spotify、Facebook、Instagram、Reddit、Telegram、WhatsApp、微信、QQ、微博、淘宝、速卖通、eBay、Quora、V2EX、Apple)——`classifyLinkPath` 把共享文件类型折叠进原有六类词汇。`ConnectionIndicator` 可渲染警告色的断联操作(常驻重试图形指明重试动作,断联文案由持有方提供)、与文案使用相同警告色的共享 ongoing loading 加一至三个点以独立于 retry 时序的 500ms 节奏推进的连接中状态,或成功色的恢复状态。点击任一警告状态都会请求立即重连;没有任何悬停交互会改变文案。药丸出现时淡入、卸载前淡出 150ms,宽度随当前 label 自适应。它的持有方提供可见性、恢复驻留时间、本地化 label 与立即重连回调;该原语不使用原生 title tooltip。`useAnchoredPosition` 与 `useAnchoredMaxHeight` 让浮动面板与底部锚定浮层始终钳制在视口内并跟随锚点;锚定浮层与 portal 模式的 `Menu` 在框架发布的顶部占用量上增加 20px,原生全屏时保留 20px,普通浏览器中沿用自身的最小边距。`HoverCard` 通过指针离开宽限期让采用 portal 的预览在跨过锚点间隙时仍可触及,并可通过 `copyText` prop 提供复制按钮。其 `preview` 变体使用 anchor 或 `widthAnchorRef` 元素的宽度减去 48px,左右各内缩 24px,并在视口内放置于行的上方或下方。浮层避开框架顶部保留区,高度最多 420px,会跟随内容及 anchor 尺寸变化;Escape 或通过鼠标和键盘激活锚点可将其关闭。整个浮层的淡入和淡出各持续 100ms;关闭中的浮层停止接收指针输入,淡出后卸载。在淡出期间移回锚点可恢复显示。减少动态效果偏好会禁用过渡动画。只有启用复制时才必须提供复制标签。锚点中嵌套的 `Tooltip` 在显示悬停或焦点标签时隐藏该预览;嵌套提示释放、禁用或卸载后,仍处于打开状态的预览会恢复。`Toast` 使用调用方的 `holdMs` 同时控制淡出延迟与停留加淡出的总时长。`holdMs` 未变时,父组件重渲染不会重启该生命周期;完成时调用最新回调,完全淡出的操作不能接收输入。新的组件 key 会重新开始横幅周期。`rankByName` 是 `/` 菜单命令源与 skill(技能)源共享的候选排序器:查询必须是名字的不区分大小写的有序子序列;前缀命中排最前,其次按对齐分数,再按来源顺序。 portal 模式的 `Menu` 列表会在拖动和 CSS 变换期间跟随锚点,并在关闭时停止跟踪。`Menu.autoFocus` 聚焦首个启用项,支持上下方向键与 Home/End 导航,并在 Escape 时聚焦 anchor 内的第一个按钮;操作菜单可显式启用。
|
|
86
87
|
|
|
87
|
-
`Tooltip` 在悬停或键盘聚焦时读取锚点位置,再根据 `ResizeObserver` 提供的边框盒尺寸调整气泡。首次定位前气泡保持隐藏;横向移入视口留白,仅在另一侧容得下时上下翻转。标签尺寸与视口变化复用锚点坐标;定位不会同步测量气泡,也不会触发 React 渲染。
|
|
88
|
+
`Tooltip` 在悬停或键盘聚焦时读取锚点位置,再根据 `ResizeObserver` 提供的边框盒尺寸调整气泡。首次定位前气泡保持隐藏;横向移入视口留白,仅在另一侧容得下时上下翻转。标签尺寸与视口变化复用锚点坐标;定位不会同步测量气泡,也不会触发 React 渲染。 信息按钮可显式启用 `openOnClick`,点击后保持同一个气泡供阅读,并将内容关联为锚点的无障碍描述;再次点击、Escape、Tab 或外部 pointerdown 会关闭。普通操作按钮的 tooltip 仍在点击时关闭。
|
|
88
89
|
|
|
89
90
|
### 渲染 agent 输出
|
|
90
91
|
|
package/lib/Menu.module.css
CHANGED
|
@@ -58,12 +58,12 @@
|
|
|
58
58
|
|
|
59
59
|
/* Viewport fit: the card stops 12px short of the viewport's top/bottom edges
|
|
60
60
|
* (the portal MARGIN in Menu.tsx; the top side widens to the frame's published
|
|
61
|
-
*
|
|
61
|
+
* overlay inset) and taller content scrolls inside
|
|
62
62
|
* .viewport, so a pinned .footer stays visible. Menus with submenu rows skip
|
|
63
63
|
* this class — the overflow clip would crop the side card, so they rely on
|
|
64
64
|
* staying short. */
|
|
65
65
|
.scrollable {
|
|
66
|
-
max-height: calc(100vh - 12px - max(12px, var(--dsh-frame-top
|
|
66
|
+
max-height: calc(100vh - 12px - max(12px, var(--dsh-frame-overlay-top, 12px)));
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
.viewport {
|
package/lib/Modal.module.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* Full-viewport layer (figma Mask + Dialog 451:18655): mask + centered card.
|
|
2
2
|
24px of air on every side; the top/bottom widen to the frame's published
|
|
3
|
-
|
|
3
|
+
overlay inset so a tall card stays clear of it.
|
|
4
4
|
Cards size against this padding box: consumers cap growth with
|
|
5
5
|
`max-height: 100%`, never their own viewport calc. */
|
|
6
6
|
.root {
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
display: flex;
|
|
12
12
|
align-items: center;
|
|
13
13
|
justify-content: center;
|
|
14
|
-
padding: max(24px, var(--dsh-frame-top
|
|
14
|
+
padding: max(24px, var(--dsh-frame-overlay-top, 24px)) 24px;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
/*
|
|
17
|
+
/* Only paint excludes the native caption; the root still blocks background clicks. */
|
|
18
18
|
.mask {
|
|
19
19
|
position: absolute;
|
|
20
|
-
inset: 0;
|
|
20
|
+
inset: var(--dsh-frame-chrome-top, 0px) 0 0;
|
|
21
21
|
backdrop-filter: var(--dsw-mask-blur);
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
/* Dialogs use the prominent elevation on the secondary layer. */
|
|
33
33
|
.dialog {
|
|
34
|
+
box-sizing: border-box;
|
|
34
35
|
position: relative;
|
|
35
36
|
z-index: 1;
|
|
36
37
|
display: flex;
|
package/lib/Switch.module.css
CHANGED
|
@@ -1,27 +1,88 @@
|
|
|
1
|
-
.root
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
.root {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: inline-grid;
|
|
4
|
+
width: max-content;
|
|
5
|
+
max-width: 100%;
|
|
6
|
+
min-width: 0;
|
|
7
|
+
vertical-align: top;
|
|
8
|
+
color: inherit;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.content {
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
min-width: 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.text {
|
|
18
|
+
color: inherit;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.text[data-shimmer-text]::after {
|
|
22
|
+
content: attr(data-shimmer-text);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.decoration {
|
|
26
|
+
position: absolute;
|
|
27
|
+
inset: 0;
|
|
28
|
+
/* The moving mask must not enlarge any ancestor's scrollable area. */
|
|
29
|
+
overflow: clip;
|
|
30
|
+
pointer-events: none;
|
|
31
|
+
user-select: none;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.sweep {
|
|
35
|
+
position: absolute;
|
|
36
|
+
inset: 0;
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
color: var(--dsw-alias-label-shimmer);
|
|
39
|
+
mask-image: linear-gradient(105deg, transparent 0%, black 40% 60%, transparent 100%);
|
|
40
|
+
transform: translateX(-100%);
|
|
41
|
+
animation-name: dsh-row-shimmer-sweep;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* Semantic base colors stay on the real content; the overlay supplies one tint. */
|
|
45
|
+
.sweep * {
|
|
46
|
+
color: inherit !important;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.sweep [data-shimmer-decoration] {
|
|
50
|
+
background: currentColor;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Opposite transforms keep every glyph aligned while their shared mask moves. */
|
|
54
|
+
.highlight {
|
|
55
|
+
width: 100%;
|
|
56
|
+
height: 100%;
|
|
57
|
+
transform: translateX(100%);
|
|
58
|
+
animation-name: dsh-row-shimmer-highlight;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.sweep,
|
|
62
|
+
.highlight {
|
|
63
|
+
animation-duration: 1.5s;
|
|
64
|
+
animation-delay: 0.3s;
|
|
65
|
+
animation-timing-function: steps(48, end);
|
|
66
|
+
animation-iteration-count: infinite;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@keyframes dsh-row-shimmer-sweep {
|
|
70
|
+
0% { transform: translateX(-100%); }
|
|
71
|
+
66.6667%, 100% { transform: translateX(100%); }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@keyframes dsh-row-shimmer-highlight {
|
|
75
|
+
0% { transform: translateX(100%); }
|
|
76
|
+
66.6667%, 100% { transform: translateX(-100%); }
|
|
19
77
|
}
|
|
20
78
|
|
|
21
79
|
@media (prefers-reduced-motion: reduce) {
|
|
22
|
-
.
|
|
23
|
-
|
|
24
|
-
|
|
80
|
+
.decoration {
|
|
81
|
+
display: none;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.sweep,
|
|
85
|
+
.highlight {
|
|
25
86
|
animation: none;
|
|
26
87
|
}
|
|
27
88
|
}
|
package/lib/Tooltip.module.css
CHANGED
package/lib/index.js
CHANGED
|
@@ -3094,20 +3094,55 @@ function StateDot({ state, size, className, appearance = "dot" }) {
|
|
|
3094
3094
|
}
|
|
3095
3095
|
//#endregion
|
|
3096
3096
|
//#region lib/types/TextShimmer.js
|
|
3097
|
-
/** Text
|
|
3097
|
+
/** Text activity animation shared by a row and its nested text fragments. */
|
|
3098
|
+
const DecorativeCopy = createContext(void 0);
|
|
3099
|
+
function TextContent({ children, className }) {
|
|
3100
|
+
const generated = useContext(DecorativeCopy) === true && typeof children === "string";
|
|
3101
|
+
return jsx("span", {
|
|
3102
|
+
className: clsx(css$1.text, className),
|
|
3103
|
+
"data-shimmer-text": generated ? children : void 0,
|
|
3104
|
+
children: generated ? null : children
|
|
3105
|
+
});
|
|
3106
|
+
}
|
|
3098
3107
|
/**
|
|
3099
|
-
* Render text with
|
|
3108
|
+
* Render text with one shared highlight while retaining selectable, accessible content.
|
|
3109
|
+
* Nested instances inherit the outer animation. Keep icons outside; mark decorative
|
|
3110
|
+
* separators with data-shimmer-decoration so their background follows the highlight.
|
|
3111
|
+
* Active children also render in an inert, clipped decoration; supply only presentation.
|
|
3100
3112
|
* @param props - localized text, running state, and owner styling.
|
|
3101
|
-
* @returns
|
|
3113
|
+
* @returns retained text and its optional decorative highlight.
|
|
3102
3114
|
*/
|
|
3103
|
-
const TextShimmer = memo(function TextShimmer({ children, active, className }) {
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
className: clsx(css$1.root, className),
|
|
3107
|
-
style,
|
|
3108
|
-
"data-text-shimmer": active || void 0,
|
|
3115
|
+
const TextShimmer = memo(function TextShimmer({ children, active = false, className, contentClassName }) {
|
|
3116
|
+
if (useContext(DecorativeCopy) !== void 0) return jsx(TextContent, {
|
|
3117
|
+
className,
|
|
3109
3118
|
children
|
|
3110
3119
|
});
|
|
3120
|
+
const content = typeof children === "string" ? jsx(TextContent, { children }) : children;
|
|
3121
|
+
return jsxs("span", {
|
|
3122
|
+
className: clsx(css$1.root, className),
|
|
3123
|
+
"data-shimmer": active || void 0,
|
|
3124
|
+
children: [jsx(DecorativeCopy.Provider, {
|
|
3125
|
+
value: false,
|
|
3126
|
+
children: jsx("span", {
|
|
3127
|
+
className: clsx(css$1.content, contentClassName),
|
|
3128
|
+
children: content
|
|
3129
|
+
})
|
|
3130
|
+
}), active && jsx("span", {
|
|
3131
|
+
className: css$1.decoration,
|
|
3132
|
+
"aria-hidden": "true",
|
|
3133
|
+
inert: "",
|
|
3134
|
+
children: jsx("span", {
|
|
3135
|
+
className: css$1.sweep,
|
|
3136
|
+
children: jsx(DecorativeCopy.Provider, {
|
|
3137
|
+
value: true,
|
|
3138
|
+
children: jsx("span", {
|
|
3139
|
+
className: clsx(css$1.content, css$1.highlight, contentClassName),
|
|
3140
|
+
children: content
|
|
3141
|
+
})
|
|
3142
|
+
})
|
|
3143
|
+
})
|
|
3144
|
+
})]
|
|
3145
|
+
});
|
|
3111
3146
|
});
|
|
3112
3147
|
//#endregion
|
|
3113
3148
|
//#region lib/types/DisclosureRow.js
|
|
@@ -3117,7 +3152,7 @@ const TextShimmer = memo(function TextShimmer({ children, active, className }) {
|
|
|
3117
3152
|
* @param props - Visual content, controlled state, and interaction policy.
|
|
3118
3153
|
* @returns the disclosure row.
|
|
3119
3154
|
*/
|
|
3120
|
-
const DisclosureRow = memo(function DisclosureRow({ icon, title, open, expandable, onToggle, running = false, expandOnRowClick = false, previewChevron = expandable, keepContentWhenOpen = false, collapsedContent, children, className, rowClassName, leadingClassName, chevronClassName, titleClassName }) {
|
|
3155
|
+
const DisclosureRow = memo(function DisclosureRow({ icon, title, open, expandable, onToggle, running = false, expandOnRowClick = false, previewChevron = expandable, keepContentWhenOpen = false, collapsedContent, children, className, rowClassName, contentClassName, contentLayoutClassName, leadingClassName, chevronClassName, titleClassName }) {
|
|
3121
3156
|
const rowExpands = expandable && expandOnRowClick;
|
|
3122
3157
|
const toggleFromLeading = (event) => {
|
|
3123
3158
|
event.stopPropagation();
|
|
@@ -3145,24 +3180,24 @@ const DisclosureRow = memo(function DisclosureRow({ icon, title, open, expandabl
|
|
|
3145
3180
|
"aria-expanded": rowExpands ? open : void 0,
|
|
3146
3181
|
onClick: rowExpands ? onToggle : void 0,
|
|
3147
3182
|
onKeyDown: rowExpands ? toggleFromKeyboard : void 0,
|
|
3148
|
-
children: [
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3183
|
+
children: [expandable && !rowExpands ? jsx("button", {
|
|
3184
|
+
type: "button",
|
|
3185
|
+
className: clsx(css$2.leading, leadingClassName),
|
|
3186
|
+
"aria-expanded": open,
|
|
3187
|
+
onClick: toggleFromLeading,
|
|
3188
|
+
children: leading
|
|
3189
|
+
}) : jsx("span", {
|
|
3190
|
+
className: clsx(css$2.leading, leadingClassName),
|
|
3191
|
+
children: leading
|
|
3192
|
+
}), jsxs(TextShimmer, {
|
|
3193
|
+
active: running,
|
|
3194
|
+
className: contentClassName,
|
|
3195
|
+
contentClassName: contentLayoutClassName,
|
|
3196
|
+
children: [jsx(TextShimmer, {
|
|
3160
3197
|
className: clsx(css$2.title, titleClassName),
|
|
3161
|
-
active: running,
|
|
3162
3198
|
children: title
|
|
3163
|
-
}),
|
|
3164
|
-
|
|
3165
|
-
]
|
|
3199
|
+
}), (keepContentWhenOpen || !open) && collapsedContent]
|
|
3200
|
+
})]
|
|
3166
3201
|
}), open && children]
|
|
3167
3202
|
});
|
|
3168
3203
|
});
|
|
@@ -3502,21 +3537,17 @@ function Input({ icon, className, ...rest }) {
|
|
|
3502
3537
|
}
|
|
3503
3538
|
//#endregion
|
|
3504
3539
|
//#region lib/types/overlay-top-margin.js
|
|
3505
|
-
/**
|
|
3506
|
-
* Overlay clearance from the window's top strip. On macOS desktop the frame
|
|
3507
|
-
* publishes `--dsh-frame-top-clearance` on the root element — the constant
|
|
3508
|
-
* step below the traffic-light strip, where clicks drag the window instead of
|
|
3509
|
-
* the overlay. JS-clamped overlays keep at least that much air above them.
|
|
3510
|
-
* Elsewhere the property is absent and the caller's own margin applies.
|
|
3511
|
-
*/
|
|
3540
|
+
/** Shared viewport inset for overlays, derived from the desktop frame's reserved top strip. */
|
|
3512
3541
|
/**
|
|
3513
3542
|
* Resolve the top margin an overlay keeps from the viewport edge.
|
|
3514
3543
|
* @param min - the overlay's own viewport margin in px, used as the floor.
|
|
3515
|
-
* @returns the larger of `min` and the frame
|
|
3544
|
+
* @returns the larger of `min` and the frame clearance plus 20px; fullscreen keeps only the 20px gap.
|
|
3516
3545
|
*/
|
|
3517
3546
|
function overlayTopMargin(min) {
|
|
3518
|
-
const
|
|
3519
|
-
|
|
3547
|
+
const root = document.documentElement;
|
|
3548
|
+
const clearance = Number.parseFloat(getComputedStyle(root).getPropertyValue("--dsh-frame-top-clearance"));
|
|
3549
|
+
if (Number.isNaN(clearance)) return min;
|
|
3550
|
+
return Math.max(min, (root.hasAttribute("data-fullscreen") ? 0 : clearance) + 20);
|
|
3520
3551
|
}
|
|
3521
3552
|
/**
|
|
3522
3553
|
* Delay a pointer-dismissed popup's close so the pointer can cross the gap
|
|
@@ -4247,7 +4278,7 @@ function Menu({ open, anchor, items = [], children, selectedId, selectedIds, onS
|
|
|
4247
4278
|
*/
|
|
4248
4279
|
/**
|
|
4249
4280
|
* Safe distance kept between the overlay and the viewport top edge (mirrors
|
|
4250
|
-
* the Menu portal margin); the frame's
|
|
4281
|
+
* the Menu portal margin); the frame's overlay inset widens it.
|
|
4251
4282
|
*/
|
|
4252
4283
|
const MARGIN = 12;
|
|
4253
4284
|
/**
|
|
@@ -4256,8 +4287,8 @@ const MARGIN = 12;
|
|
|
4256
4287
|
* @param cap - design max-height in px (the clamp never exceeds it).
|
|
4257
4288
|
* @param signal - re-measure trigger: pass the overlay's render state so anchor
|
|
4258
4289
|
* moves (composer growth) re-fit; resize/scroll re-fit while mounted.
|
|
4259
|
-
* @param margin - viewport top margin floor in px; the frame's
|
|
4260
|
-
*
|
|
4290
|
+
* @param margin - viewport top margin floor in px; the frame's overlay
|
|
4291
|
+
* inset widens it. Callers under fixed chrome (the conversation header)
|
|
4261
4292
|
* raise it past their chrome's height.
|
|
4262
4293
|
* @returns the max-height to apply inline, in px.
|
|
4263
4294
|
*/
|
|
@@ -4322,7 +4353,7 @@ function useAnchoredPosition(options) {
|
|
|
4322
4353
|
let left = align === "end" ? rect.right - width : rect.left;
|
|
4323
4354
|
let top = side === "top" ? rect.top - gap - height : rect.bottom + gap;
|
|
4324
4355
|
if (width > 0) left = Math.min(Math.max(left, margin), window.innerWidth - width - margin);
|
|
4325
|
-
if (height > 0) top = Math.min(Math.max(top, margin), window.innerHeight - height - margin);
|
|
4356
|
+
if (height > 0) top = Math.min(Math.max(top, overlayTopMargin(margin)), window.innerHeight - height - margin);
|
|
4326
4357
|
/* v8 ignore stop */
|
|
4327
4358
|
setPosition({
|
|
4328
4359
|
left,
|
|
@@ -4500,20 +4531,26 @@ const TooltipSuppression = createContext(null);
|
|
|
4500
4531
|
* bubble would overlap); default 'center'. Ignored for side 'right'.
|
|
4501
4532
|
* @param props.portal - render the bubble under document.body, so an ancestor's clipping or its
|
|
4502
4533
|
* stacking context (which confines the bubble's z-index to that context) cannot hide it.
|
|
4503
|
-
* @param props.delayMs - hover delay in milliseconds
|
|
4534
|
+
* @param props.delayMs - hover delay in milliseconds (default 0).
|
|
4535
|
+
* @param props.focusDelayMs - keyboard focus delay in milliseconds (default 0); blur, click,
|
|
4536
|
+
* mouse leave, disabling, and unmount cancel a pending show.
|
|
4504
4537
|
* @param props.gap - anchor-to-bubble distance in pixels for 'bottom'/'top' bubbles (default 8);
|
|
4505
4538
|
* ignored for side 'right'.
|
|
4506
4539
|
* @param props.disabled - suppress the bubble while true; the anchor renders identically so
|
|
4507
4540
|
* toggling never remounts it (which would cut its CSS transitions).
|
|
4508
4541
|
* @param props.maxWidth - bubble width cap in pixels, for labels long enough that the default
|
|
4509
4542
|
* half-viewport cap would render a slab wider than the surface the anchor sits on.
|
|
4543
|
+
* @param props.openOnClick - clicking also pins the bubble for reading; another click, Escape,
|
|
4544
|
+
* Tab, or an outside pointerdown dismisses it. Defaults to false for ordinary action tooltips.
|
|
4510
4545
|
* @param props.children - a single anchor element; its own ref (callback or object) is forwarded alongside the tooltip's.
|
|
4511
4546
|
* @returns the cloned anchor plus a fixed-position bubble, optionally portaled to the body.
|
|
4512
4547
|
* The bubble stays hidden until ResizeObserver supplies its size for viewport fitting; clicking the
|
|
4513
|
-
* anchor dismisses the bubble
|
|
4548
|
+
* anchor dismisses the bubble unless openOnClick is enabled, and focus arriving after a pointer
|
|
4514
4549
|
* interaction (a closing menu refocusing its trigger) never raises it.
|
|
4515
4550
|
*/
|
|
4516
|
-
function Tooltip({ label, shortcutKeys, side = "right", align = "center", delayMs = 0, gap = 8, disabled = false, portal = false, maxWidth, children }) {
|
|
4551
|
+
function Tooltip({ label, shortcutKeys, side = "right", align = "center", delayMs = 0, focusDelayMs = 0, gap = 8, disabled = false, portal = false, maxWidth, openOnClick = false, children }) {
|
|
4552
|
+
const id = useId();
|
|
4553
|
+
const [pinned, setPinned] = useState(false);
|
|
4517
4554
|
const anchor = useRef(null);
|
|
4518
4555
|
const childRef = children.ref;
|
|
4519
4556
|
const mergedRef = useCallback((el) => {
|
|
@@ -4586,6 +4623,7 @@ function Tooltip({ label, shortcutKeys, side = "right", align = "center", delayM
|
|
|
4586
4623
|
showTimer.current = null;
|
|
4587
4624
|
}, []);
|
|
4588
4625
|
useEffect(() => {
|
|
4626
|
+
if (pinned && (disabled || !openOnClick)) setPinned(false);
|
|
4589
4627
|
if (disabled) {
|
|
4590
4628
|
cancelShow();
|
|
4591
4629
|
triggers.current = {
|
|
@@ -4595,7 +4633,12 @@ function Tooltip({ label, shortcutKeys, side = "right", align = "center", delayM
|
|
|
4595
4633
|
setPos(null);
|
|
4596
4634
|
}
|
|
4597
4635
|
return cancelShow;
|
|
4598
|
-
}, [
|
|
4636
|
+
}, [
|
|
4637
|
+
cancelShow,
|
|
4638
|
+
disabled,
|
|
4639
|
+
openOnClick,
|
|
4640
|
+
pinned
|
|
4641
|
+
]);
|
|
4599
4642
|
const show = () => {
|
|
4600
4643
|
if (disabled) return;
|
|
4601
4644
|
const el = anchor.current;
|
|
@@ -4609,30 +4652,61 @@ function Tooltip({ label, shortcutKeys, side = "right", align = "center", delayM
|
|
|
4609
4652
|
});
|
|
4610
4653
|
announce(true);
|
|
4611
4654
|
};
|
|
4612
|
-
const
|
|
4655
|
+
const showAfterDelay = (delay) => {
|
|
4613
4656
|
cancelShow();
|
|
4614
|
-
if (
|
|
4657
|
+
if (delay <= 0) {
|
|
4615
4658
|
show();
|
|
4616
4659
|
return;
|
|
4617
4660
|
}
|
|
4618
4661
|
showTimer.current = setTimeout(() => {
|
|
4619
4662
|
showTimer.current = null;
|
|
4620
4663
|
show();
|
|
4621
|
-
},
|
|
4664
|
+
}, delay);
|
|
4622
4665
|
};
|
|
4623
|
-
const withdraw = () => {
|
|
4666
|
+
const withdraw = useCallback(() => {
|
|
4667
|
+
setPinned(false);
|
|
4624
4668
|
setPos(null);
|
|
4625
4669
|
announce(false);
|
|
4626
|
-
};
|
|
4670
|
+
}, [announce]);
|
|
4627
4671
|
const hide = () => {
|
|
4628
4672
|
cancelShow();
|
|
4629
|
-
if (!triggers.current.hover && !triggers.current.focus) withdraw();
|
|
4673
|
+
if (!triggers.current.hover && !triggers.current.focus && !pinned) withdraw();
|
|
4630
4674
|
};
|
|
4675
|
+
const dismiss = useCallback(() => {
|
|
4676
|
+
cancelShow();
|
|
4677
|
+
triggers.current = {
|
|
4678
|
+
hover: false,
|
|
4679
|
+
focus: false
|
|
4680
|
+
};
|
|
4681
|
+
withdraw();
|
|
4682
|
+
}, [cancelShow, withdraw]);
|
|
4683
|
+
useDismissOnOutsidePointer(anchor, openOnClick && visible, dismiss, bubble);
|
|
4684
|
+
useEffect(() => {
|
|
4685
|
+
if (!openOnClick || !visible) return;
|
|
4686
|
+
const onKeyDown = (event) => {
|
|
4687
|
+
if (event.key !== "Escape" && event.key !== "Tab") return;
|
|
4688
|
+
if (event.key === "Escape") {
|
|
4689
|
+
event.preventDefault();
|
|
4690
|
+
event.stopPropagation();
|
|
4691
|
+
}
|
|
4692
|
+
dismiss();
|
|
4693
|
+
};
|
|
4694
|
+
document.addEventListener("keydown", onKeyDown, true);
|
|
4695
|
+
return () => {
|
|
4696
|
+
document.removeEventListener("keydown", onKeyDown, true);
|
|
4697
|
+
};
|
|
4698
|
+
}, [
|
|
4699
|
+
dismiss,
|
|
4700
|
+
openOnClick,
|
|
4701
|
+
visible
|
|
4702
|
+
]);
|
|
4631
4703
|
const content = visible && !suppressed && jsxs("span", {
|
|
4632
4704
|
ref: bubble,
|
|
4705
|
+
id: openOnClick ? id : void 0,
|
|
4633
4706
|
className: css$15.bubble,
|
|
4634
4707
|
"data-side": side,
|
|
4635
4708
|
"data-portal": portal || void 0,
|
|
4709
|
+
"data-pinned": pinned || void 0,
|
|
4636
4710
|
"data-align": align,
|
|
4637
4711
|
"data-has-shortcut": shortcutKeys?.length ? true : void 0,
|
|
4638
4712
|
style: {
|
|
@@ -4655,29 +4729,32 @@ function Tooltip({ label, shortcutKeys, side = "right", align = "center", delayM
|
|
|
4655
4729
|
value: setSuppressed,
|
|
4656
4730
|
children: [cloneElement(children, {
|
|
4657
4731
|
ref: mergedRef,
|
|
4732
|
+
"aria-describedby": openOnClick && visible ? [children.props["aria-describedby"], id].filter(Boolean).join(" ") : children.props["aria-describedby"],
|
|
4658
4733
|
onMouseEnter: (e) => {
|
|
4659
4734
|
children.props.onMouseEnter?.(e);
|
|
4660
4735
|
triggers.current.hover = true;
|
|
4661
|
-
|
|
4736
|
+
showAfterDelay(delayMs);
|
|
4662
4737
|
},
|
|
4663
4738
|
onMouseLeave: (e) => {
|
|
4664
4739
|
children.props.onMouseLeave?.(e);
|
|
4665
4740
|
triggers.current.hover = false;
|
|
4666
4741
|
cancelShow();
|
|
4667
|
-
withdraw();
|
|
4742
|
+
if (!pinned) withdraw();
|
|
4668
4743
|
},
|
|
4669
4744
|
onClick: (e) => {
|
|
4670
4745
|
children.props.onClick?.(e);
|
|
4671
4746
|
triggers.current.focus = false;
|
|
4672
4747
|
cancelShow();
|
|
4673
|
-
|
|
4748
|
+
if (openOnClick && !disabled && !pinned) {
|
|
4749
|
+
setPinned(true);
|
|
4750
|
+
show();
|
|
4751
|
+
} else withdraw();
|
|
4674
4752
|
},
|
|
4675
4753
|
onFocus: (e) => {
|
|
4676
4754
|
children.props.onFocus?.(e);
|
|
4677
4755
|
if (pointerModality()) return;
|
|
4678
4756
|
triggers.current.focus = true;
|
|
4679
|
-
|
|
4680
|
-
show();
|
|
4757
|
+
showAfterDelay(focusDelayMs);
|
|
4681
4758
|
},
|
|
4682
4759
|
onBlur: (e) => {
|
|
4683
4760
|
children.props.onBlur?.(e);
|
|
@@ -12058,7 +12135,7 @@ const PluginArtworkSearch = ({ size = 36, className }) => {
|
|
|
12058
12135
|
children: [
|
|
12059
12136
|
jsx("path", {
|
|
12060
12137
|
d: "M26.5362 26.9865L22.3813 22.8317",
|
|
12061
|
-
stroke: "#
|
|
12138
|
+
stroke: "#658EFF",
|
|
12062
12139
|
strokeWidth: "3"
|
|
12063
12140
|
}),
|
|
12064
12141
|
jsx("g", {
|
|
@@ -12071,7 +12148,7 @@ const PluginArtworkSearch = ({ size = 36, className }) => {
|
|
|
12071
12148
|
width: "1917.88",
|
|
12072
12149
|
height: "1917.88",
|
|
12073
12150
|
children: jsx("div", { style: {
|
|
12074
|
-
background: "conic-gradient(from 90deg, rgb(65, 225, 172) 0deg, rgb(
|
|
12151
|
+
background: "conic-gradient(from 90deg, rgb(65, 225, 172) 0deg, rgb(101, 142, 255) 62.0619deg, rgb(65, 225, 172) 360deg)",
|
|
12075
12152
|
height: "100%",
|
|
12076
12153
|
width: "100%"
|
|
12077
12154
|
} })
|
|
@@ -12178,6 +12255,6 @@ function GuideArtworkFiles({ size = 36, className }) {
|
|
|
12178
12255
|
});
|
|
12179
12256
|
}
|
|
12180
12257
|
//#endregion
|
|
12181
|
-
export { BrandWordmark, Button, CODE_HIGHLIGHT_EXTENSIONS, Checkbox, CodeBlock, ConnectionIndicator, DEFAULT_DIFF_MAX_LINES, DEFAULT_READ_MAX_LINES, DEFAULT_SEARCH_MAX_LINES, DEFAULT_TERMINAL_MAX_LINES, DiffBlock, DisclosureRow, FISH_LOGO_PATH, FISH_LOGO_VIEWBOX, FileTypeIcon, FishLogo, GuideArtworkBrowser, GuideArtworkFiles, HoverCard, ICON_MEDIUM_STROKE, ICON_REGULAR_STROKE, IconAgentPresetOutlineMedium, IconAgentPresetOutlineRegular, IconAlarmClockOutlineMedium, IconAlarmClockOutlineRegular, IconApiOutlineMedium, IconApiOutlineRegular, IconArchiveCheckOutlineMedium, IconArchiveCheckOutlineRegular, IconArchiveOffOutlineMedium, IconArchiveOffOutlineRegular, IconArchiveOutlineMedium, IconArchiveOutlineRegular, IconBranchOutlineMedium, IconBranchOutlineRegular, IconBrowseOutlineMedium, IconBrowseOutlineRegular, IconCheckCircleFillMedium, IconCheckCircleFillRegular, IconCheckCircleOutlineMedium, IconCheckCircleOutlineRegular, IconCheckOutlineMedium, IconCheckOutlineRegular, IconChecklistOutlineMedium, IconChecklistOutlineRegular, IconChevronDownOutlineMedium, IconChevronDownOutlineRegular, IconChevronLeftOutlineMedium, IconChevronLeftOutlineRegular, IconChevronRightOutlineMedium, IconChevronRightOutlineRegular, IconChevronUpOutlineMedium, IconChevronUpOutlineRegular, IconChevronsUpDownOutlineMedium, IconChevronsUpDownOutlineRegular, IconClockOutlineMedium, IconClockOutlineRegular, IconCloseCircleFillMedium, IconCloseCircleFillRegular, IconCloseFillMedium, IconCloseFillRegular, IconCloseOutlineMedium, IconCloseOutlineRegular, IconCodeOutlineMedium, IconCodeOutlineRegular, IconCompactOutlineMedium, IconCompactOutlineRegular, IconCompareSplitOutlineMedium, IconCompareSplitOutlineRegular, IconContextInjectionOutlineMedium, IconContextInjectionOutlineRegular, IconCopyOutlineMedium, IconCopyOutlineRegular, IconCordisPluginOutlineMedium, IconCordisPluginOutlineRegular, IconDarkOutlineMedium, IconDarkOutlineRegular, IconDataOutlineMedium, IconDataOutlineRegular, IconDatabaseOutlineMedium, IconDatabaseOutlineRegular, IconDeliverDocMedium, IconDeliverDocRegular, IconDislikeFillMedium, IconDislikeFillRegular, IconDislikeOutlineMedium, IconDislikeOutlineRegular, IconDownloadOutlineMedium, IconDownloadOutlineRegular, IconEditOutlineMedium, IconEditOutlineRegular, IconEllipsisOutlineMedium, IconEllipsisOutlineRegular, IconEnhanceOutlineMedium, IconEnhanceOutlineRegular, IconFlatListOutlineMedium, IconFlatListOutlineRegular, IconFolderCloseMedium, IconFolderCloseRegular, IconFolderOpenMedium, IconFolderOpenOutlineMedium, IconFolderOpenOutlineRegular, IconFolderOpenRegular, IconFollowsystemOutlineMedium, IconFollowsystemOutlineRegular, IconFullscreenOutlineMedium, IconFullscreenOutlineRegular, IconGaugeOutlineMedium, IconGaugeOutlineRegular, IconGlobeOutlineMedium, IconGlobeOutlineRegular, IconGoalOutlineMedium, IconGoalOutlineRegular, IconInfoOutlineMedium, IconInfoOutlineRegular, IconInspectOutlineMedium, IconInspectOutlineRegular, IconLightOutlineMedium, IconLightOutlineRegular, IconLikeFillMedium, IconLikeFillRegular, IconLikeOutlineMedium, IconLikeOutlineRegular, IconLinkOutlineMedium, IconLinkOutlineRegular, IconListPenOutlineMedium, IconListPenOutlineRegular, IconLoadingOutlineMedium, IconLoadingOutlineRegular, IconMicrophoneOutlineMedium, IconMicrophoneOutlineRegular, IconNewChatOutlineMedium, IconNewChatOutlineRegular, IconNowrapFillMedium, IconNowrapFillRegular, IconPanelLeftOutlineMedium, IconPanelLeftOutlineRegular, IconPaperPlaneOutlineMedium, IconPaperPlaneOutlineRegular, IconPaperclipOutlineMedium, IconPaperclipOutlineRegular, IconPauseOutlineMedium, IconPauseOutlineRegular, IconPersonalizationOutlineMedium, IconPersonalizationOutlineRegular, IconPinFillMedium, IconPinFillRegular, IconPinOutlineMedium, IconPinOutlineRegular, IconPlanOutlineMedium, IconPlanOutlineRegular, IconPlayOutlineMedium, IconPlayOutlineRegular, IconPluginPinwheelOutlineMedium, IconPluginPinwheelOutlineRegular, IconPlusOutlineMedium, IconPlusOutlineRegular, IconProjectAddOutlineMedium, IconProjectAddOutlineRegular, IconQuestionOutlineMedium, IconQuestionOutlineRegular, IconQueueOutlineMedium, IconQueueOutlineRegular, IconRefreshOutlineMedium, IconRefreshOutlineRegular, IconRightUpOutlineMedium, IconRightUpOutlineRegular, IconSearchOutlineMedium, IconSearchOutlineRegular, IconSendOutlineMedium, IconSendOutlineRegular, IconSettingsOutlineMedium, IconSettingsOutlineRegular, IconShareOutlineMedium, IconShareOutlineRegular, IconShieldOutlineMedium, IconShieldOutlineRegular, IconSkillOutlineMedium, IconSkillOutlineRegular, IconSlidersTwoOutlineMedium, IconSlidersTwoOutlineRegular, IconSparkleMedium, IconSparkleRegular, IconStopFillMedium, IconStopFillRegular, IconThinkOutlineMedium, IconThinkOutlineRegular, IconTrashOutlineMedium, IconTrashOutlineRegular, IconTreeCornerMedium, IconTreeCornerRegular, IconTriangleRightFillMedium, IconTriangleRightFillRegular, IconUnarchiveOutlineMedium, IconUnarchiveOutlineRegular, IconUserOutlineMedium, IconUserOutlineRegular, IconUsersOutlineMedium, IconUsersOutlineRegular, IconWarningOutlineMedium, IconWarningOutlineRegular, IconWarningTriangleOutlineMedium, IconWarningTriangleOutlineRegular, IconWorkspaceTreeOutlineMedium, IconWorkspaceTreeOutlineRegular, IconWrapFillMedium, IconWrapFillRegular, IconWrapLinesOutlineMedium, IconWrapLinesOutlineRegular, ImageLightbox, Input, JsonBlock, JsonTree, LinkIconMedium, LinkIconRegular, MarkdownDelegateProvider, MarkdownText, Menu, MenuItemButton, MenuSurface, Modal, PathLabel, PermissionIconFullAccessMedium, PermissionIconFullAccessRegular, PermissionIconReadOnlyMedium, PermissionIconReadOnlyRegular, PermissionIconWorkspaceWriteMedium, PermissionIconWorkspaceWriteRegular, Pill, PluginArtworkDefault, PluginArtworkLoop, PluginArtworkSearch, PluginArtworkSubagent, PluginArtworkTerminal, ReadBlock, ReferenceIconMedium, ReferenceIconRegular, RiskConfirmation, SHIELD_OUTLINE_PATH, SearchBlock, SegmentedControl, SegmentedTabs, SettingsForm, SettingsFormModel, SettingsSecretField, SettingsValueField, ShortcutKeys, StateDot, Switch, Tag, TerminalBlock, TextShimmer, Toast, Tooltip, WebBlock, classifyFileType, classifyLinkPath, closeTopModal, diffTotals, extractMarkdownPlainText, fileExtension, fileSizeText, focusWithoutRing, isBehindModal, isDarwinDesktop, languageForPath, modalSelector, observeComposition, projectUserText, rankByName, relativeTime, settingsNumberField, settingsTextField, useAnchoredMaxHeight, useAnchoredPosition, useCodeHighlighter, useDismissOnOutsidePointer, useModalLayer, writeClipboard };
|
|
12258
|
+
export { BrandWordmark, Button, CODE_HIGHLIGHT_EXTENSIONS, Checkbox, CodeBlock, ConnectionIndicator, DEFAULT_DIFF_MAX_LINES, DEFAULT_READ_MAX_LINES, DEFAULT_SEARCH_MAX_LINES, DEFAULT_TERMINAL_MAX_LINES, DiffBlock, DisclosureRow, FISH_LOGO_PATH, FISH_LOGO_VIEWBOX, FileTypeIcon, FishLogo, GuideArtworkBrowser, GuideArtworkFiles, HoverCard, ICON_MEDIUM_STROKE, ICON_REGULAR_STROKE, IconAgentPresetOutlineMedium, IconAgentPresetOutlineRegular, IconAlarmClockOutlineMedium, IconAlarmClockOutlineRegular, IconApiOutlineMedium, IconApiOutlineRegular, IconArchiveCheckOutlineMedium, IconArchiveCheckOutlineRegular, IconArchiveOffOutlineMedium, IconArchiveOffOutlineRegular, IconArchiveOutlineMedium, IconArchiveOutlineRegular, IconBranchOutlineMedium, IconBranchOutlineRegular, IconBrowseOutlineMedium, IconBrowseOutlineRegular, IconCheckCircleFillMedium, IconCheckCircleFillRegular, IconCheckCircleOutlineMedium, IconCheckCircleOutlineRegular, IconCheckOutlineMedium, IconCheckOutlineRegular, IconChecklistOutlineMedium, IconChecklistOutlineRegular, IconChevronDownOutlineMedium, IconChevronDownOutlineRegular, IconChevronLeftOutlineMedium, IconChevronLeftOutlineRegular, IconChevronRightOutlineMedium, IconChevronRightOutlineRegular, IconChevronUpOutlineMedium, IconChevronUpOutlineRegular, IconChevronsUpDownOutlineMedium, IconChevronsUpDownOutlineRegular, IconClockOutlineMedium, IconClockOutlineRegular, IconCloseCircleFillMedium, IconCloseCircleFillRegular, IconCloseFillMedium, IconCloseFillRegular, IconCloseOutlineMedium, IconCloseOutlineRegular, IconCodeOutlineMedium, IconCodeOutlineRegular, IconCompactOutlineMedium, IconCompactOutlineRegular, IconCompareSplitOutlineMedium, IconCompareSplitOutlineRegular, IconContextInjectionOutlineMedium, IconContextInjectionOutlineRegular, IconCopyOutlineMedium, IconCopyOutlineRegular, IconCordisPluginOutlineMedium, IconCordisPluginOutlineRegular, IconDarkOutlineMedium, IconDarkOutlineRegular, IconDataOutlineMedium, IconDataOutlineRegular, IconDatabaseOutlineMedium, IconDatabaseOutlineRegular, IconDeliverDocMedium, IconDeliverDocRegular, IconDislikeFillMedium, IconDislikeFillRegular, IconDislikeOutlineMedium, IconDislikeOutlineRegular, IconDownloadOutlineMedium, IconDownloadOutlineRegular, IconEditOutlineMedium, IconEditOutlineRegular, IconEllipsisOutlineMedium, IconEllipsisOutlineRegular, IconEnhanceOutlineMedium, IconEnhanceOutlineRegular, IconFlatListOutlineMedium, IconFlatListOutlineRegular, IconFolderCloseMedium, IconFolderCloseRegular, IconFolderOpenMedium, IconFolderOpenOutlineMedium, IconFolderOpenOutlineRegular, IconFolderOpenRegular, IconFollowsystemOutlineMedium, IconFollowsystemOutlineRegular, IconFullscreenOutlineMedium, IconFullscreenOutlineRegular, IconGaugeOutlineMedium, IconGaugeOutlineRegular, IconGlobeOutlineMedium, IconGlobeOutlineRegular, IconGoalOutlineMedium, IconGoalOutlineRegular, IconInfoOutlineMedium, IconInfoOutlineRegular, IconInspectOutlineMedium, IconInspectOutlineRegular, IconLightOutlineMedium, IconLightOutlineRegular, IconLikeFillMedium, IconLikeFillRegular, IconLikeOutlineMedium, IconLikeOutlineRegular, IconLinkOutlineMedium, IconLinkOutlineRegular, IconListPenOutlineMedium, IconListPenOutlineRegular, IconLoadingOutlineMedium, IconLoadingOutlineRegular, IconMicrophoneOutlineMedium, IconMicrophoneOutlineRegular, IconNewChatOutlineMedium, IconNewChatOutlineRegular, IconNowrapFillMedium, IconNowrapFillRegular, IconPanelLeftOutlineMedium, IconPanelLeftOutlineRegular, IconPaperPlaneOutlineMedium, IconPaperPlaneOutlineRegular, IconPaperclipOutlineMedium, IconPaperclipOutlineRegular, IconPauseOutlineMedium, IconPauseOutlineRegular, IconPersonalizationOutlineMedium, IconPersonalizationOutlineRegular, IconPinFillMedium, IconPinFillRegular, IconPinOutlineMedium, IconPinOutlineRegular, IconPlanOutlineMedium, IconPlanOutlineRegular, IconPlayOutlineMedium, IconPlayOutlineRegular, IconPluginPinwheelOutlineMedium, IconPluginPinwheelOutlineRegular, IconPlusOutlineMedium, IconPlusOutlineRegular, IconProjectAddOutlineMedium, IconProjectAddOutlineRegular, IconQuestionOutlineMedium, IconQuestionOutlineRegular, IconQueueOutlineMedium, IconQueueOutlineRegular, IconRefreshOutlineMedium, IconRefreshOutlineRegular, IconRightUpOutlineMedium, IconRightUpOutlineRegular, IconSearchOutlineMedium, IconSearchOutlineRegular, IconSendOutlineMedium, IconSendOutlineRegular, IconSettingsOutlineMedium, IconSettingsOutlineRegular, IconShareOutlineMedium, IconShareOutlineRegular, IconShieldOutlineMedium, IconShieldOutlineRegular, IconSkillOutlineMedium, IconSkillOutlineRegular, IconSlidersTwoOutlineMedium, IconSlidersTwoOutlineRegular, IconSparkleMedium, IconSparkleRegular, IconStopFillMedium, IconStopFillRegular, IconThinkOutlineMedium, IconThinkOutlineRegular, IconTrashOutlineMedium, IconTrashOutlineRegular, IconTreeCornerMedium, IconTreeCornerRegular, IconTriangleRightFillMedium, IconTriangleRightFillRegular, IconUnarchiveOutlineMedium, IconUnarchiveOutlineRegular, IconUserOutlineMedium, IconUserOutlineRegular, IconUsersOutlineMedium, IconUsersOutlineRegular, IconWarningOutlineMedium, IconWarningOutlineRegular, IconWarningTriangleOutlineMedium, IconWarningTriangleOutlineRegular, IconWorkspaceTreeOutlineMedium, IconWorkspaceTreeOutlineRegular, IconWrapFillMedium, IconWrapFillRegular, IconWrapLinesOutlineMedium, IconWrapLinesOutlineRegular, ImageLightbox, Input, JsonBlock, JsonTree, LinkIconMedium, LinkIconRegular, MarkdownDelegateProvider, MarkdownText, Menu, MenuItemButton, MenuSurface, Modal, PathLabel, PermissionIconFullAccessMedium, PermissionIconFullAccessRegular, PermissionIconReadOnlyMedium, PermissionIconReadOnlyRegular, PermissionIconWorkspaceWriteMedium, PermissionIconWorkspaceWriteRegular, Pill, PluginArtworkDefault, PluginArtworkLoop, PluginArtworkSearch, PluginArtworkSubagent, PluginArtworkTerminal, ReadBlock, ReferenceIconMedium, ReferenceIconRegular, RiskConfirmation, SHIELD_OUTLINE_PATH, SearchBlock, SegmentedControl, SegmentedTabs, SettingsForm, SettingsFormModel, SettingsSecretField, SettingsValueField, ShortcutKeys, StateDot, Switch, Tag, TerminalBlock, TextShimmer, Toast, Tooltip, WebBlock, classifyFileType, classifyLinkPath, closeTopModal, diffTotals, extractMarkdownPlainText, fileExtension, fileSizeText, focusWithoutRing, isBehindModal, isDarwinDesktop, languageForPath, modalSelector, observeComposition, pointerModality, projectUserText, rankByName, relativeTime, settingsNumberField, settingsTextField, useAnchoredMaxHeight, useAnchoredPosition, useCodeHighlighter, useDismissOnOutsidePointer, useModalLayer, writeClipboard };
|
|
12182
12259
|
|
|
12183
12260
|
//# sourceMappingURL=index.js.map
|
|
@@ -6,7 +6,7 @@ export interface DisclosureRowProps {
|
|
|
6
6
|
open: boolean;
|
|
7
7
|
expandable: boolean;
|
|
8
8
|
onToggle: () => void;
|
|
9
|
-
/** Animate the
|
|
9
|
+
/** Animate the complete header while its owning operation is running. */
|
|
10
10
|
running?: boolean | undefined;
|
|
11
11
|
/** Makes the complete title row the disclosure target. */
|
|
12
12
|
expandOnRowClick?: boolean | undefined;
|
|
@@ -18,6 +18,10 @@ export interface DisclosureRowProps {
|
|
|
18
18
|
children?: ReactNode;
|
|
19
19
|
className?: string | undefined;
|
|
20
20
|
rowClassName?: string | undefined;
|
|
21
|
+
/** Sizing class for the header text area, beside the leading icon. */
|
|
22
|
+
contentClassName?: string | undefined;
|
|
23
|
+
/** Layout class shared by the header text and its decorative copy. */
|
|
24
|
+
contentLayoutClassName?: string | undefined;
|
|
21
25
|
leadingClassName?: string | undefined;
|
|
22
26
|
chevronClassName?: string | undefined;
|
|
23
27
|
titleClassName?: string | undefined;
|
|
@@ -28,5 +32,5 @@ export interface DisclosureRowProps {
|
|
|
28
32
|
* @param props - Visual content, controlled state, and interaction policy.
|
|
29
33
|
* @returns the disclosure row.
|
|
30
34
|
*/
|
|
31
|
-
export declare const DisclosureRow: import("react").MemoExoticComponent<({ icon, title, open, expandable, onToggle, running, expandOnRowClick, previewChevron, keepContentWhenOpen, collapsedContent, children, className, rowClassName, leadingClassName, chevronClassName, titleClassName, }: DisclosureRowProps) => import("react").JSX.Element>;
|
|
35
|
+
export declare const DisclosureRow: import("react").MemoExoticComponent<({ icon, title, open, expandable, onToggle, running, expandOnRowClick, previewChevron, keepContentWhenOpen, collapsedContent, children, className, rowClassName, contentClassName, contentLayoutClassName, leadingClassName, chevronClassName, titleClassName, }: DisclosureRowProps) => import("react").JSX.Element>;
|
|
32
36
|
//# sourceMappingURL=DisclosureRow.d.ts.map
|
|
@@ -1,13 +1,22 @@
|
|
|
1
|
+
/** Text activity animation shared by a row and its nested text fragments. */
|
|
2
|
+
import { type ReactNode } from 'react';
|
|
1
3
|
/** Text and activity supplied by the owning row. */
|
|
2
4
|
export interface TextShimmerProps {
|
|
3
|
-
children
|
|
4
|
-
|
|
5
|
+
/** Text or presentational children with text in nested TextShimmer instances. No effects or element ids. */
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
/** Whether to animate; nested instances share the containing row's activity. */
|
|
8
|
+
active?: boolean | undefined;
|
|
5
9
|
className?: string | undefined;
|
|
10
|
+
/** Layout class applied equally to the base and decorative content. */
|
|
11
|
+
contentClassName?: string | undefined;
|
|
6
12
|
}
|
|
7
13
|
/**
|
|
8
|
-
* Render text with
|
|
14
|
+
* Render text with one shared highlight while retaining selectable, accessible content.
|
|
15
|
+
* Nested instances inherit the outer animation. Keep icons outside; mark decorative
|
|
16
|
+
* separators with data-shimmer-decoration so their background follows the highlight.
|
|
17
|
+
* Active children also render in an inert, clipped decoration; supply only presentation.
|
|
9
18
|
* @param props - localized text, running state, and owner styling.
|
|
10
|
-
* @returns
|
|
19
|
+
* @returns retained text and its optional decorative highlight.
|
|
11
20
|
*/
|
|
12
|
-
export declare const TextShimmer: import("react").MemoExoticComponent<({ children, active, className }: TextShimmerProps) => import("react").JSX.Element>;
|
|
21
|
+
export declare const TextShimmer: import("react").MemoExoticComponent<({ children, active, className, contentClassName }: TextShimmerProps) => import("react").JSX.Element>;
|
|
13
22
|
//# sourceMappingURL=TextShimmer.d.ts.map
|
package/lib/types/Tooltip.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export type TooltipSide = 'right' | 'bottom' | 'top';
|
|
|
9
9
|
export declare const TooltipSuppression: import("react").Context<((suppressed: boolean) => void) | null>;
|
|
10
10
|
/** Props Tooltip injects into its anchor child; the child's own handlers are chained ahead of the tooltip's. */
|
|
11
11
|
interface AnchorProps {
|
|
12
|
+
'aria-describedby'?: string | undefined;
|
|
12
13
|
ref?: Ref<HTMLElement> | undefined;
|
|
13
14
|
onMouseEnter?: MouseEventHandler | undefined;
|
|
14
15
|
onMouseLeave?: MouseEventHandler | undefined;
|
|
@@ -27,29 +28,35 @@ type TooltipLabel = string | (() => string);
|
|
|
27
28
|
* bubble would overlap); default 'center'. Ignored for side 'right'.
|
|
28
29
|
* @param props.portal - render the bubble under document.body, so an ancestor's clipping or its
|
|
29
30
|
* stacking context (which confines the bubble's z-index to that context) cannot hide it.
|
|
30
|
-
* @param props.delayMs - hover delay in milliseconds
|
|
31
|
+
* @param props.delayMs - hover delay in milliseconds (default 0).
|
|
32
|
+
* @param props.focusDelayMs - keyboard focus delay in milliseconds (default 0); blur, click,
|
|
33
|
+
* mouse leave, disabling, and unmount cancel a pending show.
|
|
31
34
|
* @param props.gap - anchor-to-bubble distance in pixels for 'bottom'/'top' bubbles (default 8);
|
|
32
35
|
* ignored for side 'right'.
|
|
33
36
|
* @param props.disabled - suppress the bubble while true; the anchor renders identically so
|
|
34
37
|
* toggling never remounts it (which would cut its CSS transitions).
|
|
35
38
|
* @param props.maxWidth - bubble width cap in pixels, for labels long enough that the default
|
|
36
39
|
* half-viewport cap would render a slab wider than the surface the anchor sits on.
|
|
40
|
+
* @param props.openOnClick - clicking also pins the bubble for reading; another click, Escape,
|
|
41
|
+
* Tab, or an outside pointerdown dismisses it. Defaults to false for ordinary action tooltips.
|
|
37
42
|
* @param props.children - a single anchor element; its own ref (callback or object) is forwarded alongside the tooltip's.
|
|
38
43
|
* @returns the cloned anchor plus a fixed-position bubble, optionally portaled to the body.
|
|
39
44
|
* The bubble stays hidden until ResizeObserver supplies its size for viewport fitting; clicking the
|
|
40
|
-
* anchor dismisses the bubble
|
|
45
|
+
* anchor dismisses the bubble unless openOnClick is enabled, and focus arriving after a pointer
|
|
41
46
|
* interaction (a closing menu refocusing its trigger) never raises it.
|
|
42
47
|
*/
|
|
43
|
-
export declare function Tooltip({ label, shortcutKeys, side, align, delayMs, gap, disabled, portal, maxWidth, children }: {
|
|
48
|
+
export declare function Tooltip({ label, shortcutKeys, side, align, delayMs, focusDelayMs, gap, disabled, portal, maxWidth, openOnClick, children }: {
|
|
44
49
|
label: TooltipLabel;
|
|
45
50
|
shortcutKeys?: readonly string[] | undefined;
|
|
46
51
|
side?: TooltipSide;
|
|
47
52
|
align?: 'center' | 'end';
|
|
48
53
|
delayMs?: number;
|
|
54
|
+
focusDelayMs?: number;
|
|
49
55
|
gap?: number;
|
|
50
56
|
disabled?: boolean;
|
|
51
57
|
portal?: boolean;
|
|
52
58
|
maxWidth?: number;
|
|
59
|
+
openOnClick?: boolean;
|
|
53
60
|
children: ReactElement<AnchorProps>;
|
|
54
61
|
}): import("react").JSX.Element;
|
|
55
62
|
export {};
|
package/lib/types/index.d.ts
CHANGED
|
@@ -52,6 +52,7 @@ export type { CodeFileType, FileType, FileTypeIconProps, FileTypeKind, FileTypeP
|
|
|
52
52
|
export { projectUserText, type UserTextReferences } from './user-text.tsx';
|
|
53
53
|
export { Tooltip } from './Tooltip.tsx';
|
|
54
54
|
export type { TooltipSide } from './Tooltip.tsx';
|
|
55
|
+
export { pointerModality } from './input-modality.ts';
|
|
55
56
|
export { Toast } from './Toast.tsx';
|
|
56
57
|
export { fileSizeText } from './file-size.ts';
|
|
57
58
|
export { writeClipboard } from './clipboard.ts';
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Overlay clearance from the window's top strip. On macOS desktop the frame
|
|
3
|
-
* publishes `--dsh-frame-top-clearance` on the root element — the constant
|
|
4
|
-
* step below the traffic-light strip, where clicks drag the window instead of
|
|
5
|
-
* the overlay. JS-clamped overlays keep at least that much air above them.
|
|
6
|
-
* Elsewhere the property is absent and the caller's own margin applies.
|
|
7
|
-
*/
|
|
1
|
+
/** Shared viewport inset for overlays, derived from the desktop frame's reserved top strip. */
|
|
8
2
|
/**
|
|
9
3
|
* Resolve the top margin an overlay keeps from the viewport edge.
|
|
10
4
|
* @param min - the overlay's own viewport margin in px, used as the floor.
|
|
11
|
-
* @returns the larger of `min` and the frame
|
|
5
|
+
* @returns the larger of `min` and the frame clearance plus 20px; fullscreen keeps only the 20px gap.
|
|
12
6
|
*/
|
|
13
7
|
export declare function overlayTopMargin(min: number): number;
|
|
14
8
|
//# sourceMappingURL=overlay-top-margin.d.ts.map
|
|
@@ -5,8 +5,8 @@ import type { RefObject } from 'react';
|
|
|
5
5
|
* @param cap - design max-height in px (the clamp never exceeds it).
|
|
6
6
|
* @param signal - re-measure trigger: pass the overlay's render state so anchor
|
|
7
7
|
* moves (composer growth) re-fit; resize/scroll re-fit while mounted.
|
|
8
|
-
* @param margin - viewport top margin floor in px; the frame's
|
|
9
|
-
*
|
|
8
|
+
* @param margin - viewport top margin floor in px; the frame's overlay
|
|
9
|
+
* inset widens it. Callers under fixed chrome (the conversation header)
|
|
10
10
|
* raise it past their chrome's height.
|
|
11
11
|
* @returns the max-height to apply inline, in px.
|
|
12
12
|
*/
|
|
@@ -24,7 +24,7 @@ export interface AnchoredPositionOptions {
|
|
|
24
24
|
align?: 'start' | 'end';
|
|
25
25
|
/** Distance kept between the anchor edge named by `side` and the panel. */
|
|
26
26
|
gap: number;
|
|
27
|
-
/** Distance kept between the panel and each viewport edge. */
|
|
27
|
+
/** Distance kept between the panel and each viewport edge; the frame's overlay inset widens the top margin. */
|
|
28
28
|
margin: number;
|
|
29
29
|
}
|
|
30
30
|
/**
|
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.
|
|
4
|
+
"version": "0.2.0-rc.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
"micromark-extension-gfm": "^3.0.0",
|
|
48
48
|
"micromark-util-sanitize-uri": "^2.0.1",
|
|
49
49
|
"simple-icons": "16.31.0",
|
|
50
|
+
"@deepseek-ai/dsh-client-store": "0.2.0-rc.1",
|
|
50
51
|
"@deepseek-ai/cordis": "~4.0.4",
|
|
51
|
-
"@deepseek-ai/dsh-
|
|
52
|
-
"@deepseek-ai/dsh-util-
|
|
53
|
-
"@deepseek-ai/dsh-util-workspace-path": "0.1.7-rc.2"
|
|
52
|
+
"@deepseek-ai/dsh-util-code-language": "0.2.0-rc.1",
|
|
53
|
+
"@deepseek-ai/dsh-util-workspace-path": "0.2.0-rc.1"
|
|
54
54
|
},
|
|
55
55
|
"files": [
|
|
56
56
|
"lib/index.js",
|