@deepseek-ai/dsh-client-ui-layout 0.1.5-rc.2 → 0.1.6-alpha.2

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
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/client/ui-layout/README.md
5
- README.md: 4fe19fb9ec0a549dc76ca311d0564cbe86c9f5f9
6
- README.zh.md: 7a61e7808ffb3d81214388a2792a901ced8d9564
5
+ README.md: 582c5fbea271caf0f45f9ee22c10d21f7412bf38
6
+ README.zh.md: 14e3f429284c5c3a519fa47e1156a510b7271f91
package/README.md CHANGED
@@ -29,6 +29,8 @@ The root slot composes the sidebar, main content, and right column. The sidebar
29
29
 
30
30
  Global panels occupy the root-scoped `main` keyed slot; `conversation` is the reserved key for the Conversation. `ctx.layout.selectPanel(id)` selects a registered panel, and `null` selects the Conversation without changing the current Session. No global panel is registered by the shipped composition.
31
31
 
32
+ Windows Electron's `data-windows-titlebar` marker reserves the caption height above all columns and removes the collapsed sidebar rail. Only the content area's top-left corner has a 16px radius; the other corners and the internal divider remain square. The frame publishes `--dsh-windows-content-radius` and `--dsh-windows-sidebar-width` for ui-sidebar-right's fullscreen corner and sidebar clearance. Ordinary Web documents do not receive the marker; macOS retains its separate layout.
33
+
32
34
  ### Theme presentation
33
35
 
34
36
  The presenter consumes resolved theme snapshots and projects them onto the document: `html { color-scheme }` for native UA chrome, `body[data-ds-dark-theme]` from the active color scheme, the theme's alias tokens and `--dsh-content-font-size` as inline variables on body, and one owned `<meta name="theme-color">` whose content follows the computed body background. Disposing the presenter removes its metadata node with its other global writes.
@@ -93,4 +95,4 @@ None.
93
95
 
94
96
  </details>
95
97
 
96
- **Runtime invariant:** No companion is published. The shell viewing-state store behind ctx.layout emits no cordis events; clamp and track sequencing is asserted directly by this package's columns and service specs.
98
+ **Runtime invariant:** No companion is published. The shell viewing-state store behind `ctx.layout` emits no Cordis events; clamp and track sequencing is asserted directly by this package's columns and service specs.
package/README.zh.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "Web GUI 的外壳布局:三栏 AppFrame——其右栏是贴边面板的轨道——面板几何服务与主题呈现;供窗口外观的用户与维护者阅读。"
2
+ description: "Web GUI 的外壳布局:三栏 AppFrame(右栏作为贴边面板的轨道)、面板几何服务与主题呈现;供窗口外壳的使用者与维护者阅读。"
3
3
  kind: "package-reference"
4
4
  ---
5
5
 
@@ -25,13 +25,15 @@ kind: "package-reference"
25
25
  <a id="use-this-package"></a>
26
26
  ## 使用本包
27
27
 
28
- 本插件在 root slot 组合侧栏、中央内容与右栏。左栏为264~420px,默认280px,收起后保留56px;窗口低于1024px时自动收起,打开右栏也会收起手动展开的左栏。右栏首次打开使用窗口宽度的45%,之后保留用户像素偏好,上限为70%;中栏不足400px时先把右栏压到300px,仍不足则通知占用方收起,最后才继续压缩中栏。拖拽跟手且无过渡延迟,关闭或全屏时不显示右栏拖拽区。
28
+ 本插件在 root slot 中组合侧边栏、主内容和右栏。侧边栏宽度为 264~420px,默认为 280px,收起后保留 56px 控制栏;窗口宽度低于 1024px 时自动收起,打开右侧面板也会收起手动展开的侧边栏。右侧面板首次打开时使用视口宽度的 45%,之后保留用户的像素宽度偏好,上限为 70%。为给中栏保留 400px,框架先将右侧面板缩减至 300px,再报告空间不足,使占用方将其关闭,最后才进一步压缩中栏。拖动没有过渡延迟;右侧手柄在关闭或全屏时不显示。
29
29
 
