@bendyline/squisq 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE.md +24 -0
- package/dist/{ContentContainer-BXUlIf18.d.ts → ContentContainer-B2w9sUoL.d.ts} +15 -0
- package/dist/{Doc-DynJleo-.d.ts → Doc-BubIpWsp.d.ts} +1 -1
- package/dist/{ImageEditDoc-Ca4Tr9uN.d.ts → ImageEditDoc-CGxk5CHc.d.ts} +1 -1
- package/dist/{annotationCoercion-Dr_DY9Hx.d.ts → annotationCoercion-PtRQhk5V.d.ts} +1 -1
- package/dist/chunk-2L55443L.js +0 -0
- 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-JI77MGAK.js → chunk-7ARJZYQY.js} +159 -120
- 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-QUUPYOSP.js → chunk-CB45YGAM.js} +2 -3
- package/dist/{chunk-XNLB57UD.js → chunk-DYPMOPIW.js} +18 -2
- package/dist/{chunk-VR7UPJ7C.js → chunk-FCG3BIZN.js} +12 -1
- package/dist/{chunk-5UYI3RJB.js → chunk-FDYDYL77.js} +54 -40
- package/dist/{chunk-OTKVFVL6.js → chunk-I2O6W7DX.js} +116 -44
- 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-QKPXHDLR.js +0 -0
- package/dist/{chunk-GZY66SDN.js → chunk-R3KTTOMS.js} +0 -1
- package/dist/{chunk-ILWDXLUK.js → chunk-RS5AP3J4.js} +49 -10
- package/dist/chunk-WV5ARNDA.js +0 -0
- package/dist/{chunk-4X3JQXNM.js → chunk-XOFT65EX.js} +1 -2
- package/dist/{chunk-FVTQSNR7.js → chunk-XRW6P7IF.js} +13 -5
- package/dist/chunk-XWNNA3KE.js +0 -0
- package/dist/chunk-YZNGMV3G.js +0 -0
- package/dist/{chunk-R2YZTCLO.js → chunk-ZQKZSJAX.js} +1 -2
- package/dist/doc/index.d.ts +27 -12
- package/dist/doc/index.js +16 -17
- package/dist/generate/index.d.ts +2 -2
- package/dist/generate/index.js +2 -3
- package/dist/icons/index.js +3 -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 +11 -11
- package/dist/index.js +60 -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-wSLA2A1g.d.ts} +2 -2
- package/dist/narration/index.d.ts +16 -3
- package/dist/narration/index.js +13 -14
- package/dist/random/index.d.ts +11 -2
- package/dist/random/index.js +2 -3
- package/dist/recommend/index.d.ts +1 -1
- package/dist/recommend/index.js +3 -4
- package/dist/schemas/index.d.ts +5 -5
- package/dist/schemas/index.js +5 -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-DU9mUmVl.d.ts} +1 -1
- package/dist/timing/index.js +3 -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 +4 -2
- 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
package/src/imageEdit/export.ts
DELETED
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rasterize an {@link ImageEditDoc} to a PNG / JPEG / WebP {@link Blob}.
|
|
3
|
-
*
|
|
4
|
-
* The pipeline:
|
|
5
|
-
* 1. Build an SVG string mirroring the canvas + layers, with image
|
|
6
|
-
* hrefs inlined as `data:` URLs (so the canvas isn't tainted).
|
|
7
|
-
* 2. Wrap the SVG in a `Blob` and load it through an `Image`.
|
|
8
|
-
* 3. Draw it onto a canvas (`OffscreenCanvas` when available,
|
|
9
|
-
* otherwise a detached `HTMLCanvasElement`).
|
|
10
|
-
* 4. Convert the canvas to the requested format.
|
|
11
|
-
*
|
|
12
|
-
* Browser-only — calls `Image`, `URL.createObjectURL`, and canvas APIs.
|
|
13
|
-
* Returns a Promise that rejects on SVG parse / load failures.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import type { ContentContainer } from '../storage/ContentContainer.js';
|
|
17
|
-
import type { ImageEditCanvas, ImageEditDoc, ImageEditLayer } from '../schemas/ImageEditDoc.js';
|
|
18
|
-
import type { MarkerStyle, Position } from '../schemas/Doc.js';
|
|
19
|
-
import { markerPath, shapePath } from '../doc/utils/shapeGeometry.js';
|
|
20
|
-
|
|
21
|
-
/** Supported export formats. */
|
|
22
|
-
export type ImageEditExportFormat = 'png' | 'jpeg' | 'webp';
|
|
23
|
-
|
|
24
|
-
/** Options for {@link exportImageEditDoc}. */
|
|
25
|
-
export interface ImageEditExportOptions {
|
|
26
|
-
/** Output format. Defaults to `'png'`. */
|
|
27
|
-
format?: ImageEditExportFormat;
|
|
28
|
-
/** JPEG/WebP quality 0..1. Defaults to `0.92`. Ignored for PNG. */
|
|
29
|
-
quality?: number;
|
|
30
|
-
/** Resolution scale factor. Defaults to `1` (canvas pixels = output pixels). */
|
|
31
|
-
scale?: number;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const FORMAT_MIME: Record<ImageEditExportFormat, string> = {
|
|
35
|
-
png: 'image/png',
|
|
36
|
-
jpeg: 'image/jpeg',
|
|
37
|
-
webp: 'image/webp',
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Export the doc to a raster {@link Blob}. Asset bytes referenced by image
|
|
42
|
-
* layers are read from `container` and inlined as data URLs.
|
|
43
|
-
*/
|
|
44
|
-
export async function exportImageEditDoc(
|
|
45
|
-
doc: ImageEditDoc,
|
|
46
|
-
container: ContentContainer,
|
|
47
|
-
options: ImageEditExportOptions = {},
|
|
48
|
-
): Promise<Blob> {
|
|
49
|
-
const format: ImageEditExportFormat = options.format ?? 'png';
|
|
50
|
-
const quality = options.quality ?? 0.92;
|
|
51
|
-
const scale = options.scale ?? 1;
|
|
52
|
-
const mime = FORMAT_MIME[format];
|
|
53
|
-
|
|
54
|
-
const svg = await buildSvgString(doc, container);
|
|
55
|
-
const outW = Math.max(1, Math.round(doc.canvas.width * scale));
|
|
56
|
-
const outH = Math.max(1, Math.round(doc.canvas.height * scale));
|
|
57
|
-
|
|
58
|
-
const img = await loadSvgImage(svg);
|
|
59
|
-
const canvas = createRasterCanvas(outW, outH);
|
|
60
|
-
const ctx = canvas.getContext('2d');
|
|
61
|
-
if (!ctx) throw new Error('exportImageEditDoc: 2D canvas context unavailable');
|
|
62
|
-
|
|
63
|
-
// For JPEG (no alpha), pre-fill with the canvas background or white so
|
|
64
|
-
// transparent regions aren't rendered as black.
|
|
65
|
-
if (format === 'jpeg') {
|
|
66
|
-
const bg =
|
|
67
|
-
doc.canvas.background && doc.canvas.background !== 'transparent'
|
|
68
|
-
? doc.canvas.background
|
|
69
|
-
: '#ffffff';
|
|
70
|
-
ctx.fillStyle = bg;
|
|
71
|
-
ctx.fillRect(0, 0, outW, outH);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
ctx.drawImage(img as CanvasImageSource, 0, 0, outW, outH);
|
|
75
|
-
return canvasToBlob(canvas, mime, quality);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// ============================================
|
|
79
|
-
// SVG construction
|
|
80
|
-
// ============================================
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Build the standalone SVG string that mirrors the canvas + layers. Exposed
|
|
84
|
-
* for tests (the raster step needs a browser); shape/text/path layers don't
|
|
85
|
-
* touch `container`, only image layers do (to inline asset bytes).
|
|
86
|
-
*/
|
|
87
|
-
export async function buildSvgString(
|
|
88
|
-
doc: ImageEditDoc,
|
|
89
|
-
container: ContentContainer,
|
|
90
|
-
): Promise<string> {
|
|
91
|
-
const { width, height, background } = doc.canvas;
|
|
92
|
-
const bgRect =
|
|
93
|
-
background && background !== 'transparent'
|
|
94
|
-
? `<rect width="${width}" height="${height}" fill="${escapeAttr(background)}"/>`
|
|
95
|
-
: '';
|
|
96
|
-
|
|
97
|
-
const layerXml: string[] = [];
|
|
98
|
-
for (const layer of doc.layers) {
|
|
99
|
-
if (layer.visible === false) continue;
|
|
100
|
-
layerXml.push(await renderLayerToSvg(layer, doc.canvas, container));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return (
|
|
104
|
-
`<?xml version="1.0" encoding="UTF-8"?>` +
|
|
105
|
-
`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"` +
|
|
106
|
-
` width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">` +
|
|
107
|
-
bgRect +
|
|
108
|
-
layerXml.join('') +
|
|
109
|
-
`</svg>`
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
async function renderLayerToSvg(
|
|
114
|
-
layer: ImageEditLayer,
|
|
115
|
-
canvas: ImageEditCanvas,
|
|
116
|
-
container: ContentContainer,
|
|
117
|
-
): Promise<string> {
|
|
118
|
-
const opacity = layer.opacity ?? 1;
|
|
119
|
-
const opacityAttr = opacity < 1 ? ` opacity="${opacity}"` : '';
|
|
120
|
-
const inner = await renderLayerInner(layer, canvas, container);
|
|
121
|
-
return `<g data-layer-id="${escapeAttr(layer.id)}"${opacityAttr}>${inner}</g>`;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async function renderLayerInner(
|
|
125
|
-
layer: ImageEditLayer,
|
|
126
|
-
canvas: ImageEditCanvas,
|
|
127
|
-
container: ContentContainer,
|
|
128
|
-
): Promise<string> {
|
|
129
|
-
const { x, y, w, h } = resolveBox(layer.position, canvas);
|
|
130
|
-
|
|
131
|
-
if (layer.type === 'image') {
|
|
132
|
-
const dataUrl = await loadAssetAsDataUrl(container, layer.content.src);
|
|
133
|
-
return (
|
|
134
|
-
`<image x="${x}" y="${y}" width="${w}" height="${h}"` +
|
|
135
|
-
` preserveAspectRatio="${preserveAspectRatioFor(layer.content.fit)}"` +
|
|
136
|
-
` xlink:href="${escapeAttr(dataUrl)}"/>`
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (layer.type === 'shape') {
|
|
141
|
-
const c = layer.content;
|
|
142
|
-
const fill = c.fill ?? 'none';
|
|
143
|
-
const stroke = c.stroke ? ` stroke="${escapeAttr(c.stroke)}"` : '';
|
|
144
|
-
const strokeWidth = c.strokeWidth ? ` stroke-width="${c.strokeWidth}"` : '';
|
|
145
|
-
if (c.shape === 'rect') {
|
|
146
|
-
const rx = c.borderRadius ? ` rx="${c.borderRadius}" ry="${c.borderRadius}"` : '';
|
|
147
|
-
return `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="${escapeAttr(fill)}"${stroke}${strokeWidth}${rx}/>`;
|
|
148
|
-
}
|
|
149
|
-
if (c.shape === 'circle') {
|
|
150
|
-
const r = Math.min(w, h) / 2;
|
|
151
|
-
return `<circle cx="${x + w / 2}" cy="${y + h / 2}" r="${r}" fill="${escapeAttr(fill)}"${stroke}${strokeWidth}/>`;
|
|
152
|
-
}
|
|
153
|
-
// line
|
|
154
|
-
return `<line x1="${x}" y1="${y}" x2="${x + w}" y2="${y + h}"${stroke}${strokeWidth}/>`;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (layer.type === 'path') {
|
|
158
|
-
return renderPathToSvg(layer, x, y, w, h);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// text
|
|
162
|
-
const c = layer.content;
|
|
163
|
-
const style = c.style;
|
|
164
|
-
const lineHeight = style.lineHeight ?? 1.4;
|
|
165
|
-
const lineHeightPx = style.fontSize * lineHeight;
|
|
166
|
-
const lines = (c.text ?? '').split('\n');
|
|
167
|
-
const tspans = lines
|
|
168
|
-
.map(
|
|
169
|
-
(line, i) => `<tspan x="${x}" dy="${i === 0 ? 0 : lineHeightPx}">${escapeText(line)}</tspan>`,
|
|
170
|
-
)
|
|
171
|
-
.join('');
|
|
172
|
-
const fontFamily = style.fontFamily ?? 'sans-serif';
|
|
173
|
-
const fontWeight = style.fontWeight ?? 'normal';
|
|
174
|
-
const textAnchor =
|
|
175
|
-
style.textAlign === 'center' ? 'middle' : style.textAlign === 'right' ? 'end' : 'start';
|
|
176
|
-
return (
|
|
177
|
-
`<text x="${x}" y="${y + style.fontSize}" font-family="${escapeAttr(fontFamily)}"` +
|
|
178
|
-
` font-size="${style.fontSize}" font-weight="${fontWeight}"` +
|
|
179
|
-
` fill="${escapeAttr(style.color)}" text-anchor="${textAnchor}">` +
|
|
180
|
-
tspans +
|
|
181
|
-
`</text>`
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Serialize a `path` layer to SVG. Mirrors the runtime
|
|
187
|
-
* `react/src/layers/PathLayer.tsx`: when `shapeKind` is set, `d` is
|
|
188
|
-
* re-derived from the position box via `shapePath` (so named shapes scale);
|
|
189
|
-
* otherwise the stored absolute `d` is used. Start/end markers are emitted
|
|
190
|
-
* as `<marker>` defs scoped to the layer id, matching `markerPath` geometry.
|
|
191
|
-
*/
|
|
192
|
-
function renderPathToSvg(
|
|
193
|
-
layer: ImageEditLayer & { type: 'path' },
|
|
194
|
-
x: number,
|
|
195
|
-
y: number,
|
|
196
|
-
w: number,
|
|
197
|
-
h: number,
|
|
198
|
-
): string {
|
|
199
|
-
const c = layer.content;
|
|
200
|
-
const d = c.shapeKind ? (shapePath(c.shapeKind, x, y, w, h) ?? c.d) : c.d;
|
|
201
|
-
const stroke = c.stroke ?? '#1e293b';
|
|
202
|
-
const strokeWidth = c.strokeWidth ?? 2;
|
|
203
|
-
const fill = c.fill ?? 'none';
|
|
204
|
-
const dash = c.dasharray ? ` stroke-dasharray="${escapeAttr(c.dasharray)}"` : '';
|
|
205
|
-
|
|
206
|
-
// Keep old serialized documents readable without retaining `arrow` in the public type.
|
|
207
|
-
const legacyArrow = (c as typeof c & { arrow?: 'none' | 'end' | 'start' | 'both' }).arrow;
|
|
208
|
-
const startStyle = effectiveExportMarker(c.startMarker, legacyArrow, 'start');
|
|
209
|
-
const endStyle = effectiveExportMarker(c.endMarker, legacyArrow, 'end');
|
|
210
|
-
const start = markerPath(startStyle, 'start');
|
|
211
|
-
const end = markerPath(endStyle, 'end');
|
|
212
|
-
const startId = `marker-start-${layer.id}`;
|
|
213
|
-
const endId = `marker-end-${layer.id}`;
|
|
214
|
-
const defs =
|
|
215
|
-
start || end
|
|
216
|
-
? `<defs>${start ? markerDefSvg(startId, 'start', start, stroke) : ''}${
|
|
217
|
-
end ? markerDefSvg(endId, 'end', end, stroke) : ''
|
|
218
|
-
}</defs>`
|
|
219
|
-
: '';
|
|
220
|
-
const markerStart = start ? ` marker-start="url(#${startId})"` : '';
|
|
221
|
-
const markerEnd = end ? ` marker-end="url(#${endId})"` : '';
|
|
222
|
-
|
|
223
|
-
return (
|
|
224
|
-
defs +
|
|
225
|
-
`<path d="${escapeAttr(d)}" fill="${escapeAttr(fill)}"` +
|
|
226
|
-
` stroke="${escapeAttr(stroke)}" stroke-width="${strokeWidth}"${dash}${markerStart}${markerEnd}/>`
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function effectiveExportMarker(
|
|
231
|
-
explicit: MarkerStyle | undefined,
|
|
232
|
-
legacyArrow: 'none' | 'end' | 'start' | 'both' | undefined,
|
|
233
|
-
end: 'start' | 'end',
|
|
234
|
-
): MarkerStyle {
|
|
235
|
-
if (explicit) return explicit;
|
|
236
|
-
return legacyArrow === 'both' || legacyArrow === end ? 'arrow' : 'none';
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function markerDefSvg(
|
|
240
|
-
id: string,
|
|
241
|
-
dir: 'start' | 'end',
|
|
242
|
-
marker: { d: string; filled: boolean },
|
|
243
|
-
stroke: string,
|
|
244
|
-
): string {
|
|
245
|
-
const refX = dir === 'end' ? 9 : 1;
|
|
246
|
-
const paint = marker.filled
|
|
247
|
-
? `fill="${escapeAttr(stroke)}"`
|
|
248
|
-
: `fill="none" stroke="${escapeAttr(stroke)}" stroke-width="1.5"`;
|
|
249
|
-
return (
|
|
250
|
-
`<marker id="${escapeAttr(id)}" viewBox="0 0 10 10" refX="${refX}" refY="5"` +
|
|
251
|
-
` markerWidth="4" markerHeight="4" orient="auto-start-reverse" markerUnits="strokeWidth">` +
|
|
252
|
-
`<path d="${escapeAttr(marker.d)}" ${paint}/></marker>`
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function preserveAspectRatioFor(fit?: 'cover' | 'contain' | 'fill'): string {
|
|
257
|
-
if (fit === 'cover') return 'xMidYMid slice';
|
|
258
|
-
if (fit === 'fill') return 'none';
|
|
259
|
-
return 'xMidYMid meet'; // contain (default)
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
function resolveBox(
|
|
263
|
-
position: Position,
|
|
264
|
-
canvas: ImageEditCanvas,
|
|
265
|
-
): { x: number; y: number; w: number; h: number } {
|
|
266
|
-
const x = resolveValue(position.x, canvas.width);
|
|
267
|
-
const y = resolveValue(position.y, canvas.height);
|
|
268
|
-
const w =
|
|
269
|
-
position.width !== undefined ? resolveValue(position.width, canvas.width) : canvas.width;
|
|
270
|
-
const h =
|
|
271
|
-
position.height !== undefined ? resolveValue(position.height, canvas.height) : canvas.height;
|
|
272
|
-
const offset = anchorOffset(position.anchor, w, h);
|
|
273
|
-
return { x: x + offset.x, y: y + offset.y, w, h };
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function resolveValue(v: number | string, base: number): number {
|
|
277
|
-
if (typeof v === 'number') return v;
|
|
278
|
-
if (v.endsWith('%')) return (parseFloat(v) / 100) * base;
|
|
279
|
-
return parseFloat(v) || 0;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function anchorOffset(
|
|
283
|
-
anchor: Position['anchor'] | undefined,
|
|
284
|
-
w: number,
|
|
285
|
-
h: number,
|
|
286
|
-
): { x: number; y: number } {
|
|
287
|
-
switch (anchor) {
|
|
288
|
-
case 'center':
|
|
289
|
-
return { x: -w / 2, y: -h / 2 };
|
|
290
|
-
case 'top-right':
|
|
291
|
-
return { x: -w, y: 0 };
|
|
292
|
-
case 'bottom-left':
|
|
293
|
-
return { x: 0, y: -h };
|
|
294
|
-
case 'bottom-right':
|
|
295
|
-
return { x: -w, y: -h };
|
|
296
|
-
case 'top-left':
|
|
297
|
-
default:
|
|
298
|
-
return { x: 0, y: 0 };
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// ============================================
|
|
303
|
-
// Asset inlining
|
|
304
|
-
// ============================================
|
|
305
|
-
|
|
306
|
-
async function loadAssetAsDataUrl(container: ContentContainer, src: string): Promise<string> {
|
|
307
|
-
// Already a data: or absolute URL — pass through.
|
|
308
|
-
if (/^(data:|https?:|blob:)/.test(src)) return src;
|
|
309
|
-
const data = await container.readFile(src);
|
|
310
|
-
if (!data) throw new Error(`exportImageEditDoc: missing asset "${src}"`);
|
|
311
|
-
const list = await container.listFiles(src);
|
|
312
|
-
const mime = list.find((e) => e.path === src)?.mimeType ?? guessMime(src);
|
|
313
|
-
return arrayBufferToDataUrl(data, mime);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function arrayBufferToDataUrl(data: ArrayBuffer, mime: string): string {
|
|
317
|
-
const bytes = new Uint8Array(data);
|
|
318
|
-
let binary = '';
|
|
319
|
-
// chunk to avoid call-stack limits with large images
|
|
320
|
-
const CHUNK = 0x8000;
|
|
321
|
-
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
322
|
-
binary += String.fromCharCode.apply(null, Array.from(bytes.subarray(i, i + CHUNK)));
|
|
323
|
-
}
|
|
324
|
-
// btoa exists in browsers and modern Node (>= 16); fall back to Buffer for older runtimes.
|
|
325
|
-
const b64 = typeof btoa === 'function' ? btoa(binary) : Buffer.from(bytes).toString('base64');
|
|
326
|
-
return `data:${mime};base64,${b64}`;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
function guessMime(path: string): string {
|
|
330
|
-
const dot = path.lastIndexOf('.');
|
|
331
|
-
const ext = dot >= 0 ? path.slice(dot).toLowerCase() : '';
|
|
332
|
-
switch (ext) {
|
|
333
|
-
case '.png':
|
|
334
|
-
return 'image/png';
|
|
335
|
-
case '.jpg':
|
|
336
|
-
case '.jpeg':
|
|
337
|
-
return 'image/jpeg';
|
|
338
|
-
case '.webp':
|
|
339
|
-
return 'image/webp';
|
|
340
|
-
case '.gif':
|
|
341
|
-
return 'image/gif';
|
|
342
|
-
case '.svg':
|
|
343
|
-
return 'image/svg+xml';
|
|
344
|
-
default:
|
|
345
|
-
return 'application/octet-stream';
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// ============================================
|
|
350
|
-
// SVG → Image → Canvas → Blob
|
|
351
|
-
// ============================================
|
|
352
|
-
|
|
353
|
-
async function loadSvgImage(svg: string): Promise<HTMLImageElement> {
|
|
354
|
-
const blob = new Blob([svg], { type: 'image/svg+xml;charset=utf-8' });
|
|
355
|
-
const url = URL.createObjectURL(blob);
|
|
356
|
-
try {
|
|
357
|
-
return await new Promise<HTMLImageElement>((resolve, reject) => {
|
|
358
|
-
const img = new Image();
|
|
359
|
-
img.onload = () => resolve(img);
|
|
360
|
-
img.onerror = () => reject(new Error('exportImageEditDoc: SVG image failed to load'));
|
|
361
|
-
img.src = url;
|
|
362
|
-
});
|
|
363
|
-
} finally {
|
|
364
|
-
URL.revokeObjectURL(url);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
type RasterCanvas = HTMLCanvasElement | OffscreenCanvas;
|
|
369
|
-
|
|
370
|
-
function createRasterCanvas(width: number, height: number): RasterCanvas {
|
|
371
|
-
if (typeof OffscreenCanvas !== 'undefined') {
|
|
372
|
-
return new OffscreenCanvas(width, height);
|
|
373
|
-
}
|
|
374
|
-
const c = document.createElement('canvas');
|
|
375
|
-
c.width = width;
|
|
376
|
-
c.height = height;
|
|
377
|
-
return c;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
async function canvasToBlob(canvas: RasterCanvas, mime: string, quality: number): Promise<Blob> {
|
|
381
|
-
if ('convertToBlob' in canvas) {
|
|
382
|
-
return canvas.convertToBlob({ type: mime, quality });
|
|
383
|
-
}
|
|
384
|
-
return new Promise<Blob>((resolve, reject) => {
|
|
385
|
-
canvas.toBlob(
|
|
386
|
-
(blob) => {
|
|
387
|
-
if (blob) resolve(blob);
|
|
388
|
-
else reject(new Error('exportImageEditDoc: canvas.toBlob returned null'));
|
|
389
|
-
},
|
|
390
|
-
mime,
|
|
391
|
-
quality,
|
|
392
|
-
);
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// ============================================
|
|
397
|
-
// XML escaping
|
|
398
|
-
// ============================================
|
|
399
|
-
|
|
400
|
-
function escapeAttr(s: string): string {
|
|
401
|
-
return s
|
|
402
|
-
.replace(/&/g, '&')
|
|
403
|
-
.replace(/"/g, '"')
|
|
404
|
-
.replace(/</g, '<')
|
|
405
|
-
.replace(/>/g, '>');
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
function escapeText(s: string): string {
|
|
409
|
-
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
410
|
-
}
|
package/src/imageEdit/index.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Image-editor primitives: schema re-exports, state helpers, persistence,
|
|
3
|
-
* version history, and SVG → raster export.
|
|
4
|
-
*
|
|
5
|
-
* See `@bendyline/squisq/imageEdit` for the public subpath entry.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// Schema (re-exported from schemas for ergonomic single-import)
|
|
9
|
-
export type {
|
|
10
|
-
ImageEditDoc,
|
|
11
|
-
ImageEditLayer,
|
|
12
|
-
ImageEditLayerKind,
|
|
13
|
-
ImageEditCanvas,
|
|
14
|
-
ImageEditMeta,
|
|
15
|
-
EditorLayerMeta,
|
|
16
|
-
} from '../schemas/ImageEditDoc.js';
|
|
17
|
-
|
|
18
|
-
// State helpers
|
|
19
|
-
export {
|
|
20
|
-
IMAGE_EDIT_STATE_FILENAME,
|
|
21
|
-
IMAGE_EDIT_ASSETS_PREFIX,
|
|
22
|
-
createEmptyImageEditDoc,
|
|
23
|
-
addLayer,
|
|
24
|
-
removeLayer,
|
|
25
|
-
reorderLayer,
|
|
26
|
-
updateLayer,
|
|
27
|
-
setCanvas,
|
|
28
|
-
touch,
|
|
29
|
-
} from './state.js';
|
|
30
|
-
|
|
31
|
-
// Persistence
|
|
32
|
-
export { readImageEditDoc, writeImageEditDoc } from './persistence.js';
|
|
33
|
-
|
|
34
|
-
// Version paths
|
|
35
|
-
export {
|
|
36
|
-
IMAGE_EDIT_VERSIONS_PREFIX,
|
|
37
|
-
IMAGE_EDIT_DEFAULT_BASENAME,
|
|
38
|
-
buildImageEditVersionPath,
|
|
39
|
-
parseImageEditVersionPath,
|
|
40
|
-
} from './versionPaths.js';
|
|
41
|
-
|
|
42
|
-
// Version operations
|
|
43
|
-
export {
|
|
44
|
-
saveImageEditVersion,
|
|
45
|
-
listImageEditVersions,
|
|
46
|
-
readImageEditVersion,
|
|
47
|
-
readImageEditVersionText,
|
|
48
|
-
revertToImageEditVersion,
|
|
49
|
-
pruneImageEditVersions,
|
|
50
|
-
coalesceImageEditVersions,
|
|
51
|
-
type SaveImageEditVersionOptions,
|
|
52
|
-
type SaveImageEditVersionResult,
|
|
53
|
-
type RevertImageEditOptions,
|
|
54
|
-
} from './versions.js';
|
|
55
|
-
|
|
56
|
-
// Manager
|
|
57
|
-
export {
|
|
58
|
-
ImageEditVersionManager,
|
|
59
|
-
type ImageEditVersionManagerOptions,
|
|
60
|
-
} from './ImageEditVersionManager.js';
|
|
61
|
-
|
|
62
|
-
// Note: shared version types (`Version`, `PrunePolicy`, `CoalesceOptions`)
|
|
63
|
-
// are re-exported from `@bendyline/squisq/versions` and the package root.
|
|
64
|
-
// Import them from there to avoid duplicating the export surface.
|
|
65
|
-
|
|
66
|
-
// Export
|
|
67
|
-
export {
|
|
68
|
-
exportImageEditDoc,
|
|
69
|
-
buildSvgString,
|
|
70
|
-
type ImageEditExportFormat,
|
|
71
|
-
type ImageEditExportOptions,
|
|
72
|
-
} from './export.js';
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Load and save {@link ImageEditDoc} JSON to a sidecar
|
|
3
|
-
* {@link ContentContainer} (typically a {@link ScopedContentContainer}
|
|
4
|
-
* rooted at `<basename>_files/`).
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { ContentContainer } from '../storage/ContentContainer.js';
|
|
8
|
-
import type { ImageEditDoc } from '../schemas/ImageEditDoc.js';
|
|
9
|
-
import { IMAGE_EDIT_STATE_FILENAME } from './state.js';
|
|
10
|
-
|
|
11
|
-
const decoder = new TextDecoder();
|
|
12
|
-
const encoder = new TextEncoder();
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Read `state.json` from the sidecar and parse it. Returns `null` when
|
|
16
|
-
* the file does not exist; throws on parse / shape errors.
|
|
17
|
-
*/
|
|
18
|
-
export async function readImageEditDoc(
|
|
19
|
-
container: ContentContainer,
|
|
20
|
-
filename: string = IMAGE_EDIT_STATE_FILENAME,
|
|
21
|
-
): Promise<ImageEditDoc | null> {
|
|
22
|
-
const data = await container.readFile(filename);
|
|
23
|
-
if (!data) return null;
|
|
24
|
-
const text = decoder.decode(data);
|
|
25
|
-
let parsed: unknown;
|
|
26
|
-
try {
|
|
27
|
-
parsed = JSON.parse(text);
|
|
28
|
-
} catch (err: unknown) {
|
|
29
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
30
|
-
throw new Error(`readImageEditDoc: ${filename} is not valid JSON: ${msg}`);
|
|
31
|
-
}
|
|
32
|
-
assertImageEditDoc(parsed, filename);
|
|
33
|
-
return parsed;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Serialize `doc` to JSON and write it to the sidecar. */
|
|
37
|
-
export async function writeImageEditDoc(
|
|
38
|
-
container: ContentContainer,
|
|
39
|
-
doc: ImageEditDoc,
|
|
40
|
-
filename: string = IMAGE_EDIT_STATE_FILENAME,
|
|
41
|
-
): Promise<void> {
|
|
42
|
-
const text = JSON.stringify(doc, null, 2);
|
|
43
|
-
await container.writeFile(filename, encoder.encode(text), 'application/json');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function assertImageEditDoc(value: unknown, filename: string): asserts value is ImageEditDoc {
|
|
47
|
-
if (!value || typeof value !== 'object') {
|
|
48
|
-
throw new Error(`readImageEditDoc: ${filename} root must be an object`);
|
|
49
|
-
}
|
|
50
|
-
const v = value as Partial<ImageEditDoc>;
|
|
51
|
-
if (v.version !== 1) {
|
|
52
|
-
throw new Error(
|
|
53
|
-
`readImageEditDoc: ${filename} has unsupported schema version ${String(v.version)} (expected 1)`,
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
if (!v.canvas || typeof v.canvas.width !== 'number' || typeof v.canvas.height !== 'number') {
|
|
57
|
-
throw new Error(`readImageEditDoc: ${filename} canvas.width/height must be numbers`);
|
|
58
|
-
}
|
|
59
|
-
if (!Array.isArray(v.layers)) {
|
|
60
|
-
throw new Error(`readImageEditDoc: ${filename} layers must be an array`);
|
|
61
|
-
}
|
|
62
|
-
v.layers.forEach((layer, i) => assertLayer(layer, i, filename));
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const VALID_LAYER_TYPES = new Set(['image', 'text', 'shape', 'path']);
|
|
66
|
-
|
|
67
|
-
function assertLayer(value: unknown, index: number, filename: string): void {
|
|
68
|
-
const ctx = `${filename} layers[${index}]`;
|
|
69
|
-
if (!value || typeof value !== 'object') {
|
|
70
|
-
throw new Error(`readImageEditDoc: ${ctx} must be an object`);
|
|
71
|
-
}
|
|
72
|
-
const layer = value as Record<string, unknown>;
|
|
73
|
-
|
|
74
|
-
if (typeof layer['id'] !== 'string') {
|
|
75
|
-
throw new Error(`readImageEditDoc: ${ctx} must have a string id`);
|
|
76
|
-
}
|
|
77
|
-
if (typeof layer['type'] !== 'string' || !VALID_LAYER_TYPES.has(layer['type'])) {
|
|
78
|
-
throw new Error(
|
|
79
|
-
`readImageEditDoc: ${ctx} type must be one of image|text|shape, got ${String(layer['type'])}`,
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const pos = layer['position'];
|
|
84
|
-
if (
|
|
85
|
-
!pos ||
|
|
86
|
-
typeof pos !== 'object' ||
|
|
87
|
-
(typeof (pos as Record<string, unknown>)['x'] !== 'number' &&
|
|
88
|
-
typeof (pos as Record<string, unknown>)['x'] !== 'string') ||
|
|
89
|
-
(typeof (pos as Record<string, unknown>)['y'] !== 'number' &&
|
|
90
|
-
typeof (pos as Record<string, unknown>)['y'] !== 'string')
|
|
91
|
-
) {
|
|
92
|
-
throw new Error(`readImageEditDoc: ${ctx} position must have numeric or string x and y`);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const content = layer['content'];
|
|
96
|
-
if (!content || typeof content !== 'object') {
|
|
97
|
-
throw new Error(`readImageEditDoc: ${ctx} content must be an object`);
|
|
98
|
-
}
|
|
99
|
-
const c = content as Record<string, unknown>;
|
|
100
|
-
|
|
101
|
-
if (layer['type'] === 'image' && typeof c['src'] !== 'string') {
|
|
102
|
-
throw new Error(`readImageEditDoc: ${ctx} (image) content.src must be a string`);
|
|
103
|
-
}
|
|
104
|
-
if (layer['type'] === 'text' && typeof c['text'] !== 'string') {
|
|
105
|
-
throw new Error(`readImageEditDoc: ${ctx} (text) content.text must be a string`);
|
|
106
|
-
}
|
|
107
|
-
if (layer['type'] === 'shape' && typeof c['shape'] !== 'string') {
|
|
108
|
-
throw new Error(`readImageEditDoc: ${ctx} (shape) content.shape must be a string`);
|
|
109
|
-
}
|
|
110
|
-
if (layer['type'] === 'path' && typeof c['d'] !== 'string') {
|
|
111
|
-
throw new Error(`readImageEditDoc: ${ctx} (path) content.d must be a string`);
|
|
112
|
-
}
|
|
113
|
-
}
|