@bendyline/squisq 1.5.0 → 1.5.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.
Files changed (124) hide show
  1. package/README.md +14 -1
  2. package/dist/{ContentContainer-DNx460y8.d.ts → ContentContainer-BXUlIf18.d.ts} +6 -2
  3. package/dist/{Doc-BsMkmzH8.d.ts → Doc-BBVGq1_9.d.ts} +94 -15
  4. package/dist/{ImageEditDoc-DvoeHMP9.d.ts → ImageEditDoc-FuyGtt6o.d.ts} +1 -1
  5. package/dist/{chunk-KZNXZ5SM.js → chunk-6ATE2PSM.js} +18 -7
  6. package/dist/chunk-6ATE2PSM.js.map +1 -0
  7. package/dist/{chunk-7MQGNR76.js → chunk-A4O7GIWE.js} +2 -27
  8. package/dist/chunk-A4O7GIWE.js.map +1 -0
  9. package/dist/chunk-ET53IIEP.js +1 -0
  10. package/dist/chunk-ET53IIEP.js.map +1 -0
  11. package/dist/{chunk-OKJOQXK4.js → chunk-HWVFJAAH.js} +38 -2
  12. package/dist/chunk-HWVFJAAH.js.map +1 -0
  13. package/dist/{chunk-2TMAWB4Y.js → chunk-IMSCRLLV.js} +1 -1
  14. package/dist/chunk-IMSCRLLV.js.map +1 -0
  15. package/dist/{chunk-4AKUQPEE.js → chunk-KKNUBQ6Y.js} +1 -1
  16. package/dist/chunk-KKNUBQ6Y.js.map +1 -0
  17. package/dist/{chunk-TVSGLUID.js → chunk-LDQ2HJIX.js} +3 -3
  18. package/dist/{chunk-4ZFRZBU2.js → chunk-LH7I6SH7.js} +777 -151
  19. package/dist/chunk-LH7I6SH7.js.map +1 -0
  20. package/dist/{chunk-K32VJONL.js → chunk-T5UK6YOB.js} +41 -2
  21. package/dist/chunk-T5UK6YOB.js.map +1 -0
  22. package/dist/{chunk-OH43RPTP.js → chunk-TEEEILMP.js} +12 -2
  23. package/dist/chunk-TEEEILMP.js.map +1 -0
  24. package/dist/{chunk-FR2RBTKO.js → chunk-TQWLI6S2.js} +93 -27
  25. package/dist/chunk-TQWLI6S2.js.map +1 -0
  26. package/dist/{chunk-LRCV7N7F.js → chunk-UY7KGQ5R.js} +2 -2
  27. package/dist/{chunk-3E5F2XMR.js → chunk-VWUFZ6ZG.js} +29 -2
  28. package/dist/chunk-VWUFZ6ZG.js.map +1 -0
  29. package/dist/doc/index.d.ts +4 -4
  30. package/dist/doc/index.js +16 -7
  31. package/dist/generate/index.d.ts +2 -80
  32. package/dist/generate/index.js +2 -7
  33. package/dist/imageEdit/index.d.ts +4 -4
  34. package/dist/index.d.ts +8 -8
  35. package/dist/index.js +32 -23
  36. package/dist/jsonForm/index.d.ts +42 -1
  37. package/dist/jsonForm/index.js +9 -1
  38. package/dist/markdown/index.d.ts +18 -2
  39. package/dist/markdown/index.js +5 -3
  40. package/dist/recommend/index.js +2 -2
  41. package/dist/schemas/index.d.ts +4 -4
  42. package/dist/schemas/index.js +3 -5
  43. package/dist/storage/index.d.ts +2 -2
  44. package/dist/storage/index.js +1 -1
  45. package/dist/story/index.d.ts +125 -11
  46. package/dist/story/index.js +16 -7
  47. package/dist/{themeLibrary-DQQKuRMx.d.ts → themeLibrary-CehcJhzz.d.ts} +1 -1
  48. package/dist/timing/index.js +3 -5
  49. package/dist/transform/index.d.ts +2 -2
  50. package/dist/transform/index.js +3 -3
  51. package/dist/versions/index.d.ts +1 -1
  52. package/package.json +1 -1
  53. package/src/__tests__/contentExtractor.test.ts +60 -0
  54. package/src/__tests__/coverBlock.test.ts +46 -1
  55. package/src/__tests__/customTemplateSample.test.ts +63 -2
  56. package/src/__tests__/customTemplatesFrontmatter.test.ts +31 -0
  57. package/src/__tests__/customThemesFrontmatter.test.ts +27 -0
  58. package/src/__tests__/inputDescriptors.test.ts +162 -0
  59. package/src/__tests__/jsonForm.tokens.test.ts +84 -0
  60. package/src/__tests__/markdown.test.ts +64 -0
  61. package/src/__tests__/markdownSanitize.test.ts +15 -0
  62. package/src/__tests__/markdownToDoc.test.ts +168 -0
  63. package/src/__tests__/mediaAnnotations.test.ts +27 -0
  64. package/src/__tests__/structuredData.test.ts +73 -3
  65. package/src/__tests__/templateMetadata.test.ts +11 -1
  66. package/src/__tests__/templates.test.ts +112 -0
  67. package/src/__tests__/validateDoc.test.ts +160 -0
  68. package/src/doc/annotationBlocks.ts +117 -0
  69. package/src/doc/customTemplatesFrontmatter.ts +7 -1
  70. package/src/doc/customThemesFrontmatter.ts +6 -1
  71. package/src/doc/docToMarkdown.ts +31 -1
  72. package/src/doc/getLayers.ts +11 -2
  73. package/src/doc/index.ts +12 -0
  74. package/src/doc/markdownToDoc.ts +80 -3
  75. package/src/doc/mediaAnnotations.ts +15 -33
  76. package/src/doc/standaloneAnnotation.ts +58 -0
  77. package/src/doc/structuredData.ts +92 -21
  78. package/src/doc/templates/__tests__/customTemplate.test.ts +21 -2
  79. package/src/doc/templates/comparisonBar.ts +8 -1
  80. package/src/doc/templates/coverBlock.ts +29 -2
  81. package/src/doc/templates/customTemplate.ts +10 -4
  82. package/src/doc/templates/factCard.ts +4 -2
  83. package/src/doc/templates/imageWithCaption.ts +10 -8
  84. package/src/doc/templates/index.ts +12 -2
  85. package/src/doc/templates/inputDescriptors.ts +432 -0
  86. package/src/doc/templates/photoGrid.ts +16 -39
  87. package/src/doc/templates/tokens/__tests__/resolveTokens.test.ts +267 -1
  88. package/src/doc/templates/tokens/resolveTokens.ts +0 -0
  89. package/src/doc/templates/videoWithCaption.ts +15 -14
  90. package/src/doc/utils/nearest.ts +59 -0
  91. package/src/doc/validate.ts +153 -54
  92. package/src/generate/contentExtractor.ts +148 -35
  93. package/src/generate/index.ts +0 -3
  94. package/src/jsonForm/index.ts +2 -0
  95. package/src/jsonForm/tokens.ts +78 -0
  96. package/src/markdown/annotationCoercion.ts +1 -1
  97. package/src/markdown/attrTokens.ts +19 -0
  98. package/src/markdown/index.ts +2 -1
  99. package/src/markdown/sanitize.ts +22 -2
  100. package/src/markdown/stringify.ts +12 -3
  101. package/src/markdown/utils.ts +62 -1
  102. package/src/schemas/CustomTemplates.ts +56 -4
  103. package/src/schemas/Doc.ts +39 -41
  104. package/src/schemas/themeCompile.ts +1 -1
  105. package/src/storage/ContentContainer.ts +6 -2
  106. package/src/transform/types.ts +1 -1
  107. package/dist/chunk-2TMAWB4Y.js.map +0 -1
  108. package/dist/chunk-3E5F2XMR.js.map +0 -1
  109. package/dist/chunk-4AKUQPEE.js.map +0 -1
  110. package/dist/chunk-4X3JQXNM.js +0 -35
  111. package/dist/chunk-4X3JQXNM.js.map +0 -1
  112. package/dist/chunk-4ZFRZBU2.js.map +0 -1
  113. package/dist/chunk-7MQGNR76.js.map +0 -1
  114. package/dist/chunk-FBKP5CAO.js +0 -145
  115. package/dist/chunk-FBKP5CAO.js.map +0 -1
  116. package/dist/chunk-FR2RBTKO.js.map +0 -1
  117. package/dist/chunk-K32VJONL.js.map +0 -1
  118. package/dist/chunk-KZNXZ5SM.js.map +0 -1
  119. package/dist/chunk-OH43RPTP.js.map +0 -1
  120. package/dist/chunk-OKJOQXK4.js.map +0 -1
  121. package/src/__tests__/slideshowGenerator.test.ts +0 -128
  122. package/src/generate/slideshowGenerator.ts +0 -280
  123. /package/dist/{chunk-TVSGLUID.js.map → chunk-LDQ2HJIX.js.map} +0 -0
  124. /package/dist/{chunk-LRCV7N7F.js.map → chunk-UY7KGQ5R.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/generate/contentExtractor.ts","../src/generate/templateMapper.ts"],"sourcesContent":["/**\n * Content Extractor\n *\n * Pattern-based extraction of compelling content from plain text.\n * Identifies statistics, dates, quotes, comparisons, facts, impact lines,\n * lists, and definitions that can be turned into slideshow slides.\n *\n * Extraction is purely regex-based — no AI calls, no runtime costs,\n * deterministic and reproducible.\n */\n\n// ── Types ──────────────────────────────────────────────────────────\n\n/** Kinds of content the extractor recognises. */\nexport type ExtractionType =\n | 'stat'\n | 'date'\n | 'quote'\n | 'comparison'\n | 'fact'\n | 'impactLine'\n | 'list'\n | 'definition';\n\n/** An extracted content element with source position. */\nexport interface ExtractedElement {\n type: ExtractionType;\n /** Full extracted text (usually the surrounding sentence). */\n text: string;\n /** Confidence score 0–1. */\n confidence: number;\n /** Character offset in the source text. */\n sourcePosition: number;\n /** Character offset where element ends. */\n endPosition: number;\n /** Type-specific structured payload. */\n data:\n | StatData\n | DateData\n | QuoteData\n | ComparisonData\n | FactData\n | ImpactLineData\n | ListData\n | DefinitionData;\n}\n\nexport interface StatData {\n type: 'stat';\n value: string;\n unit?: string;\n description: string;\n}\n\nexport interface DateData {\n type: 'date';\n date: string;\n description: string;\n mood?: 'neutral' | 'somber' | 'celebratory';\n}\n\nexport interface QuoteData {\n type: 'quote';\n quote: string;\n attribution?: string;\n}\n\nexport interface ComparisonData {\n type: 'comparison';\n left: { label: string; sublabel?: string };\n right: { label: string; sublabel?: string };\n header?: string;\n}\n\nexport interface FactData {\n type: 'fact';\n fact: string;\n explanation?: string;\n}\n\nexport interface ImpactLineData {\n type: 'impactLine';\n text: string;\n}\n\nexport interface ListData {\n type: 'list';\n items: string[];\n title?: string;\n}\n\nexport interface DefinitionData {\n type: 'definition';\n term: string;\n definition: string;\n origin?: string;\n}\n\n/** Options for `extractContent`. */\nexport interface ExtractionOptions {\n /** Minimum confidence threshold (default: 0.3). */\n minConfidence?: number;\n /** Which types to extract (default: all). */\n types?: ExtractionType[];\n /** Maximum extractions per type (default: unlimited). */\n maxPerType?: number;\n}\n\n/** Result of `extractContent`. */\nexport interface ExtractionResult {\n elements: ExtractedElement[];\n sourceLength: number;\n stats: {\n statCount: number;\n dateCount: number;\n quoteCount: number;\n comparisonCount: number;\n factCount: number;\n impactLineCount: number;\n listCount: number;\n definitionCount: number;\n totalCount: number;\n };\n}\n\n// ── Patterns ───────────────────────────────────────────────────────\n\nconst STAT_PATTERNS = [\n /\\b(roughly |about |approximately |nearly |over |under |more than |less than )?([\\d,]+(?:\\.\\d+)?)\\s*%/gi,\n /\\b([\\d,]+(?:\\.\\d+)?)\\s*(million|billion|trillion|thousand|hundred)\\b/gi,\n /\\b([\\d,]+(?:\\.\\d+)?)\\s*(miles?|feet|ft|meters?|m|kilometers?|km|acres?|square miles?|sq mi|hectares?)\\b/gi,\n /\\b([\\d,]+(?:\\.\\d+)?)\\s*(x|times)\\b/gi,\n /\\b([$€£¥])\\s*([\\d,]+(?:\\.\\d+)?)\\s*(million|billion|thousand)?\\b/gi,\n /\\b(\\d+)(st|nd|rd|th)\\s+(largest|smallest|oldest|newest|most|least)/gi,\n];\n\nconst DATE_PATTERNS = [\n /\\b(January|February|March|April|May|June|July|August|September|October|November|December)\\s+(\\d{1,2},?\\s+)?(\\d{4})\\b/gi,\n /\\b(\\d{4})s\\b|\\b(\\d{1,2})(st|nd|rd|th)\\s+century\\b/gi,\n /\\b(from\\s+)?(\\d{4})\\s*(to|–|-|through)\\s*(\\d{4})\\b/gi,\n /\\b(in|by|since|after|before|during)\\s+(\\d{4})\\b/gi,\n];\n\nconst QUOTE_PATTERNS = [\n /\"([^\"]{15,200})\"/g,\n /\\u201c([^\\u201d]{15,200})\\u201d/g,\n /(\\w+(?:\\s+\\w+)?)\\s+(?:said|stated|wrote|noted|observed|commented),?\\s*\"([^\"]+)\"/gi,\n];\n\n// A single side of a comparison (\"X\" in \"from X to Y\"). Deliberately excludes\n// sentence/clause terminators (. ! ? ;) and newlines so a capture group can\n// never swallow text from an adjacent sentence. Without this, greedy `.{2,30}`\n// matches across a period — e.g. \"…contradicted from witness to witness.\n// Robertson said…\" yields right=\"witness. Robertson\", producing a nonsensical\n// \"witness → witness. Robertson\" slide. Commas and colons are allowed (ranges\n// like \"9:00 to 17:00\", ratios); downstream label truncation trims commas.\nconst COMPARISON_SIDE = '[^.!?;\\\\r\\\\n]{2,30}';\n\nconst COMPARISON_PATTERNS = [\n new RegExp(`from\\\\s+(${COMPARISON_SIDE})\\\\s+to\\\\s+(${COMPARISON_SIDE})`, 'gi'),\n new RegExp(`(${COMPARISON_SIDE})\\\\s+(?:vs\\\\.?|versus)\\\\s+(${COMPARISON_SIDE})`, 'gi'),\n new RegExp(`(${COMPARISON_SIDE})\\\\s+compared\\\\s+to\\\\s+(${COMPARISON_SIDE})`, 'gi'),\n];\n\n// Words whose trailing period is an abbreviation, not a sentence end. Used by\n// isSentenceBoundary() so names like \"George W. Tibbetts\" or \"Quong Chong & Co.\"\n// don't get split into fragments. Matched only when the entire preceding word\n// equals one of these (case-insensitive), so \"canal.\" / \"taco.\" are unaffected.\nconst SENTENCE_ABBREVIATIONS = new Set([\n 'mr',\n 'mrs',\n 'ms',\n 'dr',\n 'prof',\n 'st',\n 'mt',\n 'jr',\n 'sr',\n 'gen',\n 'col',\n 'capt',\n 'lt',\n 'sgt',\n 'rev',\n 'hon',\n 'sen',\n 'rep',\n 'gov',\n 'pres',\n 'vs',\n 'etc',\n 'inc',\n 'co',\n 'ltd',\n 'corp',\n 'al',\n 'fig',\n 'eg',\n 'ie',\n 'approx',\n 'dept',\n 'univ',\n 'assn',\n 'bros',\n 'ave',\n 'blvd',\n 'rd',\n]);\n\nconst FACT_INDICATORS = [\n 'largest',\n 'smallest',\n 'oldest',\n 'newest',\n 'first',\n 'last',\n 'most',\n 'least',\n 'only',\n 'unique',\n 'rare',\n 'famous',\n 'important',\n 'significant',\n 'notable',\n 'remarkable',\n 'extraordinary',\n 'crucial',\n 'essential',\n 'critical',\n 'major',\n 'key',\n 'discovered',\n 'founded',\n 'established',\n 'created',\n 'built',\n 'invented',\n 'developed',\n 'introduced',\n 'pioneered',\n 'transformed',\n 'revolutionized',\n 'changed',\n 'shaped',\n];\n\nconst SOMBER_INDICATORS = [\n 'disaster',\n 'tragedy',\n 'death',\n 'died',\n 'killed',\n 'destroyed',\n 'devastated',\n 'collapsed',\n 'lost',\n 'abandoned',\n 'declined',\n 'war',\n 'battle',\n 'conflict',\n 'earthquake',\n 'fire',\n 'flood',\n];\n\nconst CELEBRATORY_INDICATORS = [\n 'celebration',\n 'victory',\n 'success',\n 'achievement',\n 'triumph',\n 'opened',\n 'completed',\n 'inaugurated',\n 'launched',\n 'won',\n 'record',\n 'breakthrough',\n 'milestone',\n 'golden',\n 'grand',\n];\n\nconst IMPACT_VERBS = [\n 'check',\n 'watch',\n 'stop',\n 'prepare',\n 'imagine',\n 'consider',\n 'look',\n 'listen',\n 'notice',\n 'remember',\n 'discover',\n 'explore',\n 'visit',\n 'try',\n 'experience',\n 'avoid',\n 'beware',\n 'enjoy',\n];\n\nconst LIST_PATTERNS = [\n /(?:including|such as|namely|like|features?|offers?)\\s+([^.]{10,150})/gi,\n /(?:three|four|five|six|several|many|various)\\s+(?:main|key|primary|notable|popular|important)?\\s*\\w+(?:\\s+\\w+)?:\\s*([^.]{10,150})/gi,\n];\n\nconst DEFINITION_PATTERNS = [\n /\\b([A-Z][a-z]+(?:\\s+[A-Z]?[a-z]+){0,3})\\s+is\\s+(?:a|an|the)\\s+([^.]{10,120})/g,\n /known\\s+as\\s+([A-Z][a-z]+(?:\\s+[A-Z]?[a-z]+){0,3}),\\s+([^.]{10,120})/gi,\n /\\b([A-Z][a-z]+(?:\\s+[A-Z]?[a-z]+){0,3})\\s+refers?\\s+to\\s+([^.]{10,120})/g,\n /called\\s+([A-Z][a-z]+(?:\\s+[A-Z]?[a-z]+){0,3}),?\\s+(?:which|meaning|a)\\s+([^.]{10,120})/gi,\n];\n\n// ── Main ───────────────────────────────────────────────────────────\n\n/**\n * Extract compelling content from plain text.\n *\n * Call `stripMarkdown(text)` first if the input contains markdown.\n */\nexport function extractContent(text: string, options: ExtractionOptions = {}): ExtractionResult {\n const {\n minConfidence = 0.3,\n types = ['stat', 'date', 'quote', 'comparison', 'fact', 'impactLine', 'list', 'definition'],\n maxPerType,\n } = options;\n\n const elements: ExtractedElement[] = [];\n\n if (types.includes('stat')) elements.push(...extractStats(text));\n if (types.includes('date')) elements.push(...extractDates(text));\n if (types.includes('quote')) elements.push(...extractQuotes(text));\n if (types.includes('comparison')) elements.push(...extractComparisons(text));\n if (types.includes('fact')) elements.push(...extractFacts(text));\n if (types.includes('impactLine')) elements.push(...extractImpactLines(text));\n if (types.includes('list')) elements.push(...extractLists(text));\n if (types.includes('definition')) elements.push(...extractDefinitions(text));\n\n let filtered = elements.filter((e) => e.confidence >= minConfidence);\n\n if (maxPerType !== undefined) {\n const byType = new Map<ExtractionType, ExtractedElement[]>();\n for (const elem of filtered) {\n const list = byType.get(elem.type) || [];\n list.push(elem);\n byType.set(elem.type, list);\n }\n filtered = [];\n for (const [, list] of byType) {\n list.sort((a, b) => b.confidence - a.confidence);\n filtered.push(...list.slice(0, maxPerType));\n }\n }\n\n filtered.sort((a, b) => a.sourcePosition - b.sourcePosition);\n filtered = deduplicateOverlapping(filtered);\n\n return {\n elements: filtered,\n sourceLength: text.length,\n stats: {\n statCount: filtered.filter((e) => e.type === 'stat').length,\n dateCount: filtered.filter((e) => e.type === 'date').length,\n quoteCount: filtered.filter((e) => e.type === 'quote').length,\n comparisonCount: filtered.filter((e) => e.type === 'comparison').length,\n factCount: filtered.filter((e) => e.type === 'fact').length,\n impactLineCount: filtered.filter((e) => e.type === 'impactLine').length,\n listCount: filtered.filter((e) => e.type === 'list').length,\n definitionCount: filtered.filter((e) => e.type === 'definition').length,\n totalCount: filtered.length,\n },\n };\n}\n\n// ── Per-type extractors ────────────────────────────────────────────\n\nfunction extractStats(text: string): ExtractedElement[] {\n const elements: ExtractedElement[] = [];\n const seen = new Set<number>();\n\n for (const pattern of STAT_PATTERNS) {\n pattern.lastIndex = 0;\n let match;\n while ((match = pattern.exec(text)) !== null) {\n const position = match.index;\n if (seen.has(position)) continue;\n seen.add(position);\n\n const context = getSentenceContext(text, position, match[0].length);\n const value = match[0].trim();\n\n elements.push({\n type: 'stat',\n text: context.sentence,\n confidence: calculateStatConfidence(value, context.sentence),\n sourcePosition: context.start,\n endPosition: context.end,\n data: { type: 'stat', value, description: cleanDescription(context.sentence, value) },\n });\n }\n }\n return elements;\n}\n\nfunction extractDates(text: string): ExtractedElement[] {\n const elements: ExtractedElement[] = [];\n const seen = new Set<number>();\n\n for (const pattern of DATE_PATTERNS) {\n pattern.lastIndex = 0;\n let match;\n while ((match = pattern.exec(text)) !== null) {\n const position = match.index;\n if (seen.has(position)) continue;\n seen.add(position);\n\n const context = getSentenceContext(text, position, match[0].length);\n const dateStr = match[0].trim();\n\n elements.push({\n type: 'date',\n text: context.sentence,\n confidence: calculateDateConfidence(dateStr, context.sentence),\n sourcePosition: context.start,\n endPosition: context.end,\n data: {\n type: 'date',\n date: dateStr,\n description: cleanDescription(context.sentence, dateStr),\n mood: detectMood(context.sentence),\n },\n });\n }\n }\n return elements;\n}\n\nfunction extractQuotes(text: string): ExtractedElement[] {\n const elements: ExtractedElement[] = [];\n const seen = new Set<number>();\n\n for (const pattern of QUOTE_PATTERNS) {\n pattern.lastIndex = 0;\n let match;\n while ((match = pattern.exec(text)) !== null) {\n const position = match.index;\n if (seen.has(position)) continue;\n seen.add(position);\n\n const quote = match.length > 2 ? match[2] : match[1];\n const attribution = match.length > 2 ? match[1] : undefined;\n if (quote.length < 15 || quote.length > 200) continue;\n\n elements.push({\n type: 'quote',\n text: match[0],\n confidence: calculateQuoteConfidence(quote),\n sourcePosition: position,\n endPosition: position + match[0].length,\n data: { type: 'quote', quote: quote.trim(), attribution: attribution?.trim() },\n });\n }\n }\n return elements;\n}\n\nfunction extractComparisons(text: string): ExtractedElement[] {\n const elements: ExtractedElement[] = [];\n const seen = new Set<number>();\n\n for (const pattern of COMPARISON_PATTERNS) {\n pattern.lastIndex = 0;\n let match;\n while ((match = pattern.exec(text)) !== null) {\n const position = match.index;\n if (seen.has(position)) continue;\n seen.add(position);\n\n // Trim a trailing clause introduced by a comma + space (\"retired\n // airliners, arranged in rows\" → \"retired airliners\"). A greedy side\n // match often swallows the words after the compared thing; the comma is a\n // clause boundary, not part of the value. Numeric grouping commas\n // (\"4,000\") survive because those are comma+digit, not comma+space.\n const trimClause = (s: string) => s.replace(/,\\s+.*$/, '').trim();\n const left = trimClause(match[1].trim());\n const right = trimClause(match[2].trim());\n if (left.length < 2 || left.length > 30) continue;\n if (right.length < 2 || right.length > 30) continue;\n // Reject \"from X to X\"-style idioms — \"from witness to witness\",\n // \"from day to day\", \"from generation to generation\". These mean \"it\n // varied\", not \"A versus B\", and render as a pointless \"X → X\" card.\n // The signature is a word repeated across the connector: the last word\n // of the left side equals the first word of the right side. (Greedy\n // matching may append trailing context to the right side, so a whole-\n // string equality check is not enough.)\n const wordsOf = (s: string) =>\n s\n .toLowerCase()\n .split(/\\s+/)\n .map((w) => w.replace(/[^a-z0-9]+/g, ''))\n .filter(Boolean);\n const leftWords = wordsOf(left);\n const rightWords = wordsOf(right);\n if (\n leftWords.length > 0 &&\n rightWords.length > 0 &&\n leftWords[leftWords.length - 1] === rightWords[0]\n ) {\n continue;\n }\n\n const context = getSentenceContext(text, position, match[0].length);\n\n elements.push({\n type: 'comparison',\n text: context.sentence,\n confidence: 0.6,\n sourcePosition: context.start,\n endPosition: context.end,\n data: { type: 'comparison', left: { label: left }, right: { label: right } },\n });\n }\n }\n return elements;\n}\n\n/**\n * Whether the `. ! ?` at `index` is a real sentence terminator rather than a\n * period inside an abbreviation (\"George W. Tibbetts\", \"M. DeWitt\", \"Mr.\",\n * \"U.S.\"), a single-letter initial, a decimal (\"3.5\"), or an ellipsis. Naive\n * splitting on every period produces broken fragments — e.g. the standalone\n * slide \"They were met at George W\" from \"…at George W. Tibbetts' store…\".\n * Returns false for any non-terminator character so callers can scan freely.\n */\nfunction isSentenceBoundary(text: string, index: number): boolean {\n const ch = text[index];\n if (ch === '!' || ch === '?') return true;\n if (ch !== '.') return false;\n\n // Ellipsis: defer the boundary to the final dot in a run of dots.\n if (text[index + 1] === '.') return false;\n // Decimal number: digit \".\" digit → \"3.5\".\n if (/[0-9]/.test(text[index - 1] ?? '') && /[0-9]/.test(text[index + 1] ?? '')) return false;\n\n // The run of letters immediately preceding the period.\n let w = index - 1;\n while (w >= 0 && /[A-Za-z]/.test(text[w])) w--;\n const word = text.slice(w + 1, index);\n if (word.length === 1) return false; // single-letter initial: \"George W.\"\n if (word && SENTENCE_ABBREVIATIONS.has(word.toLowerCase())) return false;\n\n // A genuine sentence starts with an uppercase letter, digit, or opening\n // quote/bracket. A lowercase continuation means the period was mid-sentence\n // (an abbreviation we didn't enumerate).\n let j = index + 1;\n while (j < text.length && /\\s/.test(text[j])) j++;\n if (j >= text.length) return true; // end of text\n return !/[a-z]/.test(text[j]);\n}\n\n/**\n * Iterate over sentence-like spans in the text, yielding trimmed text and\n * accurate start/end indices within the original string.\n *\n * Boundaries are detected by isSentenceBoundary() so abbreviations, initials,\n * decimals, and ellipses do not split a sentence. Leading whitespace and\n * trailing whitespace/terminators are excluded from each span.\n */\nfunction forEachSentenceSpan(\n text: string,\n callback: (trimmed: string, start: number, end: number) => void,\n): void {\n const emit = (rawStart: number, rawEnd: number) => {\n let start = rawStart;\n while (start < rawEnd && /\\s/.test(text[start])) start++;\n let end = rawEnd;\n while (end > start && /[\\s.!?]/.test(text[end - 1])) end--;\n if (end <= start) return;\n const trimmed = text.slice(start, end);\n if (trimmed) callback(trimmed, start, end);\n };\n\n let spanStart = 0;\n let i = 0;\n while (i < text.length) {\n if (isSentenceBoundary(text, i)) {\n // Consume any consecutive terminators (\"?!\", \"…\") as one boundary.\n let end = i + 1;\n while (end < text.length && /[.!?]/.test(text[end])) end++;\n emit(spanStart, end);\n spanStart = end;\n i = end;\n } else {\n i++;\n }\n }\n if (spanStart < text.length) emit(spanStart, text.length);\n}\n\nfunction extractFacts(text: string): ExtractedElement[] {\n const elements: ExtractedElement[] = [];\n\n forEachSentenceSpan(text, (trimmed, start, end) => {\n if (trimmed.length <= 20) return;\n\n const score = scoreSentenceAsFact(trimmed);\n if (score < 0.4) return;\n\n elements.push({\n type: 'fact',\n text: trimmed,\n confidence: score,\n sourcePosition: start,\n endPosition: end,\n data: { type: 'fact', fact: trimmed },\n });\n });\n\n return elements;\n}\n\nfunction extractImpactLines(text: string): ExtractedElement[] {\n const elements: ExtractedElement[] = [];\n\n forEachSentenceSpan(text, (trimmed, start, end) => {\n if (trimmed.length < 8 || trimmed.length > 60) return;\n\n let score = 0.3;\n const lower = trimmed.toLowerCase();\n\n for (const verb of IMPACT_VERBS) {\n if (lower.startsWith(verb)) {\n score += 0.25;\n break;\n }\n }\n\n if (end < text.length && text[end] === '!') score += 0.15;\n if (trimmed.length < 30) score += 0.1;\n if (trimmed.includes(',')) score -= 0.1;\n if (/^(and|but|or|the|a|an)\\b/i.test(trimmed)) score -= 0.15;\n if (score < 0.5) return;\n\n elements.push({\n type: 'impactLine',\n text: trimmed,\n confidence: Math.min(1, score),\n sourcePosition: start,\n endPosition: end,\n data: { type: 'impactLine', text: trimmed },\n });\n });\n\n return elements;\n}\n\nfunction extractLists(text: string): ExtractedElement[] {\n const elements: ExtractedElement[] = [];\n const seen = new Set<number>();\n\n for (const pattern of LIST_PATTERNS) {\n pattern.lastIndex = 0;\n let match;\n while ((match = pattern.exec(text)) !== null) {\n const position = match.index;\n if (seen.has(position)) continue;\n seen.add(position);\n\n const listContent = match[1].trim();\n const items = listContent\n .split(/,\\s*(?:and|or)\\s+|,\\s+|\\s+and\\s+|\\s+or\\s+/)\n .map((item) => item.trim())\n .filter((item) => item.length >= 2 && item.length <= 60);\n\n if (items.length < 3 || items.length > 5) continue;\n\n const context = getSentenceContext(text, position, match[0].length);\n\n elements.push({\n type: 'list',\n text: context.sentence,\n confidence: 0.65,\n sourcePosition: context.start,\n endPosition: context.end,\n data: { type: 'list', items },\n });\n }\n }\n return elements;\n}\n\nfunction extractDefinitions(text: string): ExtractedElement[] {\n const elements: ExtractedElement[] = [];\n const seen = new Set<number>();\n\n for (const pattern of DEFINITION_PATTERNS) {\n pattern.lastIndex = 0;\n let match;\n while ((match = pattern.exec(text)) !== null) {\n const position = match.index;\n if (seen.has(position)) continue;\n seen.add(position);\n\n const term = match[1].trim();\n const definition = match[2].trim();\n if (term.length < 3 || term.length > 30) continue;\n if (definition.length < 10 || definition.length > 120) continue;\n\n const context = getSentenceContext(text, position, match[0].length);\n\n elements.push({\n type: 'definition',\n text: context.sentence,\n confidence: 0.6,\n sourcePosition: context.start,\n endPosition: context.end,\n data: { type: 'definition', term, definition },\n });\n }\n }\n return elements;\n}\n\n// ── Helpers ────────────────────────────────────────────────────────\n\nfunction getSentenceContext(\n text: string,\n matchStart: number,\n matchLength: number,\n): { sentence: string; start: number; end: number } {\n let start = matchStart;\n while (start > 0 && !isSentenceBoundary(text, start - 1)) start--;\n while (start < matchStart && /\\s/.test(text[start])) start++;\n\n let end = matchStart + matchLength;\n while (end < text.length && !isSentenceBoundary(text, end)) end++;\n if (end < text.length) end++;\n\n return { sentence: text.slice(start, end).trim(), start, end };\n}\n\nfunction calculateStatConfidence(value: string, context: string): number {\n let score = 0.5;\n if (value.includes('%')) score += 0.2;\n if (/million|billion|trillion/i.test(value)) score += 0.15;\n if (/increased|decreased|grew|dropped|rose|fell/i.test(context)) score += 0.15;\n if (context.length < 30) score -= 0.2;\n return Math.min(1, Math.max(0, score));\n}\n\nfunction calculateDateConfidence(date: string, context: string): number {\n let score = 0.5;\n if (\n /January|February|March|April|May|June|July|August|September|October|November|December/i.test(\n date,\n )\n )\n score += 0.2;\n if (/founded|established|built|opened|discovered|created/i.test(context)) score += 0.2;\n if (/happened|occurred|took place|began|ended/i.test(context)) score += 0.15;\n return Math.min(1, Math.max(0, score));\n}\n\nfunction calculateQuoteConfidence(quote: string): number {\n let score = 0.5;\n if (quote.length >= 30 && quote.length <= 150) score += 0.2;\n if (/\\b(I|we|our|my)\\b/i.test(quote)) score += 0.1;\n if (!/[.!?]$/.test(quote)) score -= 0.1;\n return Math.min(1, Math.max(0, score));\n}\n\nfunction scoreSentenceAsFact(sentence: string): number {\n let score = 0.3;\n const lower = sentence.toLowerCase();\n for (const indicator of FACT_INDICATORS) {\n if (lower.includes(indicator)) {\n score += 0.1;\n break;\n }\n }\n const properNouns = sentence.match(/\\b[A-Z][a-z]+\\b/g);\n if (properNouns && properNouns.length >= 2) score += 0.15;\n if (/\\d/.test(sentence)) score += 0.1;\n if (sentence.endsWith('?')) score -= 0.3;\n if (sentence.length > 200) score -= 0.15;\n return Math.min(1, Math.max(0, score));\n}\n\nfunction detectMood(sentence: string): 'neutral' | 'somber' | 'celebratory' {\n const lower = sentence.toLowerCase();\n for (const word of SOMBER_INDICATORS) {\n if (lower.includes(word)) return 'somber';\n }\n for (const word of CELEBRATORY_INDICATORS) {\n if (lower.includes(word)) return 'celebratory';\n }\n return 'neutral';\n}\n\nfunction cleanDescription(sentence: string, value: string): string {\n const prepositionPatterns = [\n new RegExp(`\\\\b[Ii]n\\\\s+${escapeRegex(value)}[,.]?\\\\s*`, 'g'),\n new RegExp(`\\\\b[Oo]n\\\\s+${escapeRegex(value)}[,.]?\\\\s*`, 'g'),\n new RegExp(`\\\\b[Dd]uring\\\\s+${escapeRegex(value)}[,.]?\\\\s*`, 'g'),\n new RegExp(`\\\\b[Bb]y\\\\s+${escapeRegex(value)}[,.]?\\\\s*`, 'g'),\n new RegExp(`\\\\b[Ss]ince\\\\s+${escapeRegex(value)}[,.]?\\\\s*`, 'g'),\n new RegExp(`\\\\b[Ff]rom\\\\s+${escapeRegex(value)}[,.]?\\\\s*`, 'g'),\n ];\n\n let desc = sentence;\n for (const pattern of prepositionPatterns) {\n desc = desc.replace(pattern, '');\n }\n if (desc === sentence) {\n desc = sentence.replace(value, '').trim();\n }\n\n desc = desc.replace(/^[,:\\-–—]+\\s*/, '').replace(/\\s*[,:\\-–—]+$/, '');\n desc = desc.replace(\n /\\s+(?:of|on|in|at|by|to|for|from|with|about|over|under|between|than|into|onto|upon)\\s*([,.])/gi,\n '$1',\n );\n desc = desc.replace(\n /\\s+(?:for|of|to|in|at|by|with|from|about|over|under|between|than|into|onto|upon)\\s*[.!?]?\\s*$/i,\n '.',\n );\n desc = desc.replace(/\\s{2,}/g, ' ').replace(/\\s+([,.])/g, '$1');\n desc = desc.charAt(0).toUpperCase() + desc.slice(1);\n return desc.trim();\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nconst TYPE_SPECIFICITY: Record<ExtractionType, number> = {\n stat: 5,\n date: 4,\n quote: 3,\n definition: 3,\n comparison: 2,\n list: 2,\n impactLine: 2,\n fact: 1,\n};\n\nfunction deduplicateOverlapping(elements: ExtractedElement[]): ExtractedElement[] {\n if (elements.length <= 1) return elements;\n\n const toRemove = new Set<number>();\n\n for (let i = 0; i < elements.length; i++) {\n if (toRemove.has(i)) continue;\n const a = elements[i];\n\n for (let j = i + 1; j < elements.length; j++) {\n if (toRemove.has(j)) continue;\n const b = elements[j];\n\n if (elementsOverlap(a, b)) {\n const aSpec = TYPE_SPECIFICITY[a.type];\n const bSpec = TYPE_SPECIFICITY[b.type];\n if (aSpec >= bSpec) {\n toRemove.add(j);\n } else {\n toRemove.add(i);\n break;\n }\n }\n }\n }\n\n return elements.filter((_, index) => !toRemove.has(index));\n}\n\nfunction elementsOverlap(a: ExtractedElement, b: ExtractedElement): boolean {\n if (a.sourcePosition === b.sourcePosition) return true;\n if (a.sourcePosition <= b.sourcePosition && a.endPosition >= b.endPosition) return true;\n if (b.sourcePosition <= a.sourcePosition && b.endPosition >= a.endPosition) return true;\n\n const overlapStart = Math.max(a.sourcePosition, b.sourcePosition);\n const overlapEnd = Math.min(a.endPosition, b.endPosition);\n if (overlapEnd > overlapStart) {\n const overlapLength = overlapEnd - overlapStart;\n const minLength = Math.min(a.endPosition - a.sourcePosition, b.endPosition - b.sourcePosition);\n if (overlapLength > minLength * 0.5) return true;\n }\n\n return false;\n}\n\n/**\n * Strip markdown formatting from text, returning plain prose.\n * Call this before `extractContent` if the input is markdown.\n */\nexport function stripMarkdown(markdown: string): string {\n return (\n markdown\n // Remove code blocks (before inline code)\n .replace(/```[\\s\\S]*?```/g, '')\n // Remove images (before links — `![` prefix distinguishes them)\n .replace(/!\\[([^\\]]*)\\]\\([^)]+\\)/g, '')\n // Remove links, keeping text\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, '$1')\n .replace(/^#{1,6}\\s+/gm, '')\n .replace(/\\*\\*([^*]+)\\*\\*/g, '$1')\n .replace(/\\*([^*]+)\\*/g, '$1')\n .replace(/__([^_]+)__/g, '$1')\n .replace(/_([^_]+)_/g, '$1')\n .replace(/`([^`]+)`/g, '$1')\n .replace(/^>\\s+/gm, '')\n .replace(/^[-*_]{3,}$/gm, '')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim()\n );\n}\n","/**\n * Template Mapper\n *\n * Converts extracted content elements into squisq TemplateBlock inputs.\n * Each ExtractionType maps to a specific template from BlockTemplates.\n */\n\nimport type {\n ExtractedElement,\n StatData,\n DateData,\n QuoteData,\n ComparisonData,\n FactData,\n ImpactLineData,\n ListData,\n DefinitionData,\n} from './contentExtractor.js';\n\nimport type {\n StatHighlightInput,\n QuoteBlockInput,\n FactCardInput,\n TwoColumnInput,\n DateEventInput,\n FullBleedQuoteInput,\n ListBlockInput,\n DefinitionCardInput,\n TemplateBlock,\n ColorScheme,\n AccentImage,\n} from '../schemas/BlockTemplates.js';\n\n/** Options for mapping an element to a template block. */\nexport interface MapOptions {\n id: string;\n duration: number;\n audioSegment: number;\n colorScheme?: ColorScheme;\n accentImage?: AccentImage;\n sourceStartTime?: number;\n sourceDuration?: number;\n}\n\n/**\n * Convert an extracted element into the matching squisq TemplateBlock.\n */\nexport function mapElementToBlock(element: ExtractedElement, options: MapOptions): TemplateBlock {\n const base = {\n id: options.id,\n duration: options.duration,\n audioSegment: options.audioSegment,\n sourceStartTime: options.sourceStartTime,\n sourceDuration: options.sourceDuration,\n };\n\n switch (element.data.type) {\n case 'stat':\n return mapStat(element.data, base, options);\n case 'date':\n return mapDate(element.data, base, options);\n case 'quote':\n return mapQuote(element.data, base, options);\n case 'comparison':\n return mapComparison(element.data, base, options);\n case 'fact':\n return mapFact(element.data, base, options);\n case 'impactLine':\n return mapImpactLine(element.data, base, options);\n case 'list':\n return mapList(element.data, base, options);\n case 'definition':\n return mapDefinition(element.data, base, options);\n }\n}\n\n// ── Per-type mappers ───────────────────────────────────────────────\n\ntype Base = {\n id: string;\n duration: number;\n audioSegment: number;\n sourceStartTime?: number;\n sourceDuration?: number;\n};\n\nfunction mapStat(data: StatData, base: Base, opts: MapOptions): StatHighlightInput {\n return {\n ...base,\n template: 'statHighlight',\n stat: data.value,\n description: data.description,\n colorScheme: opts.colorScheme,\n accentImage: opts.accentImage,\n };\n}\n\nfunction mapDate(data: DateData, base: Base, opts: MapOptions): DateEventInput {\n return {\n ...base,\n template: 'dateEvent',\n date: data.date,\n description: data.description,\n mood: data.mood,\n accentImage: opts.accentImage,\n };\n}\n\nfunction mapQuote(data: QuoteData, base: Base, opts: MapOptions): QuoteBlockInput {\n return {\n ...base,\n template: 'quote',\n quote: data.quote,\n attribution: data.attribution,\n accentImage: opts.accentImage,\n };\n}\n\nfunction mapComparison(data: ComparisonData, base: Base, opts: MapOptions): TwoColumnInput {\n return {\n ...base,\n template: 'twoColumn',\n left: data.left,\n right: data.right,\n header: data.header,\n leftColor: opts.colorScheme,\n };\n}\n\nfunction mapFact(data: FactData, base: Base, opts: MapOptions): FactCardInput {\n return {\n ...base,\n template: 'factCard',\n fact: data.fact,\n explanation: data.explanation ?? '',\n accentImage: opts.accentImage,\n };\n}\n\nfunction mapImpactLine(data: ImpactLineData, base: Base, opts: MapOptions): FullBleedQuoteInput {\n return {\n ...base,\n template: 'fullBleedQuote',\n text: data.text,\n colorScheme: opts.colorScheme,\n };\n}\n\nfunction mapList(data: ListData, base: Base, opts: MapOptions): ListBlockInput {\n return {\n ...base,\n template: 'list',\n items: data.items,\n title: data.title,\n colorScheme: opts.colorScheme,\n accentImage: opts.accentImage,\n };\n}\n\nfunction mapDefinition(data: DefinitionData, base: Base, opts: MapOptions): DefinitionCardInput {\n return {\n ...base,\n template: 'definitionCard',\n term: data.term,\n definition: data.definition,\n origin: data.origin,\n colorScheme: opts.colorScheme,\n accentImage: opts.accentImage,\n };\n}\n"],"mappings":"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","names":[]}
@@ -2,7 +2,7 @@ import {
2
2
  extractPlainText,
3
3
  findNodesByType,
4
4
  walkMarkdownTree
5
- } from "./chunk-OKJOQXK4.js";
5
+ } from "./chunk-HWVFJAAH.js";
6
6
 
