@deepseek-ai/dsh-client-ui-sidebar-documentpreview 0.1.7-rc.1 → 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 CHANGED
@@ -1,6 +1,46 @@
1
- # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
2
- # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
- # after editing either side, bring the other along and re-record with:
1
+ # Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
2
+ # section, a hash of its English and Chinese blocks outside code blocks and generated regions.
3
+ # After editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/client/ui-sidebar-documentpreview/README.md
5
- README.md: 03e25deb27591fb5b8864b48a5a0b44da854eb54
6
- README.zh.md: d90d4932f210e9cff2275bdbadd5d35c1edea860
5
+ /:
6
+ en: ef50065f5ff17aa1
7
+ zh: ee5d2b7986739fca
8
+ /deepseek-ai-dsh-client-ui-sidebar-documentpreview:
9
+ en: 5168e03d461318f5
10
+ zh: 7ad97d70ee331bfd
11
+ /deepseek-ai-dsh-client-ui-sidebar-documentpreview/summary:
12
+ en: a74c16667d0baada
13
+ zh: 4fd709ff9f98b84f
14
+ /deepseek-ai-dsh-client-ui-sidebar-documentpreview/table-of-contents:
15
+ en: 0dd8c3a22e28aacf
16
+ zh: c27c11bf4b5cceba
17
+ /deepseek-ai-dsh-client-ui-sidebar-documentpreview/what-it-registers:
18
+ en: a8eaf01a3a3390ee
19
+ zh: ddea36dbcc4a0159
20
+ /deepseek-ai-dsh-client-ui-sidebar-documentpreview/addresses:
21
+ en: 949156aa02ec8b07
22
+ zh: d3675754e2a37b5d
23
+ /deepseek-ai-dsh-client-ui-sidebar-documentpreview/how-it-reads:
24
+ en: 5cdbd4a218315e70
25
+ zh: d5054f541e0e0275
26
+ /deepseek-ai-dsh-client-ui-sidebar-documentpreview/excel-preview:
27
+ en: b99b0e0b8efc2853
28
+ zh: 4327352d1334fc6b
29
+ /deepseek-ai-dsh-client-ui-sidebar-documentpreview/office-preview:
30
+ en: 372d8ce6492e6896
31
+ zh: 912f613bc9221aa3
32
+ /deepseek-ai-dsh-client-ui-sidebar-documentpreview/navigation:
33
+ en: 5cd81a7b3cdc83bd
34
+ zh: 4cdd1b7ede497925
35
+ /deepseek-ai-dsh-client-ui-sidebar-documentpreview/model-experience:
36
+ en: ca1deb99d0e44755
37
+ zh: f285fc56cee669ec
38
+ /deepseek-ai-dsh-client-ui-sidebar-documentpreview/model-experience/kv-cache-effect:
39
+ en: 7edb4c0bb5f13847
40
+ zh: ae5d0bbebe4aa563
41
+ /deepseek-ai-dsh-client-ui-sidebar-documentpreview/known-limitations-and-deferred-work:
42
+ en: 7be2ad2e198131f8
43
+ zh: 21b35eae72a49ad2
44
+ /deepseek-ai-dsh-client-ui-sidebar-documentpreview/known-limitations-and-deferred-work/dev-note:
45
+ en: 3d8904cb970145a3
46
+ zh: a0c0cddcfedf9e42
package/README.md CHANGED
@@ -46,7 +46,9 @@ After all text pages load, Markdown images use the authenticated `/api/file` rou
46
46
  <a id="how-it-reads"></a>
47
47
  ## How it reads
48
48
 
49
- Developer tools selects the HTML preview policy in both Web and desktop. The renderer receives `interactivePreview` from plugin assembly. Off uses a DOMPurify-sanitized complete static document in an iframe with no sandbox permissions: CSP blocks scripts, external resources, connections, forms, and nested frames; all `href` and `xlink:href` attributes, refresh directives, and declarative shadow roots are removed before reparsing. Inline styles and data images remain visible, and related files are not read. On uses the scripted Blob preview described below. A mode change unmounts the previous frame and aborts its pending related-file reads. Static preview releases CSS/JS resource subscriptions and keeps the root file watched. Other document formats retain their own policies.
49
+ Coding Tools selects the HTML preview policy in both Web and desktop. The renderer receives `interactivePreview` from plugin assembly. Off uses a DOMPurify-sanitized complete static document in an iframe with no sandbox permissions: CSP blocks scripts, external resources, connections, forms, and nested frames; all `href` and `xlink:href` attributes, refresh directives, and declarative shadow roots are removed before reparsing. Inline styles and data images remain visible, and related files are not read. On uses the scripted Blob preview described below. A mode change unmounts the previous frame and aborts its pending related-file reads. Static preview releases CSS/JS resource subscriptions and keeps the root file watched. Other document formats retain their own policies.
50
+
51
+ Both HTML modes set the initial iframe name to `dsh-sidebar-html-<tab-id>` for Desktop shortcut routing. This correlation does not grant the preview access to the parent document.
50
52
 
51
53
  The body reads its record, navigation and lifetime through `useTabInfo().tab`. `useResource<'file'>(tab.contentId)` supplies metadata; ordinary inject callbacks supply content reads:
52
54
 
@@ -55,22 +57,22 @@ The body reads its record, navigation and lifetime through `useTabInfo().tab`. `
55
57
  - **Complete bytes** — PDF, HTML, common images, and spreadsheets call `remote.workspaceFiles.readBytes(sessionId, path, {}, signal)`. The binary Remote returns `data: Uint8Array<ArrayBuffer>` directly for `{ kind: 'bytes', data }`. The Host's `maxFileBytes` cap rejects oversized files rather than truncating them. PDF and spreadsheet renderers copy retained bytes before Worker transfer, keeping the Preview buffer usable. Bytes stay in transient view state, never persisted layouts or Session JSONL. Loading-mode changes retire previous results.
56
58
  - **Reload** — manual reload rereads only the current Preview tab through its Remote callbacks, preserving its scroll preference and retiring older requests. Automatic refresh uses the same callbacks after a `ResourceGroup` member changes. Each member's first metadata establishes a baseline without triggering reload or first-read version reconciliation; later changes received during a read remain pending for another refresh. Reads neither refresh shared metadata nor clear another tab's notice.
57
59
 
58
- When Developer tools is enabled, HTML fills the body edge to edge in a Blob iframe with exactly `sandbox="allow-scripts"`, without `allow-same-origin`; scripts cannot access the parent application's origin or file reader. The renderer loads directly declared relative `.js` classic scripts and `.css` stylesheets through its injected Remote callback, with fixed safety limits of 4 MiB per asset, 32 MiB total, and 64 distinct assets. Host code resolves the related path, and `readBytes` with `baseFile` returns native bytes. The dependency Resource is added after the read returns, using its `absolutePath` or a string `error.details.path` on failure; without a Host path, the Client does not guess one. Inside the renderer, base64 is used only to embed the iframe bootstrap payload in script text. A `<base href>` leaves dependency resolution to the browser, as do HTTPS resources. Local module imports, CSS `url()`/`@import`, and dynamic `fetch` do not use Host file access. Read failures, invalid UTF-8, or exceeded limits fail the preview rather than publishing a partial asset package. Replacing or unmounting the document releases its Blob URL.
60
+ When Coding Tools is enabled, HTML fills the body edge to edge in a Blob iframe with exactly `sandbox="allow-scripts"`, without `allow-same-origin`; scripts cannot access the parent application's origin or file reader. The renderer loads directly declared relative `.js` classic scripts and `.css` stylesheets through its injected Remote callback, with fixed safety limits of 4 MiB per asset, 32 MiB total, and 64 distinct assets. Host code resolves the related path, and `readBytes` with `baseFile` returns native bytes. The dependency Resource is added after the read returns, using its `absolutePath` or a string `error.details.path` on failure; without a Host path, the Client does not guess one. Inside the renderer, base64 is used only to embed the iframe bootstrap payload in script text. A `<base href>` leaves dependency resolution to the browser, as do HTTPS resources. Local module imports, CSS `url()`/`@import`, and dynamic `fetch` do not use Host file access. Read failures, invalid UTF-8, or exceeded limits fail the preview rather than publishing a partial asset package. Replacing or unmounting the document releases its Blob URL.
59
61
 
60
62
  PNG, JPEG, GIF, WebP, BMP, ICO, and SVG render through Blob URLs in an `<img>` static-image context, rounded inside a 12px inset. Images default to fit width without enlarging content smaller than the pane; 100% uses the image's intrinsic CSS-pixel width. The shared zoom controls can produce horizontal and vertical scrolling, but do not provide drag-to-pan. Zoom changes retain the same `<img>` and Blob URL, so animated images continue playing. Raster formats can soften above their intrinsic size, while SVG remains on the browser's vector rendering path. SVG markup never enters the application DOM or an iframe, so its scripts cannot execute or reach the parent page. Replacing or unmounting the image revokes its Blob URL.
61
63
 
62
- Shared copy comes from `sidebarDocumentPreview`; each builtin renderer owns its localized labels. PDF and converted Office previews use a graphite background in light mode and a matte-black background in dark mode, with subtle page shadows and original document colors. PDF and image previews share a floating control with **Fit width**, 25%, 50%, 100%, 150%, and 200% choices plus 25% incremental zoom across the 25%–400% fixed range. Fit width is the default and tracks pane resizing; 100% means the PDF's 96-DPI page size or the image's intrinsic CSS-pixel size. On fine pointers, the control starts hidden, slides up when the pointer enters the bottom 72 CSS pixels, and slides down after a 420 ms leave delay; hover, keyboard focus, an open menu, and an active gesture keep it visible, while devices without hover keep it visible continuously. Chromium maps a macOS trackpad pinch to the same live, pointer-anchored path as Ctrl+wheel; the control displays the gesture percentage, and the settled value survives body remounts until the tab closes. HTML previews do not expose zoom controls. After zoom settles or fit width changes, nearby PDF pages redraw at the resolved scale multiplied by the device pixel ratio. The previous bitmap and selectable text stay visible until the replacement bitmap is ready; offscreen pages refresh when they approach the viewport.
64
+ Shared copy comes from `sidebarDocumentPreview`; each builtin renderer owns its localized labels. PDF and converted Office previews use a cool light-grey background in light mode and a matte-black background in dark mode, with subtle page shadows and original document colors. PDF and image previews share a floating control with **Fit width**, 25%, 50%, 100%, 150%, and 200% choices plus 25% incremental zoom across the 25%–400% fixed range. Fit width is the default and tracks pane resizing; 100% means the PDF's 96-DPI page size or the image's intrinsic CSS-pixel size. On fine pointers, the control starts hidden, slides up when the pointer enters the bottom 72 CSS pixels, and slides down after a 420 ms leave delay; hover, keyboard focus, an open menu, and an active gesture keep it visible, while devices without hover keep it visible continuously. Chromium maps a macOS trackpad pinch to the same live, pointer-anchored path as Ctrl+wheel; the control displays the gesture percentage, and the settled value survives body remounts until the tab closes. HTML previews do not expose zoom controls. After zoom settles or fit width changes, nearby PDF pages redraw at the resolved scale multiplied by the device pixel ratio. The previous bitmap and selectable text stay visible until the replacement bitmap is ready; offscreen pages refresh when they approach the viewport.
63
65
 
64
- Initial reads, additional pages, and HTML/PDF/image preparation share the ongoing `StateDot` loader, which exposes its label to assistive technology and respects reduced-motion preferences; every wait before content exists centres the loader in the pane, so opening a file shows one indicator in one position until the body appears. Loaded pages stay visible while another page loads. The PDF body loads its package-local `client.pdf.js` chunk only when a PDF preview mounts; PDF.js, its Worker source, and embedded support data stay out of the startup `client.js`. PDF pages fill the pane's width edge to edge as one vertical sequence and render lazily near the viewport; an unrendered page holds its place as a quiet 3:4 placeholder block. PDF.js’s official TextLayerBuilder manages selection boundaries and normalized copying over an aligned text layer. Its companion styles keep blank line breaks unhighlighted; alignment accounts for PDF page units, page rotation, and viewport resizing, and page disposal cancels both layers. Image-only PDFs contain no selectable text. Code previews show a tertiary-colored language label and a copy icon with a tooltip; wrapping remains in the document toolbar. They show source line numbers by default without including them in copied text; plain text uses the same font size and line height as code. Code sits on the pane's own background rather than the chat card's fill; its banner is adjacent to a full-height inner scrollport, so both scrollbars begin below the copy control.
66
+ Initial reads and renderer preparation, including Office conversion, share a centered 28px ongoing `StateDot` with the visible localized status “Rendering document...”. The status exposes the same accessible name and respects reduced-motion preferences. Additional text pages keep a compact inline spinner while loaded content stays visible. The PDF body loads its package-local `client.pdf.js` chunk only when a PDF preview mounts; PDF.js, its Worker source, and embedded support data stay out of the startup `client.js`. PDF and converted Word/PowerPoint pages form a vertical sequence with 12px page gaps and a 12px outer inset showing the theme-specific document background; fit width reserves this inset, and pages render lazily near the viewport; an unrendered page holds its place as a quiet 3:4 placeholder block. PDF.js’s official TextLayerBuilder manages selection boundaries and normalized copying over an aligned text layer. Selections use translucent blue in both themes while the canvas retains the document text; blank line breaks remain unhighlighted; alignment accounts for PDF page units, page rotation, and viewport resizing, and page disposal cancels both layers. Image-only PDFs contain no selectable text. Code previews show a tertiary-colored language label and a copy icon with a tooltip; wrapping remains in the document toolbar. They show source line numbers by default without including them in copied text; plain text uses the same font size and line height as code. Code sits on the pane's own background rather than the chat card's fill; its banner is adjacent to a full-height inner scrollport, so both scrollbars begin below the copy control.
65
67
 
66
68
  <a id="excel-preview"></a>
67
69
  ## Excel preview
68
70
 
69
- Open `.xlsx`, `.xls`, `.csv`, and `.tsv` directly in the browser with worksheet tabs, cell selection, copying, and a read-only formula bar. XLSX retains fonts, solid fills, borders, number formats, rich text, merged cells, row and column sizes, hidden rows/columns/sheets, and frozen headings. XLS retains saved values, formulas, number formats, merges, and available row/column metadata; fonts, borders, and frozen panes are unsupported. Workbooks display saved formula results without recalculating; missing results remain blank, and a compact formula-bar warning marks workbooks whose displayed results may be incomplete or inaccurate. The workbook viewport fills the preview pane and follows its size changes without reloading its sheets or selection. Worksheet tabs start at the left edge; overflowing tabs scroll with horizontal trackpad gestures or left/right navigation beside a separate zoom control. Spreadsheet controls retain dark text on their light background in both app themes. Pixel-based trackpad gestures pan the grid on both axes together, including diagonally, at the gesture’s speed; frozen headings stay fixed. Selection statistics and inactive worksheet menu arrows are hidden. Frozen headings remain fixed while scrolling, without freeze dividers or drag handles. Spreadsheet preview does not call the Office conversion service.
71
+ Open `.xlsx`, `.xls`, `.csv`, and `.tsv` directly in the browser with worksheet tabs, cell selection, copying, and a read-only formula bar. XLSX retains fonts, solid fills, borders, number formats, rich text, merged cells, row and column sizes, hidden rows/columns/sheets, and frozen headings. XLS retains saved values, formulas, number formats, merges, and available row/column metadata; fonts, borders, and frozen panes are unsupported. Workbooks display saved formula results without recalculating; missing results remain blank, and a compact formula-bar warning marks workbooks whose displayed results may be incomplete or inaccurate. The workbook viewport fills the preview pane and follows its size changes without reloading its sheets or selection. Worksheet tabs start at the left edge; overflowing tabs scroll with horizontal trackpad gestures or left/right navigation beside a separate zoom control. Spreadsheet controls retain dark text on their light background in both app themes. Pixel-based trackpad gestures pan the grid on both axes together, including diagonally, at the gesture’s speed; frozen headings stay fixed. Reversing direction at a sheet edge retains the next gesture’s movement. Selection statistics and inactive worksheet menu arrows are hidden. Frozen headings remain fixed while scrolling, without freeze dividers or drag handles. Spreadsheet preview does not call the Office conversion service.
70
72
 
71
73
  XLSX preview omits DrawingML parts from an in-memory copy before parsing and ignores worksheet drawing references. The original file and worksheet XML remain unchanged. A notice above the table lists detected charts, images, shapes, and conditional formatting that are not displayed, and recommends opening the workbook in a system application. Files without these detected features have no notice; formula warnings remain separate.
72
74
 
73
- CSV and TSV default to the spreadsheet viewer and also offer Plain text. Commas and tabs delimit their fields respectively; quoted separators, escaped quotes, multiline fields, empty fields, and unequal row lengths are supported. The first row remains data. Values remain literal strings, including leading zeros, dates, booleans, and formula-looking text. Text files accept UTF-8 or BOM-marked UTF-16; invalid encoding receives conversion guidance. Malformed quoted fields fail the table preview rather than silently dropping data.
75
+ CSV and TSV default to the spreadsheet viewer and also offer Plain text; CSV additionally offers syntax-highlighted Code. Commas and tabs delimit their fields respectively; quoted separators, escaped quotes, multiline fields, empty fields, and unequal row lengths are supported. The first row remains data. Values remain literal strings, including leading zeros, dates, booleans, and formula-looking text. Text files accept UTF-8 or BOM-marked UTF-16; invalid encoding receives conversion guidance. Malformed quoted fields fail the table preview rather than silently dropping data.
74
76
 
75
77
  Configure `excel` on the same `ui-sidebar-documentpreview` entry. These limits complement the Host's complete-file read limit; they do not cap browser process memory or decompression allocations.
76
78
 
@@ -112,6 +114,8 @@ Office registration, loading, caching, and font notices live in `src/client/offi
112
114
 
