@panphora/clayjs 1.17.0 → 1.18.1

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-26C55578.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
@@ -5,186 +5,67 @@ import { canEdit, isDraftMode, isEditMode, mode as startMode } from "../core/is-
5
5
  import onDomReady from "../lib/dom-ready.js";
6
6
  import CLAYGOO from "./menu/claygoo.svg.js";
7
7
  import { modeRefusalText } from "../core/mode-refusal.js";
8
+ import MENU_CSS, { MENU_SURFACE } from "./menu/style.js";
9
+ import { attachPlacement } from "./menu/placement.js";
10
+ import { attachActions } from "./menu/actions.js";
11
+ import { attachPeople } from "./menu/people.js";
12
+ import { attachVariants } from "./menu/variants.js";
13
+ import { followLook } from "../ui/page-colour.js";
14
+ import { mountEditorUI } from "../ui/editor-ui.js";
8
15
 
9
16
  const SEO_ITEM = true;
10
17
  const NOTE_MS = 6000;
11
18
  const INTRO_GAP = 12;
12
-
13
- const MENU_CSS = `.clay-menu {
14
- position: fixed;
15
- top: max(12px, env(safe-area-inset-top));
16
- right: max(12px, env(safe-area-inset-right));
17
- z-index: 2147482000;
18
- display: flex;
19
- align-items: center;
20
- flex-wrap: nowrap;
21
- gap: 8px;
22
- font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
23
- font-size: 13px;
24
- line-height: 1;
25
- color: var(--clay-ui-fg, #1F2328);
26
- }
27
- .clay-menu-edit {
28
- display: inline-flex;
29
- align-items: center;
30
- gap: 8px;
31
- margin: 0;
32
- padding: 0;
33
- border: 0;
34
- font: inherit;
35
- color: inherit;
36
- background: none;
37
- cursor: pointer;
38
- }
39
- .clay-menu-edit:disabled { cursor: progress; opacity: .7; }
40
- .clay-menu-track {
41
- position: relative;
42
- display: block;
43
- box-sizing: border-box;
44
- width: 52px;
45
- height: 32px;
46
- border: 1px solid rgba(23, 28, 36, .16);
47
- border-radius: 999px;
48
- background: var(--clay-ui-bg, #F4F4F5);
49
- transition: background-color .15s ease, border-color .15s ease;
50
- }
51
- .clay-menu-thumb {
52
- position: absolute;
53
- top: 2px;
54
- left: 2px;
55
- width: 26px;
56
- height: 26px;
57
- border-radius: 50%;
58
- background: #FAFAFB;
59
- box-shadow: 0 1px 2px rgba(23, 28, 36, .35);
60
- transition: transform .15s ease;
61
- }
62
- .clay-menu-edit[aria-checked="true"] .clay-menu-track {
63
- border-color: transparent;
64
- background: var(--clay-ui-accent, #2F6FEB);
65
- }
66
- .clay-menu-edit[aria-checked="true"] .clay-menu-thumb { transform: translateX(20px); }
67
- .clay-menu-label { font-size: 13px; line-height: 1; }
68
- .clay-menu-goo {
69
- position: relative;
70
- display: inline-flex;
71
- align-items: center;
72
- justify-content: center;
73
- box-sizing: border-box;
74
- width: 32px;
75
- height: 32px;
76
- margin: 0;
77
- padding: 0;
78
- border: 1px solid rgba(23, 28, 36, .16);
79
- border-radius: 50%;
80
- color: inherit;
81
- background: var(--clay-ui-bg, #F4F4F5);
82
- cursor: pointer;
83
- }
84
- .clay-menu-goo svg { display: block; width: 18px; height: auto; }
85
- .clay-menu-dot {
86
- position: absolute;
87
- top: 1px;
88
- right: 1px;
89
- width: 8px;
90
- height: 8px;
91
- border-radius: 50%;
92
- background: var(--clay-ui-accent, #2F6FEB);
93
- }
94
- .clay-menu-list {
95
- position: absolute;
96
- top: calc(100% + 8px);
97
- right: 0;
98
- min-width: 184px;
99
- margin: 0;
100
- padding: 4px;
101
- border: 1px solid rgba(23, 28, 36, .16);
102
- border-radius: 10px;
103
- background: var(--clay-ui-bg, #F4F4F5);
104
- box-shadow: 0 10px 28px -14px rgba(23, 28, 36, .5);
105
- }
106
- .clay-menu-list button {
107
- display: block;
108
- width: 100%;
109
- padding: 8px 10px;
110
- border: 0;
111
- border-radius: 6px;
112
- font: inherit;
113
- text-align: left;
114
- color: inherit;
115
- background: none;
116
- cursor: pointer;
117
- }
118
- .clay-menu-list button:hover,
119
- .clay-menu-list button:focus-visible { outline: none; background: rgba(23, 28, 36, .08); }
120
- .clay-menu-note {
121
- position: absolute;
122
- top: calc(100% + 8px);
123
- right: 0;
124
- max-width: 260px;
125
- padding: 8px 10px;
126
- border: 1px solid rgba(23, 28, 36, .16);
127
- border-radius: 8px;
128
- line-height: 1.4;
129
- text-align: left;
130
- background: var(--clay-ui-bg, #F4F4F5);
131
- box-shadow: 0 10px 28px -14px rgba(23, 28, 36, .5);
132
- }
133
- @media (pointer: coarse) {
134
- .clay-menu-edit { min-height: 44px; padding: 6px 0; }
135
- .clay-menu-goo { width: 44px; height: 44px; }
136
- }
137
- @media (prefers-color-scheme: dark) {
138
- .clay-menu { color: var(--clay-ui-fg, #E9E9EC); }
139
- .clay-menu-track,
140
- .clay-menu-goo,
141
- .clay-menu-list,
142
- .clay-menu-note { border-color: rgba(233, 233, 236, .16); background: var(--clay-ui-bg, #26282C); }
143
- .clay-menu-track { background: rgba(233, 233, 236, .22); }
144
- .clay-menu-thumb { background: #E9E9EC; }
145
- .clay-menu-list button:hover,
146
- .clay-menu-list button:focus-visible { background: rgba(233, 233, 236, .12); }
147
- }
148
- @media (prefers-reduced-motion: reduce) {
149
- .clay-menu-track, .clay-menu-thumb { transition: none; }
150
- }`;
19
+ const GRIP =
20
+ '<svg viewBox="0 0 6 12" aria-hidden="true" focusable="false"><rect width="2" height="2"/><rect x="4" width="2" height="2"/>' +
21
+ '<rect y="5" width="2" height="2"/><rect x="4" y="5" width="2" height="2"/><rect y="10" width="2" height="2"/><rect x="4" y="10" width="2" height="2"/></svg>';
22
+
23
+ // Built-in items keep fixed slots, so the order never depends on which plugin
24
+ // registered first. Any other id goes in its own section above the footer, in the
25
+ // order it was added.
26
+ const SECTIONS = [
27
+ ["clay.undo", "clay.cms", "clay.ai", "clay.code"],
28
+ ["seo", "clay.variants.keep", "clay.share", "clay.people"],
29
+ ["clay.duplicate", "clay.download", "clay.export", "clay.reveal"],
30
+ ["clay.versions"],
31
+ null,
32
+ ["upgrade"],
33
+ ];
34
+ const SLOTTED = new Set(SECTIONS.flat().filter(Boolean));
151
35
 
