@celestia-island/hikari 0.55.308 → 0.55.309

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.308",
3
+ "version": "0.55.309",
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",
@@ -862,6 +862,35 @@ describe("HkRangeRibbon reset", () => {
862
862
  expect(second.defaultPrevented).toBe(true);
863
863
  });
864
864
 
865
+ it("treats a full-domain window as nothing to reset (raw-records rest state)", async () => {
866
+ // A minimal-style host rests at the controlled FULL selection [0, 1]:
867
+ // the grips paint, but there is no narrower selection to come back to.
868
+ // Escape there must reach the host (the dialog closes), not "reset" the
869
+ // bar it already shows — before 2026-11-07 every press swallowed the key.
870
+ const host = mountHost([0, 1]);
871
+ const strip = host.root.querySelector<HTMLElement>(".hk-range-ribbon-strip")!;
872
+ const event = keydown(strip, "Escape");
873
+ await nextTick();
874
+ expect(host.windowChange, "full selection: nothing resets").not.toHaveBeenCalled();
875
+ expect(event.defaultPrevented, "a host dialog must still see Escape").toBe(false);
876
+
877
+ // The reset BUTTON agrees with Escape: nothing to reset at [0, 1].
878
+ expect(host.root.querySelector(".hk-range-ribbon-reset")).toBeNull();
879
+ // The grips stay (they are the selection itself, not a reset affordance).
880
+ expect(host.root.querySelector(".hk-range-ribbon-handle")).not.toBeNull();
881
+
882
+ // A real sub-domain still resets — and the chip is back for it.
883
+ await host.setWindow([0.3, 0.7]);
884
+ expect(host.root.querySelector(".hk-range-ribbon-reset")).not.toBeNull();
885
+ const second = keydown(host.root.querySelector<HTMLElement>(".hk-range-ribbon-strip")!, "Escape");
886
+ await nextTick();
887
+ expect(host.windowChange).toHaveBeenLastCalledWith(null);
888
+ expect(second.defaultPrevented).toBe(true);
889
+ // Back at the full selection the chip is gone again.
890
+ await host.setWindow([0, 1]);
891
+ expect(host.root.querySelector(".hk-range-ribbon-reset")).toBeNull();
892
+ });
893
+
865
894
  it("cancels an in-flight brush with Escape and consumes the key", async () => {
866
895
  const host = mountHost(null);
867
896
  const { strip, x } = stubStrip(host.root);
@@ -1496,10 +1525,13 @@ describe("HkRangeRibbon stylesheet contract", () => {
1496
1525
  });
1497
1526
 
1498
1527
  // Wave (2026-11-06 raw-records five): MINIMAL MODE - the bare dual-handle
1499
- // bar. Contract: data-minimal on the root, strip present + windowed at
1500
- // the full domain, ZERO lane chrome (no lanes block, no lane rows, no
1501
- // overview minimap, no gutter probe), and the standard mode keeps its
1502
- // lane chrome + alignment probe.
1528
+ // bar. Contract: data-minimal on the root, strip present, ZERO lane chrome
1529
+ // (no lanes block, no lane rows, no overview minimap, no gutter probe),
1530
+ // and the standard mode keeps its lane chrome + alignment probe. The
1531
+ // uncontrolled default window is NULL here — the grips need a controlled
1532
+ // non-null window (the chest raw-records adapter feeds [0, 1] for its
1533
+ // "default = everything selected" reading); the aria readings below come
1534
+ // from the strip's null-window fallbacks, not from a real window.
1503
1535
  it("minimal mode renders the bare dual-handle bar (no lane chrome)", () => {
1504
1536
  const root = mountRibbon({ minimal: true });
1505
1537
  expect(root.getAttribute("data-minimal")).toBe("true");
@@ -1507,8 +1539,9 @@ describe("HkRangeRibbon stylesheet contract", () => {
1507
1539
  expect(stripEl).not.toBeNull();
1508
1540
  // The strip carries the slider a11y (role/tabindex/label/valuenow).
1509
1541
  expect(stripEl.getAttribute("aria-label")).toBe("Observation range");
1510
- // Uncontrolled default window = the FULL domain: valuenow sits at 0
1511
- // (domain start) and the valuetext reads the whole range.
1542
+ // No window ⇒ the strip's aria falls back to the full range ("0" /
1543
+ // "0% – 100%"): a truthful reading for an unfiltered bar, even though
1544
+ // no grips paint without a controlled window.
1512
1545
  expect(stripEl.getAttribute("aria-valuenow")).toBe("0");
1513
1546
  expect(stripEl.getAttribute("aria-valuetext")).toContain("0%");
1514
1547
  // The lanes BLOCK is skipped entirely (no lane rows at all).
@@ -1522,7 +1555,6 @@ describe("HkRangeRibbon stylesheet contract", () => {
1522
1555
  // static scss assertion at the end of this file — happy-dom cannot
1523
1556
  // resolve the nested attribute selector.)
1524
1557
  expect(root.querySelector(".hk-range-ribbon-overview-segment")).toBeNull();
1525
- // Uncontrolled default window = the FULL domain (edge to edge).
1526
1558
  // Standard consumers keep the lane chrome + the alignment probe.
1527
1559
  const std = mountRibbon({});
1528
1560
  expect(std.querySelector(".hk-range-ribbon-lane")).not.toBeNull();
@@ -264,9 +264,12 @@ export default defineComponent({
264
264
  * range bar. No lane rows, no overview minimap, no label gutter; the
265
265
  * strip spans the full width and its track uses muted-based tokens
266
266
  * (the surface-based track read whitish inside dark phone modals).
267
- * The uncontrolled default window is already the FULL domain, so a
268
- * minimal bar starts pinned edge to edge. `segments` / `selectedId`
269
- * are IGNORED in this mode (no segment DOM to select from). */
267
+ * The grips paint only for a NON-null window, so an uncontrolled
268
+ * minimal bar starts as a bare track; a host that wants the "default =
269
+ * everything selected" reading feeds the controlled window `[0, 1]`
270
+ * (the chest raw-records adapter does exactly that).
271
+ * `segments` / `selectedId` are IGNORED in this mode (no segment DOM to
272
+ * select from). */
270
273
  minimal: { type: Boolean, default: false },
271
274
  },
272
275
  emits: {
@@ -350,9 +353,21 @@ export default defineComponent({
350
353
  return true;
351
354
  }
352
355
 
353
- /** Returns true when a window actually existed (and was cleared), so the
354
- * caller can leave Escape alone when the host needs it. */
356
+ /** A window that covers the whole domain IS the unfiltered state — there
357
+ * is nothing to reset back to (2026-11-07, the raw-records consumer: a
358
+ * minimal bar paints its grips for a non-null window, so its rest state
359
+ * is the FULL selection `[0, 1]`; without this check Escape "reset" it
360
+ * every press, swallowed the key, and the hosting dialog could never
361
+ * close while the bar held focus). */
362
+ function isFullDomain(win: WindowRange | null): boolean {
363
+ return win !== null && win[0] <= WINDOW_EPSILON && win[1] >= 1 - WINDOW_EPSILON;
364
+ }
365
+
366
+ /** Returns true when a window actually existed AND was narrower than the
367
+ * full domain (and was cleared), so the caller can leave Escape alone
368
+ * when the host needs it — a full-domain window has nothing to reset. */
355
369
  function resetWindow(): boolean {
370
+ if (isFullDomain(activeWindow.value)) return false;
356
371
  if (!commitIfChanged(null)) return false;
357
372
  // A reset that interrupts a drag (Escape mid-brush) must drop the
358
373
  // gesture too, or the next pointermove re-brushes from the stale
@@ -818,7 +833,10 @@ export default defineComponent({
818
833
  focus; this sheet only pins the seat (position) and a
819
834
  surface backing via its override vars. The glyph slots
820
835
  as a lucide component (the house-normal integration:
821
- every in-tree HkIconButton slots its glyph). */}
836
+ every in-tree HkIconButton slots its glyph). A
837
+ full-domain window has nothing to reset, so the chip
838
+ only renders for a REAL sub-domain selection. */}
839
+ {win && !isFullDomain(win) && (
822
840
  <HIconButton
823
841
  class="hk-range-ribbon-reset"
824
842
  size={24}
@@ -829,6 +847,7 @@ export default defineComponent({
829
847
  >
830
848
  {{ icon: () => <RotateCcw aria-hidden="true" /> }}
831
849
  </HIconButton>
850
+ )}
832
851
  </>
833
852
  )}
834
853
  </div>