@takazudo/zudo-doc 6.2.0 → 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.
- package/CHANGELOG.md +14 -0
- package/README.md +16 -1
- package/dist/compiled.css +29 -10
- package/dist/content.css +3 -0
- package/dist/doclayout/doc-layout.js +2 -0
- package/dist/features.css +31 -56
- package/dist/page-loading/page-loading-overlay.d.ts +2 -2
- package/dist/page-loading/page-loading-overlay.js +4 -2
- package/dist/page-loading.css +13 -2
- package/dist/transitions/chrome-transition-bootstrap.d.ts +2 -0
- package/dist/transitions/chrome-transition-bootstrap.js +23 -0
- package/dist/transitions/page-events.d.ts +4 -0
- package/dist/transitions/page-events.js +4 -0
- package/eject/page-loading/page-loading-overlay.tsx +7 -5
- package/package.json +13 -10
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,20 @@ The format is based on Keep a Changelog, and release notes are generated from th
|
|
|
8
8
|
|
|
9
9
|
No unreleased changes.
|
|
10
10
|
|
|
11
|
+
## [7.0.0] - 2026-10-15
|
|
12
|
+
|
|
13
|
+
### Breaking Changes
|
|
14
|
+
|
|
15
|
+
- The supported Node.js runtime moves to the current production LTS line, Node 24 (`>=24 <25`). Node 22 is no longer supported. (98c94df73)
|
|
16
|
+
- Raises the optional KaTeX peer floor to `^0.18.2 || ^0.19.0` for the GHSA-238p-pmpm-9mq7 patch; 0.16.x is no longer supported. Updates the internal KaTeX color selector while preserving server-only rendering, error fallback and math-disabled builds without KaTeX. Math-enabled hosts must install a supported version and import its local CSS. (9ee3950c9)
|
|
17
|
+
- Requires the published zfb 4.5.2 family: the `@takazudo/zfb`, `zfb-runtime` and `zfb-md-wasm` peer floors move from `^4.5.0` to `^4.5.2`. This picks up live `public/assets/` development serving, explicit and compact one-line MDX table fixes, and a `zfb dev` ready banner that waits until routes are published. Upgrade the zfb family (and `zfb-adapter-cloudflare` when used) together. (e5b7de457, d5e0d7078)
|
|
18
|
+
- The `@takazudo/zudo-doc-history-server` peer floor moves from `^6.0.0` to `^7.0.0` with this major release.
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
- Keep the header stationary during dynamic page transitions, including when destination markup replaces it, and keep the desktop sidebar stationary within the same navigation category and locale/version/tree context. Fresh destination content and existing sidebar state handling are preserved; changing articles and table-of-contents content still animate. Sidebar entry and exit also cover `hide_sidebar` pages. Loading feedback now covers the content area without dimming the header or desktop sidebar, stays out of the page animation, and clears on the content swap or navigation cancellation. (ae7152ad5, 6abeadf5f, 479309f1f)
|
|
23
|
+
- Ordinary documentation prose and navigation labels now wrap at narrow widths instead of overflowing horizontally (`overflow-wrap: anywhere` on content). Preformatted code keeps its local scrolling. (648e38da8)
|
|
24
|
+
|
|
11
25
|
## [6.2.0] - 2026-10-14
|
|
12
26
|
|
|
13
27
|
### Features
|
package/README.md
CHANGED
|
@@ -109,7 +109,7 @@ If your project renders **semi-trusted or user-submitted** HTML in a preview, ov
|
|
|
109
109
|
|
|
110
110
|
**6.0.0** is the coordinated major release of `@takazudo/zudo-doc`,
|
|
111
111
|
`@takazudo/zudo-doc-history-server` and `create-zudo-doc`. The current workspace
|
|
112
|
-
targets the published **zfb 4.5.
|
|
112
|
+
targets the published **zfb 4.5.2** family (peer floor **^4.5.2**).
|
|
113
113
|
[Upstream #4097](https://github.com/Takazudo/zudo-front-builder/issues/4097) is
|
|
114
114
|
resolved; its strict published 4.3.1 consumer control passed 3/3 with no skips or
|
|
115
115
|
retries in the [source-bound verification](../../docs/findings/zfb-4.3.1/verification.md).
|
|
@@ -160,3 +160,18 @@ zfb CSS generation. Do not use physical package `dist/*.css` import paths.
|
|
|
160
160
|
This package is published to npm as `@takazudo/zudo-doc` (since `0.2.0`, `latest` tracks the current line). Inside this repo the host site consumes it as a workspace package through its compiled `dist/` — `pnpm dev` at the repo root runs two watchers in parallel, `tsup --watch` for the JS and `tsc -p tsconfig.build.json --watch` for the `.d.ts`, so edits under `src/` rebuild both halves automatically; for a one-off rebuild use `pnpm --filter @takazudo/zudo-doc build`.
|
|
161
161
|
|
|
162
162
|
zfb itself comes from npm (versions pinned in the root `package.json`). To develop against a local zfb checkout, use the temporary `pnpm.overrides` link escape hatch documented in root `CONTRIBUTING.md` — do not commit the override.
|
|
163
|
+
|
|
164
|
+
### Optional math peer (unreleased compatibility floor)
|
|
165
|
+
|
|
166
|
+
Math-enabled consumers install `katex@^0.19.0` (supported peer range:
|
|
167
|
+
`^0.18.2 || ^0.19.0`) and import `katex/dist/katex.min.css` before
|
|
168
|
+
`@takazudo/zudo-doc/features.css` in their CSS entry. CSS and fonts are bundled
|
|
169
|
+
locally. The consumer matrix covers 0.18.2, 0.18.11 and 0.19.0. The old 0.16
|
|
170
|
+
branch is excluded because GHSA-238p-pmpm-9mq7 is patched from 0.18.2.
|
|
171
|
+
KaTeX 0.18's `.katex-base` selector replaces `.base` in the package color rule.
|
|
172
|
+
|
|
173
|
+
`MathBlock` remains server-rendered, with inline/display wrappers, safe defaults
|
|
174
|
+
and visible malformed-input fallback. A math-disabled consumer needs neither
|
|
175
|
+
KaTeX nor its stylesheet; module evaluation succeeds without it, and explicit
|
|
176
|
+
`MathBlock` rendering reports a useful missing-peer error. This source change
|
|
177
|
+
raises the compatibility floor and is not yet published to npm.
|
package/dist/compiled.css
CHANGED
|
@@ -626,6 +626,7 @@ body {
|
|
|
626
626
|
color: var(--color-fg);
|
|
627
627
|
font-size: var(--text-body);
|
|
628
628
|
line-height: var(--leading-relaxed);
|
|
629
|
+
overflow-wrap: anywhere;
|
|
629
630
|
}
|
|
630
631
|
|
|
631
632
|
@layer zd-flow {
|
|
@@ -1045,6 +1046,7 @@ a.text-accent.underline {
|
|
|
1045
1046
|
|
|
1046
1047
|
.page-loading-overlay {
|
|
1047
1048
|
position: fixed;
|
|
1049
|
+
view-transition-name: zfb-loading;
|
|
1048
1050
|
inset: 0;
|
|
1049
1051
|
z-index: var(--z-index-modal, 100);
|
|
1050
1052
|
display: flex;
|
|
@@ -1053,11 +1055,12 @@ a.text-accent.underline {
|
|
|
1053
1055
|
background: var(--color-page-loading-overlay, color-mix(in oklch, var(--color-overlay, #000) 60%, transparent));
|
|
1054
1056
|
opacity: 0;
|
|
1055
1057
|
pointer-events: none;
|
|
1056
|
-
transition:
|
|
1058
|
+
transition: none;
|
|
1057
1059
|
}
|
|
1058
1060
|
|
|
1059
1061
|
.page-loading-overlay[data-visible] {
|
|
1060
1062
|
opacity: 1;
|
|
1063
|
+
transition: opacity .15s ease-out;
|
|
1061
1064
|
}
|
|
1062
1065
|
|
|
1063
1066
|
a[data-zd-nav-pending], button[data-zd-nav-pending] {
|
|
@@ -1100,6 +1103,14 @@ a[data-zd-nav-pending], button[data-zd-nav-pending] {
|
|
|
1100
1103
|
}
|
|
1101
1104
|
}
|
|
1102
1105
|
|
|
1106
|
+
::view-transition-group(zfb-loading) {
|
|
1107
|
+
animation: none;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
::view-transition-old(zfb-loading), ::view-transition-new(zfb-loading) {
|
|
1111
|
+
display: none;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1103
1114
|
header[data-header] {
|
|
1104
1115
|
background-color: var(--color-surface, var(--color-bg));
|
|
1105
1116
|
z-index: var(--z-index-toolbar, 20);
|
|
@@ -1294,7 +1305,7 @@ pre.hi-root .line .highlighted-word {
|
|
|
1294
1305
|
white-space: nowrap;
|
|
1295
1306
|
}
|
|
1296
1307
|
|
|
1297
|
-
.katex .base {
|
|
1308
|
+
.katex .katex-base {
|
|
1298
1309
|
color: var(--zd-fg);
|
|
1299
1310
|
}
|
|
1300
1311
|
|
|
@@ -1403,11 +1414,11 @@ pre.hi-root .line .highlighted-word {
|
|
|
1403
1414
|
}
|
|
1404
1415
|
}
|
|
1405
1416
|
|
|
1406
|
-
|
|
1417
|
+
body > header {
|
|
1407
1418
|
view-transition-name: zfb-header;
|
|
1408
1419
|
}
|
|
1409
1420
|
|
|
1410
|
-
|
|
1421
|
+
#desktop-sidebar:not(.sr-only) {
|
|
1411
1422
|
view-transition-name: zfb-sidebar;
|
|
1412
1423
|
}
|
|
1413
1424
|
|
|
@@ -1415,26 +1426,34 @@ pre.hi-root .line .highlighted-word {
|
|
|
1415
1426
|
view-transition-name: zfb-footer;
|
|
1416
1427
|
}
|
|
1417
1428
|
|
|
1418
|
-
|
|
1429
|
+
.zd-desktop-sidebar-toggle {
|
|
1419
1430
|
view-transition-name: zfb-sidebar-toggle;
|
|
1420
1431
|
}
|
|
1421
1432
|
|
|
1422
|
-
|
|
1433
|
+
.zd-desktop-toc-toggle {
|
|
1423
1434
|
view-transition-name: zfb-toc-toggle;
|
|
1424
1435
|
}
|
|
1425
1436
|
|
|
1426
|
-
::view-transition-old(zfb-header), ::view-transition-new(zfb-header), ::view-transition-group(zfb-header), ::view-transition-
|
|
1437
|
+
::view-transition-old(zfb-header), ::view-transition-new(zfb-header), ::view-transition-group(zfb-header), ::view-transition-group(zfb-sidebar), ::view-transition-old(zfb-footer), ::view-transition-new(zfb-footer), ::view-transition-group(zfb-footer), ::view-transition-old(zfb-sidebar-toggle), ::view-transition-new(zfb-sidebar-toggle), ::view-transition-group(zfb-sidebar-toggle), ::view-transition-old(zfb-toc-toggle), ::view-transition-new(zfb-toc-toggle), ::view-transition-group(zfb-toc-toggle) {
|
|
1427
1438
|
animation: none;
|
|
1428
1439
|
}
|
|
1429
1440
|
|
|
1430
|
-
::view-transition-
|
|
1441
|
+
::view-transition-group(zfb-header) {
|
|
1442
|
+
z-index: var(--z-index-toolbar, 20);
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
::view-transition-old(zfb-sidebar), ::view-transition-old(zfb-footer):only-child, ::view-transition-old(zfb-sidebar-toggle):only-child, ::view-transition-old(zfb-toc-toggle):only-child {
|
|
1431
1446
|
animation: var(--default-transition-duration) ease-in both contentFadeOut;
|
|
1432
1447
|
}
|
|
1433
1448
|
|
|
1434
|
-
::view-transition-new(zfb-
|
|
1449
|
+
::view-transition-new(zfb-sidebar), ::view-transition-new(zfb-footer):only-child, ::view-transition-new(zfb-sidebar-toggle):only-child, ::view-transition-new(zfb-toc-toggle):only-child {
|
|
1435
1450
|
animation: var(--zd-transition-slower) ease-out both contentFadeIn;
|
|
1436
1451
|
}
|
|
1437
1452
|
|
|
1453
|
+
:root[data-zd-sidebar-transition="stationary"]::view-transition-old(zfb-sidebar), :root[data-zd-sidebar-transition="stationary"]::view-transition-new(zfb-sidebar) {
|
|
1454
|
+
animation: none;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1438
1457
|
::view-transition-old(root) {
|
|
1439
1458
|
animation: var(--default-transition-duration) ease-in both contentFadeOut;
|
|
1440
1459
|
}
|
|
@@ -1444,7 +1463,7 @@ pre.hi-root .line .highlighted-word {
|
|
|
1444
1463
|
}
|
|
1445
1464
|
|
|
1446
1465
|
@media (prefers-reduced-motion: reduce) {
|
|
1447
|
-
::view-transition-old(root), ::view-transition-new(root), ::view-transition-group(root), ::view-transition-old(zfb-
|
|
1466
|
+
::view-transition-old(root), ::view-transition-new(root), ::view-transition-group(root), ::view-transition-old(zfb-sidebar), ::view-transition-old(zfb-footer):only-child, ::view-transition-old(zfb-sidebar-toggle):only-child, ::view-transition-old(zfb-toc-toggle):only-child, ::view-transition-new(zfb-sidebar), ::view-transition-new(zfb-footer):only-child, ::view-transition-new(zfb-sidebar-toggle):only-child, ::view-transition-new(zfb-toc-toggle):only-child {
|
|
1448
1467
|
animation: none;
|
|
1449
1468
|
}
|
|
1450
1469
|
}
|
package/dist/content.css
CHANGED
|
@@ -52,6 +52,9 @@
|
|
|
52
52
|
color: var(--color-fg);
|
|
53
53
|
font-size: var(--text-body);
|
|
54
54
|
line-height: var(--leading-relaxed);
|
|
55
|
+
/* Let ordinary prose and navigation labels reflow at narrow widths (#4585).
|
|
56
|
+
* Preformatted code keeps its white-space contract and local scrolling. */
|
|
57
|
+
overflow-wrap: anywhere;
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
/* ── Flow spacing (vertical rhythm) ── */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs } from "@takazudo/zfb/zudo-react/jsx-runtime";
|
|
2
2
|
import { ClientRouter } from "@takazudo/zfb-runtime";
|
|
3
|
+
import { buildChromeTransitionBootstrap } from "../transitions/chrome-transition-bootstrap.js";
|
|
3
4
|
const DESKTOP_SIDEBAR_ID = "desktop-sidebar";
|
|
4
5
|
function DocLayout(props) {
|
|
5
6
|
const {
|
|
@@ -70,6 +71,7 @@ function DocLayout(props) {
|
|
|
70
71
|
);
|
|
71
72
|
}
|
|
72
73
|
if (head !== void 0) headChildren.push(head);
|
|
74
|
+
if (enableClientRouter !== false) headChildren.push(/* @__PURE__ */ jsx("script", { rawHtml: buildChromeTransitionBootstrap() }));
|
|
73
75
|
return /* @__PURE__ */ jsxs("html", { ...htmlAttrs, children: [
|
|
74
76
|
/* @__PURE__ */ jsx("head", { children: headChildren }),
|
|
75
77
|
/* @__PURE__ */ jsxs("body", { class: "min-h-screen antialiased", children: [
|
package/dist/features.css
CHANGED
|
@@ -283,7 +283,7 @@ pre.hi-root .line .highlighted-word {
|
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
/* Make KaTeX respect our color scheme */
|
|
286
|
-
.katex .base {
|
|
286
|
+
.katex .katex-base {
|
|
287
287
|
color: var(--zd-fg);
|
|
288
288
|
}
|
|
289
289
|
|
|
@@ -457,56 +457,22 @@ html[data-sidebar-hidden] .zd-doc-content-band[data-zd-wide] {
|
|
|
457
457
|
}
|
|
458
458
|
}
|
|
459
459
|
|
|
460
|
-
/*
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
* <header>, <aside id="desktop-sidebar">, <footer>, the desktop-sidebar-toggle
|
|
468
|
-
* button, and (since #3254) the desktop-toc-toggle button each carry a
|
|
469
|
-
* data-zfb-transition-persist attribute whose value is keyed by locale and
|
|
470
|
-
* nav-section. The five attribute selectors below assign a stable
|
|
471
|
-
* view-transition-name based on the attribute value prefix, extracting those
|
|
472
|
-
* elements from the root snapshot into their own named layers:
|
|
473
|
-
* - header-{lang} → zfb-header
|
|
474
|
-
* - sidebar-{locale}-… → zfb-sidebar
|
|
475
|
-
* - footer-{lang} → zfb-footer
|
|
476
|
-
* - desktop-sidebar-toggle → zfb-sidebar-toggle
|
|
477
|
-
* - desktop-toc-toggle → zfb-toc-toggle
|
|
478
|
-
*
|
|
479
|
-
* Once extracted, the root cross-fade animates only non-chrome content (main,
|
|
480
|
-
* article, TOC, etc.). The ::view-transition-{old,new,group}(<name>) rules
|
|
481
|
-
* disable animation for all five chrome layers. The group pseudo must be
|
|
482
|
-
* neutralised too — even when old/new are static the group container can still
|
|
483
|
-
* produce a geometry-morph animation when snapshot size/position differs.
|
|
484
|
-
*
|
|
485
|
-
* Entry/exit cross-fade (zudolab/zudo-doc#2072): animation: none is only
|
|
486
|
-
* correct when the chrome element exists on BOTH pages of a navigation.
|
|
487
|
-
* When it exists on one side only (docs page with sidebar → top page
|
|
488
|
-
* without), the named group holds a single snapshot — frozen at full
|
|
489
|
-
* opacity for the whole transition, then dropped abruptly at finish. The
|
|
490
|
-
* :only-child rules below detect that one-sided case and cross-fade the
|
|
491
|
-
* lone snapshot in sync with the root content fade (spec-standard
|
|
492
|
-
* entry/exit pattern; :only-child outranks the animation: none rules via
|
|
493
|
-
* the extra pseudo-class specificity). */
|
|
494
|
-
|
|
495
|
-
/* Chrome extraction — assign view-transition-name from data-zfb-transition-persist */
|
|
496
|
-
[data-zfb-transition-persist^="header-"] { view-transition-name: zfb-header; }
|
|
497
|
-
[data-zfb-transition-persist^="sidebar-"] { view-transition-name: zfb-sidebar; }
|
|
460
|
+
/* Visual region identity is independent of persistence/remount policy. The
|
|
461
|
+
* layout's header slot is a direct body header, including consumer overrides.
|
|
462
|
+
* A sidebar keeps its name even when incoming island props require replacement.
|
|
463
|
+
* Never name an ancestor of these regions: it would move their whole layer.
|
|
464
|
+
*/
|
|
465
|
+
body > header { view-transition-name: zfb-header; }
|
|
466
|
+
#desktop-sidebar:not(.sr-only) { view-transition-name: zfb-sidebar; }
|
|
498
467
|
[data-zfb-transition-persist^="footer-"] { view-transition-name: zfb-footer; }
|
|
499
|
-
|
|
500
|
-
|
|
468
|
+
.zd-desktop-sidebar-toggle { view-transition-name: zfb-sidebar-toggle; }
|
|
469
|
+
.zd-desktop-toc-toggle { view-transition-name: zfb-toc-toggle; }
|
|
501
470
|
|
|
502
|
-
/*
|
|
503
|
-
*
|
|
504
|
-
* it doesn't animate on SPA swaps). */
|
|
471
|
+
/* Header snapshots and every chrome group stay at their authored geometry.
|
|
472
|
+
* Footer and toggle pairs keep their established stationary policy. */
|
|
505
473
|
::view-transition-old(zfb-header),
|
|
506
474
|
::view-transition-new(zfb-header),
|
|
507
475
|
::view-transition-group(zfb-header),
|
|
508
|
-
::view-transition-old(zfb-sidebar),
|
|
509
|
-
::view-transition-new(zfb-sidebar),
|
|
510
476
|
::view-transition-group(zfb-sidebar),
|
|
511
477
|
::view-transition-old(zfb-footer),
|
|
512
478
|
::view-transition-new(zfb-footer),
|
|
@@ -518,24 +484,35 @@ html[data-sidebar-hidden] .zd-doc-content-band[data-zd-wide] {
|
|
|
518
484
|
::view-transition-new(zfb-toc-toggle),
|
|
519
485
|
::view-transition-group(zfb-toc-toggle) { animation: none; }
|
|
520
486
|
|
|
521
|
-
/*
|
|
522
|
-
*
|
|
523
|
-
::view-transition-
|
|
524
|
-
|
|
487
|
+
/* A translating incoming sidebar/root must not paint over the header's lower
|
|
488
|
+
* edge. Named snapshot groups have their own stacking order above the live DOM. */
|
|
489
|
+
::view-transition-group(zfb-header) { z-index: var(--z-index-toolbar, 20); }
|
|
490
|
+
|
|
491
|
+
/* A category/context change or a one-sided sidebar uses the content animation.
|
|
492
|
+
* The header remains stationary even when replaced or present on only one side.
|
|
493
|
+
* Other chrome retains its established entry/exit behavior. */
|
|
494
|
+
::view-transition-old(zfb-sidebar),
|
|
525
495
|
::view-transition-old(zfb-footer):only-child,
|
|
526
496
|
::view-transition-old(zfb-sidebar-toggle):only-child,
|
|
527
497
|
::view-transition-old(zfb-toc-toggle):only-child {
|
|
528
498
|
animation: var(--default-transition-duration) ease-in both contentFadeOut;
|
|
529
499
|
}
|
|
530
500
|
/* Entry — lone new snapshot fades in with the content cross-fade. */
|
|
531
|
-
::view-transition-new(zfb-
|
|
532
|
-
::view-transition-new(zfb-sidebar):only-child,
|
|
501
|
+
::view-transition-new(zfb-sidebar),
|
|
533
502
|
::view-transition-new(zfb-footer):only-child,
|
|
534
503
|
::view-transition-new(zfb-sidebar-toggle):only-child,
|
|
535
504
|
::view-transition-new(zfb-toc-toggle):only-child {
|
|
536
505
|
animation: var(--zd-transition-slower) ease-out both contentFadeIn;
|
|
537
506
|
}
|
|
538
507
|
|
|
508
|
+
/* Resolved navSection AND the existing navigation context must agree. The
|
|
509
|
+
* context already isolates locale, version and custom-tree topology; article,
|
|
510
|
+
* focused subtree and DOM identity are deliberately irrelevant here. */
|
|
511
|
+
:root[data-zd-sidebar-transition="stationary"]::view-transition-old(zfb-sidebar),
|
|
512
|
+
:root[data-zd-sidebar-transition="stationary"]::view-transition-new(zfb-sidebar) {
|
|
513
|
+
animation: none;
|
|
514
|
+
}
|
|
515
|
+
|
|
539
516
|
/* Root cross-fade rules — animate only the non-chrome snapshot */
|
|
540
517
|
::view-transition-old(root) {
|
|
541
518
|
animation: var(--default-transition-duration) ease-in both contentFadeOut;
|
|
@@ -559,13 +536,11 @@ html[data-sidebar-hidden] .zd-doc-content-band[data-zd-wide] {
|
|
|
559
536
|
::view-transition-old(root),
|
|
560
537
|
::view-transition-new(root),
|
|
561
538
|
::view-transition-group(root),
|
|
562
|
-
::view-transition-old(zfb-
|
|
563
|
-
::view-transition-old(zfb-sidebar):only-child,
|
|
539
|
+
::view-transition-old(zfb-sidebar),
|
|
564
540
|
::view-transition-old(zfb-footer):only-child,
|
|
565
541
|
::view-transition-old(zfb-sidebar-toggle):only-child,
|
|
566
542
|
::view-transition-old(zfb-toc-toggle):only-child,
|
|
567
|
-
::view-transition-new(zfb-
|
|
568
|
-
::view-transition-new(zfb-sidebar):only-child,
|
|
543
|
+
::view-transition-new(zfb-sidebar),
|
|
569
544
|
::view-transition-new(zfb-footer):only-child,
|
|
570
545
|
::view-transition-new(zfb-sidebar-toggle):only-child,
|
|
571
546
|
::view-transition-new(zfb-toc-toggle):only-child {
|
|
@@ -15,13 +15,13 @@ export interface PageLoadingOverlayProps {
|
|
|
15
15
|
*/
|
|
16
16
|
export declare function buildPageLoadingOverlayBootstrap(overlayId: string): string;
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* Content loading overlay shown while a dynamic navigation is pending.
|
|
19
19
|
*
|
|
20
20
|
* Mount this once per layout (typically inside `DocLayoutWithDefaults`'s
|
|
21
21
|
* `bodyEnd` slot, alongside the existing body-end providers). It is
|
|
22
22
|
* server-rendered and self-wires its visibility — no hydration needed.
|
|
23
23
|
*
|
|
24
|
-
* CSS
|
|
24
|
+
* CSS ships in `@takazudo/zudo-doc/page-loading.css` (`.page-loading-overlay`,
|
|
25
25
|
* `.page-loading-spinner`, `[data-zd-nav-pending]` rules) rather than in an
|
|
26
26
|
* inline `<style>` block here — a `<style>` inside `<body>` violates HTML5
|
|
27
27
|
* element-permitted-content and fails html-validate (same fix applied to the
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "@takazudo/zfb/zudo-react/jsx-runtime";
|
|
2
2
|
import {
|
|
3
3
|
AFTER_NAVIGATE_EVENT,
|
|
4
|
-
BEFORE_NAVIGATE_EVENT
|
|
4
|
+
BEFORE_NAVIGATE_EVENT,
|
|
5
|
+
NAVIGATION_ABORTED_EVENT
|
|
5
6
|
} from "../transitions/page-events.js";
|
|
6
7
|
const PAGE_LOADING_OVERLAY_ID = "page-loading-overlay";
|
|
7
8
|
function buildPageLoadingOverlayBootstrap(overlayId) {
|
|
@@ -10,7 +11,7 @@ function buildPageLoadingOverlayBootstrap(overlayId) {
|
|
|
10
11
|
const after = JSON.stringify(AFTER_NAVIGATE_EVENT);
|
|
11
12
|
return `(function(){
|
|
12
13
|
var id=${id};
|
|
13
|
-
function show(){var el=document.getElementById(id);if(!el)return;el.setAttribute("data-visible","");el.setAttribute("aria-hidden","false");}
|
|
14
|
+
function show(){var el=document.getElementById(id);if(!el)return;var content=document.querySelector(".zd-sidebar-content-wrapper");var header=document.querySelector("body > header");el.style.left=Math.max(0,content?content.getBoundingClientRect().left:0)+"px";el.style.top=Math.max(0,header?header.getBoundingClientRect().bottom:0)+"px";el.setAttribute("data-visible","");el.setAttribute("aria-hidden","false");}
|
|
14
15
|
function hide(){var el=document.getElementById(id);if(!el)return;el.removeAttribute("data-visible");el.setAttribute("aria-hidden","true");}
|
|
15
16
|
function setPending(ev){document.querySelectorAll("[data-zd-nav-pending]").forEach(function(el){el.removeAttribute("data-zd-nav-pending");});var src=ev&&ev.sourceElement;if(src&&src instanceof Element)src.setAttribute("data-zd-nav-pending","");}
|
|
16
17
|
function clearPending(){document.querySelectorAll("[data-zd-nav-pending]").forEach(function(el){el.removeAttribute("data-zd-nav-pending");});}
|
|
@@ -18,6 +19,7 @@ document.addEventListener(${before},show);
|
|
|
18
19
|
document.addEventListener(${after},hide);
|
|
19
20
|
document.addEventListener(${before},setPending);
|
|
20
21
|
document.addEventListener(${after},clearPending);
|
|
22
|
+
document.addEventListener(${JSON.stringify(NAVIGATION_ABORTED_EVENT)},function(){hide();clearPending();});
|
|
21
23
|
})();`;
|
|
22
24
|
}
|
|
23
25
|
function PageLoadingOverlay({
|
package/dist/page-loading.css
CHANGED
|
@@ -31,8 +31,9 @@
|
|
|
31
31
|
|
|
32
32
|
.page-loading-overlay {
|
|
33
33
|
position: fixed;
|
|
34
|
+
view-transition-name: zfb-loading;
|
|
34
35
|
inset: 0;
|
|
35
|
-
/*
|
|
36
|
+
/* Pending-content overlay — the bootstrap excludes the layout's chrome.
|
|
36
37
|
--z-index-modal fallback (100) ensures the overlay stacks on top even for
|
|
37
38
|
bare consumers that have not defined the token. */
|
|
38
39
|
z-index: var(--z-index-modal, 100);
|
|
@@ -45,11 +46,13 @@
|
|
|
45
46
|
);
|
|
46
47
|
opacity: 0;
|
|
47
48
|
pointer-events: none;
|
|
48
|
-
|
|
49
|
+
/* Hidden loading feedback must disappear synchronously. */
|
|
50
|
+
transition: none;
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
.page-loading-overlay[data-visible] {
|
|
52
54
|
opacity: 1;
|
|
55
|
+
transition: opacity 150ms ease-out;
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
a[data-zd-nav-pending],
|
|
@@ -90,3 +93,11 @@ button[data-zd-nav-pending] {
|
|
|
90
93
|
border-bottom-color: var(--color-page-loading-spinner, #fff);
|
|
91
94
|
}
|
|
92
95
|
}
|
|
96
|
+
|
|
97
|
+
/* Pending feedback belongs to the fetch, not the page cross-fade. Extract it
|
|
98
|
+
* from the root snapshot, then suppress its snapshot layer. This also avoids
|
|
99
|
+
* an unscoped after-preparation event from an older fetch hiding newer feedback.
|
|
100
|
+
*/
|
|
101
|
+
::view-transition-group(zfb-loading) { animation: none; }
|
|
102
|
+
::view-transition-old(zfb-loading),
|
|
103
|
+
::view-transition-new(zfb-loading) { display: none; }
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BEFORE_SWAP_EVENT } from "./page-events.js";
|
|
2
|
+
function buildChromeTransitionBootstrap() {
|
|
3
|
+
return `(function(){
|
|
4
|
+
if(document.__zdChromeTransitionPolicy)return;
|
|
5
|
+
document.__zdChromeTransitionPolicy=true;
|
|
6
|
+
function identity(doc){
|
|
7
|
+
var sidebar=doc.getElementById("desktop-sidebar");
|
|
8
|
+
var context=sidebar&&sidebar.querySelector("[data-sidebar-context]");
|
|
9
|
+
var band=doc.querySelector("[data-zd-nav-section]");
|
|
10
|
+
return {section:band&&band.getAttribute("data-zd-nav-section"),context:band&&!band.hasAttribute("data-zd-nosidebar")&&context&&context.getAttribute("data-sidebar-context")};
|
|
11
|
+
}
|
|
12
|
+
document.addEventListener(${JSON.stringify(BEFORE_SWAP_EVENT)},function(ev){
|
|
13
|
+
var incoming=ev.newDocument;
|
|
14
|
+
if(!incoming||incoming.nodeType!==9)return;
|
|
15
|
+
var from=identity(document),to=identity(incoming);
|
|
16
|
+
var stationary=!!from.section&&!!from.context&&from.section===to.section&&from.context===to.context;
|
|
17
|
+
incoming.documentElement.setAttribute("data-zd-sidebar-transition",stationary?"stationary":"changing");
|
|
18
|
+
});
|
|
19
|
+
})();`;
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
buildChromeTransitionBootstrap
|
|
23
|
+
};
|
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
* the v2 vocabulary.
|
|
8
8
|
*/
|
|
9
9
|
export declare const BEFORE_NAVIGATE_EVENT = "zfb:before-preparation";
|
|
10
|
+
/** Fetch/preparation finished, before the native old snapshot is captured. */
|
|
11
|
+
export declare const AFTER_PREPARATION_EVENT = "zfb:after-preparation";
|
|
12
|
+
/** A navigation was abandoned before committing the destination DOM. */
|
|
13
|
+
export declare const NAVIGATION_ABORTED_EVENT = "zfb:navigation-aborted";
|
|
10
14
|
/**
|
|
11
15
|
* Event name fired after a SPA body swap. Today resolves to
|
|
12
16
|
* `"zfb:after-swap"`. The initial page load uses `zfb:page-load` instead;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const BEFORE_NAVIGATE_EVENT = "zfb:before-preparation";
|
|
2
|
+
const AFTER_PREPARATION_EVENT = "zfb:after-preparation";
|
|
3
|
+
const NAVIGATION_ABORTED_EVENT = "zfb:navigation-aborted";
|
|
2
4
|
const AFTER_NAVIGATE_EVENT = "zfb:after-swap";
|
|
3
5
|
const BEFORE_SWAP_EVENT = "zfb:before-swap";
|
|
4
6
|
function onBeforeNavigate(handler) {
|
|
@@ -15,8 +17,10 @@ function onAfterNavigate(handler) {
|
|
|
15
17
|
}
|
|
16
18
|
export {
|
|
17
19
|
AFTER_NAVIGATE_EVENT,
|
|
20
|
+
AFTER_PREPARATION_EVENT,
|
|
18
21
|
BEFORE_NAVIGATE_EVENT,
|
|
19
22
|
BEFORE_SWAP_EVENT,
|
|
23
|
+
NAVIGATION_ABORTED_EVENT,
|
|
20
24
|
onAfterNavigate,
|
|
21
25
|
onBeforeNavigate
|
|
22
26
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** @jsxRuntime automatic */
|
|
2
|
-
// Server-rendered, zero-hydration
|
|
2
|
+
// Server-rendered, zero-hydration content loading overlay.
|
|
3
3
|
//
|
|
4
4
|
// Renders the overlay and its bootstrap into the document:
|
|
5
5
|
//
|
|
@@ -15,12 +15,13 @@
|
|
|
15
15
|
// `zfb:after-swap` (AFTER_NAVIGATE_EVENT); see
|
|
16
16
|
// `transitions/page-events.ts` for rationale.
|
|
17
17
|
//
|
|
18
|
-
// Its CSS
|
|
18
|
+
// Its package CSS is imported by the host, and the component is not
|
|
19
19
|
// hydrated: the static script owns its navigation listeners.
|
|
20
20
|
|
|
21
21
|
import {
|
|
22
22
|
AFTER_NAVIGATE_EVENT,
|
|
23
23
|
BEFORE_NAVIGATE_EVENT,
|
|
24
|
+
NAVIGATION_ABORTED_EVENT,
|
|
24
25
|
} from "../transitions/page-events.js";
|
|
25
26
|
|
|
26
27
|
/** Default `id` for the overlay element. Stable so test rigs can target it. */
|
|
@@ -52,7 +53,7 @@ export function buildPageLoadingOverlayBootstrap(overlayId: string): string {
|
|
|
52
53
|
const after = JSON.stringify(AFTER_NAVIGATE_EVENT);
|
|
53
54
|
return `(function(){
|
|
54
55
|
var id=${id};
|
|
55
|
-
function show(){var el=document.getElementById(id);if(!el)return;el.setAttribute("data-visible","");el.setAttribute("aria-hidden","false");}
|
|
56
|
+
function show(){var el=document.getElementById(id);if(!el)return;var content=document.querySelector(".zd-sidebar-content-wrapper");var header=document.querySelector("body > header");el.style.left=Math.max(0,content?content.getBoundingClientRect().left:0)+"px";el.style.top=Math.max(0,header?header.getBoundingClientRect().bottom:0)+"px";el.setAttribute("data-visible","");el.setAttribute("aria-hidden","false");}
|
|
56
57
|
function hide(){var el=document.getElementById(id);if(!el)return;el.removeAttribute("data-visible");el.setAttribute("aria-hidden","true");}
|
|
57
58
|
function setPending(ev){document.querySelectorAll("[data-zd-nav-pending]").forEach(function(el){el.removeAttribute("data-zd-nav-pending");});var src=ev&&ev.sourceElement;if(src&&src instanceof Element)src.setAttribute("data-zd-nav-pending","");}
|
|
58
59
|
function clearPending(){document.querySelectorAll("[data-zd-nav-pending]").forEach(function(el){el.removeAttribute("data-zd-nav-pending");});}
|
|
@@ -60,17 +61,18 @@ document.addEventListener(${before},show);
|
|
|
60
61
|
document.addEventListener(${after},hide);
|
|
61
62
|
document.addEventListener(${before},setPending);
|
|
62
63
|
document.addEventListener(${after},clearPending);
|
|
64
|
+
document.addEventListener(${JSON.stringify(NAVIGATION_ABORTED_EVENT)},function(){hide();clearPending();});
|
|
63
65
|
})();`;
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
/**
|
|
67
|
-
*
|
|
69
|
+
* Content loading overlay shown while a dynamic navigation is pending.
|
|
68
70
|
*
|
|
69
71
|
* Mount this once per layout (typically inside `DocLayoutWithDefaults`'s
|
|
70
72
|
* `bodyEnd` slot, alongside the existing body-end providers). It is
|
|
71
73
|
* server-rendered and self-wires its visibility — no hydration needed.
|
|
72
74
|
*
|
|
73
|
-
* CSS
|
|
75
|
+
* CSS ships in `@takazudo/zudo-doc/page-loading.css` (`.page-loading-overlay`,
|
|
74
76
|
* `.page-loading-spinner`, `[data-zd-nav-pending]` rules) rather than in an
|
|
75
77
|
* inline `<style>` block here — a `<style>` inside `<body>` violates HTML5
|
|
76
78
|
* element-permitted-content and fails html-validate (same fix applied to the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@takazudo/zudo-doc",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "zudo-doc framework primitives layer that sits on top of zfb's engine — sidebar, theme, TOC, breadcrumb, layouts, head injection, View Transitions, SSR-skip wrappers (per ADR-003).",
|
|
6
6
|
"license": "MIT",
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
"bugs": {
|
|
15
15
|
"url": "https://github.com/zudolab/zudo-doc/issues"
|
|
16
16
|
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=24 <25"
|
|
19
|
+
},
|
|
17
20
|
"keywords": [
|
|
18
21
|
"zudo-doc",
|
|
19
22
|
"documentation",
|
|
@@ -733,12 +736,12 @@
|
|
|
733
736
|
"peerDependencies": {
|
|
734
737
|
"@modelcontextprotocol/sdk": "1.32.1",
|
|
735
738
|
"@takazudo/zdtp": "^0.5.2 || ^0.6.0 || ^0.7.0 || ^0.8.0",
|
|
736
|
-
"@takazudo/zfb": "^4.5.
|
|
737
|
-
"@takazudo/zfb-md-wasm": "^4.5.
|
|
738
|
-
"@takazudo/zfb-runtime": "^4.5.
|
|
739
|
-
"@takazudo/zudo-doc-history-server": "^
|
|
739
|
+
"@takazudo/zfb": "^4.5.2",
|
|
740
|
+
"@takazudo/zfb-md-wasm": "^4.5.2",
|
|
741
|
+
"@takazudo/zfb-runtime": "^4.5.2",
|
|
742
|
+
"@takazudo/zudo-doc-history-server": "^7.0.0",
|
|
740
743
|
"diff": "^8.0.0",
|
|
741
|
-
"katex": "^0.
|
|
744
|
+
"katex": "^0.18.2 || ^0.19.0",
|
|
742
745
|
"zod": "^4.3.6"
|
|
743
746
|
},
|
|
744
747
|
"peerDependenciesMeta": {
|
|
@@ -776,9 +779,9 @@
|
|
|
776
779
|
"devDependencies": {
|
|
777
780
|
"@modelcontextprotocol/sdk": "1.32.1",
|
|
778
781
|
"@takazudo/mdx-formatter": "1.3.0",
|
|
779
|
-
"@takazudo/zfb": "4.5.
|
|
780
|
-
"@takazudo/zfb-md-wasm": "4.5.
|
|
781
|
-
"@takazudo/zfb-runtime": "4.5.
|
|
782
|
+
"@takazudo/zfb": "4.5.2",
|
|
783
|
+
"@takazudo/zfb-md-wasm": "4.5.2",
|
|
784
|
+
"@takazudo/zfb-runtime": "4.5.2",
|
|
782
785
|
"@types/fs-extra": "^11.0.4",
|
|
783
786
|
"@types/minimist": "^1.2.5",
|
|
784
787
|
"@types/node": "^25.3.5",
|
|
@@ -788,7 +791,7 @@
|
|
|
788
791
|
"typescript": "^5.0.0",
|
|
789
792
|
"vitest": "^4.1.0",
|
|
790
793
|
"zod": "^4.3.6",
|
|
791
|
-
"@takazudo/zudo-doc-history-server": "
|
|
794
|
+
"@takazudo/zudo-doc-history-server": "7.0.0"
|
|
792
795
|
},
|
|
793
796
|
"scripts": {
|
|
794
797
|
"gen:search-widget-script": "node scripts/gen-search-widget-script.mjs",
|