30
30
  全局面板占据 root 作用域的 `main` keyed slot;`conversation` 是为会话界面保留的 key。`ctx.layout.selectPanel(id)` 选中已注册面板,`null` 则选中会话界面,但不改变当前会话。默认组合不注册任何全局面板。
31
31
 
32
+ Windows Electron 的 `data-windows-titlebar` 标记在所有列上方预留顶栏高度,并移除收起后的侧栏轨道。内容区仅左上角保留 16px 圆角,其余角和内部交界处保持直角。框架发布 `--dsh-windows-content-radius` 和 `--dsh-windows-sidebar-width`,供 ui-sidebar-right 的全屏圆角及侧栏避让使用。普通 Web 文档不会获得该标记;macOS 保留其独立布局。
33
+
32
34
  ### 主题呈现
33
35
 
34
- 呈现器消费解析后的主题快照,并投影到 document:`html { color-scheme }` 驱动原生 UA 控件,依据当前配色方案设置 `body[data-ds-dark-theme]`,把主题的别名 token 与 `--dsh-content-font-size` 设为 body 上的内联变量,并持有一个 `<meta name="theme-color">`,其内容随计算后的 body 背景色更新。释放呈现器时,它会连同其他全局写入一起移除自己的元数据节点。
36
+ 呈现器消费解析后的主题快照,并投影到 document:`html { color-scheme }` 驱动原生 UA 控件,依据当前配色方案设置 `body[data-ds-dark-theme]`,把主题的别名 token 与 `--dsh-content-font-size` 设为 body 上的内联变量,并持有一个 `<meta name="theme-color">`,其内容随计算后的 body 背景色更新。对呈现器执行 dispose(资源释放)时,它会连同其他全局写入一起移除自己的元数据节点。
35
37
 
36
38
  -----
37
39
 
@@ -41,9 +43,9 @@ kind: "package-reference"
41
43
  <details>
42
44
  <summary>实现细节——点击展开</summary>
43
45
 
44
- `selectPanel(id)` 在改变选中态前检查实时 `main` 注册表;缺失的 key 会抛错并保留当前面板。`beginNavigation()` 为异步 UI 导航返回 abort signal。后续调用、有效面板选择(包括重复选择)或布局释放会中止该 signal,但不取消底层会话创建。消费者在提交导航或搬移草稿前检查 signal。
46
+ `selectPanel(id)` 在改变选中态前检查实时 `main` 注册表;缺失的 key 会抛错并保留当前面板。`beginNavigation()` 为异步 UI 导航返回 abort signal。后续调用、有效面板选择(包括重复选择)或布局释放会中止该 signal,但不取消底层会话创建。消费方在提交导航或搬移草稿前检查 signal。
45
47
 
