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