@panphora/clayjs 1.17.0 → 1.18.1
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 +72474 -62090
- package/dist/m/attrs/{save-freeze-MYNVXREN.js → save-freeze-LWGF6XUN.js} +1 -1
- package/dist/m/c-2GRUM77Q.js +30 -0
- package/dist/m/c-2KIEGNC4.js +1 -0
- package/dist/m/{c-AMSNPOCX.js → c-2KL3BD52.js} +1 -1
- 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-KAU6E43D.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-3XIRD4NU.js → c-5T6NZHNM.js} +1 -1
- package/dist/m/{c-74MGYWZF.js → c-5ZQV7KC4.js} +1 -1
- package/dist/m/{c-7OLLJPWP.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-Y5HBBIQ4.js → c-AMYEFA2E.js} +1 -1
- package/dist/m/c-AQYCG7QW.js +1 -0
- package/dist/m/c-ATKAOH23.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-VHM5XQHK.js → c-BIJALSRD.js} +1 -1
- package/dist/m/c-BJ7YQ5QZ.js +1 -0
- package/dist/m/{c-KIPQJX4B.js → c-BRLCTNMC.js} +1 -1
- package/dist/m/{c-VE6ZMYMC.js → c-BUAYFEV5.js} +1 -1
- package/dist/m/c-C6IPRG34.js +1 -0
- package/dist/m/{c-KU3ZFADW.js → c-CAS3NND4.js} +1 -1
- package/dist/m/{c-PS5ARVWR.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-QJ4OM3G6.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-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-TJ6WOJL3.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-WDC5GVKU.js → c-IVTRVENZ.js} +1 -1
- package/dist/m/c-JKZJIUIP.js +1 -0
- package/dist/m/{c-UDUUJPFZ.js → c-JNLX3RJB.js} +1 -1
- package/dist/m/c-K3ADYNLU.js +1 -0
- package/dist/m/c-KGHVFRR3.js +1 -0
- package/dist/m/{c-5QWQ7A5L.js → c-KJJPV77R.js} +1 -1
- package/dist/m/{c-CZUSOB7V.js → c-KNPDOMDY.js} +1 -1
- package/dist/m/{c-EZU56NQV.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-3RUU4TPX.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-5RJFTLSF.js → c-NEL7HQW3.js} +1 -1
- package/dist/m/{c-DCXOXBF3.js → c-NQJRVJ56.js} +1 -1
- 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-R3L7ZJGB.js → c-OPLUZR3A.js} +1 -1
- package/dist/m/{c-GSFIGKOP.js → c-OTMKN2OO.js} +1 -1
- package/dist/m/{c-6NC5I2TV.js → c-OYRZ7XG2.js} +1 -1
- package/dist/m/{c-EVCQ3BKA.js → c-P3OFYUMA.js} +1 -1
- 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-FRLHSY7E.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-JU3NK25H.js → c-R27DWQKX.js} +1 -1
- package/dist/m/{c-RSMOODDU.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-Q622NS2Y.js → c-S2U6NJU4.js} +1 -1
- package/dist/m/c-SPZPGD3R.js +1 -0
- package/dist/m/c-SW4YEG2D.js +8 -0
- package/dist/m/c-T637T7SN.js +1 -0
- package/dist/m/c-TJAXGIRV.js +1 -0
- package/dist/m/{c-RYUXUUBX.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-QICP2YR5.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-VILENZTD.js +1 -0
- package/dist/m/{c-HDDEEL77.js → c-VJYEVRYK.js} +1 -1
- package/dist/m/{c-SMBZG5X4.js → c-VR2BJ4AN.js} +1 -1
- 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-I2ZATQCD.js → c-X5TSXZYJ.js} +2 -2
- 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/core/{admin-attrs-QHOKPJ7W.js → admin-attrs-YY7T5FGU.js} +1 -1
- 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-FNXVEFNE.js → host-permission-6EVJGNPL.js} +1 -1
- package/dist/m/core/is-edit-mode-GCX6767E.js +1 -0
- package/dist/m/core/{persist-JFYRHMRJ.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/internals/{index-PVXGPUDA.js → index-TGLQINN3.js} +1 -1
- package/dist/m/loader-3BBNZZGM.js +1 -0
- package/dist/m/manifest-26C55578.js +1 -0
- package/dist/m/manifest-edit-4396A009.js +1 -0
- package/dist/m/manifest.json +2111 -1573
- package/dist/m/page/{editor-NNJA4OKD.js → editor-6LRB3GE4.js} +123 -21
- 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-RM5IR6AO.js → demo-OYO5GCAO.js} +1 -1
- 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-SGPJKANK.js → people-JCHVPF7P.js} +1 -1
- package/dist/m/plugins/quickcrop-BQ5YYFCH.js +26 -0
- package/dist/m/plugins/{richclay-NRQDSWX6.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-WLYKK6TL.js → upload-NHGJXZK2.js} +1 -1
- 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-4N6GYAF6.js → wire-VBWXEXU2.js} +1 -1
- 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 +1367 -930
- package/dist/page/themes/light-1.css +8 -7
- package/dist/server/core.cjs +1440 -288
- 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/conflict-notice-ui.js +4 -7
- package/src/core/download.js +2 -2
- package/src/core/host-meta.js +38 -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 +106 -31
- 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 +170 -39
- 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/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 +89 -27
- package/src/page/boot-pack.js +1 -1
- package/src/page/chart-tables.js +21 -3
- package/src/page/chart.js +406 -63
- package/src/page/checklist.js +10 -135
- package/src/page/checkpoint-proof.js +7 -1
- package/src/page/chrome.js +250 -51
- package/src/page/clipboard-shape.js +126 -0
- package/src/page/drag.js +33 -3
- package/src/page/editor.js +136 -25
- 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/checklist.js +428 -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/registry.js +18 -0
- package/src/page/features/table.js +373 -83
- 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 +25 -1
- package/src/page/format-gate.js +68 -18
- package/src/page/format-host.js +17 -0
- package/src/page/format-native-commands.js +21 -5
- package/src/page/image-actions.js +64 -0
- package/src/page/import-markdown.js +262 -0
- package/src/page/items.js +135 -17
- package/src/page/markdown.js +6 -2
- package/src/page/media.js +35 -119
- package/src/page/placeholder.js +14 -1
- package/src/page/projection.js +98 -10
- 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 +28 -0
- package/src/page/save-states.js +13 -3
- package/src/page/schema.js +19 -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/light-1.css +8 -7
- 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 +38 -12
- package/src/page/view.js +13 -0
- package/src/page/ybind/binding.js +88 -5
- 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 +1 -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 +113 -17
- package/src/page/ybind/recovery-proof.js +32 -9
- package/src/page/ybind/recovery-replay.js +558 -15
- 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 +89 -14
- 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 +249 -44
- 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 +5 -3
- 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/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 +11 -6
- 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/c-2SPVQSHC.js +0 -1
- package/dist/m/c-336SGU5W.js +0 -1
- package/dist/m/c-3H6BZDNJ.js +0 -6
- package/dist/m/c-4DFEJ2PO.js +0 -3
- package/dist/m/c-56QRZTZH.js +0 -1
- package/dist/m/c-5J4E7O4Y.js +0 -4
- package/dist/m/c-5LKDWQTL.js +0 -19
- package/dist/m/c-5V3MOVJT.js +0 -1
- package/dist/m/c-6AZOGAPE.js +0 -1
- package/dist/m/c-6CRUUXOX.js +0 -5
- package/dist/m/c-6HMB24EV.js +0 -1
- package/dist/m/c-6KEVEQ7L.js +0 -1
- package/dist/m/c-A3E3NIMC.js +0 -1
- package/dist/m/c-BQ6LOBEE.js +0 -1
- package/dist/m/c-BTDI4Y23.js +0 -1
- package/dist/m/c-CJ3A7ZKE.js +0 -1
- package/dist/m/c-CQHPGKX2.js +0 -1
- package/dist/m/c-DFS4XZJV.js +0 -2
- package/dist/m/c-DNENWY4O.js +0 -1
- package/dist/m/c-E4LIR5X5.js +0 -1
- package/dist/m/c-FDNHHZY5.js +0 -1
- package/dist/m/c-FROJUZMV.js +0 -1
- package/dist/m/c-G2JPKCTP.js +0 -1
- package/dist/m/c-GB6TU7WV.js +0 -1
- package/dist/m/c-GFJJEBTU.js +0 -1
- package/dist/m/c-GJAEGGXY.js +0 -1
- package/dist/m/c-GOWBDM6J.js +0 -1
- package/dist/m/c-HFKUVACH.js +0 -1
- package/dist/m/c-HHDFCNHV.js +0 -1
- package/dist/m/c-IEM4NTCS.js +0 -1
- package/dist/m/c-JDCX26UP.js +0 -25
- package/dist/m/c-KGVGROZT.js +0 -1
- package/dist/m/c-KQ6TYJAP.js +0 -135
- package/dist/m/c-LFPHCXY3.js +0 -1
- package/dist/m/c-LRPUO2MX.js +0 -1
- package/dist/m/c-LWLBHLVC.js +0 -3
- package/dist/m/c-M2L47S2X.js +0 -7
- package/dist/m/c-MFP2ZWD4.js +0 -1
- package/dist/m/c-MKSQ4Y57.js +0 -1
- package/dist/m/c-NUFFJVVJ.js +0 -1
- package/dist/m/c-NUHSPT5P.js +0 -1
- package/dist/m/c-O72HVYSA.js +0 -1
- package/dist/m/c-OIBUTDXI.js +0 -1
- package/dist/m/c-OW5QIGG3.js +0 -1
- package/dist/m/c-PGRCK73F.js +0 -1
- package/dist/m/c-Q7NQD65V.js +0 -1
- package/dist/m/c-QH63LQOS.js +0 -1
- package/dist/m/c-R7IWVINQ.js +0 -1
- package/dist/m/c-RM7J7BV2.js +0 -1
- package/dist/m/c-S4ZEH46B.js +0 -9
- package/dist/m/c-SDAXDM2D.js +0 -1
- package/dist/m/c-SMGU7RT3.js +0 -235
- package/dist/m/c-SPIORRYS.js +0 -1
- package/dist/m/c-SWLRT66R.js +0 -1
- package/dist/m/c-TCJTVAFN.js +0 -1
- package/dist/m/c-TQEMVJCS.js +0 -1
- package/dist/m/c-TYLXX4NF.js +0 -21
- package/dist/m/c-U62OB4BT.js +0 -1
- package/dist/m/c-U6YWUAR3.js +0 -8
- package/dist/m/c-UDCSU5G5.js +0 -2
- package/dist/m/c-VI5RMSVY.js +0 -1
- package/dist/m/c-VRZN56XY.js +0 -1
- package/dist/m/c-W5MCHEGA.js +0 -1
- package/dist/m/c-WNYBLIOZ.js +0 -1
- package/dist/m/c-WWXIDH4O.js +0 -28
- package/dist/m/c-XCNTK76U.js +0 -1
- package/dist/m/c-XMS6DPBR.js +0 -1
- package/dist/m/c-ZUCOKOHT.js +0 -1
- package/dist/m/c-ZVPVXTJF.js +0 -4
- package/dist/m/c-ZVRKXKM7.js +0 -1
- package/dist/m/core/autosave-HRYGUWV6.js +0 -1
- package/dist/m/core/conflict-notice-6MROJN2L.js +0 -1
- package/dist/m/core/is-edit-mode-KTWA3O5N.js +0 -1
- package/dist/m/core/recovery-FLTCC2OC.js +0 -1
- package/dist/m/core/save-HQZ4S667.js +0 -1
- package/dist/m/core/save-core-KGQWFUNH.js +0 -1
- package/dist/m/core/snapshot-EGQZNT45.js +0 -1
- package/dist/m/core/unsaved-warning-IDJLD66H.js +0 -1
- package/dist/m/loader-S4I7GKXR.js +0 -1
- package/dist/m/manifest-4C419D67.js +0 -1
- package/dist/m/manifest-edit-B077F288.js +0 -1
- package/dist/m/plugins/ai-edit-QN4PMMNL.js +0 -6
- package/dist/m/plugins/indicator-URDBBOQO.js +0 -1
- package/dist/m/plugins/live-HFWD4OIH.js +0 -1
- package/dist/m/plugins/menu-3HIEQSI6.js +0 -138
- package/dist/m/plugins/page-JOKB6XPR.js +0 -2
- package/dist/m/plugins/page-view-NXOJHNW6.js +0 -1
- package/dist/m/plugins/quickcrop-QNY3PKLD.js +0 -26
- package/dist/m/plugins/sortable-GWT4PWDV.js +0 -1
- package/dist/m/plugins/source-4ZRSAIYM.js +0 -1
- package/dist/m/plugins/undo-VDA5P7FH.js +0 -1
- package/dist/m/plugins/upgrade-W7FG5VFG.js +0 -1
- package/dist/m/plugins/visitor-drafts-LIDY7NH6.js +0 -21
- package/dist/m/plugins/visitor-drafts-owner-ZXCKBZE7.js +0 -1
- package/dist/m/reader-core-DXYCURFF.js +0 -68
- package/dist/m/route/route-KOCZSEGN.js +0 -1
- package/dist/m/sync/live-sync-J7VMYTKS.js +0 -1
- package/dist/m/ui/index-3JLVI27O.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-NRQDSWX6.js.LEGAL.txt → richclay-KLGETK77.js.LEGAL.txt} +0 -0
package/src/page/table-paste.js
CHANGED
|
@@ -33,7 +33,9 @@ function textGrid(text) {
|
|
|
33
33
|
export function gridFromClipboard(html, text, doc = globalThis.document) {
|
|
34
34
|
let found = null;
|
|
35
35
|
try { found = htmlGrid(html, doc); } catch { found = null; }
|
|
36
|
-
|
|
36
|
+
// An HTML table with other blocks around it is a document, not a sheet: its tab-separated
|
|
37
|
+
// text is no grid either, and the editor's own paste keeps every block.
|
|
38
|
+
if (!found && !/<table[\s>]/i.test(html || "")) {
|
|
37
39
|
try { found = textGrid(text); } catch { found = null; }
|
|
38
40
|
}
|
|
39
41
|
if (!found || !found.grid.length) return null;
|
package/src/page/table-style.js
CHANGED
|
@@ -9,11 +9,11 @@ export const TABLE_CSS = `
|
|
|
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
11
|
.page-table-resize:hover, .page-table-resize:active, .page-table-resize:focus-visible { background: var(--page-accent); opacity: 0.4; }
|
|
12
|
-
.page-table-add-row, .page-table-add-col { position: absolute; z-index: 1;
|
|
13
|
-
.page-table-add-row { left: 0; right: 0; top: 100%; height:
|
|
14
|
-
.page-table-add-col { top: 0; bottom: 0; left: 100%; width:
|
|
12
|
+
.page-table-add-row, .page-table-add-col { position: absolute; z-index: 1; padding: 0; background: var(--page-chrome-bg-moved); color: var(--page-ink-soft); display: flex; align-items: center; justify-content: center; font: inherit; font-size: 14px; line-height: 1; cursor: pointer; opacity: 0; transition: opacity 120ms; }
|
|
13
|
+
.page-table-add-row { left: 0; right: 0; top: 100%; height: 16px; border-radius: 0 0 6px 6px; border: 1px solid var(--page-chrome-line-moved); border-top: 0; padding-bottom: 2px; box-sizing: border-box; }
|
|
14
|
+
.page-table-add-col { top: 0; bottom: 0; left: 100%; width: 16px; border-radius: 0 6px 6px 0; border: 1px solid var(--page-chrome-line-moved); border-left: 0; box-sizing: border-box; }
|
|
15
15
|
.page-table:hover > .page-table-add-row, .page-table:hover > .page-table-add-col, .page-table-add-row:focus-visible, .page-table-add-col:focus-visible { opacity: 1; }
|
|
16
|
-
.page-table-add-row:hover, .page-table-add-col:hover { background: var(--page-
|
|
16
|
+
.page-table-add-row:hover, .page-table-add-col:hover { background: var(--page-pop-hover); color: var(--page-ink); }
|
|
17
17
|
.page-table-date { position: absolute; inset-inline-start: 0; top: 100%; z-index: 3; font: inherit; color: var(--page-pop-ink); background: var(--page-pop-bg); border: 1px solid var(--page-pop-line); border-radius: 6px; padding: 4px 6px; box-shadow: var(--page-pop-shadow); }
|
|
18
18
|
@media (max-width: 560px) {
|
|
19
19
|
.page-table-date { min-height: 44px; }
|
package/src/page/table.js
CHANGED
|
@@ -213,6 +213,33 @@ export const moveColumn = (delta) => (st, dispatch) => changeTable(st, dispatch,
|
|
|
213
213
|
export const MIN_WIDTH = 48, MAX_WIDTH = 1200, DEFAULT_WIDTH = 160;
|
|
214
214
|
const widthOf = (value) => (Number.isFinite(value) && value > 0 ? Math.round(Math.min(MAX_WIDTH, Math.max(MIN_WIDTH, value))) : null);
|
|
215
215
|
|
|
216
|
+
// Clears every stored width, so the table fills the page again.
|
|
217
|
+
export const clearColumnWidths = (colId) => (st, dispatch) => changeTable(st, dispatch, (table) => {
|
|
218
|
+
const ids = columns(table);
|
|
219
|
+
if (!ids.some((id) => table.attrs.cols[id].width)) return null;
|
|
220
|
+
const cols = {};
|
|
221
|
+
for (const id of ids) {
|
|
222
|
+
const { width: _old, ...rest } = table.attrs.cols[id];
|
|
223
|
+
cols[id] = rest;
|
|
224
|
+
}
|
|
225
|
+
return { table: copyTable(table, { cols }, table.content), cell: Math.max(0, ids.indexOf(colId)) };
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Several widths in one step: the first width set on a table that fills the page
|
|
229
|
+
// also fixes every other column at the width it is drawn at, so none of them jumps.
|
|
230
|
+
export const setColumnWidths = (widths, colId) => (st, dispatch) => changeTable(st, dispatch, (table) => {
|
|
231
|
+
const cols = { ...table.attrs.cols };
|
|
232
|
+
let changed = false;
|
|
233
|
+
for (const [id, width] of Object.entries(widths)) {
|
|
234
|
+
const next = widthOf(width);
|
|
235
|
+
if (!cols[id] || next === null || cols[id].width === next) continue;
|
|
236
|
+
cols[id] = { ...cols[id], width: next };
|
|
237
|
+
changed = true;
|
|
238
|
+
}
|
|
239
|
+
if (!changed) return null;
|
|
240
|
+
return { table: copyTable(table, { cols }, table.content), cell: columns(table).indexOf(colId) };
|
|
241
|
+
});
|
|
242
|
+
|
|
216
243
|
export const setColumnWidth = (colId, width) => (st, dispatch) => changeTable(st, dispatch, (table) => {
|
|
217
244
|
const col = table.attrs.cols[colId];
|
|
218
245
|
if (!col) return null;
|
|
@@ -295,9 +322,9 @@ export function pasteTable(view, event) {
|
|
|
295
322
|
if (found.width * found.height < 2) return false;
|
|
296
323
|
return pasteGrid(found.grid)(st, view.dispatch);
|
|
297
324
|
}
|
|
298
|
-
if (found.width * found.height < 2) return false;
|
|
325
|
+
if (found.width * found.height < 2 || found.own) return false;
|
|
299
326
|
if (found.height < 2 && !/<table[\s>]/i.test(data.getData("text/html"))) return false;
|
|
300
|
-
const table = tableFromGrid(found.grid, { header:
|
|
327
|
+
const table = tableFromGrid(found.grid, { header: found.height > 1 });
|
|
301
328
|
if (!table) return false;
|
|
302
329
|
if (tableSize(table) > TABLE_IMPORT_LIMIT) {
|
|
303
330
|
toast("This paste is too large for one table.", "error");
|
|
@@ -317,10 +344,25 @@ export function pasteTable(view, event) {
|
|
|
317
344
|
|
|
318
345
|
export const tableKeys = keymap.keymap({ Tab: nextCell, "Shift-Tab": prevCell, Enter: cellBelow, "Mod-Enter": addRow(true) });
|
|
319
346
|
|
|
347
|
+
function caretInCell(view, event) {
|
|
348
|
+
const cell = cellViews.get(event.target);
|
|
349
|
+
const pos = cell?.getPos();
|
|
350
|
+
if (pos == null || event.button || event.shiftKey || !view.editable) return false;
|
|
351
|
+
event.preventDefault();
|
|
352
|
+
const start = event.clientX < cell.contentDOM.getBoundingClientRect().left;
|
|
353
|
+
view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, pos + 1 + (start ? 0 : cell.node.content.size))));
|
|
354
|
+
view.focus();
|
|
355
|
+
cell.openDate();
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
358
|
+
|
|
320
359
|
export function tablePlugin() {
|
|
321
360
|
return new Plugin({
|
|
322
361
|
props: {
|
|
323
362
|
handlePaste: pasteTable,
|
|
363
|
+
handleDOMEvents: {
|
|
364
|
+
mousedown: caretInCell,
|
|
365
|
+
},
|
|
324
366
|
handleClickOn(view, _pos, node, nodePos, event, direct) {
|
|
325
367
|
if (node.type !== N.table_cell || !direct || event.button) return false;
|
|
326
368
|
const desc = view.nodeDOM(nodePos);
|
|
@@ -215,12 +215,12 @@
|
|
|
215
215
|
--page-code-bg: rgba(35, 34, 31, 0.045);
|
|
216
216
|
--page-code-ink: #23221F;
|
|
217
217
|
|
|
218
|
-
--page-chrome-ink-rest: rgba(35, 34, 31, 0.
|
|
219
|
-
--page-chrome-ink-moved: rgba(35, 34, 31, 0.
|
|
220
|
-
--page-chrome-bg-rest: rgba(35, 34, 31, 0.
|
|
221
|
-
--page-chrome-bg-moved: rgba(35, 34, 31, 0.
|
|
222
|
-
--page-chrome-line-rest: rgba(35, 34, 31, 0.
|
|
223
|
-
--page-chrome-line-moved: rgba(35, 34, 31, 0.
|
|
218
|
+
--page-chrome-ink-rest: rgba(35, 34, 31, 0.42);
|
|
219
|
+
--page-chrome-ink-moved: rgba(35, 34, 31, 0.62);
|
|
220
|
+
--page-chrome-bg-rest: rgba(35, 34, 31, 0.035);
|
|
221
|
+
--page-chrome-bg-moved: rgba(35, 34, 31, 0.06);
|
|
222
|
+
--page-chrome-line-rest: rgba(35, 34, 31, 0.22);
|
|
223
|
+
--page-chrome-line-moved: rgba(35, 34, 31, 0.36);
|
|
224
224
|
--page-chrome-shadow-rest: none;
|
|
225
225
|
--page-chrome-shadow-moved: none;
|
|
226
226
|
--page-chrome-radius: 7px;
|
|
@@ -307,7 +307,8 @@ article[data-page] figure[data-type="chart"] > svg { display: block; width: 100%
|
|
|
307
307
|
height: 15px;
|
|
308
308
|
}
|
|
309
309
|
|
|
310
|
-
.page-shell .page-dock .page-tool-turn
|
|
310
|
+
.page-shell .page-dock .page-tool-turn,
|
|
311
|
+
.page-shell .page-bubble .page-tool-turn {
|
|
311
312
|
width: auto;
|
|
312
313
|
gap: 4px;
|
|
313
314
|
padding: 0 8px;
|
|
@@ -54,12 +54,12 @@
|
|
|
54
54
|
--page-code-bg: rgba(35, 34, 31, 0.045);
|
|
55
55
|
--page-code-ink: #23221F;
|
|
56
56
|
|
|
57
|
-
--page-chrome-ink-rest: rgba(35, 34, 31, 0.
|
|
58
|
-
--page-chrome-ink-moved: rgba(35, 34, 31, 0.
|
|
59
|
-
--page-chrome-bg-rest: rgba(35, 34, 31, 0.
|
|
60
|
-
--page-chrome-bg-moved: rgba(35, 34, 31, 0.
|
|
61
|
-
--page-chrome-line-rest: rgba(35, 34, 31, 0.
|
|
62
|
-
--page-chrome-line-moved: rgba(35, 34, 31, 0.
|
|
57
|
+
--page-chrome-ink-rest: rgba(35, 34, 31, 0.42);
|
|
58
|
+
--page-chrome-ink-moved: rgba(35, 34, 31, 0.62);
|
|
59
|
+
--page-chrome-bg-rest: rgba(35, 34, 31, 0.035);
|
|
60
|
+
--page-chrome-bg-moved: rgba(35, 34, 31, 0.06);
|
|
61
|
+
--page-chrome-line-rest: rgba(35, 34, 31, 0.22);
|
|
62
|
+
--page-chrome-line-moved: rgba(35, 34, 31, 0.36);
|
|
63
63
|
--page-chrome-shadow-rest: none;
|
|
64
64
|
--page-chrome-shadow-moved: none;
|
|
65
65
|
--page-chrome-radius: 7px;
|
|
@@ -146,7 +146,8 @@ article[data-page] figure[data-type="chart"] > svg { display: block; width: 100%
|
|
|
146
146
|
height: 15px;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
.page-shell .page-dock .page-tool-turn
|
|
149
|
+
.page-shell .page-dock .page-tool-turn,
|
|
150
|
+
.page-shell .page-bubble .page-tool-turn {
|
|
150
151
|
width: auto;
|
|
151
152
|
gap: 4px;
|
|
152
153
|
padding: 0 8px;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// The saved table of contents' links: decode the anchor a link names, and reveal
|
|
2
|
+
// the block it points at in a reader. Loaded the first time a reader follows one.
|
|
3
|
+
const TOC_ANCHOR = "page-block-";
|
|
4
|
+
|
|
5
|
+
const fromB64url = (text) => {
|
|
6
|
+
const bin = atob(String(text).replace(/-/g, "+").replace(/_/g, "/"));
|
|
7
|
+
return new TextDecoder().decode(Uint8Array.from(bin, (ch) => ch.charCodeAt(0)));
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function idFromHref(href) {
|
|
11
|
+
const hash = String(href ?? "").replace(/^#/, "");
|
|
12
|
+
if (!hash) return null;
|
|
13
|
+
try {
|
|
14
|
+
return hash.startsWith(TOC_ANCHOR) ? fromB64url(hash.slice(TOC_ANCHOR.length)) : decodeURIComponent(hash);
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// A table of contents link in a saved page shows its target and opens every collapsed
|
|
21
|
+
// body above it: reading only, so nothing is saved, no history moves and no peer is
|
|
22
|
+
// told. A link whose block is gone, or to anywhere else, changes nothing.
|
|
23
|
+
export function followTocLink(article, href) {
|
|
24
|
+
const id = idFromHref(href);
|
|
25
|
+
if (id === null) return null;
|
|
26
|
+
const target = [...article.querySelectorAll("[data-id]")].find((el) => el.getAttribute("data-id") === id) ?? null;
|
|
27
|
+
if (!target) return null;
|
|
28
|
+
for (let el = target.parentElement; el && el !== article; el = el.parentElement) if (el.tagName === "DETAILS") el.open = true;
|
|
29
|
+
target.scrollIntoView?.({ block: "start" });
|
|
30
|
+
return target;
|
|
31
|
+
}
|
package/src/page/toc.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// The table of contents: the headings a document has and the anchors that link to them.
|
|
2
|
+
// The saved renderer and the editor's node view ask one helper; a reader's reveal and
|
|
3
|
+
// the anchor decoder live in toc-link.js, which nothing but a followed link loads.
|
|
4
|
+
export { TOC_ANCHOR, TOC_LABEL, blockAnchor, tocHtml, tocEntries } from "./projection.js";
|
|
5
|
+
export { idFromHref } from "./toc-link.js";
|
package/src/page/view-hooks.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { state } from "../vendor/prosemirror.vendor.js";
|
|
2
2
|
|
|
3
|
-
// The update hooks a loaded view part registers for its editor
|
|
4
|
-
// below calls
|
|
5
|
-
//
|
|
6
|
-
// removes it on dispose.
|
|
3
|
+
// The update hooks and decorations a loaded view part registers for its editor
|
|
4
|
+
// view. The plugin below calls the hooks on every document change and collects the
|
|
5
|
+
// decorations on every draw, so a part keeps its blocks fresh without the editor
|
|
6
|
+
// importing it: the part adds its hook when it installs and removes it on dispose.
|
|
7
7
|
export const viewHooks = new WeakMap();
|
|
8
8
|
|
|
9
9
|
// The feature loader of each mounted editor, so an insert path can ask for a
|
|
@@ -18,15 +18,41 @@ export function addViewHook(view, hook) {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export function viewHookPlugin() {
|
|
21
|
+
let editorView = null;
|
|
22
|
+
const mounted = new WeakMap();
|
|
21
23
|
return new state.Plugin({
|
|
22
|
-
view: (view) =>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
view: (view) => {
|
|
25
|
+
editorView = view;
|
|
26
|
+
mounted.set(view, (mounted.get(view) ?? 0) + 1);
|
|
27
|
+
return {
|
|
28
|
+
update: (next) => { for (const hook of viewHooks.get(next) ?? []) hook.update?.(next); },
|
|
29
|
+
destroy: () => {
|
|
30
|
+
mounted.set(view, mounted.get(view) - 1);
|
|
31
|
+
if (editorView === view) editorView = null;
|
|
32
|
+
// A reconfigure destroys this plugin view and mounts a new one for the same editor in
|
|
33
|
+
// the same task; only an editor that stays without one is really going away.
|
|
34
|
+
queueMicrotask(() => {
|
|
35
|
+
if (mounted.get(view)) return;
|
|
36
|
+
const hooks = viewHooks.get(view);
|
|
37
|
+
if (!hooks) return;
|
|
38
|
+
for (const hook of hooks) hook.destroy?.(view);
|
|
39
|
+
hooks.clear();
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
props: {
|
|
45
|
+
decorations(st) {
|
|
46
|
+
const hooks = editorView ? viewHooks.get(editorView) : null;
|
|
47
|
+
if (!hooks) return null;
|
|
48
|
+
let found = null;
|
|
49
|
+
for (const hook of hooks) {
|
|
50
|
+
const set = hook.decorations?.(st);
|
|
51
|
+
if (!set) continue;
|
|
52
|
+
found = found ? found.add(st.doc, set.find()) : set;
|
|
53
|
+
}
|
|
54
|
+
return found;
|
|
29
55
|
},
|
|
30
|
-
}
|
|
56
|
+
},
|
|
31
57
|
});
|
|
32
58
|
}
|
package/src/page/view.js
CHANGED
|
@@ -16,6 +16,10 @@ const LINEAGE = ["live-at", "live-by"];
|
|
|
16
16
|
|
|
17
17
|
export { applyPreparedArticle, prepareSavedArticle };
|
|
18
18
|
|
|
19
|
+
// A table of contents link in a saved page reveals its target. The reveal code and
|
|
20
|
+
// the anchor decoder load the first time somebody follows one, never with the page.
|
|
21
|
+
export const followTocLink = (article, href) => import("./toc-link.js").then((m) => m.followTocLink(article, href));
|
|
22
|
+
|
|
19
23
|
// The stamp of the file this reader accepted, recorded where a save reads it. The
|
|
20
24
|
// stamp module is the write path's own lazy chunk: a reader paints without it, and
|
|
21
25
|
// a save loads the one copy both paths then share.
|
|
@@ -262,6 +266,15 @@ function createReader({ doc, article, represented = null, feed = null, documentU
|
|
|
262
266
|
doc.addEventListener("toggle", onToggle, true);
|
|
263
267
|
listeners.push(["toggle", onToggle, true]);
|
|
264
268
|
|
|
269
|
+
const onTocLink = (event) => {
|
|
270
|
+
const link = event.target.closest?.('a[href^="#page-block-"], a[href^="#"]');
|
|
271
|
+
if (!link || !article.contains(link) || !link.closest('nav[aria-label="Table of contents"]')) return;
|
|
272
|
+
event.preventDefault();
|
|
273
|
+
followTocLink(article, link.getAttribute("href"));
|
|
274
|
+
};
|
|
275
|
+
doc.addEventListener("click", onTocLink);
|
|
276
|
+
listeners.push(["click", onTocLink]);
|
|
277
|
+
|
|
265
278
|
if (represented) {
|
|
266
279
|
const prepared = prepareSavedArticle(represented.bytes, doc);
|
|
267
280
|
if (!prepared.ok) throw new Error(`clayjs: the saved file is not a readable page (${prepared.reason})`);
|
|
@@ -2,31 +2,43 @@ import * as Y from "../../vendor/yjs.vendor.js";
|
|
|
2
2
|
import { NET, createPageDoc, walk, docOf } from "./core.js";
|
|
3
3
|
import { createBridge, keepViewPos } from "./bridge.js";
|
|
4
4
|
import { createYProvider, entriesOf, dec } from "./provider.js";
|
|
5
|
+
import { createPageFileDebt } from "./file-debt.js";
|
|
5
6
|
|
|
6
|
-
export function createYPageBinding({ store, ydoc = new Y.Doc(), onNotice = () => {}, ownedTokens = [], authorToken = null, setTimer = setTimeout, clearTimer = clearTimeout, compact, captureTimeout = 500, checkpointWithin = () => {}, requestCheckpoint = null, registerUnsavedState = null, onStopped = () => {}, journal = null }) {
|
|
7
|
+
export function createYPageBinding({ store, ydoc = new Y.Doc(), onNotice = () => {}, ownedTokens = [], authorToken = null, setTimer = setTimeout, clearTimer = clearTimeout, compact, captureTimeout = 500, checkpointWithin = () => {}, requestCheckpoint = null, requestExitCheckpoint = null, registerUnsavedState = null, onStopped = () => {}, journal = null, exitClosed = () => false, stats = { groups: 0, mismatch: 0, renders: 0, first: null } }) {
|
|
7
8
|
for (const [, v] of entriesOf(store.value.y)) Y.applyUpdateV2(ydoc, dec(v), NET);
|
|
8
9
|
const pd = createPageDoc(ydoc);
|
|
9
10
|
// The journal is installed before the provider, because the provider is what sees an
|
|
10
11
|
// update: nothing can reach the document without passing it first. Its own code lives
|
|
11
12
|
// with the recovery channel and is only loaded when a page has one to journal into.
|
|
12
13
|
const pageJournal = journal || null;
|
|
14
|
+
// The input this tab owes the file, recorded before the provider because the provider is
|
|
15
|
+
// what sees an update. The notification it fires through is attached once the binding's
|
|
16
|
+
// own registration exists, so an update that arrives while this function is still
|
|
17
|
+
// building cannot reach an uninitialized name.
|
|
18
|
+
let notifyDebt = () => {};
|
|
19
|
+
const debt = createPageFileDebt({ changed: () => notifyDebt() });
|
|
13
20
|
const provider = createYProvider({
|
|
14
21
|
store,
|
|
15
22
|
ydoc,
|
|
16
23
|
setTimer,
|
|
17
24
|
clearTimer,
|
|
18
25
|
compact,
|
|
19
|
-
|
|
26
|
+
// A full or failed room stops offering at once, but the checkpoint of what it already
|
|
27
|
+
// admitted goes out before the page locks and holds every save.
|
|
28
|
+
onStopped: (reason) => {
|
|
29
|
+
if (reason !== "page-full" && reason !== "compaction-failed") { onStopped(reason); return; }
|
|
30
|
+
Promise.resolve(requestCheckpoint?.({ timeoutMs: 10_000 })).catch(() => {}).finally(() => onStopped(reason));
|
|
31
|
+
},
|
|
32
|
+
onLocalUpdate: debt.local,
|
|
20
33
|
journal: { local: (u) => pageJournal?.local(u), dependency: (u) => pageJournal?.dependency(u) },
|
|
21
34
|
});
|
|
22
|
-
const stats = { groups: 0, mismatch: 0, renders: 0, first: null };
|
|
23
35
|
const bridge = createBridge({ pd, onNotice, ownedTokens, authorToken, stats, captureTimeout });
|
|
24
36
|
const waiters = new Set();
|
|
25
37
|
let disposed = false;
|
|
26
38
|
let checksQueued = false;
|
|
27
39
|
const unsaved = registerUnsavedState?.({
|
|
28
40
|
id: "page:live",
|
|
29
|
-
isPending: () => store.pending.length > 0 || provider.reconcilePending || Boolean(pageJournal &&
|
|
41
|
+
isPending: () => (exitClosed() && debt.pending()) || store.pending.length > 0 || provider.pending || provider.reconcilePending || Boolean(pageJournal && pageJournal.pending() > (pageJournal.failure ? 1 : 0)),
|
|
30
42
|
flush,
|
|
31
43
|
});
|
|
32
44
|
const changed = () => {
|
|
@@ -38,6 +50,7 @@ export function createYPageBinding({ store, ydoc = new Y.Doc(), onNotice = () =>
|
|
|
38
50
|
if (!disposed) for (const waiter of [...waiters]) waiter.check();
|
|
39
51
|
});
|
|
40
52
|
};
|
|
53
|
+
notifyDebt = changed;
|
|
41
54
|
const offLocal = store.onLocal(() => { checkpointWithin(1500); changed(); });
|
|
42
55
|
const offRebase = store.onRebase(changed);
|
|
43
56
|
const offConfirm = store.onConfirm(() => {
|
|
@@ -48,8 +61,76 @@ export function createYPageBinding({ store, ydoc = new Y.Doc(), onNotice = () =>
|
|
|
48
61
|
// a write in flight, a write the store refused, or a room that has not confirmed.
|
|
49
62
|
if (pageJournal) pageJournal.onChange = changed;
|
|
50
63
|
|
|
51
|
-
|
|
64
|
+
// Everything the file or the room still owes: this tab's own input, a store op no
|
|
65
|
+
// answer has covered, a reconcile, a journal write still in flight.
|
|
66
|
+
const exitPending = () =>
|
|
67
|
+
debt.pending() || store.pending.length > 0 || provider.pending || provider.reconcilePending ||
|
|
68
|
+
Boolean(pageJournal && pageJournal.pending() > (pageJournal.failure ? 1 : 0));
|
|
69
|
+
|
|
70
|
+
// The exit's own flush, under the permit the barrier minted.
|
|
71
|
+
//
|
|
72
|
+
// A fast store's capture holds the room's value, so this tab's ops travel through the
|
|
73
|
+
// room first; a file store's capture holds its pending ops as they stand, so the
|
|
74
|
+
// checkpoint goes while they are still pending and their acceptance is what confirms
|
|
75
|
+
// them. The checkpoint is asked for only when this tab owes the file input: a tab
|
|
76
|
+
// holding nothing of its own leaves without making the room's writer save for it.
|
|
77
|
+
function flushExit({ permit, deadline, keepalive, signal, timeoutMs }) {
|
|
78
|
+
const end = Math.min(deadline ?? Infinity, Date.now() + timeoutMs);
|
|
79
|
+
const over = () => signal?.aborted || Date.now() >= end;
|
|
80
|
+
return new Promise((resolve) => {
|
|
81
|
+
let done = false, timer = null, wake = null;
|
|
82
|
+
const waiter = {
|
|
83
|
+
check() { wake?.(); },
|
|
84
|
+
finish(result) {
|
|
85
|
+
if (done) return;
|
|
86
|
+
done = true;
|
|
87
|
+
waiters.delete(waiter);
|
|
88
|
+
clearTimer(timer);
|
|
89
|
+
signal?.removeEventListener("abort", aborted);
|
|
90
|
+
resolve(result);
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
const aborted = () => waiter.finish({ ok: false, code: "timeout" });
|
|
94
|
+
const wait = (ms) => new Promise((woken) => {
|
|
95
|
+
const wakeNow = () => {
|
|
96
|
+
clearTimer(timer);
|
|
97
|
+
wake = null;
|
|
98
|
+
woken();
|
|
99
|
+
};
|
|
100
|
+
timer = setTimer(wakeNow, ms);
|
|
101
|
+
wake = wakeNow;
|
|
102
|
+
});
|
|
103
|
+
const run = async () => {
|
|
104
|
+
provider.settle();
|
|
105
|
+
if (debt.pending() && requestExitCheckpoint) {
|
|
106
|
+
const result = await requestExitCheckpoint({
|
|
107
|
+
permit,
|
|
108
|
+
deadline: end,
|
|
109
|
+
signal,
|
|
110
|
+
keepalive,
|
|
111
|
+
needsSave: () => debt.pending(),
|
|
112
|
+
});
|
|
113
|
+
if (done) return;
|
|
114
|
+
if (!result?.ok) {
|
|
115
|
+
waiter.finish(result?.ok === false ? result : { ok: false, code: "checkpoint-failed" });
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
while (!done) {
|
|
120
|
+
if (!exitPending()) { waiter.finish({ ok: true }); return; }
|
|
121
|
+
if (over()) { waiter.finish({ ok: false, code: "timeout" }); return; }
|
|
122
|
+
await wait(50);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
waiters.add(waiter);
|
|
126
|
+
signal?.addEventListener("abort", aborted, { once: true });
|
|
127
|
+
run().catch((error) => waiter.finish({ ok: false, code: "flush-failed", message: error?.message || String(error) }));
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function flush({ permit = null, deadline: exitDeadline = null, keepalive = false, signal = null, timeoutMs = 10_000 } = {}) {
|
|
52
132
|
if (disposed) return Promise.resolve({ ok: false, code: "disposed" });
|
|
133
|
+
if (permit) return flushExit({ permit, deadline: exitDeadline, keepalive, signal, timeoutMs });
|
|
53
134
|
return new Promise((resolve) => {
|
|
54
135
|
const deadline = Date.now() + timeoutMs;
|
|
55
136
|
let done = false, checking = false, checkpointing = false, timer = null;
|
|
@@ -96,6 +177,8 @@ export function createYPageBinding({ store, ydoc = new Y.Doc(), onNotice = () =>
|
|
|
96
177
|
return {
|
|
97
178
|
ydoc, pd, provider, bridge, stats, flush, awareness,
|
|
98
179
|
get journal() { return pageJournal; },
|
|
180
|
+
filePending: () => debt.pending(),
|
|
181
|
+
acceptFile: (state) => debt.accepted(state),
|
|
99
182
|
doc: () => keepViewPos(docOf(pd, walk(pd))),
|
|
100
183
|
attach: (view) => bridge.attach(view),
|
|
101
184
|
dispatch: (tr) => bridge.dispatch(tr),
|