@takazudo/zudo-doc 6.1.1 → 7.0.0

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.
@@ -25,7 +25,7 @@ import {
25
25
  CURRENT_PATH_DATASET_KEY,
26
26
  readCurrentPath
27
27
  } from "../current-path/index.js";
28
- import { ensureSidebarScrollPreserve } from "./sidebar-scroll-preserve.js";
28
+ import { ensureSidebarScrollPreserve, notifySidebarScrollReady } from "./sidebar-scroll-preserve.js";
29
29
  import {
30
30
  formatYearLabel,
31
31
  formatYearMonthLabel,
@@ -237,6 +237,13 @@ function SidebarTree({
237
237
  const filteredNodes = computed(
238
238
  () => query.value ? filterTree(selectedNodes.value, query.value) : selectedNodes.value
239
239
  );
240
+ scope.effect(() => {
241
+ void selected.value;
242
+ void selectedNodes.value;
243
+ void query.value;
244
+ const nav = navRef.current;
245
+ if (nav) notifySidebarScrollReady(nav);
246
+ });
240
247
  const locale = localeProp ?? localeLinks?.find((link) => link.active)?.code ?? "en";
241
248
  const footer = /* @__PURE__ */ jsx(
242
249
  SidebarFooter,
@@ -258,97 +265,106 @@ function SidebarTree({
258
265
  when: computed(
259
266
  () => activeSlug.value === void 0 && !!rootMenuItems
260
267
  ),
261
- fallback: () => /* @__PURE__ */ jsxs("nav", { ref: navRef, tabindex: -1, children: [
262
- rootMenuItems ? /* @__PURE__ */ jsxs(
263
- "button",
264
- {
265
- type: "button",
266
- "on:click": () => {
267
- showingRootMenu.value = true;
268
- },
269
- class: "lg:hidden flex w-full items-center gap-hsp-xs px-hsp-sm py-vsp-xs text-left text-small text-muted hover:text-fg border-b border-muted",
270
- children: [
271
- /* @__PURE__ */ jsx(ChevronLeft, { class: "h-icon-sm w-icon-sm shrink-0" }),
272
- backToMenuLabel ?? "Back to main menu"
273
- ]
274
- }
275
- ) : null,
276
- /* @__PURE__ */ jsx("div", { class: "px-hsp-sm py-vsp-xs border-b border-muted", "data-sidebar-filter-region": true, children: /* @__PURE__ */ jsxs("div", { class: "flex items-center gap-hsp-xs bg-surface rounded px-hsp-sm py-vsp-2xs", children: [
277
- /* @__PURE__ */ jsx(Search, { class: "h-[14px] w-[14px] text-muted shrink-0" }),
278
- /* @__PURE__ */ jsx(
279
- "input",
280
- {
281
- ref: filterRef,
282
- type: "text",
283
- "aria-label": "Filter navigation",
284
- placeholder: filterPlaceholder,
285
- modelValue: query,
286
- "on:input": (event) => {
287
- query.value = event.target.value;
288
- save();
289
- },
290
- class: "bg-transparent text-small outline-none w-full text-fg placeholder:text-muted focus-visible:outline-2 focus-visible:outline-accent",
291
- style: "outline-offset:-4px"
292
- }
293
- )
294
- ] }) }),
295
- navigation ? /* @__PURE__ */ jsx(Show, { when: computed(() => broader.value !== null), children: () => /* @__PURE__ */ jsx("div", { class: "border-b border-muted px-hsp-md py-vsp-2xs text-small", "data-sidebar-scope-toolbar": true, children: /* @__PURE__ */ jsxs("div", { class: "flex items-center justify-between gap-hsp-xs", "data-sidebar-scope-actions": true, children: [
296
- /* @__PURE__ */ jsxs(
297
- "button",
298
- {
299
- type: "button",
300
- "data-sidebar-broaden": true,
301
- disabled: computed(() => broader.value === null),
302
- "on:click": () => {
303
- if (broader.value !== null) changeScope(broader.value);
304
- },
305
- style: "min-height:40px",
306
- class: "flex items-center gap-hsp-sm px-hsp-xs font-medium rounded text-fg hover:bg-surface focus-visible:bg-surface focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent disabled:text-muted disabled:opacity-50",
307
- children: [
308
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2191" }),
309
- labels.broaden
310
- ]
311
- }
312
- ),
313
- /* @__PURE__ */ jsx(Show, { when: canRestore, children: () => /* @__PURE__ */ jsx(
314
- "button",
315
- {
316
- type: "button",
317
- "data-sidebar-restore": true,
318
- "on:click": () => changeScope(null),
319
- title: labels.restore,
320
- "aria-label": labels.restore,
321
- style: "width:40px;height:40px",
322
- class: "grid place-items-center shrink-0 rounded text-muted hover:text-fg focus-visible:text-fg focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
323
- children: /* @__PURE__ */ jsxs("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "aria-hidden": "true", children: [
324
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
325
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "6" }),
326
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "2" })
327
- ] })
328
- }
329
- ) })
330
- ] }) }) }) : null,
331
- /* @__PURE__ */ jsx("div", { "data-sidebar-tree-root": true, children: /* @__PURE__ */ jsx(
332
- Show,
333
- {
334
- when: computed(() => selectedNodes.value.length === 1 && selectedNodes.value[0]?.shape === "note-tray"),
335
- fallback: () => /* @__PURE__ */ jsx(NodeList, { nodes: filteredNodes, currentSlug: activeSlug, depth: 0, forceOpen: computed(() => !!query.value), scopeControls }),
336
- children: () => /* @__PURE__ */ jsx(Show, { when: computed(() => !!filteredNodes.value[0]), children: () => /* @__PURE__ */ jsx(
337
- TrayList,
268
+ fallback: () => /* @__PURE__ */ jsxs(
269
+ "nav",
270
+ {
271
+ ref: navRef,
272
+ tabindex: -1,
273
+ "data-sidebar-context": navigation?.id,
274
+ "data-sidebar-scope": computed(() => selected.value ?? ""),
275
+ children: [
276
+ rootMenuItems ? /* @__PURE__ */ jsxs(
277
+ "button",
338
278
  {
339
- tray: computed(() => filteredNodes.value[0]),
340
- itemCount: getNoteTrayItems(selectedNodes.value[0]).length,
341
- currentSlug: activeSlug,
342
- forceOpen: computed(() => !!query.value),
343
- locale,
344
- dateFormats,
345
- scopeControls
279
+ type: "button",
280
+ "on:click": () => {
281
+ showingRootMenu.value = true;
282
+ },
283
+ class: "lg:hidden flex w-full items-center gap-hsp-xs px-hsp-sm py-vsp-xs text-left text-small text-muted hover:text-fg border-b border-muted",
284
+ children: [
285
+ /* @__PURE__ */ jsx(ChevronLeft, { class: "h-icon-sm w-icon-sm shrink-0" }),
286
+ backToMenuLabel ?? "Back to main menu"
287
+ ]
346
288
  }
347
- ) })
348
- }
349
- ) }),
350
- footer
351
- ] }),
289
+ ) : null,
290
+ /* @__PURE__ */ jsx("div", { class: "px-hsp-sm py-vsp-xs border-b border-muted", "data-sidebar-filter-region": true, children: /* @__PURE__ */ jsxs("div", { class: "flex items-center gap-hsp-xs bg-surface rounded px-hsp-sm py-vsp-2xs", children: [
291
+ /* @__PURE__ */ jsx(Search, { class: "h-[14px] w-[14px] text-muted shrink-0" }),
292
+ /* @__PURE__ */ jsx(
293
+ "input",
294
+ {
295
+ ref: filterRef,
296
+ type: "text",
297
+ "aria-label": "Filter navigation",
298
+ placeholder: filterPlaceholder,
299
+ modelValue: query,
300
+ "on:input": (event) => {
301
+ query.value = event.target.value;
302
+ save();
303
+ },
304
+ class: "bg-transparent text-small outline-none w-full text-fg placeholder:text-muted focus-visible:outline-2 focus-visible:outline-accent",
305
+ style: "outline-offset:-4px"
306
+ }
307
+ )
308
+ ] }) }),
309
+ navigation ? /* @__PURE__ */ jsx(Show, { when: computed(() => broader.value !== null), children: () => /* @__PURE__ */ jsx("div", { class: "border-b border-muted px-hsp-md py-vsp-2xs text-small", "data-sidebar-scope-toolbar": true, children: /* @__PURE__ */ jsxs("div", { class: "flex items-center justify-between gap-hsp-xs", "data-sidebar-scope-actions": true, children: [
310
+ /* @__PURE__ */ jsxs(
311
+ "button",
312
+ {
313
+ type: "button",
314
+ "data-sidebar-broaden": true,
315
+ disabled: computed(() => broader.value === null),
316
+ "on:click": () => {
317
+ if (broader.value !== null) changeScope(broader.value);
318
+ },
319
+ style: "min-height:40px",
320
+ class: "flex items-center gap-hsp-sm px-hsp-xs font-medium rounded text-fg hover:bg-surface focus-visible:bg-surface focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent disabled:text-muted disabled:opacity-50",
321
+ children: [
322
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2191" }),
323
+ labels.broaden
324
+ ]
325
+ }
326
+ ),
327
+ /* @__PURE__ */ jsx(Show, { when: canRestore, children: () => /* @__PURE__ */ jsx(
328
+ "button",
329
+ {
330
+ type: "button",
331
+ "data-sidebar-restore": true,
332
+ "on:click": () => changeScope(null),
333
+ title: labels.restore,
334
+ "aria-label": labels.restore,
335
+ style: "width:40px;height:40px",
336
+ class: "grid place-items-center shrink-0 rounded text-muted hover:text-fg focus-visible:text-fg focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
337
+ children: /* @__PURE__ */ jsxs("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "aria-hidden": "true", children: [
338
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
339
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "6" }),
340
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "2" })
341
+ ] })
342
+ }
343
+ ) })
344
+ ] }) }) }) : null,
345
+ /* @__PURE__ */ jsx("div", { "data-sidebar-tree-root": true, children: /* @__PURE__ */ jsx(
346
+ Show,
347
+ {
348
+ when: computed(() => selectedNodes.value.length === 1 && selectedNodes.value[0]?.shape === "note-tray"),
349
+ fallback: () => /* @__PURE__ */ jsx(NodeList, { nodes: filteredNodes, currentSlug: activeSlug, depth: 0, forceOpen: computed(() => !!query.value), scopeControls }),
350
+ children: () => /* @__PURE__ */ jsx(Show, { when: computed(() => !!filteredNodes.value[0]), children: () => /* @__PURE__ */ jsx(
351
+ TrayList,
352
+ {
353
+ tray: computed(() => filteredNodes.value[0]),
354
+ itemCount: getNoteTrayItems(selectedNodes.value[0]).length,
355
+ currentSlug: activeSlug,
356
+ forceOpen: computed(() => !!query.value),
357
+ locale,
358
+ dateFormats,
359
+ scopeControls
360
+ }
361
+ ) })
362
+ }
363
+ ) }),
364
+ footer
365
+ ]
366
+ }
367
+ ),
352
368
  children: () => /* @__PURE__ */ jsxs("nav", { children: [
353
369
  menu,
354
370
  footer
@@ -2,20 +2,22 @@ interface SidebarScrollPreserveOptions {
2
2
  document: Document;
3
3
  requestAnimationFrame: (callback: FrameRequestCallback) => number;
4
4
  cancelAnimationFrame: (handle: number) => void;
5
+ ResizeObserver?: typeof ResizeObserver;
5
6
  }
6
7
  /**
7
8
  * Install the scroll-preservation state machine on a document.
8
9
  *
9
- * This low-level entrypoint owns an explicit cleanup for focused tests and
10
- * non-singleton hosts. The sidebar's browser module uses the durable,
11
- * duplicate-safe `ensureSidebarScrollPreserve` wrapper below instead.
12
- */
13
- export declare function installSidebarScrollPreserve({ document, requestAnimationFrame, cancelAnimationFrame, }: SidebarScrollPreserveOptions): () => void;
14
- /**
15
- * Install exactly one module-lifetime controller for a browser document.
16
- * Repeated calls from component renders or duplicate boot paths are no-ops.
10
+ * The desktop aside is replaced when sidebar island props change: preparation
11
+ * drops `data-zfb-transition-persist`, so element identity is not enough for
12
+ * the same logical tree. A saved offset is applied only after the destination
13
+ * can hold it. Chromium clamps a write that happens while `scrollHeight` is
14
+ * still too small, and that clamped 0 would stick.
17
15
  */
16
+ export declare function installSidebarScrollPreserve({ document, requestAnimationFrame, cancelAnimationFrame, ResizeObserver: ResizeObserverImpl, }: SidebarScrollPreserveOptions): () => void;
17
+ /** Install exactly one module-lifetime controller for a browser document. */
18
18
  export declare function ensureSidebarScrollPreserve(options?: SidebarScrollPreserveOptions): void;
19
+ /** The sidebar island calls this after the destination tree has committed. */
20
+ export declare function notifySidebarScrollReady(root: Element): void;
19
21
  /** Test/HMR teardown for a controller installed through the singleton wrapper. */
20
22
  export declare function disposeSidebarScrollPreserve(document: Document): void;
21
23
  export {};