@panphora/clayjs 1.15.2 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -5
- package/THIRD-PARTY-NOTICES.md +16 -0
- package/compat/highlight-11.9.0.min.js +1213 -0
- package/compat/highlight-LICENSE +29 -0
- package/compat/journal-assets.lock.json +22 -0
- package/compat/overtype-2.6.1.min.js +116 -0
- package/compat/overtype-LICENSE +21 -0
- package/dist/all.js +90 -0
- package/dist/clay-dom.js +84 -0
- package/dist/clay-events.js +103 -0
- package/dist/clay-internals.js +85 -0
- package/dist/clay-options.js +93 -0
- package/dist/clay-router.js +98 -0
- package/dist/clay-ui.js +95 -0
- package/dist/clay-utils.js +84 -0
- package/dist/clay.js +146 -0
- package/dist/clay.standalone.js +84291 -57611
- package/dist/m/attrs/add-from-T5LJXFFI.js +1 -0
- package/dist/m/attrs/onaftersave-OKSWEJQF.js +1 -0
- package/dist/m/attrs/refetch-on-save-ZUE7PSCI.js +1 -0
- package/dist/m/attrs/save-freeze-MYNVXREN.js +1 -0
- package/dist/m/c-2AZDZWCK.js +1 -0
- package/dist/m/c-2SPVQSHC.js +1 -0
- package/dist/m/c-2YYDMLNZ.js +1 -0
- package/dist/m/c-336SGU5W.js +1 -0
- package/dist/m/c-33JJ6CBX.js +2 -0
- package/dist/m/c-3GJ4SDE2.js +1 -0
- package/dist/m/c-3H6BZDNJ.js +6 -0
- package/dist/m/c-3OWDMNJR.js +2 -0
- package/dist/m/c-3RUU4TPX.js +91 -0
- package/dist/m/c-3XIRD4NU.js +1 -0
- package/dist/m/c-46XYM55L.js +1 -0
- package/dist/m/c-4DFEJ2PO.js +3 -0
- package/dist/m/c-4JZDZFF6.js +1 -0
- package/dist/m/c-4L3BTFRK.js +1 -0
- package/dist/m/c-4Q2XTQ2N.js +2 -0
- package/dist/m/c-4WKFKEKF.js +1 -0
- package/dist/m/c-56QRZTZH.js +1 -0
- package/dist/m/c-5J4E7O4Y.js +4 -0
- package/dist/m/c-5LKDWQTL.js +19 -0
- package/dist/m/c-5QWQ7A5L.js +1 -0
- package/dist/m/c-5RJFTLSF.js +1 -0
- package/dist/m/c-5V3MOVJT.js +1 -0
- package/dist/m/c-5VYOWDTI.js +1 -0
- package/dist/m/c-5YIHJ3TJ.js +1 -0
- package/dist/m/c-6AZOGAPE.js +1 -0
- package/dist/m/c-6CRUUXOX.js +5 -0
- package/dist/m/c-6HMB24EV.js +1 -0
- package/dist/m/c-6KEVEQ7L.js +1 -0
- package/dist/m/c-6NC5I2TV.js +1 -0
- package/dist/m/c-74MGYWZF.js +1 -0
- package/dist/m/c-7DJDKPGL.js +1 -0
- package/dist/m/c-7OLLJPWP.js +1 -0
- package/dist/m/c-7SWMYKAI.js +1 -0
- package/dist/m/c-A3E3NIMC.js +1 -0
- package/dist/m/c-A7LS5UZW.js +1 -0
- package/dist/m/c-AMSNPOCX.js +1 -0
- package/dist/m/c-AQLFEATB.js +1 -0
- package/dist/m/c-B3JM5ZXC.js +1 -0
- package/dist/m/c-BBVGTQG7.js +1 -0
- package/dist/m/c-BPF2NSPV.js +1 -0
- package/dist/m/c-BQ6LOBEE.js +1 -0
- package/dist/m/c-BTDI4Y23.js +1 -0
- package/dist/m/c-BWFVSBDF.js +1 -0
- package/dist/m/c-BYTKL6UX.js +1 -0
- package/dist/m/c-CFHW5AMY.js +6 -0
- package/dist/m/c-CJ3A7ZKE.js +1 -0
- package/dist/m/c-CQHPGKX2.js +1 -0
- package/dist/m/c-CYWLPPUS.js +1 -0
- package/dist/m/c-CZUSOB7V.js +1 -0
- package/dist/m/c-DCFSEJZG.js +1 -0
- package/dist/m/c-DCXOXBF3.js +1 -0
- package/dist/m/c-DFS4XZJV.js +2 -0
- package/dist/m/c-DNENWY4O.js +1 -0
- package/dist/m/c-DNZ5IFM6.js +1 -0
- package/dist/m/c-E4LIR5X5.js +1 -0
- package/dist/m/c-EJTGYSLN.js +1 -0
- package/dist/m/c-EVCQ3BKA.js +1 -0
- package/dist/m/c-EZU56NQV.js +34 -0
- package/dist/m/c-FDNHHZY5.js +1 -0
- package/dist/m/c-FILLTJA7.js +1 -0
- package/dist/m/c-FRLHSY7E.js +1 -0
- package/dist/m/c-FROJUZMV.js +1 -0
- package/dist/m/c-G2JPKCTP.js +1 -0
- package/dist/m/c-GB6TU7WV.js +1 -0
- package/dist/m/c-GFJJEBTU.js +1 -0
- package/dist/m/c-GJAEGGXY.js +1 -0
- package/dist/m/c-GOWBDM6J.js +1 -0
- package/dist/m/c-GQ6F6IDK.js +1 -0
- package/dist/m/c-GSFIGKOP.js +1 -0
- package/dist/m/c-GY422N3Q.js +1 -0
- package/dist/m/c-H4LG442Q.js +1 -0
- package/dist/m/c-HA6INT6J.js +1 -0
- package/dist/m/c-HAWFNBYG.js +1 -0
- package/dist/m/c-HDDEEL77.js +1 -0
- package/dist/m/c-HFKUVACH.js +1 -0
- package/dist/m/c-HHDFCNHV.js +1 -0
- package/dist/m/c-HPURYVZS.js +2 -0
- package/dist/m/c-I2ZATQCD.js +2 -0
- package/dist/m/c-IEM4NTCS.js +1 -0
- package/dist/m/c-IJUK2GPW.js +1 -0
- package/dist/m/c-IW6GGOU2.js +1 -0
- package/dist/m/c-JAX2667S.js +6 -0
- package/dist/m/c-JDCX26UP.js +25 -0
- package/dist/m/c-JRKY44DK.js +1 -0
- package/dist/m/c-JU3NK25H.js +1 -0
- package/dist/m/c-KAU6E43D.js +1 -0
- package/dist/m/c-KBS3UV6B.js +1 -0
- package/dist/m/c-KGVGROZT.js +1 -0
- package/dist/m/c-KI7M4AY3.js +1 -0
- package/dist/m/c-KIPQJX4B.js +1 -0
- package/dist/m/c-KQ6TYJAP.js +135 -0
- package/dist/m/c-KU3ZFADW.js +1 -0
- package/dist/m/c-L4WQSC27.js +1 -0
- package/dist/m/c-LFPHCXY3.js +1 -0
- package/dist/m/c-LRPUO2MX.js +1 -0
- package/dist/m/c-LWLBHLVC.js +3 -0
- package/dist/m/c-LZJPNR2W.js +1 -0
- package/dist/m/c-M2L47S2X.js +7 -0
- package/dist/m/c-MFP2ZWD4.js +1 -0
- package/dist/m/c-MKSQ4Y57.js +1 -0
- package/dist/m/c-MTQHWQC3.js +1 -0
- package/dist/m/c-N326R2JD.js +1 -0
- package/dist/m/c-N7JPUPGC.js +1 -0
- package/dist/m/c-NRPJEVJS.js +1 -0
- package/dist/m/c-NUFFJVVJ.js +1 -0
- package/dist/m/c-NUHP2XDB.js +1 -0
- package/dist/m/c-NUHSPT5P.js +1 -0
- package/dist/m/c-O72HVYSA.js +1 -0
- package/dist/m/c-OCSZ4QGN.js +1 -0
- package/dist/m/c-OIBUTDXI.js +1 -0
- package/dist/m/c-OIDRZKAF.js +1 -0
- package/dist/m/c-OW5QIGG3.js +1 -0
- package/dist/m/c-P7KNDG34.js +1 -0
- package/dist/m/c-PGRCK73F.js +1 -0
- package/dist/m/c-PQ5LK6QE.js +993 -0
- package/dist/m/c-PS5ARVWR.js +9 -0
- package/dist/m/c-PZ4XEPUP.js +2 -0
- package/dist/m/c-Q622NS2Y.js +1 -0
- package/dist/m/c-Q7NQD65V.js +1 -0
- package/dist/m/c-QH63LQOS.js +1 -0
- package/dist/m/c-QHIWXHRO.js +1 -0
- package/dist/m/c-QHWJ5ZIJ.js +1 -0
- package/dist/m/c-QICP2YR5.js +1 -0
- package/dist/m/c-QJ4OM3G6.js +1 -0
- package/dist/m/c-QNKREOL6.js +1 -0
- package/dist/m/c-R3L7ZJGB.js +2 -0
- package/dist/m/c-R7IWVINQ.js +1 -0
- package/dist/m/c-RM7J7BV2.js +1 -0
- package/dist/m/c-RSMOODDU.js +1 -0
- package/dist/m/c-RVMWGXEJ.js +1 -0
- package/dist/m/c-RYUXUUBX.js +1 -0
- package/dist/m/c-S4ZEH46B.js +9 -0
- package/dist/m/c-S7H2DRCB.js +1 -0
- package/dist/m/c-S7LK4KUE.js +1 -0
- package/dist/m/c-SDAXDM2D.js +1 -0
- package/dist/m/c-SGIA4IEQ.js +188 -0
- package/dist/m/c-SMBZG5X4.js +1 -0
- package/dist/m/c-SMGU7RT3.js +235 -0
- package/dist/m/c-SPIORRYS.js +1 -0
- package/dist/m/c-SWLRT66R.js +1 -0
- package/dist/m/c-SZGYW5HT.js +1 -0
- package/dist/m/c-TCCA5BZN.js +2 -0
- package/dist/m/c-TCJTVAFN.js +1 -0
- package/dist/m/c-TJ6WOJL3.js +67 -0
- package/dist/m/c-TQEMVJCS.js +1 -0
- package/dist/m/c-TRS6TM6O.js +1 -0
- package/dist/m/c-TYLXX4NF.js +21 -0
- package/dist/m/c-U62OB4BT.js +1 -0
- package/dist/m/c-U6YWUAR3.js +8 -0
- package/dist/m/c-UDCSU5G5.js +2 -0
- package/dist/m/c-UDUUJPFZ.js +1 -0
- package/dist/m/c-UGHH4MB3.js +1 -0
- package/dist/m/c-UL2YUY52.js +1 -0
- package/dist/m/c-VAK7SG37.js +1 -0
- package/dist/m/c-VDSS4K3Z.js +1 -0
- package/dist/m/c-VE6ZMYMC.js +1 -0
- package/dist/m/c-VG5XIN4T.js +1 -0
- package/dist/m/c-VHM5XQHK.js +1 -0
- package/dist/m/c-VHNSBD2M.js +1 -0
- package/dist/m/c-VI5RMSVY.js +1 -0
- package/dist/m/c-VKEDWYDF.js +1 -0
- package/dist/m/c-VRZN56XY.js +1 -0
- package/dist/m/c-W5MCHEGA.js +1 -0
- package/dist/m/c-WDC5GVKU.js +1 -0
- package/dist/m/c-WN5AY3OZ.js +1 -0
- package/dist/m/c-WNYBLIOZ.js +1 -0
- package/dist/m/c-WRBKEJD4.js +1 -0
- package/dist/m/c-WWXIDH4O.js +28 -0
- package/dist/m/c-WYFDLITL.js +1 -0
- package/dist/m/c-XCNTK76U.js +1 -0
- package/dist/m/c-XMS6DPBR.js +1 -0
- package/dist/m/c-XN6MBKI6.js +67 -0
- package/dist/m/c-XPELB6E5.js +1 -0
- package/dist/m/c-XQXZAO7N.js +1 -0
- package/dist/m/c-Y5HBBIQ4.js +1 -0
- package/dist/m/c-ZE46QDIH.js +1 -0
- package/dist/m/c-ZUCOKOHT.js +1 -0
- package/dist/m/c-ZVPVXTJF.js +4 -0
- package/dist/m/c-ZVRKXKM7.js +1 -0
- package/dist/m/c-ZWIOJGMT.js +1 -0
- package/dist/m/core/admin-attrs-QHOKPJ7W.js +1 -0
- package/dist/m/core/autosave-HRYGUWV6.js +1 -0
- package/dist/m/core/conflict-notice-6MROJN2L.js +1 -0
- package/dist/m/core/draft-mode-WSQAT67S.js +1 -0
- package/dist/m/core/host-permission-FNXVEFNE.js +1 -0
- package/dist/m/core/is-edit-mode-KTWA3O5N.js +1 -0
- package/dist/m/core/persist-JFYRHMRJ.js +3 -0
- package/dist/m/core/recovery-FLTCC2OC.js +1 -0
- package/dist/m/core/save-HQZ4S667.js +1 -0
- package/dist/m/core/save-core-KGQWFUNH.js +1 -0
- package/dist/m/core/snapshot-EGQZNT45.js +1 -0
- package/dist/m/core/unsaved-warning-IDJLD66H.js +1 -0
- package/dist/m/dom/all-APS5ZSKP.js +1 -0
- package/dist/m/dom/dom-helpers-L7OSR6S4.js +1 -0
- package/dist/m/events/index-RN2JNGBV.js +1 -0
- package/dist/m/internals/index-PVXGPUDA.js +1 -0
- package/dist/m/lib/cache-bust-MUMFXZK6.js +1 -0
- package/dist/m/lib/region-policy-SB2AWVG5.js +1 -0
- package/dist/m/loader-S4I7GKXR.js +1 -0
- package/dist/m/manifest-4C419D67.js +1 -0
- package/dist/m/manifest-edit-B077F288.js +1 -0
- package/dist/m/manifest.json +3988 -0
- package/dist/m/options/options-EJMS3K24.js +1 -0
- package/dist/m/page/editor-NNJA4OKD.js +202 -0
- package/dist/m/plugins/ai-edit-QN4PMMNL.js +6 -0
- package/dist/m/plugins/bind-text-NX46N5UV.js +1 -0
- package/dist/m/plugins/cms-HP3LSTPN.js +2293 -0
- package/dist/m/plugins/demo-RM5IR6AO.js +1 -0
- package/dist/m/plugins/derive-UAAA4V4S.js +1 -0
- package/dist/m/plugins/indicator-URDBBOQO.js +1 -0
- package/dist/m/plugins/live-HFWD4OIH.js +1 -0
- package/dist/m/plugins/menu-3HIEQSI6.js +138 -0
- package/dist/m/plugins/message-LQ6EDH4V.js +1 -0
- package/dist/m/plugins/page-JOKB6XPR.js +2 -0
- package/dist/m/plugins/page-view-NXOJHNW6.js +1 -0
- package/dist/m/plugins/people-SGPJKANK.js +1 -0
- package/dist/m/plugins/quickcrop-QNY3PKLD.js +26 -0
- package/dist/m/plugins/quickcrop-QNY3PKLD.js.LEGAL.txt +7 -0
- package/dist/m/plugins/richclay-NRQDSWX6.js +517 -0
- package/dist/m/plugins/richclay-NRQDSWX6.js.LEGAL.txt +1 -0
- package/dist/m/plugins/sortable-GWT4PWDV.js +1 -0
- package/dist/m/plugins/source-4ZRSAIYM.js +1 -0
- package/dist/m/plugins/undo-VDA5P7FH.js +1 -0
- package/dist/m/plugins/unsent-HJFLQJ2O.js +1 -0
- package/dist/m/plugins/upgrade-W7FG5VFG.js +1 -0
- package/dist/m/plugins/upload-WLYKK6TL.js +1 -0
- package/dist/m/plugins/visitor-drafts-LIDY7NH6.js +21 -0
- package/dist/m/plugins/visitor-drafts-owner-ZXCKBZE7.js +1 -0
- package/dist/m/plugins/wire-4N6GYAF6.js +1 -0
- package/dist/m/reader-core-DXYCURFF.js +68 -0
- package/dist/m/route/route-KOCZSEGN.js +1 -0
- package/dist/m/sync/live-sync-J7VMYTKS.js +1 -0
- package/dist/m/ui/index-3JLVI27O.js +1 -0
- package/dist/m/utils/index-4TJCVLT7.js +1 -0
- package/dist/m/vendor/Sortable.vendor-A755ITLN.js +3 -0
- package/dist/m/vendor/Sortable.vendor-A755ITLN.js.LEGAL.txt +1 -0
- package/dist/m/vendor/sap-core.vendor-A7BMUYZT.js +6 -0
- package/dist/offline-manifest.json +4034 -0
- package/dist/page/themes/light-1.css +430 -0
- package/dist/server/core.cjs +23748 -22855
- package/dist/server/offline-runtime.cjs +4954 -0
- package/dist/server/offline-runtime.mjs +4923 -0
- package/dist/server/rooms.mjs +9 -0
- package/docs/guide.md +1078 -669
- package/entries/all.js +2 -0
- package/entries/clay-data.js +1 -1
- package/entries/clay-dom.js +2 -0
- package/entries/clay-events.js +2 -0
- package/entries/clay-internals.js +2 -0
- package/entries/clay-options.js +2 -0
- package/entries/clay-router.js +2 -0
- package/entries/clay-ui.js +2 -0
- package/entries/clay-utils.js +2 -0
- package/entries/clay.js +2 -0
- package/entries/sap.js +6 -6
- package/fonts/ibm-plex-mono-LICENSE +93 -0
- package/fonts/ibm-plex-mono-latin-300-normal.woff2 +0 -0
- package/fonts/ibm-plex-mono-latin-400-italic.woff2 +0 -0
- package/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
- package/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
- package/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
- package/fonts/ibm-plex-sans-LICENSE +93 -0
- package/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
- package/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
- package/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
- package/fonts/ibm-plex.css +71 -0
- package/fonts/inter-LICENSE +93 -0
- package/fonts/inter-cyrillic-ext-wght-normal.woff2 +0 -0
- package/fonts/inter-cyrillic-wght-normal.woff2 +0 -0
- package/fonts/inter-greek-ext-wght-normal.woff2 +0 -0
- package/fonts/inter-greek-wght-normal.woff2 +0 -0
- package/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
- package/fonts/inter-latin-wght-normal.woff2 +0 -0
- package/fonts/inter-vietnamese-wght-normal.woff2 +0 -0
- package/fonts/inter.css +62 -0
- package/fonts/newsreader-LICENSE +93 -0
- package/fonts/newsreader-latin-ext-opsz-normal.woff2 +0 -0
- package/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
- package/fonts/newsreader-vietnamese-opsz-normal.woff2 +0 -0
- package/fonts/newsreader.css +26 -0
- package/fonts/work-sans-LICENSE +93 -0
- package/fonts/work-sans-latin-wght-normal.woff2 +0 -0
- package/fonts/work-sans.css +8 -0
- package/package.json +20 -3
- package/packed-contract.json +1 -0
- package/src/attrs/add-from.js +27 -4
- package/src/attrs/save-freeze.js +7 -52
- package/src/core/admin-attrs.js +119 -12
- package/src/core/admin-contenteditable.js +12 -10
- package/src/core/admin-inputs.js +14 -15
- package/src/core/admin-onclick.js +2 -0
- package/src/core/autosave.js +74 -21
- package/src/core/boot-phase.js +2 -1
- package/src/core/conflict-download.js +19 -23
- package/src/core/conflict-notice-ui.js +1173 -0
- package/src/core/conflict-notice.js +140 -697
- package/src/core/download.js +32 -0
- package/src/core/edit-mode.js +147 -14
- package/src/core/etag.js +30 -12
- package/src/core/host-meta.js +90 -8
- package/src/core/host-permission.js +29 -0
- package/src/core/is-edit-mode.js +145 -12
- package/src/core/mode-key.js +125 -0
- package/src/core/mode-lifecycle.js +544 -0
- package/src/core/mode-receipt.js +30 -0
- package/src/core/mode-refusal.js +13 -0
- package/src/core/mode-resources.js +52 -0
- package/src/core/mode-support.js +82 -0
- package/src/core/mode-switch.js +259 -0
- package/src/core/mode-transition.js +112 -0
- package/src/core/page-data-write.js +305 -0
- package/src/core/page-data.js +26 -227
- package/src/core/page-format-wire.js +4 -0
- package/src/core/page-format.js +58 -0
- package/src/core/persist.js +37 -9
- package/src/core/preserve-authored.js +114 -0
- package/src/core/recovery.js +772 -0
- package/src/core/runtime-url.js +105 -0
- package/src/core/save-core.js +113 -12
- package/src/core/save-replace.js +72 -0
- package/src/core/save-size-notice.js +134 -0
- package/src/core/save-size.js +140 -0
- package/src/core/save.js +806 -119
- package/src/core/snapshot.js +159 -11
- package/src/core/source-map.js +157 -9
- package/src/core/unsaved-warning.js +14 -4
- package/src/core/upgrade-run.js +408 -0
- package/src/core/version.js +18 -0
- package/src/lib/assets.js +30 -0
- package/src/lib/autosave-debug-gate.js +50 -0
- package/src/lib/autosave-scheduler.js +140 -0
- package/src/lib/boot-imports.js +8 -0
- package/src/lib/derived.js +3 -1
- package/src/lib/dirty-gate.js +15 -0
- package/src/lib/doc-storage.js +33 -0
- package/src/lib/effect.js +9 -4
- package/src/lib/mutation.js +4 -2
- package/src/lib/offline-runtime.js +226 -0
- package/src/lib/preload.js +48 -0
- package/src/lib/root-attrs.js +1 -1
- package/src/lib/trash.js +18 -0
- package/src/lib/undo/capture-move.js +152 -0
- package/src/live/local-channel.js +61 -0
- package/src/live/local-lane.js +60 -9
- package/src/live/server-lane.js +6 -3
- package/src/loader-logic.js +76 -15
- package/src/loader.js +218 -30
- package/src/page/adopt-boot.js +76 -22
- package/src/page/adopt.js +25 -4
- package/src/page/awareness.js +230 -0
- package/src/page/blocks.js +113 -6
- package/src/page/blocksel.js +20 -4
- package/src/page/board-face.js +13 -0
- package/src/page/board-panel.js +5 -17
- package/src/page/board-style.js +2 -13
- package/src/page/board-view.js +1 -11
- package/src/page/board-views.js +3 -0
- package/src/page/board.js +2 -2
- package/src/page/boot-pack.js +26 -0
- package/src/page/boot.js +237 -0
- package/src/page/chart-tables.js +11 -0
- package/src/page/chart.js +6 -10
- package/src/page/checklist.js +1 -1
- package/src/page/checkpoint-proof.js +289 -0
- package/src/page/chrome.js +431 -63
- package/src/page/csv-import.js +17 -2
- package/src/page/document-title-dom.js +52 -0
- package/src/page/document-title-runtime.js +90 -0
- package/src/page/document-title.js +12 -0
- package/src/page/drag.js +48 -13
- package/src/page/drop.js +2 -1
- package/src/page/editor.js +399 -90
- package/src/page/emoji-data.js +162 -0
- package/src/page/feature-loader.js +72 -0
- package/src/page/features/board.js +21 -0
- package/src/page/features/chart.js +11 -0
- package/src/page/features/code.js +13 -0
- package/src/page/features/dates.js +180 -0
- package/src/page/features/emoji.js +187 -0
- package/src/page/features/media.js +290 -0
- package/src/page/features/mentions.js +188 -0
- package/src/page/features/registry.js +28 -0
- package/src/page/features/table.js +383 -0
- package/src/page/{tool-view.js → features/tool.js} +33 -2
- package/src/page/format-codec.js +215 -0
- package/src/page/format-command.js +9 -0
- package/src/page/format-gate.js +179 -0
- package/src/page/format-host.js +54 -0
- package/src/page/format-level.js +157 -0
- package/src/page/format-native-commands.js +142 -0
- package/src/page/format-native.js +42 -0
- package/src/page/highlight-slot.js +23 -0
- package/src/page/highlight.js +30 -16
- package/src/page/history-intent.js +78 -0
- package/src/page/inline.js +45 -28
- package/src/page/items.js +67 -14
- package/src/page/link.js +1 -0
- package/src/page/markdown.js +112 -3
- package/src/page/media-views.js +3 -0
- package/src/page/media.js +33 -245
- package/src/page/mention-picker.js +99 -0
- package/src/page/merge.js +1 -1
- package/src/page/outline-cache.js +11 -0
- package/src/page/placeholder.js +27 -7
- package/src/page/projection.js +240 -51
- package/src/page/reader-patch.js +306 -0
- package/src/page/recover.js +1 -1
- package/src/page/rich/page-tool.js +1 -4
- package/src/page/runtime-owner.js +27 -0
- package/src/page/save-projection.js +46 -4
- package/src/page/save-states.js +1 -1
- package/src/page/schema.js +47 -0
- package/src/page/table-rect-key.js +3 -0
- package/src/page/table-select.js +4 -3
- package/src/page/table-style.js +1 -1
- package/src/page/table-views.js +3 -0
- package/src/page/table.js +8 -293
- package/src/page/themes/content.css +25 -1
- package/src/page/themes/light-1.css +163 -2
- package/src/page/themes/light-1.source.css +269 -0
- package/src/page/tool-capability.js +3 -0
- package/src/page/tool-views.js +3 -0
- package/src/page/view-hooks.js +32 -0
- package/src/page/view.js +390 -107
- package/src/page/ybind/awareness.js +172 -0
- package/src/page/ybind/binding.js +40 -5
- package/src/page/ybind/bridge.js +50 -47
- package/src/page/ybind/decode.js +52 -19
- package/src/page/ybind/doc.js +27 -2
- package/src/page/ybind/group.js +12 -3
- package/src/page/ybind/index.js +2 -0
- package/src/page/ybind/lineage.js +71 -0
- package/src/page/ybind/marks.js +26 -1
- package/src/page/ybind/migrate.js +48 -13
- package/src/page/ybind/moves.js +32 -21
- package/src/page/ybind/positions.js +50 -0
- package/src/page/ybind/provider.js +97 -24
- package/src/page/ybind/recovery-proof.js +191 -0
- package/src/page/ybind/recovery-replay.js +488 -0
- package/src/page/ybind/tokens.js +15 -6
- package/src/page/ybind/walk.js +10 -3
- package/src/page/ybind/writer.js +48 -4
- package/src/plugins/ai-edit.js +167 -32
- package/src/plugins/bind-text.js +218 -0
- package/src/plugins/cms.js +93 -0
- package/src/plugins/indicator.js +57 -5
- package/src/plugins/live.js +319 -35
- package/src/plugins/menu/claygoo.svg.js +1 -0
- package/src/plugins/menu/seo-head.js +323 -0
- package/src/plugins/menu/seo.js +849 -0
- package/src/plugins/menu.js +425 -0
- package/src/plugins/page-view.js +131 -0
- package/src/plugins/page.js +1131 -270
- package/src/plugins/people.js +158 -31
- package/src/plugins/richclay.js +119 -9
- package/src/plugins/sortable.js +370 -60
- package/src/plugins/source.js +189 -366
- package/src/plugins/undo.js +289 -19
- package/src/plugins/unsent.js +132 -0
- package/src/plugins/upgrade-run.js +1 -0
- package/src/plugins/upgrade.js +210 -0
- package/src/plugins/upload-task.js +571 -0
- package/src/plugins/upload-ui.js +265 -0
- package/src/plugins/upload.js +34 -153
- package/src/plugins/visitor-drafts/inert.js +32 -0
- package/src/plugins/visitor-drafts/intro.js +2 -1
- package/src/plugins/visitor-drafts/owner-chip.js +3 -0
- package/src/plugins/visitor-drafts/prompt.js +2 -2
- package/src/plugins/visitor-drafts-owner.js +85 -0
- package/src/plugins/visitor-drafts.js +31 -42
- package/src/plugins/wire.js +82 -1
- package/src/reader-core.js +26 -0
- package/src/recovery/conflicts.js +287 -0
- package/src/recovery/identity.js +154 -0
- package/src/recovery/store.js +792 -0
- package/src/recovery/undo.js +257 -0
- package/src/server/checkpoint/index.js +68 -4
- package/src/server/offline-runtime/index.js +214 -0
- package/src/server/rooms/index.js +2 -1
- package/src/server/rooms/live-data-rooms.js +2 -2
- package/src/server/rooms/page-admission.js +33 -0
- package/src/server/rooms/page-lineage.js +56 -0
- package/src/server/rooms/page-rebase.js +11 -5
- package/src/server/rooms/page-state.js +2 -0
- package/src/server/rooms/page-write-admission.js +9 -3
- package/src/source/session.js +705 -0
- package/src/sync/conflict-revert.js +5 -4
- package/src/sync/conflicts-edit.js +119 -0
- package/src/sync/conflicts-facade.js +49 -0
- package/src/sync/conflicts.js +99 -1
- package/src/sync/editing-marker.js +37 -6
- package/src/sync/editing-sender.js +8 -1
- package/src/sync/live-sync-edit.js +63 -0
- package/src/sync/live-sync.js +364 -119
- package/src/sync/local-presence.js +187 -0
- package/src/sync/merge-declarations.js +10 -0
- package/src/sync/merge-engine.js +12 -0
- package/src/sync/presence-store.js +412 -0
- package/src/sync/presence-target.js +243 -0
- package/src/sync/presence.js +72 -41
- package/src/sync/saved-handoff.js +200 -0
- package/src/sync/saved-stream.js +544 -0
- package/src/sync/version-guard.js +92 -0
- package/src/sync/wire-profile.js +81 -0
- package/src/ui/bevel-controls.js +2 -8
- package/src/ui/page-scheme.js +7 -0
- package/src/ui/skins/cms.js +1 -1
- package/src/ui/theme-config.js +150 -0
- package/src/ui/theme.js +6 -138
- package/src/ui/toast-lazy.js +11 -0
- package/src/vendor/LICENSES-optional.md +253 -0
- package/src/vendor/highlight.vendor.js +3 -0
- package/src/vendor/hljs-bash.vendor.js +2 -0
- package/src/vendor/hljs-css.vendor.js +2 -0
- package/src/vendor/hljs-javascript.vendor.js +2 -0
- package/src/vendor/hljs-json.vendor.js +2 -0
- package/src/vendor/hljs-python.vendor.js +2 -0
- package/src/vendor/hljs-xml.vendor.js +2 -0
- package/src/vendor/hyper-html-api-data.vendor.js +1 -1
- package/src/vendor/hyper-html-api-upgrade.vendor.js +5 -0
- package/src/vendor/hyper-morph-identity.vendor.js +2 -0
- package/src/vendor/hyper-morph-json.vendor.js +3 -0
- package/src/vendor/hyper-morph.vendor.js +6 -6
- package/src/vendor/hyper-undo.vendor.js +1 -1
- package/src/vendor/hypercms.vendor.js +169 -84
- package/src/vendor/marked.vendor.js +68 -0
- package/src/vendor/overtype.vendor.js +994 -0
- package/src/vendor/richclay.vendor.js +17 -17
- package/src/vendor/sap-core.vendor.js +5 -5
- package/src/vendor/sap-ownership.vendor.js +11 -7
package/src/page/ybind/tokens.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { attrKeys, sameJson } from "./layout.js";
|
|
2
2
|
import { blockJson } from "../model.js";
|
|
3
|
-
import { marksKey,
|
|
3
|
+
import { marksKey, marksFields } from "./marks.js";
|
|
4
4
|
import { createProjectionMap } from "./projection-map.js";
|
|
5
5
|
|
|
6
6
|
export const implicitFlags = (doc, visible) => {
|
|
@@ -19,7 +19,16 @@ export const implicitFlags = (doc, visible) => {
|
|
|
19
19
|
});
|
|
20
20
|
return out;
|
|
21
21
|
};
|
|
22
|
-
const
|
|
22
|
+
const opaqueOf = (node) => node.attrs.raw ?? null;
|
|
23
|
+
const pickAttrs = (node) => {
|
|
24
|
+
const raw = opaqueOf(node);
|
|
25
|
+
if (raw) { const o = { ...raw }; delete o.t; delete o.pos; return o; }
|
|
26
|
+
const o = {};
|
|
27
|
+
for (const k of attrKeys(node.type)) o[k] = node.attrs[k];
|
|
28
|
+
if (node.type.name === "table") o.rows = blockJson(node).rows;
|
|
29
|
+
return o;
|
|
30
|
+
};
|
|
31
|
+
const typeOfNode = (node) => opaqueOf(node)?.t ?? node.type.name;
|
|
23
32
|
|
|
24
33
|
export function tokensOf(doc, alias = new Map(), visible = null) {
|
|
25
34
|
const toks = [];
|
|
@@ -27,9 +36,9 @@ export function tokensOf(doc, alias = new Map(), visible = null) {
|
|
|
27
36
|
doc.forEach((block, _o, index) => {
|
|
28
37
|
const implicit = flags[index] && !alias.has(block.attrs.id);
|
|
29
38
|
const brk = visible ? visible[index]?.brk ?? null : null;
|
|
30
|
-
if (!implicit) toks.push({ k: "b", id: flags[index] && alias.has(block.attrs.id) ? alias.get(block.attrs.id) : block.attrs.id, t: block
|
|
39
|
+
if (!implicit) toks.push({ k: "b", id: flags[index] && alias.has(block.attrs.id) ? alias.get(block.attrs.id) : block.attrs.id, t: typeOfNode(block), attrs: pickAttrs(block), brk });
|
|
31
40
|
if (block.isTextblock) block.content.forEach((n) => {
|
|
32
|
-
if (n.isText) { const ms = block
|
|
41
|
+
if (n.isText) { const ms = typeOfNode(block) === "code_block" ? [] : n.marks; const mk = marksKey(ms), ma = marksFields(ms); for (let i = 0; i < n.text.length; i++) toks.push({ k: "c", ch: n.text[i], mk, ma }); }
|
|
33
42
|
else if (n.type.name === "hard_break") toks.push({ k: "h" });
|
|
34
43
|
});
|
|
35
44
|
});
|
|
@@ -74,8 +83,8 @@ export function textTokenRange(doc, from, to) {
|
|
|
74
83
|
const a = Math.max(0, startOffset - cursor), b = Math.min(node.nodeSize, endOffset - cursor);
|
|
75
84
|
if (a < b) {
|
|
76
85
|
if (node.isText) {
|
|
77
|
-
const marks = block
|
|
78
|
-
const mk = marksKey(marks), ma =
|
|
86
|
+
const marks = typeOfNode(block) === "code_block" ? [] : node.marks;
|
|
87
|
+
const mk = marksKey(marks), ma = marksFields(marks);
|
|
79
88
|
for (let i = a; i < b; i++) tokens.push({ k: "c", ch: node.text[i], mk, ma });
|
|
80
89
|
} else if (node.type.name === "hard_break") tokens.push({ k: "h" });
|
|
81
90
|
}
|
package/src/page/ybind/walk.js
CHANGED
|
@@ -144,14 +144,21 @@ function walkFlow(pd, index) {
|
|
|
144
144
|
const root = recoveredRoot(sourceKey, removalsBySource.get(sourceKey) ?? [], intents);
|
|
145
145
|
const id = `recovered:${sourceKey}`;
|
|
146
146
|
const t = root ? root.type : "paragraph";
|
|
147
|
-
|
|
147
|
+
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 };
|
|
148
149
|
segs.push(cur);
|
|
149
150
|
prevId = id;
|
|
150
151
|
};
|
|
151
152
|
const open = (id, brk, implicit) => {
|
|
152
153
|
cur = { kind: "b", id, baseId: id, brk, implicit, runs: [], len: implicit ? 0 : 1, atom: false, items: !implicit && (markerCount.get(id) ?? 0) > 1 ? [] : null };
|
|
153
|
-
if (!implicit) {
|
|
154
|
-
|
|
154
|
+
if (!implicit) {
|
|
155
|
+
cur.t = typeOf(id);
|
|
156
|
+
// A type this runtime has no schema for still owns the text and marks up to
|
|
157
|
+
// the next block marker: it is not an atom whose following text becomes an
|
|
158
|
+
// implicit paragraph, and it is never rewritten as one.
|
|
159
|
+
cur.opaque = !Object.hasOwn(schema.nodes, cur.t);
|
|
160
|
+
cur.atom = !cur.opaque && !schema.nodes[cur.t]?.isTextblock;
|
|
161
|
+
} else cur.t = "paragraph";
|
|
155
162
|
segs.push(cur);
|
|
156
163
|
prevId = id;
|
|
157
164
|
};
|
package/src/page/ybind/writer.js
CHANGED
|
@@ -8,10 +8,23 @@ import { resolveTableFields, tableSeed, writeTable } from "./table.js";
|
|
|
8
8
|
import { resolveBoardFields, writeBoard } from "./board.js";
|
|
9
9
|
import { createOriginIndex } from "./origins.js";
|
|
10
10
|
|
|
11
|
+
const FIELD = (value) => (value === true ? {} : value);
|
|
12
|
+
const sameValue = (a, b) => sameJson(FIELD(a), FIELD(b));
|
|
13
|
+
|
|
11
14
|
export function setAttrs(pd, id, t, attrs) {
|
|
12
15
|
let m = pd.attrs.get(id);
|
|
13
16
|
if (!m) { m = new Y.Map(); pd.attrs.set(id, m); }
|
|
14
17
|
const type = schema.nodes[t];
|
|
18
|
+
// A block type this runtime has no schema for keeps its original record: no
|
|
19
|
+
// known field list to normalize it against, and never a paragraph in its place.
|
|
20
|
+
if (!type) {
|
|
21
|
+
if (m.get("t") !== t) m.set("t", t);
|
|
22
|
+
for (const [k, v] of Object.entries(attrs ?? {})) {
|
|
23
|
+
if (k === "t" || k === "pos") continue;
|
|
24
|
+
if (!sameJson(m.has(k) ? m.get(k) : undefined, v)) m.set(k, v);
|
|
25
|
+
}
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
15
28
|
const table = t === "table" && m.get("t") === "table" && !recoveredSource(id);
|
|
16
29
|
const board = t === "board" && !recoveredSource(id);
|
|
17
30
|
const before = table ? resolveTableFields(pd.tableFields, id, tableSeed(pd, id)) : board ? resolveBoardFields(pd.boardFields, id) : null;
|
|
@@ -46,6 +59,31 @@ export function liveKeys(ctx) {
|
|
|
46
59
|
return out;
|
|
47
60
|
}
|
|
48
61
|
|
|
62
|
+
// The live keys this runtime has no schema mark for, including the reserved
|
|
63
|
+
// compact-code bridge. A command never cancels them: they stay byte for byte
|
|
64
|
+
// until something that understands them rewrites them.
|
|
65
|
+
export function opaqueKeys(ctx) {
|
|
66
|
+
const cancelled = new Set();
|
|
67
|
+
for (const [k, v] of ctx) if (isCancel(k) && v) cancelled.add(k.split("!")[0]);
|
|
68
|
+
const out = [];
|
|
69
|
+
for (const [k, v] of ctx) if (!isCancel(k) && v !== null && v !== undefined && !cancelled.has(k) && !schema.marks[markName(k)]) out.push([k, v]);
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// The attributes an inserted unit carries over from its neighbours: every known
|
|
74
|
+
// key as before, and an opaque key only when the editor's mark set still names
|
|
75
|
+
// it, so text at a span boundary does not inherit a format nobody can read.
|
|
76
|
+
export function baseAttributes(ctx, want = {}) {
|
|
77
|
+
const out = {};
|
|
78
|
+
let opaque = false;
|
|
79
|
+
for (const [k, v] of ctx) if (isCancel(k) || schema.marks[markName(k)]) out[k] = v;
|
|
80
|
+
for (const [k, v] of opaqueKeys(ctx)) {
|
|
81
|
+
opaque = true;
|
|
82
|
+
if (want[markName(k)] !== undefined) out[k] = v;
|
|
83
|
+
}
|
|
84
|
+
return { attrs: out, opaque };
|
|
85
|
+
}
|
|
86
|
+
|
|
49
87
|
export function runAttributes(pd, ctx, want) {
|
|
50
88
|
const rid = mintOp(pd);
|
|
51
89
|
const changes = {};
|
|
@@ -54,12 +92,17 @@ export function runAttributes(pd, ctx, want) {
|
|
|
54
92
|
for (const [k, v] of have) {
|
|
55
93
|
const n = markName(k);
|
|
56
94
|
const w = want[n];
|
|
57
|
-
if (w !== undefined &&
|
|
95
|
+
if (w !== undefined && sameValue(w, v)) kept.add(n);
|
|
58
96
|
else changes[`${k}!${rid}`] = true;
|
|
59
97
|
}
|
|
98
|
+
for (const [k, v] of opaqueKeys(ctx)) {
|
|
99
|
+
const n = markName(k);
|
|
100
|
+
if (want[n] !== undefined && sameValue(want[n], v)) kept.add(n);
|
|
101
|
+
}
|
|
60
102
|
for (const [n, w] of Object.entries(want)) if (!kept.has(n)) changes[`${n}~${mintOp(pd)}`] = w;
|
|
61
|
-
|
|
62
|
-
|
|
103
|
+
const base = baseAttributes(ctx, want);
|
|
104
|
+
if (!Object.keys(changes).length && !base.opaque) return undefined;
|
|
105
|
+
return { ...base.attrs, ...changes };
|
|
63
106
|
}
|
|
64
107
|
|
|
65
108
|
export const CHUNK_CHARS = 2000;
|
|
@@ -119,7 +162,7 @@ function insertChunk(pd, yIdx, toks, fences = null) {
|
|
|
119
162
|
i += run.length;
|
|
120
163
|
run = "";
|
|
121
164
|
};
|
|
122
|
-
const embed = (e) => { const attrs =
|
|
165
|
+
const embed = (e) => { const attrs = baseAttributes(ctxAt(pd, i)).attrs; beforeFence(pd, i, fences, () => pd.flow.insertEmbed(i, e, attrs)); i += 1; };
|
|
123
166
|
for (const t of toks) {
|
|
124
167
|
if (t.k === "c") { if (runMk !== null && t.mk !== runMk) flush(); runMk = t.mk; runMa = t.ma; run += t.ch; }
|
|
125
168
|
else if (t.k === "h") { flush(); runMk = null; embed({ br: 1 }); }
|
|
@@ -249,6 +292,7 @@ export function applyRegion(ctx, ta, oldToks, newToks, oldSurvives = null) {
|
|
|
249
292
|
else insertTokens(pd, map.toPhysical(e.at, "before"), e.i.toks, ctx.tx, ctx.fences);
|
|
250
293
|
}
|
|
251
294
|
for (const [ob, nb] of attrs) ctx.tx(() => {
|
|
295
|
+
if (!schema.nodes[nb.t]) return;
|
|
252
296
|
const source = ctx.recovered.get(ob.id);
|
|
253
297
|
if (source) {
|
|
254
298
|
if (ob.t !== nb.t) pd.gone.set(attrKey(source, "t"), nb.t);
|
package/src/plugins/ai-edit.js
CHANGED
|
@@ -41,10 +41,9 @@
|
|
|
41
41
|
* invisible to the mutation system (its status text changes constantly), absent from
|
|
42
42
|
* every snapshot and from what peers receive.
|
|
43
43
|
*/
|
|
44
|
-
import {
|
|
45
|
-
import { mergeTagRecognizers } from "../sync/merge-tags.js";
|
|
44
|
+
import { loadedEngine, mergeEngine } from "../sync/merge-engine.js";
|
|
46
45
|
import Mutation from "../lib/mutation.js";
|
|
47
|
-
import {
|
|
46
|
+
import { startsAtImport } from "../core/is-edit-mode.js";
|
|
48
47
|
import { holdAllSaves, releaseAllSaves } from "../core/save.js";
|
|
49
48
|
import { STRIP_FROM_SAVE, SNAPSHOT_REMOVE_SELECTOR } from "../lib/region-policy.js";
|
|
50
49
|
import { enableContentEditable } from "../core/admin-contenteditable.js";
|
|
@@ -81,7 +80,10 @@ let barMode = null; // "working", "ready", "saving" or "error"
|
|
|
81
80
|
let barLifecycle = null;
|
|
82
81
|
let barCloseTimer = null;
|
|
83
82
|
let panelPointerDown = false; // the last pointerdown began in the panel: its click is not a page click
|
|
84
|
-
|
|
83
|
+
let drafts = new WeakMap(); // compose text a target keeps while the panel is shut
|
|
84
|
+
// A WeakMap cannot be read back, and an exit has to know whether anything typed here is
|
|
85
|
+
// still unsent, so the targets that hold a draft are counted beside it.
|
|
86
|
+
const drafted = new Set();
|
|
85
87
|
let anchorEl = null; // element the panel is currently anchored to
|
|
86
88
|
let chipTarget = null; // unit the hover chip currently points at
|
|
87
89
|
let chipHideTimer = null;
|
|
@@ -92,6 +94,24 @@ let selectionTimer = null;
|
|
|
92
94
|
let anchorRange = null; // the selection the open panel was raised for
|
|
93
95
|
let returnFocus = null; // where focus goes back to when the panel closes
|
|
94
96
|
let helperState = null; // "ready" or "unavailable"
|
|
97
|
+
let listeners = null; // the AbortController every handler one session added listens on
|
|
98
|
+
let observers = []; // the page observers that session opened
|
|
99
|
+
let styleEl = null; // the one stylesheet the chrome needed
|
|
100
|
+
let chromeToken = 0; // the latest init(); a teardown retires the one before it
|
|
101
|
+
|
|
102
|
+
function dropDraft(el) {
|
|
103
|
+
drafts.delete(el);
|
|
104
|
+
drafted.delete(el);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function keepDraft(el, text) {
|
|
108
|
+
if (!text) {
|
|
109
|
+
dropDraft(el);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
drafts.set(el, text);
|
|
113
|
+
drafted.add(el);
|
|
114
|
+
}
|
|
95
115
|
|
|
96
116
|
const HIGHLIGHT = 'clay-ai-edit';
|
|
97
117
|
const OFF_MESSAGE = 'AI editing is turned off. Turn it on from the app’s menu.';
|
|
@@ -190,6 +210,7 @@ function strippedBodyHTML() {
|
|
|
190
210
|
// ---------------------------------------------------------------- morphing
|
|
191
211
|
|
|
192
212
|
function morphTo(el, content, scripts) {
|
|
213
|
+
const { HyperMorph } = loadedEngine();
|
|
193
214
|
return HyperMorph.morph(el, content, { morphStyle: 'outerHTML', restoreFocus: true, scripts });
|
|
194
215
|
}
|
|
195
216
|
|
|
@@ -201,6 +222,7 @@ function morphTo(el, content, scripts) {
|
|
|
201
222
|
// against the snapshot the model saw, so data the user changed mid-flight survives
|
|
202
223
|
// the reply. Rewinds must restore the snapshot exactly, so they disable merging.
|
|
203
224
|
function sessionMorph(s, content, { rewind = false } = {}) {
|
|
225
|
+
const { HyperMorph, mergeTagRecognizers } = loadedEngine();
|
|
204
226
|
// handle:false: a reply's scripts never run, so the preview cannot execute code
|
|
205
227
|
// before Keep, and neither can a rewind.
|
|
206
228
|
const scripts = rewind
|
|
@@ -300,7 +322,7 @@ async function sendRequest(el, comment, quote) {
|
|
|
300
322
|
}
|
|
301
323
|
// The sent comment is this target's draft until the reply is ready: Error, Stop, a
|
|
302
324
|
// refused reply, a morph failure and a host cancellation all leave it in place.
|
|
303
|
-
|
|
325
|
+
keepDraft(el, comment);
|
|
304
326
|
closePanelForSend();
|
|
305
327
|
session.paused = true;
|
|
306
328
|
pauseObservers();
|
|
@@ -321,6 +343,9 @@ async function sendRequest(el, comment, quote) {
|
|
|
321
343
|
session.handle = handle;
|
|
322
344
|
const outcome = await handle.done;
|
|
323
345
|
if (!session || session.handle !== handle) return;
|
|
346
|
+
// The engine is fetched here, where a reply is applied, not at boot.
|
|
347
|
+
await mergeEngine();
|
|
348
|
+
if (!session || session.handle !== handle) return;
|
|
324
349
|
if (outcome.state === 'done') onDone(outcome.result || {});
|
|
325
350
|
else if (outcome.state === 'cancelled') onError('HTML Clay stopped this edit.');
|
|
326
351
|
else onError(outcome.error || 'the helper reported an error');
|
|
@@ -417,7 +442,7 @@ function onDone(payload) {
|
|
|
417
442
|
return;
|
|
418
443
|
}
|
|
419
444
|
positionChrome();
|
|
420
|
-
|
|
445
|
+
dropDraft(session.el); // delivered: the comment is no longer this target's draft
|
|
421
446
|
showBar('ready');
|
|
422
447
|
setBarStatus(readyText(warnings, payload.model), warnings.length ? 'warn' : '');
|
|
423
448
|
}
|
|
@@ -444,7 +469,7 @@ function revertSession() {
|
|
|
444
469
|
session = null;
|
|
445
470
|
if (!s) return;
|
|
446
471
|
try {
|
|
447
|
-
if (s.state === 'requesting' || s.state === 'deciding') {
|
|
472
|
+
if ((s.state === 'requesting' || s.state === 'deciding') && loadedEngine()) {
|
|
448
473
|
sessionMorph(s, s.snapshot, { rewind: true });
|
|
449
474
|
}
|
|
450
475
|
} finally {
|
|
@@ -507,15 +532,16 @@ function marked(el, name, value) {
|
|
|
507
532
|
}
|
|
508
533
|
|
|
509
534
|
function buildChrome() {
|
|
510
|
-
const
|
|
511
|
-
|
|
512
|
-
|
|
535
|
+
const { signal } = listeners;
|
|
536
|
+
styleEl = document.createElement('style');
|
|
537
|
+
styleEl.setAttribute('clay', RUNTIME_ONLY);
|
|
538
|
+
styleEl.textContent = `
|
|
513
539
|
[editmode\\:contenteditable][contenteditable]:focus {
|
|
514
540
|
outline: 1px solid #4a4a6a; outline-offset: 4px; border-radius: 2px;
|
|
515
541
|
}
|
|
516
542
|
::highlight(clay-ai-edit) { background-color: ${TOKENS['brass-soft']} !important; }
|
|
517
543
|
`;
|
|
518
|
-
document.head.appendChild(
|
|
544
|
+
document.head.appendChild(styleEl);
|
|
519
545
|
|
|
520
546
|
const scheme = `color-scheme:${pageScheme()}`;
|
|
521
547
|
|
|
@@ -641,24 +667,28 @@ function buildChrome() {
|
|
|
641
667
|
openPanel(document.body, quoteFromSelection(document.body));
|
|
642
668
|
});
|
|
643
669
|
|
|
644
|
-
window.addEventListener('scroll', () => { positionChrome(); hideChip(); }, { passive: true });
|
|
645
|
-
window.addEventListener('resize', () => { placeBubble(); if (panel && !panel.hidden) fitTextarea(); positionChrome(); }, { passive: true });
|
|
670
|
+
window.addEventListener('scroll', () => { positionChrome(); hideChip(); }, { passive: true, signal });
|
|
671
|
+
window.addEventListener('resize', () => { placeBubble(); if (panel && !panel.hidden) fitTextarea(); positionChrome(); }, { passive: true, signal });
|
|
646
672
|
// The CMS toggle can arrive after this chrome, and a docked sidebar slides it left.
|
|
647
673
|
const replace = () => { placeBubble(); positionChrome(); };
|
|
648
|
-
document.addEventListener('hcms:open', () => { replace(); setTimeout(replace, 350); });
|
|
649
|
-
document.addEventListener('hcms:close', () => { replace(); setTimeout(replace, 350); });
|
|
650
|
-
new MutationObserver((records) => {
|
|
674
|
+
document.addEventListener('hcms:open', () => { replace(); setTimeout(replace, 350); }, { signal });
|
|
675
|
+
document.addEventListener('hcms:close', () => { replace(); setTimeout(replace, 350); }, { signal });
|
|
676
|
+
const cmsToggle = new MutationObserver((records) => {
|
|
651
677
|
syncBubble();
|
|
652
678
|
const touched = (nodes) => [...nodes].some((n) => n.nodeType === 1 && n.hasAttribute('data-hcms-toggle-host'));
|
|
653
679
|
if (records.some((r) => touched(r.addedNodes) || touched(r.removedNodes))) replace();
|
|
654
|
-
})
|
|
680
|
+
});
|
|
681
|
+
cmsToggle.observe(document.body, { childList: true });
|
|
682
|
+
observers.push(cmsToggle);
|
|
655
683
|
|
|
656
684
|
// A target removed from the page ends its edit, so the save hold and the paused
|
|
657
685
|
// observers never outlive it. A running bar is no exception: it is torn down with
|
|
658
686
|
// the target it was describing.
|
|
659
|
-
new MutationObserver(() => {
|
|
687
|
+
const targetGone = new MutationObserver(() => {
|
|
660
688
|
if (anchorEl && !anchorEl.isConnected) abandonTarget();
|
|
661
|
-
})
|
|
689
|
+
});
|
|
690
|
+
targetGone.observe(document.body, { childList: true, subtree: true });
|
|
691
|
+
observers.push(targetGone);
|
|
662
692
|
}
|
|
663
693
|
|
|
664
694
|
// The panel's height changes as the box grows and the status line fills, so it is
|
|
@@ -709,6 +739,7 @@ function applyHelperState() {
|
|
|
709
739
|
// The host's toggle can change while the page is open, so each opening asks again.
|
|
710
740
|
function refreshHelperState() {
|
|
711
741
|
helperStateNow().then((state) => {
|
|
742
|
+
if (!panel) return; // the session this asked for has ended
|
|
712
743
|
helperState = state || 'unavailable';
|
|
713
744
|
if (!panel.hidden && !session) applyHelperState();
|
|
714
745
|
else syncBubble();
|
|
@@ -939,8 +970,7 @@ function openPanel(el, quote) {
|
|
|
939
970
|
// panel is opened on that target again.
|
|
940
971
|
function storeDraft() {
|
|
941
972
|
if (!anchorEl) return;
|
|
942
|
-
|
|
943
|
-
else drafts.delete(anchorEl);
|
|
973
|
+
keepDraft(anchorEl, textarea.value);
|
|
944
974
|
}
|
|
945
975
|
|
|
946
976
|
function closePanel() {
|
|
@@ -1023,6 +1053,7 @@ function escapeIsMine(event) {
|
|
|
1023
1053
|
}
|
|
1024
1054
|
|
|
1025
1055
|
function wireInteractions() {
|
|
1056
|
+
const { signal } = listeners;
|
|
1026
1057
|
// Clicks: text units are contenteditable (caret) and figures keep their own
|
|
1027
1058
|
// interactivity, so neither is intercepted, and nothing here prevents the click from
|
|
1028
1059
|
// landing. Any click on the page away from ClayJS chrome closes the box, a click
|
|
@@ -1033,7 +1064,7 @@ function wireInteractions() {
|
|
|
1033
1064
|
// box and ends on the page is still the box's, not a click away from it.
|
|
1034
1065
|
document.addEventListener('pointerdown', (event) => {
|
|
1035
1066
|
panelPointerDown = panel.contains(event.target);
|
|
1036
|
-
}, { capture: true });
|
|
1067
|
+
}, { capture: true, signal });
|
|
1037
1068
|
|
|
1038
1069
|
document.addEventListener('click', (event) => {
|
|
1039
1070
|
const startedInPanel = panelPointerDown;
|
|
@@ -1050,7 +1081,7 @@ function wireInteractions() {
|
|
|
1050
1081
|
} else if (!panel.hidden) {
|
|
1051
1082
|
closePanel();
|
|
1052
1083
|
}
|
|
1053
|
-
});
|
|
1084
|
+
}, { signal });
|
|
1054
1085
|
|
|
1055
1086
|
// Hover chip: follows the unit under the cursor while no panel is open.
|
|
1056
1087
|
let lastMove = 0;
|
|
@@ -1064,7 +1095,7 @@ function wireInteractions() {
|
|
|
1064
1095
|
const unit = unitFrom(event.target);
|
|
1065
1096
|
if (unit) showChipFor(unit);
|
|
1066
1097
|
else scheduleChipHide();
|
|
1067
|
-
});
|
|
1098
|
+
}, { signal });
|
|
1068
1099
|
|
|
1069
1100
|
document.addEventListener('keydown', (event) => {
|
|
1070
1101
|
if (isShortcut(event)) {
|
|
@@ -1094,26 +1125,35 @@ function wireInteractions() {
|
|
|
1094
1125
|
if (barMode === 'error') { closeBar(); return; }
|
|
1095
1126
|
if (barMode) return;
|
|
1096
1127
|
if (!panel.hidden) closePanel();
|
|
1097
|
-
});
|
|
1128
|
+
}, { signal });
|
|
1098
1129
|
|
|
1099
1130
|
document.addEventListener('selectionchange', () => {
|
|
1100
1131
|
clearTimeout(selectionTimer);
|
|
1101
1132
|
selectionTimer = setTimeout(showChipForSelection, 150);
|
|
1102
|
-
});
|
|
1133
|
+
}, { signal });
|
|
1103
1134
|
}
|
|
1104
1135
|
|
|
1105
1136
|
// ---------------------------------------------------------------- boot
|
|
1106
1137
|
|
|
1107
|
-
async function
|
|
1108
|
-
|
|
1138
|
+
async function loadHelper() {
|
|
1139
|
+
const token = ++chromeToken;
|
|
1109
1140
|
helperState = await helperStateNow();
|
|
1110
|
-
|
|
1111
|
-
|
|
1141
|
+
return token === chromeToken;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
function build() {
|
|
1112
1145
|
if (!helperState || panel) return;
|
|
1146
|
+
listeners = new AbortController();
|
|
1113
1147
|
buildChrome();
|
|
1114
1148
|
wireInteractions();
|
|
1115
1149
|
}
|
|
1116
1150
|
|
|
1151
|
+
async function init() {
|
|
1152
|
+
if (!startsAtImport() || panel) return; // an owner/editor feature, built once
|
|
1153
|
+
if (!(await loadHelper())) return;
|
|
1154
|
+
build();
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1117
1157
|
// A target the composer can be opened on: a connected content element of this
|
|
1118
1158
|
// document. ClayJS chrome, transient UI, everything the save strips and everything
|
|
1119
1159
|
// that holds no text are not targets.
|
|
@@ -1141,11 +1181,106 @@ async function open(el, { prompt } = {}) {
|
|
|
1141
1181
|
textarea.focus();
|
|
1142
1182
|
return true;
|
|
1143
1183
|
}
|
|
1144
|
-
if (typeof prompt === 'string' && !drafts.has(el))
|
|
1184
|
+
if (typeof prompt === 'string' && !drafts.has(el)) keepDraft(el, prompt);
|
|
1145
1185
|
openPanel(el, null);
|
|
1146
1186
|
return true;
|
|
1147
1187
|
}
|
|
1148
1188
|
|
|
1149
|
-
|
|
1189
|
+
/**
|
|
1190
|
+
* A committed exit: the chrome, every handler this session added and every page
|
|
1191
|
+
* observer go. What the person typed is a draft, and an exit that could not represent it
|
|
1192
|
+
* never gets here, so nothing unsent is thrown away by this.
|
|
1193
|
+
*/
|
|
1194
|
+
function teardown() {
|
|
1195
|
+
chromeToken++;
|
|
1196
|
+
const s = session;
|
|
1197
|
+
session = null;
|
|
1198
|
+
try {
|
|
1199
|
+
s?.handle?.cancel();
|
|
1200
|
+
if (s) {
|
|
1201
|
+
if (s.paused) resumeObservers();
|
|
1202
|
+
if (s.held) releaseAllSaves();
|
|
1203
|
+
}
|
|
1204
|
+
} catch {}
|
|
1205
|
+
clearTimeout(selectionTimer);
|
|
1206
|
+
selectionTimer = null;
|
|
1207
|
+
clearTimeout(chipHideTimer);
|
|
1208
|
+
chipHideTimer = null;
|
|
1209
|
+
clearTimeout(barCloseTimer);
|
|
1210
|
+
barCloseTimer = null;
|
|
1211
|
+
clearHighlight();
|
|
1212
|
+
listeners?.abort();
|
|
1213
|
+
listeners = null;
|
|
1214
|
+
for (const observer of observers) observer.disconnect();
|
|
1215
|
+
observers = [];
|
|
1216
|
+
for (const node of [styleEl, ring, panel, bar, chip, docBubble]) node?.remove();
|
|
1217
|
+
styleEl = ring = panel = textarea = statusEl = pointer = bar = barStatus = null;
|
|
1218
|
+
barStop = barKeep = barRevert = barClose = chip = docBubble = null;
|
|
1219
|
+
buttons = {};
|
|
1220
|
+
barMode = null;
|
|
1221
|
+
barLifecycle = null;
|
|
1222
|
+
anchorEl = null;
|
|
1223
|
+
anchorRange = null;
|
|
1224
|
+
returnFocus = null;
|
|
1225
|
+
pendingSelection = undefined;
|
|
1226
|
+
chipTarget = null;
|
|
1227
|
+
chipSelection = undefined;
|
|
1228
|
+
panelPointerDown = false;
|
|
1229
|
+
helperState = null;
|
|
1230
|
+
drafts = new WeakMap();
|
|
1231
|
+
drafted.clear();
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
/**
|
|
1235
|
+
* ai-edit as a mode lease.
|
|
1236
|
+
*
|
|
1237
|
+
* Preparing this lease asks the host whether it lists a ready helper, which is safe while
|
|
1238
|
+
* the committed mode is still view; the commit that enters edit builds the chrome, inert
|
|
1239
|
+
* until somebody opens it, exactly as `clay.aiEdit.init()` does. What a session adds is
|
|
1240
|
+
* everything still unresolved — a request on the wire, a preview waiting for Keep or
|
|
1241
|
+
* Revert, a comment typed and not sent — so `quiesce` refuses the exit and `resume`
|
|
1242
|
+
* leaves that same preview, comment and selection timer exactly as they were.
|
|
1243
|
+
* `dispose` (after the barrier) stops every editor-only handler and takes the chrome
|
|
1244
|
+
* down, so a save or selection event in view draws nothing. `initial: true` adopts the
|
|
1245
|
+
* chrome the boot's own import built, and asks the host nothing a second time.
|
|
1246
|
+
*/
|
|
1247
|
+
export function aiEditParticipant() {
|
|
1248
|
+
return {
|
|
1249
|
+
id: "clay:ai-edit",
|
|
1250
|
+
order: 950, // after the wire (900): this request is sent through it
|
|
1251
|
+
prepare(context = {}) {
|
|
1252
|
+
const initial = context.initial === true;
|
|
1253
|
+
return {
|
|
1254
|
+
ready: initial ? boot : loadHelper(),
|
|
1255
|
+
enable() {
|
|
1256
|
+
if (!initial) build();
|
|
1257
|
+
},
|
|
1258
|
+
quiesce() {
|
|
1259
|
+
const unsent = (panel && !panel.hidden && textarea.value.trim() !== '') ||
|
|
1260
|
+
[...drafted].some((el) => el.isConnected);
|
|
1261
|
+
const pending = [];
|
|
1262
|
+
if (session) pending.push(session.id);
|
|
1263
|
+
if (barMode === 'saving') pending.push('save');
|
|
1264
|
+
if (unsent) pending.push('prompt');
|
|
1265
|
+
if (!pending.length) return;
|
|
1266
|
+
throw Object.assign(new Error('clay.aiEdit: an edit here is still unresolved'), {
|
|
1267
|
+
code: 'pending-input',
|
|
1268
|
+
pending,
|
|
1269
|
+
});
|
|
1270
|
+
},
|
|
1271
|
+
resume() {},
|
|
1272
|
+
dispose() {
|
|
1273
|
+
teardown();
|
|
1274
|
+
},
|
|
1275
|
+
};
|
|
1276
|
+
},
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// The boot's own answer, which an explicit edit boot's exit adopts rather than re-asking.
|
|
1281
|
+
let boot = null;
|
|
1282
|
+
onDomReady(() => { boot = init().then(() => {}, () => {}); });
|
|
1283
|
+
|
|
1284
|
+
export { aiEditParticipant as modeParticipant };
|
|
1150
1285
|
|
|
1151
1286
|
export const aiEdit = { init, open };
|