@panphora/clayjs 1.16.0 → 1.18.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/dist/all.js +1 -1
- package/dist/clay-dom.js +1 -1
- package/dist/clay-events.js +1 -1
- package/dist/clay-internals.js +1 -1
- package/dist/clay-options.js +1 -1
- package/dist/clay-router.js +1 -1
- package/dist/clay-ui.js +1 -1
- package/dist/clay-utils.js +1 -1
- package/dist/clay.js +1 -1
- package/dist/clay.standalone.js +72519 -59839
- package/dist/m/attrs/refetch-on-save-ZUE7PSCI.js +1 -0
- package/dist/m/attrs/save-freeze-LWGF6XUN.js +1 -0
- package/dist/m/c-2GRUM77Q.js +30 -0
- package/dist/m/c-2KIEGNC4.js +1 -0
- package/dist/m/{c-5R4PTRG2.js → c-2KL3BD52.js} +1 -1
- package/dist/m/c-2YYDMLNZ.js +1 -0
- package/dist/m/c-2ZZBC45O.js +1 -0
- package/dist/m/c-372N6H3B.js +1 -0
- package/dist/m/{c-4WKFKEKF.js → c-3G2DGZUP.js} +1 -1
- package/dist/m/c-3LDGIBMN.js +1 -0
- package/dist/m/c-3O7OBDCM.js +1 -0
- package/dist/m/c-4ASQPRQL.js +1 -0
- package/dist/m/c-4TXNLX4K.js +6 -0
- package/dist/m/c-4YU3BR4D.js +6 -0
- package/dist/m/c-5734MF2P.js +1 -0
- package/dist/m/c-57XDY6HC.js +1 -0
- package/dist/m/{c-VFX45IZQ.js → c-5B4YBZXC.js} +1 -1
- package/dist/m/c-5ONTYIUI.js +1 -0
- package/dist/m/c-5OOVFCJM.js +1 -0
- package/dist/m/c-5T6NZHNM.js +1 -0
- package/dist/m/{c-YDH7Q3NY.js → c-5ZQV7KC4.js} +1 -1
- package/dist/m/{c-Z36J63PP.js → c-6DB2OLRJ.js} +1 -1
- package/dist/m/c-6DNRCPNM.js +1 -0
- package/dist/m/c-6UGWFMQC.js +2 -0
- package/dist/m/c-7K4SCQB7.js +1 -0
- package/dist/m/c-7MG5RU63.js +1 -0
- package/dist/m/c-7PRJCA3E.js +1 -0
- package/dist/m/c-A6L3FMUS.js +1 -0
- package/dist/m/c-AMU3BPPR.js +4 -0
- package/dist/m/c-AMYEFA2E.js +1 -0
- package/dist/m/c-AQYCG7QW.js +1 -0
- package/dist/m/c-ATKAOH23.js +1 -0
- package/dist/m/c-B3JM5ZXC.js +1 -0
- package/dist/m/c-B5CS55WR.js +1 -0
- package/dist/m/c-B5UJQT7W.js +1 -0
- package/dist/m/c-B7J4K2AE.js +3 -0
- package/dist/m/c-BHZYSHW4.js +1 -0
- package/dist/m/c-BIJALSRD.js +1 -0
- package/dist/m/c-BJ7YQ5QZ.js +1 -0
- package/dist/m/c-BPF2NSPV.js +1 -0
- package/dist/m/{c-KIPQJX4B.js → c-BRLCTNMC.js} +1 -1
- package/dist/m/c-BUAYFEV5.js +1 -0
- package/dist/m/c-C6IPRG34.js +1 -0
- package/dist/m/{c-2JL6E75N.js → c-CAS3NND4.js} +1 -1
- package/dist/m/{c-4DRMS4QG.js → c-CCQ25GFY.js} +1 -1
- package/dist/m/c-CJFDLD43.js +1 -0
- package/dist/m/c-COPTL5WB.js +1 -0
- package/dist/m/c-D3E4WJ4M.js +166 -0
- package/dist/m/c-D5IKEKXW.js +7 -0
- package/dist/m/c-DHBRA6DL.js +1 -0
- package/dist/m/c-DKLS74XB.js +72 -0
- package/dist/m/c-DVYGFTSK.js +3 -0
- package/dist/m/c-E3ZXARWA.js +1 -0
- package/dist/m/c-EK63G3CG.js +1 -0
- package/dist/m/c-ERQSNR6K.js +13 -0
- package/dist/m/c-EVYAISP3.js +1 -0
- package/dist/m/c-EXKHPOVC.js +3 -0
- package/dist/m/{c-7VGZ7RU5.js → c-FWKHM4E7.js} +1 -1
- package/dist/m/{c-4Q2XTQ2N.js → c-GBKB5WDL.js} +1 -1
- package/dist/m/c-GNDL3TKB.js +1 -0
- package/dist/m/c-GRWMD6O5.js +1 -0
- package/dist/m/c-GRXHHFPO.js +1 -0
- package/dist/m/{c-OYTFP5QN.js → c-GY422N3Q.js} +1 -1
- package/dist/m/c-HAWFNBYG.js +1 -0
- package/dist/m/c-HG2C77BM.js +4 -0
- package/dist/m/c-HHGJBU4D.js +1 -0
- package/dist/m/c-HMV6P4RX.js +1 -0
- package/dist/m/c-HMYWIHFG.js +1 -0
- package/dist/m/c-HT2DKBV2.js +1 -0
- package/dist/m/c-I2SCCUEW.js +1 -0
- package/dist/m/{c-HRDCD3WN.js → c-ICJYHABF.js} +2 -2
- package/dist/m/c-IMZCWYHR.js +7 -0
- package/dist/m/c-IVMD3FEM.js +1 -0
- package/dist/m/c-IVTRVENZ.js +1 -0
- package/dist/m/c-IW6GGOU2.js +1 -0
- package/dist/m/c-JKZJIUIP.js +1 -0
- package/dist/m/{c-NZMNXVF6.js → c-JNLX3RJB.js} +1 -1
- package/dist/m/c-JRKY44DK.js +1 -0
- package/dist/m/c-K3ADYNLU.js +1 -0
- package/dist/m/c-KBS3UV6B.js +1 -0
- package/dist/m/c-KGHVFRR3.js +1 -0
- package/dist/m/c-KJJPV77R.js +1 -0
- package/dist/m/{c-CZUSOB7V.js → c-KNPDOMDY.js} +1 -1
- package/dist/m/{c-5Y6TNX5W.js → c-KP64LT2A.js} +2 -2
- package/dist/m/c-KQ7E3PYY.js +1 -0
- package/dist/m/c-L3F5ZLIV.js +1 -0
- package/dist/m/{c-LR4CGEPT.js → c-L42OLXWM.js} +3 -2
- package/dist/m/c-L5VFATT6.js +1 -0
- package/dist/m/c-L7JL5TL3.js +3 -0
- package/dist/m/c-LKSL4AUJ.js +1 -0
- package/dist/m/c-M6FNQCTQ.js +1 -0
- package/dist/m/c-MCOOHCSG.js +1 -0
- package/dist/m/c-MHI3GYKF.js +1 -0
- package/dist/m/c-MWXFLW4J.js +1 -0
- package/dist/m/c-NEL7HQW3.js +1 -0
- package/dist/m/c-NQJRVJ56.js +1 -0
- package/dist/m/c-NWX3MFT4.js +1 -0
- package/dist/m/{c-HPURYVZS.js → c-OJYM642Q.js} +1 -1
- package/dist/m/c-OKXI52N7.js +1 -0
- package/dist/m/{c-MMUIUUZG.js → c-OPLUZR3A.js} +1 -1
- package/dist/m/{c-J7CA54IP.js → c-OTMKN2OO.js} +1 -1
- package/dist/m/{c-LTGMXXKO.js → c-OYRZ7XG2.js} +1 -1
- package/dist/m/c-P3OFYUMA.js +1 -0
- package/dist/m/c-PLN76GF3.js +6 -0
- package/dist/m/c-PLP4JKFC.js +1 -0
- package/dist/m/c-Q26MME6N.js +1 -0
- package/dist/m/{c-S7H2DRCB.js → c-Q3XOWZEV.js} +1 -1
- package/dist/m/{c-SWRJFCNN.js → c-QIKT6SKM.js} +1 -1
- package/dist/m/c-QIXT3Q7C.js +28 -0
- package/dist/m/c-QO4HNGCQ.js +1 -0
- package/dist/m/c-R27DWQKX.js +1 -0
- package/dist/m/{c-HVYXIS72.js → c-R2XUODVY.js} +1 -1
- package/dist/m/{c-QNKREOL6.js → c-R7LBFMF5.js} +1 -1
- package/dist/m/c-RND3G2S2.js +1 -0
- package/dist/m/c-S2U6NJU4.js +1 -0
- package/dist/m/c-SPZPGD3R.js +1 -0
- package/dist/m/c-SW4YEG2D.js +8 -0
- package/dist/m/c-SZGYW5HT.js +1 -0
- package/dist/m/c-T637T7SN.js +1 -0
- package/dist/m/c-TJAXGIRV.js +1 -0
- package/dist/m/{c-KKWLDOPM.js → c-TNEM3RNM.js} +1 -1
- package/dist/m/c-TTB5EK4S.js +32 -0
- package/dist/m/c-U7SHNWDH.js +1 -0
- package/dist/m/c-UDHIVLYH.js +20 -0
- package/dist/m/{c-BBVGTQG7.js → c-UGNV5MFB.js} +1 -1
- package/dist/m/{c-TQZ2JYHD.js → c-UORXLSD3.js} +1 -1
- package/dist/m/c-UPD33ZPE.js +1 -0
- package/dist/m/c-URSMSFCB.js +1 -0
- package/dist/m/c-UY4QX42B.js +1 -0
- package/dist/m/c-V44KWI2L.js +4 -0
- package/dist/m/c-VG5XIN4T.js +1 -0
- package/dist/m/c-VILENZTD.js +1 -0
- package/dist/m/{c-33HUYEDI.js → c-VJYEVRYK.js} +1 -1
- package/dist/m/c-VR2BJ4AN.js +1 -0
- package/dist/m/c-W4JCVLAB.js +1 -0
- package/dist/m/c-W6DQSHXI.js +135 -0
- package/dist/m/c-WBGWGOM7.js +1 -0
- package/dist/m/{c-4L3BTFRK.js → c-WCXLG3MV.js} +1 -1
- package/dist/m/c-WGW764WX.js +1 -0
- package/dist/m/c-WMRJKQ2V.js +5 -0
- package/dist/m/c-WNTYKCDG.js +1 -0
- package/dist/m/c-WQWIRWO3.js +72 -0
- package/dist/m/c-X5LNHET5.js +1 -0
- package/dist/m/c-X5TSXZYJ.js +2 -0
- package/dist/m/c-XGH4GS2T.js +1 -0
- package/dist/m/c-Y6F2FORL.js +1 -0
- package/dist/m/c-YBKHUAK7.js +10 -0
- package/dist/m/c-YBSS55KU.js +20 -0
- package/dist/m/c-YCLU4UNT.js +2 -0
- package/dist/m/c-YVZ2L7CE.js +1 -0
- package/dist/m/c-ZK4GIZH2.js +1 -0
- package/dist/m/c-ZRXJD4G6.js +1 -0
- package/dist/m/c-ZWBI4HYK.js +1 -0
- package/dist/m/{c-HT33EQRN.js → c-ZWIOJGMT.js} +1 -1
- package/dist/m/core/admin-attrs-YY7T5FGU.js +1 -0
- package/dist/m/core/autosave-S6OMNDCK.js +1 -0
- package/dist/m/core/conflict-notice-IWHMHH43.js +1 -0
- package/dist/m/core/host-permission-6EVJGNPL.js +1 -0
- package/dist/m/core/is-edit-mode-GCX6767E.js +1 -0
- package/dist/m/core/{persist-HKHA66IY.js → persist-UKXV5KLA.js} +1 -1
- package/dist/m/core/recovery-DRFZRJED.js +1 -0
- package/dist/m/core/save-LYY7K6U7.js +1 -0
- package/dist/m/core/save-core-MKRPSEEO.js +1 -0
- package/dist/m/core/snapshot-NU3YM6GR.js +1 -0
- package/dist/m/core/unsaved-warning-7QTKEN7Z.js +1 -0
- package/dist/m/events/index-RN2JNGBV.js +1 -0
- package/dist/m/internals/index-TGLQINN3.js +1 -0
- package/dist/m/lib/cache-bust-MUMFXZK6.js +1 -0
- package/dist/m/loader-3BBNZZGM.js +1 -0
- package/dist/m/manifest-F449FF98.js +1 -0
- package/dist/m/manifest-edit-4396A009.js +1 -0
- package/dist/m/manifest.json +2509 -1474
- package/dist/m/options/options-EJMS3K24.js +1 -0
- package/dist/m/page/editor-6LRB3GE4.js +304 -0
- package/dist/m/plugins/ai-edit-UTV7YO2I.js +6 -0
- package/dist/m/plugins/{cms-HP3LSTPN.js → cms-LRAOZHT7.js} +9 -9
- package/dist/m/plugins/demo-OYO5GCAO.js +1 -0
- package/dist/m/plugins/{derive-UAAA4V4S.js → derive-FRE5JJQE.js} +1 -1
- package/dist/m/plugins/indicator-4VDXWYTD.js +1 -0
- package/dist/m/plugins/live-AD4H6XSL.js +1 -0
- package/dist/m/plugins/menu-M5WW7DBF.js +1 -0
- package/dist/m/plugins/page-MD3T2ZX3.js +2 -0
- package/dist/m/plugins/page-view-PAWVZNFY.js +1 -0
- package/dist/m/plugins/people-JCHVPF7P.js +1 -0
- package/dist/m/plugins/quickcrop-BQ5YYFCH.js +26 -0
- package/dist/m/plugins/{richclay-RC3L2F6X.js → richclay-KLGETK77.js} +2 -2
- package/dist/m/plugins/sortable-4S6SQC3D.js +1 -0
- package/dist/m/plugins/source-TJXOIOYY.js +1 -0
- package/dist/m/plugins/undo-NLPGCJQY.js +1 -0
- package/dist/m/plugins/{unsent-HJFLQJ2O.js → unsent-OA4RGBUT.js} +1 -1
- package/dist/m/plugins/upgrade-HSUNDNJD.js +1 -0
- package/dist/m/plugins/upload-NHGJXZK2.js +1 -0
- package/dist/m/plugins/visitor-drafts-BW43DGY3.js +20 -0
- package/dist/m/plugins/visitor-drafts-owner-7ODQG7JX.js +1 -0
- package/dist/m/plugins/wire-VBWXEXU2.js +1 -0
- package/dist/m/reader-core-4W2KYEWQ.js +77 -0
- package/dist/m/route/route-62CHXL5B.js +1 -0
- package/dist/m/sync/live-sync-MO5DH33W.js +1 -0
- package/dist/m/ui/index-IVWN2QC4.js +1 -0
- package/dist/m/vendor/sap-core.vendor-RN4ZVY4X.js +6 -0
- package/dist/offline-manifest.json +1560 -889
- package/dist/page/themes/light-1.css +33 -8
- package/dist/server/core.cjs +1554 -311
- package/dist/server/offline-runtime.cjs +63 -63
- package/dist/server/offline-runtime.mjs +63 -63
- package/dist/server/page-compaction-worker.cjs +3710 -0
- package/dist/server/rooms.mjs +5 -0
- package/docs/guide.md +653 -101
- package/entries/sap.js +5 -5
- package/package.json +1 -1
- package/src/core/admin-contenteditable.js +5 -2
- package/src/core/admin-inputs.js +1 -0
- package/src/core/admin-onclick.js +2 -1
- package/src/core/boot-phase.js +2 -1
- package/src/core/conflict-download.js +3 -29
- package/src/core/conflict-notice-ui.js +4 -7
- package/src/core/download.js +32 -0
- package/src/core/host-meta.js +56 -0
- package/src/core/is-edit-mode.js +17 -1
- package/src/core/mode-key.js +125 -19
- package/src/core/mode-support.js +5 -0
- package/src/core/mode-transition.js +20 -6
- package/src/core/preserve-authored.js +4 -4
- package/src/core/recovery.js +121 -33
- package/src/core/save-accepted.js +33 -0
- package/src/core/save-core.js +111 -32
- package/src/core/save-job.js +108 -0
- package/src/core/save-prepare.js +53 -0
- package/src/core/save-size-notice.js +3 -1
- package/src/core/save-slices.js +15 -0
- package/src/core/save.js +557 -127
- package/src/core/serialize-steps.js +109 -0
- package/src/core/snapshot.js +209 -40
- package/src/core/source-map.js +83 -38
- package/src/core/stale-host-notice.js +1 -0
- package/src/core/upgrade-run.js +59 -8
- package/src/dom/active-element.js +5 -0
- package/src/lib/assets.js +1 -0
- package/src/lib/autosave-scheduler.js +3 -4
- package/src/lib/slice.js +65 -0
- package/src/lib/uimotion.js +774 -0
- package/src/lib/unsaved-state.js +2 -2
- package/src/live/fast-lane.js +10 -3
- package/src/live/local-lane.js +202 -11
- package/src/live/ops.js +16 -0
- package/src/live/page-compaction.js +162 -0
- package/src/live/server-lane.js +1 -0
- package/src/live/store.js +11 -3
- package/src/loader-logic.js +3 -1
- package/src/loader.js +14 -4
- package/src/page/adopt-boot.js +2 -1
- package/src/page/awareness.js +33 -2
- package/src/page/blocks.js +122 -27
- package/src/page/board-views.js +2 -16
- package/src/page/boot-pack.js +1 -1
- package/src/page/chart-tables.js +29 -0
- package/src/page/chart.js +411 -72
- package/src/page/checklist.js +10 -135
- package/src/page/checkpoint-proof.js +295 -0
- package/src/page/chrome.js +257 -40
- package/src/page/clipboard-shape.js +126 -0
- package/src/page/document-title-dom.js +12 -0
- package/src/page/document-title-runtime.js +15 -1
- package/src/page/document-title.js +4 -1
- package/src/page/drag.js +33 -3
- package/src/page/editor.js +207 -31
- package/src/page/emoji-data.js +162 -0
- package/src/page/export-assets.js +357 -0
- package/src/page/export-html.js +209 -0
- package/src/page/export-markdown.js +361 -0
- package/src/page/features/board.js +12 -3
- package/src/page/features/chart.js +11 -0
- package/src/page/features/checklist.js +428 -0
- package/src/page/features/dates.js +180 -0
- package/src/page/features/emoji.js +187 -0
- package/src/page/features/export-html.js +189 -0
- package/src/page/features/export-markdown.js +169 -0
- package/src/page/features/import-markdown.js +349 -0
- package/src/page/features/media.js +61 -5
- package/src/page/features/mentions.js +188 -0
- package/src/page/features/registry.js +24 -1
- package/src/page/features/table.js +375 -85
- package/src/page/features/title-cover.js +331 -0
- package/src/page/features/title-icon.js +213 -0
- package/src/page/features/toc.js +87 -0
- package/src/page/format-command.js +33 -0
- package/src/page/format-gate.js +68 -18
- package/src/page/format-host.js +71 -0
- package/src/page/format-native-commands.js +158 -0
- package/src/page/format-native.js +42 -0
- package/src/page/image-actions.js +64 -0
- package/src/page/import-markdown.js +262 -0
- package/src/page/inline.js +32 -8
- package/src/page/items.js +141 -11
- package/src/page/markdown.js +30 -2
- package/src/page/media.js +35 -119
- package/src/page/mention-picker.js +99 -0
- package/src/page/merge.js +1 -1
- package/src/page/placeholder.js +14 -1
- package/src/page/projection.js +156 -25
- package/src/page/recover.js +10 -12
- package/src/page/recovery-ui.js +464 -0
- package/src/page/rich/chart.js +63 -7
- package/src/page/save-projection.js +67 -0
- package/src/page/save-states.js +14 -4
- package/src/page/schema.js +52 -3
- package/src/page/table-paste.js +3 -1
- package/src/page/table-style.js +4 -4
- package/src/page/table.js +44 -2
- package/src/page/themes/content.css +25 -1
- package/src/page/themes/light-1.css +33 -8
- package/src/page/themes/light-1.source.css +8 -7
- package/src/page/toc-link.js +31 -0
- package/src/page/toc.js +5 -0
- package/src/page/view-hooks.js +58 -0
- package/src/page/view.js +13 -0
- package/src/page/ybind/binding.js +116 -6
- package/src/page/ybind/bridge.js +187 -20
- package/src/page/ybind/containment.js +162 -0
- package/src/page/ybind/doc.js +17 -9
- package/src/page/ybind/file-debt.js +63 -0
- package/src/page/ybind/layout.js +7 -2
- package/src/page/ybind/marks.js +2 -1
- package/src/page/ybind/moves.js +5 -4
- package/src/page/ybind/origins.js +106 -4
- package/src/page/ybind/parts.js +8 -1
- package/src/page/ybind/provider.js +125 -18
- package/src/page/ybind/recovery-proof.js +32 -9
- package/src/page/ybind/recovery-replay.js +905 -4
- package/src/page/ybind/recovery.js +174 -45
- package/src/page/ybind/table.js +67 -11
- package/src/page/ybind/walk-delta.js +258 -0
- package/src/page/ybind/walk.js +54 -29
- package/src/page/ybind/writer.js +1 -1
- package/src/plugins/ai-edit.js +13 -9
- package/src/plugins/indicator-chip.js +91 -0
- package/src/plugins/indicator.js +13 -80
- package/src/plugins/live.js +126 -15
- package/src/plugins/menu/actions.js +196 -0
- package/src/plugins/menu/people.js +279 -0
- package/src/plugins/menu/placement.js +121 -0
- package/src/plugins/menu/preferences.js +9 -0
- package/src/plugins/menu/seo.js +316 -397
- package/src/plugins/menu/style.js +171 -0
- package/src/plugins/menu/variants.js +296 -0
- package/src/plugins/menu.js +186 -183
- package/src/plugins/page-view.js +3 -2
- package/src/plugins/page.js +362 -43
- package/src/plugins/sortable.js +8 -1
- package/src/plugins/source.js +6 -0
- package/src/plugins/upgrade.js +51 -17
- package/src/plugins/upload-ui.js +12 -17
- package/src/plugins/visitor-drafts/bottom-ui.js +12 -4
- package/src/plugins/visitor-drafts/intro-style.js +7 -2
- package/src/plugins/visitor-drafts/intro.js +7 -4
- package/src/plugins/visitor-drafts/owner-chip.js +8 -12
- package/src/plugins/visitor-drafts/prompt.js +11 -9
- package/src/plugins/visitor-drafts/source.js +4 -3
- package/src/plugins/visitor-drafts/store.js +138 -9
- package/src/plugins/visitor-drafts/ui-memory.js +2 -2
- package/src/plugins/visitor-drafts-owner.js +4 -6
- package/src/plugins/visitor-drafts.js +5 -3
- package/src/recovery/store.js +1 -1
- package/src/route/route.js +4 -0
- package/src/server/checkpoint/index.js +2 -2
- package/src/server/rooms/index.js +5 -1
- package/src/server/rooms/live-data-rooms.js +302 -50
- package/src/server/rooms/page-compaction-worker.js +12 -0
- package/src/server/rooms/page-compactor.js +92 -0
- package/src/server/rooms/page-room-conformance.js +461 -0
- package/src/source/parse-steps.js +94 -0
- package/src/source/session.js +233 -57
- package/src/sync/editing-sender.js +12 -0
- package/src/sync/live-sync-edit.js +22 -2
- package/src/sync/live-sync.js +150 -23
- package/src/sync/page-relay.js +52 -0
- package/src/sync/presence-store.js +44 -4
- package/src/sync/presence.js +6 -3
- package/src/sync/saved-stream.js +28 -14
- package/src/ui/bevel-controls.js +1 -0
- package/src/ui/bevel-dialog.js +5 -2
- package/src/ui/editor-ui.js +77 -0
- package/src/ui/page-colour.js +281 -0
- package/src/ui/toast.js +16 -7
- package/src/vendor/hyper-html-api-upgrade.vendor.js +2 -2
- package/src/vendor/hyper-undo.vendor.js +1 -1
- package/src/vendor/hypercms.vendor.js +9 -9
- package/src/vendor/parse5.vendor.js +2 -2
- package/src/vendor/sap-core.vendor.js +5 -5
- package/dist/m/attrs/refetch-on-save-NWPPXOCZ.js +0 -1
- package/dist/m/attrs/save-freeze-FUP4Q4X3.js +0 -1
- package/dist/m/c-2M73252O.js +0 -1
- package/dist/m/c-2SPVQSHC.js +0 -1
- package/dist/m/c-35NBGMZB.js +0 -1
- package/dist/m/c-3IQRECYS.js +0 -1
- package/dist/m/c-4B6H4G5V.js +0 -1
- package/dist/m/c-4FFHZM32.js +0 -1
- package/dist/m/c-4YSCRICO.js +0 -1
- package/dist/m/c-54RCDCBU.js +0 -1
- package/dist/m/c-5M4YEKCX.js +0 -4
- package/dist/m/c-5V3MOVJT.js +0 -1
- package/dist/m/c-66O32MV3.js +0 -28
- package/dist/m/c-6HMB24EV.js +0 -1
- package/dist/m/c-7O6AFR65.js +0 -1
- package/dist/m/c-ANQTJ3B5.js +0 -2
- package/dist/m/c-AYVOREBE.js +0 -1
- package/dist/m/c-B2ZXPOS3.js +0 -3
- package/dist/m/c-BMIZKMPV.js +0 -1
- package/dist/m/c-BTDI4Y23.js +0 -1
- package/dist/m/c-CJZSLMVQ.js +0 -1
- package/dist/m/c-DBE6ORSI.js +0 -1
- package/dist/m/c-EDHUR4MX.js +0 -1
- package/dist/m/c-EY6UOM54.js +0 -1
- package/dist/m/c-F3CKJTJS.js +0 -1
- package/dist/m/c-F7Y6FLPY.js +0 -1
- package/dist/m/c-FA4DZVTC.js +0 -1
- package/dist/m/c-G2BUZITR.js +0 -1
- package/dist/m/c-GB3JTV6E.js +0 -1
- package/dist/m/c-GBGWXTX4.js +0 -1
- package/dist/m/c-GHBCCVG4.js +0 -1
- package/dist/m/c-GJAEGGXY.js +0 -1
- package/dist/m/c-GOWBDM6J.js +0 -1
- package/dist/m/c-IB52R237.js +0 -1
- package/dist/m/c-IKWNE4R4.js +0 -1
- package/dist/m/c-IU3IYEU6.js +0 -1
- package/dist/m/c-IZ2EBRAJ.js +0 -1
- package/dist/m/c-KR4UW4KW.js +0 -1
- package/dist/m/c-KY3VJGUA.js +0 -8
- package/dist/m/c-LFPHCXY3.js +0 -1
- package/dist/m/c-LRPUO2MX.js +0 -1
- package/dist/m/c-LXENEBV7.js +0 -1
- package/dist/m/c-NMJRXKPC.js +0 -8
- package/dist/m/c-OIBUTDXI.js +0 -1
- package/dist/m/c-PPOSCAQD.js +0 -1
- package/dist/m/c-QIX5BJYN.js +0 -1
- package/dist/m/c-QQHEX6HA.js +0 -1
- package/dist/m/c-R7RMANJI.js +0 -9
- package/dist/m/c-RI4NT75Y.js +0 -1
- package/dist/m/c-RM7J7BV2.js +0 -1
- package/dist/m/c-RUJKSUQW.js +0 -1
- package/dist/m/c-SGCCC4FW.js +0 -25
- package/dist/m/c-T4VO4OCB.js +0 -1
- package/dist/m/c-TQEMVJCS.js +0 -1
- package/dist/m/c-TR6RMDQ7.js +0 -3
- package/dist/m/c-UKHTLWUW.js +0 -1
- package/dist/m/c-UNN7LWCT.js +0 -1
- package/dist/m/c-UXBMRDZB.js +0 -235
- package/dist/m/c-V7PZZRG7.js +0 -1
- package/dist/m/c-VL52ADDR.js +0 -1
- package/dist/m/c-WNYBLIOZ.js +0 -1
- package/dist/m/c-WWDBYXLK.js +0 -1
- package/dist/m/c-XNNW2CWK.js +0 -1
- package/dist/m/c-Y6USGTS5.js +0 -5
- package/dist/m/c-YG2NJYS6.js +0 -135
- package/dist/m/c-Z4VRC7GU.js +0 -7
- package/dist/m/c-Z6K52OLP.js +0 -19
- package/dist/m/c-ZDY2MDAA.js +0 -21
- package/dist/m/c-ZUCOKOHT.js +0 -1
- package/dist/m/core/admin-attrs-VGNLAUDK.js +0 -1
- package/dist/m/core/autosave-E4PEFPZ6.js +0 -1
- package/dist/m/core/conflict-notice-VQ6Y64PH.js +0 -1
- package/dist/m/core/host-permission-XN3K2IW3.js +0 -1
- package/dist/m/core/is-edit-mode-JXHDVGUL.js +0 -1
- package/dist/m/core/recovery-TBBSICE2.js +0 -1
- package/dist/m/core/save-WUCHTQBE.js +0 -1
- package/dist/m/core/save-core-FJVHT5M3.js +0 -1
- package/dist/m/core/snapshot-F3SWDZMM.js +0 -1
- package/dist/m/core/unsaved-warning-STKBHE6G.js +0 -1
- package/dist/m/events/index-23DPTUT4.js +0 -1
- package/dist/m/internals/index-WOVAP3RU.js +0 -1
- package/dist/m/lib/cache-bust-CGWT6ZJI.js +0 -1
- package/dist/m/loader-HXX6YNH5.js +0 -1
- package/dist/m/manifest-F22DEDAC.js +0 -1
- package/dist/m/manifest-edit-C3C7376B.js +0 -1
- package/dist/m/options/options-2LH76JQ3.js +0 -1
- package/dist/m/page/editor-XUTB2HB2.js +0 -189
- package/dist/m/plugins/ai-edit-ZQ4CGWIP.js +0 -6
- package/dist/m/plugins/demo-ZIBFAA3R.js +0 -1
- package/dist/m/plugins/indicator-PV4YW2ID.js +0 -1
- package/dist/m/plugins/live-NUTTXSBS.js +0 -1
- package/dist/m/plugins/menu-HCKO3DSP.js +0 -138
- package/dist/m/plugins/page-KSUH7G6J.js +0 -2
- package/dist/m/plugins/page-view-W73OW7WI.js +0 -1
- package/dist/m/plugins/people-AJJ32YCG.js +0 -1
- package/dist/m/plugins/quickcrop-QNY3PKLD.js +0 -26
- package/dist/m/plugins/sortable-YRMQX3ZU.js +0 -1
- package/dist/m/plugins/source-KHK5UUSK.js +0 -1
- package/dist/m/plugins/undo-OF2L3CXU.js +0 -1
- package/dist/m/plugins/upgrade-ZNYODP5Y.js +0 -1
- package/dist/m/plugins/upload-XSGNILUY.js +0 -1
- package/dist/m/plugins/visitor-drafts-XK5GW55Q.js +0 -21
- package/dist/m/plugins/visitor-drafts-owner-KSSH75EV.js +0 -1
- package/dist/m/plugins/wire-ZWVWKF76.js +0 -1
- package/dist/m/reader-core-ILWLXVMP.js +0 -68
- package/dist/m/route/route-KOCZSEGN.js +0 -1
- package/dist/m/sync/live-sync-4AUVXVJU.js +0 -1
- package/dist/m/ui/index-EVHKMKBL.js +0 -1
- package/dist/m/vendor/sap-core.vendor-A7BMUYZT.js +0 -6
- /package/dist/m/{c-FILLTJA7.js → c-QTTJYJMA.js} +0 -0
- /package/dist/m/plugins/{quickcrop-QNY3PKLD.js.LEGAL.txt → quickcrop-BQ5YYFCH.js.LEGAL.txt} +0 -0
- /package/dist/m/plugins/{richclay-RC3L2F6X.js.LEGAL.txt → richclay-KLGETK77.js.LEGAL.txt} +0 -0
package/src/loader.js
CHANGED
|
@@ -86,10 +86,11 @@ export async function boot(base, params, readyResolve, manifest = null, suppleme
|
|
|
86
86
|
const regionPolicy = await MODULES["lib/region-policy.js"]();
|
|
87
87
|
|
|
88
88
|
const hasSap = Boolean(document.querySelector("[sap]"));
|
|
89
|
+
const hasVariants = document.querySelectorAll("head style[clay-variant]").length >= 2;
|
|
89
90
|
// derive.js imports the sapjs core only when no sap.js script took the page over.
|
|
90
91
|
const hasSapJs = Boolean(document.querySelector('script[src*="sap.js"]'));
|
|
91
92
|
bootPhase.holdSettle = hasSap && isEditMode;
|
|
92
|
-
const plan = resolveModules(params, isEditMode, { isDraftMode, hasSap, canEdit, templateSource: templateSource() });
|
|
93
|
+
const plan = resolveModules(params, isEditMode, { isDraftMode, hasSap, hasVariants, canEdit, templateSource: templateSource() });
|
|
93
94
|
// Where edits land, resolved once: a visitor draft saves into its draft slot, the
|
|
94
95
|
// demo plugin into localStorage, and everything else to the host. setMode takes no
|
|
95
96
|
// destination, and V4 has no draft-to-host transition.
|
|
@@ -126,16 +127,22 @@ export async function boot(base, params, readyResolve, manifest = null, suppleme
|
|
|
126
127
|
// Nothing is fetched for it here: the decision and the controller behind it wait for the
|
|
127
128
|
// first switch, so this costs a reader with a declaration no more than one attribute.
|
|
128
129
|
if (document.documentElement.getAttribute("clay-mode-switch") === "live") {
|
|
129
|
-
const editing = resolveModules(params, true, { isDraftMode, hasSap, canEdit, templateSource: templateSource() });
|
|
130
|
+
const editing = resolveModules(params, true, { isDraftMode, hasSap, hasVariants, canEdit, templateSource: templateSource() });
|
|
130
131
|
loaded["core/edit-mode.js"].noteLiveSwitch({
|
|
131
132
|
edit: editing,
|
|
132
133
|
// The plan a view boot would have resolved, not the edit plan this boot resolved: an
|
|
133
134
|
// exit imports it and starts its reader, and an edit-only module belongs to the
|
|
134
135
|
// session being left.
|
|
135
|
-
view: resolveModules(params, false, { isDraftMode, hasSap, canEdit, templateSource: templateSource() }),
|
|
136
|
+
view: resolveModules(params, false, { isDraftMode, hasSap, hasVariants, canEdit, templateSource: templateSource() }),
|
|
136
137
|
loaded,
|
|
137
138
|
modules: MODULES,
|
|
138
|
-
|
|
139
|
+
// A live entry attaches the edit plugins after boot: clay.plugins names them from then on.
|
|
140
|
+
attach: (path, mod) => {
|
|
141
|
+
attachPluginMember(path, mod);
|
|
142
|
+
const name = PLUGIN_NAMES[path];
|
|
143
|
+
const named = window.clay.plugins;
|
|
144
|
+
if (name && Array.isArray(named) && !named.includes(name)) window.clay.plugins = Object.freeze([...named, name]);
|
|
145
|
+
},
|
|
139
146
|
attachEditCore,
|
|
140
147
|
announce,
|
|
141
148
|
loadEditHints: loadEditHints ? editHints(loadEditHints, manifest, editing, hasSapJs) : null,
|
|
@@ -146,6 +153,9 @@ export async function boot(base, params, readyResolve, manifest = null, suppleme
|
|
|
146
153
|
// leases before a plugin can take input. A reader returns at the first line.
|
|
147
154
|
await loaded["core/edit-mode.js"].activateInitialMode();
|
|
148
155
|
window.clay.plugins = Object.freeze([...plan.plugins, ...plan.late].map((path) => PLUGIN_NAMES[path]));
|
|
156
|
+
// What an edit session here would load, so view-mode chrome can offer an edit-only feature.
|
|
157
|
+
const editPlan = isEditMode ? plan : resolveModules(params, true, { isDraftMode, hasSap, hasVariants, canEdit, templateSource: templateSource() });
|
|
158
|
+
window.clay.editPlugins = Object.freeze([...editPlan.plugins, ...editPlan.late].map((path) => PLUGIN_NAMES[path]));
|
|
149
159
|
|
|
150
160
|
for (const path of plan.plugins) {
|
|
151
161
|
// A plugin that throws on evaluation degrades to absent. Unguarded, its
|
package/src/page/adopt-boot.js
CHANGED
|
@@ -54,6 +54,7 @@ export function installAdoption({
|
|
|
54
54
|
notice = () => {},
|
|
55
55
|
snapshot = () => null,
|
|
56
56
|
mergeTagless = false,
|
|
57
|
+
seeded = false,
|
|
57
58
|
writerReady = () => Promise.resolve(),
|
|
58
59
|
adopted = () => {},
|
|
59
60
|
hold = suspendAutosave,
|
|
@@ -216,7 +217,7 @@ export function installAdoption({
|
|
|
216
217
|
}
|
|
217
218
|
|
|
218
219
|
doc.addEventListener("clay:sync-applied", onFrame);
|
|
219
|
-
if (source) run(source, true);
|
|
220
|
+
if (source && !seeded) run(source, true);
|
|
220
221
|
|
|
221
222
|
return {
|
|
222
223
|
// Resolves once everything queued so far has been attempted, with the boot
|
package/src/page/awareness.js
CHANGED
|
@@ -54,6 +54,12 @@ const caretElement = (doc, name, color) => {
|
|
|
54
54
|
|
|
55
55
|
const labelOf = (person) => (typeof person.name === "string" && person.name.trim() ? person.name.trim() : "Someone");
|
|
56
56
|
|
|
57
|
+
let barrier = false;
|
|
58
|
+
if (typeof document !== "undefined") {
|
|
59
|
+
document.addEventListener("clay:presence-quiesce", () => { barrier = true; });
|
|
60
|
+
document.addEventListener("clay:presence-resume", () => { barrier = false; });
|
|
61
|
+
}
|
|
62
|
+
|
|
57
63
|
/**
|
|
58
64
|
* The decorations one snapshot produces in one document.
|
|
59
65
|
*
|
|
@@ -104,14 +110,20 @@ export function createPageAwareness({ binding, view, store = presenceStore, epoc
|
|
|
104
110
|
styleWithLegacyId(STYLE_ID, STYLE_CSS, STYLE_ID, ["editor-ui"]);
|
|
105
111
|
const doc = view.dom.ownerDocument;
|
|
106
112
|
let disposed = false;
|
|
107
|
-
|
|
113
|
+
// The exit's barrier, and the clear that came with it: while it runs this tab
|
|
114
|
+
// publishes nothing, so a caret move or a doc change during the barrier cannot put
|
|
115
|
+
// a target back the session is about to release.
|
|
116
|
+
let quiesced = barrier;
|
|
117
|
+
// Focus is a fact about the document, not a guess: an editor mounted in a background
|
|
118
|
+
// tab is not focused, and publishing a target for it would claim a caret nobody holds.
|
|
119
|
+
let focused = typeof view.hasFocus === "function" ? view.hasFocus() === true : view.dom.contains(doc.activeElement);
|
|
108
120
|
let pending = null;
|
|
109
121
|
const isComposing = () => (composing ? composing() === true : view.composing === true);
|
|
110
122
|
|
|
111
123
|
const supported = () => store.getSnapshot().pageAwareness !== false;
|
|
112
124
|
|
|
113
125
|
const publish = (state = view.state) => {
|
|
114
|
-
if (disposed) return;
|
|
126
|
+
if (disposed || quiesced) return;
|
|
115
127
|
if (!supported() || !focused || isComposing()) {
|
|
116
128
|
store.setTarget(null);
|
|
117
129
|
return;
|
|
@@ -167,6 +179,19 @@ export function createPageAwareness({ binding, view, store = presenceStore, epoc
|
|
|
167
179
|
schedule();
|
|
168
180
|
});
|
|
169
181
|
|
|
182
|
+
// The edit participant reaches these, so the page's target goes quiet with the
|
|
183
|
+
// sender during the exit's barrier and comes back with it on a refused exit.
|
|
184
|
+
const quiesce = () => {
|
|
185
|
+
if (disposed) return;
|
|
186
|
+
quiesced = true;
|
|
187
|
+
store.setTarget(null);
|
|
188
|
+
};
|
|
189
|
+
const resume = () => {
|
|
190
|
+
if (disposed) return;
|
|
191
|
+
quiesced = false;
|
|
192
|
+
publish();
|
|
193
|
+
};
|
|
194
|
+
|
|
170
195
|
const onFocus = () => { focused = true; publish(); schedule(); };
|
|
171
196
|
const onBlur = () => { focused = false; store.setTarget(null); };
|
|
172
197
|
const onHide = () => { store.setTarget(null); };
|
|
@@ -176,6 +201,8 @@ export function createPageAwareness({ binding, view, store = presenceStore, epoc
|
|
|
176
201
|
view.dom.addEventListener("blur", onBlur);
|
|
177
202
|
view.dom.addEventListener("compositionend", onCompositionEnd);
|
|
178
203
|
doc.addEventListener("pagehide", onHide);
|
|
204
|
+
doc.addEventListener("clay:presence-quiesce", quiesce);
|
|
205
|
+
doc.addEventListener("clay:presence-resume", resume);
|
|
179
206
|
view.updateState(view.state.reconfigure({ plugins: [...view.state.plugins, plugin] }));
|
|
180
207
|
publish();
|
|
181
208
|
schedule();
|
|
@@ -184,6 +211,8 @@ export function createPageAwareness({ binding, view, store = presenceStore, epoc
|
|
|
184
211
|
epoch,
|
|
185
212
|
refresh,
|
|
186
213
|
plugin,
|
|
214
|
+
quiesce,
|
|
215
|
+
resume,
|
|
187
216
|
get decorations() {
|
|
188
217
|
return awarenessKey.getState(view.state) ?? DecorationSet.empty;
|
|
189
218
|
},
|
|
@@ -199,6 +228,8 @@ export function createPageAwareness({ binding, view, store = presenceStore, epoc
|
|
|
199
228
|
view.dom.removeEventListener("blur", onBlur);
|
|
200
229
|
view.dom.removeEventListener("compositionend", onCompositionEnd);
|
|
201
230
|
doc.removeEventListener("pagehide", onHide);
|
|
231
|
+
doc.removeEventListener("clay:presence-quiesce", quiesce);
|
|
232
|
+
doc.removeEventListener("clay:presence-resume", resume);
|
|
202
233
|
store.setTarget(null);
|
|
203
234
|
store.releaseTarget();
|
|
204
235
|
if (!view.isDestroyed) {
|
package/src/page/blocks.js
CHANGED
|
@@ -8,7 +8,8 @@ import { REMOTE, newId } from "./model.js";
|
|
|
8
8
|
import { safeHref, safeSrc } from "./link.js";
|
|
9
9
|
import { flatten, runsOf, unflatten, unitsOf } from "./inline.js";
|
|
10
10
|
import { OPAQUE_MARK, opaqueMark } from "./format-codec.js";
|
|
11
|
-
import {
|
|
11
|
+
import { NATIVE_NAMES, nativeAttrs } from "./format-native.js";
|
|
12
|
+
import { DEFAULTS, MARKS, OPAQUE, envelopeAttrs, envelopeRecord, marksAttrs, marksEntries, toggleLevel } from "./projection.js";
|
|
12
13
|
|
|
13
14
|
const alignOf = (a) => (a === "left" || a === "right" ? a : null);
|
|
14
15
|
|
|
@@ -36,7 +37,9 @@ const asStep = (dispatch) => dispatch && ((tr) => dispatch(history.closeHistory(
|
|
|
36
37
|
// hidden some toggle above it is closed
|
|
37
38
|
// subEnd index of the last block of its subtree (itself when it has none)
|
|
38
39
|
// A subtree is always contiguous, so it is the range [ents[i].at, ents[subEnd].end].
|
|
39
|
-
|
|
40
|
+
// `reveal` is a set of toggle ids a link opened for this reader only: a revealed
|
|
41
|
+
// toggle reads as open here, and its saved `open` is untouched.
|
|
42
|
+
export function outline(doc, reveal = null) {
|
|
40
43
|
const ents = [];
|
|
41
44
|
const toggleAt = new Map();
|
|
42
45
|
let run = [];
|
|
@@ -52,8 +55,9 @@ export function outline(doc) {
|
|
|
52
55
|
if (run.length) up = run[run.length - 1];
|
|
53
56
|
run.push(i);
|
|
54
57
|
} else run = [];
|
|
55
|
-
const
|
|
56
|
-
|
|
58
|
+
const open = isToggle(node) && (node.attrs.open || !!reveal?.has(node.attrs.id));
|
|
59
|
+
const hidden = t >= 0 && (ents[t].hidden || !ents[t].open);
|
|
60
|
+
ents.push({ node, at, end: at + node.nodeSize, i, up, depth: t >= 0 ? ents[t].depth + 1 : 0, hidden, open, subEnd: i });
|
|
57
61
|
if (isToggle(node) && node.attrs.id) toggleAt.set(node.attrs.id, i);
|
|
58
62
|
});
|
|
59
63
|
for (let j = ents.length - 1; j >= 0; j--) {
|
|
@@ -130,11 +134,19 @@ export function structureFixes(doc, oldDoc = null) {
|
|
|
130
134
|
}
|
|
131
135
|
|
|
132
136
|
export function structurePlugin() {
|
|
137
|
+
const valid = new WeakSet();
|
|
133
138
|
return new Plugin({
|
|
134
139
|
appendTransaction(trs, old, next) {
|
|
135
140
|
if (!trs.some((tr) => tr.docChanged && !tr.getMeta(REMOTE))) return null;
|
|
141
|
+
if (valid.has(old.doc) && sameStructure(old.doc, next.doc)) {
|
|
142
|
+
valid.add(next.doc);
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
136
145
|
const fixes = structureFixes(next.doc, old.doc);
|
|
137
|
-
if (!fixes.length)
|
|
146
|
+
if (!fixes.length) {
|
|
147
|
+
valid.add(next.doc);
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
138
150
|
const tr = next.tr;
|
|
139
151
|
for (const f of fixes) tr.setNodeMarkup(f.at, null, f.attrs);
|
|
140
152
|
return tr;
|
|
@@ -642,9 +654,22 @@ export function backspaceBodyBlock(st, dispatch) {
|
|
|
642
654
|
|
|
643
655
|
// ---- open / closed ----------------------------------------------------------
|
|
644
656
|
|
|
657
|
+
// A reveal is edit-mode state, never a document attribute: the toggle ids a followed link
|
|
658
|
+
// opened live in the collapse plugin's own state, so nothing is saved, no undo step is
|
|
659
|
+
// made and no peer is told.
|
|
660
|
+
export const REVEAL = "page-reveal";
|
|
661
|
+
|
|
662
|
+
export function revealToggles(tr, ids) {
|
|
663
|
+
return ids.length ? tr.setMeta(REVEAL, { add: ids }) : tr;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// A toggle the person opens or closes themselves drops any reveal a link left on it:
|
|
667
|
+
// the override never outlives the decision it saved them.
|
|
645
668
|
export function setOpen(st, ti, open, ents = outline(st.doc)) {
|
|
646
669
|
const e = ents[ti];
|
|
647
|
-
return st.tr.setNodeMarkup(e.at, null, { ...e.node.attrs, open })
|
|
670
|
+
return st.tr.setNodeMarkup(e.at, null, { ...e.node.attrs, open })
|
|
671
|
+
.setMeta("addToHistory", false)
|
|
672
|
+
.setMeta(REVEAL, { clear: [e.node.attrs.id] });
|
|
648
673
|
}
|
|
649
674
|
|
|
650
675
|
export function toggleOpenAtSelection(st, dispatch) {
|
|
@@ -661,7 +686,7 @@ export function toggleOpenAtSelection(st, dispatch) {
|
|
|
661
686
|
export function hiddenRanges(ents) {
|
|
662
687
|
const out = [];
|
|
663
688
|
for (const e of ents) {
|
|
664
|
-
if (!isToggle(e.node) || e.hidden || e.
|
|
689
|
+
if (!isToggle(e.node) || e.hidden || e.open || e.subEnd === e.i) continue;
|
|
665
690
|
out.push({ line: e.at + 1, sumEnd: e.end - 1, from: e.end, to: ents[e.subEnd].end });
|
|
666
691
|
}
|
|
667
692
|
return out;
|
|
@@ -758,35 +783,55 @@ export function sameStructure(a, b) {
|
|
|
758
783
|
return true;
|
|
759
784
|
}
|
|
760
785
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
786
|
+
const NO_REVEAL = new Set();
|
|
787
|
+
|
|
788
|
+
function collapseState(doc, reveal = NO_REVEAL) {
|
|
789
|
+
const ents = outline(doc, reveal);
|
|
790
|
+
return { decos: decorationsFor(doc, ents), ranges: hiddenRanges(ents), reveal };
|
|
764
791
|
}
|
|
765
792
|
|
|
793
|
+
// The block decorations of a long document in one linear pass. ProseMirror's
|
|
794
|
+
// DecorationSet scans every top-level node decoration for each child the view
|
|
795
|
+
// visits and each decoration it maps, which is quadratic in blocks; this set
|
|
796
|
+
// holds only node decorations at the top and finds a toggle's widget by binary
|
|
797
|
+
// search. It is built directly in document order instead of through create().
|
|
798
|
+
let OutlineSet = null;
|
|
799
|
+
const outlineSet = () => OutlineSet ??= class extends pmView.DecorationSet {
|
|
800
|
+
forChild(offset, node) {
|
|
801
|
+
if (node.isLeaf) return pmView.DecorationSet.empty;
|
|
802
|
+
const c = this.children;
|
|
803
|
+
let lo = 0, hi = c.length / 3;
|
|
804
|
+
while (lo < hi) { const mid = (lo + hi) >> 1; if (c[mid * 3] < offset) lo = mid + 1; else hi = mid; }
|
|
805
|
+
return lo * 3 < c.length && c[lo * 3] === offset ? c[lo * 3 + 2] : pmView.DecorationSet.empty;
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
|
|
766
809
|
export function decorationsFor(doc, ents = outline(doc)) {
|
|
767
810
|
const { Decoration, DecorationSet } = pmView;
|
|
768
811
|
const markers = orderedMarkers(ents);
|
|
769
|
-
const
|
|
812
|
+
const local = [], children = [];
|
|
770
813
|
for (const e of ents) {
|
|
771
814
|
const attrs = {};
|
|
772
815
|
if (e.hidden) { attrs.class = "page-hidden"; attrs["aria-hidden"] = "true"; }
|
|
773
816
|
if (e.depth) attrs.style = `--page-depth:${e.depth}`;
|
|
774
817
|
if (markers.has(e.i)) attrs["data-marker"] = markers.get(e.i);
|
|
775
|
-
if (isToggle(e.node)) attrs["aria-expanded"] = e.
|
|
776
|
-
if (Object.keys(attrs).length)
|
|
818
|
+
if (isToggle(e.node)) attrs["aria-expanded"] = e.open ? "true" : "false";
|
|
819
|
+
if (Object.keys(attrs).length) local.push(Decoration.node(e.at, e.end, attrs));
|
|
777
820
|
if (isToggle(e.node) && !e.hidden) {
|
|
778
|
-
|
|
821
|
+
const widget = Decoration.widget(0, () => disclosure(e.node, e.open), { side: -1, ignoreSelection: true, key: `t:${e.node.attrs.id}:${e.open}` });
|
|
822
|
+
children.push(e.at, e.end, new DecorationSet([widget], []));
|
|
779
823
|
}
|
|
780
824
|
}
|
|
781
|
-
return DecorationSet.
|
|
825
|
+
if (!local.length && !children.length) return DecorationSet.empty;
|
|
826
|
+
return new (outlineSet())(local, children);
|
|
782
827
|
}
|
|
783
828
|
|
|
784
|
-
function disclosure(node) {
|
|
829
|
+
function disclosure(node, open = node.attrs.open) {
|
|
785
830
|
const b = document.createElement("button");
|
|
786
831
|
b.type = "button";
|
|
787
832
|
b.className = "page-toggle-button";
|
|
788
833
|
b.contentEditable = "false";
|
|
789
|
-
b.setAttribute("aria-label",
|
|
834
|
+
b.setAttribute("aria-label", open ? "Collapse" : "Expand");
|
|
790
835
|
b.setAttribute("data-toggle", node.attrs.id || "");
|
|
791
836
|
return b;
|
|
792
837
|
}
|
|
@@ -798,13 +843,15 @@ export function collapsePlugin() {
|
|
|
798
843
|
state: {
|
|
799
844
|
init: (_, s) => collapseState(s.doc),
|
|
800
845
|
apply(tr, value, old, s) {
|
|
846
|
+
const meta = tr.getMeta(REVEAL);
|
|
847
|
+
if (meta) {
|
|
848
|
+
const reveal = new Set(value.reveal);
|
|
849
|
+
for (const id of meta.add ?? []) reveal.add(id);
|
|
850
|
+
for (const id of meta.clear ?? []) reveal.delete(id);
|
|
851
|
+
return collapseState(s.doc, reveal);
|
|
852
|
+
}
|
|
801
853
|
if (!tr.docChanged) return value;
|
|
802
|
-
|
|
803
|
-
const m = tr.mapping;
|
|
804
|
-
return {
|
|
805
|
-
decos: value.decos.map(m, s.doc),
|
|
806
|
-
ranges: value.ranges.map((r) => ({ line: m.map(r.line, -1), sumEnd: m.map(r.sumEnd), from: m.map(r.from), to: m.map(r.to, -1) })),
|
|
807
|
-
};
|
|
854
|
+
return collapseState(s.doc, value.reveal);
|
|
808
855
|
},
|
|
809
856
|
},
|
|
810
857
|
appendTransaction(trs, old, next) {
|
|
@@ -1001,7 +1048,12 @@ export function flattenPastedHTML(html, doc = globalThis.document) {
|
|
|
1001
1048
|
t.setAttribute("data-page-toggle", k);
|
|
1002
1049
|
if (child.hasAttribute("open")) t.setAttribute("data-open", "true");
|
|
1003
1050
|
if (parentKey) t.setAttribute("data-page-parent", parentKey);
|
|
1004
|
-
|
|
1051
|
+
// A toggle heading saves as a heading in its summary: keep the level, paste its text.
|
|
1052
|
+
const head = summary?.querySelector(":scope > h1, :scope > h2, :scope > h3");
|
|
1053
|
+
if (head) {
|
|
1054
|
+
t.setAttribute("data-level", head.tagName[1]);
|
|
1055
|
+
t.append(...head.childNodes);
|
|
1056
|
+
} else if (summary) t.append(...summary.childNodes);
|
|
1005
1057
|
target.appendChild(t);
|
|
1006
1058
|
for (const c of [...child.childNodes]) if (c !== summary) { const box = doc.createElement("div"); box.appendChild(c); walk(box, k, target); }
|
|
1007
1059
|
continue;
|
|
@@ -1042,6 +1094,8 @@ export function flattenPastedHTML(html, doc = globalThis.document) {
|
|
|
1042
1094
|
if (parent) for (const piece of pieces) piece.setAttribute("data-page-parent", parent);
|
|
1043
1095
|
child.replaceWith(...pieces);
|
|
1044
1096
|
}
|
|
1097
|
+
const sliced = root.querySelector("[data-pm-slice]");
|
|
1098
|
+
if (sliced) out.firstElementChild?.setAttribute("data-pm-slice", sliced.dataset.pmSlice);
|
|
1045
1099
|
return out.innerHTML;
|
|
1046
1100
|
}
|
|
1047
1101
|
|
|
@@ -1079,14 +1133,19 @@ const pastedOpaqueMarks = (dom) => {
|
|
|
1079
1133
|
try { return { entries: marksEntries(dom.getAttribute(MARKS)) }; } catch { return false; }
|
|
1080
1134
|
};
|
|
1081
1135
|
|
|
1136
|
+
// clipboard-shape.js: lists and tables on the clipboard.
|
|
1137
|
+
let shape = null;
|
|
1138
|
+
export const loadClipboardShape = () => import("./clipboard-shape.js").then((mod) => { shape = mod; }, () => {});
|
|
1139
|
+
|
|
1082
1140
|
// The clipboard parser: the schema has toDOM only, so paste gets its own rules.
|
|
1083
1141
|
export const clipboardParser = new model.DOMParser(parseSchema, [
|
|
1142
|
+
{ tag: "table", node: "table", getAttrs: (d) => shape?.table(d) ?? false, getContent: (d) => shape.rows(d) },
|
|
1084
1143
|
{ tag: `div[${OPAQUE}]`, node: "opaque_block", getAttrs: pastedOpaque, getContent: pastedOpaqueContent },
|
|
1085
1144
|
{ tag: `span[${MARKS}]`, mark: OPAQUE_MARK, getAttrs: pastedOpaqueMarks },
|
|
1086
1145
|
{ tag: "div[data-page-li]", node: "list_item", getAttrs: (d) => ({ kind: d.getAttribute("data-kind") || "bullet", indent: +d.getAttribute("data-indent") || 0, checked: d.getAttribute("data-checked") === "true", parent: parentAttr(d) }) },
|
|
1087
1146
|
{ tag: "div.page-li", node: "list_item", getAttrs: (d) => ({ kind: d.getAttribute("data-kind") || "bullet", indent: +d.getAttribute("data-indent") || 0, checked: d.getAttribute("data-checked") === "true", parent: parentAttr(d) }) },
|
|
1088
|
-
{ tag: "div[data-page-toggle]", node: "toggle", getAttrs: (d) => ({ id: d.getAttribute("data-page-toggle"), open: d.getAttribute("data-open") === "true", parent: parentAttr(d) }) },
|
|
1089
|
-
{ tag: "div.page-toggle", node: "toggle", getAttrs: (d) => ({ id: d.getAttribute("data-id"), open: d.getAttribute("data-open") === "true", parent: null }) },
|
|
1147
|
+
{ tag: "div[data-page-toggle]", node: "toggle", getAttrs: (d) => ({ id: d.getAttribute("data-page-toggle"), open: d.getAttribute("data-open") === "true", parent: parentAttr(d), level: toggleLevel(Number(d.getAttribute("data-level"))) }) },
|
|
1148
|
+
{ tag: "div.page-toggle", node: "toggle", getAttrs: (d) => ({ id: d.getAttribute("data-id"), open: d.getAttribute("data-open") === "true", parent: null, level: toggleLevel(Number(d.getAttribute("data-level"))) }) },
|
|
1090
1149
|
{ tag: "h1", node: "heading", getAttrs: (d) => ({ level: 1, parent: parentAttr(d) }) },
|
|
1091
1150
|
{ tag: "h2", node: "heading", getAttrs: (d) => ({ level: 2, parent: parentAttr(d) }) },
|
|
1092
1151
|
{ tag: "h3", node: "heading", getAttrs: (d) => ({ level: 3, parent: parentAttr(d) }) },
|
|
@@ -1118,6 +1177,10 @@ export const clipboardParser = new model.DOMParser(parseSchema, [
|
|
|
1118
1177
|
{ tag: "del", mark: "strike" },
|
|
1119
1178
|
{ tag: "code", mark: "code" },
|
|
1120
1179
|
{ tag: "a[href]", mark: "link", getAttrs: (d) => { const href = safeHref(d.getAttribute("href")); return href ? { href } : false; } },
|
|
1180
|
+
{ tag: "blockquote", node: "quote", getAttrs: (d) => ({ parent: parentAttr(d) }) },
|
|
1181
|
+
{ tag: "u", mark: "underline" },
|
|
1182
|
+
{ tag: "mark", mark: "highlight", getAttrs: (d) => nativeAttrs("highlight", { color: d.getAttribute("data-color") }) ?? false },
|
|
1183
|
+
{ tag: "span[data-color]", mark: "text_color", getAttrs: (d) => nativeAttrs("text_color", { color: d.getAttribute("data-color") }) ?? false },
|
|
1121
1184
|
]);
|
|
1122
1185
|
|
|
1123
1186
|
// Every pasted block arrives with no id and no pos (identityPlugin mints and
|
|
@@ -1168,6 +1231,7 @@ class ClipboardSerializer extends model.DOMSerializer {
|
|
|
1168
1231
|
if (isToggle(n) && n.attrs.id) dom.setAttribute("data-page-toggle", n.attrs.id);
|
|
1169
1232
|
if (n.type === N.image && n.attrs.width) dom.setAttribute("data-width", String(n.attrs.width));
|
|
1170
1233
|
});
|
|
1234
|
+
shape?.copy(fragment, doms);
|
|
1171
1235
|
return out;
|
|
1172
1236
|
}
|
|
1173
1237
|
}
|
|
@@ -1202,11 +1266,42 @@ function pasteIntoClosedSummary(view, _event, slice) {
|
|
|
1202
1266
|
return true;
|
|
1203
1267
|
}
|
|
1204
1268
|
|
|
1269
|
+
// The four formats pasted in from elsewhere are floor-1 content too: a slice
|
|
1270
|
+
// that holds one asks the gate before it is inserted, and text waits in the
|
|
1271
|
+
// clipboard rather than being dropped when the answer is a refusal.
|
|
1272
|
+
function writesFormat(slice) {
|
|
1273
|
+
let found = false;
|
|
1274
|
+
slice?.content?.descendants((node) => {
|
|
1275
|
+
if (found) return false;
|
|
1276
|
+
if (node.type === N.quote) found = true;
|
|
1277
|
+
else if (node.isText && node.marks.some((mark) => NATIVE_NAMES.has(mark.type.name))) found = true;
|
|
1278
|
+
return !found;
|
|
1279
|
+
});
|
|
1280
|
+
return found;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
function pasteFormat(view, event, slice) {
|
|
1284
|
+
const from = view.state.selection.from, to = view.state.selection.to;
|
|
1285
|
+
const before = view.state.doc;
|
|
1286
|
+
const plain = () => {
|
|
1287
|
+
const text = slice.content.textBetween(0, slice.content.size, "\n", " ");
|
|
1288
|
+
if (!view.isDestroyed && text && view.state.doc === before) view.dispatch(view.state.tr.insertText(text, from, to));
|
|
1289
|
+
return false;
|
|
1290
|
+
};
|
|
1291
|
+
import("./format-native-commands.js").then(({ pasteFormats }) => pasteFormats(view, slice, from, to), plain);
|
|
1292
|
+
return true;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1205
1295
|
export function pastePlugin() {
|
|
1206
1296
|
return new Plugin({
|
|
1297
|
+
view() { loadClipboardShape(); return {}; },
|
|
1207
1298
|
props: {
|
|
1208
|
-
handlePaste
|
|
1299
|
+
handlePaste(view, event, slice) {
|
|
1300
|
+
if (writesFormat(slice)) return pasteFormat(view, event, slice);
|
|
1301
|
+
return pasteIntoClosedSummary(view, event, slice);
|
|
1302
|
+
},
|
|
1209
1303
|
clipboardSerializer,
|
|
1304
|
+
clipboardTextSerializer: (slice) => shape?.text(slice),
|
|
1210
1305
|
transformPastedHTML: (html) => flattenPastedHTML(html),
|
|
1211
1306
|
clipboardParser,
|
|
1212
1307
|
clipboardTextParser: (text, _$ctx, plain) => (plain ? null : parseListText(text)),
|
package/src/page/board-views.js
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// The card panels a board plugin can reach, filled by the board view part when it
|
|
4
|
-
// loads. The plugin works, and does nothing, for a board without a panel.
|
|
1
|
+
// The card panels a board part can reach, filled by the board view part when it
|
|
2
|
+
// loads. A board without a panel does nothing on every change.
|
|
5
3
|
export const cardPanels = new WeakMap();
|
|
6
|
-
|
|
7
|
-
export function boardPlugin() {
|
|
8
|
-
return new state.Plugin({
|
|
9
|
-
view: (view) => ({
|
|
10
|
-
update: () => cardPanels.get(view)?.sync(),
|
|
11
|
-
destroy: () => {
|
|
12
|
-
cardPanels.get(view)?.hide(false, false);
|
|
13
|
-
cardPanels.delete(view);
|
|
14
|
-
},
|
|
15
|
-
}),
|
|
16
|
-
});
|
|
17
|
-
}
|
package/src/page/boot-pack.js
CHANGED
|
@@ -14,7 +14,7 @@ export { installAdoption, ADOPTION_TIMEOUT_MS } from "./adopt-boot.js";
|
|
|
14
14
|
export { classifyFile, readBack } from "./adopt.js";
|
|
15
15
|
export { mergePageModels } from "./merge.js";
|
|
16
16
|
export { canon } from "./projection.js";
|
|
17
|
-
export { renderFromTags } from "./save-projection.js";
|
|
17
|
+
export { renderFromTags, acceptedPageState } from "./save-projection.js";
|
|
18
18
|
export { blocksFromYValue } from "./ybind/decode.js";
|
|
19
19
|
export { createYPageBinding } from "./ybind/binding.js";
|
|
20
20
|
export { yValueOf } from "./ybind/provider.js";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { schema } from "./schema.js";
|
|
2
|
+
import { orderedIds } from "./model.js";
|
|
3
|
+
|
|
4
|
+
// The tables a chart can be drawn from: a top-level table with a labels column
|
|
5
|
+
// and at least one more to plot. The insert menu reads this without the chart module itself, which only
|
|
6
|
+
// a document that takes a chart loads.
|
|
7
|
+
export function chartTables(doc) {
|
|
8
|
+
const tables = [];
|
|
9
|
+
doc.forEach((node) => { if (node.type === schema.nodes.table && orderedIds(node.attrs.cols).length > 1) tables.push(node); });
|
|
10
|
+
return tables;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// A table's name for a person: the heading before it with no other table in
|
|
14
|
+
// between, else its place among the tables, so a chart and the picker name it
|
|
15
|
+
// without a stored title.
|
|
16
|
+
export function tableName(doc, tableId) {
|
|
17
|
+
let name = "";
|
|
18
|
+
let count = 0;
|
|
19
|
+
let found = null;
|
|
20
|
+
doc.forEach((node) => {
|
|
21
|
+
if (found !== null) return;
|
|
22
|
+
if (node.type === schema.nodes.heading) name = node.textContent;
|
|
23
|
+
if (node.type !== schema.nodes.table) return;
|
|
24
|
+
count += 1;
|
|
25
|
+
if (node.attrs.id === tableId) found = name || `Table ${count}`;
|
|
26
|
+
name = "";
|
|
27
|
+
});
|
|
28
|
+
return found;
|
|
29
|
+
}
|