@bendyline/squisq-formats 2.3.10 → 2.4.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.
@@ -144,6 +144,7 @@ function generateInlineHtml(doc, options) {
144
144
  mode = "slideshow",
145
145
  title = "Squisq Document",
146
146
  autoPlay = false,
147
+ showCodeCopyButton = false,
147
148
  captionStyle,
148
149
  themeId,
149
150
  themeRegistry
@@ -187,6 +188,7 @@ ${mode === "static" ? "#squisq-root{display:block}" : ""}
187
188
  images: images,
188
189
  autoPlay: ${JSON.stringify(autoPlay)},${captionStyle ? `
189
190
  captionStyle: ${JSON.stringify(captionStyle)},` : ""}
191
+ showCodeCopyButton: ${JSON.stringify(showCodeCopyButton)},
190
192
  basePath: "."
191
193
  });
192
194
  })();
@@ -202,6 +204,7 @@ function generateExternalHtml(doc, options) {
202
204
  mode = "slideshow",
203
205
  title = "Squisq Document",
204
206
  autoPlay = false,
207
+ showCodeCopyButton = false,
205
208
  captionStyle,
206
209
  themeId,
207
210
  themeRegistry
@@ -238,6 +241,7 @@ ${mode === "static" ? "#squisq-root{display:block}" : ""}
238
241
  audio: audio,
239
242
  autoPlay: ${JSON.stringify(autoPlay)},${captionStyle ? `
240
243
  captionStyle: ${JSON.stringify(captionStyle)},` : ""}
244
+ showCodeCopyButton: ${JSON.stringify(showCodeCopyButton)},
241
245
  basePath: "."
242
246
  });
243
247
  })();
@@ -643,7 +647,7 @@ function nodeToHtml(node, ctx) {
643
647
  return `<code>${escapeHtml2(node.value ?? "")}</code>`;
644
648
  case "code": {
645
649
  const lang = node.lang ? ` class="language-${escapeAttr(node.lang)}"` : "";
646
- return `<pre><code${lang}>${escapeHtml2(node.value ?? "")}</code></pre>`;
650
+ return `<pre class="squisq-code-block"><code${lang}>${escapeHtml2(node.value ?? "")}</code></pre>`;
647
651
  }
648
652
  case "blockquote":
649
653
  return `<blockquote>${childrenToHtml(node, ctx)}</blockquote>`;
@@ -1012,6 +1016,7 @@ async function markdownDocsToHtmlBundle(options) {
1012
1016
  themeId,
1013
1017
  themeRegistry,
1014
1018
  mode = "static",
1019
+ showCodeCopyButton = false,
1015
1020
  maxDepth = Infinity,
1016
1021
  entryAsIndex = false
1017
1022
  } = options;
@@ -1078,6 +1083,7 @@ async function markdownDocsToHtmlBundle(options) {
1078
1083
  // sources before rendering each block.
1079
1084
  imagePathMap: imageRewriteMap.size > 0 ? Object.fromEntries(imageRewriteMap.entries()) : void 0,
1080
1085
  mode,
1086
+ showCodeCopyButton,
1081
1087
  title: pageTitle,
1082
1088
  themeId,
1083
1089
  themeRegistry
@@ -1494,6 +1500,7 @@ async function docToHtmlZip(doc, options) {
1494
1500
  mode = "slideshow",
1495
1501
  title,
1496
1502
  autoPlay,
1503
+ showCodeCopyButton,
1497
1504
  themeId,
1498
1505
  themeRegistry
1499
1506
  } = options;
@@ -1537,6 +1544,7 @@ async function docToHtmlZip(doc, options) {
1537
1544
  mode,
1538
1545
  title,
1539
1546
  autoPlay,
1547
+ showCodeCopyButton,
1540
1548
  themeId,
1541
1549
  themeRegistry
1542
1550
  });
@@ -401,14 +401,22 @@ function defaultFormats() {
401
401
  const markdownDoc = await markdownOf(input);
402
402
  const containerImages = await collectContainerImages(input.container, options.signal);
403
403
  const images = new Map([...containerImages, ...raw.images ?? /* @__PURE__ */ new Map()]);
404
+ const pptxWarnings = [];
404
405
  const buf = await markdownDocToPptx(markdownDoc, {
405
406
  ...raw,
406
407
  ...options.title !== void 0 ? { title: options.title } : {},
407
408
  themeId: resolveThemeId(input, options),
408
409
  themeRegistry: options.themeRegistry ?? raw.themeRegistry,
409
- images
410
+ images,
411
+ onWarning: (message) => {
412
+ pptxWarnings.push(message);
413
+ raw.onWarning?.(message);
414
+ }
410
415
  });
411
- return ok(await toBytes(buf), MIME.pptx, markdownFidelityWarnings(markdownDoc, "pptx"));
416
+ return ok(await toBytes(buf), MIME.pptx, [
417
+ ...markdownFidelityWarnings(markdownDoc, "pptx"),
418
+ ...pptxWarnings
419
+ ]);
412
420
  }
413
421
  };
