@panphora/clayjs 1.15.2 → 1.17.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 (551) 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 +84291 -57611
  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-ZUE7PSCI.js +1 -0
  21. package/dist/m/attrs/save-freeze-MYNVXREN.js +1 -0
  22. package/dist/m/c-2AZDZWCK.js +1 -0
  23. package/dist/m/c-2SPVQSHC.js +1 -0
  24. package/dist/m/c-2YYDMLNZ.js +1 -0
  25. package/dist/m/c-336SGU5W.js +1 -0
  26. package/dist/m/c-33JJ6CBX.js +2 -0
  27. package/dist/m/c-3GJ4SDE2.js +1 -0
  28. package/dist/m/c-3H6BZDNJ.js +6 -0
  29. package/dist/m/c-3OWDMNJR.js +2 -0
  30. package/dist/m/c-3RUU4TPX.js +91 -0
  31. package/dist/m/c-3XIRD4NU.js +1 -0
  32. package/dist/m/c-46XYM55L.js +1 -0
  33. package/dist/m/c-4DFEJ2PO.js +3 -0
  34. package/dist/m/c-4JZDZFF6.js +1 -0
  35. package/dist/m/c-4L3BTFRK.js +1 -0
  36. package/dist/m/c-4Q2XTQ2N.js +2 -0
  37. package/dist/m/c-4WKFKEKF.js +1 -0
  38. package/dist/m/c-56QRZTZH.js +1 -0
  39. package/dist/m/c-5J4E7O4Y.js +4 -0
  40. package/dist/m/c-5LKDWQTL.js +19 -0
  41. package/dist/m/c-5QWQ7A5L.js +1 -0
  42. package/dist/m/c-5RJFTLSF.js +1 -0
  43. package/dist/m/c-5V3MOVJT.js +1 -0
  44. package/dist/m/c-5VYOWDTI.js +1 -0
  45. package/dist/m/c-5YIHJ3TJ.js +1 -0
  46. package/dist/m/c-6AZOGAPE.js +1 -0
  47. package/dist/m/c-6CRUUXOX.js +5 -0
  48. package/dist/m/c-6HMB24EV.js +1 -0
  49. package/dist/m/c-6KEVEQ7L.js +1 -0
  50. package/dist/m/c-6NC5I2TV.js +1 -0
  51. package/dist/m/c-74MGYWZF.js +1 -0
  52. package/dist/m/c-7DJDKPGL.js +1 -0
  53. package/dist/m/c-7OLLJPWP.js +1 -0
  54. package/dist/m/c-7SWMYKAI.js +1 -0
  55. package/dist/m/c-A3E3NIMC.js +1 -0
  56. package/dist/m/c-A7LS5UZW.js +1 -0
  57. package/dist/m/c-AMSNPOCX.js +1 -0
  58. package/dist/m/c-AQLFEATB.js +1 -0
  59. package/dist/m/c-B3JM5ZXC.js +1 -0
  60. package/dist/m/c-BBVGTQG7.js +1 -0
  61. package/dist/m/c-BPF2NSPV.js +1 -0
  62. package/dist/m/c-BQ6LOBEE.js +1 -0
  63. package/dist/m/c-BTDI4Y23.js +1 -0
  64. package/dist/m/c-BWFVSBDF.js +1 -0
  65. package/dist/m/c-BYTKL6UX.js +1 -0
  66. package/dist/m/c-CFHW5AMY.js +6 -0
  67. package/dist/m/c-CJ3A7ZKE.js +1 -0
  68. package/dist/m/c-CQHPGKX2.js +1 -0
  69. package/dist/m/c-CYWLPPUS.js +1 -0
  70. package/dist/m/c-CZUSOB7V.js +1 -0
  71. package/dist/m/c-DCFSEJZG.js +1 -0
  72. package/dist/m/c-DCXOXBF3.js +1 -0
  73. package/dist/m/c-DFS4XZJV.js +2 -0
  74. package/dist/m/c-DNENWY4O.js +1 -0
  75. package/dist/m/c-DNZ5IFM6.js +1 -0
  76. package/dist/m/c-E4LIR5X5.js +1 -0
  77. package/dist/m/c-EJTGYSLN.js +1 -0
  78. package/dist/m/c-EVCQ3BKA.js +1 -0
  79. package/dist/m/c-EZU56NQV.js +34 -0
  80. package/dist/m/c-FDNHHZY5.js +1 -0
  81. package/dist/m/c-FILLTJA7.js +1 -0
  82. package/dist/m/c-FRLHSY7E.js +1 -0
  83. package/dist/m/c-FROJUZMV.js +1 -0
  84. package/dist/m/c-G2JPKCTP.js +1 -0
  85. package/dist/m/c-GB6TU7WV.js +1 -0
  86. package/dist/m/c-GFJJEBTU.js +1 -0
  87. package/dist/m/c-GJAEGGXY.js +1 -0
  88. package/dist/m/c-GOWBDM6J.js +1 -0
  89. package/dist/m/c-GQ6F6IDK.js +1 -0
  90. package/dist/m/c-GSFIGKOP.js +1 -0
  91. package/dist/m/c-GY422N3Q.js +1 -0
  92. package/dist/m/c-H4LG442Q.js +1 -0
  93. package/dist/m/c-HA6INT6J.js +1 -0
  94. package/dist/m/c-HAWFNBYG.js +1 -0
  95. package/dist/m/c-HDDEEL77.js +1 -0
  96. package/dist/m/c-HFKUVACH.js +1 -0
  97. package/dist/m/c-HHDFCNHV.js +1 -0
  98. package/dist/m/c-HPURYVZS.js +2 -0
  99. package/dist/m/c-I2ZATQCD.js +2 -0
  100. package/dist/m/c-IEM4NTCS.js +1 -0
  101. package/dist/m/c-IJUK2GPW.js +1 -0
  102. package/dist/m/c-IW6GGOU2.js +1 -0
  103. package/dist/m/c-JAX2667S.js +6 -0
  104. package/dist/m/c-JDCX26UP.js +25 -0
  105. package/dist/m/c-JRKY44DK.js +1 -0
  106. package/dist/m/c-JU3NK25H.js +1 -0
  107. package/dist/m/c-KAU6E43D.js +1 -0
  108. package/dist/m/c-KBS3UV6B.js +1 -0
  109. package/dist/m/c-KGVGROZT.js +1 -0
  110. package/dist/m/c-KI7M4AY3.js +1 -0
  111. package/dist/m/c-KIPQJX4B.js +1 -0
  112. package/dist/m/c-KQ6TYJAP.js +135 -0
  113. package/dist/m/c-KU3ZFADW.js +1 -0
  114. package/dist/m/c-L4WQSC27.js +1 -0
  115. package/dist/m/c-LFPHCXY3.js +1 -0
  116. package/dist/m/c-LRPUO2MX.js +1 -0
  117. package/dist/m/c-LWLBHLVC.js +3 -0
  118. package/dist/m/c-LZJPNR2W.js +1 -0
  119. package/dist/m/c-M2L47S2X.js +7 -0
  120. package/dist/m/c-MFP2ZWD4.js +1 -0
  121. package/dist/m/c-MKSQ4Y57.js +1 -0
  122. package/dist/m/c-MTQHWQC3.js +1 -0
  123. package/dist/m/c-N326R2JD.js +1 -0
  124. package/dist/m/c-N7JPUPGC.js +1 -0
  125. package/dist/m/c-NRPJEVJS.js +1 -0
  126. package/dist/m/c-NUFFJVVJ.js +1 -0
  127. package/dist/m/c-NUHP2XDB.js +1 -0
  128. package/dist/m/c-NUHSPT5P.js +1 -0
  129. package/dist/m/c-O72HVYSA.js +1 -0
  130. package/dist/m/c-OCSZ4QGN.js +1 -0
  131. package/dist/m/c-OIBUTDXI.js +1 -0
  132. package/dist/m/c-OIDRZKAF.js +1 -0
  133. package/dist/m/c-OW5QIGG3.js +1 -0
  134. package/dist/m/c-P7KNDG34.js +1 -0
  135. package/dist/m/c-PGRCK73F.js +1 -0
  136. package/dist/m/c-PQ5LK6QE.js +993 -0
  137. package/dist/m/c-PS5ARVWR.js +9 -0
  138. package/dist/m/c-PZ4XEPUP.js +2 -0
  139. package/dist/m/c-Q622NS2Y.js +1 -0
  140. package/dist/m/c-Q7NQD65V.js +1 -0
  141. package/dist/m/c-QH63LQOS.js +1 -0
  142. package/dist/m/c-QHIWXHRO.js +1 -0
  143. package/dist/m/c-QHWJ5ZIJ.js +1 -0
  144. package/dist/m/c-QICP2YR5.js +1 -0
  145. package/dist/m/c-QJ4OM3G6.js +1 -0
  146. package/dist/m/c-QNKREOL6.js +1 -0
  147. package/dist/m/c-R3L7ZJGB.js +2 -0
  148. package/dist/m/c-R7IWVINQ.js +1 -0
  149. package/dist/m/c-RM7J7BV2.js +1 -0
  150. package/dist/m/c-RSMOODDU.js +1 -0
  151. package/dist/m/c-RVMWGXEJ.js +1 -0
  152. package/dist/m/c-RYUXUUBX.js +1 -0
  153. package/dist/m/c-S4ZEH46B.js +9 -0
  154. package/dist/m/c-S7H2DRCB.js +1 -0
  155. package/dist/m/c-S7LK4KUE.js +1 -0
  156. package/dist/m/c-SDAXDM2D.js +1 -0
  157. package/dist/m/c-SGIA4IEQ.js +188 -0
  158. package/dist/m/c-SMBZG5X4.js +1 -0
  159. package/dist/m/c-SMGU7RT3.js +235 -0
  160. package/dist/m/c-SPIORRYS.js +1 -0
  161. package/dist/m/c-SWLRT66R.js +1 -0
  162. package/dist/m/c-SZGYW5HT.js +1 -0
  163. package/dist/m/c-TCCA5BZN.js +2 -0
  164. package/dist/m/c-TCJTVAFN.js +1 -0
  165. package/dist/m/c-TJ6WOJL3.js +67 -0
  166. package/dist/m/c-TQEMVJCS.js +1 -0
  167. package/dist/m/c-TRS6TM6O.js +1 -0
  168. package/dist/m/c-TYLXX4NF.js +21 -0
  169. package/dist/m/c-U62OB4BT.js +1 -0
  170. package/dist/m/c-U6YWUAR3.js +8 -0
  171. package/dist/m/c-UDCSU5G5.js +2 -0
  172. package/dist/m/c-UDUUJPFZ.js +1 -0
  173. package/dist/m/c-UGHH4MB3.js +1 -0
  174. package/dist/m/c-UL2YUY52.js +1 -0
  175. package/dist/m/c-VAK7SG37.js +1 -0
  176. package/dist/m/c-VDSS4K3Z.js +1 -0
  177. package/dist/m/c-VE6ZMYMC.js +1 -0
  178. package/dist/m/c-VG5XIN4T.js +1 -0
  179. package/dist/m/c-VHM5XQHK.js +1 -0
  180. package/dist/m/c-VHNSBD2M.js +1 -0
  181. package/dist/m/c-VI5RMSVY.js +1 -0
  182. package/dist/m/c-VKEDWYDF.js +1 -0
  183. package/dist/m/c-VRZN56XY.js +1 -0
  184. package/dist/m/c-W5MCHEGA.js +1 -0
  185. package/dist/m/c-WDC5GVKU.js +1 -0
  186. package/dist/m/c-WN5AY3OZ.js +1 -0
  187. package/dist/m/c-WNYBLIOZ.js +1 -0
  188. package/dist/m/c-WRBKEJD4.js +1 -0
  189. package/dist/m/c-WWXIDH4O.js +28 -0
  190. package/dist/m/c-WYFDLITL.js +1 -0
  191. package/dist/m/c-XCNTK76U.js +1 -0
  192. package/dist/m/c-XMS6DPBR.js +1 -0
  193. package/dist/m/c-XN6MBKI6.js +67 -0
  194. package/dist/m/c-XPELB6E5.js +1 -0
  195. package/dist/m/c-XQXZAO7N.js +1 -0
  196. package/dist/m/c-Y5HBBIQ4.js +1 -0
  197. package/dist/m/c-ZE46QDIH.js +1 -0
  198. package/dist/m/c-ZUCOKOHT.js +1 -0
  199. package/dist/m/c-ZVPVXTJF.js +4 -0
  200. package/dist/m/c-ZVRKXKM7.js +1 -0
  201. package/dist/m/c-ZWIOJGMT.js +1 -0
  202. package/dist/m/core/admin-attrs-QHOKPJ7W.js +1 -0
  203. package/dist/m/core/autosave-HRYGUWV6.js +1 -0
  204. package/dist/m/core/conflict-notice-6MROJN2L.js +1 -0
  205. package/dist/m/core/draft-mode-WSQAT67S.js +1 -0
  206. package/dist/m/core/host-permission-FNXVEFNE.js +1 -0
  207. package/dist/m/core/is-edit-mode-KTWA3O5N.js +1 -0
  208. package/dist/m/core/persist-JFYRHMRJ.js +3 -0
  209. package/dist/m/core/recovery-FLTCC2OC.js +1 -0
  210. package/dist/m/core/save-HQZ4S667.js +1 -0
  211. package/dist/m/core/save-core-KGQWFUNH.js +1 -0
  212. package/dist/m/core/snapshot-EGQZNT45.js +1 -0
  213. package/dist/m/core/unsaved-warning-IDJLD66H.js +1 -0
  214. package/dist/m/dom/all-APS5ZSKP.js +1 -0
  215. package/dist/m/dom/dom-helpers-L7OSR6S4.js +1 -0
  216. package/dist/m/events/index-RN2JNGBV.js +1 -0
  217. package/dist/m/internals/index-PVXGPUDA.js +1 -0
  218. package/dist/m/lib/cache-bust-MUMFXZK6.js +1 -0
  219. package/dist/m/lib/region-policy-SB2AWVG5.js +1 -0
  220. package/dist/m/loader-S4I7GKXR.js +1 -0
  221. package/dist/m/manifest-4C419D67.js +1 -0
  222. package/dist/m/manifest-edit-B077F288.js +1 -0
  223. package/dist/m/manifest.json +3988 -0
  224. package/dist/m/options/options-EJMS3K24.js +1 -0
  225. package/dist/m/page/editor-NNJA4OKD.js +202 -0
  226. package/dist/m/plugins/ai-edit-QN4PMMNL.js +6 -0
  227. package/dist/m/plugins/bind-text-NX46N5UV.js +1 -0
  228. package/dist/m/plugins/cms-HP3LSTPN.js +2293 -0
  229. package/dist/m/plugins/demo-RM5IR6AO.js +1 -0
  230. package/dist/m/plugins/derive-UAAA4V4S.js +1 -0
  231. package/dist/m/plugins/indicator-URDBBOQO.js +1 -0
  232. package/dist/m/plugins/live-HFWD4OIH.js +1 -0
  233. package/dist/m/plugins/menu-3HIEQSI6.js +138 -0
  234. package/dist/m/plugins/message-LQ6EDH4V.js +1 -0
  235. package/dist/m/plugins/page-JOKB6XPR.js +2 -0
  236. package/dist/m/plugins/page-view-NXOJHNW6.js +1 -0
  237. package/dist/m/plugins/people-SGPJKANK.js +1 -0
  238. package/dist/m/plugins/quickcrop-QNY3PKLD.js +26 -0
  239. package/dist/m/plugins/quickcrop-QNY3PKLD.js.LEGAL.txt +7 -0
  240. package/dist/m/plugins/richclay-NRQDSWX6.js +517 -0
  241. package/dist/m/plugins/richclay-NRQDSWX6.js.LEGAL.txt +1 -0
  242. package/dist/m/plugins/sortable-GWT4PWDV.js +1 -0
  243. package/dist/m/plugins/source-4ZRSAIYM.js +1 -0
  244. package/dist/m/plugins/undo-VDA5P7FH.js +1 -0
  245. package/dist/m/plugins/unsent-HJFLQJ2O.js +1 -0
  246. package/dist/m/plugins/upgrade-W7FG5VFG.js +1 -0
  247. package/dist/m/plugins/upload-WLYKK6TL.js +1 -0
  248. package/dist/m/plugins/visitor-drafts-LIDY7NH6.js +21 -0
  249. package/dist/m/plugins/visitor-drafts-owner-ZXCKBZE7.js +1 -0
  250. package/dist/m/plugins/wire-4N6GYAF6.js +1 -0
  251. package/dist/m/reader-core-DXYCURFF.js +68 -0
  252. package/dist/m/route/route-KOCZSEGN.js +1 -0
  253. package/dist/m/sync/live-sync-J7VMYTKS.js +1 -0
  254. package/dist/m/ui/index-3JLVI27O.js +1 -0
  255. package/dist/m/utils/index-4TJCVLT7.js +1 -0
  256. package/dist/m/vendor/Sortable.vendor-A755ITLN.js +3 -0
  257. package/dist/m/vendor/Sortable.vendor-A755ITLN.js.LEGAL.txt +1 -0
  258. package/dist/m/vendor/sap-core.vendor-A7BMUYZT.js +6 -0
  259. package/dist/offline-manifest.json +4034 -0
  260. package/dist/page/themes/light-1.css +430 -0
  261. package/dist/server/core.cjs +23748 -22855
  262. package/dist/server/offline-runtime.cjs +4954 -0
  263. package/dist/server/offline-runtime.mjs +4923 -0
  264. package/dist/server/rooms.mjs +9 -0
  265. package/docs/guide.md +1078 -669
  266. package/entries/all.js +2 -0
  267. package/entries/clay-data.js +1 -1
  268. package/entries/clay-dom.js +2 -0
  269. package/entries/clay-events.js +2 -0
  270. package/entries/clay-internals.js +2 -0
  271. package/entries/clay-options.js +2 -0
  272. package/entries/clay-router.js +2 -0
  273. package/entries/clay-ui.js +2 -0
  274. package/entries/clay-utils.js +2 -0
  275. package/entries/clay.js +2 -0
  276. package/entries/sap.js +6 -6
  277. package/fonts/ibm-plex-mono-LICENSE +93 -0
  278. package/fonts/ibm-plex-mono-latin-300-normal.woff2 +0 -0
  279. package/fonts/ibm-plex-mono-latin-400-italic.woff2 +0 -0
  280. package/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
  281. package/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
  282. package/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
  283. package/fonts/ibm-plex-sans-LICENSE +93 -0
  284. package/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
  285. package/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
  286. package/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
  287. package/fonts/ibm-plex.css +71 -0
  288. package/fonts/inter-LICENSE +93 -0
  289. package/fonts/inter-cyrillic-ext-wght-normal.woff2 +0 -0
  290. package/fonts/inter-cyrillic-wght-normal.woff2 +0 -0
  291. package/fonts/inter-greek-ext-wght-normal.woff2 +0 -0
  292. package/fonts/inter-greek-wght-normal.woff2 +0 -0
  293. package/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
  294. package/fonts/inter-latin-wght-normal.woff2 +0 -0
  295. package/fonts/inter-vietnamese-wght-normal.woff2 +0 -0
  296. package/fonts/inter.css +62 -0
  297. package/fonts/newsreader-LICENSE +93 -0
  298. package/fonts/newsreader-latin-ext-opsz-normal.woff2 +0 -0
  299. package/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
  300. package/fonts/newsreader-vietnamese-opsz-normal.woff2 +0 -0
  301. package/fonts/newsreader.css +26 -0
  302. package/fonts/work-sans-LICENSE +93 -0
  303. package/fonts/work-sans-latin-wght-normal.woff2 +0 -0
  304. package/fonts/work-sans.css +8 -0
  305. package/package.json +20 -3
  306. package/packed-contract.json +1 -0
  307. package/src/attrs/add-from.js +27 -4
  308. package/src/attrs/save-freeze.js +7 -52
  309. package/src/core/admin-attrs.js +119 -12
  310. package/src/core/admin-contenteditable.js +12 -10
  311. package/src/core/admin-inputs.js +14 -15
  312. package/src/core/admin-onclick.js +2 -0
  313. package/src/core/autosave.js +74 -21
  314. package/src/core/boot-phase.js +2 -1
  315. package/src/core/conflict-download.js +19 -23
  316. package/src/core/conflict-notice-ui.js +1173 -0
  317. package/src/core/conflict-notice.js +140 -697
  318. package/src/core/download.js +32 -0
  319. package/src/core/edit-mode.js +147 -14
  320. package/src/core/etag.js +30 -12
  321. package/src/core/host-meta.js +90 -8
  322. package/src/core/host-permission.js +29 -0
  323. package/src/core/is-edit-mode.js +145 -12
  324. package/src/core/mode-key.js +125 -0
  325. package/src/core/mode-lifecycle.js +544 -0
  326. package/src/core/mode-receipt.js +30 -0
  327. package/src/core/mode-refusal.js +13 -0
  328. package/src/core/mode-resources.js +52 -0
  329. package/src/core/mode-support.js +82 -0
  330. package/src/core/mode-switch.js +259 -0
  331. package/src/core/mode-transition.js +112 -0
  332. package/src/core/page-data-write.js +305 -0
  333. package/src/core/page-data.js +26 -227
  334. package/src/core/page-format-wire.js +4 -0
  335. package/src/core/page-format.js +58 -0
  336. package/src/core/persist.js +37 -9
  337. package/src/core/preserve-authored.js +114 -0
  338. package/src/core/recovery.js +772 -0
  339. package/src/core/runtime-url.js +105 -0
  340. package/src/core/save-core.js +113 -12
  341. package/src/core/save-replace.js +72 -0
  342. package/src/core/save-size-notice.js +134 -0
  343. package/src/core/save-size.js +140 -0
  344. package/src/core/save.js +806 -119
  345. package/src/core/snapshot.js +159 -11
  346. package/src/core/source-map.js +157 -9
  347. package/src/core/unsaved-warning.js +14 -4
  348. package/src/core/upgrade-run.js +408 -0
  349. package/src/core/version.js +18 -0
  350. package/src/lib/assets.js +30 -0
  351. package/src/lib/autosave-debug-gate.js +50 -0
  352. package/src/lib/autosave-scheduler.js +140 -0
  353. package/src/lib/boot-imports.js +8 -0
  354. package/src/lib/derived.js +3 -1
  355. package/src/lib/dirty-gate.js +15 -0
  356. package/src/lib/doc-storage.js +33 -0
  357. package/src/lib/effect.js +9 -4
  358. package/src/lib/mutation.js +4 -2
  359. package/src/lib/offline-runtime.js +226 -0
  360. package/src/lib/preload.js +48 -0
  361. package/src/lib/root-attrs.js +1 -1
  362. package/src/lib/trash.js +18 -0
  363. package/src/lib/undo/capture-move.js +152 -0
  364. package/src/live/local-channel.js +61 -0
  365. package/src/live/local-lane.js +60 -9
  366. package/src/live/server-lane.js +6 -3
  367. package/src/loader-logic.js +76 -15
  368. package/src/loader.js +218 -30
  369. package/src/page/adopt-boot.js +76 -22
  370. package/src/page/adopt.js +25 -4
  371. package/src/page/awareness.js +230 -0
  372. package/src/page/blocks.js +113 -6
  373. package/src/page/blocksel.js +20 -4
  374. package/src/page/board-face.js +13 -0
  375. package/src/page/board-panel.js +5 -17
  376. package/src/page/board-style.js +2 -13
  377. package/src/page/board-view.js +1 -11
  378. package/src/page/board-views.js +3 -0
  379. package/src/page/board.js +2 -2
  380. package/src/page/boot-pack.js +26 -0
  381. package/src/page/boot.js +237 -0
  382. package/src/page/chart-tables.js +11 -0
  383. package/src/page/chart.js +6 -10
  384. package/src/page/checklist.js +1 -1
  385. package/src/page/checkpoint-proof.js +289 -0
  386. package/src/page/chrome.js +431 -63
  387. package/src/page/csv-import.js +17 -2
  388. package/src/page/document-title-dom.js +52 -0
  389. package/src/page/document-title-runtime.js +90 -0
  390. package/src/page/document-title.js +12 -0
  391. package/src/page/drag.js +48 -13
  392. package/src/page/drop.js +2 -1
  393. package/src/page/editor.js +399 -90
  394. package/src/page/emoji-data.js +162 -0
  395. package/src/page/feature-loader.js +72 -0
  396. package/src/page/features/board.js +21 -0
  397. package/src/page/features/chart.js +11 -0
  398. package/src/page/features/code.js +13 -0
  399. package/src/page/features/dates.js +180 -0
  400. package/src/page/features/emoji.js +187 -0
  401. package/src/page/features/media.js +290 -0
  402. package/src/page/features/mentions.js +188 -0
  403. package/src/page/features/registry.js +28 -0
  404. package/src/page/features/table.js +383 -0
  405. package/src/page/{tool-view.js → features/tool.js} +33 -2
  406. package/src/page/format-codec.js +215 -0
  407. package/src/page/format-command.js +9 -0
  408. package/src/page/format-gate.js +179 -0
  409. package/src/page/format-host.js +54 -0
  410. package/src/page/format-level.js +157 -0
  411. package/src/page/format-native-commands.js +142 -0
  412. package/src/page/format-native.js +42 -0
  413. package/src/page/highlight-slot.js +23 -0
  414. package/src/page/highlight.js +30 -16
  415. package/src/page/history-intent.js +78 -0
  416. package/src/page/inline.js +45 -28
  417. package/src/page/items.js +67 -14
  418. package/src/page/link.js +1 -0
  419. package/src/page/markdown.js +112 -3
  420. package/src/page/media-views.js +3 -0
  421. package/src/page/media.js +33 -245
  422. package/src/page/mention-picker.js +99 -0
  423. package/src/page/merge.js +1 -1
  424. package/src/page/outline-cache.js +11 -0
  425. package/src/page/placeholder.js +27 -7
  426. package/src/page/projection.js +240 -51
  427. package/src/page/reader-patch.js +306 -0
  428. package/src/page/recover.js +1 -1
  429. package/src/page/rich/page-tool.js +1 -4
  430. package/src/page/runtime-owner.js +27 -0
  431. package/src/page/save-projection.js +46 -4
  432. package/src/page/save-states.js +1 -1
  433. package/src/page/schema.js +47 -0
  434. package/src/page/table-rect-key.js +3 -0
  435. package/src/page/table-select.js +4 -3
  436. package/src/page/table-style.js +1 -1
  437. package/src/page/table-views.js +3 -0
  438. package/src/page/table.js +8 -293
  439. package/src/page/themes/content.css +25 -1
  440. package/src/page/themes/light-1.css +163 -2
  441. package/src/page/themes/light-1.source.css +269 -0
  442. package/src/page/tool-capability.js +3 -0
  443. package/src/page/tool-views.js +3 -0
  444. package/src/page/view-hooks.js +32 -0
  445. package/src/page/view.js +390 -107
  446. package/src/page/ybind/awareness.js +172 -0
  447. package/src/page/ybind/binding.js +40 -5
  448. package/src/page/ybind/bridge.js +50 -47
  449. package/src/page/ybind/decode.js +52 -19
  450. package/src/page/ybind/doc.js +27 -2
  451. package/src/page/ybind/group.js +12 -3
  452. package/src/page/ybind/index.js +2 -0
  453. package/src/page/ybind/lineage.js +71 -0
  454. package/src/page/ybind/marks.js +26 -1
  455. package/src/page/ybind/migrate.js +48 -13
  456. package/src/page/ybind/moves.js +32 -21
  457. package/src/page/ybind/positions.js +50 -0
  458. package/src/page/ybind/provider.js +97 -24
  459. package/src/page/ybind/recovery-proof.js +191 -0
  460. package/src/page/ybind/recovery-replay.js +488 -0
  461. package/src/page/ybind/tokens.js +15 -6
  462. package/src/page/ybind/walk.js +10 -3
  463. package/src/page/ybind/writer.js +48 -4
  464. package/src/plugins/ai-edit.js +167 -32
  465. package/src/plugins/bind-text.js +218 -0
  466. package/src/plugins/cms.js +93 -0
  467. package/src/plugins/indicator.js +57 -5
  468. package/src/plugins/live.js +319 -35
  469. package/src/plugins/menu/claygoo.svg.js +1 -0
  470. package/src/plugins/menu/seo-head.js +323 -0
  471. package/src/plugins/menu/seo.js +849 -0
  472. package/src/plugins/menu.js +425 -0
  473. package/src/plugins/page-view.js +131 -0
  474. package/src/plugins/page.js +1131 -270
  475. package/src/plugins/people.js +158 -31
  476. package/src/plugins/richclay.js +119 -9
  477. package/src/plugins/sortable.js +370 -60
  478. package/src/plugins/source.js +189 -366
  479. package/src/plugins/undo.js +289 -19
  480. package/src/plugins/unsent.js +132 -0
  481. package/src/plugins/upgrade-run.js +1 -0
  482. package/src/plugins/upgrade.js +210 -0
  483. package/src/plugins/upload-task.js +571 -0
  484. package/src/plugins/upload-ui.js +265 -0
  485. package/src/plugins/upload.js +34 -153
  486. package/src/plugins/visitor-drafts/inert.js +32 -0
  487. package/src/plugins/visitor-drafts/intro.js +2 -1
  488. package/src/plugins/visitor-drafts/owner-chip.js +3 -0
  489. package/src/plugins/visitor-drafts/prompt.js +2 -2
  490. package/src/plugins/visitor-drafts-owner.js +85 -0
  491. package/src/plugins/visitor-drafts.js +31 -42
  492. package/src/plugins/wire.js +82 -1
  493. package/src/reader-core.js +26 -0
  494. package/src/recovery/conflicts.js +287 -0
  495. package/src/recovery/identity.js +154 -0
  496. package/src/recovery/store.js +792 -0
  497. package/src/recovery/undo.js +257 -0
  498. package/src/server/checkpoint/index.js +68 -4
  499. package/src/server/offline-runtime/index.js +214 -0
  500. package/src/server/rooms/index.js +2 -1
  501. package/src/server/rooms/live-data-rooms.js +2 -2
  502. package/src/server/rooms/page-admission.js +33 -0
  503. package/src/server/rooms/page-lineage.js +56 -0
  504. package/src/server/rooms/page-rebase.js +11 -5
  505. package/src/server/rooms/page-state.js +2 -0
  506. package/src/server/rooms/page-write-admission.js +9 -3
  507. package/src/source/session.js +705 -0
  508. package/src/sync/conflict-revert.js +5 -4
  509. package/src/sync/conflicts-edit.js +119 -0
  510. package/src/sync/conflicts-facade.js +49 -0
  511. package/src/sync/conflicts.js +99 -1
  512. package/src/sync/editing-marker.js +37 -6
  513. package/src/sync/editing-sender.js +8 -1
  514. package/src/sync/live-sync-edit.js +63 -0
  515. package/src/sync/live-sync.js +364 -119
  516. package/src/sync/local-presence.js +187 -0
  517. package/src/sync/merge-declarations.js +10 -0
  518. package/src/sync/merge-engine.js +12 -0
  519. package/src/sync/presence-store.js +412 -0
  520. package/src/sync/presence-target.js +243 -0
  521. package/src/sync/presence.js +72 -41
  522. package/src/sync/saved-handoff.js +200 -0
  523. package/src/sync/saved-stream.js +544 -0
  524. package/src/sync/version-guard.js +92 -0
  525. package/src/sync/wire-profile.js +81 -0
  526. package/src/ui/bevel-controls.js +2 -8
  527. package/src/ui/page-scheme.js +7 -0
  528. package/src/ui/skins/cms.js +1 -1
  529. package/src/ui/theme-config.js +150 -0
  530. package/src/ui/theme.js +6 -138
  531. package/src/ui/toast-lazy.js +11 -0
  532. package/src/vendor/LICENSES-optional.md +253 -0
  533. package/src/vendor/highlight.vendor.js +3 -0
  534. package/src/vendor/hljs-bash.vendor.js +2 -0
  535. package/src/vendor/hljs-css.vendor.js +2 -0
  536. package/src/vendor/hljs-javascript.vendor.js +2 -0
  537. package/src/vendor/hljs-json.vendor.js +2 -0
  538. package/src/vendor/hljs-python.vendor.js +2 -0
  539. package/src/vendor/hljs-xml.vendor.js +2 -0
  540. package/src/vendor/hyper-html-api-data.vendor.js +1 -1
  541. package/src/vendor/hyper-html-api-upgrade.vendor.js +5 -0
  542. package/src/vendor/hyper-morph-identity.vendor.js +2 -0
  543. package/src/vendor/hyper-morph-json.vendor.js +3 -0
  544. package/src/vendor/hyper-morph.vendor.js +6 -6
  545. package/src/vendor/hyper-undo.vendor.js +1 -1
  546. package/src/vendor/hypercms.vendor.js +169 -84
  547. package/src/vendor/marked.vendor.js +68 -0
  548. package/src/vendor/overtype.vendor.js +994 -0
  549. package/src/vendor/richclay.vendor.js +17 -17
  550. package/src/vendor/sap-core.vendor.js +5 -5
  551. package/src/vendor/sap-ownership.vendor.js +11 -7
