@panphora/clayjs 1.17.0 → 1.18.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 (467) hide show
  1. package/dist/all.js +1 -1
  2. package/dist/clay-dom.js +1 -1
  3. package/dist/clay-events.js +1 -1
  4. package/dist/clay-internals.js +1 -1
  5. package/dist/clay-options.js +1 -1
  6. package/dist/clay-router.js +1 -1
  7. package/dist/clay-ui.js +1 -1
  8. package/dist/clay-utils.js +1 -1
  9. package/dist/clay.js +1 -1
  10. package/dist/clay.standalone.js +72474 -62090
  11. package/dist/m/attrs/{save-freeze-MYNVXREN.js → save-freeze-LWGF6XUN.js} +1 -1
  12. package/dist/m/c-2GRUM77Q.js +30 -0
  13. package/dist/m/c-2KIEGNC4.js +1 -0
  14. package/dist/m/{c-AMSNPOCX.js → c-2KL3BD52.js} +1 -1
  15. package/dist/m/c-2ZZBC45O.js +1 -0
  16. package/dist/m/c-372N6H3B.js +1 -0
  17. package/dist/m/{c-4WKFKEKF.js → c-3G2DGZUP.js} +1 -1
  18. package/dist/m/c-3LDGIBMN.js +1 -0
  19. package/dist/m/c-3O7OBDCM.js +1 -0
  20. package/dist/m/c-4ASQPRQL.js +1 -0
  21. package/dist/m/c-4TXNLX4K.js +6 -0
  22. package/dist/m/c-4YU3BR4D.js +6 -0
  23. package/dist/m/c-5734MF2P.js +1 -0
  24. package/dist/m/c-57XDY6HC.js +1 -0
  25. package/dist/m/{c-KAU6E43D.js → c-5B4YBZXC.js} +1 -1
  26. package/dist/m/c-5ONTYIUI.js +1 -0
  27. package/dist/m/c-5OOVFCJM.js +1 -0
  28. package/dist/m/{c-3XIRD4NU.js → c-5T6NZHNM.js} +1 -1
  29. package/dist/m/{c-74MGYWZF.js → c-5ZQV7KC4.js} +1 -1
  30. package/dist/m/{c-7OLLJPWP.js → c-6DB2OLRJ.js} +1 -1
  31. package/dist/m/c-6DNRCPNM.js +1 -0
  32. package/dist/m/c-6UGWFMQC.js +2 -0
  33. package/dist/m/c-7K4SCQB7.js +1 -0
  34. package/dist/m/c-7MG5RU63.js +1 -0
  35. package/dist/m/c-7PRJCA3E.js +1 -0
  36. package/dist/m/c-A6L3FMUS.js +1 -0
  37. package/dist/m/c-AMU3BPPR.js +4 -0
  38. package/dist/m/{c-Y5HBBIQ4.js → c-AMYEFA2E.js} +1 -1
  39. package/dist/m/c-AQYCG7QW.js +1 -0
  40. package/dist/m/c-ATKAOH23.js +1 -0
  41. package/dist/m/c-B5CS55WR.js +1 -0
  42. package/dist/m/c-B5UJQT7W.js +1 -0
  43. package/dist/m/c-B7J4K2AE.js +3 -0
  44. package/dist/m/c-BHZYSHW4.js +1 -0
  45. package/dist/m/{c-VHM5XQHK.js → c-BIJALSRD.js} +1 -1
  46. package/dist/m/c-BJ7YQ5QZ.js +1 -0
  47. package/dist/m/{c-KIPQJX4B.js → c-BRLCTNMC.js} +1 -1
  48. package/dist/m/{c-VE6ZMYMC.js → c-BUAYFEV5.js} +1 -1
  49. package/dist/m/c-C6IPRG34.js +1 -0
  50. package/dist/m/{c-KU3ZFADW.js → c-CAS3NND4.js} +1 -1
  51. package/dist/m/{c-PS5ARVWR.js → c-CCQ25GFY.js} +1 -1
  52. package/dist/m/c-CJFDLD43.js +1 -0
  53. package/dist/m/c-COPTL5WB.js +1 -0
  54. package/dist/m/c-D3E4WJ4M.js +166 -0
  55. package/dist/m/c-D5IKEKXW.js +7 -0
  56. package/dist/m/c-DHBRA6DL.js +1 -0
  57. package/dist/m/c-DKLS74XB.js +72 -0
  58. package/dist/m/c-DVYGFTSK.js +3 -0
  59. package/dist/m/c-E3ZXARWA.js +1 -0
  60. package/dist/m/c-EK63G3CG.js +1 -0
  61. package/dist/m/c-ERQSNR6K.js +13 -0
  62. package/dist/m/c-EVYAISP3.js +1 -0
  63. package/dist/m/c-EXKHPOVC.js +3 -0
  64. package/dist/m/{c-QJ4OM3G6.js → c-FWKHM4E7.js} +1 -1
  65. package/dist/m/{c-4Q2XTQ2N.js → c-GBKB5WDL.js} +1 -1
  66. package/dist/m/c-GNDL3TKB.js +1 -0
  67. package/dist/m/c-GRWMD6O5.js +1 -0
  68. package/dist/m/c-GRXHHFPO.js +1 -0
  69. package/dist/m/c-HG2C77BM.js +4 -0
  70. package/dist/m/c-HHGJBU4D.js +1 -0
  71. package/dist/m/c-HMV6P4RX.js +1 -0
  72. package/dist/m/c-HMYWIHFG.js +1 -0
  73. package/dist/m/c-HT2DKBV2.js +1 -0
  74. package/dist/m/c-I2SCCUEW.js +1 -0
  75. package/dist/m/{c-TJ6WOJL3.js → c-ICJYHABF.js} +2 -2
  76. package/dist/m/c-IMZCWYHR.js +7 -0
  77. package/dist/m/c-IVMD3FEM.js +1 -0
  78. package/dist/m/{c-WDC5GVKU.js → c-IVTRVENZ.js} +1 -1
  79. package/dist/m/c-JKZJIUIP.js +1 -0
  80. package/dist/m/{c-UDUUJPFZ.js → c-JNLX3RJB.js} +1 -1
  81. package/dist/m/c-K3ADYNLU.js +1 -0
  82. package/dist/m/c-KGHVFRR3.js +1 -0
  83. package/dist/m/{c-5QWQ7A5L.js → c-KJJPV77R.js} +1 -1
  84. package/dist/m/{c-CZUSOB7V.js → c-KNPDOMDY.js} +1 -1
  85. package/dist/m/{c-EZU56NQV.js → c-KP64LT2A.js} +2 -2
  86. package/dist/m/c-KQ7E3PYY.js +1 -0
  87. package/dist/m/c-L3F5ZLIV.js +1 -0
  88. package/dist/m/{c-3RUU4TPX.js → c-L42OLXWM.js} +3 -2
  89. package/dist/m/c-L5VFATT6.js +1 -0
  90. package/dist/m/c-L7JL5TL3.js +3 -0
  91. package/dist/m/c-LKSL4AUJ.js +1 -0
  92. package/dist/m/c-M6FNQCTQ.js +1 -0
  93. package/dist/m/c-MCOOHCSG.js +1 -0
  94. package/dist/m/c-MHI3GYKF.js +1 -0
  95. package/dist/m/c-MWXFLW4J.js +1 -0
  96. package/dist/m/{c-5RJFTLSF.js → c-NEL7HQW3.js} +1 -1
  97. package/dist/m/{c-DCXOXBF3.js → c-NQJRVJ56.js} +1 -1
  98. package/dist/m/c-NWX3MFT4.js +1 -0
  99. package/dist/m/{c-HPURYVZS.js → c-OJYM642Q.js} +1 -1
  100. package/dist/m/c-OKXI52N7.js +1 -0
  101. package/dist/m/{c-R3L7ZJGB.js → c-OPLUZR3A.js} +1 -1
  102. package/dist/m/{c-GSFIGKOP.js → c-OTMKN2OO.js} +1 -1
  103. package/dist/m/{c-6NC5I2TV.js → c-OYRZ7XG2.js} +1 -1
  104. package/dist/m/{c-EVCQ3BKA.js → c-P3OFYUMA.js} +1 -1
  105. package/dist/m/c-PLN76GF3.js +6 -0
  106. package/dist/m/c-PLP4JKFC.js +1 -0
  107. package/dist/m/c-Q26MME6N.js +1 -0
  108. package/dist/m/{c-S7H2DRCB.js → c-Q3XOWZEV.js} +1 -1
  109. package/dist/m/{c-FRLHSY7E.js → c-QIKT6SKM.js} +1 -1
  110. package/dist/m/c-QIXT3Q7C.js +28 -0
  111. package/dist/m/c-QO4HNGCQ.js +1 -0
  112. package/dist/m/{c-JU3NK25H.js → c-R27DWQKX.js} +1 -1
  113. package/dist/m/{c-RSMOODDU.js → c-R2XUODVY.js} +1 -1
  114. package/dist/m/{c-QNKREOL6.js → c-R7LBFMF5.js} +1 -1
  115. package/dist/m/c-RND3G2S2.js +1 -0
  116. package/dist/m/{c-Q622NS2Y.js → c-S2U6NJU4.js} +1 -1
  117. package/dist/m/c-SPZPGD3R.js +1 -0
  118. package/dist/m/c-SW4YEG2D.js +8 -0
  119. package/dist/m/c-T637T7SN.js +1 -0
  120. package/dist/m/c-TJAXGIRV.js +1 -0
  121. package/dist/m/{c-RYUXUUBX.js → c-TNEM3RNM.js} +1 -1
  122. package/dist/m/c-TTB5EK4S.js +32 -0
  123. package/dist/m/c-U7SHNWDH.js +1 -0
  124. package/dist/m/c-UDHIVLYH.js +20 -0
  125. package/dist/m/{c-BBVGTQG7.js → c-UGNV5MFB.js} +1 -1
  126. package/dist/m/{c-QICP2YR5.js → c-UORXLSD3.js} +1 -1
  127. package/dist/m/c-UPD33ZPE.js +1 -0
  128. package/dist/m/c-URSMSFCB.js +1 -0
  129. package/dist/m/c-UY4QX42B.js +1 -0
  130. package/dist/m/c-V44KWI2L.js +4 -0
  131. package/dist/m/c-VILENZTD.js +1 -0
  132. package/dist/m/{c-HDDEEL77.js → c-VJYEVRYK.js} +1 -1
  133. package/dist/m/{c-SMBZG5X4.js → c-VR2BJ4AN.js} +1 -1
  134. package/dist/m/c-W4JCVLAB.js +1 -0
  135. package/dist/m/c-W6DQSHXI.js +135 -0
  136. package/dist/m/c-WBGWGOM7.js +1 -0
  137. package/dist/m/{c-4L3BTFRK.js → c-WCXLG3MV.js} +1 -1
  138. package/dist/m/c-WGW764WX.js +1 -0
  139. package/dist/m/c-WMRJKQ2V.js +5 -0
  140. package/dist/m/c-WNTYKCDG.js +1 -0
  141. package/dist/m/c-WQWIRWO3.js +72 -0
  142. package/dist/m/c-X5LNHET5.js +1 -0
  143. package/dist/m/{c-I2ZATQCD.js → c-X5TSXZYJ.js} +2 -2
  144. package/dist/m/c-XGH4GS2T.js +1 -0
  145. package/dist/m/c-Y6F2FORL.js +1 -0
  146. package/dist/m/c-YBKHUAK7.js +10 -0
  147. package/dist/m/c-YBSS55KU.js +20 -0
  148. package/dist/m/c-YCLU4UNT.js +2 -0
  149. package/dist/m/c-YVZ2L7CE.js +1 -0
  150. package/dist/m/c-ZK4GIZH2.js +1 -0
  151. package/dist/m/c-ZRXJD4G6.js +1 -0
  152. package/dist/m/c-ZWBI4HYK.js +1 -0
  153. package/dist/m/core/{admin-attrs-QHOKPJ7W.js → admin-attrs-YY7T5FGU.js} +1 -1
  154. package/dist/m/core/autosave-S6OMNDCK.js +1 -0
  155. package/dist/m/core/conflict-notice-IWHMHH43.js +1 -0
  156. package/dist/m/core/{host-permission-FNXVEFNE.js → host-permission-6EVJGNPL.js} +1 -1
  157. package/dist/m/core/is-edit-mode-GCX6767E.js +1 -0
  158. package/dist/m/core/{persist-JFYRHMRJ.js → persist-UKXV5KLA.js} +1 -1
  159. package/dist/m/core/recovery-DRFZRJED.js +1 -0
  160. package/dist/m/core/save-LYY7K6U7.js +1 -0
  161. package/dist/m/core/save-core-MKRPSEEO.js +1 -0
  162. package/dist/m/core/snapshot-NU3YM6GR.js +1 -0
  163. package/dist/m/core/unsaved-warning-7QTKEN7Z.js +1 -0
  164. package/dist/m/internals/{index-PVXGPUDA.js → index-TGLQINN3.js} +1 -1
  165. package/dist/m/loader-3BBNZZGM.js +1 -0
  166. package/dist/m/manifest-F449FF98.js +1 -0
  167. package/dist/m/manifest-edit-4396A009.js +1 -0
  168. package/dist/m/manifest.json +2111 -1573
  169. package/dist/m/page/{editor-NNJA4OKD.js → editor-6LRB3GE4.js} +123 -21
  170. package/dist/m/plugins/ai-edit-UTV7YO2I.js +6 -0
  171. package/dist/m/plugins/{cms-HP3LSTPN.js → cms-LRAOZHT7.js} +9 -9
  172. package/dist/m/plugins/{demo-RM5IR6AO.js → demo-OYO5GCAO.js} +1 -1
  173. package/dist/m/plugins/{derive-UAAA4V4S.js → derive-FRE5JJQE.js} +1 -1
  174. package/dist/m/plugins/indicator-4VDXWYTD.js +1 -0
  175. package/dist/m/plugins/live-AD4H6XSL.js +1 -0
  176. package/dist/m/plugins/menu-M5WW7DBF.js +1 -0
  177. package/dist/m/plugins/page-MD3T2ZX3.js +2 -0
  178. package/dist/m/plugins/page-view-PAWVZNFY.js +1 -0
  179. package/dist/m/plugins/{people-SGPJKANK.js → people-JCHVPF7P.js} +1 -1
  180. package/dist/m/plugins/quickcrop-BQ5YYFCH.js +26 -0
  181. package/dist/m/plugins/{richclay-NRQDSWX6.js → richclay-KLGETK77.js} +2 -2
  182. package/dist/m/plugins/sortable-4S6SQC3D.js +1 -0
  183. package/dist/m/plugins/source-TJXOIOYY.js +1 -0
  184. package/dist/m/plugins/undo-NLPGCJQY.js +1 -0
  185. package/dist/m/plugins/{unsent-HJFLQJ2O.js → unsent-OA4RGBUT.js} +1 -1
  186. package/dist/m/plugins/upgrade-HSUNDNJD.js +1 -0
  187. package/dist/m/plugins/{upload-WLYKK6TL.js → upload-NHGJXZK2.js} +1 -1
  188. package/dist/m/plugins/visitor-drafts-BW43DGY3.js +20 -0
  189. package/dist/m/plugins/visitor-drafts-owner-7ODQG7JX.js +1 -0
  190. package/dist/m/plugins/{wire-4N6GYAF6.js → wire-VBWXEXU2.js} +1 -1
  191. package/dist/m/reader-core-4W2KYEWQ.js +77 -0
  192. package/dist/m/route/route-62CHXL5B.js +1 -0
  193. package/dist/m/sync/live-sync-MO5DH33W.js +1 -0
  194. package/dist/m/ui/index-IVWN2QC4.js +1 -0
  195. package/dist/m/vendor/sap-core.vendor-RN4ZVY4X.js +6 -0
  196. package/dist/offline-manifest.json +1367 -930
  197. package/dist/page/themes/light-1.css +8 -7
  198. package/dist/server/core.cjs +1440 -288
  199. package/dist/server/offline-runtime.cjs +63 -63
  200. package/dist/server/offline-runtime.mjs +63 -63
  201. package/dist/server/page-compaction-worker.cjs +3710 -0
  202. package/dist/server/rooms.mjs +5 -0
  203. package/docs/guide.md +653 -101
  204. package/entries/sap.js +5 -5
  205. package/package.json +1 -1
  206. package/src/core/admin-contenteditable.js +5 -2
  207. package/src/core/admin-inputs.js +1 -0
  208. package/src/core/admin-onclick.js +2 -1
  209. package/src/core/conflict-notice-ui.js +4 -7
  210. package/src/core/download.js +2 -2
  211. package/src/core/host-meta.js +38 -0
  212. package/src/core/is-edit-mode.js +17 -1
  213. package/src/core/mode-key.js +125 -19
  214. package/src/core/mode-support.js +5 -0
  215. package/src/core/mode-transition.js +20 -6
  216. package/src/core/preserve-authored.js +4 -4
  217. package/src/core/recovery.js +121 -33
  218. package/src/core/save-accepted.js +33 -0
  219. package/src/core/save-core.js +106 -31
  220. package/src/core/save-job.js +108 -0
  221. package/src/core/save-prepare.js +53 -0
  222. package/src/core/save-size-notice.js +3 -1
  223. package/src/core/save-slices.js +15 -0
  224. package/src/core/save.js +557 -127
  225. package/src/core/serialize-steps.js +109 -0
  226. package/src/core/snapshot.js +170 -39
  227. package/src/core/source-map.js +83 -38
  228. package/src/core/stale-host-notice.js +1 -0
  229. package/src/core/upgrade-run.js +59 -8
  230. package/src/dom/active-element.js +5 -0
  231. package/src/lib/assets.js +1 -0
  232. package/src/lib/slice.js +65 -0
  233. package/src/lib/uimotion.js +774 -0
  234. package/src/lib/unsaved-state.js +2 -2
  235. package/src/live/fast-lane.js +10 -3
  236. package/src/live/local-lane.js +202 -11
  237. package/src/live/ops.js +16 -0
  238. package/src/live/page-compaction.js +162 -0
  239. package/src/live/server-lane.js +1 -0
  240. package/src/live/store.js +11 -3
  241. package/src/loader-logic.js +3 -1
  242. package/src/loader.js +14 -4
  243. package/src/page/adopt-boot.js +2 -1
  244. package/src/page/awareness.js +33 -2
  245. package/src/page/blocks.js +89 -27
  246. package/src/page/boot-pack.js +1 -1
  247. package/src/page/chart-tables.js +21 -3
  248. package/src/page/chart.js +406 -63
  249. package/src/page/checklist.js +10 -135
  250. package/src/page/checkpoint-proof.js +7 -1
  251. package/src/page/chrome.js +250 -51
  252. package/src/page/clipboard-shape.js +126 -0
  253. package/src/page/drag.js +33 -3
  254. package/src/page/editor.js +136 -25
  255. package/src/page/export-assets.js +357 -0
  256. package/src/page/export-html.js +209 -0
  257. package/src/page/export-markdown.js +361 -0
  258. package/src/page/features/checklist.js +428 -0
  259. package/src/page/features/export-html.js +189 -0
  260. package/src/page/features/export-markdown.js +169 -0
  261. package/src/page/features/import-markdown.js +349 -0
  262. package/src/page/features/media.js +61 -5
  263. package/src/page/features/registry.js +18 -0
  264. package/src/page/features/table.js +373 -83
  265. package/src/page/features/title-cover.js +331 -0
  266. package/src/page/features/title-icon.js +213 -0
  267. package/src/page/features/toc.js +87 -0
  268. package/src/page/format-command.js +25 -1
  269. package/src/page/format-gate.js +68 -18
  270. package/src/page/format-host.js +17 -0
  271. package/src/page/format-native-commands.js +21 -5
  272. package/src/page/image-actions.js +64 -0
  273. package/src/page/import-markdown.js +262 -0
  274. package/src/page/items.js +135 -17
  275. package/src/page/markdown.js +6 -2
  276. package/src/page/media.js +35 -119
  277. package/src/page/placeholder.js +14 -1
  278. package/src/page/projection.js +98 -10
  279. package/src/page/recover.js +10 -12
  280. package/src/page/recovery-ui.js +464 -0
  281. package/src/page/rich/chart.js +63 -7
  282. package/src/page/save-projection.js +28 -0
  283. package/src/page/save-states.js +13 -3
  284. package/src/page/schema.js +19 -3
  285. package/src/page/table-paste.js +3 -1
  286. package/src/page/table-style.js +4 -4
  287. package/src/page/table.js +44 -2
  288. package/src/page/themes/light-1.css +8 -7
  289. package/src/page/themes/light-1.source.css +8 -7
  290. package/src/page/toc-link.js +31 -0
  291. package/src/page/toc.js +5 -0
  292. package/src/page/view-hooks.js +38 -12
  293. package/src/page/view.js +13 -0
  294. package/src/page/ybind/binding.js +88 -5
  295. package/src/page/ybind/bridge.js +187 -20
  296. package/src/page/ybind/containment.js +162 -0
  297. package/src/page/ybind/doc.js +17 -9
  298. package/src/page/ybind/file-debt.js +63 -0
  299. package/src/page/ybind/layout.js +7 -2
  300. package/src/page/ybind/marks.js +1 -1
  301. package/src/page/ybind/moves.js +5 -4
  302. package/src/page/ybind/origins.js +106 -4
  303. package/src/page/ybind/parts.js +8 -1
  304. package/src/page/ybind/provider.js +113 -17
  305. package/src/page/ybind/recovery-proof.js +32 -9
  306. package/src/page/ybind/recovery-replay.js +558 -15
  307. package/src/page/ybind/recovery.js +174 -45
  308. package/src/page/ybind/table.js +67 -11
  309. package/src/page/ybind/walk-delta.js +258 -0
  310. package/src/page/ybind/walk.js +54 -29
  311. package/src/page/ybind/writer.js +1 -1
  312. package/src/plugins/ai-edit.js +13 -9
  313. package/src/plugins/indicator-chip.js +91 -0
  314. package/src/plugins/indicator.js +13 -80
  315. package/src/plugins/live.js +89 -14
  316. package/src/plugins/menu/actions.js +196 -0
  317. package/src/plugins/menu/people.js +279 -0
  318. package/src/plugins/menu/placement.js +121 -0
  319. package/src/plugins/menu/preferences.js +9 -0
  320. package/src/plugins/menu/seo.js +316 -397
  321. package/src/plugins/menu/style.js +171 -0
  322. package/src/plugins/menu/variants.js +296 -0
  323. package/src/plugins/menu.js +186 -183
  324. package/src/plugins/page-view.js +3 -2
  325. package/src/plugins/page.js +249 -44
  326. package/src/plugins/sortable.js +8 -1
  327. package/src/plugins/source.js +6 -0
  328. package/src/plugins/upgrade.js +51 -17
  329. package/src/plugins/upload-ui.js +12 -17
  330. package/src/plugins/visitor-drafts/bottom-ui.js +12 -4
  331. package/src/plugins/visitor-drafts/intro-style.js +7 -2
  332. package/src/plugins/visitor-drafts/intro.js +5 -3
  333. package/src/plugins/visitor-drafts/owner-chip.js +8 -12
  334. package/src/plugins/visitor-drafts/prompt.js +11 -9
  335. package/src/plugins/visitor-drafts/source.js +4 -3
  336. package/src/plugins/visitor-drafts/store.js +138 -9
  337. package/src/plugins/visitor-drafts/ui-memory.js +2 -2
  338. package/src/plugins/visitor-drafts-owner.js +4 -6
  339. package/src/plugins/visitor-drafts.js +5 -3
  340. package/src/recovery/store.js +1 -1
  341. package/src/route/route.js +4 -0
  342. package/src/server/rooms/index.js +5 -1
  343. package/src/server/rooms/live-data-rooms.js +302 -50
  344. package/src/server/rooms/page-compaction-worker.js +12 -0
  345. package/src/server/rooms/page-compactor.js +92 -0
  346. package/src/server/rooms/page-room-conformance.js +461 -0
  347. package/src/source/parse-steps.js +94 -0
  348. package/src/source/session.js +233 -57
  349. package/src/sync/editing-sender.js +12 -0
  350. package/src/sync/live-sync-edit.js +22 -2
  351. package/src/sync/live-sync.js +150 -23
  352. package/src/sync/page-relay.js +52 -0
  353. package/src/sync/presence-store.js +44 -4
  354. package/src/sync/presence.js +6 -3
  355. package/src/sync/saved-stream.js +11 -6
  356. package/src/ui/bevel-controls.js +1 -0
  357. package/src/ui/bevel-dialog.js +5 -2
  358. package/src/ui/editor-ui.js +77 -0
  359. package/src/ui/page-colour.js +281 -0
  360. package/src/ui/toast.js +16 -7
  361. package/src/vendor/hyper-html-api-upgrade.vendor.js +2 -2
  362. package/src/vendor/hyper-undo.vendor.js +1 -1
  363. package/src/vendor/hypercms.vendor.js +9 -9
  364. package/src/vendor/parse5.vendor.js +2 -2
  365. package/src/vendor/sap-core.vendor.js +5 -5
  366. package/dist/m/c-2SPVQSHC.js +0 -1
  367. package/dist/m/c-336SGU5W.js +0 -1
  368. package/dist/m/c-3H6BZDNJ.js +0 -6
  369. package/dist/m/c-4DFEJ2PO.js +0 -3
  370. package/dist/m/c-56QRZTZH.js +0 -1
  371. package/dist/m/c-5J4E7O4Y.js +0 -4
  372. package/dist/m/c-5LKDWQTL.js +0 -19
  373. package/dist/m/c-5V3MOVJT.js +0 -1
  374. package/dist/m/c-6AZOGAPE.js +0 -1
  375. package/dist/m/c-6CRUUXOX.js +0 -5
  376. package/dist/m/c-6HMB24EV.js +0 -1
  377. package/dist/m/c-6KEVEQ7L.js +0 -1
  378. package/dist/m/c-A3E3NIMC.js +0 -1
  379. package/dist/m/c-BQ6LOBEE.js +0 -1
  380. package/dist/m/c-BTDI4Y23.js +0 -1
  381. package/dist/m/c-CJ3A7ZKE.js +0 -1
  382. package/dist/m/c-CQHPGKX2.js +0 -1
  383. package/dist/m/c-DFS4XZJV.js +0 -2
  384. package/dist/m/c-DNENWY4O.js +0 -1
  385. package/dist/m/c-E4LIR5X5.js +0 -1
  386. package/dist/m/c-FDNHHZY5.js +0 -1
  387. package/dist/m/c-FROJUZMV.js +0 -1
  388. package/dist/m/c-G2JPKCTP.js +0 -1
  389. package/dist/m/c-GB6TU7WV.js +0 -1
  390. package/dist/m/c-GFJJEBTU.js +0 -1
  391. package/dist/m/c-GJAEGGXY.js +0 -1
  392. package/dist/m/c-GOWBDM6J.js +0 -1
  393. package/dist/m/c-HFKUVACH.js +0 -1
  394. package/dist/m/c-HHDFCNHV.js +0 -1
  395. package/dist/m/c-IEM4NTCS.js +0 -1
  396. package/dist/m/c-JDCX26UP.js +0 -25
  397. package/dist/m/c-KGVGROZT.js +0 -1
  398. package/dist/m/c-KQ6TYJAP.js +0 -135
  399. package/dist/m/c-LFPHCXY3.js +0 -1
  400. package/dist/m/c-LRPUO2MX.js +0 -1
  401. package/dist/m/c-LWLBHLVC.js +0 -3
  402. package/dist/m/c-M2L47S2X.js +0 -7
  403. package/dist/m/c-MFP2ZWD4.js +0 -1
  404. package/dist/m/c-MKSQ4Y57.js +0 -1
  405. package/dist/m/c-NUFFJVVJ.js +0 -1
  406. package/dist/m/c-NUHSPT5P.js +0 -1
  407. package/dist/m/c-O72HVYSA.js +0 -1
  408. package/dist/m/c-OIBUTDXI.js +0 -1
  409. package/dist/m/c-OW5QIGG3.js +0 -1
  410. package/dist/m/c-PGRCK73F.js +0 -1
  411. package/dist/m/c-Q7NQD65V.js +0 -1
  412. package/dist/m/c-QH63LQOS.js +0 -1
  413. package/dist/m/c-R7IWVINQ.js +0 -1
  414. package/dist/m/c-RM7J7BV2.js +0 -1
  415. package/dist/m/c-S4ZEH46B.js +0 -9
  416. package/dist/m/c-SDAXDM2D.js +0 -1
  417. package/dist/m/c-SMGU7RT3.js +0 -235
  418. package/dist/m/c-SPIORRYS.js +0 -1
  419. package/dist/m/c-SWLRT66R.js +0 -1
  420. package/dist/m/c-TCJTVAFN.js +0 -1
  421. package/dist/m/c-TQEMVJCS.js +0 -1
  422. package/dist/m/c-TYLXX4NF.js +0 -21
  423. package/dist/m/c-U62OB4BT.js +0 -1
  424. package/dist/m/c-U6YWUAR3.js +0 -8
  425. package/dist/m/c-UDCSU5G5.js +0 -2
  426. package/dist/m/c-VI5RMSVY.js +0 -1
  427. package/dist/m/c-VRZN56XY.js +0 -1
  428. package/dist/m/c-W5MCHEGA.js +0 -1
  429. package/dist/m/c-WNYBLIOZ.js +0 -1
  430. package/dist/m/c-WWXIDH4O.js +0 -28
  431. package/dist/m/c-XCNTK76U.js +0 -1
  432. package/dist/m/c-XMS6DPBR.js +0 -1
  433. package/dist/m/c-ZUCOKOHT.js +0 -1
  434. package/dist/m/c-ZVPVXTJF.js +0 -4
  435. package/dist/m/c-ZVRKXKM7.js +0 -1
  436. package/dist/m/core/autosave-HRYGUWV6.js +0 -1
  437. package/dist/m/core/conflict-notice-6MROJN2L.js +0 -1
  438. package/dist/m/core/is-edit-mode-KTWA3O5N.js +0 -1
  439. package/dist/m/core/recovery-FLTCC2OC.js +0 -1
  440. package/dist/m/core/save-HQZ4S667.js +0 -1
  441. package/dist/m/core/save-core-KGQWFUNH.js +0 -1
  442. package/dist/m/core/snapshot-EGQZNT45.js +0 -1
  443. package/dist/m/core/unsaved-warning-IDJLD66H.js +0 -1
  444. package/dist/m/loader-S4I7GKXR.js +0 -1
  445. package/dist/m/manifest-4C419D67.js +0 -1
  446. package/dist/m/manifest-edit-B077F288.js +0 -1
  447. package/dist/m/plugins/ai-edit-QN4PMMNL.js +0 -6
  448. package/dist/m/plugins/indicator-URDBBOQO.js +0 -1
  449. package/dist/m/plugins/live-HFWD4OIH.js +0 -1
  450. package/dist/m/plugins/menu-3HIEQSI6.js +0 -138
  451. package/dist/m/plugins/page-JOKB6XPR.js +0 -2
  452. package/dist/m/plugins/page-view-NXOJHNW6.js +0 -1
  453. package/dist/m/plugins/quickcrop-QNY3PKLD.js +0 -26
  454. package/dist/m/plugins/sortable-GWT4PWDV.js +0 -1
  455. package/dist/m/plugins/source-4ZRSAIYM.js +0 -1
  456. package/dist/m/plugins/undo-VDA5P7FH.js +0 -1
  457. package/dist/m/plugins/upgrade-W7FG5VFG.js +0 -1
  458. package/dist/m/plugins/visitor-drafts-LIDY7NH6.js +0 -21
  459. package/dist/m/plugins/visitor-drafts-owner-ZXCKBZE7.js +0 -1
  460. package/dist/m/reader-core-DXYCURFF.js +0 -68
  461. package/dist/m/route/route-KOCZSEGN.js +0 -1
  462. package/dist/m/sync/live-sync-J7VMYTKS.js +0 -1
  463. package/dist/m/ui/index-3JLVI27O.js +0 -1
  464. package/dist/m/vendor/sap-core.vendor-A7BMUYZT.js +0 -6
  465. /package/dist/m/{c-FILLTJA7.js → c-QTTJYJMA.js} +0 -0
  466. /package/dist/m/plugins/{quickcrop-QNY3PKLD.js.LEGAL.txt → quickcrop-BQ5YYFCH.js.LEGAL.txt} +0 -0
  467. /package/dist/m/plugins/{richclay-NRQDSWX6.js.LEGAL.txt → richclay-KLGETK77.js.LEGAL.txt} +0 -0
