@reslide-dev/mdx 0.0.1 → 0.1.1
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/dist/index.d.mts +61 -3273
- package/dist/index.mjs +129 -80
- package/package.json +23 -22
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import remarkFrontmatter from "remark-frontmatter";
|
|
2
1
|
import { visit } from "unist-util-visit";
|
|
3
2
|
import { compile } from "@mdx-js/mdx";
|
|
3
|
+
import rehypeShiki from "@shikijs/rehype";
|
|
4
|
+
import { transformerNotationHighlight } from "@shikijs/transformers";
|
|
5
|
+
import rehypeKatex from "rehype-katex";
|
|
4
6
|
import remarkDirective from "remark-directive";
|
|
7
|
+
import remarkFrontmatter from "remark-frontmatter";
|
|
8
|
+
import remarkGfm from "remark-gfm";
|
|
9
|
+
import remarkMath from "remark-math";
|
|
5
10
|
//#region src/remark-slides.ts
|
|
6
11
|
function parseYamlString(value) {
|
|
7
12
|
const options = {};
|
|
@@ -40,11 +45,10 @@ function tryExtractOptionsFromNodes(nodes) {
|
|
|
40
45
|
* Remark plugin that splits MDX content at `---` (thematic breaks)
|
|
41
46
|
* into `<Slide>` components wrapped in a `<Deck>`.
|
|
42
47
|
*
|
|
43
|
-
*
|
|
48
|
+
* Requires remark-frontmatter to be added before this plugin in the pipeline.
|
|
44
49
|
* Subsequent slide frontmatters are detected via setext heading pattern.
|
|
45
50
|
*/
|
|
46
51
|
function remarkSlides() {
|
|
47
|
-
this.use(remarkFrontmatter, ["yaml"]);
|
|
48
52
|
return (tree) => {
|
|
49
53
|
const slides = [];
|
|
50
54
|
let current = [];
|
|
@@ -62,7 +66,6 @@ function remarkSlides() {
|
|
|
62
66
|
const content = slideContent.slice(contentStart);
|
|
63
67
|
if (content.length === 0 && Object.keys(options).length === 0) continue;
|
|
64
68
|
const clickCount = countClickDirectives(content);
|
|
65
|
-
const slideIndex = slideElements.length;
|
|
66
69
|
const attrs = [];
|
|
67
70
|
if (options.layout) attrs.push({
|
|
68
71
|
type: "mdxJsxAttribute",
|
|
@@ -79,14 +82,6 @@ function remarkSlides() {
|
|
|
79
82
|
type: "mdxJsxFlowElement",
|
|
80
83
|
name: "ClickSteps",
|
|
81
84
|
attributes: [{
|
|
82
|
-
type: "mdxJsxAttribute",
|
|
83
|
-
name: "slideIndex",
|
|
84
|
-
value: {
|
|
85
|
-
type: "mdxJsxAttributeValueExpression",
|
|
86
|
-
value: String(slideIndex),
|
|
87
|
-
data: { estree: createNumericExpression(slideIndex) }
|
|
88
|
-
}
|
|
89
|
-
}, {
|
|
90
85
|
type: "mdxJsxAttribute",
|
|
91
86
|
name: "count",
|
|
92
87
|
value: {
|
|
@@ -142,94 +137,127 @@ function createNumericExpression(value) {
|
|
|
142
137
|
* Remark plugin that converts `::click` directives (from remark-directive)
|
|
143
138
|
* into `<Click>` MDX JSX components.
|
|
144
139
|
*
|
|
145
|
-
*
|
|
140
|
+
* For leaf directives (`::click`), all subsequent sibling nodes until the
|
|
141
|
+
* next `::click` or `---` are gathered as children of the `<Click>`.
|
|
142
|
+
*
|
|
143
|
+
* For container directives (`::: click ... :::`), children are wrapped directly.
|
|
144
|
+
*
|
|
146
145
|
* Auto-increments the `at` attribute for sequential click steps.
|
|
147
146
|
*/
|
|
148
147
|
function remarkClick() {
|
|
149
148
|
return (tree) => {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
}]
|
|
173
|
-
} }
|
|
174
|
-
}
|
|
175
|
-
}];
|
|
176
|
-
if (node.type === "leafDirective") {
|
|
177
|
-
const siblings = parent.children;
|
|
178
|
-
const gathered = [];
|
|
179
|
-
let i = index + 1;
|
|
180
|
-
while (i < siblings.length) {
|
|
181
|
-
const sibling = siblings[i];
|
|
182
|
-
if ((sibling.type === "leafDirective" || sibling.type === "containerDirective") && sibling.name === "click") break;
|
|
183
|
-
if (sibling.type === "thematicBreak") break;
|
|
184
|
-
gathered.push(siblings[i]);
|
|
185
|
-
i++;
|
|
186
|
-
}
|
|
187
|
-
if (gathered.length > 0) siblings.splice(index + 1, gathered.length);
|
|
188
|
-
parent.children[index] = {
|
|
189
|
-
type: "mdxJsxFlowElement",
|
|
190
|
-
name: "Click",
|
|
191
|
-
attributes: attrs,
|
|
192
|
-
children: gathered
|
|
193
|
-
};
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
parent.children[index] = {
|
|
149
|
+
processNode(tree);
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function isClickDirective(node) {
|
|
153
|
+
return (node.type === "leafDirective" || node.type === "containerDirective") && "name" in node && node.name === "click";
|
|
154
|
+
}
|
|
155
|
+
function processNode(node) {
|
|
156
|
+
for (const child of node.children) if ("children" in child && Array.isArray(child.children)) processNode(child);
|
|
157
|
+
const newChildren = [];
|
|
158
|
+
let stepCounter = 0;
|
|
159
|
+
let i = 0;
|
|
160
|
+
while (i < node.children.length) {
|
|
161
|
+
const child = node.children[i];
|
|
162
|
+
if (!isClickDirective(child)) {
|
|
163
|
+
newChildren.push(child);
|
|
164
|
+
i++;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
stepCounter++;
|
|
168
|
+
if (child.type === "containerDirective") {
|
|
169
|
+
newChildren.push({
|
|
197
170
|
type: "mdxJsxFlowElement",
|
|
198
171
|
name: "Click",
|
|
199
|
-
attributes:
|
|
200
|
-
children:
|
|
201
|
-
};
|
|
172
|
+
attributes: [createAtAttribute(stepCounter)],
|
|
173
|
+
children: "children" in child ? child.children : []
|
|
174
|
+
});
|
|
175
|
+
i++;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const gathered = [];
|
|
179
|
+
i++;
|
|
180
|
+
while (i < node.children.length) {
|
|
181
|
+
const sibling = node.children[i];
|
|
182
|
+
if (isClickDirective(sibling)) break;
|
|
183
|
+
if (sibling.type === "thematicBreak") break;
|
|
184
|
+
gathered.push(sibling);
|
|
185
|
+
i++;
|
|
186
|
+
}
|
|
187
|
+
newChildren.push({
|
|
188
|
+
type: "mdxJsxFlowElement",
|
|
189
|
+
name: "Click",
|
|
190
|
+
attributes: [createAtAttribute(stepCounter)],
|
|
191
|
+
children: gathered
|
|
202
192
|
});
|
|
193
|
+
}
|
|
194
|
+
node.children = newChildren;
|
|
195
|
+
}
|
|
196
|
+
function createAtAttribute(step) {
|
|
197
|
+
return {
|
|
198
|
+
type: "mdxJsxAttribute",
|
|
199
|
+
name: "at",
|
|
200
|
+
value: {
|
|
201
|
+
type: "mdxJsxAttributeValueExpression",
|
|
202
|
+
value: String(step),
|
|
203
|
+
data: { estree: {
|
|
204
|
+
type: "Program",
|
|
205
|
+
sourceType: "module",
|
|
206
|
+
body: [{
|
|
207
|
+
type: "ExpressionStatement",
|
|
208
|
+
expression: {
|
|
209
|
+
type: "Literal",
|
|
210
|
+
value: step,
|
|
211
|
+
raw: String(step)
|
|
212
|
+
}
|
|
213
|
+
}]
|
|
214
|
+
} }
|
|
215
|
+
}
|
|
203
216
|
};
|
|
204
217
|
}
|
|
205
218
|
//#endregion
|
|
206
219
|
//#region src/remark-mark.ts
|
|
220
|
+
const MARK_TYPES = [
|
|
221
|
+
"highlight",
|
|
222
|
+
"underline",
|
|
223
|
+
"circle"
|
|
224
|
+
];
|
|
207
225
|
/**
|
|
208
|
-
* Remark plugin that converts
|
|
209
|
-
*
|
|
226
|
+
* Remark plugin that converts mark directives into `<Mark>` MDX JSX components.
|
|
227
|
+
*
|
|
228
|
+
* Supports two syntax forms (both avoid `{}` for MDX compatibility):
|
|
210
229
|
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
230
|
+
* 1. Type-based directives — the directive name IS the mark type:
|
|
231
|
+
* `:highlight[text]` → `<Mark type="highlight">text</Mark>`
|
|
232
|
+
* `:underline[text]` → `<Mark type="underline">text</Mark>`
|
|
233
|
+
* `:circle[text]` → `<Mark type="circle">text</Mark>`
|
|
213
234
|
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
235
|
+
* 2. Type + color via hyphen:
|
|
236
|
+
* `:highlight-yellow[text]` → `<Mark type="highlight" color="yellow">`
|
|
237
|
+
* `:underline-blue[text]` → `<Mark type="underline" color="blue">`
|
|
238
|
+
* `:circle-red[text]` → `<Mark type="circle" color="red">`
|
|
239
|
+
*
|
|
240
|
+
* 3. Legacy `:mark[text]{.type.color}` syntax (works in non-MDX contexts):
|
|
241
|
+
* `:mark[important]{.highlight.orange}` → `<Mark type="highlight" color="orange">`
|
|
216
242
|
*/
|
|
217
243
|
function remarkMark() {
|
|
218
244
|
return (tree) => {
|
|
219
245
|
visit(tree, (node, index, parent) => {
|
|
220
246
|
if (node.type !== "textDirective") return;
|
|
221
|
-
if (node.name !== "mark") return;
|
|
222
247
|
if (index == null || !parent) return;
|
|
223
|
-
|
|
224
|
-
const markTypes = [
|
|
225
|
-
"highlight",
|
|
226
|
-
"underline",
|
|
227
|
-
"circle"
|
|
228
|
-
];
|
|
229
|
-
let type = "highlight";
|
|
248
|
+
let type;
|
|
230
249
|
let color;
|
|
231
|
-
|
|
232
|
-
|
|
250
|
+
if (node.name === "mark") {
|
|
251
|
+
const classes = (node.attributes?.class ?? "").split(/\s+/).filter(Boolean);
|
|
252
|
+
for (const cls of classes) if (MARK_TYPES.includes(cls)) type = cls;
|
|
253
|
+
else if (cls) color = cls;
|
|
254
|
+
type ??= "highlight";
|
|
255
|
+
} else {
|
|
256
|
+
const parsed = parseDirectiveName(node.name);
|
|
257
|
+
if (!parsed) return;
|
|
258
|
+
type = parsed.type;
|
|
259
|
+
color = parsed.color;
|
|
260
|
+
}
|
|
233
261
|
const attrs = [{
|
|
234
262
|
type: "mdxJsxAttribute",
|
|
235
263
|
name: "type",
|
|
@@ -249,6 +277,17 @@ function remarkMark() {
|
|
|
249
277
|
});
|
|
250
278
|
};
|
|
251
279
|
}
|
|
280
|
+
function parseDirectiveName(name) {
|
|
281
|
+
if (MARK_TYPES.includes(name)) return { type: name };
|
|
282
|
+
for (const markType of MARK_TYPES) if (name.startsWith(markType + "-")) {
|
|
283
|
+
const color = name.slice(markType.length + 1);
|
|
284
|
+
if (color) return {
|
|
285
|
+
type: markType,
|
|
286
|
+
color
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
252
291
|
//#endregion
|
|
253
292
|
//#region src/compile.ts
|
|
254
293
|
/**
|
|
@@ -279,12 +318,22 @@ async function compileMdxSlides(source, options) {
|
|
|
279
318
|
outputFormat: "function-body",
|
|
280
319
|
remarkPlugins: [
|
|
281
320
|
remarkDirective,
|
|
321
|
+
remarkGfm,
|
|
322
|
+
[remarkFrontmatter, ["yaml"]],
|
|
323
|
+
remarkMath,
|
|
282
324
|
remarkSlides,
|
|
283
325
|
remarkClick,
|
|
284
326
|
remarkMark,
|
|
285
327
|
...options?.remarkPlugins ?? []
|
|
286
328
|
],
|
|
287
|
-
rehypePlugins:
|
|
329
|
+
rehypePlugins: [
|
|
330
|
+
rehypeKatex,
|
|
331
|
+
[rehypeShiki, {
|
|
332
|
+
theme: "github-dark",
|
|
333
|
+
transformers: [transformerNotationHighlight()]
|
|
334
|
+
}],
|
|
335
|
+
...options?.rehypePlugins ?? []
|
|
336
|
+
],
|
|
288
337
|
providerImportSource: void 0
|
|
289
338
|
});
|
|
290
339
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reslide-dev/mdx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Remark/rehype plugins for reslide MDX preprocessing",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -11,39 +11,40 @@
|
|
|
11
11
|
".": "./dist/index.mjs",
|
|
12
12
|
"./package.json": "./package.json"
|
|
13
13
|
},
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"dev": "vp pack --watch",
|
|
17
|
-
"test": "vp test"
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
18
16
|
},
|
|
19
17
|
"dependencies": {
|
|
20
18
|
"@mdx-js/mdx": "^3.1.1",
|
|
19
|
+
"@shikijs/rehype": "4.0.2",
|
|
20
|
+
"@shikijs/transformers": "4.0.2",
|
|
21
|
+
"rehype-katex": "^7.0.1",
|
|
21
22
|
"remark-frontmatter": "^5.0.0",
|
|
23
|
+
"remark-gfm": "4.0.1",
|
|
24
|
+
"remark-math": "^6.0.0",
|
|
22
25
|
"unist-util-visit": "^5.0.0"
|
|
23
26
|
},
|
|
24
27
|
"devDependencies": {
|
|
25
|
-
"@types/mdast": "
|
|
26
|
-
"@types/unist": "
|
|
28
|
+
"@types/mdast": "^4.0.4",
|
|
29
|
+
"@types/unist": "^3.0.3",
|
|
27
30
|
"remark": "^15.0.0",
|
|
28
|
-
"remark-directive": "
|
|
29
|
-
"remark-frontmatter": "
|
|
31
|
+
"remark-directive": "4.0.0",
|
|
32
|
+
"remark-frontmatter": "^5.0.0",
|
|
30
33
|
"remark-mdx": "^3.1.0",
|
|
31
|
-
"unified": "
|
|
32
|
-
"vite-plus": "
|
|
33
|
-
"vitest": "
|
|
34
|
+
"unified": "^11.0.5",
|
|
35
|
+
"vite-plus": "latest",
|
|
36
|
+
"vitest": "npm:@voidzero-dev/vite-plus-test@latest"
|
|
34
37
|
},
|
|
35
38
|
"peerDependencies": {
|
|
36
|
-
"remark-directive": "^
|
|
37
|
-
},
|
|
38
|
-
"publishConfig": {
|
|
39
|
-
"access": "public"
|
|
39
|
+
"remark-directive": "^4.0.0"
|
|
40
40
|
},
|
|
41
41
|
"inlinedDependencies": {
|
|
42
42
|
"@types/mdast": "4.0.4",
|
|
43
|
-
"@types/unist": "3.0.3"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
"
|
|
43
|
+
"@types/unist": "3.0.3"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "vp pack",
|
|
47
|
+
"dev": "vp pack --watch",
|
|
48
|
+
"test": "vp test"
|
|
48
49
|
}
|
|
49
|
-
}
|
|
50
|
+
}
|