@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/plugins/people.js
CHANGED
|
@@ -19,12 +19,9 @@
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import { hostMeta, hostMetaOutcome } from "../core/host-meta.js";
|
|
22
|
-
import { isEditMode } from "../core/is-edit-mode.js";
|
|
22
|
+
import { isEditMode, modeState } from "../core/is-edit-mode.js";
|
|
23
23
|
|
|
24
24
|
const editing = () => (window.clay && "isEditMode" in window.clay ? !!window.clay.isEditMode : isEditMode);
|
|
25
|
-
import { bevelDialog, dismissOf, keepFocusIn } from "../ui/bevel-dialog.js";
|
|
26
|
-
import { bevelBox, bevelButton, bevelInput, bevelText } from "../ui/bevel-controls.js";
|
|
27
|
-
import { resolveTheme } from "../ui/theme.js";
|
|
28
25
|
import { colorIndexOf, initialsOf } from "../lib/person-face.js";
|
|
29
26
|
|
|
30
27
|
const ID = /^[A-Za-z0-9_-]{8,64}$/;
|
|
@@ -41,6 +38,7 @@ let asking = null;
|
|
|
41
38
|
let askingRoot = null;
|
|
42
39
|
let cancelAsking = null;
|
|
43
40
|
let lastRegistry = "";
|
|
41
|
+
let dialogLoad = null;
|
|
44
42
|
|
|
45
43
|
function clean(person) {
|
|
46
44
|
if (!person || typeof person !== "object") return null;
|
|
@@ -140,6 +138,7 @@ async function refresh(fresh) {
|
|
|
140
138
|
}
|
|
141
139
|
|
|
142
140
|
function get(id) {
|
|
141
|
+
observe();
|
|
143
142
|
const key = String(id ?? "");
|
|
144
143
|
const live = (host.me?.id === key && host.me) || host.members?.find((person) => person.id === key);
|
|
145
144
|
if (live) return record(live);
|
|
@@ -149,6 +148,7 @@ function get(id) {
|
|
|
149
148
|
}
|
|
150
149
|
|
|
151
150
|
function list() {
|
|
151
|
+
observe();
|
|
152
152
|
return [...saved().keys()].map(get);
|
|
153
153
|
}
|
|
154
154
|
|
|
@@ -208,6 +208,16 @@ function rename(name) {
|
|
|
208
208
|
return record(next);
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
// Same session and still editing: the two facts an await can invalidate.
|
|
212
|
+
const stale = (generation) => generation !== modeState().generation || !editing();
|
|
213
|
+
|
|
214
|
+
function refuseIfStale(generation) {
|
|
215
|
+
if (!stale(generation)) return;
|
|
216
|
+
throw Object.assign(new Error("clay.author: the page left edit mode before your name was recorded"), {
|
|
217
|
+
code: "stale-document",
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
211
221
|
function unavailable() {
|
|
212
222
|
return Object.assign(new Error("Can't reach the host to check who you are. Try again in a moment."), { code: "people-unavailable" });
|
|
213
223
|
}
|
|
@@ -220,11 +230,16 @@ function unavailable() {
|
|
|
220
230
|
export async function author(el, attr = "data-by") {
|
|
221
231
|
if (!window.clay?.isEditMode) throw new Error("clay.author: this page is not in edit mode");
|
|
222
232
|
if (!(el instanceof Element)) throw new TypeError("clay.author: needs an element");
|
|
233
|
+
// Attribution belongs to the session that asked for it. Asking the host who I am and
|
|
234
|
+
// asking a person their name both take long enough for the page to leave edit, and a
|
|
235
|
+
// stamp recorded afterwards would credit a session that has already ended.
|
|
236
|
+
const generation = modeState().generation;
|
|
223
237
|
// A host that names people can change who you are while the page is open (a sign-out,
|
|
224
238
|
// a rename in the app), so a stamp asks it again first. If it cannot answer now, nothing
|
|
225
239
|
// is stamped: the last answer might name someone who is no longer here.
|
|
226
240
|
if (host.supports) {
|
|
227
241
|
const meta = await hostMeta({ fresh: true });
|
|
242
|
+
refuseIfStale(generation);
|
|
228
243
|
const fresh = hostMetaOutcome(meta);
|
|
229
244
|
if (fresh === "none") throw Object.assign(new Error("This page lost its connection to the host. Reload it to keep editing."), { code: "people-unavailable" });
|
|
230
245
|
if (fresh !== "ok") throw unavailable();
|
|
@@ -232,11 +247,13 @@ export async function author(el, attr = "data-by") {
|
|
|
232
247
|
if (host.unavailable) throw Object.assign(new Error("The app hosting this file can't name you right now. Check its Profile settings, then try again."), { code: "people-unavailable" });
|
|
233
248
|
} else if (outcome !== "ok" && outcome !== "none") {
|
|
234
249
|
await refresh(outcome === "failed");
|
|
250
|
+
refuseIfStale(generation);
|
|
235
251
|
}
|
|
236
252
|
if (outcome === "failed") throw unavailable();
|
|
237
253
|
let me = currentMe();
|
|
238
254
|
if (!me) {
|
|
239
255
|
const chosen = await askName();
|
|
256
|
+
refuseIfStale(generation);
|
|
240
257
|
if (!chosen) return null;
|
|
241
258
|
writeLocal(chosen);
|
|
242
259
|
me = record(chosen);
|
|
@@ -247,12 +264,38 @@ export async function author(el, attr = "data-by") {
|
|
|
247
264
|
return me;
|
|
248
265
|
}
|
|
249
266
|
|
|
267
|
+
// The dialog and the theme it paints with are this page's first-use download: a
|
|
268
|
+
// reader is nobody and is asked nothing, so it never fetches them.
|
|
269
|
+
function loadDialogUI() {
|
|
270
|
+
dialogLoad ??= Promise.all([
|
|
271
|
+
import("../ui/bevel-dialog.js"),
|
|
272
|
+
import("../ui/bevel-controls.js"),
|
|
273
|
+
import("../ui/theme.js"),
|
|
274
|
+
]).then(([dialog, controls, theme]) => ({ ...dialog, ...controls, resolveTheme: theme.resolveTheme }))
|
|
275
|
+
.catch((error) => {
|
|
276
|
+
dialogLoad = null;
|
|
277
|
+
throw error;
|
|
278
|
+
});
|
|
279
|
+
return dialogLoad;
|
|
280
|
+
}
|
|
281
|
+
|
|
250
282
|
function askName() {
|
|
251
|
-
if (asking && askingRoot
|
|
283
|
+
if (asking && (askingRoot ? askingRoot.isConnected : true)) return asking;
|
|
252
284
|
if (asking) cancelAsking();
|
|
253
|
-
asking =
|
|
254
|
-
|
|
255
|
-
|
|
285
|
+
asking = promptForName().catch((error) => {
|
|
286
|
+
asking = null;
|
|
287
|
+
askingRoot = null;
|
|
288
|
+
cancelAsking = null;
|
|
289
|
+
throw error;
|
|
290
|
+
});
|
|
291
|
+
return asking;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async function promptForName() {
|
|
295
|
+
const ui = await loadDialogUI();
|
|
296
|
+
return new Promise((resolve) => {
|
|
297
|
+
const theme = ui.resolveTheme();
|
|
298
|
+
const { root, overlay, panel, heading, body, footer, close } = ui.bevelDialog({
|
|
256
299
|
zIndex: "2147483001", width: "420px", closable: true, titled: true, theme, surface: "people",
|
|
257
300
|
});
|
|
258
301
|
askingRoot = root;
|
|
@@ -260,27 +303,27 @@ function askName() {
|
|
|
260
303
|
heading.textContent = "What name should appear on your changes?";
|
|
261
304
|
panel.setAttribute("aria-label", "Your name");
|
|
262
305
|
|
|
263
|
-
const input = bevelInput("input", { rules: ["display:block", "width:100%", "margin:0"], theme, parts: ["dialog.input", "people.input"] });
|
|
306
|
+
const input = ui.bevelInput("input", { rules: ["display:block", "width:100%", "margin:0"], theme, parts: ["dialog.input", "people.input"] });
|
|
264
307
|
input.setAttribute("aria-label", "Your name");
|
|
265
308
|
input.maxLength = MAX_NAME;
|
|
266
309
|
input.autocomplete = "name";
|
|
267
|
-
const hint = bevelText("p", ["display:block", "margin:10px 0 0", "font-size:13px", "opacity:.8"],
|
|
310
|
+
const hint = ui.bevelText("p", ["display:block", "margin:10px 0 0", "font-size:13px", "opacity:.8"],
|
|
268
311
|
"Saved in this browser. Everyone who can read this page will see it.", { theme, parts: ["dialog.hint", "people.hint"], role: "mutedText" });
|
|
269
312
|
const hintText = hint.textContent;
|
|
270
313
|
body.append(input, hint);
|
|
271
314
|
|
|
272
315
|
const known = list().slice(0, 8);
|
|
273
316
|
if (known.length) {
|
|
274
|
-
const label = bevelText("p", ["display:block", "margin:18px 0 8px", "font-size:13px"], "Or continue as someone already in this page:", { theme, parts: ["people.choiceLabel"], role: "mutedText" });
|
|
275
|
-
const row = bevelBox("div", ["display:flex", "flex-wrap:wrap", "gap:8px"], { theme, parts: ["people.choices"] });
|
|
317
|
+
const label = ui.bevelText("p", ["display:block", "margin:18px 0 8px", "font-size:13px"], "Or continue as someone already in this page:", { theme, parts: ["people.choiceLabel"], role: "mutedText" });
|
|
318
|
+
const row = ui.bevelBox("div", ["display:flex", "flex-wrap:wrap", "gap:8px"], { theme, parts: ["people.choices"] });
|
|
276
319
|
for (const person of known) {
|
|
277
|
-
row.append(bevelButton(person.name, { small: true, onClick: () => finish({ id: person.id, name: person.name }), theme, parts: ["dialog.button", "people.button", "people.choice"], labelParts: ["dialog.buttonLabel", "people.buttonLabel"] }));
|
|
320
|
+
row.append(ui.bevelButton(person.name, { small: true, onClick: () => finish({ id: person.id, name: person.name }), theme, parts: ["dialog.button", "people.button", "people.choice"], labelParts: ["dialog.buttonLabel", "people.buttonLabel"] }));
|
|
278
321
|
}
|
|
279
322
|
body.append(label, row);
|
|
280
323
|
}
|
|
281
324
|
|
|
282
|
-
const cancel = bevelButton("Cancel", { onClick: () => finish(null), theme, parts: ["dialog.button", "people.button"], labelParts: ["dialog.buttonLabel", "people.buttonLabel"] });
|
|
283
|
-
const ok = bevelButton("Continue", { variant: "primary", onClick: () => submit(), theme, parts: ["dialog.button", "people.button"], labelParts: ["dialog.buttonLabel", "people.buttonLabel"] });
|
|
325
|
+
const cancel = ui.bevelButton("Cancel", { onClick: () => finish(null), theme, parts: ["dialog.button", "people.button"], labelParts: ["dialog.buttonLabel", "people.buttonLabel"] });
|
|
326
|
+
const ok = ui.bevelButton("Continue", { variant: "primary", onClick: () => submit(), theme, parts: ["dialog.button", "people.button"], labelParts: ["dialog.buttonLabel", "people.buttonLabel"] });
|
|
284
327
|
footer.append(cancel, ok);
|
|
285
328
|
|
|
286
329
|
const submit = () => {
|
|
@@ -314,7 +357,7 @@ function askName() {
|
|
|
314
357
|
const onKey = (event) => {
|
|
315
358
|
if (event.key === "Tab") {
|
|
316
359
|
event.stopPropagation();
|
|
317
|
-
keepFocusIn(panel, event);
|
|
360
|
+
ui.keepFocusIn(panel, event);
|
|
318
361
|
return;
|
|
319
362
|
}
|
|
320
363
|
if (event.key === "Escape") {
|
|
@@ -343,13 +386,12 @@ function askName() {
|
|
|
343
386
|
cancelAsking = null;
|
|
344
387
|
resolve(person);
|
|
345
388
|
}
|
|
346
|
-
dismissOf.set(root, () => finish(null));
|
|
389
|
+
ui.dismissOf.set(root, () => finish(null));
|
|
347
390
|
|
|
348
391
|
root.setAttribute("aria-hidden", "false");
|
|
349
392
|
modalHost().append(root);
|
|
350
393
|
input.focus();
|
|
351
394
|
});
|
|
352
|
-
return asking;
|
|
353
395
|
}
|
|
354
396
|
|
|
355
397
|
// A page's own modal <dialog> makes everything outside it inert, so the prompt goes inside
|
|
@@ -367,9 +409,20 @@ function registrySignature() {
|
|
|
367
409
|
return JSON.stringify([...saved().values()].map(({ id, name }) => [id, name]));
|
|
368
410
|
}
|
|
369
411
|
|
|
412
|
+
// The observer belongs to the page rather than to one edit session — a reader repaint
|
|
413
|
+
// has to keep the names in it current — so any read starts it and a session that stops
|
|
414
|
+
// takes it down. It is created with the document it watches held once: a test
|
|
415
|
+
// environment can tear that document down while a mutation is still queued, and a
|
|
416
|
+
// callback that reached for the global afterwards would read a page that is gone.
|
|
417
|
+
let watcher = null;
|
|
418
|
+
|
|
370
419
|
function observe() {
|
|
420
|
+
const doc = document;
|
|
421
|
+
if (watcher?.doc === doc) return;
|
|
422
|
+
watcher?.observer.disconnect();
|
|
371
423
|
lastRegistry = registrySignature();
|
|
372
|
-
new MutationObserver((records) => {
|
|
424
|
+
const observer = new MutationObserver((records) => {
|
|
425
|
+
if (typeof document === "undefined" || document !== doc) return;
|
|
373
426
|
for (const rec of records) {
|
|
374
427
|
const target = rec.target.nodeType === 1 ? rec.target : rec.target.parentElement;
|
|
375
428
|
// A removed clay-people attribute no longer matches the selector, so it is caught by name.
|
|
@@ -387,25 +440,99 @@ function observe() {
|
|
|
387
440
|
return;
|
|
388
441
|
}
|
|
389
442
|
}
|
|
390
|
-
})
|
|
443
|
+
});
|
|
444
|
+
observer.observe(doc.body, { subtree: true, childList: true, characterData: true, attributes: true, attributeFilter: ["value", "clay-people"] });
|
|
445
|
+
watcher = { doc, observer };
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function unobserve() {
|
|
449
|
+
watcher?.observer.disconnect();
|
|
450
|
+
watcher = null;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// The editing half: the host answer that names me and the two listeners that keep it
|
|
454
|
+
// current, added once for the boot and a lease alike. Each checks the mode when it fires,
|
|
455
|
+
// so a session that has ended asks the host nothing.
|
|
456
|
+
let session = null;
|
|
457
|
+
|
|
458
|
+
function startEditing() {
|
|
459
|
+
if (!editing()) return Promise.resolve(null);
|
|
460
|
+
if (!session) {
|
|
461
|
+
const listeners = new AbortController();
|
|
462
|
+
const { signal } = listeners;
|
|
463
|
+
window.addEventListener("storage", (event) => {
|
|
464
|
+
if (event.key !== STORE || !editing()) return;
|
|
465
|
+
local = undefined;
|
|
466
|
+
emit();
|
|
467
|
+
}, { signal });
|
|
468
|
+
document.addEventListener("visibilitychange", () => {
|
|
469
|
+
if (!editing()) return;
|
|
470
|
+
if (document.visibilityState === "visible" && outcome !== "none") refresh(true);
|
|
471
|
+
}, { signal });
|
|
472
|
+
session = { listeners, first: refresh(false) };
|
|
473
|
+
}
|
|
474
|
+
return Promise.race([session.first, new Promise((resolve) => setTimeout(resolve, BOOT_WAIT_MS))]);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function stopEditing() {
|
|
478
|
+
session?.listeners.abort();
|
|
479
|
+
session = null;
|
|
391
480
|
}
|
|
392
481
|
|
|
393
482
|
async function init() {
|
|
394
483
|
observe();
|
|
395
484
|
// A reader is nobody and picks nobody, so a read-only page never asks the host.
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
485
|
+
await startEditing();
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function peopleLease() {
|
|
489
|
+
return {
|
|
490
|
+
enable() {
|
|
491
|
+
observe();
|
|
492
|
+
startEditing();
|
|
493
|
+
},
|
|
494
|
+
quiesce() {
|
|
495
|
+
if (!asking) return;
|
|
496
|
+
throw Object.assign(new Error("clay:people: a name is still being chosen"), {
|
|
497
|
+
code: "pending-input",
|
|
498
|
+
pending: ["name"],
|
|
499
|
+
});
|
|
500
|
+
},
|
|
501
|
+
resume() {},
|
|
502
|
+
dispose() {
|
|
503
|
+
cancelAsking?.();
|
|
504
|
+
unobserve();
|
|
505
|
+
stopEditing();
|
|
506
|
+
},
|
|
507
|
+
};
|
|
407
508
|
}
|
|
408
509
|
|
|
510
|
+
/**
|
|
511
|
+
* Attribution as a mode lease.
|
|
512
|
+
*
|
|
513
|
+
* Reading names is not editing, so every read keeps the registry observer running and
|
|
514
|
+
* costs a session nothing. What a session adds is a name that is still being chosen: a
|
|
515
|
+
* half-answered prompt is input nobody has committed, so `quiesce` refuses the exit
|
|
516
|
+
* rather than closing it, and `resume` leaves that same prompt on screen. `dispose`
|
|
517
|
+
* (after the barrier) takes back both the prompt and the observer, and the next read
|
|
518
|
+
* starts watching again.
|
|
519
|
+
*/
|
|
520
|
+
export function peopleParticipant() {
|
|
521
|
+
return {
|
|
522
|
+
id: "clay:people",
|
|
523
|
+
order: 330,
|
|
524
|
+
prepare(context = {}) {
|
|
525
|
+
const lease = peopleLease();
|
|
526
|
+
// An adoption is the session this module's own import already started: the exit
|
|
527
|
+
// takes it back, and the commit starts nothing a second time.
|
|
528
|
+
if (context.initial !== true) return lease;
|
|
529
|
+
return { ...lease, enable() {} };
|
|
530
|
+
},
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
export { peopleParticipant as modeParticipant };
|
|
535
|
+
|
|
409
536
|
export const people = Object.freeze({ get, list, available, add, remove, canRename, rename });
|
|
410
537
|
|
|
411
538
|
export const ready = init();
|
package/src/plugins/richclay.js
CHANGED
|
@@ -4,18 +4,128 @@
|
|
|
4
4
|
import { installSkin } from "../ui/vendor-skin.js";
|
|
5
5
|
import { CSS, ROOTS } from "../ui/skins/richclay.js";
|
|
6
6
|
import { RichClay } from "../vendor/richclay.vendor.js";
|
|
7
|
-
import {
|
|
7
|
+
import { startsAtImport } from "../core/is-edit-mode.js";
|
|
8
8
|
|
|
9
9
|
installSkin("richclay", CSS, { roots: ROOTS });
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
let session = null;
|
|
12
|
+
|
|
13
|
+
const fault = (message, code) => Object.assign(new Error(`clay:richclay: ${message}`), { code });
|
|
14
|
+
|
|
15
|
+
const isStale = (context) => {
|
|
16
|
+
if (!context) return false;
|
|
17
|
+
if (context.signal?.aborted) return true;
|
|
18
|
+
return typeof context.isCurrent === "function" && !context.isCurrent();
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const ownership = (root) => ({
|
|
22
|
+
root,
|
|
23
|
+
win: root.ownerDocument?.defaultView || window,
|
|
24
|
+
admitted: false,
|
|
25
|
+
stopWatch: null,
|
|
26
|
+
subscriber: null,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const elements = (record) => [...record.root.querySelectorAll(RichClay.selector)];
|
|
30
|
+
|
|
31
|
+
// Mounts the regions the page has, and repairs the ones an applied frame stripped: a frame's
|
|
32
|
+
// snapshot carries none of RichClay's runtime state, and the merge removes live attributes
|
|
33
|
+
// the merged page lacks, so an applied frame leaves editors that can no longer be typed
|
|
34
|
+
// into. RichClay's reattach() restores them.
|
|
35
|
+
function mount(record) {
|
|
36
|
+
for (const editor of RichClay.init(elements(record))) editor.reattach();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// One edit session over the live DOM. `enable` mounts the page's regions and starts the one
|
|
40
|
+
// watcher for regions that arrive later; `quiesce` closes admission, so a region that
|
|
41
|
+
// arrives while the exit runs is given no editor; `resume` is the refused exit, over the
|
|
42
|
+
// same session; `dispose` destroys every instance and removes exactly the subscription it
|
|
43
|
+
// added, so the view it leaves behind holds no editor and the next entry begins from
|
|
44
|
+
// nothing.
|
|
45
|
+
function richclayLease(record) {
|
|
46
|
+
const onFrame = () => mount(record);
|
|
47
|
+
return {
|
|
48
|
+
enable() {
|
|
49
|
+
if (record.admitted) return;
|
|
50
|
+
record.admitted = true;
|
|
51
|
+
mount(record);
|
|
52
|
+
record.stopWatch = RichClay.watch(record.win);
|
|
53
|
+
const target = record.root.ownerDocument || document;
|
|
54
|
+
record.subscriber = { target, type: "clay:sync-applied", handler: onFrame };
|
|
55
|
+
target.addEventListener(record.subscriber.type, onFrame);
|
|
56
|
+
},
|
|
57
|
+
quiesce() {
|
|
58
|
+
record.admitted = false;
|
|
59
|
+
if (record.stopWatch) {
|
|
60
|
+
record.stopWatch();
|
|
61
|
+
record.stopWatch = null;
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
resume() {
|
|
65
|
+
if (record.admitted) return;
|
|
66
|
+
record.admitted = true;
|
|
67
|
+
record.stopWatch = RichClay.watch(record.win);
|
|
68
|
+
},
|
|
69
|
+
dispose() {
|
|
70
|
+
record.admitted = false;
|
|
71
|
+
if (record.stopWatch) {
|
|
72
|
+
record.stopWatch();
|
|
73
|
+
record.stopWatch = null;
|
|
74
|
+
}
|
|
75
|
+
const subscriber = record.subscriber;
|
|
76
|
+
record.subscriber = null;
|
|
77
|
+
if (subscriber) subscriber.target.removeEventListener(subscriber.type, subscriber.handler);
|
|
78
|
+
for (const el of elements(record)) RichClay.stripElement(el);
|
|
79
|
+
if (session === record) session = null;
|
|
80
|
+
},
|
|
81
|
+
};
|
|
18
82
|
}
|
|
19
83
|
|
|
20
|
-
|
|
84
|
+
/**
|
|
85
|
+
* RichClay as a mode participant: the editors the commit that enters edit mounts, and the
|
|
86
|
+
* ones the exit takes back.
|
|
87
|
+
*
|
|
88
|
+
* `prepare` takes the vendor's auto-watch out of the page first, so every instance is this
|
|
89
|
+
* session's to quiesce and destroy and an entry never meets an editor it did not mount; a
|
|
90
|
+
* vendor build without that lifecycle support is refused here rather than left half
|
|
91
|
+
* mounted in a view. `enable` mounts the regions and starts the session's own watcher.
|
|
92
|
+
* `quiesce` stops admitting regions. `dispose` destroys the instances and hands back the
|
|
93
|
+
* frame subscription, leaving no editor behind for the reader's page.
|
|
94
|
+
*/
|
|
95
|
+
export function richclayParticipant(root = document) {
|
|
96
|
+
return {
|
|
97
|
+
id: "clay:richclay",
|
|
98
|
+
order: 310,
|
|
99
|
+
async prepare(context = {}) {
|
|
100
|
+
if (context.initial === true) return adopt();
|
|
101
|
+
if (typeof RichClay.watch !== "function" || typeof RichClay.stripElement !== "function") {
|
|
102
|
+
throw fault("this vendor build has no watchable lifecycle", "unsupported-plugin");
|
|
103
|
+
}
|
|
104
|
+
if (isStale(context)) throw fault("prepared for a stale generation", "stale-document");
|
|
105
|
+
const stopAutoWatch = RichClay.autoInit?.();
|
|
106
|
+
if (typeof stopAutoWatch === "function") stopAutoWatch();
|
|
107
|
+
return richclayLease(session || (session = ownership(root)));
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// The boot this tab already made, adopted instead of prepared: it is the session `init`
|
|
113
|
+
// below enabled, or, on a boot that started none, nothing to hand back.
|
|
114
|
+
async function adopt() {
|
|
115
|
+
const lease = await ready;
|
|
116
|
+
return { enable() {}, quiesce: () => lease?.quiesce(), resume: () => lease?.resume(), dispose: () => lease?.dispose() };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Auto-init when the module is imported; the loader awaits `ready` before resolving clay.ready
|
|
120
|
+
async function init() {
|
|
121
|
+
if (!startsAtImport()) return null;
|
|
122
|
+
const lease = await richclayParticipant().prepare();
|
|
123
|
+
lease.enable();
|
|
124
|
+
return lease;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const ready = init();
|
|
128
|
+
|
|
129
|
+
export { RichClay, init, ready };
|
|
130
|
+
export { richclayParticipant as modeParticipant };
|
|
21
131
|
export default RichClay;
|