@thanh01.pmt/presentation-kit 0.1.1 → 0.2.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.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkN4Q6GUAQ_cjs = require('./chunk-N4Q6GUAQ.cjs');
3
+ var chunkRJMPTRL3_cjs = require('./chunk-RJMPTRL3.cjs');
4
4
 
5
5
  // src/engine.ts
6
6
  function createEngine(config = {}) {
@@ -17,110 +17,326 @@ function createEngine(config = {}) {
17
17
  }
18
18
  return {
19
19
  render: (markdown, options) => {
20
- return chunkN4Q6GUAQ_cjs.renderSlide(markdown, mergeOptions(options));
20
+ return chunkRJMPTRL3_cjs.renderSlide(markdown, mergeOptions(options));
21
21
  },
22
22
  renderAsync: async (markdown, options) => {
23
- return chunkN4Q6GUAQ_cjs.renderSlideAsync(markdown, mergeOptions(options));
23
+ return chunkRJMPTRL3_cjs.renderSlideAsync(markdown, mergeOptions(options));
24
24
  },
25
25
  getThemeCss: (theme, containerId) => {
26
- const resolved = chunkN4Q6GUAQ_cjs.resolveTheme(theme);
27
- return chunkN4Q6GUAQ_cjs.generateScopedCss2(resolved, containerId);
26
+ const resolved = chunkRJMPTRL3_cjs.resolveTheme(theme);
27
+ return chunkRJMPTRL3_cjs.generateScopedCss2(resolved, containerId);
28
28
  }
29
29
  };
30
30
  }
31
31
 
