@thanh01.pmt/presentation-kit 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.
@@ -0,0 +1,1231 @@
1
+ import { Marp } from '@marp-team/marp-core';
2
+
3
+ // src/core/arrow-converter.ts
4
+ function convertTextArrows(text) {
5
+ if (!text) return "";
6
+ let content = text;
7
+ let yamlFrontmatter = "";
8
+ const yamlMatch = content.match(/^(---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$))/);
9
+ if (yamlMatch?.[1]) {
10
+ yamlFrontmatter = yamlMatch[1];
11
+ content = content.slice(yamlFrontmatter.length);
12
+ }
13
+ const segments = content.split(/(```[\s\S]*?```|`[^`\n]+`|<!--[\s\S]*?-->|<style[\s\S]*?<\/style>)/g);
14
+ const processedContent = segments.map((segment) => {
15
+ if (segment.startsWith("```") || segment.startsWith("`") || segment.startsWith("<!--") || segment.startsWith("<style")) {
16
+ return segment;
17
+ }
18
+ return segment.replace(/<={3,}>/g, "\u27FA").replace(/<==>/g, "\u27FA").replace(/<=>/g, "\u21D4").replace(/<-{3,}>/g, "\u27F7").replace(/<-->/g, "\u27F7").replace(/<->/g, "\u2194").replace(/={3,}>/g, "\u27F9").replace(/==>/g, "\u27F9").replace(/(^|\s)=>(?=\s|$|[.,:;!?\)])/g, "$1\u21D2").replace(/<={3,}/g, "\u27F8").replace(/<==/g, "\u27F8").replace(/(^|\s)<=(?=\s|$|[.,:;!?\)])/g, "$1\u21D0").replace(/-{3,}>/g, "\u27F6").replace(/-->/g, "\u27F6").replace(/(^|\s)->(?=\s|$|[.,:;!?\)])/g, "$1\u2192").replace(/<-{3,}/g, "\u27F5").replace(/<--/g, "\u27F5").replace(/(^|\s)<-(?=\s|$|[.,:;!?\)])/g, "$1\u2190").replace(/\$\\rightarrow\$/g, "\u2192").replace(/\$\\leftarrow\$/g, "\u2190").replace(/\$\\Rightarrow\$/g, "\u21D2").replace(/\$\\Leftarrow\$/g, "\u21D0").replace(/\\rightarrow/g, "\u2192").replace(/\\leftarrow/g, "\u2190").replace(/\\Rightarrow/g, "\u21D2").replace(/\\Leftarrow/g, "\u21D0");
19
+ }).join("");
20
+ return yamlFrontmatter + processedContent;
21
+ }
22
+
23
+ // src/core/source-extractor.ts
24
+ function extractMarpSource(raw) {
25
+ if (!raw) return "";
26
+ let text = raw.trim();
27
+ const codeBlockMatch = text.match(/^```(?:markdown|marp|md)?\s*\n([\s\S]*?)\n```\s*$/i);
28
+ if (codeBlockMatch?.[1]) {
29
+ text = codeBlockMatch[1].trim();
30
+ }
31
+ const firstFrontmatter = text.search(/^---\s*$/m);
32
+ if (firstFrontmatter > 0 && text.includes("marp: true")) {
33
+ text = text.substring(firstFrontmatter).trim();
34
+ }
35
+ return text;
36
+ }
37
+
38
+ // src/themes/dark.ts
39
+ var darkThemeTokens = {
40
+ // Surfaces
41
+ background: "#14151b",
42
+ cardBorder: "1px solid rgba(255, 255, 255, 0.08)",
43
+ cardShadow: "0 8px 24px -4px rgba(0, 0, 0, 0.4)",
44
+ // Typography — Calm single-hue readability (Zinc-200)
45
+ text: "#cbd5e1",
46
+ heading: "#e4e4e7",
47
+ bold: "#ffffff",
48
+ link: "#60a5fa",
49
+ meta: "#94a3b8",
50
+ // Code
51
+ codeBg: "#0c0c0e",
52
+ codeText: "#e4e4e7",
53
+ inlineCodeBg: "#0c0c0e",
54
+ inlineCodeText: "#e4e4e7",
55
+ codeBorder: "rgba(255, 255, 255, 0.08)",
56
+ // Blockquotes
57
+ quoteBg: "rgba(255, 255, 255, 0.04)",
58
+ quoteBorder: "rgba(255, 255, 255, 0.15)",
59
+ quoteText: "#e4e4e7",
60
+ // Tables
61
+ tableHeaderBg: "rgba(255, 255, 255, 0.04)",
62
+ tableBorder: "rgba(255, 255, 255, 0.08)",
63
+ tableRowHover: "rgba(255, 255, 255, 0.02)",
64
+ tableText: "#cbd5e1",
65
+ tableEvenRow: "rgba(255, 255, 255, 0.03)",
66
+ // Mermaid
67
+ mermaidDark: true,
68
+ mermaidVariables: {
69
+ darkMode: "true",
70
+ background: "#18181b",
71
+ primaryColor: "#27272a",
72
+ primaryTextColor: "#f4f4f5",
73
+ primaryBorderColor: "rgba(255, 255, 255, 0.2)",
74
+ lineColor: "#71717a",
75
+ secondaryColor: "#1e1e24",
76
+ tertiaryColor: "#121214",
77
+ textColor: "#f4f4f5",
78
+ mainBkg: "#1f1f23",
79
+ nodeBorder: "rgba(255, 255, 255, 0.22)",
80
+ clusterBkg: "rgba(255, 255, 255, 0.02)",
81
+ clusterBorder: "rgba(255, 255, 255, 0.12)",
82
+ titleColor: "#f4f4f5",
83
+ edgeLabelBackground: "#27272a",
84
+ actorBorder: "rgba(255, 255, 255, 0.2)",
85
+ actorBkg: "#27272a",
86
+ actorTextColor: "#f4f4f5",
87
+ actorLineColor: "#71717a",
88
+ signalColor: "#f4f4f5",
89
+ signalTextColor: "#f4f4f5"
90
+ },
91
+ mermaidThemeCSS: `
92
+ svg, svg *, g, text, tspan, .node, .node *, .edgeLabel, .edgeLabel *, .cluster, .cluster * {
93
+ clip-path: none !important;
94
+ -webkit-clip-path: none !important;
95
+ overflow: visible !important;
96
+ }
97
+ .node rect, .node circle, .node ellipse, .node polygon, .node path {
98
+ stroke-width: 1.5px !important;
99
+ rx: 8px !important;
100
+ ry: 8px !important;
101
+ }
102
+ .node text {
103
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
104
+ font-size: 13px !important;
105
+ font-weight: 500 !important;
106
+ text-anchor: middle !important;
107
+ dominant-baseline: central !important;
108
+ }
109
+ .edgeLabel rect {
110
+ rx: 5px !important;
111
+ ry: 5px !important;
112
+ fill: #27272a !important;
113
+ stroke: rgba(255, 255, 255, 0.12) !important;
114
+ stroke-width: 1px !important;
115
+ }
116
+ .edgeLabel text {
117
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
118
+ font-size: 11px !important;
119
+ font-weight: 500 !important;
120
+ fill: #e4e4e7 !important;
121
+ text-anchor: middle !important;
122
+ dominant-baseline: central !important;
123
+ }
124
+ .cluster rect {
125
+ rx: 10px !important;
126
+ ry: 10px !important;
127
+ fill: rgba(255, 255, 255, 0.02) !important;
128
+ stroke: rgba(255, 255, 255, 0.12) !important;
129
+ stroke-width: 1.5px !important;
130
+ }
131
+ .cluster text {
132
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
133
+ font-size: 12px !important;
134
+ font-weight: 600 !important;
135
+ fill: #a1a1aa !important;
136
+ }
137
+ .edgePath path {
138
+ stroke: #71717a !important;
139
+ stroke-width: 1.5px !important;
140
+ }
141
+ .arrowheadPath {
142
+ fill: #71717a !important;
143
+ }
144
+ `
145
+ };
146
+
147
+ // src/themes/light.ts
148
+ var lightThemeTokens = {
149
+ // Surfaces
150
+ background: "#ffffff",
151
+ cardBorder: "1px solid rgba(0, 0, 0, 0.08)",
152
+ cardShadow: "0 4px 16px -2px rgba(0, 0, 0, 0.05), 0 1px 2px rgba(0, 0, 0, 0.03)",
153
+ // Typography — Calm single-hue readability (Zinc-800)
154
+ text: "#3f3f46",
155
+ heading: "#27272a",
156
+ bold: "#18181b",
157
+ link: "#2563eb",
158
+ meta: "#71717a",
159
+ // Code
160
+ codeBg: "#f4f4f5",
161
+ codeText: "#27272a",
162
+ inlineCodeBg: "#f4f4f5",
163
+ inlineCodeText: "#27272a",
164
+ codeBorder: "rgba(0, 0, 0, 0.08)",
165
+ // Blockquotes
166
+ quoteBg: "#f8f9fa",
167
+ quoteBorder: "rgba(0, 0, 0, 0.15)",
168
+ quoteText: "#27272a",
169
+ // Tables
170
+ tableHeaderBg: "#f8fafc",
171
+ tableBorder: "#e2e8f0",
172
+ tableRowHover: "rgba(0, 0, 0, 0.02)",
173
+ tableText: "#3f3f46",
174
+ tableEvenRow: "#f8fafc",
175
+ // Mermaid
176
+ mermaidDark: false,
177
+ mermaidVariables: {
178
+ darkMode: "false",
179
+ background: "#ffffff",
180
+ primaryColor: "#f4f4f6",
181
+ primaryTextColor: "#18181b",
182
+ primaryBorderColor: "rgba(0, 0, 0, 0.15)",
183
+ lineColor: "#94a3b8",
184
+ secondaryColor: "#fafafa",
185
+ tertiaryColor: "#f4f4f5",
186
+ textColor: "#18181b",
187
+ mainBkg: "#f8fafc",
188
+ nodeBorder: "rgba(0, 0, 0, 0.15)",
189
+ clusterBkg: "rgba(0, 0, 0, 0.015)",
190
+ clusterBorder: "rgba(0, 0, 0, 0.1)",
191
+ titleColor: "#18181b",
192
+ edgeLabelBackground: "#f1f5f9",
193
+ actorBorder: "rgba(0, 0, 0, 0.2)",
194
+ actorBkg: "#f4f4f6",
195
+ actorTextColor: "#18181b",
196
+ actorLineColor: "#94a3b8",
197
+ signalColor: "#18181b",
198
+ signalTextColor: "#18181b"
199
+ },
200
+ mermaidThemeCSS: `
201
+ svg, svg *, g, text, tspan, .node, .node *, .edgeLabel, .edgeLabel *, .cluster, .cluster * {
202
+ clip-path: none !important;
203
+ -webkit-clip-path: none !important;
204
+ overflow: visible !important;
205
+ }
206
+ .node rect, .node circle, .node ellipse, .node polygon, .node path {
207
+ stroke-width: 1.5px !important;
208
+ rx: 8px !important;
209
+ ry: 8px !important;
210
+ }
211
+ .node text {
212
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
213
+ font-size: 13px !important;
214
+ font-weight: 500 !important;
215
+ text-anchor: middle !important;
216
+ dominant-baseline: central !important;
217
+ }
218
+ .edgeLabel rect {
219
+ rx: 5px !important;
220
+ ry: 5px !important;
221
+ fill: #f1f5f9 !important;
222
+ stroke: rgba(0, 0, 0, 0.12) !important;
223
+ stroke-width: 1px !important;
224
+ }
225
+ .edgeLabel text {
226
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
227
+ font-size: 11px !important;
228
+ font-weight: 500 !important;
229
+ fill: #334155 !important;
230
+ text-anchor: middle !important;
231
+ dominant-baseline: central !important;
232
+ }
233
+ .cluster rect {
234
+ rx: 10px !important;
235
+ ry: 10px !important;
236
+ fill: rgba(0, 0, 0, 0.015) !important;
237
+ stroke: rgba(0, 0, 0, 0.12) !important;
238
+ stroke-width: 1.5px !important;
239
+ }
240
+ .cluster text {
241
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
242
+ font-size: 12px !important;
243
+ font-weight: 600 !important;
244
+ fill: #64748b !important;
245
+ }
246
+ .edgePath path {
247
+ stroke: #94a3b8 !important;
248
+ stroke-width: 1.5px !important;
249
+ }
250
+ .arrowheadPath {
251
+ fill: #94a3b8 !important;
252
+ }
253
+ `
254
+ };
255
+
256
+ // src/themes/navy.ts
257
+ var navyThemeTokens = {
258
+ // Surfaces
259
+ background: "#0f172a",
260
+ cardBorder: "1px solid rgba(255, 255, 255, 0.08)",
261
+ cardShadow: "0 8px 24px -4px rgba(0, 0, 0, 0.4)",
262
+ // Typography — Calm single-hue readability (Zinc-200)
263
+ text: "#94a3b8",
264
+ heading: "#f8fafc",
265
+ bold: "#ffffff",
266
+ link: "#38bdf8",
267
+ meta: "#94a3b8",
268
+ // Code
269
+ codeBg: "#020617",
270
+ codeText: "#e4e4e7",
271
+ inlineCodeBg: "#020617",
272
+ inlineCodeText: "#e4e4e7",
273
+ codeBorder: "rgba(255, 255, 255, 0.08)",
274
+ // Blockquotes — Navy uses sky tint
275
+ quoteBg: "rgba(56, 189, 248, 0.06)",
276
+ quoteBorder: "rgba(255, 255, 255, 0.15)",
277
+ quoteText: "#e4e4e7",
278
+ // Tables
279
+ tableHeaderBg: "rgba(255, 255, 255, 0.04)",
280
+ tableBorder: "rgba(255, 255, 255, 0.08)",
281
+ tableRowHover: "rgba(255, 255, 255, 0.02)",
282
+ tableText: "#94a3b8",
283
+ tableEvenRow: "rgba(56, 189, 248, 0.03)",
284
+ // Mermaid — reuse dark config with navy tint
285
+ mermaidDark: true,
286
+ mermaidVariables: {
287
+ darkMode: "true",
288
+ background: "#18181b",
289
+ primaryColor: "#27272a",
290
+ primaryTextColor: "#f4f4f5",
291
+ primaryBorderColor: "rgba(255, 255, 255, 0.2)",
292
+ lineColor: "#71717a",
293
+ secondaryColor: "#1e1e24",
294
+ tertiaryColor: "#121214",
295
+ textColor: "#f4f4f5",
296
+ mainBkg: "#1f1f23",
297
+ nodeBorder: "rgba(255, 255, 255, 0.22)",
298
+ clusterBkg: "rgba(255, 255, 255, 0.02)",
299
+ clusterBorder: "rgba(255, 255, 255, 0.12)",
300
+ titleColor: "#f4f4f5",
301
+ edgeLabelBackground: "#27272a",
302
+ actorBorder: "rgba(255, 255, 255, 0.2)",
303
+ actorBkg: "#27272a",
304
+ actorTextColor: "#f4f4f5",
305
+ actorLineColor: "#71717a",
306
+ signalColor: "#f4f4f5",
307
+ signalTextColor: "#f4f4f5"
308
+ },
309
+ mermaidThemeCSS: `
310
+ svg, svg *, g, text, tspan, .node, .node *, .edgeLabel, .edgeLabel *, .cluster, .cluster * {
311
+ clip-path: none !important;
312
+ -webkit-clip-path: none !important;
313
+ overflow: visible !important;
314
+ }
315
+ .node rect, .node circle, .node ellipse, .node polygon, .node path {
316
+ stroke-width: 1.5px !important;
317
+ rx: 8px !important;
318
+ ry: 8px !important;
319
+ }
320
+ .node text {
321
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
322
+ font-size: 13px !important;
323
+ font-weight: 500 !important;
324
+ text-anchor: middle !important;
325
+ dominant-baseline: central !important;
326
+ }
327
+ .edgeLabel rect {
328
+ rx: 5px !important;
329
+ ry: 5px !important;
330
+ fill: #27272a !important;
331
+ stroke: rgba(255, 255, 255, 0.12) !important;
332
+ stroke-width: 1px !important;
333
+ }
334
+ .edgeLabel text {
335
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
336
+ font-size: 11px !important;
337
+ font-weight: 500 !important;
338
+ fill: #e4e4e7 !important;
339
+ text-anchor: middle !important;
340
+ dominant-baseline: central !important;
341
+ }
342
+ .cluster rect {
343
+ rx: 10px !important;
344
+ ry: 10px !important;
345
+ fill: rgba(255, 255, 255, 0.02) !important;
346
+ stroke: rgba(255, 255, 255, 0.12) !important;
347
+ stroke-width: 1.5px !important;
348
+ }
349
+ .cluster text {
350
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
351
+ font-size: 12px !important;
352
+ font-weight: 600 !important;
353
+ fill: #a1a1aa !important;
354
+ }
355
+ .edgePath path {
356
+ stroke: #71717a !important;
357
+ stroke-width: 1.5px !important;
358
+ }
359
+ .arrowheadPath {
360
+ fill: #71717a !important;
361
+ }
362
+ `
363
+ };
364
+
365
+ // src/themes/scoped-css.ts
366
+ function sanitizeCssId(id) {
367
+ if (typeof CSS !== "undefined" && typeof CSS.escape === "function") {
368
+ return CSS.escape(id);
369
+ }
370
+ return id.replace(/(["'\\()\[\]#.;,{}\s!@#$%^&*=+|<>?/~`])/g, "\\$1");
371
+ }
372
+ function generateScopedCss(tokens, containerId = "marp-container") {
373
+ const safeId = sanitizeCssId(containerId);
374
+ return `
375
+ /* \u2500\u2500 Isolation: Scope all styles to #${safeId} \u2500\u2500 */
376
+ #${safeId} {
377
+ width: 100%;
378
+ }
379
+
380
+ /* Base Slide Card Styling (Thin hairline border) */
381
+ #${safeId} svg[data-marpit-svg] {
382
+ background-color: ${tokens.background} !important;
383
+ border-radius: 12px !important;
384
+ border: ${tokens.cardBorder} !important;
385
+ box-shadow: ${tokens.cardShadow} !important;
386
+ overflow: hidden !important;
387
+ transition: border-color 0.15s ease;
388
+ }
389
+
390
+ /* Slide Inner Section (1280x720 Canvas Coordinate Scale) */
391
+ #${safeId} section,
392
+ #${safeId} foreignObject > section {
393
+ background-color: ${tokens.background} !important;
394
+ color: ${tokens.text} !important;
395
+ font-family: var(--font-sans), Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
396
+ padding: 50px 60px !important;
397
+ box-sizing: border-box !important;
398
+ display: flex !important;
399
+ flex-direction: column !important;
400
+ justify-content: center !important;
401
+ }
402
+
403
+ /* Force inline display for emojis, twemojis, and inline text emojis */
404
+ #${safeId} section img.emoji,
405
+ #${safeId} section img[data-marp-twemoji],
406
+ #${safeId} section .emoji {
407
+ display: inline-block !important;
408
+ vertical-align: -0.15em !important;
409
+ height: 1.15em !important;
410
+ width: 1.15em !important;
411
+ margin: 0 0.15em !important;
412
+ }
413
+
414
+ /* Mermaid Diagram styling inside Marp Canvas */
415
+ #${safeId} section .marp-mermaid-rendered {
416
+ width: 100% !important;
417
+ display: flex !important;
418
+ justify-content: center !important;
419
+ align-items: center !important;
420
+ margin: 16px 0 !important;
421
+ }
422
+
423
+ #${safeId} section .marp-mermaid-rendered svg {
424
+ display: block !important;
425
+ max-width: 100% !important;
426
+ max-height: 420px !important;
427
+ width: auto !important;
428
+ height: auto !important;
429
+ }
430
+
431
+ #${safeId} section .marp-mermaid-rendered svg * {
432
+ clip-path: none !important;
433
+ -webkit-clip-path: none !important;
434
+ }
435
+
436
+ #${safeId} section .katex,
437
+ #${safeId} section .katex-html {
438
+ display: inline-block !important;
439
+ vertical-align: baseline !important;
440
+ }
441
+
442
+ #${safeId} section strong,
443
+ #${safeId} section b,
444
+ #${safeId} section em,
445
+ #${safeId} section span {
446
+ display: inline !important;
447
+ }
448
+
449
+ /* \u2500\u2500 Typography Scale for 1280x720 Canvas \u2500\u2500 */
450
+ #${safeId} section h1 {
451
+ font-size: 38px !important;
452
+ font-weight: 700 !important;
453
+ line-height: 1.25 !important;
454
+ color: ${tokens.heading} !important;
455
+ margin: 0 0 18px 0 !important;
456
+ letter-spacing: -0.02em !important;
457
+ font-family: var(--font-sans), Inter, sans-serif !important;
458
+ }
459
+
460
+ #${safeId} section h2 {
461
+ font-size: 28px !important;
462
+ font-weight: 600 !important;
463
+ line-height: 1.3 !important;
464
+ color: ${tokens.heading} !important;
465
+ margin: 0 0 16px 0 !important;
466
+ letter-spacing: -0.01em !important;
467
+ font-family: var(--font-sans), Inter, sans-serif !important;
468
+ }
469
+
470
+ #${safeId} section h3 {
471
+ font-size: 22px !important;
472
+ font-weight: 600 !important;
473
+ line-height: 1.4 !important;
474
+ color: ${tokens.heading} !important;
475
+ margin: 0 0 14px 0 !important;
476
+ font-family: var(--font-sans), Inter, sans-serif !important;
477
+ }
478
+
479
+ #${safeId} section p,
480
+ #${safeId} section li {
481
+ font-size: 18px !important;
482
+ line-height: 1.7 !important;
483
+ color: ${tokens.text} !important;
484
+ margin-top: 0 !important;
485
+ margin-bottom: 12px !important;
486
+ font-family: var(--font-sans), Inter, sans-serif !important;
487
+ }
488
+
489
+ #${safeId} section strong,
490
+ #${safeId} section b {
491
+ color: ${tokens.bold} !important;
492
+ font-weight: 600 !important;
493
+ }
494
+
495
+ #${safeId} section a {
496
+ color: ${tokens.link} !important;
497
+ text-decoration: underline !important;
498
+ text-decoration-thickness: 1px !important;
499
+ text-underline-offset: 2px !important;
500
+ }
501
+
502
+ #${safeId} section a:hover {
503
+ opacity: 0.85 !important;
504
+ }
505
+
506
+ #${safeId} section ul,
507
+ #${safeId} section ol {
508
+ margin: 0 0 16px 28px !important;
509
+ padding: 0 !important;
510
+ }
511
+
512
+ #${safeId} section li {
513
+ margin-bottom: 8px !important;
514
+ }
515
+
516
+ /* Blockquotes / Callout Cards */
517
+ #${safeId} section blockquote {
518
+ background: ${tokens.quoteBg} !important;
519
+ border-left: 3px solid ${tokens.quoteBorder} !important;
520
+ border-radius: 6px !important;
521
+ padding: 16px 24px !important;
522
+ margin: 16px 0 !important;
523
+ color: ${tokens.quoteText} !important;
524
+ }
525
+ #${safeId} section blockquote p {
526
+ color: ${tokens.quoteText} !important;
527
+ font-size: 18px !important;
528
+ margin: 0 !important;
529
+ }
530
+
531
+ /* Code Blocks & Inline Code (Monospace font standard) */
532
+ #${safeId} section code {
533
+ font-family: var(--font-mono), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace !important;
534
+ font-style: normal !important;
535
+ font-size: 15px !important;
536
+ background: ${tokens.inlineCodeBg} !important;
537
+ color: ${tokens.inlineCodeText} !important;
538
+ padding: 2px 8px !important;
539
+ border-radius: 6px !important;
540
+ border: 1px solid ${tokens.codeBorder} !important;
541
+ }
542
+
543
+ #${safeId} section pre {
544
+ background: ${tokens.codeBg} !important;
545
+ border: 1px solid ${tokens.codeBorder} !important;
546
+ border-radius: 8px !important;
547
+ padding: 18px 22px !important;
548
+ margin: 16px 0 !important;
549
+ overflow-x: auto !important;
550
+ }
551
+
552
+ #${safeId} section pre code {
553
+ background: transparent !important;
554
+ border: none !important;
555
+ padding: 0 !important;
556
+ font-family: var(--font-mono), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace !important;
557
+ font-style: normal !important;
558
+ font-size: 15px !important;
559
+ line-height: 1.6 !important;
560
+ color: ${tokens.codeText} !important;
561
+ }
562
+
563
+ /* Tables */
564
+ div#${safeId} svg foreignObject section table,
565
+ #${safeId} section table {
566
+ width: 100% !important;
567
+ border-collapse: collapse !important;
568
+ margin: 16px 0 !important;
569
+ font-size: 17px !important;
570
+ background-color: transparent !important;
571
+ background: transparent !important;
572
+ display: table !important;
573
+ }
574
+
575
+ div#${safeId} svg foreignObject section table tr,
576
+ #${safeId} section table tr {
577
+ background-color: transparent !important;
578
+ background: transparent !important;
579
+ border-top: 1px solid ${tokens.tableBorder} !important;
580
+ }
581
+
582
+ div#${safeId} svg foreignObject section table tbody tr:nth-child(2n),
583
+ #${safeId} section table tbody tr:nth-child(2n) {
584
+ background-color: ${tokens.tableEvenRow ?? tokens.tableHeaderBg} !important;
585
+ }
586
+
587
+ div#${safeId} svg foreignObject section table thead tr,
588
+ #${safeId} section table thead tr {
589
+ background-color: ${tokens.tableHeaderBg} !important;
590
+ }
591
+
592
+ div#${safeId} svg foreignObject section table th,
593
+ #${safeId} section table th {
594
+ background-color: ${tokens.tableHeaderBg} !important;
595
+ color: ${tokens.heading} !important;
596
+ font-weight: 600 !important;
597
+ padding: 10px 16px !important;
598
+ border: 1px solid ${tokens.tableBorder} !important;
599
+ text-align: left !important;
600
+ }
601
+
602
+ div#${safeId} svg foreignObject section table td,
603
+ #${safeId} section table td {
604
+ padding: 10px 16px !important;
605
+ border: 1px solid ${tokens.tableBorder} !important;
606
+ color: ${tokens.tableText} !important;
607
+ background-color: transparent !important;
608
+ }
609
+
610
+ div#${safeId} svg foreignObject section table tr:hover td,
611
+ #${safeId} section table tr:hover td {
612
+ background-color: ${tokens.tableRowHover} !important;
613
+ }
614
+
615
+ /* Header & Footer */
616
+ #${safeId} section header,
617
+ #${safeId} section footer {
618
+ position: absolute !important;
619
+ left: 60px !important;
620
+ right: 60px !important;
621
+ font-size: 14px !important;
622
+ color: ${tokens.meta} !important;
623
+ font-family: var(--font-sans), Inter, sans-serif !important;
624
+ opacity: 0.8 !important;
625
+ }
626
+
627
+ #${safeId} section header {
628
+ top: 24px !important;
629
+ border-bottom: 1px solid ${tokens.tableBorder} !important;
630
+ padding-bottom: 6px !important;
631
+ }
632
+
633
+ #${safeId} section footer {
634
+ bottom: 24px !important;
635
+ border-top: 1px solid ${tokens.tableBorder} !important;
636
+ padding-top: 6px !important;
637
+ }
638
+
639
+ /* Marp Split Layout Container */
640
+ #${safeId} section[data-marpit-advanced-background="background"] {
641
+ display: flex !important;
642
+ flex-direction: row !important;
643
+ padding: 0 !important;
644
+ }
645
+
646
+ #${safeId} section[data-marpit-advanced-background="background"] > .marpit-advanced-background-container {
647
+ flex: 0 0 50% !important;
648
+ height: 100% !important;
649
+ position: relative !important;
650
+ }
651
+
652
+ #${safeId} section[data-marpit-advanced-background="background"] > .marpit-advanced-background-container + * {
653
+ flex: 1 !important;
654
+ padding: 50px 60px !important;
655
+ display: flex !important;
656
+ flex-direction: column !important;
657
+ justify-content: center !important;
658
+ }
659
+
660
+ /* Hide Raw Marp Image Artifacts */
661
+ #${safeId} section img[data-marp-bg] {
662
+ display: none !important;
663
+ }
664
+ `;
665
+ }
666
+
667
+ // src/themes/index.ts
668
+ var builtInThemes = {
669
+ dark: darkThemeTokens,
670
+ light: lightThemeTokens,
671
+ navy: navyThemeTokens
672
+ };
673
+ function getThemeTokens(theme) {
674
+ return builtInThemes[theme];
675
+ }
676
+ function resolveTheme(theme) {
677
+ if (!theme) {
678
+ return { name: "dark", tokens: builtInThemes.dark };
679
+ }
680
+ if (typeof theme === "string") {
681
+ return { name: theme, tokens: builtInThemes[theme] };
682
+ }
683
+ return theme;
684
+ }
685
+ function defineTheme(definition) {
686
+ return {
687
+ name: definition.name,
688
+ tokens: definition.tokens
689
+ };
690
+ }
691
+ function generateScopedCss2(theme, containerId) {
692
+ return generateScopedCss(theme.tokens, containerId);
693
+ }
694
+
695
+ // src/plugins/mermaid.ts
696
+ var mermaidModulePromise = null;
697
+ var mermaidFailed = false;
698
+ function decodeHtmlEntities(html) {
699
+ return html.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&nbsp;/g, " ").replace(/&#(\d+);/g, (_, code) => String.fromCharCode(Number(code))).replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
700
+ }
701
+ function isValidMermaidCode(text) {
702
+ if (!text || text.length > 2500) return false;
703
+ if (text.startsWith("---") || text.includes("marp: true")) return false;
704
+ const hasHeader = /^(?:graph\s+(?:TD|TB|LR|RL|BT)|flowchart\s+(?:TD|TB|LR|RL|BT)|sequenceDiagram|classDiagram|stateDiagram|erDiagram|gantt|pie|gitGraph|mindmap|quadrantChart|journey|timeline|xychart|C4Context)\b/i.test(
705
+ text
706
+ );
707
+ const hasConnections = text.includes("-->") || text.includes("->>") || text.includes("---") || text.includes("[") || text.includes("(");
708
+ return hasHeader && text.includes("\n") && hasConnections;
709
+ }
710
+ function detectMermaidBlocks(html) {
711
+ const blocks = [];
712
+ const regex = /<pre><code class="language-(?:mermaid|diagram|graph)">([\s\S]*?)<\/code><\/pre>/g;
713
+ let match;
714
+ let index = 0;
715
+ while ((match = regex.exec(html)) !== null) {
716
+ const code = decodeHtmlEntities(match[1]);
717
+ if (isValidMermaidCode(code)) {
718
+ blocks.push({
719
+ index: index++,
720
+ code,
721
+ sanitizedCode: sanitizeMermaidCode(code)
722
+ });
723
+ }
724
+ }
725
+ return blocks;
726
+ }
727
+ function sanitizeMermaidCode(chart, isDark = false) {
728
+ let code = (chart || "").trim();
729
+ code = code.replace(/^```(?:mermaid|diagram|graph)?\s*/i, "").replace(/```$/i, "").trim();
730
+ if (code && !/^(graph|flowchart|sequenceDiagram|classDiagram|stateDiagram|erDiagram|gantt|pie|gitGraph|mindmap|journey|quadrantChart|xychart|C4Context|timeline)/i.test(
731
+ code
732
+ )) {
733
+ code = `flowchart TD
734
+ ${code}`;
735
+ }
736
+ code = code.replace(
737
+ /([a-zA-Z0-9_-]+)\[([^\]\n\r"]+)\]/g,
738
+ (match, id, label) => {
739
+ const trimmed = label.trim();
740
+ if (trimmed.startsWith('"') && trimmed.endsWith('"')) return match;
741
+ return `${id}["${trimmed.replace(/"/g, "'")}"]`;
742
+ }
743
+ );
744
+ code = code.replace(
745
+ /([a-zA-Z0-9_-]+)\(([^)\n\r"]+)\)/g,
746
+ (match, id, label) => {
747
+ const trimmed = label.trim();
748
+ if (trimmed.startsWith('"') && trimmed.endsWith('"')) return match;
749
+ return `${id}("${trimmed.replace(/"/g, "'")}")`;
750
+ }
751
+ );
752
+ code = code.replace(
753
+ /^\s*subgraph\s+([A-Za-z0-9_ -]+)\s*$/gm,
754
+ (match, rawName) => {
755
+ const trimmed = rawName.trim();
756
+ if (trimmed.includes("[") || trimmed.includes("]")) return match;
757
+ const cleanId = trimmed.replace(/[^A-Za-z0-9_]/g, "_");
758
+ return ` subgraph ${cleanId} ["${trimmed}"]`;
759
+ }
760
+ );
761
+ return code;
762
+ }
763
+ async function getMermaid() {
764
+ if (mermaidFailed) {
765
+ mermaidModulePromise = null;
766
+ mermaidFailed = false;
767
+ }
768
+ if (!mermaidModulePromise) {
769
+ mermaidModulePromise = import('mermaid').then((mod) => mod.default).catch((err) => {
770
+ mermaidModulePromise = null;
771
+ mermaidFailed = true;
772
+ throw new Error(`[presentation-kit] Failed to load Mermaid: ${err}`);
773
+ });
774
+ }
775
+ return mermaidModulePromise;
776
+ }
777
+ function getMermaidConfig(isDark) {
778
+ const tokens = isDark ? {
779
+ darkMode: true,
780
+ background: "#18181b",
781
+ primaryColor: "#27272a",
782
+ primaryTextColor: "#f4f4f5",
783
+ primaryBorderColor: "rgba(255, 255, 255, 0.2)",
784
+ lineColor: "#71717a",
785
+ secondaryColor: "#1e1e24",
786
+ tertiaryColor: "#121214",
787
+ textColor: "#f4f4f5",
788
+ mainBkg: "#1f1f23",
789
+ nodeBorder: "rgba(255, 255, 255, 0.22)",
790
+ clusterBkg: "rgba(255, 255, 255, 0.02)",
791
+ clusterBorder: "rgba(255, 255, 255, 0.12)",
792
+ titleColor: "#f4f4f5",
793
+ edgeLabelBackground: "#27272a",
794
+ actorBorder: "rgba(255, 255, 255, 0.2)",
795
+ actorBkg: "#27272a",
796
+ actorTextColor: "#f4f4f5",
797
+ actorLineColor: "#71717a",
798
+ signalColor: "#f4f4f5",
799
+ signalTextColor: "#f4f4f5"
800
+ } : {
801
+ darkMode: false,
802
+ background: "#ffffff",
803
+ primaryColor: "#f4f4f6",
804
+ primaryTextColor: "#18181b",
805
+ primaryBorderColor: "rgba(0, 0, 0, 0.15)",
806
+ lineColor: "#94a3b8",
807
+ secondaryColor: "#fafafa",
808
+ tertiaryColor: "#f4f4f5",
809
+ textColor: "#18181b",
810
+ mainBkg: "#f8fafc",
811
+ nodeBorder: "rgba(0, 0, 0, 0.15)",
812
+ clusterBkg: "rgba(0, 0, 0, 0.015)",
813
+ clusterBorder: "rgba(0, 0, 0, 0.1)",
814
+ titleColor: "#18181b",
815
+ edgeLabelBackground: "#f1f5f9",
816
+ actorBorder: "rgba(0, 0, 0, 0.2)",
817
+ actorBkg: "#f4f4f6",
818
+ actorTextColor: "#18181b",
819
+ actorLineColor: "#94a3b8",
820
+ signalColor: "#18181b",
821
+ signalTextColor: "#18181b"
822
+ };
823
+ return {
824
+ startOnLoad: false,
825
+ suppressErrorRendering: true,
826
+ theme: isDark ? "dark" : "neutral",
827
+ securityLevel: "loose",
828
+ fontFamily: 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
829
+ fontSize: 14,
830
+ flowchart: {
831
+ htmlLabels: false,
832
+ useMaxWidth: false,
833
+ padding: 32,
834
+ nodeSpacing: 55,
835
+ rankSpacing: 60,
836
+ curve: "basis"
837
+ },
838
+ themeCSS: `
839
+ svg, svg *, g, text, tspan, .node, .node *, .edgeLabel, .edgeLabel *, .cluster, .cluster * {
840
+ clip-path: none !important;
841
+ -webkit-clip-path: none !important;
842
+ overflow: visible !important;
843
+ }
844
+ .node rect, .node circle, .node ellipse, .node polygon, .node path {
845
+ stroke-width: 1.5px !important;
846
+ rx: 8px !important;
847
+ ry: 8px !important;
848
+ }
849
+ .node text {
850
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
851
+ font-size: 13px !important;
852
+ font-weight: 500 !important;
853
+ text-anchor: middle !important;
854
+ dominant-baseline: central !important;
855
+ }
856
+ .edgeLabel rect {
857
+ rx: 5px !important;
858
+ ry: 5px !important;
859
+ fill: ${isDark ? "#27272a" : "#f1f5f9"} !important;
860
+ stroke: ${isDark ? "rgba(255, 255, 255, 0.12)" : "rgba(0, 0, 0, 0.12)"} !important;
861
+ stroke-width: 1px !important;
862
+ }
863
+ .edgeLabel text {
864
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
865
+ font-size: 11px !important;
866
+ font-weight: 500 !important;
867
+ fill: ${isDark ? "#e4e4e7" : "#334155"} !important;
868
+ text-anchor: middle !important;
869
+ dominant-baseline: central !important;
870
+ }
871
+ .cluster rect {
872
+ rx: 10px !important;
873
+ ry: 10px !important;
874
+ fill: ${isDark ? "rgba(255, 255, 255, 0.02)" : "rgba(0, 0, 0, 0.015)"} !important;
875
+ stroke: ${isDark ? "rgba(255, 255, 255, 0.12)" : "rgba(0, 0, 0, 0.12)"} !important;
876
+ stroke-width: 1.5px !important;
877
+ }
878
+ .cluster text {
879
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
880
+ font-size: 12px !important;
881
+ font-weight: 600 !important;
882
+ fill: ${isDark ? "#a1a1aa" : "#64748b"} !important;
883
+ }
884
+ .edgePath path {
885
+ stroke: ${isDark ? "#71717a" : "#94a3b8"} !important;
886
+ stroke-width: 1.5px !important;
887
+ }
888
+ .arrowheadPath {
889
+ fill: ${isDark ? "#71717a" : "#94a3b8"} !important;
890
+ }
891
+ `,
892
+ themeVariables: tokens
893
+ };
894
+ }
895
+ async function renderMermaidDiagrams(container, theme = "dark") {
896
+ if (typeof document === "undefined" || typeof window === "undefined") {
897
+ console.warn("[presentation-kit] renderMermaidDiagrams skipped: no DOM available (SSR)");
898
+ return;
899
+ }
900
+ const mermaid = await getMermaid();
901
+ const isDark = theme === "dark" || theme === "navy";
902
+ mermaid.initialize(getMermaidConfig(isDark));
903
+ const codeNodes = Array.from(
904
+ container.querySelectorAll("pre > code, pre, .marp-mermaid-rendered")
905
+ );
906
+ const mermaidNodes = codeNodes.filter((node) => {
907
+ if (node.classList.contains("marp-mermaid-rendered")) return true;
908
+ const text = node.textContent?.trim() || "";
909
+ const className = node.className || "";
910
+ if (text.startsWith("---") || text.includes("marp: true") || text.length > 2500) {
911
+ return false;
912
+ }
913
+ return className.includes("language-mermaid") || className.includes("language-diagram") || className.includes("language-graph") || isValidMermaidCode(text);
914
+ });
915
+ if (mermaidNodes.length === 0) return;
916
+ for (let i = 0; i < mermaidNodes.length; i++) {
917
+ const node = mermaidNodes[i];
918
+ const isAlreadyWrapper = node.classList.contains("marp-mermaid-rendered");
919
+ const rawChartCode = isAlreadyWrapper ? node.getAttribute("data-chart-code") || "" : node.textContent?.trim() || "";
920
+ if (!rawChartCode) continue;
921
+ const preEl = isAlreadyWrapper ? node : node.tagName.toLowerCase() === "pre" ? node : node.parentElement;
922
+ if (!preEl) continue;
923
+ const sanitizedCode = sanitizeMermaidCode(rawChartCode, isDark);
924
+ const diagId = `slide_mermaid_${Date.now()}_${i}_${Math.floor(Math.random() * 1e4)}`;
925
+ try {
926
+ let { svg } = await mermaid.render(diagId, sanitizedCode);
927
+ svg = svg.replace(/clip-path="url\(#[^"]+\)"/gi, "").replace(/clip-path="[^"]*"/gi, "").replace(/<clipPath[\s\S]*?<\/clipPath>/gi, "");
928
+ const wrapper = document.createElement("div");
929
+ wrapper.className = "marp-mermaid-rendered my-3 flex items-center justify-center p-3 rounded-xl bg-black/5 dark:bg-white/5 border border-black/10 dark:border-white/10 [&_svg]:max-w-full [&_svg]:h-auto";
930
+ wrapper.setAttribute("data-chart-code", rawChartCode);
931
+ wrapper.setAttribute("data-mermaid-processed", "true");
932
+ wrapper.innerHTML = svg;
933
+ preEl.replaceWith(wrapper);
934
+ } catch (renderErr) {
935
+ console.warn("[presentation-kit] Mermaid render error:", renderErr);
936
+ }
937
+ }
938
+ }
939
+
940
+ // src/plugins/shiki.ts
941
+ var highlighterPromise = null;
942
+ var highlighterFailed = false;
943
+ var SUPPORTED_LANGS = [
944
+ "javascript",
945
+ "typescript",
946
+ "python",
947
+ "cpp",
948
+ "c",
949
+ "java",
950
+ "html",
951
+ "css",
952
+ "json",
953
+ "yaml",
954
+ "bash",
955
+ "shell",
956
+ "sql",
957
+ "go",
958
+ "rust",
959
+ "swift",
960
+ "kotlin",
961
+ "ruby",
962
+ "php",
963
+ "xml",
964
+ "markdown",
965
+ "dockerfile",
966
+ "toml",
967
+ "ini",
968
+ "graphql",
969
+ "prisma",
970
+ "solidity"
971
+ ];
972
+ async function getHighlighter() {
973
+ if (highlighterFailed) {
974
+ highlighterPromise = null;
975
+ highlighterFailed = false;
976
+ }
977
+ if (!highlighterPromise) {
978
+ highlighterPromise = import('shiki').then(
979
+ (mod) => mod.createHighlighter({
980
+ themes: ["vitesse-dark", "vitesse-light"],
981
+ langs: [...SUPPORTED_LANGS]
982
+ })
983
+ ).catch((err) => {
984
+ highlighterPromise = null;
985
+ highlighterFailed = true;
986
+ throw new Error(`[presentation-kit] Failed to load Shiki highlighter: ${err}`);
987
+ });
988
+ }
989
+ return highlighterPromise;
990
+ }
991
+ function decodeHtmlEntities2(html) {
992
+ return html.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&#x27;/g, "'").replace(/&nbsp;/g, " ").replace(/&#(\d+);/g, (_, code) => String.fromCharCode(Number(code))).replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
993
+ }
994
+ function getShikiTheme(theme) {
995
+ if (theme === "light") return "vitesse-light";
996
+ return "vitesse-dark";
997
+ }
998
+ async function highlightCodeBlocks(html, theme = "dark") {
999
+ if (!html.includes("<pre><code")) return html;
1000
+ const highlighter = await getHighlighter();
1001
+ const shikiTheme = getShikiTheme(theme);
1002
+ return html.replace(
1003
+ /<pre><code class="language-(\w+)">([\s\S]*?)<\/code><\/pre>/g,
1004
+ (_, lang, code) => {
1005
+ const decoded = decodeHtmlEntities2(code);
1006
+ try {
1007
+ return highlighter.codeToHtml(decoded, { lang, theme: shikiTheme });
1008
+ } catch {
1009
+ return `<pre><code class="language-${lang}">${code}</code></pre>`;
1010
+ }
1011
+ }
1012
+ );
1013
+ }
1014
+
1015
+ // src/vclick/preprocessor.ts
1016
+ function preprocessClicks(markdown) {
1017
+ if (!markdown || !markdown.trim()) {
1018
+ return { markdown, totalClicks: 0 };
1019
+ }
1020
+ const segments = splitByCodeFences(markdown);
1021
+ let clickIndex = 0;
1022
+ let totalClicks = 0;
1023
+ let inClickBlock = false;
1024
+ const processed = segments.map((segment) => {
1025
+ if (segment.isCodeFence) {
1026
+ return segment.content;
1027
+ }
1028
+ let content = segment.content;
1029
+ content = content.replace(
1030
+ /^<!--\s*(click|clicks)\s*-->$/gm,
1031
+ (match, type) => {
1032
+ clickIndex++;
1033
+ const closePrev = inClickBlock ? "</div>\n" : "";
1034
+ inClickBlock = true;
1035
+ if (type === "clicks") {
1036
+ totalClicks++;
1037
+ return `${closePrev}<div data-clicks="${clickIndex}">`;
1038
+ } else {
1039
+ totalClicks++;
1040
+ return `${closePrev}<div data-click-group="${clickIndex}">`;
1041
+ }
1042
+ }
1043
+ );
1044
+ return content;
1045
+ }).join("");
1046
+ const result = inClickBlock ? processed + "</div>" : processed;
1047
+ return { markdown: result, totalClicks };
1048
+ }
1049
+ function splitByCodeFences(markdown) {
1050
+ const segments = [];
1051
+ const regex = /^(```[\s\S]*?^```)/gm;
1052
+ let lastIndex = 0;
1053
+ let match;
1054
+ while ((match = regex.exec(markdown)) !== null) {
1055
+ if (match.index > lastIndex) {
1056
+ segments.push({
1057
+ content: markdown.slice(lastIndex, match.index),
1058
+ isCodeFence: false
1059
+ });
1060
+ }
1061
+ segments.push({
1062
+ content: match[0],
1063
+ isCodeFence: true
1064
+ });
1065
+ lastIndex = match.index + match[0].length;
1066
+ }
1067
+ if (lastIndex < markdown.length) {
1068
+ segments.push({
1069
+ content: markdown.slice(lastIndex),
1070
+ isCodeFence: false
1071
+ });
1072
+ }
1073
+ return segments;
1074
+ }
1075
+
1076
+ // src/vclick/postprocessor.ts
1077
+ function postprocessClicks(html) {
1078
+ if (!html || !html.includes("data-clicks")) {
1079
+ const totalClicks2 = extractMaxClicks(html);
1080
+ return { html, totalClicks: totalClicks2 };
1081
+ }
1082
+ let result = html;
1083
+ let totalClicks = 0;
1084
+ result = result.replace(
1085
+ /<div data-clicks="(\d+)">([\s\S]*?)<\/div>/g,
1086
+ (_, startIdx, innerContent) => {
1087
+ const start = parseInt(startIdx, 10);
1088
+ const listMatch = innerContent.match(/((?:<[^>]+>)*?<(?:ul|ol)[^>]*>[\s\S]*?<\/(?:ul|ol)>)/);
1089
+ if (!listMatch) {
1090
+ totalClicks++;
1091
+ return `<div data-click-group="${start}">${innerContent}</div>`;
1092
+ }
1093
+ const listBlock = listMatch[0];
1094
+ const liRegex = /<li[^>]*>[\s\S]*?<\/li>/g;
1095
+ const items = [];
1096
+ let liMatch;
1097
+ while ((liMatch = liRegex.exec(listBlock)) !== null) {
1098
+ items.push(liMatch[0]);
1099
+ }
1100
+ if (items.length === 0) {
1101
+ totalClicks++;
1102
+ return `<div data-click-group="${start}">${innerContent}</div>`;
1103
+ }
1104
+ const listOpenTag = listBlock.match(/<(ul|ol)[^>]*>/)?.[0] ?? "<ul>";
1105
+ const listCloseTag = listBlock.match(/<\/(ul|ol)>$/)?.[0] ?? "</ul>";
1106
+ let clickIdx = start;
1107
+ const wrappedItems = items.map((item) => {
1108
+ const idx = clickIdx++;
1109
+ totalClicks++;
1110
+ return `<div data-click-group="${idx}">${listOpenTag}${item}${listCloseTag}</div>`;
1111
+ });
1112
+ return wrappedItems.join("\n");
1113
+ }
1114
+ );
1115
+ const existingGroups = extractMaxClicks(result);
1116
+ if (existingGroups > totalClicks) {
1117
+ totalClicks = existingGroups;
1118
+ }
1119
+ return { html: result, totalClicks };
1120
+ }
1121
+ function extractMaxClicks(html) {
1122
+ const matches = html.match(/data-click-group="(\d+)"/g);
1123
+ if (!matches) return 0;
1124
+ let max = 0;
1125
+ for (const match of matches) {
1126
+ const num = parseInt(match.match(/data-click-group="(\d+)"/)?.[1] ?? "0", 10);
1127
+ if (num > max) max = num;
1128
+ }
1129
+ return max;
1130
+ }
1131
+
1132
+ // src/vclick/click-css.ts
1133
+ function generateClickCss(options) {
1134
+ const {
1135
+ containerId,
1136
+ duration = 300,
1137
+ easing = "ease",
1138
+ offsetY = 8,
1139
+ slideUp = true,
1140
+ fade = true
1141
+ } = options ?? {};
1142
+ const prefix = containerId ? `#${containerId} ` : "";
1143
+ const opacityFrom = fade ? "0" : "1";
1144
+ const transformFrom = slideUp ? `translateY(${offsetY}px)` : "none";
1145
+ const opacityTo = "1";
1146
+ const transformTo = "translateY(0)";
1147
+ return `
1148
+ /* \u2500\u2500 Click-to-Reveal System \u2500\u2500 */
1149
+ ${prefix}[data-click-group] {
1150
+ opacity: ${opacityFrom};
1151
+ ${slideUp ? `transform: ${transformFrom};` : ""}
1152
+ transition: opacity ${duration}ms ${easing}, transform ${duration}ms ${easing};
1153
+ pointer-events: none;
1154
+ }
1155
+
1156
+ ${prefix}[data-click-group].visible {
1157
+ opacity: ${opacityTo};
1158
+ ${slideUp ? `transform: ${transformTo};` : ""}
1159
+ pointer-events: auto;
1160
+ }
1161
+
1162
+ `;
1163
+ }
1164
+ function renderMarp(markdown, containerId = "marp-container", enableClicks = false) {
1165
+ const cleanSource = extractMarpSource(markdown);
1166
+ const { markdown: clickProcessed, totalClicks } = enableClicks ? preprocessClicks(cleanSource) : { markdown: cleanSource, totalClicks: 0 };
1167
+ const arrowsConverted = convertTextArrows(clickProcessed);
1168
+ const marp = new Marp({
1169
+ container: { tag: "div", id: containerId },
1170
+ html: true,
1171
+ emoji: { unicode: true }
1172
+ });
1173
+ const { html, css } = marp.render(arrowsConverted);
1174
+ if (enableClicks && totalClicks > 0) {
1175
+ const { html: processedHtml, totalClicks: finalClicks } = postprocessClicks(html);
1176
+ return { html: processedHtml, css, maxClicks: finalClicks };
1177
+ }
1178
+ return { html, css, maxClicks: 0 };
1179
+ }
1180
+ function countSlides(html) {
1181
+ const matches = html.match(/<svg[^>]*data-marpit-svg/g);
1182
+ return matches ? matches.length : 1;
1183
+ }
1184
+ function renderSlide(markdown, options) {
1185
+ const containerId = options?.containerId ?? "marp-container";
1186
+ const theme = resolveTheme(options?.theme ?? "dark");
1187
+ const enableClicks = options?.enableClicks ?? false;
1188
+ const { html, css, maxClicks } = renderMarp(markdown, containerId, enableClicks);
1189
+ const themeCss = generateScopedCss2(theme, containerId);
1190
+ const slideCount = countSlides(html);
1191
+ const mermaidBlocks = options?.enableMermaid !== false ? detectMermaidBlocks(html) : [];
1192
+ const clickCss = enableClicks ? generateClickCss({ containerId }) : "";
1193
+ return {
1194
+ html,
1195
+ css,
1196
+ themeCss,
1197
+ slideCount,
1198
+ mermaidBlocks,
1199
+ clickCss,
1200
+ maxClicks
1201
+ };
1202
+ }
1203
+ async function renderSlideAsync(markdown, options) {
1204
+ const containerId = options?.containerId ?? "marp-container";
1205
+ const theme = resolveTheme(options?.theme ?? "dark");
1206
+ const enableClicks = options?.enableClicks ?? false;
1207
+ const { html, css, maxClicks } = renderMarp(markdown, containerId, enableClicks);
1208
+ const themeCss = generateScopedCss2(theme, containerId);
1209
+ const slideCount = countSlides(html);
1210
+ const mermaidBlocks = options?.enableMermaid !== false ? detectMermaidBlocks(html) : [];
1211
+ const clickCss = enableClicks ? generateClickCss({ containerId }) : "";
1212
+ let processedHtml = html;
1213
+ if (options?.enableShiki !== false) {
1214
+ const shikiThemeName = theme.name === "light" ? "light" : "dark";
1215
+ processedHtml = await highlightCodeBlocks(html, shikiThemeName);
1216
+ }
1217
+ return {
1218
+ html,
1219
+ css,
1220
+ themeCss,
1221
+ slideCount,
1222
+ mermaidBlocks,
1223
+ clickCss,
1224
+ maxClicks,
1225
+ processedHtml
1226
+ };
1227
+ }
1228
+
1229
+ export { convertTextArrows, countSlides, darkThemeTokens, defineTheme, detectMermaidBlocks, extractMarpSource, extractMaxClicks, generateClickCss, generateScopedCss, generateScopedCss2, getHighlighter, getThemeTokens, highlightCodeBlocks, lightThemeTokens, navyThemeTokens, postprocessClicks, preprocessClicks, renderMarp, renderMermaidDiagrams, renderSlide, renderSlideAsync, resolveTheme, sanitizeMermaidCode };
1230
+ //# sourceMappingURL=chunk-RCHOTRWI.js.map
1231
+ //# sourceMappingURL=chunk-RCHOTRWI.js.map