@takazudo/zudo-doc 5.24.2 → 5.26.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.
Files changed (66) hide show
  1. package/CHANGELOG.md +40 -2
  2. package/dist/asset-components/asset-card.js +2 -2
  3. package/dist/asset-components/asset-code.js +1 -1
  4. package/dist/asset-index-page/body.d.ts +80 -0
  5. package/dist/asset-index-page/body.js +116 -0
  6. package/dist/asset-index-page/index.d.ts +3 -9
  7. package/dist/asset-index-page/index.js +18 -149
  8. package/dist/asset-index-page/tree.d.ts +24 -0
  9. package/dist/asset-index-page/tree.js +43 -0
  10. package/dist/asset-page/body.d.ts +98 -0
  11. package/dist/asset-page/body.js +107 -0
  12. package/dist/asset-page/components.d.ts +94 -0
  13. package/dist/asset-page/components.js +175 -0
  14. package/dist/asset-page/index.d.ts +3 -78
  15. package/dist/asset-page/index.js +30 -240
  16. package/dist/asset-page/shared.d.ts +15 -0
  17. package/dist/asset-page/shared.js +28 -0
  18. package/dist/breadcrumb/breadcrumb.js +1 -1
  19. package/dist/compiled.css +18 -71
  20. package/dist/config/component-tokens.js +3 -1
  21. package/dist/config-assertions/index.d.ts +26 -0
  22. package/dist/config-assertions/index.js +12 -0
  23. package/dist/config.d.ts +28 -0
  24. package/dist/config.js +6 -1
  25. package/dist/doc-pager/index.js +2 -2
  26. package/dist/footer/footer.js +3 -3
  27. package/dist/header/header.js +2 -1
  28. package/dist/header-with-defaults/index.d.ts +20 -0
  29. package/dist/header-with-defaults/index.js +9 -2
  30. package/dist/home-page/index.js +49 -22
  31. package/dist/i18n-defaults/index.js +3 -0
  32. package/dist/integrations/changelog/generate.js +8 -2
  33. package/dist/integrations/changelog/links.d.ts +25 -0
  34. package/dist/integrations/changelog/links.js +280 -0
  35. package/dist/mdx-components/index.js +1 -1
  36. package/dist/nav-indexing/category-nav.js +1 -1
  37. package/dist/nav-indexing/category-tree-nav.js +1 -1
  38. package/dist/nav-indexing/doc-card-grid.js +2 -2
  39. package/dist/nav-indexing/docs-sitemap.js +2 -2
  40. package/dist/nav-indexing/nav-card-grid.d.ts +3 -2
  41. package/dist/nav-indexing/nav-card-grid.js +3 -3
  42. package/dist/nav-indexing/note-tray-index-parts/card-list.js +1 -1
  43. package/dist/nav-indexing/note-tray-index-parts/index-list.js +1 -1
  44. package/dist/nav-indexing/note-tray-index-parts/timeline.js +1 -1
  45. package/dist/nav-indexing/site-tree-nav-demo.js +2 -2
  46. package/dist/nav-indexing/versions-page-content.js +2 -2
  47. package/dist/plugins/routes.js +2 -13
  48. package/dist/plugins/zdtp-loader.js +1 -1
  49. package/dist/preset.d.ts +11 -1
  50. package/dist/preset.js +12 -5
  51. package/dist/safelist.css +1 -1
  52. package/dist/settings.d.ts +9 -0
  53. package/dist/sidebar-toggle-island/index.js +1 -1
  54. package/dist/site-tree-nav-island/index.js +3 -3
  55. package/dist/theme-packs/foundry/pack.css +4 -9
  56. package/dist/theme-packs/riso/pack.css +6 -4
  57. package/dist/theme-packs/swissgrid/pack.css +7 -4
  58. package/eject/asset-components/asset-card.tsx +2 -2
  59. package/eject/asset-components/asset-code.tsx +1 -1
  60. package/eject/breadcrumb/breadcrumb.tsx +1 -1
  61. package/eject/doc-pager/index.tsx +2 -2
  62. package/eject/footer/footer.tsx +4 -4
  63. package/eject/header/header.tsx +11 -1
  64. package/eject/sidebar-toggle-island/index.tsx +1 -1
  65. package/eject/site-tree-nav-island/index.tsx +4 -4
  66. package/package.json +37 -9
