@bendyline/squisq 1.4.1 → 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.
- package/README.md +14 -1
- package/dist/{ContentContainer-DNx460y8.d.ts → ContentContainer-BXUlIf18.d.ts} +6 -2
- package/dist/{Doc-BeSeH2iX.d.ts → Doc-BBVGq1_9.d.ts} +922 -273
- package/dist/{ImageEditDoc-BTIvw0oq.d.ts → ImageEditDoc-FuyGtt6o.d.ts} +11 -4
- package/dist/{chunk-ZTX4PFFT.js → chunk-2OIBZYKP.js} +75 -2
- package/dist/chunk-2OIBZYKP.js.map +1 -0
- package/dist/chunk-2UQOHYE2.js +45 -0
- package/dist/chunk-2UQOHYE2.js.map +1 -0
- package/dist/chunk-6ATE2PSM.js +344 -0
- package/dist/chunk-6ATE2PSM.js.map +1 -0
- package/dist/{chunk-57CVQCFX.js → chunk-A4O7GIWE.js} +74 -23
- package/dist/chunk-A4O7GIWE.js.map +1 -0
- package/dist/{chunk-5WFRKURX.js → chunk-DLXZMS5K.js} +4 -2
- package/dist/chunk-DLXZMS5K.js.map +1 -0
- package/dist/chunk-ET53IIEP.js +1 -0
- package/dist/chunk-ET53IIEP.js.map +1 -0
- package/dist/chunk-HWVFJAAH.js +362 -0
- package/dist/chunk-HWVFJAAH.js.map +1 -0
- package/dist/{chunk-2TMAWB4Y.js → chunk-IMSCRLLV.js} +1 -1
- package/dist/chunk-IMSCRLLV.js.map +1 -0
- package/dist/{chunk-B4EEON3N.js → chunk-KKNUBQ6Y.js} +536 -103
- package/dist/chunk-KKNUBQ6Y.js.map +1 -0
- package/dist/chunk-LDQ2HJIX.js +596 -0
- package/dist/chunk-LDQ2HJIX.js.map +1 -0
- package/dist/chunk-LH7I6SH7.js +7208 -0
- package/dist/chunk-LH7I6SH7.js.map +1 -0
- package/dist/chunk-PGGGKYWG.js +1 -0
- package/dist/chunk-PGGGKYWG.js.map +1 -0
- package/dist/{chunk-7UDSRZKG.js → chunk-Q3ROPT5H.js} +35 -14
- package/dist/chunk-Q3ROPT5H.js.map +1 -0
- package/dist/chunk-QE7TWGVT.js +178 -0
- package/dist/chunk-QE7TWGVT.js.map +1 -0
- package/dist/chunk-RUDYOTA6.js +345 -0
- package/dist/chunk-RUDYOTA6.js.map +1 -0
- package/dist/{chunk-K32VJONL.js → chunk-T5UK6YOB.js} +41 -2
- package/dist/chunk-T5UK6YOB.js.map +1 -0
- package/dist/{chunk-3K5OG6KI.js → chunk-TEEEILMP.js} +412 -186
- package/dist/chunk-TEEEILMP.js.map +1 -0
- package/dist/{chunk-FR2RBTKO.js → chunk-TQWLI6S2.js} +93 -27
- package/dist/chunk-TQWLI6S2.js.map +1 -0
- package/dist/{chunk-WMOI7FN3.js → chunk-UY7KGQ5R.js} +12 -2
- package/dist/{chunk-WMOI7FN3.js.map → chunk-UY7KGQ5R.js.map} +1 -1
- package/dist/{chunk-3E5F2XMR.js → chunk-VWUFZ6ZG.js} +29 -2
- package/dist/chunk-VWUFZ6ZG.js.map +1 -0
- package/dist/chunk-ZLQKNOZQ.js +1 -0
- package/dist/chunk-ZLQKNOZQ.js.map +1 -0
- package/dist/doc/index.d.ts +5 -5
- package/dist/doc/index.js +135 -8
- package/dist/generate/index.d.ts +3 -74
- package/dist/generate/index.js +2 -7
- package/dist/icons/index.d.ts +3 -26
- package/dist/icons/index.js +13 -0
- package/dist/icons/inlineIconMarker.d.ts +1 -0
- package/dist/icons/inlineIconMarker.js +15 -0
- package/dist/icons/inlineIconMarker.js.map +1 -0
- package/dist/imageEdit/index.d.ts +12 -6
- package/dist/imageEdit/index.js +4 -1
- package/dist/index.d.ts +14 -11
- package/dist/index.js +265 -37
- package/dist/inlineIconMarker-CiE8Hlvz.d.ts +59 -0
- package/dist/jsonForm/index.d.ts +42 -1
- package/dist/jsonForm/index.js +9 -1
- package/dist/markdown/index.d.ts +228 -3
- package/dist/markdown/index.js +42 -7
- package/dist/recommend/index.d.ts +1 -1
- package/dist/recommend/index.js +3 -2
- package/dist/schemas/index.d.ts +28 -8
- package/dist/schemas/index.js +36 -8
- package/dist/spatial/index.d.ts +9 -4
- package/dist/spatial/index.js +1 -1
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +1 -1
- package/dist/story/index.d.ts +1021 -41
- package/dist/story/index.js +135 -8
- package/dist/{themeLibrary-BHjJ0Qx6.d.ts → themeLibrary-CehcJhzz.d.ts} +1 -1
- package/dist/timing/index.js +3 -5
- package/dist/transform/index.d.ts +48 -10
- package/dist/transform/index.js +17 -481
- package/dist/transform/index.js.map +1 -1
- package/dist/{types-BdZkdJ3z.d.ts → types-DlAZ7MW4.d.ts} +115 -1
- package/dist/versions/index.d.ts +1 -1
- package/package.json +6 -1
- package/src/__tests__/animationUtils.test.ts +40 -0
- package/src/__tests__/annotationCoercion.test.ts +243 -0
- package/src/__tests__/applyRenderStyle.test.ts +146 -0
- package/src/__tests__/atmosphereLayers.test.ts +108 -0
- package/src/__tests__/attrTokens.test.ts +162 -0
- package/src/__tests__/contentExtractor.test.ts +60 -0
- package/src/__tests__/coverBlock.test.ts +46 -1
- package/src/__tests__/customTemplateSample.test.ts +144 -0
- package/src/__tests__/customTemplatesFrontmatter.test.ts +236 -0
- package/src/__tests__/customThemesFrontmatter.test.ts +145 -0
- package/src/__tests__/diagramBlock.test.ts +122 -0
- package/src/__tests__/diagramLayout.test.ts +134 -0
- package/src/__tests__/drawing.test.ts +109 -0
- package/src/__tests__/drawingBlock.test.ts +124 -0
- package/src/__tests__/drawingLayout.test.ts +171 -0
- package/src/__tests__/geohash.test.ts +6 -5
- package/src/__tests__/getLayers.test.ts +6 -2
- package/src/__tests__/getLayersFallback.test.ts +103 -0
- package/src/__tests__/imageEditExportSvg.test.ts +70 -0
- package/src/__tests__/imageEditVersions.test.ts +72 -0
- package/src/__tests__/inlineIconMarker.test.ts +36 -0
- package/src/__tests__/inputDescriptors.test.ts +162 -0
- package/src/__tests__/jsonForm.tokens.test.ts +84 -0
- package/src/__tests__/layoutBlock.test.ts +83 -0
- package/src/__tests__/layoutLayout.test.ts +169 -0
- package/src/__tests__/markdown.test.ts +87 -0
- package/src/__tests__/markdownSanitize.test.ts +79 -0
- package/src/__tests__/markdownToDoc.test.ts +391 -2
- package/src/__tests__/mediaAnnotations.test.ts +91 -0
- package/src/__tests__/mediaSchedule.test.ts +118 -0
- package/src/__tests__/pandocAttrParse.test.ts +187 -0
- package/src/__tests__/resolveDocTheme.test.ts +55 -0
- package/src/__tests__/rootExports.test.ts +43 -0
- package/src/__tests__/shapeGeometry.test.ts +89 -0
- package/src/__tests__/shapeVocabulary.test.ts +133 -0
- package/src/__tests__/structuredData.test.ts +249 -0
- package/src/__tests__/templateAnnotationParse.test.ts +108 -0
- package/src/__tests__/templateMetadata.test.ts +31 -0
- package/src/__tests__/templates.test.ts +257 -4
- package/src/__tests__/themeCompile.test.ts +42 -0
- package/src/__tests__/themeValidator.test.ts +6 -0
- package/src/__tests__/transformV2.test.ts +137 -0
- package/src/__tests__/transitionNormalize.test.ts +61 -0
- package/src/__tests__/validateDoc.test.ts +260 -0
- package/src/doc/annotationBlocks.ts +117 -0
- package/src/doc/customTemplatesFrontmatter.ts +314 -0
- package/src/doc/customThemesFrontmatter.ts +95 -0
- package/src/doc/docToMarkdown.ts +104 -5
- package/src/doc/getLayers.ts +49 -17
- package/src/doc/index.ts +47 -1
- package/src/doc/markdownToDoc.ts +411 -13
- package/src/doc/mediaAnnotations.ts +100 -0
- package/src/doc/resolveDocTheme.ts +55 -0
- package/src/doc/standaloneAnnotation.ts +58 -0
- package/src/doc/structuredData.ts +301 -0
- package/src/doc/templateInputs.ts +240 -0
- package/src/doc/templates/__tests__/customTemplate.test.ts +170 -0
- package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +110 -0
- package/src/doc/templates/accentImage.ts +30 -6
- package/src/doc/templates/captionUtils.ts +23 -0
- package/src/doc/templates/comparisonBar.ts +33 -18
- package/src/doc/templates/coverBlock.ts +35 -5
- package/src/doc/templates/customTemplate.ts +51 -0
- package/src/doc/templates/dataTable.ts +37 -19
- package/src/doc/templates/dateEvent.ts +41 -20
- package/src/doc/templates/definitionCard.ts +26 -18
- package/src/doc/templates/diagramBlock.ts +204 -0
- package/src/doc/templates/diagramLayout.ts +159 -0
- package/src/doc/templates/drawingBlock.ts +325 -0
- package/src/doc/templates/drawingLayout.ts +539 -0
- package/src/doc/templates/factCard.ts +54 -26
- package/src/doc/templates/fallbackBlock.ts +123 -0
- package/src/doc/templates/featureBlock.ts +20 -13
- package/src/doc/templates/fullBleedQuote.ts +18 -8
- package/src/doc/templates/imageWithCaption.ts +30 -15
- package/src/doc/templates/index.ts +225 -46
- package/src/doc/templates/inputDescriptors.ts +432 -0
- package/src/doc/templates/layoutBlock.ts +43 -0
- package/src/doc/templates/layoutLayout.ts +243 -0
- package/src/doc/templates/listBlock.ts +56 -30
- package/src/doc/templates/mapBlock.ts +15 -12
- package/src/doc/templates/metadata.ts +120 -0
- package/src/doc/templates/persistentLayers.ts +129 -11
- package/src/doc/templates/photoGrid.ts +22 -34
- package/src/doc/templates/pullQuote.ts +30 -12
- package/src/doc/templates/quoteBlock.ts +54 -29
- package/src/doc/templates/sectionHeader.ts +25 -11
- package/src/doc/templates/statHighlight.ts +39 -22
- package/src/doc/templates/titleBlock.ts +59 -21
- package/src/doc/templates/tokens/__tests__/resolveTokens.test.ts +487 -0
- package/src/doc/templates/tokens/resolveTokens.ts +453 -0
- package/src/doc/templates/twoColumn.ts +48 -30
- package/src/doc/templates/videoPullQuote.ts +22 -12
- package/src/doc/templates/videoWithCaption.ts +21 -15
- package/src/doc/utils/animationUtils.ts +267 -3
- package/src/doc/utils/applyRenderStyle.ts +113 -0
- package/src/doc/utils/imageTreatment.ts +70 -0
- package/src/doc/utils/nearest.ts +59 -0
- package/src/doc/utils/shapeGeometry.ts +464 -0
- package/src/doc/utils/themeUtils.ts +75 -1
- package/src/doc/validate.ts +575 -0
- package/src/generate/contentExtractor.ts +148 -35
- package/src/generate/index.ts +0 -3
- package/src/icons/index.ts +8 -0
- package/src/icons/inlineIconMarker.ts +73 -0
- package/src/imageEdit/export.ts +85 -2
- package/src/imageEdit/index.ts +1 -0
- package/src/imageEdit/persistence.ts +51 -0
- package/src/index.ts +2 -0
- package/src/jsonForm/index.ts +2 -0
- package/src/jsonForm/tokens.ts +78 -0
- package/src/markdown/annotationCoercion.ts +295 -0
- package/src/markdown/attrTokens.ts +241 -0
- package/src/markdown/convert.ts +229 -26
- package/src/markdown/index.ts +37 -0
- package/src/markdown/sanitize.ts +318 -0
- package/src/markdown/stringify.ts +96 -6
- package/src/markdown/types.ts +66 -0
- package/src/markdown/utils.ts +111 -2
- package/src/recommend/templates.ts +24 -0
- package/src/schemas/BlockTemplates.ts +133 -4
- package/src/schemas/CustomTemplates.ts +126 -0
- package/src/schemas/Doc.ts +387 -65
- package/src/schemas/ImageEditDoc.ts +11 -4
- package/src/schemas/Media.ts +169 -0
- package/src/schemas/Theme.ts +23 -1
- package/src/schemas/Transitions.ts +224 -0
- package/src/schemas/colorUtils.ts +33 -0
- package/src/schemas/fontStacks.ts +5 -2
- package/src/schemas/index.ts +3 -0
- package/src/schemas/themeCompile.ts +24 -5
- package/src/schemas/themeValidator.ts +49 -11
- package/src/schemas/themes/cinematic.json +69 -12
- package/src/schemas/themes/documentary.json +58 -11
- package/src/schemas/themes/gezellig.json +60 -11
- package/src/schemas/themes/magazine.json +54 -9
- package/src/schemas/themes/morning-light.json +52 -9
- package/src/schemas/themes/standard-dark.json +48 -13
- package/src/schemas/themes/standard.json +44 -12
- package/src/schemas/themes/tech-dark.json +65 -12
- package/src/spatial/Geohash.ts +52 -21
- package/src/storage/ContentContainer.ts +6 -2
- package/src/transform/applyTransform.ts +43 -4
- package/src/transform/index.ts +1 -0
- package/src/transform/registry.ts +44 -13
- package/src/transform/styles/dataDriven.ts +2 -1
- package/src/transform/styles/documentary.ts +2 -1
- package/src/transform/styles/magazine.ts +3 -1
- package/src/transform/styles/minimal.ts +2 -1
- package/src/transform/styles/narrative.ts +3 -1
- package/src/transform/templateSelector.ts +87 -11
- package/src/transform/types.ts +35 -2
- package/dist/chunk-2TMAWB4Y.js.map +0 -1
- package/dist/chunk-3E5F2XMR.js.map +0 -1
- package/dist/chunk-3K5OG6KI.js.map +0 -1
- package/dist/chunk-4X3JQXNM.js +0 -35
- package/dist/chunk-4X3JQXNM.js.map +0 -1
- package/dist/chunk-57CVQCFX.js.map +0 -1
- package/dist/chunk-5WFRKURX.js.map +0 -1
- package/dist/chunk-7UDSRZKG.js.map +0 -1
- package/dist/chunk-B4EEON3N.js.map +0 -1
- package/dist/chunk-FR2RBTKO.js.map +0 -1
- package/dist/chunk-H3AXU4MJ.js +0 -179
- package/dist/chunk-H3AXU4MJ.js.map +0 -1
- package/dist/chunk-K32VJONL.js.map +0 -1
- package/dist/chunk-KSWJR66U.js +0 -3706
- package/dist/chunk-KSWJR66U.js.map +0 -1
- package/dist/chunk-MYIH7FWD.js +0 -145
- package/dist/chunk-MYIH7FWD.js.map +0 -1
- package/dist/chunk-ZTX4PFFT.js.map +0 -1
- package/src/__tests__/slideshowGenerator.test.ts +0 -128
- package/src/generate/slideshowGenerator.ts +0 -273
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/recommend/templates.ts"],"sourcesContent":["/**\n * Block template recommendations.\n *\n * Given a slice of markdown block nodes (the body underneath a heading),\n * profile the content for image / video / quote / list / table / date /\n * stat signals, then map that profile to the set of templates that make\n * sense for the block. Used by the editor's template picker to surface a\n * \"Recommended for this block\" section above the full template list.\n */\n\nimport { extractPlainText, findNodesByType, walkMarkdownTree } from '../markdown/utils.js';\nimport type {\n HtmlElement,\n HtmlNode,\n MarkdownBlockNode,\n MarkdownHtmlBlock,\n MarkdownNode,\n} from '../markdown/types.js';\n\nexport interface BlockContentProfile {\n hasImage: boolean;\n imageCount: number;\n hasVideo: boolean;\n hasBlockquote: boolean;\n hasList: boolean;\n hasTable: boolean;\n hasDate: boolean;\n hasNumberHighlight: boolean;\n wordCount: number;\n}\n\nexport interface RecommendationResult {\n recommended: string[];\n rest: string[];\n}\n\nconst EMPTY_PROFILE: BlockContentProfile = Object.freeze({\n hasImage: false,\n imageCount: 0,\n hasVideo: false,\n hasBlockquote: false,\n hasList: false,\n hasTable: false,\n hasDate: false,\n hasNumberHighlight: false,\n wordCount: 0,\n});\n\nconst DATE_PATTERNS: RegExp[] = [\n /\\b(January|February|March|April|May|June|July|August|September|October|November|December)\\s+(\\d{1,2},?\\s+)?\\d{4}\\b/i,\n /\\b\\d{1,2}\\s+(January|February|March|April|May|June|July|August|September|October|November|December)\\s+\\d{4}\\b/i,\n /\\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Sept|Oct|Nov|Dec)\\.?\\s+\\d{1,2},?\\s+\\d{4}\\b/i,\n /\\b\\d{4}-\\d{2}-\\d{2}\\b/,\n /\\b\\d{1,2}\\/\\d{1,2}\\/\\d{2,4}\\b/,\n /\\bQ[1-4]\\s+\\d{4}\\b/,\n /\\b\\d{4}s\\b/,\n /\\b\\d{1,2}(st|nd|rd|th)\\s+century\\b/i,\n];\n\n/**\n * Matches a \"highlight number\" — a prominent figure suitable for a Stat\n * Highlight block. Qualifies on any of:\n * - currency prefix: `$2.3M`, `€500`, `¥1,234`\n * - unit suffix: `50%`, `100 years`, `5×`, `2.3M`\n * - standalone large: `1,234`, `5000`, `12,345`\n * Plain small numbers (`42`) intentionally don't qualify.\n */\nconst NUMBER_HIGHLIGHT_RE =\n /(?:[$€£¥]\\s?\\d+(?:[.,]\\d+)*(?:\\s?(?:[MBK]|million|billion|thousand))?|\\d+(?:[.,]\\d+)*\\s?(?:%|‰|x|×|[MBK]|million|billion|thousand|percent|years?|days?|hours?)|\\d{3,}(?:[.,]\\d+)*)/i;\n\nconst VIDEO_HOST_RE = /(youtube\\.com|youtu\\.be|vimeo\\.com|wistia\\.|loom\\.com)/i;\n\nfunction htmlElementsByTag(root: MarkdownNode, tagNames: Set<string>): HtmlElement[] {\n const blocks = findNodesByType<MarkdownHtmlBlock>(root, 'htmlBlock');\n // Inline HTML (htmlInline) also carries htmlChildren; include both.\n const inline = findNodesByType<MarkdownNode>(root, 'htmlInline') as Array<\n MarkdownNode & { htmlChildren?: HtmlNode[] }\n >;\n const out: HtmlElement[] = [];\n const visit = (n: HtmlNode): void => {\n if (n.type === 'htmlElement') {\n if (tagNames.has(n.tagName.toLowerCase())) out.push(n);\n for (const c of n.children) visit(c);\n }\n };\n for (const b of blocks) for (const c of b.htmlChildren) visit(c);\n for (const i of inline) {\n if (Array.isArray(i.htmlChildren)) for (const c of i.htmlChildren) visit(c);\n }\n return out;\n}\n\n/**\n * Walk a slice of block nodes and summarize what kinds of content it\n * contains. Cheap to run — no markdown parsing, just AST traversal.\n */\nexport function profileBlockContents(nodes: MarkdownBlockNode[]): BlockContentProfile {\n if (!nodes || nodes.length === 0) return { ...EMPTY_PROFILE };\n\n let imageCount = 0;\n let hasBlockquote = false;\n let hasList = false;\n let hasTable = false;\n\n const plainParts: string[] = [];\n\n for (const node of nodes) {\n imageCount += findNodesByType(node, 'image').length;\n imageCount += findNodesByType(node, 'imageReference').length;\n if (findNodesByType(node, 'blockquote').length > 0) hasBlockquote = true;\n if (findNodesByType(node, 'list').length > 0) hasList = true;\n if (findNodesByType(node, 'table').length > 0) hasTable = true;\n plainParts.push(extractPlainText(node));\n }\n\n // HTML embeds: <img>, <video>, <iframe src=…video host>\n const root: MarkdownNode = { type: 'document', children: nodes };\n const imgTags = htmlElementsByTag(root, new Set(['img']));\n imageCount += imgTags.length;\n\n const videoTags = htmlElementsByTag(root, new Set(['video', 'iframe', 'source']));\n let hasVideo = false;\n for (const el of videoTags) {\n if (el.tagName.toLowerCase() === 'video') {\n hasVideo = true;\n break;\n }\n const src = el.attributes.src || el.attributes.href || '';\n if (VIDEO_HOST_RE.test(src)) {\n hasVideo = true;\n break;\n }\n }\n\n // Link-only video embeds (markdown link to a known video host).\n if (!hasVideo) {\n const links = findNodesByType<MarkdownNode & { url?: string }>(root, 'link');\n for (const link of links) {\n if (link.url && VIDEO_HOST_RE.test(link.url)) {\n hasVideo = true;\n break;\n }\n }\n }\n\n const plainText = plainParts.join(' ').trim();\n const wordCount = plainText ? plainText.split(/\\s+/).length : 0;\n\n let hasDate = false;\n for (const re of DATE_PATTERNS) {\n if (re.test(plainText)) {\n hasDate = true;\n break;\n }\n }\n\n // Number highlight: a paragraph that's mostly a single prominent figure.\n let hasNumberHighlight = false;\n walkMarkdownTree(root, (n) => {\n if (hasNumberHighlight) return true;\n if (n.type !== 'paragraph') return;\n const text = extractPlainText(n).trim();\n if (!text) return true;\n const m = text.match(NUMBER_HIGHLIGHT_RE);\n if (!m) return true;\n // Paragraph qualifies when its word count is small AND a prominent\n // number occupies a meaningful chunk of it. Keeps \"the company grew\n // 50% last year\" from triggering, but accepts \"$2.3M raised\".\n const words = text.split(/\\s+/).length;\n if (words <= 8) hasNumberHighlight = true;\n return true;\n });\n\n return {\n hasImage: imageCount > 0,\n imageCount,\n hasVideo,\n hasBlockquote,\n hasList,\n hasTable,\n hasDate,\n hasNumberHighlight,\n wordCount,\n };\n}\n\n// ── Recommendation rules ───────────────────────────────────────────\n\nconst UNIVERSAL_DEFAULTS = ['title', 'sectionHeader', 'factCard', 'twoColumn'];\n\n/**\n * Given a content profile, return the canonical template-name list that\n * should appear in the \"Recommended\" bucket. Caller is responsible for\n * preserving deduplication / ordering when intersecting with the full\n * template list (see {@link recommendTemplatesForBlock}).\n */\nfunction recommendedNamesForProfile(profile: BlockContentProfile): string[] {\n const names = new Set<string>();\n let anyContentSignal = false;\n\n if (profile.hasImage) {\n anyContentSignal = true;\n names.add('imageWithCaption');\n names.add('leftFeature');\n names.add('rightFeature');\n if (profile.imageCount >= 2) names.add('photoGrid');\n }\n\n if (profile.hasVideo) {\n anyContentSignal = true;\n names.add('videoWithCaption');\n if (profile.hasBlockquote) names.add('videoPullQuote');\n }\n\n if (profile.hasBlockquote) {\n anyContentSignal = true;\n names.add('quote');\n names.add('pullQuote');\n names.add('fullBleedQuote');\n }\n\n if (profile.hasList) {\n anyContentSignal = true;\n names.add('list');\n }\n\n if (profile.hasTable) {\n anyContentSignal = true;\n names.add('dataTable');\n names.add('comparisonBar');\n }\n\n if (profile.hasDate) {\n anyContentSignal = true;\n names.add('dateEvent');\n }\n\n if (profile.hasNumberHighlight) {\n anyContentSignal = true;\n names.add('statHighlight');\n }\n\n if (anyContentSignal) {\n // Universal pair only — keep recommended focused.\n names.add('title');\n names.add('sectionHeader');\n } else {\n for (const n of UNIVERSAL_DEFAULTS) names.add(n);\n }\n\n return Array.from(names);\n}\n\n/**\n * Split a flat list of template names into a \"Recommended\" bucket\n * (matches the active block's content profile) and a \"rest\" bucket\n * (everything else). Both buckets preserve the input ordering of\n * `allNames`, so the visual layout stays predictable as templates are\n * added.\n */\nexport function recommendTemplatesForBlock(\n profile: BlockContentProfile,\n allNames: readonly string[],\n): RecommendationResult {\n const desired = new Set(recommendedNamesForProfile(profile));\n const recommended: string[] = [];\n const rest: string[] = [];\n for (const name of allNames) {\n if (desired.has(name)) recommended.push(name);\n else rest.push(name);\n }\n return { recommended, rest };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/recommend/templates.ts"],"sourcesContent":["/**\n * Block template recommendations.\n *\n * Given a slice of markdown block nodes (the body underneath a heading),\n * profile the content for image / video / quote / list / table / date /\n * stat signals, then map that profile to the set of templates that make\n * sense for the block. Used by the editor's template picker to surface a\n * \"Recommended for this block\" section above the full template list.\n */\n\nimport { extractPlainText, findNodesByType, walkMarkdownTree } from '../markdown/utils.js';\nimport type {\n HtmlElement,\n HtmlNode,\n MarkdownBlockNode,\n MarkdownHtmlBlock,\n MarkdownNode,\n} from '../markdown/types.js';\n\nexport interface BlockContentProfile {\n hasImage: boolean;\n imageCount: number;\n hasVideo: boolean;\n hasBlockquote: boolean;\n hasList: boolean;\n hasTable: boolean;\n hasDate: boolean;\n hasNumberHighlight: boolean;\n wordCount: number;\n}\n\nexport interface RecommendationResult {\n recommended: string[];\n rest: string[];\n}\n\nconst EMPTY_PROFILE: BlockContentProfile = Object.freeze({\n hasImage: false,\n imageCount: 0,\n hasVideo: false,\n hasBlockquote: false,\n hasList: false,\n hasTable: false,\n hasDate: false,\n hasNumberHighlight: false,\n wordCount: 0,\n});\n\nconst DATE_PATTERNS: RegExp[] = [\n /\\b(January|February|March|April|May|June|July|August|September|October|November|December)\\s+(\\d{1,2},?\\s+)?\\d{4}\\b/i,\n /\\b\\d{1,2}\\s+(January|February|March|April|May|June|July|August|September|October|November|December)\\s+\\d{4}\\b/i,\n /\\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Sept|Oct|Nov|Dec)\\.?\\s+\\d{1,2},?\\s+\\d{4}\\b/i,\n /\\b\\d{4}-\\d{2}-\\d{2}\\b/,\n /\\b\\d{1,2}\\/\\d{1,2}\\/\\d{2,4}\\b/,\n /\\bQ[1-4]\\s+\\d{4}\\b/,\n /\\b\\d{4}s\\b/,\n /\\b\\d{1,2}(st|nd|rd|th)\\s+century\\b/i,\n];\n\n/**\n * Matches a \"highlight number\" — a prominent figure suitable for a Stat\n * Highlight block. Qualifies on any of:\n * - currency prefix: `$2.3M`, `€500`, `¥1,234`\n * - unit suffix: `50%`, `100 years`, `5×`, `2.3M`\n * - standalone large: `1,234`, `5000`, `12,345`\n * Plain small numbers (`42`) intentionally don't qualify.\n */\nconst NUMBER_HIGHLIGHT_RE =\n /(?:[$€£¥]\\s?\\d+(?:[.,]\\d+)*(?:\\s?(?:[MBK]|million|billion|thousand))?|\\d+(?:[.,]\\d+)*\\s?(?:%|‰|x|×|[MBK]|million|billion|thousand|percent|years?|days?|hours?)|\\d{3,}(?:[.,]\\d+)*)/i;\n\nconst VIDEO_HOST_RE = /(youtube\\.com|youtu\\.be|vimeo\\.com|wistia\\.|loom\\.com)/i;\n\nfunction htmlElementsByTag(root: MarkdownNode, tagNames: Set<string>): HtmlElement[] {\n const blocks = findNodesByType<MarkdownHtmlBlock>(root, 'htmlBlock');\n // Inline HTML (htmlInline) also carries htmlChildren; include both.\n const inline = findNodesByType<MarkdownNode>(root, 'htmlInline') as Array<\n MarkdownNode & { htmlChildren?: HtmlNode[] }\n >;\n const out: HtmlElement[] = [];\n const visit = (n: HtmlNode): void => {\n if (n.type === 'htmlElement') {\n if (tagNames.has(n.tagName.toLowerCase())) out.push(n);\n for (const c of n.children) visit(c);\n }\n };\n for (const b of blocks) for (const c of b.htmlChildren) visit(c);\n for (const i of inline) {\n if (Array.isArray(i.htmlChildren)) for (const c of i.htmlChildren) visit(c);\n }\n return out;\n}\n\n/**\n * Walk a slice of block nodes and summarize what kinds of content it\n * contains. Cheap to run — no markdown parsing, just AST traversal.\n */\nexport function profileBlockContents(nodes: MarkdownBlockNode[]): BlockContentProfile {\n if (!nodes || nodes.length === 0) return { ...EMPTY_PROFILE };\n\n let imageCount = 0;\n let hasBlockquote = false;\n let hasList = false;\n let hasTable = false;\n\n const plainParts: string[] = [];\n\n for (const node of nodes) {\n imageCount += findNodesByType(node, 'image').length;\n imageCount += findNodesByType(node, 'imageReference').length;\n if (findNodesByType(node, 'blockquote').length > 0) hasBlockquote = true;\n if (findNodesByType(node, 'list').length > 0) hasList = true;\n if (findNodesByType(node, 'table').length > 0) hasTable = true;\n plainParts.push(extractPlainText(node));\n }\n\n // HTML embeds: <img>, <video>, <iframe src=…video host>\n const root: MarkdownNode = { type: 'document', children: nodes };\n const imgTags = htmlElementsByTag(root, new Set(['img']));\n imageCount += imgTags.length;\n\n const videoTags = htmlElementsByTag(root, new Set(['video', 'iframe', 'source']));\n let hasVideo = false;\n for (const el of videoTags) {\n if (el.tagName.toLowerCase() === 'video') {\n hasVideo = true;\n break;\n }\n const src = el.attributes.src || el.attributes.href || '';\n if (VIDEO_HOST_RE.test(src)) {\n hasVideo = true;\n break;\n }\n }\n\n // Link-only video embeds (markdown link to a known video host).\n if (!hasVideo) {\n const links = findNodesByType<MarkdownNode & { url?: string }>(root, 'link');\n for (const link of links) {\n if (link.url && VIDEO_HOST_RE.test(link.url)) {\n hasVideo = true;\n break;\n }\n }\n }\n\n const plainText = plainParts.join(' ').trim();\n const wordCount = plainText ? plainText.split(/\\s+/).length : 0;\n\n let hasDate = false;\n for (const re of DATE_PATTERNS) {\n if (re.test(plainText)) {\n hasDate = true;\n break;\n }\n }\n\n // Number highlight: a paragraph that's mostly a single prominent figure.\n let hasNumberHighlight = false;\n walkMarkdownTree(root, (n) => {\n if (hasNumberHighlight) return true;\n if (n.type !== 'paragraph') return;\n const text = extractPlainText(n).trim();\n if (!text) return true;\n const m = text.match(NUMBER_HIGHLIGHT_RE);\n if (!m) return true;\n // Paragraph qualifies when its word count is small AND a prominent\n // number occupies a meaningful chunk of it. Keeps \"the company grew\n // 50% last year\" from triggering, but accepts \"$2.3M raised\".\n const words = text.split(/\\s+/).length;\n if (words <= 8) hasNumberHighlight = true;\n return true;\n });\n\n return {\n hasImage: imageCount > 0,\n imageCount,\n hasVideo,\n hasBlockquote,\n hasList,\n hasTable,\n hasDate,\n hasNumberHighlight,\n wordCount,\n };\n}\n\n// ── Recommendation rules ───────────────────────────────────────────\n\nconst UNIVERSAL_DEFAULTS = ['title', 'sectionHeader', 'factCard', 'twoColumn'];\n\n/**\n * Given a content profile, return the canonical template-name list that\n * should appear in the \"Recommended\" bucket. Caller is responsible for\n * preserving deduplication / ordering when intersecting with the full\n * template list (see {@link recommendTemplatesForBlock}).\n */\nfunction recommendedNamesForProfile(profile: BlockContentProfile): string[] {\n const names = new Set<string>();\n let anyContentSignal = false;\n\n if (profile.hasImage) {\n anyContentSignal = true;\n names.add('imageWithCaption');\n names.add('leftFeature');\n names.add('rightFeature');\n if (profile.imageCount >= 2) names.add('photoGrid');\n }\n\n if (profile.hasVideo) {\n anyContentSignal = true;\n names.add('videoWithCaption');\n if (profile.hasBlockquote) names.add('videoPullQuote');\n }\n\n if (profile.hasBlockquote) {\n anyContentSignal = true;\n names.add('quote');\n names.add('pullQuote');\n names.add('fullBleedQuote');\n }\n\n if (profile.hasList) {\n anyContentSignal = true;\n names.add('list');\n }\n\n if (profile.hasTable) {\n anyContentSignal = true;\n names.add('dataTable');\n names.add('comparisonBar');\n }\n\n if (profile.hasDate) {\n anyContentSignal = true;\n names.add('dateEvent');\n }\n\n if (profile.hasNumberHighlight) {\n anyContentSignal = true;\n names.add('statHighlight');\n }\n\n if (anyContentSignal) {\n // Universal pair only — keep recommended focused.\n names.add('title');\n names.add('sectionHeader');\n } else {\n for (const n of UNIVERSAL_DEFAULTS) names.add(n);\n }\n\n return Array.from(names);\n}\n\n/**\n * Deterministic single-template choice for an unannotated heading block,\n * from strong content signals only. Returns `undefined` when no signal is\n * decisive — the caller keeps its structural default (`sectionHeader`).\n *\n * Precedence favors the most specific/structured content: a table beats\n * an image beats a blockquote beats a stat-looking line. `blockIndex`\n * alternates left/right feature composition for single-image blocks so a\n * run of image sections doesn't stack the same layout.\n *\n * Used by `markdownToDoc`'s auto template picking (see its `autoTemplates`\n * option); the multi-candidate `recommendTemplatesForBlock` below serves\n * the editor's template-picker UI instead.\n */\nexport function pickAutoTemplate(profile: BlockContentProfile, blockIndex = 0): string | undefined {\n if (profile.hasTable) return 'dataTable';\n if (profile.imageCount >= 2) return 'photoGrid';\n if (profile.hasImage) return blockIndex % 2 === 0 ? 'leftFeature' : 'rightFeature';\n if (profile.hasBlockquote) return 'quote';\n if (profile.hasNumberHighlight) return 'statHighlight';\n if (profile.hasList) return 'list';\n return undefined;\n}\n\n/**\n * Split a flat list of template names into a \"Recommended\" bucket\n * (matches the active block's content profile) and a \"rest\" bucket\n * (everything else). Both buckets preserve the input ordering of\n * `allNames`, so the visual layout stays predictable as templates are\n * added.\n */\nexport function recommendTemplatesForBlock(\n profile: BlockContentProfile,\n allNames: readonly string[],\n): RecommendationResult {\n const desired = new Set(recommendedNamesForProfile(profile));\n const recommended: string[] = [];\n const rest: string[] = [];\n for (const name of allNames) {\n if (desired.has(name)) recommended.push(name);\n else rest.push(name);\n }\n return { recommended, rest };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -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-
|
|
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":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=chunk-ZLQKNOZQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/doc/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { AccentLayout, AudioSegmentTiming, CoverBlockInput, DEFAULT_LAYOUT, DocStylePreset, ExpandDocBlocksOptions, MarkdownToDocOptions, RenderContext, TEMPLATE_ALIASES, adjustY, comparisonBar, countBlocks, coverBlock, createAccentLayers, dataTable, dateEvent, definitionCard, docToMarkdown, expandCoverBlock, expandDocBlocks, expandPersistentLayers, expandTemplateBlock, factCard, flattenBlocks, fullBleedQuote, getAccentLayout, getAnimationProgress, getAnimationStyle, getAvailableTemplates, getBlockDepth, getDefaultAnimation, getDefaultAnimationDuration, getDocStyleConfig, getLayers, getOverlayOpacity, getTemplateHint, getThemeFont, getTransitionClass, hasTemplate, imageWithCaption, leftFeature, listBlock, mapBlock, markdownToDoc, photoGrid, pullQuote, quoteBlock, resolveAudioMapping, resolveColorScheme, resolveTemplateName, rightFeature, scaleAnimationDuration, scoreTextSimilarity, sectionHeader, shouldUseShadow, statHighlight, templateRegistry, themedFontSize, titleBlock, twoColumn, videoPullQuote, videoWithCaption } from '../story/index.js';
|
|
2
|
-
export { D as DEFAULT_THEME, g as getAvailableThemes, b as getThemeSummaries, r as resolveTheme } from '../themeLibrary-
|
|
3
|
-
export {
|
|
4
|
-
import '../types-
|
|
5
|
-
import '../ContentContainer-
|
|
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
|
+
import '../types-DlAZ7MW4.js';
|
|
5
|
+
import '../ContentContainer-BXUlIf18.js';
|
package/dist/doc/index.js
CHANGED
|
@@ -1,21 +1,48 @@
|
|
|
1
1
|
import {
|
|
2
|
+
BASE_INPUT_DESCRIPTORS,
|
|
3
|
+
CONTAINER_TEMPLATES,
|
|
2
4
|
DEFAULT_LAYOUT,
|
|
5
|
+
SHAPE_NAMES,
|
|
3
6
|
TEMPLATE_ALIASES,
|
|
7
|
+
TEMPLATE_INPUT_DESCRIPTORS,
|
|
8
|
+
TEMPLATE_METADATA,
|
|
4
9
|
adjustY,
|
|
10
|
+
applyRenderStyleToLayers,
|
|
11
|
+
buildRegistry,
|
|
12
|
+
coerceTemplateParams,
|
|
5
13
|
comparisonBar,
|
|
14
|
+
computeDiagramLayout,
|
|
15
|
+
computeDrawingLayout,
|
|
16
|
+
computeLayoutLayers,
|
|
6
17
|
countBlocks,
|
|
7
18
|
coverBlock,
|
|
8
19
|
createAccentLayers,
|
|
20
|
+
cssFilterForTreatment,
|
|
9
21
|
dataTable,
|
|
10
22
|
dateEvent,
|
|
23
|
+
decodeLayersFromFrontmatter,
|
|
11
24
|
definitionCard,
|
|
25
|
+
deriveTemplateInputs,
|
|
26
|
+
diagramBlock,
|
|
12
27
|
docToMarkdown,
|
|
28
|
+
drawingBlock,
|
|
29
|
+
encodeLayersForFrontmatter,
|
|
13
30
|
expandCoverBlock,
|
|
14
31
|
expandDocBlocks,
|
|
15
32
|
expandPersistentLayers,
|
|
16
33
|
expandTemplateBlock,
|
|
34
|
+
extractBlockquoteText,
|
|
35
|
+
extractBodyPlainText,
|
|
36
|
+
extractFirstImage,
|
|
37
|
+
extractImages,
|
|
38
|
+
extractListItems,
|
|
39
|
+
extractTableData,
|
|
40
|
+
extractTableFromContents,
|
|
17
41
|
factCard,
|
|
42
|
+
fallbackBlockLayers,
|
|
43
|
+
findFirstTable,
|
|
18
44
|
flattenBlocks,
|
|
45
|
+
flattenRenderableBlocks,
|
|
19
46
|
fullBleedQuote,
|
|
20
47
|
getAccentLayout,
|
|
21
48
|
getAnimationProgress,
|
|
@@ -27,21 +54,35 @@ import {
|
|
|
27
54
|
getDocStyleConfig,
|
|
28
55
|
getLayers,
|
|
29
56
|
getOverlayOpacity,
|
|
57
|
+
getPersistentLayersFromTheme,
|
|
30
58
|
getTemplateHint,
|
|
31
59
|
getThemeFont,
|
|
32
60
|
getTransitionClass,
|
|
33
61
|
hasTemplate,
|
|
34
62
|
imageWithCaption,
|
|
63
|
+
isContainerTemplate,
|
|
64
|
+
isDataFence,
|
|
65
|
+
isShapeName,
|
|
66
|
+
layoutBlock,
|
|
35
67
|
leftFeature,
|
|
68
|
+
lintTemplateParams,
|
|
36
69
|
listBlock,
|
|
37
70
|
mapBlock,
|
|
38
71
|
markdownToDoc,
|
|
72
|
+
normalizeShapeKind,
|
|
73
|
+
parseDataFence,
|
|
74
|
+
parseYamlSubset,
|
|
39
75
|
photoGrid,
|
|
40
76
|
pullQuote,
|
|
41
77
|
quoteBlock,
|
|
78
|
+
readCustomTemplatesFromFrontmatter,
|
|
79
|
+
readCustomThemesFromFrontmatter,
|
|
80
|
+
replaceDataFence,
|
|
42
81
|
resolveAudioMapping,
|
|
43
82
|
resolveColorScheme,
|
|
83
|
+
resolvePersistentLayers,
|
|
44
84
|
resolveTemplateName,
|
|
85
|
+
resolveThemeForDoc,
|
|
45
86
|
rightFeature,
|
|
46
87
|
scaleAnimationDuration,
|
|
47
88
|
scoreTextSimilarity,
|
|
@@ -49,18 +90,42 @@ import {
|
|
|
49
90
|
shouldUseShadow,
|
|
50
91
|
statHighlight,
|
|
51
92
|
templateRegistry,
|
|
93
|
+
themeWantsAmbientMotion,
|
|
94
|
+
themedEntrance,
|
|
52
95
|
themedFontSize,
|
|
96
|
+
themedImageTreatment,
|
|
97
|
+
themedScrim,
|
|
98
|
+
themedSurfaceGradient,
|
|
53
99
|
titleBlock,
|
|
54
100
|
twoColumn,
|
|
101
|
+
validateMarkdownDoc,
|
|
102
|
+
validateMarkdownSource,
|
|
55
103
|
videoPullQuote,
|
|
56
|
-
videoWithCaption
|
|
57
|
-
|
|
104
|
+
videoWithCaption,
|
|
105
|
+
wrapWithPersistentLayers,
|
|
106
|
+
writeCustomTemplatesToFrontmatter,
|
|
107
|
+
writeCustomThemesToFrontmatter
|
|
108
|
+
} from "../chunk-LH7I6SH7.js";
|
|
109
|
+
import "../chunk-UY7KGQ5R.js";
|
|
110
|
+
import "../chunk-V543AI2F.js";
|
|
111
|
+
import "../chunk-FVTQSNR7.js";
|
|
112
|
+
import {
|
|
113
|
+
PATH_SHAPE_KINDS,
|
|
114
|
+
clipEndpoints,
|
|
115
|
+
clipPoint,
|
|
116
|
+
connectorPath,
|
|
117
|
+
lineStyleDasharray,
|
|
118
|
+
markerPath,
|
|
119
|
+
shapePath
|
|
120
|
+
} from "../chunk-RUDYOTA6.js";
|
|
58
121
|
import {
|
|
59
122
|
DEFAULT_THEME,
|
|
123
|
+
FRONTMATTER_CUSTOM_TEMPLATES_KEY,
|
|
124
|
+
FRONTMATTER_CUSTOM_THEMES_KEY,
|
|
60
125
|
getAvailableThemes,
|
|
61
126
|
getThemeSummaries,
|
|
62
127
|
resolveTheme
|
|
63
|
-
} from "../chunk-
|
|
128
|
+
} from "../chunk-KKNUBQ6Y.js";
|
|
64
129
|
import {
|
|
65
130
|
VIEWPORT_PRESETS,
|
|
66
131
|
createTemplateContext,
|
|
@@ -70,31 +135,66 @@ import {
|
|
|
70
135
|
getViewportOrientation,
|
|
71
136
|
isTemplateBlock,
|
|
72
137
|
scaledFontSize2 as scaledFontSize
|
|
73
|
-
} from "../chunk-
|
|
74
|
-
import "../chunk-
|
|
75
|
-
import "../chunk-
|
|
76
|
-
import "../chunk-
|
|
138
|
+
} from "../chunk-DLXZMS5K.js";
|
|
139
|
+
import "../chunk-TEEEILMP.js";
|
|
140
|
+
import "../chunk-HWVFJAAH.js";
|
|
141
|
+
import "../chunk-DBS6RIFL.js";
|
|
142
|
+
import "../chunk-QE7TWGVT.js";
|
|
143
|
+
import "../chunk-VWUFZ6ZG.js";
|
|
77
144
|
export {
|
|
145
|
+
BASE_INPUT_DESCRIPTORS,
|
|
146
|
+
CONTAINER_TEMPLATES,
|
|
78
147
|
DEFAULT_LAYOUT,
|
|
79
148
|
DEFAULT_THEME,
|
|
149
|
+
FRONTMATTER_CUSTOM_TEMPLATES_KEY,
|
|
150
|
+
FRONTMATTER_CUSTOM_THEMES_KEY,
|
|
151
|
+
PATH_SHAPE_KINDS,
|
|
152
|
+
SHAPE_NAMES,
|
|
80
153
|
TEMPLATE_ALIASES,
|
|
154
|
+
TEMPLATE_INPUT_DESCRIPTORS,
|
|
155
|
+
TEMPLATE_METADATA,
|
|
81
156
|
VIEWPORT_PRESETS,
|
|
82
157
|
adjustY,
|
|
158
|
+
applyRenderStyleToLayers,
|
|
159
|
+
buildRegistry,
|
|
160
|
+
clipEndpoints,
|
|
161
|
+
clipPoint,
|
|
162
|
+
coerceTemplateParams,
|
|
83
163
|
comparisonBar,
|
|
164
|
+
computeDiagramLayout,
|
|
165
|
+
computeDrawingLayout,
|
|
166
|
+
computeLayoutLayers,
|
|
167
|
+
connectorPath,
|
|
84
168
|
countBlocks,
|
|
85
169
|
coverBlock,
|
|
86
170
|
createAccentLayers,
|
|
87
171
|
createTemplateContext,
|
|
172
|
+
cssFilterForTreatment,
|
|
88
173
|
dataTable,
|
|
89
174
|
dateEvent,
|
|
175
|
+
decodeLayersFromFrontmatter,
|
|
90
176
|
definitionCard,
|
|
177
|
+
deriveTemplateInputs,
|
|
178
|
+
diagramBlock,
|
|
91
179
|
docToMarkdown,
|
|
180
|
+
drawingBlock,
|
|
181
|
+
encodeLayersForFrontmatter,
|
|
92
182
|
expandCoverBlock,
|
|
93
183
|
expandDocBlocks,
|
|
94
184
|
expandPersistentLayers,
|
|
95
185
|
expandTemplateBlock,
|
|
186
|
+
extractBlockquoteText,
|
|
187
|
+
extractBodyPlainText,
|
|
188
|
+
extractFirstImage,
|
|
189
|
+
extractImages,
|
|
190
|
+
extractListItems,
|
|
191
|
+
extractTableData,
|
|
192
|
+
extractTableFromContents,
|
|
96
193
|
factCard,
|
|
194
|
+
fallbackBlockLayers,
|
|
195
|
+
findFirstTable,
|
|
97
196
|
flattenBlocks,
|
|
197
|
+
flattenRenderableBlocks,
|
|
98
198
|
fullBleedQuote,
|
|
99
199
|
getAccentLayout,
|
|
100
200
|
getAnimationProgress,
|
|
@@ -108,6 +208,7 @@ export {
|
|
|
108
208
|
getLayers,
|
|
109
209
|
getLayoutHints,
|
|
110
210
|
getOverlayOpacity,
|
|
211
|
+
getPersistentLayersFromTheme,
|
|
111
212
|
getTemplateHint,
|
|
112
213
|
getThemeFont,
|
|
113
214
|
getThemeSummaries,
|
|
@@ -117,30 +218,56 @@ export {
|
|
|
117
218
|
getViewportOrientation,
|
|
118
219
|
hasTemplate,
|
|
119
220
|
imageWithCaption,
|
|
221
|
+
isContainerTemplate,
|
|
222
|
+
isDataFence,
|
|
223
|
+
isShapeName,
|
|
120
224
|
isTemplateBlock,
|
|
225
|
+
layoutBlock,
|
|
121
226
|
leftFeature,
|
|
227
|
+
lineStyleDasharray,
|
|
228
|
+
lintTemplateParams,
|
|
122
229
|
listBlock,
|
|
123
230
|
mapBlock,
|
|
124
231
|
markdownToDoc,
|
|
232
|
+
markerPath,
|
|
233
|
+
normalizeShapeKind,
|
|
234
|
+
parseDataFence,
|
|
235
|
+
parseYamlSubset,
|
|
125
236
|
photoGrid,
|
|
126
237
|
pullQuote,
|
|
127
238
|
quoteBlock,
|
|
239
|
+
readCustomTemplatesFromFrontmatter,
|
|
240
|
+
readCustomThemesFromFrontmatter,
|
|
241
|
+
replaceDataFence,
|
|
128
242
|
resolveAudioMapping,
|
|
129
243
|
resolveColorScheme,
|
|
244
|
+
resolvePersistentLayers,
|
|
130
245
|
resolveTemplateName,
|
|
131
246
|
resolveTheme,
|
|
247
|
+
resolveThemeForDoc,
|
|
132
248
|
rightFeature,
|
|
133
249
|
scaleAnimationDuration,
|
|
134
250
|
scaledFontSize,
|
|
135
251
|
scoreTextSimilarity,
|
|
136
252
|
sectionHeader,
|
|
253
|
+
shapePath,
|
|
137
254
|
shouldUseShadow,
|
|
138
255
|
statHighlight,
|
|
139
256
|
templateRegistry,
|
|
257
|
+
themeWantsAmbientMotion,
|
|
258
|
+
themedEntrance,
|
|
140
259
|
themedFontSize,
|
|
260
|
+
themedImageTreatment,
|
|
261
|
+
themedScrim,
|
|
262
|
+
themedSurfaceGradient,
|
|
141
263
|
titleBlock,
|
|
142
264
|
twoColumn,
|
|
265
|
+
validateMarkdownDoc,
|
|
266
|
+
validateMarkdownSource,
|
|
143
267
|
videoPullQuote,
|
|
144
|
-
videoWithCaption
|
|
268
|
+
videoWithCaption,
|
|
269
|
+
wrapWithPersistentLayers,
|
|
270
|
+
writeCustomTemplatesToFrontmatter,
|
|
271
|
+
writeCustomThemesToFrontmatter
|
|
145
272
|
};
|
|
146
273
|
//# sourceMappingURL=index.js.map
|
package/dist/generate/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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 {
|
|
4
|
-
import '../types-
|
|
3
|
+
import { m as ColorScheme, A as AccentImage, at as TemplateBlock } from '../Doc-BBVGq1_9.js';
|
|
4
|
+
import '../types-DlAZ7MW4.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Template Mapper
|
|
@@ -25,75 +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
|
-
* ```ts
|
|
90
|
-
* const doc = generateSlideshow(articleText, myImages, {
|
|
91
|
-
* title: 'Mount Rainier',
|
|
92
|
-
* themeId: 'documentary',
|
|
93
|
-
* });
|
|
94
|
-
* // doc is a complete Doc ready for DocPlayer / LinearDocView
|
|
95
|
-
* ```
|
|
96
|
-
*/
|
|
97
|
-
declare function generateSlideshow(text: string, images?: SlideshowImage[], options?: SlideshowOptions): SlideshowDoc;
|
|
98
|
-
|
|
99
|
-
export { ExtractedElement, type MapOptions, type SlideshowDoc, type SlideshowImage, type SlideshowOptions, generateSlideshow, mapElementToBlock };
|
|
28
|
+
export { ExtractedElement, type MapOptions, mapElementToBlock };
|
package/dist/generate/index.js
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
generateSlideshow
|
|
3
|
-
} from "../chunk-MYIH7FWD.js";
|
|
1
|
+
import "../chunk-ET53IIEP.js";
|
|
4
2
|
import {
|
|
5
3
|
extractContent,
|
|
6
4
|
mapElementToBlock,
|
|
7
5
|
stripMarkdown
|
|
8
|
-
} from "../chunk-
|
|
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
|
};
|
package/dist/icons/index.d.ts
CHANGED
|
@@ -1,28 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* FontAwesome Free icon catalog. Run `node scripts/generate-icon-data.mjs`
|
|
5
|
-
* to regenerate after bumping @fortawesome/fontawesome-free.
|
|
6
|
-
*
|
|
7
|
-
* Entry count: 2141
|
|
8
|
-
* Generated: 2026-05-14T03:38:13.863Z
|
|
9
|
-
*/
|
|
10
|
-
type IconFamily = 'brands' | 'solid' | 'regular';
|
|
11
|
-
interface IconEntry {
|
|
12
|
-
/** Icon name without the `fa-` prefix (e.g. `github`). */
|
|
13
|
-
name: string;
|
|
14
|
-
/** Family bucket — drives the `fa-brands` / `fa-solid` / `fa-regular` class. */
|
|
15
|
-
family: IconFamily;
|
|
16
|
-
/** Human display label (used by the picker tooltip). */
|
|
17
|
-
label: string;
|
|
18
|
-
/** Lowercase, space-joined search keywords. */
|
|
19
|
-
keywords: string;
|
|
20
|
-
/** FontAwesome Private-Use-Area codepoint as a hex string (e.g. `'f09b'`).
|
|
21
|
-
* Use `String.fromCodePoint(parseInt(unicode, 16))` to get the rendered
|
|
22
|
-
* glyph when the FA font is loaded. */
|
|
23
|
-
unicode: string;
|
|
24
|
-
}
|
|
25
|
-
declare const ICONS: IconEntry[];
|
|
1
|
+
import { a as IconEntry } from '../inlineIconMarker-CiE8Hlvz.js';
|
|
2
|
+
export { I as ICONS, 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';
|
|
26
3
|
|
|
27
4
|
/**
|
|
28
5
|
* Icon Resolver
|
|
@@ -84,4 +61,4 @@ interface IconSuggestion {
|
|
|
84
61
|
*/
|
|
85
62
|
declare function suggestIcons(query: string, limit?: number): IconSuggestion[];
|
|
86
63
|
|
|
87
|
-
export {
|
|
64
|
+
export { IconEntry, type IconSuggestion, canonicalIconToken, iconGlyph, looksLikeIconToken, resolveIcon, suggestIcons };
|
package/dist/icons/index.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import "../chunk-PGGGKYWG.js";
|
|
2
|
+
import {
|
|
3
|
+
hasIconMarker,
|
|
4
|
+
iconClass,
|
|
5
|
+
iconMarker,
|
|
6
|
+
splitIconMarkers,
|
|
7
|
+
stripIconMarkers
|
|
8
|
+
} from "../chunk-2UQOHYE2.js";
|
|
1
9
|
import {
|
|
2
10
|
ICONS,
|
|
3
11
|
canonicalIconToken,
|
|
@@ -9,9 +17,14 @@ import {
|
|
|
9
17
|
export {
|
|
10
18
|
ICONS,
|
|
11
19
|
canonicalIconToken,
|
|
20
|
+
hasIconMarker,
|
|
21
|
+
iconClass,
|
|
12
22
|
iconGlyph,
|
|
23
|
+
iconMarker,
|
|
13
24
|
looksLikeIconToken,
|
|
14
25
|
resolveIcon,
|
|
26
|
+
splitIconMarkers,
|
|
27
|
+
stripIconMarkers,
|
|
15
28
|
suggestIcons
|
|
16
29
|
};
|
|
17
30
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { c as IconTextRun, h as hasIconMarker, i as iconClass, d as iconMarker, s as splitIconMarkers, e as stripIconMarkers } from '../inlineIconMarker-CiE8Hlvz.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
hasIconMarker,
|
|
3
|
+
iconClass,
|
|
4
|
+
iconMarker,
|
|
5
|
+
splitIconMarkers,
|
|
6
|
+
stripIconMarkers
|
|
7
|
+
} from "../chunk-2UQOHYE2.js";
|
|
8
|
+
export {
|
|
9
|
+
hasIconMarker,
|
|
10
|
+
iconClass,
|
|
11
|
+
iconMarker,
|
|
12
|
+
splitIconMarkers,
|
|
13
|
+
stripIconMarkers
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=inlineIconMarker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { a as ImageEditDoc, b as ImageEditLayer } from '../ImageEditDoc-
|
|
2
|
-
export { E as EditorLayerMeta, I as ImageEditCanvas, c as ImageEditLayerKind, d as ImageEditMeta } from '../ImageEditDoc-
|
|
3
|
-
import { C as ContentContainer } from '../ContentContainer-
|
|
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-
|
|
6
|
-
import '../types-
|
|
5
|
+
import '../Doc-BBVGq1_9.js';
|
|
6
|
+
import '../types-DlAZ7MW4.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Pure helpers for constructing and mutating {@link ImageEditDoc} values.
|
|
@@ -212,5 +212,11 @@ interface ImageEditExportOptions {
|
|
|
212
212
|
* layers are read from `container` and inlined as data URLs.
|
|
213
213
|
*/
|
|
214
214
|
declare function exportImageEditDoc(doc: ImageEditDoc, container: ContentContainer, options?: ImageEditExportOptions): Promise<Blob>;
|
|
215
|
+
/**
|
|
216
|
+
* Build the standalone SVG string that mirrors the canvas + layers. Exposed
|
|
217
|
+
* for tests (the raster step needs a browser); shape/text/path layers don't
|
|
218
|
+
* touch `container`, only image layers do (to inline asset bytes).
|
|
219
|
+
*/
|
|
220
|
+
declare function buildSvgString(doc: ImageEditDoc, container: ContentContainer): Promise<string>;
|
|
215
221
|
|
|
216
|
-
export { IMAGE_EDIT_ASSETS_PREFIX, IMAGE_EDIT_DEFAULT_BASENAME, IMAGE_EDIT_STATE_FILENAME, IMAGE_EDIT_VERSIONS_PREFIX, ImageEditDoc, type ImageEditExportFormat, type ImageEditExportOptions, ImageEditLayer, ImageEditVersionManager, type ImageEditVersionManagerOptions, type RevertImageEditOptions, type SaveImageEditVersionOptions, type SaveImageEditVersionResult, addLayer, buildImageEditVersionPath, coalesceImageEditVersions, createEmptyImageEditDoc, exportImageEditDoc, listImageEditVersions, parseImageEditVersionPath, pruneImageEditVersions, readImageEditDoc, readImageEditVersion, readImageEditVersionText, removeLayer, reorderLayer, revertToImageEditVersion, saveImageEditVersion, setCanvas, touch, updateLayer, writeImageEditDoc };
|
|
222
|
+
export { IMAGE_EDIT_ASSETS_PREFIX, IMAGE_EDIT_DEFAULT_BASENAME, IMAGE_EDIT_STATE_FILENAME, IMAGE_EDIT_VERSIONS_PREFIX, ImageEditDoc, type ImageEditExportFormat, type ImageEditExportOptions, ImageEditLayer, ImageEditVersionManager, type ImageEditVersionManagerOptions, type RevertImageEditOptions, type SaveImageEditVersionOptions, type SaveImageEditVersionResult, addLayer, buildImageEditVersionPath, buildSvgString, coalesceImageEditVersions, createEmptyImageEditDoc, exportImageEditDoc, listImageEditVersions, parseImageEditVersionPath, pruneImageEditVersions, readImageEditDoc, readImageEditVersion, readImageEditVersionText, removeLayer, reorderLayer, revertToImageEditVersion, saveImageEditVersion, setCanvas, touch, updateLayer, writeImageEditDoc };
|