@celestia-island/hikari 0.55.243 → 0.55.244

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.243",
3
+ "version": "0.55.244",
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",
@@ -33,6 +33,7 @@ vi.mock("@celestia-island/hikari", async (importOriginal) => {
33
33
 
34
34
  import { HkFaceShell } from "./HkFaceShell";
35
35
  import { HkAdminShell } from "./HkAdminShell";
36
+ import { provideMenuGroupState } from "../composables/useMenuGroupState";
36
37
  import HkMenu, { type HkMenuItem } from "./HkMenu";
37
38
 
38
39
  /**
@@ -722,6 +723,73 @@ async function settle(container: HTMLElement, key: "rail" | "full"): Promise<HTM
722
723
  return generation(container, key);
723
724
  }
724
725
 
726
+ describe("rail group fold — a host that OWNS the slot provides the store", () => {
727
+ beforeEach(() => {
728
+ vi.useFakeTimers();
729
+ });
730
+
731
+ it("carries the fold through a rail -> peek flip (chest's AdminLayout shape)", async () => {
732
+ // chest defines the shell's sidebar slot from AdminLayout, so the slot
733
+ // content's component PARENT is AdminLayout — not the shell. A provide
734
+ // inside HkFaceShell therefore cannot reach it (measured on chest:
735
+ // 0.55.240 lost the fold there while the shell's own slot kept it).
736
+ // The fix for that shape is the host starting the chain itself:
737
+ // provideMenuGroupState() in ITS setup, above the swap. This test is
738
+ // that shape, and it goes red if the export stops reaching slot
739
+ // content or if HkMenu stops injecting.
740
+ const container = document.createElement("div");
741
+ document.body.appendChild(container);
742
+ const Wrapper = defineComponent({
743
+ name: "SlotOwnerHarness",
744
+ setup() {
745
+ provideMenuGroupState();
746
+ const railStyle = ref<"expanded" | "rail">("rail");
747
+ return () =>
748
+ h(HkFaceShell, {
749
+ navTitle: "Navigation",
750
+ sidebarCollapsible: true,
751
+ sidebarRailStyle: railStyle.value,
752
+ "onUpdate:sidebarRailStyle": (v: string) => {
753
+ railStyle.value = v as "expanded" | "rail";
754
+ },
755
+ }, {
756
+ header: () => null,
757
+ sidebar: (params: { collapsed: boolean }) =>
758
+ h(HkMenu, {
759
+ variant: "sidebar",
760
+ items: GROUP_ITEMS,
761
+ open: false,
762
+ defaultExpandGroups: true,
763
+ collapsed: params.collapsed,
764
+ }),
765
+ content: () => h("div", { class: "content-mock" }, "CONTENT"),
766
+ });
767
+ },
768
+ });
769
+ const app = createApp(Wrapper);
770
+ app.mount(container);
771
+ mounts.push({ app, container });
772
+
773
+ const railGen = await settle(container, "rail");
774
+ expect(groupToggle(railGen).getAttribute("aria-expanded")).toBe("true");
775
+ groupToggle(railGen).click();
776
+ await vi.advanceTimersByTimeAsync(0);
777
+ expect(groupToggle(railGen).getAttribute("aria-expanded")).toBe("false");
778
+
779
+ // Peek: the slot is handed full rows — a brand-new HkMenu instance.
780
+ container
781
+ .querySelector<HTMLElement>(".hk-sidebar-rail-host")!
782
+ .dispatchEvent(POINTER_ENTER());
783
+ await vi.advanceTimersByTimeAsync(400);
784
+ const peekGen = await settle(container, "full");
785
+ expect(
786
+ groupToggle(peekGen).getAttribute("aria-expanded"),
787
+ "the host-provided store crosses into the peek's fresh generation",
788
+ ).toBe("false");
789
+ expect(peekGen.textContent, "and the peek lists no children").not.toContain("Audit log");
790
+ });
791
+ });
792
+
725
793
  describe("rail group fold survives the crossfade generations (#43)", () => {
726
794
  beforeEach(() => {
727
795
  vi.useFakeTimers();
@@ -41,6 +41,17 @@ import { inject, provide, shallowRef, type InjectionKey } from "vue";
41
41
  * menus mounted in the same shell share one key space — name their group
42
42
  * keys distinctly (they already name destinations, so this is the
43
43
  * natural convention).
44
+ *
45
+ * HOSTS THAT OWN THE SLOT THEMSELVES (chest's console, 2026-10-31): a
46
+ * slot's component parent is the component that DEFINED it, so a
47
+ * provide inside HkFaceShell does NOT reach content the host writes for
48
+ * the shell's sidebar slot — the host is that content's parent and the
49
+ * shell is only its DOM/CSS host (measured: chest's grouped nav lost the
50
+ * fold on 0.55.240 while the shell's own slot content kept it). Such a
51
+ * host starts the chain at its own setup level with
52
+ * provideMenuGroupState (one call, ABOVE the swap — the page component
53
+ * survives a density flip). HkMenu's inject then finds it through the
54
+ * host, and every generation the swap mounts shares it.
44
55
  */
45
56
 
46
57
  /** The fold store a shell provides above its sidebar swap. */
package/src/index.ts CHANGED
@@ -481,8 +481,25 @@ export {
481
481
  SIDEBAR_RAIL_PEEK_DELAY,
482
482
  SIDEBAR_RAIL_PEEK_GRACE,
483
483
  SIDEBAR_RAIL_PIN_FALLBACK,
484
+ SIDEBAR_RAIL_CLIP_SELECTOR,
485
+ SIDEBAR_RAIL_TOGGLE_BUTTON_SELECTOR,
484
486
  } from "./composables/useSidebarRail";
485
487
  export type { SidebarRailOptions, SidebarRailHandle } from "./composables/useSidebarRail";
488
+ // The sidebar GROUP FOLD store (known-live-issues #43). HkFaceShell and
489
+ // HkSidebar provide one above their rail swap, so slot content THEY own
490
+ // shares the fold across density generations. A host that defines the
491
+ // shell's sidebar slot ITSELF (chest's AdminLayout) owns the slot's
492
+ // component parent — a provide from inside the shell cannot reach it —
493
+ // and must start the chain at its own setup level:
494
+ //
495
+ // setup() { provideMenuGroupState(); return () => h(HkFaceShell, …) }
496
+ //
497
+ // Call it ABOVE the swap (i.e. in the component that survives a flip).
498
+ export {
499
+ provideMenuGroupState,
500
+ useMenuGroupState,
501
+ } from "./composables/useMenuGroupState";
502
+ export type { MenuGroupState } from "./composables/useMenuGroupState";
486
503
  export {
487
504
  drawnScale,
488
505
  frameMetrics,