@panphora/clayjs 1.15.2 → 1.16.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 (506) hide show
  1. package/README.md +4 -5
  2. package/THIRD-PARTY-NOTICES.md +16 -0
  3. package/compat/highlight-11.9.0.min.js +1213 -0
  4. package/compat/highlight-LICENSE +29 -0
  5. package/compat/journal-assets.lock.json +22 -0
  6. package/compat/overtype-2.6.1.min.js +116 -0
  7. package/compat/overtype-LICENSE +21 -0
  8. package/dist/all.js +90 -0
  9. package/dist/clay-dom.js +84 -0
  10. package/dist/clay-events.js +103 -0
  11. package/dist/clay-internals.js +85 -0
  12. package/dist/clay-options.js +93 -0
  13. package/dist/clay-router.js +98 -0
  14. package/dist/clay-ui.js +95 -0
  15. package/dist/clay-utils.js +84 -0
  16. package/dist/clay.js +146 -0
  17. package/dist/clay.standalone.js +83090 -58706
  18. package/dist/m/attrs/add-from-T5LJXFFI.js +1 -0
  19. package/dist/m/attrs/onaftersave-OKSWEJQF.js +1 -0
  20. package/dist/m/attrs/refetch-on-save-NWPPXOCZ.js +1 -0
  21. package/dist/m/attrs/save-freeze-FUP4Q4X3.js +1 -0
  22. package/dist/m/c-2AZDZWCK.js +1 -0
  23. package/dist/m/c-2JL6E75N.js +1 -0
  24. package/dist/m/c-2M73252O.js +1 -0
  25. package/dist/m/c-2SPVQSHC.js +1 -0
  26. package/dist/m/c-33HUYEDI.js +1 -0
  27. package/dist/m/c-33JJ6CBX.js +2 -0
  28. package/dist/m/c-35NBGMZB.js +1 -0
  29. package/dist/m/c-3GJ4SDE2.js +1 -0
  30. package/dist/m/c-3IQRECYS.js +1 -0
  31. package/dist/m/c-3OWDMNJR.js +2 -0
  32. package/dist/m/c-46XYM55L.js +1 -0
  33. package/dist/m/c-4B6H4G5V.js +1 -0
  34. package/dist/m/c-4DRMS4QG.js +9 -0
  35. package/dist/m/c-4FFHZM32.js +1 -0
  36. package/dist/m/c-4JZDZFF6.js +1 -0
  37. package/dist/m/c-4L3BTFRK.js +1 -0
  38. package/dist/m/c-4Q2XTQ2N.js +2 -0
  39. package/dist/m/c-4WKFKEKF.js +1 -0
  40. package/dist/m/c-4YSCRICO.js +1 -0
  41. package/dist/m/c-54RCDCBU.js +1 -0
  42. package/dist/m/c-5M4YEKCX.js +4 -0
  43. package/dist/m/c-5R4PTRG2.js +1 -0
  44. package/dist/m/c-5V3MOVJT.js +1 -0
  45. package/dist/m/c-5VYOWDTI.js +1 -0
  46. package/dist/m/c-5Y6TNX5W.js +34 -0
  47. package/dist/m/c-5YIHJ3TJ.js +1 -0
  48. package/dist/m/c-66O32MV3.js +28 -0
  49. package/dist/m/c-6HMB24EV.js +1 -0
  50. package/dist/m/c-7DJDKPGL.js +1 -0
  51. package/dist/m/c-7O6AFR65.js +1 -0
  52. package/dist/m/c-7SWMYKAI.js +1 -0
  53. package/dist/m/c-7VGZ7RU5.js +1 -0
  54. package/dist/m/c-A7LS5UZW.js +1 -0
  55. package/dist/m/c-ANQTJ3B5.js +2 -0
  56. package/dist/m/c-AQLFEATB.js +1 -0
  57. package/dist/m/c-AYVOREBE.js +1 -0
  58. package/dist/m/c-B2ZXPOS3.js +3 -0
  59. package/dist/m/c-BBVGTQG7.js +1 -0
  60. package/dist/m/c-BMIZKMPV.js +1 -0
  61. package/dist/m/c-BTDI4Y23.js +1 -0
  62. package/dist/m/c-BWFVSBDF.js +1 -0
  63. package/dist/m/c-BYTKL6UX.js +1 -0
  64. package/dist/m/c-CFHW5AMY.js +6 -0
  65. package/dist/m/c-CJZSLMVQ.js +1 -0
  66. package/dist/m/c-CYWLPPUS.js +1 -0
  67. package/dist/m/c-CZUSOB7V.js +1 -0
  68. package/dist/m/c-DBE6ORSI.js +1 -0
  69. package/dist/m/c-DCFSEJZG.js +1 -0
  70. package/dist/m/c-DNZ5IFM6.js +1 -0
  71. package/dist/m/c-EDHUR4MX.js +1 -0
  72. package/dist/m/c-EJTGYSLN.js +1 -0
  73. package/dist/m/c-EY6UOM54.js +1 -0
  74. package/dist/m/c-F3CKJTJS.js +1 -0
  75. package/dist/m/c-F7Y6FLPY.js +1 -0
  76. package/dist/m/c-FA4DZVTC.js +1 -0
  77. package/dist/m/c-FILLTJA7.js +1 -0
  78. package/dist/m/c-G2BUZITR.js +1 -0
  79. package/dist/m/c-GB3JTV6E.js +1 -0
  80. package/dist/m/c-GBGWXTX4.js +1 -0
  81. package/dist/m/c-GHBCCVG4.js +1 -0
  82. package/dist/m/c-GJAEGGXY.js +1 -0
  83. package/dist/m/c-GOWBDM6J.js +1 -0
  84. package/dist/m/c-GQ6F6IDK.js +1 -0
  85. package/dist/m/c-H4LG442Q.js +1 -0
  86. package/dist/m/c-HA6INT6J.js +1 -0
  87. package/dist/m/c-HPURYVZS.js +2 -0
  88. package/dist/m/c-HRDCD3WN.js +67 -0
  89. package/dist/m/c-HT33EQRN.js +1 -0
  90. package/dist/m/c-HVYXIS72.js +1 -0
  91. package/dist/m/c-IB52R237.js +1 -0
  92. package/dist/m/c-IJUK2GPW.js +1 -0
  93. package/dist/m/c-IKWNE4R4.js +1 -0
  94. package/dist/m/c-IU3IYEU6.js +1 -0
  95. package/dist/m/c-IZ2EBRAJ.js +1 -0
  96. package/dist/m/c-J7CA54IP.js +1 -0
  97. package/dist/m/c-JAX2667S.js +6 -0
  98. package/dist/m/c-KI7M4AY3.js +1 -0
  99. package/dist/m/c-KIPQJX4B.js +1 -0
  100. package/dist/m/c-KKWLDOPM.js +1 -0
  101. package/dist/m/c-KR4UW4KW.js +1 -0
  102. package/dist/m/c-KY3VJGUA.js +8 -0
  103. package/dist/m/c-L4WQSC27.js +1 -0
  104. package/dist/m/c-LFPHCXY3.js +1 -0
  105. package/dist/m/c-LR4CGEPT.js +91 -0
  106. package/dist/m/c-LRPUO2MX.js +1 -0
  107. package/dist/m/c-LTGMXXKO.js +1 -0
  108. package/dist/m/c-LXENEBV7.js +1 -0
  109. package/dist/m/c-LZJPNR2W.js +1 -0
  110. package/dist/m/c-MMUIUUZG.js +2 -0
  111. package/dist/m/c-MTQHWQC3.js +1 -0
  112. package/dist/m/c-N326R2JD.js +1 -0
  113. package/dist/m/c-N7JPUPGC.js +1 -0
  114. package/dist/m/c-NMJRXKPC.js +8 -0
  115. package/dist/m/c-NRPJEVJS.js +1 -0
  116. package/dist/m/c-NUHP2XDB.js +1 -0
  117. package/dist/m/c-NZMNXVF6.js +1 -0
  118. package/dist/m/c-OCSZ4QGN.js +1 -0
  119. package/dist/m/c-OIBUTDXI.js +1 -0
  120. package/dist/m/c-OIDRZKAF.js +1 -0
  121. package/dist/m/c-OYTFP5QN.js +1 -0
  122. package/dist/m/c-P7KNDG34.js +1 -0
  123. package/dist/m/c-PPOSCAQD.js +1 -0
  124. package/dist/m/c-PQ5LK6QE.js +993 -0
  125. package/dist/m/c-PZ4XEPUP.js +2 -0
  126. package/dist/m/c-QHIWXHRO.js +1 -0
  127. package/dist/m/c-QHWJ5ZIJ.js +1 -0
  128. package/dist/m/c-QIX5BJYN.js +1 -0
  129. package/dist/m/c-QNKREOL6.js +1 -0
  130. package/dist/m/c-QQHEX6HA.js +1 -0
  131. package/dist/m/c-R7RMANJI.js +9 -0
  132. package/dist/m/c-RI4NT75Y.js +1 -0
  133. package/dist/m/c-RM7J7BV2.js +1 -0
  134. package/dist/m/c-RUJKSUQW.js +1 -0
  135. package/dist/m/c-RVMWGXEJ.js +1 -0
  136. package/dist/m/c-S7H2DRCB.js +1 -0
  137. package/dist/m/c-S7LK4KUE.js +1 -0
  138. package/dist/m/c-SGCCC4FW.js +25 -0
  139. package/dist/m/c-SGIA4IEQ.js +188 -0
  140. package/dist/m/c-SWRJFCNN.js +1 -0
  141. package/dist/m/c-T4VO4OCB.js +1 -0
  142. package/dist/m/c-TCCA5BZN.js +2 -0
  143. package/dist/m/c-TQEMVJCS.js +1 -0
  144. package/dist/m/c-TQZ2JYHD.js +1 -0
  145. package/dist/m/c-TR6RMDQ7.js +3 -0
  146. package/dist/m/c-TRS6TM6O.js +1 -0
  147. package/dist/m/c-UGHH4MB3.js +1 -0
  148. package/dist/m/c-UKHTLWUW.js +1 -0
  149. package/dist/m/c-UL2YUY52.js +1 -0
  150. package/dist/m/c-UNN7LWCT.js +1 -0
  151. package/dist/m/c-UXBMRDZB.js +235 -0
  152. package/dist/m/c-V7PZZRG7.js +1 -0
  153. package/dist/m/c-VAK7SG37.js +1 -0
  154. package/dist/m/c-VDSS4K3Z.js +1 -0
  155. package/dist/m/c-VFX45IZQ.js +1 -0
  156. package/dist/m/c-VHNSBD2M.js +1 -0
  157. package/dist/m/c-VKEDWYDF.js +1 -0
  158. package/dist/m/c-VL52ADDR.js +1 -0
  159. package/dist/m/c-WN5AY3OZ.js +1 -0
  160. package/dist/m/c-WNYBLIOZ.js +1 -0
  161. package/dist/m/c-WRBKEJD4.js +1 -0
  162. package/dist/m/c-WWDBYXLK.js +1 -0
  163. package/dist/m/c-WYFDLITL.js +1 -0
  164. package/dist/m/c-XN6MBKI6.js +67 -0
  165. package/dist/m/c-XNNW2CWK.js +1 -0
  166. package/dist/m/c-XPELB6E5.js +1 -0
  167. package/dist/m/c-XQXZAO7N.js +1 -0
  168. package/dist/m/c-Y6USGTS5.js +5 -0
  169. package/dist/m/c-YDH7Q3NY.js +1 -0
  170. package/dist/m/c-YG2NJYS6.js +135 -0
  171. package/dist/m/c-Z36J63PP.js +1 -0
  172. package/dist/m/c-Z4VRC7GU.js +7 -0
  173. package/dist/m/c-Z6K52OLP.js +19 -0
  174. package/dist/m/c-ZDY2MDAA.js +21 -0
  175. package/dist/m/c-ZE46QDIH.js +1 -0
  176. package/dist/m/c-ZUCOKOHT.js +1 -0
  177. package/dist/m/core/admin-attrs-VGNLAUDK.js +1 -0
  178. package/dist/m/core/autosave-E4PEFPZ6.js +1 -0
  179. package/dist/m/core/conflict-notice-VQ6Y64PH.js +1 -0
  180. package/dist/m/core/draft-mode-WSQAT67S.js +1 -0
  181. package/dist/m/core/host-permission-XN3K2IW3.js +1 -0
  182. package/dist/m/core/is-edit-mode-JXHDVGUL.js +1 -0
  183. package/dist/m/core/persist-HKHA66IY.js +3 -0
  184. package/dist/m/core/recovery-TBBSICE2.js +1 -0
  185. package/dist/m/core/save-WUCHTQBE.js +1 -0
  186. package/dist/m/core/save-core-FJVHT5M3.js +1 -0
  187. package/dist/m/core/snapshot-F3SWDZMM.js +1 -0
  188. package/dist/m/core/unsaved-warning-STKBHE6G.js +1 -0
  189. package/dist/m/dom/all-APS5ZSKP.js +1 -0
  190. package/dist/m/dom/dom-helpers-L7OSR6S4.js +1 -0
  191. package/dist/m/events/index-23DPTUT4.js +1 -0
  192. package/dist/m/internals/index-WOVAP3RU.js +1 -0
  193. package/dist/m/lib/cache-bust-CGWT6ZJI.js +1 -0
  194. package/dist/m/lib/region-policy-SB2AWVG5.js +1 -0
  195. package/dist/m/loader-HXX6YNH5.js +1 -0
  196. package/dist/m/manifest-F22DEDAC.js +1 -0
  197. package/dist/m/manifest-edit-C3C7376B.js +1 -0
  198. package/dist/m/manifest.json +3491 -0
  199. package/dist/m/options/options-2LH76JQ3.js +1 -0
  200. package/dist/m/page/editor-XUTB2HB2.js +189 -0
  201. package/dist/m/plugins/ai-edit-ZQ4CGWIP.js +6 -0
  202. package/dist/m/plugins/bind-text-NX46N5UV.js +1 -0
  203. package/dist/m/plugins/cms-HP3LSTPN.js +2293 -0
  204. package/dist/m/plugins/demo-ZIBFAA3R.js +1 -0
  205. package/dist/m/plugins/derive-UAAA4V4S.js +1 -0
  206. package/dist/m/plugins/indicator-PV4YW2ID.js +1 -0
  207. package/dist/m/plugins/live-NUTTXSBS.js +1 -0
  208. package/dist/m/plugins/menu-HCKO3DSP.js +138 -0
  209. package/dist/m/plugins/message-LQ6EDH4V.js +1 -0
  210. package/dist/m/plugins/page-KSUH7G6J.js +2 -0
  211. package/dist/m/plugins/page-view-W73OW7WI.js +1 -0
  212. package/dist/m/plugins/people-AJJ32YCG.js +1 -0
  213. package/dist/m/plugins/quickcrop-QNY3PKLD.js +26 -0
  214. package/dist/m/plugins/quickcrop-QNY3PKLD.js.LEGAL.txt +7 -0
  215. package/dist/m/plugins/richclay-RC3L2F6X.js +517 -0
  216. package/dist/m/plugins/richclay-RC3L2F6X.js.LEGAL.txt +1 -0
  217. package/dist/m/plugins/sortable-YRMQX3ZU.js +1 -0
  218. package/dist/m/plugins/source-KHK5UUSK.js +1 -0
  219. package/dist/m/plugins/undo-OF2L3CXU.js +1 -0
  220. package/dist/m/plugins/unsent-HJFLQJ2O.js +1 -0
  221. package/dist/m/plugins/upgrade-ZNYODP5Y.js +1 -0
  222. package/dist/m/plugins/upload-XSGNILUY.js +1 -0
  223. package/dist/m/plugins/visitor-drafts-XK5GW55Q.js +21 -0
  224. package/dist/m/plugins/visitor-drafts-owner-KSSH75EV.js +1 -0
  225. package/dist/m/plugins/wire-ZWVWKF76.js +1 -0
  226. package/dist/m/reader-core-ILWLXVMP.js +68 -0
  227. package/dist/m/route/route-KOCZSEGN.js +1 -0
  228. package/dist/m/sync/live-sync-4AUVXVJU.js +1 -0
  229. package/dist/m/ui/index-EVHKMKBL.js +1 -0
  230. package/dist/m/utils/index-4TJCVLT7.js +1 -0
  231. package/dist/m/vendor/Sortable.vendor-A755ITLN.js +3 -0
  232. package/dist/m/vendor/Sortable.vendor-A755ITLN.js.LEGAL.txt +1 -0
  233. package/dist/m/vendor/sap-core.vendor-A7BMUYZT.js +6 -0
  234. package/dist/offline-manifest.json +3800 -0
  235. package/dist/page/themes/light-1.css +406 -0
  236. package/dist/server/core.cjs +23662 -22860
  237. package/dist/server/offline-runtime.cjs +4954 -0
  238. package/dist/server/offline-runtime.mjs +4923 -0
  239. package/dist/server/rooms.mjs +9 -0
  240. package/docs/guide.md +1078 -669
  241. package/entries/all.js +2 -0
  242. package/entries/clay-data.js +1 -1
  243. package/entries/clay-dom.js +2 -0
  244. package/entries/clay-events.js +2 -0
  245. package/entries/clay-internals.js +2 -0
  246. package/entries/clay-options.js +2 -0
  247. package/entries/clay-router.js +2 -0
  248. package/entries/clay-ui.js +2 -0
  249. package/entries/clay-utils.js +2 -0
  250. package/entries/clay.js +2 -0
  251. package/entries/sap.js +6 -6
  252. package/fonts/ibm-plex-mono-LICENSE +93 -0
  253. package/fonts/ibm-plex-mono-latin-300-normal.woff2 +0 -0
  254. package/fonts/ibm-plex-mono-latin-400-italic.woff2 +0 -0
  255. package/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
  256. package/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
  257. package/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
  258. package/fonts/ibm-plex-sans-LICENSE +93 -0
  259. package/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
  260. package/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
  261. package/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
  262. package/fonts/ibm-plex.css +71 -0
  263. package/fonts/inter-LICENSE +93 -0
  264. package/fonts/inter-cyrillic-ext-wght-normal.woff2 +0 -0
  265. package/fonts/inter-cyrillic-wght-normal.woff2 +0 -0
  266. package/fonts/inter-greek-ext-wght-normal.woff2 +0 -0
  267. package/fonts/inter-greek-wght-normal.woff2 +0 -0
  268. package/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
  269. package/fonts/inter-latin-wght-normal.woff2 +0 -0
  270. package/fonts/inter-vietnamese-wght-normal.woff2 +0 -0
  271. package/fonts/inter.css +62 -0
  272. package/fonts/newsreader-LICENSE +93 -0
  273. package/fonts/newsreader-latin-ext-opsz-normal.woff2 +0 -0
  274. package/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
  275. package/fonts/newsreader-vietnamese-opsz-normal.woff2 +0 -0
  276. package/fonts/newsreader.css +26 -0
  277. package/fonts/work-sans-LICENSE +93 -0
  278. package/fonts/work-sans-latin-wght-normal.woff2 +0 -0
  279. package/fonts/work-sans.css +8 -0
  280. package/package.json +20 -3
  281. package/packed-contract.json +1 -0
  282. package/src/attrs/add-from.js +27 -4
  283. package/src/attrs/save-freeze.js +7 -52
  284. package/src/core/admin-attrs.js +119 -12
  285. package/src/core/admin-contenteditable.js +12 -10
  286. package/src/core/admin-inputs.js +14 -15
  287. package/src/core/admin-onclick.js +2 -0
  288. package/src/core/autosave.js +74 -21
  289. package/src/core/conflict-download.js +22 -0
  290. package/src/core/conflict-notice-ui.js +1173 -0
  291. package/src/core/conflict-notice.js +140 -697
  292. package/src/core/edit-mode.js +147 -14
  293. package/src/core/etag.js +30 -12
  294. package/src/core/host-meta.js +72 -8
  295. package/src/core/host-permission.js +29 -0
  296. package/src/core/is-edit-mode.js +145 -12
  297. package/src/core/mode-key.js +125 -0
  298. package/src/core/mode-lifecycle.js +544 -0
  299. package/src/core/mode-receipt.js +30 -0
  300. package/src/core/mode-refusal.js +13 -0
  301. package/src/core/mode-resources.js +52 -0
  302. package/src/core/mode-support.js +82 -0
  303. package/src/core/mode-switch.js +259 -0
  304. package/src/core/mode-transition.js +112 -0
  305. package/src/core/page-data-write.js +305 -0
  306. package/src/core/page-data.js +26 -227
  307. package/src/core/page-format-wire.js +4 -0
  308. package/src/core/page-format.js +58 -0
  309. package/src/core/persist.js +37 -9
  310. package/src/core/preserve-authored.js +114 -0
  311. package/src/core/recovery.js +772 -0
  312. package/src/core/runtime-url.js +105 -0
  313. package/src/core/save-core.js +109 -12
  314. package/src/core/save-replace.js +72 -0
  315. package/src/core/save-size-notice.js +134 -0
  316. package/src/core/save-size.js +140 -0
  317. package/src/core/save.js +805 -118
  318. package/src/core/snapshot.js +121 -11
  319. package/src/core/source-map.js +157 -9
  320. package/src/core/unsaved-warning.js +14 -4
  321. package/src/core/upgrade-run.js +408 -0
  322. package/src/core/version.js +18 -0
  323. package/src/lib/assets.js +30 -0
  324. package/src/lib/autosave-debug-gate.js +50 -0
  325. package/src/lib/autosave-scheduler.js +141 -0
  326. package/src/lib/boot-imports.js +8 -0
  327. package/src/lib/derived.js +3 -1
  328. package/src/lib/dirty-gate.js +15 -0
  329. package/src/lib/doc-storage.js +33 -0
  330. package/src/lib/effect.js +9 -4
  331. package/src/lib/mutation.js +4 -2
  332. package/src/lib/offline-runtime.js +226 -0
  333. package/src/lib/preload.js +48 -0
  334. package/src/lib/root-attrs.js +1 -1
  335. package/src/lib/trash.js +18 -0
  336. package/src/lib/undo/capture-move.js +152 -0
  337. package/src/live/local-channel.js +61 -0
  338. package/src/live/local-lane.js +60 -9
  339. package/src/live/server-lane.js +6 -3
  340. package/src/loader-logic.js +76 -15
  341. package/src/loader.js +218 -30
  342. package/src/page/adopt-boot.js +76 -22
  343. package/src/page/adopt.js +25 -4
  344. package/src/page/awareness.js +230 -0
  345. package/src/page/blocks.js +79 -5
  346. package/src/page/blocksel.js +20 -4
  347. package/src/page/board-face.js +13 -0
  348. package/src/page/board-panel.js +5 -17
  349. package/src/page/board-style.js +2 -13
  350. package/src/page/board-view.js +1 -11
  351. package/src/page/board-views.js +17 -0
  352. package/src/page/board.js +2 -2
  353. package/src/page/boot-pack.js +26 -0
  354. package/src/page/boot.js +237 -0
  355. package/src/page/checklist.js +1 -1
  356. package/src/page/chrome.js +411 -61
  357. package/src/page/csv-import.js +17 -2
  358. package/src/page/document-title-dom.js +40 -0
  359. package/src/page/document-title-runtime.js +76 -0
  360. package/src/page/document-title.js +9 -0
  361. package/src/page/drag.js +48 -13
  362. package/src/page/drop.js +2 -1
  363. package/src/page/editor.js +330 -86
  364. package/src/page/feature-loader.js +72 -0
  365. package/src/page/features/board.js +12 -0
  366. package/src/page/features/code.js +13 -0
  367. package/src/page/features/media.js +290 -0
  368. package/src/page/features/registry.js +23 -0
  369. package/src/page/features/table.js +383 -0
  370. package/src/page/{tool-view.js → features/tool.js} +33 -2
  371. package/src/page/format-codec.js +215 -0
  372. package/src/page/format-gate.js +179 -0
  373. package/src/page/format-level.js +157 -0
  374. package/src/page/highlight-slot.js +23 -0
  375. package/src/page/highlight.js +30 -16
  376. package/src/page/history-intent.js +78 -0
  377. package/src/page/inline.js +18 -25
  378. package/src/page/items.js +52 -11
  379. package/src/page/link.js +1 -0
  380. package/src/page/markdown.js +86 -1
  381. package/src/page/media-views.js +3 -0
  382. package/src/page/media.js +33 -245
  383. package/src/page/outline-cache.js +11 -0
  384. package/src/page/placeholder.js +27 -7
  385. package/src/page/projection.js +196 -50
  386. package/src/page/reader-patch.js +306 -0
  387. package/src/page/recover.js +1 -1
  388. package/src/page/rich/page-tool.js +1 -4
  389. package/src/page/runtime-owner.js +27 -0
  390. package/src/page/save-projection.js +7 -4
  391. package/src/page/schema.js +14 -0
  392. package/src/page/table-rect-key.js +3 -0
  393. package/src/page/table-select.js +4 -3
  394. package/src/page/table-style.js +1 -1
  395. package/src/page/table-views.js +3 -0
  396. package/src/page/table.js +8 -293
  397. package/src/page/themes/light-1.css +139 -2
  398. package/src/page/themes/light-1.source.css +269 -0
  399. package/src/page/tool-capability.js +3 -0
  400. package/src/page/tool-views.js +3 -0
  401. package/src/page/view.js +390 -107
  402. package/src/page/ybind/awareness.js +172 -0
  403. package/src/page/ybind/binding.js +9 -1
  404. package/src/page/ybind/bridge.js +50 -47
  405. package/src/page/ybind/decode.js +52 -19
  406. package/src/page/ybind/doc.js +27 -2
  407. package/src/page/ybind/group.js +12 -3
  408. package/src/page/ybind/index.js +2 -0
  409. package/src/page/ybind/lineage.js +71 -0
  410. package/src/page/ybind/marks.js +25 -1
  411. package/src/page/ybind/migrate.js +48 -13
  412. package/src/page/ybind/moves.js +32 -21
  413. package/src/page/ybind/positions.js +50 -0
  414. package/src/page/ybind/provider.js +84 -22
  415. package/src/page/ybind/recovery-proof.js +191 -0
  416. package/src/page/ybind/recovery-replay.js +130 -0
  417. package/src/page/ybind/tokens.js +15 -6
  418. package/src/page/ybind/walk.js +10 -3
  419. package/src/page/ybind/writer.js +48 -4
  420. package/src/plugins/ai-edit.js +167 -32
  421. package/src/plugins/bind-text.js +218 -0
  422. package/src/plugins/cms.js +93 -0
  423. package/src/plugins/indicator.js +57 -5
  424. package/src/plugins/live.js +282 -34
  425. package/src/plugins/menu/claygoo.svg.js +1 -0
  426. package/src/plugins/menu/seo-head.js +323 -0
  427. package/src/plugins/menu/seo.js +849 -0
  428. package/src/plugins/menu.js +425 -0
  429. package/src/plugins/page-view.js +131 -0
  430. package/src/plugins/page.js +1022 -275
  431. package/src/plugins/people.js +158 -31
  432. package/src/plugins/richclay.js +119 -9
  433. package/src/plugins/sortable.js +370 -60
  434. package/src/plugins/source.js +189 -366
  435. package/src/plugins/undo.js +289 -19
  436. package/src/plugins/unsent.js +132 -0
  437. package/src/plugins/upgrade-run.js +1 -0
  438. package/src/plugins/upgrade.js +210 -0
  439. package/src/plugins/upload-task.js +571 -0
  440. package/src/plugins/upload-ui.js +265 -0
  441. package/src/plugins/upload.js +34 -153
  442. package/src/plugins/visitor-drafts/inert.js +32 -0
  443. package/src/plugins/visitor-drafts/owner-chip.js +3 -0
  444. package/src/plugins/visitor-drafts/prompt.js +2 -2
  445. package/src/plugins/visitor-drafts-owner.js +85 -0
  446. package/src/plugins/visitor-drafts.js +31 -42
  447. package/src/plugins/wire.js +82 -1
  448. package/src/reader-core.js +26 -0
  449. package/src/recovery/conflicts.js +287 -0
  450. package/src/recovery/identity.js +154 -0
  451. package/src/recovery/store.js +792 -0
  452. package/src/recovery/undo.js +257 -0
  453. package/src/server/checkpoint/index.js +68 -4
  454. package/src/server/offline-runtime/index.js +214 -0
  455. package/src/server/rooms/index.js +2 -1
  456. package/src/server/rooms/live-data-rooms.js +2 -2
  457. package/src/server/rooms/page-admission.js +33 -0
  458. package/src/server/rooms/page-lineage.js +56 -0
  459. package/src/server/rooms/page-rebase.js +11 -5
  460. package/src/server/rooms/page-state.js +2 -0
  461. package/src/server/rooms/page-write-admission.js +9 -3
  462. package/src/source/session.js +705 -0
  463. package/src/sync/conflict-revert.js +5 -4
  464. package/src/sync/conflicts-edit.js +119 -0
  465. package/src/sync/conflicts-facade.js +49 -0
  466. package/src/sync/conflicts.js +99 -1
  467. package/src/sync/editing-marker.js +37 -6
  468. package/src/sync/editing-sender.js +8 -1
  469. package/src/sync/live-sync-edit.js +63 -0
  470. package/src/sync/live-sync.js +364 -119
  471. package/src/sync/local-presence.js +187 -0
  472. package/src/sync/merge-declarations.js +10 -0
  473. package/src/sync/merge-engine.js +12 -0
  474. package/src/sync/presence-store.js +412 -0
  475. package/src/sync/presence-target.js +243 -0
  476. package/src/sync/presence.js +72 -41
  477. package/src/sync/saved-handoff.js +200 -0
  478. package/src/sync/saved-stream.js +535 -0
  479. package/src/sync/version-guard.js +92 -0
  480. package/src/sync/wire-profile.js +81 -0
  481. package/src/ui/bevel-controls.js +2 -8
  482. package/src/ui/page-scheme.js +7 -0
  483. package/src/ui/skins/cms.js +1 -1
  484. package/src/ui/theme-config.js +150 -0
  485. package/src/ui/theme.js +6 -138
  486. package/src/ui/toast-lazy.js +11 -0
  487. package/src/vendor/LICENSES-optional.md +253 -0
  488. package/src/vendor/highlight.vendor.js +3 -0
  489. package/src/vendor/hljs-bash.vendor.js +2 -0
  490. package/src/vendor/hljs-css.vendor.js +2 -0
  491. package/src/vendor/hljs-javascript.vendor.js +2 -0
  492. package/src/vendor/hljs-json.vendor.js +2 -0
  493. package/src/vendor/hljs-python.vendor.js +2 -0
  494. package/src/vendor/hljs-xml.vendor.js +2 -0
  495. package/src/vendor/hyper-html-api-data.vendor.js +1 -1
  496. package/src/vendor/hyper-html-api-upgrade.vendor.js +5 -0
  497. package/src/vendor/hyper-morph-identity.vendor.js +2 -0
  498. package/src/vendor/hyper-morph-json.vendor.js +3 -0
  499. package/src/vendor/hyper-morph.vendor.js +6 -6
  500. package/src/vendor/hyper-undo.vendor.js +1 -1
  501. package/src/vendor/hypercms.vendor.js +169 -84
  502. package/src/vendor/marked.vendor.js +68 -0
  503. package/src/vendor/overtype.vendor.js +994 -0
  504. package/src/vendor/richclay.vendor.js +17 -17
  505. package/src/vendor/sap-core.vendor.js +5 -5
  506. package/src/vendor/sap-ownership.vendor.js +11 -7