152
36
  // clay.mode is the live answer; the imported mode is the one the page booted with.
153
37
  const currentMode = () =>
154
38
  window.clay && typeof window.clay.mode === "string" ? window.clay.mode : startMode;
155
39
 
156
- function stylesOnce() {
157
- if (document.getElementById("clay-menu-style")) return;
158
- const style = document.createElement("style");
159
- style.id = "clay-menu-style";
160
- style.setAttribute("clay", "editor-ui");
161
- style.textContent = MENU_CSS;
162
- document.head.append(style);
163
- }
164
-
165
40
  function mount() {
166
- if (document.querySelector(".clay-menu")) return;
167
- stylesOnce();
41
+ if (document.querySelector('clay-editor-ui[data-clay-ui="menu"]')) return;
168
42
 
169
43
  const root = document.createElement("div");
170
- root.className = "clay-menu";
44
+ root.className = "clay-menu-dock";
171
45
  root.setAttribute("clay", "editor-ui");
172
- root.setAttribute("clay-mode-toggle", "");
46
+ root.dataset.corner = "top-right";
173
47
  root.innerHTML =
48
+ `<div class="clay-menu" clay="editor-ui">` +
49
+ `<button type="button" class="clay-menu-grip" aria-label="Move the menu. Drag it, or use the arrow keys to move it to another corner.">${GRIP}</button>` +
174
50
  `<button type="button" class="clay-menu-edit" role="switch" aria-checked="false">` +
175
51
  `<span class="clay-menu-track" aria-hidden="true"><span class="clay-menu-thumb"></span></span>` +
176
52
  `<span class="clay-menu-label">Edit</span>` +
177
53
  `</button>` +
54
+ `<span class="clay-menu-divider" aria-hidden="true"></span>` +
178
55
  `<button type="button" class="clay-menu-goo" aria-haspopup="menu" aria-expanded="false" aria-label="Clay menu">${CLAYGOO}</button>` +
179
- `<div class="clay-menu-list" role="menu" hidden></div>` +
56
+ `</div>` +
57
+ `<div class="clay-menu-list" role="menu" aria-label="Clay menu" hidden></div>` +
180
58
  `<div class="clay-menu-note" role="status" hidden></div>`;
181
59
 
60
+ const grip = root.querySelector(".clay-menu-grip");
182
61
  const edit = root.querySelector(".clay-menu-edit");
183
62
  const goo = root.querySelector(".clay-menu-goo");
184
63
  const list = root.querySelector(".clay-menu-list");
185
64
  const noteEl = root.querySelector(".clay-menu-note");
186
65
  const items = new Map();
187
66
 
67
+ // Focus inside the shadow root: document.activeElement only ever names the host.
68
+ const focusedEl = () => root.getRootNode().activeElement || null;
188
69
  const isOpen = () => !list.hidden;
189
70
 
190
71
  function setExpanded(open) {
@@ -192,7 +73,7 @@ function mount() {
192
73
  goo.setAttribute("aria-expanded", open ? "true" : "false");
193
74
  }
194
75
 
195
- const buttons = () => [...list.querySelectorAll('[role="menuitem"]')];
76
+ const buttons = () => [...list.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')];
196
77
 
197
78
  function focusItem(index) {
198
79
  const all = buttons();
@@ -201,52 +82,132 @@ function mount() {
201
82
  }
202
83
 
203
84
  function close() {
204
- if (isOpen()) setExpanded(false);
85
+ if (!isOpen()) return;
86
+ setExpanded(false);
205
87
  }
206
88
 
89
+ let actions = null;
90
+ let people = null;
91
+
207
92
  function open() {
208
- if (!isOpen()) setExpanded(true);
93
+ if (isOpen()) return;
94
+ people?.close({ restore: false });
95
+ actions?.refresh();
96
+ render();
97
+ setExpanded(true);
209
98
  }
210
99
 
211
- function render() {
212
- const hadFocus = list.contains(document.activeElement);
213
- list.textContent = "";
214
- for (const item of items.values()) {
215
- const button = document.createElement("button");
100
+ function itemButton(item) {
101
+ const link = item.href && !item.disabled;
102
+ const button = document.createElement(link ? "a" : "button");
103
+ if (link) {
104
+ button.href = item.href;
105
+ button.target = "_blank";
106
+ button.rel = "noopener";
107
+ } else {
216
108
  button.type = "button";
217
- button.setAttribute("role", "menuitem");
218
- button.dataset.menuId = item.id;
109
+ }
110
+ button.setAttribute("role", "menuitem");
111
+ button.dataset.menuId = item.id;
112
+ if (item.badge && item.id === "upgrade") {
113
+ const label = document.createElement("span");
114
+ label.className = "clay-menu-upgrade";
115
+ label.textContent = item.label;
116
+ button.append(label);
117
+ } else {
219
118
  button.textContent = item.label;
220
- button.addEventListener("click", () => {
221
- close();
222
- if (item.run) item.run();
223
- });
224
- list.append(button);
225
119
  }
120
+ if (item.keys) {
121
+ const kbd = document.createElement("kbd");
122
+ kbd.textContent = item.keys;
123
+ button.append(kbd);
124
+ }
125
+ if (item.disabled) button.setAttribute("aria-disabled", "true");
126
+ button.addEventListener("click", () => {
127
+ if (item.disabled) return;
128
+ close();
129
+ if (item.run) item.run();
130
+ });
131
+ return button;
132
+ }
133
+
134
+ function itemNode(item) {
135
+ if (item.text) {
136
+ const line = document.createElement("p");
137
+ line.className = "clay-menu-version";
138
+ line.dataset.menuId = item.id;
139
+ line.textContent = item.label;
140
+ return line;
141
+ }
142
+ if (item.pair) {
143
+ const pair = document.createElement("div");
144
+ pair.className = "clay-menu-pair";
145
+ pair.dataset.menuId = item.id;
146
+ for (const part of item.pair) pair.append(itemButton(part));
147
+ return pair;
148
+ }
149
+ return itemButton(item);
150
+ }
151
+
152
+ function sections() {
153
+ const extra = [...items.keys()].filter((id) => !SLOTTED.has(id));
154
+ return SECTIONS.map((ids) => (ids || extra).map((id) => items.get(id)).filter(Boolean)).filter((group) => group.length);
155
+ }
156
+
157
+ function render() {
158
+ const now = focusedEl();
159
+ const focused = now && list.contains(now) ? now.dataset.menuId : null;
160
+ list.textContent = "";
161
+ sections().forEach((group, index) => {
162
+ if (index) {
163
+ const sep = document.createElement("div");
164
+ sep.className = "clay-menu-sep";
165
+ sep.setAttribute("role", "separator");
166
+ list.append(sep);
167
+ }
168
+ for (const item of group) list.append(itemNode(item));
169
+ });
226
170
  const dot = goo.querySelector(".clay-menu-dot");
227
171
  const wanted = [...items.values()].some((item) => item.badge);
228
172
  if (wanted && !dot) {
229
173
  const mark = document.createElement("span");
230
174
  mark.className = "clay-menu-dot";
175
+ mark.setAttribute("aria-hidden", "true");
231
176
  goo.append(mark);
232
177
  } else if (!wanted && dot) {
233
178
  dot.remove();
234
179
  }
235
- if (hadFocus) focusItem(0);
180
+ if (focused) {
181
+ const again = buttons().find((button) => button.dataset.menuId === focused);
182
+ if (again) again.focus();
183
+ else focusItem(0);
184
+ }
236
185
  }
237
186
 
238
- function addItem({ id, label, run, badge } = {}) {
187
+ const clean = ({ id, label, run, badge, keys, disabled, href }) => ({
188
+ id,
189
+ href: typeof href === "string" ? href : "",
190
+ label: String(label ?? ""),
191
+ run: typeof run === "function" ? run : null,
192
+ badge: Boolean(badge),
193
+ keys: keys ? String(keys) : "",
194
+ disabled: Boolean(disabled),
195
+ });
196
+
197
+ function addItem({ id, label, run, badge, keys, disabled, text, pair, href } = {}) {
239
198
  if (!id) return null;
240
- items.set(id, {
241
- id,
242
- label: String(label ?? ""),
243
- run: typeof run === "function" ? run : null,
244
- badge: Boolean(badge),
245
- });
199
+ const item = clean({ id, label, run, badge, keys, disabled, href });
200
+ if (text) item.text = true;
201
+ if (Array.isArray(pair)) item.pair = pair.map(clean);
202
+ items.set(id, item);
246
203
  render();
247
204
  return id;
248
205
  }
249
206
 
207
+ function removeItem(id) {
208
+ if (items.delete(id)) render();
209
+ }
210
+
250
211
  function showNote(text) {
251
212
  if (!text) return;
252
213
  noteEl.textContent = text;
@@ -261,6 +222,10 @@ function mount() {
261
222
  let noteTimer = 0;
262
223
  let busy = false;
263
224
 
225
+ const applyHidden = () => {
226
+ root.hidden = !canEdit && currentMode() !== "edit";
227
+ };
228
+
264
229
  function setChecked() {
265
230
  edit.setAttribute("aria-checked", currentMode() === "edit" ? "true" : "false");
266
231
  }
@@ -274,6 +239,8 @@ function mount() {
274
239
  edit.addEventListener("click", async () => {
275
240
  if (busy) return;
276
241
  const previous = edit.getAttribute("aria-checked");
242
+ // Disabling the focused switch drops focus to the body; it goes back once the switch is done.
243
+ const hadFocus = focusedEl() === edit;
277
244
  const next = currentMode() === "edit" ? "view" : "edit";
278
245
  busy = true;
279
246
  edit.setAttribute("aria-busy", "true");
@@ -289,6 +256,7 @@ function mount() {
289
256
  busy = false;
290
257
  edit.removeAttribute("aria-busy");
291
258
  edit.disabled = false;
259
+ if (hadFocus && edit.isConnected && !focusedEl() && document.activeElement === document.body) edit.focus();
292
260
  if (result && result.ok === false) {
293
261
  edit.setAttribute("aria-checked", previous);
294
262
  const text = modeRefusalText(result);
@@ -304,7 +272,7 @@ function mount() {
304
272
  });
305
273
 
306
274
  document.addEventListener("click", (event) => {
307
- if (isOpen() && !root.contains(event.target)) close();
275
+ if (isOpen() && !event.composedPath().includes(root)) close();
308
276
  });
309
277
 
310
278
  root.addEventListener("keydown", (event) => {
@@ -332,7 +300,7 @@ function mount() {
332
300
  }
333
301
  const all = buttons();
334
302
  if (!all.length) return;
335
- const at = all.indexOf(document.activeElement);
303
+ const at = all.indexOf(focusedEl());
336
304
  if (event.key === "ArrowDown") {
337
305
  event.preventDefault();
338
306
  focusItem(at < 0 ? 0 : at + 1);
@@ -349,9 +317,18 @@ function mount() {
349
317
  let watched = null;
350
318
 
351
319
  function place(intro) {
352
- root.style.top = `${Math.round(intro.getBoundingClientRect().bottom) + INTRO_GAP}px`;
320
+ if (root.dataset.corner.startsWith("top")) {
321
+ root.style.top = `${Math.round(intro.getBoundingClientRect().bottom) + INTRO_GAP}px`;
322
+ } else {
323
+ root.style.removeProperty("top");
324
+ }
353
325
  }
354
326
 
327
+ const replace = () => {
328
+ if (watched) place(watched);
329
+ else root.style.removeProperty("top");
330
+ };
331
+
355
332
  function watchIntro() {
356
333
  if (!root.isConnected) return;
357
334
  const intro = doc.querySelector(".clay-intro");
@@ -383,14 +360,30 @@ function mount() {
383
360
  `:root { --clay-menu-width: ${Math.ceil(rect.width)}px; --clay-menu-height: ${Math.ceil(rect.height)}px; }`;
384
361
  }
385
362
 
386
- document.body.append(root);
363
+ const ui = mountEditorUI({ name: "menu", content: root, css: [MENU_CSS], attributes: { "clay-mode-toggle": "" } });
364
+ attachPlacement({
365
+ dock: root,
366
+ container: ui.shadow,
367
+ grip,
368
+ storage: window.clay.storage && window.clay.storage.local,
369
+ onMove: replace,
370
+ onDragStart: () => {
371
+ close();
372
+ people?.close({ restore: false });
373
+ },
374
+ });
387
375
  reserveSpace();
388
376
  if (typeof ResizeObserver === "function") new ResizeObserver(reserveSpace).observe(root);
389
377
 
390
378
  new MutationObserver(watchIntro).observe(doc.body, { childList: true });
391
379
  watchIntro();
380
+ followLook(root, root.querySelector(".clay-menu"), MENU_SURFACE);
392
381
 
393
- const openSeo = () => import("./menu/seo.js").then((m) => m.open());
382
+ const openSeo = () => import("./menu/seo.js").then((m) => m.open({ returnFocus: goo }));
383
+
384
+ actions = attachActions({ addItem, note: showNote, currentMode });
385
+ people = attachPeople({ root, capsule: root.querySelector(".clay-menu"), addItem, removeItem, closeMenu: close, note: showNote });
386
+ attachVariants({ root, capsule: root.querySelector(".clay-menu"), addItem, removeItem, note: showNote, currentMode });
394
387
 
395
388
  if (SEO_ITEM) {
396
389
  addItem({
@@ -406,10 +399,17 @@ function mount() {
406
399
  }
407
400
  }
408
401
 
409
- window.clay.menu = { addItem, open, close };
402
+ // A view-mode owner's hint can be stale: the host's own answer decides, and a page the
403
+ // host will not let this caller save hides the menu rather than offer a refused switch.
404
+ followCapability = applyHidden;
405
+ if (currentMode() !== "edit") import("../core/host-permission.js").then((m) => m.checkHostPermission()).catch(() => {});
406
+
407
+ window.clay.menu = { addItem, removeItem, open, close, note: showNote };
408
+ document.dispatchEvent(new CustomEvent("clay:menu-ready"));
410
409
  }
411
410
 
412
411
  let mounted = false;
412
+ let followCapability = null;
413
413
 
414
414
  const shouldMount = () => (canEdit || isEditMode) && !isDraftMode;
415
415
 
@@ -421,5 +421,8 @@ function mountOnce() {
421
421
 
422
422
  if (!isDraftMode) {
423
423
  onDomReady(mountOnce);
424
- document.addEventListener("clay:capabilitychange", mountOnce);
424
+ document.addEventListener("clay:capabilitychange", () => {
425
+ mountOnce();
426
+ followCapability?.();
427
+ });
425
428
  }
@@ -34,13 +34,14 @@ const oneArticle = () => document.querySelectorAll("article[data-page]").length
34
34
 
35
35
  // The reader reports what it applied on `clay:reader-status`; the first file is the
36
36
  // first applied one, and a blocked or recoverable first read settles with null while
37
- // the stream stays open for the next file.
37
+ // the stream stays open for the next file. So does a stream that cannot open: a switch
38
+ // asked before any file arrives reloads instead of waiting out its deadline.
38
39
  function listen() {
39
40
  onStatus = (event) => {
40
41
  if (cancelled) return;
41
42
  const status = event.detail;
42
43
  if (status?.state === "applied") settle?.(reader);
43
- else if (status?.state === "blocked" || status?.state === "recoverable") settle?.(null);
44
+ else if (status?.state === "blocked" || status?.state === "recoverable" || status?.state === "reconnecting") settle?.(null);
44
45
  };
45
46
  document.addEventListener("clay:reader-status", onStatus);
46
47
  }