@bendyline/squisq 1.2.2 → 1.4.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 (427) hide show
  1. package/dist/{Doc-BfBhiCNr.d.ts → Doc-BeSeH2iX.d.ts} +141 -33
  2. package/dist/ImageEditDoc-BTIvw0oq.d.ts +84 -0
  3. package/dist/__tests__/colorUtils.test.d.ts +2 -0
  4. package/dist/__tests__/colorUtils.test.d.ts.map +1 -0
  5. package/dist/__tests__/colorUtils.test.js +94 -0
  6. package/dist/__tests__/colorUtils.test.js.map +1 -0
  7. package/dist/__tests__/getLayers.test.js +31 -7
  8. package/dist/__tests__/getLayers.test.js.map +1 -1
  9. package/dist/__tests__/iconResolve.test.d.ts +2 -0
  10. package/dist/__tests__/iconResolve.test.d.ts.map +1 -0
  11. package/dist/__tests__/iconResolve.test.js +99 -0
  12. package/dist/__tests__/iconResolve.test.js.map +1 -0
  13. package/dist/__tests__/imageEditState.test.d.ts +2 -0
  14. package/dist/__tests__/imageEditState.test.d.ts.map +1 -0
  15. package/dist/__tests__/imageEditState.test.js +61 -0
  16. package/dist/__tests__/imageEditState.test.js.map +1 -0
  17. package/dist/__tests__/imageEditVersions.test.d.ts +2 -0
  18. package/dist/__tests__/imageEditVersions.test.d.ts.map +1 -0
  19. package/dist/__tests__/imageEditVersions.test.js +141 -0
  20. package/dist/__tests__/imageEditVersions.test.js.map +1 -0
  21. package/dist/__tests__/inferDocumentTitle.test.d.ts +2 -0
  22. package/dist/__tests__/inferDocumentTitle.test.d.ts.map +1 -0
  23. package/dist/__tests__/inferDocumentTitle.test.js +42 -0
  24. package/dist/__tests__/inferDocumentTitle.test.js.map +1 -0
  25. package/dist/__tests__/jsonForm.chooseControl.test.d.ts +2 -0
  26. package/dist/__tests__/jsonForm.chooseControl.test.d.ts.map +1 -0
  27. package/dist/__tests__/jsonForm.chooseControl.test.js +74 -0
  28. package/dist/__tests__/jsonForm.chooseControl.test.js.map +1 -0
  29. package/dist/__tests__/jsonForm.evaluateWhen.test.d.ts +2 -0
  30. package/dist/__tests__/jsonForm.evaluateWhen.test.d.ts.map +1 -0
  31. package/dist/__tests__/jsonForm.evaluateWhen.test.js +51 -0
  32. package/dist/__tests__/jsonForm.evaluateWhen.test.js.map +1 -0
  33. package/dist/__tests__/jsonForm.inferSchema.test.d.ts +2 -0
  34. package/dist/__tests__/jsonForm.inferSchema.test.d.ts.map +1 -0
  35. package/dist/__tests__/jsonForm.inferSchema.test.js +23 -0
  36. package/dist/__tests__/jsonForm.inferSchema.test.js.map +1 -0
  37. package/dist/__tests__/jsonForm.pointer.test.d.ts +2 -0
  38. package/dist/__tests__/jsonForm.pointer.test.d.ts.map +1 -0
  39. package/dist/__tests__/jsonForm.pointer.test.js +94 -0
  40. package/dist/__tests__/jsonForm.pointer.test.js.map +1 -0
  41. package/dist/__tests__/markdown.test.js +40 -0
  42. package/dist/__tests__/markdown.test.js.map +1 -1
  43. package/dist/__tests__/markdownIcons.test.d.ts +2 -0
  44. package/dist/__tests__/markdownIcons.test.d.ts.map +1 -0
  45. package/dist/__tests__/markdownIcons.test.js +93 -0
  46. package/dist/__tests__/markdownIcons.test.js.map +1 -0
  47. package/dist/__tests__/markdownToDoc.test.js +15 -4
  48. package/dist/__tests__/markdownToDoc.test.js.map +1 -1
  49. package/dist/__tests__/recommendTemplates.test.d.ts +2 -0
  50. package/dist/__tests__/recommendTemplates.test.d.ts.map +1 -0
  51. package/dist/__tests__/recommendTemplates.test.js +158 -0
  52. package/dist/__tests__/recommendTemplates.test.js.map +1 -0
  53. package/dist/__tests__/scopedContentContainer.test.d.ts +2 -0
  54. package/dist/__tests__/scopedContentContainer.test.d.ts.map +1 -0
  55. package/dist/__tests__/scopedContentContainer.test.js +74 -0
  56. package/dist/__tests__/scopedContentContainer.test.js.map +1 -0
  57. package/dist/__tests__/slideshowGenerator.test.js +1 -1
  58. package/dist/__tests__/slideshowGenerator.test.js.map +1 -1
  59. package/dist/__tests__/surface.test.d.ts +2 -0
  60. package/dist/__tests__/surface.test.d.ts.map +1 -0
  61. package/dist/__tests__/surface.test.js +57 -0
  62. package/dist/__tests__/surface.test.js.map +1 -0
  63. package/dist/__tests__/templateAnnotationParse.test.d.ts +2 -0
  64. package/dist/__tests__/templateAnnotationParse.test.d.ts.map +1 -0
  65. package/dist/__tests__/templateAnnotationParse.test.js +42 -0
  66. package/dist/__tests__/templateAnnotationParse.test.js.map +1 -0
  67. package/dist/__tests__/templates.test.js +90 -9
  68. package/dist/__tests__/templates.test.js.map +1 -1
  69. package/dist/__tests__/themeCompile.test.d.ts +2 -0
  70. package/dist/__tests__/themeCompile.test.d.ts.map +1 -0
  71. package/dist/__tests__/themeCompile.test.js +134 -0
  72. package/dist/__tests__/themeCompile.test.js.map +1 -0
  73. package/dist/__tests__/themeValidator.test.d.ts +2 -0
  74. package/dist/__tests__/themeValidator.test.d.ts.map +1 -0
  75. package/dist/__tests__/themeValidator.test.js +107 -0
  76. package/dist/__tests__/themeValidator.test.js.map +1 -0
  77. package/dist/__tests__/versions.test.d.ts +2 -0
  78. package/dist/__tests__/versions.test.d.ts.map +1 -0
  79. package/dist/__tests__/versions.test.js +339 -0
  80. package/dist/__tests__/versions.test.js.map +1 -0
  81. package/dist/{chunk-CYQHG27J.js → chunk-2TMAWB4Y.js} +74 -1
  82. package/dist/chunk-2TMAWB4Y.js.map +1 -0
  83. package/dist/{chunk-LAZELBON.js → chunk-3K5OG6KI.js} +165 -17
  84. package/dist/chunk-3K5OG6KI.js.map +1 -0
  85. package/dist/chunk-57CVQCFX.js +193 -0
  86. package/dist/chunk-57CVQCFX.js.map +1 -0
  87. package/dist/{chunk-QM5PKNPW.js → chunk-5WFRKURX.js} +1 -1
  88. package/dist/chunk-5WFRKURX.js.map +1 -0
  89. package/dist/chunk-B4EEON3N.js +1317 -0
  90. package/dist/chunk-B4EEON3N.js.map +1 -0
  91. package/dist/chunk-DBS6RIFL.js +81 -0
  92. package/dist/chunk-DBS6RIFL.js.map +1 -0
  93. package/dist/{chunk-MIBRIRGJ.js → chunk-FR2RBTKO.js} +3 -3
  94. package/dist/{chunk-MIBRIRGJ.js.map → chunk-FR2RBTKO.js.map} +1 -1
  95. package/dist/chunk-H3AXU4MJ.js +179 -0
  96. package/dist/chunk-H3AXU4MJ.js.map +1 -0
  97. package/dist/chunk-JELIRVDP.js +24 -0
  98. package/dist/chunk-JELIRVDP.js.map +1 -0
  99. package/dist/chunk-K32VJONL.js +193 -0
  100. package/dist/chunk-K32VJONL.js.map +1 -0
  101. package/dist/{chunk-GAQLMORN.js → chunk-KSWJR66U.js} +248 -44
  102. package/dist/chunk-KSWJR66U.js.map +1 -0
  103. package/dist/{chunk-TSG2OSE6.js → chunk-MYIH7FWD.js} +3 -3
  104. package/dist/chunk-MYIH7FWD.js.map +1 -0
  105. package/dist/chunk-VLJJHDAC.js +218 -0
  106. package/dist/chunk-VLJJHDAC.js.map +1 -0
  107. package/dist/chunk-WMOI7FN3.js +182 -0
  108. package/dist/chunk-WMOI7FN3.js.map +1 -0
  109. package/dist/chunk-ZTX4PFFT.js +520 -0
  110. package/dist/chunk-ZTX4PFFT.js.map +1 -0
  111. package/dist/doc/audioMapping.d.ts.map +1 -1
  112. package/dist/doc/audioMapping.js +80 -9
  113. package/dist/doc/audioMapping.js.map +1 -1
  114. package/dist/doc/getLayers.d.ts.map +1 -1
  115. package/dist/doc/getLayers.js +29 -18
  116. package/dist/doc/getLayers.js.map +1 -1
  117. package/dist/doc/markdownToDoc.d.ts.map +1 -1
  118. package/dist/doc/markdownToDoc.js +40 -6
  119. package/dist/doc/markdownToDoc.js.map +1 -1
  120. package/dist/doc/templates/featureBlock.d.ts +18 -0
  121. package/dist/doc/templates/featureBlock.d.ts.map +1 -0
  122. package/dist/doc/templates/featureBlock.js +180 -0
  123. package/dist/doc/templates/featureBlock.js.map +1 -0
  124. package/dist/doc/templates/fullBleedQuote.d.ts +12 -0
  125. package/dist/doc/templates/fullBleedQuote.d.ts.map +1 -1
  126. package/dist/doc/templates/fullBleedQuote.js +12 -0
  127. package/dist/doc/templates/fullBleedQuote.js.map +1 -1
  128. package/dist/doc/templates/index.d.ts +28 -4
  129. package/dist/doc/templates/index.d.ts.map +1 -1
  130. package/dist/doc/templates/index.js +45 -12
  131. package/dist/doc/templates/index.js.map +1 -1
  132. package/dist/doc/templates/listBlock.d.ts.map +1 -1
  133. package/dist/doc/templates/listBlock.js +22 -5
  134. package/dist/doc/templates/listBlock.js.map +1 -1
  135. package/dist/doc/templates/statHighlight.d.ts +12 -0
  136. package/dist/doc/templates/statHighlight.d.ts.map +1 -1
  137. package/dist/doc/templates/statHighlight.js +12 -0
  138. package/dist/doc/templates/statHighlight.js.map +1 -1
  139. package/dist/doc/templates/titleBlock.d.ts +11 -0
  140. package/dist/doc/templates/titleBlock.d.ts.map +1 -1
  141. package/dist/doc/templates/titleBlock.js +8 -0
  142. package/dist/doc/templates/titleBlock.js.map +1 -1
  143. package/dist/doc/utils/themeUtils.d.ts +4 -4
  144. package/dist/doc/utils/themeUtils.d.ts.map +1 -1
  145. package/dist/doc/utils/themeUtils.js +8 -7
  146. package/dist/doc/utils/themeUtils.js.map +1 -1
  147. package/dist/generate/slideshowGenerator.js +1 -1
  148. package/dist/generate/slideshowGenerator.js.map +1 -1
  149. package/dist/generate/templateMapper.js +2 -2
  150. package/dist/generate/templateMapper.js.map +1 -1
  151. package/dist/icons/iconData.d.ts +26 -0
  152. package/dist/icons/iconData.d.ts.map +1 -0
  153. package/dist/icons/iconData.js +12 -0
  154. package/dist/icons/iconData.js.map +1 -0
  155. package/dist/icons/index.d.ts +12 -0
  156. package/dist/icons/index.d.ts.map +1 -0
  157. package/dist/icons/index.js +10 -0
  158. package/dist/icons/index.js.map +1 -0
  159. package/dist/icons/resolve.d.ts +61 -0
  160. package/dist/icons/resolve.d.ts.map +1 -0
  161. package/dist/icons/resolve.js +130 -0
  162. package/dist/icons/resolve.js.map +1 -0
  163. package/dist/imageEdit/ImageEditVersionManager.d.ts +31 -0
  164. package/dist/imageEdit/ImageEditVersionManager.d.ts.map +1 -0
  165. package/dist/imageEdit/ImageEditVersionManager.js +39 -0
  166. package/dist/imageEdit/ImageEditVersionManager.js.map +1 -0
  167. package/dist/imageEdit/export.d.ts +33 -0
  168. package/dist/imageEdit/export.d.ts.map +1 -0
  169. package/dist/imageEdit/export.js +253 -0
  170. package/dist/imageEdit/export.js.map +1 -0
  171. package/dist/imageEdit/index.d.ts +14 -0
  172. package/dist/imageEdit/index.d.ts.map +1 -0
  173. package/dist/imageEdit/index.js +22 -0
  174. package/dist/imageEdit/index.js.map +1 -0
  175. package/dist/imageEdit/persistence.d.ts +15 -0
  176. package/dist/imageEdit/persistence.d.ts.map +1 -0
  177. package/dist/imageEdit/persistence.js +49 -0
  178. package/dist/imageEdit/persistence.js.map +1 -0
  179. package/dist/imageEdit/state.d.ts +42 -0
  180. package/dist/imageEdit/state.d.ts.map +1 -0
  181. package/dist/imageEdit/state.js +98 -0
  182. package/dist/imageEdit/state.js.map +1 -0
  183. package/dist/imageEdit/versionPaths.d.ts +27 -0
  184. package/dist/imageEdit/versionPaths.d.ts.map +1 -0
  185. package/dist/imageEdit/versionPaths.js +57 -0
  186. package/dist/imageEdit/versionPaths.js.map +1 -0
  187. package/dist/imageEdit/versions.d.ts +67 -0
  188. package/dist/imageEdit/versions.d.ts.map +1 -0
  189. package/dist/imageEdit/versions.js +161 -0
  190. package/dist/imageEdit/versions.js.map +1 -0
  191. package/dist/index.d.ts +4 -0
  192. package/dist/index.d.ts.map +1 -1
  193. package/dist/index.js +4 -0
  194. package/dist/index.js.map +1 -1
  195. package/dist/jsonForm/chooseControl.d.ts +20 -0
  196. package/dist/jsonForm/chooseControl.d.ts.map +1 -0
  197. package/dist/jsonForm/chooseControl.js +82 -0
  198. package/dist/jsonForm/chooseControl.js.map +1 -0
  199. package/dist/jsonForm/evaluateWhen.d.ts +12 -0
  200. package/dist/jsonForm/evaluateWhen.d.ts.map +1 -0
  201. package/dist/jsonForm/evaluateWhen.js +65 -0
  202. package/dist/jsonForm/evaluateWhen.js.map +1 -0
  203. package/dist/jsonForm/index.d.ts +14 -0
  204. package/dist/jsonForm/index.d.ts.map +1 -0
  205. package/dist/jsonForm/index.js +12 -0
  206. package/dist/jsonForm/index.js.map +1 -0
  207. package/dist/jsonForm/inferSchema.d.ts +12 -0
  208. package/dist/jsonForm/inferSchema.d.ts.map +1 -0
  209. package/dist/jsonForm/inferSchema.js +15 -0
  210. package/dist/jsonForm/inferSchema.js.map +1 -0
  211. package/dist/jsonForm/pointer.d.ts +26 -0
  212. package/dist/jsonForm/pointer.d.ts.map +1 -0
  213. package/dist/jsonForm/pointer.js +102 -0
  214. package/dist/jsonForm/pointer.js.map +1 -0
  215. package/dist/jsonForm/types.d.ts +120 -0
  216. package/dist/jsonForm/types.d.ts.map +1 -0
  217. package/dist/jsonForm/types.js +10 -0
  218. package/dist/jsonForm/types.js.map +1 -0
  219. package/dist/markdown/convert.d.ts +11 -1
  220. package/dist/markdown/convert.d.ts.map +1 -1
  221. package/dist/markdown/convert.js +235 -15
  222. package/dist/markdown/convert.js.map +1 -1
  223. package/dist/markdown/index.d.ts +2 -2
  224. package/dist/markdown/index.d.ts.map +1 -1
  225. package/dist/markdown/index.js +1 -1
  226. package/dist/markdown/index.js.map +1 -1
  227. package/dist/markdown/types.d.ts +34 -1
  228. package/dist/markdown/types.d.ts.map +1 -1
  229. package/dist/markdown/utils.d.ts +40 -0
  230. package/dist/markdown/utils.d.ts.map +1 -1
  231. package/dist/markdown/utils.js +155 -0
  232. package/dist/markdown/utils.js.map +1 -1
  233. package/dist/recommend/index.d.ts +16 -0
  234. package/dist/recommend/index.d.ts.map +1 -0
  235. package/dist/recommend/index.js +15 -0
  236. package/dist/recommend/index.js.map +1 -0
  237. package/dist/recommend/templates.d.ts +39 -0
  238. package/dist/recommend/templates.d.ts.map +1 -0
  239. package/dist/recommend/templates.js +235 -0
  240. package/dist/recommend/templates.js.map +1 -0
  241. package/dist/schemas/BlockTemplates.d.ts +46 -8
  242. package/dist/schemas/BlockTemplates.d.ts.map +1 -1
  243. package/dist/schemas/BlockTemplates.js +3 -3
  244. package/dist/schemas/BlockTemplates.js.map +1 -1
  245. package/dist/schemas/ImageEditDoc.d.ts +81 -0
  246. package/dist/schemas/ImageEditDoc.d.ts.map +1 -0
  247. package/dist/schemas/ImageEditDoc.js +20 -0
  248. package/dist/schemas/ImageEditDoc.js.map +1 -0
  249. package/dist/schemas/Theme.d.ts +93 -23
  250. package/dist/schemas/Theme.d.ts.map +1 -1
  251. package/dist/schemas/Theme.js +80 -13
  252. package/dist/schemas/Theme.js.map +1 -1
  253. package/dist/schemas/colorUtils.d.ts +51 -0
  254. package/dist/schemas/colorUtils.d.ts.map +1 -0
  255. package/dist/schemas/colorUtils.js +154 -0
  256. package/dist/schemas/colorUtils.js.map +1 -0
  257. package/dist/schemas/fontStacks.d.ts +57 -0
  258. package/dist/schemas/fontStacks.d.ts.map +1 -0
  259. package/dist/schemas/fontStacks.js +227 -0
  260. package/dist/schemas/fontStacks.js.map +1 -0
  261. package/dist/schemas/index.d.ts +5 -0
  262. package/dist/schemas/index.d.ts.map +1 -1
  263. package/dist/schemas/index.js +4 -0
  264. package/dist/schemas/index.js.map +1 -1
  265. package/dist/schemas/themeCompile.d.ts +45 -0
  266. package/dist/schemas/themeCompile.d.ts.map +1 -0
  267. package/dist/schemas/themeCompile.js +160 -0
  268. package/dist/schemas/themeCompile.js.map +1 -0
  269. package/dist/schemas/themeLibrary.d.ts +11 -15
  270. package/dist/schemas/themeLibrary.d.ts.map +1 -1
  271. package/dist/schemas/themeLibrary.js +18 -499
  272. package/dist/schemas/themeLibrary.js.map +1 -1
  273. package/dist/schemas/themeValidator.d.ts +26 -0
  274. package/dist/schemas/themeValidator.d.ts.map +1 -0
  275. package/dist/schemas/themeValidator.js +352 -0
  276. package/dist/schemas/themeValidator.js.map +1 -0
  277. package/dist/schemas/themes/bold.json +48 -0
  278. package/dist/schemas/themes/cinematic.json +54 -0
  279. package/dist/schemas/themes/documentary.json +49 -0
  280. package/dist/schemas/themes/gezellig.json +44 -0
  281. package/dist/schemas/themes/index.d.ts +26 -0
  282. package/dist/schemas/themes/index.d.ts.map +1 -0
  283. package/dist/schemas/themes/index.js +49 -0
  284. package/dist/schemas/themes/index.js.map +1 -0
  285. package/dist/schemas/themes/magazine.json +44 -0
  286. package/dist/schemas/themes/minimalist.json +45 -0
  287. package/dist/schemas/themes/morning-light.json +42 -0
  288. package/dist/schemas/themes/standard-dark.json +50 -0
  289. package/dist/schemas/themes/standard.json +42 -0
  290. package/dist/schemas/themes/tech-dark.json +48 -0
  291. package/dist/schemas/themes/warm-earth.json +50 -0
  292. package/dist/storage/ScopedContentContainer.d.ts +44 -0
  293. package/dist/storage/ScopedContentContainer.d.ts.map +1 -0
  294. package/dist/storage/ScopedContentContainer.js +94 -0
  295. package/dist/storage/ScopedContentContainer.js.map +1 -0
  296. package/dist/storage/index.d.ts +1 -0
  297. package/dist/storage/index.d.ts.map +1 -1
  298. package/dist/storage/index.js +1 -0
  299. package/dist/storage/index.js.map +1 -1
  300. package/dist/story/index.d.ts +53 -13
  301. package/dist/story/index.js +12 -4
  302. package/dist/themeLibrary-BHjJ0Qx6.d.ts +40 -0
  303. package/dist/{types-DYAzisMG.d.ts → types-BdZkdJ3z.d.ts} +35 -2
  304. package/dist/types-D98li1gV.d.ts +93 -0
  305. package/dist/versions/DocumentVersionManager.d.ts +31 -0
  306. package/dist/versions/DocumentVersionManager.d.ts.map +1 -0
  307. package/dist/versions/DocumentVersionManager.js +33 -0
  308. package/dist/versions/DocumentVersionManager.js.map +1 -0
  309. package/dist/versions/index.d.ts +29 -0
  310. package/dist/versions/index.d.ts.map +1 -0
  311. package/dist/versions/index.js +28 -0
  312. package/dist/versions/index.js.map +1 -0
  313. package/dist/versions/operations.d.ts +44 -0
  314. package/dist/versions/operations.d.ts.map +1 -0
  315. package/dist/versions/operations.js +190 -0
  316. package/dist/versions/operations.js.map +1 -0
  317. package/dist/versions/paths.d.ts +29 -0
  318. package/dist/versions/paths.d.ts.map +1 -0
  319. package/dist/versions/paths.js +66 -0
  320. package/dist/versions/paths.js.map +1 -0
  321. package/dist/versions/timestamp.d.ts +22 -0
  322. package/dist/versions/timestamp.d.ts.map +1 -0
  323. package/dist/versions/timestamp.js +44 -0
  324. package/dist/versions/timestamp.js.map +1 -0
  325. package/dist/versions/types.d.ts +92 -0
  326. package/dist/versions/types.d.ts.map +1 -0
  327. package/dist/versions/types.js +11 -0
  328. package/dist/versions/types.js.map +1 -0
  329. package/package.json +28 -1
  330. package/src/__tests__/colorUtils.test.ts +112 -0
  331. package/src/__tests__/getLayers.test.ts +32 -7
  332. package/src/__tests__/iconResolve.test.ts +122 -0
  333. package/src/__tests__/imageEditState.test.ts +74 -0
  334. package/src/__tests__/imageEditVersions.test.ts +169 -0
  335. package/src/__tests__/inferDocumentTitle.test.ts +50 -0
  336. package/src/__tests__/jsonForm.chooseControl.test.ts +86 -0
  337. package/src/__tests__/jsonForm.evaluateWhen.test.ts +59 -0
  338. package/src/__tests__/jsonForm.inferSchema.test.ts +25 -0
  339. package/src/__tests__/jsonForm.pointer.test.ts +103 -0
  340. package/src/__tests__/markdown.test.ts +44 -0
  341. package/src/__tests__/markdownIcons.test.ts +104 -0
  342. package/src/__tests__/markdownToDoc.test.ts +19 -4
  343. package/src/__tests__/recommendTemplates.test.ts +183 -0
  344. package/src/__tests__/scopedContentContainer.test.ts +89 -0
  345. package/src/__tests__/slideshowGenerator.test.ts +1 -1
  346. package/src/__tests__/surface.test.ts +68 -0
  347. package/src/__tests__/templateAnnotationParse.test.ts +42 -0
  348. package/src/__tests__/templates.test.ts +93 -9
  349. package/src/__tests__/themeCompile.test.ts +156 -0
  350. package/src/__tests__/themeValidator.test.ts +125 -0
  351. package/src/__tests__/versions.test.ts +415 -0
  352. package/src/doc/audioMapping.ts +95 -13
  353. package/src/doc/getLayers.ts +32 -21
  354. package/src/doc/markdownToDoc.ts +45 -7
  355. package/src/doc/templates/featureBlock.ts +202 -0
  356. package/src/doc/templates/fullBleedQuote.ts +13 -0
  357. package/src/doc/templates/index.ts +50 -16
  358. package/src/doc/templates/listBlock.ts +24 -5
  359. package/src/doc/templates/statHighlight.ts +13 -0
  360. package/src/doc/templates/titleBlock.ts +9 -0
  361. package/src/doc/utils/themeUtils.ts +8 -7
  362. package/src/generate/slideshowGenerator.ts +1 -1
  363. package/src/generate/templateMapper.ts +2 -2
  364. package/src/icons/iconData.ts +31 -0
  365. package/src/icons/index.ts +18 -0
  366. package/src/icons/resolve.ts +139 -0
  367. package/src/imageEdit/ImageEditVersionManager.ts +73 -0
  368. package/src/imageEdit/export.ts +326 -0
  369. package/src/imageEdit/index.ts +71 -0
  370. package/src/imageEdit/persistence.ts +62 -0
  371. package/src/imageEdit/state.ts +112 -0
  372. package/src/imageEdit/versionPaths.ts +57 -0
  373. package/src/imageEdit/versions.ts +231 -0
  374. package/src/index.ts +4 -0
  375. package/src/jsonForm/chooseControl.ts +88 -0
  376. package/src/jsonForm/evaluateWhen.ts +59 -0
  377. package/src/jsonForm/index.ts +22 -0
  378. package/src/jsonForm/inferSchema.ts +25 -0
  379. package/src/jsonForm/pointer.ts +109 -0
  380. package/src/jsonForm/types.ts +167 -0
  381. package/src/markdown/convert.ts +248 -15
  382. package/src/markdown/index.ts +4 -0
  383. package/src/markdown/types.ts +38 -1
  384. package/src/markdown/utils.ts +159 -0
  385. package/src/recommend/index.ts +16 -0
  386. package/src/recommend/templates.ts +273 -0
  387. package/src/schemas/BlockTemplates.ts +50 -7
  388. package/src/schemas/ImageEditDoc.ts +95 -0
  389. package/src/schemas/Theme.ts +152 -23
  390. package/src/schemas/colorUtils.ts +186 -0
  391. package/src/schemas/fontStacks.ts +257 -0
  392. package/src/schemas/index.ts +12 -0
  393. package/src/schemas/themeCompile.ts +203 -0
  394. package/src/schemas/themeLibrary.ts +18 -524
  395. package/src/schemas/themeValidator.ts +388 -0
  396. package/src/schemas/themes/bold.json +48 -0
  397. package/src/schemas/themes/cinematic.json +54 -0
  398. package/src/schemas/themes/documentary.json +49 -0
  399. package/src/schemas/themes/gezellig.json +44 -0
  400. package/src/schemas/themes/index.ts +53 -0
  401. package/src/schemas/themes/magazine.json +44 -0
  402. package/src/schemas/themes/minimalist.json +45 -0
  403. package/src/schemas/themes/morning-light.json +42 -0
  404. package/src/schemas/themes/standard-dark.json +50 -0
  405. package/src/schemas/themes/standard.json +42 -0
  406. package/src/schemas/themes/tech-dark.json +48 -0
  407. package/src/schemas/themes/warm-earth.json +50 -0
  408. package/src/storage/ScopedContentContainer.ts +113 -0
  409. package/src/storage/index.ts +1 -0
  410. package/src/versions/DocumentVersionManager.ts +70 -0
  411. package/src/versions/index.ts +54 -0
  412. package/src/versions/operations.ts +230 -0
  413. package/src/versions/paths.ts +66 -0
  414. package/src/versions/timestamp.ts +48 -0
  415. package/src/versions/types.ts +91 -0
  416. package/dist/chunk-53TZ2UTL.js +0 -470
  417. package/dist/chunk-53TZ2UTL.js.map +0 -1
  418. package/dist/chunk-7GF6RDED.js +0 -82
  419. package/dist/chunk-7GF6RDED.js.map +0 -1
  420. package/dist/chunk-CYQHG27J.js.map +0 -1
  421. package/dist/chunk-GAQLMORN.js.map +0 -1
  422. package/dist/chunk-LAZELBON.js.map +0 -1
  423. package/dist/chunk-QM5PKNPW.js.map +0 -1
  424. package/dist/chunk-TSG2OSE6.js.map +0 -1
  425. package/dist/chunk-XM4WSOHB.js +0 -92
  426. package/dist/chunk-XM4WSOHB.js.map +0 -1
  427. package/dist/themeLibrary-IP7EdyRq.d.ts +0 -44