@@ -0,0 +1,81 @@
1
+ /**
2
+ * wire-profile.js — the two live-sync wires, and the rule for choosing between them.
3
+ *
4
+ * Spec §10 puts both halves on `/_/sync`. Not every host serves that yet, and the
5
+ * ones that do not cannot be upgraded on our schedule: hyperclay-local ships behind
6
+ * Apple notarization, while this library reaches every document within one 10-minute
7
+ * cache TTL. So the client is the half that has to know both.
8
+ *
9
+ * The choice is DISCOVERED, never guessed. Spec §5 makes `/_/meta` the only way to
10
+ * learn what a host can do, and §10 says a client that has not discovered `sync`
11
+ * never opens either half of the route. Probing is also a bad instrument here: an
12
+ * EventSource reports a 404, an auth refusal and an offline browser through one
13
+ * error path, so a failed connection cannot tell you which address was wrong.
14
+ *
15
+ * One profile is chosen once and used for BOTH directions for the life of the page.
16
+ * Letting send and receive decide independently is exactly the bug this replaces: a
17
+ * client that posted to the spec address while streaming from the legacy one.
18
+ *
19
+ * Both stream addresses carry `client-id`, in the same kebab spelling as the rest of
20
+ * the query. It is the tab's own sender id — the one every outbound frame already
21
+ * carries — so a host that reads it at admission knows this connection by the value
22
+ * its frames arrive under, and can tell two tabs of one cookie-less guest apart. A
23
+ * host that does not read it ignores an unknown parameter.
24
+ */
25
+
26
+ import { hostMeta } from '../core/host-meta.js';
27
+
28
+ export const WIRE_PROFILES = {
29
+ spec: {
30
+ name: 'spec',
31
+ relayPath: '/_/sync',
32
+ documentHeader: 'Document-URL',
33
+ snapshotKey: 'snapshot',
34
+ streamPath: (href, lane, resumeId, clientId) =>
35
+ `/_/sync?document-url=${encodeURIComponent(href)}&lane=${lane}&resume-id=${resumeId}&client-id=${encodeURIComponent(clientId)}`,
36
+ },
37
+ // What every published clayjs speaks, and what hyperclayjs and the inline script in
38
+ // every Collection dashboard hardcode. Hosts keep these addresses permanently.
39
+ legacy: {
40
+ name: 'legacy',
41
+ relayPath: '/_/live-sync/save',
42
+ documentHeader: 'Page-URL',
43
+ snapshotKey: 'html',
44
+ streamPath: (href, lane, resumeId, clientId) =>
45
+ `/_/live-sync/stream?page-url=${encodeURIComponent(href)}&lane=${lane}&resume-id=${resumeId}&client-id=${encodeURIComponent(clientId)}`,
46
+ },
47
+ };
48
+
49
+ /**
50
+ * Which wire this host speaks, and which of the current worker transports it can
51
+ * carry. Absence of `sync` selects the legacy wire rather than disabling live sync.
52
+ * That is deliberate transition debt (§10 says an undiscovered capability is not
53
+ * opened at all), but both deployed first-party hosts ran live sync for a long time
54
+ * without advertising anything, and refusing them would regress every published
55
+ * version. A malformed answer, a 404 or a timeout all land on legacy too.
56
+ *
57
+ * @returns {Promise<{profile: Object, sharedSync: boolean, sharedData: boolean, liveData: boolean}>}
58
+ */
59
+ export function resolveWireProfile() {
60
+ return hostMeta()
61
+ .then((meta) => {
62
+ const extensions = meta?.extensions || [];
63
+ const hasSync = extensions.includes('sync');
64
+ const hasLiveData = extensions.includes('live-data');
65
+ const hasPresence = extensions.includes('presence');
66
+ const sharedData = hasSync && hasLiveData && extensions.includes('sync-worker-data') && !hasPresence;
67
+ const sharedSync = hasSync && !hasPresence && (sharedData || (extensions.includes('sync-worker') && !hasLiveData));
68
+ return {
69
+ profile: hasSync ? WIRE_PROFILES.spec : WIRE_PROFILES.legacy,
70
+ sharedSync,
71
+ sharedData,
72
+ liveData: hasLiveData,
73
+ };
74
+ })
75
+ .catch(() => ({
76
+ profile: WIRE_PROFILES.legacy,
77
+ sharedSync: false,
78
+ sharedData: false,
79
+ liveData: false,
80
+ }));
81
+ }
@@ -11,6 +11,7 @@
11
11
  import { style, make, set } from '../lib/hostile-css.js';
