create-zudo-doc 0.2.10 → 0.2.11
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/dist/scaffold.js
CHANGED
|
@@ -350,7 +350,7 @@ function generatePackageJson(choices) {
|
|
|
350
350
|
// ties this pin to packages/zudo-doc's version, so the lockstep release
|
|
351
351
|
// bumps both together; do not cut a create-zudo-doc release until the
|
|
352
352
|
// matching @takazudo/zudo-doc version (with content.css) is on npm.
|
|
353
|
-
"@takazudo/zudo-doc": "^0.2.
|
|
353
|
+
"@takazudo/zudo-doc": "^0.2.11",
|
|
354
354
|
// zod — used by the generated zfb.config.ts. zfb-config-gen emits
|
|
355
355
|
// `import { z } from "zod"` for the content-collection schema +
|
|
356
356
|
// `z.toJSONSchema(...)` conversion. Without this dep, the consumer
|
|
@@ -405,7 +405,7 @@ function generatePackageJson(choices) {
|
|
|
405
405
|
// @takazudo/zudo-doc/integrations/doc-history which in turn imports
|
|
406
406
|
// @takazudo/zudo-doc-history-server/git-history. Without this dep the
|
|
407
407
|
// plugin host fails at init with ERR_MODULE_NOT_FOUND — W8A (#1739).
|
|
408
|
-
deps["@takazudo/zudo-doc-history-server"] = "^0.2.
|
|
408
|
+
deps["@takazudo/zudo-doc-history-server"] = "^0.2.11";
|
|
409
409
|
// W7A (#1736): doc-history-plugin.mjs spawns `tsx -e <inline-script>` to
|
|
410
410
|
// run the v2 runtime in a TS-aware Node subprocess; without tsx the
|
|
411
411
|
// plugin's preBuild step exits with ENOENT before zfb finishes config
|
package/package.json
CHANGED
|
@@ -717,6 +717,20 @@ pre[class^="syntect-"] .line .highlighted-word {
|
|
|
717
717
|
}
|
|
718
718
|
}
|
|
719
719
|
|
|
720
|
+
/* Suppress sidebar geometry transitions during an SPA swap (#2198).
|
|
721
|
+
* swapRootAttributes wipes data-sidebar-hidden mid-swap, so without this the
|
|
722
|
+
* sidebar would animate open (attribute absent) and then animate shut again
|
|
723
|
+
* when the toggle island restores the attribute on zfb:after-swap — a visible
|
|
724
|
+
* flash + slide. The island sets data-sidebar-no-transition for the swap
|
|
725
|
+
* window and removes it (double rAF) after restoring the hidden state, so the
|
|
726
|
+
* wipe/restore apply instantly and a later user toggle still animates. */
|
|
727
|
+
html[data-sidebar-no-transition] #desktop-sidebar,
|
|
728
|
+
html[data-sidebar-no-transition] .zd-sidebar-content-wrapper,
|
|
729
|
+
html[data-sidebar-no-transition] .zd-doc-content-band,
|
|
730
|
+
html[data-sidebar-no-transition] .zd-desktop-sidebar-toggle {
|
|
731
|
+
transition: none !important;
|
|
732
|
+
}
|
|
733
|
+
|
|
720
734
|
/* ── Find-in-page highlight (W7A: unconditional — Tauri feature gates at runtime) ── */
|
|
721
735
|
.find-match {
|
|
722
736
|
background-color: color-mix(in oklch, var(--color-warning) 40%, transparent);
|
|
@@ -906,6 +920,10 @@ dialog.zd-mermaid-dialog::backdrop {
|
|
|
906
920
|
|
|
907
921
|
.zd-mermaid-viewport[data-pan-active] {
|
|
908
922
|
cursor: grab;
|
|
923
|
+
/* In pan mode a drag should pan, not select diagram text. Scoped to
|
|
924
|
+
* [data-pan-active] so text stays selectable when pan mode is off. */
|
|
925
|
+
-webkit-user-select: none;
|
|
926
|
+
user-select: none;
|
|
909
927
|
}
|
|
910
928
|
|
|
911
929
|
.zd-mermaid-viewport[data-pan-active]:active {
|
|
@@ -946,15 +964,14 @@ dialog.zd-mermaid-dialog::backdrop {
|
|
|
946
964
|
overflow: visible;
|
|
947
965
|
}
|
|
948
966
|
|
|
949
|
-
/* Toolbar — bottom-
|
|
967
|
+
/* Toolbar — bottom-right pill of zoom/pan controls (2× sized buttons). */
|
|
950
968
|
.zd-mermaid-toolbar {
|
|
951
969
|
position: absolute;
|
|
952
970
|
bottom: var(--spacing-image-overlay-inset);
|
|
953
|
-
|
|
954
|
-
transform: translateX(-50%);
|
|
971
|
+
right: var(--spacing-image-overlay-inset);
|
|
955
972
|
display: flex;
|
|
956
|
-
gap: var(--spacing-hsp-
|
|
957
|
-
padding: var(--spacing-hsp-
|
|
973
|
+
gap: var(--spacing-hsp-xs);
|
|
974
|
+
padding: var(--spacing-hsp-xs);
|
|
958
975
|
border: 1px solid var(--color-muted);
|
|
959
976
|
border-radius: var(--radius-DEFAULT);
|
|
960
977
|
background: color-mix(in oklch, var(--color-surface) 92%, transparent);
|
|
@@ -965,8 +982,8 @@ dialog.zd-mermaid-dialog::backdrop {
|
|
|
965
982
|
display: flex;
|
|
966
983
|
align-items: center;
|
|
967
984
|
justify-content: center;
|
|
968
|
-
width: var(--spacing-icon-lg);
|
|
969
|
-
height: var(--spacing-icon-lg);
|
|
985
|
+
width: calc(var(--spacing-icon-lg) * 2);
|
|
986
|
+
height: calc(var(--spacing-icon-lg) * 2);
|
|
970
987
|
padding: var(--spacing-vsp-2xs);
|
|
971
988
|
border: none;
|
|
972
989
|
border-radius: var(--radius-DEFAULT);
|
|
@@ -993,8 +1010,8 @@ dialog.zd-mermaid-dialog::backdrop {
|
|
|
993
1010
|
}
|
|
994
1011
|
|
|
995
1012
|
.zd-mermaid-tool-btn > svg {
|
|
996
|
-
width: var(--spacing-icon-md);
|
|
997
|
-
height: var(--spacing-icon-md);
|
|
1013
|
+
width: calc(var(--spacing-icon-md) * 2);
|
|
1014
|
+
height: calc(var(--spacing-icon-md) * 2);
|
|
998
1015
|
}
|
|
999
1016
|
|
|
1000
1017
|
/* @slot:global-css:feature-styles */
|
|
@@ -22,6 +22,85 @@ function setDataAttribute(isVisible: boolean) {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
// SPA-navigation guard for the desktop sidebar's hidden-state (#2198).
|
|
26
|
+
//
|
|
27
|
+
// zfb's Strategy-B client router wipes EVERY <html> attribute during the body
|
|
28
|
+
// swap (swapRootAttributes re-adds only NON_OVERRIDABLE_ZFB_ATTRS plus the
|
|
29
|
+
// incoming SSR document's attributes), so the persisted `data-sidebar-hidden`
|
|
30
|
+
// runtime value is lost on every navigation, and the pre-paint inline script
|
|
31
|
+
// does not re-run on SPA hops. Left alone, the freshly-rendered sidebar paints
|
|
32
|
+
// visible and then animates shut when the value is restored — the flash + slide.
|
|
33
|
+
//
|
|
34
|
+
// These listeners MUST live at module scope, NOT in the island's useEffect:
|
|
35
|
+
// zfb-runtime (>= 0.1.0-next.51) calls unmountIslands() BEFORE the swap and
|
|
36
|
+
// before firing AFTER_NAVIGATE_EVENT, so a useEffect-registered listener is torn
|
|
37
|
+
// down (effect cleanup) before the swap and never sees the after-swap event —
|
|
38
|
+
// the restore would never run (#2198 verification). Registering once on
|
|
39
|
+
// `document` at bundle load — the same lifecycle-independent pattern as
|
|
40
|
+
// client-router-bootstrap.tsx — keeps the guard alive across island
|
|
41
|
+
// unmount/remount. SSR-safe: no-ops when `document` is undefined.
|
|
42
|
+
//
|
|
43
|
+
// Strategy: on BEFORE_NAVIGATE_EVENT, record whether the sidebar was hidden and
|
|
44
|
+
// set a transient `data-sidebar-no-transition` marker (global.css zeroes the
|
|
45
|
+
// sidebar/wrapper/band/toggle transitions). The swap then wipes BOTH the marker
|
|
46
|
+
// and data-sidebar-hidden. On AFTER_NAVIGATE_EVENT (swap done → the live <html>
|
|
47
|
+
// is no longer wiped) RE-SET the marker, then re-add data-sidebar-hidden in the
|
|
48
|
+
// same synchronous batch, so the hidden geometry snaps in with transitions
|
|
49
|
+
// suppressed (no slide, no open frame). Remove the marker on a double rAF
|
|
50
|
+
// afterward so a later user toggle still animates.
|
|
51
|
+
let spaNavGuardRegistered = false;
|
|
52
|
+
function registerSidebarSpaNavGuard() {
|
|
53
|
+
if (typeof document === 'undefined' || spaNavGuardRegistered) return;
|
|
54
|
+
spaNavGuardRegistered = true;
|
|
55
|
+
|
|
56
|
+
let wasHidden = false;
|
|
57
|
+
let swapToken = 0;
|
|
58
|
+
// Long enough to outlast the View-Transition swap pipeline on slow
|
|
59
|
+
// machines/CI; short enough that an aborted nav self-heals quickly. Only a
|
|
60
|
+
// safety net for a nav that never reaches `restore` (aborted/superseded).
|
|
61
|
+
const STUCK_MARKER_FALLBACK_MS = 1500;
|
|
62
|
+
|
|
63
|
+
const capture = () => {
|
|
64
|
+
wasHidden = document.documentElement.hasAttribute('data-sidebar-hidden');
|
|
65
|
+
document.documentElement.setAttribute('data-sidebar-no-transition', '');
|
|
66
|
+
const token = ++swapToken;
|
|
67
|
+
window.setTimeout(() => {
|
|
68
|
+
if (token === swapToken) {
|
|
69
|
+
document.documentElement.removeAttribute('data-sidebar-no-transition');
|
|
70
|
+
}
|
|
71
|
+
}, STUCK_MARKER_FALLBACK_MS);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const restore = () => {
|
|
75
|
+
// Marker first, then the attribute, in one synchronous batch — so the
|
|
76
|
+
// hidden geometry is restored with transitions off (the swap already wiped
|
|
77
|
+
// the capture-time marker, so re-setting it here on the post-swap <html> is
|
|
78
|
+
// what actually suppresses the animation).
|
|
79
|
+
document.documentElement.setAttribute('data-sidebar-no-transition', '');
|
|
80
|
+
if (wasHidden) {
|
|
81
|
+
document.documentElement.setAttribute('data-sidebar-hidden', '');
|
|
82
|
+
}
|
|
83
|
+
// Drop the marker only after the restored state is committed. A single rAF
|
|
84
|
+
// can coincide with the restore's style recalc and animate it, so defer one
|
|
85
|
+
// extra frame. The token bump no-ops capture's safety-net for this swap.
|
|
86
|
+
const token = ++swapToken;
|
|
87
|
+
requestAnimationFrame(() => {
|
|
88
|
+
requestAnimationFrame(() => {
|
|
89
|
+
if (token === swapToken) {
|
|
90
|
+
document.documentElement.removeAttribute('data-sidebar-no-transition');
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
document.addEventListener(BEFORE_NAVIGATE_EVENT, capture);
|
|
97
|
+
document.addEventListener(AFTER_NAVIGATE_EVENT, restore);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Register at module load (browser-only via the guard) so the listeners exist
|
|
101
|
+
// before the first navigation and survive island unmount/remount.
|
|
102
|
+
registerSidebarSpaNavGuard();
|
|
103
|
+
|
|
25
104
|
export default function DesktopSidebarToggle() {
|
|
26
105
|
// Initial state must match server render (always `true`) to avoid a
|
|
27
106
|
// hydration mismatch when the persisted preference is "hidden". The
|
|
@@ -66,36 +145,10 @@ export default function DesktopSidebarToggle() {
|
|
|
66
145
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
67
146
|
}, []);
|
|
68
147
|
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
// island is persisted (data-zfb-transition-persist), this listener stays
|
|
74
|
-
// registered across SPA swaps.
|
|
75
|
-
//
|
|
76
|
-
// Strategy: capture the attribute presence just before the swap
|
|
77
|
-
// (BEFORE_NAVIGATE_EVENT fires before swapRootAttributes runs), then
|
|
78
|
-
// restore it once the swap completes (AFTER_NAVIGATE_EVENT). This is
|
|
79
|
-
// authoritative regardless of how the attribute was set (toggle click,
|
|
80
|
-
// localStorage, or external mutation). (#1551, #1552 B10)
|
|
81
|
-
useEffect(() => {
|
|
82
|
-
let wasHidden = false;
|
|
83
|
-
const capture = () => {
|
|
84
|
-
wasHidden = document.documentElement.hasAttribute('data-sidebar-hidden');
|
|
85
|
-
};
|
|
86
|
-
const restore = () => {
|
|
87
|
-
if (wasHidden) {
|
|
88
|
-
document.documentElement.setAttribute('data-sidebar-hidden', '');
|
|
89
|
-
}
|
|
90
|
-
// If not hidden, swapRootAttributes already cleared it — nothing to do.
|
|
91
|
-
};
|
|
92
|
-
document.addEventListener(BEFORE_NAVIGATE_EVENT, capture);
|
|
93
|
-
document.addEventListener(AFTER_NAVIGATE_EVENT, restore);
|
|
94
|
-
return () => {
|
|
95
|
-
document.removeEventListener(BEFORE_NAVIGATE_EVENT, capture);
|
|
96
|
-
document.removeEventListener(AFTER_NAVIGATE_EVENT, restore);
|
|
97
|
-
};
|
|
98
|
-
}, []);
|
|
148
|
+
// The SPA-navigation flash guard (data-sidebar-hidden preservation +
|
|
149
|
+
// transition suppression) is NOT registered here. It must outlive this
|
|
150
|
+
// island's mount/unmount, so it lives at module scope — see
|
|
151
|
+
// registerSidebarSpaNavGuard() above. (#2198)
|
|
99
152
|
|
|
100
153
|
return (
|
|
101
154
|
<button
|