@@ -13,21 +13,84 @@
13
13
  This wrapper conditionally loads the full Sortable.js vendor script (~118KB)
14
14
  only when in edit mode, using dynamic import().
15
15
 
16
+ The editor it wires is one mode lease (see sortableParticipant): every instance,
17
+ subscription, listener and pending restore belongs to the session that made it, so a
18
+ page that leaves edit takes all of it back and a later entry starts from nothing
19
+ instead of from the previous session's leftovers.
20
+
16
21
  */
17
- import { isEditMode } from "../core/is-edit-mode.js";
22
+ import { isEditMode, startsAtImport } from "../core/is-edit-mode.js";
18
23
  import Mutation from "../lib/mutation.js";
19
24
  import { capabilitySelector } from "../lib/region-capabilities.js";
20
25
  import { onSnapshot } from "../core/snapshot.js";
26
+ import { beginMove, holdMove, releaseMove, releaseAllMoves, recordMove } from "../lib/undo/capture-move.js";
21
27
 
22
28
  const EDITOR_UI_SELECTOR = capabilitySelector('history');
23
29
 
30
+ // The CMS hides one `cms-template` row in every list it fills: it is the seed a new row is
31
+ // cloned from, never a row itself. A drag never picks one up, and a move neither takes one
32
+ // nor lands before one.
33
+ const SEED_SELECTOR = '[cms-template]';
34
+
24
35
  // Sortable marks the picked-up item and its links and images draggable="false" on press, and
