@thanh01.pmt/presentation-kit 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkN4Q6GUAQ_cjs = require('./chunk-N4Q6GUAQ.cjs');
3
+ var chunkO4Y3VEOA_cjs = require('./chunk-O4Y3VEOA.cjs');
4
4
 
5
5
  // src/engine.ts
6
6
  function createEngine(config = {}) {
@@ -17,110 +17,314 @@ function createEngine(config = {}) {
17
17
  }
18
18
  return {
19
19
  render: (markdown, options) => {
20
- return chunkN4Q6GUAQ_cjs.renderSlide(markdown, mergeOptions(options));
20
+ return chunkO4Y3VEOA_cjs.renderSlide(markdown, mergeOptions(options));
21
21
  },
22
22
  renderAsync: async (markdown, options) => {
23
- return chunkN4Q6GUAQ_cjs.renderSlideAsync(markdown, mergeOptions(options));
23
+ return chunkO4Y3VEOA_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 = chunkO4Y3VEOA_cjs.resolveTheme(theme);
27
+ return chunkO4Y3VEOA_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 = chunkO4Y3VEOA_cjs.renderSlide(markdown);
104
+ const { slides } = chunkO4Y3VEOA_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
+
32
201
  Object.defineProperty(exports, "convertTextArrows", {
33
202
  enumerable: true,
34
- get: function () { return chunkN4Q6GUAQ_cjs.convertTextArrows; }
203
+ get: function () { return chunkO4Y3VEOA_cjs.convertTextArrows; }
35
204
  });
36
205
  Object.defineProperty(exports, "countSlides", {
37
206
  enumerable: true,
38
- get: function () { return chunkN4Q6GUAQ_cjs.countSlides; }
207
+ get: function () { return chunkO4Y3VEOA_cjs.countSlides; }
39
208
  });
40
209
  Object.defineProperty(exports, "darkThemeTokens", {
41
210
  enumerable: true,
42
- get: function () { return chunkN4Q6GUAQ_cjs.darkThemeTokens; }
211
+ get: function () { return chunkO4Y3VEOA_cjs.darkThemeTokens; }
43
212
  });
44
213
  Object.defineProperty(exports, "defineTheme", {
45
214
  enumerable: true,
46
- get: function () { return chunkN4Q6GUAQ_cjs.defineTheme; }
215
+ get: function () { return chunkO4Y3VEOA_cjs.defineTheme; }
47
216
  });
48
217
  Object.defineProperty(exports, "detectMermaidBlocks", {
49
218
  enumerable: true,
50
- get: function () { return chunkN4Q6GUAQ_cjs.detectMermaidBlocks; }
219
+ get: function () { return chunkO4Y3VEOA_cjs.detectMermaidBlocks; }
220
+ });
221
+ Object.defineProperty(exports, "extractLayoutsAndNotes", {
222
+ enumerable: true,
223
+ get: function () { return chunkO4Y3VEOA_cjs.extractLayoutsAndNotes; }
51
224
  });
52
225
  Object.defineProperty(exports, "extractMarpSource", {
53
226
  enumerable: true,
54
- get: function () { return chunkN4Q6GUAQ_cjs.extractMarpSource; }
227
+ get: function () { return chunkO4Y3VEOA_cjs.extractMarpSource; }
55
228
  });
56
229
  Object.defineProperty(exports, "extractMaxClicks", {
57
230
  enumerable: true,
58
- get: function () { return chunkN4Q6GUAQ_cjs.extractMaxClicks; }
231
+ get: function () { return chunkO4Y3VEOA_cjs.extractMaxClicks; }
232
+ });
233
+ Object.defineProperty(exports, "filterPresenterNotes", {
234
+ enumerable: true,
235
+ get: function () { return chunkO4Y3VEOA_cjs.filterPresenterNotes; }
59
236
  });
60
237
  Object.defineProperty(exports, "generateClickCss", {
61
238
  enumerable: true,
62
- get: function () { return chunkN4Q6GUAQ_cjs.generateClickCss; }
239
+ get: function () { return chunkO4Y3VEOA_cjs.generateClickCss; }
240
+ });
241
+ Object.defineProperty(exports, "generateLayoutCss", {
242
+ enumerable: true,
243
+ get: function () { return chunkO4Y3VEOA_cjs.generateLayoutCss; }
63
244
  });
64
245
  Object.defineProperty(exports, "generateScopedCss", {
65
246
  enumerable: true,
66
- get: function () { return chunkN4Q6GUAQ_cjs.generateScopedCss2; }
247
+ get: function () { return chunkO4Y3VEOA_cjs.generateScopedCss2; }
67
248
  });
68
249
  Object.defineProperty(exports, "generateScopedCssFromTokens", {
69
250
  enumerable: true,
70
- get: function () { return chunkN4Q6GUAQ_cjs.generateScopedCss; }
251
+ get: function () { return chunkO4Y3VEOA_cjs.generateScopedCss; }
71
252
  });
72
253
  Object.defineProperty(exports, "getHighlighter", {
73
254
  enumerable: true,
74
- get: function () { return chunkN4Q6GUAQ_cjs.getHighlighter; }
255
+ get: function () { return chunkO4Y3VEOA_cjs.getHighlighter; }
75
256
  });
76
257
  Object.defineProperty(exports, "getThemeTokens", {
77
258
  enumerable: true,
78
- get: function () { return chunkN4Q6GUAQ_cjs.getThemeTokens; }
259
+ get: function () { return chunkO4Y3VEOA_cjs.getThemeTokens; }
79
260
  });
80
261
  Object.defineProperty(exports, "highlightCodeBlocks", {
81
262
  enumerable: true,
82
- get: function () { return chunkN4Q6GUAQ_cjs.highlightCodeBlocks; }
263
+ get: function () { return chunkO4Y3VEOA_cjs.highlightCodeBlocks; }
264
+ });
265
+ Object.defineProperty(exports, "isLayoutComment", {
266
+ enumerable: true,
267
+ get: function () { return chunkO4Y3VEOA_cjs.isLayoutComment; }
83
268
  });
84
269
  Object.defineProperty(exports, "lightThemeTokens", {
85
270
  enumerable: true,
86
- get: function () { return chunkN4Q6GUAQ_cjs.lightThemeTokens; }
271
+ get: function () { return chunkO4Y3VEOA_cjs.lightThemeTokens; }
87
272
  });
88
273
  Object.defineProperty(exports, "navyThemeTokens", {
89
274
  enumerable: true,
90
- get: function () { return chunkN4Q6GUAQ_cjs.navyThemeTokens; }
275
+ get: function () { return chunkO4Y3VEOA_cjs.navyThemeTokens; }
276
+ });
277
+ Object.defineProperty(exports, "parseLayoutFromComment", {
278
+ enumerable: true,
279
+ get: function () { return chunkO4Y3VEOA_cjs.parseLayoutFromComment; }
91
280
  });
92
281
  Object.defineProperty(exports, "postprocessClicks", {
93
282
  enumerable: true,
94
- get: function () { return chunkN4Q6GUAQ_cjs.postprocessClicks; }
283
+ get: function () { return chunkO4Y3VEOA_cjs.postprocessClicks; }
95
284
  });
96
285
  Object.defineProperty(exports, "preprocessClicks", {
97
286
  enumerable: true,
98
- get: function () { return chunkN4Q6GUAQ_cjs.preprocessClicks; }
287
+ get: function () { return chunkO4Y3VEOA_cjs.preprocessClicks; }
99
288
  });
100
289
  Object.defineProperty(exports, "renderMarp", {
101
290
  enumerable: true,
102
- get: function () { return chunkN4Q6GUAQ_cjs.renderMarp; }
291
+ get: function () { return chunkO4Y3VEOA_cjs.renderMarp; }
103
292
  });
104
293
  Object.defineProperty(exports, "renderMermaidDiagrams", {
105
294
  enumerable: true,
106
- get: function () { return chunkN4Q6GUAQ_cjs.renderMermaidDiagrams; }
295
+ get: function () { return chunkO4Y3VEOA_cjs.renderMermaidDiagrams; }
107
296
  });
108
297
  Object.defineProperty(exports, "renderSlide", {
109
298
  enumerable: true,
110
- get: function () { return chunkN4Q6GUAQ_cjs.renderSlide; }
299
+ get: function () { return chunkO4Y3VEOA_cjs.renderSlide; }
111
300
  });
112
301
  Object.defineProperty(exports, "renderSlideAsync", {
113
302
  enumerable: true,
114
- get: function () { return chunkN4Q6GUAQ_cjs.renderSlideAsync; }
303
+ get: function () { return chunkO4Y3VEOA_cjs.renderSlideAsync; }
115
304
  });
116
305
  Object.defineProperty(exports, "resolveTheme", {
117
306
  enumerable: true,
118
- get: function () { return chunkN4Q6GUAQ_cjs.resolveTheme; }
307
+ get: function () { return chunkO4Y3VEOA_cjs.resolveTheme; }
119
308
  });
120
309
  Object.defineProperty(exports, "sanitizeMermaidCode", {
121
310
  enumerable: true,
122
- get: function () { return chunkN4Q6GUAQ_cjs.sanitizeMermaidCode; }
311
+ get: function () { return chunkO4Y3VEOA_cjs.sanitizeMermaidCode; }
312
+ });
313
+ Object.defineProperty(exports, "serializeLayoutToComment", {
314
+ enumerable: true,
315
+ get: function () { return chunkO4Y3VEOA_cjs.serializeLayoutToComment; }
316
+ });
317
+ Object.defineProperty(exports, "splitMarkdownSlides", {
318
+ enumerable: true,
319
+ get: function () { return chunkO4Y3VEOA_cjs.splitMarkdownSlides; }
320
+ });
321
+ Object.defineProperty(exports, "updateSlideLayoutInMarkdown", {
322
+ enumerable: true,
323
+ get: function () { return chunkO4Y3VEOA_cjs.updateSlideLayoutInMarkdown; }
123
324
  });
325
+ exports.cleanHexColor = cleanHexColor;
326
+ exports.convertMarkdownToPptx = convertMarkdownToPptx;
124
327
  exports.createEngine = createEngine;
328
+ exports.parseFontSizeToPt = parseFontSizeToPt;
125
329
  //# sourceMappingURL=index.cjs.map
126
330
  //# 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,71 @@ 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
+ interface PptxExportOptions {
115
+ title?: string;
116
+ author?: string;
117
+ theme?: 'dark' | 'light' | 'navy';
118
+ }
119
+ /**
120
+ * Convert font size string ('2.5rem', '32px', '24pt') to pt number for PPTX
121
+ */
122
+ declare function parseFontSizeToPt(sizeStr?: string, defaultPt?: number): number;
123
+ /**
124
+ * Clean hex color string (removes leading #)
125
+ */
126
+ declare function cleanHexColor(colorStr?: string, defaultHex?: string): string;
127
+ /**
128
+ * Convert Marp Markdown presentation to an editable PPTX file using pptxgenjs.
129
+ *
130
+ * Each box in `layout.boxes` maps directly from 1280x720 canvas px to 13.33 x 7.5 inch PPTX coordinates.
131
+ */
132
+ declare function convertMarkdownToPptx(markdown: string, options?: PptxExportOptions): Promise<Uint8Array>;
133
+
69
134
  /**
70
135
  * Converts text arrows (->, -->, --->, =>, ==>, <->, etc.) into clean Unicode
71
136
  * arrows while strictly preserving YAML frontmatter, code fences, inline code,
@@ -83,4 +148,4 @@ declare function convertTextArrows(text: string): string;
83
148
  */
84
149
  declare function extractMarpSource(raw: string): string;
85
150
 
86
- export { MermaidBlock, SlideEngine, SlideEngineConfig, ThemeTokens, convertTextArrows, createEngine, darkThemeTokens, detectMermaidBlocks, extractMarpSource, generateScopedCss as generateScopedCssFromTokens, getHighlighter, highlightCodeBlocks, lightThemeTokens, navyThemeTokens, renderMermaidDiagrams, sanitizeMermaidCode };
151
+ export { MermaidBlock, type PptxExportOptions, SlideEngine, SlideEngineConfig, SlideLayoutData, ThemeTokens, cleanHexColor, convertMarkdownToPptx, convertTextArrows, createEngine, darkThemeTokens, detectMermaidBlocks, extractLayoutsAndNotes, extractMarpSource, filterPresenterNotes, generateLayoutCss, generateScopedCss as generateScopedCssFromTokens, getHighlighter, 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,71 @@ 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
+ interface PptxExportOptions {
115
+ title?: string;
116
+ author?: string;
117
+ theme?: 'dark' | 'light' | 'navy';
118
+ }
119
+ /**
120
+ * Convert font size string ('2.5rem', '32px', '24pt') to pt number for PPTX
121
+ */
122
+ declare function parseFontSizeToPt(sizeStr?: string, defaultPt?: number): number;
123
+ /**
124
+ * Clean hex color string (removes leading #)
125
+ */
126
+ declare function cleanHexColor(colorStr?: string, defaultHex?: string): string;
127
+ /**
128
+ * Convert Marp Markdown presentation to an editable PPTX file using pptxgenjs.
129
+ *
130
+ * Each box in `layout.boxes` maps directly from 1280x720 canvas px to 13.33 x 7.5 inch PPTX coordinates.
131
+ */
132
+ declare function convertMarkdownToPptx(markdown: string, options?: PptxExportOptions): Promise<Uint8Array>;
133
+
69
134
  /**
70
135
  * Converts text arrows (->, -->, --->, =>, ==>, <->, etc.) into clean Unicode
71
136
  * arrows while strictly preserving YAML frontmatter, code fences, inline code,
@@ -83,4 +148,4 @@ declare function convertTextArrows(text: string): string;
83
148
  */
84
149
  declare function extractMarpSource(raw: string): string;
85
150
 
86
- export { MermaidBlock, SlideEngine, SlideEngineConfig, ThemeTokens, convertTextArrows, createEngine, darkThemeTokens, detectMermaidBlocks, extractMarpSource, generateScopedCss as generateScopedCssFromTokens, getHighlighter, highlightCodeBlocks, lightThemeTokens, navyThemeTokens, renderMermaidDiagrams, sanitizeMermaidCode };
151
+ export { MermaidBlock, type PptxExportOptions, SlideEngine, SlideEngineConfig, SlideLayoutData, ThemeTokens, cleanHexColor, convertMarkdownToPptx, convertTextArrows, createEngine, darkThemeTokens, detectMermaidBlocks, extractLayoutsAndNotes, extractMarpSource, filterPresenterNotes, generateLayoutCss, generateScopedCss as generateScopedCssFromTokens, getHighlighter, highlightCodeBlocks, isLayoutComment, lightThemeTokens, navyThemeTokens, parseFontSizeToPt, parseLayoutFromComment, renderMermaidDiagrams, sanitizeMermaidCode, serializeLayoutToComment, splitMarkdownSlides, updateSlideLayoutInMarkdown };