@celestia-island/hikari 0.55.89 → 0.55.91
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
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source contract: the inline landing sits FLUSH under its context. The
|
|
3
|
+
* `.is-inline` variant must drop the viewport takeover's block-axis
|
|
4
|
+
* padding entirely (the host pane already pads and a sibling header sits
|
|
5
|
+
* immediately above — the old 1.25rem top padding floated the card a
|
|
6
|
+
* full padding-frame below its context) and slim the card's page-grade
|
|
7
|
+
* top padding (2.25rem desktop / 1.75rem mobile) to one space step. The
|
|
8
|
+
* horizontal inset stays so a narrow pane never seats the card
|
|
9
|
+
* edge-to-edge. A class-name test cannot see this; the compiled contract
|
|
10
|
+
* lives here.
|
|
11
|
+
*/
|
|
12
|
+
import { describe, expect, it } from "vitest";
|
|
13
|
+
import { readFileSync } from "node:fs";
|
|
14
|
+
import { dirname, join } from "node:path";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
|
|
17
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
|
|
19
|
+
/** Extract one rule's body with nesting-aware brace matching. */
|
|
20
|
+
function ruleBody(css: string, selector: string): string {
|
|
21
|
+
const start = css.indexOf(`${selector} {`);
|
|
22
|
+
expect(start, `rule ${selector} present`).toBeGreaterThanOrEqual(0);
|
|
23
|
+
const open = css.indexOf("{", start);
|
|
24
|
+
let depth = 0;
|
|
25
|
+
for (let i = open; i < css.length; i++) {
|
|
26
|
+
if (css[i] === "{") depth++;
|
|
27
|
+
else if (css[i] === "}") {
|
|
28
|
+
depth--;
|
|
29
|
+
if (depth === 0) return css.slice(open + 1, i);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
throw new Error(`unbalanced braces in ${selector}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe("HkErrorLanding inline contract", () => {
|
|
36
|
+
const css = readFileSync(join(here, "HkErrorLanding.scss"), "utf-8");
|
|
37
|
+
const inline = ruleBody(css, ".hk-error-landing.is-inline");
|
|
38
|
+
|
|
39
|
+
it("drops the block-axis padding entirely and keeps only the horizontal inset", () => {
|
|
40
|
+
expect(inline).toContain("min-height: 0");
|
|
41
|
+
expect(inline).toContain("padding: 0 var(--space-12, 0.75rem)");
|
|
42
|
+
// The takeover padding must not survive in any form.
|
|
43
|
+
expect(inline).not.toContain("1.25rem");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("slims the card's top padding below the page-grade value", () => {
|
|
47
|
+
const card = ruleBody(inline, ".hk-error-landing__card");
|
|
48
|
+
// The shorthand's block-start value IS the slim step, not the
|
|
49
|
+
// page-grade 2.25rem (desktop) / 1.75rem (≤480px media) top.
|
|
50
|
+
expect(card).toContain("padding: var(--space-16, 1rem) ");
|
|
51
|
+
expect(card).not.toContain("2.25rem");
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -260,11 +260,26 @@
|
|
|
260
260
|
|
|
261
261
|
// Inline variant: the same card without the viewport takeover — used when
|
|
262
262
|
// HkErrorBoundary captures a crash inside a pane and swaps in the landing
|
|
263
|
-
// in-place instead of covering the whole screen
|
|
263
|
+
// in-place instead of covering the whole screen, or when a host view
|
|
264
|
+
// renders it as its failed content region right under a sibling header.
|
|
264
265
|
.hk-error-landing.is-inline {
|
|
265
266
|
min-height: 0;
|
|
266
|
-
|
|
267
|
+
// In-pane, the host region already pads and a sibling header usually
|
|
268
|
+
// sits immediately above: the takeover's block-axis padding floated
|
|
269
|
+
// the card a full padding-frame below its context. The vertical
|
|
270
|
+
// padding is dropped entirely (the card's own slimmer top padding
|
|
271
|
+
// below supplies the breathing room); the horizontal inset stays so a
|
|
272
|
+
// narrow pane never seats the card edge-to-edge.
|
|
273
|
+
padding: 0 var(--space-12, 0.75rem);
|
|
267
274
|
background: transparent;
|
|
275
|
+
|
|
276
|
+
// The card's page-grade top padding (2.25rem desktop / 1.75rem mobile)
|
|
277
|
+
// reads as a detached float inside a pane — slim it to one space step.
|
|
278
|
+
// Specificity (0,3,0) outranks the ≤480px media rule (0,1,0), so this
|
|
279
|
+
// holds on phones too.
|
|
280
|
+
.hk-error-landing__card {
|
|
281
|
+
padding: var(--space-16, 1rem) var(--space-28, 1.75rem) var(--space-24, 1.5rem);
|
|
282
|
+
}
|
|
268
283
|
}
|
|
269
284
|
|
|
270
285
|
@media (max-width: 480px) {
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
2
5
|
import { createApp, defineComponent, h } from "vue";
|
|
3
6
|
|
|
4
7
|
import HkIconButton from "./HkIconButton";
|
|
@@ -118,3 +121,33 @@ describe("HkIconButton", () => {
|
|
|
118
121
|
expect(propAndSlot.querySelector(".hk-icon")).toBeNull();
|
|
119
122
|
});
|
|
120
123
|
});
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Static pin for the header-chrome glyph step (user report 2026-09-29:
|
|
127
|
+
* the search / refresh / filter glyphs in the top-right clusters read
|
|
128
|
+
* visibly smaller than HkThemeToggle's sun beside them). The `.svg` rule
|
|
129
|
+
* in HkIconButton.scss forces ANY slotted glyph to
|
|
130
|
+
* `--hi-icon-button-icon-size`, so the 28 step must map that var to the
|
|
131
|
+
* sm token (16px — the theme toggle's own glyph size). happy-dom has no
|
|
132
|
+
* cascade here that a DOM test could measure, so — tokenInventory style —
|
|
133
|
+
* the declarations themselves are the contract; a deliberate remap is
|
|
134
|
+
* expected to update this file.
|
|
135
|
+
*/
|
|
136
|
+
describe("HkIconButton glyph step", () => {
|
|
137
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
138
|
+
const vars = readFileSync(join(here, "HkIconButtonVars.scss"), "utf8");
|
|
139
|
+
|
|
140
|
+
it("maps the 28 header step to the sm glyph (16px), matching the theme toggle", () => {
|
|
141
|
+
const block = vars.slice(vars.indexOf(".hk-icon-button-28"), vars.indexOf(".hk-icon-button-32"));
|
|
142
|
+
expect(block).toContain("--hi-icon-button-size: 28px;");
|
|
143
|
+
expect(block).toContain("--hi-icon-button-icon-size: var(--hi-icon-size-sm);");
|
|
144
|
+
expect(block).not.toContain("var(--hi-icon-size-xs)");
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("keeps the dense steps (16/24) on the xs glyph", () => {
|
|
148
|
+
const block16 = vars.slice(vars.indexOf(".hk-icon-button-16"), vars.indexOf(".hk-icon-button-24"));
|
|
149
|
+
const block24 = vars.slice(vars.indexOf(".hk-icon-button-24"), vars.indexOf(".hk-icon-button-28"));
|
|
150
|
+
expect(block16).toContain("var(--hi-icon-size-xs)");
|
|
151
|
+
expect(block24).toContain("var(--hi-icon-size-xs)");
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -74,7 +74,15 @@
|
|
|
74
74
|
|
|
75
75
|
.hk-icon-button-28 {
|
|
76
76
|
--hi-icon-button-size: 28px;
|
|
77
|
-
|
|
77
|
+
/* The header-chrome step carries the sm glyph (16px): its consumers are
|
|
78
|
+
* the header clusters — global search, the pages' refresh, the filter
|
|
79
|
+
* trigger — whose visual sibling is HkThemeToggle's own trigger buttons
|
|
80
|
+
* (28px boxes with direct 16px lucide glyphs). The xs mapping (12px)
|
|
81
|
+
* rendered those glyphs visibly smaller than the sun beside them
|
|
82
|
+
* (user report 2026-09-29: 不像一个尺寸的图标按钮) — the `.svg` rule
|
|
83
|
+
* in HkIconButton.scss forces ANY slotted glyph to this var, so the
|
|
84
|
+
* slot's size-16 attribute never reached the screen. */
|
|
85
|
+
--hi-icon-button-icon-size: var(--hi-icon-size-sm);
|
|
78
86
|
}
|
|
79
87
|
|
|
80
88
|
.hk-icon-button-32 {
|