@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
@@ -41,21 +41,24 @@ function walkFlow(pd, index) {
41
41
  const liveSources = new Set(liveBySource.keys());
42
42
  const movedSources = new Set();
43
43
  const retired = [];
44
+ const copyBoundary = (client, clock) => {
45
+ const sourceKey = `${client}.${clock}`;
46
+ const record = index.boundaryOf({ client, clock });
47
+ if (!record || record.kind !== "copy") return;
48
+ if (intents.copyActive.has(sourceKey)) { if (record.recoveryOf) movedSources.add(record.recoveryOf); }
49
+ else if (liveSources.has(sourceKey)) retired.push({ key: copyActiveKey(sourceKey), sourceKey, source: { client, clock }, operationId: null, blockId: record.blockId, end: null, sv: [], legacy: false, implicit: true });
50
+ };
51
+ const markers = index.markers?.() ?? null;
44
52
  const candidateSets = new Map();
45
- for (const key of pd.origins.keys()) {
53
+ if (markers) {
54
+ for (const entry of markers.records) if (entry.live && entry.kind === "boundary") copyBoundary(entry.client, entry.clock);
55
+ } else for (const key of pd.origins.keys()) {
46
56
  let parts;
47
57
  try { parts = JSON.parse(key); } catch { continue; }
48
58
  if (!Array.isArray(parts) || parts.length !== 3 || (parts[0] !== "boundary" && parts[0] !== "alias")) continue;
49
59
  const [, client, clock] = parts;
50
60
  if (!Number.isSafeInteger(client) || client < 0 || !Number.isSafeInteger(clock) || clock < 0) continue;
51
- if (parts[0] === "boundary") {
52
- const sourceKey = `${client}.${clock}`;
53
- const record = index.boundaryOf({ client, clock });
54
- if (record && record.kind === "copy") {
55
- if (intents.copyActive.has(sourceKey)) { if (record.recoveryOf) movedSources.add(record.recoveryOf); }
56
- else if (liveSources.has(sourceKey)) retired.push({ key: copyActiveKey(sourceKey), sourceKey, source: { client, clock }, operationId: null, blockId: record.blockId, end: null, sv: [], legacy: false, implicit: true });
57
- }
58
- }
61
+ if (parts[0] === "boundary") copyBoundary(client, clock);
59
62
  const clocks = candidateSets.get(client) ?? candidateSets.set(client, new Set()).get(client);
60
63
  clocks.add(clock);
61
64
  }
@@ -113,7 +116,7 @@ function walkFlow(pd, index) {
113
116
  for (const key of restore.covers) set.add(key);
114
117
  }
115
118
  const recoveredMarkers = new Map();
116
- for (let it = pd.flow._start; it; it = it.right) {
119
+ if (restoredSources.size) for (let it = pd.flow._start; it; it = it.right) {
117
120
  if (it.deleted) continue;
118
121
  const source = it.content instanceof Y.ContentEmbed ? markerSource(it, it.content.embed && it.content.embed.b) : null;
119
122
  if (source === null) continue;
@@ -131,9 +134,13 @@ function walkFlow(pd, index) {
131
134
  const segs = [];
132
135
  const orphans = [];
133
136
  const hidden = [];
134
- const fences = [];
137
+ const fences = [], stops = [];
135
138
  let cur = null, prevId = "start", hiding = null, at = 0;
136
139
  const cattrs = {};
140
+ let styled = null;
141
+ // The format state a block starts and ends with, so one block can be walked again on its
142
+ // own (walk-delta.js) and the next block's marks proven unchanged.
143
+ const fmt = () => { for (const key in cattrs) return { ...cattrs }; return null; };
137
144
  const typeOf = (id) => { const m = pd.attrs.get(id); return (m && m.get("t")) || "paragraph"; };
138
145
  const hideUnit = (len) => {
139
146
  if (!len) return;
@@ -145,12 +152,16 @@ function walkFlow(pd, index) {
145
152
  const id = `recovered:${sourceKey}`;
146
153
  const t = root ? root.type : "paragraph";
147
154
  const opaque = !Object.hasOwn(schema.nodes, t);
148
- cur = { kind: "b", id, baseId: id, brk: { client: it.id.client, clock: it.id.clock }, implicit: false, runs: [], len: 1, atom: !opaque && !schema.nodes[t]?.isTextblock, opaque, recovered: true, restored: !moved, sourceKey, t, fields: root ? root.attrs : null };
155
+ const f = fmt();
156
+ if (cur) cur.fmtOut = f;
157
+ cur = { kind: "b", id, baseId: id, brk: { client: it.id.client, clock: it.id.clock }, implicit: false, runs: [], len: 1, atom: !opaque && !schema.nodes[t]?.isTextblock, opaque, recovered: true, restored: !moved, sourceKey, t, fields: root ? root.attrs : null, fmtIn: f, fmtOut: null };
149
158
  segs.push(cur);
150
159
  prevId = id;
151
160
  };
152
161
  const open = (id, brk, implicit) => {
153
- cur = { kind: "b", id, baseId: id, brk, implicit, runs: [], len: implicit ? 0 : 1, atom: false, items: !implicit && (markerCount.get(id) ?? 0) > 1 ? [] : null };
162
+ const f = fmt();
163
+ if (cur) cur.fmtOut = f;
164
+ cur = { kind: "b", id, baseId: id, brk, implicit, runs: [], len: implicit ? 0 : 1, atom: false, items: !implicit && (markerCount.get(id) ?? 0) > 1 ? [] : null, fmtIn: f, fmtOut: null };
154
165
  if (!implicit) {
155
166
  cur.t = typeOf(id);
156
167
  // A type this runtime has no schema for still owns the text and marks up to
@@ -175,15 +186,15 @@ function walkFlow(pd, index) {
175
186
  if (a.legacy && a.text) orphans.push({ key: a.key, id: a.blockId, text: a.text, h: hashText(a.text) });
176
187
  hidden.push({ key: a.key, sourceKey: a.sourceKey, blockId: a.blockId, end: a.end, sv: a.sv, at: a.at, live: a.live, items: a.items });
177
188
  };
178
- const matchesEnd = (it, end) => {
179
- if (covers(it, end)) return true;
189
+ const matchesEnd = (it, end, after = -1) => {
190
+ if (covers(it, end) && end.clock > after) return true;
180
191
  return markerIdsWithin(it).some((id) => {
181
- if (!pd.origins.has(aliasKey(id.client, id.clock))) return false;
192
+ if (id.clock <= after || !pd.origins.has(aliasKey(id.client, id.clock))) return false;
182
193
  const resolved = index.resolve(id);
183
194
  return resolved.client === end.client && resolved.clock === end.clock;
184
195
  });
185
196
  };
186
- const markerClocks = new Map([...candidateSets].map(([client, clocks]) => [client, [...clocks].sort((a, b) => a - b)]));
197
+ const markerClocks = markers ? markers.clocks : new Map([...candidateSets].map(([client, clocks]) => [client, [...clocks].sort((a, b) => a - b)]));
187
198
  const markerIdsWithin = (it) => {
188
199
  const clocks = markerClocks.get(it.id.client) ?? [];
189
200
  let lo = 0, hi = clocks.length;
@@ -192,6 +203,16 @@ function walkFlow(pd, index) {
192
203
  for (let i = lo; i < clocks.length && clocks[i] < it.id.clock + it.length; i++) ids.push({ client: it.id.client, clock: clocks[i] });
193
204
  return ids;
194
205
  };
206
+ const deletedEdgesIn = (it, after = -1) => (it.deleted ? markerIdsWithin(it).flatMap((id) => {
207
+ if (id.clock <= after) return [];
208
+ const sourceKey = idKey(index.resolve(id));
209
+ const record = index.boundaryOf(id);
210
+ if (!record || (record.kind !== "removed" && record.kind !== "copy") || liveSources.has(sourceKey)) return [];
211
+ return [{ blockId: record.blockId, sourceKey }];
212
+ }) : []);
213
+ // `after` limits an end to what lies past a removal's own source: Yjs merges adjacent deleted
214
+ // items, so a removal can start and end inside the same one, on some replicas and not others.
215
+ const endsIn = (it, a, { deletedEdges, boundary = false, edge, after = -1 }) => a.end ? matchesEnd(it, a.end, after) : a.implicit ? boundary || deletedEdges.some((e) => e.sourceKey !== a.sourceKey) : (boundary && edge !== a.blockId) || deletedEdges.some((e) => e.blockId !== a.blockId);
195
216
  const proj = [];
196
217
  const endsOf = (removal) => ({ blockId: removal.blockId, end: removal.end ? parseKey(removal.end) : null, implicit: removal.implicit === true, sourceKey: removal.sourceKey });
197
218
  for (let it = pd.flow._start; it; it = it.right) {
@@ -200,13 +221,8 @@ function walkFlow(pd, index) {
200
221
  if (hiding || proj.length) {
201
222
  const edge = !it.deleted && it.content instanceof Y.ContentEmbed ? it.content.embed.b : undefined;
202
223
  const boundary = edge !== undefined && boundarySource(it, edge) === null;
203
- const deletedEdges = it.deleted ? markerIdsWithin(it).flatMap((id) => {
204
- const sourceKey = idKey(index.resolve(id));
205
- const record = index.boundaryOf(id);
206
- if (!record || record.kind !== "removed" || liveSources.has(sourceKey)) return [];
207
- return [{ blockId: record.blockId, sourceKey }];
208
- }) : [];
209
- const ends = (a) => a.end ? matchesEnd(it, a.end) : a.implicit ? boundary || deletedEdges.some((e) => e.sourceKey !== a.sourceKey) : (boundary && edge !== a.blockId) || deletedEdges.some((e) => e.blockId !== a.blockId);
224
+ const deletedEdges = deletedEdgesIn(it);
225
+ const ends = (a) => endsIn(it, a, { deletedEdges, boundary, edge });
210
226
  if (hiding) {
211
227
  const keep = [];
212
228
  for (const a of hiding.active) { if (ends(a)) settle(a); else keep.push(a); }
@@ -220,6 +236,7 @@ function walkFlow(pd, index) {
220
236
  }
221
237
  const removals = removalStarts.get(it);
222
238
  if (removals) {
239
+ if (it.deleted) stops.push({ client: it.id.client, clock: it.id.clock, len: it.length });
223
240
  if (!hiding && exposed(removals[0].sourceKey)) {
224
241
  if (!it.deleted) hideUnit(it.length);
225
242
  proj.push({ active: removals.map(endsOf), sourceKey: removals[0].sourceKey, root: null });
@@ -228,14 +245,17 @@ function walkFlow(pd, index) {
228
245
  if (!hiding && it.deleted) fences.push({ client: it.id.client, clock: it.id.clock });
229
246
  for (const removal of removals) {
230
247
  const a = { legacy: false, implicit: removal.implicit === true, key: removal.key, sourceKey: removal.sourceKey, blockId: removal.blockId, end: removal.end ? parseKey(removal.end) : null, sv: removal.sv, at: here, live: !it.deleted, items: [] };
248
+ const after = it.deleted && covers(it, removal.source) ? removal.source.clock : null;
249
+ if (after !== null && endsIn(it, a, { deletedEdges: deletedEdgesIn(it, after), after })) { settle(a); continue; }
231
250
  if (hiding) hiding.active.push(a);
232
251
  else hiding = { active: [a], len: 0, resume: cur };
233
252
  }
234
- if (!it.deleted) hiding.len += it.length;
253
+ if (hiding && !it.deleted) hiding.len += it.length;
235
254
  continue;
236
255
  }
237
256
  const start = starts.get(it);
238
257
  if (start) {
258
+ if (it.deleted) stops.push({ client: it.id.client, clock: it.id.clock, len: it.length });
239
259
  if (!hiding && exposed(start.key)) {
240
260
  if (!it.deleted) hideUnit(it.length);
241
261
  proj.push({ active: [{ blockId: start.blockId, end: start.end }], sourceKey: start.key, root: null });
@@ -249,7 +269,7 @@ function walkFlow(pd, index) {
249
269
  }
250
270
  if (it.deleted) continue;
251
271
  const c = it.content;
252
- if (c instanceof Y.ContentFormat) { if (c.value === null) delete cattrs[c.key]; else cattrs[c.key] = c.value; continue; }
272
+ if (c instanceof Y.ContentFormat) { if (c.value === null) delete cattrs[c.key]; else cattrs[c.key] = c.value; styled = null; continue; }
253
273
  if (hiding) {
254
274
  if (c instanceof Y.ContentString || c instanceof Y.ContentEmbed) {
255
275
  const piece = c instanceof Y.ContentString ? c.str : c.embed.b !== undefined ? "\u00b6" : "\n";
@@ -286,13 +306,18 @@ function walkFlow(pd, index) {
286
306
  }
287
307
  if (c instanceof Y.ContentString) {
288
308
  if (!cur || cur.atom) open(`~${prevId}`, null, true);
289
- const marks = marksFromAttributes(cattrs, cur.t);
290
- cur.runs.push({ text: c.str, marks, mk: marksKey(marks) });
309
+ const code = cur.t === "code_block";
310
+ if (!styled || styled.code !== code) {
311
+ const marks = marksFromAttributes(cattrs, cur.t);
312
+ styled = { code, marks, mk: marksKey(marks) };
313
+ }
314
+ cur.runs.push({ text: c.str, marks: styled.marks, mk: styled.mk });
291
315
  if (cur.items) cur.items.push({ at: here, id: idKey(it.id), client: it.id.client, clock: it.id.clock, length: it.length, kind: "text", text: c.str, blockId: null, raw: { ...cattrs } });
292
316
  cur.len += c.str.length;
293
317
  }
294
318
  }
295
319
  if (hiding) { for (const a of hiding.active) settle(a); flush(); }
320
+ if (cur) cur.fmtOut = fmt();
296
321
  const groups = new Map();
297
322
  for (const s of segs) {
298
323
  if (s.kind !== "b" || s.implicit) continue;
@@ -336,5 +361,5 @@ function walkFlow(pd, index) {
336
361
  }
337
362
  tokens += s.len;
338
363
  }
339
- return { visible, holes, orphans, tokens, copies, hidden, removals: lostCopies.length ? [...removals, ...lostCopies] : removals, fences };
364
+ return { visible, holes, orphans, tokens, copies, hidden, removals: lostCopies.length ? [...removals, ...lostCopies] : removals, fences, stops };
340
365
  }
@@ -146,7 +146,7 @@ const fenceAfter = (pd, yIdx, fences) => {
146
146
 
147
147
  // Yjs places an insertion after every deleted item to its right. A hidden range that starts at a
148
148
  // deleted item would then swallow text typed just before it, so the fence counts as live for the call.
149
- const beforeFence = (pd, yIdx, fences, fn) => {
149
+ export const beforeFence = (pd, yIdx, fences, fn) => {
150
150
  const fence = fenceAfter(pd, yIdx, fences);
151
151
  if (!fence) return fn();
152
152
  fence.deleted = false;
@@ -44,13 +44,14 @@
44
44
  import { loadedEngine, mergeEngine } from "../sync/merge-engine.js";
45
45
  import Mutation from "../lib/mutation.js";
46
46
  import { startsAtImport } from "../core/is-edit-mode.js";
47
+ import { deepActiveElement } from "../dom/active-element.js";
47
48
  import { holdAllSaves, releaseAllSaves } from "../core/save.js";
48
49
  import { STRIP_FROM_SAVE, SNAPSHOT_REMOVE_SELECTOR } from "../lib/region-policy.js";
49
50
  import { enableContentEditable } from "../core/admin-contenteditable.js";
50
51
  import onDomReady from "../lib/dom-ready.js";
51
52
  import wire from "./wire.js";
52
53
  import { set } from "../lib/hostile-css.js";
53
- import { bevelBox, bevelButton, bevelSurface, bevelText, bevelInput, bevelIconButton, pageScheme, setShown, RUNTIME_ONLY } from "../ui/bevel-controls.js";
54
+ import { bevelBox, bevelButton, bevelSurface, bevelText, bevelInput, bevelIconButton, pageScheme, paintLook, setShown, RUNTIME_ONLY } from "../ui/bevel-controls.js";
54
55
  import { TOKENS, GLYPHS, FONT_SANS, FONT_MONO, SHADOW } from "../ui/bevel.js";
55
56
 
56
57
  const HELPER = "ai-edit";
@@ -237,7 +238,7 @@ function sessionMorph(s, content, { rewind = false } = {}) {
237
238
  }
238
239
  HyperMorph.morph(document.body, content, {
239
240
  morphStyle: 'outerHTML',
240
- restoreFocus: true,
241
+ restoreFocus: document.activeElement?.localName !== 'clay-editor-ui',
241
242
  scripts,
242
243
  callbacks: {
243
244
  beforeNodeRemoved: node => !(node.nodeType === 1 && node.matches(STRIP_FROM_SAVE))
@@ -711,6 +712,7 @@ function syncBubble() {
711
712
  if (!doc) return;
712
713
  const wanted = !barMode && helperState === 'ready' && !!doc.querySelector('[data-edit-id]');
713
714
  setShown(docBubble, wanted, 'inline-grid');
715
+ if (wanted) paintLook(docBubble);
714
716
  }
715
717
 
716
718
  // The selected words stay marked while the person types, through the CSS Custom
@@ -757,6 +759,7 @@ function placeBubble() {
757
759
  right: beside ? `${Math.round((document.documentElement.clientWidth || window.innerWidth) - rect.left + 8)}px` : '16px',
758
760
  bottom: beside ? `${Math.round((document.documentElement.clientHeight || window.innerHeight) - rect.bottom)}px` : '16px',
759
761
  });
762
+ paintLook(docBubble);
760
763
  }
761
764
 
762
765
  // ---------------------------------------------------------------- hover chip
@@ -770,9 +773,9 @@ function showChipFor(unit) {
770
773
  chip.pin({
771
774
  left: Math.min(rect.right + 8, window.innerWidth - 34) + 'px',
772
775
  top: Math.max(8, rect.top) + 'px',
773
- 'color-scheme': pageScheme(),
774
776
  });
775
777
  setShown(chip, true, 'inline-grid');
778
+ paintLook(chip);
776
779
  }
777
780
 
778
781
  function hideChip() {
@@ -808,9 +811,9 @@ function showChipForSelection() {
808
811
  chip.pin({
809
812
  left: Math.min(end.right + 6, window.innerWidth - 34) + 'px',
810
813
  top: Math.max(8, end.top + end.height / 2 - 13) + 'px',
811
- 'color-scheme': pageScheme(),
812
814
  });
813
815
  setShown(chip, true, 'inline-grid');
816
+ paintLook(chip);
814
817
  }
815
818
 
816
819
  // Compose-only messages: the host's switch being off and a request too large to send
@@ -850,10 +853,10 @@ function showBar(mode) {
850
853
  setShown(control, controls.includes(control), 'inline-flex');
851
854
  }
852
855
  hideChip();
853
- set(bar, 'color-scheme', pageScheme());
854
856
  setShown(bar, true, 'flex');
855
857
  syncBubble();
856
858
  positionChrome();
859
+ paintLook(bar);
857
860
  // The bar opens on the control that belongs to its state, and a state change moves
858
861
  // focus only when the button holding it has just gone away.
859
862
  const first = controls[0];
@@ -950,8 +953,6 @@ function openPanel(el, quote) {
950
953
  anchorEl = el;
951
954
  anchorRange = range ? range.cloneRange() : null;
952
955
  hideChip();
953
- set(panel, 'color-scheme', pageScheme());
954
- set(ring, 'color-scheme', pageScheme());
955
956
  setShown(panel, true);
956
957
  pendingSelection = quote;
957
958
  const shown = quote ? (quote.text.trim().length > 400 ? quote.text.trim().slice(0, 400) + '\u2026' : quote.text.trim()) : '';
@@ -962,6 +963,8 @@ function openPanel(el, quote) {
962
963
  applyHelperState();
963
964
  positionChrome();
964
965
  fitTextarea();
966
+ paintLook(panel);
967
+ paintLook(ring);
965
968
  textarea.focus();
966
969
  refreshHelperState();
967
970
  }
@@ -1001,6 +1004,7 @@ function closePanelForSend() {
1001
1004
  textarea.value = '';
1002
1005
  fitTextarea();
1003
1006
  positionChrome();
1007
+ paintLook(ring);
1004
1008
  }
1005
1009
 
1006
1010
  // The target is gone from the page: whatever was live for it ends, and no observer,
@@ -1031,7 +1035,7 @@ function isShortcut(event) {
1031
1035
 
1032
1036
  // A field the page owns keeps its own Ctrl+J, and so does the panel's own box.
1033
1037
  function pageOwnsFocus() {
1034
- const el = document.activeElement;
1038
+ const el = deepActiveElement();
1035
1039
  if (!el || el === document.body) return false;
1036
1040
  if (panel && panel.contains(el)) return !panel.hidden;
1037
1041
  return el.matches('input,textarea,select');
@@ -1045,7 +1049,7 @@ const PAGE_FIELD = 'input,textarea,select,[contenteditable=""],[contenteditable=
1045
1049
  function escapeIsMine(event) {
1046
1050
  if (event.defaultPrevented) return false;
1047
1051
  if (document.querySelector(MODAL_SELECTOR)) return false;
1048
- const el = document.activeElement;
1052
+ const el = deepActiveElement();
1049
1053
  if (!el || el === document.body) return true;
1050
1054
  if (panel.contains(el) || bar.contains(el)) return true;
1051
1055
  if (el.isContentEditable === true) return false;
@@ -0,0 +1,91 @@
1
+ // The save chip's drawing: loaded at the person's first input or the first save state,
2
+ // so a page nobody edits never pays for the surface it is drawn with.
3
+ import { set, style } from "../lib/hostile-css.js";
4
+ import { bevelSurface, pageScheme, paintLook } from "../ui/bevel-controls.js";
5
+ import { TOKENS, FONT_SANS } from "../ui/bevel.js";
6
+ import { saveFeedback } from "../core/save-feedback.js";
7
+
8
+ // No 'conflict' here on purpose. core/conflict-notice.js owns that state now,
9
+ // and it ships in every document rather than only the ones that turned this chip on.
10
+ // Both listen to clay:save-conflict, so keeping a label here put a chip in the corner
11
+ // saying the same thing as the bar at the same moment. Dropping it from this side
12
+ // leaves core unaware that this plugin exists, which is the direction that
13
+ // dependency has to point.
14
+ const LABELS = {
15
+ saving: "Saving…",
16
+ saved: "Saved",
17
+ error: "Couldn't save",
18
+ offline: "Offline, not saved",
19
+ retrying: "Saving…",
20
+ blocked: "Can't save here",
21
+ pending: "Saving…",
22
+ acknowledged: "Saving…",
23
+ checkpointed: "Saved",
24
+ unavailable: "Can't store changes: download a copy",
25
+ };
26
+
27
+ // States that stay on screen instead of fading: a save still in flight, one that keeps
28
+ // trying, one the host will not take without help, and where the journal says the work is.
29
+ const STICKY = new Set(["saving", "retrying", "blocked", "pending", "acknowledged", "unavailable"]);
30
+
31
+ const ALARMING = new Set(["error", "offline", "blocked", "unavailable"]);
32
+
33
+ const REST = [`background:${TOKENS.surface}`, `color:${TOKENS.ink}`, `border-color:${TOKENS["line-2"]}`];
34
+ const ALARM = [
35
+ `background:${TOKENS["ox-soft"]}`,
36
+ `color:${TOKENS.ox}`,
37
+ `border-color:color-mix(in srgb, ${TOKENS.ox} 28%, ${TOKENS["ox-soft"]})`,
38
+ ];
39
+
40
+ let el = null;
41
+ let hideTimer = null;
42
+
43
+ function ensure() {
44
+ // Looked up on every call, never trusted once detached: a live-sync morph or a
45
+ // caller can empty the body, and a detached chip would swallow every later state.
46
+ if (el && el.isConnected) return el;
47
+ const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
48
+ el = bevelSurface("div", [
49
+ "position:fixed", "right:16px", "bottom:16px", "z-index:2147483000",
50
+ "padding:4px 12px", `font:500 13px/1.6 ${FONT_SANS}`,
51
+ "opacity:0", `transition:${reduced ? "none" : "opacity .25s"}`, "pointer-events:none",
52
+ `color-scheme:${pageScheme()}`,
53
+ ]);
54
+ el.setAttribute("data-clay-indicator", "");
55
+ el.setAttribute("role", "status");
56
+ document.body.appendChild(el);
57
+ return el;
58
+ }
59
+
60
+ export function show(state) {
61
+ if (!LABELS[state]) return;
62
+ // A failed or offline save is the persistent toast's to report when clay-ui is loaded,
63
+ // and so is saved when the page turned on clay.saveToast. Blocked is the exception:
64
+ // the page cannot save at all, so the chip stays even beside the generic toast.
65
+ const ownedByToast = state !== "blocked" &&
66
+ (ALARMING.has(state) || (state === "saved" && saveFeedback.savedToast));
67
+ if (saveFeedback.toasts && ownedByToast) {
68
+ clearTimeout(hideTimer);
69
+ if (el) {
70
+ set(el, "opacity", "0");
71
+ el.textContent = "";
72
+ delete el.dataset.state;
73
+ }
74
+ return;
75
+ }
76
+ const node = ensure();
77
+ node.textContent = LABELS[state];
78
+ node.dataset.state = state;
79
+ style(node, ALARMING.has(state) ? ALARM : REST);
80
+ paintLook(node, { background: ALARMING.has(state) ? null : TOKENS.surface });
81
+ set(node, "opacity", "1");
82
+ clearTimeout(hideTimer);
83
+ if (!STICKY.has(state)) hideTimer = setTimeout(() => { set(node, "opacity", "0"); }, 2200);
84
+ }
85
+
86
+ export function remove() {
87
+ clearTimeout(hideTimer);
88
+ hideTimer = null;
89
+ el?.remove();
90
+ el = null;
91
+ }
@@ -1,83 +1,15 @@
1
1
  import { startsAtImport } from "../core/is-edit-mode.js";
2
2
  import onDomReady from "../lib/dom-ready.js";
3
- import { set, style } from "../lib/hostile-css.js";
4
- import { bevelSurface, pageScheme } from "../ui/bevel-controls.js";
5
- import { TOKENS, FONT_SANS } from "../ui/bevel.js";
6
3
  import { saveFeedback } from "../core/save-feedback.js";
7
4
 
8
- // No 'conflict' here on purpose. core/conflict-notice.js owns that state now,
9
- // and it ships in every document rather than only the ones that turned this chip on.
10
- // Both listen to clay:save-conflict, so keeping a label here put a chip in the corner
11
- // saying the same thing as the bar at the same moment. Dropping it from this side
12
- // leaves core unaware that this plugin exists, which is the direction that
13
- // dependency has to point.
14
- const LABELS = {
15
- saving: "Saving…",
16
- saved: "Saved",
17
- error: "Couldn't save",
18
- offline: "Offline, not saved",
19
- retrying: "Saving…",
20
- blocked: "Can't save here",
21
- };
22
-
23
- // States that stay on screen instead of fading: a save still in flight, one that
24
- // keeps trying, and one the host will not take without a person's help.
25
- const STICKY = new Set(["saving", "retrying", "blocked"]);
26
-
27
- const ALARMING = new Set(["error", "offline", "blocked"]);
5
+ const SAVE_EVENTS = ["saving", "saved", "error", "offline", "retrying", "blocked"];
28
6
 
29
- const REST = [`background:${TOKENS.surface}`, `color:${TOKENS.ink}`, `border-color:${TOKENS["line-2"]}`];
30
- const ALARM = [
31
- `background:${TOKENS["ox-soft"]}`,
32
- `color:${TOKENS.ox}`,
33
- `border-color:color-mix(in srgb, ${TOKENS.ox} 28%, ${TOKENS["ox-soft"]})`,
34
- ];
35
-
36
- let el = null;
37
- let hideTimer = null;
38
-
39
- function ensure() {
40
- // Looked up on every call, never trusted once detached: a live-sync morph or a
41
- // caller can empty the body, and a detached chip would swallow every later state.
42
- if (el && el.isConnected) return el;
43
- const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
44
- el = bevelSurface("div", [
45
- "position:fixed", "right:16px", "bottom:16px", "z-index:2147483000",
46
- "padding:4px 12px", `font:500 13px/1.6 ${FONT_SANS}`,
47
- "opacity:0", `transition:${reduced ? "none" : "opacity .25s"}`, "pointer-events:none",
48
- `color-scheme:${pageScheme()}`,
49
- ]);
50
- el.setAttribute("data-clay-indicator", "");
51
- el.setAttribute("role", "status");
52
- document.body.appendChild(el);
53
- return el;
54
- }
55
-
56
- function show(state) {
57
- if (!LABELS[state]) return;
58
- // A failed or offline save is the persistent toast's to report when clay-ui is loaded,
59
- // and so is saved when the page turned on clay.saveToast. Blocked is the exception:
60
- // the page cannot save at all, so the chip stays even beside the generic toast.
61
- const ownedByToast = state !== "blocked" &&
62
- (ALARMING.has(state) || (state === "saved" && saveFeedback.savedToast));
63
- if (saveFeedback.toasts && ownedByToast) {
64
- clearTimeout(hideTimer);
65
- if (el) {
66
- set(el, "opacity", "0");
67
- el.textContent = "";
68
- delete el.dataset.state;
69
- }
70
- return;
71
- }
72
- const node = ensure();
73
- node.textContent = LABELS[state];
74
- node.dataset.state = state;
75
- set(node, "color-scheme", pageScheme());
76
- style(node, ALARMING.has(state) ? ALARM : REST);
77
- set(node, "opacity", "1");
78
- clearTimeout(hideTimer);
79
- if (!STICKY.has(state)) hideTimer = setTimeout(() => { set(node, "opacity", "0"); }, 2200);
80
- }
7
+ // The drawing arrives on demand; states that come before it are shown in order once it has.
8
+ let chip = null;
9
+ const loadChip = () => (chip ??= import("./indicator-chip.js"));
10
+ const show = (state) => {
11
+ loadChip().then((m) => { if (listeners) m.show(state); }, () => {});
12
+ };
81
13
 
82
14
  let listeners = null;
83
15
 
@@ -88,7 +20,11 @@ function arm() {
88
20
  if (listeners) return;
89
21
  listeners = new AbortController();
90
22
  const { signal } = listeners;
91
- for (const state of Object.keys(LABELS)) {
23
+ // Typing is the first sign a save is coming: fetch the drawing then, not at boot.
24
+ for (const type of ["beforeinput", "keydown", "pointerdown"]) {
25
+ document.addEventListener(type, loadChip, { signal, once: true, capture: true });
26
+ }
27
+ for (const state of SAVE_EVENTS) {
92
28
  document.addEventListener("clay:save-" + state, () => show(state), { signal });
93
29
  }
94
30
  document.addEventListener("clay:page-save-state", (event) => show(event.detail?.state), { signal });
@@ -97,10 +33,7 @@ function arm() {
97
33
  function disarm() {
98
34
  listeners?.abort();
99
35
  listeners = null;
100
- clearTimeout(hideTimer);
101
- hideTimer = null;
102
- el?.remove();
103
- el = null;
36
+ chip?.then((m) => m.remove(), () => {});
104
37
  }
105
38
 
106
39
  function init() {