@takazudo/zudo-doc 3.2.0 → 3.3.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 (48) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/chrome/derive.d.ts +7 -1
  3. package/dist/chrome/derive.js +13 -2
  4. package/dist/chrome-bindings.d.ts +159 -0
  5. package/dist/chrome-bindings.js +6 -0
  6. package/dist/color-scheme-utils.d.ts +1 -1
  7. package/dist/color-schemes-defaults/index.d.ts +23 -0
  8. package/dist/color-schemes-defaults/index.js +121 -0
  9. package/dist/config.d.ts +443 -0
  10. package/dist/config.js +116 -0
  11. package/dist/design-token-panel-bootstrap.d.ts +57 -7
  12. package/dist/design-token-panel-bootstrap.js +12 -0
  13. package/dist/design-token-panel-config/index.d.ts +49 -0
  14. package/dist/design-token-panel-config/index.js +214 -0
  15. package/dist/design-token-panel-config/manifest.d.ts +46 -0
  16. package/dist/design-token-panel-config/manifest.js +105 -0
  17. package/dist/directive-vocabulary-defaults/index.d.ts +16 -0
  18. package/dist/directive-vocabulary-defaults/index.js +12 -0
  19. package/dist/doc-body-end-islands/index.d.ts +30 -7
  20. package/dist/doc-body-end-islands/index.js +27 -0
  21. package/dist/docs-schema/index.d.ts +67 -0
  22. package/dist/docs-schema/index.js +47 -0
  23. package/dist/factory-context/index.d.ts +14 -0
  24. package/dist/features.css +10 -0
  25. package/dist/find-in-page/find-bar.d.ts +9 -0
  26. package/dist/find-in-page/find-bar.js +114 -0
  27. package/dist/find-in-page/find-in-page.d.ts +17 -0
  28. package/dist/find-in-page/find-in-page.js +131 -0
  29. package/dist/find-in-page/index.d.ts +11 -0
  30. package/dist/find-in-page/index.js +49 -0
  31. package/dist/frontmatter-preview-defaults/index.d.ts +16 -0
  32. package/dist/frontmatter-preview-defaults/index.js +25 -0
  33. package/dist/i18n-defaults/index.d.ts +22 -0
  34. package/dist/i18n-defaults/index.js +167 -0
  35. package/dist/plugins/routes.js +44 -20
  36. package/dist/preset.d.ts +9 -0
  37. package/dist/routes/_chrome.js +2 -1
  38. package/dist/safelist.css +1 -1
  39. package/dist/settings.d.ts +37 -0
  40. package/dist/theme.css +319 -0
  41. package/dist/z-index-defaults/index.d.ts +45 -0
  42. package/dist/z-index-defaults/index.js +34 -0
  43. package/package.json +50 -3
  44. package/routes-src/_chrome.tsx +30 -8
  45. package/routes-src/_virtual.d.ts +34 -2
  46. package/tsconfig.base.json +29 -0
  47. package/virtual-modules.d.ts +79 -0
  48. package/zfb-config-shim.d.ts +188 -0
