@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,95 @@
1
+ /**
2
+ * ImageEditDoc — JSON document describing a layered, editable image.
3
+ *
4
+ * This is the persistent state of the `<ImageEditor>` component. It lives
5
+ * inside a `<imagebasename>_files/` sidecar folder (exposed as a
6
+ * {@link ContentContainer}) at `state.json`, alongside referenced asset
7
+ * bytes in `assets/` and version snapshots in `.versions/`.
8
+ *
9
+ * Layers compose the existing core {@link Layer} types (image / text /
10
+ * shape) so renderers can share infrastructure with the doc system.
11
+ * Editor-specific metadata (name, visibility, lock, opacity, blendMode)
12
+ * lives in {@link EditorLayerMeta} and is merged onto each layer. The
13
+ * {@link Layer.animation} field is permitted but ignored by the image
14
+ * editor — animations are a slideshow concept.
15
+ *
16
+ * All asset paths in layers (e.g. `ImageLayer.content.src`) are
17
+ * relative to the sidecar root, keeping the document portable.
18
+ */
19
+
20
+ import type { ImageLayer, ShapeLayer, TextLayer } from './Doc.js';
21
+
22
+ // ============================================
23
+ // Layer type
24
+ // ============================================
25
+
26
+ /**
27
+ * Per-layer editor metadata. Merged into each layer so the persisted
28
+ * shape is a single object. All fields optional; sensible defaults
29
+ * apply when absent (visible: true, locked: false, opacity: 1).
30
+ */
31
+ export interface EditorLayerMeta {
32
+ /** Human-readable name shown in the layers panel. */
33
+ name?: string;
34
+ /** When false, the layer is hidden from rendering. Default true. */
35
+ visible?: boolean;
36
+ /** When true, the layer cannot be selected/edited. Default false. */
37
+ locked?: boolean;
38
+ /** 0..1 multiplier on the layer's alpha. Default 1. */
39
+ opacity?: number;
40
+ /**
41
+ * Canvas blend mode (matches the CSS / Canvas2D vocabulary).
42
+ * Default 'source-over' (normal compositing).
43
+ */
44
+ blendMode?: GlobalCompositeOperation;
45
+ }
46
+
47
+ /** A layer in an {@link ImageEditDoc}. */
48
+ export type ImageEditLayer = (ImageLayer | TextLayer | ShapeLayer) & EditorLayerMeta;
49
+
50
+ /** The layer kinds the image editor supports. */
51
+ export type ImageEditLayerKind = ImageEditLayer['type'];
52
+
53
+ // ============================================
54
+ // Document
55
+ // ============================================
56
+
57
+ /** Canvas dimensions and background. */
58
+ export interface ImageEditCanvas {
59
+ /** Canvas width in pixels. */
60
+ width: number;
61
+ /** Canvas height in pixels. */
62
+ height: number;
63
+ /**
64
+ * Background fill (CSS color, or `'transparent'` for an alpha canvas).
65
+ * Default: `'transparent'`.
66
+ */
67
+ background?: string;
68
+ }
69
+
70
+ /** Optional document metadata. */
71
+ export interface ImageEditMeta {
72
+ /** Path to the original source image (sidecar-relative). Set when the doc is seeded from an existing image. */
73
+ sourcePath?: string;
74
+ /** ISO timestamp set on first save. */
75
+ createdAt?: string;
76
+ /** ISO timestamp updated on every save. */
77
+ updatedAt?: string;
78
+ }
79
+
80
+ /**
81
+ * The persisted image-editor document.
82
+ *
83
+ * Layers are composited back-to-front: `layers[0]` is the bottom of the stack
84
+ * (typically the base raster), `layers[layers.length - 1]` is the top.
85
+ */
86
+ export interface ImageEditDoc {
87
+ /** Schema version. Bumped on breaking changes. */
88
+ version: 1;
89
+ /** Canvas configuration. */
90
+ canvas: ImageEditCanvas;
91
+ /** Layers, back-to-front. */
92
+ layers: ImageEditLayer[];
93
+ /** Optional metadata. */
94
+ meta?: ImageEditMeta;
95
+ }
@@ -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,5 +272,93 @@ 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
  }
278
+
279
+ // ============================================
280
+ // Surface Schemes — orthogonal to Theme
281
+ // ============================================
282
+
283
+ /**
284
+ * A Surface Scheme is the light/dark axis, orthogonal to the editorial
285
+ * identity of a Theme. A Theme chooses voice (serif vs sans, muted vs
286
+ * bold, documentary vs magazine); a SurfaceScheme chooses what the paper
287
+ * looks like. Any theme can render on either surface.
288
+ */
289
+ export interface SurfaceScheme {
290
+ /** Identifier — 'light', 'dark', or a custom id. */
291
+ id: string;
292
+ background: string;
293
+ backgroundLight: string;
294
+ text: string;
295
+ textMuted: string;
296
+ }
297
+
298
+ /** Near-white paper with dark text — standard light mode. */
299
+ export const LIGHT_SURFACE: SurfaceScheme = {
300
+ id: 'light',
301
+ background: '#ffffff',
302
+ backgroundLight: '#f5f5f5',
303
+ text: '#1a1a1a',
304
+ textMuted: '#666666',
305
+ };
306
+
307
+ /** Dark charcoal paper with light text — standard dark mode. */
308
+ export const DARK_SURFACE: SurfaceScheme = {
309
+ id: 'dark',
310
+ background: '#1a202c',
311
+ backgroundLight: '#2d3748',
312
+ text: '#f0f0f0',
313
+ textMuted: '#a0aec0',
314
+ };
315
+
316
+ /**
317
+ * Overlay a SurfaceScheme's surface colors onto a Theme's palette,
318
+ * leaving everything else (primary, highlight, warning, typography,
319
+ * style, renderStyle, colorSchemes) untouched.
320
+ */
321
+ export function applySurface(theme: Theme, surface: SurfaceScheme): Theme {
322
+ return {
323
+ ...theme,
324
+ colors: {
325
+ ...theme.colors,
326
+ background: surface.background,
327
+ backgroundLight: surface.backgroundLight,
328
+ text: surface.text,
329
+ textMuted: surface.textMuted,
330
+ },
331
+ };
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
+ }