@bendyline/squisq 1.3.0 → 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 (419) hide show
  1. package/dist/{Doc-Ch4tc3vv.d.ts → Doc-BeSeH2iX.d.ts} +118 -41
  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__/markdownIcons.test.d.ts +2 -0
  42. package/dist/__tests__/markdownIcons.test.d.ts.map +1 -0
  43. package/dist/__tests__/markdownIcons.test.js +93 -0
  44. package/dist/__tests__/markdownIcons.test.js.map +1 -0
  45. package/dist/__tests__/markdownToDoc.test.js +15 -4
  46. package/dist/__tests__/markdownToDoc.test.js.map +1 -1
  47. package/dist/__tests__/recommendTemplates.test.d.ts +2 -0
  48. package/dist/__tests__/recommendTemplates.test.d.ts.map +1 -0
  49. package/dist/__tests__/recommendTemplates.test.js +158 -0
  50. package/dist/__tests__/recommendTemplates.test.js.map +1 -0
  51. package/dist/__tests__/scopedContentContainer.test.d.ts +2 -0
  52. package/dist/__tests__/scopedContentContainer.test.d.ts.map +1 -0
  53. package/dist/__tests__/scopedContentContainer.test.js +74 -0
  54. package/dist/__tests__/scopedContentContainer.test.js.map +1 -0
  55. package/dist/__tests__/slideshowGenerator.test.js +1 -1
  56. package/dist/__tests__/slideshowGenerator.test.js.map +1 -1
  57. package/dist/__tests__/templateAnnotationParse.test.d.ts +2 -0
  58. package/dist/__tests__/templateAnnotationParse.test.d.ts.map +1 -0
  59. package/dist/__tests__/templateAnnotationParse.test.js +42 -0
  60. package/dist/__tests__/templateAnnotationParse.test.js.map +1 -0
  61. package/dist/__tests__/templates.test.js +90 -9
  62. package/dist/__tests__/templates.test.js.map +1 -1
  63. package/dist/__tests__/themeCompile.test.d.ts +2 -0
  64. package/dist/__tests__/themeCompile.test.d.ts.map +1 -0
  65. package/dist/__tests__/themeCompile.test.js +134 -0
  66. package/dist/__tests__/themeCompile.test.js.map +1 -0
  67. package/dist/__tests__/themeValidator.test.d.ts +2 -0
  68. package/dist/__tests__/themeValidator.test.d.ts.map +1 -0
  69. package/dist/__tests__/themeValidator.test.js +107 -0
  70. package/dist/__tests__/themeValidator.test.js.map +1 -0
  71. package/dist/__tests__/versions.test.d.ts +2 -0
  72. package/dist/__tests__/versions.test.d.ts.map +1 -0
  73. package/dist/__tests__/versions.test.js +339 -0
  74. package/dist/__tests__/versions.test.js.map +1 -0
  75. package/dist/{chunk-CYQHG27J.js → chunk-2TMAWB4Y.js} +74 -1
  76. package/dist/chunk-2TMAWB4Y.js.map +1 -0
  77. package/dist/{chunk-OASJKWO5.js → chunk-3K5OG6KI.js} +92 -7
  78. package/dist/chunk-3K5OG6KI.js.map +1 -0
  79. package/dist/chunk-57CVQCFX.js +193 -0
  80. package/dist/chunk-57CVQCFX.js.map +1 -0
  81. package/dist/{chunk-QM5PKNPW.js → chunk-5WFRKURX.js} +1 -1
  82. package/dist/chunk-5WFRKURX.js.map +1 -0
  83. package/dist/chunk-B4EEON3N.js +1317 -0
  84. package/dist/chunk-B4EEON3N.js.map +1 -0
  85. package/dist/chunk-DBS6RIFL.js +81 -0
  86. package/dist/chunk-DBS6RIFL.js.map +1 -0
  87. package/dist/{chunk-MIBRIRGJ.js → chunk-FR2RBTKO.js} +3 -3
  88. package/dist/{chunk-MIBRIRGJ.js.map → chunk-FR2RBTKO.js.map} +1 -1
  89. package/dist/chunk-H3AXU4MJ.js +179 -0
  90. package/dist/chunk-H3AXU4MJ.js.map +1 -0
  91. package/dist/chunk-JELIRVDP.js +24 -0
  92. package/dist/chunk-JELIRVDP.js.map +1 -0
  93. package/dist/chunk-K32VJONL.js +193 -0
  94. package/dist/chunk-K32VJONL.js.map +1 -0
  95. package/dist/{chunk-6BAVXFYC.js → chunk-KSWJR66U.js} +218 -42
  96. package/dist/chunk-KSWJR66U.js.map +1 -0
  97. package/dist/{chunk-TSG2OSE6.js → chunk-MYIH7FWD.js} +3 -3
  98. package/dist/chunk-MYIH7FWD.js.map +1 -0
  99. package/dist/chunk-VLJJHDAC.js +218 -0
  100. package/dist/chunk-VLJJHDAC.js.map +1 -0
  101. package/dist/chunk-WMOI7FN3.js +182 -0
  102. package/dist/chunk-WMOI7FN3.js.map +1 -0
  103. package/dist/chunk-ZTX4PFFT.js +520 -0
  104. package/dist/chunk-ZTX4PFFT.js.map +1 -0
  105. package/dist/doc/audioMapping.d.ts.map +1 -1
  106. package/dist/doc/audioMapping.js +42 -7
  107. package/dist/doc/audioMapping.js.map +1 -1
  108. package/dist/doc/getLayers.d.ts.map +1 -1
  109. package/dist/doc/getLayers.js +29 -18
  110. package/dist/doc/getLayers.js.map +1 -1
  111. package/dist/doc/markdownToDoc.d.ts.map +1 -1
  112. package/dist/doc/markdownToDoc.js +40 -6
  113. package/dist/doc/markdownToDoc.js.map +1 -1
  114. package/dist/doc/templates/featureBlock.d.ts +18 -0
  115. package/dist/doc/templates/featureBlock.d.ts.map +1 -0
  116. package/dist/doc/templates/featureBlock.js +180 -0
  117. package/dist/doc/templates/featureBlock.js.map +1 -0
  118. package/dist/doc/templates/fullBleedQuote.d.ts +12 -0
  119. package/dist/doc/templates/fullBleedQuote.d.ts.map +1 -1
  120. package/dist/doc/templates/fullBleedQuote.js +12 -0
  121. package/dist/doc/templates/fullBleedQuote.js.map +1 -1
  122. package/dist/doc/templates/index.d.ts +28 -4
  123. package/dist/doc/templates/index.d.ts.map +1 -1
  124. package/dist/doc/templates/index.js +45 -12
  125. package/dist/doc/templates/index.js.map +1 -1
  126. package/dist/doc/templates/listBlock.d.ts.map +1 -1
  127. package/dist/doc/templates/listBlock.js +22 -5
  128. package/dist/doc/templates/listBlock.js.map +1 -1
  129. package/dist/doc/templates/statHighlight.d.ts +12 -0
  130. package/dist/doc/templates/statHighlight.d.ts.map +1 -1
  131. package/dist/doc/templates/statHighlight.js +12 -0
  132. package/dist/doc/templates/statHighlight.js.map +1 -1
  133. package/dist/doc/templates/titleBlock.d.ts +11 -0
  134. package/dist/doc/templates/titleBlock.d.ts.map +1 -1
  135. package/dist/doc/templates/titleBlock.js +8 -0
  136. package/dist/doc/templates/titleBlock.js.map +1 -1
  137. package/dist/doc/utils/themeUtils.d.ts +4 -4
  138. package/dist/doc/utils/themeUtils.d.ts.map +1 -1
  139. package/dist/doc/utils/themeUtils.js +8 -7
  140. package/dist/doc/utils/themeUtils.js.map +1 -1
  141. package/dist/generate/slideshowGenerator.js +1 -1
  142. package/dist/generate/slideshowGenerator.js.map +1 -1
  143. package/dist/generate/templateMapper.js +2 -2
  144. package/dist/generate/templateMapper.js.map +1 -1
  145. package/dist/icons/iconData.d.ts +26 -0
  146. package/dist/icons/iconData.d.ts.map +1 -0
  147. package/dist/icons/iconData.js +12 -0
  148. package/dist/icons/iconData.js.map +1 -0
  149. package/dist/icons/index.d.ts +12 -0
  150. package/dist/icons/index.d.ts.map +1 -0
  151. package/dist/icons/index.js +10 -0
  152. package/dist/icons/index.js.map +1 -0
  153. package/dist/icons/resolve.d.ts +61 -0
  154. package/dist/icons/resolve.d.ts.map +1 -0
  155. package/dist/icons/resolve.js +130 -0
  156. package/dist/icons/resolve.js.map +1 -0
  157. package/dist/imageEdit/ImageEditVersionManager.d.ts +31 -0
  158. package/dist/imageEdit/ImageEditVersionManager.d.ts.map +1 -0
  159. package/dist/imageEdit/ImageEditVersionManager.js +39 -0
  160. package/dist/imageEdit/ImageEditVersionManager.js.map +1 -0
  161. package/dist/imageEdit/export.d.ts +33 -0
  162. package/dist/imageEdit/export.d.ts.map +1 -0
  163. package/dist/imageEdit/export.js +253 -0
  164. package/dist/imageEdit/export.js.map +1 -0
  165. package/dist/imageEdit/index.d.ts +14 -0
  166. package/dist/imageEdit/index.d.ts.map +1 -0
  167. package/dist/imageEdit/index.js +22 -0
  168. package/dist/imageEdit/index.js.map +1 -0
  169. package/dist/imageEdit/persistence.d.ts +15 -0
  170. package/dist/imageEdit/persistence.d.ts.map +1 -0
  171. package/dist/imageEdit/persistence.js +49 -0
  172. package/dist/imageEdit/persistence.js.map +1 -0
  173. package/dist/imageEdit/state.d.ts +42 -0
  174. package/dist/imageEdit/state.d.ts.map +1 -0
  175. package/dist/imageEdit/state.js +98 -0
  176. package/dist/imageEdit/state.js.map +1 -0
  177. package/dist/imageEdit/versionPaths.d.ts +27 -0
  178. package/dist/imageEdit/versionPaths.d.ts.map +1 -0
  179. package/dist/imageEdit/versionPaths.js +57 -0
  180. package/dist/imageEdit/versionPaths.js.map +1 -0
  181. package/dist/imageEdit/versions.d.ts +67 -0
  182. package/dist/imageEdit/versions.d.ts.map +1 -0
  183. package/dist/imageEdit/versions.js +161 -0
  184. package/dist/imageEdit/versions.js.map +1 -0
  185. package/dist/index.d.ts +4 -0
  186. package/dist/index.d.ts.map +1 -1
  187. package/dist/index.js +4 -0
  188. package/dist/index.js.map +1 -1
  189. package/dist/jsonForm/chooseControl.d.ts +20 -0
  190. package/dist/jsonForm/chooseControl.d.ts.map +1 -0
  191. package/dist/jsonForm/chooseControl.js +82 -0
  192. package/dist/jsonForm/chooseControl.js.map +1 -0
  193. package/dist/jsonForm/evaluateWhen.d.ts +12 -0
  194. package/dist/jsonForm/evaluateWhen.d.ts.map +1 -0
  195. package/dist/jsonForm/evaluateWhen.js +65 -0
  196. package/dist/jsonForm/evaluateWhen.js.map +1 -0
  197. package/dist/jsonForm/index.d.ts +14 -0
  198. package/dist/jsonForm/index.d.ts.map +1 -0
  199. package/dist/jsonForm/index.js +12 -0
  200. package/dist/jsonForm/index.js.map +1 -0
  201. package/dist/jsonForm/inferSchema.d.ts +12 -0
  202. package/dist/jsonForm/inferSchema.d.ts.map +1 -0
  203. package/dist/jsonForm/inferSchema.js +15 -0
  204. package/dist/jsonForm/inferSchema.js.map +1 -0
  205. package/dist/jsonForm/pointer.d.ts +26 -0
  206. package/dist/jsonForm/pointer.d.ts.map +1 -0
  207. package/dist/jsonForm/pointer.js +102 -0
  208. package/dist/jsonForm/pointer.js.map +1 -0
  209. package/dist/jsonForm/types.d.ts +120 -0
  210. package/dist/jsonForm/types.d.ts.map +1 -0
  211. package/dist/jsonForm/types.js +10 -0
  212. package/dist/jsonForm/types.js.map +1 -0
  213. package/dist/markdown/convert.d.ts +11 -1
  214. package/dist/markdown/convert.d.ts.map +1 -1
  215. package/dist/markdown/convert.js +135 -5
  216. package/dist/markdown/convert.js.map +1 -1
  217. package/dist/markdown/index.d.ts +1 -1
  218. package/dist/markdown/index.d.ts.map +1 -1
  219. package/dist/markdown/index.js +1 -1
  220. package/dist/markdown/index.js.map +1 -1
  221. package/dist/markdown/types.d.ts +17 -2
  222. package/dist/markdown/types.d.ts.map +1 -1
  223. package/dist/markdown/utils.d.ts +40 -0
  224. package/dist/markdown/utils.d.ts.map +1 -1
  225. package/dist/markdown/utils.js +155 -0
  226. package/dist/markdown/utils.js.map +1 -1
  227. package/dist/recommend/index.d.ts +16 -0
  228. package/dist/recommend/index.d.ts.map +1 -0
  229. package/dist/recommend/index.js +15 -0
  230. package/dist/recommend/index.js.map +1 -0
  231. package/dist/recommend/templates.d.ts +39 -0
  232. package/dist/recommend/templates.d.ts.map +1 -0
  233. package/dist/recommend/templates.js +235 -0
  234. package/dist/recommend/templates.js.map +1 -0
  235. package/dist/schemas/BlockTemplates.d.ts +46 -8
  236. package/dist/schemas/BlockTemplates.d.ts.map +1 -1
  237. package/dist/schemas/BlockTemplates.js +3 -3
  238. package/dist/schemas/BlockTemplates.js.map +1 -1
  239. package/dist/schemas/ImageEditDoc.d.ts +81 -0
  240. package/dist/schemas/ImageEditDoc.d.ts.map +1 -0
  241. package/dist/schemas/ImageEditDoc.js +20 -0
  242. package/dist/schemas/ImageEditDoc.js.map +1 -0
  243. package/dist/schemas/Theme.d.ts +70 -31
  244. package/dist/schemas/Theme.d.ts.map +1 -1
  245. package/dist/schemas/Theme.js +48 -16
  246. package/dist/schemas/Theme.js.map +1 -1
  247. package/dist/schemas/colorUtils.d.ts +51 -0
  248. package/dist/schemas/colorUtils.d.ts.map +1 -0
  249. package/dist/schemas/colorUtils.js +154 -0
  250. package/dist/schemas/colorUtils.js.map +1 -0
  251. package/dist/schemas/fontStacks.d.ts +57 -0
  252. package/dist/schemas/fontStacks.d.ts.map +1 -0
  253. package/dist/schemas/fontStacks.js +227 -0
  254. package/dist/schemas/fontStacks.js.map +1 -0
  255. package/dist/schemas/index.d.ts +5 -0
  256. package/dist/schemas/index.d.ts.map +1 -1
  257. package/dist/schemas/index.js +4 -0
  258. package/dist/schemas/index.js.map +1 -1
  259. package/dist/schemas/themeCompile.d.ts +45 -0
  260. package/dist/schemas/themeCompile.d.ts.map +1 -0
  261. package/dist/schemas/themeCompile.js +160 -0
  262. package/dist/schemas/themeCompile.js.map +1 -0
  263. package/dist/schemas/themeLibrary.d.ts +11 -15
  264. package/dist/schemas/themeLibrary.d.ts.map +1 -1
  265. package/dist/schemas/themeLibrary.js +18 -566
  266. package/dist/schemas/themeLibrary.js.map +1 -1
  267. package/dist/schemas/themeValidator.d.ts +26 -0
  268. package/dist/schemas/themeValidator.d.ts.map +1 -0
  269. package/dist/schemas/themeValidator.js +352 -0
  270. package/dist/schemas/themeValidator.js.map +1 -0
  271. package/dist/schemas/themes/bold.json +48 -0
  272. package/dist/schemas/themes/cinematic.json +54 -0
  273. package/dist/schemas/themes/documentary.json +49 -0
  274. package/dist/schemas/themes/gezellig.json +44 -0
  275. package/dist/schemas/themes/index.d.ts +26 -0
  276. package/dist/schemas/themes/index.d.ts.map +1 -0
  277. package/dist/schemas/themes/index.js +49 -0
  278. package/dist/schemas/themes/index.js.map +1 -0
  279. package/dist/schemas/themes/magazine.json +44 -0
  280. package/dist/schemas/themes/minimalist.json +45 -0
  281. package/dist/schemas/themes/morning-light.json +42 -0
  282. package/dist/schemas/themes/standard-dark.json +50 -0
  283. package/dist/schemas/themes/standard.json +42 -0
  284. package/dist/schemas/themes/tech-dark.json +48 -0
  285. package/dist/schemas/themes/warm-earth.json +50 -0
  286. package/dist/storage/ScopedContentContainer.d.ts +44 -0
  287. package/dist/storage/ScopedContentContainer.d.ts.map +1 -0
  288. package/dist/storage/ScopedContentContainer.js +94 -0
  289. package/dist/storage/ScopedContentContainer.js.map +1 -0
  290. package/dist/storage/index.d.ts +1 -0
  291. package/dist/storage/index.d.ts.map +1 -1
  292. package/dist/storage/index.js +1 -0
  293. package/dist/storage/index.js.map +1 -1
  294. package/dist/story/index.d.ts +53 -13
  295. package/dist/story/index.js +12 -4
  296. package/dist/themeLibrary-BHjJ0Qx6.d.ts +40 -0
  297. package/dist/{types-CkNttVSF.d.ts → types-BdZkdJ3z.d.ts} +17 -2
  298. package/dist/types-D98li1gV.d.ts +93 -0
  299. package/dist/versions/DocumentVersionManager.d.ts +31 -0
  300. package/dist/versions/DocumentVersionManager.d.ts.map +1 -0
  301. package/dist/versions/DocumentVersionManager.js +33 -0
  302. package/dist/versions/DocumentVersionManager.js.map +1 -0
  303. package/dist/versions/index.d.ts +29 -0
  304. package/dist/versions/index.d.ts.map +1 -0
  305. package/dist/versions/index.js +28 -0
  306. package/dist/versions/index.js.map +1 -0
  307. package/dist/versions/operations.d.ts +44 -0
  308. package/dist/versions/operations.d.ts.map +1 -0
  309. package/dist/versions/operations.js +190 -0
  310. package/dist/versions/operations.js.map +1 -0
  311. package/dist/versions/paths.d.ts +29 -0
  312. package/dist/versions/paths.d.ts.map +1 -0
  313. package/dist/versions/paths.js +66 -0
  314. package/dist/versions/paths.js.map +1 -0
  315. package/dist/versions/timestamp.d.ts +22 -0
  316. package/dist/versions/timestamp.d.ts.map +1 -0
  317. package/dist/versions/timestamp.js +44 -0
  318. package/dist/versions/timestamp.js.map +1 -0
  319. package/dist/versions/types.d.ts +92 -0
  320. package/dist/versions/types.d.ts.map +1 -0
  321. package/dist/versions/types.js +11 -0
  322. package/dist/versions/types.js.map +1 -0
  323. package/package.json +28 -1
  324. package/src/__tests__/colorUtils.test.ts +112 -0
  325. package/src/__tests__/getLayers.test.ts +32 -7
  326. package/src/__tests__/iconResolve.test.ts +122 -0
  327. package/src/__tests__/imageEditState.test.ts +74 -0
  328. package/src/__tests__/imageEditVersions.test.ts +169 -0
  329. package/src/__tests__/inferDocumentTitle.test.ts +50 -0
  330. package/src/__tests__/jsonForm.chooseControl.test.ts +86 -0
  331. package/src/__tests__/jsonForm.evaluateWhen.test.ts +59 -0
  332. package/src/__tests__/jsonForm.inferSchema.test.ts +25 -0
  333. package/src/__tests__/jsonForm.pointer.test.ts +103 -0
  334. package/src/__tests__/markdownIcons.test.ts +104 -0
  335. package/src/__tests__/markdownToDoc.test.ts +19 -4
  336. package/src/__tests__/recommendTemplates.test.ts +183 -0
  337. package/src/__tests__/scopedContentContainer.test.ts +89 -0
  338. package/src/__tests__/slideshowGenerator.test.ts +1 -1
  339. package/src/__tests__/templateAnnotationParse.test.ts +42 -0
  340. package/src/__tests__/templates.test.ts +93 -9
  341. package/src/__tests__/themeCompile.test.ts +156 -0
  342. package/src/__tests__/themeValidator.test.ts +125 -0
  343. package/src/__tests__/versions.test.ts +415 -0
  344. package/src/doc/audioMapping.ts +55 -11
  345. package/src/doc/getLayers.ts +32 -21
  346. package/src/doc/markdownToDoc.ts +45 -7
  347. package/src/doc/templates/featureBlock.ts +202 -0
  348. package/src/doc/templates/fullBleedQuote.ts +13 -0
  349. package/src/doc/templates/index.ts +50 -16
  350. package/src/doc/templates/listBlock.ts +24 -5
  351. package/src/doc/templates/statHighlight.ts +13 -0
  352. package/src/doc/templates/titleBlock.ts +9 -0
  353. package/src/doc/utils/themeUtils.ts +8 -7
  354. package/src/generate/slideshowGenerator.ts +1 -1
  355. package/src/generate/templateMapper.ts +2 -2
  356. package/src/icons/iconData.ts +31 -0
  357. package/src/icons/index.ts +18 -0
  358. package/src/icons/resolve.ts +139 -0
  359. package/src/imageEdit/ImageEditVersionManager.ts +73 -0
  360. package/src/imageEdit/export.ts +326 -0
  361. package/src/imageEdit/index.ts +71 -0
  362. package/src/imageEdit/persistence.ts +62 -0
  363. package/src/imageEdit/state.ts +112 -0
  364. package/src/imageEdit/versionPaths.ts +57 -0
  365. package/src/imageEdit/versions.ts +231 -0
  366. package/src/index.ts +4 -0
  367. package/src/jsonForm/chooseControl.ts +88 -0
  368. package/src/jsonForm/evaluateWhen.ts +59 -0
  369. package/src/jsonForm/index.ts +22 -0
  370. package/src/jsonForm/inferSchema.ts +25 -0
  371. package/src/jsonForm/pointer.ts +109 -0
  372. package/src/jsonForm/types.ts +167 -0
  373. package/src/markdown/convert.ts +145 -5
  374. package/src/markdown/index.ts +3 -0
  375. package/src/markdown/types.ts +19 -2
  376. package/src/markdown/utils.ts +159 -0
  377. package/src/recommend/index.ts +16 -0
  378. package/src/recommend/templates.ts +273 -0
  379. package/src/schemas/BlockTemplates.ts +50 -7
  380. package/src/schemas/ImageEditDoc.ts +95 -0
  381. package/src/schemas/Theme.ts +98 -31
  382. package/src/schemas/colorUtils.ts +186 -0
  383. package/src/schemas/fontStacks.ts +257 -0
  384. package/src/schemas/index.ts +12 -0
  385. package/src/schemas/themeCompile.ts +203 -0
  386. package/src/schemas/themeLibrary.ts +18 -597
  387. package/src/schemas/themeValidator.ts +388 -0
  388. package/src/schemas/themes/bold.json +48 -0
  389. package/src/schemas/themes/cinematic.json +54 -0
  390. package/src/schemas/themes/documentary.json +49 -0
  391. package/src/schemas/themes/gezellig.json +44 -0
  392. package/src/schemas/themes/index.ts +53 -0
  393. package/src/schemas/themes/magazine.json +44 -0
  394. package/src/schemas/themes/minimalist.json +45 -0
  395. package/src/schemas/themes/morning-light.json +42 -0
  396. package/src/schemas/themes/standard-dark.json +50 -0
  397. package/src/schemas/themes/standard.json +42 -0
  398. package/src/schemas/themes/tech-dark.json +48 -0
  399. package/src/schemas/themes/warm-earth.json +50 -0
  400. package/src/storage/ScopedContentContainer.ts +113 -0
  401. package/src/storage/index.ts +1 -0
  402. package/src/versions/DocumentVersionManager.ts +70 -0
  403. package/src/versions/index.ts +54 -0
  404. package/src/versions/operations.ts +230 -0
  405. package/src/versions/paths.ts +66 -0
  406. package/src/versions/timestamp.ts +48 -0
  407. package/src/versions/types.ts +91 -0
  408. package/dist/chunk-6BAVXFYC.js.map +0 -1
  409. package/dist/chunk-7GF6RDED.js +0 -82
  410. package/dist/chunk-7GF6RDED.js.map +0 -1
  411. package/dist/chunk-CYQHG27J.js.map +0 -1
  412. package/dist/chunk-F22AE6BY.js +0 -121
  413. package/dist/chunk-F22AE6BY.js.map +0 -1
  414. package/dist/chunk-FIQR4AJG.js +0 -517
  415. package/dist/chunk-FIQR4AJG.js.map +0 -1
  416. package/dist/chunk-OASJKWO5.js.map +0 -1
  417. package/dist/chunk-QM5PKNPW.js.map +0 -1
  418. package/dist/chunk-TSG2OSE6.js.map +0 -1
  419. package/dist/themeLibrary-CEo2D4b6.d.ts +0 -44
