@bendyline/squisq 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE.md +24 -0
- package/README.md +8 -8
- package/dist/{ContentContainer-BXUlIf18.d.ts → ContentContainer-B2w9sUoL.d.ts} +15 -0
- package/dist/{Doc-DynJleo-.d.ts → Doc-COe-rPQB.d.ts} +7 -5
- package/dist/{ImageEditDoc-Ca4Tr9uN.d.ts → ImageEditDoc-dtKahVyD.d.ts} +1 -1
- package/dist/{annotationCoercion-Dr_DY9Hx.d.ts → annotationCoercion-PtRQhk5V.d.ts} +1 -1
- package/dist/{chunk-VWCJ2WXC.js → chunk-2ZWIXGAC.js} +0 -1
- package/dist/{chunk-VYFRI7R6.js → chunk-32R2RZAO.js} +72 -3
- package/dist/chunk-3IGPAPQ7.js +645 -0
- package/dist/{chunk-QE7TWGVT.js → chunk-4VOD55SX.js} +0 -1
- package/dist/{chunk-3E5F2XMR.js → chunk-67L6WRJN.js} +0 -1
- package/dist/{chunk-5DKBFXPY.js → chunk-6ECMNUIP.js} +26 -18
- package/dist/{chunk-DBS6RIFL.js → chunk-7N4G32LG.js} +0 -1
- package/dist/{chunk-JOQYPRDZ.js → chunk-7YEZFHLS.js} +10 -8
- package/dist/{chunk-2UQOHYE2.js → chunk-7ZAAICW4.js} +0 -1
- package/dist/{chunk-66QO7XFB.js → chunk-ACZOVWX3.js} +117 -7
- package/dist/{chunk-5J4HKRJF.js → chunk-BAOV476U.js} +0 -1
- package/dist/chunk-BCCXTMN5.js +699 -0
- package/dist/{chunk-JHZWYRSW.js → chunk-C33GTPUZ.js} +11 -4
- package/dist/{chunk-XNLB57UD.js → chunk-EK446BUE.js} +18 -2
- package/dist/{chunk-VR7UPJ7C.js → chunk-FCG3BIZN.js} +12 -1
- package/dist/{chunk-JI77MGAK.js → chunk-GIIOY6XR.js} +2178 -1291
- package/dist/{chunk-Q7LROV2H.js → chunk-NKNMGIIN.js} +0 -1
- package/dist/chunk-OPO5K4DZ.js +241 -0
- package/dist/{chunk-TUWMK62B.js → chunk-PUS54YU6.js} +45 -2
- package/dist/{chunk-OTKVFVL6.js → chunk-QNTQIEIV.js} +130 -47
- package/dist/{chunk-5UYI3RJB.js → chunk-QWCFK5FN.js} +55 -40
- package/dist/{chunk-GZY66SDN.js → chunk-R3KTTOMS.js} +0 -1
- package/dist/{chunk-ILWDXLUK.js → chunk-RS5AP3J4.js} +49 -10
- package/dist/{chunk-QUUPYOSP.js → chunk-SPTY4C6F.js} +136 -5
- package/dist/{chunk-4X3JQXNM.js → chunk-XOFT65EX.js} +1 -2
- package/dist/{chunk-FVTQSNR7.js → chunk-XRW6P7IF.js} +13 -5
- package/dist/{chunk-R2YZTCLO.js → chunk-ZQKZSJAX.js} +1 -2
- package/dist/doc/index.d.ts +311 -13
- package/dist/doc/index.js +25 -17
- package/dist/generate/index.d.ts +2 -2
- package/dist/generate/index.js +1 -3
- package/dist/icons/index.js +2 -4
- package/dist/icons/inlineIconMarker.js +1 -2
- package/dist/imageEdit/index.d.ts +48 -17
- package/dist/imageEdit/index.js +3 -4
- package/dist/index.d.ts +13 -13
- package/dist/index.js +67 -33
- package/dist/jsonForm/index.d.ts +10 -3
- package/dist/jsonForm/index.js +8 -7
- package/dist/markdown/index.d.ts +75 -11
- package/dist/markdown/index.js +32 -7
- package/dist/{materializePageSection-DDzubQXo.d.ts → materializePageSection-BSMOocve.d.ts} +2 -2
- package/dist/narration/index.d.ts +16 -3
- package/dist/narration/index.js +12 -14
- package/dist/random/index.d.ts +11 -2
- package/dist/random/index.js +1 -3
- package/dist/recommend/index.d.ts +1 -1
- package/dist/recommend/index.js +2 -4
- package/dist/schemas/index.d.ts +18 -6
- package/dist/schemas/index.js +7 -6
- package/dist/spatial/index.d.ts +2 -1
- package/dist/spatial/index.js +1 -2
- package/dist/storage/index.d.ts +4 -2
- package/dist/storage/index.js +1 -2
- package/dist/{themeLibrary-B72m0W1y.d.ts → themeLibrary-BUTWjufL.d.ts} +1 -1
- package/dist/timing/index.js +2 -4
- package/dist/transform/index.d.ts +3 -3
- package/dist/transform/index.js +6 -7
- package/dist/{types-C4kiRn_k.d.ts → types-8QjefM9J.d.ts} +38 -2
- package/dist/{types-BwMPl2CB.d.ts → types-CUNc9biN.d.ts} +24 -1
- package/dist/versions/index.d.ts +14 -11
- package/dist/versions/index.js +2 -3
- package/package.json +8 -3
- package/dist/chunk-2UQOHYE2.js.map +0 -1
- package/dist/chunk-3E5F2XMR.js.map +0 -1
- package/dist/chunk-4X3JQXNM.js.map +0 -1
- package/dist/chunk-5DKBFXPY.js.map +0 -1
- package/dist/chunk-5J4HKRJF.js.map +0 -1
- package/dist/chunk-5UYI3RJB.js.map +0 -1
- package/dist/chunk-66QO7XFB.js.map +0 -1
- package/dist/chunk-AMIR72JP.js +0 -380
- package/dist/chunk-AMIR72JP.js.map +0 -1
- package/dist/chunk-DBS6RIFL.js.map +0 -1
- package/dist/chunk-DNJKBAI7.js +0 -1
- package/dist/chunk-DNJKBAI7.js.map +0 -1
- package/dist/chunk-ET53IIEP.js +0 -1
- package/dist/chunk-ET53IIEP.js.map +0 -1
- package/dist/chunk-FVTQSNR7.js.map +0 -1
- package/dist/chunk-GZY66SDN.js.map +0 -1
- package/dist/chunk-ILWDXLUK.js.map +0 -1
- package/dist/chunk-JHZWYRSW.js.map +0 -1
- package/dist/chunk-JI77MGAK.js.map +0 -1
- package/dist/chunk-JOQYPRDZ.js.map +0 -1
- package/dist/chunk-OTKVFVL6.js.map +0 -1
- package/dist/chunk-PGGGKYWG.js +0 -1
- package/dist/chunk-PGGGKYWG.js.map +0 -1
- package/dist/chunk-Q7LROV2H.js.map +0 -1
- package/dist/chunk-QE7TWGVT.js.map +0 -1
- package/dist/chunk-QUUPYOSP.js.map +0 -1
- package/dist/chunk-R2GC6RLD.js +0 -344
- package/dist/chunk-R2GC6RLD.js.map +0 -1
- package/dist/chunk-R2YZTCLO.js.map +0 -1
- package/dist/chunk-S7A5D7ZJ.js +0 -174
- package/dist/chunk-S7A5D7ZJ.js.map +0 -1
- package/dist/chunk-TUWMK62B.js.map +0 -1
- package/dist/chunk-V543AI2F.js +0 -1
- package/dist/chunk-V543AI2F.js.map +0 -1
- package/dist/chunk-VR7UPJ7C.js.map +0 -1
- package/dist/chunk-VWCJ2WXC.js.map +0 -1
- package/dist/chunk-VYFRI7R6.js.map +0 -1
- package/dist/chunk-XNLB57UD.js.map +0 -1
- package/dist/chunk-ZLQKNOZQ.js +0 -1
- package/dist/chunk-ZLQKNOZQ.js.map +0 -1
- package/dist/doc/index.js.map +0 -1
- package/dist/generate/index.js.map +0 -1
- package/dist/icons/index.js.map +0 -1
- package/dist/icons/inlineIconMarker.js.map +0 -1
- package/dist/imageEdit/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/jsonForm/index.js.map +0 -1
- package/dist/markdown/index.js.map +0 -1
- package/dist/narration/index.js.map +0 -1
- package/dist/random/index.js.map +0 -1
- package/dist/recommend/index.js.map +0 -1
- package/dist/schemas/index.js.map +0 -1
- package/dist/spatial/index.js.map +0 -1
- package/dist/storage/index.js.map +0 -1
- package/dist/timing/index.js.map +0 -1
- package/dist/transform/index.js.map +0 -1
- package/dist/versions/index.js.map +0 -1
- package/src/__tests__/animationUtils.test.ts +0 -117
- package/src/__tests__/annotationCoercion.test.ts +0 -243
- package/src/__tests__/applyNarrationTiming.test.ts +0 -190
- package/src/__tests__/applyRenderStyle.test.ts +0 -146
- package/src/__tests__/asciiDiagramBattle.test.ts +0 -246
- package/src/__tests__/asciiDiagramDetect.test.ts +0 -162
- package/src/__tests__/asciiDiagramMapping.test.ts +0 -38
- package/src/__tests__/asciiDiagramParse.test.ts +0 -233
- package/src/__tests__/asciiDiagramPipeline.test.ts +0 -273
- package/src/__tests__/asciiDiagramRender.test.ts +0 -162
- package/src/__tests__/asciiDiagramRepair.test.ts +0 -84
- package/src/__tests__/asciiTimelineDetect.test.ts +0 -157
- package/src/__tests__/asciiTimelineParse.test.ts +0 -205
- package/src/__tests__/asciiTimelinePipeline.test.ts +0 -349
- package/src/__tests__/asciiTimelineRender.test.ts +0 -376
- package/src/__tests__/atmosphereLayers.test.ts +0 -108
- package/src/__tests__/attrTokens.test.ts +0 -167
- package/src/__tests__/colorUtils.test.ts +0 -112
- package/src/__tests__/contentContainer.test.ts +0 -325
- package/src/__tests__/contentExtractor.test.ts +0 -243
- package/src/__tests__/coverBlock.test.ts +0 -310
- package/src/__tests__/customTemplateSample.test.ts +0 -144
- package/src/__tests__/customTemplatesFrontmatter.test.ts +0 -221
- package/src/__tests__/customThemesFrontmatter.test.ts +0 -146
- package/src/__tests__/dataTable.test.ts +0 -145
- package/src/__tests__/diagramBlock.test.ts +0 -122
- package/src/__tests__/diagramLayout.test.ts +0 -134
- package/src/__tests__/diagramText.test.ts +0 -26
- package/src/__tests__/docToMarkdownMedia.test.ts +0 -83
- package/src/__tests__/drawing.test.ts +0 -109
- package/src/__tests__/drawingBlock.test.ts +0 -124
- package/src/__tests__/drawingLayout.test.ts +0 -171
- package/src/__tests__/fixtures/asciiDiagramBattle.ts +0 -512
- package/src/__tests__/fixtures/asciiDiagrams.ts +0 -287
- package/src/__tests__/fixtures/asciiTimelines.ts +0 -35
- package/src/__tests__/fixtures/treeviewFixtures.ts +0 -243
- package/src/__tests__/geohash.test.ts +0 -110
- package/src/__tests__/getLayers.test.ts +0 -243
- package/src/__tests__/getLayersFallback.test.ts +0 -103
- package/src/__tests__/haversine.test.ts +0 -63
- package/src/__tests__/iconResolve.test.ts +0 -122
- package/src/__tests__/imageEditExportSvg.test.ts +0 -70
- package/src/__tests__/imageEditState.test.ts +0 -74
- package/src/__tests__/imageEditVersions.test.ts +0 -243
- package/src/__tests__/inferDocumentTitle.test.ts +0 -50
- package/src/__tests__/inlineIconMarker.test.ts +0 -36
- package/src/__tests__/inputDescriptors.test.ts +0 -162
- package/src/__tests__/jsonForm.chooseControl.test.ts +0 -86
- package/src/__tests__/jsonForm.evaluateWhen.test.ts +0 -59
- package/src/__tests__/jsonForm.inferSchema.test.ts +0 -25
- package/src/__tests__/jsonForm.pointer.test.ts +0 -149
- package/src/__tests__/jsonForm.tokens.test.ts +0 -84
- package/src/__tests__/layoutBlock.test.ts +0 -83
- package/src/__tests__/layoutLayout.test.ts +0 -169
- package/src/__tests__/localForageAdapter.test.ts +0 -155
- package/src/__tests__/majorApiTypes.test.ts +0 -18
- package/src/__tests__/markdown.test.ts +0 -1009
- package/src/__tests__/markdownIcons.test.ts +0 -104
- package/src/__tests__/markdownSanitize.test.ts +0 -81
- package/src/__tests__/markdownToDoc.test.ts +0 -957
- package/src/__tests__/matchFontFamily.test.ts +0 -114
- package/src/__tests__/materializeBlockLayers.test.ts +0 -167
- package/src/__tests__/materializePageSections.test.ts +0 -404
- package/src/__tests__/materializeTestUtils.ts +0 -17
- package/src/__tests__/mediaAnnotations.test.ts +0 -91
- package/src/__tests__/mediaSchedule.test.ts +0 -118
- package/src/__tests__/narrationAlign.test.ts +0 -150
- package/src/__tests__/narrationFeatures.test.ts +0 -71
- package/src/__tests__/narrationNuclei.test.ts +0 -45
- package/src/__tests__/narrationPacing.test.ts +0 -189
- package/src/__tests__/narrationScript.test.ts +0 -149
- package/src/__tests__/narrationSessionRepro.test.ts +0 -62
- package/src/__tests__/narrationSidecar.test.ts +0 -88
- package/src/__tests__/narrationSyllables.test.ts +0 -65
- package/src/__tests__/narrationTestSignals.ts +0 -167
- package/src/__tests__/narrationVad.test.ts +0 -66
- package/src/__tests__/pageStyle.test.ts +0 -258
- package/src/__tests__/pandocAttrParse.test.ts +0 -187
- package/src/__tests__/recommendTemplates.test.ts +0 -183
- package/src/__tests__/resolveDocTheme.test.ts +0 -69
- package/src/__tests__/rootExports.test.ts +0 -61
- package/src/__tests__/scopedContentContainer.test.ts +0 -109
- package/src/__tests__/seededRandom.test.ts +0 -142
- package/src/__tests__/shapeGeometry.test.ts +0 -138
- package/src/__tests__/shapeVocabulary.test.ts +0 -133
- package/src/__tests__/storage.test.ts +0 -60
- package/src/__tests__/structuredData.test.ts +0 -249
- package/src/__tests__/surface.test.ts +0 -68
- package/src/__tests__/templateAnnotationParse.test.ts +0 -173
- package/src/__tests__/templateInputs.test.ts +0 -69
- package/src/__tests__/templateMetadata.test.ts +0 -32
- package/src/__tests__/templates.test.ts +0 -710
- package/src/__tests__/themeCompile.test.ts +0 -225
- package/src/__tests__/themeValidator.test.ts +0 -131
- package/src/__tests__/timing.test.ts +0 -167
- package/src/__tests__/transformProvenance.test.ts +0 -160
- package/src/__tests__/transformV2.test.ts +0 -163
- package/src/__tests__/transitionNormalize.test.ts +0 -61
- package/src/__tests__/treeviewBattle.test.ts +0 -76
- package/src/__tests__/treeviewDetect.test.ts +0 -168
- package/src/__tests__/treeviewParse.test.ts +0 -118
- package/src/__tests__/treeviewPipeline.test.ts +0 -183
- package/src/__tests__/treeviewRender.test.ts +0 -91
- package/src/__tests__/validateDoc.test.ts +0 -260
- package/src/__tests__/versions.test.ts +0 -459
- package/src/doc/annotationBlocks.ts +0 -117
- package/src/doc/applyNarrationTiming.ts +0 -244
- package/src/doc/asciiDiagram/chars.ts +0 -210
- package/src/doc/asciiDiagram/detect.ts +0 -175
- package/src/doc/asciiDiagram/index.ts +0 -38
- package/src/doc/asciiDiagram/mapping.ts +0 -225
- package/src/doc/asciiDiagram/parse.ts +0 -1095
- package/src/doc/asciiDiagram/render.ts +0 -963
- package/src/doc/asciiDiagram/repair.ts +0 -400
- package/src/doc/asciiDiagram/types.ts +0 -65
- package/src/doc/asciiTimeline/detect.ts +0 -138
- package/src/doc/asciiTimeline/index.ts +0 -26
- package/src/doc/asciiTimeline/mapping.ts +0 -43
- package/src/doc/asciiTimeline/parse.ts +0 -870
- package/src/doc/asciiTimeline/render.ts +0 -427
- package/src/doc/asciiTimeline/types.ts +0 -73
- package/src/doc/asciiTimeline/wrappedFlow.ts +0 -427
- package/src/doc/audioMapping.ts +0 -442
- package/src/doc/customTemplatesFrontmatter.ts +0 -273
- package/src/doc/customThemesFrontmatter.ts +0 -95
- package/src/doc/docToMarkdown.ts +0 -284
- package/src/doc/index.ts +0 -161
- package/src/doc/markdownToDoc.ts +0 -1054
- package/src/doc/materializeBlockLayers.ts +0 -465
- package/src/doc/mediaAnnotations.ts +0 -120
- package/src/doc/page/PageSection.ts +0 -174
- package/src/doc/page/materializePageSection.ts +0 -616
- package/src/doc/page/resolvePageBlock.ts +0 -108
- package/src/doc/page/sectionExtractors.ts +0 -466
- package/src/doc/pageCss.ts +0 -628
- package/src/doc/resolveDocTheme.ts +0 -56
- package/src/doc/standaloneAnnotation.ts +0 -58
- package/src/doc/structuredData.ts +0 -301
- package/src/doc/templateInputs.ts +0 -424
- package/src/doc/templates/__tests__/customTemplate.test.ts +0 -170
- package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +0 -124
- package/src/doc/templates/__tests__/listBlock.test.ts +0 -64
- package/src/doc/templates/accentImage.ts +0 -362
- package/src/doc/templates/captionUtils.ts +0 -56
- package/src/doc/templates/comparisonBar.ts +0 -173
- package/src/doc/templates/coverBlock.ts +0 -255
- package/src/doc/templates/customTemplate.ts +0 -51
- package/src/doc/templates/dataTable.ts +0 -102
- package/src/doc/templates/dateEvent.ts +0 -147
- package/src/doc/templates/definitionCard.ts +0 -140
- package/src/doc/templates/diagramBlock.ts +0 -403
- package/src/doc/templates/diagramLayout.ts +0 -159
- package/src/doc/templates/drawingBlock.ts +0 -325
- package/src/doc/templates/drawingLayout.ts +0 -539
- package/src/doc/templates/factCard.ts +0 -146
- package/src/doc/templates/fallbackBlock.ts +0 -123
- package/src/doc/templates/featureBlock.ts +0 -209
- package/src/doc/templates/fullBleedQuote.ts +0 -83
- package/src/doc/templates/imageWithCaption.ts +0 -186
- package/src/doc/templates/index.ts +0 -642
- package/src/doc/templates/inputDescriptors.ts +0 -451
- package/src/doc/templates/layoutBlock.ts +0 -43
- package/src/doc/templates/layoutLayout.ts +0 -243
- package/src/doc/templates/listBlock.ts +0 -207
- package/src/doc/templates/mapBlock.ts +0 -138
- package/src/doc/templates/metadata.ts +0 -130
- package/src/doc/templates/persistentLayers.ts +0 -526
- package/src/doc/templates/photoGrid.ts +0 -190
- package/src/doc/templates/pullQuote.ts +0 -141
- package/src/doc/templates/quoteBlock.ts +0 -141
- package/src/doc/templates/registry.ts +0 -88
- package/src/doc/templates/sectionHeader.ts +0 -120
- package/src/doc/templates/statHighlight.ts +0 -146
- package/src/doc/templates/templateNames.ts +0 -22
- package/src/doc/templates/timelineBlock.ts +0 -613
- package/src/doc/templates/titleBlock.ts +0 -150
- package/src/doc/templates/tokens/__tests__/resolveTokens.test.ts +0 -487
- package/src/doc/templates/tokens/resolveTokens.ts +0 -453
- package/src/doc/templates/treeBlock.ts +0 -131
- package/src/doc/templates/twoColumn.ts +0 -263
- package/src/doc/templates/videoPullQuote.ts +0 -142
- package/src/doc/templates/videoWithCaption.ts +0 -135
- package/src/doc/treeview/chars.ts +0 -72
- package/src/doc/treeview/detect.ts +0 -145
- package/src/doc/treeview/index.ts +0 -30
- package/src/doc/treeview/mapping.ts +0 -95
- package/src/doc/treeview/parse.ts +0 -201
- package/src/doc/treeview/render.ts +0 -41
- package/src/doc/treeview/types.ts +0 -43
- package/src/doc/utils/animationUtils.ts +0 -399
- package/src/doc/utils/applyRenderStyle.ts +0 -106
- package/src/doc/utils/diagramText.ts +0 -78
- package/src/doc/utils/imageTreatment.ts +0 -70
- package/src/doc/utils/nearest.ts +0 -59
- package/src/doc/utils/shapeGeometry.ts +0 -614
- package/src/doc/utils/themeUtils.ts +0 -243
- package/src/doc/validate.ts +0 -575
- package/src/generate/contentExtractor.ts +0 -921
- package/src/generate/index.ts +0 -18
- package/src/generate/templateMapper.ts +0 -177
- package/src/icons/iconData.ts +0 -31
- package/src/icons/index.ts +0 -26
- package/src/icons/inlineIconMarker.ts +0 -73
- package/src/icons/resolve.ts +0 -139
- package/src/imageEdit/ImageEditVersionManager.ts +0 -73
- package/src/imageEdit/export.ts +0 -410
- package/src/imageEdit/index.ts +0 -72
- package/src/imageEdit/persistence.ts +0 -113
- package/src/imageEdit/state.ts +0 -112
- package/src/imageEdit/versionPaths.ts +0 -44
- package/src/imageEdit/versions.ts +0 -152
- package/src/index.ts +0 -15
- package/src/internal/immutable.ts +0 -58
- package/src/jsonForm/chooseControl.ts +0 -88
- package/src/jsonForm/evaluateWhen.ts +0 -59
- package/src/jsonForm/index.ts +0 -32
- package/src/jsonForm/inferSchema.ts +0 -25
- package/src/jsonForm/pointer.ts +0 -154
- package/src/jsonForm/tokens.ts +0 -78
- package/src/jsonForm/types.ts +0 -167
- package/src/markdown/annotationCoercion.ts +0 -295
- package/src/markdown/attrTokens.ts +0 -243
- package/src/markdown/convert.ts +0 -1353
- package/src/markdown/htmlParse.ts +0 -212
- package/src/markdown/index.ts +0 -152
- package/src/markdown/parse.ts +0 -103
- package/src/markdown/sanitize.ts +0 -318
- package/src/markdown/stringify.ts +0 -207
- package/src/markdown/types.ts +0 -710
- package/src/markdown/utils.ts +0 -459
- package/src/narration/align.ts +0 -514
- package/src/narration/features.ts +0 -231
- package/src/narration/index.ts +0 -86
- package/src/narration/nuclei.ts +0 -118
- package/src/narration/pacing.ts +0 -211
- package/src/narration/script.ts +0 -239
- package/src/narration/session.ts +0 -100
- package/src/narration/sidecar.ts +0 -187
- package/src/narration/syllables.ts +0 -85
- package/src/narration/trace.ts +0 -50
- package/src/narration/types.ts +0 -299
- package/src/narration/vad.ts +0 -131
- package/src/ngeohash.d.ts +0 -11
- package/src/random/SeededRandom.ts +0 -127
- package/src/random/index.ts +0 -1
- package/src/recommend/index.ts +0 -16
- package/src/recommend/numberHighlight.ts +0 -25
- package/src/recommend/templates.ts +0 -393
- package/src/schemas/BlockTemplates.ts +0 -1046
- package/src/schemas/CustomTemplates.ts +0 -126
- package/src/schemas/Doc.ts +0 -1073
- package/src/schemas/ImageEditDoc.ts +0 -102
- package/src/schemas/LayoutStrategy.ts +0 -178
- package/src/schemas/Media.ts +0 -179
- package/src/schemas/MediaProvider.ts +0 -70
- package/src/schemas/PageStyle.ts +0 -213
- package/src/schemas/Theme.ts +0 -413
- package/src/schemas/Transitions.ts +0 -224
- package/src/schemas/Types.ts +0 -15
- package/src/schemas/Viewport.ts +0 -91
- package/src/schemas/colorUtils.ts +0 -219
- package/src/schemas/fontStacks.ts +0 -339
- package/src/schemas/index.ts +0 -31
- package/src/schemas/pageStyleDefaults.ts +0 -204
- package/src/schemas/themeCompile.ts +0 -244
- package/src/schemas/themeConstants.ts +0 -2
- package/src/schemas/themeLibrary.ts +0 -60
- package/src/schemas/themeValidator.ts +0 -609
- package/src/schemas/themes/bold.json +0 -77
- package/src/schemas/themes/cinematic.json +0 -143
- package/src/schemas/themes/documentary.json +0 -125
- package/src/schemas/themes/gezellig.json +0 -123
- package/src/schemas/themes/index.ts +0 -53
- package/src/schemas/themes/magazine.json +0 -126
- package/src/schemas/themes/minimalist.json +0 -74
- package/src/schemas/themes/morning-light.json +0 -117
- package/src/schemas/themes/standard-dark.json +0 -109
- package/src/schemas/themes/standard.json +0 -98
- package/src/schemas/themes/tech-dark.json +0 -143
- package/src/schemas/themes/warm-earth.json +0 -74
- package/src/spatial/Geohash.ts +0 -196
- package/src/spatial/Haversine.ts +0 -59
- package/src/spatial/index.ts +0 -2
- package/src/storage/ContentContainer.ts +0 -220
- package/src/storage/LocalForageAdapter.ts +0 -103
- package/src/storage/LocalStorageAdapter.ts +0 -57
- package/src/storage/MediaProviderFromContainer.ts +0 -92
- package/src/storage/MemoryStorageAdapter.ts +0 -37
- package/src/storage/ScopedContentContainer.ts +0 -143
- package/src/storage/Storage.ts +0 -28
- package/src/storage/index.ts +0 -9
- package/src/timing/index.ts +0 -17
- package/src/timing/narrationTiming.ts +0 -220
- package/src/timing/readingTime.ts +0 -94
- package/src/transform/applyTransform.ts +0 -122
- package/src/transform/blockAnalyzer.ts +0 -181
- package/src/transform/index.ts +0 -23
- package/src/transform/registry.ts +0 -217
- package/src/transform/styles/dataDriven.ts +0 -18
- package/src/transform/styles/documentary.ts +0 -18
- package/src/transform/styles/index.ts +0 -5
- package/src/transform/styles/magazine.ts +0 -19
- package/src/transform/styles/minimal.ts +0 -18
- package/src/transform/styles/narrative.ts +0 -19
- package/src/transform/templateSelector.ts +0 -389
- package/src/transform/timingAllocator.ts +0 -257
- package/src/transform/types.ts +0 -158
- package/src/versions/DocumentVersionManager.ts +0 -70
- package/src/versions/gitignore.ts +0 -34
- package/src/versions/index.ts +0 -56
- package/src/versions/operations.ts +0 -144
- package/src/versions/paths.ts +0 -51
- package/src/versions/snapshotStore.ts +0 -202
- package/src/versions/timestamp.ts +0 -48
- package/src/versions/types.ts +0 -93
|
@@ -1,424 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Template input derivation — build a template's required inputs from a
|
|
3
|
-
* block's heading + markdown body.
|
|
4
|
-
*
|
|
5
|
-
* Used by:
|
|
6
|
-
* - `markdownToDoc`'s content-aware auto template picking, so an
|
|
7
|
-
* auto-picked `quote`/`statHighlight`/`leftFeature` block carries the
|
|
8
|
-
* inputs its template needs through every render path (player, linear
|
|
9
|
-
* view, exports).
|
|
10
|
-
* - `LinearDocView` / editor previews, to render annotated blocks whose
|
|
11
|
-
* authors didn't spell out every template param.
|
|
12
|
-
*
|
|
13
|
-
* Two modes:
|
|
14
|
-
* - strict (default): returns `null` when an essential input can't be
|
|
15
|
-
* derived (no image for a feature block, no table for dataTable…) —
|
|
16
|
-
* auto-picking uses this to fall back to the structural default.
|
|
17
|
-
* - placeholders: returns visible placeholder values instead of failing —
|
|
18
|
-
* preview surfaces use this so a half-authored block still renders.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import type {
|
|
22
|
-
MarkdownBlockNode,
|
|
23
|
-
MarkdownCodeBlock,
|
|
24
|
-
MarkdownList,
|
|
25
|
-
MarkdownTable,
|
|
26
|
-
} from '../markdown/types.js';
|
|
27
|
-
import { extractPlainText } from '../markdown/utils.js';
|
|
28
|
-
import { matchNumberHighlight } from '../recommend/numberHighlight.js';
|
|
29
|
-
import {
|
|
30
|
-
detectAsciiDiagram,
|
|
31
|
-
isEligibleAsciiFenceLang,
|
|
32
|
-
isExplicitDiagramLang,
|
|
33
|
-
} from './asciiDiagram/detect.js';
|
|
34
|
-
import { asciiDiagramToTemplateData } from './asciiDiagram/mapping.js';
|
|
35
|
-
import { detectAsciiTimeline, isEligibleAsciiTimelineFenceLang } from './asciiTimeline/detect.js';
|
|
36
|
-
import { asciiTimelineToTemplateData } from './asciiTimeline/mapping.js';
|
|
37
|
-
import { detectTree, isEligibleTreeFenceLang, isExplicitTreeLang } from './treeview/detect.js';
|
|
38
|
-
import { treeToTemplateData, treeFromMarkdownList, findFirstList } from './treeview/mapping.js';
|
|
39
|
-
|
|
40
|
-
/** First image discovered in a block's body, with explicit dimensions when present. */
|
|
41
|
-
export interface FirstImage {
|
|
42
|
-
src: string;
|
|
43
|
-
alt: string;
|
|
44
|
-
width?: number;
|
|
45
|
-
height?: number;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Plain text of a block's body contents (excluding the heading). */
|
|
49
|
-
export function extractBodyPlainText(contents?: MarkdownBlockNode[]): string {
|
|
50
|
-
if (!contents || contents.length === 0) return '';
|
|
51
|
-
return contents
|
|
52
|
-
.filter((node) => !(node.type === 'code' && node.lang?.trim().toLowerCase() === 'mermaid'))
|
|
53
|
-
.map((n) => extractPlainText(n))
|
|
54
|
-
.join('\n')
|
|
55
|
-
.trim();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Extract list items as plain text. */
|
|
59
|
-
export function extractListItems(contents?: MarkdownBlockNode[]): string[] {
|
|
60
|
-
if (!contents) return [];
|
|
61
|
-
const items: string[] = [];
|
|
62
|
-
for (const node of contents) {
|
|
63
|
-
if (node.type === 'list') {
|
|
64
|
-
for (const item of (node as MarkdownList).children) {
|
|
65
|
-
const text = extractPlainText(item).trim();
|
|
66
|
-
if (text) items.push(text);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return items;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** Parse a `width`/`height` HTML attribute to a positive number. */
|
|
74
|
-
function parseDim(raw: string | undefined): number | undefined {
|
|
75
|
-
if (raw === undefined) return undefined;
|
|
76
|
-
const n = parseFloat(raw);
|
|
77
|
-
return Number.isFinite(n) && n > 0 ? n : undefined;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Find images referenced anywhere in block contents — both markdown
|
|
82
|
-
* shorthand `` (type `image`) and raw HTML `<img>` tags
|
|
83
|
-
* (type `htmlBlock`/`htmlInline`). The WYSIWYG editor emits the HTML form
|
|
84
|
-
* whenever a user resizes an image, so missing that path silently breaks
|
|
85
|
-
* every resized image.
|
|
86
|
-
*
|
|
87
|
-
* @param limit Stop after this many images (default: all).
|
|
88
|
-
*/
|
|
89
|
-
export function extractImages(
|
|
90
|
-
contents: MarkdownBlockNode[] | undefined,
|
|
91
|
-
limit = Infinity,
|
|
92
|
-
): FirstImage[] {
|
|
93
|
-
if (!contents || contents.length === 0) return [];
|
|
94
|
-
const found: FirstImage[] = [];
|
|
95
|
-
|
|
96
|
-
function fromHtml(nodes: unknown[]): void {
|
|
97
|
-
for (const node of nodes) {
|
|
98
|
-
if (found.length >= limit) return;
|
|
99
|
-
if (!node || typeof node !== 'object') continue;
|
|
100
|
-
const n = node as Record<string, unknown>;
|
|
101
|
-
if (n.type === 'htmlElement' && n.tagName === 'img') {
|
|
102
|
-
const attrs = n.attributes as Record<string, string> | undefined;
|
|
103
|
-
if (attrs && typeof attrs.src === 'string' && attrs.src) {
|
|
104
|
-
found.push({
|
|
105
|
-
src: attrs.src,
|
|
106
|
-
alt: typeof attrs.alt === 'string' ? attrs.alt : '',
|
|
107
|
-
width: parseDim(attrs.width),
|
|
108
|
-
height: parseDim(attrs.height),
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (Array.isArray(n.children)) fromHtml(n.children);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function walk(node: unknown): void {
|
|
117
|
-
if (found.length >= limit) return;
|
|
118
|
-
if (!node || typeof node !== 'object') return;
|
|
119
|
-
const n = node as Record<string, unknown>;
|
|
120
|
-
if (n.type === 'image' && typeof n.url === 'string' && n.url) {
|
|
121
|
-
found.push({ src: n.url, alt: typeof n.alt === 'string' ? n.alt : '' });
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if ((n.type === 'htmlBlock' || n.type === 'htmlInline') && Array.isArray(n.htmlChildren)) {
|
|
125
|
-
fromHtml(n.htmlChildren);
|
|
126
|
-
}
|
|
127
|
-
if (Array.isArray(n.children)) {
|
|
128
|
-
for (const child of n.children) walk(child);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
for (const node of contents) {
|
|
133
|
-
if (found.length >= limit) break;
|
|
134
|
-
walk(node);
|
|
135
|
-
}
|
|
136
|
-
return found;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/** First image in a block's body, or null. */
|
|
140
|
-
export function extractFirstImage(contents: MarkdownBlockNode[] | undefined): FirstImage | null {
|
|
141
|
-
return extractImages(contents, 1)[0] ?? null;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/** Extract table data (headers, rows, alignment) from block contents. */
|
|
145
|
-
export function extractTableFromContents(contents?: MarkdownBlockNode[]): {
|
|
146
|
-
headers: string[];
|
|
147
|
-
rows: string[][];
|
|
148
|
-
align?: (('left' | 'right' | 'center') | null)[];
|
|
149
|
-
} | null {
|
|
150
|
-
if (!contents) return null;
|
|
151
|
-
for (const node of contents) {
|
|
152
|
-
if (node.type === 'table') {
|
|
153
|
-
const table = node as MarkdownTable;
|
|
154
|
-
const [headerRow, ...bodyRows] = table.children;
|
|
155
|
-
if (!headerRow) return null;
|
|
156
|
-
const headers = headerRow.children.map((cell) => extractPlainText(cell).trim());
|
|
157
|
-
const rows = bodyRows.map((row) => row.children.map((cell) => extractPlainText(cell).trim()));
|
|
158
|
-
return { headers, rows, align: table.align };
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/** First blockquote's plain text, or ''. */
|
|
165
|
-
export function extractBlockquoteText(contents?: MarkdownBlockNode[]): string {
|
|
166
|
-
if (!contents) return '';
|
|
167
|
-
for (const node of contents) {
|
|
168
|
-
if (node.type === 'blockquote') return extractPlainText(node).trim();
|
|
169
|
-
}
|
|
170
|
-
return '';
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function firstParagraph(
|
|
174
|
-
contents: MarkdownBlockNode[] | undefined,
|
|
175
|
-
): { node: Extract<MarkdownBlockNode, { type: 'paragraph' }>; index: number } | null {
|
|
176
|
-
if (!contents) return null;
|
|
177
|
-
const index = contents.findIndex((node) => node.type === 'paragraph');
|
|
178
|
-
if (index < 0) return null;
|
|
179
|
-
return {
|
|
180
|
-
node: contents[index] as Extract<MarkdownBlockNode, { type: 'paragraph' }>,
|
|
181
|
-
index,
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/** A leading bold number is an explicit authoring signal for the hero stat. */
|
|
186
|
-
function leadingStrongStat(
|
|
187
|
-
paragraph: Extract<MarkdownBlockNode, { type: 'paragraph' }>,
|
|
188
|
-
): string | null {
|
|
189
|
-
for (const child of paragraph.children) {
|
|
190
|
-
if (child.type === 'text' && child.value.trim() === '') continue;
|
|
191
|
-
if (child.type !== 'strong') return null;
|
|
192
|
-
const text = extractPlainText(child).trim();
|
|
193
|
-
// Explicit bold authoring is intentionally broader than automatic stat
|
|
194
|
-
// recommendation: a small integer such as `**42**` is a valid hero when
|
|
195
|
-
// the author chose statHighlight. Anchor at the beginning so a bold phrase
|
|
196
|
-
// like `**Revenue grew 42%**` does not become oversized wholesale.
|
|
197
|
-
const match = text.match(/^(?:[$€£¥]\s*)?[+-]?\d+(?:[.,]\d+)*(?:\s?(?:[%‰x×]|[A-Za-z]+))?/);
|
|
198
|
-
return match?.[0].trim() || null;
|
|
199
|
-
}
|
|
200
|
-
return null;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
function removeStatPhrase(text: string, start: number, end: number): string {
|
|
204
|
-
const before = text.slice(0, start).trim();
|
|
205
|
-
let after = text.slice(end);
|
|
206
|
-
// A dash/colon visually separates inline prose, but is redundant once the
|
|
207
|
-
// stat and description render on separate lines.
|
|
208
|
-
if (!before) after = after.replace(/^\s*(?:[-–—:]\s*)?/, '');
|
|
209
|
-
else after = after.trim();
|
|
210
|
-
return [before, after].filter(Boolean).join(' ').trim();
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function bodyWithoutParagraphStat(
|
|
214
|
-
contents: MarkdownBlockNode[] | undefined,
|
|
215
|
-
paragraphIndex: number,
|
|
216
|
-
paragraphText: string,
|
|
217
|
-
start: number,
|
|
218
|
-
end: number,
|
|
219
|
-
): string {
|
|
220
|
-
if (!contents) return '';
|
|
221
|
-
return contents
|
|
222
|
-
.map((node, index) =>
|
|
223
|
-
index === paragraphIndex
|
|
224
|
-
? removeStatPhrase(paragraphText, start, end)
|
|
225
|
-
: extractPlainText(node).trim(),
|
|
226
|
-
)
|
|
227
|
-
.filter(Boolean)
|
|
228
|
-
.join('\n')
|
|
229
|
-
.trim();
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Map Markdown-authored stat content onto the template's visual roles.
|
|
234
|
-
*
|
|
235
|
-
* A leading bold metric in the body is the strongest signal (`**42%** of
|
|
236
|
-
* teams`), followed by a stat-looking heading for backward compatibility,
|
|
237
|
-
* then an unformatted metric in the first body paragraph (used by automatic
|
|
238
|
-
* templates). Generic content retains the historical heading/body mapping.
|
|
239
|
-
*/
|
|
240
|
-
function deriveStatHighlightInputs(
|
|
241
|
-
headingText: string,
|
|
242
|
-
contents: MarkdownBlockNode[] | undefined,
|
|
243
|
-
bodyText: string,
|
|
244
|
-
): Record<string, unknown> {
|
|
245
|
-
const paragraph = firstParagraph(contents);
|
|
246
|
-
if (paragraph) {
|
|
247
|
-
const paragraphText = extractPlainText(paragraph.node).trim();
|
|
248
|
-
const strongStat = leadingStrongStat(paragraph.node);
|
|
249
|
-
if (strongStat) {
|
|
250
|
-
const start = paragraphText.indexOf(strongStat);
|
|
251
|
-
const description = bodyWithoutParagraphStat(
|
|
252
|
-
contents,
|
|
253
|
-
paragraph.index,
|
|
254
|
-
paragraphText,
|
|
255
|
-
start,
|
|
256
|
-
start + strongStat.length,
|
|
257
|
-
);
|
|
258
|
-
return {
|
|
259
|
-
stat: strongStat,
|
|
260
|
-
description: description || headingText || strongStat,
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const trimmedHeading = headingText.trim();
|
|
266
|
-
const headingStat = matchNumberHighlight(trimmedHeading);
|
|
267
|
-
if (headingStat && headingStat.index === 0 && headingStat.end === trimmedHeading.length) {
|
|
268
|
-
return { stat: headingText, description: bodyText || headingText };
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (paragraph) {
|
|
272
|
-
const paragraphText = extractPlainText(paragraph.node).trim();
|
|
273
|
-
const bodyStat = matchNumberHighlight(paragraphText);
|
|
274
|
-
if (bodyStat) {
|
|
275
|
-
const description = bodyWithoutParagraphStat(
|
|
276
|
-
contents,
|
|
277
|
-
paragraph.index,
|
|
278
|
-
paragraphText,
|
|
279
|
-
bodyStat.index,
|
|
280
|
-
bodyStat.end,
|
|
281
|
-
);
|
|
282
|
-
return {
|
|
283
|
-
stat: bodyStat.value,
|
|
284
|
-
description: description || headingText || bodyStat.value,
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return { stat: headingText, description: bodyText || headingText };
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
export interface DeriveTemplateInputsOptions {
|
|
293
|
-
/**
|
|
294
|
-
* Return visible placeholder values instead of `null` when an essential
|
|
295
|
-
* input can't be derived (preview surfaces). Default false (strict).
|
|
296
|
-
*/
|
|
297
|
-
placeholders?: boolean;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Derive a template's inputs from a block's heading text and body nodes.
|
|
302
|
-
* Returns the input fields to merge onto the block, or `null` in strict
|
|
303
|
-
* mode when an essential input is missing.
|
|
304
|
-
*/
|
|
305
|
-
export function deriveTemplateInputs(
|
|
306
|
-
templateName: string,
|
|
307
|
-
headingText: string,
|
|
308
|
-
contents: MarkdownBlockNode[] | undefined,
|
|
309
|
-
options: DeriveTemplateInputsOptions = {},
|
|
310
|
-
): Record<string, unknown> | null {
|
|
311
|
-
const placeholders = options.placeholders === true;
|
|
312
|
-
const bodyText = extractBodyPlainText(contents);
|
|
313
|
-
|
|
314
|
-
switch (templateName) {
|
|
315
|
-
case 'statHighlight':
|
|
316
|
-
return deriveStatHighlightInputs(headingText, contents, bodyText);
|
|
317
|
-
case 'quote': {
|
|
318
|
-
const quote = extractBlockquoteText(contents) || bodyText || headingText;
|
|
319
|
-
return { quote };
|
|
320
|
-
}
|
|
321
|
-
case 'fullBleedQuote':
|
|
322
|
-
case 'pullQuote': {
|
|
323
|
-
// These templates take `text` (not `quote`).
|
|
324
|
-
const text = extractBlockquoteText(contents) || bodyText || headingText;
|
|
325
|
-
return { text };
|
|
326
|
-
}
|
|
327
|
-
case 'factCard':
|
|
328
|
-
return { fact: headingText, explanation: bodyText || headingText };
|
|
329
|
-
case 'comparisonBar':
|
|
330
|
-
return placeholders
|
|
331
|
-
? { leftLabel: 'A', leftValue: 60, rightLabel: 'B', rightValue: 40 }
|
|
332
|
-
: null;
|
|
333
|
-
case 'list': {
|
|
334
|
-
const items = extractListItems(contents);
|
|
335
|
-
if (items.length > 0) return { items };
|
|
336
|
-
return placeholders ? { items: ['Item 1', 'Item 2', 'Item 3'] } : null;
|
|
337
|
-
}
|
|
338
|
-
case 'definitionCard':
|
|
339
|
-
return { term: headingText, definition: bodyText || headingText };
|
|
340
|
-
case 'dateEvent':
|
|
341
|
-
return { date: headingText, description: bodyText || headingText };
|
|
342
|
-
case 'dataTable': {
|
|
343
|
-
const tableData = extractTableFromContents(contents);
|
|
344
|
-
if (tableData) return tableData;
|
|
345
|
-
return placeholders ? { headers: ['Column'], rows: [['Data']] } : null;
|
|
346
|
-
}
|
|
347
|
-
case 'imageWithCaption': {
|
|
348
|
-
const img = extractFirstImage(contents);
|
|
349
|
-
if (!img) return placeholders ? { caption: headingText } : null;
|
|
350
|
-
return { imageSrc: img.src, imageAlt: img.alt || headingText, caption: headingText };
|
|
351
|
-
}
|
|
352
|
-
case 'photoGrid': {
|
|
353
|
-
const images = extractImages(contents, 4);
|
|
354
|
-
if (images.length < 2) return placeholders ? {} : null;
|
|
355
|
-
return {
|
|
356
|
-
images: images.map((i) => ({ src: i.src, alt: i.alt })),
|
|
357
|
-
caption: headingText,
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
case 'leftFeature':
|
|
361
|
-
case 'rightFeature': {
|
|
362
|
-
const img = extractFirstImage(contents);
|
|
363
|
-
if (!img && !placeholders) return null;
|
|
364
|
-
return {
|
|
365
|
-
imageSrc: img?.src ?? '',
|
|
366
|
-
imageAlt: img?.alt || headingText,
|
|
367
|
-
imageWidth: img?.width,
|
|
368
|
-
imageHeight: img?.height,
|
|
369
|
-
title: headingText,
|
|
370
|
-
body: bodyText,
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
case 'diagram': {
|
|
374
|
-
// Nodes/edges from an ASCII-art fence in the body (the fence itself
|
|
375
|
-
// stays in `contents`, untouched, so round-trips are lossless).
|
|
376
|
-
const fences = (contents ?? []).filter((n): n is MarkdownCodeBlock => n.type === 'code');
|
|
377
|
-
const fence =
|
|
378
|
-
fences.length === 1 && isEligibleAsciiFenceLang(fences[0].lang) ? fences[0] : undefined;
|
|
379
|
-
const detection = fence
|
|
380
|
-
? detectAsciiDiagram(fence.value, { explicit: isExplicitDiagramLang(fence.lang) })
|
|
381
|
-
: undefined;
|
|
382
|
-
if (!detection?.isDiagram || !detection.diagram) return placeholders ? {} : null;
|
|
383
|
-
const { nodes, edges } = asciiDiagramToTemplateData(detection.diagram);
|
|
384
|
-
return { nodes, edges, ...(headingText ? { title: headingText } : {}) };
|
|
385
|
-
}
|
|
386
|
-
case 'timeline': {
|
|
387
|
-
// Tracks/events from a spatial ASCII timeline fence. Calling this case
|
|
388
|
-
// already implies author/template intent, so accept the detector's
|
|
389
|
-
// explicit one-event form even when the fence itself is untagged.
|
|
390
|
-
const fences = (contents ?? []).filter((n): n is MarkdownCodeBlock => n.type === 'code');
|
|
391
|
-
const fence =
|
|
392
|
-
fences.length === 1 && isEligibleAsciiTimelineFenceLang(fences[0].lang)
|
|
393
|
-
? fences[0]
|
|
394
|
-
: undefined;
|
|
395
|
-
const detection = fence ? detectAsciiTimeline(fence.value, { explicit: true }) : undefined;
|
|
396
|
-
if (!detection?.isTimeline || !detection.timeline) return placeholders ? {} : null;
|
|
397
|
-
const { tracks, links } = asciiTimelineToTemplateData(detection.timeline);
|
|
398
|
-
return { tracks, links, ...(headingText ? { title: headingText } : {}) };
|
|
399
|
-
}
|
|
400
|
-
case 'tree': {
|
|
401
|
-
// Items from an ASCII tree fence, or a nested markdown bullet list when
|
|
402
|
-
// the author explicitly annotates a listed body. The fence/list stays
|
|
403
|
-
// in `contents`, so round-trips are lossless.
|
|
404
|
-
const fences = (contents ?? []).filter((n): n is MarkdownCodeBlock => n.type === 'code');
|
|
405
|
-
const fence =
|
|
406
|
-
fences.length === 1 && isEligibleTreeFenceLang(fences[0].lang) ? fences[0] : undefined;
|
|
407
|
-
if (fence) {
|
|
408
|
-
const detection = detectTree(fence.value, { explicit: isExplicitTreeLang(fence.lang) });
|
|
409
|
-
if (detection.isTree && detection.tree) {
|
|
410
|
-
const { items } = treeToTemplateData(detection.tree);
|
|
411
|
-
return { items, ...(headingText ? { title: headingText } : {}) };
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
const list = findFirstList(contents);
|
|
415
|
-
if (list) {
|
|
416
|
-
const { items } = treeToTemplateData(treeFromMarkdownList(list));
|
|
417
|
-
if (items.length > 0) return { items, ...(headingText ? { title: headingText } : {}) };
|
|
418
|
-
}
|
|
419
|
-
return placeholders ? {} : null;
|
|
420
|
-
}
|
|
421
|
-
default:
|
|
422
|
-
return placeholders ? {} : null;
|
|
423
|
-
}
|
|
424
|
-
}
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* makeCustomTemplateFn — verifies a CustomTemplateDefinition expands
|
|
3
|
-
* correctly via the standard template function signature and that
|
|
4
|
-
* `%`-based positions resolve correctly across viewport presets.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { describe, it, expect } from 'vitest';
|
|
8
|
-
import { makeCustomTemplateFn } from '../customTemplate';
|
|
9
|
-
import type { CustomTemplateDefinition } from '../../../schemas/CustomTemplates.js';
|
|
10
|
-
import type { Block, TextLayer } from '../../../schemas/Doc.js';
|
|
11
|
-
import type { RawLayersInput, TemplateContext } from '../../../schemas/BlockTemplates.js';
|
|
12
|
-
import { createTemplateContext } from '../../../schemas/BlockTemplates.js';
|
|
13
|
-
import { DEFAULT_THEME } from '../../../schemas/themeLibrary.js';
|
|
14
|
-
import { VIEWPORT_PRESETS, type ViewportConfig } from '../../../schemas/Viewport.js';
|
|
15
|
-
|
|
16
|
-
function defn(layers: TextLayer[]): CustomTemplateDefinition {
|
|
17
|
-
return {
|
|
18
|
-
name: 'hero',
|
|
19
|
-
label: 'Hero',
|
|
20
|
-
viewport: { width: 1920, height: 1080 },
|
|
21
|
-
layers,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function makeContext(
|
|
26
|
-
block: Block,
|
|
27
|
-
viewport: ViewportConfig = VIEWPORT_PRESETS.landscape,
|
|
28
|
-
): TemplateContext {
|
|
29
|
-
const ctx = createTemplateContext(DEFAULT_THEME, 0, 1, viewport);
|
|
30
|
-
ctx.block = block;
|
|
31
|
-
return ctx;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function makeBlock(overrides: Partial<Block> = {}): Block {
|
|
35
|
-
return {
|
|
36
|
-
id: 'b',
|
|
37
|
-
startTime: 0,
|
|
38
|
-
duration: 1,
|
|
39
|
-
audioSegment: 0,
|
|
40
|
-
title: 'Welcome',
|
|
41
|
-
template: 'hero',
|
|
42
|
-
...overrides,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function makeInput(): RawLayersInput {
|
|
47
|
-
return {
|
|
48
|
-
id: 'b',
|
|
49
|
-
template: 'layout',
|
|
50
|
-
duration: 1,
|
|
51
|
-
audioSegment: 0,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
describe('makeCustomTemplateFn', () => {
|
|
56
|
-
it('substitutes the block title into a layer carrying {title}', () => {
|
|
57
|
-
const fn = makeCustomTemplateFn(
|
|
58
|
-
defn([
|
|
59
|
-
{
|
|
60
|
-
id: 't',
|
|
61
|
-
type: 'text',
|
|
62
|
-
position: { x: '10%', y: '20%', width: '80%', height: '15%' },
|
|
63
|
-
content: { text: 'Hello, {title}!', style: { fontSize: 48, color: '#000' } },
|
|
64
|
-
},
|
|
65
|
-
]),
|
|
66
|
-
);
|
|
67
|
-
const ctx = makeContext(makeBlock({ title: 'World' }));
|
|
68
|
-
const layers = fn(makeInput(), ctx);
|
|
69
|
-
expect(layers).toHaveLength(1);
|
|
70
|
-
expect((layers[0] as TextLayer).content.text).toBe('Hello, World!');
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('falls back to the input block when context.block is missing', () => {
|
|
74
|
-
const fn = makeCustomTemplateFn(
|
|
75
|
-
defn([
|
|
76
|
-
{
|
|
77
|
-
id: 't',
|
|
78
|
-
type: 'text',
|
|
79
|
-
position: { x: '0%', y: '0%', width: '100%', height: '10%' },
|
|
80
|
-
content: { text: '{title}', style: { fontSize: 24, color: '#000' } },
|
|
81
|
-
},
|
|
82
|
-
]),
|
|
83
|
-
);
|
|
84
|
-
const ctx = createTemplateContext(DEFAULT_THEME, 0, 1, VIEWPORT_PRESETS.landscape);
|
|
85
|
-
// No ctx.block set; the fn resolves against `input` instead. The
|
|
86
|
-
// default input carries no title, so {title} collapses to empty.
|
|
87
|
-
const layers = fn(makeInput(), ctx);
|
|
88
|
-
expect((layers[0] as TextLayer).content.text).toBe('');
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('resolves {attr:key} from the input block when context.block is missing', () => {
|
|
92
|
-
const fn = makeCustomTemplateFn(
|
|
93
|
-
defn([
|
|
94
|
-
{
|
|
95
|
-
id: 't',
|
|
96
|
-
type: 'text',
|
|
97
|
-
position: { x: '0%', y: '0%', width: '100%', height: '10%' },
|
|
98
|
-
content: { text: '{attr:role}', style: { fontSize: 24, color: '#000' } },
|
|
99
|
-
},
|
|
100
|
-
]),
|
|
101
|
-
);
|
|
102
|
-
const ctx = createTemplateContext(DEFAULT_THEME, 0, 1, VIEWPORT_PRESETS.landscape);
|
|
103
|
-
const input = { ...makeInput(), templateOverrides: { role: 'lead' } } as RawLayersInput;
|
|
104
|
-
const layers = fn(input, ctx);
|
|
105
|
-
expect((layers[0] as TextLayer).content.text).toBe('lead');
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('preserves %-based positions verbatim — they resolve at SSR render time', () => {
|
|
109
|
-
const fn = makeCustomTemplateFn(
|
|
110
|
-
defn([
|
|
111
|
-
{
|
|
112
|
-
id: 't',
|
|
113
|
-
type: 'text',
|
|
114
|
-
position: { x: '10%', y: '20%', width: '80%' },
|
|
115
|
-
content: { text: 'static', style: { fontSize: 24, color: '#000' } },
|
|
116
|
-
},
|
|
117
|
-
]),
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
// Landscape: 1920×1080
|
|
121
|
-
const landscapeLayers = fn(makeInput(), makeContext(makeBlock(), VIEWPORT_PRESETS.landscape));
|
|
122
|
-
expect(landscapeLayers[0].position.x).toBe('10%');
|
|
123
|
-
|
|
124
|
-
// Portrait: 1080×1920
|
|
125
|
-
const portraitLayers = fn(makeInput(), makeContext(makeBlock(), VIEWPORT_PRESETS.portrait));
|
|
126
|
-
expect(portraitLayers[0].position.x).toBe('10%');
|
|
127
|
-
|
|
128
|
-
// Square: 1080×1080
|
|
129
|
-
const squareLayers = fn(makeInput(), makeContext(makeBlock(), VIEWPORT_PRESETS.square));
|
|
130
|
-
expect(squareLayers[0].position.x).toBe('10%');
|
|
131
|
-
|
|
132
|
-
// The positions stay as `%`-strings — the SSR layer renderer (not
|
|
133
|
-
// this function) is responsible for resolving them into pixels
|
|
134
|
-
// against the target viewport. We verify the function doesn't
|
|
135
|
-
// perturb authoring intent.
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it('round-trips multiple tokens in one definition', () => {
|
|
139
|
-
const fn = makeCustomTemplateFn(
|
|
140
|
-
defn([
|
|
141
|
-
{
|
|
142
|
-
id: 'title',
|
|
143
|
-
type: 'text',
|
|
144
|
-
position: { x: '5%', y: '5%', width: '90%', height: '20%' },
|
|
145
|
-
content: { text: '{title}', style: { fontSize: 72, color: '#000' } },
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
id: 'body',
|
|
149
|
-
type: 'text',
|
|
150
|
-
position: { x: '5%', y: '30%', width: '90%', height: '60%' },
|
|
151
|
-
content: { text: '{content}', style: { fontSize: 32, color: '#333' } },
|
|
152
|
-
},
|
|
153
|
-
]),
|
|
154
|
-
);
|
|
155
|
-
const ctx = makeContext(
|
|
156
|
-
makeBlock({
|
|
157
|
-
title: 'Welcome',
|
|
158
|
-
contents: [
|
|
159
|
-
{
|
|
160
|
-
type: 'paragraph',
|
|
161
|
-
children: [{ type: 'text', value: 'A small editor for big ideas.' }],
|
|
162
|
-
},
|
|
163
|
-
],
|
|
164
|
-
}),
|
|
165
|
-
);
|
|
166
|
-
const layers = fn(makeInput(), ctx);
|
|
167
|
-
expect((layers[0] as TextLayer).content.text).toBe('Welcome');
|
|
168
|
-
expect((layers[1] as TextLayer).content.text).toBe('A small editor for big ideas.');
|
|
169
|
-
});
|
|
170
|
-
});
|