@@ -0,0 +1,49 @@
1
+ /**
2
+ * `@takazudo/zudo-doc/design-token-panel-config` — the PACKAGE-DEFAULT zdtp
3
+ * PanelConfig builder (#2658, epic Minimal Scaffold #2651, decision wave
4
+ * #2653 "Approach (a)").
5
+ *
6
+ * Ported from the showcase's `src/config/design-token-panel-config.ts` (441
7
+ * lines, ~90% mechanical derivation per the decision-wave audit) so
8
+ * `designTokenPanel: true` works with NO host config file: the Palette tab
9
+ * comes from `defaultColorSchemes`' shared `ramps`, the Color tab from
10
+ * `buildSemanticTierItems`, and Font/Spacing/Size from the manifest in
11
+ * `./manifest.js`. The hand-authored panel-identity constants
12
+ * (`storagePrefix`, `consoleNamespace`, `modalClassPrefix`, `schemaId`,
13
+ * `exportFilenameBase`) and the `FONT_ROLE_TO_SCALE` map are carried over
14
+ * verbatim — `storagePrefix: "zudo-doc-tweak"` in particular MUST NOT change
15
+ * (existing user-save carry-over guarantee, see `packages/zudo-doc/CLAUDE.md`
16
+ * and `src/CLAUDE.md`).
17
+ *
18
+ * A host that needs a fully custom panel (its own color schemes, its own
19
+ * token manifest) points `settings.designTokenPanelConfigModule` at a module
20
+ * exporting a named `buildDesignTokenPanelConfig` — see
21
+ * `../plugins/routes.ts` (`virtual:zudo-doc-design-token-panel-config`,
22
+ * mirrors the `chromeBindingsModule` contract). This module is what the
23
+ * routes plugin re-exports when NO override is configured.
24
+ *
25
+ * Unlike the showcase original, this builder does not resolve
26
+ * `settings.colorMode`/`settings.colorScheme` — the PACKAGE has no settings
27
+ * singleton to read (the preset's node-free eval-graph rule keeps this
28
+ * module out of the config eval graph too, so it must stay side-effect-free
29
+ * on import). It seeds the Color tab straight from `defaultColorSchemes`'
30
+ * "Default Light" / "Default Dark" entries for the requested `mode` — the
31
+ * exact pair `@takazudo/zudo-doc/theme.css` ships as the default scheme.
32
+ */
33
+ import type { PanelConfig } from "@takazudo/zdtp";
34
+ type PanelMode = "light" | "dark";
35
+ /**
36
+ * Build the full PACKAGE-DEFAULT PanelConfig for a given color-scheme
37
+ * `mode`. Only the Color tab's semantic tier and `panelSettings.colorMode.
38
+ * defaultMode` vary by mode; the Palette/Font/Spacing/Size tabs are
39
+ * mode-independent. `@takazudo/zudo-doc/design-token-panel-bootstrap` calls
40
+ * this per mode on every `color-scheme-changed` toggle (destroy +
41
+ * reconfigure) — it is passed as the BUILDER, not a resolved config (#2610).
42
+ *
43
+ * `storagePrefix: "zudo-doc-tweak"` is the same value the showcase's own
44
+ * `design-token-panel-config.ts` has always used — keep it unchanged so a
45
+ * host migrating from an ejected config to this package default carries its
46
+ * existing user-saved tweaks over.
47
+ */
48
+ export declare function buildDesignTokenPanelConfig(mode: PanelMode): PanelConfig;
49
+ export {};
@@ -0,0 +1,214 @@
1
+ import { SPACING_TOKENS, FONT_TOKENS, SIZE_TOKENS } from "./manifest.js";
2
+ import { STATE_ROLES, buildSemanticTierItems } from "../color-scheme-utils.js";
3
+ import { defaultColorSchemes } from "../color-schemes-defaults/index.js";
4
+ const DEFAULT_SHIKI_THEME = "github-dark";
5
+ function schemeNameForMode(mode) {
6
+ return mode === "dark" ? "Default Dark" : "Default Light";
7
+ }
8
+ function schemeForMode(mode) {
9
+ const scheme = defaultColorSchemes[schemeNameForMode(mode)];
10
+ if (!scheme) {
11
+ throw new Error(
12
+ `zudo-doc: defaultColorSchemes is missing "${schemeNameForMode(mode)}" \u2014 this is a package bug.`
13
+ );
14
+ }
15
+ return scheme;
16
+ }
17
+ function toTierItem(t) {
18
+ let kind;
19
+ if (t.control === "select") {
20
+ kind = { kind: "select", options: t.options ?? [] };
21
+ } else if (t.control === "text") {
22
+ kind = { kind: "text" };
23
+ } else {
24
+ kind = {
25
+ kind: "length",
26
+ step: t.step,
27
+ unit: t.unit
28
+ };
29
+ }
30
+ const item = {
31
+ id: t.id,
32
+ cssVar: t.cssVar,
33
+ label: t.label,
34
+ default: t.default,
35
+ type: kind
36
+ };
37
+ if (t.pill) item.pill = t.pill;
38
+ if (t.readonly) item.readonly = true;
39
+ return item;
40
+ }
41
+ function tierFromGroup(tokens, groupId, label) {
42
+ return {
43
+ id: groupId,
44
+ label,
45
+ items: tokens.filter((t) => t.group === groupId).map(toTierItem)
46
+ };
47
+ }
48
+ function buildRampTiers(mode) {
49
+ const { ramps } = schemeForMode(mode);
50
+ const baseTier = {
51
+ id: "base",
52
+ label: "Base",
53
+ items: ramps.base.map((color, i) => ({
54
+ id: `base-${i}`,
55
+ cssVar: `--palette-base-${i}`,
56
+ label: String(i),
57
+ default: color,
58
+ type: { kind: "color", format: "oklch" }
59
+ }))
60
+ };
61
+ const accentTier = {
62
+ id: "accent",
63
+ label: "Accent",
64
+ items: ramps.accent.map((color, i) => ({
65
+ id: `accent-${i}`,
66
+ cssVar: `--palette-accent-${i}`,
67
+ label: String(i),
68
+ default: color,
69
+ type: { kind: "color", format: "oklch" }
70
+ }))
71
+ };
72
+ const stateTier = {
73
+ id: "state",
74
+ label: "State",
75
+ items: STATE_ROLES.map((role) => ({
76
+ id: `state-${role}`,
77
+ cssVar: `--palette-state-${role}`,
78
+ label: role,
79
+ default: ramps.state[role],
80
+ type: { kind: "color", format: "oklch" }
81
+ }))
82
+ };
83
+ return [baseTier, accentTier, stateTier];
84
+ }
85
+ function buildPaletteTab(mode) {
86
+ return {
87
+ id: "palette",
88
+ label: "Palette",
89
+ tiers: buildRampTiers(mode)
90
+ // No colorExtras: a tab with multiple kind:'color' tiers MUST omit it so
91
+ // resolveColorClusterFromTab is not invoked and zdtp renders the ramps
92
+ // with its native curve editor (zdtp palette-tab contract).
93
+ };
94
+ }
95
+ function buildSemanticTier(mode) {
96
+ return {
97
+ id: "semantic",
98
+ label: "Semantic",
99
+ semantic: true,
100
+ referencesRamps: [
101
+ { tab: "palette", tier: "base" },
102
+ { tab: "palette", tier: "accent" },
103
+ { tab: "palette", tier: "state" }
104
+ ],
105
+ items: buildSemanticTierItems(schemeForMode(mode))
106
+ };
107
+ }
108
+ function buildColorExtras(mode) {
109
+ const lightScheme = schemeNameForMode("light");
110
+ const darkScheme = schemeNameForMode("dark");
111
+ return {
112
+ id: "zudo-doc",
113
+ label: "Zudo Doc",
114
+ baseRoles: {},
115
+ baseDefaults: {},
116
+ defaultShikiTheme: DEFAULT_SHIKI_THEME,
117
+ colorSchemes: {},
118
+ panelSettings: {
119
+ colorScheme: schemeNameForMode(mode),
120
+ colorMode: { defaultMode: mode, lightScheme, darkScheme }
121
+ }
122
+ };
123
+ }
124
+ function buildColorTab(mode) {
125
+ return {
126
+ id: "color",
127
+ label: "Color",
128
+ tiers: [buildSemanticTier(mode)],
129
+ colorExtras: buildColorExtras(mode)
130
+ };
131
+ }
132
+ const FONT_SCALE_TIER_ID = "font-scale";
133
+ const FONT_ROLE_TO_SCALE = {
134
+ "text-micro": "text-scale-2xs",
135
+ "text-caption": "text-scale-xs",
136
+ "text-small": "text-scale-sm",
137
+ "text-body": "text-scale-md",
138
+ "text-title": "text-scale-lg",
139
+ "text-heading": "text-scale-xl",
140
+ "text-display": "text-scale-2xl"
141
+ };
142
+ function buildFontRoleTier() {
143
+ const base = tierFromGroup(FONT_TOKENS, "font-size", "Font size");
144
+ return {
145
+ ...base,
146
+ items: base.items.map((item) => {
147
+ const scaleId = FONT_ROLE_TO_SCALE[item.id];
148
+ return scaleId ? { ...item, default: scaleId } : item;
149
+ }),
150
+ referencesTier: FONT_SCALE_TIER_ID
151
+ };
152
+ }
153
+ function buildFontTab() {
154
+ return {
155
+ id: "font",
156
+ label: "Font",
157
+ tiers: [
158
+ tierFromGroup(FONT_TOKENS, FONT_SCALE_TIER_ID, "Scale"),
159
+ buildFontRoleTier(),
160
+ tierFromGroup(FONT_TOKENS, "line-height", "Line height"),
161
+ tierFromGroup(FONT_TOKENS, "font-weight", "Font weight"),
162
+ tierFromGroup(FONT_TOKENS, "font-family", "Font family")
163
+ ]
164
+ };
165
+ }
166
+ function buildSpacingTab() {
167
+ return {
168
+ id: "spacing",
169
+ label: "Spacing",
170
+ tiers: [
171
+ tierFromGroup(SPACING_TOKENS, "hsp", "Horizontal spacing"),
172
+ tierFromGroup(SPACING_TOKENS, "vsp", "Vertical spacing"),
173
+ tierFromGroup(SPACING_TOKENS, "icon", "Icons"),
174
+ tierFromGroup(SPACING_TOKENS, "layout", "Layout")
175
+ ]
176
+ };
177
+ }
178
+ function buildSizeTab() {
179
+ return {
180
+ id: "size",
181
+ label: "Size",
182
+ tiers: [
183
+ tierFromGroup(SIZE_TOKENS, "radius", "Radius"),
184
+ tierFromGroup(SIZE_TOKENS, "transition", "Transition")
185
+ ]
186
+ };
187
+ }
188
+ function buildDesignTokenPanelConfig(mode) {
189
+ return {
190
+ storagePrefix: "zudo-doc-tweak",
191
+ consoleNamespace: "zudoDoc",
192
+ modalClassPrefix: "zudo-doc-design-token-panel-modal",
193
+ // DISPLAY-ONLY in zdtp 0.4.6: the panel's export hard-codes
194
+ // `zudo-design-tokens/v2` and auto-upgrades to `.../v3` when object leaves
195
+ // ({ref}/{literal}/per-mode) are present — which the semantic tier's ramp
196
+ // refs always are, so real exports carry v3. `schemaId` does NOT gate
197
+ // import, and (verified against the installed zdtp 0.4.6 bundle) zdtp's
198
+ // Import/Export modals do not read this field at all — their hint/error
199
+ // text is hardcoded to zdtp's own internal `SCHEMA_V1`/`SCHEMA_V2`/
200
+ // `SCHEMA_V3` constants (#498/#505), which are unrelated to this field.
201
+ // It is thus a purely descriptive config value with no runtime effect;
202
+ // set to v3 (a literal, not one of those constants) to match what real
203
+ // exports carry. Distinct from the host serde's `DESIGN_TOKEN_SCHEMA`
204
+ // (`zudo-doc-design-tokens/v3` — bumped from v2 in #2599 so a stale
205
+ // pre-5/3-minimize export resets instead of crashing on import), which
206
+ // governs a separate round-trip.
207
+ schemaId: "zudo-design-tokens/v3",
208
+ exportFilenameBase: "zudo-doc-design-tokens",
209
+ tabs: [buildPaletteTab(mode), buildColorTab(mode), buildFontTab(), buildSpacingTab(), buildSizeTab()]
210
+ };
211
+ }
212
+ export {
213
+ buildDesignTokenPanelConfig
214
+ };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Design-token manifest data arrays — the PACKAGE-DEFAULT source of truth for
3
+ * the spacing/font/size tabs of `buildDesignTokenPanelConfig` (#2658, epic
4
+ * Minimal Scaffold #2651).
5
+ *
6
+ * Ported verbatim from the showcase's `src/config/design-tokens-manifest.ts`
7
+ * (values mirror the defaults shipped by `@takazudo/zudo-doc/theme.css`,
8
+ * #2655) so `designTokenPanel: true` works with no host manifest file. A
9
+ * project that needs its own token set entirely ejects via
10
+ * `designTokenPanelConfigModule` (see `../plugins/routes.ts`), not by editing
11
+ * this file — this module stays the PACKAGE default.
12
+ *
13
+ * Type strategy: arrays are typed `readonly TokenDef[]`, matching the
14
+ * upstream zdtp `TokenDef` shape consumed by `../color-scheme-utils.js` and
15
+ * `./index.ts` (which partitions them into `TabConfig.tiers` by `group`).
16
+ */
17
+ import type { TokenDef } from "@takazudo/zdtp";
18
+ /**
19
+ * Spacing tokens — mirrors every `--spacing-*` declaration shipped by
20
+ * `@takazudo/zudo-doc/theme.css`, plus the `--zd-sidebar-w` layout token.
21
+ * Read-only rows surface tokens whose value can't be expressed on a
22
+ * single-axis slider (`clamp()`, structural `0`).
23
+ */
24
+ export declare const SPACING_TOKENS: readonly TokenDef[];
25
+ /**
26
+ * Font tokens — mirrors every font-related declaration shipped by
27
+ * `@takazudo/zudo-doc/theme.css`.
28
+ *
29
+ * Tier 2 semantic tokens (sizes, line-heights, weights, families) are exposed
30
+ * as primary tiers; Tier 1 abstract scale (`--text-scale-*`) lives in its own
31
+ * `font-scale` tier so designers who tweak the scale see the tokens that the
32
+ * semantic sizes resolve from.
33
+ */
34
+ export declare const FONT_TOKENS: readonly TokenDef[];
35
+ /**
36
+ * Size tokens — mirrors every non-breakpoint size-category custom property
37
+ * shipped by `@takazudo/zudo-doc/theme.css`. Breakpoints (`--breakpoint-*`)
38
+ * are intentionally omitted — live-changing them causes layout thrash
39
+ * mid-drag and adds no real tweak value.
40
+ *
41
+ * Radius defaults use `px` (matches a 0-100 slider), even though
42
+ * `theme.css` expresses them in `rem` — the browser accepts both.
43
+ * `--radius-full` carries a `pill` toggle: its design default (`9999px`) is
44
+ * an intentional sentinel a 0-100 slider can't reach.
45
+ */
46
+ export declare const SIZE_TOKENS: readonly TokenDef[];
@@ -0,0 +1,105 @@
1
+ const FONT_WEIGHT_OPTIONS = [
2
+ "100",
3
+ "200",
4
+ "300",
5
+ "400",
6
+ "500",
7
+ "600",
8
+ "700",
9
+ "800",
10
+ "900"
11
+ ];
12
+ const SPACING_TOKENS = [
13
+ // --- Horizontal spacing ---
14
+ { id: "hsp-2xs", cssVar: "--spacing-hsp-2xs", label: "hsp-2xs", group: "hsp", default: "0.125rem", step: 0.025, unit: "rem" },
15
+ { id: "hsp-xs", cssVar: "--spacing-hsp-xs", label: "hsp-xs", group: "hsp", default: "0.375rem", step: 0.025, unit: "rem" },
16
+ { id: "hsp-sm", cssVar: "--spacing-hsp-sm", label: "hsp-sm", group: "hsp", default: "0.5rem", step: 0.025, unit: "rem" },
17
+ { id: "hsp-md", cssVar: "--spacing-hsp-md", label: "hsp-md", group: "hsp", default: "0.75rem", step: 0.025, unit: "rem" },
18
+ { id: "hsp-lg", cssVar: "--spacing-hsp-lg", label: "hsp-lg", group: "hsp", default: "1rem", step: 0.025, unit: "rem" },
19
+ { id: "hsp-xl", cssVar: "--spacing-hsp-xl", label: "hsp-xl", group: "hsp", default: "1.5rem", step: 0.025, unit: "rem" },
20
+ { id: "hsp-2xl", cssVar: "--spacing-hsp-2xl", label: "hsp-2xl", group: "hsp", default: "2rem", step: 0.025, unit: "rem" },
21
+ // --- Vertical spacing ---
22
+ { id: "vsp-3xs", cssVar: "--spacing-vsp-3xs", label: "vsp-3xs", group: "vsp", default: "0.25rem", step: 0.025, unit: "rem" },
23
+ { id: "vsp-2xs", cssVar: "--spacing-vsp-2xs", label: "vsp-2xs", group: "vsp", default: "0.4375rem", step: 0.025, unit: "rem" },
24
+ { id: "vsp-xs", cssVar: "--spacing-vsp-xs", label: "vsp-xs", group: "vsp", default: "0.875rem", step: 0.025, unit: "rem" },
25
+ { id: "vsp-sm", cssVar: "--spacing-vsp-sm", label: "vsp-sm", group: "vsp", default: "1.25rem", step: 0.025, unit: "rem" },
26
+ { id: "vsp-md", cssVar: "--spacing-vsp-md", label: "vsp-md", group: "vsp", default: "1.5rem", step: 0.025, unit: "rem" },
27
+ { id: "vsp-lg", cssVar: "--spacing-vsp-lg", label: "vsp-lg", group: "vsp", default: "1.75rem", step: 0.025, unit: "rem" },
28
+ { id: "vsp-xl", cssVar: "--spacing-vsp-xl", label: "vsp-xl", group: "vsp", default: "2.5rem", step: 0.025, unit: "rem" },
29
+ { id: "vsp-2xl", cssVar: "--spacing-vsp-2xl", label: "vsp-2xl", group: "vsp", default: "3.5rem", step: 0.025, unit: "rem" },
30
+ // --- Icons ---
31
+ { id: "icon-xs", cssVar: "--spacing-icon-xs", label: "icon-xs", group: "icon", default: "0.75rem", step: 0.05, unit: "rem" },
32
+ { id: "icon-sm", cssVar: "--spacing-icon-sm", label: "icon-sm", group: "icon", default: "1rem", step: 0.05, unit: "rem" },
33
+ { id: "icon-md", cssVar: "--spacing-icon-md", label: "icon-md", group: "icon", default: "1.25rem", step: 0.05, unit: "rem" },
34
+ { id: "icon-lg", cssVar: "--spacing-icon-lg", label: "icon-lg", group: "icon", default: "1.5rem", step: 0.05, unit: "rem" },
35
+ // --- Layout ---
36
+ { id: "image-overlay-inset", cssVar: "--spacing-image-overlay-inset", label: "image-overlay-inset", group: "layout", default: "0.5rem", step: 0.05, unit: "rem" },
37
+ // Structural zero — surfaced as read-only so designers see it exists, but
38
+ // editing it would break every utility that relies on "0 is 0".
39
+ { id: "spacing-0", cssVar: "--spacing-0", label: "spacing-0", group: "layout", default: "0", step: 1, unit: "", readonly: true },
40
+ // 1px hairline — also read-only by design.
41
+ { id: "spacing-px", cssVar: "--spacing-px", label: "spacing-px", group: "layout", default: "1px", step: 1, unit: "px", readonly: true },
42
+ // Responsive clamp() expression — can't be expressed on a single slider.
43
+ { id: "sidebar-w", cssVar: "--zd-sidebar-w", label: "sidebar-w", group: "layout", default: "clamp(14rem, 20vw, 22rem)", step: 1, unit: "", readonly: true }
44
+ ];
45
+ const FONT_TOKENS = [
46
+ // --- Font sizes (Tier 2 semantic) ---
47
+ { id: "text-micro", cssVar: "--text-micro", label: "text-micro", group: "font-size", default: "0.75rem", step: 0.05, unit: "rem" },
48
+ { id: "text-caption", cssVar: "--text-caption", label: "text-caption", group: "font-size", default: "0.875rem", step: 0.05, unit: "rem" },
49
+ { id: "text-small", cssVar: "--text-small", label: "text-small", group: "font-size", default: "1rem", step: 0.05, unit: "rem" },
50
+ { id: "text-body", cssVar: "--text-body", label: "text-body", group: "font-size", default: "1.2rem", step: 0.05, unit: "rem" },
51
+ { id: "text-title", cssVar: "--text-title", label: "text-title", group: "font-size", default: "1.4rem", step: 0.05, unit: "rem" },
52
+ { id: "text-heading", cssVar: "--text-heading", label: "text-heading", group: "font-size", default: "3rem", step: 0.05, unit: "rem" },
53
+ { id: "text-display", cssVar: "--text-display", label: "text-display", group: "font-size", default: "3.75rem", step: 0.05, unit: "rem" },
54
+ // --- Line heights (unitless) ---
55
+ { id: "leading-tight", cssVar: "--leading-tight", label: "leading-tight", group: "line-height", default: "1.25", step: 0.05, unit: "" },
56
+ { id: "leading-snug", cssVar: "--leading-snug", label: "leading-snug", group: "line-height", default: "1.375", step: 0.05, unit: "" },
57
+ { id: "leading-normal", cssVar: "--leading-normal", label: "leading-normal", group: "line-height", default: "1.5", step: 0.05, unit: "" },
58
+ { id: "leading-relaxed", cssVar: "--leading-relaxed", label: "leading-relaxed", group: "line-height", default: "1.625", step: 0.05, unit: "" },
59
+ // --- Font weights (select) ---
60
+ { id: "font-weight-normal", cssVar: "--font-weight-normal", label: "font-weight-normal", group: "font-weight", default: "400", step: 1, unit: "", control: "select", options: FONT_WEIGHT_OPTIONS },
61
+ { id: "font-weight-medium", cssVar: "--font-weight-medium", label: "font-weight-medium", group: "font-weight", default: "500", step: 1, unit: "", control: "select", options: FONT_WEIGHT_OPTIONS },
62
+ { id: "font-weight-semibold", cssVar: "--font-weight-semibold", label: "font-weight-semibold", group: "font-weight", default: "600", step: 1, unit: "", control: "select", options: FONT_WEIGHT_OPTIONS },
63
+ { id: "font-weight-bold", cssVar: "--font-weight-bold", label: "font-weight-bold", group: "font-weight", default: "700", step: 1, unit: "", control: "select", options: FONT_WEIGHT_OPTIONS },
64
+ // --- Font families (text input) ---
65
+ { id: "font-sans", cssVar: "--font-sans", label: "font-sans", group: "font-family", default: "system-ui, sans-serif", step: 1, unit: "", control: "text" },
66
+ { id: "font-mono", cssVar: "--font-mono", label: "font-mono", group: "font-family", default: "ui-monospace, monospace", step: 1, unit: "", control: "text" },
67
+ // --- Tier 1 abstract scale ---
68
+ { id: "text-scale-2xs", cssVar: "--text-scale-2xs", label: "text-scale-2xs", group: "font-scale", default: "0.75rem", step: 0.05, unit: "rem" },
69
+ { id: "text-scale-xs", cssVar: "--text-scale-xs", label: "text-scale-xs", group: "font-scale", default: "0.875rem", step: 0.05, unit: "rem" },
70
+ { id: "text-scale-sm", cssVar: "--text-scale-sm", label: "text-scale-sm", group: "font-scale", default: "1rem", step: 0.05, unit: "rem" },
71
+ { id: "text-scale-md", cssVar: "--text-scale-md", label: "text-scale-md", group: "font-scale", default: "1.2rem", step: 0.05, unit: "rem" },
72
+ { id: "text-scale-lg", cssVar: "--text-scale-lg", label: "text-scale-lg", group: "font-scale", default: "1.4rem", step: 0.05, unit: "rem" },
73
+ { id: "text-scale-xl", cssVar: "--text-scale-xl", label: "text-scale-xl", group: "font-scale", default: "3rem", step: 0.05, unit: "rem" },
74
+ { id: "text-scale-2xl", cssVar: "--text-scale-2xl", label: "text-scale-2xl", group: "font-scale", default: "3.75rem", step: 0.05, unit: "rem" }
75
+ ];
76
+ const SIZE_TOKENS = [
77
+ // --- Radius ---
78
+ { id: "radius-DEFAULT", cssVar: "--radius-DEFAULT", label: "radius-DEFAULT", group: "radius", default: "4px", step: 1, unit: "px" },
79
+ { id: "radius-lg", cssVar: "--radius-lg", label: "radius-lg", group: "radius", default: "8px", step: 1, unit: "px" },
80
+ {
81
+ id: "radius-full",
82
+ cssVar: "--radius-full",
83
+ label: "radius-full",
84
+ group: "radius",
85
+ default: "9999px",
86
+ step: 1,
87
+ unit: "px",
88
+ pill: { value: "9999px", customDefault: "16px" }
89
+ },
90
+ // --- Transitions ---
91
+ {
92
+ id: "default-transition-duration",
93
+ cssVar: "--default-transition-duration",
94
+ label: "default-transition-duration",
95
+ group: "transition",
96
+ default: "150ms",
97
+ step: 10,
98
+ unit: "ms"
99
+ }
100
+ ];
101
+ export {
102
+ FONT_TOKENS,
103
+ SIZE_TOKENS,
104
+ SPACING_TOKENS
105
+ };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Default directive vocabulary — the canonical seven.
3
+ *
4
+ * Ported from the `directiveVocabulary` object that every
5
+ * `create-zudo-doc`-generated `zfb.config.ts` previously hardcoded inline
6
+ * (see `packages/create-zudo-doc/src/zfb-config-gen.ts`'s `generateZfbConfig`
7
+ * and this repo's own `zfb.config.ts`) into a package default (epic
8
+ * zudolab/zudo-doc#2651, S4 #2654).
9
+ *
10
+ * Keys are directive names; values are the JSX component names the markdown
11
+ * pipeline's `directives` feature resolves them to (registered in the host's
12
+ * `pages/_mdx-components.ts`). `details` routes to a collapsible, NOT an
13
+ * admonition — the other six are admonition variants.
14
+ */
15
+ import type { DirectiveVocabulary } from "../preset.js";
16
+ export declare const defaultDirectiveVocabulary: DirectiveVocabulary;
@@ -0,0 +1,12 @@
1
+ const defaultDirectiveVocabulary = {
2
+ note: "Note",
3
+ tip: "Tip",
4
+ info: "Info",
5
+ warning: "Warning",
6
+ danger: "Danger",
7
+ caution: "Caution",
8
+ details: "Details"
9
+ };
10
+ export {
11
+ defaultDirectiveVocabulary
12
+ };
@@ -1,7 +1,8 @@
1
1
  /** @jsxRuntime automatic */
2
2
  /** @jsxImportSource preact */
3
3
  import type { JSX } from "preact";
4
- /** The `settings` subset this factory reads — the three package-island flags.
4
+ import type { FactoryComponent } from "../factory-context/index.js";
5
+ /** The `settings` subset this factory reads — the four package-island flags.
5
6
  * A structural subset so the host can pass its full `Settings` object. */
6
7
  export interface BodyEndIslandsSettings {
7
8
  aiAssistant: boolean;
@@ -14,10 +15,38 @@ export interface BodyEndIslandsSettings {
14
15
  * `undefined` is treated as `false` (no overlay) at the mount site, preserving
15
16
  * pre-#2482 behavior; internal callers always pass the full `Settings`. */
16
17
  dynamicPageTransition?: boolean;
18
+ /** Gates the `DesignTokenPanelBootstrap` island mount (#2658). Optional for
19
+ * the same external-caller-compat reason as `dynamicPageTransition` above.
20
+ * `undefined` is treated as `false` (no panel island). Even when `true`,
21
+ * nothing mounts unless `deps.DesignTokenPanelBootstrap` was also supplied
22
+ * — see {@link BodyEndIslandsDeps}. */
23
+ designTokenPanel?: boolean;
24
+ /**
25
+ * Gates the `FindInPageInit` island mount (zudolab/zudo-doc#2689). Optional
26
+ * for the same external-caller-compat reason as `dynamicPageTransition`/
27
+ * `designTokenPanel` above. `undefined` is treated as `false` (no island).
28
+ * Controls the PACKAGE-DEFAULT `BodyEndIslands` slot only — a host that
29
+ * overrides the `BodyEndIslands` chrome binding must mount `FindInPageInit`
30
+ * itself.
31
+ */
32
+ findInPage?: boolean;
17
33
  }
18
34
  /** Dependencies injected by `_chrome.tsx` (carries the virtual-module settings). */
19
35
  export interface BodyEndIslandsDeps {
20
36
  settings: BodyEndIslandsSettings;
37
+ /**
38
+ * The real `DesignTokenPanelBootstrap` component (#2658) — see the module
39
+ * header note above for why it is NOT imported directly here.
40
+ * `chrome/derive.tsx`'s `deriveBodyEndIslands` supplies
41
+ * `@takazudo/zudo-doc/design-token-panel-bootstrap`'s
42
+ * `DesignTokenPanelBootstrap` as the default for every `createChrome`
43
+ * consumer (#2659 gate-2 fix), so chrome-derived callers always carry it.
44
+ * Omitted (a bare `createBodyEndIslands({ settings })` call outside the
45
+ * chrome path, as this factory's own unit tests do) means no panel island
46
+ * mounts even when `settings.designTokenPanel` is `true` — a safe no-op,
47
+ * not a crash.
48
+ */
49
+ DesignTokenPanelBootstrap?: FactoryComponent;
21
50
  }
22
51
  /** Props for the produced `BodyEndIslands` component. */
23
52
  export interface BodyEndIslandsProps {
@@ -30,10 +59,4 @@ export interface BodyEndIslandsProps {
30
59
  */
31
60
  aiChatBodyLabel?: string;
32
61
  }
33
- /**
34
- * Build the package-default `BodyEndIslands` component bound to the host's
35
- * serializable `settings` flags. The produced component matches the
36
- * `createDocBodyEnd` `BodyEndIslands` slot contract
37
- * (`(props: { basePath: string }) => JSX.Element`).
38
- */
39
62
  export declare function createBodyEndIslands(deps: BodyEndIslandsDeps): (props: BodyEndIslandsProps) => JSX.Element;
@@ -3,10 +3,24 @@ import { Island } from "@takazudo/zfb";
3
3
  import { AiChatModal } from "../ai-chat-modal/index.js";
4
4
  import { ImageEnlarge, ImageEnlargeSsrFallback } from "../image-enlarge/index.js";
5
5
  import { MermaidEnlarge, MermaidEnlargeSsrFallback } from "../mermaid-enlarge/index.js";
6
+ import { FindInPageInit } from "../find-in-page/index.js";
6
7
  import { PageLoadingOverlay } from "../page-loading/index.js";
7
8
  const DEFAULT_AI_CHAT_BODY_LABEL = "Ask a question about the documentation.";
9
+ const ZDTP_TOGGLE_SHIM_SRC = `(function(){
10
+ if(window.__zdtpToggleShimInstalled)return;
11
+ window.__zdtpToggleShimInstalled=true;
12
+ var pending=false;
13
+ function shim(){pending=true;}
14
+ window.addEventListener('toggle-design-token-panel',shim);
15
+ window.__zdtpReadyClicks=function(){
16
+ window.removeEventListener('toggle-design-token-panel',shim);
17
+ delete window.__zdtpReadyClicks;
18
+ if(pending){pending=false;window.dispatchEvent(new CustomEvent('toggle-design-token-panel'));}
19
+ };
20
+ })();`;
8
21
  function createBodyEndIslands(deps) {
9
22
  const { settings } = deps;
23
+ const DesignTokenPanelBootstrap = deps.DesignTokenPanelBootstrap;
10
24
  function BodyEndIslands({
11
25
  basePath,
12
26
  aiChatBodyLabel = DEFAULT_AI_CHAT_BODY_LABEL
@@ -28,8 +42,21 @@ function createBodyEndIslands(deps) {
28
42
  ssrFallback: /* @__PURE__ */ jsx(MermaidEnlargeSsrFallback, {}),
29
43
  children: /* @__PURE__ */ jsx(MermaidEnlarge, {})
30
44
  }) : null;
45
+ const designTokenPanelBootstrap = settings.designTokenPanel && DesignTokenPanelBootstrap ? /* @__PURE__ */ jsxs(Fragment, { children: [
46
+ /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: ZDTP_TOGGLE_SHIM_SRC } }),
47
+ Island({
48
+ when: "load",
49
+ children: /* @__PURE__ */ jsx(DesignTokenPanelBootstrap, {})
50
+ })
51
+ ] }) : null;
52
+ const findInPageInit = settings.findInPage ? Island({
53
+ when: "load",
54
+ children: /* @__PURE__ */ jsx(FindInPageInit, {})
55
+ }) : null;
31
56
  return /* @__PURE__ */ jsxs(Fragment, { children: [
32
57
  settings.dynamicPageTransition ? /* @__PURE__ */ jsx(PageLoadingOverlay, {}) : null,
58
+ designTokenPanelBootstrap,
59
+ findInPageInit,
33
60
  aiAssistant,
34
61
  imageEnlarge,
35
62
  mermaidEnlarge
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Default docs-frontmatter zod schema builder.
3
+ *
4
+ * Ported (and parameterized) from the `create-zudo-doc` base template's
5
+ * `src/config/docs-schema.ts` `buildDocsSchema` export (epic
6
+ * zudolab/zudo-doc#2651, S4 #2654).
7
+ *
8
+ * Unlike the template original — which read the host `settings` and
9
+ * `tag-vocabulary` singletons directly — this package default NEVER imports
10
+ * host singletons: governance mode and the vocabulary entries are passed in
11
+ * as `opts`. `zudoDoc()` (#2657) calls this with the project's merged
12
+ * governance config; a project may also override `buildDocsSchema` entirely
13
+ * via `ZudoDocConfig.buildDocsSchema`.
14
+ */
15
+ import { z } from "zod";
16
+ import type { PresetTagVocabularyEntry } from "../preset.js";
17
+ export interface BuildDocsSchemaOptions {
18
+ tagGovernance?: "off" | "warn" | "strict";
19
+ tagVocabulary?: readonly PresetTagVocabularyEntry[];
20
+ }
21
+ /**
22
+ * Build the docs frontmatter zod schema.
23
+ *
24
+ * Returns a single `z.object(...).passthrough()` reused for every docs
25
+ * collection (default + per-locale + per-version + per-version-per-locale).
26
+ * The `tags` field is governance-aware: `buildTagsSchema()` returns a plain
27
+ * `z.array(z.string())` when governance is off (or `opts` is omitted), or a
28
+ * restricted `z.enum` when `opts.tagGovernance: "strict"` plus a non-empty
29
+ * `opts.tagVocabulary` is supplied.
30
+ *
31
+ * `.passthrough()` keeps custom frontmatter keys (e.g. `author`, `status`)
32
+ * available downstream — the frontmatter-preview UI relies on this to
33
+ * surface arbitrary keys without declaring each one here.
34
+ */
35
+ export declare function buildDocsSchema(opts?: BuildDocsSchemaOptions): z.ZodObject<{
36
+ title: z.ZodString;
37
+ description: z.ZodOptional<z.ZodString>;
38
+ category: z.ZodOptional<z.ZodString>;
39
+ sidebar_position: z.ZodOptional<z.ZodNumber>;
40
+ sidebar_label: z.ZodOptional<z.ZodString>;
41
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>> | z.ZodOptional<z.ZodArray<z.ZodEnum<{
42
+ [x: string]: string;
43
+ }>>>;
44
+ search_exclude: z.ZodOptional<z.ZodBoolean>;
45
+ pagination_next: z.ZodOptional<z.ZodNullable<z.ZodString>>;
46
+ pagination_prev: z.ZodOptional<z.ZodNullable<z.ZodString>>;
47
+ draft: z.ZodOptional<z.ZodBoolean>;
48
+ unlisted: z.ZodOptional<z.ZodBoolean>;
49
+ hide_sidebar: z.ZodOptional<z.ZodBoolean>;
50
+ hide_toc: z.ZodOptional<z.ZodBoolean>;
51
+ wide: z.ZodOptional<z.ZodBoolean>;
52
+ doc_history: z.ZodOptional<z.ZodBoolean>;
53
+ standalone: z.ZodOptional<z.ZodBoolean>;
54
+ slug: z.ZodOptional<z.ZodString>;
55
+ generated: z.ZodOptional<z.ZodBoolean>;
56
+ category_no_page: z.ZodOptional<z.ZodBoolean>;
57
+ category_sort_order: z.ZodOptional<z.ZodEnum<{
58
+ asc: "asc";
59
+ desc: "desc";
60
+ }>>;
61
+ }, z.core.$loose>;
62
+ /**
63
+ * TypeScript type inferred from the default docs frontmatter zod schema.
64
+ * A project overriding `buildDocsSchema` via `ZudoDocConfig` should derive
65
+ * its own `DocsData` type from its own builder instead of this one.
66
+ */
67
+ export type DocsData = z.infer<ReturnType<typeof buildDocsSchema>>;