@takazudo/zudo-doc 5.5.3 → 5.7.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 +51 -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 +31 -0
- package/dist/header/nav-active.js +2 -1
- package/dist/header/nav-overflow-generated-script.d.ts +11 -0
- package/dist/header/nav-overflow-generated-script.js +302 -0
- package/dist/header/nav-overflow-script.d.ts +1 -1
- package/dist/header/nav-overflow-script.js +1 -286
- 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/md-utils/index.js +33 -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-toggle-island/index.js +2 -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/dist/transitions/index.d.ts +1 -0
- package/dist/transitions/index.js +2 -0
- package/dist/transitions/nested-island-props-refresh.d.ts +19 -0
- package/dist/transitions/nested-island-props-refresh.js +104 -0
- package/eject/header/header.tsx +13 -5
- package/eject/header/nav-active.ts +16 -1
- package/eject/header/nav-class-tokens.ts +9 -5
- package/eject/header/nav-overflow-generated-script.ts +29 -0
- package/eject/header/nav-overflow-script.ts +26 -304
- package/eject/sidebar-toggle-island/index.tsx +13 -1
- package/eject/sidebar-tree-island/index.tsx +44 -20
- package/package.json +25 -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
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
function buildNavOverflowScript() {
|
|
2
|
+
return `(function () {
|
|
3
|
+
var cleanupNavOverflow = null;
|
|
4
|
+
|
|
5
|
+
function trimSlashes(p) {
|
|
6
|
+
while (p.length > 1 && p.charAt(p.length - 1) === "/") p = p.slice(0, -1);
|
|
7
|
+
return p || "/";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function navPathname(a) {
|
|
11
|
+
try { return trimSlashes(new URL(a.href, location.href).pathname); }
|
|
12
|
+
catch (e) { return ""; }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Explicit current-route override, embedded from current-path/index.ts so
|
|
16
|
+
// this script cannot drift from the three other read sites
|
|
17
|
+
// (zudolab/zudo-doc#3398, #3408).
|
|
18
|
+
var CURRENT_PATH_DATASET_KEY="zdCurrentPath";var readCurrentPath=function readCurrentPath(datasetKey, explicit) {
|
|
19
|
+
const override = typeof document === "undefined" ? void 0 : document.documentElement.dataset[datasetKey];
|
|
20
|
+
return explicit || override || (typeof window === "undefined" ? void 0 : window.location.pathname);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Shared matching core (zudolab/zudo-doc#3398): embedded verbatim from
|
|
24
|
+
// nav-active.ts so this script's longest-match walk cannot drift from the
|
|
25
|
+
// SSR header's own computeActiveNavPath call (header.tsx). computeActiveNavPath
|
|
26
|
+
// closes over pathMatchesNavPath, so both are embedded together.
|
|
27
|
+
var pathMatchesNavPath = function pathMatchesNavPath(currentPath, navPath) {
|
|
28
|
+
if (currentPath === navPath) return true;
|
|
29
|
+
const prefix = navPath.endsWith("/") ? navPath : \`\${navPath}/\`;
|
|
30
|
+
return currentPath.startsWith(prefix);
|
|
31
|
+
};
|
|
32
|
+
var computeActiveNavPath = function computeActiveNavPath(navItems, pathForMatchValue) {
|
|
33
|
+
const allNavPaths = navItems.flatMap((item) => {
|
|
34
|
+
const paths = [item.path];
|
|
35
|
+
if (item.children) {
|
|
36
|
+
paths.push(...item.children.map((child) => child.path));
|
|
37
|
+
}
|
|
38
|
+
return paths;
|
|
39
|
+
});
|
|
40
|
+
return allNavPaths.filter((p) => pathMatchesNavPath(pathForMatchValue, p)).sort((a, b) => b.length - a.length)[0];
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Recompute which header nav item is "active" from the CURRENT URL and
|
|
44
|
+
// repaint the highlight. SSR sets the active item on first paint, but the
|
|
45
|
+
// header is persisted across same-locale client-router swaps
|
|
46
|
+
// (data-zfb-transition-persist), so without this the highlight would stay
|
|
47
|
+
// frozen on the page where the header was first rendered. Mirrors the
|
|
48
|
+
// sidebar island's client-side approach (match the current path against
|
|
49
|
+
// each entry's href) and the SSR longest-match + dropdown-parent rules.
|
|
50
|
+
// URL-based: hrefs and the current path both carry the base + locale
|
|
51
|
+
// prefix, so they compare directly without stripping.
|
|
52
|
+
function applyActiveNav() {
|
|
53
|
+
var nav = document.querySelector("[data-header-nav]");
|
|
54
|
+
if (!nav) return;
|
|
55
|
+
var topItems = Array.from(nav.querySelectorAll(":scope > [data-nav-item]"));
|
|
56
|
+
if (topItems.length === 0) return;
|
|
57
|
+
|
|
58
|
+
var cur = trimSlashes(readCurrentPath(CURRENT_PATH_DATASET_KEY));
|
|
59
|
+
|
|
60
|
+
// Build NavItemLike-shaped entries from the live DOM so the shared
|
|
61
|
+
// computeActiveNavPath can do the deepest-match walk \u2014 the same call
|
|
62
|
+
// shape the SSR header uses (matches computeActiveNavPath). A dropdown
|
|
63
|
+
// missing its own top-level anchor is skipped entirely (path "" would
|
|
64
|
+
// otherwise match every current path \u2014 pathMatchesNavPath treats "" as
|
|
65
|
+
// the root "/"), mirroring the parentLink guard used below for the same
|
|
66
|
+
// malformed-markup case.
|
|
67
|
+
var navItems = [];
|
|
68
|
+
topItems.forEach(function (it) {
|
|
69
|
+
var isDropdown = it.hasAttribute("data-nav-item-dropdown");
|
|
70
|
+
var topA = isDropdown ? it.querySelector(":scope > a") : it;
|
|
71
|
+
if (!topA) return;
|
|
72
|
+
var children = [];
|
|
73
|
+
if (isDropdown) {
|
|
74
|
+
it.querySelectorAll(":scope > div a").forEach(function (c) {
|
|
75
|
+
children.push({ path: navPathname(c) });
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
navItems.push({ path: navPathname(topA), children: children });
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
var activePath = computeActiveNavPath(navItems, cur) || "";
|
|
82
|
+
|
|
83
|
+
function setTopActive(a, active) {
|
|
84
|
+
if (!a) return;
|
|
85
|
+
if (active) {
|
|
86
|
+
a.classList.add("bg-fg", "text-bg");
|
|
87
|
+
a.classList.remove("text-muted", "hover:text-accent", "hover:underline", "focus:underline", "focus:text-accent");
|
|
88
|
+
a.setAttribute("aria-current", "page");
|
|
89
|
+
} else {
|
|
90
|
+
a.classList.remove("bg-fg", "text-bg");
|
|
91
|
+
a.classList.add("text-muted", "hover:text-accent", "hover:underline", "focus:underline", "focus:text-accent");
|
|
92
|
+
a.removeAttribute("aria-current");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
topItems.forEach(function (it) {
|
|
97
|
+
var isDropdown = it.hasAttribute("data-nav-item-dropdown");
|
|
98
|
+
var topA = isDropdown ? it.querySelector(":scope > a") : it;
|
|
99
|
+
var topActive = false;
|
|
100
|
+
|
|
101
|
+
if (isDropdown) {
|
|
102
|
+
var parentMatch = !!topA && navPathname(topA) === activePath && activePath !== "";
|
|
103
|
+
var anyChild = false;
|
|
104
|
+
it.querySelectorAll(":scope > div a").forEach(function (c) {
|
|
105
|
+
var childActive = navPathname(c) === activePath && activePath !== "";
|
|
106
|
+
if (childActive) {
|
|
107
|
+
anyChild = true;
|
|
108
|
+
c.setAttribute("data-active", "");
|
|
109
|
+
c.classList.add("font-bold", "text-accent");
|
|
110
|
+
c.classList.remove("text-fg", "hover:text-accent", "focus-visible:text-accent");
|
|
111
|
+
} else {
|
|
112
|
+
c.removeAttribute("data-active");
|
|
113
|
+
c.classList.remove("font-bold", "text-accent");
|
|
114
|
+
c.classList.add("text-fg", "hover:text-accent", "focus-visible:text-accent");
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
topActive = parentMatch || anyChild;
|
|
118
|
+
var svg = topA ? topA.querySelector("svg") : null;
|
|
119
|
+
if (svg) {
|
|
120
|
+
if (topActive) { svg.classList.add("text-bg"); svg.classList.remove("text-muted"); }
|
|
121
|
+
else { svg.classList.add("text-muted"); svg.classList.remove("text-bg"); }
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
topActive = activePath !== "" && navPathname(topA) === activePath;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
setTopActive(topA, topActive);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function initNavOverflow() {
|
|
132
|
+
if (cleanupNavOverflow) cleanupNavOverflow();
|
|
133
|
+
|
|
134
|
+
// Repaint the active highlight for the current URL before measuring /
|
|
135
|
+
// cloning, so the overflow "\xB7\xB7\xB7" menu mirrors the correct active state.
|
|
136
|
+
applyActiveNav();
|
|
137
|
+
|
|
138
|
+
var nav = document.querySelector("[data-header-nav]");
|
|
139
|
+
var moreContainer = document.querySelector("[data-nav-more]");
|
|
140
|
+
var moreMenu = document.querySelector("[data-nav-more-menu]");
|
|
141
|
+
var moreToggle = document.querySelector("[data-nav-more-toggle]");
|
|
142
|
+
if (!nav || !moreContainer || !moreMenu || !moreToggle) return;
|
|
143
|
+
|
|
144
|
+
var items = Array.from(nav.querySelectorAll(":scope > [data-nav-item]"));
|
|
145
|
+
if (items.length === 0) return;
|
|
146
|
+
|
|
147
|
+
var controller = new AbortController();
|
|
148
|
+
|
|
149
|
+
function update() {
|
|
150
|
+
items.forEach(function (el) { el.style.display = ""; });
|
|
151
|
+
moreContainer.style.display = "";
|
|
152
|
+
moreMenu.innerHTML = "";
|
|
153
|
+
moreMenu.classList.add("hidden");
|
|
154
|
+
moreToggle.setAttribute("aria-expanded", "false");
|
|
155
|
+
|
|
156
|
+
var itemWidths = items.map(function (el) { return el.offsetWidth; });
|
|
157
|
+
var moreWidth = moreContainer.offsetWidth;
|
|
158
|
+
var navGap = parseFloat(getComputedStyle(nav).columnGap) || 0;
|
|
159
|
+
var available = nav.clientWidth;
|
|
160
|
+
|
|
161
|
+
if (available <= 0) {
|
|
162
|
+
moreContainer.style.display = "none";
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
var total = 0;
|
|
167
|
+
for (var i = 0; i < itemWidths.length; i++) {
|
|
168
|
+
total += itemWidths[i] + (i > 0 ? navGap : 0);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (total <= available) {
|
|
172
|
+
moreContainer.style.display = "none";
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
var used = 0;
|
|
177
|
+
var cutoffIndex = 0;
|
|
178
|
+
|
|
179
|
+
for (var i2 = 0; i2 < items.length; i2++) {
|
|
180
|
+
var w = itemWidths[i2] + (i2 > 0 ? navGap : 0);
|
|
181
|
+
if (used + w > available - moreWidth - navGap) break;
|
|
182
|
+
used += w;
|
|
183
|
+
cutoffIndex = i2 + 1;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
for (var i3 = cutoffIndex; i3 < items.length; i3++) {
|
|
187
|
+
items[i3].style.display = "none";
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
for (var i4 = cutoffIndex; i4 < items.length; i4++) {
|
|
191
|
+
var el = items[i4];
|
|
192
|
+
var isDropdown = el.hasAttribute("data-nav-item-dropdown");
|
|
193
|
+
|
|
194
|
+
if (isDropdown) {
|
|
195
|
+
var parentLink = el.querySelector(":scope > a");
|
|
196
|
+
var childLinks = el.querySelectorAll(":scope > div a");
|
|
197
|
+
if (parentLink) {
|
|
198
|
+
var li = document.createElement("li");
|
|
199
|
+
var a = document.createElement("a");
|
|
200
|
+
a.href = parentLink.href;
|
|
201
|
+
var parentText = parentLink.textContent ? parentLink.textContent.trim().replace(/\\s+/g, " ") : "";
|
|
202
|
+
a.textContent = parentText;
|
|
203
|
+
a.className = "block px-hsp-md py-vsp-2xs text-small font-bold hover:bg-accent/10 hover:underline focus-visible:underline focus-visible:text-accent text-fg hover:text-accent";
|
|
204
|
+
if (parentLink.getAttribute("aria-current") === "page") {
|
|
205
|
+
a.className += " text-accent";
|
|
206
|
+
}
|
|
207
|
+
li.appendChild(a);
|
|
208
|
+
moreMenu.appendChild(li);
|
|
209
|
+
}
|
|
210
|
+
childLinks.forEach(function (child) {
|
|
211
|
+
var li = document.createElement("li");
|
|
212
|
+
var a = document.createElement("a");
|
|
213
|
+
a.href = child.href;
|
|
214
|
+
a.textContent = child.textContent ? child.textContent.trim() : "";
|
|
215
|
+
var isChildActive = child.hasAttribute("data-active");
|
|
216
|
+
a.className = isChildActive
|
|
217
|
+
? "block pl-hsp-xl pr-hsp-md py-vsp-2xs text-small font-bold text-accent hover:bg-accent/10 hover:underline focus-visible:underline"
|
|
218
|
+
: "block pl-hsp-xl pr-hsp-md py-vsp-2xs text-small text-fg hover:bg-accent/10 hover:text-accent hover:underline focus-visible:underline focus-visible:text-accent";
|
|
219
|
+
li.appendChild(a);
|
|
220
|
+
moreMenu.appendChild(li);
|
|
221
|
+
});
|
|
222
|
+
} else {
|
|
223
|
+
var anchor = el;
|
|
224
|
+
var li2 = document.createElement("li");
|
|
225
|
+
var a2 = document.createElement("a");
|
|
226
|
+
a2.href = anchor.href;
|
|
227
|
+
a2.textContent = anchor.textContent ? anchor.textContent.trim() : "";
|
|
228
|
+
a2.className = "block px-hsp-md py-vsp-2xs text-small hover:bg-accent/10 hover:underline focus-visible:underline focus-visible:text-accent text-fg hover:text-accent";
|
|
229
|
+
if (anchor.getAttribute("aria-current") === "page") {
|
|
230
|
+
a2.className += " font-bold text-accent";
|
|
231
|
+
}
|
|
232
|
+
li2.appendChild(a2);
|
|
233
|
+
moreMenu.appendChild(li2);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
moreToggle.addEventListener("click", function () {
|
|
239
|
+
var isOpen = !moreMenu.classList.contains("hidden");
|
|
240
|
+
moreMenu.classList.toggle("hidden", isOpen);
|
|
241
|
+
moreToggle.setAttribute("aria-expanded", String(!isOpen));
|
|
242
|
+
}, { signal: controller.signal });
|
|
243
|
+
|
|
244
|
+
document.addEventListener("click", function (e) {
|
|
245
|
+
if (!moreContainer.contains(e.target)) {
|
|
246
|
+
moreMenu.classList.add("hidden");
|
|
247
|
+
moreToggle.setAttribute("aria-expanded", "false");
|
|
248
|
+
}
|
|
249
|
+
}, { signal: controller.signal });
|
|
250
|
+
|
|
251
|
+
document.addEventListener("keydown", function (e) {
|
|
252
|
+
if (e.key !== "Escape") return;
|
|
253
|
+
if (!moreMenu.classList.contains("hidden")) {
|
|
254
|
+
moreMenu.classList.add("hidden");
|
|
255
|
+
moreToggle.setAttribute("aria-expanded", "false");
|
|
256
|
+
moreToggle.focus();
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
var active = document.activeElement;
|
|
260
|
+
var dropdown = active && active.closest ? active.closest("[data-nav-item-dropdown]") : null;
|
|
261
|
+
if (dropdown && active && active.blur) {
|
|
262
|
+
active.blur();
|
|
263
|
+
}
|
|
264
|
+
}, { signal: controller.signal });
|
|
265
|
+
|
|
266
|
+
var dropdowns = nav.querySelectorAll("[data-nav-item-dropdown]");
|
|
267
|
+
dropdowns.forEach(function (dd) {
|
|
268
|
+
var trigger = dd.querySelector(":scope > a");
|
|
269
|
+
if (!trigger) return;
|
|
270
|
+
function setExpanded(v) {
|
|
271
|
+
trigger.setAttribute("aria-expanded", String(v));
|
|
272
|
+
}
|
|
273
|
+
dd.addEventListener("mouseenter", function () { setExpanded(true); }, { signal: controller.signal });
|
|
274
|
+
dd.addEventListener("mouseleave", function () { setExpanded(false); }, { signal: controller.signal });
|
|
275
|
+
dd.addEventListener("focusin", function () { setExpanded(true); }, { signal: controller.signal });
|
|
276
|
+
dd.addEventListener("focusout", function (e) {
|
|
277
|
+
if (!dd.contains(e.relatedTarget)) {
|
|
278
|
+
setExpanded(false);
|
|
279
|
+
}
|
|
280
|
+
}, { signal: controller.signal });
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
var ro = new ResizeObserver(update);
|
|
284
|
+
ro.observe(nav);
|
|
285
|
+
controller.signal.addEventListener("abort", function () { ro.disconnect(); });
|
|
286
|
+
|
|
287
|
+
document.fonts.ready.then(update);
|
|
288
|
+
|
|
289
|
+
update();
|
|
290
|
+
|
|
291
|
+
cleanupNavOverflow = function () { controller.abort(); };
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
initNavOverflow();
|
|
295
|
+
document.addEventListener("zfb:after-swap", initNavOverflow);
|
|
296
|
+
})();`;
|
|
297
|
+
}
|
|
298
|
+
const NAV_OVERFLOW_SCRIPT = buildNavOverflowScript();
|
|
299
|
+
export {
|
|
300
|
+
NAV_OVERFLOW_SCRIPT,
|
|
301
|
+
buildNavOverflowScript
|
|
302
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { NAV_OVERFLOW_SCRIPT } from "./nav-overflow-generated-script.js";
|
|
@@ -1,289 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
NAV_CHEVRON_ACTIVE,
|
|
4
|
-
NAV_CHEVRON_INACTIVE,
|
|
5
|
-
NAV_CHILD_ACTIVE,
|
|
6
|
-
NAV_CHILD_INACTIVE,
|
|
7
|
-
NAV_MENU_CHILD_ACTIVE,
|
|
8
|
-
NAV_MENU_CHILD_INACTIVE,
|
|
9
|
-
NAV_MENU_PARENT,
|
|
10
|
-
NAV_MENU_PARENT_ACTIVE_SUFFIX,
|
|
11
|
-
NAV_MENU_PLAIN,
|
|
12
|
-
NAV_MENU_PLAIN_ACTIVE_SUFFIX,
|
|
13
|
-
NAV_TOP_ACTIVE,
|
|
14
|
-
NAV_TOP_INACTIVE
|
|
15
|
-
} from "./nav-class-tokens.js";
|
|
16
|
-
const clsArgs = (tokens) => tokens.map((token) => JSON.stringify(token)).join(", ");
|
|
17
|
-
const clsLiteral = (tokens) => JSON.stringify(tokens.join(" "));
|
|
18
|
-
const clsAppend = (tokens) => JSON.stringify(" " + tokens.join(" "));
|
|
19
|
-
const NAV_OVERFLOW_SCRIPT = `(function () {
|
|
20
|
-
var cleanupNavOverflow = null;
|
|
21
|
-
|
|
22
|
-
function trimSlashes(p) {
|
|
23
|
-
while (p.length > 1 && p.charAt(p.length - 1) === "/") p = p.slice(0, -1);
|
|
24
|
-
return p || "/";
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function navPathname(a) {
|
|
28
|
-
try { return trimSlashes(new URL(a.href, location.href).pathname); }
|
|
29
|
-
catch (e) { return ""; }
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function isUnderPath(cur, p) {
|
|
33
|
-
if (!p) return false;
|
|
34
|
-
if (cur === p) return true;
|
|
35
|
-
return p !== "/" && cur.indexOf(p + "/") === 0;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Recompute which header nav item is "active" from the CURRENT URL and
|
|
39
|
-
// repaint the highlight. SSR sets the active item on first paint, but the
|
|
40
|
-
// header is persisted across same-locale client-router swaps
|
|
41
|
-
// (data-zfb-transition-persist), so without this the highlight would stay
|
|
42
|
-
// frozen on the page where the header was first rendered. Mirrors the
|
|
43
|
-
// sidebar island's client-side approach (match location.pathname against
|
|
44
|
-
// each entry's href) and the SSR longest-match + dropdown-parent rules.
|
|
45
|
-
// URL-based: hrefs and location.pathname both carry the base + locale
|
|
46
|
-
// prefix, so they compare directly without stripping.
|
|
47
|
-
function applyActiveNav() {
|
|
48
|
-
var nav = document.querySelector("[data-header-nav]");
|
|
49
|
-
if (!nav) return;
|
|
50
|
-
var topItems = Array.from(nav.querySelectorAll(":scope > [data-nav-item]"));
|
|
51
|
-
if (topItems.length === 0) return;
|
|
52
|
-
|
|
53
|
-
var cur = trimSlashes(location.pathname);
|
|
54
|
-
|
|
55
|
-
// Deepest (longest) nav path the current URL lives under, across both
|
|
56
|
-
// top-level and dropdown-child paths \u2014 matches computeActiveNavPath.
|
|
57
|
-
var activePath = "";
|
|
58
|
-
topItems.forEach(function (it) {
|
|
59
|
-
var isDropdown = it.hasAttribute("data-nav-item-dropdown");
|
|
60
|
-
var topA = isDropdown ? it.querySelector(":scope > a") : it;
|
|
61
|
-
if (topA) {
|
|
62
|
-
var tp = navPathname(topA);
|
|
63
|
-
if (isUnderPath(cur, tp) && tp.length > activePath.length) activePath = tp;
|
|
64
|
-
}
|
|
65
|
-
if (isDropdown) {
|
|
66
|
-
it.querySelectorAll(":scope > div a").forEach(function (c) {
|
|
67
|
-
var cp = navPathname(c);
|
|
68
|
-
if (isUnderPath(cur, cp) && cp.length > activePath.length) activePath = cp;
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
function setTopActive(a, active) {
|
|
74
|
-
if (!a) return;
|
|
75
|
-
if (active) {
|
|
76
|
-
a.classList.add(${clsArgs(NAV_TOP_ACTIVE)});
|
|
77
|
-
a.classList.remove(${clsArgs(NAV_TOP_INACTIVE)});
|
|
78
|
-
a.setAttribute("aria-current", "page");
|
|
79
|
-
} else {
|
|
80
|
-
a.classList.remove(${clsArgs(NAV_TOP_ACTIVE)});
|
|
81
|
-
a.classList.add(${clsArgs(NAV_TOP_INACTIVE)});
|
|
82
|
-
a.removeAttribute("aria-current");
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
topItems.forEach(function (it) {
|
|
87
|
-
var isDropdown = it.hasAttribute("data-nav-item-dropdown");
|
|
88
|
-
var topA = isDropdown ? it.querySelector(":scope > a") : it;
|
|
89
|
-
var topActive = false;
|
|
90
|
-
|
|
91
|
-
if (isDropdown) {
|
|
92
|
-
var parentMatch = !!topA && navPathname(topA) === activePath && activePath !== "";
|
|
93
|
-
var anyChild = false;
|
|
94
|
-
it.querySelectorAll(":scope > div a").forEach(function (c) {
|
|
95
|
-
var childActive = navPathname(c) === activePath && activePath !== "";
|
|
96
|
-
if (childActive) {
|
|
97
|
-
anyChild = true;
|
|
98
|
-
c.setAttribute("data-active", "");
|
|
99
|
-
c.classList.add(${clsArgs(NAV_CHILD_ACTIVE)});
|
|
100
|
-
c.classList.remove(${clsArgs(NAV_CHILD_INACTIVE)});
|
|
101
|
-
} else {
|
|
102
|
-
c.removeAttribute("data-active");
|
|
103
|
-
c.classList.remove(${clsArgs(NAV_CHILD_ACTIVE)});
|
|
104
|
-
c.classList.add(${clsArgs(NAV_CHILD_INACTIVE)});
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
topActive = parentMatch || anyChild;
|
|
108
|
-
var svg = topA ? topA.querySelector("svg") : null;
|
|
109
|
-
if (svg) {
|
|
110
|
-
if (topActive) { svg.classList.add(${clsArgs(NAV_CHEVRON_ACTIVE)}); svg.classList.remove(${clsArgs(NAV_CHEVRON_INACTIVE)}); }
|
|
111
|
-
else { svg.classList.add(${clsArgs(NAV_CHEVRON_INACTIVE)}); svg.classList.remove(${clsArgs(NAV_CHEVRON_ACTIVE)}); }
|
|
112
|
-
}
|
|
113
|
-
} else {
|
|
114
|
-
topActive = activePath !== "" && navPathname(topA) === activePath;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
setTopActive(topA, topActive);
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function initNavOverflow() {
|
|
122
|
-
if (cleanupNavOverflow) cleanupNavOverflow();
|
|
123
|
-
|
|
124
|
-
// Repaint the active highlight for the current URL before measuring /
|
|
125
|
-
// cloning, so the overflow "\xB7\xB7\xB7" menu mirrors the correct active state.
|
|
126
|
-
applyActiveNav();
|
|
127
|
-
|
|
128
|
-
var nav = document.querySelector("[data-header-nav]");
|
|
129
|
-
var moreContainer = document.querySelector("[data-nav-more]");
|
|
130
|
-
var moreMenu = document.querySelector("[data-nav-more-menu]");
|
|
131
|
-
var moreToggle = document.querySelector("[data-nav-more-toggle]");
|
|
132
|
-
if (!nav || !moreContainer || !moreMenu || !moreToggle) return;
|
|
133
|
-
|
|
134
|
-
var items = Array.from(nav.querySelectorAll(":scope > [data-nav-item]"));
|
|
135
|
-
if (items.length === 0) return;
|
|
136
|
-
|
|
137
|
-
var controller = new AbortController();
|
|
138
|
-
|
|
139
|
-
function update() {
|
|
140
|
-
items.forEach(function (el) { el.style.display = ""; });
|
|
141
|
-
moreContainer.style.display = "";
|
|
142
|
-
moreMenu.innerHTML = "";
|
|
143
|
-
moreMenu.classList.add("hidden");
|
|
144
|
-
moreToggle.setAttribute("aria-expanded", "false");
|
|
145
|
-
|
|
146
|
-
var itemWidths = items.map(function (el) { return el.offsetWidth; });
|
|
147
|
-
var moreWidth = moreContainer.offsetWidth;
|
|
148
|
-
var navGap = parseFloat(getComputedStyle(nav).columnGap) || 0;
|
|
149
|
-
var available = nav.clientWidth;
|
|
150
|
-
|
|
151
|
-
if (available <= 0) {
|
|
152
|
-
moreContainer.style.display = "none";
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
var total = 0;
|
|
157
|
-
for (var i = 0; i < itemWidths.length; i++) {
|
|
158
|
-
total += itemWidths[i] + (i > 0 ? navGap : 0);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (total <= available) {
|
|
162
|
-
moreContainer.style.display = "none";
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
var used = 0;
|
|
167
|
-
var cutoffIndex = 0;
|
|
168
|
-
|
|
169
|
-
for (var i2 = 0; i2 < items.length; i2++) {
|
|
170
|
-
var w = itemWidths[i2] + (i2 > 0 ? navGap : 0);
|
|
171
|
-
if (used + w > available - moreWidth - navGap) break;
|
|
172
|
-
used += w;
|
|
173
|
-
cutoffIndex = i2 + 1;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
for (var i3 = cutoffIndex; i3 < items.length; i3++) {
|
|
177
|
-
items[i3].style.display = "none";
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
for (var i4 = cutoffIndex; i4 < items.length; i4++) {
|
|
181
|
-
var el = items[i4];
|
|
182
|
-
var isDropdown = el.hasAttribute("data-nav-item-dropdown");
|
|
183
|
-
|
|
184
|
-
if (isDropdown) {
|
|
185
|
-
var parentLink = el.querySelector(":scope > a");
|
|
186
|
-
var childLinks = el.querySelectorAll(":scope > div a");
|
|
187
|
-
if (parentLink) {
|
|
188
|
-
var li = document.createElement("li");
|
|
189
|
-
var a = document.createElement("a");
|
|
190
|
-
a.href = parentLink.href;
|
|
191
|
-
var parentText = parentLink.textContent ? parentLink.textContent.trim().replace(/\\s+/g, " ") : "";
|
|
192
|
-
a.textContent = parentText;
|
|
193
|
-
a.className = ${clsLiteral(NAV_MENU_PARENT)};
|
|
194
|
-
if (parentLink.getAttribute("aria-current") === "page") {
|
|
195
|
-
a.className += ${clsAppend(NAV_MENU_PARENT_ACTIVE_SUFFIX)};
|
|
196
|
-
}
|
|
197
|
-
li.appendChild(a);
|
|
198
|
-
moreMenu.appendChild(li);
|
|
199
|
-
}
|
|
200
|
-
childLinks.forEach(function (child) {
|
|
201
|
-
var li = document.createElement("li");
|
|
202
|
-
var a = document.createElement("a");
|
|
203
|
-
a.href = child.href;
|
|
204
|
-
a.textContent = child.textContent ? child.textContent.trim() : "";
|
|
205
|
-
var isChildActive = child.hasAttribute("data-active");
|
|
206
|
-
a.className = isChildActive
|
|
207
|
-
? ${clsLiteral(NAV_MENU_CHILD_ACTIVE)}
|
|
208
|
-
: ${clsLiteral(NAV_MENU_CHILD_INACTIVE)};
|
|
209
|
-
li.appendChild(a);
|
|
210
|
-
moreMenu.appendChild(li);
|
|
211
|
-
});
|
|
212
|
-
} else {
|
|
213
|
-
var anchor = el;
|
|
214
|
-
var li2 = document.createElement("li");
|
|
215
|
-
var a2 = document.createElement("a");
|
|
216
|
-
a2.href = anchor.href;
|
|
217
|
-
a2.textContent = anchor.textContent ? anchor.textContent.trim() : "";
|
|
218
|
-
a2.className = ${clsLiteral(NAV_MENU_PLAIN)};
|
|
219
|
-
if (anchor.getAttribute("aria-current") === "page") {
|
|
220
|
-
a2.className += ${clsAppend(NAV_MENU_PLAIN_ACTIVE_SUFFIX)};
|
|
221
|
-
}
|
|
222
|
-
li2.appendChild(a2);
|
|
223
|
-
moreMenu.appendChild(li2);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
moreToggle.addEventListener("click", function () {
|
|
229
|
-
var isOpen = !moreMenu.classList.contains("hidden");
|
|
230
|
-
moreMenu.classList.toggle("hidden", isOpen);
|
|
231
|
-
moreToggle.setAttribute("aria-expanded", String(!isOpen));
|
|
232
|
-
}, { signal: controller.signal });
|
|
233
|
-
|
|
234
|
-
document.addEventListener("click", function (e) {
|
|
235
|
-
if (!moreContainer.contains(e.target)) {
|
|
236
|
-
moreMenu.classList.add("hidden");
|
|
237
|
-
moreToggle.setAttribute("aria-expanded", "false");
|
|
238
|
-
}
|
|
239
|
-
}, { signal: controller.signal });
|
|
240
|
-
|
|
241
|
-
document.addEventListener("keydown", function (e) {
|
|
242
|
-
if (e.key !== "Escape") return;
|
|
243
|
-
if (!moreMenu.classList.contains("hidden")) {
|
|
244
|
-
moreMenu.classList.add("hidden");
|
|
245
|
-
moreToggle.setAttribute("aria-expanded", "false");
|
|
246
|
-
moreToggle.focus();
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
var active = document.activeElement;
|
|
250
|
-
var dropdown = active && active.closest ? active.closest("[data-nav-item-dropdown]") : null;
|
|
251
|
-
if (dropdown && active && active.blur) {
|
|
252
|
-
active.blur();
|
|
253
|
-
}
|
|
254
|
-
}, { signal: controller.signal });
|
|
255
|
-
|
|
256
|
-
var dropdowns = nav.querySelectorAll("[data-nav-item-dropdown]");
|
|
257
|
-
dropdowns.forEach(function (dd) {
|
|
258
|
-
var trigger = dd.querySelector(":scope > a");
|
|
259
|
-
if (!trigger) return;
|
|
260
|
-
function setExpanded(v) {
|
|
261
|
-
trigger.setAttribute("aria-expanded", String(v));
|
|
262
|
-
}
|
|
263
|
-
dd.addEventListener("mouseenter", function () { setExpanded(true); }, { signal: controller.signal });
|
|
264
|
-
dd.addEventListener("mouseleave", function () { setExpanded(false); }, { signal: controller.signal });
|
|
265
|
-
dd.addEventListener("focusin", function () { setExpanded(true); }, { signal: controller.signal });
|
|
266
|
-
dd.addEventListener("focusout", function (e) {
|
|
267
|
-
if (!dd.contains(e.relatedTarget)) {
|
|
268
|
-
setExpanded(false);
|
|
269
|
-
}
|
|
270
|
-
}, { signal: controller.signal });
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
var ro = new ResizeObserver(update);
|
|
274
|
-
ro.observe(nav);
|
|
275
|
-
controller.signal.addEventListener("abort", function () { ro.disconnect(); });
|
|
276
|
-
|
|
277
|
-
document.fonts.ready.then(update);
|
|
278
|
-
|
|
279
|
-
update();
|
|
280
|
-
|
|
281
|
-
cleanupNavOverflow = function () { controller.abort(); };
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
initNavOverflow();
|
|
285
|
-
document.addEventListener(${JSON.stringify(AFTER_NAVIGATE_EVENT)}, initNavOverflow);
|
|
286
|
-
})();`;
|
|
1
|
+
import { NAV_OVERFLOW_SCRIPT } from "./nav-overflow-generated-script.js";
|
|
287
2
|
export {
|
|
288
3
|
NAV_OVERFLOW_SCRIPT
|
|
289
4
|
};
|
|
@@ -12,7 +12,8 @@ import { assertChromeContext } from "../chrome/assert-chrome-context.js";
|
|
|
12
12
|
import {
|
|
13
13
|
deriveGetUnavailableVersions,
|
|
14
14
|
deriveNavDataPrep,
|
|
15
|
-
deriveSearchWidgetSlot
|
|
15
|
+
deriveSearchWidgetSlot,
|
|
16
|
+
skipsPackageDefaultDesignTokenPanel
|
|
16
17
|
} from "../chrome/derive.js";
|
|
17
18
|
function createHeaderWithDefaults(ctx) {
|
|
18
19
|
assertChromeContext(ctx, "createHeaderWithDefaults");
|
|
@@ -130,7 +131,15 @@ function createHeaderWithDefaults(ctx) {
|
|
|
130
131
|
const headerRightItems = filterHeaderRightItems(
|
|
131
132
|
settings.headerRightItems ?? [],
|
|
132
133
|
{
|
|
133
|
-
|
|
134
|
+
// Mirrors `deriveBodyEndIslands`' slot resolution (#3414): when the
|
|
135
|
+
// derive-level skip leaves a page with no panel island and no
|
|
136
|
+
// pre-hydration toggle shim, the header toggle button must go with
|
|
137
|
+
// them — otherwise it dispatches `toggle-design-token-panel` into a
|
|
138
|
+
// document with no listener and no click queue (a dead button).
|
|
139
|
+
// `hostBindings.DesignTokenPanelBootstrap` covers the injected-route
|
|
140
|
+
// path too (`routes/_chrome.tsx` threads the configured island through
|
|
141
|
+
// that slot), so injected pages keep the button.
|
|
142
|
+
designTokenPanel: Boolean(settings.designTokenPanel) && (ctx.hostBindings.DesignTokenPanelBootstrap != null || !skipsPackageDefaultDesignTokenPanel(ctx.settings)),
|
|
134
143
|
aiAssistant: Boolean(settings.aiAssistant),
|
|
135
144
|
colorMode: Boolean(settings.colorMode),
|
|
136
145
|
hasLocales: Object.keys(settings.locales).length > 0,
|
|
@@ -40,6 +40,12 @@ export declare function switchLocaleHref(pathname: string, config: LanguageSwitc
|
|
|
40
40
|
* `window[FLAG]` makes it idempotent: the tag may re-execute on a hard reload
|
|
41
41
|
* or a cross-locale header repaint, but the listener is registered exactly
|
|
42
42
|
* once per page lifetime.
|
|
43
|
+
*
|
|
44
|
+
* The pathname fed to `switchLocaleHref` comes from the embedded
|
|
45
|
+
* `readCurrentPath`, which prefers the `data-zd-current-path` override over
|
|
46
|
+
* `location.pathname` — the same explicit current-route reader
|
|
47
|
+
* `nav-overflow-script.ts` / `sidebar-tree-island` / `version-switcher.tsx`
|
|
48
|
+
* use (zudolab/zudo-doc#3398, consolidated by #3408).
|
|
43
49
|
*/
|
|
44
50
|
export declare const LANGUAGE_SWITCHER_INIT_SCRIPT: string;
|
|
45
51
|
export interface LanguageSwitcherProps {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
2
2
|
import { Fragment } from "preact";
|
|
3
3
|
import { AFTER_NAVIGATE_EVENT } from "../transitions/index.js";
|
|
4
|
+
import { CURRENT_PATH_SCRIPT_PRELUDE } from "../current-path/index.js";
|
|
4
5
|
function switchLocaleHref(pathname, config, currentLang, targetLang) {
|
|
5
6
|
const normalizedBase = config.base;
|
|
6
7
|
const defaultLocale = config.defaultLocale;
|
|
@@ -45,6 +46,7 @@ const LANGUAGE_SWITCHER_INIT_SCRIPT = `(function(){
|
|
|
45
46
|
var FLAG="__zdLanguageSwitcherInit";
|
|
46
47
|
if(window[FLAG])return;
|
|
47
48
|
window[FLAG]=true;
|
|
49
|
+
${CURRENT_PATH_SCRIPT_PRELUDE}
|
|
48
50
|
var switchLocaleHref=${switchLocaleHref.toString()};
|
|
49
51
|
function rewire(){
|
|
50
52
|
var containers=document.querySelectorAll("[data-language-switcher]");
|
|
@@ -57,7 +59,7 @@ for(var j=0;j<anchors.length;j++){
|
|
|
57
59
|
var a=anchors[j];
|
|
58
60
|
var target=a.getAttribute("lang");
|
|
59
61
|
if(!target)continue;
|
|
60
|
-
a.setAttribute("href",switchLocaleHref(
|
|
62
|
+
a.setAttribute("href",switchLocaleHref(readCurrentPath(CURRENT_PATH_DATASET_KEY),config,currentLang,target));
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
65
|
}
|
|
@@ -208,6 +208,12 @@ export declare const VERSION_SWITCHER_INIT_SCRIPT: string;
|
|
|
208
208
|
* `window[FLAG]` makes it idempotent: the tag may re-execute on a hard reload or
|
|
209
209
|
* a cross-locale header repaint, but the listener registers exactly once per
|
|
210
210
|
* page lifetime.
|
|
211
|
+
*
|
|
212
|
+
* The pathname fed to `computeVersionSwitcherState` comes from the embedded
|
|
213
|
+
* `readCurrentPath`, which prefers the `data-zd-current-path` override over
|
|
214
|
+
* `location.pathname` — the same explicit current-route reader
|
|
215
|
+
* `nav-overflow-script.ts` / `sidebar-tree-island` / `language-switcher.tsx`
|
|
216
|
+
* use (zudolab/zudo-doc#3398, consolidated by #3408).
|
|
211
217
|
*/
|
|
212
218
|
export declare const VERSION_SWITCHER_REWIRE_SCRIPT: string;
|
|
213
219
|
export type { VersionEntry, VersionSwitcherLabels };
|