@heycys/gallery 0.1.2 → 0.2.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/THIRD-PARTY-NOTICES.md +2 -2
- package/browser/editor/components/align.mjs +58 -0
- package/browser/editor/components/code/index.mjs +1 -1
- package/browser/editor/components/embed/page.mjs +1 -1
- package/browser/editor/components/file/page.mjs +4 -4
- package/browser/editor/components/heading/index.mjs +7 -6
- package/browser/editor/components/icon/page.mjs +6 -4
- package/browser/editor/components/icons.mjs +5 -2
- package/browser/editor/components/image/index.mjs +2 -0
- package/browser/editor/components/image/page.mjs +172 -90
- package/browser/editor/components/installed/index.mjs +6 -2
- package/browser/editor/components/installed/page.mjs +80 -13
- package/browser/editor/components/media/icons.mjs +13 -8
- package/browser/editor/components/media/page.mjs +5 -3
- package/browser/editor/components/media/toolbar.mjs +12 -3
- package/browser/editor/components/paragraph/index.mjs +4 -3
- package/browser/editor/components/registry.mjs +17 -5
- package/browser/editor/components/table/index.mjs +4 -2
- package/browser/editor/page/after/index.mjs +288 -0
- package/browser/editor/page/align.mjs +91 -0
- package/browser/editor/page/beside.mjs +5 -6
- package/browser/editor/page/block-menu/index.mjs +6 -3
- package/browser/editor/page/blocks.mjs +3 -1
- package/browser/editor/page/board/hint.mjs +64 -27
- package/browser/editor/page/board/index.mjs +160 -71
- package/browser/editor/page/board/motion.mjs +177 -0
- package/browser/editor/page/board/settings.mjs +4 -3
- package/browser/editor/page/clipboard/import/read.mjs +20 -2
- package/browser/editor/page/clipboard/index.mjs +10 -3
- package/browser/editor/page/clipboard/own/blocks.mjs +3 -4
- package/browser/editor/page/clipboard/own/describe.mjs +6 -2
- package/browser/editor/page/commit.mjs +2 -2
- package/browser/editor/page/core.mjs +3 -1
- package/browser/editor/page/custom-page.mjs +15 -11
- package/browser/editor/page/editor.mjs +31 -14
- package/browser/editor/page/history.mjs +19 -4
- package/browser/editor/page/insert/index.mjs +20 -22
- package/browser/editor/page/menu.mjs +15 -7
- package/browser/editor/page/page-objects.mjs +3 -7
- package/browser/editor/page/present-links.mjs +5 -4
- package/browser/editor/page/present-shell.mjs +63 -0
- package/browser/editor/page/selection/index.mjs +10 -2
- package/browser/editor/page/table/binding.mjs +87 -0
- package/browser/editor/page/table/icons.mjs +0 -2
- package/browser/editor/page/table/index.mjs +10 -14
- package/browser/editor/page/table/views.mjs +5 -52
- package/browser/editor/page/table/widths.mjs +82 -10
- package/browser/editor/page/typing/index.mjs +44 -12
- package/browser/editor/page/typing/leave.mjs +19 -5
- package/browser/shared/block-packs.mjs +23 -8
- package/browser/shared/component-catalog.mjs +15 -8
- package/browser/shared/component-source.mjs +3 -1
- package/browser/shared/components/heading.mjs +2 -1
- package/browser/shared/components/installed.mjs +1 -1
- package/browser/shared/components/page.mjs +2 -0
- package/browser/shared/components/paragraph.mjs +8 -1
- package/browser/shared/components/table.mjs +1 -0
- package/browser/shared/document-copy.mjs +43 -0
- package/browser/shared/drafts.mjs +10 -3
- package/browser/shared/emoji/icon-value.mjs +2 -2
- package/browser/shared/emoji/line-icons.mjs +37 -0
- package/browser/shared/extensions.mjs +83 -7
- package/browser/shared/http.mjs +9 -0
- package/browser/shared/i18n/en.mjs +50 -17
- package/browser/shared/outline-shape.mjs +6 -0
- package/browser/shared/outline.mjs +165 -12
- package/browser/shared/pack-manifest.mjs +12 -1
- package/browser/shared/pages.mjs +169 -57
- package/browser/shared/pinyin.mjs +92 -0
- package/browser/shared/present-step.mjs +17 -0
- package/browser/shared/sidebar-head.mjs +70 -0
- package/browser/shared/web-links.mjs +5 -0
- package/browser/shared/workspace-columns.mjs +11 -7
- package/dist/{chunk-N7AZZLGT.mjs → chunk-2GKGEVMR.mjs} +29 -24
- package/dist/chunk-2OHANJ6Q.mjs +2 -0
- package/dist/{chunk-HYMEEXKN.mjs → chunk-2RKIHJI2.mjs} +1 -1
- package/dist/{chunk-742D2WWJ.mjs → chunk-36FIRJIF.mjs} +2 -2
- package/dist/{chunk-BPL64HGA.mjs → chunk-3A5I2GJK.mjs} +1 -1
- package/dist/{chunk-RFDZXFJF.mjs → chunk-3OFXMN6N.mjs} +1 -1
- package/dist/chunk-46ACXOU5.mjs +2 -0
- package/dist/{chunk-PUOQ65NC.mjs → chunk-4AMTKWDO.mjs} +1 -1
- package/dist/{chunk-VTKNEYT3.mjs → chunk-4DNHHJSL.mjs} +1 -1
- package/dist/chunk-5DPABPBI.mjs +2 -0
- package/dist/chunk-5IIH335D.mjs +3 -0
- package/dist/chunk-5L26JUYA.mjs +2 -0
- package/dist/{chunk-3NJACR4W.mjs → chunk-5MEXZ2UF.mjs} +1 -1
- package/dist/{chunk-ZHEHPMBK.mjs → chunk-6MPKCH3P.mjs} +1 -1
- package/dist/{chunk-C564NU2H.mjs → chunk-74RPP2M2.mjs} +1 -1
- package/dist/chunk-7M2BQQGZ.mjs +2 -0
- package/dist/{chunk-VXACTLO3.mjs → chunk-7M7UPWU6.mjs} +1 -1
- package/dist/{chunk-ZB4H7ZN4.mjs → chunk-7N2LPG33.mjs} +1 -1
- package/dist/{chunk-UBBRTJ2R.mjs → chunk-7XDYK3UC.mjs} +1 -1
- package/dist/chunk-AEMVZYZQ.mjs +166 -0
- package/dist/{chunk-POQSE4C2.mjs → chunk-AFGUR7SY.mjs} +1 -1
- package/dist/{chunk-QKXMPUXC.mjs → chunk-AMDGVDNV.mjs} +1 -1
- package/dist/{chunk-KTKHRC6H.mjs → chunk-ASAXY2DJ.mjs} +1 -1
- package/dist/{chunk-NVRNLK25.mjs → chunk-BYSF5UMM.mjs} +2 -2
- package/dist/{chunk-U3SSPL4K.mjs → chunk-CCSGFCLZ.mjs} +1 -1
- package/dist/{chunk-NWFBE2YA.mjs → chunk-CG3UHDKH.mjs} +1 -1
- package/dist/chunk-CPS4SRPF.mjs +5 -0
- package/dist/{chunk-B4P2CM2J.mjs → chunk-CZ5KJSGK.mjs} +1 -1
- package/dist/chunk-DAMVDXR3.mjs +2 -0
- package/dist/{chunk-NG375ILQ.mjs → chunk-DH6GMDNN.mjs} +1 -1
- package/dist/chunk-DHB7UZ7F.mjs +3 -0
- package/dist/{chunk-MHW7ZKOU.mjs → chunk-DKR7LFIY.mjs} +1 -1
- package/dist/chunk-DLFZJJEE.mjs +2 -0
- package/dist/{chunk-6EZ7FNIK.mjs → chunk-F4ZA6JRZ.mjs} +1 -1
- package/dist/{chunk-6VTU6KEO.mjs → chunk-FCK6NXON.mjs} +1 -1
- package/dist/{chunk-ZWPMCK7P.mjs → chunk-FX42XU6J.mjs} +1 -1
- package/dist/chunk-FXQBADMN.mjs +5 -0
- package/dist/{chunk-W3BGBJQW.mjs → chunk-G4YP7GVC.mjs} +1 -1
- package/dist/{chunk-V6XZ4VIR.mjs → chunk-GWOYMENX.mjs} +1 -1
- package/dist/chunk-HATA2W7X.mjs +2 -0
- package/dist/{chunk-YI43RG4P.mjs → chunk-HBAUKKQH.mjs} +1 -1
- package/dist/{chunk-MAFIGVXY.mjs → chunk-HM4E43VM.mjs} +1 -1
- package/dist/{chunk-CRJEG7MT.mjs → chunk-JI6T3A4Y.mjs} +1 -1
- package/dist/{chunk-NFMCP2HI.mjs → chunk-JJNRIFND.mjs} +2 -2
- package/dist/chunk-JL6R4FG4.mjs +4 -0
- package/dist/{chunk-UMHUSOPJ.mjs → chunk-JXLSHVJ2.mjs} +1 -1
- package/dist/{chunk-FJYN7RTH.mjs → chunk-KFZBYDIS.mjs} +1 -1
- package/dist/{chunk-ZTHICSSF.mjs → chunk-KH24LWAT.mjs} +1 -1
- package/dist/{chunk-RKPWLGZ3.mjs → chunk-KUILYI7H.mjs} +1 -1
- package/dist/{chunk-RMECZA2K.mjs → chunk-L7W624FD.mjs} +1 -1
- package/dist/chunk-LE44MD3O.mjs +4 -0
- package/dist/{chunk-4K5KC6V2.mjs → chunk-LV24RY2E.mjs} +1 -1
- package/dist/{chunk-43B75J5T.mjs → chunk-MKTX5PGV.mjs} +1 -1
- package/dist/{chunk-LKX55H76.mjs → chunk-NAGMRVW4.mjs} +1 -1
- package/dist/{chunk-D4CKRD3V.mjs → chunk-NFABH3QW.mjs} +2 -2
- package/dist/{chunk-PVER7LSC.mjs → chunk-NIW7F7LU.mjs} +2 -2
- package/dist/{chunk-PAREWQGB.mjs → chunk-NWRZXELO.mjs} +1 -1
- package/dist/{chunk-OJKMINIU.mjs → chunk-OU3S466R.mjs} +15 -15
- package/dist/{chunk-5ZJA7CXT.mjs → chunk-PAFSFVYB.mjs} +1 -1
- package/dist/chunk-QCEATQC4.mjs +2 -0
- package/dist/{chunk-Y34NR5JL.mjs → chunk-QJ3TFJLQ.mjs} +1 -1
- package/dist/{chunk-IA4PSIMD.mjs → chunk-QK3VISCA.mjs} +1 -1
- package/dist/{chunk-ZUNVAXLH.mjs → chunk-QXVNUASA.mjs} +1 -1
- package/dist/{chunk-GRAXKKG4.mjs → chunk-QZ35UAB4.mjs} +1 -1
- package/dist/{chunk-UGWYKHBL.mjs → chunk-S2Y7VI4H.mjs} +2 -2
- package/dist/{chunk-OW5NWPOJ.mjs → chunk-SAHS56QM.mjs} +1 -1
- package/dist/{chunk-QOUEFUCH.mjs → chunk-SOD23RGL.mjs} +1 -1
- package/dist/chunk-TDWJKOLN.mjs +2 -0
- package/dist/{chunk-V6RIYQZZ.mjs → chunk-TOE6DPLH.mjs} +1 -1
- package/dist/chunk-UGO5N3EI.mjs +15 -0
- package/dist/{chunk-Q47PLKIJ.mjs → chunk-UGWMMEJ5.mjs} +1 -1
- package/dist/{chunk-NWR2LT5B.mjs → chunk-V5JRSGZF.mjs} +1 -1
- package/dist/{chunk-BZ5RAF7L.mjs → chunk-VA3KAQZD.mjs} +1 -1
- package/dist/chunk-VG5JEIUQ.mjs +12 -0
- package/dist/{chunk-UNOYVIYR.mjs → chunk-VGTMLQWZ.mjs} +1 -1
- package/dist/chunk-VKSRM7EY.mjs +22 -0
- package/dist/{chunk-YQGT4AB2.mjs → chunk-VNUWREXU.mjs} +1 -1
- package/dist/{chunk-AGDILNWB.mjs → chunk-VPVOAJ7X.mjs} +1 -1
- package/dist/{chunk-HLYV7RIH.mjs → chunk-WCWYNFDF.mjs} +1 -1
- package/dist/chunk-WTEGUPFG.mjs +16 -0
- package/dist/{chunk-N76HWBA3.mjs → chunk-XKOHV4H6.mjs} +1 -1
- package/dist/{chunk-HMYTM3GT.mjs → chunk-XMKHCUI6.mjs} +1 -1
- package/dist/{chunk-OUUP3WKT.mjs → chunk-XQRUG4G3.mjs} +1 -1
- package/dist/{chunk-32ZUEFZ7.mjs → chunk-YBB5LWZK.mjs} +1 -1
- package/dist/{chunk-SX4LJYT6.mjs → chunk-YFJU3O7G.mjs} +1 -1
- package/dist/chunk-YPPJVDQI.mjs +2 -0
- package/dist/chunk-ZANMKAWS.mjs +2 -0
- package/dist/{chunk-6QBHU4DF.mjs → chunk-ZCP7BTOZ.mjs} +1 -1
- package/dist/{chunk-ERLAIBOA.mjs → chunk-ZEY2RLBT.mjs} +2 -2
- package/dist/{chunk-SQ6Y2ZMA.mjs → chunk-ZO7SFB2E.mjs} +2 -2
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/worker.mjs +1 -1
- package/kit/board.css +5 -5
- package/kit/code.js +15 -15
- package/kit/math.js +1 -1
- package/kit/report.css +123 -44
- package/kit/runtime.js +45 -7
- package/kit/tables.js +2 -0
- package/kit/ui.js +2 -0
- package/package.json +1 -1
- package/packs/gallery/chart-view/kit.js +3 -3
- package/packs/gallery/chart-view/writing.md +1 -1
- package/packs/gallery/countdown/component.json +1 -1
- package/packs/gallery/countdown/kit.js +89 -29
- package/packs/gallery/countdown/preview.svg +1 -1
- package/packs/gallery/countdown/style.css +88 -100
- package/packs/gallery/countdown/writing.md +2 -2
- package/packs/gallery/habit/component.json +3 -3
- package/packs/gallery/habit/kit.js +114 -75
- package/packs/gallery/habit/preview.svg +1 -1
- package/packs/gallery/habit/style.css +133 -205
- package/packs/gallery/habit/writing.md +2 -2
- package/packs/gallery/heatmap/component.json +2 -2
- package/packs/gallery/heatmap/kit.js +335 -173
- package/packs/gallery/heatmap/preview.svg +1 -1
- package/packs/gallery/heatmap/style.css +158 -170
- package/packs/gallery/heatmap/writing.md +2 -2
- package/packs/gallery/kanban/kit.js +3 -3
- package/packs/gallery/kanban/writing.md +1 -1
- package/packs/gallery/metric/kit.js +3 -3
- package/packs/gallery/metric/writing.md +1 -1
- package/packs/gallery/note/component.json +3 -3
- package/packs/gallery/note/kit.js +40 -13
- package/packs/gallery/note/preview.svg +1 -1
- package/packs/gallery/note/style.css +51 -30
- package/packs/gallery/note/writing.md +2 -2
- package/packs/gallery/recent/component.json +2 -2
- package/packs/gallery/recent/kit.js +141 -86
- package/packs/gallery/recent/preview.svg +1 -1
- package/packs/gallery/recent/style.css +53 -126
- package/packs/gallery/recent/writing.md +2 -2
- package/packs/gallery/static/component.json +2 -2
- package/packs/gallery/static/preview.svg +1 -1
- package/packs/gallery/static/style.css +99 -66
- package/packs/gallery/static/writing.md +2 -2
- package/packs/gallery/stats/component.json +3 -3
- package/packs/gallery/stats/kit.js +253 -72
- package/packs/gallery/stats/preview.svg +1 -1
- package/packs/gallery/stats/style.css +64 -142
- package/packs/gallery/stats/writing.md +2 -2
- package/packs/gallery/today/component.json +2 -2
- package/packs/gallery/today/kit.js +62 -27
- package/packs/gallery/today/preview.svg +1 -1
- package/packs/gallery/today/style.css +101 -72
- package/packs/gallery/today/writing.md +2 -2
- package/packs/gallery/todos/component.json +1 -1
- package/packs/gallery/todos/kit.js +218 -71
- package/packs/gallery/todos/preview.svg +1 -1
- package/packs/gallery/todos/style.css +170 -223
- package/packs/gallery/todos/writing.md +1 -1
- package/packs/gallery/weather/component.json +2 -2
- package/packs/gallery/weather/kit.js +165 -90
- package/packs/gallery/weather/preview.svg +1 -1
- package/packs/gallery/weather/style.css +100 -218
- package/packs/gallery/weather/writing.md +1 -1
- package/packs/gallery-soft/countdown/component.json +18 -0
- package/packs/gallery-soft/countdown/example.html +3 -0
- package/packs/gallery-soft/countdown/kit.js +206 -0
- package/packs/gallery-soft/countdown/preview.svg +1 -0
- package/packs/gallery-soft/countdown/style.css +211 -0
- package/packs/gallery-soft/countdown/template.html +3 -0
- package/packs/gallery-soft/countdown/writing.md +24 -0
- package/packs/gallery-soft/habit/component.json +14 -0
- package/packs/gallery-soft/habit/example.html +3 -0
- package/packs/gallery-soft/habit/kit.js +366 -0
- package/packs/gallery-soft/habit/preview.svg +1 -0
- package/packs/gallery-soft/habit/style.css +251 -0
- package/packs/gallery-soft/habit/template.html +3 -0
- package/packs/gallery-soft/habit/writing.md +23 -0
- package/packs/gallery-soft/heatmap/component.json +18 -0
- package/packs/gallery-soft/heatmap/example.html +3 -0
- package/packs/gallery-soft/heatmap/kit.js +498 -0
- package/packs/gallery-soft/heatmap/preview.svg +1 -0
- package/packs/gallery-soft/heatmap/style.css +181 -0
- package/packs/gallery-soft/heatmap/template.html +3 -0
- package/packs/gallery-soft/heatmap/writing.md +23 -0
- package/packs/gallery-soft/note/component.json +14 -0
- package/packs/gallery-soft/note/example.html +3 -0
- package/packs/gallery-soft/note/kit.js +162 -0
- package/packs/gallery-soft/note/preview.svg +1 -0
- package/packs/gallery-soft/note/style.css +148 -0
- package/packs/gallery-soft/note/template.html +3 -0
- package/packs/gallery-soft/note/writing.md +20 -0
- package/packs/gallery-soft/recent/component.json +13 -0
- package/packs/gallery-soft/recent/example.html +1 -0
- package/packs/gallery-soft/recent/kit.js +335 -0
- package/packs/gallery-soft/recent/preview.svg +1 -0
- package/packs/gallery-soft/recent/style.css +160 -0
- package/packs/gallery-soft/recent/template.html +1 -0
- package/packs/gallery-soft/recent/writing.md +17 -0
- package/packs/gallery-soft/static/component.json +13 -0
- package/packs/gallery-soft/static/example.html +12 -0
- package/packs/gallery-soft/static/preview.svg +1 -0
- package/packs/gallery-soft/static/style.css +186 -0
- package/packs/gallery-soft/static/template.html +1 -0
- package/packs/gallery-soft/static/writing.md +20 -0
- package/packs/gallery-soft/stats/component.json +13 -0
- package/packs/gallery-soft/stats/example.html +1 -0
- package/packs/gallery-soft/stats/kit.js +341 -0
- package/packs/gallery-soft/stats/preview.svg +1 -0
- package/packs/gallery-soft/stats/style.css +119 -0
- package/packs/gallery-soft/stats/template.html +1 -0
- package/packs/gallery-soft/stats/writing.md +13 -0
- package/packs/gallery-soft/today/component.json +12 -0
- package/packs/gallery-soft/today/example.html +1 -0
- package/packs/gallery-soft/today/kit.js +222 -0
- package/packs/gallery-soft/today/preview.svg +1 -0
- package/packs/gallery-soft/today/style.css +178 -0
- package/packs/gallery-soft/today/template.html +1 -0
- package/packs/gallery-soft/today/writing.md +16 -0
- package/packs/gallery-soft/todos/component.json +19 -0
- package/packs/gallery-soft/todos/example.html +3 -0
- package/packs/gallery-soft/todos/kit.js +527 -0
- package/packs/gallery-soft/todos/preview.svg +1 -0
- package/packs/gallery-soft/todos/style.css +212 -0
- package/packs/gallery-soft/todos/template.html +3 -0
- package/packs/gallery-soft/todos/writing.md +32 -0
- package/packs/gallery-soft/weather/component.json +19 -0
- package/packs/gallery-soft/weather/example.html +3 -0
- package/packs/gallery-soft/weather/kit.js +411 -0
- package/packs/gallery-soft/weather/preview.svg +1 -0
- package/packs/gallery-soft/weather/style.css +185 -0
- package/packs/gallery-soft/weather/template.html +3 -0
- package/packs/gallery-soft/weather/writing.md +28 -0
- package/release.json +10 -10
- package/skill/SKILL.md +15 -14
- package/skill/references/building-blocks.md +4 -4
- package/skill/references/extensions.md +11 -7
- package/skill/references/pages-and-data.md +13 -9
- package/skill/references/writing-html.md +2 -0
- package/web/assets/index-BHC5ZOMh.js +15 -0
- package/web/assets/index-xP0uw3a0.css +1 -0
- package/web/index.html +2 -2
- package/dist/chunk-2NRBY6AJ.mjs +0 -2
- package/dist/chunk-35NQ4PLQ.mjs +0 -2
- package/dist/chunk-3KJHLHUO.mjs +0 -2
- package/dist/chunk-4AV456RQ.mjs +0 -2
- package/dist/chunk-5XYHDBJ5.mjs +0 -2
- package/dist/chunk-6A53MZYZ.mjs +0 -2
- package/dist/chunk-6EXH3ORZ.mjs +0 -166
- package/dist/chunk-BVEFGE4B.mjs +0 -2
- package/dist/chunk-D4EURAX4.mjs +0 -4
- package/dist/chunk-DQCE7TJY.mjs +0 -5
- package/dist/chunk-FWNRPMCJ.mjs +0 -12
- package/dist/chunk-FWW4CSAZ.mjs +0 -2
- package/dist/chunk-GY3FAUVM.mjs +0 -2
- package/dist/chunk-JVHHHGEA.mjs +0 -3
- package/dist/chunk-L7UP52JO.mjs +0 -2
- package/dist/chunk-NAMN3RAF.mjs +0 -2
- package/dist/chunk-PZDLJJTJ.mjs +0 -3
- package/dist/chunk-SXHBYZST.mjs +0 -16
- package/dist/chunk-TEZAWDSQ.mjs +0 -2
- package/dist/chunk-UFNYFFKO.mjs +0 -20
- package/dist/chunk-UKSHDZZ6.mjs +0 -2
- package/dist/chunk-VJPFVNNW.mjs +0 -15
- package/dist/chunk-VS3ZMVGX.mjs +0 -5
- package/web/assets/index-BK2e_07w.js +0 -13
- package/web/assets/index-CWFI83mF.css +0 -1
- /package/dist/{chunk-YEY3RSFQ.mjs → chunk-5MMN3N5J.mjs} +0 -0
- /package/dist/{chunk-UH4SIXTR.mjs → chunk-74UW7QSL.mjs} +0 -0
- /package/dist/{chunk-W7XHE4CT.mjs → chunk-EKGYYOSP.mjs} +0 -0
- /package/dist/{chunk-QAIHRH3I.mjs → chunk-KNZJT4ET.mjs} +0 -0
- /package/dist/{chunk-A55HN5OK.mjs → chunk-N3DSBH5S.mjs} +0 -0
- /package/dist/{chunk-QR6A54KJ.mjs → chunk-ZW2A6GBW.mjs} +0 -0
|
@@ -11,7 +11,8 @@ import { t } from "../../../shared/i18n/index.mjs";
|
|
|
11
11
|
|
|
12
12
|
// A table's column widths (notion-lite's: a 3px strip on each column's right edge; the plan's D4:
|
|
13
13
|
// the kit's own widths until the reader sizes a column). Dragging a strip sizes its column (35px at
|
|
14
|
-
// least
|
|
14
|
+
// least; the last one's, the table's right edge, snaps where the table is exactly as wide as the
|
|
15
|
+
// text: SNAP), shown as it goes (Esc puts it back), written when let go as one undo
|
|
15
16
|
// step: every column's width on the topmost cell of that column alone (--doc-column-width,
|
|
16
17
|
// index.mjs COLUMN_WIDTH; shared/table-slots.mjs widthHolder: a merged cell holds none), the kit laying the table
|
|
17
18
|
// out at them (tables/layout.js manualLayout); the first
|
|
@@ -50,6 +51,8 @@ const STYLE = `
|
|
|
50
51
|
.ge-trows > b > svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; transform: rotate(90deg); }
|
|
51
52
|
${gestureLock("data-ge-tresize", { cursor: "col-resize", select: true })}
|
|
52
53
|
`;
|
|
54
|
+
const SNAP = 6; // px: the last column's edge within this of the width that fills the text lands on it (as the resize tool's: resize/)
|
|
55
|
+
const LIVE = 60000; // ms: the notice saying the table is full stays while the drag lasts (taken off when it ends)
|
|
53
56
|
const DOUBLE = 500; // two presses on a strip within this many ms are a double click (a press on the armed edge after its click too)
|
|
54
57
|
const EDGE = 8; // the edges' strips reach this far past the table (the resize tool's grab)
|
|
55
58
|
const ARROWS = '<svg viewBox="0 0 12 12" aria-hidden="true"><path d="M1.5 6h9M3.5 4 1.5 6l2 2M8.5 4l2 2-2 2"/></svg>';
|
|
@@ -62,8 +65,29 @@ export function createColumnWidths(tools) {
|
|
|
62
65
|
let armed = null; // an edge clicked: { unit, axis: "x" (right) | "y" (bottom), at: when, shown }, the next drag of it the table's size
|
|
63
66
|
let quick = null; // the armed right edge pressed soon after its click: { unit, index, x } (let go there, a double click)
|
|
64
67
|
|
|
65
|
-
/**
|
|
66
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Each column's width as the table shows it now, px: the width of its cells, not the distance
|
|
70
|
+
* between their edges. A table scrolled sideways keeps its first column in sight (position: sticky,
|
|
71
|
+
* tables.css: a header column or .doc-table--sticky-first), so the edges of those cells are not the
|
|
72
|
+
* columns' and the column under them would read as the part of it in sight: every width then sums
|
|
73
|
+
* to the frame's, the table seeming full, the columns before the border squeezed when it was pressed.
|
|
74
|
+
*/
|
|
75
|
+
const shown = (unit) => {
|
|
76
|
+
const { slots } = tableState(unit);
|
|
77
|
+
if (!slots) return tools.geometry(unit).columns.map((column) => Math.round((column.right - column.left) * 100) / 100);
|
|
78
|
+
const cells = [...slots.places].map(([cell, place]) => ({ ...place, width: cell.getBoundingClientRect().width }));
|
|
79
|
+
const widths = Array(slots.columns).fill(null);
|
|
80
|
+
for (const { c, cols, width } of cells) if (cols === 1) widths[c] ??= width;
|
|
81
|
+
// A column no single cell gives a width: what the cells merged over it leave, shared out.
|
|
82
|
+
for (const { c, cols, width } of cells.filter((cell) => cell.cols > 1).sort((a, b) => a.cols - b.cols)) {
|
|
83
|
+
const over = Array.from({ length: cols }, (_, i) => c + i);
|
|
84
|
+
const open = over.filter((i) => widths[i] === null);
|
|
85
|
+
if (open.length === 0) continue;
|
|
86
|
+
const left = Math.max(0, width - over.reduce((sum, i) => sum + (widths[i] ?? 0), 0));
|
|
87
|
+
for (const i of open) widths[i] = left / open.length;
|
|
88
|
+
}
|
|
89
|
+
return widths.map((width) => Math.round((width ?? 0) * 100) / 100);
|
|
90
|
+
};
|
|
67
91
|
/** The cells holding the columns' widths: per column, its topmost cell alone, or null. */
|
|
68
92
|
const holders = (unit) => {
|
|
69
93
|
const { slots } = tableState(unit);
|
|
@@ -101,20 +125,56 @@ export function createColumnWidths(tools) {
|
|
|
101
125
|
return done;
|
|
102
126
|
}
|
|
103
127
|
|
|
104
|
-
// Shown as it goes: the holders' widths set straight (taken back before the undo step)
|
|
105
|
-
|
|
128
|
+
// Shown as it goes: the holders' widths set straight (taken back before the undo step), the
|
|
129
|
+
// table's own width (--doc-span) off while it lasts, as the kit would else keep the columns in
|
|
130
|
+
// proportion to it and the table where it was.
|
|
131
|
+
function preview(drag, widths) {
|
|
132
|
+
const { unit } = drag;
|
|
133
|
+
if (drag.span === undefined) {
|
|
134
|
+
drag.span = unit.style.getPropertyValue(SPAN);
|
|
135
|
+
unit.style.removeProperty(SPAN);
|
|
136
|
+
}
|
|
106
137
|
holders(unit).forEach((cell, c) => cell?.style.setProperty(COLUMN_WIDTH, `${widths[c]}px`));
|
|
107
138
|
relayout(unit);
|
|
108
139
|
}
|
|
109
|
-
function putBack({ unit, before }) {
|
|
140
|
+
function putBack({ unit, before, span }) {
|
|
110
141
|
for (const [cell, width] of before) {
|
|
111
142
|
if (width) cell.style.setProperty(COLUMN_WIDTH, width);
|
|
112
143
|
else cell.style.removeProperty(COLUMN_WIDTH);
|
|
113
144
|
if (cell.getAttribute("style") === "") cell.removeAttribute("style");
|
|
114
145
|
}
|
|
146
|
+
if (span) unit.style.setProperty(SPAN, span);
|
|
115
147
|
relayout(unit);
|
|
116
148
|
}
|
|
117
149
|
|
|
150
|
+
// The columns' widths together (px) at which the table is exactly as wide as the text (or the
|
|
151
|
+
// column it stands in): the room its frame has, as the kit lays a table out at the reader's widths
|
|
152
|
+
// (tables/layout.js manualLayout: a table of that width or more has the frame at 100%, one less
|
|
153
|
+
// a frame as wide as it). Null where the frame has none.
|
|
154
|
+
function fillOf(unit) {
|
|
155
|
+
const parent = unit.parentElement;
|
|
156
|
+
if (!parent) return null;
|
|
157
|
+
const sides = (node) => {
|
|
158
|
+
const style = getComputedStyle(node);
|
|
159
|
+
return ["borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight"].reduce((sum, name) => sum + (parseFloat(style[name]) || 0), 0);
|
|
160
|
+
};
|
|
161
|
+
const room = parent.getBoundingClientRect().width - sides(parent) - sides(unit);
|
|
162
|
+
return room > 0 ? room : null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// The last column's right edge is the table's: within SNAP of the width that fills the text, the
|
|
166
|
+
// last column takes what the others leave of it (rounded down: never a hair past the frame).
|
|
167
|
+
// True when it did. `widths` is changed in place.
|
|
168
|
+
function snapFull({ last, fill, start, index }, widths) {
|
|
169
|
+
if (!last || fill === null) return false;
|
|
170
|
+
const rest = start.reduce((sum, width, c) => (c === index ? sum : sum + width), 0);
|
|
171
|
+
const wanted = Math.floor((fill - rest) * 100) / 100;
|
|
172
|
+
if (wanted < MIN_COLUMN_WIDTH || Math.abs(rest + widths[index] - fill) > SNAP) return false;
|
|
173
|
+
widths[index] = wanted;
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
const FULL = () => [t("表格"), t("宽度"), t("铺满正文")];
|
|
177
|
+
|
|
118
178
|
// A column fitted to its widest cell of it alone, unwrapped (+1px): by its words, not the words an
|
|
119
179
|
// Agent took out that the page shows in it (changes/: out of the layout while it is measured).
|
|
120
180
|
function fit(unit, index) {
|
|
@@ -221,7 +281,7 @@ export function createColumnWidths(tools) {
|
|
|
221
281
|
return fit(unit, index);
|
|
222
282
|
}
|
|
223
283
|
const { rows } = tableParts(unit);
|
|
224
|
-
drag = { unit, index, x: event.clientX, last, fresh: true, start: shown(unit), before: new Map(rows.flatMap((row) => [...row.cells]).map((cell) => [cell, widthOf(cell)])) };
|
|
284
|
+
drag = { unit, index, x: event.clientX, last, fill: last ? fillOf(unit) : null, told: false, fresh: true, start: shown(unit), before: new Map(rows.flatMap((row) => [...row.cells]).map((cell) => [cell, widthOf(cell)])) };
|
|
225
285
|
document.documentElement.setAttribute("data-ge-tresize", "");
|
|
226
286
|
document.documentElement.setPointerCapture?.(event.pointerId);
|
|
227
287
|
});
|
|
@@ -262,8 +322,16 @@ export function createColumnWidths(tools) {
|
|
|
262
322
|
drag.moved = true;
|
|
263
323
|
const widths = [...drag.start];
|
|
264
324
|
widths[drag.index] = Math.max(MIN_COLUMN_WIDTH, Math.round(drag.start[drag.index] + event.clientX - drag.x));
|
|
325
|
+
// The last column's edge snaps to the table that fills the text; the bottom notice says so while it holds.
|
|
326
|
+
const snapped = snapFull(drag, widths);
|
|
265
327
|
drag.widths = widths;
|
|
266
|
-
|
|
328
|
+
drag.snapped = snapped;
|
|
329
|
+
preview(drag, widths);
|
|
330
|
+
if (snapped !== drag.told) {
|
|
331
|
+
drag.told = snapped;
|
|
332
|
+
if (snapped) tools.say(t("{0}{1}:{2}", ...FULL()), "note", LIVE);
|
|
333
|
+
else tools.settle();
|
|
334
|
+
}
|
|
267
335
|
tools.draw();
|
|
268
336
|
}, true);
|
|
269
337
|
|
|
@@ -273,9 +341,13 @@ export function createColumnWidths(tools) {
|
|
|
273
341
|
document.documentElement.removeAttribute("data-ge-tresize");
|
|
274
342
|
if (!done) return;
|
|
275
343
|
putBack(done);
|
|
276
|
-
if (
|
|
344
|
+
if (done.told) tools.settle(); // the notice of the table filling the text: the result's follows, or nothing
|
|
345
|
+
// Back at the widths it had, snapped to a table that was full already (or dragged out and back): nothing to write.
|
|
346
|
+
const unchanged = done.widths?.every((width, c) => Math.abs(width - done.start[c]) < 0.5);
|
|
347
|
+
if (!cancel && done.widths) {
|
|
348
|
+
if (!unchanged && set(done.unit, done.widths) && done.snapped) tools.say(t("已调整{0}{1}:{2} · Ctrl+Z 撤销", ...FULL()));
|
|
277
349
|
// The last strip clicked (pressed, not moved): the table's right edge armed.
|
|
278
|
-
else if (!cancel && done.last) return arm(done.unit, "x");
|
|
350
|
+
} else if (!cancel && done.last) return arm(done.unit, "x");
|
|
279
351
|
tools.draw();
|
|
280
352
|
}
|
|
281
353
|
document.addEventListener("pointerup", () => end(false), true);
|
|
@@ -7,6 +7,7 @@ import { joinCode } from "../marks.mjs";
|
|
|
7
7
|
import { numberWithUnit, sideOf, WORD } from "../../../shared/inline-spacing.mjs";
|
|
8
8
|
import { pageOf, pagesAround } from "../page-objects.mjs";
|
|
9
9
|
import { BLOCK_TYPES, HOSTS, accepts, firstSaysOf, placeholderOf, textFilters, textTypeOf } from "../../components/registry.mjs";
|
|
10
|
+
import { unalign } from "../align.mjs";
|
|
10
11
|
import { t } from "../../../shared/i18n/index.mjs";
|
|
11
12
|
|
|
12
13
|
// Typing in a block (docs/editor.md, "Browser side"): every key goes first to the component the block
|
|
@@ -14,7 +15,7 @@ import { t } from "../../../shared/i18n/index.mjs";
|
|
|
14
15
|
// `if (!ctx.def.keys?.enter?.(ctx)) splitBlock(...)`, and then to the rules of every block. Enter
|
|
15
16
|
// splits it, Backspace and Delete at its edges merge it with the block before or after, or remove it
|
|
16
17
|
// once empty, the caret going to the neighbouring block. Backspace in a container with nothing
|
|
17
|
-
// written in it (`removedEmpty`)
|
|
18
|
+
// written in it (`removedEmpty`) or in an empty heading turns it into an empty paragraph. Chinese typed next to a Latin letter or
|
|
18
19
|
// digit gets a space between them (autoSpace; not a number and its unit, nor in a block written without), and an empty block under the caret says what it takes
|
|
19
20
|
// (placeholder). Plain typing and input methods stay with the browser; the keys are routed here by
|
|
20
21
|
// editor.mjs.
|
|
@@ -53,8 +54,11 @@ function writtenTogether(host, node, start, end) {
|
|
|
53
54
|
* deleted as the selected ones are (selection/delete.mjs). adding(): the block the "/" menu the
|
|
54
55
|
* handle's "+" opened is open in (slash-menu/), or null. leave: where Enter and Backspace leave a
|
|
55
56
|
* container (leave.mjs). showHidden(node): the folds hiding a block opened (fold/ showAround).
|
|
57
|
+
* look(element, change): the editor's undoable change of classes (a block's alignment, align.mjs).
|
|
58
|
+
* afterAbove(host): Backspace at the start of a text block right after a block of no text, the caret
|
|
59
|
+
* put after that block (after/ back); whether it was.
|
|
56
60
|
*/
|
|
57
|
-
export function createTyping({ struct, say, keepText, paragraphBefore, removeBlocks, selectBlock = () => {}, adding = () => null, leave, showHidden = () => {} }) {
|
|
61
|
+
export function createTyping({ struct, say, keepText, paragraphBefore, removeBlocks, selectBlock = () => {}, adding = () => null, leave, showHidden = () => {}, look = () => false, afterAbove = () => false }) {
|
|
58
62
|
// A key, asked of the component of the text block `host` and then of what stands around it, nearest
|
|
59
63
|
// first (docs/editor.md, "The order of keys"): whether it was theirs. `ctx` is notion-lite's, as
|
|
60
64
|
// much of it as a key reads, the block being an element here.
|
|
@@ -101,8 +105,8 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
|
|
|
101
105
|
function split(host) {
|
|
102
106
|
if (HOSTS[host.getAttribute("data-ge-kind")]?.opensBody) return enterBody(host);
|
|
103
107
|
// The caret at the very start of a block with text: an empty paragraph goes before the block and
|
|
104
|
-
// the caret stays (a block that splits does this itself, splitBlock).
|
|
105
|
-
//
|
|
108
|
+
// the caret stays (a block that splits does this itself, splitBlock). Only hosts that opt in take
|
|
109
|
+
// this rule; code keeps its own Enter, which breaks the line even at the start.
|
|
106
110
|
const own = HOSTS[host.getAttribute("data-ge-kind")]?.opensBefore; // not a cell, a card's field, the title
|
|
107
111
|
if (own && !can(host, "split") && !isEmpty(host) && atEdge(host, false) && paragraphBefore(host)) return;
|
|
108
112
|
// Its component's Enter (a code block's line, a nested item out a level, a title going into its
|
|
@@ -152,10 +156,33 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
|
|
|
152
156
|
return true;
|
|
153
157
|
}
|
|
154
158
|
|
|
155
|
-
//
|
|
156
|
-
|
|
157
|
-
|
|
159
|
+
// Whether a block may not go (keepText): the reason said, a note that stays a while.
|
|
160
|
+
function kept(node) {
|
|
161
|
+
const reason = keepText(node);
|
|
162
|
+
if (reason) say(reason, "note", 6000);
|
|
163
|
+
return Boolean(reason);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// An empty container turned into an empty paragraph where it stands, the caret in it (the user's,
|
|
167
|
+
// 2026-11-09: as an empty heading, an empty item and every other empty block go back to body text,
|
|
168
|
+
// not away with the caret on the block before); one undo step, which brings the container back.
|
|
169
|
+
// Where its box takes no paragraph it is deleted whole (one undo step, which selects it again), the
|
|
170
|
+
// caret at the end of the block before it, or at the start of the one after it when it was first (a
|
|
171
|
+
// formula block passed over: textNear).
|
|
158
172
|
function removeContainer(container) {
|
|
173
|
+
const box = container.parentElement;
|
|
174
|
+
const paragraph = newParagraphHost(document);
|
|
175
|
+
if (box && accepts(boxKind(box), paragraph.getAttribute("data-ge-type"))) {
|
|
176
|
+
if (kept(container)) return true;
|
|
177
|
+
const parts = withLeads(container);
|
|
178
|
+
struct([box], [], () => {
|
|
179
|
+
parts[0].before(paragraph);
|
|
180
|
+
parts.forEach((part) => part.remove());
|
|
181
|
+
return { touched: [paragraph], focus: paragraph };
|
|
182
|
+
});
|
|
183
|
+
caretAt(paragraph, "start");
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
159
186
|
const list = hosts();
|
|
160
187
|
const inside = list.filter((node) => container.contains(node));
|
|
161
188
|
const before = textNear(inside[0], -1, list);
|
|
@@ -181,11 +208,7 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
|
|
|
181
208
|
? (next ? [next, "start"] : [previous, "end"])
|
|
182
209
|
: (previous ? [previous, "end"] : [next, "start"]);
|
|
183
210
|
const node = removalTarget(host);
|
|
184
|
-
|
|
185
|
-
if (kept) {
|
|
186
|
-
say(kept, "note", 6000);
|
|
187
|
-
return true;
|
|
188
|
-
}
|
|
211
|
+
if (kept(node)) return true;
|
|
189
212
|
struct([node.parentNode], [host], () => {
|
|
190
213
|
takeOut(node);
|
|
191
214
|
return { touched: [], focus: target };
|
|
@@ -203,6 +226,9 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
|
|
|
203
226
|
// Backspace at the start of a block. Returns whether it was handled.
|
|
204
227
|
function backspace(host) {
|
|
205
228
|
opened(previousLine(host));
|
|
229
|
+
// A paragraph's or a heading's alignment, then its indent a level at a time, goes before anything
|
|
230
|
+
// else, one undo step each (align.mjs unalign: Feishu's 退对齐 and 反缩进 before a join).
|
|
231
|
+
if (unalign(host, look)) return true;
|
|
206
232
|
// The block's component (a list item's: a nested item moves out a level, the first or last item of
|
|
207
233
|
// a top-level list leaves it as body text, an emptied item holding lists stays), then what stands
|
|
208
234
|
// around it (the item a block stands under; a node, at the start of its first line, holding
|
|
@@ -212,6 +238,12 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
|
|
|
212
238
|
const container = emptyContainer(host);
|
|
213
239
|
if (container) return removeContainer(container);
|
|
214
240
|
if (leave.backspace(host)) return true;
|
|
241
|
+
// An empty heading (or small text) is an empty paragraph, where it stands (leave.mjs emptied).
|
|
242
|
+
if (leave.emptied(host)) return true;
|
|
243
|
+
// Right after a block of no text (a picture, a table, a code block, a callout, a divider, a card…):
|
|
244
|
+
// the caret after it, at its bottom right (after/), an empty block going (the user's, 2026-11-09:
|
|
245
|
+
// Backspace there went into the block, or past a picture to the text before it); never a join.
|
|
246
|
+
if (afterAbove(host)) return true;
|
|
215
247
|
if (isEmpty(host)) return removeHost(host, false);
|
|
216
248
|
if (merge(host)) return true;
|
|
217
249
|
// A block holding blocks that did not join the line above says why, as its component puts it.
|
|
@@ -14,6 +14,8 @@ import { BLOCK_TYPES, LEAVES_BY_ENTER, accepts } from "../../components/registry
|
|
|
14
14
|
// too) moves out after the box, which goes if nothing is left in it (`leaveBox`).
|
|
15
15
|
// - A block of a type that says `resettable` (a quote's paragraph, a list item) turns into a
|
|
16
16
|
// paragraph where it stands, its container splitting around it (convert.mjs).
|
|
17
|
+
// - Backspace in an empty block of a type that says `emptyToText` (a heading, small text) turns it
|
|
18
|
+
// into an empty paragraph where it stands (`emptied`; the user's, 2026-11-09).
|
|
17
19
|
// Enter in a title that goes into its content (a disclosure, a card, a code block) is another rule
|
|
18
20
|
// (their components').
|
|
19
21
|
|
|
@@ -36,8 +38,10 @@ export function leaveBox(host) {
|
|
|
36
38
|
* and touchedBy (a structural undo step), convertHost, typeOf and targetsOf (convert.mjs).
|
|
37
39
|
*/
|
|
38
40
|
export function createLeaving({ struct, touchedBy, convertHost, typeOf, targetsOf }) {
|
|
39
|
-
// A block of a type that
|
|
40
|
-
const
|
|
41
|
+
// A block of a type that says `field` (resettable, emptyToText), which can be body text where it stands.
|
|
42
|
+
const says = (host, field) => BLOCK_TYPES[typeOf(host)]?.[field] === true && targetsOf(host).includes("paragraph");
|
|
43
|
+
const resets = (host) => says(host, "resettable");
|
|
44
|
+
const toText = (host) => convertHost(host, "paragraph");
|
|
41
45
|
|
|
42
46
|
// Enter on an empty text block. True when it left its container or became text.
|
|
43
47
|
function enter(host) {
|
|
@@ -52,7 +56,7 @@ export function createLeaving({ struct, touchedBy, convertHost, typeOf, targetsO
|
|
|
52
56
|
return true;
|
|
53
57
|
}
|
|
54
58
|
if (!resets(host)) return false;
|
|
55
|
-
|
|
59
|
+
toText(host);
|
|
56
60
|
return true;
|
|
57
61
|
}
|
|
58
62
|
|
|
@@ -60,9 +64,19 @@ export function createLeaving({ struct, touchedBy, convertHost, typeOf, targetsO
|
|
|
60
64
|
// quote's first paragraph), turns into body text before the container. True when it did.
|
|
61
65
|
function backspace(host) {
|
|
62
66
|
if (!resets(host) || host.parentElement?.firstElementChild !== host) return false;
|
|
63
|
-
|
|
67
|
+
toText(host);
|
|
64
68
|
return true;
|
|
65
69
|
}
|
|
66
70
|
|
|
67
|
-
|
|
71
|
+
// Backspace in an empty text block of a type that says `emptyToText` (a heading, small text): it turns
|
|
72
|
+
// into an empty paragraph where it stands, the caret in it, one undo step (the user's, 2026-11-09: as an
|
|
73
|
+
// emptied item or quote paragraph, and as every container left empty, goes back to body text). True
|
|
74
|
+
// when it did.
|
|
75
|
+
function emptied(host) {
|
|
76
|
+
if (!isEmpty(host) || !says(host, "emptyToText")) return false;
|
|
77
|
+
toText(host);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { enter, backspace, emptied };
|
|
68
82
|
}
|
|
@@ -2,7 +2,7 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { componentSettings, problemIn, writeComponentSettings } from "./component-catalog.mjs";
|
|
4
4
|
import { refusal, said } from "./i18n/index.mjs";
|
|
5
|
-
import { PACK_FILE, PACK_ID, readPackManifest } from "./pack-manifest.mjs";
|
|
5
|
+
import { DEFAULT_PACK, OWN_SCOPE, PACK_FILE, PACK_ID, readPackManifest } from "./pack-manifest.mjs";
|
|
6
6
|
import { packsDirectory } from "./paths.mjs";
|
|
7
7
|
import { filesIn, fingerprintOf, fingerprintOfFiles, isSystemFile, recordOf, shippedBlocks, shippedPackIds, versionAfter, writeRecord, writingOrder } from "./shipped-blocks.mjs";
|
|
8
8
|
import { DEVICE_NAMES, PACKAGE_MANIFEST, layoutOf, markerOf, packageFolders } from "./workspace.mjs";
|
|
@@ -10,8 +10,9 @@ import { DEVICE_NAMES, PACKAGE_MANIFEST, layoutOf, markerOf, packageFolders } fr
|
|
|
10
10
|
// Block packs (自定义块包: notes/plans/block-packs-plan-2026-11-09.md; docs/render.md "Block packs"). A pack
|
|
11
11
|
// is a scope of the workspace's custom blocks, components/<id>/, with its pack.json (./pack-manifest.mjs)
|
|
12
12
|
// and a folder of each of its blocks, <id>/<name>/, the blocks' ids <id>/<name> as ever, so that nothing
|
|
13
|
-
// written of a block changes; a scope with no pack.json
|
|
14
|
-
//
|
|
13
|
+
// written of a block changes; a scope with no pack.json is a pack of its own, named by its scope, and
|
|
14
|
+
// local/ (OWN_SCOPE: gallery block new <name>'s, where an Agent's block goes when it names no pack) is the
|
|
15
|
+
// default pack (默认块包, pack-manifest.mjs DEFAULT_PACK), always listed, first. A pack is shared as its folder, or a zip of it (the folder itself, or what it
|
|
15
16
|
// holds, at the zip's top), and installed into a workspace by gallery block pack install (src/cli/component.mjs)
|
|
16
17
|
// or 设置 › 组件列表's 导入 (src/server/component-settings.mjs), which both read it (src/transfer/pack-source.mjs)
|
|
17
18
|
// and hand its files here, checked alike:
|
|
@@ -43,6 +44,18 @@ import { DEVICE_NAMES, PACKAGE_MANIFEST, layoutOf, markerOf, packageFolders } fr
|
|
|
43
44
|
/** Gallery's own packs that a workspace has switched off when they are first installed. */
|
|
44
45
|
export const OFF_AT_FIRST = Object.freeze(["gallery-soft"]);
|
|
45
46
|
|
|
47
|
+
/**
|
|
48
|
+
* The ids of Gallery's own packs that are off though gallery.json names no switch for them: one off at first
|
|
49
|
+
* (OFF_AT_FIRST) that this workspace has not installed yet, which its first install will switch off. A
|
|
50
|
+
* start that installs none (NO_PACKS, a workspace made by hand) has the library offer Gallery's own blocks
|
|
51
|
+
* from the package, and a pack that is off when it comes in is not one of them. `switches` is the catalog
|
|
52
|
+
* settings' `packs` (true on, false off, by id).
|
|
53
|
+
*/
|
|
54
|
+
export function offUntilInstalled(root, switches = {}) {
|
|
55
|
+
const installed = recordOf(root).packs;
|
|
56
|
+
return OFF_AT_FIRST.filter((id) => switches?.[id] === undefined && !isTable(installed?.[id]));
|
|
57
|
+
}
|
|
58
|
+
|
|
46
59
|
/** The environment variable that keeps a start (and gallery init) from installing Gallery's own packs: the tests' workspaces. */
|
|
47
60
|
export const NO_PACKS = "GALLERY_NO_PACKS";
|
|
48
61
|
|
|
@@ -285,14 +298,16 @@ const both = (problem) => ({ zh: problemIn("zh", problem), en: problemIn("en", p
|
|
|
285
298
|
* switch, gallery.json's components.packs), changed (of what was installed, the blocks changed since, and
|
|
286
299
|
* pack.json where it was), newer (of one of Gallery's own that was changed since, Gallery's version of it
|
|
287
300
|
* when that comes after the one installed, which is not put over it; else null) }]: Gallery's own first,
|
|
288
|
-
* then those installed, then the workspace's own, each by id
|
|
301
|
+
* then those installed, then the workspace's own, each by id; and before them all the default pack (local/,
|
|
302
|
+
* OWN_SCOPE: kind "default", named and described by DEFAULT_PACK, its switch as any pack's), whether or
|
|
303
|
+
* not it holds a block yet: where an Agent's block goes when it names no pack.
|
|
289
304
|
*/
|
|
290
305
|
export function workspacePacks(root, { settings = null, shippedIds = shippedPackIds(), directory = packsDirectory } = {}) {
|
|
291
306
|
const { components } = layoutOf(root);
|
|
292
307
|
const record = recordOf(root);
|
|
293
308
|
const installed = isTable(record.packs) ? record.packs : {};
|
|
294
309
|
const blocks = packageFolders(root);
|
|
295
|
-
const scopes = new Set(blocks.map(({ id }) => id.split("/")[0]));
|
|
310
|
+
const scopes = new Set([OWN_SCOPE, ...blocks.map(({ id }) => id.split("/")[0])]);
|
|
296
311
|
try {
|
|
297
312
|
for (const name of fs.readdirSync(components)) if (PACK_ID.test(name) && fs.existsSync(path.join(components, name, PACK_FILE))) scopes.add(name);
|
|
298
313
|
} catch {}
|
|
@@ -336,7 +351,7 @@ export function workspacePacks(root, { settings = null, shippedIds = shippedPack
|
|
|
336
351
|
const ownBlocks = official ? shippedBlocks(directory) : [];
|
|
337
352
|
const behind = official && shipped && changed.some((block) => (block.endsWith(`/${PACK_FILE}`) ? versionAfter(shipped.version, manifest?.version ?? null) : (ownBlocks.some((one) => one.id === block) && versionAfter(ownBlocks.find((one) => one.id === block).version, versionAt(block)))));
|
|
338
353
|
const newer = behind ? shipped.version : null;
|
|
339
|
-
const told = manifest ?? (problem ? null : shipped);
|
|
354
|
+
const told = id === OWN_SCOPE ? DEFAULT_PACK : manifest ?? (problem ? null : shipped);
|
|
340
355
|
return {
|
|
341
356
|
id,
|
|
342
357
|
name: told?.name ?? { zh: id, en: id },
|
|
@@ -345,7 +360,7 @@ export function workspacePacks(root, { settings = null, shippedIds = shippedPack
|
|
|
345
360
|
author: told?.author ?? null,
|
|
346
361
|
homepage: told?.homepage ?? null,
|
|
347
362
|
icon: told?.icon ?? null,
|
|
348
|
-
kind: official ? "official" : was ? "installed" : "own",
|
|
363
|
+
kind: id === OWN_SCOPE ? "default" : official ? "official" : was ? "installed" : "own",
|
|
349
364
|
problem: problem ? both(problem) : null,
|
|
350
365
|
blocks: ids.length,
|
|
351
366
|
enabled: switches[id] !== false,
|
|
@@ -353,7 +368,7 @@ export function workspacePacks(root, { settings = null, shippedIds = shippedPack
|
|
|
353
368
|
newer,
|
|
354
369
|
};
|
|
355
370
|
});
|
|
356
|
-
const rank = ({ id, kind }) => (kind === "official" ? shippedIds.indexOf(id) : kind === "installed" ? 1000 : 2000);
|
|
371
|
+
const rank = ({ id, kind }) => (kind === "default" ? -1 : kind === "official" ? shippedIds.indexOf(id) : kind === "installed" ? 1000 : 2000);
|
|
357
372
|
return listed.sort((a, b) => rank(a) - rank(b) || (a.id < b.id ? -1 : 1));
|
|
358
373
|
}
|
|
359
374
|
|
|
@@ -10,7 +10,7 @@ import { writeAtomic } from "./files.mjs";
|
|
|
10
10
|
import { attr, walk } from "./html-tree.mjs";
|
|
11
11
|
import { HOST, NET, netHostsOf } from "./net-policy.mjs";
|
|
12
12
|
import { inLanguage, refusal, said, saying, told } from "./i18n/index.mjs";
|
|
13
|
-
import { PACK_FILE, PACK_ID, readPackManifest } from "./pack-manifest.mjs";
|
|
13
|
+
import { DEFAULT_PACK, OWN_SCOPE, PACK_FILE, PACK_ID, readPackManifest } from "./pack-manifest.mjs";
|
|
14
14
|
import { DEVICE_NAMES, PACKAGE_MANIFEST, WORKSPACE_MARK, findWorkspace, layoutOf, markerOf, packageFolders } from "./workspace.mjs";
|
|
15
15
|
|
|
16
16
|
// 组件包, custom blocks (自定义块) as the UI and the Agent's documents call them: what the workspace's
|
|
@@ -64,7 +64,7 @@ const PLACES = ["document", "page"];
|
|
|
64
64
|
const DOCUMENT_ONLY = ["document"];
|
|
65
65
|
// What `card` says of a card on a board, in cells of the grid: a row is 12 of them, and a card at most
|
|
66
66
|
// 24 high.
|
|
67
|
-
const CARD_FIELDS = ["sizes", "w", "h", "min", "max", "resize", "fit", "bare"];
|
|
67
|
+
const CARD_FIELDS = ["sizes", "w", "h", "min", "max", "resize", "fit", "bare", "consent"];
|
|
68
68
|
const GRID = { w: 12, h: 24 };
|
|
69
69
|
const FITS = ["fixed", "content"];
|
|
70
70
|
const NO_CARD = { sizes: null, any: false, w: 4, h: null, min: { w: 1, h: 1 }, max: { ...GRID }, resize: false, fit: "fixed", bare: false };
|
|
@@ -268,7 +268,9 @@ function placesOf(places) {
|
|
|
268
268
|
// the fewest whole cells its content takes). With `sizes`, the first is the default, and no w or h is
|
|
269
269
|
// written beside them; a min or a max beside them frees the card (`any`): the sizes are the common ones
|
|
270
270
|
// its 大小 menu lists, any whole size between min and max is its too (resizing by the corner, a place),
|
|
271
|
-
// and each of the sizes stands inside them.
|
|
271
|
+
// and each of the sizes stands inside them. `consent` ({ zh, en }, where it says one) is what the kit's
|
|
272
|
+
// banner on its card says while it waits for the reader to let it online (允许联网之后显示天气), in place of
|
|
273
|
+
// the kit's own line (允许联网之后显示内容).
|
|
272
274
|
function cardOf(card) {
|
|
273
275
|
if (card === undefined) return NO_CARD;
|
|
274
276
|
if (!isTable(card)) fail(said("{0} 要写成一张表", "card"));
|
|
@@ -307,12 +309,14 @@ function cardOf(card) {
|
|
|
307
309
|
}
|
|
308
310
|
for (const flag of ["resize", "bare"]) if (card[flag] !== undefined && typeof card[flag] !== "boolean") fail(said("{0} 要写成 true 或 false", `card.${flag}`));
|
|
309
311
|
if (card.fit !== undefined && !FITS.includes(card.fit)) fail(said("card.fit 只能是 fixed 或 content"));
|
|
312
|
+
if (card.consent !== undefined) bothLanguages(card.consent, "card.consent");
|
|
310
313
|
return {
|
|
311
314
|
sizes: card.sizes ? card.sizes.map(([width, height]) => [width, height]) : null,
|
|
312
315
|
any, w, h, min, max,
|
|
313
316
|
resize: card.resize ?? false,
|
|
314
317
|
fit: card.fit ?? "fixed",
|
|
315
318
|
bare: card.bare ?? false,
|
|
319
|
+
...(card.consent !== undefined ? { consent: { zh: card.consent.zh, en: card.consent.en } } : {}),
|
|
316
320
|
};
|
|
317
321
|
}
|
|
318
322
|
|
|
@@ -635,7 +639,8 @@ export function readCatalog(root = workspaceRoot(), held = NO_SETTINGS, { on = n
|
|
|
635
639
|
/**
|
|
636
640
|
* What the pack.json of each scope of `scopes` (and of each folder of components/ that holds one) names
|
|
637
641
|
* it: a Map, by scope, of { zh, en }, or null where it has none or one that does not read (a scope of
|
|
638
|
-
* blocks with no pack.json is a pack of its own by its scope's name:
|
|
642
|
+
* blocks with no pack.json is a pack of its own by its scope's name, the default pack, local/, by its own:
|
|
643
|
+
* ./pack-manifest.mjs DEFAULT_PACK, ./block-packs.mjs).
|
|
639
644
|
*/
|
|
640
645
|
export function packNames(root, scopes = []) {
|
|
641
646
|
const { components } = layoutOf(root);
|
|
@@ -647,7 +652,7 @@ export function packNames(root, scopes = []) {
|
|
|
647
652
|
for (const scope of [...new Set([...scopes, ...withFile])].sort()) {
|
|
648
653
|
let name = null;
|
|
649
654
|
try {
|
|
650
|
-
name = readPackManifest(readFileSync(path.join(components, scope, PACK_FILE), "utf8")).name;
|
|
655
|
+
name = scope === OWN_SCOPE ? DEFAULT_PACK.name : readPackManifest(readFileSync(path.join(components, scope, PACK_FILE), "utf8")).name;
|
|
651
656
|
} catch {}
|
|
652
657
|
names.set(scope, name);
|
|
653
658
|
}
|
|
@@ -687,9 +692,9 @@ const stateOf = (found, settings) => (found.problem ? (found.disabled ? "disable
|
|
|
687
692
|
* What the kit is told of a package: where its instances are, its parts, what it leaves on a page, how far
|
|
688
693
|
* its content's shape goes, and what it uses (`needs`, where it names any: the kit gives an instance
|
|
689
694
|
* context.workspace for "workspace", context.fetch for a host of the net and context.table() for
|
|
690
|
-
* "tables").
|
|
695
|
+
* "tables"), and the line its card's consent banner says (`consent`, its card's, where it says one).
|
|
691
696
|
*/
|
|
692
|
-
export const descriptionOf = ({ id, match, parts, runtime, schema, needs }) => ({ id, match, parts, ...(runtime ? { runtime } : {}), ...(schema !== undefined ? { schema } : {}), ...(needs?.length ? { needs } : {}) });
|
|
697
|
+
export const descriptionOf = ({ id, match, parts, runtime, schema, needs, card }) => ({ id, match, parts, ...(runtime ? { runtime } : {}), ...(schema !== undefined ? { schema } : {}), ...(needs?.length ? { needs } : {}), ...(card?.consent ? { consent: card.consent } : {}) });
|
|
693
698
|
|
|
694
699
|
/**
|
|
695
700
|
* What the kit is told of a catalog, each by DocKit.describe, the one way a page learns a package's
|
|
@@ -786,7 +791,8 @@ export const templateOf = (found) => readTemplate(found).markup ?? null;
|
|
|
786
791
|
* no route and no dynamic import. One entry for each package that loads, by id: { id, version, name:
|
|
787
792
|
* { zh, en }, description: { zh, en }, words, definition, stamp, template (the markup "/" puts in: one
|
|
788
793
|
* instance of it, or null), preview (the address of its picture, or null), state ("normal", or "hidden": a menu offers what is "normal" and reads no setting), places (which the page's
|
|
789
|
-
* settingState reads with gallery.json's lists as its event stream says them), needs,
|
|
794
|
+
* settingState reads with gallery.json's lists as its event stream says them), needs, settings (the fields of its 设置 form, a
|
|
795
|
+
* manifest's `settings`, [] where it has none), markdown, assets (the kit's files it asks for,
|
|
790
796
|
* by id), tags (packageTags: what loads it in a page that was served without it, the line that tells the
|
|
791
797
|
* kit of its parts among them), pack ({ id, name }: the pack it is of, its scope, and what its pack.json names
|
|
792
798
|
* it, null where none does: a menu writes the pack's name after a block's in grey where two packs offer
|
|
@@ -806,6 +812,7 @@ export const menuOf = ({ packages, settings = NO_SETTINGS, packs = new Map() })
|
|
|
806
812
|
state: stateOf(found, settings),
|
|
807
813
|
places: found.places,
|
|
808
814
|
needs: found.needs,
|
|
815
|
+
settings: found.settings,
|
|
809
816
|
markdown: found.markdown,
|
|
810
817
|
assets: found.assets,
|
|
811
818
|
tags: packageTags(found),
|
|
@@ -16,7 +16,7 @@ export const SOURCE_ATTRIBUTES = ["data-checked", "rowspan", "colspan", "data-so
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* The classes that are a block's or a cell's look, which a reader sets and the file keeps: a text color
|
|
19
|
-
* or a fill (doc-text-<color>, doc-highlight-<color>), a cell's alignments and its bold (table.mjs's
|
|
19
|
+
* or a fill (doc-text-<color>, doc-highlight-<color>), a text block's alignment and indent (a table's frame's alignment is the same two classes), a cell's alignments and its bold (table.mjs's
|
|
20
20
|
* CELL_ALIGN_CLASSES, CELL_VALIGN_CLASSES, CELL_BOLD_CLASS, the editor's CELL_LOOKS). What the kit and
|
|
21
21
|
* the editor toggle as they lay a page out (a table's number and doc-table--auto, a code block's
|
|
22
22
|
* folds) is none, so that no component hears its own layout as a change of the file, and draws again
|
|
@@ -28,6 +28,8 @@ export const LOOK_CLASSES = new Set([
|
|
|
28
28
|
// file would bring its description, prose and all, into the kit's runtime (tests/unit/installed.mjs
|
|
29
29
|
// holds the two lists together).
|
|
30
30
|
"doc-align-left", "doc-align-center", "doc-align-right", "doc-valign-top", "doc-valign-middle", "doc-valign-bottom", "doc-bold",
|
|
31
|
+
// A paragraph's or a heading's indent (the editor's components/align.mjs INDENTS; its alignment is a cell's classes above).
|
|
32
|
+
...Array.from({ length: 8 }, (_, index) => `doc-indent-${index + 1}`),
|
|
31
33
|
]);
|
|
32
34
|
|
|
33
35
|
/** Whether a class attribute's look classes (LOOK_CLASSES) differ from `before` to `after`, either null for none. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// A heading, levels 1 to 4 (the fourth body-sized): a basic block.
|
|
1
|
+
// A heading, levels 1 to 4 (the fourth body-sized): a basic block. Aligned and indented as a paragraph
|
|
2
|
+
// is (paragraph.mjs TEXT_ALIGN_CLASSES, described there and by the table).
|
|
2
3
|
export default {
|
|
3
4
|
id: "heading",
|
|
4
5
|
category: "block",
|
|
@@ -124,7 +124,7 @@ export const PACKAGE_MARK = "data-doc-package";
|
|
|
124
124
|
export const ARRIVING = "data-ge-arriving";
|
|
125
125
|
|
|
126
126
|
/**
|
|
127
|
-
* Whether the document's insert entries ("/", 在下方新建, the handle's grid
|
|
127
|
+
* Whether the document's insert entries ("/", 在下方新建, the handle's grid) offer the
|
|
128
128
|
* block `id` whose manifest's `places` are those (left out: ["document"]), by gallery.json's lists
|
|
129
129
|
* (`settings`: hidden, shown, disabled, unlisted, packsOff, each left out for none): one that says it stands in a
|
|
130
130
|
* document is offered unless hidden; one that does not, only where shown; one disabled never, as it does
|
|
@@ -47,6 +47,8 @@ export default {
|
|
|
47
47
|
// a copy of the view keeps; never written in doc.html.
|
|
48
48
|
state: { html: ["data-doc-theme", ...Object.values(LOOK_ATTRIBUTES)] },
|
|
49
49
|
internal: ["doc-display*", "data-doc-export-copy", "data-theme", "doc-export-id", "doc-reveal", "doc-kit-error", "doc-net-consent*", "data-doc-snapshot",
|
|
50
|
+
// A consent bar on a card under 240px of content (runtime/net.js), its line over its button.
|
|
51
|
+
"data-doc-net-narrow",
|
|
50
52
|
// The time an export's snapshot was made (its data-doc-snapshot tag's: render/net-snapshot.mjs), which context.workspace.query answers as `at`.
|
|
51
53
|
"data-at",
|
|
52
54
|
// A custom page's (no document's: src/render/page-html.mjs, the kit's board/): its cards' cells, the Agent's
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
// A paragraph (文本), or small text (小字, p.doc-note): a basic block. Small text may end in a part at
|
|
2
2
|
// the line's right end (span.doc-tab: the page editor's Tab).
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A paragraph's or a heading's alignment and indent (the page editor's 对齐与缩进): centred or at the
|
|
6
|
+
* right (left is neither), moved in by levels of two body characters (styles/flow.css).
|
|
7
|
+
*/
|
|
8
|
+
export const TEXT_ALIGN_CLASSES = ["doc-align-center", "doc-align-right", ...Array.from({ length: 8 }, (_, index) => `doc-indent-${index + 1}`)];
|
|
9
|
+
|
|
3
10
|
export default {
|
|
4
11
|
id: "paragraph",
|
|
5
12
|
category: "block",
|
|
6
13
|
match: "p",
|
|
7
14
|
tail: ".doc-tab", // small text's end part, a span at the line's right end
|
|
8
|
-
classes: ["doc-note", "doc-tab"],
|
|
15
|
+
classes: ["doc-note", "doc-tab", ...TEXT_ALIGN_CLASSES.filter((name) => name.startsWith("doc-indent-"))], // the alignments are the table's (a cell's), the same classes
|
|
9
16
|
};
|
|
@@ -30,6 +30,7 @@ export default {
|
|
|
30
30
|
"data-number-columns": "off: no column read as numbers (none centered, none sortable by number), on the table or its frame",
|
|
31
31
|
"data-doc-chart-source": "on its frame: the key a chart drawn from it reads it by (data-doc-chart-data on the chart's host)",
|
|
32
32
|
},
|
|
33
|
+
// The frame may be placed centred or at the right (doc-align-center, doc-align-right, a text block's: the page editor's 对齐 ›).
|
|
33
34
|
// A cell may also be given a text color or a fill (doc-text-*, doc-highlight-*: text.mjs), an alignment, a vertical one and bold
|
|
34
35
|
// (doc-bold); a header row's cell's look is doc-bold doc-highlight-gray, as the page editor gives it (a header column's th scope="row" none).
|
|
35
36
|
classes: ["doc-table", "doc-table-wrap", "doc-table-meta", "doc-table--sticky-first", ...CELL_ALIGN_CLASSES, ...CELL_VALIGN_CLASSES, CELL_BOLD_CLASS],
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parse } from "parse5";
|
|
4
|
+
import { attr, walk } from "./html-tree.mjs";
|
|
5
|
+
import { escapeAttribute } from "./escape.mjs";
|
|
6
|
+
import { newNames } from "./new-names.mjs";
|
|
7
|
+
import { COMPONENTS_FOLDER, DOCUMENT_FOLDERS, SHARED_FOLDERS, documentFiles, packageFolders, readLink } from "./workspace.mjs";
|
|
8
|
+
|
|
9
|
+
/** Files belonging to a document, excluding packages/pages sharing a legacy reserved folder. */
|
|
10
|
+
export async function documentNames(root, slug) {
|
|
11
|
+
const entries = await fs.readdir(path.join(root, slug), { withFileTypes: true });
|
|
12
|
+
if (!SHARED_FOLDERS.includes(slug)) return entries.map(({ name }) => name);
|
|
13
|
+
const scopes = slug === COMPONENTS_FOLDER ? new Set(packageFolders(root).map(({ id }) => id.split("/")[0])) : new Set();
|
|
14
|
+
return entries.filter(entry => entry.isFile() || (DOCUMENT_FOLDERS.includes(entry.name) && !scopes.has(entry.name))).map(({ name }) => name);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Same copy primitive for duplicate and cross-workspace copy: local assets and metadata stay intact. */
|
|
18
|
+
export async function copyEntryFiles(root, slug, destination, copy, { names = new Map() } = {}) {
|
|
19
|
+
const source = path.join(root, slug);
|
|
20
|
+
const document = await fs.access(documentFiles(source).html).then(() => true, () => false);
|
|
21
|
+
const link = document ? null : await readLink(source);
|
|
22
|
+
const own = new Set(["", ...(await documentNames(root, slug))]);
|
|
23
|
+
await fs.cp(source, destination, { recursive: true, errorOnExist: true, force: false, filter: from => own.has(path.relative(source, from).split(path.sep)[0]) });
|
|
24
|
+
if (link) return [];
|
|
25
|
+
const file = documentFiles(destination).html;
|
|
26
|
+
const html = await fs.readFile(file, "utf8");
|
|
27
|
+
const text = newNames(html);
|
|
28
|
+
const edits = new Map(), packages = new Set();
|
|
29
|
+
walk(parse(text.replace(/^\uFEFF/, " "), { sourceCodeLocationInfo: true }), node => {
|
|
30
|
+
const component = attr(node, "data-doc-component");
|
|
31
|
+
if (component) packages.add(component);
|
|
32
|
+
for (const { name, value } of node.attrs ?? []) {
|
|
33
|
+
const at = node.sourceCodeLocation?.attrs?.[name];
|
|
34
|
+
if (!at) continue;
|
|
35
|
+
const relative = /^(\.\.\/)([a-z0-9]+(?:-[a-z0-9]+)*)(\/.*)$/.exec(value);
|
|
36
|
+
const next = name === "data-doc-id" && value === slug ? copy : ["href", "src", "poster"].includes(name) && relative && names.has(relative[2]) ? `../${names.get(relative[2])}${relative[3]}` : value;
|
|
37
|
+
if (next !== value) edits.set(at.startOffset, { to: at.endOffset, text: `${name}="${escapeAttribute(next)}"` });
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
const next = [...edits].sort(([a], [b]) => b - a).reduce((text, [from, edit]) => text.slice(0, from) + edit.text + text.slice(edit.to), text);
|
|
41
|
+
await fs.writeFile(file, next);
|
|
42
|
+
return [...packages];
|
|
43
|
+
}
|