113
115
  The Office Remote returns converted PDFs as native `Uint8Array` values through Connection's multipart binary transport. Renderers borrow retained bytes read-only and copy them before Worker transfer.
114
116
 
117
+ The page refresh shortcut reuses the selected preview’s reload operation, including its request retirement and scroll retention. The header reload tooltip and ARIA combination follow the effective shortcut binding.
118
+
115
119
  </details>
116
120
 
117
121
  <a id="navigation"></a>
package/README.zh.md CHANGED
@@ -46,7 +46,9 @@ tab 使用 `fileAddressFor` 构造的 Session 地址,携带相对或绝对路
46
46
  <a id="how-it-reads"></a>
47
47
  ## 怎么读
48
48
 
49
- Web 和桌面端均通过开发者工具选择 HTML 预览策略。渲染器从插件组装层接收 `interactivePreview`。关闭时,将经 DOMPurify 清理的完整静态文档放入不授予沙箱权限的 iframe:CSP 禁止脚本、外部资源、连接、表单和嵌套框架;所有 `href` 和 `xlink:href` 属性、刷新指令及声明式 Shadow DOM 均在重新解析前被移除。行内样式和 data 图片仍可显示,不读取关联文件。开启时使用下述支持脚本的 Blob 预览。切换模式会卸载之前的框架并中止其待处理关联文件读取。静态预览释放 CSS/JS 的 Resource 订阅,根文件继续监听。其他文档格式保持各自策略。
49
+ Web 和桌面端均通过代码工作工具选择 HTML 预览策略。渲染器从插件组装层接收 `interactivePreview`。关闭时,将经 DOMPurify 清理的完整静态文档放入不授予沙箱权限的 iframe:CSP 禁止脚本、外部资源、连接、表单和嵌套框架;所有 `href` 和 `xlink:href` 属性、刷新指令及声明式 Shadow DOM 均在重新解析前被移除。行内样式和 data 图片仍可显示,不读取关联文件。开启时使用下述支持脚本的 Blob 预览。切换模式会卸载之前的框架并中止其待处理关联文件读取。静态预览释放 CSS/JS 的 Resource 订阅,根文件继续监听。其他文档格式保持各自策略。
50
+
51
+ 两种 HTML 模式均将 iframe 初始名称设为 `dsh-sidebar-html-<tab-id>`,供 Desktop 快捷键路由关联目标。这种关联不授予预览访问父文档的权限。
50
52
 
51
53
  正文通过 `useTabInfo().tab` 读取记录、导航和生命周期。`useResource<'file'>(tab.contentId)` 提供元数据,普通 inject 回调提供内容读取:
52
54
 
@@ -55,22 +57,22 @@ Web 和桌面端均通过开发者工具选择 HTML 预览策略。渲染器从
55
57
  - **完整字节** —— PDF、HTML、常见图片和表格调用 `remote.workspaceFiles.readBytes(sessionId, path, {}, signal)`。二进制 Remote 直接返回 `data: Uint8Array<ArrayBuffer>`,供 `{ kind: 'bytes', data }` 使用。Host 的 `maxFileBytes` 上限拒绝超大文件,不截断。PDF 和表格渲染器在传给 Worker 前复制保留的字节,使 Preview 缓冲区仍可使用。字节仅保存在临时视图状态中,绝不进入持久布局或 Session JSONL。加载模式变化会淘汰先前结果。
56
58
  - **重新载入** —— 手动重新载入仅让当前 Preview tab 通过自己的 Remote 回调重读,保留滚动偏好并淘汰旧请求。`ResourceGroup` 成员变化后,自动刷新使用相同回调。各成员首次元数据仅建立基线,不触发重新载入或首读版本对账;后续在读取期间收到的变化仍会留待下一次刷新。读取既不刷新共享元数据,也不清除其它 tab 的提示。
57
59
 
58
- 开启开发者工具时,HTML 以贴合正文四边的 Blob iframe 运行,沙箱属性严格为 `sandbox="allow-scripts"`,不含 `allow-same-origin`;脚本无法访问父应用的源或文件读取接口。渲染器通过注入的 Remote 回调,加载直接声明的相对 `.js` 经典脚本和 `.css` 样式表;固定安全上限为单个资源 4 MiB、总计 32 MiB、64 个不同资源。Host 代码解析关联路径,带 `baseFile` 的 `readBytes` 返回原生字节。依赖 Resource 在读取返回后加入,使用返回的 `absolutePath`,失败时则使用字符串类型的 `error.details.path`;没有 Host 路径时,Client 不自行猜测。在渲染器内部,base64 仅用于把 iframe 引导载荷嵌入脚本文本。`<base href>` 将依赖解析交给浏览器,HTTPS 资源也由浏览器处理。本地模块 import、CSS `url()`/`@import` 和动态 `fetch` 不使用 Host 文件访问。读取失败、无效 UTF-8 或超出上限都使预览失败,不发布部分资源包。替换或卸载文档会释放其 Blob URL。
60
+ 开启代码工作工具时,HTML 以贴合正文四边的 Blob iframe 运行,沙箱属性严格为 `sandbox="allow-scripts"`,不含 `allow-same-origin`;脚本无法访问父应用的源或文件读取接口。渲染器通过注入的 Remote 回调,加载直接声明的相对 `.js` 经典脚本和 `.css` 样式表;固定安全上限为单个资源 4 MiB、总计 32 MiB、64 个不同资源。Host 代码解析关联路径,带 `baseFile` 的 `readBytes` 返回原生字节。依赖 Resource 在读取返回后加入,使用返回的 `absolutePath`,失败时则使用字符串类型的 `error.details.path`;没有 Host 路径时,Client 不自行猜测。在渲染器内部,base64 仅用于把 iframe 引导载荷嵌入脚本文本。`<base href>` 将依赖解析交给浏览器,HTTPS 资源也由浏览器处理。本地模块 import、CSS `url()`/`@import` 和动态 `fetch` 不使用 Host 文件访问。读取失败、无效 UTF-8 或超出上限都使预览失败,不发布部分资源包。替换或卸载文档会释放其 Blob URL。
59
61
 
60
62
  PNG、JPEG、GIF、WebP、BMP、ICO 和 SVG 通过 Blob URL 在 `<img>` 静态图片上下文中渲染,带 12px 内边距和圆角。图片默认适应宽度,但不会放大小于面板的内容;100% 使用图片的固有 CSS 像素宽度。共享缩放控件可产生横向和纵向滚动,但不提供拖拽平移。缩放不会替换 `<img>` 或 Blob URL,因此动画图片会继续播放。位图超过固有尺寸后可能变虚,SVG 则继续使用浏览器的矢量渲染路径。SVG 标记绝不进入应用 DOM 或 iframe,因此其中的脚本无法执行,也无法访问父页面。替换或卸载图片会撤销其 Blob URL。
61
63
 
