@panphora/clayjs 1.15.1 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -5
- package/THIRD-PARTY-NOTICES.md +16 -0
- package/compat/highlight-11.9.0.min.js +1213 -0
- package/compat/highlight-LICENSE +29 -0
- package/compat/journal-assets.lock.json +22 -0
- package/compat/overtype-2.6.1.min.js +116 -0
- package/compat/overtype-LICENSE +21 -0
- package/dist/all.js +90 -0
- package/dist/clay-dom.js +84 -0
- package/dist/clay-events.js +103 -0
- package/dist/clay-internals.js +85 -0
- package/dist/clay-options.js +93 -0
- package/dist/clay-router.js +98 -0
- package/dist/clay-ui.js +95 -0
- package/dist/clay-utils.js +84 -0
- package/dist/clay.js +146 -0
- package/dist/clay.standalone.js +83090 -58706
- package/dist/m/attrs/add-from-T5LJXFFI.js +1 -0
- package/dist/m/attrs/onaftersave-OKSWEJQF.js +1 -0
- package/dist/m/attrs/refetch-on-save-NWPPXOCZ.js +1 -0
- package/dist/m/attrs/save-freeze-FUP4Q4X3.js +1 -0
- package/dist/m/c-2AZDZWCK.js +1 -0
- package/dist/m/c-2JL6E75N.js +1 -0
- package/dist/m/c-2M73252O.js +1 -0
- package/dist/m/c-2SPVQSHC.js +1 -0
- package/dist/m/c-33HUYEDI.js +1 -0
- package/dist/m/c-33JJ6CBX.js +2 -0
- package/dist/m/c-35NBGMZB.js +1 -0
- package/dist/m/c-3GJ4SDE2.js +1 -0
- package/dist/m/c-3IQRECYS.js +1 -0
- package/dist/m/c-3OWDMNJR.js +2 -0
- package/dist/m/c-46XYM55L.js +1 -0
- package/dist/m/c-4B6H4G5V.js +1 -0
- package/dist/m/c-4DRMS4QG.js +9 -0
- package/dist/m/c-4FFHZM32.js +1 -0
- package/dist/m/c-4JZDZFF6.js +1 -0
- package/dist/m/c-4L3BTFRK.js +1 -0
- package/dist/m/c-4Q2XTQ2N.js +2 -0
- package/dist/m/c-4WKFKEKF.js +1 -0
- package/dist/m/c-4YSCRICO.js +1 -0
- package/dist/m/c-54RCDCBU.js +1 -0
- package/dist/m/c-5M4YEKCX.js +4 -0
- package/dist/m/c-5R4PTRG2.js +1 -0
- package/dist/m/c-5V3MOVJT.js +1 -0
- package/dist/m/c-5VYOWDTI.js +1 -0
- package/dist/m/c-5Y6TNX5W.js +34 -0
- package/dist/m/c-5YIHJ3TJ.js +1 -0
- package/dist/m/c-66O32MV3.js +28 -0
- package/dist/m/c-6HMB24EV.js +1 -0
- package/dist/m/c-7DJDKPGL.js +1 -0
- package/dist/m/c-7O6AFR65.js +1 -0
- package/dist/m/c-7SWMYKAI.js +1 -0
- package/dist/m/c-7VGZ7RU5.js +1 -0
- package/dist/m/c-A7LS5UZW.js +1 -0
- package/dist/m/c-ANQTJ3B5.js +2 -0
- package/dist/m/c-AQLFEATB.js +1 -0
- package/dist/m/c-AYVOREBE.js +1 -0
- package/dist/m/c-B2ZXPOS3.js +3 -0
- package/dist/m/c-BBVGTQG7.js +1 -0
- package/dist/m/c-BMIZKMPV.js +1 -0
- package/dist/m/c-BTDI4Y23.js +1 -0
- package/dist/m/c-BWFVSBDF.js +1 -0
- package/dist/m/c-BYTKL6UX.js +1 -0
- package/dist/m/c-CFHW5AMY.js +6 -0
- package/dist/m/c-CJZSLMVQ.js +1 -0
- package/dist/m/c-CYWLPPUS.js +1 -0
- package/dist/m/c-CZUSOB7V.js +1 -0
- package/dist/m/c-DBE6ORSI.js +1 -0
- package/dist/m/c-DCFSEJZG.js +1 -0
- package/dist/m/c-DNZ5IFM6.js +1 -0
- package/dist/m/c-EDHUR4MX.js +1 -0
- package/dist/m/c-EJTGYSLN.js +1 -0
- package/dist/m/c-EY6UOM54.js +1 -0
- package/dist/m/c-F3CKJTJS.js +1 -0
- package/dist/m/c-F7Y6FLPY.js +1 -0
- package/dist/m/c-FA4DZVTC.js +1 -0
- package/dist/m/c-FILLTJA7.js +1 -0
- package/dist/m/c-G2BUZITR.js +1 -0
- package/dist/m/c-GB3JTV6E.js +1 -0
- package/dist/m/c-GBGWXTX4.js +1 -0
- package/dist/m/c-GHBCCVG4.js +1 -0
- package/dist/m/c-GJAEGGXY.js +1 -0
- package/dist/m/c-GOWBDM6J.js +1 -0
- package/dist/m/c-GQ6F6IDK.js +1 -0
- package/dist/m/c-H4LG442Q.js +1 -0
- package/dist/m/c-HA6INT6J.js +1 -0
- package/dist/m/c-HPURYVZS.js +2 -0
- package/dist/m/c-HRDCD3WN.js +67 -0
- package/dist/m/c-HT33EQRN.js +1 -0
- package/dist/m/c-HVYXIS72.js +1 -0
- package/dist/m/c-IB52R237.js +1 -0
- package/dist/m/c-IJUK2GPW.js +1 -0
- package/dist/m/c-IKWNE4R4.js +1 -0
- package/dist/m/c-IU3IYEU6.js +1 -0
- package/dist/m/c-IZ2EBRAJ.js +1 -0
- package/dist/m/c-J7CA54IP.js +1 -0
- package/dist/m/c-JAX2667S.js +6 -0
- package/dist/m/c-KI7M4AY3.js +1 -0
- package/dist/m/c-KIPQJX4B.js +1 -0
- package/dist/m/c-KKWLDOPM.js +1 -0
- package/dist/m/c-KR4UW4KW.js +1 -0
- package/dist/m/c-KY3VJGUA.js +8 -0
- package/dist/m/c-L4WQSC27.js +1 -0
- package/dist/m/c-LFPHCXY3.js +1 -0
- package/dist/m/c-LR4CGEPT.js +91 -0
- package/dist/m/c-LRPUO2MX.js +1 -0
- package/dist/m/c-LTGMXXKO.js +1 -0
- package/dist/m/c-LXENEBV7.js +1 -0
- package/dist/m/c-LZJPNR2W.js +1 -0
- package/dist/m/c-MMUIUUZG.js +2 -0
- package/dist/m/c-MTQHWQC3.js +1 -0
- package/dist/m/c-N326R2JD.js +1 -0
- package/dist/m/c-N7JPUPGC.js +1 -0
- package/dist/m/c-NMJRXKPC.js +8 -0
- package/dist/m/c-NRPJEVJS.js +1 -0
- package/dist/m/c-NUHP2XDB.js +1 -0
- package/dist/m/c-NZMNXVF6.js +1 -0
- package/dist/m/c-OCSZ4QGN.js +1 -0
- package/dist/m/c-OIBUTDXI.js +1 -0
- package/dist/m/c-OIDRZKAF.js +1 -0
- package/dist/m/c-OYTFP5QN.js +1 -0
- package/dist/m/c-P7KNDG34.js +1 -0
- package/dist/m/c-PPOSCAQD.js +1 -0
- package/dist/m/c-PQ5LK6QE.js +993 -0
- package/dist/m/c-PZ4XEPUP.js +2 -0
- package/dist/m/c-QHIWXHRO.js +1 -0
- package/dist/m/c-QHWJ5ZIJ.js +1 -0
- package/dist/m/c-QIX5BJYN.js +1 -0
- package/dist/m/c-QNKREOL6.js +1 -0
- package/dist/m/c-QQHEX6HA.js +1 -0
- package/dist/m/c-R7RMANJI.js +9 -0
- package/dist/m/c-RI4NT75Y.js +1 -0
- package/dist/m/c-RM7J7BV2.js +1 -0
- package/dist/m/c-RUJKSUQW.js +1 -0
- package/dist/m/c-RVMWGXEJ.js +1 -0
- package/dist/m/c-S7H2DRCB.js +1 -0
- package/dist/m/c-S7LK4KUE.js +1 -0
- package/dist/m/c-SGCCC4FW.js +25 -0
- package/dist/m/c-SGIA4IEQ.js +188 -0
- package/dist/m/c-SWRJFCNN.js +1 -0
- package/dist/m/c-T4VO4OCB.js +1 -0
- package/dist/m/c-TCCA5BZN.js +2 -0
- package/dist/m/c-TQEMVJCS.js +1 -0
- package/dist/m/c-TQZ2JYHD.js +1 -0
- package/dist/m/c-TR6RMDQ7.js +3 -0
- package/dist/m/c-TRS6TM6O.js +1 -0
- package/dist/m/c-UGHH4MB3.js +1 -0
- package/dist/m/c-UKHTLWUW.js +1 -0
- package/dist/m/c-UL2YUY52.js +1 -0
- package/dist/m/c-UNN7LWCT.js +1 -0
- package/dist/m/c-UXBMRDZB.js +235 -0
- package/dist/m/c-V7PZZRG7.js +1 -0
- package/dist/m/c-VAK7SG37.js +1 -0
- package/dist/m/c-VDSS4K3Z.js +1 -0
- package/dist/m/c-VFX45IZQ.js +1 -0
- package/dist/m/c-VHNSBD2M.js +1 -0
- package/dist/m/c-VKEDWYDF.js +1 -0
- package/dist/m/c-VL52ADDR.js +1 -0
- package/dist/m/c-WN5AY3OZ.js +1 -0
- package/dist/m/c-WNYBLIOZ.js +1 -0
- package/dist/m/c-WRBKEJD4.js +1 -0
- package/dist/m/c-WWDBYXLK.js +1 -0
- package/dist/m/c-WYFDLITL.js +1 -0
- package/dist/m/c-XN6MBKI6.js +67 -0
- package/dist/m/c-XNNW2CWK.js +1 -0
- package/dist/m/c-XPELB6E5.js +1 -0
- package/dist/m/c-XQXZAO7N.js +1 -0
- package/dist/m/c-Y6USGTS5.js +5 -0
- package/dist/m/c-YDH7Q3NY.js +1 -0
- package/dist/m/c-YG2NJYS6.js +135 -0
- package/dist/m/c-Z36J63PP.js +1 -0
- package/dist/m/c-Z4VRC7GU.js +7 -0
- package/dist/m/c-Z6K52OLP.js +19 -0
- package/dist/m/c-ZDY2MDAA.js +21 -0
- package/dist/m/c-ZE46QDIH.js +1 -0
- package/dist/m/c-ZUCOKOHT.js +1 -0
- package/dist/m/core/admin-attrs-VGNLAUDK.js +1 -0
- package/dist/m/core/autosave-E4PEFPZ6.js +1 -0
- package/dist/m/core/conflict-notice-VQ6Y64PH.js +1 -0
- package/dist/m/core/draft-mode-WSQAT67S.js +1 -0
- package/dist/m/core/host-permission-XN3K2IW3.js +1 -0
- package/dist/m/core/is-edit-mode-JXHDVGUL.js +1 -0
- package/dist/m/core/persist-HKHA66IY.js +3 -0
- package/dist/m/core/recovery-TBBSICE2.js +1 -0
- package/dist/m/core/save-WUCHTQBE.js +1 -0
- package/dist/m/core/save-core-FJVHT5M3.js +1 -0
- package/dist/m/core/snapshot-F3SWDZMM.js +1 -0
- package/dist/m/core/unsaved-warning-STKBHE6G.js +1 -0
- package/dist/m/dom/all-APS5ZSKP.js +1 -0
- package/dist/m/dom/dom-helpers-L7OSR6S4.js +1 -0
- package/dist/m/events/index-23DPTUT4.js +1 -0
- package/dist/m/internals/index-WOVAP3RU.js +1 -0
- package/dist/m/lib/cache-bust-CGWT6ZJI.js +1 -0
- package/dist/m/lib/region-policy-SB2AWVG5.js +1 -0
- package/dist/m/loader-HXX6YNH5.js +1 -0
- package/dist/m/manifest-F22DEDAC.js +1 -0
- package/dist/m/manifest-edit-C3C7376B.js +1 -0
- package/dist/m/manifest.json +3491 -0
- package/dist/m/options/options-2LH76JQ3.js +1 -0
- package/dist/m/page/editor-XUTB2HB2.js +189 -0
- package/dist/m/plugins/ai-edit-ZQ4CGWIP.js +6 -0
- package/dist/m/plugins/bind-text-NX46N5UV.js +1 -0
- package/dist/m/plugins/cms-HP3LSTPN.js +2293 -0
- package/dist/m/plugins/demo-ZIBFAA3R.js +1 -0
- package/dist/m/plugins/derive-UAAA4V4S.js +1 -0
- package/dist/m/plugins/indicator-PV4YW2ID.js +1 -0
- package/dist/m/plugins/live-NUTTXSBS.js +1 -0
- package/dist/m/plugins/menu-HCKO3DSP.js +138 -0
- package/dist/m/plugins/message-LQ6EDH4V.js +1 -0
- package/dist/m/plugins/page-KSUH7G6J.js +2 -0
- package/dist/m/plugins/page-view-W73OW7WI.js +1 -0
- package/dist/m/plugins/people-AJJ32YCG.js +1 -0
- package/dist/m/plugins/quickcrop-QNY3PKLD.js +26 -0
- package/dist/m/plugins/quickcrop-QNY3PKLD.js.LEGAL.txt +7 -0
- package/dist/m/plugins/richclay-RC3L2F6X.js +517 -0
- package/dist/m/plugins/richclay-RC3L2F6X.js.LEGAL.txt +1 -0
- package/dist/m/plugins/sortable-YRMQX3ZU.js +1 -0
- package/dist/m/plugins/source-KHK5UUSK.js +1 -0
- package/dist/m/plugins/undo-OF2L3CXU.js +1 -0
- package/dist/m/plugins/unsent-HJFLQJ2O.js +1 -0
- package/dist/m/plugins/upgrade-ZNYODP5Y.js +1 -0
- package/dist/m/plugins/upload-XSGNILUY.js +1 -0
- package/dist/m/plugins/visitor-drafts-XK5GW55Q.js +21 -0
- package/dist/m/plugins/visitor-drafts-owner-KSSH75EV.js +1 -0
- package/dist/m/plugins/wire-ZWVWKF76.js +1 -0
- package/dist/m/reader-core-ILWLXVMP.js +68 -0
- package/dist/m/route/route-KOCZSEGN.js +1 -0
- package/dist/m/sync/live-sync-4AUVXVJU.js +1 -0
- package/dist/m/ui/index-EVHKMKBL.js +1 -0
- package/dist/m/utils/index-4TJCVLT7.js +1 -0
- package/dist/m/vendor/Sortable.vendor-A755ITLN.js +3 -0
- package/dist/m/vendor/Sortable.vendor-A755ITLN.js.LEGAL.txt +1 -0
- package/dist/m/vendor/sap-core.vendor-A7BMUYZT.js +6 -0
- package/dist/offline-manifest.json +3800 -0
- package/dist/page/themes/light-1.css +406 -0
- package/dist/server/core.cjs +23662 -22860
- package/dist/server/offline-runtime.cjs +4954 -0
- package/dist/server/offline-runtime.mjs +4923 -0
- package/dist/server/rooms.mjs +9 -0
- package/docs/guide.md +1078 -669
- package/entries/all.js +2 -0
- package/entries/clay-data.js +1 -1
- package/entries/clay-dom.js +2 -0
- package/entries/clay-events.js +2 -0
- package/entries/clay-internals.js +2 -0
- package/entries/clay-options.js +2 -0
- package/entries/clay-router.js +2 -0
- package/entries/clay-ui.js +2 -0
- package/entries/clay-utils.js +2 -0
- package/entries/clay.js +2 -0
- package/entries/sap.js +6 -6
- package/fonts/ibm-plex-mono-LICENSE +93 -0
- package/fonts/ibm-plex-mono-latin-300-normal.woff2 +0 -0
- package/fonts/ibm-plex-mono-latin-400-italic.woff2 +0 -0
- package/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
- package/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
- package/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
- package/fonts/ibm-plex-sans-LICENSE +93 -0
- package/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
- package/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
- package/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
- package/fonts/ibm-plex.css +71 -0
- package/fonts/inter-LICENSE +93 -0
- package/fonts/inter-cyrillic-ext-wght-normal.woff2 +0 -0
- package/fonts/inter-cyrillic-wght-normal.woff2 +0 -0
- package/fonts/inter-greek-ext-wght-normal.woff2 +0 -0
- package/fonts/inter-greek-wght-normal.woff2 +0 -0
- package/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
- package/fonts/inter-latin-wght-normal.woff2 +0 -0
- package/fonts/inter-vietnamese-wght-normal.woff2 +0 -0
- package/fonts/inter.css +62 -0
- package/fonts/newsreader-LICENSE +93 -0
- package/fonts/newsreader-latin-ext-opsz-normal.woff2 +0 -0
- package/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
- package/fonts/newsreader-vietnamese-opsz-normal.woff2 +0 -0
- package/fonts/newsreader.css +26 -0
- package/fonts/work-sans-LICENSE +93 -0
- package/fonts/work-sans-latin-wght-normal.woff2 +0 -0
- package/fonts/work-sans.css +8 -0
- package/package.json +20 -3
- package/packed-contract.json +1 -0
- package/src/attrs/add-from.js +27 -4
- package/src/attrs/save-freeze.js +7 -52
- package/src/core/admin-attrs.js +119 -12
- package/src/core/admin-contenteditable.js +12 -10
- package/src/core/admin-inputs.js +14 -15
- package/src/core/admin-onclick.js +2 -0
- package/src/core/autosave.js +74 -21
- package/src/core/conflict-download.js +22 -0
- package/src/core/conflict-notice-ui.js +1173 -0
- package/src/core/conflict-notice.js +140 -697
- package/src/core/edit-mode.js +147 -14
- package/src/core/etag.js +30 -12
- package/src/core/host-meta.js +72 -8
- package/src/core/host-permission.js +29 -0
- package/src/core/is-edit-mode.js +145 -12
- package/src/core/mode-key.js +125 -0
- package/src/core/mode-lifecycle.js +544 -0
- package/src/core/mode-receipt.js +30 -0
- package/src/core/mode-refusal.js +13 -0
- package/src/core/mode-resources.js +52 -0
- package/src/core/mode-support.js +82 -0
- package/src/core/mode-switch.js +259 -0
- package/src/core/mode-transition.js +112 -0
- package/src/core/page-data-write.js +305 -0
- package/src/core/page-data.js +26 -227
- package/src/core/page-format-wire.js +4 -0
- package/src/core/page-format.js +58 -0
- package/src/core/persist.js +37 -9
- package/src/core/preserve-authored.js +114 -0
- package/src/core/recovery.js +772 -0
- package/src/core/runtime-url.js +105 -0
- package/src/core/save-core.js +109 -12
- package/src/core/save-replace.js +72 -0
- package/src/core/save-size-notice.js +134 -0
- package/src/core/save-size.js +140 -0
- package/src/core/save.js +805 -118
- package/src/core/snapshot.js +121 -11
- package/src/core/source-map.js +157 -9
- package/src/core/unsaved-warning.js +14 -4
- package/src/core/upgrade-run.js +408 -0
- package/src/core/version.js +18 -0
- package/src/lib/assets.js +30 -0
- package/src/lib/autosave-debug-gate.js +50 -0
- package/src/lib/autosave-scheduler.js +141 -0
- package/src/lib/boot-imports.js +8 -0
- package/src/lib/derived.js +3 -1
- package/src/lib/dirty-gate.js +15 -0
- package/src/lib/doc-storage.js +33 -0
- package/src/lib/effect.js +9 -4
- package/src/lib/mutation.js +4 -2
- package/src/lib/offline-runtime.js +226 -0
- package/src/lib/preload.js +48 -0
- package/src/lib/root-attrs.js +1 -1
- package/src/lib/trash.js +18 -0
- package/src/lib/undo/capture-move.js +152 -0
- package/src/live/local-channel.js +61 -0
- package/src/live/local-lane.js +60 -9
- package/src/live/server-lane.js +6 -3
- package/src/loader-logic.js +76 -15
- package/src/loader.js +218 -30
- package/src/page/adopt-boot.js +76 -22
- package/src/page/adopt.js +25 -4
- package/src/page/awareness.js +230 -0
- package/src/page/blocks.js +79 -5
- package/src/page/blocksel.js +20 -4
- package/src/page/board-face.js +13 -0
- package/src/page/board-panel.js +5 -17
- package/src/page/board-style.js +2 -13
- package/src/page/board-view.js +1 -11
- package/src/page/board-views.js +17 -0
- package/src/page/board.js +2 -2
- package/src/page/boot-pack.js +26 -0
- package/src/page/boot.js +237 -0
- package/src/page/checklist.js +1 -1
- package/src/page/chrome.js +411 -61
- package/src/page/csv-import.js +17 -2
- package/src/page/document-title-dom.js +40 -0
- package/src/page/document-title-runtime.js +76 -0
- package/src/page/document-title.js +9 -0
- package/src/page/drag.js +48 -13
- package/src/page/drop.js +2 -1
- package/src/page/editor.js +330 -86
- package/src/page/feature-loader.js +72 -0
- package/src/page/features/board.js +12 -0
- package/src/page/features/code.js +13 -0
- package/src/page/features/media.js +290 -0
- package/src/page/features/registry.js +23 -0
- package/src/page/features/table.js +383 -0
- package/src/page/{tool-view.js → features/tool.js} +33 -2
- package/src/page/format-codec.js +215 -0
- package/src/page/format-gate.js +179 -0
- package/src/page/format-level.js +157 -0
- package/src/page/highlight-slot.js +23 -0
- package/src/page/highlight.js +30 -16
- package/src/page/history-intent.js +78 -0
- package/src/page/inline.js +18 -25
- package/src/page/items.js +52 -11
- package/src/page/link.js +1 -0
- package/src/page/markdown.js +86 -1
- package/src/page/media-views.js +3 -0
- package/src/page/media.js +33 -245
- package/src/page/outline-cache.js +11 -0
- package/src/page/placeholder.js +27 -7
- package/src/page/projection.js +196 -50
- package/src/page/reader-patch.js +306 -0
- package/src/page/recover.js +1 -1
- package/src/page/rich/page-tool.js +1 -4
- package/src/page/runtime-owner.js +27 -0
- package/src/page/save-projection.js +7 -4
- package/src/page/schema.js +14 -0
- package/src/page/table-rect-key.js +3 -0
- package/src/page/table-select.js +4 -3
- package/src/page/table-style.js +1 -1
- package/src/page/table-views.js +3 -0
- package/src/page/table.js +8 -293
- package/src/page/themes/light-1.css +139 -2
- package/src/page/themes/light-1.source.css +269 -0
- package/src/page/tool-capability.js +3 -0
- package/src/page/tool-views.js +3 -0
- package/src/page/view.js +390 -107
- package/src/page/ybind/awareness.js +172 -0
- package/src/page/ybind/binding.js +9 -1
- package/src/page/ybind/bridge.js +50 -47
- package/src/page/ybind/decode.js +52 -19
- package/src/page/ybind/doc.js +27 -2
- package/src/page/ybind/group.js +12 -3
- package/src/page/ybind/index.js +2 -0
- package/src/page/ybind/lineage.js +71 -0
- package/src/page/ybind/marks.js +25 -1
- package/src/page/ybind/migrate.js +48 -13
- package/src/page/ybind/moves.js +32 -21
- package/src/page/ybind/positions.js +50 -0
- package/src/page/ybind/provider.js +84 -22
- package/src/page/ybind/recovery-proof.js +191 -0
- package/src/page/ybind/recovery-replay.js +130 -0
- package/src/page/ybind/tokens.js +15 -6
- package/src/page/ybind/walk.js +10 -3
- package/src/page/ybind/writer.js +48 -4
- package/src/plugins/ai-edit.js +167 -32
- package/src/plugins/bind-text.js +218 -0
- package/src/plugins/cms.js +93 -0
- package/src/plugins/indicator.js +57 -5
- package/src/plugins/live.js +282 -34
- package/src/plugins/menu/claygoo.svg.js +1 -0
- package/src/plugins/menu/seo-head.js +323 -0
- package/src/plugins/menu/seo.js +849 -0
- package/src/plugins/menu.js +425 -0
- package/src/plugins/page-view.js +131 -0
- package/src/plugins/page.js +1022 -275
- package/src/plugins/people.js +158 -31
- package/src/plugins/richclay.js +119 -9
- package/src/plugins/sortable.js +370 -60
- package/src/plugins/source.js +189 -366
- package/src/plugins/undo.js +289 -19
- package/src/plugins/unsent.js +132 -0
- package/src/plugins/upgrade-run.js +1 -0
- package/src/plugins/upgrade.js +210 -0
- package/src/plugins/upload-task.js +571 -0
- package/src/plugins/upload-ui.js +265 -0
- package/src/plugins/upload.js +34 -153
- package/src/plugins/visitor-drafts/inert.js +32 -0
- package/src/plugins/visitor-drafts/owner-chip.js +3 -0
- package/src/plugins/visitor-drafts/prompt.js +2 -2
- package/src/plugins/visitor-drafts-owner.js +85 -0
- package/src/plugins/visitor-drafts.js +31 -42
- package/src/plugins/wire.js +82 -1
- package/src/reader-core.js +26 -0
- package/src/recovery/conflicts.js +287 -0
- package/src/recovery/identity.js +154 -0
- package/src/recovery/store.js +792 -0
- package/src/recovery/undo.js +257 -0
- package/src/server/checkpoint/index.js +68 -4
- package/src/server/offline-runtime/index.js +214 -0
- package/src/server/rooms/index.js +2 -1
- package/src/server/rooms/live-data-rooms.js +2 -2
- package/src/server/rooms/page-admission.js +33 -0
- package/src/server/rooms/page-lineage.js +56 -0
- package/src/server/rooms/page-rebase.js +11 -5
- package/src/server/rooms/page-state.js +2 -0
- package/src/server/rooms/page-write-admission.js +9 -3
- package/src/source/session.js +705 -0
- package/src/sync/conflict-revert.js +5 -4
- package/src/sync/conflicts-edit.js +119 -0
- package/src/sync/conflicts-facade.js +49 -0
- package/src/sync/conflicts.js +99 -1
- package/src/sync/editing-marker.js +37 -6
- package/src/sync/editing-sender.js +8 -1
- package/src/sync/live-sync-edit.js +63 -0
- package/src/sync/live-sync.js +364 -119
- package/src/sync/local-presence.js +187 -0
- package/src/sync/merge-declarations.js +10 -0
- package/src/sync/merge-engine.js +12 -0
- package/src/sync/presence-store.js +412 -0
- package/src/sync/presence-target.js +243 -0
- package/src/sync/presence.js +72 -41
- package/src/sync/saved-handoff.js +200 -0
- package/src/sync/saved-stream.js +535 -0
- package/src/sync/version-guard.js +92 -0
- package/src/sync/wire-profile.js +81 -0
- package/src/ui/bevel-controls.js +2 -8
- package/src/ui/page-scheme.js +7 -0
- package/src/ui/skins/cms.js +1 -1
- package/src/ui/theme-config.js +150 -0
- package/src/ui/theme.js +6 -138
- package/src/ui/toast-lazy.js +11 -0
- package/src/vendor/LICENSES-optional.md +253 -0
- package/src/vendor/highlight.vendor.js +3 -0
- package/src/vendor/hljs-bash.vendor.js +2 -0
- package/src/vendor/hljs-css.vendor.js +2 -0
- package/src/vendor/hljs-javascript.vendor.js +2 -0
- package/src/vendor/hljs-json.vendor.js +2 -0
- package/src/vendor/hljs-python.vendor.js +2 -0
- package/src/vendor/hljs-xml.vendor.js +2 -0
- package/src/vendor/hyper-html-api-data.vendor.js +1 -1
- package/src/vendor/hyper-html-api-upgrade.vendor.js +5 -0
- package/src/vendor/hyper-morph-identity.vendor.js +2 -0
- package/src/vendor/hyper-morph-json.vendor.js +3 -0
- package/src/vendor/hyper-morph.vendor.js +6 -6
- package/src/vendor/hyper-undo.vendor.js +1 -1
- package/src/vendor/hypercms.vendor.js +169 -84
- package/src/vendor/marked.vendor.js +68 -0
- package/src/vendor/overtype.vendor.js +994 -0
- package/src/vendor/richclay.vendor.js +17 -17
- package/src/vendor/sap-core.vendor.js +5 -5
- package/src/vendor/sap-ownership.vendor.js +11 -7
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wire-profile.js — the two live-sync wires, and the rule for choosing between them.
|
|
3
|
+
*
|
|
4
|
+
* Spec §10 puts both halves on `/_/sync`. Not every host serves that yet, and the
|
|
5
|
+
* ones that do not cannot be upgraded on our schedule: hyperclay-local ships behind
|
|
6
|
+
* Apple notarization, while this library reaches every document within one 10-minute
|
|
7
|
+
* cache TTL. So the client is the half that has to know both.
|
|
8
|
+
*
|
|
9
|
+
* The choice is DISCOVERED, never guessed. Spec §5 makes `/_/meta` the only way to
|
|
10
|
+
* learn what a host can do, and §10 says a client that has not discovered `sync`
|
|
11
|
+
* never opens either half of the route. Probing is also a bad instrument here: an
|
|
12
|
+
* EventSource reports a 404, an auth refusal and an offline browser through one
|
|
13
|
+
* error path, so a failed connection cannot tell you which address was wrong.
|
|
14
|
+
*
|
|
15
|
+
* One profile is chosen once and used for BOTH directions for the life of the page.
|
|
16
|
+
* Letting send and receive decide independently is exactly the bug this replaces: a
|
|
17
|
+
* client that posted to the spec address while streaming from the legacy one.
|
|
18
|
+
*
|
|
19
|
+
* Both stream addresses carry `client-id`, in the same kebab spelling as the rest of
|
|
20
|
+
* the query. It is the tab's own sender id — the one every outbound frame already
|
|
21
|
+
* carries — so a host that reads it at admission knows this connection by the value
|
|
22
|
+
* its frames arrive under, and can tell two tabs of one cookie-less guest apart. A
|
|
23
|
+
* host that does not read it ignores an unknown parameter.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { hostMeta } from '../core/host-meta.js';
|
|
27
|
+
|
|
28
|
+
export const WIRE_PROFILES = {
|
|
29
|
+
spec: {
|
|
30
|
+
name: 'spec',
|
|
31
|
+
relayPath: '/_/sync',
|
|
32
|
+
documentHeader: 'Document-URL',
|
|
33
|
+
snapshotKey: 'snapshot',
|
|
34
|
+
streamPath: (href, lane, resumeId, clientId) =>
|
|
35
|
+
`/_/sync?document-url=${encodeURIComponent(href)}&lane=${lane}&resume-id=${resumeId}&client-id=${encodeURIComponent(clientId)}`,
|
|
36
|
+
},
|
|
37
|
+
// What every published clayjs speaks, and what hyperclayjs and the inline script in
|
|
38
|
+
// every Collection dashboard hardcode. Hosts keep these addresses permanently.
|
|
39
|
+
legacy: {
|
|
40
|
+
name: 'legacy',
|
|
41
|
+
relayPath: '/_/live-sync/save',
|
|
42
|
+
documentHeader: 'Page-URL',
|
|
43
|
+
snapshotKey: 'html',
|
|
44
|
+
streamPath: (href, lane, resumeId, clientId) =>
|
|
45
|
+
`/_/live-sync/stream?page-url=${encodeURIComponent(href)}&lane=${lane}&resume-id=${resumeId}&client-id=${encodeURIComponent(clientId)}`,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Which wire this host speaks, and which of the current worker transports it can
|
|
51
|
+
* carry. Absence of `sync` selects the legacy wire rather than disabling live sync.
|
|
52
|
+
* That is deliberate transition debt (§10 says an undiscovered capability is not
|
|
53
|
+
* opened at all), but both deployed first-party hosts ran live sync for a long time
|
|
54
|
+
* without advertising anything, and refusing them would regress every published
|
|
55
|
+
* version. A malformed answer, a 404 or a timeout all land on legacy too.
|
|
56
|
+
*
|
|
57
|
+
* @returns {Promise<{profile: Object, sharedSync: boolean, sharedData: boolean, liveData: boolean}>}
|
|
58
|
+
*/
|
|
59
|
+
export function resolveWireProfile() {
|
|
60
|
+
return hostMeta()
|
|
61
|
+
.then((meta) => {
|
|
62
|
+
const extensions = meta?.extensions || [];
|
|
63
|
+
const hasSync = extensions.includes('sync');
|
|
64
|
+
const hasLiveData = extensions.includes('live-data');
|
|
65
|
+
const hasPresence = extensions.includes('presence');
|
|
66
|
+
const sharedData = hasSync && hasLiveData && extensions.includes('sync-worker-data') && !hasPresence;
|
|
67
|
+
const sharedSync = hasSync && !hasPresence && (sharedData || (extensions.includes('sync-worker') && !hasLiveData));
|
|
68
|
+
return {
|
|
69
|
+
profile: hasSync ? WIRE_PROFILES.spec : WIRE_PROFILES.legacy,
|
|
70
|
+
sharedSync,
|
|
71
|
+
sharedData,
|
|
72
|
+
liveData: hasLiveData,
|
|
73
|
+
};
|
|
74
|
+
})
|
|
75
|
+
.catch(() => ({
|
|
76
|
+
profile: WIRE_PROFILES.legacy,
|
|
77
|
+
sharedSync: false,
|
|
78
|
+
sharedData: false,
|
|
79
|
+
liveData: false,
|
|
80
|
+
}));
|
|
81
|
+
}
|
package/src/ui/bevel-controls.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { style, make, set } from '../lib/hostile-css.js';
|
|
12
12
|
import { RULES, MEDIA, FONT_SANS, TOKENS } from './bevel.js';
|
|
13
13
|
import { themed, tokenRulesFor, partRules, markParts, floorRules } from './theme-parts.js';
|
|
14
|
+
import { pageScheme } from './page-scheme.js';
|
|
14
15
|
|
|
15
16
|
export const RUNTIME_ONLY = 'no-save no-watch no-snapshot';
|
|
16
17
|
|
|
@@ -325,13 +326,6 @@ export function bevelInput(tag = 'input', opts = {}) {
|
|
|
325
326
|
return paintInput(el, opts);
|
|
326
327
|
}
|
|
327
328
|
|
|
328
|
-
// The scheme a UI root gives its subtree: the page's own when it declares one, so
|
|
329
|
-
// light-dark() matches what the person is looking at, else the reader's preference.
|
|
330
|
-
export function pageScheme() {
|
|
331
|
-
const s = getComputedStyle(document.documentElement).colorScheme;
|
|
332
|
-
return s === 'light' || s === 'dark' ? s : 'light dark';
|
|
333
|
-
}
|
|
334
|
-
|
|
335
329
|
// `hidden` loses to an inline !important display, so showing and hiding a control
|
|
336
330
|
// sets both: the attribute for assistive tech and callers, the declaration for looks.
|
|
337
331
|
export function setShown(el, shown, display = 'block') {
|
|
@@ -340,4 +334,4 @@ export function setShown(el, shown, display = 'block') {
|
|
|
340
334
|
else set(el, 'display', shown ? display : 'none');
|
|
341
335
|
}
|
|
342
336
|
|
|
343
|
-
export { protectIcon };
|
|
337
|
+
export { pageScheme, protectIcon };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// The scheme a UI root gives its subtree: the page's own when it declares one, so
|
|
2
|
+
// light-dark() matches what the person is looking at, else the reader's preference.
|
|
3
|
+
// It lives alone so a reader can ask for it without the controls.
|
|
4
|
+
export function pageScheme() {
|
|
5
|
+
const s = getComputedStyle(document.documentElement).colorScheme;
|
|
6
|
+
return s === 'light' || s === 'dark' ? s : 'light dark';
|
|
7
|
+
}
|
package/src/ui/skins/cms.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// GENERATED from src/vendor/hypercms.vendor.js by scripts/build-vendor-skins.mjs. Run `npm run build:skins`.
|
|
2
|
-
export const SOURCE_SHA256 = "
|
|
2
|
+
export const SOURCE_SHA256 = "f4a8bf46fe5d4f1037810077d8068d59cd996896c59977abc2d2baa6ad3f0abd";
|
|
3
3
|
export const ROOTS = [".hcms-shell"];
|
|
4
4
|
export const CSS = "@layer clay-skin{\n:is(.hcms-shell):not([data-theme]),:is(.hcms-shell):not([data-theme]) *{--mirk-canvas:light-dark(#FDF8F0, #0B0C13) !important;--mirk-bg:light-dark(#FFFCF6, #11131E) !important;--mirk-fg:light-dark(#2B241B, #ECEAF2) !important;--mirk-accent:light-dark(#F4ECDF, #1A1D2C) !important;--mirk-destructive:light-dark(#A83A2C, #FF5566) !important;--mirk-focus-color:light-dark(#8F6310, #D9A445) !important;--mirk-bevel-bg:light-dark(#F1E7D4, #22273E) !important;--mirk-bevel-fg:light-dark(#2B241B, #ECEAF2) !important;--mirk-bevel-tl:light-dark(#FFF9ED, #3C4260) !important;--mirk-bevel-br:light-dark(#D6C3A5, #1B2033) !important;--mirk-bevel-hover-bg:color-mix(in srgb, light-dark(#F1E7D4, #22273E), light-dark(#FFF9ED, #3C4260) 45%) !important;--mirk-pill-inner-top:light-dark(#FFF9ED, #3C4260) !important;--mirk-input-border:light-dark(#D8C8AF, #353B52) !important;--mirk-placeholder-color:light-dark(#9A8A70, #6A7090) !important;--mirk-ctrl-bg:light-dark(#6B5942, #8A90AB) !important;--mirk-toggle-bg:light-dark(#FCF8F1, #4A5275) !important;--mirk-toggle-hi:light-dark(#FFF9ED, #6C759A) !important;--mirk-toggle-lo:light-dark(#D6C3A5, #1B2033) !important;--mirk-mark-fg:light-dark(#2B241B, #ECEAF2) !important;--mirk-sortable-dot:light-dark(#D8C8AF, #353B52) !important;--mirk-sortable-shadow:light-dark(#D6C3A5, #1B2033) !important;--mirk-sortable-label:light-dark(#6B5942, #8A90AB) !important;--mirk-sortable-placeholder:light-dark(#9A8A70, #6A7090) !important;--mirk-slider-fill:light-dark(#F0E4CC, #3A2F17) !important;--mirk-slider-nub-bg:light-dark(#FCF8F1, #4A5275) !important;--mirk-slider-nub-hi:light-dark(#FFF9ED, #6C759A) !important;--mirk-slider-nub-lo:light-dark(#D6C3A5, #1B2033) !important;--mirk-chip-surface:light-dark(#FFFCF6, #11131E) !important;--mirk-chip-edge:light-dark(#D8C8AF, #353B52) !important;--mirk-chip-primary-bg:light-dark(#2B241B, #ECEAF2) !important;--mirk-chip-primary-fg:light-dark(#FDF8F0, #0B0C13) !important;--mirk-chip-alert:light-dark(#A83A2C, #FF5566) !important;--mirk-radius:0px !important;--mirk-focus-offset:2px !important}\n:is(.hcms-shell){font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace !important}\n.hcms-shell .mirk-chip__actions .mirk-chip__action--primary{--mirk-bevel-bg:var(--mirk-chip-primary-bg) !important;--mirk-bevel-fg:var(--mirk-chip-primary-fg) !important;--mirk-bevel-tl:color-mix(in srgb, var(--mirk-chip-primary-bg), white 24%) !important;--mirk-bevel-br:color-mix(in srgb, var(--mirk-chip-primary-bg), black 32%) !important;--mirk-bevel-hover-bg:color-mix(in srgb, var(--mirk-chip-primary-bg), white 10%) !important}\n}";
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// Theme configuration for the UI ClayJS draws on a page: dialogs, prompts, toasts,
|
|
2
|
+
// notices. A page configures it (window.clayTheme at first use, or clay.theme());
|
|
3
|
+
// the surfaces that paint it are elsewhere, so a reader that never opens one never
|
|
4
|
+
// loads them. Configuration is synchronous: clay.theme() answers and throws without
|
|
5
|
+
// waiting for a stylesheet, an element or an import.
|
|
6
|
+
|
|
7
|
+
export const TOKEN_PROPS = {
|
|
8
|
+
font: "font-family",
|
|
9
|
+
headingFont: "font-family",
|
|
10
|
+
text: "color",
|
|
11
|
+
mutedText: "color",
|
|
12
|
+
background: "background-color",
|
|
13
|
+
surface: "background-color",
|
|
14
|
+
border: "border-color",
|
|
15
|
+
accent: "background-color",
|
|
16
|
+
accentText: "color",
|
|
17
|
+
danger: "background-color",
|
|
18
|
+
dangerText: "color",
|
|
19
|
+
success: "color",
|
|
20
|
+
warning: "color",
|
|
21
|
+
radius: "border-radius",
|
|
22
|
+
shadow: "box-shadow",
|
|
23
|
+
overlay: "background-color",
|
|
24
|
+
spacing: "outline-offset",
|
|
25
|
+
buttonHeight: "min-height",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const STATES = ["base", "hover", "active", "focus", "disabled"];
|
|
29
|
+
|
|
30
|
+
const DIALOG = ["root", "overlay", "panel", "header", "title", "body", "footer", "close", "closeIcon", "content", "input", "hint", "actions", "button", "buttonLabel", "well", "code", "copyButton"];
|
|
31
|
+
const NOTICE = ["root", "panel", "header", "title", "text", "icon", "dot", "actions", "button", "buttonLabel", "close", "well", "list", "row", "location", "valueLabel", "value", "before", "after", "mine", "theirs", "warning", "previewRing"];
|
|
32
|
+
|
|
33
|
+
export const PART_NAMES = new Set([
|
|
34
|
+
"button", "button.default", "button.primary", "button.quiet", "button.danger",
|
|
35
|
+
"buttonLabel", "input", "text", "mutedText", "icon", "well", "close",
|
|
36
|
+
...["dialog", "people", "crop"].flatMap((s) => DIALOG.map((p) => `${s}.${p}`)),
|
|
37
|
+
"people.choices", "people.choice", "people.choiceLabel",
|
|
38
|
+
"crop.stage", "crop.image", "crop.dim", "crop.selection", "crop.handle",
|
|
39
|
+
"crop.handle.nw", "crop.handle.ne", "crop.handle.sw", "crop.handle.se",
|
|
40
|
+
"toast.stack", "toast.panel", "toast.icon", "toast.text", "toast.close", "toast.closeIcon",
|
|
41
|
+
...["notice", "conflict", "section", "staleHost"].flatMap((s) => NOTICE.map((p) => `${s}.${p}`)),
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
const SCHEMES = ["page", "light", "dark"];
|
|
45
|
+
const DEFAULT = Object.freeze({ auto: true, colorScheme: "page", tokens: {}, parts: {} });
|
|
46
|
+
|
|
47
|
+
let config = null;
|
|
48
|
+
let initialized = false;
|
|
49
|
+
|
|
50
|
+
// A CSS value a page hands us. It lands inside an inline declaration, so it may
|
|
51
|
+
// never close that declaration or add a priority of its own.
|
|
52
|
+
export function validValue(prop, value) {
|
|
53
|
+
if (typeof value !== "string") return false;
|
|
54
|
+
const v = value.trim();
|
|
55
|
+
if (!v || v.length > 500 || /[;{}]|!\s*important/i.test(v)) return false;
|
|
56
|
+
const supports = globalThis.CSS?.supports;
|
|
57
|
+
return typeof supports === "function" ? supports.call(globalThis.CSS, prop, v) : true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function plainObject(x) {
|
|
61
|
+
return !!x && typeof x === "object" && Object.getPrototypeOf(x) === Object.prototype;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function normalize(options) {
|
|
65
|
+
if (!plainObject(options)) throw new TypeError("clay.theme: pass an options object, false or null");
|
|
66
|
+
const { auto = true, colorScheme = "page", tokens = {}, parts = {}, ...rest } = options;
|
|
67
|
+
const unknown = Object.keys(rest);
|
|
68
|
+
if (unknown.length) throw new TypeError(`clay.theme: unknown option "${unknown[0]}"`);
|
|
69
|
+
if (typeof auto !== "boolean") throw new TypeError("clay.theme: auto must be true or false");
|
|
70
|
+
if (!SCHEMES.includes(colorScheme)) throw new TypeError(`clay.theme: colorScheme must be one of ${SCHEMES.join(", ")}`);
|
|
71
|
+
if (!plainObject(tokens)) throw new TypeError("clay.theme: tokens must be an object");
|
|
72
|
+
if (!plainObject(parts)) throw new TypeError("clay.theme: parts must be an object");
|
|
73
|
+
const outTokens = {};
|
|
74
|
+
for (const [name, value] of Object.entries(tokens)) {
|
|
75
|
+
if (!(name in TOKEN_PROPS)) throw new TypeError(`clay.theme: unknown token "${name}"`);
|
|
76
|
+
if (!validValue(TOKEN_PROPS[name], value)) throw new TypeError(`clay.theme: token "${name}" is not a valid ${TOKEN_PROPS[name]} value`);
|
|
77
|
+
outTokens[name] = name === "spacing" && value.trim() === "0" ? "0px" : value.trim();
|
|
78
|
+
}
|
|
79
|
+
const outParts = {};
|
|
80
|
+
for (const [name, states] of Object.entries(parts)) {
|
|
81
|
+
if (!PART_NAMES.has(name)) throw new TypeError(`clay.theme: unknown part "${name}"`);
|
|
82
|
+
if (!plainObject(states)) throw new TypeError(`clay.theme: part "${name}" must map states to declarations`);
|
|
83
|
+
outParts[name] = {};
|
|
84
|
+
for (const [state, decls] of Object.entries(states)) {
|
|
85
|
+
if (!STATES.includes(state)) throw new TypeError(`clay.theme: part "${name}" has unknown state "${state}"`);
|
|
86
|
+
if (!plainObject(decls)) throw new TypeError(`clay.theme: "${name}.${state}" must be an object of CSS declarations`);
|
|
87
|
+
outParts[name][state] = {};
|
|
88
|
+
for (const [prop, value] of Object.entries(decls)) {
|
|
89
|
+
if (!/^-?[a-z][a-z-]*$/.test(prop) || prop.startsWith("--")) throw new TypeError(`clay.theme: "${prop}" in ${name}.${state} is not a CSS property name`);
|
|
90
|
+
if (!validValue(prop, value)) throw new TypeError(`clay.theme: "${prop}: ${value}" in ${name}.${state} is not valid`);
|
|
91
|
+
outParts[name][state][prop] = value.trim();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return Object.freeze({ auto, colorScheme, tokens: Object.freeze(outTokens), parts: Object.freeze(outParts) });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function copy(c) {
|
|
99
|
+
if (c === false) return false;
|
|
100
|
+
return JSON.parse(JSON.stringify(c));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* clay.theme(options) replaces the page's theme; clay.theme(false) restores the exact
|
|
105
|
+
* Bevel look; clay.theme(null) restores the default automatic theme; clay.theme()
|
|
106
|
+
* returns a copy of the current configuration. Invalid options throw a TypeError and
|
|
107
|
+
* leave the previous theme in place.
|
|
108
|
+
*/
|
|
109
|
+
export function theme(options) {
|
|
110
|
+
initTheme();
|
|
111
|
+
if (arguments.length === 0) return copy(config);
|
|
112
|
+
if (options === false) config = false;
|
|
113
|
+
else if (options === null) config = DEFAULT;
|
|
114
|
+
else config = normalize(options);
|
|
115
|
+
return copy(config);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Idempotent. Reads window.clayTheme once and attaches clay.theme. An invalid
|
|
119
|
+
// preloaded theme warns and falls back to the default; it never stops ClayJS booting.
|
|
120
|
+
export function initTheme() {
|
|
121
|
+
if (initialized) return;
|
|
122
|
+
initialized = true;
|
|
123
|
+
const pre = typeof window !== "undefined" ? window.clayTheme : undefined;
|
|
124
|
+
if (pre === false) config = false;
|
|
125
|
+
else if (pre === undefined || pre === null) config = DEFAULT;
|
|
126
|
+
else {
|
|
127
|
+
try {
|
|
128
|
+
config = normalize(pre);
|
|
129
|
+
} catch (err) {
|
|
130
|
+
console.warn(`clayjs: ignoring window.clayTheme: ${err.message}`);
|
|
131
|
+
config = DEFAULT;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (typeof window !== "undefined") {
|
|
135
|
+
const clay = (window.clay = window.clay || {});
|
|
136
|
+
clay.theme = theme;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// The configuration a surface resolves against. One owner: theme() writes it here
|
|
141
|
+
// and a surface reads it here, so a split module cannot hold a stale copy.
|
|
142
|
+
export function currentConfig() {
|
|
143
|
+
return config;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Test hook: forget configuration so the next call re-reads window.clayTheme.
|
|
147
|
+
export function _resetTheme() {
|
|
148
|
+
config = null;
|
|
149
|
+
initialized = false;
|
|
150
|
+
}
|
package/src/ui/theme.js
CHANGED
|
@@ -2,142 +2,15 @@
|
|
|
2
2
|
// A page configures it with window.clayTheme (read at first use) or clay.theme().
|
|
3
3
|
// resolveTheme() captures one surface's theme when that surface is built; a later
|
|
4
4
|
// clay.theme() call affects the next surface, never one already open.
|
|
5
|
-
import {
|
|
5
|
+
import { TOKEN_PROPS, currentConfig, initTheme, validValue } from "./theme-config.js";
|
|
6
|
+
import { pageScheme } from "./page-scheme.js";
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
text: "color",
|
|
11
|
-
mutedText: "color",
|
|
12
|
-
background: "background-color",
|
|
13
|
-
surface: "background-color",
|
|
14
|
-
border: "border-color",
|
|
15
|
-
accent: "background-color",
|
|
16
|
-
accentText: "color",
|
|
17
|
-
danger: "background-color",
|
|
18
|
-
dangerText: "color",
|
|
19
|
-
success: "color",
|
|
20
|
-
warning: "color",
|
|
21
|
-
radius: "border-radius",
|
|
22
|
-
shadow: "box-shadow",
|
|
23
|
-
overlay: "background-color",
|
|
24
|
-
spacing: "outline-offset",
|
|
25
|
-
buttonHeight: "min-height",
|
|
26
|
-
};
|
|
8
|
+
// The configuration itself lives in theme-config.js, which the loader reads at
|
|
9
|
+
// boot; these names stay here because every surface imported them from here.
|
|
10
|
+
export { PART_NAMES, STATES, TOKEN_PROPS, _resetTheme, initTheme, theme, validValue } from "./theme-config.js";
|
|
27
11
|
|
|
28
|
-
export const STATES = ["base", "hover", "active", "focus", "disabled"];
|
|
29
|
-
|
|
30
|
-
const DIALOG = ["root", "overlay", "panel", "header", "title", "body", "footer", "close", "closeIcon", "content", "input", "hint", "actions", "button", "buttonLabel", "well", "code", "copyButton"];
|
|
31
|
-
const NOTICE = ["root", "panel", "header", "title", "text", "icon", "dot", "actions", "button", "buttonLabel", "close", "well", "list", "row", "location", "valueLabel", "value", "before", "after", "mine", "theirs", "warning", "previewRing"];
|
|
32
|
-
|
|
33
|
-
export const PART_NAMES = new Set([
|
|
34
|
-
"button", "button.default", "button.primary", "button.quiet", "button.danger",
|
|
35
|
-
"buttonLabel", "input", "text", "mutedText", "icon", "well", "close",
|
|
36
|
-
...["dialog", "people", "crop"].flatMap((s) => DIALOG.map((p) => `${s}.${p}`)),
|
|
37
|
-
"people.choices", "people.choice", "people.choiceLabel",
|
|
38
|
-
"crop.stage", "crop.image", "crop.dim", "crop.selection", "crop.handle",
|
|
39
|
-
"crop.handle.nw", "crop.handle.ne", "crop.handle.sw", "crop.handle.se",
|
|
40
|
-
"toast.stack", "toast.panel", "toast.icon", "toast.text", "toast.close", "toast.closeIcon",
|
|
41
|
-
...["notice", "conflict", "section", "staleHost"].flatMap((s) => NOTICE.map((p) => `${s}.${p}`)),
|
|
42
|
-
]);
|
|
43
|
-
|
|
44
|
-
const SCHEMES = ["page", "light", "dark"];
|
|
45
|
-
const DEFAULT = Object.freeze({ auto: true, colorScheme: "page", tokens: {}, parts: {} });
|
|
46
12
|
const kebab = (name) => name.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
|
|
47
13
|
|
|
48
|
-
let config = null;
|
|
49
|
-
let initialized = false;
|
|
50
|
-
|
|
51
|
-
// A CSS value a page hands us. It lands inside an inline declaration, so it may
|
|
52
|
-
// never close that declaration or add a priority of its own.
|
|
53
|
-
export function validValue(prop, value) {
|
|
54
|
-
if (typeof value !== "string") return false;
|
|
55
|
-
const v = value.trim();
|
|
56
|
-
if (!v || v.length > 500 || /[;{}]|!\s*important/i.test(v)) return false;
|
|
57
|
-
const supports = globalThis.CSS?.supports;
|
|
58
|
-
return typeof supports === "function" ? supports.call(globalThis.CSS, prop, v) : true;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function plainObject(x) {
|
|
62
|
-
return !!x && typeof x === "object" && Object.getPrototypeOf(x) === Object.prototype;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function normalize(options) {
|
|
66
|
-
if (!plainObject(options)) throw new TypeError("clay.theme: pass an options object, false or null");
|
|
67
|
-
const { auto = true, colorScheme = "page", tokens = {}, parts = {}, ...rest } = options;
|
|
68
|
-
const unknown = Object.keys(rest);
|
|
69
|
-
if (unknown.length) throw new TypeError(`clay.theme: unknown option "${unknown[0]}"`);
|
|
70
|
-
if (typeof auto !== "boolean") throw new TypeError("clay.theme: auto must be true or false");
|
|
71
|
-
if (!SCHEMES.includes(colorScheme)) throw new TypeError(`clay.theme: colorScheme must be one of ${SCHEMES.join(", ")}`);
|
|
72
|
-
if (!plainObject(tokens)) throw new TypeError("clay.theme: tokens must be an object");
|
|
73
|
-
if (!plainObject(parts)) throw new TypeError("clay.theme: parts must be an object");
|
|
74
|
-
const outTokens = {};
|
|
75
|
-
for (const [name, value] of Object.entries(tokens)) {
|
|
76
|
-
if (!(name in TOKEN_PROPS)) throw new TypeError(`clay.theme: unknown token "${name}"`);
|
|
77
|
-
if (!validValue(TOKEN_PROPS[name], value)) throw new TypeError(`clay.theme: token "${name}" is not a valid ${TOKEN_PROPS[name]} value`);
|
|
78
|
-
outTokens[name] = name === "spacing" && value.trim() === "0" ? "0px" : value.trim();
|
|
79
|
-
}
|
|
80
|
-
const outParts = {};
|
|
81
|
-
for (const [name, states] of Object.entries(parts)) {
|
|
82
|
-
if (!PART_NAMES.has(name)) throw new TypeError(`clay.theme: unknown part "${name}"`);
|
|
83
|
-
if (!plainObject(states)) throw new TypeError(`clay.theme: part "${name}" must map states to declarations`);
|
|
84
|
-
outParts[name] = {};
|
|
85
|
-
for (const [state, decls] of Object.entries(states)) {
|
|
86
|
-
if (!STATES.includes(state)) throw new TypeError(`clay.theme: part "${name}" has unknown state "${state}"`);
|
|
87
|
-
if (!plainObject(decls)) throw new TypeError(`clay.theme: "${name}.${state}" must be an object of CSS declarations`);
|
|
88
|
-
outParts[name][state] = {};
|
|
89
|
-
for (const [prop, value] of Object.entries(decls)) {
|
|
90
|
-
if (!/^-?[a-z][a-z-]*$/.test(prop) || prop.startsWith("--")) throw new TypeError(`clay.theme: "${prop}" in ${name}.${state} is not a CSS property name`);
|
|
91
|
-
if (!validValue(prop, value)) throw new TypeError(`clay.theme: "${prop}: ${value}" in ${name}.${state} is not valid`);
|
|
92
|
-
outParts[name][state][prop] = value.trim();
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return Object.freeze({ auto, colorScheme, tokens: Object.freeze(outTokens), parts: Object.freeze(outParts) });
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function copy(c) {
|
|
100
|
-
if (c === false) return false;
|
|
101
|
-
return JSON.parse(JSON.stringify(c));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* clay.theme(options) replaces the page's theme; clay.theme(false) restores the exact
|
|
106
|
-
* Bevel look; clay.theme(null) restores the default automatic theme; clay.theme()
|
|
107
|
-
* returns a copy of the current configuration. Invalid options throw a TypeError and
|
|
108
|
-
* leave the previous theme in place.
|
|
109
|
-
*/
|
|
110
|
-
export function theme(options) {
|
|
111
|
-
initTheme();
|
|
112
|
-
if (arguments.length === 0) return copy(config);
|
|
113
|
-
if (options === false) config = false;
|
|
114
|
-
else if (options === null) config = DEFAULT;
|
|
115
|
-
else config = normalize(options);
|
|
116
|
-
return copy(config);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Idempotent. Reads window.clayTheme once and attaches clay.theme. An invalid
|
|
120
|
-
// preloaded theme warns and falls back to the default; it never stops ClayJS booting.
|
|
121
|
-
export function initTheme() {
|
|
122
|
-
if (initialized) return;
|
|
123
|
-
initialized = true;
|
|
124
|
-
const pre = typeof window !== "undefined" ? window.clayTheme : undefined;
|
|
125
|
-
if (pre === false) config = false;
|
|
126
|
-
else if (pre === undefined || pre === null) config = DEFAULT;
|
|
127
|
-
else {
|
|
128
|
-
try {
|
|
129
|
-
config = normalize(pre);
|
|
130
|
-
} catch (err) {
|
|
131
|
-
console.warn(`clayjs: ignoring window.clayTheme: ${err.message}`);
|
|
132
|
-
config = DEFAULT;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
if (typeof window !== "undefined") {
|
|
136
|
-
const clay = (window.clay = window.clay || {});
|
|
137
|
-
clay.theme = theme;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
14
|
// --- colour helpers --------------------------------------------------------
|
|
142
15
|
|
|
143
16
|
// [r, g, b, a] for rgb()/rgba() or #rgb/#rrggbb, else null.
|
|
@@ -251,6 +124,7 @@ function onColor(fill, t) {
|
|
|
251
124
|
*/
|
|
252
125
|
export function resolveTheme() {
|
|
253
126
|
initTheme();
|
|
127
|
+
const config = currentConfig();
|
|
254
128
|
if (config === false) return { bevel: true, scheme: pageScheme(), tokens: {}, parts: {} };
|
|
255
129
|
const sampled = config.auto ? samplePage() : {};
|
|
256
130
|
const tokens = { ...sampled, ...cssTokens(), ...config.tokens };
|
|
@@ -269,9 +143,3 @@ export function resolveTheme() {
|
|
|
269
143
|
}
|
|
270
144
|
return { bevel: false, scheme: scheme(config.colorScheme, tokens), tokens, parts: config.parts };
|
|
271
145
|
}
|
|
272
|
-
|
|
273
|
-
// Test hook: forget configuration so the next call re-reads window.clayTheme.
|
|
274
|
-
export function _resetTheme() {
|
|
275
|
-
config = null;
|
|
276
|
-
initialized = false;
|
|
277
|
-
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// The toast stack is fetched the first time a toast shows, so the page editor does
|
|
2
|
+
// not download it to become ready. Calls made before it arrives run in order once it has.
|
|
3
|
+
let loading = null;
|
|
4
|
+
const load = () => (loading ??= import("./toast.js"));
|
|
5
|
+
const later = (name) => (...args) => { load().then((m) => (name ? m[name] : m.default)(...args)); };
|
|
6
|
+
|
|
7
|
+
export default later(null);
|
|
8
|
+
export const toastPersistent = later("toastPersistent");
|
|
9
|
+
// Dismissing a toast nobody showed does nothing, so it never fetches the stack: a page
|
|
10
|
+
// that tears down without having shown one keeps it unloaded.
|
|
11
|
+
export const dismissPersistent = (...args) => { if (loading) later("dismissPersistent")(...args); };
|