@@ -3,25 +3,41 @@
3
3
  *
4
4
  * A Theme bundles color palette, typography, visual style, render-style
5
5
  * algorithm, and per-block color schemes into one JSON-serializable object.
6
- * Builders choose a theme from the built-in library or create a custom one
7
- * via `createTheme(base, overrides)`.
6
+ *
7
+ * Built-in themes and customizer-authored themes share this exact schema.
8
+ * Customizer-authored themes additionally specify `seedColors` so the few
9
+ * fields the user picked can be re-edited later; built-ins typically omit
10
+ * `seedColors` and ship with explicit `colors` already filled in.
8
11
  *
9
12
  * Design principles:
10
- * - Fully JSON-serializable (no functions) storable in config / APIs.
11
- * - Doc carries an optional `themeId` pointer; resolution happens at render time.
12
- * - `createTheme` deep-merges a base theme with partial overrides.
13
+ * - Fully JSON-serializable. No functions; no raw CSS font strings.
14
+ * - Font families are structured `FontFamily` references resolved by
15
+ * `resolveFontFamily()` at render time.
16
+ * - Doc carries an optional `themeId`; resolution happens at render time
17
+ * via `resolveTheme(id)`.
18
+ * - `createTheme` deep-merges a base theme with partial overrides;
19
+ * `compileTheme` fills in defaults and derives missing color slots from
20
+ * `seedColors`; both produce a complete `Theme`.
13
21
  */