25
36
  // leaves style="" behind after a drag. Those attributes would be saved into the document, so a
26
37
  // mere click would change the file. Record them when an item is chosen and put them back after.
27
38
  const RUNTIME_ATTRS = ['draggable', 'style'];
28
39
 
40
+ // A press ends on one of these, wherever it lands.
41
+ const ENDS = ['pointerup', 'pointercancel', 'dragend', 'drop'];
42
+
43
+ // What a press recorded, for the snapshot hook below.
29
44
  const pressed = new Set();
30
45
 
46
+ // The page's vendor constructor, snapshot transform, and one sortable session. All three
47
+ // outlive a session: a second entry asks for what the page already has rather than adding
48
+ // a second copy of it.
49
+ let vendor = null;
50
+ let installation = null;
51
+ let session = null;
52
+
53
+ // Every listener and timer a session starts is recorded with its target, type and options,
54
+ // so cleanup removes the exact subscription instead of hoping a bare type is enough.
55
+ function track(record, target, type, handler, options) {
56
+ const entry = { target, type, handler, options };
57
+ target.addEventListener(type, handler, options);
58
+ record.listeners.push(entry);
59
+ return entry;
60
+ }
61
+
62
+ function untrack(record, entry) {
63
+ entry.target.removeEventListener(entry.type, entry.handler, entry.options);
64
+ const index = record.listeners.indexOf(entry);
65
+ if (index !== -1) record.listeners.splice(index, 1);
66
+ }
67
+
68
+ function later(record, run) {
69
+ const id = setTimeout(() => {
70
+ record.timers.delete(id);
71
+ run();
72
+ }, 0);
73
+ record.timers.add(id);
74
+ return id;
75
+ }
76
+
77
+ function ownership(Sortable, root) {
78
+ return {
79
+ Sortable,
80
+ root,
81
+ admitted: false,
82
+ instances: new Set(),
83
+ listeners: [],
84
+ timers: new Set(),
85
+ presses: new Set(),
86
+ stop: null,
87
+ };
88
+ }
89
+
90
+ // A direct makeSortable() call, outside any session, is still wired the same way; nothing
91
+ // disposes it, which is what such a call asked for.
92
+ const loose = { admitted: true, instances: new Set(), listeners: [], timers: new Set(), presses: new Set() };
93
+
31
94
  function recordRuntimeAttrs(item) {
32
95
  return [item, ...item.querySelectorAll('*')]
33
96
  .filter(el => !el.closest(EDITOR_UI_SELECTOR))
@@ -50,10 +113,80 @@ function restoreRuntimeAttrs(recorded) {
50
113
  }
51
114
  }
