@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
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
// Projecting an accepted saved file onto the article a reader is showing.
|
|
2
|
+
//
|
|
3
|
+
// The saved markup is already the rendered form of the writer's model, so this is
|
|
4
|
+
// not a second merge engine: it never combines concurrent authored changes. It only
|
|
5
|
+
// brings a read-only article up to one accepted file while keeping the nodes that
|
|
6
|
+
// file did not change, so a mounted tool, an open toggle and find-in-page survive.
|
|
7
|
+
//
|
|
8
|
+
// Identity comes from logical block `data-id` values. Lists and toggle bodies are
|
|
9
|
+
// walked; boards, tables, charts, media and tools are opaque interiors, so a board
|
|
10
|
+
// card id can never match an article block id. An id that appears twice is not
|
|
11
|
+
// reused at all: neither occurrence promises node identity.
|
|
12
|
+
|
|
13
|
+
const ARTICLE = "article[data-page]";
|
|
14
|
+
const TOOL = 'section[data-type="tool"][data-id]';
|
|
15
|
+
const CONTAINERS = new Set(["UL", "OL", "LI", "DETAILS"]);
|
|
16
|
+
const LISTS = new Set(["UL", "OL"]);
|
|
17
|
+
|
|
18
|
+
export const isTool = (el) => el.tagName === "SECTION" && el.getAttribute("data-type") === "tool" && el.hasAttribute("data-id");
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The tools an article holds, keyed by id, with the revision and artifact their
|
|
22
|
+
* root names. A decode failure is kept as `invalid` so a reader can say so and
|
|
23
|
+
* leave the saved fallback markup visible instead of mounting garbage.
|
|
24
|
+
*/
|
|
25
|
+
export function toolInfoOf(el) {
|
|
26
|
+
return toolInfo(el);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function toolInfo(el) {
|
|
30
|
+
const data = el.querySelector(':scope > script[type="application/json"][data-tool]');
|
|
31
|
+
let parsed = {};
|
|
32
|
+
try {
|
|
33
|
+
parsed = data ? JSON.parse(data.textContent) : {};
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return { rev: null, artifact: null, state: {}, signature: null, invalid: true, error };
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
rev: parsed.rev ?? null,
|
|
39
|
+
artifact: parsed.artifact ?? null,
|
|
40
|
+
state: parsed.state ?? {},
|
|
41
|
+
signature: JSON.stringify(parsed.artifact ?? null),
|
|
42
|
+
invalid: false,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function toolsOf(root) {
|
|
47
|
+
const tools = new Map();
|
|
48
|
+
const duplicated = new Set();
|
|
49
|
+
for (const el of root.querySelectorAll(TOOL)) {
|
|
50
|
+
const id = el.getAttribute("data-id");
|
|
51
|
+
if (duplicated.has(id)) continue;
|
|
52
|
+
if (tools.has(id)) {
|
|
53
|
+
tools.delete(id);
|
|
54
|
+
duplicated.add(id);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
tools.set(id, toolInfo(el));
|
|
58
|
+
}
|
|
59
|
+
return tools;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function toolStateOf(doc) {
|
|
63
|
+
const tag = doc.querySelector('script[type="application/json"][merge="page.tools"]');
|
|
64
|
+
if (!tag) return {};
|
|
65
|
+
try { return JSON.parse(tag.textContent); } catch { return {}; }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function indexBlocks(root) {
|
|
69
|
+
const found = new Map();
|
|
70
|
+
const duplicated = new Set();
|
|
71
|
+
const walk = (container) => {
|
|
72
|
+
for (const child of container.children) {
|
|
73
|
+
const id = child.getAttribute("data-id");
|
|
74
|
+
if (id) {
|
|
75
|
+
if (duplicated.has(id)) continue;
|
|
76
|
+
if (found.has(id)) {
|
|
77
|
+
found.delete(id);
|
|
78
|
+
duplicated.add(id);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
found.set(id, child);
|
|
82
|
+
}
|
|
83
|
+
if (CONTAINERS.has(child.tagName)) walk(child);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
walk(root);
|
|
87
|
+
return found;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function retainedIds(root) {
|
|
91
|
+
const ids = new Set();
|
|
92
|
+
const walk = (container) => {
|
|
93
|
+
for (const child of container.children) {
|
|
94
|
+
const id = child.getAttribute("data-id");
|
|
95
|
+
if (id) ids.add(id);
|
|
96
|
+
if (CONTAINERS.has(child.tagName)) walk(child);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
walk(root);
|
|
100
|
+
return ids;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Validate one full saved file before anything is replaced. Exactly one page
|
|
105
|
+
* article must be present, and the bytes must be the string the host sent, not a
|
|
106
|
+
* live DOM snapshot.
|
|
107
|
+
*/
|
|
108
|
+
export function prepareSavedArticle(html, doc = document) {
|
|
109
|
+
if (typeof html !== "string" || html === "") return { ok: false, reason: "bytes" };
|
|
110
|
+
const parser = (doc.defaultView ?? globalThis).DOMParser;
|
|
111
|
+
if (typeof parser !== "function") return { ok: false, reason: "parser" };
|
|
112
|
+
const source = new parser().parseFromString(html, "text/html");
|
|
113
|
+
const articles = [...source.querySelectorAll(ARTICLE)];
|
|
114
|
+
if (articles.length !== 1) return { ok: false, reason: "article" };
|
|
115
|
+
const article = articles[0];
|
|
116
|
+
const savedOpen = new Map();
|
|
117
|
+
for (const details of article.querySelectorAll("details[data-id]")) {
|
|
118
|
+
savedOpen.set(details.getAttribute("data-id"), details.hasAttribute("open"));
|
|
119
|
+
}
|
|
120
|
+
const tools = toolsOf(article);
|
|
121
|
+
return {
|
|
122
|
+
ok: true,
|
|
123
|
+
article,
|
|
124
|
+
source,
|
|
125
|
+
rev: article.getAttribute("data-rev"),
|
|
126
|
+
title: source.title || null,
|
|
127
|
+
savedOpen,
|
|
128
|
+
tools,
|
|
129
|
+
toolState: tools.size ? toolStateOf(source) : {},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export const keepToolVersion = (live, incoming) => {
|
|
134
|
+
const a = toolInfo(live);
|
|
135
|
+
const b = toolInfo(incoming);
|
|
136
|
+
return !a.invalid && !b.invalid && a.rev === b.rev && a.signature === b.signature;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Apply one prepared file to the live article. Returns whether anything changed.
|
|
141
|
+
*
|
|
142
|
+
* Each container's children are reconciled in saved order: an equal keyed block is
|
|
143
|
+
* reused, a compatible keyed block is moved rather than cloned, a changed ordinary
|
|
144
|
+
* leaf is replaced, and a changed list or toggle is recursed into so its unchanged
|
|
145
|
+
* descendants survive. A tool whose id, revision and artifact still match is left
|
|
146
|
+
* untouched: its runtime subtree and reader-local interaction state are the host's.
|
|
147
|
+
*/
|
|
148
|
+
export function applyPreparedArticle(prepared, { article, readerOpen = new Map(), savedOpen = null, keepTool = keepToolVersion } = {}) {
|
|
149
|
+
if (!prepared?.ok || !article) return { changed: false };
|
|
150
|
+
for (const details of prepared.article.querySelectorAll("details[data-id]")) {
|
|
151
|
+
const id = details.getAttribute("data-id");
|
|
152
|
+
if (!readerOpen.has(id)) continue;
|
|
153
|
+
if (details.hasAttribute("open") !== readerOpen.get(id)) details.toggleAttribute("open", readerOpen.get(id));
|
|
154
|
+
}
|
|
155
|
+
const index = indexBlocks(article);
|
|
156
|
+
const used = new Set();
|
|
157
|
+
let changed = false;
|
|
158
|
+
|
|
159
|
+
const fresh = (incoming) => {
|
|
160
|
+
changed = true;
|
|
161
|
+
return incoming.cloneNode(true);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const matchingUnkeyed = (incoming, container) => {
|
|
165
|
+
const wanted = retainedIds(incoming);
|
|
166
|
+
for (const live of container.children) {
|
|
167
|
+
if (used.has(live) || live.hasAttribute("data-id")) continue;
|
|
168
|
+
if (live.tagName !== incoming.tagName) continue;
|
|
169
|
+
if (!wanted.size) return live;
|
|
170
|
+
const have = retainedIds(live);
|
|
171
|
+
for (const id of wanted) if (have.has(id)) return live;
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const matchingLeaf = (incoming, container) => {
|
|
177
|
+
for (const live of container.children) {
|
|
178
|
+
if (used.has(live) || live.hasAttribute("data-id")) continue;
|
|
179
|
+
if (live.tagName === incoming.tagName) return live;
|
|
180
|
+
}
|
|
181
|
+
return null;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const syncAttributes = (live, incoming, skip = null) => {
|
|
185
|
+
for (const { name, value } of [...incoming.attributes]) {
|
|
186
|
+
if (name === skip || live.getAttribute(name) === value) continue;
|
|
187
|
+
live.setAttribute(name, value);
|
|
188
|
+
changed = true;
|
|
189
|
+
}
|
|
190
|
+
for (const { name } of [...live.attributes]) {
|
|
191
|
+
if (name === skip || incoming.hasAttribute(name)) continue;
|
|
192
|
+
live.removeAttribute(name);
|
|
193
|
+
changed = true;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const reuseNode = (incoming, live, at) => {
|
|
198
|
+
const same = (candidate) =>
|
|
199
|
+
candidate && candidate.nodeType === incoming.nodeType && candidate.nodeValue === incoming.nodeValue && !used.has(candidate);
|
|
200
|
+
const found = same(live.childNodes[at]) ? live.childNodes[at] : [...live.childNodes].find(same);
|
|
201
|
+
if (!found) return incoming.cloneNode(true);
|
|
202
|
+
used.add(found);
|
|
203
|
+
return found;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const reconcileContainer = (live, incoming) => {
|
|
207
|
+
const ordered = [];
|
|
208
|
+
const children = [...incoming.childNodes];
|
|
209
|
+
for (let i = 0; i < children.length; i++) {
|
|
210
|
+
const child = children[i];
|
|
211
|
+
if (child.nodeType !== 1) {
|
|
212
|
+
ordered.push(reuseNode(child, live, i));
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
const node = pick(child, live);
|
|
216
|
+
used.add(node);
|
|
217
|
+
ordered.push(node);
|
|
218
|
+
}
|
|
219
|
+
const kept = new Set(ordered);
|
|
220
|
+
let walk = live.firstChild;
|
|
221
|
+
for (const node of ordered) {
|
|
222
|
+
while (walk && !kept.has(walk)) walk = walk.nextSibling;
|
|
223
|
+
if (walk === node) {
|
|
224
|
+
walk = walk.nextSibling;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
live.insertBefore(node, walk);
|
|
228
|
+
changed = true;
|
|
229
|
+
}
|
|
230
|
+
for (const child of [...live.childNodes]) {
|
|
231
|
+
if (kept.has(child)) continue;
|
|
232
|
+
child.remove();
|
|
233
|
+
changed = true;
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const freshShell = (incoming) => {
|
|
238
|
+
changed = true;
|
|
239
|
+
const node = incoming.cloneNode(false);
|
|
240
|
+
reconcileContainer(node, incoming);
|
|
241
|
+
return node;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const reconcileDetails = (live, incoming) => {
|
|
245
|
+
changed = true;
|
|
246
|
+
const id = live.getAttribute("data-id");
|
|
247
|
+
const open = readerOpen.has(id) ? readerOpen.get(id) : incoming.hasAttribute("open");
|
|
248
|
+
syncAttributes(live, incoming, "open");
|
|
249
|
+
if (live.hasAttribute("open") !== open) live.toggleAttribute("open", open);
|
|
250
|
+
reconcileContainer(live, incoming);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const reconcileItem = (live, incoming) => {
|
|
254
|
+
changed = true;
|
|
255
|
+
syncAttributes(live, incoming);
|
|
256
|
+
reconcileContainer(live, incoming);
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
function pick(incoming, container) {
|
|
260
|
+
const id = incoming.getAttribute("data-id");
|
|
261
|
+
if (id) {
|
|
262
|
+
const live = index.get(id);
|
|
263
|
+
if (!live || used.has(live) || live === container || live.contains(container)) return fresh(incoming);
|
|
264
|
+
used.add(live);
|
|
265
|
+
if (isTool(live) && isTool(incoming)) return keepTool(live, incoming) ? live : fresh(incoming);
|
|
266
|
+
if (live.tagName !== incoming.tagName) return fresh(incoming);
|
|
267
|
+
if (live.isEqualNode(incoming)) return live;
|
|
268
|
+
if (incoming.tagName === "DETAILS") {
|
|
269
|
+
reconcileDetails(live, incoming);
|
|
270
|
+
return live;
|
|
271
|
+
}
|
|
272
|
+
if (incoming.tagName === "LI") {
|
|
273
|
+
reconcileItem(live, incoming);
|
|
274
|
+
return live;
|
|
275
|
+
}
|
|
276
|
+
if (LISTS.has(incoming.tagName)) {
|
|
277
|
+
syncAttributes(live, incoming);
|
|
278
|
+
reconcileContainer(live, incoming);
|
|
279
|
+
return live;
|
|
280
|
+
}
|
|
281
|
+
return fresh(incoming);
|
|
282
|
+
}
|
|
283
|
+
if (LISTS.has(incoming.tagName)) {
|
|
284
|
+
const live = matchingUnkeyed(incoming, container);
|
|
285
|
+
if (!live) return freshShell(incoming);
|
|
286
|
+
used.add(live);
|
|
287
|
+
syncAttributes(live, incoming);
|
|
288
|
+
reconcileContainer(live, incoming);
|
|
289
|
+
return live;
|
|
290
|
+
}
|
|
291
|
+
const live = matchingLeaf(incoming, container);
|
|
292
|
+
if (!live) return fresh(incoming);
|
|
293
|
+
used.add(live);
|
|
294
|
+
if (live.isEqualNode(incoming)) return live;
|
|
295
|
+
changed = true;
|
|
296
|
+
return fresh(incoming);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
reconcileContainer(article, prepared.article);
|
|
300
|
+
if (savedOpen) {
|
|
301
|
+
savedOpen.clear();
|
|
302
|
+
for (const [id, open] of prepared.savedOpen) savedOpen.set(id, open);
|
|
303
|
+
}
|
|
304
|
+
for (const id of [...readerOpen.keys()]) if (!prepared.savedOpen.has(id)) readerOpen.delete(id);
|
|
305
|
+
return { changed };
|
|
306
|
+
}
|
package/src/page/recover.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import toast, { toastPersistent, dismissPersistent } from "../ui/toast.js";
|
|
1
|
+
import toast, { toastPersistent, dismissPersistent } from "../ui/toast-lazy.js";
|
|
2
2
|
import { state as pmState } from "../vendor/prosemirror.vendor.js";
|
|
3
3
|
|
|
4
4
|
export const NOTICE_TEXT = "Some text you typed was kept aside when its block moved or was removed.";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { cloneJson } from "../../live/ops.js";
|
|
2
2
|
import { validateArtifact, validateState } from "./tool-runtime.js";
|
|
3
|
+
export { capabilityAdvertised } from "../tool-capability.js";
|
|
3
4
|
|
|
4
5
|
const CONTEXT_LIMIT = 16384;
|
|
5
6
|
const bytes = (value) => new TextEncoder().encode(JSON.stringify(value)).length;
|
|
@@ -30,10 +31,6 @@ function trimmedContext(context) {
|
|
|
30
31
|
return copy;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
export function capabilityAdvertised(meta) {
|
|
34
|
-
return Array.isArray(meta?.extensions) && meta.extensions.includes("page-tool/1");
|
|
35
|
-
}
|
|
36
|
-
|
|
37
34
|
export function createToolClient({ transport, newId }) {
|
|
38
35
|
let active = null;
|
|
39
36
|
const discard = (candidate) => {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// One runtime owns an article at a time. A reader owns the article it projects;
|
|
2
|
+
// the editor owns it from the moment it mounts, including the noneditable period
|
|
3
|
+
// while saved feature views are still arriving. A mode flag is not enough: two
|
|
4
|
+
// runtimes both think they may write, and a late frame lands over a mounted tool.
|
|
5
|
+
//
|
|
6
|
+
// The kind is diagnostic, not permission to share. A second claim on the same
|
|
7
|
+
// article throws even when it names the same kind, so a double start fails loudly
|
|
8
|
+
// instead of leaving two listeners on one article.
|
|
9
|
+
|
|
10
|
+
const owners = new WeakMap();
|
|
11
|
+
|
|
12
|
+
export function claim(article, kind) {
|
|
13
|
+
if (!article || article.nodeType !== 1) throw new TypeError("clayjs: claim needs an element to own");
|
|
14
|
+
if (owners.has(article)) throw new Error(`clayjs: the article already has a ${owners.get(article).kind} runtime`);
|
|
15
|
+
const token = { kind: String(kind ?? "runtime"), active: true };
|
|
16
|
+
owners.set(article, token);
|
|
17
|
+
return function release() {
|
|
18
|
+
if (!token.active) return false;
|
|
19
|
+
token.active = false;
|
|
20
|
+
if (owners.get(article) === token) owners.delete(article);
|
|
21
|
+
return true;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function ownerOf(article) {
|
|
26
|
+
return owners.get(article)?.kind ?? null;
|
|
27
|
+
}
|
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
// never run after this and undo it.
|
|
6
6
|
import "../attrs/save-freeze.js";
|
|
7
7
|
import { addDocumentTransform } from "../core/snapshot.js";
|
|
8
|
-
import {
|
|
8
|
+
import { parseJsonRelaxed } from "../vendor/hyper-morph-json.vendor.js";
|
|
9
9
|
import { fragmentCleaner, project, renderModel, revOf } from "./projection.js";
|
|
10
|
+
import { documentTitle } from "./document-title.js";
|
|
11
|
+
import { customTitle, writeTitle } from "./document-title-dom.js";
|
|
10
12
|
import { blocksFromPageValues } from "./ybind/decode.js";
|
|
11
13
|
import { YDecodeError } from "./ybind/provider.js";
|
|
12
14
|
|
|
@@ -27,7 +29,7 @@ export function renderFromTags(texts) {
|
|
|
27
29
|
const key = texts.join("\u0000");
|
|
28
30
|
if (memo && memo.key === key) return memo;
|
|
29
31
|
const values = texts.map((text) => {
|
|
30
|
-
try { return
|
|
32
|
+
try { return parseJsonRelaxed(text); }
|
|
31
33
|
catch { throw new YDecodeError("invalid-json", "Cannot read the page data as JSON"); }
|
|
32
34
|
});
|
|
33
35
|
const blocks = blocksFromPageValues(values);
|
|
@@ -36,7 +38,7 @@ export function renderFromTags(texts) {
|
|
|
36
38
|
const html = blocks[id]?.artifact?.fallbackHtml;
|
|
37
39
|
return typeof html === "string" ? html : "";
|
|
38
40
|
};
|
|
39
|
-
memo = { key, html: renderModel(model, { fallbackOf, clean: fragmentCleaner(document) }), rev: revOf(model) };
|
|
41
|
+
memo = { key, html: renderModel(model, { fallbackOf, clean: fragmentCleaner(document) }), rev: revOf(model), model, title: documentTitle(model) };
|
|
40
42
|
return memo;
|
|
41
43
|
}
|
|
42
44
|
|
|
@@ -45,9 +47,49 @@ export function projectInto(clone) {
|
|
|
45
47
|
if (!article) return;
|
|
46
48
|
const tags = pageTags(clone);
|
|
47
49
|
if (!tags.length) return;
|
|
48
|
-
const { html, rev } = renderFromTags(tags.map((el) => el.textContent));
|
|
50
|
+
const { html, rev, title } = renderFromTags(tags.map((el) => el.textContent));
|
|
49
51
|
if (article.innerHTML !== html) article.innerHTML = html;
|
|
50
52
|
article.setAttribute("data-rev", rev);
|
|
53
|
+
if (!customTitle(clone)) writeTitle(clone, title);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The page state a final save clone carries, or null.
|
|
58
|
+
*
|
|
59
|
+
* One page tag is one page state: a Yjs page never has two, a tag holding plain block
|
|
60
|
+
* data is a page's own content rather than one, and a tag that does not parse is not one
|
|
61
|
+
* either. The value is copied, because the store keeps writing to its own after the
|
|
62
|
+
* capture and a checkpoint must prove the bytes this capture sent.
|
|
63
|
+
*
|
|
64
|
+
* Registered with core/snapshot only by the recovery integration, so a page that
|
|
65
|
+
* journals nothing never reads it.
|
|
66
|
+
*
|
|
67
|
+
* @param {HTMLElement} root - the save clone, after every transform
|
|
68
|
+
* @returns {?Object}
|
|
69
|
+
*/
|
|
70
|
+
export function pageStateOfClone(root) {
|
|
71
|
+
const tags = pageTags(root);
|
|
72
|
+
if (tags.length !== 1) return null;
|
|
73
|
+
let value;
|
|
74
|
+
try { value = parseJsonRelaxed(tags[0].textContent); }
|
|
75
|
+
catch { return null; }
|
|
76
|
+
const { v, g, y } = value ?? {};
|
|
77
|
+
if (v !== 1 || !y || typeof y !== "object" || Array.isArray(y)) return null;
|
|
78
|
+
return { v, g, y: { ...y } };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The canonical article one page state projects to.
|
|
83
|
+
*
|
|
84
|
+
* The same projection the save writes into the capture's article, run over the state a
|
|
85
|
+
* capture pinned or a host handed back. A state whose projection is not the article
|
|
86
|
+
* that was accepted is not a proof of those bytes, whichever transform changed it.
|
|
87
|
+
*
|
|
88
|
+
* @param {Object|string} state - a page value, or the page tag text holding one
|
|
89
|
+
* @returns {string}
|
|
90
|
+
*/
|
|
91
|
+
export function articleOfPageState(state) {
|
|
92
|
+
return renderFromTags([typeof state === "string" ? state : JSON.stringify(state)]).html;
|
|
51
93
|
}
|
|
52
94
|
|
|
53
95
|
addDocumentTransform(projectInto);
|
package/src/page/save-states.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { captureForSaveAndComparison } from "../core/snapshot.js";
|
|
2
|
-
import { downloadHtml, documentName } from "../core/
|
|
2
|
+
import { downloadHtml, documentName } from "../core/download.js";
|
|
3
3
|
|
|
4
4
|
// One plain state per save refusal code, so the indicator, the toast and the
|
|
5
5
|
// page plugin all read the same answer. `saved` is the only happy one; every
|
package/src/page/schema.js
CHANGED
|
@@ -50,6 +50,12 @@ export const schema = new model.Schema({
|
|
|
50
50
|
"data-checked": n.attrs.checked ? "true" : "false",
|
|
51
51
|
}), 0],
|
|
52
52
|
},
|
|
53
|
+
quote: {
|
|
54
|
+
group: "block",
|
|
55
|
+
content: "inline*",
|
|
56
|
+
attrs: block,
|
|
57
|
+
toDOM: (n) => ["blockquote", ref(n), 0],
|
|
58
|
+
},
|
|
53
59
|
callout: {
|
|
54
60
|
group: "block",
|
|
55
61
|
content: "inline*",
|
|
@@ -141,6 +147,20 @@ export const schema = new model.Schema({
|
|
|
141
147
|
attrs: { ...block, html: { default: "" } },
|
|
142
148
|
toDOM: (n) => ["div", ref(n, { "data-type": "preserved" })],
|
|
143
149
|
},
|
|
150
|
+
// A block type a newer peer wrote and this runtime has no schema for. It keeps
|
|
151
|
+
// the original record in raw and its inline content for mapping, and it shows
|
|
152
|
+
// an inert fallback: no content DOM to edit, no command that rewrites it.
|
|
153
|
+
opaque_block: {
|
|
154
|
+
group: "block",
|
|
155
|
+
content: "inline*",
|
|
156
|
+
atom: true,
|
|
157
|
+
isolating: true,
|
|
158
|
+
selectable: true,
|
|
159
|
+
attrs: { ...block, raw: { default: null } },
|
|
160
|
+
toDOM: (n) => ["div", ref(n, { "data-type": "newer-format", "data-format": String(n.attrs.raw?.t ?? ""), contenteditable: "false" }),
|
|
161
|
+
["span", { class: "page-newer-format" }, `Newer format: ${String(n.attrs.raw?.t ?? "")}`],
|
|
162
|
+
["span", { class: "page-newer-format-text" }, n.textContent]],
|
|
163
|
+
},
|
|
144
164
|
|
|
145
165
|
text: { group: "inline" },
|
|
146
166
|
hard_break: {
|
|
@@ -160,5 +180,32 @@ export const schema = new model.Schema({
|
|
|
160
180
|
inclusive: false,
|
|
161
181
|
toDOM: (m) => ["a", { href: safeHref(m.attrs.href) }, 0],
|
|
162
182
|
},
|
|
183
|
+
// A person mention is ordinary text with this mark over it: the name is the label
|
|
184
|
+
// and `id` is the people registry's reference. It links nowhere and notifies nobody.
|
|
185
|
+
mention: {
|
|
186
|
+
attrs: { id: {} },
|
|
187
|
+
inclusive: false,
|
|
188
|
+
excludes: "mention date link",
|
|
189
|
+
toDOM: (m) => ["span", { "data-page-mention": m.attrs.id }, 0],
|
|
190
|
+
},
|
|
191
|
+
// A date mention is the calendar date as ordinary ISO text with this mark over it:
|
|
192
|
+
// `date` is YYYY-MM-DD, and no time, zone, reminder or relative word is stored.
|
|
193
|
+
date: {
|
|
194
|
+
attrs: { date: {} },
|
|
195
|
+
inclusive: false,
|
|
196
|
+
excludes: "mention date link",
|
|
197
|
+
toDOM: (m) => ["time", { datetime: m.attrs.date, "data-page-date": "" }, 0],
|
|
198
|
+
},
|
|
199
|
+
// The floor-1 formats (format-native.js): written as named descriptors,
|
|
200
|
+
// drawn as the elements the saved article keeps for them.
|
|
201
|
+
underline: { toDOM: () => ["u", 0] },
|
|
202
|
+
text_color: {
|
|
203
|
+
attrs: { color: {} },
|
|
204
|
+
toDOM: (m) => ["span", { "data-color": m.attrs.color }, 0],
|
|
205
|
+
},
|
|
206
|
+
highlight: {
|
|
207
|
+
attrs: { color: {} },
|
|
208
|
+
toDOM: (m) => ["mark", { "data-color": m.attrs.color }, 0],
|
|
209
|
+
},
|
|
163
210
|
},
|
|
164
211
|
});
|
package/src/page/table-select.js
CHANGED
|
@@ -11,10 +11,11 @@ import { clipboardSerializer } from "./blocks.js";
|
|
|
11
11
|
import { asStep } from "./blocksel.js";
|
|
12
12
|
import { announce } from "./announce.js";
|
|
13
13
|
import { REMOTE_META } from "./ybind/layout.js";
|
|
14
|
+
import { rectKey } from "./table-rect-key.js";
|
|
14
15
|
|
|
15
|
-
const { Plugin,
|
|
16
|
+
const { Plugin, TextSelection } = state;
|
|
16
17
|
const N = schema.nodes;
|
|
17
|
-
export
|
|
18
|
+
export { rectKey };
|
|
18
19
|
|
|
19
20
|
const findTable = (doc, id) => {
|
|
20
21
|
let found = null;
|
|
@@ -171,7 +172,7 @@ export function tableSelectPlugin() {
|
|
|
171
172
|
const step = { ArrowUp: [-1, 0], ArrowDown: [1, 0], ArrowLeft: [0, -1], ArrowRight: [0, 1] }[event.key];
|
|
172
173
|
if (step) return extend(...step)(st, view.dispatch, view);
|
|
173
174
|
}
|
|
174
|
-
if (MODIFIERS.has(event.key) || ((event.metaKey || event.ctrlKey) && (event.key === "c" || event.key === "x" || event.key === "v"))) return false;
|
|
175
|
+
if (MODIFIERS.has(event.key) || ((event.metaKey || event.ctrlKey) && (event.key === "a" || event.key === "c" || event.key === "x" || event.key === "v"))) return false;
|
|
175
176
|
view.dispatch(st.tr.setMeta(rectKey, null));
|
|
176
177
|
return false;
|
|
177
178
|
},
|
package/src/page/table-style.js
CHANGED
|
@@ -8,7 +8,7 @@ export const TABLE_CSS = `
|
|
|
8
8
|
.page-table table.is-sized { table-layout: fixed; min-width: 0; }
|
|
9
9
|
.page-table table.is-sized th, .page-table table.is-sized td { min-width: 0; overflow-wrap: anywhere; }
|
|
10
10
|
.page-table-resize { position: absolute; top: 0; bottom: 0; inset-inline-end: -4px; width: 8px; z-index: 2; cursor: col-resize; touch-action: none; }
|
|
11
|
-
.page-table-resize:hover, .page-table-resize:active { background: var(--page-accent); opacity: 0.4; }
|
|
11
|
+
.page-table-resize:hover, .page-table-resize:active, .page-table-resize:focus-visible { background: var(--page-accent); opacity: 0.4; }
|
|
12
12
|
.page-table-add-row, .page-table-add-col { position: absolute; z-index: 1; border: 0; padding: 0; background: var(--page-chrome-bg-rest); color: var(--page-chrome-ink-rest); font: inherit; line-height: 1; cursor: pointer; opacity: 0; transition: opacity 120ms; }
|
|
13
13
|
.page-table-add-row { left: 0; right: 0; top: 100%; height: 14px; border-radius: 0 0 6px 6px; }
|
|
14
14
|
.page-table-add-col { top: 0; bottom: 0; left: 100%; width: 14px; border-radius: 0 6px 6px 0; }
|