@heycys/gallery 0.1.1 → 0.2.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/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/columns/page.mjs +4 -4
- package/browser/editor/components/embed/index.mjs +2 -2
- package/browser/editor/components/embed/page.mjs +1 -1
- package/browser/editor/components/file/page.mjs +4 -4
- package/browser/editor/components/flowchart/add.mjs +7 -6
- package/browser/editor/components/flowchart/page.mjs +1 -1
- package/browser/editor/components/heading/index.mjs +7 -6
- package/browser/editor/components/icons.mjs +11 -0
- package/browser/editor/components/image/crop.mjs +6 -9
- 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 +15 -4
- package/browser/editor/components/installed/page.mjs +103 -25
- package/browser/editor/components/installed/served.mjs +6 -5
- package/browser/editor/components/instances.mjs +18 -0
- package/browser/editor/components/list/page.mjs +3 -6
- 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 +30 -9
- package/browser/editor/components/table/index.mjs +61 -2
- package/browser/editor/components/table/page.mjs +1 -1
- package/browser/editor/page/after/index.mjs +288 -0
- package/browser/editor/page/align.mjs +91 -0
- package/browser/editor/page/annotate/card.mjs +3 -6
- package/browser/editor/page/autosave.mjs +310 -37
- 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/client.mjs +57 -0
- package/browser/editor/page/board/hint.mjs +182 -0
- package/browser/editor/page/board/history.mjs +119 -0
- package/browser/editor/page/board/index.mjs +1059 -0
- package/browser/editor/page/board/motion.mjs +177 -0
- package/browser/editor/page/board/settings.mjs +210 -0
- package/browser/editor/page/caret.mjs +1 -1
- package/browser/editor/page/changes/bar.mjs +6 -14
- package/browser/editor/page/changes/index.mjs +2 -2
- package/browser/editor/page/clipboard/import/html.mjs +29 -6
- package/browser/editor/page/clipboard/import/inline.mjs +32 -0
- package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
- package/browser/editor/page/clipboard/import/read.mjs +6 -1
- package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
- package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
- package/browser/editor/page/clipboard/index.mjs +133 -15
- package/browser/editor/page/clipboard/own/blocks.mjs +13 -14
- package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
- package/browser/editor/page/clipboard/own/describe.mjs +6 -2
- package/browser/editor/page/clipboard/own/selection.mjs +1 -1
- package/browser/editor/page/columns/index.mjs +48 -46
- package/browser/editor/page/commit.mjs +80 -22
- package/browser/editor/page/conflicts.mjs +7 -7
- package/browser/editor/page/core.mjs +34 -16
- package/browser/editor/page/custom-page.mjs +110 -0
- package/browser/editor/page/editor.mjs +71 -17
- package/browser/editor/page/emoji-picker/styles.mjs +7 -12
- package/browser/editor/page/emoji-picker/upload.mjs +2 -2
- package/browser/editor/page/handle/index.mjs +5 -8
- package/browser/editor/page/history.mjs +41 -6
- package/browser/editor/page/insert/index.mjs +20 -22
- package/browser/editor/page/links/index.mjs +5 -3
- package/browser/editor/page/links/pages.mjs +27 -9
- package/browser/editor/page/look.mjs +54 -3
- package/browser/editor/page/margin.mjs +18 -3
- package/browser/editor/page/media-menu/index.mjs +6 -7
- package/browser/editor/page/menu.mjs +33 -14
- package/browser/editor/page/notices.mjs +2 -2
- package/browser/editor/page/page-objects.mjs +9 -2
- package/browser/editor/page/panel.mjs +4 -9
- package/browser/editor/page/present-links.mjs +15 -5
- package/browser/editor/page/present-shell.mjs +63 -0
- package/browser/editor/page/resize/index.mjs +42 -29
- package/browser/editor/page/selection/index.mjs +10 -2
- package/browser/editor/page/served.mjs +14 -0
- package/browser/editor/page/session.mjs +48 -4
- package/browser/editor/page/slash-menu/index.mjs +3 -3
- package/browser/editor/page/table/binding.mjs +87 -0
- package/browser/editor/page/table/cells.mjs +102 -46
- package/browser/editor/page/table/index.mjs +24 -9
- package/browser/editor/page/table/pictures.mjs +299 -0
- package/browser/editor/page/table/views.mjs +103 -0
- package/browser/editor/page/table/widths.mjs +82 -10
- package/browser/editor/page/text-select/index.mjs +26 -12
- package/browser/editor/page/todo-writes.mjs +75 -0
- package/browser/editor/page/typing/index.mjs +97 -15
- package/browser/editor/page/typing/leave.mjs +19 -5
- package/browser/editor/page/ui.mjs +13 -0
- package/browser/shared/block-packs.mjs +419 -0
- package/browser/shared/board-places.mjs +224 -0
- package/browser/shared/card-size.mjs +59 -0
- package/browser/shared/colors.mjs +3 -2
- package/browser/shared/component-catalog.mjs +330 -46
- package/browser/shared/component-source.mjs +39 -0
- package/browser/shared/components/heading.mjs +2 -1
- package/browser/shared/components/index.mjs +12 -3
- package/browser/shared/components/installed.mjs +35 -3
- package/browser/shared/components/page.mjs +20 -8
- package/browser/shared/components/paragraph.mjs +8 -1
- package/browser/shared/components/state.mjs +5 -1
- package/browser/shared/components/table.mjs +1 -0
- package/browser/shared/document-look.mjs +10 -5
- package/browser/shared/drafts.mjs +432 -0
- package/browser/shared/emoji/line-icons.mjs +37 -0
- package/browser/shared/extension-sidebar.mjs +126 -0
- package/browser/shared/extensions.mjs +79 -0
- package/browser/shared/file-table.mjs +101 -0
- package/browser/shared/http.mjs +9 -0
- package/browser/shared/i18n/en.mjs +330 -27
- package/browser/shared/json-layout.mjs +47 -0
- package/browser/shared/net-cache.mjs +133 -0
- package/browser/shared/net-keys.mjs +32 -0
- package/browser/shared/net-policy.mjs +177 -0
- package/browser/shared/outline-shape.mjs +128 -0
- package/browser/shared/outline.mjs +359 -67
- package/browser/shared/pack-manifest.mjs +88 -0
- package/browser/shared/page-address.mjs +6 -3
- package/browser/shared/page-cards.mjs +308 -0
- package/browser/shared/page-links.mjs +69 -6
- package/browser/shared/pages.mjs +500 -0
- package/browser/shared/paths.mjs +6 -0
- package/browser/shared/pinyin.mjs +92 -0
- package/browser/shared/present-step.mjs +17 -0
- package/browser/shared/preview-server.mjs +3 -7
- package/browser/shared/session.mjs +8 -1
- package/browser/shared/shipped-blocks.mjs +299 -0
- package/browser/shared/sidebar-head.mjs +70 -0
- package/browser/shared/table-chart.mjs +33 -1
- package/browser/shared/todos.mjs +83 -0
- package/browser/shared/user-directory.mjs +24 -0
- package/browser/shared/versions.mjs +14 -0
- package/browser/shared/web-links.mjs +139 -0
- package/browser/shared/workspace-columns.mjs +120 -0
- package/browser/shared/workspace-name.mjs +154 -0
- package/browser/shared/workspace-query.mjs +125 -0
- package/browser/shared/workspace-registry.mjs +272 -0
- package/browser/shared/workspace.mjs +171 -20
- package/dist/chunk-2OHANJ6Q.mjs +2 -0
- package/dist/chunk-3MBRL2PM.mjs +16 -0
- package/dist/chunk-4OKWZY5E.mjs +2 -0
- package/dist/chunk-4OZWXZE5.mjs +5 -0
- package/dist/chunk-5K44HLTZ.mjs +2 -0
- package/dist/{chunk-5ZKJ3H4P.mjs → chunk-5XA2ZBAE.mjs} +3 -3
- package/dist/{chunk-4FS7Z7WR.mjs → chunk-67N2QJYT.mjs} +1 -1
- package/dist/chunk-6KBYRA2C.mjs +2 -0
- package/dist/chunk-6N3PX4XX.mjs +8 -0
- package/dist/{chunk-V5JTW2LH.mjs → chunk-6QBHU4DF.mjs} +1 -1
- package/dist/chunk-7JDX4E65.mjs +13 -0
- package/dist/chunk-7M2BQQGZ.mjs +2 -0
- package/dist/chunk-7OG26PGF.mjs +2 -0
- package/dist/chunk-AHN3NFKJ.mjs +3 -0
- package/dist/chunk-ALZ6ZENZ.mjs +3 -0
- package/dist/chunk-AR5D57ZD.mjs +170 -0
- package/dist/{chunk-W3BGBJQW.mjs → chunk-BFJGHSQN.mjs} +1 -1
- package/dist/{chunk-LS4F7JUM.mjs → chunk-BZ5RAF7L.mjs} +1 -1
- package/dist/chunk-CMA72MAG.mjs +2 -0
- package/dist/{chunk-LCTHTZIL.mjs → chunk-DAZL73VK.mjs} +91 -91
- package/dist/{chunk-Y6RLRPG3.mjs → chunk-DJISHPUL.mjs} +1 -1
- package/dist/chunk-DR73Y2UJ.mjs +3 -0
- package/dist/{chunk-FDLXYYG4.mjs → chunk-EAIFITAV.mjs} +1 -1
- package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
- package/dist/chunk-EP25HDAJ.mjs +2 -0
- package/dist/{chunk-GB5SOYQJ.mjs → chunk-ERLAIBOA.mjs} +2 -2
- package/dist/chunk-EURLTOTZ.mjs +4 -0
- package/dist/chunk-F4ZA6JRZ.mjs +3 -0
- package/dist/chunk-F6HVDZR4.mjs +2 -0
- package/dist/chunk-FDMAXMQA.mjs +2 -0
- package/dist/chunk-FETSREUN.mjs +5 -0
- package/dist/chunk-GHOYKMQ3.mjs +4 -0
- package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
- package/dist/chunk-HDWTZ763.mjs +12 -0
- package/dist/chunk-HPOI4ZX7.mjs +6 -0
- package/dist/{chunk-BGGDRNYQ.mjs → chunk-HXG7EOPJ.mjs} +1 -1
- package/dist/chunk-IA4PSIMD.mjs +2 -0
- package/dist/{chunk-E7LWZRXY.mjs → chunk-ITOH5EGO.mjs} +1 -1
- package/dist/chunk-IV64FFI4.mjs +2 -0
- package/dist/chunk-J43Z6LSS.mjs +2 -0
- package/dist/chunk-J5PUIV3Y.mjs +4 -0
- package/dist/chunk-JA7G53PC.mjs +2 -0
- package/dist/chunk-JEUK3ZO7.mjs +2 -0
- package/dist/chunk-JLTZF4LA.mjs +2 -0
- package/dist/chunk-JZT7I2OJ.mjs +2 -0
- package/dist/chunk-K5XATEOO.mjs +2 -0
- package/dist/chunk-L2SUIS5S.mjs +2 -0
- package/dist/chunk-L7UP52JO.mjs +2 -0
- package/dist/chunk-LM4XFQHZ.mjs +2 -0
- package/dist/chunk-MN7BZL4R.mjs +2 -0
- package/dist/chunk-MTYYHM2G.mjs +15 -0
- package/dist/chunk-MXUBKDRO.mjs +15 -0
- package/dist/chunk-NAMN3RAF.mjs +2 -0
- package/dist/{chunk-SYGN7GLU.mjs → chunk-OEXWRJME.mjs} +1 -1
- package/dist/chunk-OFHXGWOX.mjs +2 -0
- package/dist/chunk-ORID3AE7.mjs +166 -0
- package/dist/chunk-PAREWQGB.mjs +4 -0
- package/dist/chunk-PGDE24N5.mjs +2 -0
- package/dist/chunk-POTA2FV4.mjs +2 -0
- package/dist/chunk-PUOQ65NC.mjs +2 -0
- package/dist/chunk-Q4UEPUWF.mjs +2 -0
- package/dist/chunk-QE5RG76S.mjs +549 -0
- package/dist/chunk-R2ZDLJYT.mjs +10 -0
- package/dist/{chunk-7DTINW6U.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
- package/dist/chunk-SWUTTZCN.mjs +2 -0
- package/dist/chunk-TANZRINB.mjs +2 -0
- package/dist/chunk-TR7TWGHB.mjs +2 -0
- package/dist/chunk-U5XL7D6A.mjs +3 -0
- package/dist/{chunk-XNROSH2T.mjs → chunk-U7NZI6N4.mjs} +2 -2
- package/dist/chunk-UGWMMEJ5.mjs +15 -0
- package/dist/chunk-UJQJKNGK.mjs +2 -0
- package/dist/chunk-UYVCQK3H.mjs +22 -0
- package/dist/chunk-VFX2KNHP.mjs +4 -0
- package/dist/chunk-VS7JIGJW.mjs +24 -0
- package/dist/chunk-W7665ZEC.mjs +6 -0
- package/dist/chunk-WQDQWCX5.mjs +2 -0
- package/dist/chunk-YI43RG4P.mjs +2 -0
- package/dist/chunk-YLPSMDIS.mjs +5 -0
- package/dist/chunk-YNAWBAYN.mjs +3 -0
- package/dist/chunk-YROX2O22.mjs +2 -0
- package/dist/chunk-ZDLPUOAG.mjs +6 -0
- package/dist/{chunk-IVDLMMBD.mjs → chunk-ZHEHPMBK.mjs} +1 -1
- package/dist/chunk-ZQS6H473.mjs +16 -0
- package/dist/chunk-ZTHICSSF.mjs +2 -0
- package/dist/chunk-ZWWC4KLF.mjs +20 -0
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/{chunk-U6KNPJPR.mjs → update-fetch.mjs} +1 -1
- package/dist/worker.mjs +1 -1
- package/kit/board.css +95 -0
- package/kit/board.js +250 -0
- package/kit/charts.js +5 -71
- package/kit/code.js +17 -17
- package/kit/report.css +335 -18
- package/kit/runtime.js +1638 -125
- package/kit/state.js +10 -1
- package/kit/tables.js +130 -43
- package/kit/ui.js +79 -35
- package/package.json +2 -1
- package/packs/gallery/card/component.json +14 -0
- package/packs/gallery/card/example.html +10 -0
- package/packs/gallery/card/preview.svg +1 -0
- package/packs/gallery/card/style.css +6 -0
- package/packs/gallery/card/template.html +6 -0
- package/packs/gallery/card/writing.md +14 -0
- package/packs/gallery/chart-card/component.json +15 -0
- package/packs/gallery/chart-card/example.html +14 -0
- package/packs/gallery/chart-card/kit.js +130 -0
- package/packs/gallery/chart-card/preview.svg +1 -0
- package/packs/gallery/chart-card/style.css +42 -0
- package/packs/gallery/chart-card/template.html +13 -0
- package/packs/gallery/chart-card/writing.md +20 -0
- package/packs/gallery/chart-view/component.json +20 -0
- package/packs/gallery/chart-view/example.html +13 -0
- package/packs/gallery/chart-view/kit.js +355 -0
- package/packs/gallery/chart-view/preview.svg +1 -0
- package/packs/gallery/chart-view/style.css +94 -0
- package/packs/gallery/chart-view/template.html +3 -0
- package/packs/gallery/chart-view/writing.md +22 -0
- package/packs/gallery/countdown/component.json +18 -0
- package/packs/gallery/countdown/example.html +3 -0
- package/packs/gallery/countdown/kit.js +216 -0
- package/packs/gallery/countdown/preview.svg +1 -0
- package/packs/gallery/countdown/style.css +118 -0
- package/packs/gallery/countdown/template.html +3 -0
- package/packs/gallery/countdown/writing.md +22 -0
- package/packs/gallery/habit/component.json +14 -0
- package/packs/gallery/habit/example.html +3 -0
- package/packs/gallery/habit/kit.js +334 -0
- package/packs/gallery/habit/preview.svg +1 -0
- package/packs/gallery/habit/style.css +174 -0
- package/packs/gallery/habit/template.html +3 -0
- package/packs/gallery/habit/writing.md +21 -0
- package/packs/gallery/heatmap/component.json +18 -0
- package/packs/gallery/heatmap/example.html +3 -0
- package/packs/gallery/heatmap/kit.js +513 -0
- package/packs/gallery/heatmap/preview.svg +1 -0
- package/packs/gallery/heatmap/style.css +189 -0
- package/packs/gallery/heatmap/template.html +3 -0
- package/packs/gallery/heatmap/writing.md +21 -0
- package/packs/gallery/kanban/component.json +18 -0
- package/packs/gallery/kanban/example.html +12 -0
- package/packs/gallery/kanban/kit.js +540 -0
- package/packs/gallery/kanban/preview.svg +1 -0
- package/packs/gallery/kanban/style.css +212 -0
- package/packs/gallery/kanban/template.html +3 -0
- package/packs/gallery/kanban/writing.md +20 -0
- package/packs/gallery/metric/component.json +22 -0
- package/packs/gallery/metric/example.html +15 -0
- package/packs/gallery/metric/kit.js +248 -0
- package/packs/gallery/metric/preview.svg +1 -0
- package/packs/gallery/metric/style.css +92 -0
- package/packs/gallery/metric/template.html +3 -0
- package/packs/gallery/metric/writing.md +23 -0
- package/packs/gallery/note/component.json +14 -0
- package/packs/gallery/note/example.html +3 -0
- package/packs/gallery/note/kit.js +129 -0
- package/packs/gallery/note/preview.svg +1 -0
- package/packs/gallery/note/style.css +97 -0
- package/packs/gallery/note/template.html +3 -0
- package/packs/gallery/note/writing.md +18 -0
- package/packs/gallery/pack.json +8 -0
- package/packs/gallery/recent/component.json +13 -0
- package/packs/gallery/recent/example.html +1 -0
- package/packs/gallery/recent/kit.js +293 -0
- package/packs/gallery/recent/preview.svg +1 -0
- package/packs/gallery/recent/style.css +85 -0
- package/packs/gallery/recent/template.html +1 -0
- package/packs/gallery/recent/writing.md +15 -0
- package/packs/gallery/static/component.json +13 -0
- package/packs/gallery/static/example.html +11 -0
- package/packs/gallery/static/preview.svg +1 -0
- package/packs/gallery/static/style.css +171 -0
- package/packs/gallery/static/template.html +1 -0
- package/packs/gallery/static/writing.md +18 -0
- package/packs/gallery/stats/component.json +13 -0
- package/packs/gallery/stats/example.html +1 -0
- package/packs/gallery/stats/kit.js +347 -0
- package/packs/gallery/stats/preview.svg +1 -0
- package/packs/gallery/stats/style.css +73 -0
- package/packs/gallery/stats/template.html +1 -0
- package/packs/gallery/stats/writing.md +11 -0
- package/packs/gallery/today/component.json +12 -0
- package/packs/gallery/today/example.html +1 -0
- package/packs/gallery/today/kit.js +220 -0
- package/packs/gallery/today/preview.svg +1 -0
- package/packs/gallery/today/style.css +149 -0
- package/packs/gallery/today/template.html +1 -0
- package/packs/gallery/today/writing.md +14 -0
- package/packs/gallery/todos/component.json +19 -0
- package/packs/gallery/todos/example.html +3 -0
- package/packs/gallery/todos/kit.js +489 -0
- package/packs/gallery/todos/preview.svg +1 -0
- package/packs/gallery/todos/style.css +214 -0
- package/packs/gallery/todos/template.html +3 -0
- package/packs/gallery/todos/writing.md +30 -0
- package/packs/gallery/weather/component.json +19 -0
- package/packs/gallery/weather/example.html +3 -0
- package/packs/gallery/weather/kit.js +387 -0
- package/packs/gallery/weather/preview.svg +1 -0
- package/packs/gallery/weather/style.css +140 -0
- package/packs/gallery/weather/template.html +3 -0
- package/packs/gallery/weather/writing.md +26 -0
- 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/pack.json +8 -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 +12 -10
- package/sdk/doc-kit.d.ts +396 -5
- package/sdk/doc-state.d.ts +2 -0
- package/skill/SKILL.md +56 -23
- package/skill/references/block-script.md +140 -0
- package/skill/references/building-blocks.md +257 -0
- package/skill/references/extensions.md +59 -0
- package/skill/references/pages-and-data.md +225 -0
- package/skill/references/writing-html.md +8 -4
- package/skill/sdk/doc-kit.d.ts +396 -5
- package/skill/sdk/doc-state.d.ts +2 -0
- package/web/assets/index-BM_K-Auu.css +1 -0
- package/web/assets/index-DRslOBiv.js +15 -0
- package/web/index.html +2 -2
- package/dist/chunk-3HIRPVLU.mjs +0 -2
- package/dist/chunk-5MHMDLZD.mjs +0 -4
- package/dist/chunk-64K7IPLO.mjs +0 -255
- package/dist/chunk-6QXGZM36.mjs +0 -8
- package/dist/chunk-6RGJOMJP.mjs +0 -16
- package/dist/chunk-AJ73XJF3.mjs +0 -2
- package/dist/chunk-AUZGSZJH.mjs +0 -13
- package/dist/chunk-BFE45AKL.mjs +0 -2
- package/dist/chunk-BXO2ZY5P.mjs +0 -2
- package/dist/chunk-CEH4MRCC.mjs +0 -2
- package/dist/chunk-CY2FNNAB.mjs +0 -16
- package/dist/chunk-DFUDV4LX.mjs +0 -2
- package/dist/chunk-DKXG4XDG.mjs +0 -2
- package/dist/chunk-EZQ34M3F.mjs +0 -124
- package/dist/chunk-EZY3WC6Z.mjs +0 -15
- package/dist/chunk-FUKQNOQS.mjs +0 -9
- package/dist/chunk-JPOSLGOC.mjs +0 -6
- package/dist/chunk-JVHHHGEA.mjs +0 -3
- package/dist/chunk-L3QKH4OK.mjs +0 -26
- package/dist/chunk-LAE5NQ4B.mjs +0 -2
- package/dist/chunk-LEF6DRCK.mjs +0 -59
- package/dist/chunk-NO5NJCHO.mjs +0 -2
- package/dist/chunk-NQPVAU63.mjs +0 -2
- package/dist/chunk-NSKUTQ5J.mjs +0 -5
- package/dist/chunk-O35FIXRB.mjs +0 -2
- package/dist/chunk-P2CAZPDP.mjs +0 -3
- package/dist/chunk-PL6GHLGD.mjs +0 -15
- package/dist/chunk-QJIR2BLP.mjs +0 -6
- package/dist/chunk-QUPLVPB2.mjs +0 -7
- package/dist/chunk-R7BNENLY.mjs +0 -4
- package/dist/chunk-S6O4UHLC.mjs +0 -2
- package/dist/chunk-SGJWQKEI.mjs +0 -2
- package/dist/chunk-TX6JH7TR.mjs +0 -2
- package/dist/chunk-TYK6VNAB.mjs +0 -10
- package/dist/chunk-UALRNVSE.mjs +0 -4
- package/dist/chunk-V3HXVQEM.mjs +0 -2
- package/dist/chunk-V5VXUJKG.mjs +0 -2
- package/dist/chunk-VBXMADMP.mjs +0 -2
- package/dist/chunk-VNV55RUA.mjs +0 -2
- package/dist/chunk-VPD2PS35.mjs +0 -2
- package/dist/chunk-W4VKN3GF.mjs +0 -7
- package/dist/chunk-W5BXXPDJ.mjs +0 -3
- package/dist/chunk-XUNHRCOG.mjs +0 -6
- package/skill/references/building-components.md +0 -367
- package/web/assets/index-Bh74DfsV.css +0 -1
- package/web/assets/index-UW0RyFFt.js +0 -13
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { insertRow, moveRow, removeRows, tableState } from "../../components/table/page.mjs";
|
|
2
|
+
import { tableOf } from "../../components/table/grid.mjs";
|
|
3
|
+
import { ownHTML } from "../core.mjs";
|
|
4
|
+
|
|
5
|
+
// The views of a table (docs/editor.md, "Table views"; the plan's 阶段 4): an instance of a custom
|
|
6
|
+
// block whose needs hold "tables", bound to a table of the document by the key its frame carries
|
|
7
|
+
// (shared/table-chart.mjs VIEW_FROM, the key a chart drawn from a table reads it by), reads the table's
|
|
8
|
+
// rows (the kit's context.table()) and changes them only by asking: a doc-table-intent the kit puts on
|
|
9
|
+
// the instance (runtime/kernel.js), which these tools answer at once, made as the table's own tools make
|
|
10
|
+
// a change, so that a view has no commit, undo or conflict of its own:
|
|
11
|
+
//
|
|
12
|
+
// set one cell's words: a text step of that cell (history.mjs recordStep), its commit a cell's text
|
|
13
|
+
// as typing's is, merged word by word with someone else's change of the cell (source/merge.mjs);
|
|
14
|
+
// move a row put before or after another, the cells it names set in the same step (a card dropped
|
|
15
|
+
// in another column: its status and its place);
|
|
16
|
+
// add a row put in after another or last, its cells' words those it names;
|
|
17
|
+
// remove a row taken out (never the last of the body, as the tools' 删除);
|
|
18
|
+
// check nothing: answered as the others would be (the kit's table().canEdit()), so that a view of a
|
|
19
|
+
// table these tools do not manage shows it read-only;
|
|
20
|
+
//
|
|
21
|
+
// move, add and remove are the table tools' operations (components/table/page.mjs moveRow, insertRow,
|
|
22
|
+
// removeRows) in one undo step each (index.mjs change), their commit the table's operation, which a
|
|
23
|
+
// change someone else made to the table meanwhile holds back as a conflict with its card, as any. Only a
|
|
24
|
+
// table these tools manage (GRID: written as the kit writes one) and with no merged cell takes them: a
|
|
25
|
+
// view of any other is read-only, as it is in an export (the kit asks nothing there). Its rows of data
|
|
26
|
+
// are those after its header row: the head's rows, or with no head its body's first row, which a view
|
|
27
|
+
// reads its columns' names from; no intent puts a row there or takes that one.
|
|
28
|
+
//
|
|
29
|
+
// Which table a view reads is binding.mjs's: a view made from a menu is bound to the table above it, and
|
|
30
|
+
// its 设置 (components/installed/page.mjs) changes it.
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* active(): whether the page edits now. change(unit, mutate, said, touched): the table tools' one undo
|
|
34
|
+
* step (index.mjs). tableAt(node): the table unit these tools manage that a node is in. recordStep(host,
|
|
35
|
+
* before): a text step of a text block (history.mjs). drawn(): the tools drawn again (a row taken out).
|
|
36
|
+
*/
|
|
37
|
+
export function createViews({ active, change, tableAt, recordStep, drawn = () => {} }) {
|
|
38
|
+
const merged = (rows) => rows.some((row) => [...row.cells].some((cell) => cell.rowSpan !== 1 || cell.colSpan !== 1));
|
|
39
|
+
const writable = (cell) => cell?.getAttribute("contenteditable") === "true";
|
|
40
|
+
const holds = (cell, text) => cell.textContent === text && cell.childElementCount === 0;
|
|
41
|
+
|
|
42
|
+
// What a view asks (`detail` of doc-table-intent: kernel.js tableView), made, or refused (false).
|
|
43
|
+
function run({ table, op, row = null, before = null, after = null, cells = [] }) {
|
|
44
|
+
if (!active() || !table?.isConnected) return false;
|
|
45
|
+
const unit = tableAt(table);
|
|
46
|
+
if (!unit || tableOf(unit) !== table) return false;
|
|
47
|
+
const state = tableState(unit);
|
|
48
|
+
if (merged(state.rows) || !Array.isArray(cells) || !cells.every(([column, text]) => Number.isInteger(column) && column >= 0 && column < state.columns && typeof text === "string")) return false;
|
|
49
|
+
// A view's table().canEdit(): whether an intent of this table would be taken now, nothing changed.
|
|
50
|
+
if (op === "check") return true;
|
|
51
|
+
// Its rows of data: after the header a view reads its names from (the head, else the body's first row).
|
|
52
|
+
const all = state.rows;
|
|
53
|
+
const data = all.slice(Math.max(1, state.head?.rows.length ?? 0));
|
|
54
|
+
const ofData = (node) => data.includes(node);
|
|
55
|
+
const cellsOf = (target) => cells.map(([column]) => target.cells[column]);
|
|
56
|
+
if (op === "set") {
|
|
57
|
+
if (!ofData(row) || cells.length !== 1) return false;
|
|
58
|
+
const [[column, text]] = cells;
|
|
59
|
+
const cell = row.cells[column];
|
|
60
|
+
if (!writable(cell)) return false;
|
|
61
|
+
if (holds(cell, text)) return true;
|
|
62
|
+
const was = ownHTML(cell);
|
|
63
|
+
cell.textContent = text;
|
|
64
|
+
recordStep(cell, was);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
if (op === "move") {
|
|
68
|
+
const target = before ?? after;
|
|
69
|
+
if (!ofData(row) || (target && !ofData(target)) || !cellsOf(row).every(writable)) return false;
|
|
70
|
+
const from = all.indexOf(row);
|
|
71
|
+
const rest = all.filter((node) => node !== row);
|
|
72
|
+
const to = !target || target === row ? from : before ? rest.indexOf(before) : rest.indexOf(after) + 1;
|
|
73
|
+
if (to === from && cells.every(([column, text]) => holds(row.cells[column], text))) return true;
|
|
74
|
+
return change(unit, () => {
|
|
75
|
+
if (to !== from && moveRow(unit, from, to) === false) return false;
|
|
76
|
+
for (const [column, text] of cells) row.cells[column].textContent = text;
|
|
77
|
+
return true;
|
|
78
|
+
}, null, cellsOf(row)) !== null;
|
|
79
|
+
}
|
|
80
|
+
if (op === "add") {
|
|
81
|
+
if (after && !ofData(after)) return false;
|
|
82
|
+
const at = after ? all.indexOf(after) + 1 : all.length;
|
|
83
|
+
return change(unit, () => {
|
|
84
|
+
const made = insertRow(unit, at);
|
|
85
|
+
for (const [column, text] of cells) if (made.cells[column]) made.cells[column].textContent = text;
|
|
86
|
+
return made;
|
|
87
|
+
}, null) !== null;
|
|
88
|
+
}
|
|
89
|
+
if (op === "remove") {
|
|
90
|
+
if (!ofData(row)) return false;
|
|
91
|
+
const at = all.indexOf(row);
|
|
92
|
+
const done = change(unit, () => removeRows(unit, at, at), null) !== null;
|
|
93
|
+
drawn();
|
|
94
|
+
return done;
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
document.addEventListener("doc-table-intent", (event) => {
|
|
99
|
+
if (run(event.detail ?? {})) event.preventDefault();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return {};
|
|
103
|
+
}
|
|
@@ -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);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { chipBox } from "../chip-fills.mjs";
|
|
2
2
|
import { DETAILS, DIALOG } from "../../components/kit.mjs";
|
|
3
3
|
import { boxRole } from "../../components/registry.mjs";
|
|
4
|
-
import { UNIT, can, isHost, mergeInto, partsOf, removalTarget, takeOut, textEnd, unitElement } from "../core.mjs";
|
|
4
|
+
import { UNIT, can, isEmpty, isHost, mergeInto, partsOf, removalTarget, takeOut, textEnd, unitElement } from "../core.mjs";
|
|
5
5
|
import { atomOf, caretAt, caretAtOffset, dragPlace, editable, hosts, pointRange, select } from "../caret.mjs";
|
|
6
6
|
import { edgeFollower } from "../edge-scroll.mjs";
|
|
7
7
|
import { FOLDED } from "../folded.mjs";
|
|
@@ -22,7 +22,9 @@ import { t } from "../../../shared/i18n/index.mjs";
|
|
|
22
22
|
// the window's edges), drawn with the CSS Custom Highlight API in the selection's own colors, the
|
|
23
23
|
// browser's selecting held off meanwhile; back in that block, the browser's again. Shift+click in
|
|
24
24
|
// another block selects from the caret to there.
|
|
25
|
-
// Its text is that of body text, headings and list items (in quotes, highlight blocks, callouts, columns…)
|
|
25
|
+
// Its text is that of body text, headings and list items (in quotes, highlight blocks, callouts, columns…),
|
|
26
|
+
// and the page's title's, which a deletion takes its part of but never joins with the body's (notion-lite's
|
|
27
|
+
// selection runs from its page title into the blocks; the user's: what is left of the body stays in the body).
|
|
26
28
|
// A block holding none (a code block, a table, a file, an image, a formula block, a
|
|
27
29
|
// divider…) is taken whole as it passes it, filled as a selected block is (selection/ mark), its
|
|
28
30
|
// own text not marked: over one, an end of the selection stands before it or after it, as the drag
|
|
@@ -108,6 +110,10 @@ function lineStrips(texts, origin) {
|
|
|
108
110
|
|
|
109
111
|
// The text blocks it takes text from, and a deletion joins: body text, headings, list items.
|
|
110
112
|
const isText = (host) => isHost(host) && (host.getAttribute("data-ge-kind") ?? "flow") === "flow";
|
|
113
|
+
// The page's title: text it takes too (drawn, copied, deleted), kept apart: a deletion leaves it what
|
|
114
|
+
// stands outside the selection and joins nothing to it (remove).
|
|
115
|
+
const isTitle = (host) => isHost(host) && host.getAttribute("data-ge-kind") === "title";
|
|
116
|
+
const isPiece = (host) => isText(host) || isTitle(host);
|
|
111
117
|
const textHosts = (unit) => [...unit.querySelectorAll("[data-ge-block], [data-ge-new]")].filter((node) => isHost(node) && isText(node));
|
|
112
118
|
|
|
113
119
|
// The outermost block around `node` holding no text of the body (a code block, a table, a file…),
|
|
@@ -194,12 +200,12 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
194
200
|
function pointAt(x, y, from) {
|
|
195
201
|
const place = dragPlace([from.node, from.offset], x, y);
|
|
196
202
|
const host = place && editable(place[0]);
|
|
197
|
-
if (host?.closest("main") &&
|
|
203
|
+
if (host?.closest("main") && isPiece(host)) return { host, node: place[0], offset: place[1] };
|
|
198
204
|
const whole = wholeOf(document.elementFromPoint(x, y));
|
|
199
205
|
if (whole) return edge(whole, !from || before(from, edge(whole, false)));
|
|
200
206
|
let best = null;
|
|
201
207
|
let bestScore = null;
|
|
202
|
-
for (const each of hosts().filter((node) => node.closest("main") &&
|
|
208
|
+
for (const each of hosts().filter((node) => node.closest("main") && isPiece(node))) {
|
|
203
209
|
const rect = each.getBoundingClientRect();
|
|
204
210
|
// By height, then (level ones: columns side by side) by width; of nested ones, the innermost.
|
|
205
211
|
const score = gapScore(rect, x, y);
|
|
@@ -220,7 +226,7 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
220
226
|
// Where the selection starts, `focus` being its other end: the press's place in body text; begun
|
|
221
227
|
// in a block taken whole (its code, a cell), that block's edge away from `focus`.
|
|
222
228
|
function startOf(anchor, focus) {
|
|
223
|
-
if (
|
|
229
|
+
if (isPiece(anchor.host)) return anchor;
|
|
224
230
|
const whole = wholeOf(anchor.host) ?? unitElement(anchor.host);
|
|
225
231
|
if (!whole) return anchor;
|
|
226
232
|
const head = edge(whole, false);
|
|
@@ -243,7 +249,7 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
243
249
|
// text it reaches: none when its text stands before the start (the selection begun in a block the
|
|
244
250
|
// item holds) or after the end.
|
|
245
251
|
const reaches = (host) => host === selection.start.host || host === selection.end.host || (range.isPointInRange(host, 0) && range.isPointInRange(host, textEnd(host)));
|
|
246
|
-
const texts = hosts().filter((host) => host.closest("main") &&
|
|
252
|
+
const texts = hosts().filter((host) => host.closest("main") && isPiece(host) && range.intersectsNode(host) && reaches(host) && !folded(host)).map((host) => {
|
|
247
253
|
const part = document.createRange();
|
|
248
254
|
part.setStart(host, 0);
|
|
249
255
|
part.setEnd(host, textEnd(host));
|
|
@@ -496,7 +502,7 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
496
502
|
select(range);
|
|
497
503
|
return;
|
|
498
504
|
}
|
|
499
|
-
const texts = hosts().filter((host) => host.closest("main") &&
|
|
505
|
+
const texts = hosts().filter((host) => host.closest("main") && isPiece(host));
|
|
500
506
|
const next = texts.find((host) => before(point, { node: host, offset: 0 }));
|
|
501
507
|
const previous = texts.filter((host) => before({ node: host, offset: textEnd(host) }, point)).at(-1);
|
|
502
508
|
const host = forward ? next ?? previous : previous ?? next;
|
|
@@ -504,14 +510,17 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
504
510
|
}
|
|
505
511
|
|
|
506
512
|
// Delete it: the first block keeps its text before it and takes the last block's after it, the
|
|
507
|
-
// blocks between go (those taken whole among them); one undo step, the caret where it began.
|
|
513
|
+
// blocks between go (those taken whole among them); one undo step, the caret where it began. From
|
|
514
|
+
// the page's title (`apart`) nothing joins: the title keeps what stands before it (empty, it says
|
|
515
|
+
// 未命名文档), the last block what stands after it in a block of its own (gone when that is nothing).
|
|
508
516
|
// Returns whether it went.
|
|
509
517
|
function remove() {
|
|
510
518
|
const selection = cross;
|
|
511
519
|
const { start, end } = selection;
|
|
512
520
|
letGo();
|
|
513
521
|
if (!(start.host ?? start.node).isConnected || !(end.host ?? end.node).isConnected) return false;
|
|
514
|
-
|
|
522
|
+
const apart = isTitle(start.host) || isTitle(end.host);
|
|
523
|
+
if (![start.host, end.host].every((host) => !host || isPiece(host))) {
|
|
515
524
|
say(t("跨块删除只支持正文、标题和列表里的文字。"));
|
|
516
525
|
return false;
|
|
517
526
|
}
|
|
@@ -553,9 +562,14 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
553
562
|
}
|
|
554
563
|
for (const target of targets) takeOut(target);
|
|
555
564
|
// Joined unless the two cannot be (a block that may not merge, lists that cannot go along):
|
|
556
|
-
// then each keeps what is left of its text.
|
|
557
|
-
|
|
558
|
-
if (
|
|
565
|
+
// then each keeps what is left of its text. Apart from the title, the last block left empty
|
|
566
|
+
// goes as the blocks between do (it was all selected), else it stays with its rest.
|
|
567
|
+
if (apart) {
|
|
568
|
+
const last = isTitle(end.host) ? null : end.host;
|
|
569
|
+
if (last && endTarget && isEmpty(last) && can(last, "remove") && !keepText(endTarget)) takeOut(endTarget);
|
|
570
|
+
} else if (start.host && end.host && mergeInto(start.host, end.host, { anyKind: true }) && endTarget !== end.host && endTarget.isConnected) takeOut(endTarget);
|
|
571
|
+
if (start.host && !apart) joinCode(start.host); // inline code meeting inline code at the join is one piece
|
|
572
|
+
if (isTitle(start.host) && isEmpty(start.host)) start.host.replaceChildren(); // no <br> left in an emptied title
|
|
559
573
|
return { touched: touched.filter((host) => host.isConnected), focus: start.host ?? end.host ?? null };
|
|
560
574
|
});
|
|
561
575
|
if (!result) return false;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { TODO_EVENT, TODO_MOST, TODO_ROUTE } from "../../shared/workspace-query.mjs";
|
|
2
|
+
import { postAnswer } from "./post.mjs";
|
|
3
|
+
|
|
4
|
+
// To-dos of documents checked from this page (workspace.setTodo, the plan's 5.1; docs/editor.md "To-dos
|
|
5
|
+
// checked from another page"): the kit's ask (TODO_EVENT, cancelable on the window: { ask: { slug, ref,
|
|
6
|
+
// done }, answer(promise) }) taken by whoever holds the page's token (a custom page's board, a document's
|
|
7
|
+
// editor) and written by the workspace's service (POST TODO_ROUTE, one document a request: the edit
|
|
8
|
+
// service's setTodos, one commit of the reader's). The checks of one document wait in a line of their own:
|
|
9
|
+
// those asked while one write of it is out go together in the next (its items in the order asked, the
|
|
10
|
+
// last of an item winning), so that a reader ticking five boxes quickly makes two commits, not five.
|
|
11
|
+
// Each ask is answered { ok: true, changed, block } (`block` the item's id now, which the commit gives
|
|
12
|
+
// one that had none) or { ok: false, reason, message? }, never rejected.
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* `token`: the page map's. `done(ask, answer)`: an ask answered (the board keeps an undo step of one that
|
|
16
|
+
* changed its document). Returns { write(ask) (a promise of its answer), idle() (once every write asked so
|
|
17
|
+
* far is answered), listen() (takes the kit's asks; returns the function that stops it) }.
|
|
18
|
+
*/
|
|
19
|
+
export function createTodoWrites({ token, done = () => {} }) {
|
|
20
|
+
const lines = new Map(); // slug -> { waiting: [{ ask, resolve }], out: Promise | null }
|
|
21
|
+
|
|
22
|
+
async function send(slug, line) {
|
|
23
|
+
const batch = line.waiting.splice(0, TODO_MOST);
|
|
24
|
+
const answer = await postAnswer(TODO_ROUTE, token, { slug, items: batch.map(({ ask }) => ({ ref: ask.ref, done: ask.done })) });
|
|
25
|
+
batch.forEach(({ ask, resolve }, index) => {
|
|
26
|
+
const result = answer?.ok ? answer.results?.[index] ?? { ok: false, reason: "failed" } : { ok: false, reason: answer?.reason === "offline" ? "offline" : answer?.reason ?? "failed", ...(typeof answer?.message === "string" ? { message: answer.message } : {}) };
|
|
27
|
+
try {
|
|
28
|
+
done(ask, result);
|
|
29
|
+
} finally {
|
|
30
|
+
resolve(result);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// The line of a document: written once nothing of it is out, what waits then going together.
|
|
36
|
+
function run(slug) {
|
|
37
|
+
const line = lines.get(slug);
|
|
38
|
+
if (line.out || line.waiting.length === 0) return;
|
|
39
|
+
// A microtask's wait, so that the asks of one gesture (a block checking several at once) go together.
|
|
40
|
+
line.out = Promise.resolve().then(() => send(slug, line)).catch(() => {}).finally(() => {
|
|
41
|
+
line.out = null;
|
|
42
|
+
if (line.waiting.length > 0) run(slug);
|
|
43
|
+
else lines.delete(slug);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function write(ask) {
|
|
48
|
+
return new Promise((resolve) => {
|
|
49
|
+
if (!lines.has(ask.slug)) lines.set(ask.slug, { waiting: [], out: null });
|
|
50
|
+
lines.get(ask.slug).waiting.push({ ask, resolve });
|
|
51
|
+
run(ask.slug);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
write,
|
|
57
|
+
async idle() {
|
|
58
|
+
for (;;) {
|
|
59
|
+
const out = [...lines.values()].map((line) => line.out).filter(Boolean);
|
|
60
|
+
if (out.length === 0) return;
|
|
61
|
+
await Promise.all(out);
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
listen() {
|
|
65
|
+
const take = (event) => {
|
|
66
|
+
const { ask, answer } = event.detail ?? {};
|
|
67
|
+
if (event.defaultPrevented || !ask || typeof answer !== "function") return;
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
answer(write(ask));
|
|
70
|
+
};
|
|
71
|
+
addEventListener(TODO_EVENT, take);
|
|
72
|
+
return () => removeEventListener(TODO_EVENT, take);
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
boxKind, can, emptyContainer, isEmpty, isFirstLine, isHost, limitText, mergeWithPrevious, nestedBlocks, nestedLists, nextLine, parentItem, previousLine, removalTarget, splitBlock, takeOut, textEnd, unitElement,
|
|
2
|
+
UNIT, boxKind, can, emptyContainer, isEmpty, isFirstLine, isHost, limitText, mergeWithPrevious, nestedBlocks, nestedLists, nextLine, parentItem, previousLine, removalTarget, splitBlock, takeOut, textEnd, unitElement, newParagraphHost, withLeads,
|
|
3
3
|
} from "../core.mjs";
|
|
4
4
|
import { atEdge, caretAt, hosts, select, textNear } from "../caret.mjs";
|
|
5
5
|
import { convertible } from "../convert.mjs";
|
|
6
6
|
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
|
-
import { BLOCK_TYPES, HOSTS, firstSaysOf, placeholderOf, textFilters, textTypeOf } from "../../components/registry.mjs";
|
|
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.
|
|
@@ -25,6 +26,8 @@ import { t } from "../../../shared/i18n/index.mjs";
|
|
|
25
26
|
// 3万5千), and a block written without such spaces is typed in its own way (none added).
|
|
26
27
|
const HAN = /[\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30fa\u30fc-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff]/;
|
|
27
28
|
const LATIN = /[A-Za-z0-9]/;
|
|
29
|
+
// The text blocks that say their placeholder whenever they are empty (HOSTS' `untitled`: the page's title).
|
|
30
|
+
const UNTITLED = Object.keys(HOSTS).filter((kind) => HOSTS[kind].untitled).map((kind) => `main [data-ge-kind="${kind}"]`).join(", ");
|
|
28
31
|
const needsSpace = (a, b, before) => ((HAN.test(a) && LATIN.test(b)) || (LATIN.test(a) && HAN.test(b))) && !numberWithUnit(a, b, before);
|
|
29
32
|
// The block's own way with Chinese beside Latin letters and digits, from its text but what was just
|
|
30
33
|
// typed: true when it writes them together more often than apart (a number's unit is no sign either way).
|
|
@@ -51,8 +54,11 @@ function writtenTogether(host, node, start, end) {
|
|
|
51
54
|
* deleted as the selected ones are (selection/delete.mjs). adding(): the block the "/" menu the
|
|
52
55
|
* handle's "+" opened is open in (slash-menu/), or null. leave: where Enter and Backspace leave a
|
|
53
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.
|
|
54
60
|
*/
|
|
55
|
-
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 }) {
|
|
56
62
|
// A key, asked of the component of the text block `host` and then of what stands around it, nearest
|
|
57
63
|
// first (docs/editor.md, "The order of keys"): whether it was theirs. `ctx` is notion-lite's, as
|
|
58
64
|
// much of it as a key reads, the block being an element here.
|
|
@@ -61,11 +67,46 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
|
|
|
61
67
|
return Boolean(key(pageOf(host)?.keys ?? {})?.(ctx, ...rest) || pagesAround(host).some((page) => key(page.keys?.around ?? {})?.(ctx, ...rest)));
|
|
62
68
|
}
|
|
63
69
|
|
|
70
|
+
// Enter in the page's title (HOSTS' `opensBody`): notion-lite's splitBlock for the page (enter.js, its
|
|
71
|
+
// first rule): what is selected goes, what follows the caret leaves the title for a new paragraph right
|
|
72
|
+
// below it, the first block of the page (an empty one at its end, a new untitled document's too), and
|
|
73
|
+
// the caret goes to its start; the title keeps what stands before the caret, never a line break. One
|
|
74
|
+
// undo step, the caret back in the title where it was. Below the title is the header's first line when it has one
|
|
75
|
+
// (the paragraph goes before it, in the header), else the first block after the header.
|
|
76
|
+
function enterBody(title) {
|
|
77
|
+
const selection = getSelection();
|
|
78
|
+
if (!selection.rangeCount || !title.contains(selection.getRangeAt(0).startContainer) || !title.contains(selection.getRangeAt(0).endContainer)) return;
|
|
79
|
+
const range = selection.getRangeAt(0);
|
|
80
|
+
const header = title.parentElement;
|
|
81
|
+
let line = title.nextElementSibling;
|
|
82
|
+
while (line && !line.matches(UNIT)) line = line.nextElementSibling;
|
|
83
|
+
const [box, before] = line ? [header, withLeads(line)[0]] : [header.parentElement, header.nextSibling];
|
|
84
|
+
const paragraph = newParagraphHost(document);
|
|
85
|
+
if (!box?.hasAttribute("data-ge-box") || !accepts(box.getAttribute("data-ge-box-kind"), paragraph.getAttribute("data-ge-type"))) {
|
|
86
|
+
say(limitText(title, "split"));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
struct([...new Set([header, box])], [title], () => {
|
|
90
|
+
range.deleteContents();
|
|
91
|
+
const tail = document.createRange();
|
|
92
|
+
tail.setStart(range.startContainer, range.startOffset);
|
|
93
|
+
tail.setEnd(title, title.childNodes.length);
|
|
94
|
+
const moved = tail.extractContents();
|
|
95
|
+
if (moved.textContent.length > 0) paragraph.append(document.createTextNode(moved.textContent)); // the title's words, plain
|
|
96
|
+
title.normalize();
|
|
97
|
+
if (isEmpty(title)) title.replaceChildren();
|
|
98
|
+
box.insertBefore(paragraph, before);
|
|
99
|
+
return { touched: [title, paragraph], focus: paragraph };
|
|
100
|
+
}, { caret: true });
|
|
101
|
+
caretAt(paragraph, "start");
|
|
102
|
+
}
|
|
103
|
+
|
|
64
104
|
// Enter.
|
|
65
105
|
function split(host) {
|
|
106
|
+
if (HOSTS[host.getAttribute("data-ge-kind")]?.opensBody) return enterBody(host);
|
|
66
107
|
// The caret at the very start of a block with text: an empty paragraph goes before the block and
|
|
67
|
-
// the caret stays (a block that splits does this itself, splitBlock).
|
|
68
|
-
//
|
|
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.
|
|
69
110
|
const own = HOSTS[host.getAttribute("data-ge-kind")]?.opensBefore; // not a cell, a card's field, the title
|
|
70
111
|
if (own && !can(host, "split") && !isEmpty(host) && atEdge(host, false) && paragraphBefore(host)) return;
|
|
71
112
|
// Its component's Enter (a code block's line, a nested item out a level, a title going into its
|
|
@@ -115,10 +156,33 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
|
|
|
115
156
|
return true;
|
|
116
157
|
}
|
|
117
158
|
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
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).
|
|
121
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
|
+
}
|
|
122
186
|
const list = hosts();
|
|
123
187
|
const inside = list.filter((node) => container.contains(node));
|
|
124
188
|
const before = textNear(inside[0], -1, list);
|
|
@@ -144,11 +208,7 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
|
|
|
144
208
|
? (next ? [next, "start"] : [previous, "end"])
|
|
145
209
|
: (previous ? [previous, "end"] : [next, "start"]);
|
|
146
210
|
const node = removalTarget(host);
|
|
147
|
-
|
|
148
|
-
if (kept) {
|
|
149
|
-
say(kept, "note", 6000);
|
|
150
|
-
return true;
|
|
151
|
-
}
|
|
211
|
+
if (kept(node)) return true;
|
|
152
212
|
struct([node.parentNode], [host], () => {
|
|
153
213
|
takeOut(node);
|
|
154
214
|
return { touched: [], focus: target };
|
|
@@ -166,6 +226,9 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
|
|
|
166
226
|
// Backspace at the start of a block. Returns whether it was handled.
|
|
167
227
|
function backspace(host) {
|
|
168
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;
|
|
169
232
|
// The block's component (a list item's: a nested item moves out a level, the first or last item of
|
|
170
233
|
// a top-level list leaves it as body text, an emptied item holding lists stays), then what stands
|
|
171
234
|
// around it (the item a block stands under; a node, at the start of its first line, holding
|
|
@@ -175,6 +238,12 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
|
|
|
175
238
|
const container = emptyContainer(host);
|
|
176
239
|
if (container) return removeContainer(container);
|
|
177
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;
|
|
178
247
|
if (isEmpty(host)) return removeHost(host, false);
|
|
179
248
|
if (merge(host)) return true;
|
|
180
249
|
// A block holding blocks that did not join the line above says why, as its component puts it.
|
|
@@ -266,10 +335,23 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
|
|
|
266
335
|
if (hint) host.setAttribute("data-ge-placeholder", hint);
|
|
267
336
|
else host?.removeAttribute("data-ge-placeholder");
|
|
268
337
|
host?.toggleAttribute("data-ge-adding", add);
|
|
338
|
+
untitled();
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// The page's title says 未命名文档 whenever it is empty, the caret in it or not (HOSTS' `untitled`:
|
|
342
|
+
// notion-lite's page title, data-ph 新页面); asked again on every move of the caret and every input,
|
|
343
|
+
// so an undo, a deletion across blocks and the workbench's renaming are followed too.
|
|
344
|
+
function untitled() {
|
|
345
|
+
if (!UNTITLED) return;
|
|
346
|
+
for (const host of document.querySelectorAll(UNTITLED)) {
|
|
347
|
+
if (!isHost(host)) continue;
|
|
348
|
+
if (isEmpty(host)) host.setAttribute("data-ge-placeholder", placeholderOf(host));
|
|
349
|
+
else if (host !== placeholder) host.removeAttribute("data-ge-placeholder");
|
|
350
|
+
}
|
|
269
351
|
}
|
|
270
352
|
|
|
271
353
|
return {
|
|
272
|
-
split, backspace, forwardDelete, autoSpace, updatePlaceholder,
|
|
354
|
+
split, backspace, forwardDelete, autoSpace, updatePlaceholder, untitled,
|
|
273
355
|
/** Tab (`back`: Shift+Tab). Whether the key was taken. */
|
|
274
356
|
tab: (host, back) => asked((keys) => keys.tab, host, back),
|
|
275
357
|
/** Ctrl+Enter. Whether the key was taken. */
|