@celestia-island/hikari 0.55.265 → 0.55.266

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@celestia-island/hikari",
3
- "version": "0.55.265",
3
+ "version": "0.55.266",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Hikari UI library, Vue 3 runtime — one design system for Vue 3 and Rust/WASM applications",
@@ -185,6 +185,10 @@ describe("HkFaceShell rail mode", () => {
185
185
 
186
186
  expect(c.aside().style.width).toBe("224px");
187
187
  expect(c.aside().getAttribute("data-rail")).toBeNull();
188
+ // The shell declares the rail width token for the rail row square's
189
+ // inline track (same contract as HkSidebar's collapsedWidth); the
190
+ // default rides the 56px fallback.
191
+ expect(c.aside().style.getPropertyValue("--hk-sidebar-rail-w")).toBe("56px");
188
192
  expect(c.toggle().getAttribute("aria-expanded")).toBe("true");
189
193
 
190
194
  c.toggle().click();
@@ -265,6 +269,10 @@ describe("HkFaceShell rail mode", () => {
265
269
 
266
270
  it("honors a configured rail width", async () => {
267
271
  const c = mountShell({ sidebarCollapsible: true, sidebarCollapsedWidth: "72px" });
272
+ expect(
273
+ c.aside().style.getPropertyValue("--hk-sidebar-rail-w"),
274
+ "a non-default collapsed width retunes the square track via the token",
275
+ ).toBe("72px");
268
276
  c.toggle().click();
269
277
  await vi.advanceTimersByTimeAsync(0);
270
278
  expect(c.aside().style.width).toBe("72px");
@@ -461,7 +461,14 @@ export const HkFaceShell = defineComponent({
461
461
  // while THIS host's width transition plays — expanding must
462
462
  // not replay the sidebar slide.
463
463
  data-pinning={rail.pinning.value || undefined}
464
- style={{ width: hostSidebarWidth.value, flexShrink: 0 }}
464
+ style={{
465
+ width: hostSidebarWidth.value,
466
+ flexShrink: 0,
467
+ // The rail row square's inline track (HkSidebar.scss)
468
+ // derives from this token, so a non-default
469
+ // sidebarCollapsedWidth keeps producing exact squares.
470
+ "--hk-sidebar-rail-w": props.sidebarCollapsedWidth,
471
+ }}
465
472
  onPointerenter={onSidebarHostPointerEnter}
466
473
  onPointerleave={rail.onPointerLeave}
467
474
  onPointermove={onSidebarHostPointerMove}
@@ -95,6 +95,12 @@ describe("HkSidebar rail capability", () => {
95
95
  const c = mountSidebar({ width: "240px", collapsible: true, collapsedWidth: "64px" });
96
96
  expect(c.aside().className).toContain("hk-sidebar-rail-host");
97
97
  expect(c.aside().style.width).toBe("240px");
98
+ // The rail width travels to the sheet as a token: the rail row
99
+ // square's inline track (HkSidebar.scss) computes from it, so a
100
+ // non-default collapsedWidth keeps exact squares without a second
101
+ // edit. Deleting the declaration regresses non-56 hosts silently
102
+ // (the 56px fallback renders identically at the default).
103
+ expect(c.aside().style.getPropertyValue("--hk-sidebar-rail-w")).toBe("64px");
98
104
 
99
105
  c.toggle().click();
100
106
  await vi.advanceTimersByTimeAsync(0);
@@ -102,13 +102,17 @@
102
102
  * THE RAIL ROW SQUARE (2026-11-02 user screenshot: the collapsed
103
103
  * selected pill read as "not quite square — a bit squat"). The body's
104
104
  * inline track narrows so a rail row is EXACTLY its own min-height
105
- * square: the default 56px rail minus the menu-item grammar's 34px row
106
- * leaves 22px, 11px a side. The row spans its track (width: 100% in the
107
- * shared spec), so the hover/active pill fills 34×34 instead of the
108
- * 32×34 oblong a 12px track produced. INLINE ONLY: the block paddings —
109
- * the 20px leading air and the scroll tail — stay with the base rule, so
110
- * the vertical rhythm invariant above is untouched. The literal is
111
- * derived, not tunable: --hk-menu-item-min-h is declared ON each row (the
105
+ * square: the rail width minus the menu-item grammar's 34px row, half
106
+ * a side each. The row spans its track (width: 100% in the shared
107
+ * spec), so the hover/active pill fills 34×34 instead of the 32×34
108
+ * oblong a 12px track produced. INLINE ONLY: the block paddings — the
109
+ * 20px leading air and the scroll tail — stay with the base rule, so
110
+ * the vertical rhythm invariant above is untouched. The rail width
111
+ * travels as `--hk-sidebar-rail-w`, declared inline by both rail
112
+ * holders (HkSidebar's `collapsedWidth`, HkFaceShell's
113
+ * `sidebarCollapsedWidth`) — a host retuning the width keeps exact
114
+ * squares with no second edit. The 34px minuend stays a literal
115
+ * because --hk-menu-item-min-h is declared ON each row (the
112
116
  * custom-property trap), so this ancestor cannot compute from it. */
113
117
  .hk-sidebar[data-collapsed],
114
118
  .hk-sidebar-rail-generation[data-rail] {
@@ -122,7 +126,7 @@
122
126
  }
123
127
 
124
128
  .hk-sidebar-body {
125
- padding-inline: 11px;
129
+ padding-inline: calc((var(--hk-sidebar-rail-w, 56px) - 34px) / 2);
126
130
  }
127
131
  }
128
132
 
@@ -94,7 +94,7 @@ describe("HkSidebar scroll end-cap", () => {
94
94
  expect(
95
95
  bodySquare![1]!.trim(),
96
96
  "the body dress is the row square's inline track ALONE — any block spelling here moves rows",
97
- ).toBe("padding-inline: 11px;");
97
+ ).toBe("padding-inline: calc((var(--hk-sidebar-rail-w, 56px) - 34px) / 2);");
98
98
  const header = ruleBody(css, ".hk-sidebar-rail-generation[data-rail] .hk-sidebar-header");
99
99
  expect(header, "the collapsed header rule exists (grouped density carriers)").not.toBeNull();
100
100
  expect(header).toContain("padding: var(--space-16) var(--space-8)");
@@ -104,7 +104,8 @@ describe("HkSidebar scroll end-cap", () => {
104
104
  // The stronger, spelling-proof form (whole-dress scan): EVERY
105
105
  // padding declaration in ANY dress rule must be EXACTLY one of the
106
106
  // two sanctioned values — the expanded two-track shorthand (header/
107
- // footer bands) or the body's square track — exact, not a prefix: a
107
+ // footer bands) or the body's token-derived square track — exact,
108
+ // not a prefix: a
108
109
  // three-track spelling (`padding: var(--space-16) var(--space-8)
109
110
  // var(--space-12)`) drifts the block END past a block-start-only
110
111
  // check, and a longhand (`padding-block-start:`) hides from a
@@ -146,7 +147,7 @@ describe("HkSidebar scroll end-cap", () => {
146
147
  expect(
147
148
  text,
148
149
  `a dress inline track drifted from the row square: ${text}`,
149
- ).toBe("padding-inline: 11px");
150
+ ).toBe("padding-inline: calc((var(--hk-sidebar-rail-w, 56px) - 34px) / 2)");
150
151
  } else {
151
152
  expect(
152
153
  text,
@@ -29,11 +29,10 @@ export default defineComponent({
29
29
  * no peek, `collapsed` stays the plain presentational 56px rail. */
30
30
  collapsible: { type: Boolean, default: false },
31
31
  /** Layout width of the icon rail (the one-icon column). Mirrors the
32
- * 56px this component always used for its collapsed mode.
33
- * COUPLING (2026-11-02): the rail row square in HkSidebar.scss
34
- * derives its body inline track from the DEFAULT — 56px rail − 34px
35
- * menu row = 11px a side. A non-56 rail re-flattens the selected
36
- * pill unless that track is retuned alongside. */
32
+ * 56px this component always used for its collapsed mode. Declared
33
+ * to the sheet as `--hk-sidebar-rail-w` on this aside, so the rail
34
+ * row square (HkSidebar.scss's body inline track) retunes with it —
35
+ * any width yields exact 34px squares. */
37
36
  collapsedWidth: { type: String, default: "56px" },
38
37
  /** Hover dwell on the rail before the peek drawer opens, ms. */
39
38
  peekDelay: { type: Number, default: 400 },
@@ -268,7 +267,17 @@ export default defineComponent({
268
267
  // panel and the panel's inner widths snap while THIS host's width
269
268
  // transition plays — expanding must not replay the sidebar slide.
270
269
  data-pinning={rail.pinning.value || undefined}
271
- style={props.mobile ? undefined : { width: hostWidth.value }}
270
+ style={
271
+ props.mobile
272
+ ? undefined
273
+ : {
274
+ width: hostWidth.value,
275
+ // The rail row square's inline track (HkSidebar.scss)
276
+ // derives from this token, so a non-default
277
+ // collapsedWidth keeps producing exact squares.
278
+ "--hk-sidebar-rail-w": props.collapsedWidth,
279
+ }
280
+ }
272
281
  onPointerenter={railChrome.value ? onHostPointerEnter : undefined}
273
282
  onPointerleave={railChrome.value ? rail.onPointerLeave : undefined}
274
283
  onPointermove={railChrome.value ? onHostPointerMove : undefined}
@@ -102,9 +102,10 @@ export default defineComponent({
102
102
  rail: { type: Boolean, default: false },
103
103
  /** Pinned width of the RAIL generation. The host's collapsed-width
104
104
  * token (HkSidebar's `collapsedWidth`, the shell's
105
- * `sidebarCollapsedWidth`, wowsp's 56px). COUPLING (2026-11-02): the
106
- * rail row square in HkSidebar.scss derives from the 56px default —
107
- * a non-56 rail needs its body inline track retuned alongside. */
105
+ * `sidebarCollapsedWidth`, wowsp's 56px). The rail row square's
106
+ * body inline track reads the same width as
107
+ * `--hk-sidebar-rail-w` — declared by the rail holder (HkSidebar /
108
+ * HkFaceShell), so a non-default width keeps exact squares. */
108
109
  railWidth: { type: String, default: "56px" },
109
110
  /** Pinned width of the EXPANDED generation. The host's full sidebar
110
111
  * width token — a CSS length or a var() reference. */
@@ -32,7 +32,7 @@ import HkSidebarRailSwap from "../components/HkSidebarRailSwap";
32
32
  *
33
33
  * The assertions pin the choreography DECISIONS:
34
34
  * 1. A flip with moving keyed icons arms the flight: `data-flipping` on
35
- * the swap host, a flight layer on the ENTERING item with one clone
35
+ * the swap host, a flight layer ON THE HOST with one clone
36
36
  * per PAIRED key, each clone painted at the leaving rect (logical
37
37
  * insets relative to the stage) and animated by the signed delta.
38
38
  * 2. The pairing contract is visible: matched leaving cells carry the
@@ -202,6 +202,11 @@ afterEach(() => {
202
202
  for (const app of mounts.splice(0)) app.unmount();
203
203
  containers.splice(0).forEach((c) => c.remove());
204
204
  document.body.innerHTML = "";
205
+ // Restores every vi.spyOn (getComputedStyle / matchMedia / rect
206
+ // stubs) even when a test failed before its own inline restore —
207
+ // the probes recorded the leak as harmless, but the class is free
208
+ // to close.
209
+ vi.restoreAllMocks();
205
210
  vi.unstubAllGlobals();
206
211
  vi.useRealTimers();
207
212
  __teardownMediaQueries();
@@ -219,7 +224,7 @@ describe("enterDelayMs", () => {
219
224
  });
220
225
 
221
226
  describe("useRailIconFlight", () => {
222
- it("arms a flight on collapse: matched cells marked, layer on the entering item, clones at the leaving rects", async () => {
227
+ it("arms a flight on collapse: matched cells marked, layer on the swap host, clones at the leaving rects", async () => {
223
228
  const h = mountSwap();
224
229
  await h.set(true);
225
230
  // Expanded geometry: icon cells at x=32 (the leading padding column).