46
- 一次注册声明四个子slot并绑定 `ctx.layout` 的 `selectPanel`、`toggleSidebar`、`openRightbar(track, fullscreen)` 与 `closeRightbar`。同一个 root 存储把 `panelInfo` 选中态与 `layoutInfo` 测量、宽度偏好、呈现报告分开。`usePanelInfo` 订阅引用稳定的选中态对象,AppFrame 订阅引用稳定的布局对象。`rightbar` 的owner参数为实际 `width`、`viewportWidth` 与普通呈现的 `canShow`;占用方在空间不足时执行确定性的收起,变宽不自行重新展开。全屏隐藏宽度手柄,但不自行释放占用方要求保留的轨道。AppFrame 保持各列容器挂载。右栏的 root 控制器仅在选中会话界面时,经 `SessionProvider` 渲染 `rightbar.session`;内容卸载时的报告释放列宽。独立的标题组件仅在会话界面可见时使用所选会话标题,以构建配置的产品标题或本地化 `common.brand.localBuild` 为回退值;语言变化会更新该回退值。主题呈现器是第二个 effect:从解析后的快照做纯 DOM 写入——初始状态经 getter 读取一次,此后仅事件驱动,不经过 React。它先应用调色板、字号与 token 变量,再把渲染出的背景测量为唯一的颜色依据。 全屏呈现禁用网格和手柄过渡;占用方完全覆盖框架后才报告新的列宽。 退出全屏时,框架先保持无过渡并安装目标布局:关闭移除右轨道,恢复保留右轨道。后续普通几何操作恢复正常过渡。
48
+ 一次注册声明四个子 slot,并绑定 `ctx.layout` 的 `selectPanel`、`toggleSidebar`、`openRightbar(track, fullscreen)` 与 `closeRightbar`。同一个 root 存储把 `panelInfo` 选中态与 `layoutInfo` 测量、宽度偏好、呈现报告分开。`usePanelInfo` 订阅引用稳定的选中态对象,AppFrame 订阅引用稳定的布局对象。`rightbar` owner 提供实际 `width`、`viewportWidth`,以及表示能否以普通模式呈现的 `canShow`;占用方在空间不足时执行确定性的收起,变宽不自行重新展开。全屏隐藏宽度手柄,但不自行释放占用方要求保留的轨道。AppFrame 保持各列容器挂载。右栏的 root 控制器仅在选中会话界面时,经 `SessionProvider` 渲染 `rightbar.session`;内容卸载时的报告释放轨道。独立的标题组件仅在会话界面可见时使用所选会话标题,以构建配置的产品标题或本地化 `common.brand.localBuild` 为回退值;语言变化会更新该回退值。主题呈现器是第二个 effect:从解析后的快照做纯 DOM 写入——初始状态经 getter 读取一次,此后仅事件驱动,不经过 React。它先应用调色板、字号与 token 变量,再把渲染出的背景测量为唯一的颜色依据。全屏呈现禁用网格和手柄过渡;占用方完全覆盖框架后才报告新的列布局。退出全屏时,框架先保持无过渡并安装目标布局:关闭移除右轨道,恢复保留右轨道。后续普通几何操作恢复正常过渡。
47
49
 
48
50
  </details>
49
51
 
@@ -78,9 +80,9 @@ kind: "package-reference"
78
80
 
79
81
  这些限制界定了当前布局行为。它们是当前包约束,不是通用窗口管理器对比或任务积压。
80
82
 
81
- - **面板几何是瞬时状态**——重新加载会恢复侧栏默认值并隐藏右侧面板;每个拖出的宽度都是一份框架级偏好,不是按 Session 的事实。
82
- - **极窄窗口**——右栏关闭后,中栏仍可能小于400px;左侧56px控制栏保留。
83
- - **轨道与面板沿同一条曲线运动**——框架的轨道过渡和占位方的滑入读取同一组时长与缓动变量;占位方若自用一套,挤压时面板边缘就会与对话边缘脱开。
83
+ - **面板几何是瞬时状态**——重新加载会恢复侧栏默认值并隐藏右侧面板;拖动设置的宽度是整个框架共用的一份偏好,而非每个会话各自的属性。
84
+ - **极窄窗口**——右侧面板关闭后,中栏仍可能小于 400px;左侧 56px 控制栏仍会保留。
85
+ - **轨道与面板沿同一条曲线运动**——框架的轨道过渡和占用方的滑入读取同一组时长与缓动变量;占用方若自用一套,挤压时面板边缘就会与会话界面的边缘脱开。
84
86
  - **挤压重排期间无滚动锚定**——布局变化可能移动读者的视口。
85
87
 
86
88
  <a id="dev-note"></a>
@@ -93,4 +95,4 @@ kind: "package-reference"
93
95
 
94
96
  </details>
95
97
 