62
- 共享文案来自 `sidebarDocumentPreview`;各内置渲染器拥有自己的本地化标签。PDF 与转换后的 Office 预览在浅色模式下使用石墨灰底色,在深色模式下使用哑黑底色,页面带有轻微阴影并保留文档原色。PDF 与图片预览共用浮动控件,提供**适应宽度**、25%、50%、100%、150% 和 200% 选项,并在 25%–400% 固定范围内按 25% 逐级缩放。适应宽度是默认模式并跟随面板尺寸;100% 表示 PDF 的 96 DPI 页面尺寸或图片的固有 CSS 像素尺寸。在精细指针设备上,控件初始隐藏;指针进入底部 72 个 CSS 像素时向上滑入,离开 420 ms 后向下退出;控件悬停、键盘焦点、菜单展开和手势进行期间保持显示,无 hover 的设备则始终显示。Chromium 将 macOS 触控板捏合映射到与 Ctrl+滚轮相同的实时指针锚定路径;控件同步显示手势比例,静止后的值在正文重新挂载后继续保留,直至 tab 关闭。HTML 预览不显示缩放控件。缩放稳定或适应宽度发生变化后,视口附近的 PDF 页面按最终缩放比例乘以设备像素比重绘。新位图完成前保留原有画面和可选文字层;屏幕外的页面在接近视口时更新。
64
+ 共享文案来自 `sidebarDocumentPreview`;各内置渲染器拥有自己的本地化标签。PDF 与转换后的 Office 预览在浅色模式下使用冷调浅灰底色,在深色模式下使用哑黑底色,页面带有轻微阴影并保留文档原色。PDF 与图片预览共用浮动控件,提供**适应宽度**、25%、50%、100%、150% 和 200% 选项,并在 25%–400% 固定范围内按 25% 逐级缩放。适应宽度是默认模式并跟随面板尺寸;100% 表示 PDF 的 96 DPI 页面尺寸或图片的固有 CSS 像素尺寸。在精细指针设备上,控件初始隐藏;指针进入底部 72 个 CSS 像素时向上滑入,离开 420 ms 后向下退出;控件悬停、键盘焦点、菜单展开和手势进行期间保持显示,无 hover 的设备则始终显示。Chromium 将 macOS 触控板捏合映射到与 Ctrl+滚轮相同的实时指针锚定路径;控件同步显示手势比例,静止后的值在正文重新挂载后继续保留,直至 tab 关闭。HTML 预览不显示缩放控件。缩放稳定或适应宽度发生变化后,视口附近的 PDF 页面按最终缩放比例乘以设备像素比重绘。新位图完成前保留原有画面和可选文字层;屏幕外的页面在接近视口时更新。
63
65
 
64
- 首次读取、追加页及 HTML/PDF/图片准备共用 ongoing `StateDot` loading,其标签暴露给辅助技术,并遵循减少动态效果偏好;内容出现前的每个等待都把 loading 居中在面板中,打开文件到正文出现始终是同一位置的一个标记。下一页加载期间保留已显示的内容。PDF 正文仅在 PDF 预览挂载时加载包内 `client.pdf.js` chunk;PDF.js、Worker 源码和内嵌支持数据不会进入启动 `client.js`。PDF 页面贴边占满面板宽度,组成一个纵向连续序列并在接近视口时惰性渲染;未渲染的页以安静的 3:4 占位块保持位置。PDF.js 官方 TextLayerBuilder 在与画面重合的文字层上管理选区边界和复制文本规范化。配套样式不高亮空白换行;对齐同时考虑 PDF 页面单位、页面旋转与视口宽度变化,页面释放时取消两层渲染。纯图片 PDF 不包含可选取的文字。代码预览使用 tertiary 色的语言名称和带提示的复制图标;换行仍由文档工具栏控制。默认显示源码行号,但复制文本不包含行号;纯文本与代码使用相同字号和行高。代码直接坐在分栏自身的背景上,而不是会话卡片的填充色;复制条与占满剩余高度的内部滚动区相邻,因此横纵滚动条都从复制控件下方开始。
66
+ 首次读取及渲染器准备(包括 Office 转换)共用居中的 28px ongoing `StateDot`,下方显示本地化状态文字“文档渲染中...”。状态向辅助技术提供相同的名称,并遵循减少动态效果偏好。追加文本页时使用紧凑的行内转圈,同时保留已显示的内容。PDF 正文仅在 PDF 预览挂载时加载包内 `client.pdf.js` chunk;PDF.js、Worker 源码和内嵌支持数据不会进入启动 `client.js`。PDF 与转换后的 Word/PowerPoint 页面组成纵向序列,页间距与四周留白均为 12px,露出当前主题的文档背景色;适应宽度会预留此留白,页面在接近视口时惰性渲染;未渲染的页以安静的 3:4 占位块保持位置。PDF.js 官方 TextLayerBuilder 在与画面重合的文字层上管理选区边界和复制文本规范化。两种主题均使用半透明蓝色选区,画布保留文档文字,空白换行不高亮;对齐同时考虑 PDF 页面单位、页面旋转与视口宽度变化,页面释放时取消两层渲染。纯图片 PDF 不包含可选取的文字。代码预览使用 tertiary 色的语言名称和带提示的复制图标;换行仍由文档工具栏控制。默认显示源码行号,但复制文本不包含行号;纯文本与代码使用相同字号和行高。代码直接坐在分栏自身的背景上,而不是会话卡片的填充色;复制条与占满剩余高度的内部滚动区相邻,因此横纵滚动条都从复制控件下方开始。
65
67
 
66
68
  <a id="excel-preview"></a>
67
69
  ## Excel 预览
68
70
 
69
- 直接在浏览器中打开 `.xlsx`、`.xls`、`.csv` 和 `.tsv`,支持工作表标签、单元格选择、复制和只读公式栏。XLSX 保留字体、纯色填充、边框、数字格式、富文本、合并单元格、行列尺寸、隐藏行列及工作表,以及冻结标题。XLS 保留已保存的值、公式、数字格式、合并及可用的行列元数据;不支持字体、边框和冻结窗格。工作簿显示已保存的公式结果而不重新计算;缺少的结果保持为空,公式栏旁的紧凑提示会标记显示结果可能不完整或不准确的工作簿。工作簿视图填满预览面板,并随面板尺寸变化自动调整,无需重新加载工作表或选择状态。工作表标签从左侧边缘开始排列;标签溢出时可用触控板横向手势或左右按钮滚动,缩放控件独立占位。表格控件在应用的明暗两种主题下均保持浅色背景和深色文字。触控板的像素位移可同时平移表格的横纵两个方向,包括斜向平移,移动距离跟随手势;冻结标题保持固定。隐藏选区统计栏及无效的工作表菜单箭头。冻结标题在滚动时保持固定,不显示冻结分隔线和拖拽条。表格预览不调用 Office 转换服务。
71
+ 直接在浏览器中打开 `.xlsx`、`.xls`、`.csv` 和 `.tsv`,支持工作表标签、单元格选择、复制和只读公式栏。XLSX 保留字体、纯色填充、边框、数字格式、富文本、合并单元格、行列尺寸、隐藏行列及工作表,以及冻结标题。XLS 保留已保存的值、公式、数字格式、合并及可用的行列元数据;不支持字体、边框和冻结窗格。工作簿显示已保存的公式结果而不重新计算;缺少的结果保持为空,公式栏旁的紧凑提示会标记显示结果可能不完整或不准确的工作簿。工作簿视图填满预览面板,并随面板尺寸变化自动调整,无需重新加载工作表或选择状态。工作表标签从左侧边缘开始排列;标签溢出时可用触控板横向手势或左右按钮滚动,缩放控件独立占位。表格控件在应用的明暗两种主题下均保持浅色背景和深色文字。触控板的像素位移可同时平移表格的横纵两个方向,包括斜向平移,移动距离跟随手势;冻结标题保持固定。到达工作表边缘后反向移动,仍会保留下一次手势的位移。隐藏选区统计栏及无效的工作表菜单箭头。冻结标题在滚动时保持固定,不显示冻结分隔线和拖拽条。表格预览不调用 Office 转换服务。
70
72
 
71
73
  XLSX 预览在解析前从内存副本中移除 DrawingML 部件,并忽略工作表的绘图引用。原文件和工作表 XML 保持不变。表格上方的提示列出实际检测到但未展示的图表、图片、形状和条件格式,并建议使用系统应用打开工作簿。未检测到这些内容的文件不显示此提示;公式提示保持独立。
72
74
 
73
- CSV 和 TSV 默认使用表格查看器,也可选择纯文本。两者分别以逗号和制表符分隔字段,支持引号内分隔符、转义引号、多行字段、空字段和不等长行。首行仍作为数据。值保持为字面字符串,包括前导零、日期、布尔值和类似公式的文本。文本文件支持 UTF-8 或带 BOM 的 UTF-16;无效编码会显示转换提示。引号字段格式错误会使表格预览失败,不会静默丢弃数据。
75
+ CSV 和 TSV 默认使用表格查看器,也可选择纯文本;CSV 还提供带语法高亮的 Code 预览。两者分别以逗号和制表符分隔字段,支持引号内分隔符、转义引号、多行字段、空字段和不等长行。首行仍作为数据。值保持为字面字符串,包括前导零、日期、布尔值和类似公式的文本。文本文件支持 UTF-8 或带 BOM 的 UTF-16;无效编码会显示转换提示。引号字段格式错误会使表格预览失败,不会静默丢弃数据。
74
76
 
75
77
  在同一个 `ui-sidebar-documentpreview` 条目上配置 `excel`。这些限制补充 Host 的完整文件读取限制,但不限制浏览器进程内存或解压分配量。
76
78
 
@@ -112,6 +114,8 @@ Office 注册、加载、缓存和字体提示位于 `src/client/office/`。注
112
114
 
113
115
  Office Remote 通过 Connection 的 multipart 二进制传输返回原生 `Uint8Array` PDF。渲染器以只读方式借用保留的字节,并在传给 Worker 前复制。
114
116
 
117
+ 页面刷新快捷键复用所选预览的重载操作,包括旧请求失效与滚动位置保留。头部重载 Tooltip 和 ARIA 组合随有效快捷键绑定更新。
118
+
115
119
  </details>
116
120
 
117
121
  <a id="navigation"></a>
