@lemoncat7/dsh-theme-xiaohei 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import { XIAOHEI_SCENE_LAYER_ID, XIAOHEI_SCENE_WORLD_CLASS } from './scene.js';
2
2
  import { subscribeXiaoheiHostDom } from './host-dom.js';
3
3
  import { XIAOHEI_HOST_SELECTORS } from './host-contract.js';
4
+ import { createSidebarReveal } from './sidebar-reveal.js';
4
5
  /** Stable id for the paint-only glass surface behind DSH's native sidebar. */
5
6
  export const XIAOHEI_SIDEBAR_GLASS_ID = 'dsh-theme-xiaohei/sidebar-glass';
6
7
  const HORIZONTAL_INSET_START = 7;
@@ -35,6 +36,7 @@ export function installXiaoheiSidebarGlass(doc = typeof document === 'undefined'
35
36
  let resizing = false;
36
37
  let appliedBounds;
37
38
  let geometryDirty = true;
39
+ const reveal = createSidebarReveal(doc);
38
40
  const clearResizeState = () => {
39
41
  if (resizeSettleTimer !== undefined)
40
42
  win.clearTimeout(resizeSettleTimer);
@@ -63,15 +65,19 @@ export function installXiaoheiSidebarGlass(doc = typeof document === 'undefined'
63
65
  return;
64
66
  // RO runs after host layout and before paint. Update the independent
65
67
  // paint layer now, not in next frame's RAF (which visibly trails).
66
- applyBounds();
68
+ const changed = applyBounds();
67
69
  geometryDirty = false;
68
- markResizeActivity();
70
+ if (changed)
71
+ markResizeActivity();
69
72
  })
70
73
  : undefined;
71
74
  const applyBounds = () => {
72
75
  if (glass === undefined || sidebarColumn === undefined)
73
- return;
76
+ return false;
74
77
  const bounds = resolveXiaoheiSidebarGlassBounds(sidebarColumn.getBoundingClientRect());
78
+ reveal.resize(bounds.width + HORIZONTAL_INSET_START + HORIZONTAL_INSET_END);
79
+ const changed = appliedBounds !== undefined && (bounds.left !== appliedBounds.left || bounds.top !== appliedBounds.top ||
80
+ bounds.width !== appliedBounds.width || bounds.height !== appliedBounds.height);
75
81
  if (bounds.left !== appliedBounds?.left) {
76
82
  glass.style.setProperty('--xiaohei-sidebar-glass-left', `${bounds.left}px`);
77
83
  }
@@ -85,6 +91,7 @@ export function installXiaoheiSidebarGlass(doc = typeof document === 'undefined'
85
91
  glass.style.setProperty('--xiaohei-sidebar-glass-height', `${bounds.height}px`);
86
92
  }
87
93
  appliedBounds = bounds;
94
+ return changed;
88
95
  };
89
96
  const reconcile = () => {
90
97
  if (disposed)
@@ -99,6 +106,7 @@ export function installXiaoheiSidebarGlass(doc = typeof document === 'undefined'
99
106
  resizeObserver?.observe(sidebarColumn);
100
107
  }
101
108
  if (sceneLayer === null || sidebarColumn === undefined) {
109
+ reveal.setColumn(undefined);
102
110
  clearResizeState();
103
111
  glass?.remove();
104
112
  glass = undefined;
@@ -106,6 +114,7 @@ export function installXiaoheiSidebarGlass(doc = typeof document === 'undefined'
106
114
  geometryDirty = true;
107
115
  return;
108
116
  }
117
+ reveal.setColumn(sidebarColumn);
109
118
  if (glass === undefined || glass.parentElement !== sceneLayer) {
110
119
  doc.getElementById(XIAOHEI_SIDEBAR_GLASS_ID)?.remove();
111
120
  glass = doc.createElement('div');
@@ -147,6 +156,7 @@ export function installXiaoheiSidebarGlass(doc = typeof document === 'undefined'
147
156
  animationFrame = undefined;
148
157
  unsubscribeHostDom();
149
158
  resizeObserver?.disconnect();
159
+ reveal.dispose();
150
160
  win.removeEventListener('resize', onViewportResize);
151
161
  clearResizeState();
152
162
  glass?.remove();
@@ -0,0 +1,8 @@
1
+ /** Synchronize native wide content with the visible column, without changing
2
+ * Host layout/state or adding a competing animation timer. */
3
+ export declare function createSidebarReveal(doc: Document): {
4
+ setColumn(column: HTMLElement | undefined): void;
5
+ resize(nextWidth: number): void;
6
+ dispose(): void;
7
+ };
8
+ //# sourceMappingURL=sidebar-reveal.d.ts.map
@@ -0,0 +1,51 @@
1
+ /** Synchronize native wide content with the visible column, without changing
2
+ * Host layout/state or adding a competing animation timer. */
3
+ export function createSidebarReveal(doc) {
4
+ let shell;
5
+ let observer;
6
+ let phase = '', width = 0, waiting = false;
7
+ const attribute = 'data-xiaohei-sidebar-reveal';
8
+ const readPhase = () => shell?.className.includes('_collapsed') ? 'rail'
9
+ : shell?.className.includes('_fading') ? 'closing' : 'wide';
10
+ const apply = () => {
11
+ if (!shell)
12
+ return;
13
+ // The Host freezes its shell at the requested width during grid motion.
14
+ // Reading the inline target does not force a layout.
15
+ const target = Number.parseFloat(shell.style.width);
16
+ if (waiting && phase === 'wide' && (!Number.isFinite(target) || width >= target - 2))
17
+ waiting = false;
18
+ const value = waiting ? 'waiting' : 'ready';
19
+ if (shell.getAttribute(attribute) !== value)
20
+ shell.setAttribute(attribute, value);
21
+ };
22
+ const changed = () => {
23
+ const next = readPhase();
24
+ if (next === 'wide' && phase !== 'wide')
25
+ waiting = true;
26
+ if (next === 'rail')
27
+ waiting = false;
28
+ phase = next;
29
+ apply();
30
+ };
31
+ return {
32
+ setColumn(column) {
33
+ const next = column?.querySelector?.("[data-slot='sidebar'] > div") ?? undefined;
34
+ if (next === shell)
35
+ return;
36
+ observer?.disconnect();
37
+ shell?.removeAttribute(attribute);
38
+ shell = next;
39
+ waiting = false;
40
+ phase = readPhase();
41
+ if (!shell)
42
+ return;
43
+ observer = new doc.defaultView.MutationObserver(changed);
44
+ observer.observe(shell, { attributes: true, attributeFilter: ['class', 'style'] });
45
+ apply();
46
+ },
47
+ resize(nextWidth) { width = nextWidth; apply(); },
48
+ dispose() { observer?.disconnect(); shell?.removeAttribute(attribute); shell = undefined; },
49
+ };
50
+ }
51
+ //# sourceMappingURL=sidebar-reveal.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lemoncat7/dsh-theme-xiaohei",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "A Luo Xiaohei-inspired animated dark theme for DeepSeek Harness",
5
5
  "keywords": [
6
6
  "deepseek-harness",