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