@panphora/clayjs 1.15.1 → 1.16.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 +83090 -58706
- 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-NWPPXOCZ.js +1 -0
- package/dist/m/attrs/save-freeze-FUP4Q4X3.js +1 -0
- package/dist/m/c-2AZDZWCK.js +1 -0
- package/dist/m/c-2JL6E75N.js +1 -0
- package/dist/m/c-2M73252O.js +1 -0
- package/dist/m/c-2SPVQSHC.js +1 -0
- package/dist/m/c-33HUYEDI.js +1 -0
- package/dist/m/c-33JJ6CBX.js +2 -0
- package/dist/m/c-35NBGMZB.js +1 -0
- package/dist/m/c-3GJ4SDE2.js +1 -0
- package/dist/m/c-3IQRECYS.js +1 -0
- package/dist/m/c-3OWDMNJR.js +2 -0
- package/dist/m/c-46XYM55L.js +1 -0
- package/dist/m/c-4B6H4G5V.js +1 -0
- package/dist/m/c-4DRMS4QG.js +9 -0
- package/dist/m/c-4FFHZM32.js +1 -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-4YSCRICO.js +1 -0
- package/dist/m/c-54RCDCBU.js +1 -0
- package/dist/m/c-5M4YEKCX.js +4 -0
- package/dist/m/c-5R4PTRG2.js +1 -0
- package/dist/m/c-5V3MOVJT.js +1 -0
- package/dist/m/c-5VYOWDTI.js +1 -0
- package/dist/m/c-5Y6TNX5W.js +34 -0
- package/dist/m/c-5YIHJ3TJ.js +1 -0
- package/dist/m/c-66O32MV3.js +28 -0
- package/dist/m/c-6HMB24EV.js +1 -0
- package/dist/m/c-7DJDKPGL.js +1 -0
- package/dist/m/c-7O6AFR65.js +1 -0
- package/dist/m/c-7SWMYKAI.js +1 -0
- package/dist/m/c-7VGZ7RU5.js +1 -0
- package/dist/m/c-A7LS5UZW.js +1 -0
- package/dist/m/c-ANQTJ3B5.js +2 -0
- package/dist/m/c-AQLFEATB.js +1 -0
- package/dist/m/c-AYVOREBE.js +1 -0
- package/dist/m/c-B2ZXPOS3.js +3 -0
- package/dist/m/c-BBVGTQG7.js +1 -0
- package/dist/m/c-BMIZKMPV.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-CJZSLMVQ.js +1 -0
- package/dist/m/c-CYWLPPUS.js +1 -0
- package/dist/m/c-CZUSOB7V.js +1 -0
- package/dist/m/c-DBE6ORSI.js +1 -0
- package/dist/m/c-DCFSEJZG.js +1 -0
- package/dist/m/c-DNZ5IFM6.js +1 -0
- package/dist/m/c-EDHUR4MX.js +1 -0
- package/dist/m/c-EJTGYSLN.js +1 -0
- package/dist/m/c-EY6UOM54.js +1 -0
- package/dist/m/c-F3CKJTJS.js +1 -0
- package/dist/m/c-F7Y6FLPY.js +1 -0
- package/dist/m/c-FA4DZVTC.js +1 -0
- package/dist/m/c-FILLTJA7.js +1 -0
- package/dist/m/c-G2BUZITR.js +1 -0
- package/dist/m/c-GB3JTV6E.js +1 -0
- package/dist/m/c-GBGWXTX4.js +1 -0
- package/dist/m/c-GHBCCVG4.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-H4LG442Q.js +1 -0
- package/dist/m/c-HA6INT6J.js +1 -0
- package/dist/m/c-HPURYVZS.js +2 -0
- package/dist/m/c-HRDCD3WN.js +67 -0
- package/dist/m/c-HT33EQRN.js +1 -0
- package/dist/m/c-HVYXIS72.js +1 -0
- package/dist/m/c-IB52R237.js +1 -0
- package/dist/m/c-IJUK2GPW.js +1 -0
- package/dist/m/c-IKWNE4R4.js +1 -0
- package/dist/m/c-IU3IYEU6.js +1 -0
- package/dist/m/c-IZ2EBRAJ.js +1 -0
- package/dist/m/c-J7CA54IP.js +1 -0
- package/dist/m/c-JAX2667S.js +6 -0
- package/dist/m/c-KI7M4AY3.js +1 -0
- package/dist/m/c-KIPQJX4B.js +1 -0
- package/dist/m/c-KKWLDOPM.js +1 -0
- package/dist/m/c-KR4UW4KW.js +1 -0
- package/dist/m/c-KY3VJGUA.js +8 -0
- package/dist/m/c-L4WQSC27.js +1 -0
- package/dist/m/c-LFPHCXY3.js +1 -0
- package/dist/m/c-LR4CGEPT.js +91 -0
- package/dist/m/c-LRPUO2MX.js +1 -0
- package/dist/m/c-LTGMXXKO.js +1 -0
- package/dist/m/c-LXENEBV7.js +1 -0
- package/dist/m/c-LZJPNR2W.js +1 -0
- package/dist/m/c-MMUIUUZG.js +2 -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-NMJRXKPC.js +8 -0
- package/dist/m/c-NRPJEVJS.js +1 -0
- package/dist/m/c-NUHP2XDB.js +1 -0
- package/dist/m/c-NZMNXVF6.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-OYTFP5QN.js +1 -0
- package/dist/m/c-P7KNDG34.js +1 -0
- package/dist/m/c-PPOSCAQD.js +1 -0
- package/dist/m/c-PQ5LK6QE.js +993 -0
- package/dist/m/c-PZ4XEPUP.js +2 -0
- package/dist/m/c-QHIWXHRO.js +1 -0
- package/dist/m/c-QHWJ5ZIJ.js +1 -0
- package/dist/m/c-QIX5BJYN.js +1 -0
- package/dist/m/c-QNKREOL6.js +1 -0
- package/dist/m/c-QQHEX6HA.js +1 -0
- package/dist/m/c-R7RMANJI.js +9 -0
- package/dist/m/c-RI4NT75Y.js +1 -0
- package/dist/m/c-RM7J7BV2.js +1 -0
- package/dist/m/c-RUJKSUQW.js +1 -0
- package/dist/m/c-RVMWGXEJ.js +1 -0
- package/dist/m/c-S7H2DRCB.js +1 -0
- package/dist/m/c-S7LK4KUE.js +1 -0
- package/dist/m/c-SGCCC4FW.js +25 -0
- package/dist/m/c-SGIA4IEQ.js +188 -0
- package/dist/m/c-SWRJFCNN.js +1 -0
- package/dist/m/c-T4VO4OCB.js +1 -0
- package/dist/m/c-TCCA5BZN.js +2 -0
- package/dist/m/c-TQEMVJCS.js +1 -0
- package/dist/m/c-TQZ2JYHD.js +1 -0
- package/dist/m/c-TR6RMDQ7.js +3 -0
- package/dist/m/c-TRS6TM6O.js +1 -0
- package/dist/m/c-UGHH4MB3.js +1 -0
- package/dist/m/c-UKHTLWUW.js +1 -0
- package/dist/m/c-UL2YUY52.js +1 -0
- package/dist/m/c-UNN7LWCT.js +1 -0
- package/dist/m/c-UXBMRDZB.js +235 -0
- package/dist/m/c-V7PZZRG7.js +1 -0
- package/dist/m/c-VAK7SG37.js +1 -0
- package/dist/m/c-VDSS4K3Z.js +1 -0
- package/dist/m/c-VFX45IZQ.js +1 -0
- package/dist/m/c-VHNSBD2M.js +1 -0
- package/dist/m/c-VKEDWYDF.js +1 -0
- package/dist/m/c-VL52ADDR.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-WWDBYXLK.js +1 -0
- package/dist/m/c-WYFDLITL.js +1 -0
- package/dist/m/c-XN6MBKI6.js +67 -0
- package/dist/m/c-XNNW2CWK.js +1 -0
- package/dist/m/c-XPELB6E5.js +1 -0
- package/dist/m/c-XQXZAO7N.js +1 -0
- package/dist/m/c-Y6USGTS5.js +5 -0
- package/dist/m/c-YDH7Q3NY.js +1 -0
- package/dist/m/c-YG2NJYS6.js +135 -0
- package/dist/m/c-Z36J63PP.js +1 -0
- package/dist/m/c-Z4VRC7GU.js +7 -0
- package/dist/m/c-Z6K52OLP.js +19 -0
- package/dist/m/c-ZDY2MDAA.js +21 -0
- package/dist/m/c-ZE46QDIH.js +1 -0
- package/dist/m/c-ZUCOKOHT.js +1 -0
- package/dist/m/core/admin-attrs-VGNLAUDK.js +1 -0
- package/dist/m/core/autosave-E4PEFPZ6.js +1 -0
- package/dist/m/core/conflict-notice-VQ6Y64PH.js +1 -0
- package/dist/m/core/draft-mode-WSQAT67S.js +1 -0
- package/dist/m/core/host-permission-XN3K2IW3.js +1 -0
- package/dist/m/core/is-edit-mode-JXHDVGUL.js +1 -0
- package/dist/m/core/persist-HKHA66IY.js +3 -0
- package/dist/m/core/recovery-TBBSICE2.js +1 -0
- package/dist/m/core/save-WUCHTQBE.js +1 -0
- package/dist/m/core/save-core-FJVHT5M3.js +1 -0
- package/dist/m/core/snapshot-F3SWDZMM.js +1 -0
- package/dist/m/core/unsaved-warning-STKBHE6G.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-23DPTUT4.js +1 -0
- package/dist/m/internals/index-WOVAP3RU.js +1 -0
- package/dist/m/lib/cache-bust-CGWT6ZJI.js +1 -0
- package/dist/m/lib/region-policy-SB2AWVG5.js +1 -0
- package/dist/m/loader-HXX6YNH5.js +1 -0
- package/dist/m/manifest-F22DEDAC.js +1 -0
- package/dist/m/manifest-edit-C3C7376B.js +1 -0
- package/dist/m/manifest.json +3491 -0
- package/dist/m/options/options-2LH76JQ3.js +1 -0
- package/dist/m/page/editor-XUTB2HB2.js +189 -0
- package/dist/m/plugins/ai-edit-ZQ4CGWIP.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-ZIBFAA3R.js +1 -0
- package/dist/m/plugins/derive-UAAA4V4S.js +1 -0
- package/dist/m/plugins/indicator-PV4YW2ID.js +1 -0
- package/dist/m/plugins/live-NUTTXSBS.js +1 -0
- package/dist/m/plugins/menu-HCKO3DSP.js +138 -0
- package/dist/m/plugins/message-LQ6EDH4V.js +1 -0
- package/dist/m/plugins/page-KSUH7G6J.js +2 -0
- package/dist/m/plugins/page-view-W73OW7WI.js +1 -0
- package/dist/m/plugins/people-AJJ32YCG.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-RC3L2F6X.js +517 -0
- package/dist/m/plugins/richclay-RC3L2F6X.js.LEGAL.txt +1 -0
- package/dist/m/plugins/sortable-YRMQX3ZU.js +1 -0
- package/dist/m/plugins/source-KHK5UUSK.js +1 -0
- package/dist/m/plugins/undo-OF2L3CXU.js +1 -0
- package/dist/m/plugins/unsent-HJFLQJ2O.js +1 -0
- package/dist/m/plugins/upgrade-ZNYODP5Y.js +1 -0
- package/dist/m/plugins/upload-XSGNILUY.js +1 -0
- package/dist/m/plugins/visitor-drafts-XK5GW55Q.js +21 -0
- package/dist/m/plugins/visitor-drafts-owner-KSSH75EV.js +1 -0
- package/dist/m/plugins/wire-ZWVWKF76.js +1 -0
- package/dist/m/reader-core-ILWLXVMP.js +68 -0
- package/dist/m/route/route-KOCZSEGN.js +1 -0
- package/dist/m/sync/live-sync-4AUVXVJU.js +1 -0
- package/dist/m/ui/index-EVHKMKBL.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 +3800 -0
- package/dist/page/themes/light-1.css +406 -0
- package/dist/server/core.cjs +23662 -22860
- 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/conflict-download.js +22 -0
- package/src/core/conflict-notice-ui.js +1173 -0
- package/src/core/conflict-notice.js +140 -697
- package/src/core/edit-mode.js +147 -14
- package/src/core/etag.js +30 -12
- package/src/core/host-meta.js +72 -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 +109 -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 +805 -118
- package/src/core/snapshot.js +121 -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 +141 -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 +79 -5
- 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 +17 -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/checklist.js +1 -1
- package/src/page/chrome.js +411 -61
- package/src/page/csv-import.js +17 -2
- package/src/page/document-title-dom.js +40 -0
- package/src/page/document-title-runtime.js +76 -0
- package/src/page/document-title.js +9 -0
- package/src/page/drag.js +48 -13
- package/src/page/drop.js +2 -1
- package/src/page/editor.js +330 -86
- package/src/page/feature-loader.js +72 -0
- package/src/page/features/board.js +12 -0
- package/src/page/features/code.js +13 -0
- package/src/page/features/media.js +290 -0
- package/src/page/features/registry.js +23 -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-gate.js +179 -0
- package/src/page/format-level.js +157 -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 +18 -25
- package/src/page/items.js +52 -11
- package/src/page/link.js +1 -0
- package/src/page/markdown.js +86 -1
- package/src/page/media-views.js +3 -0
- package/src/page/media.js +33 -245
- package/src/page/outline-cache.js +11 -0
- package/src/page/placeholder.js +27 -7
- package/src/page/projection.js +196 -50
- 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 +7 -4
- package/src/page/schema.js +14 -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/light-1.css +139 -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.js +390 -107
- package/src/page/ybind/awareness.js +172 -0
- package/src/page/ybind/binding.js +9 -1
- 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 +25 -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 +84 -22
- package/src/page/ybind/recovery-proof.js +191 -0
- package/src/page/ybind/recovery-replay.js +130 -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 +282 -34
- 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 +1022 -275
- 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/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 +535 -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
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
// The menu plugin: an Edit switch and claygoo in the top right, for anyone who can
|
|
2
|
+
// edit. Everything it draws is `clay="editor-ui"`, so none of it reaches the saved
|
|
3
|
+
// file, a sync frame, the dirty check or undo.
|
|
4
|
+
import { canEdit, isDraftMode, isEditMode, mode as startMode } from "../core/is-edit-mode.js";
|
|
5
|
+
import onDomReady from "../lib/dom-ready.js";
|
|
6
|
+
import CLAYGOO from "./menu/claygoo.svg.js";
|
|
7
|
+
import { modeRefusalText } from "../core/mode-refusal.js";
|
|
8
|
+
|
|
9
|
+
const SEO_ITEM = true;
|
|
10
|
+
const NOTE_MS = 6000;
|
|
11
|
+
const INTRO_GAP = 12;
|
|
12
|
+
|
|
13
|
+
const MENU_CSS = `.clay-menu {
|
|
14
|
+
position: fixed;
|
|
15
|
+
top: max(12px, env(safe-area-inset-top));
|
|
16
|
+
right: max(12px, env(safe-area-inset-right));
|
|
17
|
+
z-index: 2147482000;
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
flex-wrap: nowrap;
|
|
21
|
+
gap: 8px;
|
|
22
|
+
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
23
|
+
font-size: 13px;
|
|
24
|
+
line-height: 1;
|
|
25
|
+
color: var(--clay-ui-fg, #1F2328);
|
|
26
|
+
}
|
|
27
|
+
.clay-menu-edit {
|
|
28
|
+
display: inline-flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
gap: 8px;
|
|
31
|
+
margin: 0;
|
|
32
|
+
padding: 0;
|
|
33
|
+
border: 0;
|
|
34
|
+
font: inherit;
|
|
35
|
+
color: inherit;
|
|
36
|
+
background: none;
|
|
37
|
+
cursor: pointer;
|
|
38
|
+
}
|
|
39
|
+
.clay-menu-edit:disabled { cursor: progress; opacity: .7; }
|
|
40
|
+
.clay-menu-track {
|
|
41
|
+
position: relative;
|
|
42
|
+
display: block;
|
|
43
|
+
box-sizing: border-box;
|
|
44
|
+
width: 52px;
|
|
45
|
+
height: 32px;
|
|
46
|
+
border: 1px solid rgba(23, 28, 36, .16);
|
|
47
|
+
border-radius: 999px;
|
|
48
|
+
background: var(--clay-ui-bg, #F4F4F5);
|
|
49
|
+
transition: background-color .15s ease, border-color .15s ease;
|
|
50
|
+
}
|
|
51
|
+
.clay-menu-thumb {
|
|
52
|
+
position: absolute;
|
|
53
|
+
top: 2px;
|
|
54
|
+
left: 2px;
|
|
55
|
+
width: 26px;
|
|
56
|
+
height: 26px;
|
|
57
|
+
border-radius: 50%;
|
|
58
|
+
background: #FAFAFB;
|
|
59
|
+
box-shadow: 0 1px 2px rgba(23, 28, 36, .35);
|
|
60
|
+
transition: transform .15s ease;
|
|
61
|
+
}
|
|
62
|
+
.clay-menu-edit[aria-checked="true"] .clay-menu-track {
|
|
63
|
+
border-color: transparent;
|
|
64
|
+
background: var(--clay-ui-accent, #2F6FEB);
|
|
65
|
+
}
|
|
66
|
+
.clay-menu-edit[aria-checked="true"] .clay-menu-thumb { transform: translateX(20px); }
|
|
67
|
+
.clay-menu-label { font-size: 13px; line-height: 1; }
|
|
68
|
+
.clay-menu-goo {
|
|
69
|
+
position: relative;
|
|
70
|
+
display: inline-flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
justify-content: center;
|
|
73
|
+
box-sizing: border-box;
|
|
74
|
+
width: 32px;
|
|
75
|
+
height: 32px;
|
|
76
|
+
margin: 0;
|
|
77
|
+
padding: 0;
|
|
78
|
+
border: 1px solid rgba(23, 28, 36, .16);
|
|
79
|
+
border-radius: 50%;
|
|
80
|
+
color: inherit;
|
|
81
|
+
background: var(--clay-ui-bg, #F4F4F5);
|
|
82
|
+
cursor: pointer;
|
|
83
|
+
}
|
|
84
|
+
.clay-menu-goo svg { display: block; width: 18px; height: auto; }
|
|
85
|
+
.clay-menu-dot {
|
|
86
|
+
position: absolute;
|
|
87
|
+
top: 1px;
|
|
88
|
+
right: 1px;
|
|
89
|
+
width: 8px;
|
|
90
|
+
height: 8px;
|
|
91
|
+
border-radius: 50%;
|
|
92
|
+
background: var(--clay-ui-accent, #2F6FEB);
|
|
93
|
+
}
|
|
94
|
+
.clay-menu-list {
|
|
95
|
+
position: absolute;
|
|
96
|
+
top: calc(100% + 8px);
|
|
97
|
+
right: 0;
|
|
98
|
+
min-width: 184px;
|
|
99
|
+
margin: 0;
|
|
100
|
+
padding: 4px;
|
|
101
|
+
border: 1px solid rgba(23, 28, 36, .16);
|
|
102
|
+
border-radius: 10px;
|
|
103
|
+
background: var(--clay-ui-bg, #F4F4F5);
|
|
104
|
+
box-shadow: 0 10px 28px -14px rgba(23, 28, 36, .5);
|
|
105
|
+
}
|
|
106
|
+
.clay-menu-list button {
|
|
107
|
+
display: block;
|
|
108
|
+
width: 100%;
|
|
109
|
+
padding: 8px 10px;
|
|
110
|
+
border: 0;
|
|
111
|
+
border-radius: 6px;
|
|
112
|
+
font: inherit;
|
|
113
|
+
text-align: left;
|
|
114
|
+
color: inherit;
|
|
115
|
+
background: none;
|
|
116
|
+
cursor: pointer;
|
|
117
|
+
}
|
|
118
|
+
.clay-menu-list button:hover,
|
|
119
|
+
.clay-menu-list button:focus-visible { outline: none; background: rgba(23, 28, 36, .08); }
|
|
120
|
+
.clay-menu-note {
|
|
121
|
+
position: absolute;
|
|
122
|
+
top: calc(100% + 8px);
|
|
123
|
+
right: 0;
|
|
124
|
+
max-width: 260px;
|
|
125
|
+
padding: 8px 10px;
|
|
126
|
+
border: 1px solid rgba(23, 28, 36, .16);
|
|
127
|
+
border-radius: 8px;
|
|
128
|
+
line-height: 1.4;
|
|
129
|
+
text-align: left;
|
|
130
|
+
background: var(--clay-ui-bg, #F4F4F5);
|
|
131
|
+
box-shadow: 0 10px 28px -14px rgba(23, 28, 36, .5);
|
|
132
|
+
}
|
|
133
|
+
@media (pointer: coarse) {
|
|
134
|
+
.clay-menu-edit { min-height: 44px; padding: 6px 0; }
|
|
135
|
+
.clay-menu-goo { width: 44px; height: 44px; }
|
|
136
|
+
}
|
|
137
|
+
@media (prefers-color-scheme: dark) {
|
|
138
|
+
.clay-menu { color: var(--clay-ui-fg, #E9E9EC); }
|
|
139
|
+
.clay-menu-track,
|
|
140
|
+
.clay-menu-goo,
|
|
141
|
+
.clay-menu-list,
|
|
142
|
+
.clay-menu-note { border-color: rgba(233, 233, 236, .16); background: var(--clay-ui-bg, #26282C); }
|
|
143
|
+
.clay-menu-track { background: rgba(233, 233, 236, .22); }
|
|
144
|
+
.clay-menu-thumb { background: #E9E9EC; }
|
|
145
|
+
.clay-menu-list button:hover,
|
|
146
|
+
.clay-menu-list button:focus-visible { background: rgba(233, 233, 236, .12); }
|
|
147
|
+
}
|
|
148
|
+
@media (prefers-reduced-motion: reduce) {
|
|
149
|
+
.clay-menu-track, .clay-menu-thumb { transition: none; }
|
|
150
|
+
}`;
|
|
151
|
+
|
|
152
|
+
// clay.mode is the live answer; the imported mode is the one the page booted with.
|
|
153
|
+
const currentMode = () =>
|
|
154
|
+
window.clay && typeof window.clay.mode === "string" ? window.clay.mode : startMode;
|
|
155
|
+
|
|
156
|
+
function stylesOnce() {
|
|
157
|
+
if (document.getElementById("clay-menu-style")) return;
|
|
158
|
+
const style = document.createElement("style");
|
|
159
|
+
style.id = "clay-menu-style";
|
|
160
|
+
style.setAttribute("clay", "editor-ui");
|
|
161
|
+
style.textContent = MENU_CSS;
|
|
162
|
+
document.head.append(style);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function mount() {
|
|
166
|
+
if (document.querySelector(".clay-menu")) return;
|
|
167
|
+
stylesOnce();
|
|
168
|
+
|
|
169
|
+
const root = document.createElement("div");
|
|
170
|
+
root.className = "clay-menu";
|
|
171
|
+
root.setAttribute("clay", "editor-ui");
|
|
172
|
+
root.setAttribute("clay-mode-toggle", "");
|
|
173
|
+
root.innerHTML =
|
|
174
|
+
`<button type="button" class="clay-menu-edit" role="switch" aria-checked="false">` +
|
|
175
|
+
`<span class="clay-menu-track" aria-hidden="true"><span class="clay-menu-thumb"></span></span>` +
|
|
176
|
+
`<span class="clay-menu-label">Edit</span>` +
|
|
177
|
+
`</button>` +
|
|
178
|
+
`<button type="button" class="clay-menu-goo" aria-haspopup="menu" aria-expanded="false" aria-label="Clay menu">${CLAYGOO}</button>` +
|
|
179
|
+
`<div class="clay-menu-list" role="menu" hidden></div>` +
|
|
180
|
+
`<div class="clay-menu-note" role="status" hidden></div>`;
|
|
181
|
+
|
|
182
|
+
const edit = root.querySelector(".clay-menu-edit");
|
|
183
|
+
const goo = root.querySelector(".clay-menu-goo");
|
|
184
|
+
const list = root.querySelector(".clay-menu-list");
|
|
185
|
+
const noteEl = root.querySelector(".clay-menu-note");
|
|
186
|
+
const items = new Map();
|
|
187
|
+
|
|
188
|
+
const isOpen = () => !list.hidden;
|
|
189
|
+
|
|
190
|
+
function setExpanded(open) {
|
|
191
|
+
list.hidden = !open;
|
|
192
|
+
goo.setAttribute("aria-expanded", open ? "true" : "false");
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const buttons = () => [...list.querySelectorAll('[role="menuitem"]')];
|
|
196
|
+
|
|
197
|
+
function focusItem(index) {
|
|
198
|
+
const all = buttons();
|
|
199
|
+
if (!all.length) return;
|
|
200
|
+
all[(index + all.length) % all.length].focus();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function close() {
|
|
204
|
+
if (isOpen()) setExpanded(false);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function open() {
|
|
208
|
+
if (!isOpen()) setExpanded(true);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function render() {
|
|
212
|
+
const hadFocus = list.contains(document.activeElement);
|
|
213
|
+
list.textContent = "";
|
|
214
|
+
for (const item of items.values()) {
|
|
215
|
+
const button = document.createElement("button");
|
|
216
|
+
button.type = "button";
|
|
217
|
+
button.setAttribute("role", "menuitem");
|
|
218
|
+
button.dataset.menuId = item.id;
|
|
219
|
+
button.textContent = item.label;
|
|
220
|
+
button.addEventListener("click", () => {
|
|
221
|
+
close();
|
|
222
|
+
if (item.run) item.run();
|
|
223
|
+
});
|
|
224
|
+
list.append(button);
|
|
225
|
+
}
|
|
226
|
+
const dot = goo.querySelector(".clay-menu-dot");
|
|
227
|
+
const wanted = [...items.values()].some((item) => item.badge);
|
|
228
|
+
if (wanted && !dot) {
|
|
229
|
+
const mark = document.createElement("span");
|
|
230
|
+
mark.className = "clay-menu-dot";
|
|
231
|
+
goo.append(mark);
|
|
232
|
+
} else if (!wanted && dot) {
|
|
233
|
+
dot.remove();
|
|
234
|
+
}
|
|
235
|
+
if (hadFocus) focusItem(0);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function addItem({ id, label, run, badge } = {}) {
|
|
239
|
+
if (!id) return null;
|
|
240
|
+
items.set(id, {
|
|
241
|
+
id,
|
|
242
|
+
label: String(label ?? ""),
|
|
243
|
+
run: typeof run === "function" ? run : null,
|
|
244
|
+
badge: Boolean(badge),
|
|
245
|
+
});
|
|
246
|
+
render();
|
|
247
|
+
return id;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function showNote(text) {
|
|
251
|
+
if (!text) return;
|
|
252
|
+
noteEl.textContent = text;
|
|
253
|
+
noteEl.hidden = false;
|
|
254
|
+
clearTimeout(noteTimer);
|
|
255
|
+
noteTimer = setTimeout(() => {
|
|
256
|
+
noteEl.hidden = true;
|
|
257
|
+
noteEl.textContent = "";
|
|
258
|
+
}, NOTE_MS);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
let noteTimer = 0;
|
|
262
|
+
let busy = false;
|
|
263
|
+
|
|
264
|
+
function setChecked() {
|
|
265
|
+
edit.setAttribute("aria-checked", currentMode() === "edit" ? "true" : "false");
|
|
266
|
+
}
|
|
267
|
+
setChecked();
|
|
268
|
+
|
|
269
|
+
// The switch shows the mode that was committed, not the one a click asked for: a
|
|
270
|
+
// change can land from the keyboard, from another plugin's lease or from a live entry
|
|
271
|
+
// this menu did not start, and each commit is announced once on the document.
|
|
272
|
+
document.addEventListener("clay:modechange", setChecked);
|
|
273
|
+
|
|
274
|
+
edit.addEventListener("click", async () => {
|
|
275
|
+
if (busy) return;
|
|
276
|
+
const previous = edit.getAttribute("aria-checked");
|
|
277
|
+
const next = currentMode() === "edit" ? "view" : "edit";
|
|
278
|
+
busy = true;
|
|
279
|
+
edit.setAttribute("aria-busy", "true");
|
|
280
|
+
edit.disabled = true;
|
|
281
|
+
let result;
|
|
282
|
+
try {
|
|
283
|
+
result = await window.clay?.setMode?.(next);
|
|
284
|
+
} catch (err) {
|
|
285
|
+
result = { ok: false, message: err && err.message };
|
|
286
|
+
}
|
|
287
|
+
// A reload is coming: stay busy until the page goes.
|
|
288
|
+
if (result && result.reloading) return;
|
|
289
|
+
busy = false;
|
|
290
|
+
edit.removeAttribute("aria-busy");
|
|
291
|
+
edit.disabled = false;
|
|
292
|
+
if (result && result.ok === false) {
|
|
293
|
+
edit.setAttribute("aria-checked", previous);
|
|
294
|
+
const text = modeRefusalText(result);
|
|
295
|
+
if (text) showNote(text);
|
|
296
|
+
} else {
|
|
297
|
+
setChecked();
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
goo.addEventListener("click", () => {
|
|
302
|
+
if (isOpen()) close();
|
|
303
|
+
else open();
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
document.addEventListener("click", (event) => {
|
|
307
|
+
if (isOpen() && !root.contains(event.target)) close();
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
root.addEventListener("keydown", (event) => {
|
|
311
|
+
if (event.key === "Escape") {
|
|
312
|
+
if (!isOpen()) return;
|
|
313
|
+
event.preventDefault();
|
|
314
|
+
close();
|
|
315
|
+
goo.focus();
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (event.target === goo && (event.key === "Enter" || event.key === " ")) {
|
|
319
|
+
event.preventDefault();
|
|
320
|
+
if (isOpen()) close();
|
|
321
|
+
else {
|
|
322
|
+
open();
|
|
323
|
+
focusItem(0);
|
|
324
|
+
}
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (!isOpen()) return;
|
|
328
|
+
if (event.key === "Enter" && list.contains(event.target)) {
|
|
329
|
+
event.preventDefault();
|
|
330
|
+
event.target.click();
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const all = buttons();
|
|
334
|
+
if (!all.length) return;
|
|
335
|
+
const at = all.indexOf(document.activeElement);
|
|
336
|
+
if (event.key === "ArrowDown") {
|
|
337
|
+
event.preventDefault();
|
|
338
|
+
focusItem(at < 0 ? 0 : at + 1);
|
|
339
|
+
} else if (event.key === "ArrowUp") {
|
|
340
|
+
event.preventDefault();
|
|
341
|
+
focusItem(at < 0 ? all.length - 1 : at - 1);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
// The intro sits at the top right in normal flow, so the group moves below its
|
|
346
|
+
// bottom edge while it is on the page, and back when it goes.
|
|
347
|
+
const doc = document;
|
|
348
|
+
let introObserver = null;
|
|
349
|
+
let watched = null;
|
|
350
|
+
|
|
351
|
+
function place(intro) {
|
|
352
|
+
root.style.top = `${Math.round(intro.getBoundingClientRect().bottom) + INTRO_GAP}px`;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function watchIntro() {
|
|
356
|
+
if (!root.isConnected) return;
|
|
357
|
+
const intro = doc.querySelector(".clay-intro");
|
|
358
|
+
if (intro === watched) return;
|
|
359
|
+
if (introObserver) {
|
|
360
|
+
introObserver.disconnect();
|
|
361
|
+
introObserver = null;
|
|
362
|
+
}
|
|
363
|
+
watched = intro;
|
|
364
|
+
if (!intro) {
|
|
365
|
+
root.style.removeProperty("top");
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
if (typeof ResizeObserver === "function") {
|
|
369
|
+
introObserver = new ResizeObserver(() => place(intro));
|
|
370
|
+
introObserver.observe(intro);
|
|
371
|
+
}
|
|
372
|
+
place(intro);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const vars = document.createElement("style");
|
|
376
|
+
vars.id = "clay-menu-vars";
|
|
377
|
+
vars.setAttribute("clay", "editor-ui");
|
|
378
|
+
document.head.append(vars);
|
|
379
|
+
|
|
380
|
+
function reserveSpace() {
|
|
381
|
+
const rect = root.getBoundingClientRect();
|
|
382
|
+
vars.textContent =
|
|
383
|
+
`:root { --clay-menu-width: ${Math.ceil(rect.width)}px; --clay-menu-height: ${Math.ceil(rect.height)}px; }`;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
document.body.append(root);
|
|
387
|
+
reserveSpace();
|
|
388
|
+
if (typeof ResizeObserver === "function") new ResizeObserver(reserveSpace).observe(root);
|
|
389
|
+
|
|
390
|
+
new MutationObserver(watchIntro).observe(doc.body, { childList: true });
|
|
391
|
+
watchIntro();
|
|
392
|
+
|
|
393
|
+
const openSeo = () => import("./menu/seo.js").then((m) => m.open());
|
|
394
|
+
|
|
395
|
+
if (SEO_ITEM) {
|
|
396
|
+
addItem({
|
|
397
|
+
id: "seo",
|
|
398
|
+
label: "SEO settings…",
|
|
399
|
+
run: openSeo,
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
const storage = window.clay.storage && window.clay.storage.session;
|
|
403
|
+
if (storage && storage.get("reopen-seo") === true) {
|
|
404
|
+
storage.remove("reopen-seo");
|
|
405
|
+
openSeo().catch(() => {});
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
window.clay.menu = { addItem, open, close };
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
let mounted = false;
|
|
413
|
+
|
|
414
|
+
const shouldMount = () => (canEdit || isEditMode) && !isDraftMode;
|
|
415
|
+
|
|
416
|
+
function mountOnce() {
|
|
417
|
+
if (mounted || !shouldMount()) return;
|
|
418
|
+
mounted = true;
|
|
419
|
+
mount();
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (!isDraftMode) {
|
|
423
|
+
onDomReady(mountOnce);
|
|
424
|
+
document.addEventListener("clay:capabilitychange", mountOnce);
|
|
425
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// The reader half of plugins=page. A Document opened in view mode follows saved
|
|
2
|
+
// files through the receive-only saved transport (sync/saved-stream.js): the reader
|
|
3
|
+
// opens that transport itself and mounts the article's tools from what the host
|
|
4
|
+
// served before the stream says anything, so a host that cannot stream (static,
|
|
5
|
+
// offline, file://) still shows a working article. The first full body the
|
|
6
|
+
// transport accepts is projected onto that same article. The editor half,
|
|
7
|
+
// plugins/page.js, is edit-only. resolveModules adds this module; no URL names it.
|
|
8
|
+
//
|
|
9
|
+
// When the resolved plan also carries generic sync, sync already streams the saved
|
|
10
|
+
// lane: this module opens no stream of its own and takes the frames that lane
|
|
11
|
+
// applied instead. The loader passes that choice from the plan it resolved, so the
|
|
12
|
+
// reader never reparses the script URL to guess what else is loaded.
|
|
13
|
+
import { servedDocumentEtag } from "../core/host-attrs.js";
|
|
14
|
+
import { start as startReader } from "../page/view.js";
|
|
15
|
+
|
|
16
|
+
let reader = null;
|
|
17
|
+
let settle = null;
|
|
18
|
+
let cancelled = false;
|
|
19
|
+
let following = false;
|
|
20
|
+
let onStatus = null;
|
|
21
|
+
|
|
22
|
+
// The promise the loader holds clay:ready for: it settles once the reader has
|
|
23
|
+
// started its saved transport, or null with no single article, so clay:ready
|
|
24
|
+
// never waits on the network and fires even if the stream never opens.
|
|
25
|
+
export let ready = null;
|
|
26
|
+
|
|
27
|
+
// The first saved file's outcome: the started reader, or null on a blocked or
|
|
28
|
+
// recoverable status. The stream keeps running after that null, so a later
|
|
29
|
+
// accepted file still reaches the article through the same reader. Await this,
|
|
30
|
+
// not `ready`, for the file.
|
|
31
|
+
export let acquired = null;
|
|
32
|
+
|
|
33
|
+
const oneArticle = () => document.querySelectorAll("article[data-page]").length === 1;
|
|
34
|
+
|
|
35
|
+
// The reader reports what it applied on `clay:reader-status`; the first file is the
|
|
36
|
+
// first applied one, and a blocked or recoverable first read settles with null while
|
|
37
|
+
// the stream stays open for the next file.
|
|
38
|
+
function listen() {
|
|
39
|
+
onStatus = (event) => {
|
|
40
|
+
if (cancelled) return;
|
|
41
|
+
const status = event.detail;
|
|
42
|
+
if (status?.state === "applied") settle?.(reader);
|
|
43
|
+
else if (status?.state === "blocked" || status?.state === "recoverable") settle?.(null);
|
|
44
|
+
};
|
|
45
|
+
document.addEventListener("clay:reader-status", onStatus);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function silence() {
|
|
49
|
+
if (onStatus) document.removeEventListener("clay:reader-status", onStatus);
|
|
50
|
+
onStatus = null;
|
|
51
|
+
settle = null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// The reader opens the saved transport and mounts the served article's tools at
|
|
55
|
+
// once, so the article works before any file arrives; the first accepted file
|
|
56
|
+
// commits into that same reader. A caller that already holds the receipt a switch
|
|
57
|
+
// accepted passes it here: the article is painted from those bytes at once, with
|
|
58
|
+
// no acquisition request, so an exit shows the file it left on.
|
|
59
|
+
function acquire(represented = null) {
|
|
60
|
+
if (!oneArticle()) return Promise.resolve(null);
|
|
61
|
+
try {
|
|
62
|
+
reader = represented
|
|
63
|
+
? startReader({ represented })
|
|
64
|
+
: startReader({ documentURL: window.location.href, servedEtag: servedDocumentEtag });
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.warn("clayjs: the reader could not start over the served article", error);
|
|
67
|
+
return Promise.resolve(null);
|
|
68
|
+
}
|
|
69
|
+
if (represented) return Promise.resolve(reader.represented);
|
|
70
|
+
return new Promise((resolve) => { settle = resolve; });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Generic sync owns the saved lane here, so the reader takes its frames from that
|
|
74
|
+
// lane's accepted disk applies and keeps no stream of its own. A receipt the caller
|
|
75
|
+
// already holds is painted at once, so the tag on screen is the file's even before a
|
|
76
|
+
// frame arrives.
|
|
77
|
+
function followSync(represented = null) {
|
|
78
|
+
if (!oneArticle()) return Promise.resolve(null);
|
|
79
|
+
try {
|
|
80
|
+
reader = startReader({ feed: document, represented, documentURL: window.location.href });
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.warn("clayjs: the reader could not start over the page sync projects", error);
|
|
83
|
+
return Promise.resolve(null);
|
|
84
|
+
}
|
|
85
|
+
return Promise.resolve(reader);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Start the reader for the page in front of it. `sync` reports whether the plan
|
|
90
|
+
* the loader resolved carries generic sync, and therefore whether the saved lane
|
|
91
|
+
* already has an owner. `represented` is the receipt a switch accepted: with it
|
|
92
|
+
* the reader paints that file at once and asks the host for nothing, which is how
|
|
93
|
+
* an exit restarts the reader without waiting for a frame.
|
|
94
|
+
*/
|
|
95
|
+
export function start({ sync = false, represented = null } = {}) {
|
|
96
|
+
if (ready) return ready;
|
|
97
|
+
cancelled = false;
|
|
98
|
+
following = sync;
|
|
99
|
+
listen();
|
|
100
|
+
acquired = sync ? followSync(represented) : acquire(represented);
|
|
101
|
+
// With generic sync the reader starts before this returns, so both promises
|
|
102
|
+
// settle together; otherwise only the transport starts here and the first
|
|
103
|
+
// file arrives later, from the stream.
|
|
104
|
+
ready = sync ? acquired : Promise.resolve(null);
|
|
105
|
+
return ready;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Start the reader again after a switch retired the one this page booted: `start` keeps
|
|
109
|
+
// the promise its own boot returns, so the reader an exit replaces has to be taken down
|
|
110
|
+
// first. The receipt it is handed is painted at once, so no fetch is made for it.
|
|
111
|
+
export function restart(options = {}) {
|
|
112
|
+
stop();
|
|
113
|
+
return start(options);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// The reader's half of a live switch: the lane keeps its pending files, and the
|
|
117
|
+
// switch is answered with the receipt they will be built from.
|
|
118
|
+
export function prepareHandoff(options) {
|
|
119
|
+
if (!reader) return Promise.reject(new Error("clayjs: the reader has not started"));
|
|
120
|
+
return reader.prepareHandoff(options);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function stop() {
|
|
124
|
+
cancelled = true;
|
|
125
|
+
if (!following) settle?.(null);
|
|
126
|
+
silence();
|
|
127
|
+
reader?.stop();
|
|
128
|
+
reader = null;
|
|
129
|
+
acquired = null;
|
|
130
|
+
ready = null;
|
|
131
|
+
}
|