@@ -0,0 +1,109 @@
1
+ /**
2
+ * JSON Pointer helpers (RFC 6901) plus immutable get/set, plus a tiny
3
+ * dotted-path normalizer so hosts can write `user.role` instead of
4
+ * `/user/role`. `$ref` resolution is local-only (`#/$defs/Foo`).
5
+ */
6
+
7
+ import type { SquisqAnnotatedSchema } from './types.js';
8
+
9
+ /** Normalize a path to a JSON Pointer string. Accepts both forms. */
10
+ export function toPointer(path: string): string {
11
+ if (path === '' || path === '/') return '';
12
+ if (path.startsWith('/')) return path;
13
+ // Dotted form: split on `.` and escape per RFC 6901.
14
+ return (
15
+ '/' +
16
+ path
17
+ .split('.')
18
+ .map((seg) => seg.replace(/~/g, '~0').replace(/\//g, '~1'))
19
+ .join('/')
20
+ );
21
+ }
22
+
23
+ /** Split a JSON Pointer into decoded segments. Empty string → []. */
24
+ export function pointerSegments(pointer: string): string[] {
25
+ if (pointer === '') return [];
26
+ return pointer
27
+ .slice(1)
28
+ .split('/')
29
+ .map((seg) => seg.replace(/~1/g, '/').replace(/~0/g, '~'));
30
+ }
31
+
32
+ /** Read a value from data by path (dotted or pointer). Returns undefined if missing. */
33
+ export function getByPointer(data: unknown, path: string): unknown {
34
+ const segments = pointerSegments(toPointer(path));
35
+ let cur: unknown = data;
36
+ for (const seg of segments) {
37
+ if (cur === null || cur === undefined) return undefined;
38
+ if (Array.isArray(cur)) {
39
+ const idx = Number(seg);
40
+ if (!Number.isInteger(idx) || idx < 0 || idx >= cur.length) return undefined;
41
+ cur = cur[idx];
42
+ } else if (typeof cur === 'object') {
43
+ cur = (cur as Record<string, unknown>)[seg];
44
+ } else {
45
+ return undefined;
46
+ }
47
+ }
48
+ return cur;
49
+ }
50
+
51
+ /**
52
+ * Return a structurally-shared copy of `data` with the value at `path`
53
+ * replaced. Intermediate objects/arrays are cloned along the path; the
54
+ * rest is shared by reference. Creates intermediate objects if missing.
55
+ */
56
+ export function setByPointer<T>(data: T, path: string, value: unknown): T {
57
+ const segments = pointerSegments(toPointer(path));
58
+ if (segments.length === 0) return value as T;
59
+ return setRec(data, segments, 0, value) as T;
60
+ }
61
+
62
+ function setRec(node: unknown, segments: string[], i: number, value: unknown): unknown {
63
+ const seg = segments[i];
64
+ const isLast = i === segments.length - 1;
65
+
66
+ // Decide whether the slot we're about to write into is an array index.
67
+ const nextSeg = isLast ? undefined : segments[i + 1];
68
+ const writingArrayChild = nextSeg !== undefined && /^\d+$/.test(nextSeg);
69
+
70
+ if (Array.isArray(node)) {
71
+ const idx = Number(seg);
72
+ const next = node.slice();
73
+ next[idx] = isLast
74
+ ? value
75
+ : setRec(node[idx] ?? (writingArrayChild ? [] : {}), segments, i + 1, value);
76
+ return next;
77
+ }
78
+
79
+ const obj = (node && typeof node === 'object' ? { ...(node as object) } : {}) as Record<
80
+ string,
81
+ unknown
82
+ >;
83
+ obj[seg] = isLast
84
+ ? value
85
+ : setRec(obj[seg] ?? (writingArrayChild ? [] : {}), segments, i + 1, value);
86
+ return obj;
87
+ }
88
+
89
+ /**
90
+ * Resolve a local `$ref` (e.g. `#/$defs/Foo`) against the root schema.
91
+ * Returns the original schema if no `$ref` is present, or `undefined`
92
+ * if the reference cannot be resolved. Cross-document refs are not
93
+ * supported.
94
+ */
95
+ export function resolveRef(
96
+ schema: SquisqAnnotatedSchema,
97
+ root: SquisqAnnotatedSchema,
98
+ ): SquisqAnnotatedSchema | undefined {
99
+ if (!schema.$ref) return schema;
100
+ const ref = schema.$ref;
101
+ if (!ref.startsWith('#/')) return undefined;
102
+ const segments = pointerSegments(ref.slice(1));
103
+ let cur: unknown = root;
104
+ for (const seg of segments) {
105
+ if (cur === null || cur === undefined || typeof cur !== 'object') return undefined;
106
+ cur = (cur as Record<string, unknown>)[seg];
107
+ }
108
+ return (cur as SquisqAnnotatedSchema | undefined) ?? undefined;
109
+ }
@@ -0,0 +1,167 @@
1
+ /**
2
+ * JSON Form types — Squisq's hint vocabulary layered on JSON Schema.
3
+ *
4
+ * Hints live inline on a JSON Schema under a single `squisq` key. The
5
+ * schema remains a valid JSON Schema; the extra key is ignored by
6
+ * standard validators. Renderers consult the hints to pick a control
7
+ * and tune its presentation.
8
+ */
9
+
10
+ /**
11
+ * Every concrete control rendered by `<JsonView>` and `<JsonEditor>`.
12
+ *
13
+ * Auto-defaults pick one based on schema shape; hosts override via
14
+ * `squisq.control` when they want something specific (e.g. radio over
15
+ * segmented for a long, descriptive enum).
16
+ */
17
+ export type ControlKind =
18
+ | 'text'
19
+ | 'multiline'
20
+ | 'richtext'
21
+ | 'color'
22
+ | 'date'
23
+ | 'time'
24
+ | 'datetime'
25
+ | 'slider'
26
+ | 'stepper'
27
+ | 'segmented'
28
+ | 'radio'
29
+ | 'combobox'
30
+ | 'toggle'
31
+ | 'checkbox'
32
+ | 'card'
33
+ | 'card-stack'
34
+ | 'chip-bin'
35
+ | 'tabs'
36
+ | 'group';
37
+
38
+ /**
39
+ * Conditional rule: looked up by field path against the root data and
40
+ * compared with one of the operators. The first defined operator wins
41
+ * (in declaration order: equals, oneOf, matches, truthy).
42
+ */
43
+ export interface SquisqWhen {
44
+ /**
45
+ * Path to the controlling field, relative to the root data.
46
+ * Accepts dotted-path (`user.role`) or JSON Pointer (`/user/role`).
47
+ */
48
+ field: string;
49
+ equals?: unknown;
50
+ oneOf?: readonly unknown[];
51
+ /** ECMAScript regex source; matched against the string value. */
52
+ matches?: string;
53
+ /** When true, condition holds if value is truthy; when false, if falsy. */
54
+ truthy?: boolean;
55
+ }
56
+
57
+ /**
58
+ * Hints for a single schema node. Attach via `squisq` on any JSON
59
+ * Schema object — properties, items, the root, or sub-schemas inside
60
+ * `oneOf`/`anyOf`.
61
+ */
62
+ export interface SquisqHints {
63
+ /** Force a specific control. If omitted, picked from type/format/enum cardinality. */
64
+ control?: ControlKind;
65
+
66
+ /** Override schema `title` for display. */
67
+ label?: string;
68
+ /** Override schema `description` for the inline helper text. */
69
+ help?: string;
70
+ /** Placeholder text for empty fields. */
71
+ placeholder?: string;
72
+
73
+ /** Suggested layout sizing in a parent grid. Renderers may ignore on narrow viewports. */
74
+ width?: 'full' | 'half' | 'third' | 'auto';
75
+
76
+ /** Hide the field — literal, or a `SquisqWhen` evaluated against root data. */
77
+ hidden?: boolean | SquisqWhen;
78
+ /** Disable the field — literal, or a `SquisqWhen` evaluated against root data. */
79
+ disabled?: boolean | SquisqWhen;
80
+
81
+ /** Override schema's required-ness for the UI only. */
82
+ required?: boolean;
83
+
84
+ /** For arrays of objects: how to label each card in a `card-stack`. */
85
+ itemLabel?: string | { fromField: string };
86
+ /** Label for the "+ Add" button on arrays. */
87
+ addLabel?: string;
88
+ /** Label for the remove button on arrays. */
89
+ removeLabel?: string;
90
+
91
+ /** Slider/stepper visual step. Falls back to schema `multipleOf`. */
92
+ step?: number;
93
+
94
+ /** Optional human-readable labels for enum values. */
95
+ enumLabels?: Record<string, string>;
96
+ }
97
+
98
+ /**
99
+ * The subset of JSON Schema we understand, with an optional `squisq`
100
+ * key. We deliberately keep this as a structural type so any JSON
101
+ * Schema authored elsewhere can be passed in without conversion.
102
+ */
103
+ export interface SquisqAnnotatedSchema {
104
+ type?: string | readonly string[];
105
+ format?: string;
106
+ title?: string;
107
+ description?: string;
108
+ default?: unknown;
109
+ examples?: readonly unknown[];
110
+
111
+ enum?: readonly unknown[];
112
+ const?: unknown;
113
+
114
+ // Object
115
+ properties?: Record<string, SquisqAnnotatedSchema>;
116
+ required?: readonly string[];
117
+ additionalProperties?: boolean | SquisqAnnotatedSchema;
118
+
119
+ // Array
120
+ items?: SquisqAnnotatedSchema | readonly SquisqAnnotatedSchema[];
121
+ minItems?: number;
122
+ maxItems?: number;
123
+
124
+ // Number
125
+ minimum?: number;
126
+ maximum?: number;
127
+ exclusiveMinimum?: number;
128
+ exclusiveMaximum?: number;
129
+ multipleOf?: number;
130
+
131
+ // String
132
+ minLength?: number;
133
+ maxLength?: number;
134
+ pattern?: string;
135
+
136
+ // Combinators
137
+ oneOf?: readonly SquisqAnnotatedSchema[];
138
+ anyOf?: readonly SquisqAnnotatedSchema[];
139
+ allOf?: readonly SquisqAnnotatedSchema[];
140
+
141
+ // References
142
+ $ref?: string;
143
+ $defs?: Record<string, SquisqAnnotatedSchema>;
144
+ definitions?: Record<string, SquisqAnnotatedSchema>;
145
+
146
+ // Squisq-native UI hints
147
+ squisq?: SquisqHints;
148
+ }
149
+
150
+ /**
151
+ * A validation error reported by the consumer-supplied `validate` prop.
152
+ * Matches the shape of common validators (ajv, etc.) without depending
153
+ * on any specific one.
154
+ */
155
+ export interface JsonFormValidationError {
156
+ /** JSON Pointer to the failing value, e.g. `/sections/0/heading`. */
157
+ path: string;
158
+ /** Human-readable message. */
159
+ message: string;
160
+ /** Optional schema keyword that failed (e.g. "required", "minimum"). */
161
+ keyword?: string;
162
+ }
163
+
164
+ export type JsonFormValidator = (
165
+ value: unknown,
166
+ schema: SquisqAnnotatedSchema,
167
+ ) => readonly JsonFormValidationError[];
@@ -20,8 +20,10 @@ import type {
20
20
  MarkdownSourcePosition,
21
21
  HeadingTemplateAnnotation,
22
22
  MarkdownHeading,
23
+ MarkdownInlineIcon,
23
24
  } from './types.js';
24
25
  import { parseHtmlToNodes } from './htmlParse.js';
26
+ import { resolveIcon } from '../icons/resolve.js';
25
27
 
26
28
  // ============================================
27
29
  // Generic mdast node shape
@@ -132,8 +134,13 @@ function extractText(node: MdastNode): string {
132
134
  /**
133
135
  * Regex matching a trailing `{[templateName key=value …]}` annotation.
134
136
  * Captures the content between `{[` and `]}`.
137
+ *
138
+ * The trailing `[\s\]\}]*` tolerates accidental doubled `]}` that users
139
+ * sometimes type when learning the syntax (e.g. `{[foo]}]}`). It does
140
+ * not allow trailing word characters, so a non-trailing annotation like
141
+ * `## The {[chart]} section` still doesn't match.
135
142
  */
136
- const TEMPLATE_ANNOTATION_RE = /\s*\{\[([^\]]+)\]\}\s*$/;
143
+ const TEMPLATE_ANNOTATION_RE = /\s*\{\[([^\]]+)\]\}[\s\]}]*$/;
137
144
 