14
22
 
15
23
  import type { LayoutHints } from './LayoutStrategy.js';
16
24
  import type { AnimationType, TransitionType } from './Doc.js';
17
25
  import type { PersistentLayerConfig } from './BlockTemplates.js';
18
26
 
27
+ // ============================================
28
+ // Schema version
29
+ // ============================================
30
+
31
+ /** Current Theme schema version. Bump on breaking changes; loader migrates. */
32
+ export const THEME_SCHEMA_VERSION = '1' as const;
33
+ export type ThemeSchemaVersion = typeof THEME_SCHEMA_VERSION;
34
+
19
35
  // ============================================
20
36
  // Color Palette
21
37
  // ============================================
22
38
 
23
39
  /**
24
- * Core color palette for a theme. Every color is a CSS color string.
40
+ * Core color palette for a theme. Every color is a `#rrggbb` hex string.
25
41
  */
26
42
  export interface ThemeColorPalette {
27
43
  /** Primary accent color */
@@ -55,20 +71,51 @@ export interface ThemeColorScheme {
55
71
  accent: string;
56
72
  }
57
73
 
74
+ /**
75
+ * Optional authoring metadata. When present and `colors` is partial,
76
+ * `compileTheme` derives missing color slots from these seeds via OKLCh
77
+ * lightening / darkening. Round-trips a customizer-authored theme back
78
+ * into editable form.
79
+ */
80
+ export interface ThemeSeedColors {
81
+ primary: string;
82
+ secondary?: string;
83
+ accent?: string;
84
+ background?: string;
85
+ text?: string;
86
+ }
87
+
58
88
  // ============================================
59
89
  // Typography
60
90
  // ============================================
61
91
 
92
+ /** Categorical bucket for a font family — drives default fallback. */
93
+ export type FontFamilyKind = 'sans' | 'serif' | 'mono' | 'display';
94
+
95
+ /**
96
+ * Structured reference to a font family. Either a curated stack id (looked
97
+ * up in `AVAILABLE_FONT_STACKS`) or a custom user-supplied name with a
98
+ * structured fallback bucket. Themes never carry raw CSS family strings.
99
+ */
100
+ export type FontFamily =
101
+ | { stackId: string }
102
+ | {
103
+ custom: {
104
+ name: string;
105
+ fallback: 'serif' | 'sans-serif' | 'monospace' | 'system-ui';
106
+ };
107
+ };
108
+
62
109
  /**
63
110
  * Typography settings for a theme.
64
111
  */
65
112
  export interface ThemeTypography {
66
113
  /** Font family for body / description text */
67
- bodyFontFamily: string;
114
+ bodyFont: FontFamily;
68
115
  /** Font family for titles and headings */
69
- titleFontFamily: string;
116
+ titleFont: FontFamily;
70
117
  /** Font family for code / monospaced text (optional) */
71
- monoFontFamily?: string;
118
+ monoFont?: FontFamily;
72
119
  /** Multiplier applied to LayoutHints.titleScale (default 1.0) */
73
120
  titleScale?: number;
74
121
  /** Multiplier applied to LayoutHints.bodyScale (default 1.0) */
@@ -125,11 +172,8 @@ export interface RenderStyle {
125
172
  /**
126
173
  * Per-template behavioral hints. Keys are template names, values are
127
174
  * string/number/boolean maps that templates can read to vary their output.
128
- *
129
- * @example
130
- * ```
131
- * { statHighlight: { entrance: 'dramatic' }, titleBlock: { showAccentLine: false } }
132
- * ```
175
+ * Templates that consume hints publish a `hintSchema` export documenting
176
+ * the keys they recognise.
133
177
  */
134
178
  templateHints?: Record<string, Record<string, string | number | boolean>>;
135
179
  }
@@ -139,15 +183,20 @@ export interface RenderStyle {
139
183
  // ============================================
140
184
 
141
185
  /**
142
- * A complete, JSON-serializable theme definition.
186
+ * A complete, JSON-serializable theme definition. Built-in and customizer-
187
+ * authored themes share this exact shape.
143
188
  */
144
189
  export interface Theme {
190
+ /** Schema version. Always '1' for now. */
191
+ schemaVersion: ThemeSchemaVersion;
145
192
  /** Unique identifier (e.g. "documentary") */
146
193
  id: string;
147
194
  /** Human-readable display name */
148
195
  name: string;
149
196
  /** Short description for theme pickers */
150
197
  description?: string;
198
+ /** Optional authoring seeds (customizer fills these; built-ins typically omit) */
199
+ seedColors?: ThemeSeedColors;
151
200
  /** Color palette */
152
201
  colors: ThemeColorPalette;
153
202
  /** Typography settings */
@@ -214,14 +263,6 @@ function deepMerge<T extends Record<string, unknown>>(target: T, source: DeepPar
214
263
  * Create a new theme by deep-merging overrides onto a base theme.
215
264
  * The returned theme gets its own `id` if one is provided in overrides,
216
265
  * otherwise keeps the base theme's `id` suffixed with "-custom".
217
- *
218
- * @example
219
- * ```ts
220
- * const myTheme = createTheme(THEMES.documentary, {
221
- * colors: { primary: '#ff0000' },
222
- * typography: { bodyFontFamily: '"Inter", sans-serif' },
223
- * });
224
- * ```
225
266
  */
226
267
  export function createTheme(base: Theme, overrides: DeepPartial<Theme>): Theme {
227
268
  const merged = deepMerge(
@@ -231,6 +272,7 @@ export function createTheme(base: Theme, overrides: DeepPartial<Theme>): Theme {
231
272
  if (!overrides.id && merged.id === base.id) {
232
273
  merged.id = `${base.id}-custom`;
233
274
  }
275
+ if (!merged.schemaVersion) merged.schemaVersion = THEME_SCHEMA_VERSION;
234
276
  return merged;
235
277
  }
236
278
 
@@ -243,11 +285,6 @@ export function createTheme(base: Theme, overrides: DeepPartial<Theme>): Theme {
243
285
  * identity of a Theme. A Theme chooses voice (serif vs sans, muted vs
244
286
  * bold, documentary vs magazine); a SurfaceScheme chooses what the paper
245
287
  * looks like. Any theme can render on either surface.
246
- *
247
- * When a SurfaceScheme is applied to a Theme (via `applySurface`), these
248
- * fields override the corresponding entries in `ThemeColorPalette` —
249
- * everything else (primary, highlight, warning, etc.) stays as the theme
250
- * defined it.
251
288
  */
252
289
  export interface SurfaceScheme {
253
290
  /** Identifier — 'light', 'dark', or a custom id. */
@@ -279,9 +316,7 @@ export const DARK_SURFACE: SurfaceScheme = {
279
316
  /**
280
317
  * Overlay a SurfaceScheme's surface colors onto a Theme's palette,
281
318
  * leaving everything else (primary, highlight, warning, typography,
282
- * style, renderStyle, colorSchemes) untouched. Returns a new Theme;
283
- * callers that want to preserve the original's id should set it
284
- * explicitly in the overrides.
319
+ * style, renderStyle, colorSchemes) untouched.
285
320
  */
286
321
  export function applySurface(theme: Theme, surface: SurfaceScheme): Theme {
287
322
  return {
@@ -295,3 +330,35 @@ export function applySurface(theme: Theme, surface: SurfaceScheme): Theme {
295
330
  },
296
331
  };
297
332
  }
333
+
334
+ // ============================================
335
+ // Runtime registry — for custom themes
336
+ // ============================================
337
+
338
+ const CUSTOM_THEME_REGISTRY = new Map<string, Theme>();
339
+
340
+ /**
341
+ * Register a Theme so it can be looked up by id via `resolveTheme(id)`.
342
+ * Lets `Doc.themeId` round-trip through Doc serialization for custom themes.
343
+ *
344
+ * Registered themes take precedence over built-ins with the same id.
345
+ */
346
+ export function registerTheme(theme: Theme): void {
347
+ CUSTOM_THEME_REGISTRY.set(theme.id, theme);
348
+ }
349
+
350
+ /** Remove a previously registered theme. */
351
+ export function unregisterTheme(id: string): void {
352
+ CUSTOM_THEME_REGISTRY.delete(id);
353
+ }
354
+
355
+ /** Snapshot of all currently registered (non-built-in) themes. */
356
+ export function getRegisteredThemes(): Theme[] {
357
+ return Array.from(CUSTOM_THEME_REGISTRY.values());
358
+ }
359
+
360
+ /** @internal — used by themeLibrary's `resolveTheme` to check the registry first. */
361
+ export function lookupRegisteredTheme(id: string | undefined): Theme | undefined {
362
+ if (!id) return undefined;
363
+ return CUSTOM_THEME_REGISTRY.get(id);
364
+ }
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Color Utilities
3
+ *
4
+ * Pure-JS color math used by theme compilation and contrast checks.
5
+ * No dependencies. Operates on `#rrggbb` hex strings.
6
+ *
7
+ * Internally uses OKLCh — perceptually uniform, so lightening by 0.1
8
+ * looks like the same change at any starting point. Out-of-gamut
9
+ * results are clamped to sRGB.
10
+ */
11
+
12
+ const HEX_RE = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
13
+
14
+ /** Test whether a string is a valid `#rgb` or `#rrggbb` hex color. */
15
+ export function isHex(value: string): boolean {
16
+ return HEX_RE.test(value);
17
+ }
18
+
19
+ /** Parse `#rgb` or `#rrggbb` into 0..1 sRGB triplet. Returns null on failure. */
20
+ function parseHex(hex: string): [number, number, number] | null {
21
+ if (!HEX_RE.test(hex)) return null;
22
+ let body = hex.slice(1);
23
+ if (body.length === 3)
24
+ body = body
25
+ .split('')
26
+ .map((c) => c + c)
27
+ .join('');
28
+ return [
29
+ parseInt(body.slice(0, 2), 16) / 255,
30
+ parseInt(body.slice(2, 4), 16) / 255,
31
+ parseInt(body.slice(4, 6), 16) / 255,
32
+ ];
33
+ }
34
+
35
+ function toHex(rgb: [number, number, number]): string {
36
+ const ch = (v: number) => {
37
+ const c = Math.max(0, Math.min(255, Math.round(v * 255)));
38
+ return c.toString(16).padStart(2, '0');
39
+ };
40
+ return '#' + ch(rgb[0]) + ch(rgb[1]) + ch(rgb[2]);
41
+ }
42
+
43
+ function srgbToLinear(c: number): number {
44
+ return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
45
+ }
46
+
47
+ function linearToSrgb(c: number): number {
48
+ return c <= 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
49
+ }
50
+
51
+ interface OKLCh {
52
+ L: number;
53
+ C: number;
54
+ h: number;
55
+ }
56
+
57
+ function rgbToOklch(rgb: [number, number, number]): OKLCh {
58
+ const [sr, sg, sb] = rgb;
59
+ const r = srgbToLinear(sr);
60
+ const g = srgbToLinear(sg);
61
+ const b = srgbToLinear(sb);
62
+
63
+ const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
64
+ const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
65
+ const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
66
+
67
+ const l_ = Math.cbrt(l);
68
+ const m_ = Math.cbrt(m);
69
+ const s_ = Math.cbrt(s);
70
+
71
+ const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
72
+ const a = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
73
+ const bb = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
74
+
75
+ const C = Math.sqrt(a * a + bb * bb);
76
+ let h = (Math.atan2(bb, a) * 180) / Math.PI;
77
+ if (h < 0) h += 360;
78
+ return { L, C, h };
79
+ }
80
+
81
+ function oklchToRgb({ L, C, h }: OKLCh): [number, number, number] {
82
+ const hr = (h * Math.PI) / 180;
83
+ const a = C * Math.cos(hr);
84
+ const bb = C * Math.sin(hr);
85
+
86
+ const l_ = L + 0.3963377774 * a + 0.2158037573 * bb;
87
+ const m_ = L - 0.1055613458 * a - 0.0638541728 * bb;
88
+ const s_ = L - 0.0894841775 * a - 1.291485548 * bb;
89
+
90
+ const l = l_ * l_ * l_;
91
+ const m = m_ * m_ * m_;
92
+ const s = s_ * s_ * s_;
93
+
94
+ const r = +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
95
+ const g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
96
+ const b = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;
97
+
98
+ return [
99
+ Math.max(0, Math.min(1, linearToSrgb(r))),
100
+ Math.max(0, Math.min(1, linearToSrgb(g))),
101
+ Math.max(0, Math.min(1, linearToSrgb(b))),
102
+ ];
103
+ }
104
+
105
+ /**
106
+ * Lighten a color by `amount` (0..1) in OKLCh L space.
107
+ * Falls back to the input on parse failure.
108
+ */
109
+ export function oklchLighten(hex: string, amount: number): string {
110
+ const rgb = parseHex(hex);
111
+ if (!rgb) return hex;
112
+ const lch = rgbToOklch(rgb);
113
+ lch.L = Math.max(0, Math.min(1, lch.L + amount));
114
+ return toHex(oklchToRgb(lch));
115
+ }
116
+
117
+ /**
118
+ * Darken a color by `amount` (0..1) in OKLCh L space.
119
+ * Falls back to the input on parse failure.
120
+ */
121
+ export function oklchDarken(hex: string, amount: number): string {
122
+ return oklchLighten(hex, -amount);
123
+ }
124
+
125
+ /**
126
+ * Adjust the OKLCh chroma of a color by a multiplier (e.g. 0.7 to mute).
127
+ */
128
+ export function oklchSetChroma(hex: string, multiplier: number): string {
129
+ const rgb = parseHex(hex);
130
+ if (!rgb) return hex;
131
+ const lch = rgbToOklch(rgb);
132
+ lch.C = Math.max(0, lch.C * multiplier);
133
+ return toHex(oklchToRgb(lch));
134
+ }
135
+
136
+ /**
137
+ * WCAG relative luminance of a hex color, returned as 0..1.
138
+ */
139
+ export function relativeLuminance(hex: string): number {
140
+ const rgb = parseHex(hex);
141
+ if (!rgb) return 0;
142
+ const [r, g, b] = rgb.map(srgbToLinear) as [number, number, number];
143
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
144
+ }
145
+
146
+ /**
147
+ * WCAG contrast ratio between two hex colors. Returns 1..21.
148
+ */
149
+ export function contrastRatio(a: string, b: string): number {
150
+ const la = relativeLuminance(a);
151
+ const lb = relativeLuminance(b);
152
+ const lighter = Math.max(la, lb);
153
+ const darker = Math.min(la, lb);
154
+ return (lighter + 0.05) / (darker + 0.05);
155
+ }
156
+
157
+ /**
158
+ * Pick a near-white or near-black text color that contrasts well against `bg`.
159
+ */
160
+ export function pickContrastingText(bg: string, light = '#f7fafc', dark = '#1a202c'): string {
161
+ return contrastRatio(bg, dark) >= contrastRatio(bg, light) ? dark : light;
162
+ }
163
+
164
+ /**
165
+ * Derive a 5-step lighter→darker scale from a seed color.
166
+ * Stops are evenly spaced in OKLCh L space around the seed.
167
+ * `spread` controls amplitude (0.05 = subtle, 0.15 = balanced, 0.22 = high).
168
+ */
169
+ export function deriveScale(
170
+ seedHex: string,
171
+ spread = 0.15,
172
+ ): {
173
+ lighter2: string;
174
+ lighter1: string;
175
+ base: string;
176
+ darker1: string;
177
+ darker2: string;
178
+ } {
179
+ return {
180
+ lighter2: oklchLighten(seedHex, spread),
181
+ lighter1: oklchLighten(seedHex, spread / 2),
182
+ base: seedHex,
183
+ darker1: oklchDarken(seedHex, spread / 2),
184
+ darker2: oklchDarken(seedHex, spread),
185
+ };
186
+ }
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Font Stacks
3
+ *
4
+ * Curated registry of font families used by built-in themes and offered in
5
+ * the theme customizer. Each stack has a stable `id` (referenced by JSON
6
+ * theme files via `{ stackId }`) and a CSS `family` string that resolves
7
+ * to the actual font when rendered.
8
+ *
9
+ * Themes never carry raw CSS font strings — they reference a `stackId` or
10
+ * specify a `{ custom: { name, fallback } }` form, both of which resolve
11
+ * here at render time.
12
+ */
13
+
14
+ import type { FontFamily, FontFamilyKind } from './Theme.js';
15
+
16
+ export interface FontStack {
17
+ /** Stable identifier referenced by Theme JSON. */
18
+ id: string;
19
+ /** Display label for pickers. */
20
+ label: string;
21
+ /** Full CSS font-family string with safe fallbacks. */
22
+ family: string;
23
+ /** Categorical bucket for the picker UI. */
24
+ kind: FontFamilyKind;
25
+ /**
26
+ * Google Fonts family name, when this stack is served by Google Fonts.
27
+ * Used by exports that bundle a `<link>` to fonts.googleapis.com so the
28
+ * face renders correctly even when the host page doesn't preload it.
29
+ * Omit (or set to undefined) for purely system stacks.
30
+ */
31
+ googleFontFamily?: string;
32
+ }
33
+
34
+ /** All curated stacks, in the order they should appear in pickers. */
35
+ export const AVAILABLE_FONT_STACKS: FontStack[] = [
36
+ // System defaults
37
+ {
38
+ id: 'system-sans',
39
+ label: 'System Sans',
40
+ family: 'system-ui, -apple-system, "Segoe UI", Roboto, sans-serif',
41
+ kind: 'sans',
42
+ },
43
+ {
44
+ id: 'system-serif',
45
+ label: 'System Serif',
46
+ family: 'Georgia, "Times New Roman", serif',
47
+ kind: 'serif',
48
+ },
49
+ {
50
+ id: 'system-mono',
51
+ label: 'System Mono',
52
+ family: 'Consolas, "Courier New", monospace',
53
+ kind: 'mono',
54
+ },
55
+ // Curated Google Fonts. `googleFontFamily` is the canonical family
56
+ // name Google serves the face under (used by exports that emit a
57
+ // `<link rel="stylesheet" href="https://fonts.googleapis.com/...">`
58
+ // so the face renders even when the host doesn't preload it).
59
+ {
60
+ id: 'inter',
61
+ label: 'Inter',
62
+ family: '"Inter", "Segoe UI", Roboto, sans-serif',
63
+ kind: 'sans',
64
+ googleFontFamily: 'Inter',
65
+ },
66
+ {
67
+ id: 'ibm-plex-sans',
68
+ label: 'IBM Plex Sans',
69
+ family: '"IBM Plex Sans", "Segoe UI", Roboto, sans-serif',
70
+ kind: 'sans',
71
+ googleFontFamily: 'IBM Plex Sans',
72
+ },
73
+ {
74
+ id: 'roboto',
75
+ label: 'Roboto',
76
+ family: '"Roboto", "Segoe UI", Arial, sans-serif',
77
+ kind: 'sans',
78
+ googleFontFamily: 'Roboto',
79
+ },
80
+ {
81
+ id: 'dm-sans',
82
+ label: 'DM Sans',
83
+ family: '"DM Sans", "Segoe UI", Roboto, sans-serif',
84
+ kind: 'sans',
85
+ googleFontFamily: 'DM Sans',
86
+ },
87
+ {
88
+ id: 'oswald',
89
+ label: 'Oswald',
90
+ family: '"Oswald", Impact, "Arial Black", sans-serif',
91
+ kind: 'display',
92
+ googleFontFamily: 'Oswald',
93
+ },
94
+ {
95
+ id: 'playfair',
96
+ label: 'Playfair Display',
97
+ family: '"Playfair Display", Georgia, serif',
98
+ kind: 'serif',
99
+ googleFontFamily: 'Playfair Display',
100
+ },
101
+ {
102
+ id: 'source-serif',
103
+ label: 'Source Serif',
104
+ family: '"Source Serif 4", "PT Serif", Georgia, serif',
105
+ kind: 'serif',
106
+ googleFontFamily: 'Source Serif 4',
107
+ },
108
+ {
109
+ id: 'merriweather',
110
+ label: 'Merriweather',
111
+ family: '"Merriweather", Georgia, serif',
112
+ kind: 'serif',
113
+ googleFontFamily: 'Merriweather',
114
+ },
115
+ {
116
+ id: 'lora',
117
+ label: 'Lora',
118
+ family: '"Lora", "Merriweather", Georgia, serif',
119
+ kind: 'serif',
120
+ googleFontFamily: 'Lora',
121
+ },
122
+ {
123
+ id: 'pt-serif',
124
+ label: 'PT Serif',
125
+ family: '"PT Serif", Georgia, serif',
126
+ kind: 'serif',
127
+ googleFontFamily: 'PT Serif',
128
+ },
129
+ {
130
+ id: 'crimson',
131
+ label: 'Crimson Text',
132
+ family: '"Crimson Text", Georgia, serif',
133
+ kind: 'serif',
134
+ googleFontFamily: 'Crimson Text',
135
+ },
136
+ {
137
+ id: 'cormorant',
138
+ label: 'Cormorant Garamond',
139
+ family: '"Cormorant Garamond", Garamond, Georgia, serif',
140
+ kind: 'serif',
141
+ googleFontFamily: 'Cormorant Garamond',
142
+ },
143
+ {
144
+ id: 'dm-serif',
145
+ label: 'DM Serif Display',
146
+ family: '"DM Serif Display", Georgia, serif',
147
+ kind: 'display',
148
+ googleFontFamily: 'DM Serif Display',
149
+ },
150
+ {
151
+ id: 'jetbrains-mono',
152
+ label: 'JetBrains Mono',
153
+ family: '"JetBrains Mono", "Fira Code", Consolas, monospace',
154
+ kind: 'mono',
155
+ googleFontFamily: 'JetBrains Mono',
156
+ },
157
+ // Themed system stacks with emoji fallbacks (used by gezellig)
158
+ {
159
+ id: 'system-sans-emoji',
160
+ label: 'System Sans + Emoji',
161
+ family:
162
+ 'system-ui, -apple-system, "Segoe UI", Roboto, "OpenMoji Color", "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif',
163
+ kind: 'sans',
164
+ },
165
+ {
166
+ id: 'system-serif-emoji',
167
+ label: 'System Serif + Emoji',
168
+ family:
169
+ 'Georgia, "Times New Roman", "OpenMoji Color", "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", serif',
170
+ kind: 'serif',
171
+ },
172
+ ];
173
+
174
+ const STACKS_BY_ID: Record<string, FontStack> = Object.fromEntries(
175
+ AVAILABLE_FONT_STACKS.map((s) => [s.id, s]),
176
+ );
177
+
178
+ /** Look up a stack by id. Returns undefined if not registered. */
179
+ export function getFontStack(id: string): FontStack | undefined {
180
+ return STACKS_BY_ID[id];
181
+ }
182
+
183
+ /** Default fallback CSS family per kind, used when a custom font has no fallback specified. */
184
+ const FALLBACK_BY_KIND: Record<FontFamilyKind, string> = {
185
+ sans: 'system-ui, sans-serif',
186
+ serif: 'Georgia, serif',
187
+ mono: 'Consolas, monospace',
188
+ display: 'Impact, Arial, sans-serif',
189
+ };
190
+
191
+ /**
192
+ * Resolve a `FontFamily` reference (or legacy raw string) to a CSS family string.
193
+ * Used by `getThemeFont` at render time. Never returns an empty string —
194
+ * unrecognized stackIds fall back to the requested role's default.
195
+ */
196
+ export function resolveFontFamily(
197
+ family: FontFamily | string | undefined,
198
+ roleFallback: string,
199
+ ): string {
200
+ if (!family) return roleFallback;
201
+ if (typeof family === 'string') return family;
202
+ if ('stackId' in family) {
203
+ const stack = STACKS_BY_ID[family.stackId];
204
+ return stack ? stack.family : roleFallback;
205
+ }
206
+ if ('custom' in family) {
207
+ const { name, fallback } = family.custom;
208
+ const fb =
209
+ fallback === 'system-ui'
210
+ ? 'system-ui, sans-serif'
211
+ : fallback === 'serif'
212
+ ? 'Georgia, serif'
213
+ : fallback === 'monospace'
214
+ ? 'Consolas, monospace'
215
+ : 'system-ui, sans-serif';
216
+ const safeName = name.includes(' ') || name.includes(',') ? `"${name}"` : name;
217
+ return `${safeName}, ${fb}`;
218
+ }
219
+ return roleFallback;
220
+ }
221
+
222
+ /** Convenience: quick `{ stackId }` factory for code that constructs themes. */
223
+ export function fontStack(id: string): FontFamily {
224
+ return { stackId: id };
225
+ }
226
+
227
+ /**
228
+ * Build a `https://fonts.googleapis.com/css2?...` URL that loads the
229
+ * subset of supplied `FontFamily` references that are served by Google
230
+ * Fonts. Returns `null` when nothing in the list needs Google hosting
231
+ * (system stacks, custom fonts, or unknown stack ids) — callers can use
232
+ * that to skip emitting a `<link>` entirely.
233
+ *
234
+ * The URL requests regular + bold (400/700) for each family, which is
235
+ * what the templates use. `display=swap` keeps the fallback visible
236
+ * while the web font streams in.
237
+ */
238
+ export function buildGoogleFontsUrl(families: Array<FontFamily | undefined>): string | null {
239
+ const names = new Set<string>();
240
+ for (const f of families) {
241
+ if (!f || typeof f === 'string') continue;
242
+ if ('stackId' in f) {
243
+ const stack = STACKS_BY_ID[f.stackId];
244
+ if (stack?.googleFontFamily) names.add(stack.googleFontFamily);
245
+ }
246
+ }
247
+ if (names.size === 0) return null;
248
+ // css2 syntax: ?family=Name+With+Spaces:wght@400;700&family=Other:wght@400;700&display=swap
249
+ const params = Array.from(names)
250
+ .sort()
251
+ .map((name) => `family=${encodeURIComponent(name).replace(/%20/g, '+')}:wght@400;700`)
252
+ .join('&');
253
+ return `https://fonts.googleapis.com/css2?${params}&display=swap`;
254
+ }
255
+
256
+ /** Default fallback families exposed for tools that need them. */
257
+ export const FONT_FALLBACKS = FALLBACK_BY_KIND;
@@ -3,6 +3,10 @@ export * from './Doc.js';
3
3
  export * from './BlockTemplates.js';
4
4
  export * from './Theme.js';
5
5
  export * from './themeLibrary.js';
6
+ export * from './themeValidator.js';
7
+ export * from './themeCompile.js';
8
+ export * from './fontStacks.js';
9
+ export * from './colorUtils.js';
6
10
  export * from './Viewport.js';
7
11
  export {
8
12
  getLayoutHints,
@@ -12,3 +16,11 @@ export {
12
16
  } from './LayoutStrategy.js';
13
17
  export type { LayoutHints } from './LayoutStrategy.js';
14
18
  export type { MediaProvider, MediaEntry } from './MediaProvider.js';
19
+ export type {
20
+ ImageEditDoc,
21
+ ImageEditLayer,
22
+ ImageEditLayerKind,
23
+ ImageEditCanvas,
24
+ ImageEditMeta,
25
+ EditorLayerMeta,
26
+ } from './ImageEditDoc.js';