@celestia-island/hikari 0.55.304 → 0.55.305
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 +1 -1
- package/src/components/HkBreadcrumb.tsx +3 -3
- package/src/components/HkDraggableGrid.tsx +3 -8
- package/src/components/HkDraggableList.tsx +3 -8
- package/src/components/HkEmptyState.tsx +3 -13
- package/src/components/HkExpansionPanel.tsx +3 -3
- package/src/components/HkFab.test.tsx +4 -3
- package/src/components/HkFab.tsx +5 -13
- package/src/components/HkLocalePicker.tsx +3 -8
- package/src/components/HkModal.open-close-scale.test.ts +75 -72
- package/src/components/HkModal.scss +17 -51
- package/src/components/HkModalBreadcrumb.tsx +3 -12
- package/src/components/HkSignInCard.tsx +3 -14
- package/src/components/HkStepGuide.tsx +3 -14
- package/src/components/HkTable.tsx +7 -42
- package/src/components/HkTree.tsx +3 -3
package/package.json
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ChevronRight } from "lucide-vue-next";
|
|
2
|
+
|
|
1
3
|
import { computed, defineComponent, type PropType } from "vue";
|
|
2
4
|
import { safeHref } from "../utils/safeHref";
|
|
3
5
|
import { useI18n } from "../i18n/context";
|
|
@@ -26,9 +28,7 @@ export default defineComponent({
|
|
|
26
28
|
)}
|
|
27
29
|
{index < props.items.length - 1 && (
|
|
28
30
|
<span class="hk-breadcrumb-separator">
|
|
29
|
-
<
|
|
30
|
-
<polyline points="9 18 15 12 9 6" />
|
|
31
|
-
</svg>
|
|
31
|
+
<ChevronRight />
|
|
32
32
|
</span>
|
|
33
33
|
)}
|
|
34
34
|
</li>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { GripVertical } from "lucide-vue-next";
|
|
2
|
+
|
|
1
3
|
import { defineComponent, onBeforeUnmount, ref, shallowRef, watch, type PropType } from "vue";
|
|
2
4
|
import { onceFrame } from "../runtime/animationBus";
|
|
3
5
|
import { useReportedTransition } from "../composables/useReportedTransition";
|
|
@@ -271,14 +273,7 @@ export default defineComponent({
|
|
|
271
273
|
}}
|
|
272
274
|
>
|
|
273
275
|
{slots.handle ? slots.handle() : (
|
|
274
|
-
<
|
|
275
|
-
<circle cx="4" cy="3" r="1.2" />
|
|
276
|
-
<circle cx="4" cy="7" r="1.2" />
|
|
277
|
-
<circle cx="4" cy="11" r="1.2" />
|
|
278
|
-
<circle cx="10" cy="3" r="1.2" />
|
|
279
|
-
<circle cx="10" cy="7" r="1.2" />
|
|
280
|
-
<circle cx="10" cy="11" r="1.2" />
|
|
281
|
-
</svg>
|
|
276
|
+
<GripVertical size={14} />
|
|
282
277
|
)}
|
|
283
278
|
</span>
|
|
284
279
|
<div class="hk-draggable-grid-content">
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { GripVertical } from "lucide-vue-next";
|
|
2
|
+
|
|
1
3
|
import { defineComponent, onBeforeUnmount, onMounted, ref, shallowRef, type PropType } from "vue";
|
|
2
4
|
import { onceFrame } from "../runtime/animationBus";
|
|
3
5
|
import { useReportedTransition } from "../composables/useReportedTransition";
|
|
@@ -349,14 +351,7 @@ export default defineComponent({
|
|
|
349
351
|
}}
|
|
350
352
|
>
|
|
351
353
|
{slots.handle ? slots.handle() : (
|
|
352
|
-
<
|
|
353
|
-
<circle cx="4" cy="3" r="1.2" />
|
|
354
|
-
<circle cx="4" cy="7" r="1.2" />
|
|
355
|
-
<circle cx="4" cy="11" r="1.2" />
|
|
356
|
-
<circle cx="10" cy="3" r="1.2" />
|
|
357
|
-
<circle cx="10" cy="7" r="1.2" />
|
|
358
|
-
<circle cx="10" cy="11" r="1.2" />
|
|
359
|
-
</svg>
|
|
354
|
+
<GripVertical size={14} />
|
|
360
355
|
)}
|
|
361
356
|
</span>
|
|
362
357
|
<div class="hk-draggable-list-content">
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Package } from "lucide-vue-next";
|
|
2
|
+
|
|
1
3
|
import { defineComponent, h, type Component, type PropType } from "vue";
|
|
2
4
|
|
|
3
5
|
import { useI18n } from "../i18n/context";
|
|
@@ -56,19 +58,7 @@ export default defineComponent({
|
|
|
56
58
|
) : props.icon ? (
|
|
57
59
|
h(props.icon, { size: 32, "aria-hidden": true })
|
|
58
60
|
) : (
|
|
59
|
-
<
|
|
60
|
-
viewBox="0 0 24 24"
|
|
61
|
-
fill="none"
|
|
62
|
-
stroke="currentColor"
|
|
63
|
-
stroke-width="1.5"
|
|
64
|
-
stroke-linecap="round"
|
|
65
|
-
stroke-linejoin="round"
|
|
66
|
-
width="48"
|
|
67
|
-
height="48"
|
|
68
|
-
>
|
|
69
|
-
<polyline points="22 12 16 12 14 15 10 15 8 12 2 12" />
|
|
70
|
-
<path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" />
|
|
71
|
-
</svg>
|
|
61
|
+
<Package size={48} stroke-width={1.5} />
|
|
72
62
|
)}
|
|
73
63
|
</div>
|
|
74
64
|
{props.title ? <p class="hk-empty-title">{props.title}</p> : null}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ChevronDown } from "lucide-vue-next";
|
|
2
|
+
|
|
1
3
|
import { computed, defineComponent, ref, watch } from "vue";
|
|
2
4
|
import "./HkExpansionPanel.scss";
|
|
3
5
|
|
|
@@ -87,9 +89,7 @@ export default defineComponent({
|
|
|
87
89
|
</div>
|
|
88
90
|
)}
|
|
89
91
|
<span class="hk-expansion-panel-chevron" aria-hidden="true">
|
|
90
|
-
<
|
|
91
|
-
<polyline points="6 9 12 15 18 9" />
|
|
92
|
-
</svg>
|
|
92
|
+
<ChevronDown />
|
|
93
93
|
</span>
|
|
94
94
|
</button>
|
|
95
95
|
<div class="hk-expansion-panel-body">
|
|
@@ -64,11 +64,12 @@ afterEach(() => {
|
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
describe("HkFab shell", () => {
|
|
67
|
-
it("renders a round button with the aria label and the default chevron
|
|
67
|
+
it("renders a round button with the aria label and the default chevron glyph", () => {
|
|
68
68
|
const m = mountFab({ ariaLabel: "Jump to latest" });
|
|
69
69
|
expect(m.button.getAttribute("aria-label")).toBe("Jump to latest");
|
|
70
|
-
// No icon prop ->
|
|
71
|
-
|
|
70
|
+
// No icon prop -> the standard lucide chevron-down (wave B4: the
|
|
71
|
+
// hand-drawn inline fallback retired).
|
|
72
|
+
expect(m.button.querySelector("svg.lucide-chevron-down")).not.toBeNull();
|
|
72
73
|
});
|
|
73
74
|
|
|
74
75
|
it("mirrors positioning/corner/size/variant props onto data attributes", () => {
|
package/src/components/HkFab.tsx
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ChevronDown } from "lucide-vue-next";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
defineComponent,
|
|
3
5
|
h,
|
|
@@ -141,19 +143,9 @@ export default defineComponent({
|
|
|
141
143
|
: RegistryIcon
|
|
142
144
|
? h(RegistryIcon)
|
|
143
145
|
: (
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
<
|
|
147
|
-
viewBox="0 0 24 24"
|
|
148
|
-
fill="none"
|
|
149
|
-
stroke="currentColor"
|
|
150
|
-
stroke-width="2"
|
|
151
|
-
stroke-linecap="round"
|
|
152
|
-
stroke-linejoin="round"
|
|
153
|
-
aria-hidden="true"
|
|
154
|
-
>
|
|
155
|
-
<polyline points="6 9 12 15 18 9" />
|
|
156
|
-
</svg>
|
|
146
|
+
// Wave B4: the hand-drawn fallback retired — the standard
|
|
147
|
+
// lucide component, same channel as every other control.
|
|
148
|
+
<ChevronDown aria-hidden="true" />
|
|
157
149
|
)}
|
|
158
150
|
</span>
|
|
159
151
|
);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ChevronDown } from "lucide-vue-next";
|
|
2
|
+
|
|
1
3
|
import { defineComponent, ref, type PropType } from "vue";
|
|
2
4
|
|
|
3
5
|
import HkLocalePickerPopup from "./HkLocalePickerPopup";
|
|
@@ -50,14 +52,7 @@ export const HkLocalePicker = defineComponent({
|
|
|
50
52
|
onClick={() => (open.value = !open.value)}
|
|
51
53
|
>
|
|
52
54
|
{props.currentLocale.toUpperCase()}
|
|
53
|
-
<
|
|
54
|
-
<path
|
|
55
|
-
d="M2 3.5l3 3 3-3"
|
|
56
|
-
fill="none"
|
|
57
|
-
stroke="currentColor"
|
|
58
|
-
stroke-width="1.2"
|
|
59
|
-
/>
|
|
60
|
-
</svg>
|
|
55
|
+
<ChevronDown size={10} aria-hidden="true" />
|
|
61
56
|
</button>
|
|
62
57
|
<HkLocalePickerPopup
|
|
63
58
|
open={open.value}
|
|
@@ -2,21 +2,19 @@
|
|
|
2
2
|
* Behavioral contract for the DESKTOP modal open/close choreography — run
|
|
3
3
|
* against the COMPILED stylesheet, not the source text.
|
|
4
4
|
*
|
|
5
|
-
* User direction 2026-11-
|
|
6
|
-
* the
|
|
7
|
-
* `translate(…) scaleY(0.9) →
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* `
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* body-only uniform `scale(0.9)`, and the 2026-11-06 `scale(1.1, 1)`
|
|
19
|
-
* overshoot.
|
|
5
|
+
* User direction 2026-11-07 (supersedes the 2026-11-05 content-only ride
|
|
6
|
+
* and the 2026-11-06 body scales): ONLY THE HEIGHT COMPRESSES — width is
|
|
7
|
+
* never scaled. The frame settles `translate(…) scaleY(0.9) →
|
|
8
|
+
* translate(…) scaleY(1)` about its center, so the box grows symmetrically
|
|
9
|
+
* and anything centered in it (the content region above all) stays
|
|
10
|
+
* horizontally AND vertically centered at every t; the translate prefix is
|
|
11
|
+
* byte-identical in every state so the ride can never re-seat the frame.
|
|
12
|
+
* `.hk-modal-body` carries NO transform rule of its own: its vertical ride
|
|
13
|
+
* is entirely the frame's scaleY, so its width stays exactly 100% while its
|
|
14
|
+
* height follows the 0.9 → 1 compression. The retired grammars, oldest
|
|
15
|
+
* first: the 2026-11-04 whole-frame `scale(1, 0.9)`, the 2026-11-05
|
|
16
|
+
* body-only uniform `scale(0.9)`, the 2026-11-06 `scale(1.1, 1)` overshoot
|
|
17
|
+
* and its same-day `scale(0.95, 1)` pinch.
|
|
20
18
|
*
|
|
21
19
|
* Why compile: a source-text scanner can be dodged by a later duplicate
|
|
22
20
|
* rule, a block comment, SCSS interpolation, `@extend` or an `@use`d
|
|
@@ -343,12 +341,8 @@ const ENTER_TRANSITION =
|
|
|
343
341
|
const LEAVE_TRANSITION =
|
|
344
342
|
"opacity var(--hk-modal-duration, 0.32s) var(--hk-modal-ease-in, cubic-bezier(0.45, 0, 0.55, 1)), " +
|
|
345
343
|
"transform var(--hk-modal-duration, 0.32s) var(--hk-modal-ease-in, cubic-bezier(0.45, 0, 0.55, 1))";
|
|
346
|
-
const BODY_ENTER_TRANSITION =
|
|
347
|
-
"transform var(--hk-modal-duration, 0.42s) var(--hk-modal-ease-out, cubic-bezier(0.33, 1, 0.68, 1))";
|
|
348
|
-
const BODY_LEAVE_TRANSITION =
|
|
349
|
-
"transform var(--hk-modal-duration, 0.32s) var(--hk-modal-ease-in, cubic-bezier(0.45, 0, 0.55, 1))";
|
|
350
344
|
|
|
351
|
-
describe("HkModal desktop open/close contract (compiled cascade, user direction 2026-11-
|
|
345
|
+
describe("HkModal desktop open/close contract (compiled cascade, user direction 2026-11-07)", () => {
|
|
352
346
|
it("compiles into a stylesheet with the ride rules present (known-positive)", () => {
|
|
353
347
|
// Guard against a vacuous suite: the compiled sheet must really contain
|
|
354
348
|
// the frame rule, the body rule and the reduced-motion flatten.
|
|
@@ -437,49 +431,27 @@ describe("HkModal desktop open/close contract (compiled cascade, user direction
|
|
|
437
431
|
expect(leaveWill).toBe("opacity, transform");
|
|
438
432
|
});
|
|
439
433
|
|
|
440
|
-
it("
|
|
441
|
-
// 2026-11-
|
|
442
|
-
//
|
|
443
|
-
//
|
|
444
|
-
//
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
.
|
|
453
|
-
.
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
expect_("leave-from", "scale(1, 1)");
|
|
461
|
-
// …and the same with the opt-in draggable flag on, where an
|
|
462
|
-
// attribute-qualified rule could otherwise slip past the mocks.
|
|
463
|
-
for (const state of RIDE) {
|
|
464
|
-
const frame = draggableFrameWith(...state.classes);
|
|
465
|
-
const body = child(frame, "hk-modal-body");
|
|
466
|
-
const expected =
|
|
467
|
-
state.name === "enter-from" || state.name === "leave-to" ? "scale(0.95, 1)" : "scale(1, 1)";
|
|
468
|
-
expect(winner(body, "transform", DESKTOP), `draggable ${state.name}`).toBe(expected);
|
|
434
|
+
it("never scales the content region: width stays 100% at every t", () => {
|
|
435
|
+
// 2026-11-07: only the height compresses. The body must carry no
|
|
436
|
+
// transform of its own in ANY ride state — its vertical ride is the
|
|
437
|
+
// frame's scaleY inherited down the tree, so a body transform here
|
|
438
|
+
// would either re-scale the width or double the Y compression.
|
|
439
|
+
const REST_OR_RIDE = [...RIDE, { name: "rest", classes: [] as string[] }];
|
|
440
|
+
// The whole transform family, on BOTH branches (R2 finding 2026-11-07
|
|
441
|
+
// (S2): the draggable branch used to pin `transform` only, so a
|
|
442
|
+
// `[data-draggable] … { scale: … }` longhand stayed green).
|
|
443
|
+
const PROPS = ["transform", "transform-origin", "scale", "translate", "rotate", "zoom", "perspective"];
|
|
444
|
+
for (const state of REST_OR_RIDE) {
|
|
445
|
+
for (const [label, frame] of [
|
|
446
|
+
["", frameWith(...state.classes)],
|
|
447
|
+
["draggable ", draggableFrameWith(...state.classes)],
|
|
448
|
+
] as const) {
|
|
449
|
+
const body = child(frame, "hk-modal-body");
|
|
450
|
+
for (const prop of PROPS) {
|
|
451
|
+
expect(winner(body, prop, DESKTOP), `${label}${state.name} body ${prop}`).toBeUndefined();
|
|
452
|
+
}
|
|
453
|
+
}
|
|
469
454
|
}
|
|
470
|
-
// At rest the body carries no transform at all.
|
|
471
|
-
expect(winner(child(frameWith(), "hk-modal-body"), "transform", DESKTOP)).toBeUndefined();
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
it("rides the content scale on the family timing tokens", () => {
|
|
475
|
-
const body = (state: string, prop: string) => {
|
|
476
|
-
const frame = frameWith(...RIDE.find((r) => r.name === state)!.classes);
|
|
477
|
-
return winner(child(frame, "hk-modal-body"), prop, DESKTOP);
|
|
478
|
-
};
|
|
479
|
-
// Whole-value pins, same rationale as the frame transitions above.
|
|
480
|
-
expect(body("enter-from", "transition")).toBe(BODY_ENTER_TRANSITION);
|
|
481
|
-
expect(body("leave-to", "transition")).toBe(BODY_LEAVE_TRANSITION);
|
|
482
|
-
expect(body("enter-from", "will-change")).toBe("transform");
|
|
483
455
|
});
|
|
484
456
|
|
|
485
457
|
it("never transforms the chrome: title bar, sub-header, footer, close button, title glyph", () => {
|
|
@@ -509,7 +481,7 @@ describe("HkModal desktop open/close contract (compiled cascade, user direction
|
|
|
509
481
|
}
|
|
510
482
|
});
|
|
511
483
|
|
|
512
|
-
it("flattens the
|
|
484
|
+
it("flattens the frame ride (and any stray body transform) under prefers-reduced-motion", () => {
|
|
513
485
|
const frame = frameWith("hk-modal-content-enter-from", "hk-modal-content-enter-active");
|
|
514
486
|
const body = child(frame, "hk-modal-body");
|
|
515
487
|
expect(winner(body, "transform", DESKTOP_REDUCED)).toBe("none");
|
|
@@ -562,6 +534,35 @@ describe("HkModal desktop open/close contract (compiled cascade, user direction
|
|
|
562
534
|
).toBeUndefined();
|
|
563
535
|
});
|
|
564
536
|
|
|
537
|
+
it("never lets ANY rule put a ride transform on the content region", () => {
|
|
538
|
+
// Fail-closed sweep, selector-level and media-independent (R2 finding
|
|
539
|
+
// 2026-11-07 (S2): the cascade mock cannot match `:not()`, a type
|
|
540
|
+
// qualifier, an extra media gate or a pseudo-element, so twelve such
|
|
541
|
+
// mutations stayed green). Every rule that targets the body — in any
|
|
542
|
+
// media query, at any specificity — must never SCALE it. Allowed
|
|
543
|
+
// anywhere: an inert `transform: none` (the reduced-motion guard) and
|
|
544
|
+
// any `transform-origin`, which does nothing without a transform.
|
|
545
|
+
//
|
|
546
|
+
// Class-TOKEN based, not class-dot based: `div.hk-modal-body` (the same
|
|
547
|
+
// compound, type-qualified) puts a letter before the dot and slipped
|
|
548
|
+
// through the first cut, as did `[class~="hk-modal-body"]` (R3 finding
|
|
549
|
+
// 2026-11-07 (S2)). The trailing guard keeps -scroll / -inner out.
|
|
550
|
+
const BODY_TARGET = /(^|[^\w-])hk-modal-body(?![\w-])/;
|
|
551
|
+
const TRANSFORM_FAMILY = /^(transform|transform-origin|translate|scale|rotate|zoom|perspective)$/;
|
|
552
|
+
const INERT = new Set(["none", "auto"]);
|
|
553
|
+
const offenders: string[] = [];
|
|
554
|
+
for (const rule of RULES) {
|
|
555
|
+
if (!BODY_TARGET.test(rule.selector)) continue;
|
|
556
|
+
for (const prop of rule.declarations.keys()) {
|
|
557
|
+
if (!TRANSFORM_FAMILY.test(prop)) continue;
|
|
558
|
+
if (prop === "transform-origin") continue;
|
|
559
|
+
const value = (rule.declarations.get(prop) ?? "").replace(/\s+/g, " ").trim();
|
|
560
|
+
if (!INERT.has(value)) offenders.push(`${rule.selector} { ${prop}: ${value} }`);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
expect(offenders, "the content region must never be scaled").toEqual([]);
|
|
564
|
+
});
|
|
565
|
+
|
|
565
566
|
it("never lets ANY rule put a transform on a chrome surface", () => {
|
|
566
567
|
// Fail-closed sweep: selector-level and media-independent, so a chrome
|
|
567
568
|
// transform is caught whatever the combinator, grouping, attribute
|
|
@@ -598,9 +599,11 @@ describe("HkModal desktop open/close contract (compiled cascade, user direction
|
|
|
598
599
|
const CHROME_ALLOWED = new Set(["opacity", "transition", "will-change", "transform"]);
|
|
599
600
|
// The contracted transform values a ride rule may carry. Frame: the
|
|
600
601
|
// three translate+scaleY states (reduced-motion flatten included);
|
|
601
|
-
// body:
|
|
602
|
+
// body: nothing (its width is never scaled — 2026-11-07).
|
|
602
603
|
const LEGAL_FRAME = new Set([CENTERING, FRAME_FROM, FRAME_TO]);
|
|
603
|
-
|
|
604
|
+
// The body carries no transform contract any more (2026-11-07): any
|
|
605
|
+
// ride rule targeting it is an offender outright.
|
|
606
|
+
const LEGAL_BODY = new Set<string>([]);
|
|
604
607
|
const offenders: string[] = [];
|
|
605
608
|
// Media-independent on purpose: a ride selector declared at top level
|
|
606
609
|
// (no media query) applies at every width, so it must obey the same
|
|
@@ -641,19 +644,19 @@ describe("HkModal desktop open/close contract (compiled cascade, user direction
|
|
|
641
644
|
});
|
|
642
645
|
|
|
643
646
|
it("keeps the contracted per-axis grammar (no alternate syntax escapes)", () => {
|
|
644
|
-
// 2026-11-
|
|
645
|
-
// body rides
|
|
646
|
-
//
|
|
647
|
-
//
|
|
648
|
-
// properties — would break the contracted
|
|
649
|
-
// be impossible.
|
|
647
|
+
// 2026-11-07 grammar: the FRAME rides `translate(…) scaleY(s)` and the
|
|
648
|
+
// body rides nothing. Any other expression of the same idea — a
|
|
649
|
+
// single-arg scale or a scaleX on the frame list, a two-arg scale, any
|
|
650
|
+
// body transform, scale3d, a computed matrix, or the independent
|
|
651
|
+
// transform properties — would break the contracted shape (or the
|
|
652
|
+
// width contract) and must be impossible.
|
|
650
653
|
const BODY_ESCAPES = /scale[XYZ]\(|scale3d\(|matrix[23]d?\(/;
|
|
651
654
|
const FRAME_ESCAPES = /scale\([^)]*,|scaleX\(|scale3d\(|matrix[23]d?\(|\brotate\(/;
|
|
652
655
|
for (const state of RIDE) {
|
|
653
656
|
const frame = frameWith(...state.classes);
|
|
654
657
|
const body = child(frame, "hk-modal-body");
|
|
655
658
|
const bodyTransform = winner(body, "transform", DESKTOP) ?? "";
|
|
656
|
-
expect(bodyTransform, `body ${state.name}`).
|
|
659
|
+
expect(bodyTransform, `body ${state.name}`).toBe("");
|
|
657
660
|
expect(bodyTransform, `body ${state.name}`).not.toMatch(BODY_ESCAPES);
|
|
658
661
|
expect(winner(body, "scale", DESKTOP), `body ${state.name}`).toBeUndefined();
|
|
659
662
|
expect(winner(body, "translate", DESKTOP), `body ${state.name}`).toBeUndefined();
|
|
@@ -113,23 +113,21 @@
|
|
|
113
113
|
// transform rule of its own; it inherits this single frame scale, which
|
|
114
114
|
// IS the window-height motion the user asked for.
|
|
115
115
|
//
|
|
116
|
-
// The content region
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
// would produce.
|
|
116
|
+
// The content region does NOT ride on its own (user direction 2026-11-07,
|
|
117
|
+
// superseding the body scale that shipped in 0.55.303 / 0.55.304): width
|
|
118
|
+
// is never scaled, only height is. `.hk-modal-body` therefore carries NO
|
|
119
|
+
// transform rule in any ride state — its vertical ride is entirely the
|
|
120
|
+
// frame's `scaleY` above, so during the open/close its width stays exactly
|
|
121
|
+
// 100% of the window while its height follows the 0.9 → 1 compression. Two
|
|
122
|
+
// retired grammars before this one: the two-arg `scale(0.95, 1)` pinch and
|
|
123
|
+
// the `scale(1.1, 1)` overshoot.
|
|
125
124
|
//
|
|
126
125
|
// Hosts retune the ride through the `--hk-modal-*` tokens (duration /
|
|
127
126
|
// easing) or the body padding vars — NOT by setting `transform` on
|
|
128
|
-
// `.hk-modal-body` or the frame: the state rules pair matched
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
// reduced motion.
|
|
127
|
+
// `.hk-modal-body` or the frame: the frame's state rules pair a matched
|
|
128
|
+
// function list (`translate + scaleY`) so both ends of the interpolation
|
|
129
|
+
// ride the same shape, and a host's single-class transform would be
|
|
130
|
+
// overridden mid-ride and again under reduced motion.
|
|
133
131
|
//
|
|
134
132
|
// No clip-path and no Y offset ride the open/close: the visible box IS the
|
|
135
133
|
// frame at every t, so nothing is ever sliced off (the 2026-09-14 clip
|
|
@@ -153,7 +151,7 @@
|
|
|
153
151
|
}
|
|
154
152
|
|
|
155
153
|
// Close: the reveal's TRUE reverse — same chrome fade, while the window
|
|
156
|
-
// settles back toward 90% height
|
|
154
|
+
// settles back toward 90% height, width untouched in both directions.
|
|
157
155
|
.hk-modal-content-leave-active {
|
|
158
156
|
transition:
|
|
159
157
|
opacity var(--hk-modal-duration, 0.32s)
|
|
@@ -185,37 +183,6 @@
|
|
|
185
183
|
)
|
|
186
184
|
scaleY(1);
|
|
187
185
|
}
|
|
188
|
-
|
|
189
|
-
// Content region: the one surface with its own transform. The timing
|
|
190
|
-
// lives on the per-state transition so the enter and the leave can
|
|
191
|
-
// differ (0.42s open / 0.32s close) exactly like the chrome fade does.
|
|
192
|
-
.hk-modal-content-enter-active .hk-modal-body {
|
|
193
|
-
transform-origin: 50% 50%;
|
|
194
|
-
transition:
|
|
195
|
-
transform var(--hk-modal-duration, 0.42s)
|
|
196
|
-
var(--hk-modal-ease-out, cubic-bezier(0.33, 1, 0.68, 1));
|
|
197
|
-
will-change: transform;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
.hk-modal-content-leave-active .hk-modal-body {
|
|
201
|
-
transform-origin: 50% 50%;
|
|
202
|
-
transition:
|
|
203
|
-
transform var(--hk-modal-duration, 0.32s)
|
|
204
|
-
var(--hk-modal-ease-in, cubic-bezier(0.45, 0, 0.55, 1));
|
|
205
|
-
will-change: transform;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Both ends two-arg `scale`: X starts at 95% and spreads to 1, Y stays 1
|
|
209
|
-
// (the body's vertical ride comes from the frame's scaleY, not itself).
|
|
210
|
-
.hk-modal-content-enter-from .hk-modal-body,
|
|
211
|
-
.hk-modal-content-leave-to .hk-modal-body {
|
|
212
|
-
transform: scale(0.95, 1);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
.hk-modal-content-enter-to .hk-modal-body,
|
|
216
|
-
.hk-modal-content-leave-from .hk-modal-body {
|
|
217
|
-
transform: scale(1, 1);
|
|
218
|
-
}
|
|
219
186
|
}
|
|
220
187
|
|
|
221
188
|
// ------
|
|
@@ -704,14 +671,13 @@
|
|
|
704
671
|
calc(-50% + var(--hk-modal-shift-y, 0px))
|
|
705
672
|
);
|
|
706
673
|
}
|
|
707
|
-
// The content
|
|
708
|
-
//
|
|
709
|
-
//
|
|
674
|
+
// The content region carries no transform of its own any more (width is
|
|
675
|
+
// never scaled — 2026-11-07), so only the frame needs flattening above.
|
|
676
|
+
// The body lines stay as a fail-closed guard: if a future state rule ever
|
|
677
|
+
// reintroduces a body transform, reduced motion still flattens it.
|
|
710
678
|
.hk-modal-content .hk-modal-body {
|
|
711
679
|
transform: none;
|
|
712
680
|
transition: none;
|
|
713
|
-
// …and drop the compositor hint the ride would otherwise leave on
|
|
714
|
-
// the (tall) content block for the flattened frame.
|
|
715
681
|
will-change: auto;
|
|
716
682
|
}
|
|
717
683
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ChevronRight } from "lucide-vue-next";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
computed,
|
|
3
5
|
defineComponent,
|
|
@@ -626,18 +628,7 @@ export default defineComponent({
|
|
|
626
628
|
.join(" ");
|
|
627
629
|
|
|
628
630
|
const separator = () => (
|
|
629
|
-
<
|
|
630
|
-
class="hk-modal-breadcrumb-sep"
|
|
631
|
-
width="12"
|
|
632
|
-
height="12"
|
|
633
|
-
viewBox="0 0 24 24"
|
|
634
|
-
fill="none"
|
|
635
|
-
stroke="currentColor"
|
|
636
|
-
stroke-width="2"
|
|
637
|
-
stroke-linecap="round"
|
|
638
|
-
>
|
|
639
|
-
<polyline points="9 18 15 12 9 6" />
|
|
640
|
-
</svg>
|
|
631
|
+
<ChevronRight class="hk-modal-breadcrumb-sep" size={12} />
|
|
641
632
|
);
|
|
642
633
|
|
|
643
634
|
return () =>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { User } from "lucide-vue-next";
|
|
2
|
+
|
|
1
3
|
import { credentialAutocomplete } from "../runtime/credentialAutofill";
|
|
2
4
|
import { defineComponent, ref } from "vue";
|
|
3
5
|
import { useI18n } from "../i18n/context";
|
|
@@ -131,20 +133,7 @@ export const HkSignInCard = defineComponent({
|
|
|
131
133
|
slots.usernameIcon ? (
|
|
132
134
|
slots.usernameIcon()
|
|
133
135
|
) : (
|
|
134
|
-
<
|
|
135
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
136
|
-
viewBox="0 0 24 24"
|
|
137
|
-
fill="none"
|
|
138
|
-
stroke="currentColor"
|
|
139
|
-
stroke-width="2"
|
|
140
|
-
stroke-linecap="round"
|
|
141
|
-
stroke-linejoin="round"
|
|
142
|
-
class="s-auth-card-field-icon"
|
|
143
|
-
aria-hidden="true"
|
|
144
|
-
>
|
|
145
|
-
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"></path>
|
|
146
|
-
<circle cx="12" cy="7" r="4"></circle>
|
|
147
|
-
</svg>
|
|
136
|
+
<User class="s-auth-card-field-icon" aria-hidden="true" />
|
|
148
137
|
),
|
|
149
138
|
}}
|
|
150
139
|
</HkInput>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Check } from "lucide-vue-next";
|
|
2
|
+
|
|
1
3
|
import { defineComponent, h, type Component, type PropType } from "vue";
|
|
2
4
|
|
|
3
5
|
import "./HkStepGuide.scss";
|
|
@@ -77,20 +79,7 @@ export default defineComponent({
|
|
|
77
79
|
>
|
|
78
80
|
<span class="hk-step-guide-ordinal">
|
|
79
81
|
{isDone ? (
|
|
80
|
-
<
|
|
81
|
-
class="hk-step-guide-check"
|
|
82
|
-
viewBox="0 0 24 24"
|
|
83
|
-
aria-hidden="true"
|
|
84
|
-
>
|
|
85
|
-
<path
|
|
86
|
-
d="M20 6L9 17l-5-5"
|
|
87
|
-
fill="none"
|
|
88
|
-
stroke="currentColor"
|
|
89
|
-
stroke-width="3"
|
|
90
|
-
stroke-linecap="round"
|
|
91
|
-
stroke-linejoin="round"
|
|
92
|
-
/>
|
|
93
|
-
</svg>
|
|
82
|
+
<Check class="hk-step-guide-check" stroke-width={3} aria-hidden="true" />
|
|
94
83
|
) : (
|
|
95
84
|
idx + 1
|
|
96
85
|
)}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Check, ChevronUp, GripVertical } from "lucide-vue-next";
|
|
2
|
+
|
|
1
3
|
import { computed, defineComponent, inject, onBeforeUnmount, onMounted, ref, watch, type PropType } from "vue";
|
|
2
4
|
|
|
3
5
|
import { useI18n } from "../i18n/context";
|
|
@@ -770,17 +772,7 @@ export default defineComponent({
|
|
|
770
772
|
]}
|
|
771
773
|
>
|
|
772
774
|
{allChecked.value && (
|
|
773
|
-
<
|
|
774
|
-
class="hk-table-checkbox-icon"
|
|
775
|
-
viewBox="0 0 24 24"
|
|
776
|
-
fill="none"
|
|
777
|
-
stroke="currentColor"
|
|
778
|
-
stroke-width="3"
|
|
779
|
-
stroke-linecap="round"
|
|
780
|
-
stroke-linejoin="round"
|
|
781
|
-
>
|
|
782
|
-
<polyline points="20 6 9 17 4 12" />
|
|
783
|
-
</svg>
|
|
775
|
+
<Check class="hk-table-checkbox-icon" stroke-width={3} />
|
|
784
776
|
)}
|
|
785
777
|
</span>
|
|
786
778
|
</label>
|
|
@@ -802,20 +794,10 @@ export default defineComponent({
|
|
|
802
794
|
>
|
|
803
795
|
<span class="hk-table-header-label">{col.title}</span>
|
|
804
796
|
{canSort && sortKey.value === col.key && (
|
|
805
|
-
<
|
|
806
|
-
class={[
|
|
797
|
+
<ChevronUp class={[
|
|
807
798
|
"hk-table-sort-icon",
|
|
808
799
|
sortDirection.value === "desc" ? "hk-table-sort-icon-desc" : "",
|
|
809
|
-
]}
|
|
810
|
-
viewBox="0 0 24 24"
|
|
811
|
-
fill="none"
|
|
812
|
-
stroke="currentColor"
|
|
813
|
-
stroke-width="2"
|
|
814
|
-
stroke-linecap="round"
|
|
815
|
-
stroke-linejoin="round"
|
|
816
|
-
>
|
|
817
|
-
<polyline points="18 15 12 9 6 15" />
|
|
818
|
-
</svg>
|
|
800
|
+
]} />
|
|
819
801
|
)}
|
|
820
802
|
</th>
|
|
821
803
|
);
|
|
@@ -874,14 +856,7 @@ export default defineComponent({
|
|
|
874
856
|
onPointerdown={(e: PointerEvent) => onHandlePointerdown(e, index)}
|
|
875
857
|
onKeydown={(e: KeyboardEvent) => onHandleKeydown(e, index)}
|
|
876
858
|
>
|
|
877
|
-
<
|
|
878
|
-
<circle cx="3.5" cy="3" r="1.2" />
|
|
879
|
-
<circle cx="8.5" cy="3" r="1.2" />
|
|
880
|
-
<circle cx="3.5" cy="7" r="1.2" />
|
|
881
|
-
<circle cx="8.5" cy="7" r="1.2" />
|
|
882
|
-
<circle cx="3.5" cy="11" r="1.2" />
|
|
883
|
-
<circle cx="8.5" cy="11" r="1.2" />
|
|
884
|
-
</svg>
|
|
859
|
+
<GripVertical size={14} aria-hidden="true" />
|
|
885
860
|
</span>
|
|
886
861
|
</td>
|
|
887
862
|
)}
|
|
@@ -902,17 +877,7 @@ export default defineComponent({
|
|
|
902
877
|
]}
|
|
903
878
|
>
|
|
904
879
|
{selectedRowKeys.value.has(rowKey) && (
|
|
905
|
-
<
|
|
906
|
-
class="hk-table-checkbox-icon"
|
|
907
|
-
viewBox="0 0 24 24"
|
|
908
|
-
fill="none"
|
|
909
|
-
stroke="currentColor"
|
|
910
|
-
stroke-width="3"
|
|
911
|
-
stroke-linecap="round"
|
|
912
|
-
stroke-linejoin="round"
|
|
913
|
-
>
|
|
914
|
-
<polyline points="20 6 9 17 4 12" />
|
|
915
|
-
</svg>
|
|
880
|
+
<Check class="hk-table-checkbox-icon" stroke-width={3} />
|
|
916
881
|
)}
|
|
917
882
|
</span>
|
|
918
883
|
</label>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ChevronRight } from "lucide-vue-next";
|
|
2
|
+
|
|
1
3
|
import { defineComponent, ref, watch, h, type Component, type PropType, type VNodeChild } from "vue";
|
|
2
4
|
|
|
3
5
|
import "./HkTree.scss";
|
|
@@ -158,9 +160,7 @@ const TreeNodeRow = ({
|
|
|
158
160
|
onClick={(e: MouseEvent) => { e.stopPropagation(); if (hasChildren) onToggle(node.id); }}
|
|
159
161
|
>
|
|
160
162
|
{hasChildren ? (
|
|
161
|
-
<
|
|
162
|
-
<path d="M6 4l4 4-4 4" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
|
163
|
-
</svg>
|
|
163
|
+
<ChevronRight class="hk-tree-chevron" data-open={isExpanded || undefined} size={12} stroke-width={1.5} />
|
|
164
164
|
) : (
|
|
165
165
|
<span class="hk-tree-leaf" />
|
|
166
166
|
)}
|