7
7
  // src/recommend/templates.ts
8
8
  var EMPTY_PROFILE = Object.freeze({
@@ -189,4 +189,4 @@ export {
189
189
  pickAutoTemplate,
190
190
  recommendTemplatesForBlock
191
191
  };
192
- //# sourceMappingURL=chunk-LRCV7N7F.js.map
192
+ //# sourceMappingURL=chunk-UY7KGQ5R.js.map
@@ -118,12 +118,39 @@ function estimateNarrationDuration(text, wordsPerSecond = DEFAULT_WORDS_PER_SECO
118
118
  return spokenWords / wordsPerSecond;
119
119
  }
120
120
 
121
+ // src/timing/readingTime.ts
122
+ var DEFAULT_READING_WPM = 200;
123
+ function estimateReadingTime(text, options) {
124
+ const configuredWpm = options?.wordsPerMinute;
125
+ const wpm = typeof configuredWpm === "number" && configuredWpm > 0 ? configuredWpm : DEFAULT_READING_WPM;
126
+ const words = text.split(/\s+/).filter((w) => w.length > 0).length;
127
+ const minutes = words / wpm;
128
+ return {
129
+ words,
130
+ minutes,
131
+ seconds: Math.round(minutes * 60)
132
+ };
133
+ }
134
+ function estimateNarrationTime(text, options) {
135
+ const providedWps = options?.wordsPerSecond;
136
+ const wps = typeof providedWps === "number" && providedWps > 0 ? providedWps : DEFAULT_WORDS_PER_SECOND;
137
+ const spokenWords = countSpokenWords(text);
138
+ const totalSeconds = spokenWords / wps;
139
+ return {
140
+ spokenWords,
141
+ minutes: totalSeconds / 60,
142
+ seconds: Math.round(totalSeconds)
143
+ };
144
+ }
145
+
121
146
  export {
122
147
  DEFAULT_WORDS_PER_SECOND,
123
148
  estimateSpokenWordCount,
124
149
  countSpokenWords,
125
150
  estimateTimeFromText,
126
151
  calculatePrefixDuration,
127
- estimateNarrationDuration
152
+ estimateNarrationDuration,
153
+ estimateReadingTime,
154
+ estimateNarrationTime
128
155
  };
129
- //# sourceMappingURL=chunk-3E5F2XMR.js.map
156
+ //# sourceMappingURL=chunk-VWUFZ6ZG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/timing/narrationTiming.ts","../src/timing/readingTime.ts"],"sourcesContent":["/**\n * Narration timing estimation.\n *\n * Estimates how long text takes to speak aloud, accounting for:\n * - Numbers spoken as multiple words (e.g., \"1910\" → \"nineteen ten\")\n * - Pauses at commas\n * - Year pronunciation conventions (1000–2099)\n *\n * Ported from qualla-internal's AudioTiming.ts (pure functions, no Node.js deps).\n */\n\n/** Numbers are spoken more slowly than regular words (1.3× multiplier). */\nconst NUMBER_SPEAKING_MULTIPLIER = 1.3;\n\n/** Comma pause in \"word equivalents\" — speakers pause ~0.3 words at commas. */\nconst COMMA_PAUSE_PENALTY = 0.3;\n\n/** Default speaking rate in words per second (~150 WPM). */\nexport const DEFAULT_WORDS_PER_SECOND = 2.5;\n\n/**\n * Estimate how many \"spoken word equivalents\" a single token represents.\n * Numbers get expanded (e.g., \"175,000\" → ~5 words × 1.3 multiplier).\n */\nexport function estimateSpokenWordCount(token: string): number {\n const cleaned = token.replace(/,/g, '');\n const num = parseFloat(cleaned);\n\n if (isNaN(num) || !isFinite(num)) {\n return 1; // Not a number — count as 1 word\n }\n\n return estimateNumberWordCount(cleaned, num) * NUMBER_SPEAKING_MULTIPLIER;\n}\n\n/**\n * Raw word count for a number (before the speaking multiplier).\n */\nfunction estimateNumberWordCount(cleaned: string, num: number): number {\n // Handle decimals: \"3.14\" → words(\"3\") + \"point\" + 2 digits\n if (cleaned.includes('.')) {\n const [whole, decimal] = cleaned.split('.');\n const wholeNum = parseFloat(whole) || 0;\n return estimateNumberWordCount(whole, wholeNum) + 1 + decimal.length;\n }\n\n const absNum = Math.abs(num);\n let words = num < 0 ? 1 : 0; // \"negative\" / \"minus\"\n\n if (absNum === 0) return 1; // \"zero\"\n\n // Years (1000–2099) are spoken as two two-digit groups:\n // \"1910\" → \"nineteen ten\", \"2024\" → \"twenty twenty-four\"\n if (absNum >= 1000 && absNum <= 2099 && Number.isInteger(absNum)) {\n const yearStr = absNum.toString();\n if (yearStr.length === 4) {\n const firstTwo = parseInt(yearStr.slice(0, 2));\n const lastTwo = parseInt(yearStr.slice(2));\n\n // First part\n if (firstTwo >= 10 && firstTwo <= 19) {\n words += 1;\n } else if (firstTwo >= 20 && firstTwo <= 99) {\n words += firstTwo % 10 === 0 ? 1 : 2;\n } else {\n words += 2; // \"two thousand\"\n }\n\n // Second part\n if (lastTwo === 0) {\n if (firstTwo >= 10 && firstTwo <= 99 && firstTwo !== 20) {\n words += 1; // \"hundred\"\n }\n } else if (lastTwo >= 1 && lastTwo <= 9) {\n words += 2; // \"oh five\"\n } else if (lastTwo >= 10 && lastTwo <= 19) {\n words += 1;\n } else {\n words += lastTwo % 10 === 0 ? 1 : 2;\n }\n\n return Math.max(words, 2);\n }\n }\n\n // General number handling — each magnitude group adds words\n let remaining = absNum;\n\n if (remaining >= 1_000_000_000) {\n const billions = Math.floor(remaining / 1_000_000_000);\n words += estimateNumberWordCount(String(billions), billions);\n words += 1; // \"billion\"\n remaining %= 1_000_000_000;\n }\n\n if (remaining >= 1_000_000) {\n const millions = Math.floor(remaining / 1_000_000);\n words += estimateNumberWordCount(String(millions), millions);\n words += 1; // \"million\"\n remaining %= 1_000_000;\n }\n\n if (remaining >= 1_000) {\n const thousands = Math.floor(remaining / 1_000);\n words += estimateNumberWordCount(String(thousands), thousands);\n words += 1; // \"thousand\"\n remaining %= 1_000;\n }\n\n if (remaining >= 100) {\n words += 2; // digit + \"hundred\"\n remaining %= 100;\n }\n\n if (remaining >= 1) {\n if (remaining >= 20) {\n words += remaining % 10 === 0 ? 1 : 2;\n } else {\n words += 1; // 1–19\n }\n }\n\n return Math.max(words, 1);\n}\n\n/**\n * Count \"spoken word equivalents\" in a block of text,\n * expanding numbers and adding comma pauses.\n */\nexport function countSpokenWords(text: string): number {\n const tokens = text.split(/\\s+/).filter((w) => w.length > 0);\n let count = 0;\n\n for (const token of tokens) {\n // Strip punctuation only at token boundaries so internal punctuation\n // (e.g., decimals like \"3.14\" or digit-grouping commas \"1,000\") is preserved.\n const stripped = token.replace(/^[.,!?;:'\"()[\\]{}]+|[.,!?;:'\"()[\\]{}]+$/g, '');\n count += estimateSpokenWordCount(stripped);\n\n // Count only punctuation commas for pauses: exclude digit-grouping commas\n // (i.e., commas with digits on both sides, like in \"1,234\").\n let punctuationCommaCount = 0;\n for (let i = 0; i < token.length; i++) {\n if (token[i] === ',') {\n const prev = i > 0 ? token[i - 1] : '';\n const next = i < token.length - 1 ? token[i + 1] : '';\n const prevIsDigit = prev >= '0' && prev <= '9';\n const nextIsDigit = next >= '0' && next <= '9';\n if (!(prevIsDigit && nextIsDigit)) {\n punctuationCommaCount++;\n }\n }\n }\n count += punctuationCommaCount * COMMA_PAUSE_PENALTY;\n }\n\n return count;\n}\n\n/**\n * Estimate audio time at a character offset using word-proportion mapping.\n *\n * Given the full source text and a character position, returns the\n * estimated time (in seconds) at which that position would be spoken.\n *\n * @param text - Full source text\n * @param charOffset - Character offset to estimate timing for\n * @param totalDuration - Total audio duration in seconds\n * @returns Estimated time in seconds\n */\nexport function estimateTimeFromText(\n text: string,\n charOffset: number,\n totalDuration: number,\n): number {\n const textBefore = text.slice(0, charOffset);\n const spokenWordsBefore = countSpokenWords(textBefore);\n const totalSpokenWords = countSpokenWords(text);\n\n if (totalSpokenWords === 0) return 0;\n return (spokenWordsBefore / totalSpokenWords) * totalDuration;\n}\n\n/**\n * Estimate how long a spoken prefix adds to audio duration.\n *\n * When audio includes a spoken title or header before the main content,\n * this calculates the extra duration to offset timing calculations.\n *\n * @param prefix - Prefix text (e.g., an article title spoken before the body)\n * @param wordsPerSecond - Speaking rate (default: 2.5)\n * @returns Estimated duration in seconds\n */\nexport function calculatePrefixDuration(\n prefix: string,\n wordsPerSecond: number = DEFAULT_WORDS_PER_SECOND,\n): number {\n if (!prefix) return 0;\n\n const words = prefix.split(/\\s+/).filter((w) => w.length > 0);\n const newlineCount = (prefix.match(/\\n\\n/g) || []).length;\n const pauseTime = newlineCount * 0.5;\n\n return words.length / wordsPerSecond + pauseTime;\n}\n\n/**\n * Estimate narration duration for a block of text.\n *\n * @param text - The text to estimate\n * @param wordsPerSecond - Speaking rate (default: 2.5, i.e. ~150 WPM)\n * @returns Duration in seconds\n */\nexport function estimateNarrationDuration(\n text: string,\n wordsPerSecond: number = DEFAULT_WORDS_PER_SECOND,\n): number {\n const spokenWords = countSpokenWords(text);\n return spokenWords / wordsPerSecond;\n}\n","/**\n * Reading time estimation.\n *\n * Estimates how long it takes to read text silently vs. narrate it aloud.\n * Uses configurable words-per-minute rates.\n */\n\nimport { countSpokenWords, DEFAULT_WORDS_PER_SECOND } from './narrationTiming.js';\n\n/** Default silent reading rate (adults average ~200–250 WPM). */\nconst DEFAULT_READING_WPM = 200;\n\n/** Result of a reading-time estimate. */\nexport interface ReadingTimeEstimate {\n /** Number of words (plain word count, not spoken equivalents). */\n words: number;\n /** Estimated minutes (decimal). */\n minutes: number;\n /** Estimated seconds (rounded). */\n seconds: number;\n}\n\n/** Options for reading-time estimation. */\nexport interface ReadingTimeOptions {\n /** Words per minute for silent reading (default: 200). */\n wordsPerMinute?: number;\n}\n\n/**\n * Estimate silent reading time for a block of text.\n *\n * @param text - The text to estimate\n * @param options - Optional configuration\n * @returns Word count + time estimate\n */\nexport function estimateReadingTime(\n text: string,\n options?: ReadingTimeOptions,\n): ReadingTimeEstimate {\n const configuredWpm = options?.wordsPerMinute;\n const wpm =\n typeof configuredWpm === 'number' && configuredWpm > 0 ? configuredWpm : DEFAULT_READING_WPM;\n const words = text.split(/\\s+/).filter((w) => w.length > 0).length;\n const minutes = words / wpm;\n\n return {\n words,\n minutes,\n seconds: Math.round(minutes * 60),\n };\n}\n\n/** Result of a narration-time estimate. */\nexport interface NarrationTimeEstimate {\n /** Spoken word equivalents (numbers expanded, comma pauses added). */\n spokenWords: number;\n /** Estimated minutes (decimal). */\n minutes: number;\n /** Estimated seconds (rounded). */\n seconds: number;\n}\n\n/** Options for narration-time estimation. */\nexport interface NarrationTimeOptions {\n /** Words per second for narration (default: 2.5 ≈ 150 WPM). */\n wordsPerSecond?: number;\n}\n\n/**\n * Estimate narration (spoken) time for a block of text.\n *\n * Unlike silent reading, this accounts for numbers being spoken as\n * multiple words and pauses at commas.\n *\n * @param text - The text to estimate\n * @param options - Optional configuration\n * @returns Spoken word equivalents + time estimate\n */\nexport function estimateNarrationTime(\n text: string,\n options?: NarrationTimeOptions,\n): NarrationTimeEstimate {\n const providedWps = options?.wordsPerSecond;\n const wps =\n typeof providedWps === 'number' && providedWps > 0 ? providedWps : DEFAULT_WORDS_PER_SECOND;\n const spokenWords = countSpokenWords(text);\n const totalSeconds = spokenWords / wps;\n\n return {\n spokenWords,\n minutes: totalSeconds / 60,\n seconds: Math.round(totalSeconds),\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,5 +1,5 @@
1
- export { AccentLayout, AudioSegmentTiming, CONTAINER_TEMPLATES, ClipBox, ConnectorRouting, CoverBlockInput, DEFAULT_LAYOUT, DataFenceParseResult, DeriveTemplateInputsOptions, DiagramEdge, DiagramLayout, DiagramLayoutOptions, DiagramNodePosition, DocStylePreset, DrawingConnector, DrawingLayout, DrawingLayoutOptions, DrawingShape, DrawingShapeKind, ExpandDocBlocksOptions, ExtractedTableData, FirstImage, LayoutLayerDefaults, LayoutLayersResult, MarkdownToDocOptions, MarkdownValidationResult, PATH_SHAPE_KINDS, RenderContext, RuntimeTemplateRegistry, SHAPE_NAMES, TEMPLATE_ALIASES, TEMPLATE_METADATA, TemplateMetadata, ValidateOptions, adjustY, applyRenderStyleToLayers, buildRegistry, clipEndpoints, clipPoint, comparisonBar, computeDiagramLayout, computeDrawingLayout, computeLayoutLayers, connectorPath, countBlocks, coverBlock, createAccentLayers, cssFilterForTreatment, dataTable, dateEvent, decodeLayersFromFrontmatter, definitionCard, deriveTemplateInputs, diagramBlock, docToMarkdown, drawingBlock, encodeLayersForFrontmatter, expandCoverBlock, expandDocBlocks, expandPersistentLayers, expandTemplateBlock, extractBlockquoteText, extractBodyPlainText, extractFirstImage, extractImages, extractListItems, extractTableData, extractTableFromContents, factCard, fallbackBlockLayers, findFirstTable, flattenBlocks, flattenRenderableBlocks, fullBleedQuote, getAccentLayout, getAnimationProgress, getAnimationStyle, getAvailableTemplates, getBlockDepth, getDefaultAnimation, getDefaultAnimationDuration, getDocStyleConfig, getLayers, getOverlayOpacity, getPersistentLayersFromTheme, getTemplateHint, getThemeFont, getTransitionClass, hasTemplate, imageWithCaption, isContainerTemplate, isDataFence, isShapeName, layoutBlock, leftFeature, lineStyleDasharray, listBlock, mapBlock, markdownToDoc, markerPath, normalizeShapeKind, parseDataFence, parseYamlSubset, photoGrid, pullQuote, quoteBlock, readCustomTemplatesFromFrontmatter, readCustomThemesFromFrontmatter, resolveAudioMapping, resolveColorScheme, resolvePersistentLayers, resolveTemplateName, resolveThemeForDoc, rightFeature, scaleAnimationDuration, scoreTextSimilarity, sectionHeader, shapePath, shouldUseShadow, statHighlight, templateRegistry, themeWantsAmbientMotion, themedEntrance, themedFontSize, themedImageTreatment, themedScrim, themedSurfaceGradient, titleBlock, twoColumn, validateMarkdownDoc, validateMarkdownSource, videoPullQuote, videoWithCaption, wrapWithPersistentLayers, writeCustomTemplatesToFrontmatter, writeCustomThemesToFrontmatter } from '../story/index.js';
2
- export { D as DEFAULT_THEME, g as getAvailableThemes, b as getThemeSummaries, r as resolveTheme } from '../themeLibrary-DQQKuRMx.js';
3
- export { y as DocBlock, F as FRONTMATTER_CUSTOM_TEMPLATES_KEY, G as FRONTMATTER_CUSTOM_THEMES_KEY, S as LayoutHints, a3 as PersistentLayerConfig, ad as RenderStyle, ar as TemplateBlock, as as TemplateContext, ax as Theme, ay as ThemeColorPalette, az as ThemeColorScheme, aC as ThemeStyle, aD as ThemeTypography, aH as VIEWPORT_PRESETS, aL as ViewportConfig, aM as ViewportOrientation, aN as ViewportPreset, aS as createTemplateContext, aY as getLayoutHints, b0 as getTwoColumnPositions, b1 as getViewport, b2 as getViewportOrientation, b4 as isTemplateBlock, b9 as scaledFontSize } from '../Doc-BsMkmzH8.js';
1
+ export { AccentLayout, AudioSegmentTiming, BASE_INPUT_DESCRIPTORS, CONTAINER_TEMPLATES, ClipBox, ConnectorRouting, CoverBlockInput, DEFAULT_LAYOUT, DataFenceParseResult, DeriveTemplateInputsOptions, DiagramEdge, DiagramLayout, DiagramLayoutOptions, DiagramNodePosition, DocStylePreset, DrawingConnector, DrawingLayout, DrawingLayoutOptions, DrawingShape, DrawingShapeKind, ExpandDocBlocksOptions, ExtractedTableData, FirstImage, InputCoercion, LayoutLayerDefaults, LayoutLayersResult, MarkdownToDocOptions, MarkdownValidationResult, PATH_SHAPE_KINDS, RenderContext, RuntimeTemplateRegistry, SHAPE_NAMES, TEMPLATE_ALIASES, TEMPLATE_INPUT_DESCRIPTORS, TEMPLATE_METADATA, TemplateInputDescriptor, TemplateMetadata, TemplateParamFinding, ValidateOptions, adjustY, applyRenderStyleToLayers, buildRegistry, clipEndpoints, clipPoint, coerceTemplateParams, comparisonBar, computeDiagramLayout, computeDrawingLayout, computeLayoutLayers, connectorPath, countBlocks, coverBlock, createAccentLayers, cssFilterForTreatment, dataTable, dateEvent, decodeLayersFromFrontmatter, definitionCard, deriveTemplateInputs, diagramBlock, docToMarkdown, drawingBlock, encodeLayersForFrontmatter, expandCoverBlock, expandDocBlocks, expandPersistentLayers, expandTemplateBlock, extractBlockquoteText, extractBodyPlainText, extractFirstImage, extractImages, extractListItems, extractTableData, extractTableFromContents, factCard, fallbackBlockLayers, findFirstTable, flattenBlocks, flattenRenderableBlocks, fullBleedQuote, getAccentLayout, getAnimationProgress, getAnimationStyle, getAvailableTemplates, getBlockDepth, getDefaultAnimation, getDefaultAnimationDuration, getDocStyleConfig, getLayers, getOverlayOpacity, getPersistentLayersFromTheme, getTemplateHint, getThemeFont, getTransitionClass, hasTemplate, imageWithCaption, isContainerTemplate, isDataFence, isShapeName, layoutBlock, leftFeature, lineStyleDasharray, lintTemplateParams, listBlock, mapBlock, markdownToDoc, markerPath, normalizeShapeKind, parseDataFence, parseYamlSubset, photoGrid, pullQuote, quoteBlock, readCustomTemplatesFromFrontmatter, readCustomThemesFromFrontmatter, replaceDataFence, resolveAudioMapping, resolveColorScheme, resolvePersistentLayers, resolveTemplateName, resolveThemeForDoc, rightFeature, scaleAnimationDuration, scoreTextSimilarity, sectionHeader, shapePath, shouldUseShadow, statHighlight, templateRegistry, themeWantsAmbientMotion, themedEntrance, themedFontSize, themedImageTreatment, themedScrim, themedSurfaceGradient, titleBlock, twoColumn, validateMarkdownDoc, validateMarkdownSource, videoPullQuote, videoWithCaption, wrapWithPersistentLayers, writeCustomTemplatesToFrontmatter, writeCustomThemesToFrontmatter } from '../story/index.js';
2
+ export { D as DEFAULT_THEME, g as getAvailableThemes, b as getThemeSummaries, r as resolveTheme } from '../themeLibrary-CehcJhzz.js';
3
+ export { z as DocBlock, G as FRONTMATTER_CUSTOM_TEMPLATES_KEY, H as FRONTMATTER_CUSTOM_THEMES_KEY, U as LayoutHints, a5 as PersistentLayerConfig, af as RenderStyle, at as TemplateBlock, au as TemplateContext, az as Theme, aA as ThemeColorPalette, aB as ThemeColorScheme, aE as ThemeStyle, aF as ThemeTypography, aJ as VIEWPORT_PRESETS, aN as ViewportConfig, aO as ViewportOrientation, aP as ViewportPreset, aU as createTemplateContext, a_ as getLayoutHints, b2 as getTwoColumnPositions, b3 as getViewport, b4 as getViewportOrientation, b6 as isTemplateBlock, bb as scaledFontSize } from '../Doc-BBVGq1_9.js';
4
4
  import '../types-DlAZ7MW4.js';
5
- import '../ContentContainer-DNx460y8.js';
5
+ import '../ContentContainer-BXUlIf18.js';
package/dist/doc/index.js CHANGED
@@ -1,12 +1,15 @@
1
1
  import {
2
+ BASE_INPUT_DESCRIPTORS,
2
3
  CONTAINER_TEMPLATES,
3
4
  DEFAULT_LAYOUT,
4
5
  SHAPE_NAMES,
5
6
  TEMPLATE_ALIASES,
7
+ TEMPLATE_INPUT_DESCRIPTORS,
6
8
  TEMPLATE_METADATA,
7
9
  adjustY,
8
10
  applyRenderStyleToLayers,
9
11
  buildRegistry,
12
+ coerceTemplateParams,
10
13
  comparisonBar,
11
14
  computeDiagramLayout,
12
15
  computeDrawingLayout,
@@ -62,6 +65,7 @@ import {
62
65
  isShapeName,
63
66
  layoutBlock,
64
67
  leftFeature,
68
+ lintTemplateParams,
65
69
  listBlock,
66
70
  mapBlock,
67
71
  markdownToDoc,
@@ -73,6 +77,7 @@ import {
73
77
  quoteBlock,
74
78
  readCustomTemplatesFromFrontmatter,
75
79
  readCustomThemesFromFrontmatter,
80
+ replaceDataFence,
76
81
  resolveAudioMapping,
77
82
  resolveColorScheme,
78
83
  resolvePersistentLayers,
@@ -100,8 +105,8 @@ import {
100
105
  wrapWithPersistentLayers,
101
106
  writeCustomTemplatesToFrontmatter,
102
107
  writeCustomThemesToFrontmatter
103
- } from "../chunk-4ZFRZBU2.js";
104
- import "../chunk-LRCV7N7F.js";
108
+ } from "../chunk-LH7I6SH7.js";
109
+ import "../chunk-UY7KGQ5R.js";
105
110
  import "../chunk-V543AI2F.js";
106
111
  import "../chunk-FVTQSNR7.js";
107
112
  import {
@@ -120,7 +125,7 @@ import {
120
125
  getAvailableThemes,
121
126
  getThemeSummaries,
122
127
  resolveTheme
123
- } from "../chunk-4AKUQPEE.js";
128
+ } from "../chunk-KKNUBQ6Y.js";
124
129
  import {
125
130
  VIEWPORT_PRESETS,
126
131
  createTemplateContext,
@@ -131,13 +136,13 @@ import {
131
136
  isTemplateBlock,
132
137
  scaledFontSize2 as scaledFontSize
133
138
  } from "../chunk-DLXZMS5K.js";
134
- import "../chunk-OH43RPTP.js";
135
- import "../chunk-OKJOQXK4.js";
139
+ import "../chunk-TEEEILMP.js";
140
+ import "../chunk-HWVFJAAH.js";
136
141
  import "../chunk-DBS6RIFL.js";
137
142
  import "../chunk-QE7TWGVT.js";
138
- import "../chunk-4X3JQXNM.js";
139
- import "../chunk-3E5F2XMR.js";
143
+ import "../chunk-VWUFZ6ZG.js";
140
144
  export {
145
+ BASE_INPUT_DESCRIPTORS,
141
146
  CONTAINER_TEMPLATES,
142
147
  DEFAULT_LAYOUT,
143
148
  DEFAULT_THEME,
@@ -146,6 +151,7 @@ export {
146
151
  PATH_SHAPE_KINDS,
147
152
  SHAPE_NAMES,
148
153
  TEMPLATE_ALIASES,
154
+ TEMPLATE_INPUT_DESCRIPTORS,
149
155
  TEMPLATE_METADATA,
150
156
  VIEWPORT_PRESETS,
151
157
  adjustY,
@@ -153,6 +159,7 @@ export {
153
159
  buildRegistry,
154
160
  clipEndpoints,
155
161
  clipPoint,
162
+ coerceTemplateParams,
156
163
  comparisonBar,
157
164
  computeDiagramLayout,
158
165
  computeDrawingLayout,
@@ -218,6 +225,7 @@ export {
218
225
  layoutBlock,
219
226
  leftFeature,
220
227
  lineStyleDasharray,
228
+ lintTemplateParams,
221
229
  listBlock,
222
230
  mapBlock,
223
231
  markdownToDoc,
@@ -230,6 +238,7 @@ export {
230
238
  quoteBlock,
231
239
  readCustomTemplatesFromFrontmatter,
232
240
  readCustomThemesFromFrontmatter,
241
+ replaceDataFence,
233
242
  resolveAudioMapping,
234
243
  resolveColorScheme,
235
244
  resolvePersistentLayers,
@@ -1,6 +1,6 @@
1
1
  import { E as ExtractedElement } from '../contentExtractor-BNfVJV2U.js';
2
2
  export { C as ComparisonData, D as DateData, a as DefinitionData, b as ExtractionOptions, c as ExtractionResult, d as ExtractionType, F as FactData, I as ImpactLineData, L as ListData, Q as QuoteData, S as StatData, e as extractContent, s as stripMarkdown } from '../contentExtractor-BNfVJV2U.js';
3
- import { m as ColorScheme, A as AccentImage, ar as TemplateBlock, x as Doc, a as AccentPosition } from '../Doc-BsMkmzH8.js';
3
+ import { m as ColorScheme, A as AccentImage, at as TemplateBlock } from '../Doc-BBVGq1_9.js';
4
4
  import '../types-DlAZ7MW4.js';
5
5
 
6
6
  /**
@@ -25,82 +25,4 @@ interface MapOptions {
25
25
  */
26
26
  declare function mapElementToBlock(element: ExtractedElement, options: MapOptions): TemplateBlock;
27
27
 
28
- /**
29
- * Slideshow Generator
30
- *
31
- * Turns plain text + optional images into a complete squisq `Doc`.
32
- *
33
- * Pipeline:
34
- * 1. Strip markdown (if needed)
35
- * 2. Extract compelling content (stats, dates, quotes, …)
36
- * 3. Estimate narration timing
37
- * 4. Map extractions → template blocks
38
- * 5. Interleave image slides
39
- * 6. Return a ready-to-render `Doc`
40
- */
41
-
42
- /** A Doc variant whose blocks are TemplateBlocks (no startTime required). */
43
- type SlideshowDoc = Omit<Doc, 'blocks'> & {
44
- blocks: TemplateBlock[];
45
- };
46
- /** Image metadata passed to the generator. */
47
- interface SlideshowImage {
48
- /** Image source path or URL. */
49
- src: string;
50
- /** Alt text for accessibility. */
51
- alt?: string;
52
- /** Photo credit. */
53
- credit?: string;
54
- /** License identifier. */
55
- license?: string;
56
- }
57
- /** Options for `generateSlideshow`. */
58
- interface SlideshowOptions {
59
- /** Deterministic seed (default: hash of the text). */
60
- seed?: number;
61
- /** Title slide text. Omit to skip the title slide. */
62
- title?: string;
63
- /** Subtitle for the title slide. */
64
- subtitle?: string;
65
- /** Explicit total duration in seconds. When omitted, estimated from text. */
66
- duration?: number;
67
- /** Target number of content slides (default: 5–8, auto-scaled). */
68
- targetSlides?: number;
69
- /** Color schemes to rotate (default: ['blue','green','purple','orange','red']). */
70
- colorSchemes?: ColorScheme[];
71
- /** Ambient motions to rotate on images. */
72
- ambientMotions?: Array<'zoomIn' | 'zoomOut' | 'panLeft' | 'panRight'>;
73
- /** Accent positions to rotate on text slides. */
74
- accentPositions?: AccentPosition[];
75
- /** Minimum slide duration in seconds (default: 4). */
76
- minSlideDuration?: number;
77
- /** Maximum slide duration in seconds (default: 15). */
78
- maxSlideDuration?: number;
79
- /** Theme identifier to embed in the Doc. */
80
- themeId?: string;
81
- /** Whether the input text is markdown (default: false). */
82
- isMarkdown?: boolean;
83
- /** Minimum extraction confidence (default: 0.3). */
84
- minConfidence?: number;
85
- }
86
- /**
87
- * Generate a slideshow `Doc` from text and optional images.
88
- *
89
- * @deprecated Prefer the transform pipeline: convert content with
90
- * `markdownToDoc` (content-aware auto templates are on by default) and
91
- * shape it with `applyTransform` from `@bendyline/squisq/transform` —
92
- * one engine for text→slides, with styles, theme pairing, pacing, and a
93
- * duration budget (`TransformStyleConfig.budget`). This standalone
94
- * generator is kept for API stability but no longer gains features.
95
- *
96
- * ```ts
97
- * const doc = generateSlideshow(articleText, myImages, {
98
- * title: 'Mount Rainier',
99
- * themeId: 'documentary',
100
- * });
101
- * // doc is a complete Doc ready for DocPlayer / LinearDocView
102
- * ```
103
- */
104
- declare function generateSlideshow(text: string, images?: SlideshowImage[], options?: SlideshowOptions): SlideshowDoc;
105
-
106
- export { ExtractedElement, type MapOptions, type SlideshowDoc, type SlideshowImage, type SlideshowOptions, generateSlideshow, mapElementToBlock };
28
+ export { ExtractedElement, type MapOptions, mapElementToBlock };
@@ -1,16 +1,11 @@
1
- import {
2
- generateSlideshow
3
- } from "../chunk-FBKP5CAO.js";
1
+ import "../chunk-ET53IIEP.js";
4
2
  import {
5
3
  extractContent,
6
4
  mapElementToBlock,
7
5
  stripMarkdown
8
- } from "../chunk-FR2RBTKO.js";
9
- import "../chunk-FVTQSNR7.js";
10
- import "../chunk-3E5F2XMR.js";
6
+ } from "../chunk-TQWLI6S2.js";
11
7
  export {
12
8
  extractContent,
13
- generateSlideshow,
14
9
  mapElementToBlock,
15
10
  stripMarkdown
16
11
  };
@@ -1,8 +1,8 @@
1
- import { a as ImageEditDoc, b as ImageEditLayer } from '../ImageEditDoc-DvoeHMP9.js';
2
- export { E as EditorLayerMeta, I as ImageEditCanvas, c as ImageEditLayerKind, d as ImageEditMeta } from '../ImageEditDoc-DvoeHMP9.js';
3
- import { C as ContentContainer } from '../ContentContainer-DNx460y8.js';
1
+ import { a as ImageEditDoc, b as ImageEditLayer } from '../ImageEditDoc-FuyGtt6o.js';
2
+ export { E as EditorLayerMeta, I as ImageEditCanvas, c as ImageEditLayerKind, d as ImageEditMeta } from '../ImageEditDoc-FuyGtt6o.js';
3
+ import { C as ContentContainer } from '../ContentContainer-BXUlIf18.js';
4
4
  import { V as Version, C as CoalesceOptions, P as PrunePolicy } from '../types-D98li1gV.js';
5
- import '../Doc-BsMkmzH8.js';
5
+ import '../Doc-BBVGq1_9.js';
6
6
  import '../types-DlAZ7MW4.js';
7
7
 
8
8
  /**
package/dist/index.d.ts CHANGED
@@ -1,23 +1,23 @@
1
1
  export { B as BoundingBox, C as Coordinates } from './Types-sh2VRxfo.js';
2
- export { A as AccentImage, a as AccentPosition, b as AmbientGradientConfig, c as Animation, d as AnimationType, e as AudioBookmark, f as AudioSegment, g as AudioTimingData, h as AudioTrack, B as Block, i as BlockConnection, j as BorderStyle, C as CaptionPhrase, k as CaptionTrack, l as CaptionWord, m as ColorScheme, n as ComparisonBarInput, o as CornerBrandingConfig, p as CustomTemplateDefinition, D as DARK_SURFACE, q as DEFAULT_DOC_FONT, r as DEFAULT_TITLE_FONT, s as DataTableInput, t as DateEventInput, u as DeepPartial, v as DefinitionCardInput, w as DiagramBlockInput, x as Doc, y as DocBlock, z as DocDiagnostic, E as DrawingBlockInput, F as FRONTMATTER_CUSTOM_TEMPLATES_KEY, G as FRONTMATTER_CUSTOM_THEMES_KEY, H as FactCardInput, I as FontFamily, J as FontFamilyKind, K as FullBleedQuoteInput, L as GradientBackgroundConfig, M as ImageBackgroundConfig, N as ImageLayer, O as ImageTreatment, P as ImageWithCaptionInput, Q as LIGHT_SURFACE, R as Layer, S as LayoutHints, T as LeftFeatureInput, U as LinearGradient, V as ListBlockInput, W as MapBlockInput, X as MapLayer, Y as MapMarker, Z as MapTileStyle, _ as MarkerStyle, $ as MediaClip, a0 as PathLayer, a1 as PatternBackgroundConfig, a2 as PersistentLayer, a3 as PersistentLayerConfig, a4 as PersistentLayerTemplate, a5 as PersistentLayerTemplateConfig, a6 as PersistentLayerTemplateType, a7 as PhotoGridInput, a8 as Position, a9 as ProgressIndicatorConfig, aa as PullQuoteInput, ab as QuoteBlockInput, ac as RawLayersInput, ad as RenderStyle, ae as RightFeatureInput, af as ScheduledClip, ag as SectionHeaderInput, ah as ShapeFilter, ai as ShapeLayer, aj as ShapePattern, ak as SolidBackgroundConfig, al as StartBlockConfig, am as StatHighlightInput, an as SurfaceScheme, ao as THEME_SCHEMA_VERSION, ap as TableLayer, aq as TableLayerStyle, ar as TemplateBlock, as as TemplateContext, at as TemplateFunction, au as TemplateRegistry, av as TextLayer, aw as TextStyle, ax as Theme, ay as ThemeColorPalette, az as ThemeColorScheme, aA as ThemeSchemaVersion, aB as ThemeSeedColors, aC as ThemeStyle, aD as ThemeTypography, aE as TitleBlockInput, aF as TitleCaptionConfig, aG as TwoColumnInput, aH as VIEWPORT_PRESETS, aI as VideoLayer, aJ as VideoPullQuoteInput, aK as VideoWithCaptionInput, aL as ViewportConfig, aM as ViewportOrientation, aN as ViewportPreset, aO as VignetteConfig, aP as applySurface, aQ as calculateDuration, aR as calculateFontScale, aS as createTemplateContext, aT as createTheme, aU as getAspectRatioString, aV as getBlockAtTime, aW as getCaptionAtTime, aX as getDocPlaybackDuration, aY as getLayoutHints, aZ as getRegisteredThemes, a_ as getSafeTextBounds, a$ as getSegmentAtTime, b0 as getTwoColumnPositions, b1 as getViewport, b2 as getViewportOrientation, b3 as isPersistentLayerTemplate, b4 as isTemplateBlock, b5 as layoutScaledFontSize, b6 as lookupRegisteredTheme, b7 as registerTheme, b8 as resolveMediaSchedule, b9 as scaledFontSize, ba as unregisterTheme, bb as validateDoc } from './Doc-BsMkmzH8.js';
2
+ export { A as AccentImage, a as AccentPosition, b as AmbientGradientConfig, c as Animation, d as AnimationType, e as AudioBookmark, f as AudioSegment, g as AudioTimingData, h as AudioTrack, B as Block, i as BlockConnection, j as BorderStyle, C as CaptionPhrase, k as CaptionTrack, l as CaptionWord, m as ColorScheme, n as ComparisonBarInput, o as CornerBrandingConfig, p as CustomTemplateDefinition, q as CustomTemplateLayer, D as DARK_SURFACE, r as DEFAULT_DOC_FONT, s as DEFAULT_TITLE_FONT, t as DataTableInput, u as DateEventInput, v as DeepPartial, w as DefinitionCardInput, x as DiagramBlockInput, y as Doc, z as DocBlock, E as DocDiagnostic, F as DrawingBlockInput, G as FRONTMATTER_CUSTOM_TEMPLATES_KEY, H as FRONTMATTER_CUSTOM_THEMES_KEY, I as FactCardInput, J as FontFamily, K as FontFamilyKind, L as FullBleedQuoteInput, M as GradientBackgroundConfig, N as ImageBackgroundConfig, O as ImageLayer, P as ImageTreatment, Q as ImageWithCaptionInput, R as LIGHT_SURFACE, S as Layer, T as LayerRepeat, U as LayoutHints, V as LeftFeatureInput, W as LinearGradient, X as ListBlockInput, Y as MapBlockInput, Z as MapLayer, _ as MapMarker, $ as MapTileStyle, a0 as MarkerStyle, a1 as MediaClip, a2 as PathLayer, a3 as PatternBackgroundConfig, a4 as PersistentLayer, a5 as PersistentLayerConfig, a6 as PersistentLayerTemplate, a7 as PersistentLayerTemplateConfig, a8 as PersistentLayerTemplateType, a9 as PhotoGridInput, aa as Position, ab as ProgressIndicatorConfig, ac as PullQuoteInput, ad as QuoteBlockInput, ae as RawLayersInput, af as RenderStyle, ag as RightFeatureInput, ah as ScheduledClip, ai as SectionHeaderInput, aj as ShapeFilter, ak as ShapeLayer, al as ShapePattern, am as SolidBackgroundConfig, an as StartBlockConfig, ao as StatHighlightInput, ap as SurfaceScheme, aq as THEME_SCHEMA_VERSION, ar as TableLayer, as as TableLayerStyle, at as TemplateBlock, au as TemplateContext, av as TemplateFunction, aw as TemplateRegistry, ax as TextLayer, ay as TextStyle, az as Theme, aA as ThemeColorPalette, aB as ThemeColorScheme, aC as ThemeSchemaVersion, aD as ThemeSeedColors, aE as ThemeStyle, aF as ThemeTypography, aG as TitleBlockInput, aH as TitleCaptionConfig, aI as TwoColumnInput, aJ as VIEWPORT_PRESETS, aK as VideoLayer, aL as VideoPullQuoteInput, aM as VideoWithCaptionInput, aN as ViewportConfig, aO as ViewportOrientation, aP as ViewportPreset, aQ as VignetteConfig, aR as applySurface, aS as calculateDuration, aT as calculateFontScale, aU as createTemplateContext, aV as createTheme, aW as getAspectRatioString, aX as getBlockAtTime, aY as getCaptionAtTime, aZ as getDocPlaybackDuration, a_ as getLayoutHints, a$ as getRegisteredThemes, b0 as getSafeTextBounds, b1 as getSegmentAtTime, b2 as getTwoColumnPositions, b3 as getViewport, b4 as getViewportOrientation, b5 as isPersistentLayerTemplate, b6 as isTemplateBlock, b7 as layoutScaledFontSize, b8 as lookupRegisteredTheme, b9 as registerTheme, ba as resolveMediaSchedule, bb as scaledFontSize, bc as unregisterTheme } from './Doc-BBVGq1_9.js';
3
3
  export { D as DEFAULT_TRANSITION_DURATION_SECONDS, H as HeadingAttributes, a as HeadingTemplateAnnotation, b as HtmlComment, c as HtmlElement, d as HtmlNode, e as HtmlText, M as MarkdownBlockNode, f as MarkdownBlockquote, g as MarkdownBreak, h as MarkdownCodeBlock, i as MarkdownContainerDirective, j as MarkdownDefinitionDescription, k as MarkdownDefinitionList, l as MarkdownDefinitionTerm, m as MarkdownDocument, n as MarkdownEmphasis, o as MarkdownFootnoteDefinition, p as MarkdownFootnoteReference, q as MarkdownHeading, r as MarkdownHtmlBlock, s as MarkdownImage, t as MarkdownImageReference, u as MarkdownInlineCode, v as MarkdownInlineHtml, w as MarkdownInlineMath, x as MarkdownInlineNode, y as MarkdownLeafDirective, z as MarkdownLink, A as MarkdownLinkDefinition, B as MarkdownLinkReference, C as MarkdownList, E as MarkdownListItem, F as MarkdownMathBlock, G as MarkdownMention, I as MarkdownNode, J as MarkdownParagraph, K as MarkdownPoint, L as MarkdownSourcePosition, N as MarkdownStrikethrough, O as MarkdownStrong, P as MarkdownTable, Q as MarkdownTableCell, R as MarkdownTableRow, S as MarkdownText, T as MarkdownTextDirective, U as MarkdownThematicBreak, V as ParseOptions, W as StringifyOptions, X as TRANSITION_DIRECTIONS, Y as TRANSITION_TYPES, Z as Transition, _ as TransitionDirection, $ as TransitionType, a0 as isTransitionType, a1 as normalizeTransitionDirection, a2 as normalizeTransitionType, a3 as resolveBlockTransition, a4 as resolveTransitionDuration } from './types-DlAZ7MW4.js';
4
- export { D as DEFAULT_THEME, a as DEFAULT_THEME_ID, T as THEMES, g as getAvailableThemes, b as getThemeSummaries, r as resolveTheme } from './themeLibrary-DQQKuRMx.js';
4
+ export { D as DEFAULT_THEME, a as DEFAULT_THEME_ID, T as THEMES, g as getAvailableThemes, b as getThemeSummaries, r as resolveTheme } from './themeLibrary-CehcJhzz.js';
5
5
  export { AVAILABLE_FONT_STACKS, CompileOptions, ContrastPreset, FONT_FALLBACKS, FontStack, STARTER_THEME, ValidationError, ValidationResult, assertTheme, buildGoogleFontsUrl, compileTheme, contrastRatio, deriveColorPalette, deriveScale, fontStack, getFontStack, hexHueDegrees, isHex, oklchDarken, oklchLighten, oklchSetChroma, parseTheme, pickContrastingText, relativeLuminance, resolveFontFamily, serializeTheme, validateTheme, withAlpha } from './schemas/index.js';
6
6
  export { M as MediaEntry, a as MediaProvider } from './MediaProvider-wpSe21B3.js';
7
- export { E as EditorLayerMeta, I as ImageEditCanvas, a as ImageEditDoc, b as ImageEditLayer, c as ImageEditLayerKind, d as ImageEditMeta } from './ImageEditDoc-DvoeHMP9.js';
8
- export { AccentLayout, AudioSegmentTiming, CONTAINER_TEMPLATES, ClipBox, ConnectorRouting, CoverBlockInput, DEFAULT_LAYOUT, DataFenceParseResult, DeriveTemplateInputsOptions, DiagramEdge, DiagramLayout, DiagramLayoutOptions, DiagramNodePosition, DocStylePreset, DrawingConnector, DrawingLayout, DrawingLayoutOptions, DrawingShape, DrawingShapeKind, ExpandDocBlocksOptions, ExtractedTableData, FirstImage, LayoutLayerDefaults, LayoutLayersResult, MarkdownToDocOptions, MarkdownValidationResult, PATH_SHAPE_KINDS, RenderContext, RuntimeTemplateRegistry, SHAPE_NAMES, TEMPLATE_ALIASES, TEMPLATE_METADATA, TemplateMetadata, ValidateOptions, adjustY, applyRenderStyleToLayers, buildRegistry, clipEndpoints, clipPoint, comparisonBar, computeDiagramLayout, computeDrawingLayout, computeLayoutLayers, connectorPath, countBlocks, coverBlock, createAccentLayers, cssFilterForTreatment, dataTable, dateEvent, decodeLayersFromFrontmatter, definitionCard, deriveTemplateInputs, diagramBlock, docToMarkdown, drawingBlock, encodeLayersForFrontmatter, expandCoverBlock, expandDocBlocks, expandPersistentLayers, expandTemplateBlock, extractBlockquoteText, extractBodyPlainText, extractFirstImage, extractImages, extractListItems, extractTableData, extractTableFromContents, factCard, fallbackBlockLayers, findFirstTable, flattenBlocks, flattenRenderableBlocks, fullBleedQuote, getAccentLayout, getAnimationProgress, getAnimationStyle, getAvailableTemplates, getBlockDepth, getDefaultAnimation, getDefaultAnimationDuration, getDocStyleConfig, getLayers, getOverlayOpacity, getPersistentLayersFromTheme, getTemplateHint, getThemeFont, getTransitionClass, hasTemplate, imageWithCaption, isContainerTemplate, isDataFence, isShapeName, layoutBlock, leftFeature, lineStyleDasharray, listBlock, mapBlock, markdownToDoc, markerPath, normalizeShapeKind, parseDataFence, parseYamlSubset, photoGrid, pullQuote, quoteBlock, readCustomTemplatesFromFrontmatter, readCustomThemesFromFrontmatter, resolveAudioMapping, resolveColorScheme, resolvePersistentLayers, resolveTemplateName, resolveThemeForDoc, rightFeature, scaleAnimationDuration, scoreTextSimilarity, sectionHeader, shapePath, shouldUseShadow, statHighlight, templateRegistry, themeWantsAmbientMotion, themedEntrance, themedFontSize, themedImageTreatment, themedScrim, themedSurfaceGradient, titleBlock, twoColumn, validateMarkdownDoc, validateMarkdownSource, videoPullQuote, videoWithCaption, wrapWithPersistentLayers, writeCustomTemplatesToFrontmatter, writeCustomThemesToFrontmatter } from './story/index.js';
7
+ export { E as EditorLayerMeta, I as ImageEditCanvas, a as ImageEditDoc, b as ImageEditLayer, c as ImageEditLayerKind, d as ImageEditMeta } from './ImageEditDoc-FuyGtt6o.js';
8
+ export { AccentLayout, AudioSegmentTiming, BASE_INPUT_DESCRIPTORS, CONTAINER_TEMPLATES, ClipBox, ConnectorRouting, CoverBlockInput, DEFAULT_LAYOUT, DataFenceParseResult, DeriveTemplateInputsOptions, DiagramEdge, DiagramLayout, DiagramLayoutOptions, DiagramNodePosition, DocStylePreset, DrawingConnector, DrawingLayout, DrawingLayoutOptions, DrawingShape, DrawingShapeKind, ExpandDocBlocksOptions, ExtractedTableData, FirstImage, InputCoercion, LayoutLayerDefaults, LayoutLayersResult, MarkdownToDocOptions, MarkdownValidationResult, PATH_SHAPE_KINDS, RenderContext, RuntimeTemplateRegistry, SHAPE_NAMES, TEMPLATE_ALIASES, TEMPLATE_INPUT_DESCRIPTORS, TEMPLATE_METADATA, TemplateInputDescriptor, TemplateMetadata, TemplateParamFinding, ValidateOptions, adjustY, applyRenderStyleToLayers, buildRegistry, clipEndpoints, clipPoint, coerceTemplateParams, comparisonBar, computeDiagramLayout, computeDrawingLayout, computeLayoutLayers, connectorPath, countBlocks, coverBlock, createAccentLayers, cssFilterForTreatment, dataTable, dateEvent, decodeLayersFromFrontmatter, definitionCard, deriveTemplateInputs, diagramBlock, docToMarkdown, drawingBlock, encodeLayersForFrontmatter, expandCoverBlock, expandDocBlocks, expandPersistentLayers, expandTemplateBlock, extractBlockquoteText, extractBodyPlainText, extractFirstImage, extractImages, extractListItems, extractTableData, extractTableFromContents, factCard, fallbackBlockLayers, findFirstTable, flattenBlocks, flattenRenderableBlocks, fullBleedQuote, getAccentLayout, getAnimationProgress, getAnimationStyle, getAvailableTemplates, getBlockDepth, getDefaultAnimation, getDefaultAnimationDuration, getDocStyleConfig, getLayers, getOverlayOpacity, getPersistentLayersFromTheme, getTemplateHint, getThemeFont, getTransitionClass, hasTemplate, imageWithCaption, isContainerTemplate, isDataFence, isShapeName, layoutBlock, leftFeature, lineStyleDasharray, lintTemplateParams, listBlock, mapBlock, markdownToDoc, markerPath, normalizeShapeKind, parseDataFence, parseYamlSubset, photoGrid, pullQuote, quoteBlock, readCustomTemplatesFromFrontmatter, readCustomThemesFromFrontmatter, replaceDataFence, resolveAudioMapping, resolveColorScheme, resolvePersistentLayers, resolveTemplateName, resolveThemeForDoc, rightFeature, scaleAnimationDuration, scoreTextSimilarity, sectionHeader, shapePath, shouldUseShadow, statHighlight, templateRegistry, themeWantsAmbientMotion, themedEntrance, themedFontSize, themedImageTreatment, themedScrim, themedSurfaceGradient, titleBlock, twoColumn, validateMarkdownDoc, validateMarkdownSource, videoPullQuote, videoWithCaption, wrapWithPersistentLayers, writeCustomTemplatesToFrontmatter, writeCustomThemesToFrontmatter } from './story/index.js';
9
9
  export { calculateBearing, decodeGeohash, encodeGeohash, geohashOverlapsBounds, geohashToHierarchicalPath, getGeohash4Neighbors, getGeohashPath, getGeohashPrefix, getNeighbors, haversineDistance } from './spatial/index.js';
10
10
  export { LocalForageAdapter, LocalForageAdapterOptions, LocalStorageAdapter, MemoryStorageAdapter, ScopedContentContainer, StorageAdapter, createMediaProviderFromContainer, scopeContainer } from './storage/index.js';
11
- export { C as ContentContainer, a as ContentEntry, M as MemoryContentContainer, f as findDocumentPath } from './ContentContainer-DNx460y8.js';
12
- export { BLOCK_META_KEY_DESCRIPTORS, BlockMetaKeyDescriptor, HtmlPolicy, KNOWN_BLOCK_META_KEYS, KnownBlockMetaKey, TrailingAnnotationMatch, UrlKind, countNodes, createDocument, extractPlainText, findNodesByType, fromMdast, getChildren, inferDocumentTitle, matchTrailingPandocAttr, matchTrailingTemplateAnnotation, needsQuoting, parseFrontmatter, parseHtmlToNodes, parseMarkdown, parsePandocAttrTokens, parseTimeSeconds, plainTextFromInlineHtml, quoteAttrValue, readFrontmatterThemeId, sanitizeHtmlNodes, sanitizeUrl, serializePandocAttributes, setFrontmatterValues, splitKeyValueToken, stringifyHtmlNodes, stringifyMarkdown, toMdast, tokenizeAttrTokens, unquoteAttrValue, walkMarkdownTree } from './markdown/index.js';
11
+ export { C as ContentContainer, a as ContentEntry, M as MemoryContentContainer, f as findDocumentPath } from './ContentContainer-BXUlIf18.js';
12
+ export { BLOCK_META_KEY_DESCRIPTORS, BlockMetaKeyDescriptor, HtmlPolicy, KNOWN_BLOCK_META_KEYS, KnownBlockMetaKey, SanitizeUrlOptions, TrailingAnnotationMatch, UrlKind, countNodes, createDocument, extractPlainText, findNodesByType, formatBlockScalar, fromMdast, getChildren, inferDocumentTitle, matchTrailingPandocAttr, matchTrailingTemplateAnnotation, needsQuoting, parseFrontmatter, parseHtmlToNodes, parseMarkdown, parsePandocAttrTokens, parseTimeSeconds, plainTextFromInlineHtml, quoteAttrValue, readFrontmatterThemeId, sanitizeHtmlNodes, sanitizeUrl, serializePandocAttributes, setFrontmatterValues, splitKeyValueToken, stringifyHtmlNodes, stringifyMarkdown, toMdast, tokenizeAttrTokens, unquoteAttrValue, walkMarkdownTree } from './markdown/index.js';
13
13
  export { DEFAULT_WORDS_PER_SECOND, NarrationTimeEstimate, NarrationTimeOptions, ReadingTimeEstimate, ReadingTimeOptions, calculatePrefixDuration, countSpokenWords, estimateNarrationDuration, estimateNarrationTime, estimateReadingTime, estimateSpokenWordCount, estimateTimeFromText } from './timing/index.js';
14
14
  export { SeededRandom, hashString } from './random/index.js';
15
15
  export { C as ComparisonData, D as DateData, a as DefinitionData, E as ExtractedElement, b as ExtractionOptions, c as ExtractionResult, d as ExtractionType, F as FactData, I as ImpactLineData, L as ListData, Q as QuoteData, S as StatData, e as extractContent, s as stripMarkdown } from './contentExtractor-BNfVJV2U.js';
16
- export { MapOptions, SlideshowDoc, SlideshowImage, SlideshowOptions, generateSlideshow, mapElementToBlock } from './generate/index.js';
16
+ export { MapOptions, mapElementToBlock } from './generate/index.js';
17
17
  export { AnalyzedBlock, BlockImage, DEFAULT_TRANSFORM_STYLE_ID, TransformImage, TransformOptions, TransformResult, TransformStyleConfig, TransformStyleId, TransformStyleSummary, analyzeBlocks, applyTransform, extractDocImages, getTransformStyleIds, getTransformStyleSummaries, registerTransformStyle, resolveTransformStyle, unregisterTransformStyle } from './transform/index.js';
18
18
  export { C as CoalesceOptions, P as PrunePolicy, R as RevertOptions, S as SaveVersionOptions, a as SaveVersionResult, V as Version } from './types-D98li1gV.js';
19
19
  export { DocumentVersionManager, DocumentVersionManagerOptions, VERSIONS_PREFIX, VERSION_TIMESTAMP_PATTERN, buildVersionPath, coalesceVersions, formatVersionTimestamp, getDocBasename, listVersions, parseVersionPath, parseVersionTimestamp, pruneVersions, readVersion, revertToVersion, saveVersion } from './versions/index.js';
20
- export { ControlKind, InferSchemaOptions, JsonFormValidationError, JsonFormValidator, SquisqAnnotatedSchema, SquisqHints, SquisqWhen, arrayItemKind, chooseControl, evaluateWhen, getByPointer, inferSchema, pointerSegments, primaryType, resolveFlag, resolveRef, setByPointer, toPointer } from './jsonForm/index.js';
20
+ export { BuildJsonFormTokensOptions, ControlKind, InferSchemaOptions, JsonFormValidationError, JsonFormValidator, SquisqAnnotatedSchema, SquisqHints, SquisqWhen, arrayItemKind, buildJsonFormTokens, chooseControl, evaluateWhen, getByPointer, inferSchema, pointerSegments, primaryType, resolveFlag, resolveJsonFormTheme, resolveRef, setByPointer, toPointer } from './jsonForm/index.js';
21
21
  export { IMAGE_EDIT_ASSETS_PREFIX, IMAGE_EDIT_DEFAULT_BASENAME, IMAGE_EDIT_STATE_FILENAME, IMAGE_EDIT_VERSIONS_PREFIX, ImageEditExportFormat, ImageEditExportOptions, ImageEditVersionManager, ImageEditVersionManagerOptions, RevertImageEditOptions, SaveImageEditVersionOptions, SaveImageEditVersionResult, addLayer, buildImageEditVersionPath, buildSvgString, coalesceImageEditVersions, createEmptyImageEditDoc, exportImageEditDoc, listImageEditVersions, parseImageEditVersionPath, pruneImageEditVersions, readImageEditDoc, readImageEditVersion, readImageEditVersionText, removeLayer, reorderLayer, revertToImageEditVersion, saveImageEditVersion, setCanvas, touch, updateLayer, writeImageEditDoc } from './imageEdit/index.js';
22
22
  export { I as ICONS, a as IconEntry, b as IconFamily, c as IconTextRun, h as hasIconMarker, i as iconClass, d as iconMarker, s as splitIconMarkers, e as stripIconMarkers } from './inlineIconMarker-CiE8Hlvz.js';
23
23
  export { IconSuggestion, canonicalIconToken, iconGlyph, looksLikeIconToken, resolveIcon, suggestIcons } from './icons/index.js';