138
145
  /**
139
146
  * Extract a `{[templateName key=value …]}` annotation from a heading's
@@ -247,13 +254,187 @@ function convertBlockChildren(children: MdastNode[], parseHtml: boolean): Markdo
247
254
  return result;
248
255
  }
249
256
 
250
- function convertInlineChildren(children: MdastNode[], parseHtml: boolean): MarkdownInlineNode[] {
257
+ function convertInlineChildren(
258
+ children: MdastNode[],
259
+ parseHtml: boolean,
260
+ /** When false, skip the inline-icon split. Headings opt out so the
261
+ * `extractTemplateAnnotation` pass still sees the trailing
262
+ * `{[…]}` in raw text form; the caller runs `splitInlineIcons`
263
+ * itself afterward on the remaining children. */
264
+ applyIconSplit: boolean = true,
265
+ ): MarkdownInlineNode[] {
251
266
  const result: MarkdownInlineNode[] = [];
252
267
  for (const child of children) {
253
268
  const node = convertInlineNode(child, parseHtml);
254
269
  if (node) result.push(node);
255
270
  }
256
- return result;
271
+ const mentioned = coalesceMentions(result);
272
+ return applyIconSplit ? splitInlineIcons(mentioned) : mentioned;
273
+ }
274
+
275
+ /**
276
+ * Walk an inline-children list and split each text node on `{[token]}`
277
+ * occurrences whose tokens resolve to known FontAwesome icons. Returns
278
+ * a new array — unresolved tokens are left as literal text so authors
279
+ * can write `{[notathing]}` verbatim if they really mean to.
280
+ *
281
+ * Exposed for the heading code path, which first strips the trailing
282
+ * template annotation and then runs this on what remains.
283
+ */
284
+ export function splitInlineIcons(nodes: MarkdownInlineNode[]): MarkdownInlineNode[] {
285
+ // First pass: reassemble `text + textDirective + text` patterns
286
+ // formed when a qualified token like `{[fa-solid:user]}` was split
287
+ // by remark-directive's colon recognition. We collapse those triples
288
+ // back into a single text node containing the original token so the
289
+ // regex below can match.
290
+ const recombined = recombineDirectiveTokens(nodes);
291
+
292
+ const out: MarkdownInlineNode[] = [];
293
+ for (const node of recombined) {
294
+ if (node.type !== 'text') {
295
+ out.push(node);
296
+ continue;
297
+ }
298
+ out.push(...splitTextOnIcons(node.value, node.position));
299
+ }
300
+ return out;
301
+ }
302
+
303
+ /**
304
+ * When the user types `{[fa-solid:user]}`, remark's directive plugin
305
+ * sees `:user` and emits a `textDirective` node. The result is a
306
+ * three-node sequence `text("…{[fa-solid") + textDirective("user") +
307
+ * text("]}…")`. This helper detects that shape and stitches the three
308
+ * back into one text node so downstream icon detection works on the
309
+ * authored token.
310
+ */
311
+ function recombineDirectiveTokens(nodes: MarkdownInlineNode[]): MarkdownInlineNode[] {
312
+ const out: MarkdownInlineNode[] = [];
313
+ for (let i = 0; i < nodes.length; i++) {
314
+ const cur = nodes[i];
315
+ const next = nodes[i + 1];
316
+ const after = nodes[i + 2];
317
+ if (
318
+ cur?.type === 'text' &&
319
+ next?.type === 'textDirective' &&
320
+ after?.type === 'text' &&
321
+ /\{\[[a-zA-Z0-9_-]+$/.test(cur.value) &&
322
+ /^\]\}/.test(after.value)
323
+ ) {
324
+ const directive = next as unknown as { name?: string };
325
+ const directiveName = directive.name ?? '';
326
+ const merged: MarkdownInlineNode = {
327
+ type: 'text',
328
+ value: cur.value + ':' + directiveName + after.value,
329
+ ...(cur.position ? { position: cur.position } : {}),
330
+ };
331
+ out.push(merged);
332
+ i += 2;
333
+ continue;
334
+ }
335
+ out.push(cur);
336
+ }
337
+ return out;
338
+ }
339
+
340
+ const ICON_TOKEN_RE = /\{\[([a-zA-Z0-9_:-]+)\]\}/g;
341
+
342
+ function splitTextOnIcons(value: string, position?: MarkdownSourcePosition): MarkdownInlineNode[] {
343
+ if (!value) return [];
344
+ ICON_TOKEN_RE.lastIndex = 0;
345
+ let lastIndex = 0;
346
+ let match: RegExpExecArray | null;
347
+ const out: MarkdownInlineNode[] = [];
348
+ while ((match = ICON_TOKEN_RE.exec(value)) !== null) {
349
+ const token = match[1];
350
+ const icon = resolveIcon(token);
351
+ if (!icon) continue; // leave the literal `{[…]}` in place
352
+ if (match.index > lastIndex) {
353
+ out.push({
354
+ type: 'text',
355
+ value: value.slice(lastIndex, match.index),
356
+ ...(position ? { position } : {}),
357
+ });
358
+ }
359
+ const iconNode: MarkdownInlineIcon = {
360
+ type: 'inlineIcon',
361
+ token,
362
+ family: icon.family,
363
+ name: icon.name,
364
+ ...(position ? { position } : {}),
365
+ };
366
+ out.push(iconNode);
367
+ lastIndex = match.index + match[0].length;
368
+ }
369
+ if (lastIndex === 0) {
370
+ // No matches — return the original text node unchanged.
371
+ return [{ type: 'text', value, ...(position ? { position } : {}) }];
372
+ }
373
+ if (lastIndex < value.length) {
374
+ out.push({
375
+ type: 'text',
376
+ value: value.slice(lastIndex),
377
+ ...(position ? { position } : {}),
378
+ });
379
+ }
380
+ return out;
381
+ }
382
+
383
+ /**
384
+ * Post-process an inline-children list to collapse `text('@') + link(scheme:id)`
385
+ * pairs into a single `mention` node. The wire format `@[Display](scheme:id)`
386
+ * comes back from remark as two adjacent nodes — we merge them so consumers
387
+ * see a single atomic mention. A plain link whose URL doesn't have `scheme:id`
388
+ * shape, or that isn't immediately preceded by `@`, is left alone so ordinary
389
+ * links keep working.
390
+ */
391
+ function coalesceMentions(inlines: MarkdownInlineNode[]): MarkdownInlineNode[] {
392
+ const out: MarkdownInlineNode[] = [];
393
+ for (const cur of inlines) {
394
+ const prev = out[out.length - 1];
395
+ if (
396
+ cur.type === 'link' &&
397
+ typeof cur.url === 'string' &&
398
+ prev &&
399
+ prev.type === 'text' &&
400
+ prev.value.endsWith('@')
401
+ ) {
402
+ const schemeMatch = cur.url.match(/^([a-z][a-z0-9+.-]*):(.+)$/i);
403
+ if (schemeMatch && schemeMatch[1] && schemeMatch[2]) {
404
+ const targetKind = schemeMatch[1];
405
+ const targetId = schemeMatch[2];
406
+ const displayName = extractInlineText(cur.children);
407
+ if (prev.value === '@') {
408
+ out.pop();
409
+ } else {
410
+ prev.value = prev.value.slice(0, -1);
411
+ }
412
+ out.push({
413
+ type: 'mention',
414
+ targetKind,
415
+ targetId,
416
+ displayName,
417
+ ...(cur.position ? { position: cur.position } : {}),
418
+ });
419
+ continue;
420
+ }
421
+ }
422
+ out.push(cur);
423
+ }
424
+ return out;
425
+ }
426
+
427
+ /** Plain-text of an inline children list — used to pull the display name
428
+ * out of a mention link's children. */
429
+ function extractInlineText(nodes: MarkdownInlineNode[]): string {
430
+ let out = '';
431
+ for (const n of nodes) {
432
+ if (n.type === 'text' || n.type === 'inlineCode') out += n.value;
433
+ else if ('children' in n && Array.isArray(n.children)) {
434
+ out += extractInlineText(n.children as MarkdownInlineNode[]);
435
+ }
436
+ }
437
+ return out;
257
438
  }