package/src/loader.js CHANGED
@@ -86,10 +86,11 @@ export async function boot(base, params, readyResolve, manifest = null, suppleme
86
86
  const regionPolicy = await MODULES["lib/region-policy.js"]();
87
87
 
88
88
  const hasSap = Boolean(document.querySelector("[sap]"));
89
+ const hasVariants = document.querySelectorAll("head style[clay-variant]").length >= 2;
89
90
  // derive.js imports the sapjs core only when no sap.js script took the page over.
90
91
  const hasSapJs = Boolean(document.querySelector('script[src*="sap.js"]'));
91
92
  bootPhase.holdSettle = hasSap && isEditMode;
92
- const plan = resolveModules(params, isEditMode, { isDraftMode, hasSap, canEdit, templateSource: templateSource() });
93
+ const plan = resolveModules(params, isEditMode, { isDraftMode, hasSap, hasVariants, canEdit, templateSource: templateSource() });
93
94
  // Where edits land, resolved once: a visitor draft saves into its draft slot, the
94
95
  // demo plugin into localStorage, and everything else to the host. setMode takes no
95
96
  // destination, and V4 has no draft-to-host transition.
@@ -126,16 +127,22 @@ export async function boot(base, params, readyResolve, manifest = null, suppleme
126
127
  // Nothing is fetched for it here: the decision and the controller behind it wait for the
127
128
  // first switch, so this costs a reader with a declaration no more than one attribute.
128
129
  if (document.documentElement.getAttribute("clay-mode-switch") === "live") {
129
- const editing = resolveModules(params, true, { isDraftMode, hasSap, canEdit, templateSource: templateSource() });
130
+ const editing = resolveModules(params, true, { isDraftMode, hasSap, hasVariants, canEdit, templateSource: templateSource() });
130
131
  loaded["core/edit-mode.js"].noteLiveSwitch({
131
132
  edit: editing,
132
133
  // The plan a view boot would have resolved, not the edit plan this boot resolved: an
133
134
  // exit imports it and starts its reader, and an edit-only module belongs to the
134
135
  // session being left.
135
- view: resolveModules(params, false, { isDraftMode, hasSap, canEdit, templateSource: templateSource() }),
136
+ view: resolveModules(params, false, { isDraftMode, hasSap, hasVariants, canEdit, templateSource: templateSource() }),
136
137
  loaded,
137
138
  modules: MODULES,
138
- attach: attachPluginMember,
139
+ // A live entry attaches the edit plugins after boot: clay.plugins names them from then on.
140
+ attach: (path, mod) => {
141
+ attachPluginMember(path, mod);
142
+ const name = PLUGIN_NAMES[path];
143
+ const named = window.clay.plugins;
144
+ if (name && Array.isArray(named) && !named.includes(name)) window.clay.plugins = Object.freeze([...named, name]);
145
+ },
139
146
  attachEditCore,
140
147
  announce,
141
148
  loadEditHints: loadEditHints ? editHints(loadEditHints, manifest, editing, hasSapJs) : null,
@@ -146,6 +153,9 @@ export async function boot(base, params, readyResolve, manifest = null, suppleme
146
153
  // leases before a plugin can take input. A reader returns at the first line.
147
154
  await loaded["core/edit-mode.js"].activateInitialMode();
148
155
  window.clay.plugins = Object.freeze([...plan.plugins, ...plan.late].map((path) => PLUGIN_NAMES[path]));
156
+ // What an edit session here would load, so view-mode chrome can offer an edit-only feature.
157
+ const editPlan = isEditMode ? plan : resolveModules(params, true, { isDraftMode, hasSap, hasVariants, canEdit, templateSource: templateSource() });
158
+ window.clay.editPlugins = Object.freeze([...editPlan.plugins, ...editPlan.late].map((path) => PLUGIN_NAMES[path]));
149
159
 
150
160
  for (const path of plan.plugins) {
151
161
  // A plugin that throws on evaluation degrades to absent. Unguarded, its
@@ -54,6 +54,7 @@ export function installAdoption({
54
54
  notice = () => {},
55
55
  snapshot = () => null,
56
56
  mergeTagless = false,
57
+ seeded = false,
57
58
  writerReady = () => Promise.resolve(),
58
59
  adopted = () => {},
59
60
  hold = suspendAutosave,
@@ -216,7 +217,7 @@ export function installAdoption({
216
217
  }
217
218
 
218
219
  doc.addEventListener("clay:sync-applied", onFrame);
219
- if (source) run(source, true);
220
+ if (source && !seeded) run(source, true);
220
221
 
221
222
  return {
222
223
  // Resolves once everything queued so far has been attempted, with the boot
@@ -54,6 +54,12 @@ const caretElement = (doc, name, color) => {
54
54
 
55
55
  const labelOf = (person) => (typeof person.name === "string" && person.name.trim() ? person.name.trim() : "Someone");
56
56
 
57
+ let barrier = false;
58
+ if (typeof document !== "undefined") {
59
+ document.addEventListener("clay:presence-quiesce", () => { barrier = true; });
60
+ document.addEventListener("clay:presence-resume", () => { barrier = false; });
61
+ }
62
+
57
63
  /**
58
64
  * The decorations one snapshot produces in one document.
59
65
  *
@@ -104,14 +110,20 @@ export function createPageAwareness({ binding, view, store = presenceStore, epoc
104
110
  styleWithLegacyId(STYLE_ID, STYLE_CSS, STYLE_ID, ["editor-ui"]);
105
111
  const doc = view.dom.ownerDocument;
106
112
  let disposed = false;
107
- let focused = true;
113
+ // The exit's barrier, and the clear that came with it: while it runs this tab
114
+ // publishes nothing, so a caret move or a doc change during the barrier cannot put
115
+ // a target back the session is about to release.
116
+ let quiesced = barrier;
117
+ // Focus is a fact about the document, not a guess: an editor mounted in a background
118
+ // tab is not focused, and publishing a target for it would claim a caret nobody holds.
119
+ let focused = typeof view.hasFocus === "function" ? view.hasFocus() === true : view.dom.contains(doc.activeElement);
108
120
  let pending = null;
109
121
  const isComposing = () => (composing ? composing() === true : view.composing === true);
110
122
 
111
123
  const supported = () => store.getSnapshot().pageAwareness !== false;
112
124
 
113
125
  const publish = (state = view.state) => {
114
- if (disposed) return;
126
+ if (disposed || quiesced) return;
115
127
  if (!supported() || !focused || isComposing()) {
116
128
  store.setTarget(null);
117
129
  return;
@@ -167,6 +179,19 @@ export function createPageAwareness({ binding, view, store = presenceStore, epoc
167
179
  schedule();
168
180
  });
169
181
 
182
+ // The edit participant reaches these, so the page's target goes quiet with the
183
+ // sender during the exit's barrier and comes back with it on a refused exit.
184
+ const quiesce = () => {
185
+ if (disposed) return;
186
+ quiesced = true;
187
+ store.setTarget(null);
188
+ };
189
+ const resume = () => {
190
+ if (disposed) return;
191
+ quiesced = false;
192
+ publish();
193
+ };
194
+
170
195
  const onFocus = () => { focused = true; publish(); schedule(); };
171
196
  const onBlur = () => { focused = false; store.setTarget(null); };
172
197
  const onHide = () => { store.setTarget(null); };
@@ -176,6 +201,8 @@ export function createPageAwareness({ binding, view, store = presenceStore, epoc
176
201
  view.dom.addEventListener("blur", onBlur);
177
202
  view.dom.addEventListener("compositionend", onCompositionEnd);
178
203
  doc.addEventListener("pagehide", onHide);
204
+ doc.addEventListener("clay:presence-quiesce", quiesce);
205
+ doc.addEventListener("clay:presence-resume", resume);
179
206
  view.updateState(view.state.reconfigure({ plugins: [...view.state.plugins, plugin] }));
180
207
  publish();
181
208
  schedule();
@@ -184,6 +211,8 @@ export function createPageAwareness({ binding, view, store = presenceStore, epoc
184
211
  epoch,
185
212
  refresh,
186
213
  plugin,
214
+ quiesce,
215
+ resume,
187
216
  get decorations() {
188
217
  return awarenessKey.getState(view.state) ?? DecorationSet.empty;
189
218
  },
@@ -199,6 +228,8 @@ export function createPageAwareness({ binding, view, store = presenceStore, epoc
199
228
  view.dom.removeEventListener("blur", onBlur);
200
229
  view.dom.removeEventListener("compositionend", onCompositionEnd);
201
230
  doc.removeEventListener("pagehide", onHide);
231
+ doc.removeEventListener("clay:presence-quiesce", quiesce);
232
+ doc.removeEventListener("clay:presence-resume", resume);
202
233
  store.setTarget(null);
203
234
  store.releaseTarget();
204
235
  if (!view.isDestroyed) {
@@ -9,7 +9,7 @@ import { safeHref, safeSrc } from "./link.js";
9
9
  import { flatten, runsOf, unflatten, unitsOf } from "./inline.js";
10
10
  import { OPAQUE_MARK, opaqueMark } from "./format-codec.js";
11
11
  import { NATIVE_NAMES, nativeAttrs } from "./format-native.js";
12
- import { DEFAULTS, MARKS, OPAQUE, envelopeAttrs, envelopeRecord, marksAttrs, marksEntries } from "./projection.js";
12
+ import { DEFAULTS, MARKS, OPAQUE, envelopeAttrs, envelopeRecord, marksAttrs, marksEntries, toggleLevel } from "./projection.js";
13
13
 
14
14
  const alignOf = (a) => (a === "left" || a === "right" ? a : null);
15
15
 
@@ -37,7 +37,9 @@ const asStep = (dispatch) => dispatch && ((tr) => dispatch(history.closeHistory(
37
37
  // hidden some toggle above it is closed
38
38
  // subEnd index of the last block of its subtree (itself when it has none)
39
39
  // A subtree is always contiguous, so it is the range [ents[i].at, ents[subEnd].end].
40
- export function outline(doc) {
40
+ // `reveal` is a set of toggle ids a link opened for this reader only: a revealed
41
+ // toggle reads as open here, and its saved `open` is untouched.
42
+ export function outline(doc, reveal = null) {
41
43
  const ents = [];
42
44
  const toggleAt = new Map();
43
45
  let run = [];
@@ -53,8 +55,9 @@ export function outline(doc) {
53
55
  if (run.length) up = run[run.length - 1];
54
56
  run.push(i);
55
57
  } else run = [];
56
- const hidden = t >= 0 && (ents[t].hidden || !ents[t].node.attrs.open);
57
- ents.push({ node, at, end: at + node.nodeSize, i, up, depth: t >= 0 ? ents[t].depth + 1 : 0, hidden, subEnd: i });
58
+ const open = isToggle(node) && (node.attrs.open || !!reveal?.has(node.attrs.id));
59
+ const hidden = t >= 0 && (ents[t].hidden || !ents[t].open);
60
+ ents.push({ node, at, end: at + node.nodeSize, i, up, depth: t >= 0 ? ents[t].depth + 1 : 0, hidden, open, subEnd: i });
58
61
  if (isToggle(node) && node.attrs.id) toggleAt.set(node.attrs.id, i);
59
62
  });
60
63
  for (let j = ents.length - 1; j >= 0; j--) {
@@ -131,11 +134,19 @@ export function structureFixes(doc, oldDoc = null) {
131
134
  }
132
135
 
133
136
  export function structurePlugin() {
137
+ const valid = new WeakSet();
134
138
  return new Plugin({
135
139
  appendTransaction(trs, old, next) {
136
140
  if (!trs.some((tr) => tr.docChanged && !tr.getMeta(REMOTE))) return null;
141
+ if (valid.has(old.doc) && sameStructure(old.doc, next.doc)) {
142
+ valid.add(next.doc);
143
+ return null;
144
+ }
137
145
  const fixes = structureFixes(next.doc, old.doc);
138
- if (!fixes.length) return null;
146
+ if (!fixes.length) {
147
+ valid.add(next.doc);
148
+ return null;
149
+ }
139
150
  const tr = next.tr;
140
151
  for (const f of fixes) tr.setNodeMarkup(f.at, null, f.attrs);
141
152
  return tr;
@@ -643,9 +654,22 @@ export function backspaceBodyBlock(st, dispatch) {
643
654
 
644
655
  // ---- open / closed ----------------------------------------------------------
645
656
 
657
+ // A reveal is edit-mode state, never a document attribute: the toggle ids a followed link
658
+ // opened live in the collapse plugin's own state, so nothing is saved, no undo step is
659
+ // made and no peer is told.
660
+ export const REVEAL = "page-reveal";
661
+
662
+ export function revealToggles(tr, ids) {
663
+ return ids.length ? tr.setMeta(REVEAL, { add: ids }) : tr;
664
+ }
665
+
666
+ // A toggle the person opens or closes themselves drops any reveal a link left on it:
667
+ // the override never outlives the decision it saved them.
646
668
  export function setOpen(st, ti, open, ents = outline(st.doc)) {
647
669
  const e = ents[ti];
648
- return st.tr.setNodeMarkup(e.at, null, { ...e.node.attrs, open }).setMeta("addToHistory", false);
670
+ return st.tr.setNodeMarkup(e.at, null, { ...e.node.attrs, open })
671
+ .setMeta("addToHistory", false)
672
+ .setMeta(REVEAL, { clear: [e.node.attrs.id] });
649
673
  }
650
674
 
651
675
  export function toggleOpenAtSelection(st, dispatch) {
@@ -662,7 +686,7 @@ export function toggleOpenAtSelection(st, dispatch) {
662
686
  export function hiddenRanges(ents) {
663
687
  const out = [];
664
688
  for (const e of ents) {
665
- if (!isToggle(e.node) || e.hidden || e.node.attrs.open || e.subEnd === e.i) continue;
689
+ if (!isToggle(e.node) || e.hidden || e.open || e.subEnd === e.i) continue;
666
690
  out.push({ line: e.at + 1, sumEnd: e.end - 1, from: e.end, to: ents[e.subEnd].end });
667
691
  }
668
692
  return out;
@@ -759,35 +783,55 @@ export function sameStructure(a, b) {
759
783
  return true;
760
784
  }
761
785
 
762
- function collapseState(doc) {
763
- const ents = outline(doc);
764
- return { decos: decorationsFor(doc, ents), ranges: hiddenRanges(ents) };
786
+ const NO_REVEAL = new Set();
787
+
788
+ function collapseState(doc, reveal = NO_REVEAL) {
789
+ const ents = outline(doc, reveal);
790
+ return { decos: decorationsFor(doc, ents), ranges: hiddenRanges(ents), reveal };
765
791
  }
766
792
 
793
+ // The block decorations of a long document in one linear pass. ProseMirror's
794
+ // DecorationSet scans every top-level node decoration for each child the view
795
+ // visits and each decoration it maps, which is quadratic in blocks; this set
796
+ // holds only node decorations at the top and finds a toggle's widget by binary
797
+ // search. It is built directly in document order instead of through create().
798
+ let OutlineSet = null;
799
+ const outlineSet = () => OutlineSet ??= class extends pmView.DecorationSet {
800
+ forChild(offset, node) {
801
+ if (node.isLeaf) return pmView.DecorationSet.empty;
802
+ const c = this.children;
803
+ let lo = 0, hi = c.length / 3;
804
+ while (lo < hi) { const mid = (lo + hi) >> 1; if (c[mid * 3] < offset) lo = mid + 1; else hi = mid; }
805
+ return lo * 3 < c.length && c[lo * 3] === offset ? c[lo * 3 + 2] : pmView.DecorationSet.empty;
806
+ }
807
+ };
808
+
767
809
  export function decorationsFor(doc, ents = outline(doc)) {
768
810
  const { Decoration, DecorationSet } = pmView;
769
811
  const markers = orderedMarkers(ents);
770
- const decos = [];
812
+ const local = [], children = [];
771
813
  for (const e of ents) {
772
814
  const attrs = {};
773
815
  if (e.hidden) { attrs.class = "page-hidden"; attrs["aria-hidden"] = "true"; }
774
816
  if (e.depth) attrs.style = `--page-depth:${e.depth}`;
775
817
  if (markers.has(e.i)) attrs["data-marker"] = markers.get(e.i);
776
- if (isToggle(e.node)) attrs["aria-expanded"] = e.node.attrs.open ? "true" : "false";
777
- if (Object.keys(attrs).length) decos.push(Decoration.node(e.at, e.end, attrs));
818
+ if (isToggle(e.node)) attrs["aria-expanded"] = e.open ? "true" : "false";
819
+ if (Object.keys(attrs).length) local.push(Decoration.node(e.at, e.end, attrs));
778
820
  if (isToggle(e.node) && !e.hidden) {
779
- decos.push(Decoration.widget(e.at + 1, () => disclosure(e.node), { side: -1, ignoreSelection: true, key: `t:${e.node.attrs.id}:${e.node.attrs.open}` }));
821
+ const widget = Decoration.widget(0, () => disclosure(e.node, e.open), { side: -1, ignoreSelection: true, key: `t:${e.node.attrs.id}:${e.open}` });
822
+ children.push(e.at, e.end, new DecorationSet([widget], []));
780
823
  }
781
824
  }
782
- return DecorationSet.create(doc, decos);
825
+ if (!local.length && !children.length) return DecorationSet.empty;
826
+ return new (outlineSet())(local, children);
783
827
  }
784
828
 
785
- function disclosure(node) {
829
+ function disclosure(node, open = node.attrs.open) {
786
830
  const b = document.createElement("button");
787
831
  b.type = "button";
788
832
  b.className = "page-toggle-button";
789
833
  b.contentEditable = "false";
790
- b.setAttribute("aria-label", node.attrs.open ? "Collapse" : "Expand");
834
+ b.setAttribute("aria-label", open ? "Collapse" : "Expand");
791
835
  b.setAttribute("data-toggle", node.attrs.id || "");
792
836
  return b;
793
837
  }
@@ -799,13 +843,15 @@ export function collapsePlugin() {
799
843
  state: {
800
844
  init: (_, s) => collapseState(s.doc),
801
845
  apply(tr, value, old, s) {
846
+ const meta = tr.getMeta(REVEAL);
847
+ if (meta) {
848
+ const reveal = new Set(value.reveal);
849
+ for (const id of meta.add ?? []) reveal.add(id);
850
+ for (const id of meta.clear ?? []) reveal.delete(id);
851
+ return collapseState(s.doc, reveal);
852
+ }
802
853
  if (!tr.docChanged) return value;
803
- if (!sameStructure(old.doc, s.doc)) return collapseState(s.doc);
804
- const m = tr.mapping;
805
- return {
806
- decos: value.decos.map(m, s.doc),
807
- ranges: value.ranges.map((r) => ({ line: m.map(r.line, -1), sumEnd: m.map(r.sumEnd), from: m.map(r.from), to: m.map(r.to, -1) })),
808
- };
854
+ return collapseState(s.doc, value.reveal);
809
855
  },
810
856
  },
811
857
  appendTransaction(trs, old, next) {
@@ -1002,7 +1048,12 @@ export function flattenPastedHTML(html, doc = globalThis.document) {
1002
1048
  t.setAttribute("data-page-toggle", k);
1003
1049
  if (child.hasAttribute("open")) t.setAttribute("data-open", "true");
1004
1050
  if (parentKey) t.setAttribute("data-page-parent", parentKey);
1005
- if (summary) t.append(...summary.childNodes);
1051
+ // A toggle heading saves as a heading in its summary: keep the level, paste its text.
1052
+ const head = summary?.querySelector(":scope > h1, :scope > h2, :scope > h3");
1053
+ if (head) {
1054
+ t.setAttribute("data-level", head.tagName[1]);
1055
+ t.append(...head.childNodes);
1056
+ } else if (summary) t.append(...summary.childNodes);
1006
1057
  target.appendChild(t);
1007
1058
  for (const c of [...child.childNodes]) if (c !== summary) { const box = doc.createElement("div"); box.appendChild(c); walk(box, k, target); }
1008
1059
  continue;
@@ -1043,6 +1094,8 @@ export function flattenPastedHTML(html, doc = globalThis.document) {
1043
1094
  if (parent) for (const piece of pieces) piece.setAttribute("data-page-parent", parent);
1044
1095
  child.replaceWith(...pieces);
1045
1096
  }
1097
+ const sliced = root.querySelector("[data-pm-slice]");
1098
+ if (sliced) out.firstElementChild?.setAttribute("data-pm-slice", sliced.dataset.pmSlice);
1046
1099
  return out.innerHTML;
1047
1100
  }
1048
1101
 
@@ -1080,14 +1133,19 @@ const pastedOpaqueMarks = (dom) => {
1080
1133
  try { return { entries: marksEntries(dom.getAttribute(MARKS)) }; } catch { return false; }
1081
1134
  };
1082
1135
 
1136
+ // clipboard-shape.js: lists and tables on the clipboard.
1137
+ let shape = null;
1138
+ export const loadClipboardShape = () => import("./clipboard-shape.js").then((mod) => { shape = mod; }, () => {});
1139
+
1083
1140
  // The clipboard parser: the schema has toDOM only, so paste gets its own rules.
1084
1141
  export const clipboardParser = new model.DOMParser(parseSchema, [
1142
+ { tag: "table", node: "table", getAttrs: (d) => shape?.table(d) ?? false, getContent: (d) => shape.rows(d) },
1085
1143
  { tag: `div[${OPAQUE}]`, node: "opaque_block", getAttrs: pastedOpaque, getContent: pastedOpaqueContent },
1086
1144
  { tag: `span[${MARKS}]`, mark: OPAQUE_MARK, getAttrs: pastedOpaqueMarks },
1087
1145
  { tag: "div[data-page-li]", node: "list_item", getAttrs: (d) => ({ kind: d.getAttribute("data-kind") || "bullet", indent: +d.getAttribute("data-indent") || 0, checked: d.getAttribute("data-checked") === "true", parent: parentAttr(d) }) },
1088
1146
  { tag: "div.page-li", node: "list_item", getAttrs: (d) => ({ kind: d.getAttribute("data-kind") || "bullet", indent: +d.getAttribute("data-indent") || 0, checked: d.getAttribute("data-checked") === "true", parent: parentAttr(d) }) },
1089
- { tag: "div[data-page-toggle]", node: "toggle", getAttrs: (d) => ({ id: d.getAttribute("data-page-toggle"), open: d.getAttribute("data-open") === "true", parent: parentAttr(d) }) },
1090
- { tag: "div.page-toggle", node: "toggle", getAttrs: (d) => ({ id: d.getAttribute("data-id"), open: d.getAttribute("data-open") === "true", parent: null }) },
1147
+ { tag: "div[data-page-toggle]", node: "toggle", getAttrs: (d) => ({ id: d.getAttribute("data-page-toggle"), open: d.getAttribute("data-open") === "true", parent: parentAttr(d), level: toggleLevel(Number(d.getAttribute("data-level"))) }) },
1148
+ { tag: "div.page-toggle", node: "toggle", getAttrs: (d) => ({ id: d.getAttribute("data-id"), open: d.getAttribute("data-open") === "true", parent: null, level: toggleLevel(Number(d.getAttribute("data-level"))) }) },
1091
1149
  { tag: "h1", node: "heading", getAttrs: (d) => ({ level: 1, parent: parentAttr(d) }) },
1092
1150
  { tag: "h2", node: "heading", getAttrs: (d) => ({ level: 2, parent: parentAttr(d) }) },
1093
1151
  { tag: "h3", node: "heading", getAttrs: (d) => ({ level: 3, parent: parentAttr(d) }) },
@@ -1173,6 +1231,7 @@ class ClipboardSerializer extends model.DOMSerializer {
1173
1231
  if (isToggle(n) && n.attrs.id) dom.setAttribute("data-page-toggle", n.attrs.id);
1174
1232
  if (n.type === N.image && n.attrs.width) dom.setAttribute("data-width", String(n.attrs.width));
1175
1233
  });
1234
+ shape?.copy(fragment, doms);
1176
1235
  return out;
1177
1236
  }
1178
1237
  }
@@ -1223,9 +1282,10 @@ function writesFormat(slice) {
1223
1282
 
1224
1283
  function pasteFormat(view, event, slice) {
1225
1284
  const from = view.state.selection.from, to = view.state.selection.to;
1285
+ const before = view.state.doc;
1226
1286
  const plain = () => {
1227
1287
  const text = slice.content.textBetween(0, slice.content.size, "\n", " ");
1228
- if (!view.isDestroyed && text) view.dispatch(view.state.tr.insertText(text, from, to));
1288
+ if (!view.isDestroyed && text && view.state.doc === before) view.dispatch(view.state.tr.insertText(text, from, to));
1229
1289
  return false;
1230
1290
  };
1231
1291
  import("./format-native-commands.js").then(({ pasteFormats }) => pasteFormats(view, slice, from, to), plain);
@@ -1234,12 +1294,14 @@ function pasteFormat(view, event, slice) {
1234
1294
 
1235
1295
  export function pastePlugin() {
1236
1296
  return new Plugin({
1297
+ view() { loadClipboardShape(); return {}; },
1237
1298
  props: {
1238
1299
  handlePaste(view, event, slice) {
1239
1300
  if (writesFormat(slice)) return pasteFormat(view, event, slice);
1240
1301
  return pasteIntoClosedSummary(view, event, slice);
1241
1302
  },
1242
1303
  clipboardSerializer,
1304
+ clipboardTextSerializer: (slice) => shape?.text(slice),
1243
1305
  transformPastedHTML: (html) => flattenPastedHTML(html),
1244
1306
  clipboardParser,
1245
1307
  clipboardTextParser: (text, _$ctx, plain) => (plain ? null : parseListText(text)),
@@ -14,7 +14,7 @@ export { installAdoption, ADOPTION_TIMEOUT_MS } from "./adopt-boot.js";
14
14
  export { classifyFile, readBack } from "./adopt.js";
15
15
  export { mergePageModels } from "./merge.js";
16
16
  export { canon } from "./projection.js";
17
- export { renderFromTags } from "./save-projection.js";
17
+ export { renderFromTags, acceptedPageState } from "./save-projection.js";
18
18
  export { blocksFromYValue } from "./ybind/decode.js";
19
19
  export { createYPageBinding } from "./ybind/binding.js";
20
20
  export { yValueOf } from "./ybind/provider.js";
@@ -1,11 +1,29 @@
1
1
  import { schema } from "./schema.js";
2
2
  import { orderedIds } from "./model.js";
3
3
 
4
- // The tables a chart can be drawn from: a top-level table with at least one
5
- // column. The insert menu reads this without the chart module itself, which only
4
+ // The tables a chart can be drawn from: a top-level table with a labels column
5
+ // and at least one more to plot. The insert menu reads this without the chart module itself, which only
6
6
  // a document that takes a chart loads.
7
7
  export function chartTables(doc) {
8
8
  const tables = [];
9
- doc.forEach((node) => { if (node.type === schema.nodes.table && orderedIds(node.attrs.cols).length) tables.push(node); });
9
+ doc.forEach((node) => { if (node.type === schema.nodes.table && orderedIds(node.attrs.cols).length > 1) tables.push(node); });
10
10
  return tables;
11
11
  }
12
+
13
+ // A table's name for a person: the heading before it with no other table in
14
+ // between, else its place among the tables, so a chart and the picker name it
15
+ // without a stored title.
16
+ export function tableName(doc, tableId) {
17
+ let name = "";
18
+ let count = 0;
19
+ let found = null;
20
+ doc.forEach((node) => {
21
+ if (found !== null) return;
22
+ if (node.type === schema.nodes.heading) name = node.textContent;
23
+ if (node.type !== schema.nodes.table) return;
24
+ count += 1;
25
+ if (node.attrs.id === tableId) found = name || `Table ${count}`;
26
+ name = "";
27
+ });
28
+ return found;
29
+ }