@takazudo/zudo-doc 5.5.3 → 5.6.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 +26 -0
- package/README.md +39 -0
- package/dist/chrome/derive.d.ts +46 -0
- package/dist/chrome/derive.js +6 -2
- package/dist/config-assertions/index.d.ts +31 -0
- package/dist/config-assertions/index.js +24 -0
- package/dist/config.d.ts +23 -2
- package/dist/config.js +3 -0
- package/dist/current-path/index.d.ts +27 -0
- package/dist/current-path/index.js +11 -0
- package/dist/design-token-panel-bootstrap.d.ts +89 -23
- package/dist/design-token-panel-bootstrap.js +19 -6
- package/dist/doc-page-props/index.d.ts +5 -67
- package/dist/doc-route-entries/index.d.ts +10 -95
- package/dist/doc-route-entries/index.js +1 -78
- package/dist/doc-route-paths/index.d.ts +1 -1
- package/dist/head-with-defaults/index.d.ts +3 -1
- package/dist/head-with-defaults/index.js +76 -4
- package/dist/header/nav-active.d.ts +28 -0
- package/dist/header/nav-active.js +2 -1
- package/dist/header/nav-overflow-script.js +30 -17
- package/dist/header-with-defaults/index.js +11 -2
- package/dist/i18n-version/language-switcher.d.ts +6 -0
- package/dist/i18n-version/language-switcher.js +3 -1
- package/dist/i18n-version/version-switcher.d.ts +6 -0
- package/dist/i18n-version/version-switcher.js +3 -1
- package/dist/nav-source-docs/index.d.ts +7 -11
- package/dist/plugins/route-pages-candidates.d.ts +19 -0
- package/dist/plugins/route-pages-candidates.js +17 -0
- package/dist/plugins/routes.d.ts +46 -0
- package/dist/plugins/routes.js +72 -18
- package/dist/preset.d.ts +12 -1
- package/dist/preset.js +2 -0
- package/dist/route-context/index.js +2 -2
- package/dist/routes/_chrome.d.ts +1 -1
- package/dist/routes/_chrome.js +4 -0
- package/dist/routes/_context.d.ts +3 -3
- package/dist/routes/_design-token-panel-bootstrap.d.ts +18 -0
- package/dist/routes/_design-token-panel-bootstrap.js +11 -0
- package/dist/routes/_docs-helpers.d.ts +1 -36
- package/dist/routes/_docs-helpers.js +0 -138
- package/dist/safelist.css +1 -1
- package/dist/search-widget-script/generated-script.d.ts +8 -0
- package/dist/search-widget-script/generated-script.js +465 -0
- package/dist/search-widget-script/index.d.ts +1 -18
- package/dist/search-widget-script/index.js +1 -443
- package/dist/settings.d.ts +82 -1
- package/dist/sidebar-tree/category-meta.d.ts +9 -0
- package/dist/sidebar-tree/category-meta.js +21 -12
- package/dist/sidebar-tree-island/index.d.ts +8 -1
- package/dist/sidebar-tree-island/index.js +16 -14
- package/dist/site-schema/doc-route-entries.d.ts +89 -0
- package/dist/site-schema/doc-route-entries.js +83 -0
- package/dist/site-schema/index.d.ts +17 -0
- package/dist/site-schema/index.js +46 -0
- package/dist/site-schema/nav-tree.d.ts +28 -0
- package/dist/site-schema/nav-tree.js +138 -0
- package/dist/site-schema/types.d.ts +97 -0
- package/dist/site-schema/types.js +0 -0
- package/dist/theme/theme-pack-provider.d.ts +34 -3
- package/dist/theme/theme-pack-provider.js +30 -2
- package/eject/header/nav-active.ts +13 -1
- package/eject/header/nav-overflow-script.ts +30 -17
- package/eject/sidebar-tree-island/index.tsx +44 -20
- package/package.json +22 -12
- package/routes-src/_chrome.tsx +21 -9
- package/routes-src/_design-token-panel-bootstrap.tsx +63 -0
- package/routes-src/_docs-helpers.ts +18 -225
- package/routes-src/_virtual.d.ts +5 -2
- package/virtual-modules.d.ts +5 -2
|
@@ -11,6 +11,9 @@ import {
|
|
|
11
11
|
THEME_PACK_STORAGE_KEY,
|
|
12
12
|
buildPackCssUrl
|
|
13
13
|
} from "../theme-pack-switcher/theme-pack-sync.js";
|
|
14
|
+
const THEME_PACK_LOADING_ATTR = "data-zd-theme-pack-loading";
|
|
15
|
+
const THEME_PACK_LOAD_WATCHDOG_MS = 2e3;
|
|
16
|
+
const THEME_PACK_LATCH_CSS = `html[${THEME_PACK_LOADING_ATTR}] body{visibility:hidden}`;
|
|
14
17
|
function themePackVersionMap(registry) {
|
|
15
18
|
const map = {};
|
|
16
19
|
for (const entry of registry) {
|
|
@@ -33,6 +36,8 @@ function buildThemePackBootstrap(configuredSlug, enabled, base) {
|
|
|
33
36
|
const runtimeGlobal = JSON.stringify(THEME_PACK_RUNTIME_GLOBAL);
|
|
34
37
|
const afterNav = JSON.stringify(AFTER_NAVIGATE_EVENT);
|
|
35
38
|
const beforeSwap = JSON.stringify(BEFORE_SWAP_EVENT);
|
|
39
|
+
const loadingAttr = JSON.stringify(THEME_PACK_LOADING_ATTR);
|
|
40
|
+
const watchdog = JSON.stringify(THEME_PACK_LOAD_WATCHDOG_MS);
|
|
36
41
|
return `(function(){
|
|
37
42
|
var configured=${configured};
|
|
38
43
|
var packs=${packs};
|
|
@@ -40,12 +45,31 @@ var base=${b};
|
|
|
40
45
|
var KEY=${key};
|
|
41
46
|
var ATTR=${attr};
|
|
42
47
|
var LINK_ATTR=${linkAttr};
|
|
48
|
+
var LOADING_ATTR=${loadingAttr};
|
|
49
|
+
var WATCHDOG=${watchdog};
|
|
43
50
|
var DEFAULT_SLUG=${defaultSlug};
|
|
44
51
|
function resolveSlug(){var stored=null;try{stored=localStorage.getItem(KEY);}catch(e){}if(stored&&Object.prototype.hasOwnProperty.call(packs,stored))return stored;var live=document.documentElement.getAttribute(ATTR);if(live&&Object.prototype.hasOwnProperty.call(packs,live))return live;return configured;}
|
|
45
52
|
function packHref(slug){return base+"theme-packs/"+slug+"/pack.css?v="+packs[slug];}
|
|
53
|
+
function hasPackLink(href){var ls=document.querySelectorAll("link["+LINK_ATTR+"]");for(var i=0;i<ls.length;i++){if(ls[i].getAttribute("href")===href)return true;}return false;}
|
|
46
54
|
var slug=resolveSlug();
|
|
47
|
-
document.documentElement
|
|
48
|
-
|
|
55
|
+
var root=document.documentElement;
|
|
56
|
+
root.setAttribute(ATTR,slug);
|
|
57
|
+
if(slug!==DEFAULT_SLUG){
|
|
58
|
+
var href=packHref(slug);
|
|
59
|
+
if(!hasPackLink(href)){
|
|
60
|
+
var shouldLatch=document.readyState==="loading";
|
|
61
|
+
if(shouldLatch){root.setAttribute(LOADING_ATTR,"");}
|
|
62
|
+
var release=function(){root.removeAttribute(LOADING_ATTR);};
|
|
63
|
+
var link=document.createElement("link");
|
|
64
|
+
link.setAttribute("rel","stylesheet");
|
|
65
|
+
link.setAttribute(LINK_ATTR,"");
|
|
66
|
+
link.setAttribute("href",href);
|
|
67
|
+
link.onload=release;
|
|
68
|
+
link.onerror=release;
|
|
69
|
+
document.head.appendChild(link);
|
|
70
|
+
if(shouldLatch){setTimeout(release,WATCHDOG);}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
49
73
|
window[${runtimeGlobal}]={base:base,packs:packs,configured:configured};
|
|
50
74
|
document.addEventListener(${beforeSwap},function(e){
|
|
51
75
|
var s=resolveSlug();
|
|
@@ -81,11 +105,15 @@ function ThemePackProvider({
|
|
|
81
105
|
const configuredVersion = enabled[configuredSlug];
|
|
82
106
|
const noscriptHref = configuredSlug !== DEFAULT_THEME_PACK_SLUG && configuredVersion !== void 0 ? buildPackCssUrl(base, configuredSlug, configuredVersion) : null;
|
|
83
107
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
108
|
+
/* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: THEME_PACK_LATCH_CSS } }),
|
|
84
109
|
/* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: bootstrap } }),
|
|
85
110
|
noscriptHref !== null && /* @__PURE__ */ jsx("noscript", { children: /* @__PURE__ */ jsx("link", { rel: "stylesheet", href: noscriptHref }) })
|
|
86
111
|
] });
|
|
87
112
|
}
|
|
88
113
|
export {
|
|
114
|
+
THEME_PACK_LATCH_CSS,
|
|
115
|
+
THEME_PACK_LOADING_ATTR,
|
|
116
|
+
THEME_PACK_LOAD_WATCHDOG_MS,
|
|
89
117
|
buildThemePackBootstrap,
|
|
90
118
|
ThemePackProvider as default,
|
|
91
119
|
resolveThemePackSsrSlug,
|
|
@@ -53,13 +53,25 @@ export function pathForMatch(
|
|
|
53
53
|
/**
|
|
54
54
|
* Segment-aware prefix test: nav path `/docs/guides` matches `/docs/guides`
|
|
55
55
|
* and `/docs/guides/...` but NOT `/docs/guideship`.
|
|
56
|
+
*
|
|
57
|
+
* Exported (not just module-private) so `nav-overflow-script.ts` can embed it
|
|
58
|
+
* verbatim via `.toString()` alongside `computeActiveNavPath` — that function
|
|
59
|
+
* closes over this one, so a bare `computeActiveNavPath.toString()` embed
|
|
60
|
+
* would reference an undefined `pathMatchesNavPath` in the browser (see the
|
|
61
|
+
* caution note on `computeActiveNavPath` below). Kept self-contained (no
|
|
62
|
+
* outer references) for the same reason.
|
|
56
63
|
*/
|
|
57
|
-
function pathMatchesNavPath(currentPath: string, navPath: string): boolean {
|
|
64
|
+
export function pathMatchesNavPath(currentPath: string, navPath: string): boolean {
|
|
58
65
|
if (currentPath === navPath) return true;
|
|
59
66
|
const prefix = navPath.endsWith("/") ? navPath : `${navPath}/`;
|
|
60
67
|
return currentPath.startsWith(prefix);
|
|
61
68
|
}
|
|
62
69
|
|
|
70
|
+
/**
|
|
71
|
+
* CAUTION (zudolab/zudo-doc#3398): this closes over `pathMatchesNavPath`
|
|
72
|
+
* above. `nav-overflow-script.ts` embeds both via `.toString()` (never this
|
|
73
|
+
* one alone) so the generated browser script is self-contained.
|
|
74
|
+
*/
|
|
63
75
|
export function computeActiveNavPath(
|
|
64
76
|
navItems: readonly NavItemLike[],
|
|
65
77
|
pathForMatchValue: string,
|
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
// script can be reviewed in isolation.
|
|
32
32
|
|
|
33
33
|
import { AFTER_NAVIGATE_EVENT } from "../transitions/page-events.js";
|
|
34
|
+
import { CURRENT_PATH_SCRIPT_PRELUDE } from "../current-path/index.js";
|
|
35
|
+
import { computeActiveNavPath, pathMatchesNavPath } from "./nav-active.js";
|
|
34
36
|
import {
|
|
35
37
|
NAV_CHEVRON_ACTIVE,
|
|
36
38
|
NAV_CHEVRON_INACTIVE,
|
|
@@ -78,20 +80,26 @@ export const NAV_OVERFLOW_SCRIPT = `(function () {
|
|
|
78
80
|
catch (e) { return ""; }
|
|
79
81
|
}
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
// Explicit current-route override, embedded from current-path/index.ts so
|
|
84
|
+
// this script cannot drift from the three other read sites
|
|
85
|
+
// (zudolab/zudo-doc#3398, #3408).
|
|
86
|
+
${CURRENT_PATH_SCRIPT_PRELUDE}
|
|
87
|
+
|
|
88
|
+
// Shared matching core (zudolab/zudo-doc#3398): embedded verbatim from
|
|
89
|
+
// nav-active.ts so this script's longest-match walk cannot drift from the
|
|
90
|
+
// SSR header's own computeActiveNavPath call (header.tsx). computeActiveNavPath
|
|
91
|
+
// closes over pathMatchesNavPath, so both are embedded together.
|
|
92
|
+
var pathMatchesNavPath = ${pathMatchesNavPath.toString()};
|
|
93
|
+
var computeActiveNavPath = ${computeActiveNavPath.toString()};
|
|
86
94
|
|
|
87
95
|
// Recompute which header nav item is "active" from the CURRENT URL and
|
|
88
96
|
// repaint the highlight. SSR sets the active item on first paint, but the
|
|
89
97
|
// header is persisted across same-locale client-router swaps
|
|
90
98
|
// (data-zfb-transition-persist), so without this the highlight would stay
|
|
91
99
|
// frozen on the page where the header was first rendered. Mirrors the
|
|
92
|
-
// sidebar island's client-side approach (match
|
|
100
|
+
// sidebar island's client-side approach (match the current path against
|
|
93
101
|
// each entry's href) and the SSR longest-match + dropdown-parent rules.
|
|
94
|
-
// URL-based: hrefs and
|
|
102
|
+
// URL-based: hrefs and the current path both carry the base + locale
|
|
95
103
|
// prefix, so they compare directly without stripping.
|
|
96
104
|
function applyActiveNav() {
|
|
97
105
|
var nav = document.querySelector("[data-header-nav]");
|
|
@@ -99,26 +107,31 @@ export const NAV_OVERFLOW_SCRIPT = `(function () {
|
|
|
99
107
|
var topItems = Array.from(nav.querySelectorAll(":scope > [data-nav-item]"));
|
|
100
108
|
if (topItems.length === 0) return;
|
|
101
109
|
|
|
102
|
-
var cur = trimSlashes(
|
|
110
|
+
var cur = trimSlashes(readCurrentPath(CURRENT_PATH_DATASET_KEY));
|
|
103
111
|
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
|
|
112
|
+
// Build NavItemLike-shaped entries from the live DOM so the shared
|
|
113
|
+
// computeActiveNavPath can do the deepest-match walk — the same call
|
|
114
|
+
// shape the SSR header uses (matches computeActiveNavPath). A dropdown
|
|
115
|
+
// missing its own top-level anchor is skipped entirely (path "" would
|
|
116
|
+
// otherwise match every current path — pathMatchesNavPath treats "" as
|
|
117
|
+
// the root "/"), mirroring the parentLink guard used below for the same
|
|
118
|
+
// malformed-markup case.
|
|
119
|
+
var navItems = [];
|
|
107
120
|
topItems.forEach(function (it) {
|
|
108
121
|
var isDropdown = it.hasAttribute("data-nav-item-dropdown");
|
|
109
122
|
var topA = isDropdown ? it.querySelector(":scope > a") : it;
|
|
110
|
-
if (topA)
|
|
111
|
-
|
|
112
|
-
if (isUnderPath(cur, tp) && tp.length > activePath.length) activePath = tp;
|
|
113
|
-
}
|
|
123
|
+
if (!topA) return;
|
|
124
|
+
var children = [];
|
|
114
125
|
if (isDropdown) {
|
|
115
126
|
it.querySelectorAll(":scope > div a").forEach(function (c) {
|
|
116
|
-
|
|
117
|
-
if (isUnderPath(cur, cp) && cp.length > activePath.length) activePath = cp;
|
|
127
|
+
children.push({ path: navPathname(c) });
|
|
118
128
|
});
|
|
119
129
|
}
|
|
130
|
+
navItems.push({ path: navPathname(topA), children: children });
|
|
120
131
|
});
|
|
121
132
|
|
|
133
|
+
var activePath = computeActiveNavPath(navItems, cur) || "";
|
|
134
|
+
|
|
122
135
|
function setTopActive(a, active) {
|
|
123
136
|
if (!a) return;
|
|
124
137
|
if (active) {
|
|
@@ -18,6 +18,7 @@ import { smartBreakToHtml } from "../smart-break/index.js";
|
|
|
18
18
|
import { AFTER_NAVIGATE_EVENT, BEFORE_NAVIGATE_EVENT } from "../transitions/index.js";
|
|
19
19
|
import { filterTree } from "../sidebar-filter/index.js";
|
|
20
20
|
import { findActiveSlug, normalizePath } from "../sidebar-active-slug/index.js";
|
|
21
|
+
import { CURRENT_PATH_DATASET_KEY, readCurrentPath } from "../current-path/index.js";
|
|
21
22
|
import { ensureSidebarScrollPreserve } from "./sidebar-scroll-preserve.js";
|
|
22
23
|
|
|
23
24
|
// The persisted aside can transiently tear down and re-mount its SidebarTree
|
|
@@ -61,38 +62,54 @@ function saveOpenSet(set: Set<string>) {
|
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
/**
|
|
64
|
-
* Derive the active slug from
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
65
|
+
* Derive the active slug from an explicit current-route input. Resolution
|
|
66
|
+
* order is owned by {@link readCurrentPath}: the `pathname` argument, then the
|
|
67
|
+
* `data-zd-current-path` override, then `window.location.pathname`. Used as a
|
|
68
|
+
* hydration-time fallback when the parent island does not forward
|
|
69
|
+
* `currentSlug` through its prop boundary, and at every View Transition to
|
|
70
|
+
* keep the highlight in sync.
|
|
71
|
+
*
|
|
72
|
+
* Returns `undefined` both when no pathname is resolvable AND when the
|
|
73
|
+
* resolved pathname matches no route (e.g. the literal "srcdoc") — callers
|
|
74
|
+
* must treat `undefined` as "no update," preserving whatever active slug is
|
|
75
|
+
* already set rather than clearing it.
|
|
68
76
|
*/
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
77
|
+
function deriveActiveSlug(nodes: SidebarNavNode[], pathname?: string): string | undefined {
|
|
78
|
+
// An empty-string `pathname` must fall through to the live sources instead
|
|
79
|
+
// of silently disabling derivation — SidebarWithDefaults defaults its own
|
|
80
|
+
// currentPath to "", so "" is the natural absent shape.
|
|
81
|
+
const resolved = readCurrentPath(CURRENT_PATH_DATASET_KEY, pathname);
|
|
82
|
+
if (!resolved) return undefined;
|
|
83
|
+
return findActiveSlug(nodes, normalizePath(resolved));
|
|
73
84
|
}
|
|
74
85
|
|
|
75
86
|
/**
|
|
76
87
|
* Track the current active slug, updating on View Transition navigations.
|
|
77
88
|
*
|
|
78
89
|
* The initial-state initialiser prefers the SSR-supplied `initial` prop, but
|
|
79
|
-
* falls back to
|
|
80
|
-
* prop is missing.
|
|
90
|
+
* falls back to `deriveActiveSlug` (explicit `currentPath` input, then the
|
|
91
|
+
* override/location fallbacks) when the prop is missing.
|
|
81
92
|
*/
|
|
82
|
-
function useActiveSlug(nodes: SidebarNavNode[], initial?: string): string | undefined {
|
|
93
|
+
function useActiveSlug(nodes: SidebarNavNode[], initial?: string, currentPath?: string): string | undefined {
|
|
83
94
|
const [slug, setSlug] = useState<string | undefined>(() =>
|
|
84
|
-
initial !== undefined ? initial :
|
|
95
|
+
initial !== undefined ? initial : deriveActiveSlug(nodes, currentPath),
|
|
85
96
|
);
|
|
86
97
|
|
|
87
98
|
useEffect(() => {
|
|
88
|
-
const update = () => {
|
|
89
|
-
const found =
|
|
99
|
+
const update = (pathname?: string) => {
|
|
100
|
+
const found = deriveActiveSlug(nodes, pathname);
|
|
90
101
|
if (found !== undefined) setSlug(found);
|
|
91
102
|
};
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
// The static `currentPath` prop is an SSR-serialized value for the page the
|
|
104
|
+
// island first hydrated on — valid at hydration time only. Post-navigation
|
|
105
|
+
// updates must re-read the LIVE sources (dataset override, then
|
|
106
|
+
// location.pathname); recomputing from the frozen prop would pin the
|
|
107
|
+
// highlight to the first-loaded page across client-router navigations.
|
|
108
|
+
const onNavigate = () => update();
|
|
109
|
+
update(currentPath);
|
|
110
|
+
document.addEventListener(AFTER_NAVIGATE_EVENT, onNavigate);
|
|
111
|
+
return () => document.removeEventListener(AFTER_NAVIGATE_EVENT, onNavigate);
|
|
112
|
+
}, [nodes, currentPath]);
|
|
96
113
|
|
|
97
114
|
return slug;
|
|
98
115
|
}
|
|
@@ -143,6 +160,13 @@ function RootMenuItemEntry({ item }: { item: SidebarRootMenuItem }) {
|
|
|
143
160
|
export interface SidebarTreeProps {
|
|
144
161
|
nodes: SidebarNavNode[];
|
|
145
162
|
currentSlug?: string;
|
|
163
|
+
/**
|
|
164
|
+
* Explicit current-route override, checked before the
|
|
165
|
+
* `data-zd-current-path` dataset override and `window.location.pathname`
|
|
166
|
+
* when deriving the active slug on hydration and at every View Transition.
|
|
167
|
+
* See `deriveActiveSlug` (zudolab/zudo-doc#3398).
|
|
168
|
+
*/
|
|
169
|
+
currentPath?: string;
|
|
146
170
|
rootMenuItems?: SidebarRootMenuItem[];
|
|
147
171
|
backToMenuLabel?: string;
|
|
148
172
|
localeLinks?: SidebarLocaleLink[];
|
|
@@ -171,8 +195,8 @@ function SidebarFooter({ links, themeDefaultMode }: { links?: SidebarLocaleLink[
|
|
|
171
195
|
);
|
|
172
196
|
}
|
|
173
197
|
|
|
174
|
-
export function SidebarTree({ nodes, currentSlug, rootMenuItems, backToMenuLabel, localeLinks, themeDefaultMode }: SidebarTreeProps) {
|
|
175
|
-
const activeSlug = useActiveSlug(nodes, currentSlug);
|
|
198
|
+
export function SidebarTree({ nodes, currentSlug, currentPath, rootMenuItems, backToMenuLabel, localeLinks, themeDefaultMode }: SidebarTreeProps) {
|
|
199
|
+
const activeSlug = useActiveSlug(nodes, currentSlug, currentPath);
|
|
176
200
|
const [query, setQuery] = useState("");
|
|
177
201
|
const [showingRootMenu, setShowingRootMenu] = useState(false);
|
|
178
202
|
const filterRef = useRef<HTMLInputElement>(null);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@takazudo/zudo-doc",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.6.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",
|
|
@@ -239,6 +239,10 @@
|
|
|
239
239
|
"types": "./dist/catalog.d.ts",
|
|
240
240
|
"default": "./dist/catalog.js"
|
|
241
241
|
},
|
|
242
|
+
"./site-schema": {
|
|
243
|
+
"types": "./dist/site-schema/index.d.ts",
|
|
244
|
+
"default": "./dist/site-schema/index.js"
|
|
245
|
+
},
|
|
242
246
|
"./theme.css": "./dist/theme.css",
|
|
243
247
|
"./safelist.css": "./dist/safelist.css",
|
|
244
248
|
"./content.css": "./dist/content.css",
|
|
@@ -553,6 +557,10 @@
|
|
|
553
557
|
"types": "./dist/sidebar-active-slug/index.d.ts",
|
|
554
558
|
"default": "./dist/sidebar-active-slug/index.js"
|
|
555
559
|
},
|
|
560
|
+
"./current-path": {
|
|
561
|
+
"types": "./dist/current-path/index.d.ts",
|
|
562
|
+
"default": "./dist/current-path/index.js"
|
|
563
|
+
},
|
|
556
564
|
"./i18n-defaults": {
|
|
557
565
|
"types": "./dist/i18n-defaults/index.d.ts",
|
|
558
566
|
"default": "./dist/i18n-defaults/index.js"
|
|
@@ -609,11 +617,11 @@
|
|
|
609
617
|
"CHANGELOG.md"
|
|
610
618
|
],
|
|
611
619
|
"peerDependencies": {
|
|
612
|
-
"@takazudo/zdtp": "^0.4.
|
|
613
|
-
"@takazudo/zfb": "^2.
|
|
614
|
-
"@takazudo/zfb-md-wasm": "^2.
|
|
615
|
-
"@takazudo/zfb-runtime": "^2.
|
|
616
|
-
"@takazudo/zudo-doc-history-server": "^5.5.
|
|
620
|
+
"@takazudo/zdtp": "^0.4.11",
|
|
621
|
+
"@takazudo/zfb": "^2.7.1",
|
|
622
|
+
"@takazudo/zfb-md-wasm": "^2.7.1",
|
|
623
|
+
"@takazudo/zfb-runtime": "^2.7.1",
|
|
624
|
+
"@takazudo/zudo-doc-history-server": "^5.5.3",
|
|
617
625
|
"diff": "^8.0.0",
|
|
618
626
|
"katex": "^0.16.0",
|
|
619
627
|
"preact": "^10.29.1",
|
|
@@ -647,14 +655,15 @@
|
|
|
647
655
|
"tsx": "^4.21.0"
|
|
648
656
|
},
|
|
649
657
|
"devDependencies": {
|
|
650
|
-
"@takazudo/zfb": "2.
|
|
651
|
-
"@takazudo/zfb-md-wasm": "2.
|
|
652
|
-
"@takazudo/zfb-runtime": "2.
|
|
658
|
+
"@takazudo/zfb": "2.7.1",
|
|
659
|
+
"@takazudo/zfb-md-wasm": "2.7.1",
|
|
660
|
+
"@takazudo/zfb-runtime": "2.7.1",
|
|
653
661
|
"@types/fs-extra": "^11.0.4",
|
|
654
662
|
"@types/minimist": "^1.2.5",
|
|
655
663
|
"@types/node": "^25.3.5",
|
|
656
664
|
"@types/pluralize": "^0.0.33",
|
|
657
665
|
"@types/string-similarity": "^4.0.2",
|
|
666
|
+
"esbuild": ">=0.28.1",
|
|
658
667
|
"happy-dom": "^20.10.6",
|
|
659
668
|
"npm-run-all2": "^7.0.2",
|
|
660
669
|
"preact": "^10.29.1",
|
|
@@ -663,11 +672,12 @@
|
|
|
663
672
|
"typescript": "^5.0.0",
|
|
664
673
|
"vitest": "^4.1.0",
|
|
665
674
|
"zod": "^4.3.6",
|
|
666
|
-
"@takazudo/zudo-doc-history-server": "5.
|
|
675
|
+
"@takazudo/zudo-doc-history-server": "5.6.0"
|
|
667
676
|
},
|
|
668
677
|
"scripts": {
|
|
669
|
-
"
|
|
670
|
-
"
|
|
678
|
+
"gen:search-widget-script": "node scripts/gen-search-widget-script.mjs",
|
|
679
|
+
"build": "node scripts/gen-search-widget-script.mjs && tsup && tsc -p tsconfig.build.json",
|
|
680
|
+
"predev": "node ../../scripts/ensure-workspace-build.mjs && node scripts/gen-search-widget-script.mjs",
|
|
671
681
|
"// dev": "Do NOT add `--continue-on-error` here. It stops a fatal watcher exit from cascading, but the dead watcher then fails silently — a dead dev:dts leaves dist/*.d.ts frozen while the JS keeps updating, which typechecks cleanly against stale types instead of failing loudly like #3113's absent declarations did. See the #3129 section in CLAUDE.md.",
|
|
672
682
|
"dev": "run-p dev:js dev:dts",
|
|
673
683
|
"dev:js": "tsup --watch",
|
package/routes-src/_chrome.tsx
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import { routeCtx } from "./_context.js";
|
|
14
14
|
import { createChrome } from "@takazudo/zudo-doc/chrome";
|
|
15
15
|
import { DocHistory } from "@takazudo/zudo-doc/doc-history";
|
|
16
|
-
import type { DocNavNode } from "
|
|
16
|
+
import type { DocNavNode } from "@takazudo/zudo-doc/site-schema";
|
|
17
17
|
// Imported via the BARE published subpath rather than a relative
|
|
18
18
|
// `../chrome-bindings.js`. This file is copied into consumer projects by the
|
|
19
19
|
// routes-src mechanism (`scripts/copy-routes-src.mjs`), which rewrites relative
|
|
@@ -27,6 +27,10 @@ import { defineChromeBindings } from "@takazudo/zudo-doc/chrome-bindings";
|
|
|
27
27
|
// ("Host-callables channel — chromeBindingsModule"). Not present on disk; the
|
|
28
28
|
// package ships ambient typings for it (`routes/_virtual.d.ts`).
|
|
29
29
|
import { chromeBindings } from "virtual:zudo-doc-chrome-bindings";
|
|
30
|
+
// Routes-only configured design-token-panel island (#3396) — the ONLY importer
|
|
31
|
+
// of `virtual:zudo-doc-design-token-panel-config` in the package. Static, for
|
|
32
|
+
// the same island-scanner reason as `DocHistory` above.
|
|
33
|
+
import { ConfiguredDesignTokenPanelBootstrap } from "./_design-token-panel-bootstrap.js";
|
|
30
34
|
|
|
31
35
|
// Island-scanner contract (load-bearing): the injected doc routes reach the real
|
|
32
36
|
// DocHistory client island ONLY through this static import → `createChrome`
|
|
@@ -57,15 +61,23 @@ import { chromeBindings } from "virtual:zudo-doc-chrome-bindings";
|
|
|
57
61
|
// the way the static `DocHistory` import above is (the virtual re-export sits
|
|
58
62
|
// outside zfb's static-import scanner reachability graph) — see the ADR.
|
|
59
63
|
//
|
|
60
|
-
// `DesignTokenPanelBootstrap`
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
// `
|
|
64
|
+
// `DesignTokenPanelBootstrap` IS threaded here since #3396, but only to swap
|
|
65
|
+
// the BUILDER — the mount, the settings gate, and the slot default all still
|
|
66
|
+
// belong to `chrome/derive.tsx`'s `deriveBodyEndIslands` (gate-2 fix from the
|
|
67
|
+
// Wave-5 confirm #2659), so the locked-manifest self-contained doc stub (#2653)
|
|
68
|
+
// and every other bare `createChrome` caller keep getting the package-default
|
|
69
|
+
// island with no explicit wiring. On THESE injected routes the configured
|
|
70
|
+
// wrapper wins, which is what carries a host's
|
|
71
|
+
// `settings.designTokenPanelConfigModule` through. Scanner reachability holds
|
|
72
|
+
// through the static chain route → this shim → `_design-token-panel-bootstrap`.
|
|
73
|
+
//
|
|
74
|
+
// It is spread BEFORE `...chromeBindings` (unlike `DocHistory`, which is spread
|
|
75
|
+
// after): a host's own `DesignTokenPanelBootstrap` slot value must still win,
|
|
76
|
+
// exactly as it did when the derive-level default was the only package wiring.
|
|
68
77
|
const chrome = createChrome(routeCtx, {
|
|
78
|
+
...defineChromeBindings({
|
|
79
|
+
DesignTokenPanelBootstrap: ConfiguredDesignTokenPanelBootstrap,
|
|
80
|
+
}),
|
|
69
81
|
...chromeBindings,
|
|
70
82
|
...defineChromeBindings({ DocHistory }),
|
|
71
83
|
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/** @jsxRuntime automatic */
|
|
4
|
+
/** @jsxImportSource preact */
|
|
5
|
+
|
|
6
|
+
// routes/_design-token-panel-bootstrap — the ROUTES-ONLY configured
|
|
7
|
+
// design-token-panel island (#3396, epic #3394).
|
|
8
|
+
//
|
|
9
|
+
// WHY THIS FILE EXISTS: `virtual:zudo-doc-design-token-panel-config` is
|
|
10
|
+
// registered by the routes plugin, so any module that imports it statically
|
|
11
|
+
// drags the plugin along as a hard requirement. Until #3396 that importer was
|
|
12
|
+
// `../design-token-panel-bootstrap.tsx`, which `chrome/derive.tsx` imports —
|
|
13
|
+
// meaning `@takazudo/zudo-doc/chrome` could not be bundled outside a zfb build
|
|
14
|
+
// (or by a `packageOwnedRoutes: false` host) without aliasing the specifier.
|
|
15
|
+
// Moving the import HERE confines it to the routes graph, which zfb always
|
|
16
|
+
// bundles with the plugin active.
|
|
17
|
+
//
|
|
18
|
+
// WHY A COMPONENT AND NOT A SETTER: the route/SSR module graph and the
|
|
19
|
+
// hydrated island bundle are SEPARATE graphs. A `setPanelConfigBuilder(...)`
|
|
20
|
+
// called while `_chrome.tsx` evaluates would configure only the server-side
|
|
21
|
+
// copy of the bootstrap module; the client bundle re-evaluates that module
|
|
22
|
+
// independently and would keep the package default. Passing the builder as an
|
|
23
|
+
// argument from a component that lives INSIDE the island bundle is the only
|
|
24
|
+
// shape that survives the boundary.
|
|
25
|
+
//
|
|
26
|
+
// ISLAND-SCANNER CONTRACT (#2480 lesson): `_chrome.tsx` imports this module
|
|
27
|
+
// STATICALLY and threads the component into `hostBindings`, so the scanner
|
|
28
|
+
// walks route → _chrome → here. The exported binding identifier and the
|
|
29
|
+
// `displayName` must stay IDENTICAL — zfb registers islands by the
|
|
30
|
+
// scanner-visible export name, and a marker whose name has no registry entry
|
|
31
|
+
// silently never hydrates. The name must also stay DISTINCT from
|
|
32
|
+
// `DesignTokenPanelBootstrap`: `chrome/derive.tsx` still statically imports
|
|
33
|
+
// that package default (it is the slot default for bare `createChrome`
|
|
34
|
+
// callers), so both components are in the scanned graph and a shared name
|
|
35
|
+
// would trip zfb's "island marker name collision" warning and drop one of them.
|
|
36
|
+
|
|
37
|
+
import type { JSX } from "preact";
|
|
38
|
+
import { runDesignTokenPanelBootstrapOnce } from "@takazudo/zudo-doc/design-token-panel-bootstrap";
|
|
39
|
+
// Host-callables channel, third virtual module (#2658, mirrors #2501's
|
|
40
|
+
// chromeBindingsModule): absent `settings.designTokenPanelConfigModule` →
|
|
41
|
+
// re-exports the package default (`@takazudo/zudo-doc/design-token-panel-config`);
|
|
42
|
+
// present → re-exports the host's module. Registered unconditionally by the
|
|
43
|
+
// routes plugin (`../plugins/routes.ts`) whenever `packageOwnedRoutes` is on.
|
|
44
|
+
// Not present on disk; the package ships ambient typings for it
|
|
45
|
+
// (`./_virtual.d.ts`).
|
|
46
|
+
import { buildDesignTokenPanelConfig } from "virtual:zudo-doc-design-token-panel-config";
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The design-token-panel island injected routes mount instead of the package
|
|
50
|
+
* default: identical behavior, except the mode-scoped `PanelConfig` builder is
|
|
51
|
+
* the one the routes plugin resolved — the host's
|
|
52
|
+
* `settings.designTokenPanelConfigModule` when set, the package default
|
|
53
|
+
* otherwise.
|
|
54
|
+
*
|
|
55
|
+
* Renders `null` on both SSR and client (the panel self-mounts as a side
|
|
56
|
+
* effect of `bootstrapDesignTokenPanel`), matching the package default's
|
|
57
|
+
* non-`ssrFallback` `Island({ when: "load" })` shape.
|
|
58
|
+
*/
|
|
59
|
+
export function ConfiguredDesignTokenPanelBootstrap(): JSX.Element | null {
|
|
60
|
+
runDesignTokenPanelBootstrapOnce(buildDesignTokenPanelConfig, "configured");
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
ConfiguredDesignTokenPanelBootstrap.displayName = "ConfiguredDesignTokenPanelBootstrap";
|