@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/plugins/live.js
CHANGED
|
@@ -12,7 +12,7 @@ import { capturePageState, onSnapshot } from "../core/snapshot.js";
|
|
|
12
12
|
import { onSaveAccepted, onSaveAttempt, onSaveOutcome, isSaveInProgress, saveFateIsUnknown, exitSave } from "../core/save-core.js";
|
|
13
13
|
import { savePageForce, baselineSettled, isSaveConflicted, autosaveIsSuspended } from "../core/save.js";
|
|
14
14
|
import { withKeepalive } from "../core/save-core.js";
|
|
15
|
-
import { isEditMode } from "../core/is-edit-mode.js";
|
|
15
|
+
import { isEditMode, isDraftMode } from "../core/is-edit-mode.js";
|
|
16
16
|
import { registerUnsavedState } from "../lib/unsaved-state.js";
|
|
17
17
|
import { createCheckpoints } from "../live/checkpoint.js";
|
|
18
18
|
import { parseJsonRelaxed } from "../vendor/hyper-morph-json.vendor.js";
|
|
@@ -687,10 +687,12 @@ function endDomPin(maybeLanded, ownerId = null) {
|
|
|
687
687
|
|
|
688
688
|
// A capture that sent nothing is definitely unsent. Otherwise only a 4xx proves
|
|
689
689
|
// the host wrote nothing, and only when no attempt timed out. A lost answer, a
|
|
690
|
-
// timeout, a 5xx or a historical duplicate may have landed.
|
|
690
|
+
// timeout, a 5xx or a historical duplicate may have landed. A refusal from this
|
|
691
|
+
// browser's draft store wrote nothing anywhere.
|
|
691
692
|
function mayHaveLanded(result, sent) {
|
|
693
|
+
if (result?.code === "draft-storage" || result?.code === "draft-not-ready") return false;
|
|
692
694
|
const code = result?.code;
|
|
693
|
-
const precommit = code === "
|
|
695
|
+
const precommit = code === "blockeditor-converting" || code === "blockeditor-capacity";
|
|
694
696
|
return code === "save-already-applied" || result?.hadTimeout === true ||
|
|
695
697
|
(sent !== false && !precommit && !(result?.status >= 400 && result?.status < 500));
|
|
696
698
|
}
|
|
@@ -765,6 +767,12 @@ function ensureLane() {
|
|
|
765
767
|
laneGates();
|
|
766
768
|
if (laneRequested || !(writerSession ? writerSession.admitted || writerSession.wantsLane : isEditMode)) return;
|
|
767
769
|
laneRequested = true;
|
|
770
|
+
// A visitor's draft opens no lane: its tabs share the draft record, not a room.
|
|
771
|
+
if (isDraftMode) {
|
|
772
|
+
settleLane?.(null);
|
|
773
|
+
settleWriter?.(null);
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
768
776
|
const request = ++laneRequest;
|
|
769
777
|
hostMeta.hostSupports("live-data").then(
|
|
770
778
|
async (supported) => {
|
|
@@ -786,7 +794,7 @@ function ensureLane() {
|
|
|
786
794
|
// never shares the lane a tab that cannot read it is on. The room scope
|
|
787
795
|
// puts this tab's sequencer in the host-mode room, which a tab of the lane
|
|
788
796
|
// before it never joins.
|
|
789
|
-
local = lane.localTransport({ seed: seedLocalRoom, rooms: true, floor: document.querySelector('meta[name="clay-
|
|
797
|
+
local = lane.localTransport({ seed: seedLocalRoom, rooms: true, floor: document.querySelector('meta[name="clay-blockeditor-format"]')?.getAttribute("content") });
|
|
790
798
|
fast = lane.createFastLane(laneOptions(local));
|
|
791
799
|
} else {
|
|
792
800
|
settleLane?.(null);
|
|
@@ -853,7 +861,7 @@ function parseHtml(html) {
|
|
|
853
861
|
function textOf(entry) {
|
|
854
862
|
const fastMode = entry.store.handle.status.mode === "fast";
|
|
855
863
|
const current = fastMode ? entry.store.authoritative : entry.store.value;
|
|
856
|
-
const value = fastMode && /^
|
|
864
|
+
const value = fastMode && /^blockeditor(\.[0-9]+)?$/.test(entry.store.name) ? captureYValue(current) : current;
|
|
857
865
|
if (entry.layout === "lines") return serializeLines(value);
|
|
858
866
|
return entry.layout === "pretty" ? JSON.stringify(value, null, 2).replace(/</g, "\\u003c") : serializeLive(value);
|
|
859
867
|
}
|
|
@@ -903,12 +911,12 @@ function openEntry(name, store, { layout = "line", leftAt = null, staged = null
|
|
|
903
911
|
if (event.code === "receipt-expired") document.dispatchEvent(new CustomEvent("clay:live-notice", {
|
|
904
912
|
detail: { name, code: event.code, ops: event.ops, message: "The room retired an update receipt. Check the saved value before restoring this update." },
|
|
905
913
|
}));
|
|
906
|
-
if (event.phase === "refused" && event.code === "too-large" && !/^
|
|
914
|
+
if (event.phase === "refused" && event.code === "too-large" && !/^blockeditor(\.[0-9]+)?$/.test(name)) document.dispatchEvent(new CustomEvent("clay:live-notice", {
|
|
907
915
|
detail: { name, code: "op-too-large", message: "That change was too large to share, so it was undone." },
|
|
908
916
|
}));
|
|
909
917
|
// The room was opened from a document with no store of this name, so the
|
|
910
918
|
// page it holds is not the one this tab is editing.
|
|
911
|
-
if (event.phase === "left" && event.code === "no-store" && /^
|
|
919
|
+
if (event.phase === "left" && event.code === "no-store" && /^blockeditor(\.[0-9]+)?$/.test(name)) document.dispatchEvent(new CustomEvent("clay:live-notice", {
|
|
912
920
|
detail: { name, code: "unknown-store", message: `The room has no "${name}" store, so the page it holds is not the one this tab is editing.` },
|
|
913
921
|
}));
|
|
914
922
|
});
|
|
@@ -1003,7 +1011,7 @@ onSnapshot((clone, { forSave, requestRefresh }) => {
|
|
|
1003
1011
|
// A staged store reaches the file here, where the boot would have put its tag, and
|
|
1004
1012
|
// so does one that started that way, on every save after its first.
|
|
1005
1013
|
if (!tag && (entry.staged || entry.tagless)) {
|
|
1006
|
-
const article = clone.querySelector("article[data-
|
|
1014
|
+
const article = clone.querySelector("article[data-blockeditor]");
|
|
1007
1015
|
if (!article) continue;
|
|
1008
1016
|
const element = article.ownerDocument.createElement("script");
|
|
1009
1017
|
element.setAttribute("type", "application/json");
|
|
@@ -1124,7 +1132,7 @@ for (const type of ["clay:save-error", "clay:save-offline"]) {
|
|
|
1124
1132
|
document.addEventListener(type, (event) => {
|
|
1125
1133
|
const status = event.detail?.status;
|
|
1126
1134
|
const code = event.detail?.code;
|
|
1127
|
-
const precommit = code === "
|
|
1135
|
+
const precommit = code === "blockeditor-converting" || code === "blockeditor-capacity";
|
|
1128
1136
|
endDomPin(code === "save-already-applied" || event.detail?.hadTimeout === true ||
|
|
1129
1137
|
(event.detail?.sent !== false && !precommit && !(status >= 400 && status < 500)), event.detail?.captureId);
|
|
1130
1138
|
});
|
|
@@ -1233,7 +1241,7 @@ onSaveOutcome(({ captureId, result, attempts, sent }) => {
|
|
|
1233
1241
|
if (!pin) return;
|
|
1234
1242
|
const stagedEntry = [...pin.keys()].map((name) => entries.get(name)).find((entry) => entry?.staged);
|
|
1235
1243
|
// Nothing was written: the staged store is clean and nothing follows.
|
|
1236
|
-
if (stagedEntry && result.code === "
|
|
1244
|
+
if (stagedEntry && result.code === "blockeditor-nothing-to-write") {
|
|
1237
1245
|
stagedEntry.store.confirm(stagedEntry.store.mark);
|
|
1238
1246
|
dropCapture(captureId);
|
|
1239
1247
|
releaseBody();
|
|
@@ -1241,7 +1249,7 @@ onSaveOutcome(({ captureId, result, attempts, sent }) => {
|
|
|
1241
1249
|
return;
|
|
1242
1250
|
}
|
|
1243
1251
|
// This tab's value does not descend from the stored document: never send it again.
|
|
1244
|
-
if (stagedEntry && result.code === "
|
|
1252
|
+
if (stagedEntry && result.code === "blockeditor-lineage-stale") stagedEntry.staged.conflict = "conflict";
|
|
1245
1253
|
dropCapture(captureId);
|
|
1246
1254
|
const landed = mayHaveLanded(result, sent);
|
|
1247
1255
|
const plan = landed ? historyPlan(captureId) : null;
|
|
@@ -1277,7 +1285,7 @@ function offerCheckpoint(captureId, html) {
|
|
|
1277
1285
|
const state = capturePageState(captureId);
|
|
1278
1286
|
if (!state) return;
|
|
1279
1287
|
let article = null;
|
|
1280
|
-
try { article = parseHtml(html).querySelector("article[data-
|
|
1288
|
+
try { article = parseHtml(html).querySelector("article[data-blockeditor]")?.innerHTML ?? null; }
|
|
1281
1289
|
catch (_) { article = null; }
|
|
1282
1290
|
const etag = lastSeenEtag();
|
|
1283
1291
|
Promise.resolve()
|
|
@@ -1491,7 +1499,7 @@ export async function requestExitCheckpoint({ name, needsSave, permit, deadline,
|
|
|
1491
1499
|
const result = await withKeepalive(keepalive, () => save(permit));
|
|
1492
1500
|
if (over()) return failed("timeout");
|
|
1493
1501
|
if (!result?.ok) return failed(result?.code ?? "checkpoint-failed");
|
|
1494
|
-
return needsSave() ? failed("
|
|
1502
|
+
return needsSave() ? failed("blockeditor-not-checkpointed") : { ok: true };
|
|
1495
1503
|
}
|
|
1496
1504
|
}
|
|
1497
1505
|
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
// The menu's editing items: Undo and Redo, Ask AI, and Download a
|
|
2
|
-
// the service that already does the job and keeps no second copy
|
|
1
|
+
// The menu's editing items: Undo and Redo, Ask AI to improve this page, and Download a
|
|
2
|
+
// copy. Each one calls the service that already does the job and keeps no second copy
|
|
3
|
+
// of its state.
|
|
3
4
|
import { modeRefusalText } from "../../core/mode-refusal.js";
|
|
4
5
|
import { downloadHtml, documentName } from "../../core/download.js";
|
|
5
6
|
import { keys, revealLabel } from "./preferences.js";
|
|
7
|
+
import { hostMeta } from "../../core/host-meta.js";
|
|
6
8
|
|
|
7
9
|
const RESUME_KEY = "menu-resume";
|
|
8
10
|
const READY_MS = 5000;
|
|
11
|
+
const PAGE_READY_MS = 8000;
|
|
9
12
|
|
|
10
13
|
const clay = () => window.clay || {};
|
|
11
14
|
const session = () => clay().storage && clay().storage.session;
|
|
@@ -28,8 +31,31 @@ function whenPresent(get, ms = READY_MS) {
|
|
|
28
31
|
});
|
|
29
32
|
}
|
|
30
33
|
|
|
34
|
+
// A reload entry runs before the page session it reloaded into has finished preparing,
|
|
35
|
+
// so the surface it needs is not there yet. Waiting here is bounded: a page that never
|
|
36
|
+
// gets one ends at the same unavailable message a missing helper does.
|
|
37
|
+
function waitForPageAi(ms = PAGE_READY_MS) {
|
|
38
|
+
const page = clay().blockeditor;
|
|
39
|
+
if (!page) return Promise.resolve(true);
|
|
40
|
+
const start = Date.now();
|
|
41
|
+
return new Promise((resolve) => {
|
|
42
|
+
let done = false;
|
|
43
|
+
const finish = (ok) => { if (!done) { done = true; clearTimeout(timer); resolve(ok); } };
|
|
44
|
+
const tick = () => {
|
|
45
|
+
if (done) return;
|
|
46
|
+
if (clay().blockeditor?.ai) return finish(true);
|
|
47
|
+
if (Date.now() - start >= ms) return finish(false);
|
|
48
|
+
setTimeout(tick, 50);
|
|
49
|
+
};
|
|
50
|
+
const timer = setTimeout(() => finish(false), ms);
|
|
51
|
+
Promise.resolve(page.ready).catch(() => null).then(tick, tick);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
31
55
|
export function attachActions({ addItem, note, currentMode }) {
|
|
32
56
|
const resumers = new Map();
|
|
57
|
+
// A receipt for an item that registers later, once its host has answered.
|
|
58
|
+
let pendingReceipt = null;
|
|
33
59
|
|
|
34
60
|
// Runs `run` in edit mode, entering it first when the page is in view. A reload entry
|
|
35
61
|
// leaves a one-shot receipt in session storage so the action runs once the page is
|
|
@@ -56,15 +82,24 @@ export function attachActions({ addItem, note, currentMode }) {
|
|
|
56
82
|
|
|
57
83
|
function resumable(action, run) {
|
|
58
84
|
resumers.set(action, run);
|
|
85
|
+
if (pendingReceipt === action) {
|
|
86
|
+
pendingReceipt = null;
|
|
87
|
+
if (currentMode() === "edit") run();
|
|
88
|
+
}
|
|
59
89
|
return () => inEditMode(action, run);
|
|
60
90
|
}
|
|
61
91
|
|
|
62
92
|
let history = { canUndo: false, canRedo: false };
|
|
63
93
|
let heard = false;
|
|
64
94
|
|
|
95
|
+
// A Document keeps its history in its own editor, so the pair reads the page's service
|
|
96
|
+
// there and hyper-undo everywhere else. Reading it at use time means an editor that
|
|
97
|
+
// closed after the item was drawn takes the press with it.
|
|
98
|
+
const historySource = () => (pageWants("blockeditor") && clay().blockeditor?.history ? clay().blockeditor.history : pageWants("undo") ? clay().undo : null);
|
|
99
|
+
|
|
65
100
|
function renderUndo() {
|
|
66
|
-
if (!pageWants("undo")) return;
|
|
67
|
-
const live = currentMode() === "edit" &&
|
|
101
|
+
if (!pageWants("blockeditor") && !pageWants("undo")) return;
|
|
102
|
+
const live = currentMode() === "edit" && historySource();
|
|
68
103
|
// The menu loads late, so edits made before it are read from the service itself.
|
|
69
104
|
if (!heard && live && typeof live.canUndo === "boolean") history = { canUndo: live.canUndo, canRedo: !!live.canRedo };
|
|
70
105
|
addItem({
|
|
@@ -75,14 +110,14 @@ export function attachActions({ addItem, note, currentMode }) {
|
|
|
75
110
|
label: "Undo",
|
|
76
111
|
keys: keys("⌘Z", "Ctrl+Z"),
|
|
77
112
|
disabled: !(live && history.canUndo),
|
|
78
|
-
run: () =>
|
|
113
|
+
run: () => historySource()?.undo(),
|
|
79
114
|
},
|
|
80
115
|
{
|
|
81
116
|
id: "clay.undo.redo",
|
|
82
117
|
label: "Redo",
|
|
83
118
|
keys: keys("⌘⇧Z", "Ctrl+Shift+Z"),
|
|
84
119
|
disabled: !(live && history.canRedo),
|
|
85
|
-
run: () =>
|
|
120
|
+
run: () => historySource()?.redo(),
|
|
86
121
|
},
|
|
87
122
|
],
|
|
88
123
|
});
|
|
@@ -97,17 +132,39 @@ export function attachActions({ addItem, note, currentMode }) {
|
|
|
97
132
|
document.addEventListener("clay:modechange", renderUndo);
|
|
98
133
|
renderUndo();
|
|
99
134
|
|
|
135
|
+
// Only a host that lists an ai-edit helper, ready or turned off, gets the item: on
|
|
136
|
+
// hyperclay.com someone with an edit link who is not listed would otherwise see an
|
|
137
|
+
// item that can only say it is unavailable. In view mode the plugin is not loaded
|
|
138
|
+
// yet, so there is nobody to ask and the item waits for the click, as it always has.
|
|
100
139
|
if (pageWants("ai-edit")) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
140
|
+
(async () => {
|
|
141
|
+
// ai-edit loads late, after the editor is ready, so it can attach after this menu.
|
|
142
|
+
// Ask for it where it lands, as the item's own run does, rather than where the
|
|
143
|
+
// menu boots: the item is drawn once there is a plugin to say what the host lists.
|
|
144
|
+
const loaded = clay().aiEdit || (currentMode() === "edit" ? await whenPresent(() => clay().aiEdit) : null);
|
|
145
|
+
if (loaded?.available) {
|
|
146
|
+
if (!(await loaded.available())) return;
|
|
147
|
+
} else if (!loaded && pageWants("blockeditor")) {
|
|
148
|
+
// In view mode a Block document has no plugin to ask, so the host's own
|
|
149
|
+
// discovery says whether an ai-edit helper exists at all.
|
|
150
|
+
const meta = await hostMeta();
|
|
151
|
+
const listed = Array.isArray(meta.document?.helpers) && meta.document.helpers.some(
|
|
152
|
+
(helper) => helper && helper.name === "ai-edit" && (helper.state === "ready" || helper.state === "unavailable"),
|
|
153
|
+
);
|
|
154
|
+
if (!listed) return;
|
|
155
|
+
}
|
|
156
|
+
addItem({
|
|
157
|
+
id: "clay.ai",
|
|
158
|
+
label: "Ask AI to improve this page",
|
|
159
|
+
keys: keys("⌘J", "Ctrl+J"),
|
|
160
|
+
run: resumable("ai", async () => {
|
|
161
|
+
const ai = await whenPresent(() => clay().aiEdit);
|
|
162
|
+
const ready = ai && (pageWants("blockeditor") || !!clay().blockeditor) ? await waitForPageAi() : !!ai;
|
|
163
|
+
const opened = ready ? await ai.pick() : false;
|
|
164
|
+
if (!opened) note("Ask AI isn't available on this page right now.");
|
|
165
|
+
}),
|
|
166
|
+
});
|
|
167
|
+
})();
|
|
111
168
|
}
|
|
112
169
|
|
|
113
170
|
if (pageWants("cms") && clay().cms?.hasRules?.(document)) {
|
|
@@ -127,6 +184,18 @@ export function attachActions({ addItem, note, currentMode }) {
|
|
|
127
184
|
});
|
|
128
185
|
}
|
|
129
186
|
|
|
187
|
+
// The Yjs page store (`blockeditor`, and its split parts `blockeditor.1`, `blockeditor.2`, …) holds upload paths
|
|
188
|
+
// inside base64 updates, where no text rewrite reaches them. A copy that leaves this host
|
|
189
|
+
// leaves those tags out, as Hyperclay's own download does: the article names every upload
|
|
190
|
+
// in full, and the editor that opens the copy seeds the page from it.
|
|
191
|
+
const PAGE_STORE_TAG = /<script\b[^>]*>[\s\S]*?<\/script>\n?/gi;
|
|
192
|
+
const isPageStoreTag = (tag) => {
|
|
193
|
+
const open = tag.slice(0, tag.indexOf(">") + 1);
|
|
194
|
+
return /\bmerge="blockeditor(?:\.\d+)?"/.test(open) && /\bclay="[^"]*\blive\b/.test(open);
|
|
195
|
+
};
|
|
196
|
+
const withoutPageStore = (html) =>
|
|
197
|
+
/<article\b[^>]*\bdata-blockeditor\b/.test(html) ? html.replace(PAGE_STORE_TAG, (tag) => (isPageStoreTag(tag) ? "" : tag)) : html;
|
|
198
|
+
|
|
130
199
|
// The copy is what a save would send now, unsaved edits included. A reader has no
|
|
131
200
|
// unsaved edits, so the saved file is the same document.
|
|
132
201
|
addItem({
|
|
@@ -142,8 +211,10 @@ export function attachActions({ addItem, note, currentMode }) {
|
|
|
142
211
|
if (response.ok) html = await response.text();
|
|
143
212
|
}
|
|
144
213
|
} catch {}
|
|
145
|
-
//
|
|
214
|
+
// A copy that leaves this host keeps nothing that only resolves on it: the page store
|
|
215
|
+
// goes, and upload paths are named in full. A file: copy has no host to leave.
|
|
146
216
|
if (typeof html === "string" && /^https?:$/.test(location.protocol)) {
|
|
217
|
+
html = withoutPageStore(html);
|
|
147
218
|
html = html.replace(/(^|[^\w./:-])\/_\/uploads\//g, `$1${location.origin}/_/uploads/`);
|
|
148
219
|
}
|
|
149
220
|
if (typeof html !== "string" || !(await downloadHtml({ html, name: `${documentName()}.html` }))) {
|
|
@@ -190,6 +261,7 @@ export function attachActions({ addItem, note, currentMode }) {
|
|
|
190
261
|
storage.remove(RESUME_KEY);
|
|
191
262
|
const run = resumers.get(pending);
|
|
192
263
|
if (run && currentMode() === "edit") run();
|
|
264
|
+
else if (!run) pendingReceipt = pending;
|
|
193
265
|
}
|
|
194
266
|
|
|
195
267
|
return { inEditMode, resumable, refresh: renderUndo };
|
package/src/plugins/menu/seo.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { applyHead, FIELDS, readHead } from "./seo-head.js";
|
|
6
6
|
import { lookAt } from "../../ui/page-colour.js";
|
|
7
7
|
import MENU_CSS, { MENU_SURFACE } from "./style.js";
|
|
8
|
+
import { pageSkin } from "./shell.js";
|
|
8
9
|
import { mountEditorUI } from "../../ui/editor-ui.js";
|
|
9
10
|
import { deepActiveElement } from "../../dom/active-element.js";
|
|
10
11
|
import { hostMeta } from "../../core/host-meta.js";
|
|
@@ -60,7 +61,7 @@ const SHEET_CSS = `.clay-seo { box-sizing: border-box; width: 100%; border-botto
|
|
|
60
61
|
.clay-seo-count[data-over] { color: var(--bevel-ox); }
|
|
61
62
|
.clay-seo-derived { padding: 0; border: 0; background: none; color: var(--bevel-brass); font: 500 12px/1.3 var(--bevel-font-sans); text-decoration: underline; text-decoration-color: var(--bevel-line-3); text-underline-offset: 2px; cursor: pointer; }
|
|
62
63
|
.clay-seo-input { box-sizing: border-box; width: 100%; min-height: 32px; padding: 6px 9px; border: 1px solid var(--bevel-line-2); background: var(--bevel-ground); color: var(--bevel-ink); font: 400 13px/1.45 var(--bevel-font-sans); }
|
|
63
|
-
textarea.clay-seo-input { min-height: 52px; resize:
|
|
64
|
+
textarea.clay-seo-input { min-height: 52px; resize: none; overflow: hidden; }
|
|
64
65
|
textarea.clay-seo-input.is-short { min-height: 32px; }
|
|
65
66
|
.clay-seo-input::placeholder { color: var(--bevel-faint); opacity: 1; }
|
|
66
67
|
.clay-seo-input:hover { border-color: var(--bevel-faint); }
|
|
@@ -115,6 +116,9 @@ textarea.clay-seo-input.is-short { min-height: 32px; }
|
|
|
115
116
|
@media (pointer: coarse), (max-width: 680px) { .clay-seo .clay-menu-btn { min-height: 40px; } .clay-seo :is(input, textarea, select) { font-size: 16px; } }
|
|
116
117
|
@media (prefers-reduced-motion: reduce) { .clay-seo { animation: none; transition: none; } }`;
|
|
117
118
|
|
|
119
|
+
// Fields on a skinned sheet sit on the page's own surface.
|
|
120
|
+
const SKINNED_SHEET = `.clay-seo[part~="dock"] { --bevel-ground: var(--bevel-surface); }`;
|
|
121
|
+
|
|
118
122
|
const text = (value) => (value == null ? "" : String(value));
|
|
119
123
|
|
|
120
124
|
function element(tag, className, content) {
|
|
@@ -176,7 +180,7 @@ function pageBase() {
|
|
|
176
180
|
}
|
|
177
181
|
|
|
178
182
|
function isDocumentPage() {
|
|
179
|
-
return document.querySelectorAll("article[data-
|
|
183
|
+
return document.querySelectorAll("article[data-blockeditor]").length === 1;
|
|
180
184
|
}
|
|
181
185
|
|
|
182
186
|
const ATOM = "\uFFFC";
|
|
@@ -199,7 +203,7 @@ function titleItems(view) {
|
|
|
199
203
|
}
|
|
200
204
|
return [];
|
|
201
205
|
}
|
|
202
|
-
const article = document.querySelector("article[data-
|
|
206
|
+
const article = document.querySelector("article[data-blockeditor]");
|
|
203
207
|
const heading = article && [...article.children].find((node) => node.tagName === "H1");
|
|
204
208
|
if (!heading) return [];
|
|
205
209
|
let c = "";
|
|
@@ -217,7 +221,7 @@ function titleItems(view) {
|
|
|
217
221
|
// The same rule the runtime and the checkpoint use: the first root H1, and Untitled
|
|
218
222
|
// when it is empty or missing.
|
|
219
223
|
function firstHeadingText() {
|
|
220
|
-
const view = window.clay && window.clay.
|
|
224
|
+
const view = window.clay && window.clay.blockeditor && window.clay.blockeditor.view;
|
|
221
225
|
return documentTitle(titleItems(view));
|
|
222
226
|
}
|
|
223
227
|
|
|
@@ -471,11 +475,25 @@ export function open({ returnFocus } = {}) {
|
|
|
471
475
|
}
|
|
472
476
|
}
|
|
473
477
|
|
|
478
|
+
// A description box is as tall as its text, or its placeholder while empty: no inner scroll
|
|
479
|
+
// (David, Nov 11).
|
|
480
|
+
function fitBoxes() {
|
|
481
|
+
for (const box of inputs.values()) {
|
|
482
|
+
if (box.localName !== "textarea" || !box.isConnected) continue;
|
|
483
|
+
const stand = !box.value && box.placeholder;
|
|
484
|
+
if (stand) box.value = box.placeholder;
|
|
485
|
+
box.style.height = "auto";
|
|
486
|
+
box.style.height = `${box.scrollHeight + box.offsetHeight - box.clientHeight}px`;
|
|
487
|
+
if (stand) box.value = "";
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
474
491
|
function refresh() {
|
|
475
492
|
const titleValue = text(readField("title")).trim();
|
|
476
493
|
const descriptionValue = text(readField("description")).trim();
|
|
477
494
|
inputs.get("ogTitle").placeholder = titleValue;
|
|
478
495
|
inputs.get("ogDescription").placeholder = descriptionValue;
|
|
496
|
+
fitBoxes();
|
|
479
497
|
|
|
480
498
|
for (const [key, entry] of counters) {
|
|
481
499
|
const length = text(readField(key)).trim().length;
|
|
@@ -753,11 +771,19 @@ export function open({ returnFocus } = {}) {
|
|
|
753
771
|
});
|
|
754
772
|
|
|
755
773
|
document.addEventListener("clay:modechange", followMode);
|
|
774
|
+
// A page that skins its menu dresses this sheet the same way: its dock rule maps the page's own
|
|
775
|
+
// colours and fonts onto the sheet's tokens, so each look gets its own sheet.
|
|
776
|
+
const skin = pageSkin();
|
|
777
|
+
if (skin) root.setAttribute("part", "dock");
|
|
756
778
|
lookAt(root, { x: 0, y: 0, width: innerWidth, height: Math.min(200, innerHeight) }, MENU_SURFACE);
|
|
757
|
-
|
|
779
|
+
if (skin) root.style.removeProperty("--bevel-surface");
|
|
780
|
+
ui = mountEditorUI({ name: "seo", content: root, css: skin ? [MENU_CSS, SHEET_CSS, skin, SKINNED_SHEET] : [MENU_CSS, SHEET_CSS], before: document.body.firstChild });
|
|
758
781
|
writeHeight();
|
|
759
782
|
if (typeof ResizeObserver === "function") {
|
|
760
|
-
heightObserver = new ResizeObserver(
|
|
783
|
+
heightObserver = new ResizeObserver(() => {
|
|
784
|
+
fitBoxes();
|
|
785
|
+
writeHeight();
|
|
786
|
+
});
|
|
761
787
|
heightObserver.observe(root);
|
|
762
788
|
}
|
|
763
789
|
refresh();
|
|
@@ -2,7 +2,8 @@ export const MENU_SAFETY = `@layer clay-menu-safety {
|
|
|
2
2
|
.clay-menu-dock [hidden], .clay-menu-spots[hidden], .clay-menu-dock[hidden] { display: none !important; }
|
|
3
3
|
.clay-menu :focus-visible:not(.clay-menu-edit) { outline: 2px solid var(--bevel-brass) !important; outline-offset: -2px !important; }
|
|
4
4
|
@media (pointer: coarse), (max-width: 680px) {
|
|
5
|
-
|
|
5
|
+
/* A dismissible row's message and Dismiss sit inline on one line; their reach comes from MENU_TOUCH's pseudo-elements. */
|
|
6
|
+
.clay-menu-goo, .clay-menu-list [part~="step"], .clay-menu-list [role^="menuitem"]:not(.clay-menu-row > *) { min-width: 44px !important; min-height: 44px !important; }
|
|
6
7
|
}
|
|
7
8
|
@media (prefers-reduced-motion: reduce) {
|
|
8
9
|
.clay-menu-dock *, .clay-menu-dock *::before, .clay-menu-dock *::after { transition: none !important; animation: none !important; }
|
|
@@ -78,13 +79,20 @@ export const SHELL_C = `/* Popovers: the menu, the people panel, the status note
|
|
|
78
79
|
.clay-menu-list [role^="menuitem"] { box-sizing: border-box; display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%; margin: 0; border: 0; background: none; text-align: left; text-decoration: none; cursor: pointer; }
|
|
79
80
|
.clay-menu-list [role^="menuitem"]:hover:not([aria-disabled="true"]), .clay-menu-list [role^="menuitem"]:focus-visible { outline: none; background: var(--bevel-sunk); }
|
|
80
81
|
.clay-menu-list [role^="menuitem"][aria-disabled="true"] { cursor: default; }
|
|
81
|
-
.clay-menu-pair { display: flex; gap: 12px; padding: 3px 9px; }
|
|
82
|
+
.clay-menu-pair { display: flex; flex-wrap: wrap; gap: 12px; padding: 3px 9px; }
|
|
82
83
|
.clay-menu-list .clay-menu-pair [role="menuitem"] { flex: none; width: auto; justify-content: flex-start; gap: 9px; }
|
|
83
84
|
.clay-menu-list kbd { flex: none; white-space: nowrap; }
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
.clay-menu-row
|
|
85
|
+
/* The message, then a small Dismiss right after its last word (David, Nov 11). Both are inline, so
|
|
86
|
+
Dismiss follows the text wherever it wraps; the message reaches over the whole row, and Dismiss
|
|
87
|
+
sits above it with its own reach. */
|
|
88
|
+
.clay-menu-row { position: relative; padding: 5px 9px; }
|
|
89
|
+
.clay-menu-row:has(> [part~="item"]:hover, > [part~="item"]:focus-visible) { background: var(--bevel-sunk); }
|
|
90
|
+
.clay-menu-list .clay-menu-row > [part~="item"], .clay-menu-list .clay-menu-row > [part~="item"]:is(:hover, :focus-visible) { display: inline; width: auto; padding: 0; background: none; }
|
|
91
|
+
.clay-menu-list .clay-menu-row > [part~="item"]::before { content: ""; position: absolute; inset: 0; }
|
|
92
|
+
.clay-menu-list .clay-menu-row > [part~="dismiss"], .clay-menu-list .clay-menu-row > [part~="dismiss"]:is(:hover, :focus-visible) { position: relative; z-index: 1; display: inline; width: auto; min-height: 0; margin-left: 6px; padding: 0; background: none; white-space: nowrap; }
|
|
93
|
+
.clay-menu-list .clay-menu-row > [part~="dismiss"]::after { content: ""; position: absolute; inset: -6px -6px; }
|
|
94
|
+
.clay-menu-row [part~="dismiss-label"] { display: inline-block; padding: 2px 7px; border-radius: 4px; background: var(--bevel-sunk); color: var(--bevel-ink-2); font: 500 11px/1.3 var(--bevel-font-sans); }
|
|
95
|
+
.clay-menu-row > [part~="dismiss"]:hover [part~="dismiss-label"], .clay-menu-row > [part~="dismiss"]:focus-visible [part~="dismiss-label"] { color: var(--bevel-ink); }
|
|
88
96
|
.clay-menu-upgrade { display: inline-flex; align-items: center; gap: 8px; }
|
|
89
97
|
.clay-menu-upgrade::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--bevel-brass); }
|
|
90
98
|
.clay-menu-toggle .clay-menu-track { flex: none; }
|
|
@@ -125,12 +133,23 @@ export const MENU_SKIN = `.clay-menu { height: 34px; padding: 0 4px 0 2px; borde
|
|
|
125
133
|
.clay-menu-list kbd { font: 500 11px/1 var(--bevel-font-mono); padding: 3px 5px; border: 1px solid var(--bevel-line-2); background: var(--bevel-sunk); color: var(--bevel-muted); }
|
|
126
134
|
.clay-menu-list [part~="quiet"] { font-size: 12px; color: var(--bevel-muted); }
|
|
127
135
|
.clay-menu-sep { height: 1px; margin: 4px 2px; background: var(--bevel-line); }
|
|
128
|
-
.clay-menu-version { font: 400
|
|
136
|
+
.clay-menu-version { font: 400 13px/1.35 var(--bevel-font-sans); color: var(--bevel-ink); }
|
|
129
137
|
`;
|
|
130
138
|
|
|
131
139
|
// Last, so no skin can shrink a touch target or bring motion back.
|
|
132
140
|
export const MENU_TOUCH = `@media (pointer: coarse), (max-width: 680px) {
|
|
141
|
+
/* A phone menu fits the screen and never scrolls sideways: a little wider than on a desktop, long
|
|
142
|
+
labels wrap, and the shortcut keys a phone cannot press are hidden (David, Nov 11). */
|
|
143
|
+
.clay-menu-list { min-width: min(300px, calc(100vw - 16px)) !important; max-width: calc(100vw - 16px) !important; overflow-x: hidden !important; }
|
|
144
|
+
.clay-menu-list [role^="menuitem"], .clay-menu-list .clay-menu-version { white-space: normal; overflow-wrap: anywhere; }
|
|
145
|
+
.clay-menu-list kbd { display: none !important; }
|
|
146
|
+
.clay-menu-list .clay-menu-row { box-sizing: border-box; min-height: 44px; padding: 11px 9px; }
|
|
147
|
+
/* Dismiss sits inline after the message's last word, so its reach never goes up or left into the
|
|
148
|
+
message's own text: a taller label plus reach to the right and down makes the 44px. */
|
|
149
|
+
.clay-menu-row [part~="dismiss-label"] { padding: 7px 12px; font-size: 13px; }
|
|
150
|
+
.clay-menu-list .clay-menu-row > [part~="dismiss"]::after { inset: -2px -10px -11px 0; }
|
|
133
151
|
.clay-menu-list [role^="menuitem"] { min-height: 44px; font-size: 15px; }
|
|
152
|
+
.clay-menu-list .clay-menu-version { display: flex; align-items: center; min-height: 44px; font-size: 15px; }
|
|
134
153
|
.clay-menu-list .clay-menu-pair [role="menuitem"] { min-height: 44px; }
|
|
135
154
|
.clay-menu-list .clay-menu-stepper [role="menuitem"] { width: 44px; min-height: 44px; }
|
|
136
155
|
:is(.clay-menu-dock, .clay-seo) :is(input, textarea, select) { font-size: 16px; }
|
|
@@ -3,7 +3,7 @@ import { mountEditorUI } from "../../ui/editor-ui.js";
|
|
|
3
3
|
|
|
4
4
|
const SKIN_VERSION = "1";
|
|
5
5
|
const EDGE_GAP = 8;
|
|
6
|
-
const
|
|
6
|
+
const DISMISS_TEXT = "Dismiss";
|
|
7
7
|
const ARROW_PREV = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" aria-hidden="true" focusable="false"><path d="M224,128a8,8,0,0,1-8,8H59.31l58.35,58.34a8,8,0,0,1-11.32,11.32l-72-72a8,8,0,0,1,0-11.32l72-72a8,8,0,0,1,11.32,11.32L59.31,120H216A8,8,0,0,1,224,128Z"/></svg>';
|
|
8
8
|
const ARROW_NEXT = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" aria-hidden="true" focusable="false"><path d="M221.66,133.66l-72,72a8,8,0,0,1-11.32-11.32L196.69,136H40a8,8,0,0,1,0-16H196.69L138.34,61.66a8,8,0,0,1,11.32-11.32l72,72A8,8,0,0,1,221.66,133.66Z"/></svg>';
|
|
9
9
|
export const TRACK = '<span class="clay-menu-track" aria-hidden="true"><span class="clay-menu-thumb"></span></span>';
|
|
@@ -18,7 +18,7 @@ function findSlot() {
|
|
|
18
18
|
|
|
19
19
|
// A skin the page wrote, in <style clay-menu-skin="1" media="not all">. The media keeps it
|
|
20
20
|
// off the page itself. An unknown version means the default skin.
|
|
21
|
-
function pageSkin() {
|
|
21
|
+
export function pageSkin() {
|
|
22
22
|
const style = document.querySelector("style[clay-menu-skin]");
|
|
23
23
|
if (!style) return null;
|
|
24
24
|
if (style.getAttribute("clay-menu-skin") !== SKIN_VERSION) {
|
|
@@ -28,7 +28,8 @@ function pageSkin() {
|
|
|
28
28
|
return style.textContent;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
// `icon` and `label` draw the button (the Claygoo by default); a slot's own icon and label still win.
|
|
32
|
+
export function createShell({ capsuleStart = "", sections = [null], icon = CLAYGOO, label = "Clay menu" } = {}) {
|
|
32
33
|
const slotted = new Set(sections.flat().filter(Boolean));
|
|
33
34
|
const slot = findSlot();
|
|
34
35
|
const embedded = Boolean(slot);
|
|
@@ -43,9 +44,9 @@ export function createShell({ capsuleStart = "", sections = [null] } = {}) {
|
|
|
43
44
|
root.innerHTML =
|
|
44
45
|
`<div class="clay-menu" part="capsule" clay="editor-ui">` +
|
|
45
46
|
capsuleStart +
|
|
46
|
-
`<button type="button" class="clay-menu-goo" part="button" aria-haspopup="menu" aria-expanded="false" aria-label="
|
|
47
|
+
`<button type="button" class="clay-menu-goo" part="button" aria-haspopup="menu" aria-expanded="false" aria-label="${label}">${icon}</button>` +
|
|
47
48
|
`</div>` +
|
|
48
|
-
`<div class="clay-menu-list" part="list" role="menu" aria-label="
|
|
49
|
+
`<div class="clay-menu-list" part="list" role="menu" aria-label="${label}" hidden></div>` +
|
|
49
50
|
`<div class="clay-menu-note" part="note" role="status" hidden></div>`;
|
|
50
51
|
|
|
51
52
|
const goo = root.querySelector(".clay-menu-goo");
|
|
@@ -177,6 +178,8 @@ export function createShell({ capsuleStart = "", sections = [null] } = {}) {
|
|
|
177
178
|
return itemButton(item);
|
|
178
179
|
}
|
|
179
180
|
|
|
181
|
+
// The item, then a small Dismiss right after its last word. An x at the row's end read as the
|
|
182
|
+
// close for the whole menu. The item's own dismiss label stays as the button's title.
|
|
180
183
|
function dismissibleRow(item) {
|
|
181
184
|
const row = document.createElement("div");
|
|
182
185
|
row.className = "clay-menu-row";
|
|
@@ -186,9 +189,11 @@ export function createShell({ capsuleStart = "", sections = [null] } = {}) {
|
|
|
186
189
|
dismiss.setAttribute("role", "menuitem");
|
|
187
190
|
dismiss.setAttribute("part", "dismiss");
|
|
188
191
|
dismiss.dataset.menuId = `${item.id}.dismiss`;
|
|
189
|
-
dismiss.setAttribute("aria-label", item.dismiss.label);
|
|
190
192
|
dismiss.title = item.dismiss.label;
|
|
191
|
-
|
|
193
|
+
const text = document.createElement("span");
|
|
194
|
+
text.setAttribute("part", "dismiss-label");
|
|
195
|
+
text.textContent = DISMISS_TEXT;
|
|
196
|
+
dismiss.append(text);
|
|
192
197
|
dismiss.addEventListener("click", async () => {
|
|
193
198
|
dismiss.disabled = true;
|
|
194
199
|
let result;
|
|
@@ -10,7 +10,6 @@ import { OFF, labelOf, looks, nameOf, paintLook, recordLook } from "./looks.js";
|
|
|
10
10
|
export { looks };
|
|
11
11
|
|
|
12
12
|
const RECEIPT = "variants-choose";
|
|
13
|
-
const KEEP_ID = "clay.variants.keep";
|
|
14
13
|
const CHOOSE_LABEL = "Change the page look";
|
|
15
14
|
const KEEP_LABEL = "Keep one page look";
|
|
16
15
|
|
|
@@ -234,22 +233,23 @@ export function attachVariants({ root, capsule, addItem, removeItem, note, curre
|
|
|
234
233
|
pill = null;
|
|
235
234
|
removeItem("clay.look");
|
|
236
235
|
removeItem("clay.look.use");
|
|
237
|
-
removeItem(KEEP_ID);
|
|
238
236
|
return;
|
|
239
237
|
}
|
|
240
238
|
if (root.hasAttribute("data-embedded")) {
|
|
241
239
|
const name = shown();
|
|
240
|
+
// "Theme: Dusk" and two arrows. While editing, each step is the choice and saves like any
|
|
241
|
+
// edit: no confirm, no Keep row (David, Nov 11).
|
|
242
242
|
if (wantsRow) {
|
|
243
243
|
addItem({
|
|
244
244
|
id: "clay.look",
|
|
245
245
|
section: "start",
|
|
246
246
|
stepper: {
|
|
247
|
-
label: "
|
|
248
|
-
value:
|
|
247
|
+
label: "Theme:",
|
|
248
|
+
value: labelFor(name),
|
|
249
249
|
prev: () => step(-1),
|
|
250
250
|
next: () => step(1),
|
|
251
|
-
prevLabel: "Previous
|
|
252
|
-
nextLabel: "Next
|
|
251
|
+
prevLabel: "Previous theme",
|
|
252
|
+
nextLabel: "Next theme",
|
|
253
253
|
},
|
|
254
254
|
});
|
|
255
255
|
} else {
|
|
@@ -257,8 +257,6 @@ export function attachVariants({ root, capsule, addItem, removeItem, note, curre
|
|
|
257
257
|
}
|
|
258
258
|
if (!isEdit() && previewing !== null) addItem({ id: "clay.look.use", section: "start", label: "Use this look", run: useShown });
|
|
259
259
|
else removeItem("clay.look.use");
|
|
260
|
-
if (isEdit()) addItem({ id: KEEP_ID, label: `Keep ${labelFor(savedName())}, remove the others…`, run: () => keep() });
|
|
261
|
-
else removeItem(KEEP_ID);
|
|
262
260
|
return;
|
|
263
261
|
}
|
|
264
262
|
if (!pill) pill = buildPill();
|
|
@@ -271,8 +269,6 @@ export function attachVariants({ root, capsule, addItem, removeItem, note, curre
|
|
|
271
269
|
label.append(count);
|
|
272
270
|
pill.querySelector(".clay-variants-use").hidden = isEdit() || previewing === null;
|
|
273
271
|
pill.querySelector(".clay-variants-keep").hidden = !isEdit();
|
|
274
|
-
if (isEdit()) addItem({ id: KEEP_ID, label: `Keep ${labelFor(savedName())}, remove the others…`, run: () => keep() });
|
|
275
|
-
else removeItem(KEEP_ID);
|
|
276
272
|
}
|
|
277
273
|
|
|
278
274
|
function refresh() {
|