258
439
 
259
440
  function convertBlockNode(node: MdastNode, parseHtml: boolean): MarkdownBlockNode | null {
@@ -261,12 +442,18 @@ function convertBlockNode(node: MdastNode, parseHtml: boolean): MarkdownBlockNod
261
442
 
262
443
  switch (node.type) {
263
444
  case 'heading': {
264
- const headingChildren = convertInlineChildren(node.children ?? [], parseHtml);
445
+ // Defer icon splitting so `extractTemplateAnnotation` sees the
446
+ // trailing `{[name]}` as plain text and can decide whether it's
447
+ // a template annotation. Anything that's NOT the template still
448
+ // needs to become an icon node, so we run `splitInlineIcons` on
449
+ // what's left after the template extraction.
450
+ const headingChildren = convertInlineChildren(node.children ?? [], parseHtml, false);
265
451
  const annotation = extractTemplateAnnotation(headingChildren);
452
+ const finalChildren = splitInlineIcons(headingChildren);
266
453
  const result: MarkdownHeading = {
267
454
  type: 'heading',
268
455
  depth: (node.depth ?? 1) as 1 | 2 | 3 | 4 | 5 | 6,
269
- children: headingChildren,
456
+ children: finalChildren,
270
457
  ...posField(pos),
271
458
  };
272
459
  if (annotation) {
@@ -590,7 +777,7 @@ export function toMdast(doc: MarkdownDocument): MdastNode {
590
777
  function blockToMdast(node: MarkdownBlockNode): MdastNode {
591
778
  switch (node.type) {
592
779
  case 'heading': {
593
- const mdastChildren = node.children.map(inlineToMdast);
780
+ const mdastChildren = inlineChildrenToMdast(node.children);
594
781
  if (node.templateAnnotation) {
595
782
  const suffix = serializeTemplateAnnotation(node.templateAnnotation);
596
783
  // Append to last text node, or create a new one
@@ -612,7 +799,7 @@ function blockToMdast(node: MarkdownBlockNode): MdastNode {
612
799
  case 'paragraph':
613
800
  return {
614
801
  type: 'paragraph',
615
- children: node.children.map(inlineToMdast),
802
+ children: inlineChildrenToMdast(node.children),
616
803
  ...mdastPosField(node.position),
617
804
  };
618
805
 
@@ -718,7 +905,7 @@ function blockToMdast(node: MarkdownBlockNode): MdastNode {
718
905
  type: 'leafDirective',
719
906
  name: node.name,
720
907
  ...(node.attributes ? { attributes: node.attributes } : {}),
721
- children: node.children.map(inlineToMdast),
908
+ children: inlineChildrenToMdast(node.children),
722
909
  ...mdastPosField(node.position),
723
910
  };
724
911
 
@@ -757,11 +944,34 @@ function tableRowToMdast(row: MarkdownTableRow): MdastNode {
757
944
  function tableCellToMdast(cell: MarkdownTableCell): MdastNode {
758
945
  return {
759
946
  type: 'tableCell',
760
- children: cell.children.map(inlineToMdast),
947
+ children: inlineChildrenToMdast(cell.children),
761
948
  ...mdastPosField(cell.position),
762
949
  };
763
950
  }
764
951
 
952
+ /**
953
+ * Serialize an array of inline nodes to mdast, flat-mapping the result so
954
+ * a single `mention` expands to two mdast nodes (`text('@')` + `link`).
955
+ * Use in place of `.map(inlineToMdast)` wherever we walk a children array.
956
+ */
957
+ function inlineChildrenToMdast(nodes: MarkdownInlineNode[]): MdastNode[] {
958
+ const out: MdastNode[] = [];
959
+ for (const n of nodes) {
960
+ if (n.type === 'mention') {
961
+ out.push({ type: 'text', value: '@' });
962
+ out.push({
963
+ type: 'link',
964
+ url: `${n.targetKind}:${n.targetId}`,
965
+ children: [{ type: 'text', value: n.displayName }],
966
+ ...mdastPosField(n.position),
967
+ });
968
+ } else {
969
+ out.push(inlineToMdast(n));
970
+ }
971
+ }
972
+ return out;
973
+ }
974
+
765
975
  function inlineToMdast(node: MarkdownInlineNode): MdastNode {
766
976
  switch (node.type) {
767
977
  case 'text':
@@ -774,21 +984,21 @@ function inlineToMdast(node: MarkdownInlineNode): MdastNode {
774
984
  case 'emphasis':
775
985
  return {
776
986
  type: 'emphasis',
777
- children: node.children.map(inlineToMdast),
987
+ children: inlineChildrenToMdast(node.children),
778
988
  ...mdastPosField(node.position),
779
989
  };
780
990
 
781
991
  case 'strong':
782
992
  return {
783
993
  type: 'strong',
784
- children: node.children.map(inlineToMdast),
994
+ children: inlineChildrenToMdast(node.children),
785
995
  ...mdastPosField(node.position),
786
996
  };
787
997
 
788
998
  case 'delete':
789
999
  return {
790
1000
  type: 'delete',
791
- children: node.children.map(inlineToMdast),
1001
+ children: inlineChildrenToMdast(node.children),
792
1002
  ...mdastPosField(node.position),
793
1003
  };
794
1004
 
@@ -804,7 +1014,7 @@ function inlineToMdast(node: MarkdownInlineNode): MdastNode {
804
1014
  type: 'link',
805
1015
  url: node.url,
806
1016
  ...(node.title != null ? { title: node.title } : {}),
807
- children: node.children.map(inlineToMdast),
1017
+ children: inlineChildrenToMdast(node.children),
808
1018
  ...mdastPosField(node.position),
809
1019
  };
810
1020
 
@@ -851,7 +1061,7 @@ function inlineToMdast(node: MarkdownInlineNode): MdastNode {
851
1061
  identifier: node.identifier,
852
1062
  ...(node.label != null ? { label: node.label } : {}),
853
1063
  referenceType: node.referenceType,
854
- children: node.children.map(inlineToMdast),
1064
+ children: inlineChildrenToMdast(node.children),
855
1065
  ...mdastPosField(node.position),
856
1066
  };
857
1067
 
@@ -870,7 +1080,30 @@ function inlineToMdast(node: MarkdownInlineNode): MdastNode {
870
1080
  type: 'textDirective',
871
1081
  name: node.name,
872
1082
  ...(node.attributes ? { attributes: node.attributes } : {}),
873
- children: node.children.map(inlineToMdast),
1083
+ children: inlineChildrenToMdast(node.children),
1084
+ ...mdastPosField(node.position),
1085
+ };
1086
+
1087
+ case 'mention':
1088
+ // Fallback: when `inlineToMdast` is called directly (not via
1089
+ // `inlineChildrenToMdast`), collapse the mention to just the link
1090
+ // form. The `@` prefix is lost, but the id+name still round-trip.
1091
+ // Normal call sites go through `inlineChildrenToMdast` and get
1092
+ // the proper text('@') + link pair.
1093
+ return {
1094
+ type: 'link',
1095
+ url: `${node.targetKind}:${node.targetId}`,
1096
+ children: [{ type: 'text', value: node.displayName }],
1097
+ ...mdastPosField(node.position),
1098
+ };
1099
+
1100
+ case 'inlineIcon':
1101
+ // Serialize back to the authored token so source round-trips
1102
+ // byte-stable. The token already carries the qualified form when
1103
+ // required (the parser preserved it verbatim).
1104
+ return {
1105
+ type: 'text',
1106
+ value: `{[${node.token}]}`,
874
1107
  ...mdastPosField(node.position),
875
1108
  };
876
1109
 
@@ -77,6 +77,7 @@ export type {
77
77
  MarkdownLinkReference,
78
78
  MarkdownImageReference,
79
79
  MarkdownTextDirective,
80
+ MarkdownMention,
80
81
 
81
82
  // Union types
82
83
  MarkdownBlockNode,
@@ -107,4 +108,7 @@ export {
107
108
  countNodes,
108
109
  createDocument,
109
110
  parseFrontmatter,
111
+ setFrontmatterValues,
112
+ inferDocumentTitle,
113
+ readFrontmatterThemeId,
110
114
  } from './utils.js';