96
- **运行时不变式:** 不发布伴生入口。`ctx.layout` 后的 viewing-state store 不发出 Cordis 事件;clamp 与轨道的时序由本包的 columns 与 service 规格直接断言。
98
+ **运行时不变式:** 不发布伴生入口。外壳中 `ctx.layout` 背后的浏览状态存储不发出 Cordis 事件;clamp 与轨道的时序由本包各栏与服务规格直接断言。
package/lib/client.js CHANGED
@@ -30,11 +30,13 @@ window.__ModuleLoader__.load({
30
30
  * @param viewport - available frame width in px.
31
31
  * @param sidebar - sidebar width preference in px (0 = closed).
32
32
  * @param rightbar - requested right panel width in px (0 = no track).
33
+ * @param collapsedWidth - track width of the closed sidebar; the default keeps
34
+ * the icon rail, 0 hides the column entirely (macOS desktop).
33
35
  * @returns actual widths after shrinking or removing the right track; only
34
36
  * without that track may the center fall below its minimum, down to zero.
35
37
  */
36
- function computeColumns(viewport, sidebar, rightbar) {
37
- const s = sidebar === 0 ? 56 : clampWidth(sidebar, 264, 420);
38
+ function computeColumns(viewport, sidebar, rightbar, collapsedWidth = 56) {
39
+ const s = sidebar === 0 ? collapsedWidth : clampWidth(sidebar, 264, 420);
38
40
  const available = viewport - s - 400;
39
41
  const r = rightbar === 0 || available < 300 ? 0 : Math.min(available, clampWidth(rightbar, 300, viewport * RIGHTBAR_MAX_RATIO));
40
42
  return {
@@ -55,7 +57,7 @@ window.__ModuleLoader__.load({
55
57
  function DocumentTitle({ useSessions, usePanelInfo, productTitle }) {
56
58
  const showSessionTitle = usePanelInfo((info) => info.activePanelId === null);
57
59
  const title = useSessions((state) => {
58
- const current = state.current;
60
+ const current = Object.values(state.byId).find((session) => (session.retainedBy.mainView ?? 0) > 0)?.id;
59
61
  return !showSessionTitle || current === void 0 ? void 0 : state.byId[current]?.title;
60
62
  });
61
63
  (0, react.useEffect)(() => {
@@ -68,7 +70,7 @@ window.__ModuleLoader__.load({
68
70
  }
69
71
  //#endregion
70
72
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-layout/src/client/AppFrame.module.css.mjs
71
- const css = ".pI_x6G_frame{background:var(--dsw-alias-bg-base);height:100%;transition:grid-template-columns var(--ds-transition-duration-slow) var(--ds-ease-in-out);grid-template-rows:100%;display:grid;position:relative;overflow:hidden}.pI_x6G_frame[data-dragging]{transition:none}@media (prefers-reduced-motion:reduce){.pI_x6G_frame{transition:none}}.pI_x6G_sidebarCol{background:var(--dsw-specific-sidebar-fill);border-right:.5px solid var(--dsw-alias-border-l3);min-width:0;overflow:hidden}.pI_x6G_centerCol{flex-direction:column;min-width:0;display:flex;overflow:hidden}.pI_x6G_handle{cursor:col-resize;z-index:11;touch-action:none;width:8px;transition:left var(--ds-transition-duration-slow) var(--ds-ease-in-out);margin-left:-4px;position:absolute;top:0;bottom:0}.pI_x6G_frame[data-dragging] .pI_x6G_handle,.pI_x6G_frame[data-rightbar-fullscreen],.pI_x6G_frame[data-rightbar-fullscreen] .pI_x6G_handle,.pI_x6G_frame[data-rightbar-instant],.pI_x6G_frame[data-rightbar-instant] .pI_x6G_handle{transition:none}@media (prefers-reduced-motion:reduce){.pI_x6G_handle{transition:none}}.pI_x6G_rightbarCol{min-width:0;position:relative;overflow:visible}.pI_x6G_overlayLayer{z-index:20;pointer-events:none;position:absolute;inset:0}.pI_x6G_overlayLayer>*{pointer-events:auto}";
73
+ const css = ".pI_x6G_frame{background:var(--dsw-alias-bg-base);height:100%;transition:grid-template-columns var(--ds-transition-duration-slow) var(--ds-ease-in-out);grid-template-rows:100%;display:grid;position:relative;overflow:hidden}.pI_x6G_frame[data-dragging]{transition:none}[data-windows-titlebar] .pI_x6G_frame{--dsh-windows-content-radius:16px;box-sizing:border-box;padding-top:var(--dsh-windows-titlebar-height);background:var(--dsw-specific-sidebar-fill);grid-template-rows:minmax(0,1fr)}[data-windows-titlebar] .pI_x6G_centerCol{background:var(--dsw-alias-bg-base);border-radius:var(--dsh-windows-content-radius) 0 0 0;corner-shape:round}[data-windows-titlebar] .pI_x6G_frame:before{content:\"\";height:var(--dsh-windows-titlebar-height);background:var(--dsw-specific-sidebar-fill);-webkit-app-region:drag;position:absolute;inset:0 0 auto}[data-windows-titlebar] .pI_x6G_sidebarCol{border-right:none}[data-windows-titlebar] .pI_x6G_handle{top:var(--dsh-windows-titlebar-height)}@media (prefers-reduced-motion:reduce){.pI_x6G_frame{transition:none}}.pI_x6G_sidebarCol{background:var(--dsw-specific-sidebar-fill);border-right:.5px solid var(--dsw-alias-border-l3);min-width:0;overflow:hidden}.pI_x6G_centerCol{flex-direction:column;min-width:0;display:flex;overflow:hidden}[data-platform=darwin] .pI_x6G_frame{background:0 0}[data-platform=darwin] .pI_x6G_sidebarCol{background:color-mix(in srgb, var(--dsw-specific-sidebar-fill) 60%, transparent);border-right:none}[data-platform=darwin] .pI_x6G_centerCol{background:var(--dsw-alias-bg-base);border-left:.5px solid var(--dsw-alias-border-l3)}[data-platform=darwin] [data-sidebar-collapsed] .pI_x6G_centerCol{border-left:none}.pI_x6G_handle{cursor:col-resize;z-index:11;touch-action:none;width:8px;transition:left var(--ds-transition-duration-slow) var(--ds-ease-in-out);margin-left:-4px;position:absolute;top:0;bottom:0}.pI_x6G_frame[data-dragging] .pI_x6G_handle,.pI_x6G_frame[data-rightbar-fullscreen],.pI_x6G_frame[data-rightbar-fullscreen] .pI_x6G_handle,.pI_x6G_frame[data-rightbar-instant],.pI_x6G_frame[data-rightbar-instant] .pI_x6G_handle{transition:none}@media (prefers-reduced-motion:reduce){.pI_x6G_handle{transition:none}}.pI_x6G_rightbarCol{min-width:0;position:relative;overflow:visible}.pI_x6G_overlayLayer{z-index:20;pointer-events:none;position:absolute;inset:0}.pI_x6G_overlayLayer>*{pointer-events:auto}";
72
74
  const tagId = "@deepseek-ai/dsh-client-ui-layout/AppFrame.module.css";
73
75
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
74
76
  const tag = document.createElement("style");
@@ -234,8 +236,9 @@ window.__ModuleLoader__.load({
234
236
  const sidebarCollapsed = narrow ? !layoutInfo.narrowExpanded : layoutInfo.sidebar === 0;
235
237
  const sidebarPreference = sidebarCollapsed ? 0 : layoutInfo.sidebar === 0 ? 280 : layoutInfo.sidebar;
236
238
  const rightbarPreference = layoutInfo.rightbar ?? viewport * .45;
237
- const normal = computeColumns(viewport, !layoutInfo.rightbarShown && narrow ? 0 : sidebarPreference, rightbarPreference);
238
- const cols = computeColumns(viewport, sidebarPreference, layoutInfo.rightbarTrack ? rightbarPreference : 0);
239
+ const collapsedWidth = document.documentElement.dataset.platform === "darwin" || document.documentElement.hasAttribute("data-windows-titlebar") ? 0 : 56;
240
+ const normal = computeColumns(viewport, !layoutInfo.rightbarShown && narrow ? 0 : sidebarPreference, rightbarPreference, collapsedWidth);
241
+ const cols = computeColumns(viewport, sidebarPreference, layoutInfo.rightbarTrack ? rightbarPreference : 0, collapsedWidth);
239
242
  const colsRef = (0, react.useRef)(cols);
240
243
  colsRef.current = cols;
241
244
  const rightbarWidth = (0, react.useRef)(normal.rightbar);
@@ -277,7 +280,10 @@ window.__ModuleLoader__.load({
277
280
  return (0, react_jsx_runtime.jsxs)("div", {
278
281
  ref: frameRef,
279
282
  className: AppFrame_module_css_default.frame,
280
- style: { gridTemplateColumns: `${cols.sidebar}px minmax(0, 1fr) ${cols.rightbar}px` },
283
+ style: {
284
+ ...document.documentElement.hasAttribute("data-windows-titlebar") ? { "--dsh-windows-sidebar-width": `${cols.sidebar}px` } : {},
285
+ gridTemplateColumns: `${cols.sidebar}px minmax(0, 1fr) ${cols.rightbar}px`
286
+ },
281
287
  "data-sidebar-collapsed": sidebarCollapsed || void 0,
282
288
  "data-rightbar-collapsed": cols.rightbar === 0 || void 0,
283
289
  "data-rightbar-fullscreen": layoutInfo.rightbarFullscreen || void 0,
@@ -441,6 +447,14 @@ window.__ModuleLoader__.load({
441
447
  //#region lib/types/client/theme-presenter.js
442
448
  /** Body attribute selecting the dark base palette in the token stylesheets. */
443
449
  const DARK_ATTRIBUTE = "data-ds-dark-theme";
450
+ /**
451
+ * Root attribute publishing the theme source (`light`, `dark`, or `system`)
452
+ * for host shells that mirror it into native window chrome (the Electron
453
+ * preload forwards it to `nativeTheme.themeSource` so macOS vibrancy follows
454
+ * the app theme). `system` only when the preference is `system`; a fixed
455
+ * preference (including registered theme ids) publishes its resolved scheme.
456
+ */
457
+ const THEME_SOURCE_ATTRIBUTE = "data-ds-theme-source";
444
458
  /** Body variable carrying the user's content font size in px. */
445
459
  const CONTENT_FONT_SIZE_VARIABLE = "--dsh-content-font-size";
446
460
  /** Applies theme snapshots to the document; one instance per plugin fiber. */
@@ -466,6 +480,7 @@ window.__ModuleLoader__.load({
466
480
  apply(snapshot) {
467
481
  const scheme = snapshot.active.colorScheme;
468
482
  document.documentElement.style.colorScheme = scheme;
483
+ document.documentElement.setAttribute(THEME_SOURCE_ATTRIBUTE, snapshot.preference === "system" ? "system" : scheme);
469
484
  const body = document.body;
470
485
  if (scheme === "dark") body.setAttribute(DARK_ATTRIBUTE, "");
471
486
  else body.removeAttribute(DARK_ATTRIBUTE);
@@ -479,9 +494,13 @@ window.__ModuleLoader__.load({
479
494
  this.themeColorMeta.content = getComputedStyle(body).backgroundColor;
480
495
  if (!this.themeColorMeta.isConnected) document.head.append(this.themeColorMeta);
481
496
  }
482
- /** Retract root color-scheme, the palette attribute, token variables, the font-size axis, and the owned metadata node. */
497
+ /**
498
+ * Retract root color-scheme, the theme-source attribute, the palette
499
+ * attribute, token variables, the font-size axis, and the owned metadata node.
500
+ */
483
501
  dispose() {
484
502
  document.documentElement.style.removeProperty("color-scheme");
503
+ document.documentElement.removeAttribute(THEME_SOURCE_ATTRIBUTE);
485
504
  const body = document.body;
486
505
  body.removeAttribute(DARK_ATTRIBUTE);
487
506
  body.style.removeProperty(CONTENT_FONT_SIZE_VARIABLE);
@@ -42,8 +42,10 @@ export declare function clampWidth(px: number, min: number, max: number): number
42
42
  * @param viewport - available frame width in px.
43
43
  * @param sidebar - sidebar width preference in px (0 = closed).
44
44
  * @param rightbar - requested right panel width in px (0 = no track).
45
+ * @param collapsedWidth - track width of the closed sidebar; the default keeps
46
+ * the icon rail, 0 hides the column entirely (macOS desktop).
45
47
  * @returns actual widths after shrinking or removing the right track; only
46
48
  * without that track may the center fall below its minimum, down to zero.
47
49
  */
48
- export declare function computeColumns(viewport: number, sidebar: number, rightbar: number): Columns;
50
+ export declare function computeColumns(viewport: number, sidebar: number, rightbar: number, collapsedWidth?: number): Columns;
49
51
  //# sourceMappingURL=columns.d.ts.map
@@ -3,7 +3,8 @@
3
3
  * document — `html { color-scheme }` for native UA chrome (scrollbars, form
4
4
  * controls), `body[data-ds-dark-theme]` for the token palette, the active
5
5
  * theme's alias-token overrides as inline CSS variables on body, the content
6
- * font-size axis (`--dsh-content-font-size`), and one presenter-owned
6
+ * font-size axis (`--dsh-content-font-size`), `html[data-ds-theme-source]`
7
+ * for native-chrome mirroring, and one presenter-owned
7
8
  * `meta[name="theme-color"]` for surrounding browser UI. Pure DOM writes, no
8
9
  * React involvement; the presenter only ever retracts what it wrote itself,
9
10
  * so foreign attributes, metadata, and inline styles survive.
@@ -11,6 +12,14 @@
11
12
  import type { ThemeSnapshot } from '@deepseek-ai/dsh-client-ui-theme/client';
12
13
  /** Body attribute selecting the dark base palette in the token stylesheets. */
13
14
  export declare const DARK_ATTRIBUTE = "data-ds-dark-theme";
15
+ /**
16
+ * Root attribute publishing the theme source (`light`, `dark`, or `system`)
17
+ * for host shells that mirror it into native window chrome (the Electron
18
+ * preload forwards it to `nativeTheme.themeSource` so macOS vibrancy follows
19
+ * the app theme). `system` only when the preference is `system`; a fixed
20
+ * preference (including registered theme ids) publishes its resolved scheme.
21
+ */
22
+ export declare const THEME_SOURCE_ATTRIBUTE = "data-ds-theme-source";
14
23
  /** Body variable carrying the user's content font size in px. */
15
24
  export declare const CONTENT_FONT_SIZE_VARIABLE = "--dsh-content-font-size";
16
25
  /** Applies theme snapshots to the document; one instance per plugin fiber. */
@@ -31,7 +40,10 @@ export declare class ThemePresenter {
31
40
  * @param snapshot - resolved theme snapshot from ctx.theme.
32
41
  */
33
42
  apply(snapshot: ThemeSnapshot): void;
34
- /** Retract root color-scheme, the palette attribute, token variables, the font-size axis, and the owned metadata node. */
43
+ /**
44
+ * Retract root color-scheme, the theme-source attribute, the palette
45
+ * attribute, token variables, the font-size axis, and the owned metadata node.
46
+ */
35
47
  dispose(): void;
36
48
  }
37
49
  //# sourceMappingURL=theme-presenter.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-layout",
3
3
  "description": "Shell plugin: three-column AppFrame with drag handles, ctx.layout viewing-state service (navigation + panels)",
4
- "version": "0.1.5-rc.2",
4
+ "version": "0.1.6-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -43,13 +43,13 @@
43
43
  "devDependencies": {
44
44
  "@types/react": "~18.3.1",
45
45
  "react": "^18.2.0",
46
- "@deepseek-ai/dsh-brand": "^0.1.5-rc.2",
47
- "@deepseek-ai/dsh-client-locale": "^0.1.5-rc.2",
48
- "@deepseek-ai/dsh-client-store": "^0.1.5-rc.2",
49
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-rc.2",
50
- "@deepseek-ai/dsh-client-ui-session": "^0.1.5-rc.2",
51
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.5-rc.2",
52
- "@deepseek-ai/dsh-client-ui-theme": "^0.1.5-rc.2",
46
+ "@deepseek-ai/dsh-brand": "^0.1.6-alpha.2",
47
+ "@deepseek-ai/dsh-client-locale": "^0.1.6-alpha.2",
48
+ "@deepseek-ai/dsh-client-store": "^0.1.6-alpha.2",
49
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.6-alpha.2",
50
+ "@deepseek-ai/dsh-client-ui-session": "^0.1.6-alpha.2",
51
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.6-alpha.2",
52
+ "@deepseek-ai/dsh-client-ui-theme": "^0.1.6-alpha.2",
53
53
  "@deepseek-ai/cordis": "^4.0.2"
54
54
  },
55
55
  "files": [