52
115
 
53
- function makeSortable(sortableElem, Sortable) {
116
+ // What one of a container's items is: a list holds its own rows, any other element holds
117
+ // its element children.
118
+ function childSelector(container) {
119
+ return /^(UL|OL)$/.test(container.tagName) ? 'li' : '*';
120
+ }
121
+
122
+ function draggableSelector(container) {
123
+ return `> ${childSelector(container)}:not(${EDITOR_UI_SELECTOR})`;
124
+ }
125
+
126
+ // The half of eligibility a container can answer about a node it does not hold yet: is
127
+ // this the kind of child it takes, and is it a real row rather than furniture or a seed?
128
+ // makeSortable gives the vendor the same rules through draggableSelector.
129
+ function acceptsItem(container, node) {
130
+ if (!container || !node || node.nodeType !== 1) return false;
131
+ if (!node.matches(childSelector(container))) return false;
132
+ return !node.closest(EDITOR_UI_SELECTOR) && !node.closest(SEED_SELECTOR);
133
+ }
134
+
135
+ function isItemOf(container, node) {
136
+ if (!container || !node || node.parentElement !== container) return false;
137
+ return acceptsItem(container, node);
138
+ }
139
+
140
+ // The next thing in the container that counts as an item. A seed row or a piece of editor
141
+ // furniture between two rows is not a position, so it is stepped over.
142
+ function nextItem(container, node) {
143
+ let sibling = node.nextElementSibling;
144
+ while (sibling && !isItemOf(container, sibling)) sibling = sibling.nextElementSibling;
145
+ return sibling;
146
+ }
147
+
148
+ // SortableJS reports a position as the item's element index among its container's
149
+ // children, and the facade keeps that convention so a drag report and a move report read
150
+ // the same way. Nothing in a template's intent should ever depend on these.
151
+ function elementIndex(container, node) {
152
+ return Array.prototype.indexOf.call(container.children, node);
153
+ }
154
+
155
+ // The one notification a completed reorder makes. A drag and clay.sortable.move() both
156
+ // reach it exactly once: the source container's author code, then `clay:sorted` with what
157
+ // moved, then the compatibility input event, both dispatched on the source container and
158
+ // bubbling from it.
159
+ function finishMove(result, onSorted) {
160
+ if (onSorted) {
161
+ try {
162
+ const asyncFn = new Function(`return (async function(evt) { ${onSorted} })`)();
163
+ asyncFn.call(result.from, result);
164
+ } catch (error) {
165
+ console.error('Error in onsorted execution:', error);
166
+ }
167
+ }
168
+ // Announce the reorder as a real, self-documenting event carrying what moved.
169
+ // Reactive libs (e.g. Sap) and author code key off this without us knowing
170
+ // about them. Fires only in edit mode, since sortable only inits there.
171
+ result.from.dispatchEvent(new CustomEvent('clay:sorted', {
172
+ bubbles: true,
173
+ detail: {
174
+ item: result.item,
175
+ from: result.from,
176
+ to: result.to,
177
+ oldIndex: result.oldIndex,
178
+ newIndex: result.newIndex,
179
+ },
180
+ }));
181
+ // DEPRECATED: early versions dispatched a synthetic `input` here so reactive
182
+ // libs would re-derive. It is semantically off (a container has no value) and
183
+ // now redundant with clay:sorted and the mutation observers. Kept as a compat shim.
184
+ result.from.dispatchEvent(new Event('input', { bubbles: true }));
185
+ }
186
+
187
+ function makeSortable(sortableElem, Sortable, record = loose) {
54
188
  let options = {};
55
- const childSelector = /^(UL|OL)$/.test(sortableElem.tagName) ? 'li' : '*';
56
- options.draggable = `> ${childSelector}:not(${EDITOR_UI_SELECTOR})`;
189
+ options.draggable = draggableSelector(sortableElem);
57
190
 
58
191
  // Check if Sortable instance already exists
59
192
  if (Sortable.get(sortableElem)) return;
@@ -78,6 +211,7 @@ function makeSortable(sortableElem, Sortable) {
78
211
  const onsortingCode = sortableElem.getAttribute('onsorting');
79
212
  if (onsortingCode) {
80
213
  options.onMove = function(evt) {
214
+ if (!record.admitted) return;
81
215
  try {
82
216
  const asyncFn = new Function(`return (async function(evt) { ${onsortingCode} })`)();
83
217
  asyncFn.call(sortableElem, evt);
@@ -90,68 +224,159 @@ function makeSortable(sortableElem, Sortable) {
90
224
  // After a drop, run any author onsorted code, then notify reactive libraries.
91
225
  const onsortedCode = sortableElem.getAttribute('onsorted');
92
226
  options.onEnd = function(evt) {
93
- if (onsortedCode) {
94
- try {
95
- const asyncFn = new Function(`return (async function(evt) { ${onsortedCode} })`)();
96
- asyncFn.call(sortableElem, evt);
97
- } catch (error) {
98
- console.error('Error in onsorted execution:', error);
99
- }
227
+ // A session that has closed admission has already handed the page to the exit's
228
+ // barrier. The drop it allowed is not a new edit, so nothing of it reaches an author
229
+ // handler, a reactive engine or the file.
230
+ if (!record.admitted) return;
231
+ const result = { item: evt.item, from: evt.from, to: evt.to, oldIndex: evt.oldIndex, newIndex: evt.newIndex };
232
+ const start = press;
233
+ press = null;
234
+ // The runtime attributes go back before the move is recorded, so the entry holds
235
+ // the move and nothing of what the vendor wrote around it.
236
+ if (restoring) {
237
+ restoreRuntimeAttrs(restoring);
238
+ restoring = null;
100
239
  }
101
- // Announce the reorder as a real, self-documenting event carrying what moved.
102
- // Reactive libs (e.g. Sap) and author code key off this without us knowing
103
- // about them. Fires only in edit mode, since sortable only inits there.
104
- sortableElem.dispatchEvent(new CustomEvent('clay:sorted', {
105
- bubbles: true,
106
- detail: {
107
- item: evt.item,
108
- from: evt.from,
109
- to: evt.to,
110
- oldIndex: evt.oldIndex,
111
- newIndex: evt.newIndex,
112
- },
113
- }));
114
- // DEPRECATED: early versions dispatched a synthetic `input` here so reactive
115
- // libs would re-derive. It is semantically off (a container has no value) and
116
- // now redundant with clay:sorted and the mutation observers. Kept as a compat shim.
117
- sortableElem.dispatchEvent(new Event('input', { bubbles: true }));
240
+ if (start) {
241
+ recordMove(start, result);
242
+ releaseMove(start);
243
+ }
244
+ finishMove(result, onsortedCode);
118
245
  };
119
246
 
120
247
  // Record on the capture phase, before Sortable's own press handler changes anything, and
121
248
  // restore once the press ends: a plain click never fires Sortable's unchoose.
122
- const ENDS = ['pointerup', 'pointercancel', 'dragend', 'drop'];
123
249
  let recorded = null;
250
+ let press = null;
251
+ let restoring = null;
252
+ let started = false;
253
+ let ends = [];
254
+ // A press that ends without a drop (a click, a cancel) still has to hand the
255
+ // gesture's exclusion back: the drop itself releases it once its entry is recorded.
256
+ const endPress = () => {
257
+ const start = press;
258
+ press = null;
259
+ restoring = null;
260
+ releaseMove(start);
261
+ };
124
262
  const restoreSoon = () => {
125
263
  const pending = recorded;
126
264
  recorded = null;
127
- pressed.delete(pending);
128
- ENDS.forEach(type => document.removeEventListener(type, restoreSoon, true));
129
- if (pending) setTimeout(() => restoreRuntimeAttrs(pending), 0);
265
+ if (pending) {
266
+ record.presses.delete(pending);
267
+ pressed.delete(pending);
268
+ restoring = pending;
269
+ }
270
+ ends.forEach(entry => untrack(record, entry));
271
+ ends = [];
272
+ if (pending) later(record, () => restoreRuntimeAttrs(pending));
273
+ };
274
+ const settleSoon = () => {
275
+ // Only the press that became a drag holds: a click has nothing to keep out of
276
+ // history, and its own handler's writes are the next entry.
277
+ if (started) {
278
+ holdMove(press);
279
+ } else {
280
+ releaseMove(press);
281
+ press = null;
282
+ }
283
+ started = false;
284
+ restoreSoon();
285
+ later(record, endPress);
130
286
  };
131
- sortableElem.addEventListener('pointerdown', (event) => {
287
+ track(record, sortableElem, 'pointerdown', (event) => {
132
288
  let item = event.target instanceof Element ? event.target : null;
133
289
  while (item && item.parentElement !== sortableElem) item = item.parentElement;
134
290
  if (!item || recorded) return;
135
291
  recorded = recordRuntimeAttrs(item);
292
+ press = beginMove(item);
293
+ started = false;
294
+ record.presses.add(recorded);
136
295
  pressed.add(recorded);
137
- ENDS.forEach(type => document.addEventListener(type, restoreSoon, true));
296
+ ends = ENDS.map(type => track(record, document, type, settleSoon, true));
138
297
  }, true);
139
298
  options.onUnchoose = restoreSoon;
299
+ // The one signal a click never makes: Sortable says the press became a drag, so this
300
+ // press is the one that may hold the engine. A click's own writes are history's.
301
+ options.onStart = () => {
302
+ started = true;
303
+ };
140
304
 
141
305
  Sortable.create(sortableElem, options);
306
+ record.instances.add(sortableElem);
142
307
  }
143
308
 
144
- async function init() {
145
- if (!isEditMode) return;
309
+ // The semantic move: the reorder a drag makes, without dragging, without SortableJS and
310
+ // without waiting for it. Everything is validated before anything moves, and every
311
+ // refusal says why. It does not guess: an anchor that is gone is refused rather than
312
+ // re-targeted at a neighbour, and a request to stay put is not an insertion, an event or
313
+ // a history entry.
314
+ function move(item, toContainer, beforeItem = null) {
315
+ const refusal = (code) => ({ ok: false, code });
146
316
 
147
- // Sortable's UMD header picks its target at run time: window.Sortable when no
148
- // module system is present (a module load, and the single-file build), a
149
- // default export when a bundler hands it one. Cover both.
150
- const mod = await import('../vendor/Sortable.vendor.js');
151
- const Sortable = window.Sortable || mod.default;
317
+ if (!isEditMode) return refusal('not-editable');
318
+ // Admission is the session's, exactly as a drag's is: a lease whose exit is already
319
+ // running has handed the page on, and a move is a new edit.
320
+ if (session && !session.admitted) return refusal('not-editable');
321
+
322
+ const doc = document;
323
+ if (!item || item.nodeType !== 1 || !item.isConnected || item.ownerDocument !== doc) {
324
+ return refusal('detached');
325
+ }
326
+ const from = item.parentElement;
327
+ if (!from || !from.isConnected) return refusal('detached');
328
+ if (!toContainer || toContainer.nodeType !== 1 || !toContainer.isConnected || toContainer.ownerDocument !== doc) {
329
+ return refusal('detached');
330
+ }
331
+ // The item has to be one of its source's own items, and the destination has to be a
332
+ // declared sortable that would hold it. A subtree cannot be moved into itself.
333
+ if (!from.hasAttribute('sortable') || !isItemOf(from, item)) return refusal('item');
334
+ if (!toContainer.hasAttribute('sortable') || !acceptsItem(toContainer, item)) return refusal('item');
335
+ if (item === toContainer || item.contains(toContainer)) return refusal('item');
336
+ // Crossing containers needs an equal, named group on both. Within one container there
337
+ // is nothing to compare, and SortableJS's own ungrouped lists stay single-list too.
338
+ if (from !== toContainer) {
339
+ const group = from.getAttribute('sortable');
340
+ if (!group || group !== toContainer.getAttribute('sortable')) return refusal('group');
341
+ }
342
+ // Asked to land before itself, the item is already where the call wants it.
343
+ if (beforeItem === item) return { ok: true, moved: false };
344
+ if (beforeItem !== null && !isItemOf(toContainer, beforeItem)) return refusal('anchor');
345
+ // The position the item already holds is not a move.
346
+ if (from === toContainer && nextItem(from, item) === beforeItem) return { ok: true, moved: false };
347
+
348
+ const oldIndex = elementIndex(from, item);
349
+ const start = beginMove(item);
350
+ holdMove(start);
351
+ let result;
352
+ try {
353
+ toContainer.insertBefore(item, beforeItem);
354
+ result = { item, from, to: toContainer, oldIndex, newIndex: elementIndex(toContainer, item) };
355
+ recordMove(start, result);
356
+ } finally {
357
+ releaseMove(start);
358
+ }
359
+ finishMove(result, from.getAttribute('onsorted'));
360
+ return { ok: true, moved: true, ...result };
361
+ }
362
+
363
+ // Sortable's UMD header picks its target at run time: window.Sortable when no
364
+ // module system is present (a module load, and the single-file build), a
365
+ // default export when a bundler hands it one. Cover both. A failed fetch is forgotten,
366
+ // so the next entry asks again instead of inheriting the rejection.
367
+ function loadVendor() {
368
+ if (!vendor) {
369
+ vendor = import('../vendor/Sortable.vendor.js').then((mod) => window.Sortable || mod.default);
370
+ vendor.catch(() => { vendor = null; });
371
+ }
372
+ return vendor;
373
+ }
152
374
 
153
- // A save taken mid-drag would otherwise write Sortable's classes and attributes into the
154
- // file. Strip them from the snapshot clone only, so the live drag carries on untouched.
375
+ // A save taken mid-drag would otherwise write Sortable's classes and attributes into the
376
+ // file. Strip them from the snapshot clone only, so the live drag carries on untouched.
377
+ // Installed once, and it reads whatever the live session recorded.
378
+ function install() {
379
+ if (installation) return installation;
155
380
  onSnapshot((root, { original }) => {
156
381
  for (const el of root.querySelectorAll("[sortable] .sortable-chosen, [sortable] .sortable-ghost, [sortable] .sortable-drag")) {
157
382
  el.classList.remove("sortable-chosen", "sortable-ghost", "sortable-drag");
@@ -168,27 +393,112 @@ async function init() {
168
393
  });
169
394
  }
170
395
  });
396
+ installation = true;
397
+ return installation;
398
+ }
171
399
 
172
- // Set up sortable on page load
173
- document.querySelectorAll('[sortable]').forEach(el => makeSortable(el, Sortable));
174
-
175
- // Set up listener for dynamically added elements.
176
- // require:'observed' so drag works inside no-save / save-* regions (e.g. the
177
- // CMS panel); pausable:false so it keeps wiring during a live-sync pause.
178
- Mutation.onAddElement({
179
- selectorFilter: "[sortable]",
180
- debounce: 200,
181
- require: 'observed',
182
- pausable: false
183
- }, (changes) => {
184
- changes.forEach(({ element }) => {
185
- makeSortable(element, Sortable);
186
- });
187
- });
400
+ // One edit session over the live DOM. `enable` creates the instances and starts watching
401
+ // for containers that arrive afterwards; `quiesce` closes admission, so a drag that ends
402
+ // after it produces no event; `resume` is the refused exit; `dispose` destroys every
403
+ // instance this session created and removes exactly the subscriptions it added.
404
+ function sortableLease(record) {
405
+ return {
406
+ enable() {
407
+ if (record.admitted) return;
408
+ record.admitted = true;
409
+ for (const el of record.root.querySelectorAll('[sortable]')) makeSortable(el, record.Sortable, record);
410
+ // Set up listener for dynamically added elements.
411
+ // require:'observed' so drag works inside no-save / save-* regions (e.g. the
412
+ // CMS panel); pausable:false so it keeps wiring during a live-sync pause.
413
+ record.stop = Mutation.onAddElement({
414
+ selectorFilter: "[sortable]",
415
+ debounce: 200,
416
+ require: 'observed',
417
+ pausable: false
418
+ }, (changes) => {
419
+ if (!record.admitted) return;
420
+ changes.forEach(({ element }) => {
421
+ makeSortable(element, record.Sortable, record);
422
+ });
423
+ });
424
+ },
425
+ quiesce() {
426
+ record.admitted = false;
427
+ },
428
+ resume() {
429
+ record.admitted = true;
430
+ },
431
+ dispose() {
432
+ record.admitted = false;
433
+ if (record.stop) {
434
+ record.stop();
435
+ record.stop = null;
436
+ }
437
+ for (const entry of [...record.listeners]) untrack(record, entry);
438
+ for (const id of record.timers) clearTimeout(id);
439
+ record.timers.clear();
440
+ for (const recording of record.presses) pressed.delete(recording);
441
+ record.presses.clear();
442
+ releaseAllMoves();
443
+ for (const el of record.instances) record.Sortable?.get?.(el)?.destroy?.();
444
+ record.instances.clear();
445
+ if (session === record) session = null;
446
+ },
447
+ };
448
+ }
449
+
450
+ const isStale = (context) => {
451
+ if (!context) return false;
452
+ if (context.signal?.aborted) return true;
453
+ return typeof context.isCurrent === "function" && !context.isCurrent();
454
+ };
455
+
456
+ /**
457
+ * Sortable as a mode participant: the drag editor the commit that enters edit starts, and
458
+ * the one the exit takes back.
459
+ *
460
+ * `prepare` fetches the vendor and answers with the lease; the fetch can outlive the
461
+ * session that asked for it, so the generation is asked again once it is here. `enable`
462
+ * creates the instances. `quiesce` refuses a completion that arrives after it. `dispose`
463
+ * destroys the instances and hands back every listener and timer this session started.
464
+ */
465
+ export function sortableParticipant(root = document) {
466
+ return {
467
+ id: "clay:sortable",
468
+ order: 300,
469
+ async prepare(context = {}) {
470
+ if (context.initial === true) return adopt();
471
+ const Sortable = await loadVendor();
472
+ if (isStale(context)) {
473
+ throw Object.assign(new Error("clay:sortable prepared for a stale generation"), { code: "stale-document" });
474
+ }
475
+ install();
476
+ return sortableLease(session || (session = ownership(Sortable, root)));
477
+ },
478
+ };
479
+ }
480
+
481
+ // The boot this tab already made, adopted instead of prepared: it is the session `init`
482
+ // below enabled, or, on a boot that started none, nothing to hand back.
483
+ async function adopt() {
484
+ const lease = await ready;
485
+ return { enable() {}, quiesce: () => lease?.quiesce(), resume: () => lease?.resume(), dispose: () => lease?.dispose() };
188
486
  }
189
487
 
190
488
  // Auto-init when module is imported; the loader awaits `ready` before resolving clay.ready
489
+ async function init() {
490
+ if (!startsAtImport()) return null;
491
+ const lease = await sortableParticipant().prepare();
492
+ lease.enable();
493
+ return lease;
494
+ }
495
+
191
496
  const ready = init();
192
497
 
193
- export { init, ready, makeSortable };
498
+ // What the loader publishes on clay.sortable as soon as this module evaluates, so a move
499
+ // control never waits for the vendor the drag editor awaits.
500
+ const sortable = Object.freeze({ move });
501
+
502
+ export { init, ready, makeSortable, move, sortable };
503
+ export { sortableParticipant as modeParticipant };
194
504
  export default init;