32
+ // src/core/export/pptx-converter.ts
33
+ function parseFontSizeToPt(sizeStr, defaultPt = 18) {
34
+ if (!sizeStr) return defaultPt;
35
+ const trimmed = sizeStr.trim().toLowerCase();
36
+ if (trimmed.endsWith("rem")) {
37
+ const rem = parseFloat(trimmed);
38
+ return Math.round(rem * 16 * 0.75) || defaultPt;
39
+ }
40
+ if (trimmed.endsWith("px")) {
41
+ const px = parseFloat(trimmed);
42
+ return Math.round(px * 0.75) || defaultPt;
43
+ }
44
+ if (trimmed.endsWith("pt")) {
45
+ return parseInt(trimmed, 10) || defaultPt;
46
+ }
47
+ const num = parseFloat(trimmed);
48
+ return !isNaN(num) ? Math.round(num) : defaultPt;
49
+ }
50
+ function cleanHexColor(colorStr, defaultHex = "1F2937") {
51
+ if (!colorStr) return defaultHex;
52
+ const hex = colorStr.trim().replace(/^#/, "");
53
+ if (/^[0-9A-Fa-f]{6}$/.test(hex)) return hex.toUpperCase();
54
+ if (/^[0-9A-Fa-f]{3}$/.test(hex)) {
55
+ return hex.split("").map((c) => c + c).join("").toUpperCase();
56
+ }
57
+ return defaultHex;
58
+ }
59
+ function extractSlideBgColor(slideMd, defaultColor) {
60
+ const match = slideMd.match(/<!--\s*_backgroundColor:\s*([^\s>]+)\s*-->/i);
61
+ if (match && match[1]) {
62
+ return cleanHexColor(match[1], defaultColor);
63
+ }
64
+ return defaultColor;
65
+ }
66
+ function parseSimpleMarkdown(md) {
67
+ const lines = md.split("\n");
68
+ const blocks = [];
69
+ for (const line of lines) {
70
+ const trimmed = line.trim();
71
+ if (!trimmed) continue;
72
+ if (trimmed.startsWith("<!--") && trimmed.endsWith("-->")) continue;
73
+ const hMatch = trimmed.match(/^(#{1,6})\s+(.*)$/);
74
+ if (hMatch && hMatch[1] && hMatch[2]) {
75
+ blocks.push({
76
+ type: "heading",
77
+ level: hMatch[1].length,
78
+ text: hMatch[2].replace(/\*\*(.*?)\*\*/g, "$1").replace(/\*(.*?)\*/g, "$1")
79
+ });
80
+ continue;
81
+ }
82
+ if (/^[-*+]\s+/.test(trimmed)) {
83
+ blocks.push({
84
+ type: "bullet",
85
+ text: trimmed.replace(/^[-*+]\s+/, "").replace(/\*\*(.*?)\*\*/g, "$1")
86
+ });
87
+ continue;
88
+ }
89
+ blocks.push({
90
+ type: "paragraph",
91
+ text: trimmed.replace(/\*\*(.*?)\*\*/g, "$1").replace(/\*(.*?)\*/g, "$1")
92
+ });
93
+ }
94
+ return blocks;
95
+ }
96
+ async function convertMarkdownToPptx(markdown, options) {
97
+ const PptxGenModule = await import('pptxgenjs');
98
+ const PptxGenClass = PptxGenModule.default || PptxGenModule;
99
+ const pptx = new PptxGenClass();
100
+ pptx.layout = "LAYOUT_WIDE";
101
+ if (options?.title) pptx.title = options.title;
102
+ if (options?.author) pptx.author = options.author;
103
+ const renderResult = chunkRJMPTRL3_cjs.renderSlide(markdown);
104
+ const { slides } = chunkRJMPTRL3_cjs.splitMarkdownSlides(markdown);
105
+ const isDark = options?.theme !== "light";
106
+ const defaultBg = isDark ? "14151B" : "FFFFFF";
107
+ const defaultText = isDark ? "F1F5F9" : "1E293B";
108
+ const defaultHeading = isDark ? "38BDF8" : "0284C7";
109
+ const scaleX = 13.33 / 1280;
110
+ const scaleY = 7.5 / 720;
111
+ slides.forEach((slideMd, slideIndex) => {
112
+ const pptxSlide = pptx.addSlide();
113
+ const bgColor = extractSlideBgColor(slideMd, defaultBg);
114
+ pptxSlide.background = { color: bgColor };
115
+ const notes = renderResult.notes?.[slideIndex];
116
+ if (notes && notes.length > 0) {
117
+ pptxSlide.addNotes(notes.join("\n\n"));
118
+ }
119
+ const layout = renderResult.layouts?.[slideIndex];
120
+ const blocks = parseSimpleMarkdown(slideMd);
121
+ if (layout && layout.boxes && layout.boxes.length > 0) {
122
+ for (const box of layout.boxes) {
123
+ const [x, y, w, h] = box.pos;
124
+ const xInch = Math.max(0, x * scaleX);
125
+ const yInch = Math.max(0, y * scaleY);
126
+ const wInch = Math.min(13.33 - xInch, w * scaleX);
127
+ const hInch = Math.min(7.5 - yInch, h * scaleY);
128
+ let contentText = "";
129
+ if (box.target === "h1") {
130
+ contentText = blocks.find((b) => b.type === "heading" && b.level === 1)?.text || "Heading";
131
+ } else if (box.target === "h2") {
132
+ contentText = blocks.find((b) => b.type === "heading" && b.level === 2)?.text || "Subheading";
133
+ } else {
134
+ contentText = blocks.find((b) => b.type === "paragraph" || b.type === "bullet")?.text || "Content block";
135
+ }
136
+ const fontSizePt = parseFontSizeToPt(box.fontSize, box.target === "h1" ? 28 : 16);
137
+ const colorHex = cleanHexColor(box.color, box.target === "h1" ? defaultHeading : defaultText);
138
+ pptxSlide.addText(contentText, {
139
+ x: xInch,
140
+ y: yInch,
141
+ w: wInch,
142
+ h: hInch,
143
+ fontSize: fontSizePt,
144
+ color: colorHex,
145
+ align: box.textAlign ?? "left",
146
+ bold: box.target?.startsWith("h") ?? false,
147
+ fontFace: "Arial"
148
+ });
149
+ }
150
+ } else {
151
+ let currentY = 0.8;
152
+ const marginX = 1;
153
+ const contentWidth = 11.33;
154
+ for (const block of blocks) {
155
+ if (block.type === "heading") {
156
+ const fontSize = block.level === 1 ? 30 : block.level === 2 ? 22 : 18;
157
+ const color = block.level === 1 ? defaultHeading : defaultText;
158
+ pptxSlide.addText(block.text, {
159
+ x: marginX,
160
+ y: currentY,
161
+ w: contentWidth,
162
+ h: 0.8,
163
+ fontSize,
164
+ color,
165
+ bold: true,
166
+ fontFace: "Arial"
167
+ });
168
+ currentY += 0.9;
169
+ } else if (block.type === "bullet") {
170
+ pptxSlide.addText(block.text, {
171
+ x: marginX + 0.3,
172
+ y: currentY,
173
+ w: contentWidth - 0.3,
174
+ h: 0.45,
175
+ fontSize: 15,
176
+ color: defaultText,
177
+ bullet: true,
178
+ fontFace: "Arial"
179
+ });
180
+ currentY += 0.5;
181
+ } else {
182
+ pptxSlide.addText(block.text, {
183
+ x: marginX,
184
+ y: currentY,
185
+ w: contentWidth,
186
+ h: 0.5,
187
+ fontSize: 15,
188
+ color: defaultText,
189
+ fontFace: "Arial"
190
+ });
191
+ currentY += 0.55;
192
+ }
193
+ if (currentY > 6.5) break;
194
+ }
195
+ }
196
+ });
197
+ const pptxArray = await pptx.write({ outputType: "arraybuffer" });
198
+ return new Uint8Array(pptxArray);
199
+ }
200
+
201
+ Object.defineProperty(exports, "SLIDE_LAYOUT_PRESETS", {
202
+ enumerable: true,
203
+ get: function () { return chunkRJMPTRL3_cjs.SLIDE_LAYOUT_PRESETS; }
204
+ });
32
205
  Object.defineProperty(exports, "convertTextArrows", {
33
206
  enumerable: true,
34
- get: function () { return chunkN4Q6GUAQ_cjs.convertTextArrows; }
207
+ get: function () { return chunkRJMPTRL3_cjs.convertTextArrows; }
35
208
  });
36
209
  Object.defineProperty(exports, "countSlides", {
37
210
  enumerable: true,
38
- get: function () { return chunkN4Q6GUAQ_cjs.countSlides; }
211
+ get: function () { return chunkRJMPTRL3_cjs.countSlides; }
39
212
  });
40
213
  Object.defineProperty(exports, "darkThemeTokens", {
41
214
  enumerable: true,
42
- get: function () { return chunkN4Q6GUAQ_cjs.darkThemeTokens; }
215
+ get: function () { return chunkRJMPTRL3_cjs.darkThemeTokens; }
43
216
  });
44
217
  Object.defineProperty(exports, "defineTheme", {
45
218
  enumerable: true,
46
- get: function () { return chunkN4Q6GUAQ_cjs.defineTheme; }
219
+ get: function () { return chunkRJMPTRL3_cjs.defineTheme; }
47
220
  });
48
221
  Object.defineProperty(exports, "detectMermaidBlocks", {
49
222
  enumerable: true,
50
- get: function () { return chunkN4Q6GUAQ_cjs.detectMermaidBlocks; }
223
+ get: function () { return chunkRJMPTRL3_cjs.detectMermaidBlocks; }
224
+ });
225
+ Object.defineProperty(exports, "extractLayoutsAndNotes", {
226
+ enumerable: true,
227
+ get: function () { return chunkRJMPTRL3_cjs.extractLayoutsAndNotes; }
51
228
  });
52
229
  Object.defineProperty(exports, "extractMarpSource", {
53
230
  enumerable: true,
54
- get: function () { return chunkN4Q6GUAQ_cjs.extractMarpSource; }
231
+ get: function () { return chunkRJMPTRL3_cjs.extractMarpSource; }
55
232
  });
56
233
  Object.defineProperty(exports, "extractMaxClicks", {
57
234
  enumerable: true,
58
- get: function () { return chunkN4Q6GUAQ_cjs.extractMaxClicks; }
235
+ get: function () { return chunkRJMPTRL3_cjs.extractMaxClicks; }
236
+ });
237
+ Object.defineProperty(exports, "filterPresenterNotes", {
238
+ enumerable: true,
239
+ get: function () { return chunkRJMPTRL3_cjs.filterPresenterNotes; }
59
240
  });
60
241
  Object.defineProperty(exports, "generateClickCss", {
61
242
  enumerable: true,
62
- get: function () { return chunkN4Q6GUAQ_cjs.generateClickCss; }
243
+ get: function () { return chunkRJMPTRL3_cjs.generateClickCss; }
244
+ });
245
+ Object.defineProperty(exports, "generateLayoutCss", {
246
+ enumerable: true,
247
+ get: function () { return chunkRJMPTRL3_cjs.generateLayoutCss; }
63
248
  });
64
249
  Object.defineProperty(exports, "generateScopedCss", {
65
250
  enumerable: true,
66
- get: function () { return chunkN4Q6GUAQ_cjs.generateScopedCss2; }
251
+ get: function () { return chunkRJMPTRL3_cjs.generateScopedCss2; }
67
252
  });
68
253
  Object.defineProperty(exports, "generateScopedCssFromTokens", {
69
254
  enumerable: true,
70
- get: function () { return chunkN4Q6GUAQ_cjs.generateScopedCss; }
255
+ get: function () { return chunkRJMPTRL3_cjs.generateScopedCss; }
71
256
  });
72
257
  Object.defineProperty(exports, "getHighlighter", {
73
258
  enumerable: true,
74
- get: function () { return chunkN4Q6GUAQ_cjs.getHighlighter; }
259
+ get: function () { return chunkRJMPTRL3_cjs.getHighlighter; }
260
+ });
261
+ Object.defineProperty(exports, "getSlideLayoutPresetById", {
262
+ enumerable: true,
263
+ get: function () { return chunkRJMPTRL3_cjs.getSlideLayoutPresetById; }
264
+ });
265
+ Object.defineProperty(exports, "getSlideLayoutPresetsByCategory", {
266
+ enumerable: true,
267
+ get: function () { return chunkRJMPTRL3_cjs.getSlideLayoutPresetsByCategory; }
75
268
  });
76
269
  Object.defineProperty(exports, "getThemeTokens", {
77
270
  enumerable: true,
78
- get: function () { return chunkN4Q6GUAQ_cjs.getThemeTokens; }
271
+ get: function () { return chunkRJMPTRL3_cjs.getThemeTokens; }
79
272
  });
80
273
  Object.defineProperty(exports, "highlightCodeBlocks", {
81
274
  enumerable: true,
82
- get: function () { return chunkN4Q6GUAQ_cjs.highlightCodeBlocks; }
275
+ get: function () { return chunkRJMPTRL3_cjs.highlightCodeBlocks; }
276
+ });
277
+ Object.defineProperty(exports, "isLayoutComment", {
278
+ enumerable: true,
279
+ get: function () { return chunkRJMPTRL3_cjs.isLayoutComment; }
83
280
  });
84
281
  Object.defineProperty(exports, "lightThemeTokens", {
85
282
  enumerable: true,
86
- get: function () { return chunkN4Q6GUAQ_cjs.lightThemeTokens; }
283
+ get: function () { return chunkRJMPTRL3_cjs.lightThemeTokens; }
87
284
  });
88
285
  Object.defineProperty(exports, "navyThemeTokens", {
89
286
  enumerable: true,
90
- get: function () { return chunkN4Q6GUAQ_cjs.navyThemeTokens; }
287
+ get: function () { return chunkRJMPTRL3_cjs.navyThemeTokens; }
288
+ });
289
+ Object.defineProperty(exports, "parseLayoutFromComment", {
290
+ enumerable: true,
291
+ get: function () { return chunkRJMPTRL3_cjs.parseLayoutFromComment; }
91
292
  });
92
293
  Object.defineProperty(exports, "postprocessClicks", {
93
294
  enumerable: true,
94
- get: function () { return chunkN4Q6GUAQ_cjs.postprocessClicks; }
295
+ get: function () { return chunkRJMPTRL3_cjs.postprocessClicks; }
95
296
  });
96
297
  Object.defineProperty(exports, "preprocessClicks", {
97
298
  enumerable: true,
98
- get: function () { return chunkN4Q6GUAQ_cjs.preprocessClicks; }
299
+ get: function () { return chunkRJMPTRL3_cjs.preprocessClicks; }
99
300
  });
100
301
  Object.defineProperty(exports, "renderMarp", {
101
302
  enumerable: true,
102
- get: function () { return chunkN4Q6GUAQ_cjs.renderMarp; }
303
+ get: function () { return chunkRJMPTRL3_cjs.renderMarp; }
103
304
  });
104
305
  Object.defineProperty(exports, "renderMermaidDiagrams", {
105
306
  enumerable: true,
106
- get: function () { return chunkN4Q6GUAQ_cjs.renderMermaidDiagrams; }
307
+ get: function () { return chunkRJMPTRL3_cjs.renderMermaidDiagrams; }
107
308
  });
108
309
  Object.defineProperty(exports, "renderSlide", {
109
310
  enumerable: true,
110
- get: function () { return chunkN4Q6GUAQ_cjs.renderSlide; }
311
+ get: function () { return chunkRJMPTRL3_cjs.renderSlide; }
111
312
  });
112
313
  Object.defineProperty(exports, "renderSlideAsync", {
113
314
  enumerable: true,
114
- get: function () { return chunkN4Q6GUAQ_cjs.renderSlideAsync; }
315
+ get: function () { return chunkRJMPTRL3_cjs.renderSlideAsync; }
115
316
  });
116
317
  Object.defineProperty(exports, "resolveTheme", {
117
318
  enumerable: true,
118
- get: function () { return chunkN4Q6GUAQ_cjs.resolveTheme; }
319
+ get: function () { return chunkRJMPTRL3_cjs.resolveTheme; }
119
320
  });
120
321
  Object.defineProperty(exports, "sanitizeMermaidCode", {
121
322
  enumerable: true,
122
- get: function () { return chunkN4Q6GUAQ_cjs.sanitizeMermaidCode; }
323
+ get: function () { return chunkRJMPTRL3_cjs.sanitizeMermaidCode; }
324
+ });
325
+ Object.defineProperty(exports, "serializeLayoutToComment", {
326
+ enumerable: true,
327
+ get: function () { return chunkRJMPTRL3_cjs.serializeLayoutToComment; }
328
+ });
329
+ Object.defineProperty(exports, "splitMarkdownSlides", {
330
+ enumerable: true,
331
+ get: function () { return chunkRJMPTRL3_cjs.splitMarkdownSlides; }
332
+ });
333
+ Object.defineProperty(exports, "updateSlideLayoutInMarkdown", {
334
+ enumerable: true,
335
+ get: function () { return chunkRJMPTRL3_cjs.updateSlideLayoutInMarkdown; }
123
336
  });
337
+ exports.cleanHexColor = cleanHexColor;
338
+ exports.convertMarkdownToPptx = convertMarkdownToPptx;
124
339
  exports.createEngine = createEngine;
340
+ exports.parseFontSizeToPt = parseFontSizeToPt;
125
341
  //# sourceMappingURL=index.cjs.map
126
342
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/engine.ts"],"names":["renderSlide","renderSlideAsync","resolveTheme","generateScopedCss"],"mappings":";;;;;AAyBO,SAAS,YAAA,CAAa,MAAA,GAA4B,EAAC,EAAgB;AACxE,EAAA,MAAM,YAAA,GAAe,OAAO,KAAA,IAAS,MAAA;AACrC,EAAA,MAAM,kBAAA,GAAqB,OAAO,WAAA,IAAe,IAAA;AACjD,EAAA,MAAM,oBAAA,GAAuB,OAAO,aAAA,IAAiB,IAAA;AAErD,EAAA,SAAS,aAAa,OAAA,EAAkD;AACtE,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,SAAS,KAAA,IAAS,YAAA;AAAA,MACzB,WAAA,EAAa,SAAS,WAAA,IAAe,kBAAA;AAAA,MACrC,aAAA,EAAe,SAAS,aAAA,IAAiB,oBAAA;AAAA,MACzC,aAAa,OAAA,EAAS;AAAA,KACxB;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,CAAC,QAAA,EAAkB,OAAA,KAAoD;AAC7E,MAAA,OAAOA,6BAAA,CAAY,QAAA,EAAU,YAAA,CAAa,OAAO,CAAC,CAAA;AAAA,IACpD,CAAA;AAAA,IAEA,WAAA,EAAa,OAAO,QAAA,EAAkB,OAAA,KAAkE;AACtG,MAAA,OAAOC,kCAAA,CAAiB,QAAA,EAAU,YAAA,CAAa,OAAO,CAAC,CAAA;AAAA,IACzD,CAAA;AAAA,IAEA,WAAA,EAAa,CAAC,KAAA,EAAkC,WAAA,KAAiC;AAC/E,MAAA,MAAM,QAAA,GAAWC,+BAAa,KAAK,CAAA;AACnC,MAAA,OAAOC,oCAAAA,CAAkB,UAAU,WAAW,CAAA;AAAA,IAChD;AAAA,GACF;AACF","file":"index.cjs","sourcesContent":["// ═══════════════════════════════════════════════════════════════════════════════\n// Engine Factory — createEngine() for advanced usage\n// ═══════════════════════════════════════════════════════════════════════════════\n\nimport type { SlideEngine, SlideEngineConfig, SlideRenderOptions, SlideRenderResult, SlideRenderAsyncResult, BuiltInTheme, SlideTheme } from './types.js';\nimport { renderSlide, renderSlideAsync } from './core/render.js';\nimport { resolveTheme, generateScopedCss } from './themes/index.js';\n\n/**\n * Create a slide engine instance with default configuration.\n *\n * @example\n * ```ts\n * const engine = createEngine({ theme: 'dark' });\n *\n * // Synchronous\n * const result = engine.render(markdown);\n *\n * // Async (with Shiki highlighting)\n * const fullResult = await engine.renderAsync(markdown);\n *\n * // Get theme CSS independently\n * const css = engine.getThemeCss('navy');\n * ```\n */\nexport function createEngine(config: SlideEngineConfig = {}): SlideEngine {\n const defaultTheme = config.theme ?? 'dark';\n const defaultEnableShiki = config.enableShiki ?? true;\n const defaultEnableMermaid = config.enableMermaid ?? true;\n\n function mergeOptions(options?: SlideRenderOptions): SlideRenderOptions {\n return {\n theme: options?.theme ?? defaultTheme,\n enableShiki: options?.enableShiki ?? defaultEnableShiki,\n enableMermaid: options?.enableMermaid ?? defaultEnableMermaid,\n containerId: options?.containerId,\n };\n }\n\n return {\n render: (markdown: string, options?: SlideRenderOptions): SlideRenderResult => {\n return renderSlide(markdown, mergeOptions(options));\n },\n\n renderAsync: async (markdown: string, options?: SlideRenderOptions): Promise<SlideRenderAsyncResult> => {\n return renderSlideAsync(markdown, mergeOptions(options));\n },\n\n getThemeCss: (theme: BuiltInTheme | SlideTheme, containerId?: string): string => {\n const resolved = resolveTheme(theme);\n return generateScopedCss(resolved, containerId);\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/engine.ts","../src/core/export/pptx-converter.ts"],"names":["renderSlide","renderSlideAsync","resolveTheme","generateScopedCss","splitMarkdownSlides"],"mappings":"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","file":"index.cjs","sourcesContent":["// ═══════════════════════════════════════════════════════════════════════════════\n// Engine Factory — createEngine() for advanced usage\n// ═══════════════════════════════════════════════════════════════════════════════\n\nimport type { SlideEngine, SlideEngineConfig, SlideRenderOptions, SlideRenderResult, SlideRenderAsyncResult, BuiltInTheme, SlideTheme } from './types.js';\nimport { renderSlide, renderSlideAsync } from './core/render.js';\nimport { resolveTheme, generateScopedCss } from './themes/index.js';\n\n/**\n * Create a slide engine instance with default configuration.\n *\n * @example\n * ```ts\n * const engine = createEngine({ theme: 'dark' });\n *\n * // Synchronous\n * const result = engine.render(markdown);\n *\n * // Async (with Shiki highlighting)\n * const fullResult = await engine.renderAsync(markdown);\n *\n * // Get theme CSS independently\n * const css = engine.getThemeCss('navy');\n * ```\n */\nexport function createEngine(config: SlideEngineConfig = {}): SlideEngine {\n const defaultTheme = config.theme ?? 'dark';\n const defaultEnableShiki = config.enableShiki ?? true;\n const defaultEnableMermaid = config.enableMermaid ?? true;\n\n function mergeOptions(options?: SlideRenderOptions): SlideRenderOptions {\n return {\n theme: options?.theme ?? defaultTheme,\n enableShiki: options?.enableShiki ?? defaultEnableShiki,\n enableMermaid: options?.enableMermaid ?? defaultEnableMermaid,\n containerId: options?.containerId,\n };\n }\n\n return {\n render: (markdown: string, options?: SlideRenderOptions): SlideRenderResult => {\n return renderSlide(markdown, mergeOptions(options));\n },\n\n renderAsync: async (markdown: string, options?: SlideRenderOptions): Promise<SlideRenderAsyncResult> => {\n return renderSlideAsync(markdown, mergeOptions(options));\n },\n\n getThemeCss: (theme: BuiltInTheme | SlideTheme, containerId?: string): string => {\n const resolved = resolveTheme(theme);\n return generateScopedCss(resolved, containerId);\n },\n };\n}\n","// ═══════════════════════════════════════════════════════════════════════════════\n// pptx-converter.ts — Pure JS converter: Marp Markdown + Layouts → Native PPTX\n//\n// Generates native, fully editable PowerPoint textboxes and shapes\n// that open directly in PowerPoint, Keynote, and Google Slides.\n// ═══════════════════════════════════════════════════════════════════════════════\n\nimport { renderSlide } from '../render.js';\nimport { splitMarkdownSlides } from '../layout/serializer.js';\nimport type { LayoutBoxConfig } from '../../types.js';\n\nexport interface PptxExportOptions {\n title?: string;\n author?: string;\n theme?: 'dark' | 'light' | 'navy';\n}\n\n/**\n * Convert font size string ('2.5rem', '32px', '24pt') to pt number for PPTX\n */\nexport function parseFontSizeToPt(sizeStr?: string, defaultPt: number = 18): number {\n if (!sizeStr) return defaultPt;\n const trimmed = sizeStr.trim().toLowerCase();\n\n if (trimmed.endsWith('rem')) {\n const rem = parseFloat(trimmed);\n return Math.round(rem * 16 * 0.75) || defaultPt;\n }\n if (trimmed.endsWith('px')) {\n const px = parseFloat(trimmed);\n return Math.round(px * 0.75) || defaultPt;\n }\n if (trimmed.endsWith('pt')) {\n return parseInt(trimmed, 10) || defaultPt;\n }\n const num = parseFloat(trimmed);\n return !isNaN(num) ? Math.round(num) : defaultPt;\n}\n\n/**\n * Clean hex color string (removes leading #)\n */\nexport function cleanHexColor(colorStr?: string, defaultHex: string = '1F2937'): string {\n if (!colorStr) return defaultHex;\n const hex = colorStr.trim().replace(/^#/, '');\n if (/^[0-9A-Fa-f]{6}$/.test(hex)) return hex.toUpperCase();\n if (/^[0-9A-Fa-f]{3}$/.test(hex)) {\n return hex.split('').map(c => c + c).join('').toUpperCase();\n }\n return defaultHex;\n}\n\n/**\n * Extract slide-level background color directive from slide markdown\n */\nfunction extractSlideBgColor(slideMd: string, defaultColor: string): string {\n const match = slideMd.match(/<!--\\s*_backgroundColor:\\s*([^\\s>]+)\\s*-->/i);\n if (match && match[1]) {\n return cleanHexColor(match[1], defaultColor);\n }\n return defaultColor;\n}\n\n/**\n * Parse plain markdown lines into simple text items\n */\ninterface SimpleBlock {\n type: 'heading' | 'paragraph' | 'bullet' | 'code';\n level?: number;\n text: string;\n}\n\nfunction parseSimpleMarkdown(md: string): SimpleBlock[] {\n const lines = md.split('\\n');\n const blocks: SimpleBlock[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n if (trimmed.startsWith('<!--') && trimmed.endsWith('-->')) continue;\n\n // Heading\n const hMatch = trimmed.match(/^(#{1,6})\\s+(.*)$/);\n if (hMatch && hMatch[1] && hMatch[2]) {\n blocks.push({\n type: 'heading',\n level: hMatch[1].length,\n text: hMatch[2].replace(/\\*\\*(.*?)\\*\\*/g, '$1').replace(/\\*(.*?)\\*/g, '$1'),\n });\n continue;\n }\n\n // Bullet\n if (/^[-*+]\\s+/.test(trimmed)) {\n blocks.push({\n type: 'bullet',\n text: trimmed.replace(/^[-*+]\\s+/, '').replace(/\\*\\*(.*?)\\*\\*/g, '$1'),\n });\n continue;\n }\n\n // Paragraph\n blocks.push({\n type: 'paragraph',\n text: trimmed.replace(/\\*\\*(.*?)\\*\\*/g, '$1').replace(/\\*(.*?)\\*/g, '$1'),\n });\n }\n\n return blocks;\n}\n\n/**\n * Convert Marp Markdown presentation to an editable PPTX file using pptxgenjs.\n *\n * Each box in `layout.boxes` maps directly from 1280x720 canvas px to 13.33 x 7.5 inch PPTX coordinates.\n */\nexport async function convertMarkdownToPptx(\n markdown: string,\n options?: PptxExportOptions\n): Promise<Uint8Array> {\n const PptxGenModule = await import('pptxgenjs');\n const PptxGenClass = (PptxGenModule as any).default || PptxGenModule;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const pptx = new (PptxGenClass as any)();\n\n pptx.layout = 'LAYOUT_WIDE'; // 16:9 aspect ratio (13.33 x 7.5 inches)\n if (options?.title) pptx.title = options.title;\n if (options?.author) pptx.author = options.author;\n\n const renderResult = renderSlide(markdown);\n const { slides } = splitMarkdownSlides(markdown);\n\n const isDark = options?.theme !== 'light';\n const defaultBg = isDark ? '14151B' : 'FFFFFF';\n const defaultText = isDark ? 'F1F5F9' : '1E293B';\n const defaultHeading = isDark ? '38BDF8' : '0284C7';\n\n // Coordinate scales from 1280x720 to 13.33x7.5 inches\n const scaleX = 13.33 / 1280;\n const scaleY = 7.5 / 720;\n\n slides.forEach((slideMd, slideIndex) => {\n const pptxSlide = pptx.addSlide();\n\n // 1. Set background\n const bgColor = extractSlideBgColor(slideMd, defaultBg);\n pptxSlide.background = { color: bgColor };\n\n // 2. Add Speaker / Teacher Notes\n const notes = renderResult.notes?.[slideIndex];\n if (notes && notes.length > 0) {\n pptxSlide.addNotes(notes.join('\\n\\n'));\n }\n\n // 3. Layout boxes\n const layout = renderResult.layouts?.[slideIndex];\n const blocks = parseSimpleMarkdown(slideMd);\n\n if (layout && layout.boxes && layout.boxes.length > 0) {\n // Freeform layout: Render boxes with exact pos\n for (const box of layout.boxes) {\n const [x, y, w, h] = box.pos;\n const xInch = Math.max(0, x * scaleX);\n const yInch = Math.max(0, y * scaleY);\n const wInch = Math.min(13.33 - xInch, w * scaleX);\n const hInch = Math.min(7.5 - yInch, h * scaleY);\n\n // Find corresponding text\n let contentText = '';\n if (box.target === 'h1') {\n contentText = blocks.find(b => b.type === 'heading' && b.level === 1)?.text || 'Heading';\n } else if (box.target === 'h2') {\n contentText = blocks.find(b => b.type === 'heading' && b.level === 2)?.text || 'Subheading';\n } else {\n contentText = blocks.find(b => b.type === 'paragraph' || b.type === 'bullet')?.text || 'Content block';\n }\n\n const fontSizePt = parseFontSizeToPt(box.fontSize, box.target === 'h1' ? 28 : 16);\n const colorHex = cleanHexColor(box.color, box.target === 'h1' ? defaultHeading : defaultText);\n\n pptxSlide.addText(contentText, {\n x: xInch,\n y: yInch,\n w: wInch,\n h: hInch,\n fontSize: fontSizePt,\n color: colorHex,\n align: box.textAlign ?? 'left',\n bold: box.target?.startsWith('h') ?? false,\n fontFace: 'Arial',\n });\n }\n } else {\n // Flow layout fallback: Stack headings and paragraphs nicely\n let currentY = 0.8;\n const marginX = 1.0;\n const contentWidth = 11.33;\n\n for (const block of blocks) {\n if (block.type === 'heading') {\n const fontSize = block.level === 1 ? 30 : block.level === 2 ? 22 : 18;\n const color = block.level === 1 ? defaultHeading : defaultText;\n\n pptxSlide.addText(block.text, {\n x: marginX,\n y: currentY,\n w: contentWidth,\n h: 0.8,\n fontSize,\n color,\n bold: true,\n fontFace: 'Arial',\n });\n currentY += 0.9;\n } else if (block.type === 'bullet') {\n pptxSlide.addText(block.text, {\n x: marginX + 0.3,\n y: currentY,\n w: contentWidth - 0.3,\n h: 0.45,\n fontSize: 15,\n color: defaultText,\n bullet: true,\n fontFace: 'Arial',\n });\n currentY += 0.5;\n } else {\n pptxSlide.addText(block.text, {\n x: marginX,\n y: currentY,\n w: contentWidth,\n h: 0.5,\n fontSize: 15,\n color: defaultText,\n fontFace: 'Arial',\n });\n currentY += 0.55;\n }\n\n if (currentY > 6.5) break; // Prevent vertical overflow off slide\n }\n }\n });\n\n const pptxArray = (await pptx.write({ outputType: 'arraybuffer' })) as ArrayBuffer;\n return new Uint8Array(pptxArray);\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as SlideEngineConfig, a as SlideEngine, T as ThemeTokens, M as MermaidBlock } from './click-css-CadkoJ_A.cjs';
2
- export { B as BuiltInTheme, m as ClickCssOptions, l as ClickPostprocessResult, C as ClickPreprocessResult, s as SlideRenderAsyncResult, o as SlideRenderOptions, q as SlideRenderResult, n as SlideTheme, d as countSlides, e as defineTheme, j as extractMaxClicks, k as generateClickCss, h as generateScopedCss, g as getThemeTokens, i as postprocessClicks, p as preprocessClicks, c as renderMarp, r as renderSlide, b as renderSlideAsync, f as resolveTheme } from './click-css-CadkoJ_A.cjs';
1
+ import { S as SlideEngineConfig, a as SlideEngine, T as ThemeTokens, M as MermaidBlock, b as SlideLayoutData } from './click-css-C84mdmU0.cjs';
2
+ export { B as BuiltInTheme, n as ClickCssOptions, m as ClickPostprocessResult, C as ClickPreprocessResult, L as LayoutBoxConfig, t as SlideRenderAsyncResult, q as SlideRenderOptions, s as SlideRenderResult, o as SlideTheme, e as countSlides, f as defineTheme, k as extractMaxClicks, l as generateClickCss, i as generateScopedCss, h as getThemeTokens, j as postprocessClicks, p as preprocessClicks, d as renderMarp, r as renderSlide, c as renderSlideAsync, g as resolveTheme } from './click-css-C84mdmU0.cjs';
3
3
  import { Highlighter } from 'shiki';
4
4
 
5
5
  /**
@@ -66,6 +66,90 @@ declare function sanitizeMermaidCode(chart: string, isDark?: boolean): string;
66
66
  */
67
67
  declare function renderMermaidDiagrams(container: HTMLElement, theme?: 'dark' | 'light' | 'navy'): Promise<void>;
68
68
 
69
+ /**
70
+ * Check if a comment string represents a layout definition
71
+ */
72
+ declare function isLayoutComment(comment: string): boolean;
73
+ /**
74
+ * Parse YAML layout data from a comment string
75
+ */
76
+ declare function parseLayoutFromComment(comment: string): SlideLayoutData | null;
77
+ /**
78
+ * Filter presenter notes from a slide's comment list,
79
+ * excluding layout blocks and Marp system directives.
80
+ */
81
+ declare function filterPresenterNotes(comments: string[]): string[];
82
+ /**
83
+ * Extract per-slide layout data and presenter notes from Marp's comments array.
84
+ */
85
+ declare function extractLayoutsAndNotes(rawComments: (string[] | undefined)[]): {
86
+ layouts: (SlideLayoutData | null)[];
87
+ notes: string[][];
88
+ };
89
+
90
+ /**
91
+ * Serialize a SlideLayoutData object into a Markdown HTML comment
92
+ */
93
+ declare function serializeLayoutToComment(layout: SlideLayoutData): string;
94
+ /**
95
+ * Split a Markdown presentation into individual slide strings,
96
+ * properly handling frontmatter and code blocks.
97
+ */
98
+ declare function splitMarkdownSlides(markdown: string): {
99
+ frontmatter: string | null;
100
+ slides: string[];
101
+ };
102
+ /**
103
+ * Update or insert a layout comment inside a specific slide's markdown
104
+ */
105
+ declare function updateSlideLayoutInMarkdown(markdown: string, slideIndex: number, layout: SlideLayoutData | null): string;
106
+
107
+ /**
108
+ * Generate scoped CSS for per-slide layout overrides.
109
+ *
110
+ * Targets each slide's section within Marp's 1280x720 SVG coordinate space.
111
+ */
112
+ declare function generateLayoutCss(layouts: (SlideLayoutData | null)[], containerId?: string): string;
113
+
114
+ type SlideLayoutCategory = 'cover' | 'content' | 'split' | 'code' | 'metrics' | 'diagram' | 'quote' | 'assessment';
115
+ interface SlideLayoutPreset {
116
+ id: string;
117
+ name: string;
118
+ category: SlideLayoutCategory;
119
+ description: string;
120
+ layout: SlideLayoutData;
121
+ markdownSnippet: string;
122
+ }
123
+ declare const SLIDE_LAYOUT_PRESETS: SlideLayoutPreset[];
124
+ /**
125
+ * Find a preset by its unique ID
126
+ */
127
+ declare function getSlideLayoutPresetById(id: string): SlideLayoutPreset | undefined;
128
+ /**
129
+ * Filter presets by category
130
+ */
131
+ declare function getSlideLayoutPresetsByCategory(category: SlideLayoutCategory): SlideLayoutPreset[];
132
+
133
+ interface PptxExportOptions {
134
+ title?: string;
135
+ author?: string;
136
+ theme?: 'dark' | 'light' | 'navy';
137
+ }
138
+ /**
139
+ * Convert font size string ('2.5rem', '32px', '24pt') to pt number for PPTX
140
+ */
141
+ declare function parseFontSizeToPt(sizeStr?: string, defaultPt?: number): number;
142
+ /**
143
+ * Clean hex color string (removes leading #)
144
+ */
145
+ declare function cleanHexColor(colorStr?: string, defaultHex?: string): string;
146
+ /**
147
+ * Convert Marp Markdown presentation to an editable PPTX file using pptxgenjs.
148
+ *
149
+ * Each box in `layout.boxes` maps directly from 1280x720 canvas px to 13.33 x 7.5 inch PPTX coordinates.
150
+ */
151
+ declare function convertMarkdownToPptx(markdown: string, options?: PptxExportOptions): Promise<Uint8Array>;
152
+
69
153
  /**
70
154
  * Converts text arrows (->, -->, --->, =>, ==>, <->, etc.) into clean Unicode
71
155
  * arrows while strictly preserving YAML frontmatter, code fences, inline code,
@@ -83,4 +167,4 @@ declare function convertTextArrows(text: string): string;
83
167
  */
84
168
  declare function extractMarpSource(raw: string): string;
85
169
 
86
- export { MermaidBlock, SlideEngine, SlideEngineConfig, ThemeTokens, convertTextArrows, createEngine, darkThemeTokens, detectMermaidBlocks, extractMarpSource, generateScopedCss as generateScopedCssFromTokens, getHighlighter, highlightCodeBlocks, lightThemeTokens, navyThemeTokens, renderMermaidDiagrams, sanitizeMermaidCode };
170
+ export { MermaidBlock, type PptxExportOptions, SLIDE_LAYOUT_PRESETS, SlideEngine, SlideEngineConfig, type SlideLayoutCategory, SlideLayoutData, type SlideLayoutPreset, ThemeTokens, cleanHexColor, convertMarkdownToPptx, convertTextArrows, createEngine, darkThemeTokens, detectMermaidBlocks, extractLayoutsAndNotes, extractMarpSource, filterPresenterNotes, generateLayoutCss, generateScopedCss as generateScopedCssFromTokens, getHighlighter, getSlideLayoutPresetById, getSlideLayoutPresetsByCategory, highlightCodeBlocks, isLayoutComment, lightThemeTokens, navyThemeTokens, parseFontSizeToPt, parseLayoutFromComment, renderMermaidDiagrams, sanitizeMermaidCode, serializeLayoutToComment, splitMarkdownSlides, updateSlideLayoutInMarkdown };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as SlideEngineConfig, a as SlideEngine, T as ThemeTokens, M as MermaidBlock } from './click-css-CadkoJ_A.js';
2
- export { B as BuiltInTheme, m as ClickCssOptions, l as ClickPostprocessResult, C as ClickPreprocessResult, s as SlideRenderAsyncResult, o as SlideRenderOptions, q as SlideRenderResult, n as SlideTheme, d as countSlides, e as defineTheme, j as extractMaxClicks, k as generateClickCss, h as generateScopedCss, g as getThemeTokens, i as postprocessClicks, p as preprocessClicks, c as renderMarp, r as renderSlide, b as renderSlideAsync, f as resolveTheme } from './click-css-CadkoJ_A.js';
1
+ import { S as SlideEngineConfig, a as SlideEngine, T as ThemeTokens, M as MermaidBlock, b as SlideLayoutData } from './click-css-C84mdmU0.js';
2
+ export { B as BuiltInTheme, n as ClickCssOptions, m as ClickPostprocessResult, C as ClickPreprocessResult, L as LayoutBoxConfig, t as SlideRenderAsyncResult, q as SlideRenderOptions, s as SlideRenderResult, o as SlideTheme, e as countSlides, f as defineTheme, k as extractMaxClicks, l as generateClickCss, i as generateScopedCss, h as getThemeTokens, j as postprocessClicks, p as preprocessClicks, d as renderMarp, r as renderSlide, c as renderSlideAsync, g as resolveTheme } from './click-css-C84mdmU0.js';
3
3
  import { Highlighter } from 'shiki';
4
4
 
5
5
  /**
@@ -66,6 +66,90 @@ declare function sanitizeMermaidCode(chart: string, isDark?: boolean): string;
66
66
  */
67
67
  declare function renderMermaidDiagrams(container: HTMLElement, theme?: 'dark' | 'light' | 'navy'): Promise<void>;
68
68
 
69
+ /**
70
+ * Check if a comment string represents a layout definition
71
+ */
72
+ declare function isLayoutComment(comment: string): boolean;
73
+ /**
74
+ * Parse YAML layout data from a comment string
75
+ */
76
+ declare function parseLayoutFromComment(comment: string): SlideLayoutData | null;
77
+ /**
78
+ * Filter presenter notes from a slide's comment list,
79
+ * excluding layout blocks and Marp system directives.
80
+ */
81
+ declare function filterPresenterNotes(comments: string[]): string[];
82
+ /**
83
+ * Extract per-slide layout data and presenter notes from Marp's comments array.
84
+ */
85
+ declare function extractLayoutsAndNotes(rawComments: (string[] | undefined)[]): {
86
+ layouts: (SlideLayoutData | null)[];
87
+ notes: string[][];
88
+ };
89
+
90
+ /**
91
+ * Serialize a SlideLayoutData object into a Markdown HTML comment
92
+ */
93
+ declare function serializeLayoutToComment(layout: SlideLayoutData): string;
94
+ /**
95
+ * Split a Markdown presentation into individual slide strings,
96
+ * properly handling frontmatter and code blocks.
97
+ */
98
+ declare function splitMarkdownSlides(markdown: string): {
99
+ frontmatter: string | null;
100
+ slides: string[];
101
+ };
102
+ /**
103
+ * Update or insert a layout comment inside a specific slide's markdown
104
+ */
105
+ declare function updateSlideLayoutInMarkdown(markdown: string, slideIndex: number, layout: SlideLayoutData | null): string;
106
+
107
+ /**
108
+ * Generate scoped CSS for per-slide layout overrides.
109
+ *
110
+ * Targets each slide's section within Marp's 1280x720 SVG coordinate space.
111
+ */
112
+ declare function generateLayoutCss(layouts: (SlideLayoutData | null)[], containerId?: string): string;
113
+
114
+ type SlideLayoutCategory = 'cover' | 'content' | 'split' | 'code' | 'metrics' | 'diagram' | 'quote' | 'assessment';
115
+ interface SlideLayoutPreset {
116
+ id: string;
117
+ name: string;
118
+ category: SlideLayoutCategory;
119
+ description: string;
120
+ layout: SlideLayoutData;
121
+ markdownSnippet: string;
122
+ }
123
+ declare const SLIDE_LAYOUT_PRESETS: SlideLayoutPreset[];
124
+ /**
125
+ * Find a preset by its unique ID
126
+ */
127
+ declare function getSlideLayoutPresetById(id: string): SlideLayoutPreset | undefined;
128
+ /**
129
+ * Filter presets by category
130
+ */
131
+ declare function getSlideLayoutPresetsByCategory(category: SlideLayoutCategory): SlideLayoutPreset[];
132
+
133
+ interface PptxExportOptions {
134
+ title?: string;
135
+ author?: string;
136
+ theme?: 'dark' | 'light' | 'navy';
137
+ }
138
+ /**
139
+ * Convert font size string ('2.5rem', '32px', '24pt') to pt number for PPTX
140
+ */
141
+ declare function parseFontSizeToPt(sizeStr?: string, defaultPt?: number): number;
142
+ /**
143
+ * Clean hex color string (removes leading #)
144
+ */
145
+ declare function cleanHexColor(colorStr?: string, defaultHex?: string): string;
146
+ /**
147
+ * Convert Marp Markdown presentation to an editable PPTX file using pptxgenjs.
148
+ *
149
+ * Each box in `layout.boxes` maps directly from 1280x720 canvas px to 13.33 x 7.5 inch PPTX coordinates.
150
+ */
151
+ declare function convertMarkdownToPptx(markdown: string, options?: PptxExportOptions): Promise<Uint8Array>;
152
+
69
153
  /**
70
154
  * Converts text arrows (->, -->, --->, =>, ==>, <->, etc.) into clean Unicode
71
155
  * arrows while strictly preserving YAML frontmatter, code fences, inline code,
@@ -83,4 +167,4 @@ declare function convertTextArrows(text: string): string;
83
167
  */
84
168
  declare function extractMarpSource(raw: string): string;
85
169
 
86
- export { MermaidBlock, SlideEngine, SlideEngineConfig, ThemeTokens, convertTextArrows, createEngine, darkThemeTokens, detectMermaidBlocks, extractMarpSource, generateScopedCss as generateScopedCssFromTokens, getHighlighter, highlightCodeBlocks, lightThemeTokens, navyThemeTokens, renderMermaidDiagrams, sanitizeMermaidCode };
170
+ export { MermaidBlock, type PptxExportOptions, SLIDE_LAYOUT_PRESETS, SlideEngine, SlideEngineConfig, type SlideLayoutCategory, SlideLayoutData, type SlideLayoutPreset, ThemeTokens, cleanHexColor, convertMarkdownToPptx, convertTextArrows, createEngine, darkThemeTokens, detectMermaidBlocks, extractLayoutsAndNotes, extractMarpSource, filterPresenterNotes, generateLayoutCss, generateScopedCss as generateScopedCssFromTokens, getHighlighter, getSlideLayoutPresetById, getSlideLayoutPresetsByCategory, highlightCodeBlocks, isLayoutComment, lightThemeTokens, navyThemeTokens, parseFontSizeToPt, parseLayoutFromComment, renderMermaidDiagrams, sanitizeMermaidCode, serializeLayoutToComment, splitMarkdownSlides, updateSlideLayoutInMarkdown };