@panphora/clayjs 1.23.0 → 1.24.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/blockeditor/themes/light-1.css +431 -0
- 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 +30285 -26613
- package/dist/m/c-277QP5ET.js +1 -0
- package/dist/m/c-2BLVA6IN.js +5 -0
- package/dist/m/c-2OJMOUPC.js +1 -0
- package/dist/m/c-2PVGJFI5.js +1 -0
- package/dist/m/{c-AYVGD6A6.js → c-3UW5EJ77.js} +1 -1
- package/dist/m/{c-T5NK2TVY.js → c-42ZNV7LI.js} +1 -1
- package/dist/m/{c-3TLG3OLG.js → c-46LJAZZJ.js} +1 -1
- package/dist/m/c-47IBJGPQ.js +1 -0
- package/dist/m/c-5FXEKU4Y.js +1 -0
- package/dist/m/c-5KXDKC5G.js +1 -0
- package/dist/m/{c-EUGJVHDD.js → c-5RZNFTWD.js} +1 -1
- package/dist/m/c-65LJU2H2.js +72 -0
- package/dist/m/{c-NQJRVJ56.js → c-6IJEVE6B.js} +1 -1
- package/dist/m/{c-NW54NHKE.js → c-6LEYVQJK.js} +1 -1
- package/dist/m/{c-GSRLXYWL.js → c-6Q6RGFBF.js} +1 -1
- package/dist/m/c-6RGEQNVV.js +1 -0
- package/dist/m/c-7CM4GMTS.js +6 -0
- package/dist/m/c-7NCWENHV.js +1 -0
- package/dist/m/c-7V6MGMX2.js +1 -0
- package/dist/m/{c-LKSL4AUJ.js → c-7WZSUTYP.js} +1 -1
- package/dist/m/c-A4L7APIU.js +1 -0
- package/dist/m/c-APGHGDZM.js +1 -0
- package/dist/m/c-AT7GLQGV.js +34 -0
- package/dist/m/{c-ZRXJD4G6.js → c-B7GOFGQR.js} +1 -1
- package/dist/m/{c-KDXIJEEF.js → c-BGN7RCTJ.js} +1 -1
- package/dist/m/c-BKM46LUJ.js +1 -0
- package/dist/m/c-BOMQIQ3V.js +1 -0
- package/dist/m/{c-62HZW5DH.js → c-C5AKJVRH.js} +1 -1
- package/dist/m/{c-BXYSDKAN.js → c-CJ7QYEWI.js} +1 -1
- package/dist/m/c-CTGRDT6E.js +1 -0
- package/dist/m/c-CV4T65JE.js +6 -0
- package/dist/m/c-CVSWLX3X.js +1 -0
- package/dist/m/c-CZHTXGJS.js +1 -0
- package/dist/m/c-D7NT5S4F.js +1 -0
- package/dist/m/c-DD26VXAP.js +1 -0
- package/dist/m/{c-ANNFZFLN.js → c-DDS23EY6.js} +1 -1
- package/dist/m/{c-ALDVFPWL.js → c-DFKBGSN2.js} +1 -1
- package/dist/m/c-DIKR7H57.js +147 -0
- package/dist/m/c-DXPOFLEJ.js +1 -0
- package/dist/m/c-EDE45NM7.js +1 -0
- package/dist/m/c-EILLN2H2.js +1 -0
- package/dist/m/c-EODTTNVA.js +1 -0
- package/dist/m/{c-G6COVIZB.js → c-ESK4S67I.js} +1 -1
- package/dist/m/c-FDWR3FL7.js +1 -0
- package/dist/m/{c-WQZTI5P2.js → c-FEC6LGFF.js} +1 -1
- package/dist/m/c-FLEIU6CG.js +1 -0
- package/dist/m/c-FQAQRXGK.js +1 -0
- package/dist/m/{c-W4JCVLAB.js → c-FSQXFG5T.js} +1 -1
- package/dist/m/c-FVPNX2GO.js +135 -0
- package/dist/m/c-FYDKYW6E.js +1 -0
- package/dist/m/c-GNI7WHKF.js +32 -0
- package/dist/m/c-GO635CRU.js +3 -0
- package/dist/m/c-H3FNLBHN.js +2 -0
- package/dist/m/c-HDVH3MVC.js +72 -0
- package/dist/m/c-HIX5H5L7.js +1 -0
- package/dist/m/c-HKSLOVU4.js +1 -0
- package/dist/m/{c-SGRIYOAJ.js → c-HL6BLJNA.js} +1 -1
- package/dist/m/c-HTLYXCUH.js +1 -0
- package/dist/m/{c-QIR5CAKM.js → c-IUL7PU4P.js} +1 -1
- package/dist/m/c-IXO7EI2Q.js +1 -0
- package/dist/m/{c-W5E5P2TZ.js → c-JQF2EUCG.js} +1 -1
- package/dist/m/{c-NEL7HQW3.js → c-JWDCQL6J.js} +1 -1
- package/dist/m/c-KQKKIVLW.js +20 -0
- package/dist/m/c-LATNQ6Q5.js +1 -0
- package/dist/m/c-LD6UVV5R.js +1 -0
- package/dist/m/c-LS7IVQVW.js +1 -0
- package/dist/m/{c-JCOQVZYS.js → c-LSVN3OLG.js} +1 -1
- package/dist/m/{c-JDZDF2QM.js → c-LTSPHVAK.js} +1 -1
- package/dist/m/c-MFOSMAVM.js +3 -0
- package/dist/m/c-MJ7GVE46.js +1 -0
- package/dist/m/c-MP6S4AZU.js +6 -0
- package/dist/m/c-MQKSKQHG.js +2 -0
- package/dist/m/{c-UHUNXWKN.js → c-MQYEDF3Q.js} +1 -1
- package/dist/m/{c-IHUWUKIU.js → c-MR75YPRT.js} +1 -1
- package/dist/m/c-ND3Q2G2I.js +1 -0
- package/dist/m/c-NEQRFC4O.js +1 -0
- package/dist/m/{c-5FKRZNJV.js → c-NFQFV7OP.js} +1 -1
- package/dist/m/c-NHXOBD6A.js +1 -0
- package/dist/m/{c-QIKT6SKM.js → c-NICICT4P.js} +1 -1
- package/dist/m/c-NQAPWM7O.js +1 -0
- package/dist/m/{c-QUGCKMWF.js → c-NVU3DORS.js} +1 -1
- package/dist/m/{c-LWIDDWAR.js → c-OCYG4NBQ.js} +22 -22
- package/dist/m/c-OH2FPYSY.js +19 -0
- package/dist/m/c-OYHI67B6.js +1 -0
- package/dist/m/{c-R2XUODVY.js → c-OYW5MFPZ.js} +1 -1
- package/dist/m/{c-5B4YBZXC.js → c-P2HKMJAW.js} +1 -1
- package/dist/m/{c-TSBVMWAH.js → c-PCNJETUA.js} +1 -1
- package/dist/m/c-PDBNCJCT.js +1 -0
- package/dist/m/c-PGSBXHUE.js +1 -0
- package/dist/m/{c-5TIZ2I64.js → c-PYG2NGWU.js} +1 -1
- package/dist/m/c-Q26XHBLQ.js +1 -0
- package/dist/m/c-Q6BG3ZLO.js +1 -0
- package/dist/m/c-QENKN7QI.js +1 -0
- package/dist/m/c-QQFHEODI.js +1 -0
- package/dist/m/c-QTEUO2K6.js +1 -0
- package/dist/m/c-R23UHMXG.js +1 -0
- package/dist/m/c-RETTCOWO.js +10 -0
- package/dist/m/c-SE3SIY7Y.js +7 -0
- package/dist/m/{c-XX75FFNL.js → c-SGGGCIVD.js} +1 -1
- package/dist/m/c-SGH3UTF3.js +1 -0
- package/dist/m/c-SIM7Z3U7.js +1 -0
- package/dist/m/{c-X5LNHET5.js → c-SKMIR5HQ.js} +1 -1
- package/dist/m/{c-R27DWQKX.js → c-STRI73GQ.js} +1 -1
- package/dist/m/c-SUXHUL7U.js +1 -0
- package/dist/m/c-SXGEWPFC.js +10 -0
- package/dist/m/c-SXNSSHPP.js +1 -0
- package/dist/m/c-T3P3AXEW.js +1 -0
- package/dist/m/{c-PXLTUYZC.js → c-TFLRT5JX.js} +1 -1
- package/dist/m/{c-YCLU4UNT.js → c-TGIMBAWE.js} +1 -1
- package/dist/m/c-TGSHHFO6.js +1 -0
- package/dist/m/c-U4NTUVDZ.js +1 -0
- package/dist/m/c-UOOIF2AL.js +1 -0
- package/dist/m/{c-6TYGD5AB.js → c-UOUUI265.js} +1 -1
- package/dist/m/c-V2U3F4QX.js +1 -0
- package/dist/m/c-V2V5FKXX.js +1 -0
- package/dist/m/c-VBXRXTVS.js +26 -0
- package/dist/m/c-VHSMPITY.js +1 -0
- package/dist/m/c-VPXCXBDT.js +1 -0
- package/dist/m/c-WCG6AKA7.js +1 -0
- package/dist/m/c-WNOLMHI2.js +1 -0
- package/dist/m/{c-CRPIDGXC.js → c-X6MOYATI.js} +1 -1
- package/dist/m/{c-FQGHR32O.js → c-X75G43SZ.js} +1 -1
- package/dist/m/c-XB6EAIAR.js +13 -0
- package/dist/m/c-XMIDHEKF.js +1 -0
- package/dist/m/c-XUZMRQ7O.js +4 -0
- package/dist/m/{c-2Z22FCFK.js → c-XW5TIYYB.js} +1 -1
- package/dist/m/c-YDW4VCHP.js +1 -0
- package/dist/m/{c-QGAPG7OM.js → c-YLHTD3KX.js} +1 -1
- package/dist/m/c-YNIEIPBS.js +1 -0
- package/dist/m/c-Z4G2UK6T.js +4 -0
- package/dist/m/c-Z6MROEQ4.js +1 -0
- package/dist/m/c-ZFO5RW6G.js +2 -0
- package/dist/m/c-ZGCO4J3H.js +8 -0
- package/dist/m/c-ZKKAF4UT.js +3 -0
- package/dist/m/c-ZRGEN6QQ.js +4 -0
- package/dist/m/core/{admin-attrs-U7IJNYBG.js → admin-attrs-ONRWVXPK.js} +1 -1
- package/dist/m/core/{autosave-F5YQCKVL.js → autosave-TBKAAAFB.js} +1 -1
- package/dist/m/core/conflict-notice-FOEE6I7E.js +1 -0
- package/dist/m/core/draft-mode-4MCL3LYI.js +1 -0
- package/dist/m/core/{host-permission-6EVJGNPL.js → host-permission-X4BENZEU.js} +1 -1
- package/dist/m/core/{is-edit-mode-GCX6767E.js → is-edit-mode-FFHCQ5DR.js} +1 -1
- package/dist/m/core/{persist-CJXIL7D4.js → persist-6ILUR34S.js} +1 -1
- package/dist/m/core/{recovery-DRFZRJED.js → recovery-APWADU4K.js} +1 -1
- package/dist/m/core/save-6HT2LABE.js +1 -0
- package/dist/m/core/save-core-EVMNZQ4V.js +1 -0
- package/dist/m/core/site-edits-G4BOZMV4.js +1 -0
- package/dist/m/core/{unsaved-warning-HNQVTA2D.js → unsaved-warning-ITZDIZ2I.js} +1 -1
- package/dist/m/internals/{index-NRPNDTSA.js → index-HS3CQDFW.js} +1 -1
- package/dist/m/loader-GLLVDUZA.js +1 -0
- package/dist/m/manifest-50FF1C45.js +1 -0
- package/dist/m/manifest-edit-BE1A621D.js +1 -0
- package/dist/m/manifest.json +2072 -1811
- package/dist/m/page/editor-KAZDJNND.js +307 -0
- package/dist/m/plugins/ai-edit-LABECCSN.js +6 -0
- package/dist/m/plugins/{cms-H7DTMUQX.js → cms-T2HLI7JG.js} +16 -16
- package/dist/m/plugins/{demo-42BSYQ7T.js → demo-T7B4RIKL.js} +1 -1
- package/dist/m/plugins/{derive-QVI3LI3A.js → derive-6LPJOCAV.js} +1 -1
- package/dist/m/plugins/indicator-J4ABFARX.js +1 -0
- package/dist/m/plugins/{live-DCUBKXY4.js → live-PGBIEMGB.js} +1 -1
- package/dist/m/plugins/menu-YZL3X2AJ.js +1 -0
- package/dist/m/plugins/page-WOCNX2IN.js +2 -0
- package/dist/m/plugins/page-view-SJODOOGE.js +1 -0
- package/dist/m/plugins/{people-5XRNRP5U.js → people-C4TCWFOQ.js} +1 -1
- package/dist/m/plugins/{quickcrop-WWF5I422.js → quickcrop-X5MRIBAP.js} +2 -2
- package/dist/m/plugins/richclay-Y2NV44NA.js +549 -0
- package/dist/m/plugins/sortable-XCHQG65Z.js +1 -0
- package/dist/m/plugins/{source-6BKMK4PO.js → source-YK7MO23W.js} +1 -1
- package/dist/m/plugins/{undo-3JEYK5QY.js → undo-VLRBQNPN.js} +1 -1
- package/dist/m/plugins/upgrade-NNTJBSK2.js +1 -0
- package/dist/m/plugins/{upload-TTCQRIM5.js → upload-ZKKJV76X.js} +1 -1
- package/dist/m/plugins/visitor-drafts-RTZNONHT.js +20 -0
- package/dist/m/plugins/{visitor-drafts-owner-Z5B2OQBR.js → visitor-drafts-owner-LHUHFU3L.js} +1 -1
- package/dist/m/plugins/{visitor-menu-4LQMKLPP.js → visitor-menu-FY4KM2SW.js} +1 -1
- package/dist/m/plugins/wire-M2NR354P.js +1 -0
- package/dist/m/{reader-core-POFQCKRV.js → reader-core-T2S3JC4E.js} +2 -2
- package/dist/m/sync/live-sync-Z64YREWQ.js +1 -0
- package/dist/m/ui/index-MGTWOW2C.js +1 -0
- package/dist/m/vendor/{sap-core.vendor-OA5SKL7Q.js → sap-core.vendor-QAEPMETX.js} +1 -1
- package/dist/offline-manifest.json +1250 -1082
- package/dist/server/core.cjs +132 -109
- package/dist/server/page-compaction-worker.cjs +5 -5
- package/dist/server/rooms.mjs +3 -1
- package/docs/guide.md +89 -44
- package/entries/clay-data.js +1 -1
- package/entries/sap.js +1 -1
- package/package.json +5 -3
- package/src/blockeditor/themes/content.css +70 -0
- package/src/blockeditor/themes/light-1.css +431 -0
- package/src/blockeditor/themes/light-1.source.css +270 -0
- package/src/blockeditor/themes/light-2.css +211 -0
- package/src/blockeditor/themes/light-3.css +130 -0
- package/src/blockeditor/themes/light-4.css +299 -0
- package/src/core/conflict-notice.js +28 -0
- package/src/core/draft-mode.js +6 -0
- package/src/core/host-meta.js +6 -6
- package/src/core/is-edit-mode.js +9 -3
- package/src/core/mode-support.js +3 -0
- package/src/core/mode-switch.js +4 -4
- package/src/core/mode-transition.js +3 -1
- package/src/core/page-format-wire.js +1 -1
- package/src/core/page-format.js +8 -8
- package/src/core/save-accepted.js +6 -7
- package/src/core/save-core.js +52 -23
- package/src/core/save-failure-notice.js +37 -0
- package/src/core/save-feedback.js +6 -0
- package/src/core/save-replace.js +1 -1
- package/src/core/save-size.js +2 -2
- package/src/core/save.js +78 -15
- package/src/core/site-edits.js +166 -0
- package/src/core/unsaved-warning.js +2 -2
- package/src/core/upgrade-run.js +4 -4
- package/src/lib/ai-comment.js +23 -0
- package/src/lib/effect.js +8 -0
- package/src/lib/idb-error-code.js +20 -0
- package/src/live/fast-lane.js +10 -10
- package/src/live/local-lane.js +10 -10
- package/src/live/page-compaction.js +8 -8
- package/src/live/server-lane.js +1 -1
- package/src/loader-logic.js +48 -18
- package/src/loader.js +11 -6
- package/src/page/adopt-boot.js +1 -1
- package/src/page/adopt.js +2 -2
- package/src/page/ai-area.js +182 -0
- package/src/page/ai-preview.js +80 -0
- package/src/page/ai-surface.js +257 -0
- package/src/page/ai-tool.js +308 -145
- package/src/page/announce.js +2 -2
- package/src/page/awareness.js +18 -18
- package/src/page/blocks.js +35 -34
- package/src/page/blocksel.js +2 -2
- package/src/page/board-drag.js +11 -11
- package/src/page/board-face.js +1 -1
- package/src/page/board-panel.js +26 -26
- package/src/page/board-style.js +127 -127
- package/src/page/board-view.js +48 -48
- package/src/page/chart.js +29 -29
- package/src/page/checkpoint-proof.js +19 -19
- package/src/page/chrome.js +74 -65
- package/src/page/clipboard-shape.js +1 -1
- package/src/page/csv-import.js +4 -4
- package/src/page/drag.js +5 -5
- package/src/page/editor.js +301 -296
- package/src/page/export-html.js +8 -8
- package/src/page/features/checklist.js +36 -36
- package/src/page/features/export-html.js +19 -19
- package/src/page/features/export-markdown.js +10 -10
- package/src/page/features/import-markdown.js +13 -13
- package/src/page/features/media.js +50 -50
- package/src/page/features/table.js +17 -17
- package/src/page/features/title-cover.js +17 -17
- package/src/page/features/title-icon.js +7 -7
- package/src/page/features/toc.js +1 -1
- package/src/page/features/tool.js +42 -18
- package/src/page/format-command.js +4 -4
- package/src/page/format-gate.js +6 -6
- package/src/page/format-host.js +6 -6
- package/src/page/format-level.js +3 -3
- package/src/page/format-native-commands.js +2 -2
- package/src/page/highlight-slot.js +1 -1
- package/src/page/highlight.js +4 -4
- package/src/page/history-intent.js +2 -2
- package/src/page/image-actions.js +4 -4
- package/src/page/link.js +10 -10
- package/src/page/media.js +3 -3
- package/src/page/mention-picker.js +7 -7
- package/src/page/merge.js +1 -1
- package/src/page/placeholder.js +3 -3
- package/src/page/projection.js +11 -11
- package/src/page/reader-patch.js +2 -2
- package/src/page/recover.js +26 -26
- package/src/page/recovery-ui.js +28 -28
- package/src/page/rich/chart.js +1 -1
- package/src/page/rich/page-tool.js +21 -6
- package/src/page/rich/tool-runtime.js +3 -2
- package/src/page/save-projection.js +2 -2
- package/src/page/save-states.js +9 -9
- package/src/page/schema.js +9 -9
- package/src/page/table-style.js +21 -21
- package/src/page/toc-link.js +1 -1
- package/src/page/tool-capability.js +8 -3
- package/src/page/tool-transport.js +52 -0
- package/src/page/tool-views.js +4 -0
- package/src/page/tools.js +6 -1
- package/src/page/view.js +6 -6
- package/src/page/ybind/binding.js +1 -1
- package/src/page/ybind/conversion.js +1 -1
- package/src/page/ybind/layout.js +4 -4
- package/src/page/ybind/migrate.js +1 -1
- package/src/page/ybind/origins.js +2 -2
- package/src/page/ybind/provider.js +2 -2
- package/src/page/ybind/recovery-proof.js +3 -3
- package/src/page/ybind/recovery-replay.js +2 -2
- package/src/plugins/ai-edit/picker.js +235 -0
- package/src/plugins/ai-edit.js +220 -34
- package/src/plugins/indicator-chip.js +39 -34
- package/src/plugins/indicator.js +13 -4
- package/src/plugins/live.js +21 -13
- package/src/plugins/menu/actions.js +89 -17
- package/src/plugins/menu/seo.js +32 -6
- package/src/plugins/menu/shell-style.js +26 -7
- package/src/plugins/menu/shell.js +12 -7
- package/src/plugins/menu/variants.js +6 -10
- package/src/plugins/menu/visitor.js +44 -34
- package/src/plugins/menu.js +3 -2
- package/src/plugins/page-view.js +2 -2
- package/src/plugins/page.js +257 -98
- package/src/plugins/sortable.js +7 -0
- package/src/plugins/upgrade.js +2 -1
- package/src/plugins/visitor-drafts/commit.js +303 -0
- package/src/plugins/visitor-drafts/idb.js +221 -0
- package/src/plugins/visitor-drafts/intro-style.js +1 -1
- package/src/plugins/visitor-drafts/intro.js +8 -25
- package/src/plugins/visitor-drafts/prompt.js +30 -4
- package/src/plugins/visitor-drafts/session.js +345 -0
- package/src/plugins/visitor-drafts/store.js +351 -32
- package/src/plugins/visitor-drafts.js +158 -27
- package/src/server/checkpoint/index.js +8 -8
- package/src/server/rooms/index.js +2 -2
- package/src/server/rooms/live-data-rooms.js +35 -35
- package/src/server/rooms/live-page-history.js +2 -2
- package/src/server/rooms/page-admission.js +34 -6
- package/src/server/rooms/page-conversion.js +1 -1
- package/src/server/rooms/page-lineage.js +4 -4
- package/src/server/rooms/page-rebase.js +4 -4
- package/src/server/rooms/page-room-conformance.js +14 -14
- package/src/server/rooms/page-state.js +2 -2
- package/src/server/rooms/page-write-admission.js +7 -7
- package/src/server/rooms/page-write-guard.js +3 -3
- package/src/sync/data-guard-notice.js +265 -0
- package/src/sync/live-sync.js +54 -11
- package/src/sync/page-relay.js +4 -4
- package/src/sync/presence-store.js +1 -1
- package/src/sync/presence-target.js +3 -3
- package/src/sync/presence.js +1 -1
- package/src/sync/stream.js +54 -13
- package/src/sync/wire-profile.js +8 -3
- package/src/ui/bevel.js +1 -1
- package/src/ui/index.js +9 -10
- package/src/ui/skins/cms.js +1 -1
- package/src/ui/skins/quickcrop.js +1 -1
- package/src/ui/skins/richclay.js +2 -2
- package/src/ui/toast-lazy.js +12 -3
- package/src/ui/toast.js +9 -3
- package/src/vendor/hyper-html-api-data.vendor.js +1 -1
- package/src/vendor/hyper-html-api-upgrade.vendor.js +2 -2
- package/src/vendor/hypercms.vendor.js +16 -16
- package/src/vendor/richclay.vendor.js +48 -20
- package/src/vendor/sap-core.vendor.js +1 -1
- package/tool-generation/context.md +44 -0
- package/tool-generation/system.md +23 -0
- package/dist/m/c-24PMUJIV.js +0 -2
- package/dist/m/c-2AYVYEI4.js +0 -1
- package/dist/m/c-2AZDZWCK.js +0 -1
- package/dist/m/c-2L6O5PDS.js +0 -6
- package/dist/m/c-2RYOGUQM.js +0 -2
- package/dist/m/c-2ZVOEU4M.js +0 -1
- package/dist/m/c-37NAONZA.js +0 -1
- package/dist/m/c-3GJ4SDE2.js +0 -1
- package/dist/m/c-3O7OBDCM.js +0 -1
- package/dist/m/c-5OJ7YF2N.js +0 -1
- package/dist/m/c-5WMXEKFH.js +0 -135
- package/dist/m/c-6RDOKLN7.js +0 -1
- package/dist/m/c-A4IP6MBC.js +0 -1
- package/dist/m/c-A6L3FMUS.js +0 -1
- package/dist/m/c-ATKAOH23.js +0 -1
- package/dist/m/c-B6O7AJYG.js +0 -32
- package/dist/m/c-BCGWJYXW.js +0 -1
- package/dist/m/c-BGKAT2FL.js +0 -7
- package/dist/m/c-BYTKL6UX.js +0 -1
- package/dist/m/c-DHBRA6DL.js +0 -1
- package/dist/m/c-DTMZ3ZHI.js +0 -1
- package/dist/m/c-E3ZXARWA.js +0 -1
- package/dist/m/c-EK63G3CG.js +0 -1
- package/dist/m/c-ELYIIYRS.js +0 -1
- package/dist/m/c-EXKHPOVC.js +0 -3
- package/dist/m/c-FCSZ3DC5.js +0 -20
- package/dist/m/c-FTWGYI5E.js +0 -1
- package/dist/m/c-G4PWUDD5.js +0 -1
- package/dist/m/c-GBKB5WDL.js +0 -2
- package/dist/m/c-GBTVCJXC.js +0 -1
- package/dist/m/c-GC2HICFJ.js +0 -1
- package/dist/m/c-GRWMD6O5.js +0 -1
- package/dist/m/c-HCNWJE4A.js +0 -4
- package/dist/m/c-HG2C77BM.js +0 -4
- package/dist/m/c-JGHEACGK.js +0 -1
- package/dist/m/c-JGLX6TBK.js +0 -1
- package/dist/m/c-JNRKHYWO.js +0 -1
- package/dist/m/c-KBS3UV6B.js +0 -1
- package/dist/m/c-KQ7E3PYY.js +0 -1
- package/dist/m/c-L3F5ZLIV.js +0 -1
- package/dist/m/c-L4KMT7FO.js +0 -6
- package/dist/m/c-L5VFATT6.js +0 -1
- package/dist/m/c-LCYPMULG.js +0 -1
- package/dist/m/c-LIGQYZ7M.js +0 -6
- package/dist/m/c-LKIWEPAV.js +0 -1
- package/dist/m/c-MPSKIU2I.js +0 -1
- package/dist/m/c-N7JPUPGC.js +0 -1
- package/dist/m/c-NK33MMYF.js +0 -1
- package/dist/m/c-NQLWOHLH.js +0 -10
- package/dist/m/c-NTHUTABN.js +0 -1
- package/dist/m/c-NWX3MFT4.js +0 -1
- package/dist/m/c-OKXI52N7.js +0 -1
- package/dist/m/c-OPONJ2UK.js +0 -128
- package/dist/m/c-OWQWOGYI.js +0 -1
- package/dist/m/c-P6Q2ZTFQ.js +0 -1
- package/dist/m/c-QEN6HZCA.js +0 -1
- package/dist/m/c-QIXT3Q7C.js +0 -28
- package/dist/m/c-QM5LXRDT.js +0 -9
- package/dist/m/c-QYYUVLVG.js +0 -1
- package/dist/m/c-RQRMPZXD.js +0 -1
- package/dist/m/c-SBCBXKOZ.js +0 -26
- package/dist/m/c-SKF5HL4I.js +0 -4
- package/dist/m/c-SRPC3VBE.js +0 -1
- package/dist/m/c-TANBH7FI.js +0 -1
- package/dist/m/c-THGQQDYY.js +0 -1
- package/dist/m/c-UD5JZTDL.js +0 -1
- package/dist/m/c-UDGEFWNU.js +0 -1
- package/dist/m/c-UGNV5MFB.js +0 -1
- package/dist/m/c-VIRFF5HG.js +0 -8
- package/dist/m/c-VJYEVRYK.js +0 -1
- package/dist/m/c-VQCEOGKH.js +0 -13
- package/dist/m/c-VYJ7O4RI.js +0 -34
- package/dist/m/c-W7IPVCAA.js +0 -1
- package/dist/m/c-WBGWGOM7.js +0 -1
- package/dist/m/c-WJ5DRBHT.js +0 -72
- package/dist/m/c-X5WC4PX5.js +0 -1
- package/dist/m/c-XCFQEWW6.js +0 -3
- package/dist/m/c-XGH4GS2T.js +0 -1
- package/dist/m/c-XLQ3BDMM.js +0 -1
- package/dist/m/c-ZQXNHZZT.js +0 -72
- package/dist/m/core/conflict-notice-42H4ASLA.js +0 -1
- package/dist/m/core/draft-mode-WSQAT67S.js +0 -1
- package/dist/m/core/save-ESPSQPLV.js +0 -1
- package/dist/m/core/save-core-6SQHOR6W.js +0 -1
- package/dist/m/loader-FBDE2UAB.js +0 -1
- package/dist/m/manifest-1D2F5CA5.js +0 -1
- package/dist/m/manifest-edit-F7CC5CFD.js +0 -1
- package/dist/m/page/editor-OSKOW6RS.js +0 -304
- package/dist/m/plugins/ai-edit-VV4QTINH.js +0 -6
- package/dist/m/plugins/indicator-WVPGMOZ7.js +0 -1
- package/dist/m/plugins/menu-Q4MFFQ6E.js +0 -1
- package/dist/m/plugins/page-OAWUJQEL.js +0 -2
- package/dist/m/plugins/page-view-DZ26ZDDQ.js +0 -1
- package/dist/m/plugins/richclay-PGOOJ4OK.js +0 -517
- package/dist/m/plugins/sortable-266HY6TR.js +0 -1
- package/dist/m/plugins/upgrade-BNZVFHMZ.js +0 -1
- package/dist/m/plugins/visitor-drafts-2AUYKAIJ.js +0 -20
- package/dist/m/plugins/wire-W2EV36KZ.js +0 -1
- package/dist/m/sync/live-sync-XGUPHI3I.js +0 -1
- package/dist/m/ui/index-VGYAKAKI.js +0 -1
- package/dist/page/themes/light-1.css +0 -431
- package/src/page/themes/content.css +0 -70
- package/src/page/themes/light-1.css +0 -431
- package/src/page/themes/light-1.source.css +0 -270
- package/src/page/themes/light-2.css +0 -211
- package/src/page/themes/light-3.css +0 -130
- package/src/page/themes/light-4.css +0 -299
- /package/dist/m/{c-FILLTJA7.js → c-QTTJYJMA.js} +0 -0
- /package/dist/m/plugins/{quickcrop-WWF5I422.js.LEGAL.txt → quickcrop-X5MRIBAP.js.LEGAL.txt} +0 -0
- /package/dist/m/plugins/{richclay-PGOOJ4OK.js.LEGAL.txt → richclay-Y2NV44NA.js.LEGAL.txt} +0 -0
package/src/page/ai-tool.js
CHANGED
|
@@ -1,188 +1,351 @@
|
|
|
1
|
+
// /ai tools as contract A targets: the page's AI surface builds one of these and the
|
|
2
|
+
// shared panel in ai-edit.js drives it. Making a tool and revising one differ only in
|
|
3
|
+
// the request's target and current revision, and in what Keep writes.
|
|
1
4
|
import { state } from "../vendor/prosemirror.vendor.js";
|
|
2
5
|
import { schema } from "./schema.js";
|
|
3
6
|
import { asStep } from "./blocksel.js";
|
|
4
7
|
import { keyBetween, newId } from "./model.js";
|
|
5
8
|
import { createToolClient } from "./rich/page-tool.js";
|
|
6
9
|
import { createToolHost } from "./tools.js";
|
|
7
|
-
import { toolContext } from "./tool-data.js";
|
|
10
|
+
import { tablesFromDoc, toolContext } from "./tool-data.js";
|
|
11
|
+
import { showPreview, showWidget, clearPreview } from "./ai-preview.js";
|
|
12
|
+
import { validateArtifact, validateState } from "./rich/tool-runtime.js";
|
|
13
|
+
import { createToolTransport } from "./tool-transport.js";
|
|
14
|
+
import { toolBlockViews } from "./tool-views.js";
|
|
8
15
|
|
|
9
16
|
const { Selection } = state;
|
|
10
17
|
|
|
18
|
+
const GONE = "This page is not open for editing any more.";
|
|
19
|
+
const NO_WIRE = "AI tool making isn't available on this page right now.";
|
|
20
|
+
const NO_STORE = "This document can't save tool data.";
|
|
21
|
+
const MOVED = "The place for this tool moved. Close this and run /ai where you want the tool.";
|
|
22
|
+
const STALE_REVISION = "This tool changed while you were revising, so nothing was replaced. Ask again.";
|
|
23
|
+
const BAD_ARTIFACT = "AI did not make a usable tool. Try again.";
|
|
24
|
+
const BAD_STATE = "The tool data from AI is too large or not usable. Try again.";
|
|
25
|
+
const CHANGED = "This tool's data changed while AI was working, so it was not replaced. Ask again to include the latest data.";
|
|
26
|
+
const SAVE_FAILED = "The tool could not be saved, so it was not added. Try again.";
|
|
27
|
+
const UNSAVED = "Your tool is in the document, but saving failed. It will be saved with your next edit.";
|
|
28
|
+
|
|
11
29
|
function findBlock(doc, id) {
|
|
12
30
|
let found = null;
|
|
13
31
|
doc.forEach((node, at, index) => { if (node.attrs.id === id) found = { node, at, index }; });
|
|
14
32
|
return found;
|
|
15
33
|
}
|
|
16
34
|
|
|
35
|
+
// The block the /ai was typed in and the text of that query. Keep uses it to place the
|
|
36
|
+
// tool and to remove exactly the slash text, never a caret that moved meanwhile.
|
|
37
|
+
function bookmarkIn(st, remove) {
|
|
38
|
+
const $head = st.selection.$head;
|
|
39
|
+
const index = Math.min(Math.max($head.index(0), 0), st.doc.childCount - 1);
|
|
40
|
+
const host = st.doc.child(index);
|
|
41
|
+
return {
|
|
42
|
+
hostId: host?.attrs.id ?? null,
|
|
43
|
+
slashText: remove ? st.doc.textBetween(remove.from, remove.to) : null,
|
|
44
|
+
slashOffset: remove && $head.depth ? remove.from - $head.before(1) - 1 : null,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Where the tool goes: over an empty or slash-only block, else in a new block after it.
|
|
49
|
+
function placeIn(st, bookmark) {
|
|
50
|
+
const found = bookmark?.hostId ? findBlock(st.doc, bookmark.hostId) : null;
|
|
51
|
+
if (!found) return null;
|
|
52
|
+
const next = st.doc.maybeChild(found.index + 1);
|
|
53
|
+
const replace = found.node.isTextblock && (found.node.content.size === 0 || found.node.textContent === bookmark.slashText);
|
|
54
|
+
return {
|
|
55
|
+
...found,
|
|
56
|
+
replace,
|
|
57
|
+
pos: replace ? found.node.attrs.pos : keyBetween(found.node.attrs.pos, next?.attrs.pos ?? null),
|
|
58
|
+
insertAt: replace ? found.at : found.at + found.node.nodeSize,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
17
62
|
function insertCandidate(view, candidate, bookmark) {
|
|
18
63
|
const st = view.state;
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
for (let i = 0; i < index; i++) at += st.doc.child(i).nodeSize;
|
|
23
|
-
return { node: st.doc.child(index), at, index };
|
|
24
|
-
})();
|
|
25
|
-
const { node: current, at, index } = found;
|
|
26
|
-
const next = st.doc.maybeChild(index + 1);
|
|
27
|
-
const replace = current.isTextblock && (current.content.size === 0 || bookmark?.hostId === current.attrs.id && current.textContent === bookmark.slashText);
|
|
28
|
-
const pos = replace ? current.attrs.pos : keyBetween(current.attrs.pos, next?.attrs.pos ?? null);
|
|
64
|
+
const place = placeIn(st, bookmark);
|
|
65
|
+
if (!place) return false;
|
|
66
|
+
const { node: current, at, insertAt, replace } = place;
|
|
29
67
|
const tool = schema.nodes.tool.create({
|
|
30
|
-
id: candidate.id, pos, parent: current.attrs.parent ?? null,
|
|
68
|
+
id: candidate.id, pos: place.pos, parent: current.attrs.parent ?? null,
|
|
31
69
|
artifact: candidate.artifact, rev: candidate.rev, state: candidate.state,
|
|
32
70
|
});
|
|
33
|
-
const place = replace ? at : at + current.nodeSize;
|
|
34
71
|
const tr = st.tr;
|
|
35
72
|
if (!replace && bookmark?.hostId === current.attrs.id && bookmark.slashText && bookmark.slashOffset >= 0) {
|
|
36
73
|
const from = at + 1 + bookmark.slashOffset;
|
|
37
74
|
const to = from + bookmark.slashText.length;
|
|
38
75
|
if (to <= at + current.nodeSize - 1 && st.doc.textBetween(from, to) === bookmark.slashText) tr.delete(from, to);
|
|
39
76
|
}
|
|
40
|
-
const mapped = tr.mapping.map(
|
|
77
|
+
const mapped = tr.mapping.map(insertAt);
|
|
41
78
|
tr.replaceWith(mapped, replace ? tr.mapping.map(at + current.nodeSize) : mapped, tool);
|
|
42
79
|
tr.setSelection(Selection.near(tr.doc.resolve(Math.min(mapped + tool.nodeSize, tr.doc.content.size))));
|
|
43
80
|
view.dispatch(asStep(tr).scrollIntoView());
|
|
81
|
+
return true;
|
|
44
82
|
}
|
|
45
83
|
|
|
46
|
-
|
|
47
|
-
const client = transport ? createToolClient({ transport, newId: () => allocate("request") }) : null;
|
|
48
|
-
let panel = null;
|
|
49
|
-
let generation = 0;
|
|
50
|
-
|
|
51
|
-
const close = () => {
|
|
52
|
-
generation++;
|
|
53
|
-
if (!panel) return;
|
|
54
|
-
client?.discard(panel.pending);
|
|
55
|
-
panel.preview?.dispose();
|
|
56
|
-
panel.previewHost?.dispose();
|
|
57
|
-
panel.element.remove();
|
|
58
|
-
panel = null;
|
|
59
|
-
};
|
|
84
|
+
const emptyRect = () => ({ x: 0, y: 0, left: 0, top: 0, right: 0, bottom: 0, width: 0, height: 0 });
|
|
60
85
|
|
|
61
|
-
|
|
62
|
-
|
|
86
|
+
export function createToolTargets({
|
|
87
|
+
getView,
|
|
88
|
+
store = () => null,
|
|
89
|
+
acceptState = () => globalThis.clay?.save?.flush?.(),
|
|
90
|
+
newId: allocate = newId,
|
|
91
|
+
transport = createToolTransport(),
|
|
92
|
+
} = {}) {
|
|
93
|
+
const viewNow = () => {
|
|
63
94
|
const view = getView();
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
panel.previewRoot.replaceChildren();
|
|
105
|
-
panel.input.hidden = false;
|
|
106
|
-
panel.actions.replaceChildren();
|
|
107
|
-
button("Generate", generate);
|
|
108
|
-
button("Cancel", close);
|
|
109
|
-
panel.input.focus();
|
|
95
|
+
return view && !view.isDestroyed ? view : null;
|
|
96
|
+
};
|
|
97
|
+
const storeNow = () => (typeof store === "function" ? store() : store);
|
|
98
|
+
|
|
99
|
+
const liveState = (id, rev) => {
|
|
100
|
+
const value = storeNow()?.data?.[id]?.[rev];
|
|
101
|
+
return value === undefined ? {} : value;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const targets = new Map();
|
|
105
|
+
|
|
106
|
+
const canonical = (value) => {
|
|
107
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
108
|
+
if (value && typeof value === "object") {
|
|
109
|
+
const keys = Object.keys(value).sort();
|
|
110
|
+
return `{${keys.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`).join(",")}}`;
|
|
111
|
+
}
|
|
112
|
+
return JSON.stringify(value) ?? "null";
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
function toolTarget(toolId = null, remove = null) {
|
|
116
|
+
const opened = viewNow();
|
|
117
|
+
const bookmark = toolId || !opened ? null : bookmarkIn(opened.state, remove);
|
|
118
|
+
let onStatus = null;
|
|
119
|
+
const client = createToolClient({
|
|
120
|
+
transport: {
|
|
121
|
+
request: (request) => transport.request(request, { onStatus: (status) => onStatus?.(status) }),
|
|
122
|
+
cancel: (id) => transport.cancel(id),
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
let pending = null;
|
|
126
|
+
let candidate = null;
|
|
127
|
+
let preview = null;
|
|
128
|
+
let kept = false;
|
|
129
|
+
let revision = null;
|
|
130
|
+
let captured = null;
|
|
131
|
+
|
|
132
|
+
const disposePreview = () => {
|
|
133
|
+
preview?.host?.dispose();
|
|
134
|
+
preview = null;
|
|
110
135
|
};
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
p.actions.replaceChildren();
|
|
118
|
-
button("Keep", keep);
|
|
119
|
-
button("Revise", showPrompt);
|
|
120
|
-
button("Discard", close);
|
|
136
|
+
|
|
137
|
+
// The block that runs this tool, if this editor mounts it, so a revision can pause
|
|
138
|
+
// it while the request and its preview are up.
|
|
139
|
+
const blockNow = () => {
|
|
140
|
+
const view = viewNow();
|
|
141
|
+
return view && toolId ? toolBlockViews.get(view)?.get(toolId) ?? null : null;
|
|
121
142
|
};
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (panel !== p || turn !== generation) return;
|
|
136
|
-
p.candidate = { artifact: result.artifact, state: result.state, id: null, rev: null };
|
|
137
|
-
showCandidate();
|
|
138
|
-
} catch (error) {
|
|
139
|
-
if (panel !== p || turn !== generation) return;
|
|
140
|
-
p.status.textContent = error.message;
|
|
141
|
-
p.actions.replaceChildren();
|
|
142
|
-
button("Generate", generate);
|
|
143
|
-
button("Cancel", close);
|
|
144
|
-
} finally { p.busy = false; }
|
|
143
|
+
|
|
144
|
+
const suspendTool = () => blockNow()?.suspend();
|
|
145
|
+
const resumeTool = () => blockNow()?.resume();
|
|
146
|
+
|
|
147
|
+
// Every way Keep can fail leaves the same trace: no proposal on screen, the block
|
|
148
|
+
// and its state as they were, and an editor that answers again.
|
|
149
|
+
const failKeep = (message) => {
|
|
150
|
+
kept = false;
|
|
151
|
+
const view = viewNow();
|
|
152
|
+
disposePreview();
|
|
153
|
+
if (view) clearPreview(view);
|
|
154
|
+
resumeTool();
|
|
155
|
+
return { status: "failed", message };
|
|
145
156
|
};
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (!
|
|
155
|
-
|
|
156
|
-
|
|
157
|
+
|
|
158
|
+
const target = {
|
|
159
|
+
aiTarget: true,
|
|
160
|
+
label: toolId ? "This tool" : "New tool",
|
|
161
|
+
ref: toolId ? [toolId] : [],
|
|
162
|
+
placeholder: toolId ? "What should change?" : "Describe the tool",
|
|
163
|
+
get isConnected() {
|
|
164
|
+
const view = viewNow();
|
|
165
|
+
if (!view) return false;
|
|
166
|
+
return toolId ? !!findBlock(view.state.doc, toolId) : true;
|
|
167
|
+
},
|
|
168
|
+
getBoundingClientRect() {
|
|
169
|
+
const view = viewNow();
|
|
170
|
+
if (!view) return emptyRect();
|
|
171
|
+
if (preview) return preview.dom.getBoundingClientRect();
|
|
172
|
+
const id = toolId ?? bookmark?.hostId;
|
|
173
|
+
const found = id ? findBlock(view.state.doc, id) : null;
|
|
174
|
+
const node = found ? view.nodeDOM(found.at) : null;
|
|
175
|
+
return node && typeof node.getBoundingClientRect === "function" ? node.getBoundingClientRect() : emptyRect();
|
|
176
|
+
},
|
|
177
|
+
async start(comment) {
|
|
178
|
+
candidate = null;
|
|
179
|
+
kept = false;
|
|
180
|
+
const view = viewNow();
|
|
181
|
+
if (!view) return { status: "refused", code: "gone", message: GONE };
|
|
182
|
+
// Read here, not imported: a page with exclude=wire must not pull the wire in.
|
|
183
|
+
if (!globalThis.window?.clay?.wire) return { status: "refused", code: "no-wire", message: NO_WIRE };
|
|
184
|
+
let payloadTarget = null;
|
|
185
|
+
let current = null;
|
|
186
|
+
if (toolId) {
|
|
187
|
+
const found = findBlock(view.state.doc, toolId);
|
|
188
|
+
if (found?.node.type !== schema.nodes.tool) return { status: "refused", code: "gone", message: GONE };
|
|
189
|
+
revision = found.node.attrs.rev;
|
|
190
|
+
payloadTarget = { toolId, rev: revision };
|
|
191
|
+
// The tool must not write to its own data while the request runs or its
|
|
192
|
+
// preview is shown, so it pauses and the snapshot is taken from its saved data.
|
|
193
|
+
suspendTool();
|
|
194
|
+
current = { artifact: found.node.attrs.artifact, state: liveState(toolId, revision) };
|
|
195
|
+
captured = canonical(current.state);
|
|
196
|
+
}
|
|
197
|
+
pending = client.request(comment, toolContext(view.state.doc, view.dom.ownerDocument.title), payloadTarget, current);
|
|
198
|
+
return {
|
|
199
|
+
status: "ok",
|
|
200
|
+
id: pending.requestId,
|
|
201
|
+
send: (hooks = {}) => {
|
|
202
|
+
onStatus = typeof hooks.onStatus === "function" ? hooks.onStatus : null;
|
|
203
|
+
const done = client.wait(pending).then(
|
|
204
|
+
(result) => {
|
|
205
|
+
candidate = { id: toolId, rev: null, artifact: result.artifact, state: result.state };
|
|
206
|
+
return { state: "done", result };
|
|
207
|
+
},
|
|
208
|
+
(error) => {
|
|
209
|
+
resumeTool();
|
|
210
|
+
return { state: "error", error: error?.message || error?.code || "the helper reported an error", code: error?.code ?? null };
|
|
211
|
+
},
|
|
212
|
+
);
|
|
213
|
+
return { done, cancel: () => { resumeTool(); client.discard(pending); } };
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
},
|
|
217
|
+
async propose(result) {
|
|
218
|
+
const view = viewNow();
|
|
219
|
+
if (!view || !result) return { status: "refused", message: GONE };
|
|
220
|
+
const artifact = validateArtifact(result.artifact);
|
|
221
|
+
if (!artifact.ok) return { status: "refused", message: BAD_ARTIFACT };
|
|
222
|
+
const held = validateState(result.state);
|
|
223
|
+
if (!held.ok) return { status: "refused", message: BAD_STATE };
|
|
224
|
+
candidate = { id: toolId, rev: null, artifact: result.artifact, state: result.state };
|
|
225
|
+
const mounted = mountPreview(view);
|
|
226
|
+
if (mounted.status !== "ready") candidate = null;
|
|
227
|
+
return mounted;
|
|
228
|
+
},
|
|
229
|
+
async keep() {
|
|
230
|
+
if (!candidate || kept) return failKeep(STALE_REVISION);
|
|
231
|
+
const view = viewNow();
|
|
232
|
+
if (!view) return failKeep(GONE);
|
|
233
|
+
const tools = storeNow();
|
|
234
|
+
if (!tools) return failKeep(NO_STORE);
|
|
235
|
+
const liveChanged = () => toolId && captured !== null && canonical(liveState(toolId, revision)) !== captured;
|
|
236
|
+
if (liveChanged()) return failKeep(CHANGED);
|
|
237
|
+
kept = true;
|
|
238
|
+
const id = candidate.id ?? allocate("b");
|
|
239
|
+
const rev = allocate("rev");
|
|
240
|
+
const edit = { ...candidate, id, rev };
|
|
241
|
+
// Two stages: the state has to be accepted first, and only then does the block
|
|
242
|
+
// appear, so a refused state leaves no block and one undo item.
|
|
243
|
+
try {
|
|
244
|
+
await tools.set([id, rev], edit.state);
|
|
245
|
+
} catch (error) {
|
|
246
|
+
return failKeep(error?.message ?? NO_STORE);
|
|
247
|
+
}
|
|
248
|
+
let accepted = null;
|
|
249
|
+
try {
|
|
250
|
+
accepted = await acceptState();
|
|
251
|
+
} catch {
|
|
252
|
+
return failKeep(SAVE_FAILED);
|
|
253
|
+
}
|
|
157
254
|
if (accepted?.ok !== true && !["saved", "clean"].includes(accepted?.state)) {
|
|
158
|
-
|
|
255
|
+
return failKeep(accepted?.msg ?? accepted?.message ?? SAVE_FAILED);
|
|
159
256
|
}
|
|
160
|
-
if (
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
257
|
+
if (toolId) {
|
|
258
|
+
const found = findBlock(view.state.doc, toolId);
|
|
259
|
+
if (found?.node.type !== schema.nodes.tool || found.node.attrs.rev !== revision) return failKeep(STALE_REVISION);
|
|
260
|
+
} else if (!placeIn(view.state, bookmark)) {
|
|
261
|
+
return failKeep(MOVED);
|
|
262
|
+
}
|
|
263
|
+
if (liveChanged()) return failKeep(CHANGED);
|
|
264
|
+
disposePreview();
|
|
265
|
+
clearPreview(view);
|
|
266
|
+
if (toolId) {
|
|
267
|
+
const found = findBlock(view.state.doc, toolId);
|
|
173
268
|
view.dispatch(asStep(view.state.tr.setNodeMarkup(found.at, null, {
|
|
174
|
-
...found.node.attrs, artifact:
|
|
269
|
+
...found.node.attrs, artifact: edit.artifact, rev: edit.rev,
|
|
175
270
|
})));
|
|
176
|
-
} else insertCandidate(view,
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
271
|
+
} else if (!insertCandidate(view, edit, bookmark)) {
|
|
272
|
+
return failKeep(MOVED);
|
|
273
|
+
}
|
|
274
|
+
// The block is in the document now: a failed save neither undoes it nor asks the
|
|
275
|
+
// model again, it retries the save alone, once.
|
|
276
|
+
let saved = false;
|
|
277
|
+
for (let attempt = 0; attempt < 2 && !saved; attempt++) {
|
|
278
|
+
try {
|
|
279
|
+
const result = await acceptState();
|
|
280
|
+
saved = result?.ok !== false;
|
|
281
|
+
} catch {
|
|
282
|
+
saved = false;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (!saved) return { status: "failed", message: UNSAVED };
|
|
286
|
+
targets.delete(toolId ?? "new");
|
|
287
|
+
return { status: "kept" };
|
|
288
|
+
},
|
|
289
|
+
discard() {
|
|
290
|
+
disposePreview();
|
|
291
|
+
const view = viewNow();
|
|
292
|
+
if (view) clearPreview(view);
|
|
293
|
+
client.discard(pending);
|
|
294
|
+
resumeTool();
|
|
295
|
+
targets.delete(toolId ?? "new");
|
|
296
|
+
},
|
|
182
297
|
};
|
|
183
|
-
showPrompt();
|
|
184
|
-
return element;
|
|
185
|
-
};
|
|
186
298
|
|
|
187
|
-
|
|
299
|
+
function mountPreview(view) {
|
|
300
|
+
disposePreview();
|
|
301
|
+
const host = createToolHost({
|
|
302
|
+
mode: "view",
|
|
303
|
+
tables: () => tablesFromDoc(view.state.doc).map(({ id, cols, rows }) => ({ id, cols, rows })),
|
|
304
|
+
});
|
|
305
|
+
const dom = view.dom.ownerDocument.createElement("div");
|
|
306
|
+
dom.className = "blockeditor-ai-preview";
|
|
307
|
+
let mounted = null;
|
|
308
|
+
try {
|
|
309
|
+
mounted = host.mount(dom, { id: "preview", rev: "preview", artifact: candidate.artifact, seed: candidate.state });
|
|
310
|
+
} catch (error) {
|
|
311
|
+
host.dispose();
|
|
312
|
+
return { status: "refused", message: BAD_ARTIFACT };
|
|
313
|
+
}
|
|
314
|
+
if (mounted.failed) {
|
|
315
|
+
host.dispose();
|
|
316
|
+
return { status: "refused", message: BAD_ARTIFACT };
|
|
317
|
+
}
|
|
318
|
+
preview = { host, dom };
|
|
319
|
+
// A revision covers the block it replaces; a new tool stands at its bookmark.
|
|
320
|
+
if (toolId) {
|
|
321
|
+
showPreview(view, { ids: [toolId], dom });
|
|
322
|
+
return { status: "ready" };
|
|
323
|
+
}
|
|
324
|
+
const place = placeIn(view.state, bookmark);
|
|
325
|
+
if (!place) {
|
|
326
|
+
disposePreview();
|
|
327
|
+
return { status: "refused", message: MOVED };
|
|
328
|
+
}
|
|
329
|
+
if (place.replace) showPreview(view, { ids: [place.node.attrs.id], dom });
|
|
330
|
+
else showWidget(view, { at: place.insertAt, dom });
|
|
331
|
+
return { status: "ready" };
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (toolId) targets.set(toolId, target);
|
|
335
|
+
return target;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return {
|
|
339
|
+
newTool(remove = null) {
|
|
340
|
+
return toolTarget(null, remove);
|
|
341
|
+
},
|
|
342
|
+
// A revision target follows the block it names: the same tool asked about twice is
|
|
343
|
+
// the same target, so its draft survives a closed panel.
|
|
344
|
+
reviseTool(toolId) {
|
|
345
|
+
const known = targets.get(toolId);
|
|
346
|
+
if (known?.isConnected) return known;
|
|
347
|
+
targets.delete(toolId);
|
|
348
|
+
return toolTarget(toolId);
|
|
349
|
+
},
|
|
350
|
+
};
|
|
188
351
|
}
|
package/src/page/announce.js
CHANGED
|
@@ -4,7 +4,7 @@ export function announcementPlugin() {
|
|
|
4
4
|
return new state.Plugin({
|
|
5
5
|
view(view) {
|
|
6
6
|
const live = view.dom.ownerDocument.createElement("div");
|
|
7
|
-
live.className = "
|
|
7
|
+
live.className = "blockeditor-live";
|
|
8
8
|
live.setAttribute("role", "status");
|
|
9
9
|
live.setAttribute("aria-live", "polite");
|
|
10
10
|
view.dom.parentElement.appendChild(live);
|
|
@@ -14,7 +14,7 @@ export function announcementPlugin() {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export function announce(view, text) {
|
|
17
|
-
const region = view.dom.parentElement?.querySelector(".
|
|
17
|
+
const region = view.dom.parentElement?.querySelector(".blockeditor-live");
|
|
18
18
|
if (!region) return;
|
|
19
19
|
region.textContent = "";
|
|
20
20
|
region.textContent = text;
|
package/src/page/awareness.js
CHANGED
|
@@ -18,16 +18,16 @@ import { styleWithLegacyId } from "../lib/style.js";
|
|
|
18
18
|
const { Plugin, PluginKey } = state;
|
|
19
19
|
const { Decoration, DecorationSet } = pmView;
|
|
20
20
|
|
|
21
|
-
export const awarenessKey = new PluginKey("
|
|
21
|
+
export const awarenessKey = new PluginKey("blockeditor-awareness");
|
|
22
22
|
|
|
23
|
-
const STYLE_ID = "
|
|
23
|
+
const STYLE_ID = "blockeditor-awareness-style";
|
|
24
24
|
const STYLE_CSS = `
|
|
25
|
-
.
|
|
26
|
-
.
|
|
27
|
-
.
|
|
28
|
-
.
|
|
29
|
-
.
|
|
30
|
-
.
|
|
25
|
+
.blockeditor-remote-selection { background-color: color-mix(in srgb, var(--blockeditor-remote-color, currentColor) 22%, transparent); }
|
|
26
|
+
.blockeditor-remote-caret { position: relative; display: inline-block; width: 0; height: 1.1em; vertical-align: text-bottom; }
|
|
27
|
+
.blockeditor-remote-caret::before { content: ""; position: absolute; inset-inline-start: -1px; top: 0; bottom: 0; width: 2px; background: var(--blockeditor-remote-color, currentColor); }
|
|
28
|
+
.blockeditor-remote-name { position: absolute; inset-inline-start: -1px; bottom: 100%; padding: 1px 4px; border-radius: 4px; background: var(--blockeditor-remote-color, currentColor); color: #fff; font-size: 10px; line-height: 1.4; white-space: nowrap; pointer-events: none; }
|
|
29
|
+
.blockeditor-remote-cell { outline: 2px solid var(--blockeditor-remote-color, currentColor); outline-offset: -2px; }
|
|
30
|
+
.blockeditor-remote-block { box-shadow: inset 2px 0 0 var(--blockeditor-remote-color, currentColor); }
|
|
31
31
|
`;
|
|
32
32
|
|
|
33
33
|
// A fixed palette, chosen for contrast against both page themes. A peer's id
|
|
@@ -42,11 +42,11 @@ export const colorOf = (id) => {
|
|
|
42
42
|
|
|
43
43
|
const caretElement = (doc, name, color) => {
|
|
44
44
|
const bar = doc.createElement("span");
|
|
45
|
-
bar.className = "
|
|
45
|
+
bar.className = "blockeditor-remote-caret";
|
|
46
46
|
bar.setAttribute("aria-hidden", "true");
|
|
47
|
-
bar.style.setProperty("--
|
|
47
|
+
bar.style.setProperty("--blockeditor-remote-color", color);
|
|
48
48
|
const tag = doc.createElement("span");
|
|
49
|
-
tag.className = "
|
|
49
|
+
tag.className = "blockeditor-remote-name";
|
|
50
50
|
tag.textContent = name;
|
|
51
51
|
bar.appendChild(tag);
|
|
52
52
|
return bar;
|
|
@@ -78,19 +78,19 @@ export function decorationsFor({ binding, doc, snapshot, epoch }) {
|
|
|
78
78
|
for (const session of person.sessions ?? []) {
|
|
79
79
|
if (session.you) continue;
|
|
80
80
|
const target = session.editing;
|
|
81
|
-
if (!target || target.kind !== "
|
|
81
|
+
if (!target || target.kind !== "blockeditor" || target.v !== PRESENCE_VERSION) continue;
|
|
82
82
|
if (target.epoch !== epoch || target.generation !== generation) continue;
|
|
83
83
|
const spot = decodeSelection(context, target.selection);
|
|
84
84
|
if (!spot) continue;
|
|
85
85
|
if (spot.kind === "text") {
|
|
86
|
-
if (spot.to > spot.from) decorations.push(Decoration.inline(spot.from, spot.to, { class: "
|
|
86
|
+
if (spot.to > spot.from) decorations.push(Decoration.inline(spot.from, spot.to, { class: "blockeditor-remote-selection", style: `--blockeditor-remote-color:${color}` }));
|
|
87
87
|
decorations.push(Decoration.widget(spot.to, (view) => caretElement(view.dom.ownerDocument, name, color), { side: 1, key: `caret:${person.id}:${session.id}` }));
|
|
88
88
|
} else if (spot.kind === "cell") {
|
|
89
|
-
decorations.push(Decoration.node(spot.from, spot.to, { class: "
|
|
89
|
+
decorations.push(Decoration.node(spot.from, spot.to, { class: "blockeditor-remote-cell", style: `--blockeditor-remote-color:${color}` }));
|
|
90
90
|
decorations.push(Decoration.widget(spot.from + 1, (view) => caretElement(view.dom.ownerDocument, name, color), { side: -1, key: `cell:${person.id}:${session.id}` }));
|
|
91
91
|
} else if (spot.kind === "blocks") {
|
|
92
92
|
const [first] = spot.ranges;
|
|
93
|
-
for (const range of spot.ranges) decorations.push(Decoration.node(range.from, range.to, { class: "
|
|
93
|
+
for (const range of spot.ranges) decorations.push(Decoration.node(range.from, range.to, { class: "blockeditor-remote-block", style: `--blockeditor-remote-color:${color}` }));
|
|
94
94
|
decorations.push(Decoration.widget(first.from + 1, (view) => caretElement(view.dom.ownerDocument, name, color), { side: -1, key: `blocks:${person.id}:${session.id}` }));
|
|
95
95
|
}
|
|
96
96
|
}
|
|
@@ -133,7 +133,7 @@ export function createPageAwareness({ binding, view, store = presenceStore, epoc
|
|
|
133
133
|
store.setTarget(null);
|
|
134
134
|
return;
|
|
135
135
|
}
|
|
136
|
-
store.setTarget({ kind: "
|
|
136
|
+
store.setTarget({ kind: "blockeditor", v: PRESENCE_VERSION, epoch, generation: binding.awareness.generation(), selection });
|
|
137
137
|
};
|
|
138
138
|
|
|
139
139
|
const rebuild = (next) => {
|
|
@@ -252,9 +252,9 @@ export async function installPageAwareness({ binding, view, store = presenceStor
|
|
|
252
252
|
store.setCapabilities({
|
|
253
253
|
supported: extensions.includes("presence"),
|
|
254
254
|
recordAwareness: extensions.includes("record-awareness-v1"),
|
|
255
|
-
pageAwareness: extensions.includes("
|
|
255
|
+
pageAwareness: extensions.includes("blockeditor-awareness-v1"),
|
|
256
256
|
});
|
|
257
|
-
if (!extensions.includes("
|
|
257
|
+
if (!extensions.includes("blockeditor-awareness-v1")) return null;
|
|
258
258
|
const epoch = answer.document?.awareness?.scope;
|
|
259
259
|
if (typeof epoch !== "string" || !epoch) return null;
|
|
260
260
|
return createPageAwareness({ binding, view, store, epoch });
|