@honeydeck/honeydeck 0.1.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/AGENTS.md +25 -0
- package/DEVELOPMENT.md +522 -0
- package/LICENSE +21 -0
- package/Readme.md +49 -0
- package/SPEC.md +88 -0
- package/docs/components.md +63 -0
- package/docs/configuration.md +91 -0
- package/docs/getting-started.md +116 -0
- package/docs/kit-authoring.md +207 -0
- package/docs/kits.md +387 -0
- package/docs/local-development.md +95 -0
- package/docs/mermaid.md +198 -0
- package/docs/mobile.md +108 -0
- package/docs/navigation.md +93 -0
- package/docs/next-steps.md +377 -0
- package/docs/pdf-export.md +91 -0
- package/docs/presenter-mode.md +104 -0
- package/docs/slides.md +130 -0
- package/docs/slidev-migration.md +42 -0
- package/docs/steps-and-reveals.md +171 -0
- package/package.json +134 -0
- package/skills/SPEC.md +21 -0
- package/skills/honeydeck/SKILL.md +65 -0
- package/skills/presentation-writing/SKILL.md +75 -0
- package/skills/slidev-migration/SKILL.md +153 -0
- package/src/SPEC.md +89 -0
- package/src/assets.d.ts +30 -0
- package/src/cli/SPEC.md +230 -0
- package/src/cli/args.ts +3 -0
- package/src/cli/banner.ts +9 -0
- package/src/cli/bin.js +5 -0
- package/src/cli/build.ts +229 -0
- package/src/cli/deck-path.ts +32 -0
- package/src/cli/dev.ts +263 -0
- package/src/cli/index.ts +126 -0
- package/src/cli/init.ts +369 -0
- package/src/cli/pdf.ts +923 -0
- package/src/cli/skill.ts +75 -0
- package/src/cli/templates/SPEC.md +70 -0
- package/src/cli/templates/deck-mdx.ts +15 -0
- package/src/cli/templates/package-json.ts +36 -0
- package/src/cli/templates/sparkle-button.ts +15 -0
- package/src/cli/templates/starter/components/SparkleButton.tsx +84 -0
- package/src/cli/templates/starter/deck.mdx +153 -0
- package/src/cli/templates/starter/styles.css +14 -0
- package/src/cli/templates/styles-css.ts +14 -0
- package/src/defaults.ts +1 -0
- package/src/layouts/ColorModeImage.tsx +55 -0
- package/src/layouts/SPEC.md +393 -0
- package/src/layouts/SlideFrame.tsx +48 -0
- package/src/layouts/bee/Blank.tsx +12 -0
- package/src/layouts/bee/Cover.tsx +70 -0
- package/src/layouts/bee/Default.tsx +42 -0
- package/src/layouts/bee/Image/Image.tsx +151 -0
- package/src/layouts/bee/Image/placeholder-dark.webp +0 -0
- package/src/layouts/bee/Image/placeholder-vertical-dark.webp +0 -0
- package/src/layouts/bee/Image/placeholder-vertical.webp +0 -0
- package/src/layouts/bee/Image/placeholder.webp +0 -0
- package/src/layouts/bee/ImageLeft.tsx +27 -0
- package/src/layouts/bee/ImageRight.tsx +27 -0
- package/src/layouts/bee/ImageSide.tsx +107 -0
- package/src/layouts/bee/Section.tsx +40 -0
- package/src/layouts/bee/TwoCol.tsx +108 -0
- package/src/layouts/bee/index.ts +40 -0
- package/src/layouts/clean/Blank.tsx +12 -0
- package/src/layouts/clean/Cover.tsx +58 -0
- package/src/layouts/clean/Default.tsx +33 -0
- package/src/layouts/clean/Image/Image.tsx +103 -0
- package/src/layouts/clean/ImageLeft.tsx +27 -0
- package/src/layouts/clean/ImageRight.tsx +27 -0
- package/src/layouts/clean/ImageSide.tsx +113 -0
- package/src/layouts/clean/Section.tsx +35 -0
- package/src/layouts/clean/TwoCol.tsx +63 -0
- package/src/layouts/clean/index.ts +40 -0
- package/src/layouts/index.ts +60 -0
- package/src/layouts/placeholders.ts +9 -0
- package/src/layouts/utils.ts +13 -0
- package/src/remark/SPEC.md +49 -0
- package/src/remark/h1-extract.ts +124 -0
- package/src/remark/index.ts +4 -0
- package/src/remark/shiki-code-blocks.ts +325 -0
- package/src/remark/step-numbering.ts +412 -0
- package/src/runtime/Deck.tsx +533 -0
- package/src/runtime/SPEC.md +256 -0
- package/src/runtime/SlideCanvas.tsx +95 -0
- package/src/runtime/TimelineContext.tsx +122 -0
- package/src/runtime/app-shell/index.html +31 -0
- package/src/runtime/app-shell/main.tsx +42 -0
- package/src/runtime/aspectRatio.ts +34 -0
- package/src/runtime/colorMode.ts +23 -0
- package/src/runtime/components/BrowserFrame.tsx +233 -0
- package/src/runtime/components/Button.tsx +57 -0
- package/src/runtime/components/CodeBlock.tsx +210 -0
- package/src/runtime/components/ColorModeCycleButton.tsx +59 -0
- package/src/runtime/components/ErrorBoundary.tsx +125 -0
- package/src/runtime/components/Keyboard.tsx +87 -0
- package/src/runtime/components/ListStyle.tsx +203 -0
- package/src/runtime/components/NavBar.tsx +223 -0
- package/src/runtime/components/NavBarButton.tsx +47 -0
- package/src/runtime/components/NavBarDivider.tsx +3 -0
- package/src/runtime/components/Notes.tsx +171 -0
- package/src/runtime/components/Reveal.tsx +82 -0
- package/src/runtime/components/RevealGroup.tsx +193 -0
- package/src/runtime/components/SPEC.md +263 -0
- package/src/runtime/components/SlideNumberBadge.tsx +11 -0
- package/src/runtime/components/TimelineSteps.tsx +115 -0
- package/src/runtime/components/index.ts +55 -0
- package/src/runtime/index.ts +42 -0
- package/src/runtime/inputOwnership.ts +68 -0
- package/src/runtime/keyboardTarget.ts +7 -0
- package/src/runtime/lastSlideRoute.ts +56 -0
- package/src/runtime/navigation.ts +211 -0
- package/src/runtime/router.ts +157 -0
- package/src/runtime/slideData.ts +137 -0
- package/src/runtime/sync.ts +267 -0
- package/src/runtime/types.ts +182 -0
- package/src/runtime/useKeyboardNav.ts +138 -0
- package/src/runtime/useSwipeNav.ts +257 -0
- package/src/runtime/views/DocsView.tsx +74 -0
- package/src/runtime/views/OverviewView.tsx +386 -0
- package/src/runtime/views/PresenterNotesPanel.tsx +76 -0
- package/src/runtime/views/PresenterView.tsx +340 -0
- package/src/runtime/views/SPEC.md +152 -0
- package/src/runtime/views/docs/ComponentsTab.tsx +178 -0
- package/src/runtime/views/docs/DocsHeader.tsx +101 -0
- package/src/runtime/views/docs/Intro.tsx +20 -0
- package/src/runtime/views/docs/LayoutsTab.tsx +324 -0
- package/src/runtime/views/docs/ThemeTab.tsx +110 -0
- package/src/runtime/views/index.ts +7 -0
- package/src/runtime/views/overviewGrid.ts +106 -0
- package/src/runtime/views/presenterPreview.ts +27 -0
- package/src/runtime/virtual-modules.d.ts +98 -0
- package/src/theme/SPEC.md +179 -0
- package/src/theme/base.css +623 -0
- package/src/theme/bee.css +35 -0
- package/src/theme/clean.css +38 -0
- package/src/vite-plugin/SPEC.md +114 -0
- package/src/vite-plugin/component-doc-crawler.ts +350 -0
- package/src/vite-plugin/deck-loader.ts +148 -0
- package/src/vite-plugin/index.ts +373 -0
- package/src/vite-plugin/layout-demo-crawler.ts +802 -0
- package/src/vite-plugin/splitter.ts +353 -0
- package/src/vite-plugin/token-manifest.ts +163 -0
- package/src/vite-plugin/virtual-modules.ts +587 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remark plugin: assign `at` props to `<Reveal>` and `<RevealGroup>` elements
|
|
3
|
+
* and count total timeline steps per slide.
|
|
4
|
+
*
|
|
5
|
+
* ### What it does
|
|
6
|
+
* Walks the MDAST (including MDX JSX nodes) in document order and:
|
|
7
|
+
* 1. Assigns `at={n}` to each `<Reveal>` element (starting at 1) and
|
|
8
|
+
* injects `as="div"`/`as="span"` from the MDX flow/text context.
|
|
9
|
+
* 2. Assigns `at={n}` to each `<RevealGroup>` element using the starting
|
|
10
|
+
* index of the group and adds internal per-target step numbers for group
|
|
11
|
+
* children/list items.
|
|
12
|
+
* 3. Assigns `at={n}` to each `<TimelineSteps steps={n}>` element and
|
|
13
|
+
* advances the timeline by its literal static step count.
|
|
14
|
+
* 4. Counts timeline steps from code fence `|`-separated groups after the
|
|
15
|
+
* first baseline group (counted here so `stepCount` is already accurate).
|
|
16
|
+
* 5. Writes the total step count to `vfile.data.stepCount`.
|
|
17
|
+
*
|
|
18
|
+
* ### `at` prop injection
|
|
19
|
+
* Numeric JSX props require an ESTree expression node. We construct a minimal
|
|
20
|
+
* `Program` → `ExpressionStatement` → `Literal` subtree so that `@mdx-js/mdx`
|
|
21
|
+
* generates `at={<number>}` (not `at="<string>"`).
|
|
22
|
+
*
|
|
23
|
+
* ### Existing `at` props
|
|
24
|
+
* If a `<Reveal>` or `<RevealGroup>` already has an explicit `at` prop, this
|
|
25
|
+
* plugin leaves it untouched. Future V2 may expose `<Reveal at={2}>` as a
|
|
26
|
+
* public API for out-of-order reveals. `<Reveal>` still receives a compiler
|
|
27
|
+
* `as` prop when missing, so manually numbered inline reveals remain valid HTML.
|
|
28
|
+
*
|
|
29
|
+
* ### Recursion
|
|
30
|
+
* Nested step producers are flattened into the same slide-local timeline.
|
|
31
|
+
* Parent reveal targets consume their step first, then nested reveals, groups,
|
|
32
|
+
* and code walkthrough steps after the first baseline highlight consume later
|
|
33
|
+
* steps before the next sibling target.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import type { Program } from "estree";
|
|
37
|
+
import type { Code, Root } from "mdast";
|
|
38
|
+
import type {
|
|
39
|
+
MdxJsxAttribute,
|
|
40
|
+
MdxJsxAttributeValueExpression,
|
|
41
|
+
MdxJsxFlowElement,
|
|
42
|
+
MdxJsxTextElement,
|
|
43
|
+
} from "mdast-util-mdx-jsx";
|
|
44
|
+
import type { Plugin } from "unified";
|
|
45
|
+
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Helper: build an `at={n}` attribute node
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
function makeAtAttribute(n: number): MdxJsxAttribute {
|
|
51
|
+
// The ESTree program for the numeric literal `n`.
|
|
52
|
+
const estree: Program = {
|
|
53
|
+
type: "Program",
|
|
54
|
+
sourceType: "module",
|
|
55
|
+
comments: [],
|
|
56
|
+
body: [
|
|
57
|
+
{
|
|
58
|
+
type: "ExpressionStatement",
|
|
59
|
+
expression: {
|
|
60
|
+
type: "Literal",
|
|
61
|
+
value: n,
|
|
62
|
+
raw: String(n),
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const valueExpr: MdxJsxAttributeValueExpression = {
|
|
69
|
+
type: "mdxJsxAttributeValueExpression",
|
|
70
|
+
value: String(n),
|
|
71
|
+
data: { estree },
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
type: "mdxJsxAttribute",
|
|
76
|
+
name: "at",
|
|
77
|
+
value: valueExpr,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function makeStringAttribute(name: string, value: string): MdxJsxAttribute {
|
|
82
|
+
return {
|
|
83
|
+
type: "mdxJsxAttribute",
|
|
84
|
+
name,
|
|
85
|
+
value,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// Helper: check if a node is a JSX element with a given name
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
type MdxJsxElement = MdxJsxFlowElement | MdxJsxTextElement;
|
|
94
|
+
|
|
95
|
+
function isJsxElement(node: unknown): node is MdxJsxElement {
|
|
96
|
+
const n = node as { type?: string };
|
|
97
|
+
return n.type === "mdxJsxFlowElement" || n.type === "mdxJsxTextElement";
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function hasAtProp(el: MdxJsxElement): boolean {
|
|
101
|
+
return el.attributes.some(
|
|
102
|
+
(a) => a.type === "mdxJsxAttribute" && a.name === "at",
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function getAttribute(
|
|
107
|
+
el: MdxJsxElement,
|
|
108
|
+
name: string,
|
|
109
|
+
): MdxJsxAttribute | undefined {
|
|
110
|
+
return el.attributes.find(
|
|
111
|
+
(a): a is MdxJsxAttribute =>
|
|
112
|
+
a.type === "mdxJsxAttribute" && a.name === name,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function injectRevealWrapperElement(el: MdxJsxElement): void {
|
|
117
|
+
if (getAttribute(el, "as")) return;
|
|
118
|
+
|
|
119
|
+
el.attributes.push(
|
|
120
|
+
makeStringAttribute("as", el.type === "mdxJsxTextElement" ? "span" : "div"),
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// Helper: count reveal steps produced by a RevealGroup child
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
|
|
128
|
+
function countListItems(node: unknown): number | null {
|
|
129
|
+
const n = node as { type?: string; children?: unknown[] };
|
|
130
|
+
|
|
131
|
+
if (n.type === "list") {
|
|
132
|
+
return (n.children ?? []).filter((child) => {
|
|
133
|
+
const c = child as { type?: string };
|
|
134
|
+
return c.type === "listItem";
|
|
135
|
+
}).length;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (isJsxElement(node) && (node.name === "ul" || node.name === "ol")) {
|
|
139
|
+
return node.children.filter((child) => {
|
|
140
|
+
const c = child as { type?: string; value?: string };
|
|
141
|
+
if (c.type === "text") {
|
|
142
|
+
return (c.value ?? "").trim().length > 0;
|
|
143
|
+
}
|
|
144
|
+
return true;
|
|
145
|
+
}).length;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function getMeaningfulChildren(children: unknown[]): unknown[] {
|
|
152
|
+
return children.filter((child) => {
|
|
153
|
+
const c = child as { type?: string; value?: string };
|
|
154
|
+
if (c.type === "text") {
|
|
155
|
+
return (c.value ?? "").trim().length > 0;
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function getRevealGroupTargets(el: MdxJsxElement): unknown[] {
|
|
162
|
+
const targets: unknown[] = [];
|
|
163
|
+
|
|
164
|
+
for (const child of getMeaningfulChildren(el.children)) {
|
|
165
|
+
const listItemCount = countListItems(child);
|
|
166
|
+
const c = child as { type?: string; children?: unknown[] };
|
|
167
|
+
|
|
168
|
+
if (listItemCount !== null && Array.isArray(c.children)) {
|
|
169
|
+
if (c.type === "list") {
|
|
170
|
+
targets.push(
|
|
171
|
+
...c.children.filter((item) => {
|
|
172
|
+
const i = item as { type?: string };
|
|
173
|
+
return i.type === "listItem";
|
|
174
|
+
}),
|
|
175
|
+
);
|
|
176
|
+
} else {
|
|
177
|
+
targets.push(...getMeaningfulChildren(c.children));
|
|
178
|
+
}
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
targets.push(child);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return targets;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
// Helper: count groups/steps encoded in a code fence meta string
|
|
190
|
+
//
|
|
191
|
+
// Pattern: `{2|4-5|all}` → 3 groups, 2 timeline steps.
|
|
192
|
+
// The first group is the baseline active highlight. Each later group consumes
|
|
193
|
+
// one timeline step.
|
|
194
|
+
// ---------------------------------------------------------------------------
|
|
195
|
+
|
|
196
|
+
function countCodeFenceGroups(meta: string | null | undefined): number {
|
|
197
|
+
if (!meta) return 0;
|
|
198
|
+
const match = meta.match(/\{([^}]+)\}/);
|
|
199
|
+
if (!match?.[1]) return 0;
|
|
200
|
+
return match[1].split("|").filter(Boolean).length;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function countCodeFenceSteps(meta: string | null | undefined): number {
|
|
204
|
+
return Math.max(0, countCodeFenceGroups(meta) - 1);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function expressionValue(attr: MdxJsxAttribute): unknown {
|
|
208
|
+
const value = attr.value;
|
|
209
|
+
if (
|
|
210
|
+
!value ||
|
|
211
|
+
typeof value === "string" ||
|
|
212
|
+
value.type !== "mdxJsxAttributeValueExpression"
|
|
213
|
+
) {
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const body = value.data?.estree?.body;
|
|
218
|
+
const statement = body?.[0];
|
|
219
|
+
if (statement?.type !== "ExpressionStatement") return undefined;
|
|
220
|
+
|
|
221
|
+
const expression = statement.expression;
|
|
222
|
+
if (expression.type !== "Literal") return undefined;
|
|
223
|
+
return expression.value;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function parsePositiveIntegerLiteral(attr: MdxJsxAttribute): number | null {
|
|
227
|
+
if (typeof attr.value === "string") {
|
|
228
|
+
if (!/^[1-9]\d*$/.test(attr.value)) return null;
|
|
229
|
+
return Number(attr.value);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const value = expressionValue(attr);
|
|
233
|
+
if (typeof value === "number" && Number.isInteger(value) && value > 0) {
|
|
234
|
+
return value;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (typeof value === "string" && /^[1-9]\d*$/.test(value)) {
|
|
238
|
+
return Number(value);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function readTimelineSteps(el: MdxJsxElement): number {
|
|
245
|
+
const attr = getAttribute(el, "steps");
|
|
246
|
+
if (!attr || attr.value === null) {
|
|
247
|
+
throw new Error(
|
|
248
|
+
"Honeydeck <TimelineSteps> requires a literal positive integer `steps` prop.",
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const steps = parsePositiveIntegerLiteral(attr);
|
|
253
|
+
if (steps === null) {
|
|
254
|
+
throw new Error(
|
|
255
|
+
"Honeydeck <TimelineSteps> `steps` must be a literal positive integer, for example steps={3}. Dynamic expressions are not supported because timeline steps are counted at build time.",
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return steps;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function findNestedStepProducer(node: unknown): string | null {
|
|
263
|
+
const n = node as { type?: string; children?: unknown[] };
|
|
264
|
+
|
|
265
|
+
if (n.type === "code") {
|
|
266
|
+
const codeNode = node as Code;
|
|
267
|
+
return countCodeFenceSteps(codeNode.meta) > 0 ? "stepped code fence" : null;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (isJsxElement(node)) {
|
|
271
|
+
if (
|
|
272
|
+
node.name === "Reveal" ||
|
|
273
|
+
node.name === "RevealGroup" ||
|
|
274
|
+
node.name === "TimelineSteps"
|
|
275
|
+
) {
|
|
276
|
+
return `<${node.name}>`;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (!Array.isArray(n.children)) return null;
|
|
281
|
+
|
|
282
|
+
for (const child of n.children) {
|
|
283
|
+
const producer = findNestedStepProducer(child);
|
|
284
|
+
if (producer) return producer;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ---------------------------------------------------------------------------
|
|
291
|
+
// Plugin
|
|
292
|
+
// ---------------------------------------------------------------------------
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Remark plugin that numbers `<Reveal>` and `<RevealGroup>` elements with
|
|
296
|
+
* sequential `at` props and stores the total step count in `vfile.data`.
|
|
297
|
+
*
|
|
298
|
+
* Usage (in Vite plugin config):
|
|
299
|
+
* ```ts
|
|
300
|
+
* mdx({ remarkPlugins: [remarkFrontmatter, remarkStepNumbering] })
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
303
|
+
export const remarkStepNumbering: Plugin<[], Root> = () => (tree, vfile) => {
|
|
304
|
+
let counter = 1; // next `at` value to assign; 1-based
|
|
305
|
+
|
|
306
|
+
function visitChildren(node: unknown): void {
|
|
307
|
+
const n = node as { children?: unknown[] };
|
|
308
|
+
if (!Array.isArray(n.children)) return;
|
|
309
|
+
|
|
310
|
+
for (const child of n.children) {
|
|
311
|
+
visitNode(child);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function visitNode(node: unknown): void {
|
|
316
|
+
const n = node as { type?: string };
|
|
317
|
+
|
|
318
|
+
// ── Code blocks with step-through meta ─────────────────────────────
|
|
319
|
+
if (n.type === "code") {
|
|
320
|
+
const codeNode = node as Code;
|
|
321
|
+
const groupCount = countCodeFenceGroups(codeNode.meta);
|
|
322
|
+
const steps = Math.max(0, groupCount - 1);
|
|
323
|
+
if (groupCount > 0) {
|
|
324
|
+
// Annotate the code node with the first timeline step that advances
|
|
325
|
+
// beyond the baseline group so that remarkShikiCodeBlocks (which runs
|
|
326
|
+
// after us) can embed it in the <HoneydeckCodeBlock startAt={N}> prop
|
|
327
|
+
// without needing its own counter.
|
|
328
|
+
if (!(codeNode as unknown as Record<string, unknown>).data) {
|
|
329
|
+
(codeNode as unknown as Record<string, unknown>).data = {};
|
|
330
|
+
}
|
|
331
|
+
(
|
|
332
|
+
(codeNode as unknown as Record<string, unknown>).data as Record<
|
|
333
|
+
string,
|
|
334
|
+
unknown
|
|
335
|
+
>
|
|
336
|
+
).honeydeckStartAt = counter;
|
|
337
|
+
}
|
|
338
|
+
counter += steps;
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ── MDX JSX elements ─────────────────────────────────────────────────
|
|
343
|
+
if (isJsxElement(node)) {
|
|
344
|
+
const el = node as unknown as MdxJsxElement;
|
|
345
|
+
|
|
346
|
+
if (el.name === "TimelineSteps") {
|
|
347
|
+
const steps = readTimelineSteps(el);
|
|
348
|
+
const nestedProducer = findNestedStepProducer({
|
|
349
|
+
type: "honeydeckTimelineStepsChildren",
|
|
350
|
+
children: el.children,
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
if (nestedProducer) {
|
|
354
|
+
throw new Error(
|
|
355
|
+
`Honeydeck <TimelineSteps> cannot contain nested timeline producers (${nestedProducer}). Register custom component steps with the outer <TimelineSteps> and use useTimelineSteps() inside the custom component instead.`,
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (!hasAtProp(el)) {
|
|
360
|
+
el.attributes.push(makeAtAttribute(counter));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
counter += steps;
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (el.name === "Reveal") {
|
|
368
|
+
injectRevealWrapperElement(el);
|
|
369
|
+
|
|
370
|
+
if (!hasAtProp(el)) {
|
|
371
|
+
el.attributes.push(makeAtAttribute(counter));
|
|
372
|
+
counter++;
|
|
373
|
+
visitChildren(el);
|
|
374
|
+
}
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (el.name === "RevealGroup") {
|
|
379
|
+
if (hasAtProp(el)) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const targets = getRevealGroupTargets(el);
|
|
384
|
+
const targetSteps: number[] = [];
|
|
385
|
+
|
|
386
|
+
el.attributes.push(makeAtAttribute(counter));
|
|
387
|
+
if (targets.length === 0) {
|
|
388
|
+
counter++;
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
for (const target of targets) {
|
|
393
|
+
targetSteps.push(counter);
|
|
394
|
+
counter++;
|
|
395
|
+
visitNode(target);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
el.attributes.push(
|
|
399
|
+
makeStringAttribute("targetStepsJson", JSON.stringify(targetSteps)),
|
|
400
|
+
);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
visitChildren(node);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
visitChildren(tree);
|
|
409
|
+
|
|
410
|
+
// Store total step count on the vfile for the virtual modules plugin to read.
|
|
411
|
+
vfile.data.stepCount = counter - 1; // counter started at 1
|
|
412
|
+
};
|