414
422
  const xlsx = {
@@ -119,7 +119,7 @@ async function markdownDocToPptx(doc, options = {}) {
119
119
  options.signal?.throwIfAborted();
120
120
  const themeId = options.themeId ?? readFrontmatterThemeId(doc.frontmatter);
121
121
  const style = resolveSlideStyle(themeId, options, doc);
122
- const slides = segmentIntoSlides(doc.children, options.slideBreak ?? "h2");
122
+ const slides = segmentIntoSlides(doc.children, options.slideBreak ?? "h2", options.onWarning);
123
123
  if (slides.length === 0) {
124
124
  slides.push({ bodyNodes: [] });
125
125
  }
@@ -255,13 +255,20 @@ function shouldIncludeCoverSlide(doc, options) {
255
255
  }
256
256
  return true;
257
257
  }
258
- function segmentIntoSlides(children, slideBreak) {
258
+ function segmentIntoSlides(children, slideBreak, onWarning) {
259
259
  const maxDepth = slideBreak === "h1" ? 1 : slideBreak === "h2" ? 2 : 6;
260
260
  const slides = [];
261
261
  let current;
262
+ let redundantThematicBreaks = 0;
262
263
  for (const node of children) {
263
264
  if (node.type === "heading" && node.depth <= maxDepth) {
264
- if (current) slides.push(current);
265
+ if (current) {
266
+ while (current.bodyNodes[current.bodyNodes.length - 1]?.type === "thematicBreak") {
267
+ current.bodyNodes.pop();
268
+ redundantThematicBreaks += 1;
269
+ }
270
+ if (current.title || current.bodyNodes.length > 0) slides.push(current);
271
+ }
265
272
  current = {
266
273
  title: node.children,
267
274
  titleDepth: node.depth,
@@ -276,6 +283,11 @@ function segmentIntoSlides(children, slideBreak) {
276
283
  }
277
284
  }
278
285
  if (current) slides.push(current);
286
+ if (redundantThematicBreaks > 0) {
287
+ onWarning?.(
288
+ `PPTX export removed ${redundantThematicBreaks} redundant thematic break(s) immediately before slide headings. A heading already starts the next slide; omit --- unless a visible horizontal rule is intended.`
289
+ );
290
+ }
279
291
  return slides;
280
292
  }
281
293
  var SlideContext = class {
@@ -1182,7 +1194,7 @@ function convertTableRow(row, ctx, isHeader) {
1182
1194
  return `<a:p>${makeRun(text, format, ctx.style)}</a:p>`;
1183
1195
  }
1184
1196
  function convertThematicBreak(ctx) {
1185
- return `<a:p><a:pPr><a:spcAft><a:spcPts val="1200"/></a:spcAft></a:pPr><a:r><a:rPr lang="en-US" sz="400"><a:solidFill><a:srgbClr val="${ctx.style.mutedColor}"/></a:solidFill></a:rPr><a:t>\u2014\u2014\u2014</a:t></a:r></a:p>`;
1197
+ return `<a:p><a:pPr algn="ctr"><a:spcBef><a:spcPts val="600"/></a:spcBef><a:spcAft><a:spcPts val="1200"/></a:spcAft><a:buNone/></a:pPr><a:r><a:rPr lang="en-US" sz="800"><a:solidFill><a:srgbClr val="${ctx.style.mutedColor}"/></a:solidFill></a:rPr><a:t>\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500</a:t></a:r><a:endParaRPr lang="en-US" sz="800"/></a:p>`;
1186
1198
  }
1187
1199
  function convertHtmlBlock(node, ctx) {
1188
1200
  const text = stripHtmlTags(node.rawHtml).trim();
@@ -1,6 +1,6 @@
1
1
  import { Theme, ThemeRegistry, Doc } from '@bendyline/squisq/schemas';
2
- import { H as HtmlExportOptions } from '../import-BhOL4D1B.js';
3
- export { a as HtmlImportOptions, c as collectImagePaths, g as generateExternalHtml, h as htmlToMarkdown, b as htmlToMarkdownDoc, d as htmlToMarkdownDocSync } from '../import-BhOL4D1B.js';
2
+ import { H as HtmlExportOptions } from '../import-BQFf0iEG.js';
3
+ export { a as HtmlImportOptions, c as collectImagePaths, g as generateExternalHtml, h as htmlToMarkdown, b as htmlToMarkdownDoc, d as htmlToMarkdownDocSync } from '../import-BQFf0iEG.js';
4
4
  import { HtmlPolicy, MarkdownDocument } from '@bendyline/squisq/markdown';
5
5
 
6
6
  /**
@@ -226,6 +226,8 @@ interface HtmlBundleOptions {
226
226
  themeRegistry?: ThemeRegistry;
227
227
  /** Rendering mode for every page (default: 'static' — scrollable, link-friendly). */
228
228
  mode?: 'slideshow' | 'static';
229
+ /** Show Copy controls on ordinary fenced code blocks (default: false). */
230
+ showCodeCopyButton?: boolean;
229
231
  /** Maximum recursion depth (default: unlimited; cycles always handled). */
230
232
  maxDepth?: number;
231
233
  /**
@@ -10,7 +10,7 @@ import {
10
10
  markdownDocToPlainHtml,
11
11
  markdownDocsToHtmlBundle,
12
12
  markdownDocsToPlainHtmlBundle
13
- } from "../chunk-VF2AML3R.js";
13
+ } from "../chunk-A5Y23TAF.js";
14
14
  import {
15
15
  arrayBufferToBase64DataUrl,
16
16
  extractFilename,
@@ -36,6 +36,8 @@ interface HtmlExportOptions {
36
36
  title?: string;
37
37
  /** Auto-play slideshow on load (default: false) */
38
38
  autoPlay?: boolean;
39
+ /** Show Copy controls on ordinary fenced code blocks (default: false). */
40
+ showCodeCopyButton?: boolean;
39
41
  /**
40
42
  * Caption rendering for slideshow playback. Passed through to
41
43
  * `SquisqPlayer.mount` — 'social' shows the large centered 3-5 word
@@ -65,7 +67,7 @@ declare function collectImagePaths(doc: Doc): Set<string>;
65
67
  * @param options - Export options (playerScript is not embedded, referenced via src)
66
68
  * @returns Complete HTML string
67
69
  */
68
- declare function generateExternalHtml(doc: Doc, options: Pick<HtmlExportOptions, 'mode' | 'title' | 'autoPlay' | 'captionStyle' | 'themeId' | 'themeRegistry'> & {
70
+ declare function generateExternalHtml(doc: Doc, options: Pick<HtmlExportOptions, 'mode' | 'title' | 'autoPlay' | 'showCodeCopyButton' | 'captionStyle' | 'themeId' | 'themeRegistry'> & {
69
71
  /** Relative path to the player JS file (e.g., 'squisq-player.js') */
70
72
  playerScriptPath: string;
71
73
  /** Map of original image paths to their rewritten relative paths in the ZIP */
@@ -51,6 +51,8 @@ interface PptxExportOptions {
51
51
  * - `'heading'` — any heading (H1–H6) starts a slide
52
52
  */
53
53
  slideBreak?: 'h1' | 'h2' | 'heading';
54
+ /** Receives non-fatal export warnings. */
55
+ onWarning?: (message: string) => void;
54
56
  /** Default body font family. Default: "Calibri" */
55
57
  defaultFont?: string;
56
58
  /** Default body font size in points. Default: 18 */
package/dist/index.d.ts CHANGED
@@ -8,8 +8,8 @@ export { EpubExportOptions, docToEpub, markdownDocToEpub } from './epub/index.js
8
8
  export { ExtractedFileTheme, InferSourceFormat, InferThemeOptions, InferredFileTheme, compileExtractedTheme, inferThemeFromFile } from './infer/index.js';
9
9
  export { BUILTIN_FORMAT_IDS, BuiltinFormatOptions, ConversionError, ConversionErrorCode, ConversionErrorOptions, ConversionLimits, ConversionResult, ConvertOptions, ConvertSource, DEFAULT_CONVERSION_LIMITS, DbkFormatOptions, FormatDefinition, FormatId, FormatRegistry, MarkdownFormatOptions, NormalizedInput, PreparedConversion, PreparedExportOptions, convert, createRegistry, defaultFormats, defaultRegistry, prepareConversion, resolveConversionLimits } from './registry/index.js';
10
10
  export { Z as ZipSafetyError, a as ZipSafetyErrorCode, b as ZipSafetyErrorOptions, c as ZipSafetyLimits } from './zipLimits-BOKCB7qk.js';
11
- export { H as HtmlExportOptions, a as HtmlImportOptions, c as collectImagePaths, h as htmlToMarkdown, b as htmlToMarkdownDoc, d as htmlToMarkdownDocSync } from './import-BhOL4D1B.js';
12
- export { P as PptxExportOptions, a as PptxImportOptions, d as docToPptx, m as markdownDocToPptx, p as pptxToMarkdownDoc } from './import-BhBGQqnz.js';
11
+ export { H as HtmlExportOptions, a as HtmlImportOptions, c as collectImagePaths, h as htmlToMarkdown, b as htmlToMarkdownDoc, d as htmlToMarkdownDocSync } from './import-BQFf0iEG.js';
12
+ export { P as PptxExportOptions, a as PptxImportOptions, d as docToPptx, m as markdownDocToPptx, p as pptxToMarkdownDoc } from './import-Dug5rlEL.js';
13
13
  export { X as XlsxExportOptions, a as XlsxImportOptions, d as docToXlsx, m as markdownDocToXlsx, x as xlsxToMarkdownDoc } from './export-D9msROJS.js';
14
14
  import '@bendyline/squisq/schemas';
15
15
  import '@bendyline/squisq/markdown';
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  defaultRegistry,
12
12
  prepareConversion,
13
13
  resolveConversionLimits
14
- } from "./chunk-34ER6JR3.js";
14
+ } from "./chunk-XXNCA3EH.js";
15
15
  import {
16
16
  inferThemeFromFile
17
17
  } from "./chunk-KMBBO5H7.js";
@@ -33,7 +33,7 @@ import {
33
33
  markdownDocToPptx,
34
34
  pptxToDoc,
35
35
  pptxToMarkdownDoc
36
- } from "./chunk-TBB4PAX5.js";
36
+ } from "./chunk-ZRRZY57C.js";
37
37
  import "./chunk-6N2J7C2B.js";
38
38
  import "./chunk-DWNNYO5H.js";
39
39
  import {
@@ -72,7 +72,7 @@ import {
72
72
  htmlToMarkdown,
73
73
  htmlToMarkdownDoc,
74
74
  htmlToMarkdownDocSync
75
- } from "./chunk-VF2AML3R.js";
75
+ } from "./chunk-A5Y23TAF.js";
76
76
  import "./chunk-6RQOV3B3.js";
77
77
  import "./chunk-AONELFLA.js";
78
78
  export {
@@ -1,5 +1,5 @@
1
- import { a as PptxImportOptions } from '../import-BhBGQqnz.js';
2
- export { P as PptxExportOptions, d as docToPptx, m as markdownDocToPptx, b as pptxToContainer, p as pptxToMarkdownDoc } from '../import-BhBGQqnz.js';
1
+ import { a as PptxImportOptions } from '../import-Dug5rlEL.js';
2
+ export { P as PptxExportOptions, d as docToPptx, m as markdownDocToPptx, b as pptxToContainer, p as pptxToMarkdownDoc } from '../import-Dug5rlEL.js';
3
3
  import { Doc } from '@bendyline/squisq/schemas';
4
4
  export { A as AnalyzePptxLayoutsOptions, a as AnalyzedLayout, E as ExtractedPlaceholder, b as ExtractedSlideLayout, I as InspectPptxLayoutsOptions, L as LayoutVerdict, P as PptxColorHints, c as PptxLayoutInference, d as PptxLayoutSummary, e as analyzePptxLayouts, i as inspectPptxLayouts } from '../layouts-CTdPlB-u.js';
5
5
  import '@bendyline/squisq/markdown';
@@ -4,7 +4,7 @@ import {
4
4
  pptxToContainer,
5
5
  pptxToDoc,
6
6
  pptxToMarkdownDoc
7
- } from "../chunk-TBB4PAX5.js";
7
+ } from "../chunk-ZRRZY57C.js";
8
8
  import {
9
9
  analyzePptxLayouts,
10
10
  inspectPptxLayouts
@@ -3,11 +3,11 @@ import { TransformStyleInput, TransformStyleRegistry } from '@bendyline/squisq/t
3
3
  import { ParseOptions, StringifyOptions, MarkdownDocument } from '@bendyline/squisq/markdown';
4
4
  import { ContentContainer } from '@bendyline/squisq/storage';
5
5
  import { DocxImportOptions, DocxExportOptions } from '../docx/index.js';
6
- import { a as PptxImportOptions, P as PptxExportOptions } from '../import-BhBGQqnz.js';
6
+ import { a as PptxImportOptions, P as PptxExportOptions } from '../import-Dug5rlEL.js';
7
7
  import { a as XlsxImportOptions, X as XlsxExportOptions } from '../export-D9msROJS.js';
8
8
  import { CsvImportOptions, CsvExportOptions } from '../csv/index.js';
9
9
  import { PdfImportOptions, PdfExportOptions } from '../pdf/index.js';
10
- import { a as HtmlImportOptions, H as HtmlExportOptions } from '../import-BhOL4D1B.js';
10
+ import { a as HtmlImportOptions, H as HtmlExportOptions } from '../import-BQFf0iEG.js';
11
11
  import { EpubExportOptions } from '../epub/index.js';
12
12
  import { ContainerToZipOptions } from '../container/index.js';
13
13
  import { c as ZipSafetyLimits } from '../zipLimits-BOKCB7qk.js';
@@ -7,7 +7,7 @@ import {
7
7
  defaultRegistry,
8
8
  prepareConversion,
9
9
  resolveConversionLimits
10
- } from "../chunk-34ER6JR3.js";
10
+ } from "../chunk-XXNCA3EH.js";
11
11
  import {
12
12
  ConversionError
13
13
  } from "../chunk-KXOZMWBS.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bendyline/squisq-formats",
3
- "version": "2.3.10",
3
+ "version": "2.4.1",
4
4
  "description": "Document format converters — DOCX, PDF, OOXML import/export",
5
5
  "license": "MIT",
6
6
  "author": "Bendyline",
@@ -108,7 +108,7 @@
108
108
  "@pdf-lib/fontkit": "1.1.1",
109
109
  "@pdf-lib/upng": "1.0.1",
110
110
  "@xmldom/xmldom": "0.9.10",
111
- "@bendyline/squisq": "2.5.0",
111
+ "@bendyline/squisq": "2.7.0",
112
112
  "jszip": "3.10.1",
113
113
  "pdf-lib": "1.17.1",
114
114
  "pdfjs-dist": "4.10.38"