@celestia-island/hikari 0.55.138 → 0.55.139
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
|
@@ -139,6 +139,26 @@ describe("HkPlaceholderMarquee", () => {
|
|
|
139
139
|
expect(host.classList.contains("hk-placeholder-marquee--hidden")).toBe(false);
|
|
140
140
|
});
|
|
141
141
|
|
|
142
|
+
it("keeps a sub-pixel-exact fit static instead of flipping to scroll", async () => {
|
|
143
|
+
// A shrink-wrapped host (window == text width, e.g. the status-bar
|
|
144
|
+
// version cells) compares a fractional copy width against the
|
|
145
|
+
// INTEGER clientWidth: without the epsilon, every fractional part
|
|
146
|
+
// < 0.5 made the predicate true and permanently scrolled a FITTING
|
|
147
|
+
// text (2026-10-11 R1 finding, reproduced in Chromium). The epsilon
|
|
148
|
+
// lets exact fits keep the hidden probe while real overflow (≥0.5px
|
|
149
|
+
// past the edge) still flips.
|
|
150
|
+
const { container } = mountMarquee({ text: "0.1.0 feat/model-usage-selfhosted:770f625" });
|
|
151
|
+
// Copy (incl. 24px spacing) lands 0.3px past the window: fits.
|
|
152
|
+
await forceGeometry(container, /* copy */ 224.3, /* window */ 200);
|
|
153
|
+
const host = container.querySelector(".hk-placeholder-marquee") as HTMLElement;
|
|
154
|
+
expect(host.classList.contains("hk-placeholder-marquee--hidden"), "0.3px past → still fits").toBe(true);
|
|
155
|
+
expect(container.querySelectorAll(".hk-placeholder-marquee__copy")).toHaveLength(1);
|
|
156
|
+
// 2px past the edge: real overflow, the strip takes over.
|
|
157
|
+
await forceGeometry(container, /* copy */ 226, /* window */ 200);
|
|
158
|
+
expect(host.classList.contains("hk-placeholder-marquee--hidden"), "2px past → scrolls").toBe(false);
|
|
159
|
+
expect(container.querySelectorAll(".hk-placeholder-marquee__copy")).toHaveLength(3);
|
|
160
|
+
});
|
|
161
|
+
|
|
142
162
|
it("drives the sweep with CSS custom properties instead of per-frame JS", async () => {
|
|
143
163
|
const { container } = mountMarquee({ text: "advent calendar of placeholders" });
|
|
144
164
|
await forceGeometry(container, 500, 200);
|
|
@@ -79,7 +79,16 @@ export const HkPlaceholderMarquee = defineComponent({
|
|
|
79
79
|
const factor = space.x > 0 ? space.x : 1;
|
|
80
80
|
const copyWidth = copy.getBoundingClientRect().width / factor;
|
|
81
81
|
loopWidth.value = copyWidth;
|
|
82
|
-
|
|
82
|
+
// Sub-pixel boundary (2026-10-11): the copy width is deliberately
|
|
83
|
+
// fractional while clientWidth is an integer. A shrink-wrapped
|
|
84
|
+
// host — window == text width, e.g. the status-bar version cells —
|
|
85
|
+
// degenerates the predicate to `textW > round(textW)`, which is
|
|
86
|
+
// TRUE for every fractional part < 0.5 and would permanently flip
|
|
87
|
+
// a FITTING text into scrolling (no size change → the
|
|
88
|
+
// ResizeObserver never re-fires; reproduced in Chromium). The
|
|
89
|
+
// epsilon keeps exact fits static; real overflow (≥0.5px past the
|
|
90
|
+
// edge) still flips.
|
|
91
|
+
overflowing.value = copyWidth - COPY_SPACING > host.clientWidth + 0.5;
|
|
83
92
|
emit("overflowChange", overflowing.value);
|
|
84
93
|
};
|
|
85
94
|
|
|
@@ -668,5 +668,14 @@ describe("HkStatusBar", () => {
|
|
|
668
668
|
const popoverRule = /\.s-status-bar-popover-value\s*\{[^}]*\}/.exec(scss)?.[0] ?? "";
|
|
669
669
|
expect(popoverRule, "popover value cell bound exists").toContain("max-width: min(16rem, 60vw)");
|
|
670
670
|
expect(scss).toMatch(/\.s-status-bar-popover-value \.s-status-bar-version\s*\{[^}]*max-width:\s*100%/s);
|
|
671
|
+
// Dead-overlay guard: if the marquee's measurement never fires, a
|
|
672
|
+
// capped cell degrades to an ellipsis cut, never a silent hard clip.
|
|
673
|
+
expect(scss).toMatch(
|
|
674
|
+
/\.s-status-bar-version__static\s*\{[^}]*text-overflow:\s*ellipsis/s,
|
|
675
|
+
);
|
|
676
|
+
// The stale combined selector list (`.s-status-bar-version,
|
|
677
|
+
// .s-status-bar-version-sep { nowrap }`) is gone — the dedicated
|
|
678
|
+
// block owns the version cell's rules (2026-10-11 R1 cleanup).
|
|
679
|
+
expect(scss).not.toMatch(/\.s-status-bar-version,\s*\n\s*\.s-status-bar-version-sep\s*\{/);
|
|
671
680
|
});
|
|
672
681
|
});
|
|
@@ -199,9 +199,13 @@
|
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
.s-status-bar-version__static {
|
|
202
|
-
/*
|
|
203
|
-
|
|
202
|
+
/* Dead-overlay guard: if the marquee's measurement never fires (RO
|
|
203
|
+
unavailable, zero-width probe), a capped cell must degrade to an
|
|
204
|
+
ellipsis cut, not a silent hard clip. Invisible while the marquee
|
|
205
|
+
owns the window (the ghost is opacity-0 by then). */
|
|
204
206
|
min-width: 0;
|
|
207
|
+
overflow: hidden;
|
|
208
|
+
text-overflow: ellipsis;
|
|
205
209
|
}
|
|
206
210
|
|
|
207
211
|
.s-status-bar-version[data-overflowing] .s-status-bar-version__static {
|
|
@@ -258,12 +262,8 @@
|
|
|
258
262
|
}
|
|
259
263
|
}
|
|
260
264
|
|
|
261
|
-
.s-status-bar-version,
|
|
262
265
|
.s-status-bar-version-sep {
|
|
263
266
|
white-space: nowrap;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
.s-status-bar-version-sep {
|
|
267
267
|
opacity: 0.5;
|
|
268
268
|
}
|
|
269
269
|
|