@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
|
@@ -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
|
|
1500
|
-
//
|
|
1501
|
-
//
|
|
1502
|
-
//
|
|
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
|
-
//
|
|
1511
|
-
//
|
|
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
|
|
268
|
-
* minimal bar starts
|
|
269
|
-
*
|
|
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
|
-
/**
|
|
354
|
-
*
|
|
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>
|