12
12
  import { RULES, MEDIA, FONT_SANS, TOKENS } from './bevel.js';
13
13
  import { themed, tokenRulesFor, partRules, markParts, floorRules } from './theme-parts.js';
14
+ import { pageScheme } from './page-scheme.js';
14
15
 
15
16
  export const RUNTIME_ONLY = 'no-save no-watch no-snapshot';
16
17
 
@@ -325,13 +326,6 @@ export function bevelInput(tag = 'input', opts = {}) {
325
326
  return paintInput(el, opts);
326
327
  }
327
328
 
328
- // The scheme a UI root gives its subtree: the page's own when it declares one, so
329
- // light-dark() matches what the person is looking at, else the reader's preference.
330
- export function pageScheme() {
331
- const s = getComputedStyle(document.documentElement).colorScheme;
332
- return s === 'light' || s === 'dark' ? s : 'light dark';
333
- }
334
-
335
329
  // `hidden` loses to an inline !important display, so showing and hiding a control
336
330
  // sets both: the attribute for assistive tech and callers, the declaration for looks.
337
331
  export function setShown(el, shown, display = 'block') {
@@ -340,4 +334,4 @@ export function setShown(el, shown, display = 'block') {
340
334
  else set(el, 'display', shown ? display : 'none');
341
335
  }
342
336
 
343
- export { protectIcon };
337
+ export { pageScheme, protectIcon };
@@ -0,0 +1,7 @@
1
+ // The scheme a UI root gives its subtree: the page's own when it declares one, so
2
+ // light-dark() matches what the person is looking at, else the reader's preference.
3
+ // It lives alone so a reader can ask for it without the controls.
4
+ export function pageScheme() {
5
+ const s = getComputedStyle(document.documentElement).colorScheme;
6
+ return s === 'light' || s === 'dark' ? s : 'light dark';
7
+ }
@@ -1,4 +1,4 @@
1
1
  // GENERATED from src/vendor/hypercms.vendor.js by scripts/build-vendor-skins.mjs. Run `npm run build:skins`.
2
- export const SOURCE_SHA256 = "a1757cdc7333f40185cb497dd0a7db863289aac55e96c9d9f24239d56ceeacc2";
2
+ export const SOURCE_SHA256 = "f4a8bf46fe5d4f1037810077d8068d59cd996896c59977abc2d2baa6ad3f0abd";
3
3
  export const ROOTS = [".hcms-shell"];
4
4
  export const CSS = "@layer clay-skin{\n:is(.hcms-shell):not([data-theme]),:is(.hcms-shell):not([data-theme]) *{--mirk-canvas:light-dark(#FDF8F0, #0B0C13) !important;--mirk-bg:light-dark(#FFFCF6, #11131E) !important;--mirk-fg:light-dark(#2B241B, #ECEAF2) !important;--mirk-accent:light-dark(#F4ECDF, #1A1D2C) !important;--mirk-destructive:light-dark(#A83A2C, #FF5566) !important;--mirk-focus-color:light-dark(#8F6310, #D9A445) !important;--mirk-bevel-bg:light-dark(#F1E7D4, #22273E) !important;--mirk-bevel-fg:light-dark(#2B241B, #ECEAF2) !important;--mirk-bevel-tl:light-dark(#FFF9ED, #3C4260) !important;--mirk-bevel-br:light-dark(#D6C3A5, #1B2033) !important;--mirk-bevel-hover-bg:color-mix(in srgb, light-dark(#F1E7D4, #22273E), light-dark(#FFF9ED, #3C4260) 45%) !important;--mirk-pill-inner-top:light-dark(#FFF9ED, #3C4260) !important;--mirk-input-border:light-dark(#D8C8AF, #353B52) !important;--mirk-placeholder-color:light-dark(#9A8A70, #6A7090) !important;--mirk-ctrl-bg:light-dark(#6B5942, #8A90AB) !important;--mirk-toggle-bg:light-dark(#FCF8F1, #4A5275) !important;--mirk-toggle-hi:light-dark(#FFF9ED, #6C759A) !important;--mirk-toggle-lo:light-dark(#D6C3A5, #1B2033) !important;--mirk-mark-fg:light-dark(#2B241B, #ECEAF2) !important;--mirk-sortable-dot:light-dark(#D8C8AF, #353B52) !important;--mirk-sortable-shadow:light-dark(#D6C3A5, #1B2033) !important;--mirk-sortable-label:light-dark(#6B5942, #8A90AB) !important;--mirk-sortable-placeholder:light-dark(#9A8A70, #6A7090) !important;--mirk-slider-fill:light-dark(#F0E4CC, #3A2F17) !important;--mirk-slider-nub-bg:light-dark(#FCF8F1, #4A5275) !important;--mirk-slider-nub-hi:light-dark(#FFF9ED, #6C759A) !important;--mirk-slider-nub-lo:light-dark(#D6C3A5, #1B2033) !important;--mirk-chip-surface:light-dark(#FFFCF6, #11131E) !important;--mirk-chip-edge:light-dark(#D8C8AF, #353B52) !important;--mirk-chip-primary-bg:light-dark(#2B241B, #ECEAF2) !important;--mirk-chip-primary-fg:light-dark(#FDF8F0, #0B0C13) !important;--mirk-chip-alert:light-dark(#A83A2C, #FF5566) !important;--mirk-radius:0px !important;--mirk-focus-offset:2px !important}\n:is(.hcms-shell){font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace !important}\n.hcms-shell .mirk-chip__actions .mirk-chip__action--primary{--mirk-bevel-bg:var(--mirk-chip-primary-bg) !important;--mirk-bevel-fg:var(--mirk-chip-primary-fg) !important;--mirk-bevel-tl:color-mix(in srgb, var(--mirk-chip-primary-bg), white 24%) !important;--mirk-bevel-br:color-mix(in srgb, var(--mirk-chip-primary-bg), black 32%) !important;--mirk-bevel-hover-bg:color-mix(in srgb, var(--mirk-chip-primary-bg), white 10%) !important}\n}";
@@ -0,0 +1,150 @@
1
+ // Theme configuration for the UI ClayJS draws on a page: dialogs, prompts, toasts,
2
+ // notices. A page configures it (window.clayTheme at first use, or clay.theme());
3
+ // the surfaces that paint it are elsewhere, so a reader that never opens one never
4
+ // loads them. Configuration is synchronous: clay.theme() answers and throws without
5
+ // waiting for a stylesheet, an element or an import.
6
+
7
+ export const TOKEN_PROPS = {
8
+ font: "font-family",
9
+ headingFont: "font-family",
10
+ text: "color",
11
+ mutedText: "color",
12
+ background: "background-color",
13
+ surface: "background-color",
14
+ border: "border-color",
15
+ accent: "background-color",
16
+ accentText: "color",
17
+ danger: "background-color",
18
+ dangerText: "color",
19
+ success: "color",
20
+ warning: "color",
21
+ radius: "border-radius",
22
+ shadow: "box-shadow",
23
+ overlay: "background-color",
24
+ spacing: "outline-offset",
25
+ buttonHeight: "min-height",
26
+ };
27
+
28
+ export const STATES = ["base", "hover", "active", "focus", "disabled"];
29
+
30
+ const DIALOG = ["root", "overlay", "panel", "header", "title", "body", "footer", "close", "closeIcon", "content", "input", "hint", "actions", "button", "buttonLabel", "well", "code", "copyButton"];
31
+ const NOTICE = ["root", "panel", "header", "title", "text", "icon", "dot", "actions", "button", "buttonLabel", "close", "well", "list", "row", "location", "valueLabel", "value", "before", "after", "mine", "theirs", "warning", "previewRing"];
32
+
33
+ export const PART_NAMES = new Set([
34
+ "button", "button.default", "button.primary", "button.quiet", "button.danger",
35
+ "buttonLabel", "input", "text", "mutedText", "icon", "well", "close",
36
+ ...["dialog", "people", "crop"].flatMap((s) => DIALOG.map((p) => `${s}.${p}`)),
37
+ "people.choices", "people.choice", "people.choiceLabel",
38
+ "crop.stage", "crop.image", "crop.dim", "crop.selection", "crop.handle",
39
+ "crop.handle.nw", "crop.handle.ne", "crop.handle.sw", "crop.handle.se",
40
+ "toast.stack", "toast.panel", "toast.icon", "toast.text", "toast.close", "toast.closeIcon",
41
+ ...["notice", "conflict", "section", "staleHost"].flatMap((s) => NOTICE.map((p) => `${s}.${p}`)),
42
+ ]);
43
+
44
+ const SCHEMES = ["page", "light", "dark"];
45
+ const DEFAULT = Object.freeze({ auto: true, colorScheme: "page", tokens: {}, parts: {} });
46
+
47
+ let config = null;
48
+ let initialized = false;
49
+
50
+ // A CSS value a page hands us. It lands inside an inline declaration, so it may
51
+ // never close that declaration or add a priority of its own.
52
+ export function validValue(prop, value) {
53
+ if (typeof value !== "string") return false;
54
+ const v = value.trim();
55
+ if (!v || v.length > 500 || /[;{}]|!\s*important/i.test(v)) return false;
56
+ const supports = globalThis.CSS?.supports;
57
+ return typeof supports === "function" ? supports.call(globalThis.CSS, prop, v) : true;
58
+ }
59
+
60
+ function plainObject(x) {
61
+ return !!x && typeof x === "object" && Object.getPrototypeOf(x) === Object.prototype;
62
+ }
63
+
64
+ function normalize(options) {
65
+ if (!plainObject(options)) throw new TypeError("clay.theme: pass an options object, false or null");
66
+ const { auto = true, colorScheme = "page", tokens = {}, parts = {}, ...rest } = options;
67
+ const unknown = Object.keys(rest);
68
+ if (unknown.length) throw new TypeError(`clay.theme: unknown option "${unknown[0]}"`);
69
+ if (typeof auto !== "boolean") throw new TypeError("clay.theme: auto must be true or false");
70
+ if (!SCHEMES.includes(colorScheme)) throw new TypeError(`clay.theme: colorScheme must be one of ${SCHEMES.join(", ")}`);
71
+ if (!plainObject(tokens)) throw new TypeError("clay.theme: tokens must be an object");
72
+ if (!plainObject(parts)) throw new TypeError("clay.theme: parts must be an object");
73
+ const outTokens = {};
74
+ for (const [name, value] of Object.entries(tokens)) {
75
+ if (!(name in TOKEN_PROPS)) throw new TypeError(`clay.theme: unknown token "${name}"`);
76
+ if (!validValue(TOKEN_PROPS[name], value)) throw new TypeError(`clay.theme: token "${name}" is not a valid ${TOKEN_PROPS[name]} value`);
77
+ outTokens[name] = name === "spacing" && value.trim() === "0" ? "0px" : value.trim();
78
+ }
79
+ const outParts = {};
80
+ for (const [name, states] of Object.entries(parts)) {
81
+ if (!PART_NAMES.has(name)) throw new TypeError(`clay.theme: unknown part "${name}"`);
82
+ if (!plainObject(states)) throw new TypeError(`clay.theme: part "${name}" must map states to declarations`);
83
+ outParts[name] = {};
84
+ for (const [state, decls] of Object.entries(states)) {
85
+ if (!STATES.includes(state)) throw new TypeError(`clay.theme: part "${name}" has unknown state "${state}"`);
86
+ if (!plainObject(decls)) throw new TypeError(`clay.theme: "${name}.${state}" must be an object of CSS declarations`);
87
+ outParts[name][state] = {};
88
+ for (const [prop, value] of Object.entries(decls)) {
89
+ if (!/^-?[a-z][a-z-]*$/.test(prop) || prop.startsWith("--")) throw new TypeError(`clay.theme: "${prop}" in ${name}.${state} is not a CSS property name`);
90
+ if (!validValue(prop, value)) throw new TypeError(`clay.theme: "${prop}: ${value}" in ${name}.${state} is not valid`);
91
+ outParts[name][state][prop] = value.trim();
92
+ }
93
+ }
94
+ }
95
+ return Object.freeze({ auto, colorScheme, tokens: Object.freeze(outTokens), parts: Object.freeze(outParts) });
96
+ }
97
+
98
+ function copy(c) {
99
+ if (c === false) return false;
100
+ return JSON.parse(JSON.stringify(c));
101
+ }
102
+
103
+ /**
104
+ * clay.theme(options) replaces the page's theme; clay.theme(false) restores the exact
105
+ * Bevel look; clay.theme(null) restores the default automatic theme; clay.theme()
106
+ * returns a copy of the current configuration. Invalid options throw a TypeError and
107
+ * leave the previous theme in place.
108
+ */
109
+ export function theme(options) {
110
+ initTheme();
111
+ if (arguments.length === 0) return copy(config);
112
+ if (options === false) config = false;
113
+ else if (options === null) config = DEFAULT;
114
+ else config = normalize(options);
115
+ return copy(config);
116
+ }
117
+
118
+ // Idempotent. Reads window.clayTheme once and attaches clay.theme. An invalid
119
+ // preloaded theme warns and falls back to the default; it never stops ClayJS booting.
120
+ export function initTheme() {
121
+ if (initialized) return;
122
+ initialized = true;
123
+ const pre = typeof window !== "undefined" ? window.clayTheme : undefined;
124
+ if (pre === false) config = false;
125
+ else if (pre === undefined || pre === null) config = DEFAULT;
126
+ else {
127
+ try {
128
+ config = normalize(pre);
129
+ } catch (err) {
130
+ console.warn(`clayjs: ignoring window.clayTheme: ${err.message}`);
131
+ config = DEFAULT;
132
+ }
133
+ }
134
+ if (typeof window !== "undefined") {
135
+ const clay = (window.clay = window.clay || {});
136
+ clay.theme = theme;
137
+ }
138
+ }
139
+
140
+ // The configuration a surface resolves against. One owner: theme() writes it here
141
+ // and a surface reads it here, so a split module cannot hold a stale copy.
142
+ export function currentConfig() {
143
+ return config;
144
+ }
145
+
146
+ // Test hook: forget configuration so the next call re-reads window.clayTheme.
147
+ export function _resetTheme() {
148
+ config = null;
149
+ initialized = false;
150
+ }
package/src/ui/theme.js CHANGED
@@ -2,142 +2,15 @@
2
2
  // A page configures it with window.clayTheme (read at first use) or clay.theme().
3
3
  // resolveTheme() captures one surface's theme when that surface is built; a later
4
4
  // clay.theme() call affects the next surface, never one already open.
5
- import { pageScheme } from "./bevel-controls.js";
5
+ import { TOKEN_PROPS, currentConfig, initTheme, validValue } from "./theme-config.js";
6
+ import { pageScheme } from "./page-scheme.js";
6
7
 
7
- export const TOKEN_PROPS = {
8
- font: "font-family",
9
- headingFont: "font-family",
10
- text: "color",
11
- mutedText: "color",
12
- background: "background-color",
13
- surface: "background-color",
14
- border: "border-color",
15
- accent: "background-color",
16
- accentText: "color",
17
- danger: "background-color",
18
- dangerText: "color",
19
- success: "color",
20
- warning: "color",
21
- radius: "border-radius",
22
- shadow: "box-shadow",
23
- overlay: "background-color",
24
- spacing: "outline-offset",
25
- buttonHeight: "min-height",
26
- };
8
+ // The configuration itself lives in theme-config.js, which the loader reads at
9
+ // boot; these names stay here because every surface imported them from here.
10
+ export { PART_NAMES, STATES, TOKEN_PROPS, _resetTheme, initTheme, theme, validValue } from "./theme-config.js";
27
11
 
28
- export const STATES = ["base", "hover", "active", "focus", "disabled"];
29
-
30
- const DIALOG = ["root", "overlay", "panel", "header", "title", "body", "footer", "close", "closeIcon", "content", "input", "hint", "actions", "button", "buttonLabel", "well", "code", "copyButton"];
31
- const NOTICE = ["root", "panel", "header", "title", "text", "icon", "dot", "actions", "button", "buttonLabel", "close", "well", "list", "row", "location", "valueLabel", "value", "before", "after", "mine", "theirs", "warning", "previewRing"];
32
-
33
- export const PART_NAMES = new Set([
34
- "button", "button.default", "button.primary", "button.quiet", "button.danger",
35
- "buttonLabel", "input", "text", "mutedText", "icon", "well", "close",
36
- ...["dialog", "people", "crop"].flatMap((s) => DIALOG.map((p) => `${s}.${p}`)),
37
- "people.choices", "people.choice", "people.choiceLabel",
38
- "crop.stage", "crop.image", "crop.dim", "crop.selection", "crop.handle",
39
- "crop.handle.nw", "crop.handle.ne", "crop.handle.sw", "crop.handle.se",
40
- "toast.stack", "toast.panel", "toast.icon", "toast.text", "toast.close", "toast.closeIcon",
41
- ...["notice", "conflict", "section", "staleHost"].flatMap((s) => NOTICE.map((p) => `${s}.${p}`)),
42
- ]);
43
-
44
- const SCHEMES = ["page", "light", "dark"];
45
- const DEFAULT = Object.freeze({ auto: true, colorScheme: "page", tokens: {}, parts: {} });
46
12
  const kebab = (name) => name.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
47
13
 
48
- let config = null;
49
- let initialized = false;
50
-
51
- // A CSS value a page hands us. It lands inside an inline declaration, so it may
52
- // never close that declaration or add a priority of its own.
53
- export function validValue(prop, value) {
54
- if (typeof value !== "string") return false;
55
- const v = value.trim();
56
- if (!v || v.length > 500 || /[;{}]|!\s*important/i.test(v)) return false;
57
- const supports = globalThis.CSS?.supports;
58
- return typeof supports === "function" ? supports.call(globalThis.CSS, prop, v) : true;
59
- }
60
-
61
- function plainObject(x) {
62
- return !!x && typeof x === "object" && Object.getPrototypeOf(x) === Object.prototype;
63
- }
64
-
65
- function normalize(options) {
66
- if (!plainObject(options)) throw new TypeError("clay.theme: pass an options object, false or null");
67
- const { auto = true, colorScheme = "page", tokens = {}, parts = {}, ...rest } = options;
68
- const unknown = Object.keys(rest);
69
- if (unknown.length) throw new TypeError(`clay.theme: unknown option "${unknown[0]}"`);
70
- if (typeof auto !== "boolean") throw new TypeError("clay.theme: auto must be true or false");
71
- if (!SCHEMES.includes(colorScheme)) throw new TypeError(`clay.theme: colorScheme must be one of ${SCHEMES.join(", ")}`);
72
- if (!plainObject(tokens)) throw new TypeError("clay.theme: tokens must be an object");
73
- if (!plainObject(parts)) throw new TypeError("clay.theme: parts must be an object");
74
- const outTokens = {};
75
- for (const [name, value] of Object.entries(tokens)) {
76
- if (!(name in TOKEN_PROPS)) throw new TypeError(`clay.theme: unknown token "${name}"`);
77
- if (!validValue(TOKEN_PROPS[name], value)) throw new TypeError(`clay.theme: token "${name}" is not a valid ${TOKEN_PROPS[name]} value`);
78
- outTokens[name] = name === "spacing" && value.trim() === "0" ? "0px" : value.trim();
79
- }
80
- const outParts = {};
81
- for (const [name, states] of Object.entries(parts)) {
82
- if (!PART_NAMES.has(name)) throw new TypeError(`clay.theme: unknown part "${name}"`);
83
- if (!plainObject(states)) throw new TypeError(`clay.theme: part "${name}" must map states to declarations`);
84
- outParts[name] = {};
85
- for (const [state, decls] of Object.entries(states)) {
86
- if (!STATES.includes(state)) throw new TypeError(`clay.theme: part "${name}" has unknown state "${state}"`);
87
- if (!plainObject(decls)) throw new TypeError(`clay.theme: "${name}.${state}" must be an object of CSS declarations`);
88
- outParts[name][state] = {};
89
- for (const [prop, value] of Object.entries(decls)) {
90
- if (!/^-?[a-z][a-z-]*$/.test(prop) || prop.startsWith("--")) throw new TypeError(`clay.theme: "${prop}" in ${name}.${state} is not a CSS property name`);
91
- if (!validValue(prop, value)) throw new TypeError(`clay.theme: "${prop}: ${value}" in ${name}.${state} is not valid`);
92
- outParts[name][state][prop] = value.trim();
93
- }
94
- }
95
- }
96
- return Object.freeze({ auto, colorScheme, tokens: Object.freeze(outTokens), parts: Object.freeze(outParts) });
97
- }
98
-
99
- function copy(c) {
100
- if (c === false) return false;
101
- return JSON.parse(JSON.stringify(c));
102
- }
103
-
104
- /**
105
- * clay.theme(options) replaces the page's theme; clay.theme(false) restores the exact
106
- * Bevel look; clay.theme(null) restores the default automatic theme; clay.theme()
107
- * returns a copy of the current configuration. Invalid options throw a TypeError and
108
- * leave the previous theme in place.
109
- */
110
- export function theme(options) {
111
- initTheme();
112
- if (arguments.length === 0) return copy(config);
113
- if (options === false) config = false;
114
- else if (options === null) config = DEFAULT;
115
- else config = normalize(options);
116
- return copy(config);
117
- }
118
-
119
- // Idempotent. Reads window.clayTheme once and attaches clay.theme. An invalid
120
- // preloaded theme warns and falls back to the default; it never stops ClayJS booting.
121
- export function initTheme() {
122
- if (initialized) return;
123
- initialized = true;
124
- const pre = typeof window !== "undefined" ? window.clayTheme : undefined;
125
- if (pre === false) config = false;
126
- else if (pre === undefined || pre === null) config = DEFAULT;
127
- else {
128
- try {
129
- config = normalize(pre);
130
- } catch (err) {
131
- console.warn(`clayjs: ignoring window.clayTheme: ${err.message}`);
132
- config = DEFAULT;
133
- }
134
- }
135
- if (typeof window !== "undefined") {
136
- const clay = (window.clay = window.clay || {});
137
- clay.theme = theme;
138
- }
139
- }
140
-
141
14
  // --- colour helpers --------------------------------------------------------
142
15
 
143
16
  // [r, g, b, a] for rgb()/rgba() or #rgb/#rrggbb, else null.
@@ -251,6 +124,7 @@ function onColor(fill, t) {
251
124
  */
252
125
  export function resolveTheme() {
253
126
  initTheme();
127
+ const config = currentConfig();
254
128
  if (config === false) return { bevel: true, scheme: pageScheme(), tokens: {}, parts: {} };
255
129
  const sampled = config.auto ? samplePage() : {};
256
130
  const tokens = { ...sampled, ...cssTokens(), ...config.tokens };
@@ -269,9 +143,3 @@ export function resolveTheme() {
269
143
  }
270
144
  return { bevel: false, scheme: scheme(config.colorScheme, tokens), tokens, parts: config.parts };
271
145
  }
272
-
273
- // Test hook: forget configuration so the next call re-reads window.clayTheme.
274
- export function _resetTheme() {
275
- config = null;
276
- initialized = false;
277
- }
@@ -0,0 +1,11 @@
1
+ // The toast stack is fetched the first time a toast shows, so the page editor does
2
+ // not download it to become ready. Calls made before it arrives run in order once it has.
3
+ let loading = null;
4
+ const load = () => (loading ??= import("./toast.js"));
5
+ const later = (name) => (...args) => { load().then((m) => (name ? m[name] : m.default)(...args)); };
6
+
7
+ export default later(null);
8
+ export const toastPersistent = later("toastPersistent");
9
+ // Dismissing a toast nobody showed does nothing, so it never fetches the stack: a page
10
+ // that tears down without having shown one keeps it unloaded.
11
+ export const dismissPersistent = (...args) => { if (loading) later("dismissPersistent")(...args); };