@@ -0,0 +1,280 @@
1
+ import { basename } from "node:path";
2
+ function formatChangelogEntryHeadingText(entry) {
3
+ return entry.date ? `[${entry.version}] - ${entry.date}` : `[${entry.version}]`;
4
+ }
5
+ const GITHUB_SLUG_ALLOWED_RE = /[\p{L}\p{N}_\- ]/u;
6
+ function githubSlugify(text) {
7
+ let out = "";
8
+ for (const ch of text.toLowerCase()) {
9
+ if (GITHUB_SLUG_ALLOWED_RE.test(ch)) {
10
+ out += ch === " " ? "-" : ch;
11
+ }
12
+ }
13
+ return out;
14
+ }
15
+ class GithubSlugAllocator {
16
+ seen = /* @__PURE__ */ new Map();
17
+ allocate(text) {
18
+ const slug = githubSlugify(text);
19
+ const count = this.seen.get(slug) ?? 0;
20
+ this.seen.set(slug, count + 1);
21
+ return count === 0 ? slug : `${slug}-${count}`;
22
+ }
23
+ }
24
+ function stripInlineLinkSyntax(text) {
25
+ return text.replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1");
26
+ }
27
+ function isSetextParagraphLine(line) {
28
+ const text = line.trim();
29
+ return /^ {0,3}\S/.test(line) && !/^#{1,6}(?:[ \t]|$)/.test(text) && !/^(?:[-+*]|\d{1,9}[.)])(?:[ \t]|$)/.test(text) && !text.startsWith(">") && !text.includes("|") && !/^(?:(?:\*[ \t]*){3,}|(?:_[ \t]*){3,}|(?:-[ \t]*){3,})$/.test(text);
30
+ }
31
+ function extractHeadingTexts(content) {
32
+ const headings = [];
33
+ let fenceChar = null;
34
+ let fenceLen = 0;
35
+ let paragraphLineCount = 0;
36
+ let paragraphLine = "";
37
+ for (const line of content.split("\n")) {
38
+ const trimmed = line.trimStart();
39
+ const fenceMatch = /^([`~]{3,})/.exec(trimmed);
40
+ if (fenceMatch) {
41
+ paragraphLineCount = 0;
42
+ const fence = fenceMatch[1];
43
+ if (fence === void 0) continue;
44
+ if (fenceChar === null) {
45
+ fenceChar = fence[0] ?? null;
46
+ fenceLen = fence.length;
47
+ } else if (fence[0] === fenceChar && fence.length >= fenceLen) {
48
+ fenceChar = null;
49
+ }
50
+ continue;
51
+ }
52
+ if (fenceChar !== null) continue;
53
+ const headingMatch = /^(#{1,6})[ \t]+(.+)$/.exec(line.trim());
54
+ if (headingMatch) {
55
+ paragraphLineCount = 0;
56
+ const rawText = headingMatch[2];
57
+ if (rawText === void 0) continue;
58
+ const text = stripInlineLinkSyntax(rawText.trim().replace(/\s+#+\s*$/, ""));
59
+ headings.push(text);
60
+ continue;
61
+ }
62
+ if (/^ {0,3}(=+|-+)[ \t]*$/.test(line)) {
63
+ if (paragraphLineCount === 1) {
64
+ headings.push(stripInlineLinkSyntax(paragraphLine));
65
+ }
66
+ paragraphLineCount = 0;
67
+ continue;
68
+ }
69
+ if (isSetextParagraphLine(line)) {
70
+ paragraphLine = line.trim();
71
+ paragraphLineCount += 1;
72
+ } else {
73
+ paragraphLineCount = 0;
74
+ }
75
+ }
76
+ return headings;
77
+ }
78
+ function buildChangelogAnchorMap(title, entries) {
79
+ const allocator = new GithubSlugAllocator();
80
+ allocator.allocate(title);
81
+ const anchors = /* @__PURE__ */ new Map();
82
+ for (const entry of entries) {
83
+ const anchor = allocator.allocate(formatChangelogEntryHeadingText(entry));
84
+ anchors.set(basename(entry.sourcePath), anchor);
85
+ for (const headingText of extractHeadingTexts(entry.content)) {
86
+ allocator.allocate(headingText);
87
+ }
88
+ }
89
+ return anchors;
90
+ }
91
+ const FENCE_PLACEHOLDER_PREFIX = "\0CHANGELOG_LINK_FENCE_";
92
+ const INLINE_CODE_PLACEHOLDER_PREFIX = "\0CHANGELOG_LINK_CODE_";
93
+ const PLACEHOLDER_SUFFIX = "\0";
94
+ function protectCode(content) {
95
+ const stashed = [];
96
+ const stash = (prefix, value) => {
97
+ const token = `${prefix}${stashed.length}${PLACEHOLDER_SUFFIX}`;
98
+ stashed.push(value);
99
+ return token;
100
+ };
101
+ const outLines = [];
102
+ let fenceChar = null;
103
+ let fenceLen = 0;
104
+ let fenceBuf = [];
105
+ for (const line of content.split("\n")) {
106
+ const trimmed = line.trimStart();
107
+ const fenceMatch = /^([`~]{3,})/.exec(trimmed);
108
+ if (fenceChar === null) {
109
+ if (fenceMatch) {
110
+ const fence = fenceMatch[1];
111
+ if (fence !== void 0) {
112
+ fenceChar = fence[0] ?? null;
113
+ fenceLen = fence.length;
114
+ fenceBuf = [line];
115
+ continue;
116
+ }
117
+ }
118
+ outLines.push(line);
119
+ } else {
120
+ fenceBuf.push(line);
121
+ if (fenceMatch) {
122
+ const fence = fenceMatch[1];
123
+ if (fence !== void 0 && fence[0] === fenceChar && fence.length >= fenceLen) {
124
+ outLines.push(stash(FENCE_PLACEHOLDER_PREFIX, fenceBuf.join("\n")));
125
+ fenceChar = null;
126
+ fenceBuf = [];
127
+ }
128
+ }
129
+ }
130
+ }
131
+ if (fenceChar !== null) {
132
+ outLines.push(...fenceBuf);
133
+ }
134
+ let text = outLines.join("\n");
135
+ text = text.replace(
136
+ /(`+)((?:(?!\n[ \t]*\n)[\s\S])*?)\1(?!`)/g,
137
+ (whole) => stash(INLINE_CODE_PLACEHOLDER_PREFIX, whole)
138
+ );
139
+ return {
140
+ text,
141
+ restore: (s) => {
142
+ let result = s;
143
+ for (let i = 0; i < stashed.length; i += 1) {
144
+ const value = stashed[i];
145
+ if (value === void 0) continue;
146
+ const fenceToken = `${FENCE_PLACEHOLDER_PREFIX}${i}${PLACEHOLDER_SUFFIX}`;
147
+ const codeToken = `${INLINE_CODE_PLACEHOLDER_PREFIX}${i}${PLACEHOLDER_SUFFIX}`;
148
+ result = result.split(fenceToken).join(value).split(codeToken).join(value);
149
+ }
150
+ return result;
151
+ }
152
+ };
153
+ }
154
+ function findMatchingDelimiter(text, start, open, close) {
155
+ let depth = 1;
156
+ let j = start;
157
+ while (j < text.length) {
158
+ const ch = text[j];
159
+ if (ch === "\\") {
160
+ j += 2;
161
+ continue;
162
+ }
163
+ if (ch === open) depth += 1;
164
+ else if (ch === close) {
165
+ depth -= 1;
166
+ if (depth === 0) return j;
167
+ }
168
+ j += 1;
169
+ }
170
+ return -1;
171
+ }
172
+ function parseLinkInner(inner) {
173
+ const trimmed = inner.trim();
174
+ if (trimmed === "") return { dest: "" };
175
+ let dest;
176
+ let rest;
177
+ if (trimmed.startsWith("<")) {
178
+ const closeIdx = trimmed.indexOf(">");
179
+ if (closeIdx === -1) return null;
180
+ dest = trimmed.slice(1, closeIdx);
181
+ rest = trimmed.slice(closeIdx + 1).trim();
182
+ } else {
183
+ const spaceIdx = trimmed.search(/\s/);
184
+ if (spaceIdx === -1) {
185
+ dest = trimmed;
186
+ rest = "";
187
+ } else {
188
+ dest = trimmed.slice(0, spaceIdx);
189
+ rest = trimmed.slice(spaceIdx).trim();
190
+ }
191
+ }
192
+ let title;
193
+ if (rest !== "") {
194
+ const quotedTitle = /^(["'])[\s\S]*\1$/.test(rest);
195
+ const parenthesizedTitle = rest.startsWith("(") && findMatchingDelimiter(rest, 1, "(", ")") === rest.length - 1;
196
+ if (!quotedTitle && !parenthesizedTitle) return null;
197
+ title = rest;
198
+ }
199
+ return { dest, title };
200
+ }
201
+ function scanLinks(text) {
202
+ const matches = [];
203
+ let i = 0;
204
+ while (i < text.length) {
205
+ if (text[i] === "[") {
206
+ const isImage = i > 0 && text[i - 1] === "!";
207
+ const labelStart = i + 1;
208
+ const labelEnd = findMatchingDelimiter(text, labelStart, "[", "]");
209
+ if (labelEnd !== -1 && text[labelEnd + 1] === "(") {
210
+ const parenStart = labelEnd + 2;
211
+ const parenEnd = findMatchingDelimiter(text, parenStart, "(", ")");
212
+ if (parenEnd !== -1) {
213
+ const parsed = parseLinkInner(text.slice(parenStart, parenEnd));
214
+ if (parsed) {
215
+ matches.push({
216
+ start: isImage ? i - 1 : i,
217
+ end: parenEnd + 1,
218
+ label: text.slice(labelStart, labelEnd),
219
+ dest: parsed.dest,
220
+ title: parsed.title,
221
+ isImage
222
+ });
223
+ i = parenEnd + 1;
224
+ continue;
225
+ }
226
+ }
227
+ }
228
+ }
229
+ i += 1;
230
+ }
231
+ return matches;
232
+ }
233
+ const URL_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
234
+ function parseRelativeDocLink(dest) {
235
+ const hashIdx = dest.indexOf("#");
236
+ const withoutFragment = hashIdx === -1 ? dest : dest.slice(0, hashIdx);
237
+ if (withoutFragment === "") return null;
238
+ if (!/\.(?:mdx|md)$/i.test(withoutFragment)) return null;
239
+ if (URL_SCHEME_RE.test(withoutFragment)) return null;
240
+ if (withoutFragment.startsWith("//")) return null;
241
+ if (withoutFragment.startsWith("/")) return null;
242
+ const normalized = withoutFragment.startsWith("./") ? withoutFragment.slice(2) : withoutFragment;
243
+ const sameDir = normalized.length > 0 && !normalized.includes("/");
244
+ return { sameDir, filename: normalized };
245
+ }
246
+ function rewriteChangelogEntryLinks(content, anchorByFilename) {
247
+ const { text: protectedText, restore } = protectCode(content);
248
+ const matches = scanLinks(protectedText);
249
+ let rewritten = "";
250
+ let cursor = 0;
251
+ for (const match of matches) {
252
+ rewritten += protectedText.slice(cursor, match.start);
253
+ if (match.isImage) {
254
+ rewritten += protectedText.slice(match.start, match.end);
255
+ cursor = match.end;
256
+ continue;
257
+ }
258
+ const parsed = parseRelativeDocLink(match.dest);
259
+ if (!parsed) {
260
+ rewritten += protectedText.slice(match.start, match.end);
261
+ cursor = match.end;
262
+ continue;
263
+ }
264
+ const anchor = parsed.sameDir ? anchorByFilename.get(parsed.filename) : void 0;
265
+ if (anchor === void 0) {
266
+ rewritten += match.label;
267
+ } else {
268
+ const titlePart = match.title !== void 0 ? ` ${match.title}` : "";
269
+ rewritten += `[${match.label}](#${anchor}${titlePart})`;
270
+ }
271
+ cursor = match.end;
272
+ }
273
+ rewritten += protectedText.slice(cursor);
274
+ return restore(rewritten);
275
+ }
276
+ export {
277
+ buildChangelogAnchorMap,
278
+ formatChangelogEntryHeadingText,
279
+ rewriteChangelogEntryLinks
280
+ };
@@ -124,7 +124,7 @@ function makeEnlargeableParagraph(imageEnlarge, ContentImg, assetOptions) {
124
124
  {
125
125
  type: "a",
126
126
  props: {
127
- class: "text-accent hover:underline focus-visible:underline",
127
+ class: "text-fg hover:text-accent focus-visible:text-accent hover:underline focus-visible:underline",
128
128
  href: assetViewerHref({
129
129
  base: assetOptions.base,
130
130
  routePrefix: assetOptions.routePrefix,
@@ -26,7 +26,7 @@ function CategoryNav(props) {
26
26
  href: child.href,
27
27
  class: "group block rounded border border-muted bg-surface px-hsp-lg py-vsp-md hover:border-accent",
28
28
  children: [
29
- /* @__PURE__ */ jsxs("span", { class: "flex items-start gap-hsp-xs font-medium text-accent underline group-hover:underline", children: [
29
+ /* @__PURE__ */ jsxs("span", { class: "flex items-start gap-hsp-xs font-medium text-fg group-hover:text-accent group-hover:underline group-focus-visible:text-accent group-focus-visible:underline", children: [
30
30
  /* @__PURE__ */ jsx("span", { class: "flex h-[1lh] items-center", children: /* @__PURE__ */ jsx(ArrowIcon, {}) }),
31
31
  child.label
32
32
  ] }),
@@ -9,7 +9,7 @@ function NodeItem({ node, depth, maxDepth, index }) {
9
9
  "a",
10
10
  {
11
11
  href: node.href,
12
- class: "inline-block py-vsp-3xs text-accent hover:underline",
12
+ class: "inline-block py-vsp-3xs text-fg hover:text-accent hover:underline focus-visible:text-accent focus-visible:underline",
13
13
  children: node.label
14
14
  }
15
15
  ) : /* @__PURE__ */ jsx("span", { class: "inline-block py-vsp-3xs text-fg font-medium", children: node.label }),
@@ -7,7 +7,7 @@ function ArrowIcon() {
7
7
  fill: "currentColor",
8
8
  viewBox: "0 0 103.395 107.049",
9
9
  "aria-hidden": "true",
10
- class: "w-[16px] shrink-0 text-accent",
10
+ class: "w-[16px] shrink-0 text-muted group-hover:text-accent group-focus-visible:text-accent",
11
11
  children: /* @__PURE__ */ jsx("path", { d: "M5.746 5.74 0 11.49l20.987 20.96C34.126 45.572 41.963 53.45 41.948 53.523c-.012.062-9.456 9.544-20.986 21.07L0 95.55l5.714 5.715c3.142 3.143 5.748 5.715 5.79 5.715s2.63-2.563 5.75-5.696l17.939-18.001c21.867-21.94 29.443-29.599 29.443-29.768 0-.114-.665-.804-5.084-5.275C51.872 40.47 11.71.125 11.565.036 11.525.01 8.906 2.578 5.746 5.74m38.345-.066c-3.132 3.13-5.696 5.71-5.696 5.732-.001.022 2.16 2.185 4.8 4.807 2.641 2.623 8.382 8.338 12.758 12.702 15.38 15.337 23.763 23.641 24.314 24.086.19.153.346.336.346.405 0 .07-1.738 1.847-3.887 3.976a17515 17515 0 0 0-20.35 20.264 19555 19555 0 0 1-17.223 17.158c-.416.409-.757.77-.757.8 0 .083 11.415 11.485 11.457 11.445.235-.22 53.542-53.528 53.542-53.543C103.395 53.472 49.891.02 49.837 0c-.028-.01-2.613 2.543-5.746 5.674" })
12
12
  }
13
13
  );
@@ -27,7 +27,7 @@ function DocCardGrid(props) {
27
27
  children: [
28
28
  /* @__PURE__ */ jsxs("span", { class: "flex items-center gap-hsp-xs", children: [
29
29
  /* @__PURE__ */ jsx(ArrowIcon, {}),
30
- /* @__PURE__ */ jsx("span", { class: "font-medium text-accent group-hover:underline", children: item.title })
30
+ /* @__PURE__ */ jsx("span", { class: "font-medium text-fg group-hover:text-accent group-hover:underline group-focus-visible:text-accent group-focus-visible:underline", children: item.title })
31
31
  ] }),
32
32
  item.description && /* @__PURE__ */ jsx("span", { class: "mt-vsp-2xs block text-small text-muted group-hover:text-accent group-focus-visible:text-accent", children: item.description })
33
33
  ]
@@ -15,14 +15,14 @@ function SitemapSection({ node, index }) {
15
15
  return /* @__PURE__ */ jsxs("details", { class: "group border border-muted overflow-hidden", open: true, children: [
16
16
  /* @__PURE__ */ jsxs("summary", { class: "flex items-center gap-x-hsp-md px-hsp-xl py-vsp-md text-title font-bold cursor-pointer select-none bg-surface list-none [&::-webkit-details-marker]:hidden", children: [
17
17
  /* @__PURE__ */ jsx("span", { class: "inline-block text-caption text-muted transition-transform duration-200 group-open:rotate-90", children: "\u25B6" }),
18
- node.href ? /* @__PURE__ */ jsx("a", { href: node.href, class: "hover:underline focus:underline", children: node.label }) : /* @__PURE__ */ jsx("span", { children: node.label })
18
+ node.href ? /* @__PURE__ */ jsx("a", { href: node.href, class: "hover:text-accent hover:underline focus:underline focus-visible:text-accent", children: node.label }) : /* @__PURE__ */ jsx("span", { children: node.label })
19
19
  ] }),
20
20
  leaves.length > 0 && /* @__PURE__ */ jsx("div", { class: "px-hsp-xl py-vsp-md", children: /* @__PURE__ */ jsx("ul", { class: "space-y-vsp-2xs pl-[1.25rem] list-none", children: leaves.map((leaf, li) => /* @__PURE__ */ jsxs("li", { children: [
21
21
  /* @__PURE__ */ jsx(
22
22
  "a",
23
23
  {
24
24
  href: leaf.href,
25
- class: "text-accent hover:underline focus:underline",
25
+ class: "text-fg hover:text-accent hover:underline focus-visible:text-accent focus-visible:underline",
26
26
  children: leaf.label
27
27
  }
28
28
  ),
@@ -16,8 +16,9 @@ export interface NavCardGridProps {
16
16
  * NavCardGrid — JSX port of `src/components/nav-card-grid`.
17
17
  *
18
18
  * Renders direct children of a category as a two-column grid of card links.
19
- * Unlike `CategoryNav`, the arrow icon uses `text-accent` and sits inline with
20
- * the label via `items-center`. Description lines have a hover-underline effect.
19
+ * Unlike `CategoryNav`, the arrow icon uses `text-muted` (accent on
20
+ * hover/focus) and sits inline with the label via `items-center`. Description
21
+ * lines have a hover-underline effect.
21
22
  *
22
23
  * The caller must pre-resolve `href` for each node. Nodes with neither
23
24
  * `hasPage` nor children are excluded; nodes without an `href` are skipped.
@@ -7,7 +7,7 @@ function ArrowIcon() {
7
7
  fill: "currentColor",
8
8
  viewBox: "0 0 103.395 107.049",
9
9
  "aria-hidden": "true",
10
- class: "w-[16px] shrink-0 text-accent",
10
+ class: "w-[16px] shrink-0 text-muted group-hover:text-accent group-focus-visible:text-accent",
11
11
  children: /* @__PURE__ */ jsx("path", { d: "M5.746 5.74 0 11.49l20.987 20.96C34.126 45.572 41.963 53.45 41.948 53.523c-.012.062-9.456 9.544-20.986 21.07L0 95.55l5.714 5.715c3.142 3.143 5.748 5.715 5.79 5.715s2.63-2.563 5.75-5.696l17.939-18.001c21.867-21.94 29.443-29.599 29.443-29.768 0-.114-.665-.804-5.084-5.275C51.872 40.47 11.71.125 11.565.036 11.525.01 8.906 2.578 5.746 5.74m38.345-.066c-3.132 3.13-5.696 5.71-5.696 5.732-.001.022 2.16 2.185 4.8 4.807 2.641 2.623 8.382 8.338 12.758 12.702 15.38 15.337 23.763 23.641 24.314 24.086.19.153.346.336.346.405 0 .07-1.738 1.847-3.887 3.976a17515 17515 0 0 0-20.35 20.264 19555 19555 0 0 1-17.223 17.158c-.416.409-.757.77-.757.8 0 .083 11.415 11.485 11.457 11.445.235-.22 53.542-53.528 53.542-53.543C103.395 53.472 49.891.02 49.837 0c-.028-.01-2.613 2.543-5.746 5.674" })
12
12
  }
13
13
  );
@@ -30,9 +30,9 @@ function NavCardGrid(props) {
30
30
  children: [
31
31
  /* @__PURE__ */ jsxs("span", { class: "flex items-center gap-hsp-sm", children: [
32
32
  /* @__PURE__ */ jsx(ArrowIcon, {}),
33
- /* @__PURE__ */ jsx("span", { class: "font-medium text-accent group-hover:underline", children: child.label })
33
+ /* @__PURE__ */ jsx("span", { class: "font-medium text-fg group-hover:text-accent group-hover:underline group-focus-visible:text-accent group-focus-visible:underline", children: child.label })
34
34
  ] }),
35
- child.description && /* @__PURE__ */ jsx("span", { class: "mt-vsp-2xs block text-small text-muted group-hover:text-accent group-hover:underline group-focus-visible:text-accent decoration-muted", children: child.description })
35
+ child.description && /* @__PURE__ */ jsx("span", { class: "mt-vsp-2xs block text-small text-muted group-hover:text-accent group-hover:underline group-focus-visible:text-accent", children: child.description })
36
36
  ]
37
37
  },
38
38
  `nav-card-${i}`
@@ -9,7 +9,7 @@ function CardBody({
9
9
  linked,
10
10
  hasStamp
11
11
  }) {
12
- const titleClass = linked ? "flex items-start gap-hsp-xs text-accent underline group-hover:text-accent-hover group-focus-visible:text-accent-hover" : "flex items-start gap-hsp-xs text-accent underline";
12
+ const titleClass = linked ? "flex items-start gap-hsp-xs text-fg group-hover:text-accent group-hover:underline group-focus-visible:text-accent group-focus-visible:underline" : "flex items-start gap-hsp-xs text-fg";
13
13
  const descriptionClass = linked ? "mt-vsp-xs text-small text-muted group-hover:text-accent group-hover:underline group-focus-visible:text-accent group-focus-visible:underline" : "mt-vsp-xs text-small text-muted";
14
14
  return /* @__PURE__ */ jsxs("div", { class: "min-w-0", children: [
15
15
  /* @__PURE__ */ jsxs("div", { class: "flex flex-wrap items-baseline gap-x-hsp-md gap-y-vsp-3xs", children: [
@@ -6,7 +6,7 @@ function IndexList(props) {
6
6
  return /* @__PURE__ */ jsx("ol", { class: "[&_li]:mb-0", children: props.items.map((item) => {
7
7
  const rowClass = item.href ? "relative -mt-px first:mt-0 border-y border-muted hover:z-local-1 hover:border-accent focus-within:z-local-1 focus-within:border-accent" : "relative -mt-px first:mt-0 border-y border-muted";
8
8
  const rankClass = item.href ? "tabular-nums text-heading leading-none text-muted group-hover:text-fg group-focus-visible:text-fg" : "tabular-nums text-heading leading-none text-muted";
9
- const labelClass = item.href ? "font-medium text-fg underline decoration-muted group-hover:text-accent group-hover:decoration-accent group-focus-visible:text-accent group-focus-visible:decoration-accent" : "font-medium text-fg";
9
+ const labelClass = item.href ? "font-medium text-fg group-hover:text-accent group-hover:underline group-focus-visible:text-accent group-focus-visible:underline" : "font-medium text-fg";
10
10
  const detailClass = item.href ? "mt-vsp-2xs block text-small text-muted group-hover:text-accent group-hover:underline group-focus-visible:text-accent group-focus-visible:underline" : "mt-vsp-2xs block text-small text-muted";
11
11
  const dateClass = item.href ? "mt-vsp-2xs block text-caption text-muted group-hover:text-accent group-hover:underline group-focus-visible:text-accent group-focus-visible:underline" : "mt-vsp-2xs block text-caption text-muted";
12
12
  const rowContent = /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -14,7 +14,7 @@ function Timeline(props) {
14
14
  item.href ? /* @__PURE__ */ jsx(
15
15
  "a",
16
16
  {
17
- class: "peer font-medium text-fg underline decoration-muted hover:text-accent hover:decoration-accent focus-visible:text-accent focus-visible:decoration-accent",
17
+ class: "peer font-medium text-fg hover:text-accent hover:underline focus-visible:text-accent focus-visible:underline",
18
18
  href: item.href,
19
19
  children: item.label
20
20
  }
@@ -29,14 +29,14 @@ function Section({ node }) {
29
29
  return /* @__PURE__ */ jsxs("details", { class: "group border border-muted overflow-hidden", open: true, children: [
30
30
  /* @__PURE__ */ jsxs("summary", { class: "flex items-center gap-x-hsp-md px-hsp-xl py-vsp-md text-title font-bold cursor-pointer select-none bg-surface list-none [&::-webkit-details-marker]:hidden", children: [
31
31
  /* @__PURE__ */ jsx("span", { class: "inline-block text-caption text-muted transition-transform duration-200 group-open:rotate-90", children: "\u25B6" }),
32
- node.href ? /* @__PURE__ */ jsx("a", { href: node.href, class: "hover:underline focus:underline", children: node.label }) : /* @__PURE__ */ jsx("span", { children: node.label })
32
+ node.href ? /* @__PURE__ */ jsx("a", { href: node.href, class: "hover:text-accent hover:underline focus:underline focus-visible:text-accent", children: node.label }) : /* @__PURE__ */ jsx("span", { children: node.label })
33
33
  ] }),
34
34
  leaves.length > 0 && /* @__PURE__ */ jsx("div", { class: "px-hsp-xl py-vsp-md", children: /* @__PURE__ */ jsx("ul", { class: "space-y-vsp-2xs pl-[1.25rem] list-none", children: leaves.map((leaf, i) => /* @__PURE__ */ jsxs("li", { children: [
35
35
  /* @__PURE__ */ jsx(
36
36
  "a",
37
37
  {
38
38
  href: leaf.href,
39
- class: "text-accent hover:underline focus:underline",
39
+ class: "text-fg hover:text-accent hover:underline focus-visible:text-accent focus-visible:underline",
40
40
  children: leaf.label
41
41
  }
42
42
  ),
@@ -11,7 +11,7 @@ function VersionsPageContent(props) {
11
11
  "a",
12
12
  {
13
13
  href: latestHref,
14
- class: "inline-flex items-center gap-hsp-xs text-small text-accent underline hover:text-accent-hover",
14
+ class: "inline-flex items-center gap-hsp-xs text-small text-fg hover:text-accent hover:underline focus-visible:text-accent focus-visible:underline",
15
15
  children: [
16
16
  labels.latestLink,
17
17
  /* @__PURE__ */ jsx(ChevronRight, { className: "h-[0.875rem] w-[0.875rem]" })
@@ -42,7 +42,7 @@ function VersionsPageContent(props) {
42
42
  "a",
43
43
  {
44
44
  href: v.docsHref,
45
- class: "text-accent underline hover:text-accent-hover",
45
+ class: "text-fg hover:text-accent hover:underline focus-visible:text-accent focus-visible:underline",
46
46
  children: labels.docsCol
47
47
  }
48
48
  ) })
@@ -1,6 +1,6 @@
1
1
  import { prepareHomeIntros } from "../home-intro/prepare.js";
2
2
  import { createRequire } from "node:module";
3
- import { existsSync, statSync, readFileSync, cpSync, rmSync, mkdirSync } from "node:fs";
3
+ import { existsSync, statSync, readFileSync } from "node:fs";
4
4
  import { dirname, basename, join } from "node:path";
5
5
  import { definePlugin } from "@takazudo/zfb/plugins";
6
6
  import { loadThemePackRegistry } from "../theme-packs-registry/load-registry.js";
@@ -326,16 +326,6 @@ const plugin = definePlugin({
326
326
  }
327
327
  }
328
328
  const require2 = createRequire(import.meta.url);
329
- let stagedRoutesDir;
330
- const ensureStaged = (routesSrcDir) => {
331
- if (stagedRoutesDir) return stagedRoutesDir;
332
- const dest = join(ctx.projectRoot, ".zudo-doc", "routes-src");
333
- rmSync(dest, { recursive: true, force: true });
334
- mkdirSync(dirname(dest), { recursive: true });
335
- cpSync(routesSrcDir, dest, { recursive: true });
336
- stagedRoutesDir = dest;
337
- return dest;
338
- };
339
329
  for (const route of derivedRoutes) {
340
330
  let resolvedEntrypoint;
341
331
  try {
@@ -348,8 +338,7 @@ const plugin = definePlugin({
348
338
  const routesSrcPath = join(routesSrcDir, tsxName);
349
339
  const srcPath = compiledPath.replace(/[\\/]dist[\\/]/, "/src/").replace(/\.js$/, ".tsx");
350
340
  if (existsSync(routesSrcPath)) {
351
- const underNodeModules = /[\\/]node_modules[\\/]/.test(routesSrcPath);
352
- resolvedEntrypoint = underNodeModules ? join(ensureStaged(routesSrcDir), tsxName) : routesSrcPath;
341
+ resolvedEntrypoint = routesSrcPath;
353
342
  } else if (existsSync(srcPath)) {
354
343
  resolvedEntrypoint = srcPath;
355
344
  } else {
@@ -1,5 +1,5 @@
1
1
  const ZDTP_LOADER_SPECIFIER = "@takazudo/zudo-doc/zdtp-loader";
2
- const DISABLED_LOADER_SOURCE = 'throw new Error("@takazudo/zdtp is not bundled: designTokenPanel is disabled in this build.");\nexport {};\n';
2
+ const DISABLED_LOADER_SOURCE = 'throw new Error("@takazudo/zdtp is not bundled: designTokenPanel is false and bundleZdtp is not set, so this build shadows @takazudo/zudo-doc/zdtp-loader. If you reached this through @takazudo/zudo-doc/design-token-panel-bootstrap to mount your own panel, set bundleZdtp: true and install @takazudo/zdtp.");\nexport {};\n';
3
3
  const plugin = {
4
4
  name: "zdtp-loader",
5
5
  setup(ctx) {
package/dist/preset.d.ts CHANGED
@@ -124,8 +124,18 @@ export interface PresetSettings {
124
124
  docHistory?: boolean;
125
125
  /** Whether the doc history dropdown UI and related artifacts are enabled. */
126
126
  docHistoryUi?: boolean;
127
- /** Falsy → the zdtp-loader plugin keeps `@takazudo/zdtp` out of the island build (#4201). */
127
+ /**
128
+ * Mount the package-owned design token panel and its header trigger. Does
129
+ * NOT decide bundling on its own — the zdtp-loader plugin follows
130
+ * `bundleZdtp ?? designTokenPanel` (#4201, #4261).
131
+ */
128
132
  designTokenPanel?: boolean;
133
+ /**
134
+ * Bundle `@takazudo/zdtp` into the island build. Omitted → follows
135
+ * `designTokenPanel`. Full contract: `ZudoDocConfig.bundleZdtp` in
136
+ * `config.ts`.
137
+ */
138
+ bundleZdtp?: boolean;
129
139
  docHistoryExclude?: string[];
130
140
  /** Generate package-owned viewer pages for files under the configured asset directory. */
131
141
  assetViewer?: boolean;
package/dist/preset.js CHANGED
@@ -2,6 +2,8 @@ import { z } from "zod";
2
2
  import { assertNoCommaInVersionSlugs } from "./version-availability/index.js";
3
3
  import {
4
4
  assertNoEmptyStringFaviconOrLogo,
5
+ assertZdtpBundlingConsistent,
6
+ resolvesBundleZdtp,
5
7
  warnAmbiguousDropdownCategoryMatch
6
8
  } from "./config-assertions/index.js";
7
9
  function zudoDocPreset({
@@ -14,6 +16,7 @@ function zudoDocPreset({
14
16
  }) {
15
17
  assertNoCommaInVersionSlugs(settings.versions);
16
18
  assertNoEmptyStringFaviconOrLogo(settings);
19
+ assertZdtpBundlingConsistent(settings);
17
20
  warnAmbiguousDropdownCategoryMatch(settings.headerNav);
18
21
  const docsSchemaJson = z.toJSONSchema(buildDocsSchema());
19
22
  return {
@@ -304,11 +307,15 @@ function buildPlugins(settings, routeContext) {
304
307
  onBroken: settings.onBrokenMarkdownLinks
305
308
  }
306
309
  },
307
- // Panel OFF → shadow the bootstrap's `@takazudo/zudo-doc/zdtp-loader` lazy
308
- // import with a throwing virtual module so the island build emits no zdtp chunks
309
- // (#4201). Preset-level rather than inside the routes plugin because the
310
- // bootstrap is reachable from chrome even when packageOwnedRoutes is off.
311
- ...settings.designTokenPanel ? [] : [{ name: "@takazudo/zudo-doc/plugins/zdtp-loader", options: {} }]
310
+ // zdtp not bundled → shadow the bootstrap's `@takazudo/zudo-doc/zdtp-loader`
311
+ // lazy import with a throwing virtual module so the island build emits no
312
+ // zdtp chunks (#4201). Bundling follows `bundleZdtp ?? designTokenPanel`:
313
+ // omit `bundleZdtp` and it tracks the panel exactly as before; set it to
314
+ // `true` with the panel off when the host mounts its own panel through
315
+ // `design-token-panel-bootstrap` (#4261). Preset-level rather than inside
316
+ // the routes plugin because the bootstrap is reachable from chrome even
317
+ // when packageOwnedRoutes is off.
318
+ ...resolvesBundleZdtp(settings) ? [] : [{ name: "@takazudo/zudo-doc/plugins/zdtp-loader", options: {} }]
312
319
  ];
313
320
  }
314
321
  export {