@@ -28117,7 +28117,7 @@ window.__ModuleLoader__.load({
28117
28117
  return stringify(rnds);
28118
28118
  }
28119
28119
  //#endregion
28120
- //#region ../../../node_modules/.pnpm/@fortune-sheet+core@1.0.4_patch_hash=886223a70a0cf76d4fa174608852763fe76bbdc9374db127665024c8c150dd68/node_modules/@fortune-sheet/core/dist/index.esm.js
28120
+ //#region ../../../node_modules/.pnpm/@fortune-sheet+core@1.0.4_patch_hash=8791a230763dbf853fd65d627c68c31de37209992851377855e16cf08ea70532/node_modules/@fortune-sheet/core/dist/index.esm.js
28121
28121
  function _arrayLikeToArray$1(r, a) {
28122
28122
  (null == a || a > r.length) && (a = r.length);
28123
28123
  for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
@@ -119987,6 +119987,8 @@ window.__ModuleLoader__.load({
119987
119987
  if (ctx.allowEdit === false && e.deltaMode === 0) {
119988
119988
  scrollbarX.scrollLeft += e.deltaX;
119989
119989
  scrollbarY.scrollTop += e.deltaY;
119990
+ ctx.scrollLeft = scrollbarX.scrollLeft;
119991
+ ctx.scrollTop = scrollbarY.scrollTop;
119990
119992
  e.preventDefault();
119991
119993
  return;
119992
119994
  }
@@ -133666,7 +133668,7 @@ window.__ModuleLoader__.load({
133666
133668
  }
133667
133669
  //#endregion
133668
133670
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-sidebar-documentpreview/src/client/excel/ExcelBody.module.css.mjs
133669
- const css = "._3HaaOG_body{white-space:normal;height:100%;min-height:0;font-family:var(--dsw-font,sans-serif);flex-direction:column;display:flex;overflow:hidden}._3HaaOG_workbook{color-scheme:light;color:canvastext;flex:1;min-width:0;min-height:0;position:relative}._3HaaOG_workbook .fortune-stat-area,._3HaaOG_workbook .luckysheet-sheets-item-function,._3HaaOG_workbook .fortune-cols-freeze-handle,._3HaaOG_workbook .fortune-rows-freeze-handle{display:none}._3HaaOG_workbook .luckysheet-sheet-area div.luckysheet-sheets-item{padding-right:5px}._3HaaOG_workbook .luckysheet-sheet-area{padding:0}._3HaaOG_workbook #luckysheet-sheet-content{flex:1;min-width:0}._3HaaOG_workbook .fortune-sheettab-container{flex:1;min-width:0;max-width:100%}._3HaaOG_workbook .fortune-sheettab-container .fortune-sheettab-container-c{overscroll-behavior-x:contain;scrollbar-width:none;overflow:auto hidden}._3HaaOG_workbook .fortune-sheettab-scroll,._3HaaOG_workbook .fortune-sheet-area-right{flex:none}._3HaaOG_workbook .fortune-fx-input-container{min-width:0}._3HaaOG_workbook .fortune-fx-input{white-space:nowrap;scrollbar-width:none;min-width:0;overflow:auto hidden}._3HaaOG_notice{color:var(--dsw-alias-state-warn-label);background:var(--dsw-alias-state-warn-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);overflow-wrap:anywhere;flex:none;align-items:flex-start;gap:8px;padding:8px 12px;line-height:1.5;display:flex}._3HaaOG_notice>svg{flex:none;margin-top:2px}._3HaaOG_formulaWarning{z-index:3;width:20px;height:20px;color:var(--dsw-alias-state-warn-label);background:0 0;border:0;border-radius:4px;padding:3px;display:flex;position:absolute;top:4px;left:142px}._3HaaOG_formulaWarning:hover,._3HaaOG_formulaWarning:focus-visible{background:var(--dsw-alias-state-warn-tertiary);outline:none}._3HaaOG_withFormulaWarning .fortune-fx-input{padding-left:24px}._3HaaOG_status{height:100%;color:var(--dsw-alias-label-secondary);justify-content:center;align-items:center;gap:8px;padding:16px;display:flex}";
133671
+ const css = "._3HaaOG_body{white-space:normal;height:100%;min-height:0;font-family:var(--dsw-font,sans-serif);flex-direction:column;display:flex;overflow:hidden}._3HaaOG_workbook{color-scheme:light;color:canvastext;flex:1;min-width:0;min-height:0;position:relative}._3HaaOG_workbook .fortune-stat-area,._3HaaOG_workbook .luckysheet-sheets-item-function,._3HaaOG_workbook .fortune-cols-freeze-handle,._3HaaOG_workbook .fortune-rows-freeze-handle{display:none}._3HaaOG_workbook .luckysheet-sheet-area div.luckysheet-sheets-item{padding-right:5px}._3HaaOG_workbook .luckysheet-sheet-area{padding:0}._3HaaOG_workbook #luckysheet-sheet-content{flex:1;min-width:0}._3HaaOG_workbook .fortune-sheettab-container{flex:1;min-width:0;max-width:100%}._3HaaOG_workbook .fortune-sheettab-container .fortune-sheettab-container-c{overscroll-behavior-x:contain;scrollbar-width:none;overflow:auto hidden}._3HaaOG_workbook .fortune-sheettab-scroll,._3HaaOG_workbook .fortune-sheet-area-right{flex:none}._3HaaOG_workbook .fortune-fx-input-container{min-width:0}._3HaaOG_workbook .fortune-fx-input{white-space:nowrap;scrollbar-width:none;min-width:0;overflow:auto hidden}._3HaaOG_notice{color:var(--dsw-alias-state-warn-label);background:var(--dsw-alias-state-warn-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);overflow-wrap:anywhere;flex:none;align-items:flex-start;gap:8px;padding:8px 12px;line-height:1.5;display:flex}._3HaaOG_notice>svg{flex:none;margin-top:2px}._3HaaOG_formulaWarning{z-index:3;width:20px;height:20px;color:var(--dsw-alias-state-warn-label);border-radius:var(--dsw-radius-sm);background:0 0;border:0;padding:3px;display:flex;position:absolute;top:4px;left:142px}._3HaaOG_formulaWarning:hover,._3HaaOG_formulaWarning:focus-visible{background:var(--dsw-alias-state-warn-tertiary);outline:none}._3HaaOG_withFormulaWarning .fortune-fx-input{padding-left:24px}._3HaaOG_status{height:100%;color:var(--dsw-alias-label-secondary);justify-content:center;align-items:center;gap:8px;padding:16px;display:flex}";
133670
133672
  const tagId = "@deepseek-ai/dsh-client-ui-sidebar-documentpreview/ExcelBody.module.css";
133671
133673
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
133672
133674
  const tag = document.createElement("style");
@@ -133693,7 +133695,7 @@ window.__ModuleLoader__.load({
133693
133695
  * @param props - Complete workbook bytes, limits, and locale.
133694
133696
  * @returns An isolated spreadsheet surface with cancellable loading.
133695
133697
  */
133696
- function ExcelBody({ content, format, limits, t }) {
133698
+ function ExcelBody({ content, format, limits, t, loading }) {
133697
133699
  const data = content.kind === "bytes" ? content.data : void 0;
133698
133700
  const [state, setState] = (0, react.useState)();
133699
133701
  const [attempt, setAttempt] = (0, react.useState)(0);
@@ -133740,13 +133742,7 @@ window.__ModuleLoader__.load({
133740
133742
  role: "alert",
133741
133743
  children: t("invalid")
133742
133744
  });
133743
- if (state?.data !== data || state.format !== format) return (0, react_jsx_runtime.jsx)("span", {
133744
- className: ExcelBody_module_css_default.status,
133745
- role: "status",
133746
- "aria-label": t("loading"),
133747
- "data-document-loading": true,
133748
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" })
133749
- });
133745
+ if (state?.data !== data || state.format !== format) return loading;
133750
133746
  if ("error" in state) return (0, react_jsx_runtime.jsxs)("div", {
133751
133747
  className: ExcelBody_module_css_default.status,
133752
133748
  role: "alert",
package/lib/client.js CHANGED
@@ -132,12 +132,12 @@ window.__ModuleLoader__.load({
132
132
  }
133
133
  /**
134
134
  * Address a decoded absolute file path through the authenticated file route.
135
- * @param base - HTTP(S) application base, including its deployment prefix.
135
+ * @param base - HTTP(S) application base, including its deployment prefix, or `dsh-app://app/`.
136
136
  * @param path - Native file path; URL escapes in authored Markdown must already be decoded.
137
137
  * @returns File URL, or undefined for unsupported transports and non-absolute paths.
138
138
  */
139
139
  function fileMediaUrl(base, path) {
140
- if (!/^https?:/u.test(base) || !isAbsoluteWorkspacePath(path) || /^[/\\]{2}/u.test(path) || /[\u0000-\u001f\u007f]/u.test(path)) return void 0;
140
+ if (!/^https?:/u.test(base) && !base.startsWith("dsh-app://app/") || !isAbsoluteWorkspacePath(path) || /^[/\\]{2}/u.test(path) || /[\u0000-\u001f\u007f]/u.test(path)) return void 0;
141
141
  return new URL(`api/file?path=${encodeURIComponent(path)}`, base).href;
142
142
  }
143
143
  //#endregion
@@ -181,7 +181,7 @@ window.__ModuleLoader__.load({
181
181
  }
182
182
  //#endregion
183
183
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-sidebar-documentpreview/src/client/LoadingIndicator.module.css.mjs
184
- const css$9 = ".tKrPPq_loading{vertical-align:middle;white-space:normal;align-items:center;gap:8px;display:inline-flex}";
184
+ const css$9 = ".tKrPPq_loading{box-sizing:border-box;width:100%;height:100%;min-height:0;color:var(--dsw-alias-label-secondary);font-family:var(--dsw-font,sans-serif);font-size:var(--dsh-content-font-size,14px);text-align:center;white-space:normal;flex-direction:column;justify-content:center;align-items:center;gap:12px;padding:24px;line-height:1.5;display:flex}.tKrPPq_inline{vertical-align:middle;flex-direction:row;gap:8px;width:auto;height:auto;padding:0;display:inline-flex}";
185
185
  const tagId$9 = "@deepseek-ai/dsh-client-ui-sidebar-documentpreview/LoadingIndicator.module.css";
186
186
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$9) + "]") === null) {
187
187
  const tag = document.createElement("style");
@@ -190,21 +190,26 @@ window.__ModuleLoader__.load({
190
190
  tag.textContent = css$9;
191
191
  document.head.appendChild(tag);
192
192
  }
193
- var LoadingIndicator_module_css_default = { "loading": "tKrPPq_loading" };
193
+ var LoadingIndicator_module_css_default = {
194
+ "inline": "tKrPPq_inline",
195
+ "loading": "tKrPPq_loading"
196
+ };
194
197
  //#endregion
195
198
  //#region lib/types/client/LoadingIndicator.js
196
199
  /**
197
- * @param props - localized status label, carried as the accessible name with
198
- * no visible text, and optional placement style.
199
- * @returns an animated, accessible loading status.
200
+ * @param props - localized status label and compact inline placement for additional pages.
201
+ * @returns a centered document loading status or an accessible inline spinner.
200
202
  */
201
- function LoadingIndicator({ label, className }) {
202
- return (0, react_jsx_runtime.jsx)("span", {
203
- className: clsx(LoadingIndicator_module_css_default.loading, className),
203
+ function LoadingIndicator({ label, inline = false }) {
204
+ return (0, react_jsx_runtime.jsxs)("span", {
205
+ className: clsx(LoadingIndicator_module_css_default.loading, inline && LoadingIndicator_module_css_default.inline),
204
206
  role: "status",
205
207
  "aria-label": label,
206
208
  "data-document-loading": true,
207
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" })
209
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
210
+ state: "ongoing",
211
+ size: inline ? 14 : 28
212
+ }), !inline && (0, react_jsx_runtime.jsx)("span", { children: label })]
208
213
  });
209
214
  }
210
215
  //#endregion
@@ -483,7 +488,7 @@ window.__ModuleLoader__.load({
483
488
  }
484
489
  //#endregion
485
490
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-sidebar-documentpreview/src/client/TextPreview.module.css.mjs
486
- const css$8 = ".dhJKeW_preview{flex-direction:column;flex:auto;height:100%;min-height:0;display:flex}.dhJKeW_header{box-sizing:border-box;border-bottom:.5px solid var(--dsw-alias-border-l3);flex:none;align-items:center;gap:4px;height:38px;padding:0 6px 0 16px;display:flex}.dhJKeW_path{margin-right:12px}.dhJKeW_changed{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);border-bottom:.5px solid var(--dsw-alias-border-l1);flex:none;align-items:center;gap:10px;margin:0;padding:6px 10px;font-size:12px;display:flex}.dhJKeW_body{--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);min-height:0;color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size-secondary,13px);font-family:var(--dsw-font-mono,ui-monospace, monospace);white-space:pre;flex:auto;margin:0;padding:0;line-height:1.6;position:relative;overflow:auto}.dhJKeW_body::-webkit-scrollbar-track{margin:2px}.dhJKeW_body:has([data-code-preview]){flex-direction:column;display:flex;overflow:hidden}.dhJKeW_body:has([data-pdf-preview]){background:var(--dsw-alias-bg-document-preview)}.dhJKeW_wrap{white-space:pre-wrap;word-break:break-word}.dhJKeW_textDocument{box-sizing:border-box;min-width:100%;min-height:100%;padding:8px}.dhJKeW_page{font:var(--dsw-font-markdown-code-block);white-space:inherit;margin:0}.dhJKeW_line{padding:0 10px}.dhJKeW_lineTarget{background:var(--dsw-alias-interactive-bg-hover)}.dhJKeW_empty{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-secondary);font-size:var(--dsh-content-font-size-secondary,13px);font-family:var(--dsw-font-family);text-align:center;white-space:normal;flex-direction:column;justify-content:center;align-items:center;gap:16px;padding:0 24px;line-height:1.6;display:flex}.dhJKeW_empty:after{content:\"\";flex:0 12%}.dhJKeW_emptyIcon{opacity:.6;filter:grayscale();flex:none}.dhJKeW_emptyLine{margin:0}.dhJKeW_retry{height:32px;color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size-secondary,13px);border:.5px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:16px;flex:none;align-items:center;gap:6px;padding:0 14px 0 12px;font-family:inherit;display:inline-flex}.dhJKeW_retry:hover{background:var(--dsw-alias-interactive-bg-hover)}.dhJKeW_titleIcon{flex:none}.dhJKeW_statusLine{color:var(--dsw-alias-label-secondary);font-size:var(--dsh-content-font-size-secondary,13px);white-space:normal;align-items:center;gap:10px;margin:0;padding:6px 10px;line-height:1.6;display:flex}.dhJKeW_status{box-sizing:border-box;flex-direction:column;justify-content:center;align-items:center;gap:8px;height:100%;padding:12px 10px;display:flex}.dhJKeW_bodyLoading{box-sizing:border-box;justify-content:center;width:100%;height:100%}.dhJKeW_action{color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size-secondary,13px);font-family:var(--dsw-font,inherit);white-space:normal;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l2);cursor:pointer;border-radius:6px;padding:4px 10px}.dhJKeW_action:hover{background:var(--dsw-alias-bg-layer-3)}.dhJKeW_more{color:var(--dsw-alias-label-secondary);font-size:12px;font-family:var(--dsw-font,inherit);white-space:normal;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l2);cursor:pointer;border-radius:6px;margin:8px 10px;padding:4px 10px;display:block}.dhJKeW_more:hover:not(:disabled){color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3)}.dhJKeW_more:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.dhJKeW_tool{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:28px;flex:none;justify-content:center;align-items:center;padding:6px;line-height:1;display:inline-flex}.dhJKeW_tool svg{width:15px;height:15px}.dhJKeW_tool:hover,.dhJKeW_tool[data-textpreview-tool=auto-refresh][aria-pressed=true]{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.dhJKeW_viewerTool{width:auto;max-width:160px;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;flex:none;padding:0 6px;font-size:12px;overflow:hidden}";
491
+ const css$8 = ".dhJKeW_preview{flex-direction:column;flex:auto;height:100%;min-height:0;display:flex}.dhJKeW_header{box-sizing:border-box;border-bottom:.5px solid var(--dsw-alias-border-l3);flex:none;align-items:center;gap:4px;height:38px;padding:0 6px 0 16px;display:flex}.dhJKeW_path{margin-right:12px}.dhJKeW_changed{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);border-bottom:.5px solid var(--dsw-alias-border-l1);flex:none;align-items:center;gap:10px;margin:0;padding:6px 10px;font-size:12px;display:flex}.dhJKeW_body{--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);min-height:0;color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size-secondary,13px);font-family:var(--dsw-font-mono,ui-monospace, monospace);white-space:pre;flex:auto;margin:0;padding:0;line-height:1.6;position:relative;overflow:auto}.dhJKeW_body::-webkit-scrollbar-track{margin:2px}.dhJKeW_body:has([data-code-preview]){flex-direction:column;display:flex;overflow:hidden}.dhJKeW_body:has([data-pdf-preview]){background:var(--dsw-alias-bg-document-preview)}.dhJKeW_wrap{white-space:pre-wrap;word-break:break-word}.dhJKeW_textDocument{box-sizing:border-box;min-width:100%;min-height:100%;padding:8px}.dhJKeW_page{font:var(--dsw-font-markdown-code-block);white-space:inherit;margin:0}.dhJKeW_line{padding:0 10px}.dhJKeW_lineTarget{background:var(--dsw-alias-interactive-bg-hover)}.dhJKeW_empty{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-secondary);font-size:var(--dsh-content-font-size-secondary,13px);font-family:var(--dsw-font-family);text-align:center;white-space:normal;flex-direction:column;justify-content:center;align-items:center;gap:16px;padding:0 24px;line-height:1.6;display:flex}.dhJKeW_empty:after{content:\"\";flex:0 12%}.dhJKeW_emptyIcon{opacity:.6;filter:grayscale();flex:none}.dhJKeW_emptyLine{margin:0}.dhJKeW_retry{height:32px;color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size-secondary,13px);border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md);cursor:pointer;background:0 0;flex:none;align-items:center;gap:6px;padding:0 14px 0 12px;font-family:inherit;display:inline-flex}.dhJKeW_retry:hover{background:var(--dsw-alias-interactive-bg-hover)}.dhJKeW_titleIcon{flex:none}.dhJKeW_statusLine{color:var(--dsw-alias-label-secondary);font-size:var(--dsh-content-font-size-secondary,13px);white-space:normal;align-items:center;gap:10px;margin:0;padding:6px 10px;line-height:1.6;display:flex}.dhJKeW_status{box-sizing:border-box;flex-direction:column;justify-content:center;align-items:center;gap:8px;height:100%;padding:12px 10px;display:flex}.dhJKeW_action{color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size-secondary,13px);font-family:var(--dsw-font,inherit);white-space:normal;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-sm);cursor:pointer;padding:4px 10px}.dhJKeW_action:hover{background:var(--dsw-alias-bg-layer-3)}.dhJKeW_more{color:var(--dsw-alias-label-secondary);font-size:12px;font-family:var(--dsw-font,inherit);white-space:normal;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-sm);cursor:pointer;margin:8px 10px;padding:4px 10px;display:block}.dhJKeW_more:hover:not(:disabled){color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3)}.dhJKeW_more:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.dhJKeW_tool{width:28px;height:28px;color:var(--dsw-alias-label-secondary);border-radius:var(--dsw-radius-sm);cursor:pointer;background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:6px;line-height:1;display:inline-flex}.dhJKeW_tool svg{width:15px;height:15px}.dhJKeW_tool:hover,.dhJKeW_tool[data-textpreview-tool=auto-refresh][aria-pressed=true]{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.dhJKeW_viewerTool{width:auto;max-width:160px;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;flex:none;padding:0 6px;font-size:12px;overflow:hidden}";
487
492
  const tagId$8 = "@deepseek-ai/dsh-client-ui-sidebar-documentpreview/TextPreview.module.css";
488
493
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$8) + "]") === null) {
489
494
  const tag = document.createElement("style");
@@ -495,7 +500,6 @@ window.__ModuleLoader__.load({
495
500
  var TextPreview_module_css_default = {
496
501
  "action": "dhJKeW_action",
497
502
  "body": "dhJKeW_body",
498
- "bodyLoading": "dhJKeW_bodyLoading",
499
503
  "changed": "dhJKeW_changed",
500
504
  "empty": "dhJKeW_empty",
501
505
  "emptyIcon": "dhJKeW_emptyIcon",
@@ -732,6 +736,7 @@ window.__ModuleLoader__.load({
732
736
  signal,
733
737
  observedVersion
734
738
  ]);
739
+ (0, react.useEffect)(() => tab.actions.bindCommands({ refresh: reload }), [tab.actions, reload]);
735
740
  (0, react.useEffect)(() => {
736
741
  if (state?.autoRefresh && changed && current !== void 0 && !current.loading && meta.status === "live") reload();
737
742
  }, [
@@ -819,10 +824,7 @@ window.__ModuleLoader__.load({
819
824
  children: meta.status === "none" ? (0, react_jsx_runtime.jsx)("p", {
820
825
  className: TextPreview_module_css_default.statusLine,
821
826
  children: t("resourceUnavailable")
822
- }) : (0, react_jsx_runtime.jsx)(LoadingIndicator, {
823
- className: TextPreview_module_css_default.statusLine,
824
- label: t("loading")
825
- })
827
+ }) : (0, react_jsx_runtime.jsx)(LoadingIndicator, { label: t("loading") })
826
828
  });
827
829
  const next = loadedThrough + 1;
828
830
  const { name } = pathPartsOf(displayPath);
@@ -935,6 +937,7 @@ window.__ModuleLoader__.load({
935
937
  }),
936
938
  (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
937
939
  label: t("reload"),
940
+ shortcutKeys: tab.refreshShortcut?.keys,
938
941
  side: "bottom",
939
942
  delayMs: 500,
940
943
  children: (0, react_jsx_runtime.jsx)("button", {
@@ -942,6 +945,7 @@ window.__ModuleLoader__.load({
942
945
  className: TextPreview_module_css_default.tool,
943
946
  "aria-label": t("reload"),
944
947
  "data-textpreview-tool": "reload",
948
+ "aria-keyshortcuts": tab.refreshShortcut?.aria,
945
949
  onClick: reload,
946
950
  children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutlineRegular, {})
947
951
  })
@@ -963,10 +967,7 @@ window.__ModuleLoader__.load({
963
967
  if (mode === "text-pages" && current?.failure === void 0 && body.clientHeight > 0 && body.scrollTop + body.clientHeight >= body.scrollHeight - 1) loadNext();
964
968
  },
965
969
  children: [
966
- mode !== "renderer" && !hasContent && current?.failure === void 0 && (0, react_jsx_runtime.jsx)(LoadingIndicator, {
967
- className: clsx(TextPreview_module_css_default.statusLine, TextPreview_module_css_default.bodyLoading),
968
- label: t("loading")
969
- }),
970
+ mode !== "renderer" && !hasContent && current?.failure === void 0 && (0, react_jsx_runtime.jsx)(LoadingIndicator, { label: t("loading") }),
970
971
  content !== void 0 && renderSlot("sidebar.right.tab.document", {
971
972
  resourceAddress: tab.contentId,
972
973
  content,
@@ -1021,7 +1022,10 @@ window.__ModuleLoader__.load({
1021
1022
  disabled: current.loading,
1022
1023
  "data-textpreview-more": true,
1023
1024
  onClick: loadNext,
1024
- children: current.loading ? (0, react_jsx_runtime.jsx)(LoadingIndicator, { label: t("loading") }) : t("loadMore")
1025
+ children: current.loading ? (0, react_jsx_runtime.jsx)(LoadingIndicator, {
1026
+ inline: true,
1027
+ label: t("loading")
1028
+ }) : t("loadMore")
1025
1029
  })
1026
1030
  ]
1027
1031
  })
@@ -1444,7 +1448,7 @@ window.__ModuleLoader__.load({
1444
1448
  */
1445
1449
  /** Simplified Chinese dictionary and key-set source of truth. */
1446
1450
  const zh$7 = {
1447
- loading: "正在读取…",
1451
+ loading: "文档渲染中...",
1448
1452
  loadMore: "加载更多",
1449
1453
  changed: "文件已更新,当前显示为旧内容",
1450
1454
  reloadNow: "重新载入",
@@ -1469,7 +1473,7 @@ window.__ModuleLoader__.load({
1469
1473
  };
1470
1474
  /** English dictionary, checked against the Chinese key set. */
1471
1475
  const en$7 = {
1472
- loading: "Reading…",
1476
+ loading: "Rendering document...",
1473
1477
  loadMore: "Load more",
1474
1478
  changed: "The file has changed, showing the previous content.",
1475
1479
  reloadNow: "Reload",
@@ -1509,7 +1513,7 @@ window.__ModuleLoader__.load({
1509
1513
  * @param base - document base URI, including any deployment prefix.
1510
1514
  * @param documentPath - absolute source path reported by the Host, when available.
1511
1515
  * @param destination - authored Markdown image URL; query and fragment are not filename components.
1512
- * @returns an HTTP(S) file URL, or undefined for unsupported or malformed destinations.
1516
+ * @returns a Web or Desktop file URL, or undefined for unsupported or malformed destinations.
1513
1517
  */
1514
1518
  function markdownImageUrl(base, documentPath, destination) {
1515
1519
  const suffix = destination.search(/[?#]/u);
@@ -3940,7 +3944,7 @@ document.open();document.write(html);document.close();
3940
3944
  }
3941
3945
  //#endregion
3942
3946
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-sidebar-documentpreview/src/client/html/HtmlBody.module.css.mjs
3943
- const css$6 = ".HyIruq_frame{background:var(--dsw-alias-bg-base);border:none;width:100%;height:100%;min-height:240px;display:block}.HyIruq_status{color:var(--dsw-alias-label-secondary);white-space:normal;margin:0;padding:10px}.HyIruq_opening{box-sizing:border-box;justify-content:center;width:100%;min-height:100%}";
3947
+ const css$6 = ".HyIruq_frame{background:var(--dsw-alias-bg-base);border:none;width:100%;height:100%;min-height:240px;display:block}.HyIruq_status{color:var(--dsw-alias-label-secondary);white-space:normal;margin:0;padding:10px}";
3944
3948
  const tagId$6 = "@deepseek-ai/dsh-client-ui-sidebar-documentpreview/HtmlBody.module.css";
3945
3949
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$6) + "]") === null) {
3946
3950
  const tag = document.createElement("style");
@@ -3951,14 +3955,13 @@ document.open();document.write(html);document.close();
3951
3955
  }
3952
3956
  var HtmlBody_module_css_default = {
3953
3957
  "frame": "HyIruq_frame",
3954
- "opening": "HyIruq_opening",
3955
3958
  "status": "HyIruq_status"
3956
3959
  };
3957
3960
  //#endregion
3958
3961
  //#region lib/types/client/html/HtmlBody.js
3959
3962
  /** Static or interactive HTML in an opaque iframe, without parent application access. */
3960
3963
  /** One mounted file owns its root Blob; replacing content also replaces the browsing context. */
3961
- function HtmlFrame({ data, resourceAddress, readRelated, addResource, setResources, signal, t }) {
3964
+ function HtmlFrame({ data, resourceAddress, readRelated, addResource, setResources, signal, frameName, t }) {
3962
3965
  const [frame, setFrame] = (0, react.useState)();
3963
3966
  (0, react.useEffect)(() => {
3964
3967
  const controller = new AbortController();
@@ -4001,16 +4004,14 @@ document.open();document.write(html);document.close();
4001
4004
  setResources,
4002
4005
  signal
4003
4006
  ]);
4004
- if (frame?.data !== data || frame.readRelated !== readRelated) return (0, react_jsx_runtime.jsx)(LoadingIndicator, {
4005
- className: clsx(HtmlBody_module_css_default.status, HtmlBody_module_css_default.opening),
4006
- label: t("loading")
4007
- });
4007
+ if (frame?.data !== data || frame.readRelated !== readRelated) return (0, react_jsx_runtime.jsx)(LoadingIndicator, { label: t("loading") });
4008
4008
  if (frame.url === void 0) return (0, react_jsx_runtime.jsx)("p", {
4009
4009
  className: HtmlBody_module_css_default.status,
4010
4010
  role: "alert",
4011
4011
  children: t("failed")
4012
4012
  });
4013
4013
  return (0, react_jsx_runtime.jsx)("iframe", {
4014
+ name: frameName,
4014
4015
  className: HtmlBody_module_css_default.frame,
4015
4016
  src: frame.url,
4016
4017
  sandbox: "allow-scripts",
@@ -4030,8 +4031,10 @@ document.open();document.write(html);document.close();
4030
4031
  if (!interactivePreview) setResources([]);
4031
4032
  }, [interactivePreview, setResources]);
4032
4033
  if (content.kind !== "bytes") return null;
4034
+ const frameName = `dsh-sidebar-html-${tab.id}`;
4033
4035
  if (!interactivePreview) return (0, react_jsx_runtime.jsx)(BasicHtmlFrame, {
4034
4036
  data: content.data,
4037
+ frameName,
4035
4038
  t
4036
4039
  });
4037
4040
  return (0, react_jsx_runtime.jsx)(HtmlFrame, {
@@ -4039,13 +4042,14 @@ document.open();document.write(html);document.close();
4039
4042
  resourceAddress,
4040
4043
  readRelated,
4041
4044
  signal: tab.signal,
4045
+ frameName,
4042
4046
  addResource,
4043
4047
  setResources,
4044
4048
  t
4045
4049
  }, resourceAddress);
4046
4050
  }
4047
4051
  /** Static preview mounts a separate browsing context so a mode change retires running scripts. */
4048
- function BasicHtmlFrame({ data, t }) {
4052
+ function BasicHtmlFrame({ data, frameName, t }) {
4049
4053
  const html = (0, react.useMemo)(() => {
4050
4054
  try {
4051
4055
  return createBasicHtmlDocument(data);
@@ -4059,6 +4063,7 @@ document.open();document.write(html);document.close();
4059
4063
  children: t("failed")
4060
4064
  });
4061
4065
  return (0, react_jsx_runtime.jsx)("iframe", {
4066
+ name: frameName,
4062
4067
  className: HtmlBody_module_css_default.frame,
4063
4068
  srcDoc: html,
4064
4069
  sandbox: "",
@@ -4072,14 +4077,14 @@ document.open();document.write(html);document.close();
4072
4077
  const zh$5 = {
4073
4078
  title: "HTML",
4074
4079
  frame: "HTML 文档预览",
4075
- loading: "正在读取…",
4080
+ loading: "文档渲染中...",
4076
4081
  failed: "无法预览这份 HTML 文档"
4077
4082
  };
4078
4083
  /** English dictionary with the same keys as the Chinese dictionary. */
4079
4084
  const en$5 = {
4080
4085
  title: "HTML",
4081
4086
  frame: "HTML document preview",
4082
- loading: "Reading…",
4087
+ loading: "Rendering document...",
4083
4088
  failed: "This HTML document could not be previewed."
4084
4089
  };
4085
4090
  //#endregion
@@ -4193,7 +4198,7 @@ document.open();document.write(html);document.close();
4193
4198
  const DEFAULT_ZOOM = FIT_WIDTH;
4194
4199
  //#endregion
4195
4200
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-sidebar-documentpreview/src/client/zoom/ZoomControls.module.css.mjs
4196
- const css$5 = ".lyqg2a_panel{z-index:2;inset-inline-start:50%;box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);opacity:0;pointer-events:none;will-change:opacity, transform;border-radius:12px;align-items:center;gap:2px;padding:4px 6px;font-size:12px;line-height:18px;transition:opacity .16s ease-in,transform .16s cubic-bezier(.4,0,1,1);display:flex;position:absolute;bottom:14px;transform:translate(-50%,16px)scale(.98);box-shadow:0 8px 24px light-dark(#0000001a,#00000060),0 2px 5px light-dark(#00000009,#00000035)}.lyqg2a_visible{opacity:1;pointer-events:auto;transition:opacity .14s ease-out,transform .18s cubic-bezier(.22,1,.36,1);transform:translate(-50%)scale(1)}.lyqg2a_controlAnchor{display:flex}.lyqg2a_zoomButton{flex:none;width:28px;padding:0}.lyqg2a_percent{font-variant-numeric:tabular-nums;justify-content:center;align-items:center;gap:2px;min-width:58px;padding-inline:6px;display:inline-flex}.lyqg2a_zoomMenu{min-width:112px}@media (hover:none),(pointer:coarse){.lyqg2a_panel{opacity:1;pointer-events:auto;transform:translate(-50%)scale(1)}}@media (prefers-reduced-motion:reduce){.lyqg2a_panel,.lyqg2a_visible{transition-duration:.01ms}}";
4201
+ const css$5 = ".lyqg2a_panel{z-index:2;inset-inline-start:50%;box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-lg);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);opacity:0;pointer-events:none;will-change:opacity, transform;align-items:center;gap:2px;padding:4px 6px;font-size:12px;line-height:18px;transition:opacity .16s ease-in,transform .16s cubic-bezier(.4,0,1,1);display:flex;position:absolute;bottom:14px;transform:translate(-50%,16px)scale(.98);box-shadow:0 8px 24px light-dark(#0000001a,#00000060),0 2px 5px light-dark(#00000009,#00000035)}.lyqg2a_visible{opacity:1;pointer-events:auto;transition:opacity .14s ease-out,transform .18s cubic-bezier(.22,1,.36,1);transform:translate(-50%)scale(1)}.lyqg2a_controlAnchor{display:flex}.lyqg2a_zoomButton{flex:none;width:28px;padding:0}.lyqg2a_percent{font-variant-numeric:tabular-nums;justify-content:center;align-items:center;gap:2px;min-width:58px;padding-inline:6px;display:inline-flex}.lyqg2a_zoomMenu{min-width:112px}@media (hover:none),(pointer:coarse){.lyqg2a_panel{opacity:1;pointer-events:auto;transform:translate(-50%)scale(1)}}@media (prefers-reduced-motion:reduce){.lyqg2a_panel,.lyqg2a_visible{transition-duration:.01ms}}";
4197
4202
  const tagId$5 = "@deepseek-ai/dsh-client-ui-sidebar-documentpreview/ZoomControls.module.css";
4198
4203
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
4199
4204
  const tag = document.createElement("style");
@@ -4607,7 +4612,7 @@ document.open();document.write(html);document.close();
4607
4612
  const zoomSurfaceClass = ZoomViewport_module_css_default.surface;
4608
4613
  //#endregion
4609
4614
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-sidebar-documentpreview/src/client/image/ImageBody.module.css.mjs
4610
- const css$3 = ".JFRUHG_frame{box-sizing:border-box;width:100%;min-width:100%;height:max-content;min-height:100%;font-family:var(--dsw-font,sans-serif);white-space:normal;padding:12px;display:flex}.JFRUHG_surface{flex:none;max-width:none;margin:auto;display:block}.JFRUHG_surface[hidden]{display:none}.JFRUHG_image{user-select:none;border-radius:8px;width:100%;max-width:none;height:auto;max-height:none;display:block}.JFRUHG_status{box-sizing:border-box;width:100%;min-height:100%;color:var(--dsw-alias-label-secondary);white-space:normal;justify-content:center;align-items:center;margin:0;padding:10px;font-size:13px;line-height:1.5;display:flex}";
4615
+ const css$3 = ".JFRUHG_frame{box-sizing:border-box;width:100%;min-width:100%;height:max-content;min-height:100%;font-family:var(--dsw-font,sans-serif);white-space:normal;padding:12px;display:flex}.JFRUHG_frame:has([data-document-loading]){height:100%}.JFRUHG_surface{flex:none;max-width:none;margin:auto;display:block}.JFRUHG_surface[hidden]{display:none}.JFRUHG_image{border-radius:var(--dsw-radius-md);user-select:none;width:100%;max-width:none;height:auto;max-height:none;display:block}.JFRUHG_status{box-sizing:border-box;width:100%;min-height:100%;color:var(--dsw-alias-label-secondary);white-space:normal;justify-content:center;align-items:center;margin:0;padding:10px;font-size:13px;line-height:1.5;display:flex}";
4611
4616
  const tagId$3 = "@deepseek-ai/dsh-client-ui-sidebar-documentpreview/ImageBody.module.css";
4612
4617
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
4613
4618
  const tag = document.createElement("style");
@@ -4695,10 +4700,7 @@ document.open();document.write(html);document.close();
4695
4700
  role: "alert",
4696
4701
  children: t("unsupported")
4697
4702
  });
4698
- if (source?.data !== data || source.mediaType !== mediaType) return (0, react_jsx_runtime.jsx)(LoadingIndicator, {
4699
- className: ImageBody_module_css_default.status,
4700
- label: t("loading")
4701
- });
4703
+ if (source?.data !== data || source.mediaType !== mediaType) return (0, react_jsx_runtime.jsx)(LoadingIndicator, { label: t("loading") });
4702
4704
  if (source.kind === "failed") return (0, react_jsx_runtime.jsx)("p", {
4703
4705
  className: ImageBody_module_css_default.status,
4704
4706
  role: "alert",
@@ -4740,10 +4742,7 @@ document.open();document.write(html);document.close();
4740
4742
  className: ImageBody_module_css_default.frame,
4741
4743
  "data-image-preview": true,
4742
4744
  children: [
4743
- state === "loading" && (0, react_jsx_runtime.jsx)(LoadingIndicator, {
4744
- className: ImageBody_module_css_default.status,
4745
- label: t("loading")
4746
- }),
4745
+ state === "loading" && (0, react_jsx_runtime.jsx)(LoadingIndicator, { label: t("loading") }),
4747
4746
  state === "failed" && (0, react_jsx_runtime.jsx)("p", {
4748
4747
  className: ImageBody_module_css_default.status,
4749
4748
  role: "alert",
@@ -4801,7 +4800,7 @@ document.open();document.write(html);document.close();
4801
4800
  ...zoomZh,
4802
4801
  title: "图片",
4803
4802
  preview: "图片预览:{name}",
4804
- loading: "正在读取…",
4803
+ loading: "文档渲染中...",
4805
4804
  failed: "无法显示这张图片",
4806
4805
  unsupported: "图片预览需要完整文件内容"
4807
4806
  };
@@ -4810,7 +4809,7 @@ document.open();document.write(html);document.close();
4810
4809
  ...zoomEn,
4811
4810
  title: "Image",
4812
4811
  preview: "Image preview: {name}",
4813
- loading: "Reading…",
4812
+ loading: "Rendering document...",
4814
4813
  failed: "This image could not be displayed.",
4815
4814
  unsupported: "Image preview requires the complete file contents."
4816
4815
  };
@@ -4888,12 +4887,13 @@ document.open();document.write(html);document.close();
4888
4887
  * @returns the deferred PDF renderer.
4889
4888
  */
4890
4889
  function LazyPdfBody(props) {
4890
+ const loading = (0, react_jsx_runtime.jsx)(LoadingIndicator, { label: props.t("loading") });
4891
4891
  return (0, react_jsx_runtime.jsx)(react.Suspense, {
4892
- fallback: (0, react_jsx_runtime.jsx)(LoadingIndicator, {
4893
- className: TextPreview_module_css_default.status,
4894
- label: props.t("loading")
4895
- }),
4896
- children: (0, react_jsx_runtime.jsx)(LoadedPdfBody, { ...props })
4892
+ fallback: loading,
4893
+ children: (0, react_jsx_runtime.jsx)(LoadedPdfBody, {
4894
+ ...props,
4895
+ loading
4896
+ })
4897
4897
  });
4898
4898
  }
4899
4899
  //#endregion
@@ -4937,7 +4937,7 @@ document.open();document.write(html);document.close();
4937
4937
  ...zoomZh,
4938
4938
  title: "PDF",
4939
4939
  pageImage: "PDF 第 {page} 页",
4940
- loading: "正在读取…",
4940
+ loading: "文档渲染中...",
4941
4941
  rendering: "正在绘制页面…",
4942
4942
  failed: "无法显示 PDF:{message}",
4943
4943
  password: "此 PDF 需要密码,暂不支持预览",
@@ -4950,7 +4950,7 @@ document.open();document.write(html);document.close();
4950
4950
  ...zoomEn,
4951
4951
  title: "PDF",
4952
4952
  pageImage: "PDF page {page}",
4953
- loading: "Reading…",
4953
+ loading: "Rendering document...",
4954
4954
  rendering: "Rendering page…",
4955
4955
  failed: "Cannot display PDF: {message}",
4956
4956
  password: "This PDF requires a password; password-protected previews are not supported.",
@@ -5102,7 +5102,7 @@ document.open();document.write(html);document.close();
5102
5102
  /** Office preview copy and Host render configuration guidance. */
5103
5103
  const zh$1 = {
5104
5104
  title: "Office 文档",
5105
- loading: "正在读取…",
5105
+ loading: "文档渲染中...",
5106
5106
  retry: "重试",
5107
5107
  viewMissingFonts: "缺失 {count} 种字体,点击查看",
5108
5108
  missingFontsTitle: "缺失的字体",
@@ -5120,7 +5120,7 @@ document.open();document.write(html);document.close();
5120
5120
  /** English translations checked against the Chinese key set. */
5121
5121
  const en$1 = {
5122
5122
  title: "Office document",
5123
- loading: "Reading…",
5123
+ loading: "Rendering document...",
5124
5124
  retry: "Retry",
5125
5125
  viewMissingFonts: "Missing fonts: {count}. Click to view.",
5126
5126
  missingFontsTitle: "Missing fonts",
@@ -5394,10 +5394,7 @@ document.open();document.write(html);document.close();
5394
5394
  ]
5395
5395
  });
5396
5396
  }
5397
- if (file === void 0) return (0, react_jsx_runtime.jsx)(LoadingIndicator, {
5398
- className: TextPreview_module_css_default.statusLine,
5399
- label: t("loading")
5400
- });
5397
+ if (file === void 0) return (0, react_jsx_runtime.jsx)(LoadingIndicator, { label: t("loading") });
5401
5398
  return (0, react_jsx_runtime.jsx)("div", {
5402
5399
  className: OfficeBody_module_css_default.body,
5403
5400
  children: props.renderSlot("sidebar.right.tab.document.office.pdf", {
@@ -5418,7 +5415,7 @@ document.open();document.write(html);document.close();
5418
5415
  }
5419
5416
  //#endregion
5420
5417
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-sidebar-documentpreview/src/client/office/FontNotice.module.css.mjs
5421
- const css = ".JqwYuG_anchor{flex:none;display:inline-flex}.JqwYuG_anchor .JqwYuG_warning,.JqwYuG_anchor .JqwYuG_warning:hover{color:var(--dsw-alias-state-warn-label)}.JqwYuG_anchor .JqwYuG_warning:hover,.JqwYuG_anchor .JqwYuG_warning[aria-expanded=true]{background:var(--dsw-alias-state-warn-tertiary)}.JqwYuG_panel{--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);z-index:100;box-sizing:border-box;width:min(340px,100vw - 24px);max-height:calc(100dvh - 24px);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);box-shadow:var(--dsw-elevation-prominent);border:0;border-radius:12px;padding:16px;font-size:13px;line-height:1.6;position:fixed;overflow:auto}.JqwYuG_panelHeader{justify-content:space-between;align-items:center;gap:12px;display:flex}.JqwYuG_panelHeader h3{margin:0;font-size:14px;font-weight:600}.JqwYuG_description{color:var(--dsw-alias-label-secondary);margin:8px 0 16px}.JqwYuG_count{color:var(--dsw-alias-label-tertiary);margin:0 0 6px;font-size:12px}.JqwYuG_fonts{overflow-wrap:anywhere;margin:0;padding:0;list-style:none}.JqwYuG_fonts li{border-top:.5px solid var(--dsw-alias-border-l2);padding:8px 0}";
5418
+ const css = ".JqwYuG_anchor{flex:none;display:inline-flex}.JqwYuG_anchor .JqwYuG_warning,.JqwYuG_anchor .JqwYuG_warning:hover{color:var(--dsw-alias-state-warn-label)}.JqwYuG_anchor .JqwYuG_warning:hover,.JqwYuG_anchor .JqwYuG_warning[aria-expanded=true]{background:var(--dsw-alias-state-warn-tertiary)}.JqwYuG_panel{--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);z-index:100;box-sizing:border-box;width:min(340px,100vw - 24px);max-height:calc(100dvh - 24px);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border-radius:var(--dsw-radius-lg);box-shadow:var(--dsw-elevation-prominent);border:0;padding:16px;font-size:13px;line-height:1.6;position:fixed;overflow:auto}.JqwYuG_panelHeader{justify-content:space-between;align-items:center;gap:12px;display:flex}.JqwYuG_panelHeader h3{margin:0;font-size:14px;font-weight:600}.JqwYuG_description{color:var(--dsw-alias-label-secondary);margin:8px 0 16px}.JqwYuG_count{color:var(--dsw-alias-label-tertiary);margin:0 0 6px;font-size:12px}.JqwYuG_fonts{overflow-wrap:anywhere;margin:0;padding:0;list-style:none}.JqwYuG_fonts li{border-top:.5px solid var(--dsw-alias-border-l2);padding:8px 0}";
5422
5419
  const tagId = "@deepseek-ai/dsh-client-ui-sidebar-documentpreview/FontNotice.module.css";
5423
5420
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
5424
5421
  const tag = document.createElement("style");
@@ -5798,14 +5795,13 @@ document.open();document.write(html);document.close();
5798
5795
  */
5799
5796
  function LazyExcelBody(props) {
5800
5797
  const format = excelFormat(hostFileOf(props.resourceAddress).path);
5798
+ const loading = (0, react_jsx_runtime.jsx)(LoadingIndicator, { label: props.t("loading") });
5801
5799
  return (0, react_jsx_runtime.jsx)(react.Suspense, {
5802
- fallback: (0, react_jsx_runtime.jsx)(LoadingIndicator, {
5803
- className: TextPreview_module_css_default.status,
5804
- label: props.t("loading")
5805
- }),
5800
+ fallback: loading,
5806
5801
  children: (0, react_jsx_runtime.jsx)(LoadedExcelBody, {
5807
5802
  ...props,
5808
- format
5803
+ format,
5804
+ loading
5809
5805
  })
5810
5806
  });
5811
5807
  }
@@ -5815,7 +5811,7 @@ document.open();document.write(html);document.close();
5815
5811
  const zh = {
5816
5812
  title: "表格",
5817
5813
  language: "zh",
5818
- loading: "正在打开表格…",
5814
+ loading: "文档渲染中...",
5819
5815
  invalid: "无法打开此表格。请检查文件格式、内容或密码保护。",
5820
5816
  tooLarge: "此表格超过预览大小限制。",
5821
5817
  timeout: "打开表格超时。请缩小文件后重试。",
@@ -5833,7 +5829,7 @@ document.open();document.write(html);document.close();
5833
5829
  const en = {
5834
5830
  title: "Spreadsheet",
5835
5831
  language: "en",
5836
- loading: "Opening spreadsheet…",
5832
+ loading: "Rendering document...",
5837
5833
  invalid: "This spreadsheet could not be opened. Check its format, contents, or password protection.",
5838
5834
  tooLarge: "This workbook exceeds the preview size limit.",
5839
5835
  timeout: "Opening this workbook timed out. Try a smaller file.",
@@ -6862,9 +6858,9 @@ document.open();document.write(html);document.close();
6862
6858
  apply$6(ctx);
6863
6859
  apply$5(ctx);
6864
6860
  apply$4(ctx);
6865
- apply$3(ctx);
6866
6861
  apply$2(ctx, config.office);
6867
6862
  apply$1(ctx, config.excel);
6863
+ apply$3(ctx);
6868
6864
  }
6869
6865
  //#endregion
6870
6866
  exports.apply = apply;
package/lib/client.pdf.js CHANGED
@@ -32376,7 +32376,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
32376
32376
  }
32377
32377
  //#endregion
32378
32378
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-sidebar-documentpreview/src/client/pdf/PdfBody.module.css.mjs
32379
- const css = ".E0GbtG_body{box-sizing:border-box;background:var(--dsw-alias-bg-document-preview);width:100%;min-width:100%;min-height:0;font-family:var(--dsw-font,sans-serif);white-space:normal;flex-direction:column;display:flex;overflow:visible}.E0GbtG_page{box-sizing:border-box;width:100%;min-width:0;overflow-x:visible}.E0GbtG_placeholder{aspect-ratio:3/4;background:var(--dsw-alias-bg-skeleton);width:100%}.E0GbtG_canvas{width:100%;max-width:none;height:auto;margin-inline:auto;display:block}.E0GbtG_surface{max-width:none;box-shadow:var(--dsw-elevation-prominent);margin-inline:auto;position:relative}.E0GbtG_surface[hidden]{display:none}.E0GbtG_text{position:absolute;inset:0;overflow:clip}.E0GbtG_text .textLayer{text-align:initial;letter-spacing:normal;word-spacing:normal;text-size-adjust:none;forced-color-adjust:none;transform-origin:0 0;caret-color:canvastext;z-index:0;--text-scale-factor:calc(var(--total-scale-factor) * var(--min-font-size));--min-font-size-inv:calc(1 / var(--min-font-size));line-height:1;position:absolute;inset:0;overflow:clip}.E0GbtG_text .textLayer[data-main-rotation=\"90\"]{transform:rotate(90deg)translateY(-100%)}.E0GbtG_text .textLayer[data-main-rotation=\"180\"]{transform:rotate(180deg)translate(-100%,-100%)}.E0GbtG_text .textLayer[data-main-rotation=\"270\"]{transform:rotate(270deg)translate(-100%)}.E0GbtG_text :is(span,br){color:#0000;white-space:pre;cursor:text;transform-origin:0 0;user-select:text;position:absolute}.E0GbtG_text .textLayer>:not(.markedContent),.E0GbtG_text .markedContent span:not(.markedContent){z-index:1;--font-height:0;--scale-x:1;--rotate:0deg;font-size:calc(var(--text-scale-factor) * var(--font-height));transform:rotate(var(--rotate)) scaleX(var(--scale-x)) scale(var(--min-font-size-inv))}.E0GbtG_text .markedContent{display:contents}.E0GbtG_text ::selection{background:var(--dsw-alias-interactive-bg-hover-accent);color:#0000}.E0GbtG_text br::selection{background:0 0}.E0GbtG_text .textLayer .endOfContent{z-index:0;cursor:default;user-select:none;display:block;position:absolute;inset:100% 0 0}.E0GbtG_text .selecting .endOfContent{top:0}.E0GbtG_status{color:var(--dsw-alias-label-secondary);align-items:center;gap:8px;padding:10px;font-size:13px;line-height:1.5;display:flex}.E0GbtG_body .E0GbtG_status{color:var(--dsw-alias-label-document-preview)}.E0GbtG_opening{box-sizing:border-box;justify-content:center;width:100%;min-height:100%}";
32379
+ const css = ".E0GbtG_body{box-sizing:border-box;background:var(--dsw-alias-bg-document-preview);width:100%;min-width:100%;min-height:100%;font-family:var(--dsw-font,sans-serif);white-space:normal;flex-direction:column;gap:12px;padding:12px;display:flex;overflow:visible}[data-document-zoom-mode=fixed] .E0GbtG_body{width:max-content}.E0GbtG_page{box-sizing:border-box;width:100%;min-width:0;overflow-x:visible}.E0GbtG_placeholder{aspect-ratio:3/4;background:var(--dsw-alias-bg-skeleton);width:100%}.E0GbtG_canvas{width:100%;max-width:none;height:auto;margin-inline:auto;display:block}.E0GbtG_surface{max-width:none;box-shadow:var(--dsw-elevation-prominent);margin-inline:auto;position:relative}.E0GbtG_surface[hidden]{display:none}.E0GbtG_text{position:absolute;inset:0;overflow:clip}.E0GbtG_text .textLayer{text-align:initial;letter-spacing:normal;word-spacing:normal;text-size-adjust:none;forced-color-adjust:none;transform-origin:0 0;caret-color:canvastext;z-index:0;--text-scale-factor:calc(var(--total-scale-factor) * var(--min-font-size));--min-font-size-inv:calc(1 / var(--min-font-size));line-height:1;position:absolute;inset:0;overflow:clip}.E0GbtG_text .textLayer[data-main-rotation=\"90\"]{transform:rotate(90deg)translateY(-100%)}.E0GbtG_text .textLayer[data-main-rotation=\"180\"]{transform:rotate(180deg)translate(-100%,-100%)}.E0GbtG_text .textLayer[data-main-rotation=\"270\"]{transform:rotate(270deg)translate(-100%)}.E0GbtG_text :is(span,br){color:#0000;white-space:pre;cursor:text;transform-origin:0 0;user-select:text;position:absolute}.E0GbtG_text .textLayer>:not(.markedContent),.E0GbtG_text .markedContent span:not(.markedContent){z-index:1;--font-height:0;--scale-x:1;--rotate:0deg;font-size:calc(var(--text-scale-factor) * var(--font-height));transform:rotate(var(--rotate)) scaleX(var(--scale-x)) scale(var(--min-font-size-inv))}.E0GbtG_text .markedContent{display:contents}.E0GbtG_text ::selection{background:var(--dsw-alias-bg-document-selection);color:#0000}.E0GbtG_text br::selection{background:0 0}.E0GbtG_text .textLayer .endOfContent{z-index:0;cursor:default;user-select:none;display:block;position:absolute;inset:100% 0 0}.E0GbtG_text .selecting .endOfContent{top:0}.E0GbtG_status{color:var(--dsw-alias-label-secondary);align-items:center;gap:8px;padding:10px;font-size:13px;line-height:1.5;display:flex}.E0GbtG_body .E0GbtG_status{color:var(--dsw-alias-label-document-preview)}";
32380
32380
  const tagId = "@deepseek-ai/dsh-client-ui-sidebar-documentpreview/PdfBody.module.css";
32381
32381
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
32382
32382
  const tag = document.createElement("style");
@@ -32388,7 +32388,6 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
32388
32388
  var PdfBody_module_css_default = {
32389
32389
  "body": "E0GbtG_body",
32390
32390
  "canvas": "E0GbtG_canvas",
32391
- "opening": "E0GbtG_opening",
32392
32391
  "page": "E0GbtG_page",
32393
32392
  "placeholder": "E0GbtG_placeholder",
32394
32393
  "status": "E0GbtG_status",
@@ -32402,7 +32401,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
32402
32401
  const FIT_WIDTH = { kind: "fit-width" };
32403
32402
  /**
32404
32403
  * Present a PDF with tab-local viewing preferences and component-owned rendering resources.
32405
- * @param props - complete bytes and framework-owned tab/store/locale seats.
32404
+ * @param props - complete bytes, framework-owned tab/store/locale seats, and main-bundle loading content.
32406
32405
  * @returns the PDF reader.
32407
32406
  */
32408
32407
  function PdfBody(props) {
@@ -32475,13 +32474,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
32475
32474
  role: "alert",
32476
32475
  children: t("unsupported")
32477
32476
  });
32478
- if (load?.data !== data) return (0, react_jsx_runtime.jsx)("span", {
32479
- className: `${PdfBody_module_css_default.status} ${PdfBody_module_css_default.opening}`,
32480
- role: "status",
32481
- "aria-label": t("loading"),
32482
- "data-document-loading": true,
32483
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" })
32484
- });
32477
+ if (load?.data !== data) return props.loading;
32485
32478
  if (load.kind === "failed") return (0, react_jsx_runtime.jsxs)("div", {
32486
32479
  className: PdfBody_module_css_default.status,
32487
32480
  role: "alert",
@@ -32511,6 +32504,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
32511
32504
  return (0, react_jsx_runtime.jsx)(ZoomViewport, {
32512
32505
  preference,
32513
32506
  intrinsicWidth: pageWidth,
32507
+ horizontalInset: 24,
32514
32508
  labels,
32515
32509
  signal: tab.signal,
32516
32510
  scrollportRef: props.scrollportRef,
@@ -1,12 +1,11 @@
1
1
  /** Shared indeterminate loading feedback for document reads and rendering. */
2
2
  import type { ReactNode } from 'react';
3
3
  /**
4
- * @param props - localized status label, carried as the accessible name with
5
- * no visible text, and optional placement style.
6
- * @returns an animated, accessible loading status.
4
+ * @param props - localized status label and compact inline placement for additional pages.
5
+ * @returns a centered document loading status or an accessible inline spinner.
7
6
  */
8
- export declare function LoadingIndicator({ label, className }: {
7
+ export declare function LoadingIndicator({ label, inline }: {
9
8
  label: string;
10
- className?: string | undefined;
9
+ inline?: boolean;
11
10
  }): ReactNode;
12
11
  //# sourceMappingURL=LoadingIndicator.d.ts.map
@@ -8,9 +8,10 @@ import type { ExcelLimits } from './model.ts';
8
8
  export type ExcelBodyProps = DocumentPreviewProps & PropsLocale<'sidebarExcel'> & {
9
9
  readonly limits: ExcelLimits;
10
10
  };
11
- /** Lazily loaded renderer input with the filename-derived parser choice. */
11
+ /** Lazily loaded renderer input with the parser choice and main-bundle loading content. */
12
12
  export type LoadedExcelBodyProps = ExcelBodyProps & {
13
13
  readonly format: ExcelFormat;
14
+ readonly loading: ReactNode;
14
15
  };
15
16
  /**
16
17
  * Load the browser spreadsheet renderer for every registered format.
@@ -7,5 +7,5 @@ import type { LoadedExcelBodyProps } from './LazyExcelBody.tsx';
7
7
  * @param props - Complete workbook bytes, limits, and locale.
8
8
  * @returns An isolated spreadsheet surface with cancellable loading.
9
9
  */
10
- export declare function ExcelBody({ content, format, limits, t }: LoadedExcelBodyProps): ReactNode;
10
+ export declare function ExcelBody({ content, format, limits, t, loading }: LoadedExcelBodyProps): ReactNode;
11
11
  //# sourceMappingURL=excel.d.ts.map
@@ -3,7 +3,7 @@
3
3
  * @param base - document base URI, including any deployment prefix.
4
4
  * @param documentPath - absolute source path reported by the Host, when available.
5
5
  * @param destination - authored Markdown image URL; query and fragment are not filename components.
6
- * @returns an HTTP(S) file URL, or undefined for unsupported or malformed destinations.
6
+ * @returns a Web or Desktop file URL, or undefined for unsupported or malformed destinations.
7
7
  */
8
8
  export declare function markdownImageUrl(base: string, documentPath: string | undefined, destination: string): string | undefined;
9
9
  //# sourceMappingURL=path-images.d.ts.map
@@ -22,8 +22,10 @@ export interface PdfBodyInjected {
22
22
  export type PdfBodyProps = DocumentPreviewProps & PropsLocale<'sidebarPdf'> & PropsStore<PdfStore> & PdfBodyInjected;
23
23
  /**
24
24
  * Present a PDF with tab-local viewing preferences and component-owned rendering resources.
25
- * @param props - complete bytes and framework-owned tab/store/locale seats.
25
+ * @param props - complete bytes, framework-owned tab/store/locale seats, and main-bundle loading content.
26
26
  * @returns the PDF reader.
27
27
  */
28
- export declare function PdfBody(props: PdfBodyProps): ReactNode;
28
+ export declare function PdfBody(props: PdfBodyProps & {
29
+ readonly loading: ReactNode;
30
+ }): ReactNode;
29
31
  //# sourceMappingURL=pdf.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-sidebar-documentpreview",
3
3
  "description": "Extensible Sidebar previews for Office documents, spreadsheets, Markdown, code, images, PDF, HTML, and plain text",
4
- "version": "0.1.7-rc.1",
4
+ "version": "0.2.0-rc.1",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -62,25 +62,25 @@
62
62
  "react-dom": "^18.2.0",
63
63
  "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
64
64
  "@deepseek-ai/cordis": "~4.0.4",
65
- "@deepseek-ai/dsh-api-gateway": "0.1.7-rc.1",
66
- "@deepseek-ai/dsh-api-remotes": "0.1.7-rc.1",
67
- "@deepseek-ai/dsh-api-workspace-files": "0.1.7-rc.1",
68
- "@deepseek-ai/dsh-client-connection": "0.1.7-rc.1",
69
- "@deepseek-ai/dsh-client-locale": "0.1.7-rc.1",
70
- "@deepseek-ai/dsh-client-resources": "0.1.7-rc.1",
71
- "@deepseek-ai/dsh-client-ui-dockkit": "0.1.7-rc.1",
72
- "@deepseek-ai/dsh-client-test-runtime": "0.1.7-rc.1",
73
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.1",
74
- "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-rc.1",
75
- "@deepseek-ai/dsh-client-ui-session": "0.1.7-rc.1",
76
- "@deepseek-ai/dsh-client-store": "0.1.7-rc.1",
77
- "@deepseek-ai/dsh-client-ui-sidebar-right": "0.1.7-rc.1",
78
- "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.1",
79
- "@deepseek-ai/dsh-office-to-pdf": "0.1.7-rc.1",
80
- "@deepseek-ai/dsh-host-webserver": "0.1.7-rc.1",
81
- "@deepseek-ai/dsh-session": "0.1.7-rc.1",
82
- "@deepseek-ai/dsh-util-workspace-path": "0.1.7-rc.1",
83
- "@deepseek-ai/dsh-client-ui-settings": "0.1.7-rc.1"
65
+ "@deepseek-ai/dsh-api-gateway": "0.2.0-rc.1",
66
+ "@deepseek-ai/dsh-api-remotes": "0.2.0-rc.1",
67
+ "@deepseek-ai/dsh-api-workspace-files": "0.2.0-rc.1",
68
+ "@deepseek-ai/dsh-client-connection": "0.2.0-rc.1",
69
+ "@deepseek-ai/dsh-client-locale": "0.2.0-rc.1",
70
+ "@deepseek-ai/dsh-client-store": "0.2.0-rc.1",
71
+ "@deepseek-ai/dsh-client-resources": "0.2.0-rc.1",
72
+ "@deepseek-ai/dsh-client-test-runtime": "0.2.0-rc.1",
73
+ "@deepseek-ai/dsh-client-ui-dockkit": "0.2.0-rc.1",
74
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.1",
75
+ "@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.1",
76
+ "@deepseek-ai/dsh-client-ui-session": "0.2.0-rc.1",
77
+ "@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.1",
78
+ "@deepseek-ai/dsh-client-ui-sidebar-right": "0.2.0-rc.1",
79
+ "@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.1",
80
+ "@deepseek-ai/dsh-office-to-pdf": "0.2.0-rc.1",
81
+ "@deepseek-ai/dsh-host-webserver": "0.2.0-rc.1",
82
+ "@deepseek-ai/dsh-session": "0.2.0-rc.1",
83
+ "@deepseek-ai/dsh-util-workspace-path": "0.2.0-rc.1"
84
84
  },
85
85
  "files": [
86
86
  "lib/index.js",