@heycys/gallery 0.1.0 → 0.1.2
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 +51 -1
- package/browser/editor/components/callout/index.mjs +40 -15
- package/browser/editor/components/columns/page.mjs +45 -32
- package/browser/editor/components/details/index.mjs +2 -1
- package/browser/editor/components/dialog/index.mjs +2 -1
- package/browser/editor/components/dialog/page.mjs +0 -18
- package/browser/editor/components/divider/index.mjs +1 -1
- package/browser/editor/components/embed/index.mjs +2 -2
- package/browser/editor/components/figure/page.mjs +10 -1
- package/browser/editor/components/file/page.mjs +2 -2
- 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 +2 -0
- package/browser/editor/components/heading/page.mjs +6 -0
- package/browser/editor/components/highlight/index.mjs +4 -20
- package/browser/editor/components/icons.mjs +13 -2
- package/browser/editor/components/image/crop.mjs +6 -9
- package/browser/editor/components/image/page.mjs +2 -2
- package/browser/editor/components/installed/index.mjs +82 -29
- package/browser/editor/components/installed/page.mjs +146 -34
- package/browser/editor/components/installed/served.mjs +6 -5
- package/browser/editor/components/instances.mjs +18 -0
- package/browser/editor/components/kit.mjs +3 -0
- package/browser/editor/components/list/page.mjs +3 -6
- package/browser/editor/components/media/page.mjs +44 -14
- package/browser/editor/components/pages.mjs +2 -2
- package/browser/editor/components/registry.mjs +68 -33
- package/browser/editor/components/section/index.mjs +2 -1
- package/browser/editor/components/set-apart.mjs +24 -0
- package/browser/editor/components/table/index.mjs +64 -5
- package/browser/editor/components/table/page.mjs +30 -19
- package/browser/editor/page/annotate/anchors.mjs +4 -3
- package/browser/editor/page/annotate/card.mjs +3 -6
- package/browser/editor/page/annotate/index.mjs +61 -34
- package/browser/editor/page/autosave.mjs +357 -38
- package/browser/editor/page/beside.mjs +5 -5
- package/browser/editor/page/block-menu/colors.mjs +3 -1
- package/browser/editor/page/block-menu/index.mjs +8 -6
- package/browser/editor/page/blocks.mjs +16 -7
- package/browser/editor/page/board/client.mjs +57 -0
- package/browser/editor/page/board/hint.mjs +145 -0
- package/browser/editor/page/board/history.mjs +119 -0
- package/browser/editor/page/board/index.mjs +970 -0
- package/browser/editor/page/board/settings.mjs +209 -0
- package/browser/editor/page/caret.mjs +5 -2
- package/browser/editor/page/changes/bar.mjs +94 -0
- package/browser/editor/page/changes/ghost.mjs +206 -0
- package/browser/editor/page/changes/gone-words.mjs +94 -0
- package/browser/editor/page/changes/index.mjs +447 -0
- package/browser/editor/page/changes/words.mjs +27 -0
- package/browser/editor/page/clipboard/import/colors.mjs +3 -3
- 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 +156 -26
- package/browser/editor/page/clipboard/own/blocks.mjs +25 -16
- package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
- package/browser/editor/page/clipboard/own/describe.mjs +16 -7
- package/browser/editor/page/clipboard/own/export.mjs +6 -6
- package/browser/editor/page/clipboard/own/selection.mjs +3 -3
- package/browser/editor/page/clipboard/own/writers.mjs +0 -11
- package/browser/editor/page/columns/index.mjs +48 -46
- package/browser/editor/page/commit.mjs +98 -25
- package/browser/editor/page/conflicts.mjs +13 -33
- package/browser/editor/page/convert.mjs +8 -7
- package/browser/editor/page/core.mjs +81 -27
- package/browser/editor/page/custom-page.mjs +106 -0
- package/browser/editor/page/drag/index.mjs +40 -24
- package/browser/editor/page/drag/preview.mjs +9 -4
- package/browser/editor/page/editor.mjs +120 -28
- package/browser/editor/page/emoji-picker/emoji-tab.mjs +22 -13
- package/browser/editor/page/emoji-picker/grid.mjs +7 -5
- package/browser/editor/page/emoji-picker/icon-tab.mjs +4 -4
- package/browser/editor/page/emoji-picker/icons.mjs +0 -1
- package/browser/editor/page/emoji-picker/index.mjs +11 -9
- package/browser/editor/page/emoji-picker/styles.mjs +156 -2
- package/browser/editor/page/emoji-picker/support.mjs +6 -4
- package/browser/editor/page/emoji-picker/upload.mjs +14 -13
- package/browser/editor/page/fills.mjs +5 -3
- package/browser/editor/page/fold/index.mjs +348 -0
- package/browser/editor/page/fold/rule.mjs +125 -0
- package/browser/editor/page/folded.mjs +23 -0
- package/browser/editor/page/format-bar/bar.mjs +2 -1
- package/browser/editor/page/format-bar/index.mjs +1 -1
- package/browser/editor/page/geometry.mjs +8 -6
- package/browser/editor/page/handle/index.mjs +22 -14
- package/browser/editor/page/hints/index.mjs +1 -1
- package/browser/editor/page/history.mjs +24 -4
- package/browser/editor/page/insert/index.mjs +30 -17
- package/browser/editor/page/links/index.mjs +5 -3
- package/browser/editor/page/links/pages.mjs +27 -9
- package/browser/editor/page/long-runs.mjs +75 -0
- package/browser/editor/page/look.mjs +69 -6
- package/browser/editor/page/margin.mjs +63 -27
- package/browser/editor/page/media-menu/index.mjs +6 -7
- package/browser/editor/page/menu.mjs +86 -31
- package/browser/editor/page/merge.mjs +24 -0
- package/browser/editor/page/notices.mjs +3 -3
- package/browser/editor/page/offered.mjs +1 -1
- package/browser/editor/page/outline/folds.mjs +11 -10
- package/browser/editor/page/outline/index.mjs +131 -45
- package/browser/editor/page/outline/list.mjs +23 -11
- package/browser/editor/page/outline/read.mjs +1 -1
- package/browser/editor/page/outline/strip.mjs +7 -1
- package/browser/editor/page/page-objects.mjs +13 -2
- package/browser/editor/page/panel.mjs +9 -13
- package/browser/editor/page/present-links.mjs +11 -2
- package/browser/editor/page/resize/index.mjs +42 -29
- package/browser/editor/page/selection/delete.mjs +8 -6
- package/browser/editor/page/selection/index.mjs +10 -3
- package/browser/editor/page/served.mjs +14 -0
- package/browser/editor/page/session.mjs +101 -6
- package/browser/editor/page/slash-menu/index.mjs +3 -3
- package/browser/editor/page/table/cell-bar.mjs +4 -1
- package/browser/editor/page/table/cells.mjs +103 -47
- package/browser/editor/page/table/icons.mjs +3 -1
- package/browser/editor/page/table/index.mjs +40 -16
- package/browser/editor/page/table/pictures.mjs +299 -0
- package/browser/editor/page/table/views.mjs +150 -0
- package/browser/editor/page/table/widths.mjs +9 -4
- package/browser/editor/page/text-select/index.mjs +43 -14
- package/browser/editor/page/todo-writes.mjs +75 -0
- package/browser/editor/page/tooltip.mjs +1 -1
- package/browser/editor/page/type-grid.mjs +4 -3
- package/browser/editor/page/typing/code-edges.mjs +63 -17
- package/browser/editor/page/typing/index.mjs +65 -9
- package/browser/editor/page/typing/leave.mjs +1 -1
- package/browser/editor/page/ui.mjs +13 -0
- package/browser/shared/annotations.mjs +8 -10
- package/browser/shared/block-packs.mjs +404 -0
- package/browser/shared/board-places.mjs +224 -0
- package/browser/shared/card-size.mjs +59 -0
- package/browser/shared/code-folds.mjs +5 -1
- package/browser/shared/colors.mjs +17 -14
- package/browser/shared/component-catalog.mjs +345 -54
- package/browser/shared/component-source.mjs +37 -0
- package/browser/shared/components/callout.mjs +4 -2
- package/browser/shared/components/index.mjs +72 -9
- package/browser/shared/components/installed.mjs +110 -8
- package/browser/shared/components/page.mjs +22 -3
- package/browser/shared/components/state.mjs +5 -1
- package/browser/shared/components/table.mjs +1 -1
- package/browser/shared/components/text.mjs +2 -2
- package/browser/shared/document-look.mjs +183 -0
- package/browser/shared/drafts.mjs +432 -0
- package/browser/shared/emoji/data/LICENSE-lucide.txt +43 -0
- package/browser/shared/emoji/data/README.md +4 -2
- package/browser/shared/emoji/data/categories.json +1 -1
- package/browser/shared/emoji/data/keywords-en.json +1 -1
- package/browser/shared/emoji/data/keywords-zh.json +1 -1
- package/browser/shared/emoji/data/names.json +1 -1
- package/browser/shared/emoji/data/positions.json +1 -1
- package/browser/shared/emoji/data/twemoji-index.json +1 -1
- package/browser/shared/emoji/data/twemoji-svg.bin +0 -0
- package/browser/shared/emoji/data.mjs +10 -12
- package/browser/shared/emoji/emoji.mjs +8 -7
- package/browser/shared/emoji/icon-value.mjs +4 -3
- 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/html-tree.mjs +11 -5
- package/browser/shared/i18n/en.mjs +374 -35
- package/browser/shared/json-layout.mjs +47 -0
- package/browser/shared/long-runs.mjs +39 -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/new-names.mjs +5 -2
- package/browser/shared/outline-shape.mjs +128 -0
- package/browser/shared/outline.mjs +458 -0
- package/browser/shared/pack-manifest.mjs +77 -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 +388 -0
- package/browser/shared/paths.mjs +6 -0
- package/browser/shared/preferences.mjs +10 -4
- package/browser/shared/preview-server.mjs +3 -7
- package/browser/shared/session.mjs +13 -5
- package/browser/shared/shipped-blocks.mjs +299 -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 +134 -0
- package/browser/shared/workspace-columns.mjs +120 -0
- package/browser/shared/workspace-look.mjs +91 -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/browser/shared/zoom.mjs +5 -5
- package/dist/chunk-2NRBY6AJ.mjs +2 -0
- package/dist/chunk-32ZUEFZ7.mjs +2 -0
- package/dist/chunk-35NQ4PLQ.mjs +2 -0
- package/dist/chunk-3KJHLHUO.mjs +2 -0
- package/dist/chunk-3NJACR4W.mjs +2 -0
- package/dist/chunk-4AV456RQ.mjs +2 -0
- package/dist/chunk-4OZWXZE5.mjs +5 -0
- package/dist/chunk-5XYHDBJ5.mjs +2 -0
- package/dist/chunk-5ZJA7CXT.mjs +2 -0
- package/dist/chunk-6A53MZYZ.mjs +2 -0
- package/dist/chunk-6EXH3ORZ.mjs +166 -0
- package/dist/chunk-6EZ7FNIK.mjs +3 -0
- package/dist/{chunk-UXUK4PMC.mjs → chunk-6QBHU4DF.mjs} +1 -1
- package/dist/{chunk-6U2SLSDN.mjs → chunk-6VTU6KEO.mjs} +1 -1
- package/dist/chunk-B4P2CM2J.mjs +3 -0
- package/dist/chunk-BPL64HGA.mjs +4 -0
- package/dist/chunk-BVEFGE4B.mjs +2 -0
- package/dist/chunk-BZ5RAF7L.mjs +2 -0
- package/dist/chunk-CRJEG7MT.mjs +2 -0
- package/dist/{chunk-B3VTYBYR.mjs → chunk-D4CKRD3V.mjs} +91 -91
- package/dist/chunk-D4EURAX4.mjs +4 -0
- package/dist/chunk-DQCE7TJY.mjs +5 -0
- package/dist/chunk-DR73Y2UJ.mjs +3 -0
- package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
- package/dist/{chunk-DB4WKGYF.mjs → chunk-ERLAIBOA.mjs} +2 -2
- package/dist/chunk-EURLTOTZ.mjs +4 -0
- package/dist/chunk-FJYN7RTH.mjs +4 -0
- package/dist/chunk-FWNRPMCJ.mjs +12 -0
- package/dist/chunk-FWW4CSAZ.mjs +2 -0
- package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
- package/dist/chunk-GY3FAUVM.mjs +2 -0
- package/dist/chunk-HLYV7RIH.mjs +2 -0
- package/dist/chunk-HMYTM3GT.mjs +15 -0
- package/dist/chunk-IA4PSIMD.mjs +2 -0
- package/dist/chunk-JEUK3ZO7.mjs +2 -0
- package/dist/chunk-JVHHHGEA.mjs +3 -0
- package/dist/chunk-KTKHRC6H.mjs +2 -0
- package/dist/chunk-L7UP52JO.mjs +2 -0
- package/dist/chunk-MHW7ZKOU.mjs +2 -0
- package/dist/chunk-N76HWBA3.mjs +10 -0
- package/dist/chunk-N7AZZLGT.mjs +548 -0
- package/dist/chunk-NAMN3RAF.mjs +2 -0
- package/dist/{chunk-YXAUQPVK.mjs → chunk-NFMCP2HI.mjs} +3 -3
- package/dist/chunk-NG375ILQ.mjs +2 -0
- package/dist/chunk-NVRNLK25.mjs +6 -0
- package/dist/chunk-NWFBE2YA.mjs +2 -0
- package/dist/chunk-NWR2LT5B.mjs +2 -0
- package/dist/chunk-OJKMINIU.mjs +20 -0
- package/dist/chunk-OUUP3WKT.mjs +2 -0
- package/dist/chunk-OW5NWPOJ.mjs +10 -0
- package/dist/chunk-PAREWQGB.mjs +4 -0
- package/dist/chunk-POQSE4C2.mjs +2 -0
- package/dist/chunk-PUOQ65NC.mjs +2 -0
- package/dist/{chunk-Z52HTUW7.mjs → chunk-PVER7LSC.mjs} +2 -2
- package/dist/chunk-PZDLJJTJ.mjs +3 -0
- package/dist/chunk-Q47PLKIJ.mjs +15 -0
- package/dist/chunk-Q4UEPUWF.mjs +2 -0
- package/dist/chunk-QKXMPUXC.mjs +2 -0
- package/dist/chunk-QOUEFUCH.mjs +16 -0
- package/dist/chunk-RFDZXFJF.mjs +13 -0
- package/dist/chunk-RKPWLGZ3.mjs +4 -0
- package/dist/chunk-RMECZA2K.mjs +2 -0
- package/dist/{chunk-EUX7IC5J.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
- package/dist/chunk-SX4LJYT6.mjs +8 -0
- package/dist/chunk-SXHBYZST.mjs +16 -0
- package/dist/chunk-TANZRINB.mjs +2 -0
- package/dist/chunk-TEZAWDSQ.mjs +2 -0
- package/dist/chunk-UBBRTJ2R.mjs +24 -0
- package/dist/chunk-UFNYFFKO.mjs +20 -0
- package/dist/chunk-UGWYKHBL.mjs +170 -0
- package/dist/chunk-UKSHDZZ6.mjs +2 -0
- package/dist/chunk-UMHUSOPJ.mjs +2 -0
- package/dist/chunk-UNOYVIYR.mjs +2 -0
- package/dist/chunk-V6RIYQZZ.mjs +4 -0
- package/dist/chunk-VJPFVNNW.mjs +15 -0
- package/dist/chunk-VS3ZMVGX.mjs +5 -0
- package/dist/chunk-VTKNEYT3.mjs +6 -0
- package/dist/chunk-VXACTLO3.mjs +3 -0
- package/dist/chunk-W3BGBJQW.mjs +2 -0
- package/dist/chunk-YI43RG4P.mjs +2 -0
- package/dist/chunk-YQGT4AB2.mjs +6 -0
- package/dist/chunk-ZB4H7ZN4.mjs +2 -0
- package/dist/{chunk-ACOPDCNB.mjs → chunk-ZHEHPMBK.mjs} +1 -1
- package/dist/chunk-ZTHICSSF.mjs +2 -0
- package/dist/chunk-ZUNVAXLH.mjs +2 -0
- package/dist/chunk-ZWPMCK7P.mjs +2 -0
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/{chunk-EVJ3BX3M.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 +14 -14
- package/kit/math.js +18 -2
- package/kit/report.css +500 -151
- package/kit/runtime.js +1720 -170
- package/kit/state.js +10 -1
- package/kit/tables.js +172 -37
- package/kit/ui.js +166 -27
- 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 +156 -0
- package/packs/gallery/countdown/preview.svg +1 -0
- package/packs/gallery/countdown/style.css +130 -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 +295 -0
- package/packs/gallery/habit/preview.svg +1 -0
- package/packs/gallery/habit/style.css +246 -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 +351 -0
- package/packs/gallery/heatmap/preview.svg +1 -0
- package/packs/gallery/heatmap/style.css +201 -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 +102 -0
- package/packs/gallery/note/preview.svg +1 -0
- package/packs/gallery/note/style.css +76 -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 +238 -0
- package/packs/gallery/recent/preview.svg +1 -0
- package/packs/gallery/recent/style.css +158 -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 +138 -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 +166 -0
- package/packs/gallery/stats/preview.svg +1 -0
- package/packs/gallery/stats/style.css +151 -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 +185 -0
- package/packs/gallery/today/preview.svg +1 -0
- package/packs/gallery/today/style.css +120 -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 +342 -0
- package/packs/gallery/todos/preview.svg +1 -0
- package/packs/gallery/todos/style.css +267 -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 +312 -0
- package/packs/gallery/weather/preview.svg +1 -0
- package/packs/gallery/weather/style.css +258 -0
- package/packs/gallery/weather/template.html +3 -0
- package/packs/gallery/weather/writing.md +26 -0
- package/packs/gallery-soft/pack.json +8 -0
- package/release.json +13 -11
- package/sdk/doc-kit.d.ts +404 -7
- package/sdk/doc-state.d.ts +2 -0
- package/skill/SKILL.md +71 -26
- package/skill/references/block-script.md +140 -0
- package/skill/references/building-blocks.md +257 -0
- package/skill/references/example-report.html +1 -1
- package/skill/references/extensions.md +59 -0
- package/skill/references/pages-and-data.md +221 -0
- package/skill/references/writing-html.md +9 -7
- package/skill/sdk/doc-kit.d.ts +404 -7
- package/skill/sdk/doc-state.d.ts +2 -0
- package/web/assets/index-BK2e_07w.js +13 -0
- package/web/assets/index-CWFI83mF.css +1 -0
- package/web/index.html +2 -2
- package/browser/editor/components/callout/page.mjs +0 -13
- package/dist/chunk-2PBALTR3.mjs +0 -57
- package/dist/chunk-3LA3EMDE.mjs +0 -15
- package/dist/chunk-5FRMCDPY.mjs +0 -16
- package/dist/chunk-5LEK2CBS.mjs +0 -2
- package/dist/chunk-5OFN5AHC.mjs +0 -2
- package/dist/chunk-5SIYS5HN.mjs +0 -2
- package/dist/chunk-5TEK3RAD.mjs +0 -2
- package/dist/chunk-6CYG3Z4V.mjs +0 -2
- package/dist/chunk-7GHT2UCA.mjs +0 -15
- package/dist/chunk-7QQBR7PB.mjs +0 -2
- package/dist/chunk-ATCJYAR4.mjs +0 -2
- package/dist/chunk-C7HWOBIF.mjs +0 -2
- package/dist/chunk-E7VYDG2X.mjs +0 -2
- package/dist/chunk-EZY3WC6Z.mjs +0 -15
- package/dist/chunk-FQGQH4KM.mjs +0 -2
- package/dist/chunk-G7TOXONE.mjs +0 -6
- package/dist/chunk-GPF4YWWB.mjs +0 -9
- package/dist/chunk-GYQV7Y4J.mjs +0 -120
- package/dist/chunk-HMHK3EQ6.mjs +0 -2
- package/dist/chunk-HQQMJCQJ.mjs +0 -10
- package/dist/chunk-IERUOGC3.mjs +0 -6
- package/dist/chunk-ITNLYXXV.mjs +0 -3
- package/dist/chunk-L4DVONOG.mjs +0 -2
- package/dist/chunk-LAE5NQ4B.mjs +0 -2
- package/dist/chunk-LC7YNQFG.mjs +0 -2
- package/dist/chunk-LHTFLRB6.mjs +0 -4
- package/dist/chunk-NFIBI4IP.mjs +0 -26
- package/dist/chunk-NSKUTQ5J.mjs +0 -5
- package/dist/chunk-O52JMOCZ.mjs +0 -2
- package/dist/chunk-P2CAZPDP.mjs +0 -3
- package/dist/chunk-QMQUXTU4.mjs +0 -12
- package/dist/chunk-QVWVFC5K.mjs +0 -6
- package/dist/chunk-QYKCJ7FG.mjs +0 -8
- package/dist/chunk-QZY6Q64C.mjs +0 -2
- package/dist/chunk-TDQP3DKQ.mjs +0 -10
- package/dist/chunk-TX6JH7TR.mjs +0 -2
- package/dist/chunk-UNUEWH4S.mjs +0 -2
- package/dist/chunk-V4CPWKMZ.mjs +0 -2
- package/dist/chunk-VACRB2NE.mjs +0 -3
- package/dist/chunk-W63L7367.mjs +0 -7
- package/dist/chunk-W7CXPCRV.mjs +0 -6
- package/dist/chunk-XINNG4F2.mjs +0 -4
- package/dist/chunk-YL2DPWVS.mjs +0 -4
- package/dist/chunk-YZ5Z6H4W.mjs +0 -4
- package/dist/chunk-ZBIM6ARY.mjs +0 -216
- package/skill/references/building-components.md +0 -327
- package/web/assets/index-B6Ai3wsa.js +0 -13
- package/web/assets/index-SYPC3EZy.css +0 -1
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
import { t } from "../../../shared/i18n/index.mjs";
|
|
2
|
+
import { onPreferences, preference } from "../../../shared/preferences.mjs";
|
|
3
|
+
import { readText, rangeOf } from "../annotate/anchors.mjs";
|
|
4
|
+
import { GONE_WORDS, nestedBlocks } from "../core.mjs";
|
|
5
|
+
import { createFills } from "../fills.mjs";
|
|
6
|
+
import { FOLLOW, task } from "../frames.mjs";
|
|
7
|
+
import { onSettle, own, provide } from "../overlays.mjs";
|
|
8
|
+
import { failure, postAnswer } from "../post.mjs";
|
|
9
|
+
import { addStyle } from "../ui.mjs";
|
|
10
|
+
import { UNDO_SHOWN, createBar } from "./bar.mjs";
|
|
11
|
+
import { GHOST_STYLE, createGhosts } from "./ghost.mjs";
|
|
12
|
+
import { editsBy, goneMark, placeOf, putMark, takeMark } from "./gone-words.mjs";
|
|
13
|
+
import { wordMarks } from "./words.mjs";
|
|
14
|
+
|
|
15
|
+
// The Agent's changes on the page (docs/editor.md "Agent's changes"), as Cursor reviews an Agent's:
|
|
16
|
+
// what an Agent wrote to the report since the reader last kept or reverted it (the server's review,
|
|
17
|
+
// editor/changes.mjs, read at the editor's start and never holding it back, drawn once the page is
|
|
18
|
+
// ready), marked without a change to the file: a block added (or changed with no words to tell, or
|
|
19
|
+
// whose words cannot be compared) a green fill (fills.mjs), words added the 批注's look in green (a
|
|
20
|
+
// CSS highlight under the 批注's own), the words taken out shown where they were, in red struck
|
|
21
|
+
// through (gone-words.mjs: an empty inline mark of the editor's own, its words drawn by CSS, which
|
|
22
|
+
// nothing that reads or writes the block's content takes), the blocks deleted shown where they were,
|
|
23
|
+
// a ghost of them in red struck through in room made for it (ghost.mjs, drawn in the overlay layer:
|
|
24
|
+
// nothing of it in the document). Nothing to rest the pointer on: all of it shows at once. The reader
|
|
25
|
+
// editing a block takes its words taken out away first (the keys, input, an input method, a paste,
|
|
26
|
+
// cut or drop in it, the format bar over it), and they are not drawn in it again until the caret has
|
|
27
|
+
// left it (the review read again then). The bar at the window's bottom (bar.mjs) says how many blocks
|
|
28
|
+
// and offers 撤回 (the server writes the baseline back: the reader's own saved edits stay; undone within
|
|
29
|
+
// UNDO_SHOWN from the bar of the page shown again) and 确认 (no more marks). 显示变更 off (设置),
|
|
30
|
+
// nothing is drawn and a review read is kept at once, quietly. The page reads the review again when
|
|
31
|
+
// its server says it changed (another tab kept it, an Agent wrote more) and 1.5s after a commit of its
|
|
32
|
+
// own while the bar shows. Not on a page opened on its own in a frame (?solo), printed, or presented
|
|
33
|
+
// (the preview's ?present has no editor).
|
|
34
|
+
|
|
35
|
+
const ROUTE = "/__gallery/edit/changes";
|
|
36
|
+
const REREAD_AFTER = 1500; // after a commit of the page's own, the review read again this long after (the reader paused)
|
|
37
|
+
const LEFT_AFTER = 150; // the caret left a block the reader edited: the review read again this long after (once saved)
|
|
38
|
+
const KEEP_TRIES = 3; // a quiet keep refused (the review grew meanwhile) is tried again this often
|
|
39
|
+
// What may edit the block it happens in: its words taken out go first (gone-words.mjs editsBy for a key).
|
|
40
|
+
const EDITS = ["keydown", "beforeinput", "compositionstart", "paste", "cut", "drop", "dragstart"];
|
|
41
|
+
|
|
42
|
+
const STYLE = `
|
|
43
|
+
::highlight(ge-diff-add) { background-color: var(--ge-diff-add); text-decoration: underline 2px var(--ge-diff-add-line); }
|
|
44
|
+
.ge-diff-del { user-select: none; pointer-events: none; }
|
|
45
|
+
.ge-diff-del::before { content: attr(data-ge-gone-words); border-radius: 3px; background: var(--ge-diff-del); color: var(--ge-diff-del-text); text-decoration: line-through; text-decoration-color: var(--ge-diff-del-text); -webkit-box-decoration-break: clone; box-decoration-break: clone; }
|
|
46
|
+
.ge-diff-del[data-ge-gone-lead]::before { margin-left: .28em; }
|
|
47
|
+
.ge-diff-del[data-ge-gone-tail]::after { content: " "; }
|
|
48
|
+
${GHOST_STYLE}
|
|
49
|
+
@media print { ::highlight(ge-diff-add) { background-color: transparent; text-decoration: none; } .ge-diff-del, .ge-diff-halo { display: none; } }
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
const highlights = () => Boolean(globalThis.CSS?.highlights && globalThis.Highlight);
|
|
53
|
+
const holdsSelection = (block) => {
|
|
54
|
+
const selection = getSelection();
|
|
55
|
+
return selection.rangeCount > 0 && (block.contains(selection.anchorNode) || block.contains(selection.focusNode));
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* slug, token: the map's; commits(), autosave(): the page's (made later than this); flush(): what
|
|
60
|
+
* waits saved now (as Ctrl+S); say(text, kind); session: sessionStorage (storage.mjs storageOf), where
|
|
61
|
+
* a revert's undo is kept over the page shown again; across: the selection across blocks (text-select/:
|
|
62
|
+
* texts(), redraw(texts)), kept on its words while marks go and come. Returns { start(),
|
|
63
|
+
* committed(receipt), leave() }.
|
|
64
|
+
*/
|
|
65
|
+
export function createChanges({ slug, token, commits, autosave, flush, say, session, across = null }) {
|
|
66
|
+
const undoKey = `gallery-edit:${slug}:changes-undo`;
|
|
67
|
+
const shows = () => preference("showChanges");
|
|
68
|
+
let review = null; // the review as last read and drawn: { stamp, counts, added, changed, removed }
|
|
69
|
+
let started = false;
|
|
70
|
+
let left = false;
|
|
71
|
+
let busy = false; // 撤回, 确认 or 撤销 under way
|
|
72
|
+
let reading = read(); // at once: the page's start does not wait for it
|
|
73
|
+
let rereadTimer = 0;
|
|
74
|
+
let keepTries = 0;
|
|
75
|
+
let offering = 0; // until when the bar offers 撤销 of this tab's revert
|
|
76
|
+
const filled = new Set(); // block elements filled green
|
|
77
|
+
const changedBlocks = new Map(); // a text block -> its words in the baseline
|
|
78
|
+
const added = new Map(); // a text block -> the ranges of its words added (the green highlight's)
|
|
79
|
+
let dels = []; // the words taken out shown: { node, block }
|
|
80
|
+
const edited = new Set(); // text blocks the reader edited since their words taken out were drawn
|
|
81
|
+
const ghosts = createGhosts();
|
|
82
|
+
let fills = null;
|
|
83
|
+
const bar = createBar({ revert: () => revert(), accept: () => keep() });
|
|
84
|
+
|
|
85
|
+
function read() {
|
|
86
|
+
return postAnswer(ROUTE, token, { slug, action: "read" });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ---------- finding the blocks it names (in the file now) ----------
|
|
90
|
+
const unitOf = (id) => document.querySelector(`[data-ge-unit="${id}"]`);
|
|
91
|
+
const body = () => document.querySelector("main");
|
|
92
|
+
function find(ref) {
|
|
93
|
+
if (!ref) return null;
|
|
94
|
+
const main = body() ?? document;
|
|
95
|
+
if (ref.title) return main.querySelector('[data-ge-kind="title"]'); // the page's own title, as the editor made it a text block
|
|
96
|
+
if (ref.id) return main.querySelector(`[data-block-id="${CSS.escape(ref.id)}"]`);
|
|
97
|
+
if (typeof ref.hash !== "string") return null;
|
|
98
|
+
const list = commits();
|
|
99
|
+
if (!list) return null;
|
|
100
|
+
let nth = 0;
|
|
101
|
+
for (const node of main.querySelectorAll("[data-ge-unit]")) {
|
|
102
|
+
if (list.fileHash(Number(node.getAttribute("data-ge-unit"))) !== ref.hash) continue;
|
|
103
|
+
if (nth++ === ref.nth) return node;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
// A unit's own text blocks in the page's order (the server's: its scope line's first, if a table's).
|
|
108
|
+
function ownBlocks(unit, ref) {
|
|
109
|
+
if (ref.title) return [unit];
|
|
110
|
+
const owner = (block) => {
|
|
111
|
+
const at = block.closest("[data-ge-unit], [data-ge-lead]");
|
|
112
|
+
return at?.hasAttribute("data-ge-lead") && !at.hasAttribute("data-ge-unit") ? unitOf(at.getAttribute("data-ge-lead")) : at;
|
|
113
|
+
};
|
|
114
|
+
const lead = document.querySelector(`[data-ge-lead="${unit.getAttribute("data-ge-unit")}"]`);
|
|
115
|
+
const within = (root) => [root, ...root.querySelectorAll("[data-ge-block]")].filter((block) => block.hasAttribute("data-ge-block") && owner(block) === unit);
|
|
116
|
+
return [...(lead && lead !== unit ? within(lead) : []), ...within(unit)];
|
|
117
|
+
}
|
|
118
|
+
// A text block's words as the server reads them: a list item's own, not the blocks it holds.
|
|
119
|
+
const readBlock = (block) => {
|
|
120
|
+
const held = nestedBlocks(block);
|
|
121
|
+
return readText([block], held.length ? { skip: (child) => held.includes(child) } : undefined);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// ---------- drawing ----------
|
|
125
|
+
const frames = task("changes", { run: place, fail: () => keepingAcross(takeDown) });
|
|
126
|
+
// A selection across blocks (text-select/) kept on its words while marks go and come: its ends are
|
|
127
|
+
// points of its own, which a text node joined again (takeMark) would leave off the page, and so its
|
|
128
|
+
// pieces' live ranges are taken first (a text node split, putMark, they follow; one joined, takeMark
|
|
129
|
+
// sets them) and it is drawn again from them.
|
|
130
|
+
function keepingAcross(change) {
|
|
131
|
+
const texts = across?.texts() ?? null;
|
|
132
|
+
change(texts ? texts.map(({ range }) => range) : []);
|
|
133
|
+
if (texts) across.redraw(texts);
|
|
134
|
+
}
|
|
135
|
+
function takeDown(ranges = []) {
|
|
136
|
+
fills?.clear();
|
|
137
|
+
for (const { node } of dels) if (node.isConnected) takeMark(node, ranges);
|
|
138
|
+
dels = [];
|
|
139
|
+
ghosts.clear();
|
|
140
|
+
filled.clear();
|
|
141
|
+
changedBlocks.clear();
|
|
142
|
+
added.clear();
|
|
143
|
+
if (highlights()) CSS.highlights.delete("ge-diff-add");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function draw() {
|
|
147
|
+
keepingAcross((ranges) => drawNow(ranges));
|
|
148
|
+
}
|
|
149
|
+
function drawNow(ranges) {
|
|
150
|
+
takeDown(ranges);
|
|
151
|
+
if (!review || !shows()) {
|
|
152
|
+
edited.clear();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
addStyle(STYLE);
|
|
156
|
+
fills ??= createFills({ kind: "changes", className: "ge-diff-halo", stands: (block) => filled.has(block) });
|
|
157
|
+
for (const { ref } of review.added) {
|
|
158
|
+
const unit = find(ref);
|
|
159
|
+
if (unit) filled.add(unit);
|
|
160
|
+
}
|
|
161
|
+
for (const change of review.changed) {
|
|
162
|
+
const unit = find(change.ref);
|
|
163
|
+
if (!unit) continue;
|
|
164
|
+
if (change.whole) {
|
|
165
|
+
filled.add(unit);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
const blocks = ownBlocks(unit, change.ref);
|
|
169
|
+
for (const { nth, base } of change.texts ?? []) {
|
|
170
|
+
if (blocks[nth]) changedBlocks.set(blocks[nth], base);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// A block the reader edited keeps its words taken out away while the caret is in it.
|
|
174
|
+
for (const block of [...edited]) if (!changedBlocks.has(block) || !holdsSelection(block)) edited.delete(block);
|
|
175
|
+
for (const [block, base] of changedBlocks) markWords(block, base, !edited.has(block));
|
|
176
|
+
paintAdded();
|
|
177
|
+
for (const group of review.removed) {
|
|
178
|
+
const anchor = group.before ? find(group.before) : group.after ? find(group.after) : body();
|
|
179
|
+
if (anchor) ghosts.add(group, anchor, group.before ? "before" : group.after ? "after" : "into");
|
|
180
|
+
}
|
|
181
|
+
if (filled.size || added.size || dels.length || ghosts.count) frames.wake();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// A changed text block's marks: the ranges of its words added (live: they follow the reader's
|
|
185
|
+
// typing), and, `taken`, its words taken out put in where they were (from the last, so that each
|
|
186
|
+
// place read before is still where it was: a text node is split only after it).
|
|
187
|
+
function markWords(block, base, taken) {
|
|
188
|
+
const text = readBlock(block);
|
|
189
|
+
const { ins, cuts } = wordMarks(base, text.text);
|
|
190
|
+
added.set(block, ins.map(([from, to]) => rangeOf(text, from, to)).filter(Boolean));
|
|
191
|
+
if (!taken) return;
|
|
192
|
+
for (const { at, text: words } of [...cuts].reverse()) {
|
|
193
|
+
const where = placeOf(text, at);
|
|
194
|
+
if (!where) continue;
|
|
195
|
+
const node = goneMark(words, document, { before: text.text[at - 1], after: text.text[at] });
|
|
196
|
+
const entry = { node, block };
|
|
197
|
+
own(node, "changes", { owner: block, alive: () => block.contains(node) && dels.includes(entry) });
|
|
198
|
+
putMark(node, where);
|
|
199
|
+
dels.push(entry);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function paintAdded() {
|
|
204
|
+
if (!highlights()) return;
|
|
205
|
+
const ranges = [...added.values()].flat();
|
|
206
|
+
if (ranges.length === 0) return void CSS.highlights.delete("ge-diff-add");
|
|
207
|
+
const highlight = new Highlight(...ranges);
|
|
208
|
+
highlight.priority = -1; // a 批注's marks over these
|
|
209
|
+
CSS.highlights.set("ge-diff-add", highlight);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Each frame something may have moved: the fills where their blocks are, the ghosts where their rooms are.
|
|
213
|
+
function place() {
|
|
214
|
+
if (!review) return false;
|
|
215
|
+
fills?.paint([...filled].filter((block) => block.isConnected));
|
|
216
|
+
ghosts.place();
|
|
217
|
+
return filled.size || ghosts.count ? FOLLOW : false;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// What the page's edits took off the page goes with it (a block deleted, its marks): the words taken
|
|
221
|
+
// out shown in a block deleted or turned into another are taken out of it too, so that undo, which
|
|
222
|
+
// puts the very same element back, puts back none of them.
|
|
223
|
+
// A copy of a mark that a change made (a cell turned into a header cell or back, cells merged or
|
|
224
|
+
// filled, a disclosure's title made a paragraph, a block duplicated: whatever clones a block's
|
|
225
|
+
// content) stands for nothing and goes at once, before the overlays' audit would find it a stray:
|
|
226
|
+
// the review read again after the change's commit draws the words taken out where they are then.
|
|
227
|
+
onSettle(() => {
|
|
228
|
+
const drawn = dels.length > 0;
|
|
229
|
+
for (const block of [...filled]) if (!block.isConnected) filled.delete(block);
|
|
230
|
+
dels = dels.filter((entry) => {
|
|
231
|
+
if (entry.block.isConnected && entry.node.isConnected) return true;
|
|
232
|
+
if (entry.node.parentNode) takeMark(entry.node);
|
|
233
|
+
return false;
|
|
234
|
+
});
|
|
235
|
+
if (drawn) {
|
|
236
|
+
const ours = new Set(dels.map((entry) => entry.node));
|
|
237
|
+
for (const node of document.querySelectorAll(`main ${GONE_WORDS}`)) if (!ours.has(node)) takeMark(node);
|
|
238
|
+
}
|
|
239
|
+
ghosts.settle();
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// ---------- the reader edits a block holding words taken out ----------
|
|
243
|
+
// They go first, before the edit touches the block (window, capture: before the editor's own
|
|
244
|
+
// listeners): the text either side of each one text node again, the caret where it was, and the
|
|
245
|
+
// block's words added marked anew (a range that ended in the half that went would cover the wrong
|
|
246
|
+
// words). The block is `edited`: drawn without them until the caret leaves it.
|
|
247
|
+
// The blocks an edit may touch: the one it happens in, those the selection reaches, the browser's
|
|
248
|
+
// or the page's across blocks (text-select/, which the browser's then holds none of).
|
|
249
|
+
function blocksOf(event) {
|
|
250
|
+
const selection = getSelection();
|
|
251
|
+
const range = selection.rangeCount ? selection.getRangeAt(0) : null;
|
|
252
|
+
const target = event?.target instanceof Node ? event.target : null;
|
|
253
|
+
const reached = across?.texts()?.map(({ host }) => host) ?? [];
|
|
254
|
+
const hit = new Set();
|
|
255
|
+
for (const { block } of dels) {
|
|
256
|
+
if (hit.has(block)) continue;
|
|
257
|
+
if ((target && block.contains(target)) || (range && range.intersectsNode(block)) || reached.some((host) => host === block || host.contains(block) || block.contains(host))) hit.add(block);
|
|
258
|
+
}
|
|
259
|
+
return hit;
|
|
260
|
+
}
|
|
261
|
+
function takeOut(blocks) {
|
|
262
|
+
if (blocks.size === 0) return;
|
|
263
|
+
keepingAcross((ranges) => {
|
|
264
|
+
for (const entry of dels) if (blocks.has(entry.block) && entry.node.isConnected) takeMark(entry.node, ranges);
|
|
265
|
+
});
|
|
266
|
+
dels = dels.filter((entry) => !blocks.has(entry.block));
|
|
267
|
+
for (const block of blocks) {
|
|
268
|
+
edited.add(block);
|
|
269
|
+
const base = changedBlocks.get(block);
|
|
270
|
+
if (base !== undefined) markWords(block, base, false);
|
|
271
|
+
}
|
|
272
|
+
paintAdded();
|
|
273
|
+
}
|
|
274
|
+
function editing(event) {
|
|
275
|
+
if (dels.length === 0 || (event.type === "keydown" && !editsBy(event))) return;
|
|
276
|
+
takeOut(blocksOf(event));
|
|
277
|
+
}
|
|
278
|
+
// The format bar over words of such a block (its buttons keep the selection where it is).
|
|
279
|
+
function pressed(event) {
|
|
280
|
+
if (dels.length > 0 && event.target instanceof Element && event.target.closest(".ge-format")) takeOut(blocksOf(null));
|
|
281
|
+
}
|
|
282
|
+
// The caret left a block the reader edited: the review read again once what waits is saved, and drawn.
|
|
283
|
+
function moved() {
|
|
284
|
+
if (edited.size === 0) return;
|
|
285
|
+
let leaving = false;
|
|
286
|
+
for (const block of [...edited]) {
|
|
287
|
+
if (block.isConnected && holdsSelection(block)) continue;
|
|
288
|
+
edited.delete(block);
|
|
289
|
+
leaving = true;
|
|
290
|
+
}
|
|
291
|
+
if (leaving) rereadSaved(LEFT_AFTER);
|
|
292
|
+
}
|
|
293
|
+
for (const type of EDITS) addEventListener(type, editing, true);
|
|
294
|
+
addEventListener("pointerdown", pressed, true);
|
|
295
|
+
document.addEventListener("selectionchange", moved);
|
|
296
|
+
|
|
297
|
+
// ---------- what the server says ----------
|
|
298
|
+
function take(answer) {
|
|
299
|
+
if (left) return;
|
|
300
|
+
review = answer?.ok && answer.pending ? answer : null;
|
|
301
|
+
if (review && !shows()) return void keep({ quiet: true });
|
|
302
|
+
if (busy) return;
|
|
303
|
+
if (review) bar.counts(review.counts);
|
|
304
|
+
else if (Date.now() >= offering) bar.hide();
|
|
305
|
+
draw();
|
|
306
|
+
}
|
|
307
|
+
async function reread() {
|
|
308
|
+
clearTimeout(rereadTimer);
|
|
309
|
+
if (left || !started) return;
|
|
310
|
+
reading = read();
|
|
311
|
+
take(await reading);
|
|
312
|
+
}
|
|
313
|
+
// Read again `after` ms from now, once nothing waits to be saved (the reader paused).
|
|
314
|
+
function rereadSaved(after) {
|
|
315
|
+
clearTimeout(rereadTimer);
|
|
316
|
+
const again = () => {
|
|
317
|
+
if (autosave()?.state.waiting > 0) rereadTimer = setTimeout(again, REREAD_AFTER);
|
|
318
|
+
else reread();
|
|
319
|
+
};
|
|
320
|
+
rereadTimer = setTimeout(again, after);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// 确认: the review ended; `quiet`, as the setting being off does it (nothing said).
|
|
324
|
+
async function keep({ quiet = false } = {}) {
|
|
325
|
+
if (!review || busy) return;
|
|
326
|
+
const stamp = review.stamp;
|
|
327
|
+
busy = true;
|
|
328
|
+
review = null;
|
|
329
|
+
draw();
|
|
330
|
+
bar.hide();
|
|
331
|
+
const answer = await postAnswer(ROUTE, token, { slug, action: "accept", stamp });
|
|
332
|
+
busy = false;
|
|
333
|
+
if (answer.ok) {
|
|
334
|
+
keepTries = 0;
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
// Refused (the review grew meanwhile, the file was held): read again, and kept again when quiet, a few times at most.
|
|
338
|
+
if (quiet) {
|
|
339
|
+
if (++keepTries > KEEP_TRIES) return;
|
|
340
|
+
} else if (answer.reason === "changed") say(failure(answer, t("Agent 刚刚又改了文档,再看一眼")), "note");
|
|
341
|
+
else say(t("没能确认:{0}", failure(answer, t("预览服务器出错"))), "error");
|
|
342
|
+
reread();
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// 撤回: what waits is saved first, and nothing may wait for the reader (a conflict); then the server
|
|
346
|
+
// writes the baseline, and the page is shown again as after a write of its own (autosave showOwn: no
|
|
347
|
+
// question of what that write put back of the reader's, which the reader asked for).
|
|
348
|
+
async function revert() {
|
|
349
|
+
if (!review || busy) return;
|
|
350
|
+
const stamp = review.stamp;
|
|
351
|
+
busy = true;
|
|
352
|
+
await flush();
|
|
353
|
+
const state = autosave()?.state;
|
|
354
|
+
if (!state || state.waiting > 0 || state.syncing || state.held > 0 || state.offline) {
|
|
355
|
+
busy = false;
|
|
356
|
+
say(t("还有修改没保存或有冲突待处理,处理完再撤回"), "error");
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
let answer = null;
|
|
360
|
+
const shown = await autosave().showOwn(async () => {
|
|
361
|
+
answer = await postAnswer(ROUTE, token, { slug, action: "revert", stamp });
|
|
362
|
+
if (!answer.ok || answer.none) return false;
|
|
363
|
+
session?.set(undoKey, JSON.stringify({ undo: answer.undo, at: Date.now() }));
|
|
364
|
+
return answer.version || true; // the version it wrote: the page shown again on another asks what that put back
|
|
365
|
+
});
|
|
366
|
+
if (shown) return; // the page goes: the one shown again offers 撤销
|
|
367
|
+
busy = false;
|
|
368
|
+
if (answer?.ok) return void reread(); // nothing was under review any more
|
|
369
|
+
say(answer?.reason === "changed" ? failure(answer, t("Agent 刚刚又改了文档,再看一眼")) : t("没能撤回:{0}", failure(answer ?? {}, t("预览服务器出错"))), answer?.reason === "changed" ? "note" : "error");
|
|
370
|
+
reread();
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// 撤销 of a revert: the server writes back what the revert wrote over, while the file is still the revert's.
|
|
374
|
+
async function undo(id) {
|
|
375
|
+
if (busy) return;
|
|
376
|
+
busy = true;
|
|
377
|
+
offering = 0;
|
|
378
|
+
session?.remove(undoKey);
|
|
379
|
+
bar.hide();
|
|
380
|
+
await flush();
|
|
381
|
+
let answer = null;
|
|
382
|
+
const shown = await autosave().showOwn(async () => {
|
|
383
|
+
answer = await postAnswer(ROUTE, token, { slug, action: "undo", undo: id });
|
|
384
|
+
return answer.ok ? answer.version || true : false;
|
|
385
|
+
});
|
|
386
|
+
if (shown) return;
|
|
387
|
+
busy = false;
|
|
388
|
+
say(t("没能撤销:{0}", failure(answer ?? {}, t("预览服务器出错"))), "error");
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// A revert of this tab's, the page shown again since: 撤销 on the bar for what is left of UNDO_SHOWN.
|
|
392
|
+
function undoShown() {
|
|
393
|
+
let kept = null;
|
|
394
|
+
try { kept = JSON.parse(session?.get(undoKey) ?? "null"); } catch {}
|
|
395
|
+
const remaining = kept && typeof kept.undo === "string" ? UNDO_SHOWN - (Date.now() - kept.at) : 0;
|
|
396
|
+
if (remaining <= 0) {
|
|
397
|
+
session?.remove(undoKey);
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
offering = Date.now() + remaining;
|
|
401
|
+
bar.reverted(remaining, () => undo(kept.undo));
|
|
402
|
+
setTimeout(() => session?.remove(undoKey), remaining);
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// The server's word that the review changed (another tab kept or reverted it, the Agent wrote more).
|
|
407
|
+
const heard = () => {
|
|
408
|
+
clearTimeout(rereadTimer);
|
|
409
|
+
rereadTimer = setTimeout(reread, 100);
|
|
410
|
+
};
|
|
411
|
+
addEventListener("doc-changes-changed", heard);
|
|
412
|
+
// 显示变更 switched (设置, another page of the origin): off, what is under review is kept and nothing drawn; on, read again.
|
|
413
|
+
onPreferences(() => {
|
|
414
|
+
if (!started || left) return;
|
|
415
|
+
if (!shows()) {
|
|
416
|
+
if (review) keep({ quiet: true });
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
reread();
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
provide("changes", () => ({ pending: Boolean(review), counts: review?.counts ?? null, filled: filled.size, words: dels.length, ghosts: ghosts.count, edited: edited.size }));
|
|
423
|
+
|
|
424
|
+
return {
|
|
425
|
+
/** The page is ready: what was read is drawn (the bar, or 撤销 after a revert of this tab's). */
|
|
426
|
+
async start() {
|
|
427
|
+
if (started) return;
|
|
428
|
+
started = true;
|
|
429
|
+
undoShown();
|
|
430
|
+
take(await reading);
|
|
431
|
+
},
|
|
432
|
+
/** A commit of the page's was taken in: while the bar shows, the review is read again once the reader pauses. */
|
|
433
|
+
committed(receipt) {
|
|
434
|
+
if (!receipt?.wrote || !review || !started) return;
|
|
435
|
+
rereadSaved(REREAD_AFTER);
|
|
436
|
+
},
|
|
437
|
+
/** The page goes. */
|
|
438
|
+
leave() {
|
|
439
|
+
left = true;
|
|
440
|
+
clearTimeout(rereadTimer);
|
|
441
|
+
removeEventListener("doc-changes-changed", heard);
|
|
442
|
+
for (const type of EDITS) removeEventListener(type, editing, true);
|
|
443
|
+
removeEventListener("pointerdown", pressed, true);
|
|
444
|
+
document.removeEventListener("selectionchange", moved);
|
|
445
|
+
},
|
|
446
|
+
};
|
|
447
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { wordDiff } from "../merge.mjs";
|
|
2
|
+
|
|
3
|
+
// The words an Agent changed in a text block, as the page marks them (docs/editor.md "Agent's
|
|
4
|
+
// changes"): the word diff of the block's text in the baseline against its text on the page
|
|
5
|
+
// (merge.mjs wordDiff), as places in the page's text.
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* What `now` (the block's text on the page) has that `base` did not and where `base`'s words were
|
|
9
|
+
* taken out of it: { ins: [[from, to]] (ranges of `now`), cuts: [{ at, text }] (a place in `now`,
|
|
10
|
+
* what was taken out there; one where several runs meet) }.
|
|
11
|
+
*/
|
|
12
|
+
export function wordMarks(base, now) {
|
|
13
|
+
const ins = [];
|
|
14
|
+
const cuts = [];
|
|
15
|
+
let at = 0;
|
|
16
|
+
for (const { tag, text } of wordDiff(base, now)) {
|
|
17
|
+
if (tag === "del") {
|
|
18
|
+
const last = cuts.at(-1);
|
|
19
|
+
if (last?.at === at) last.text += text;
|
|
20
|
+
else cuts.push({ at, text });
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (tag === "ins") ins.push([at, at + text.length]);
|
|
24
|
+
at += text.length;
|
|
25
|
+
}
|
|
26
|
+
return { ins, cuts };
|
|
27
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Pasted colors onto the page's nine (feishu-lite model/color-match.ts and css-color.ts, after Feishu
|
|
2
2
|
// 855470 · bn / mG / WW, 99121 · FB, 768176 CIEDE2000; Notion keeps only its own colors). Pure, no
|
|
3
3
|
// DOM. A color is given as the CSS text of a style (named, #hex, rgb[a](), hsl[a]()).
|
|
4
|
-
// exact a color equal to one of the page's (the kit's light values
|
|
5
|
-
// doc-highlight-*) is that one: what a page whose styles are not meant (any web page)
|
|
4
|
+
// exact a color equal to one of the page's (the kit's light values: doc-text-*, and
|
|
5
|
+
// doc-highlight-* as a block's fill or a run of words') is that one: what a page whose styles are not meant (any web page)
|
|
6
6
|
// keeps
|
|
7
7
|
// nearest for sources whose styles are meant (Word, Google Docs, Notion): text — too dark (HSV
|
|
8
8
|
// v ≤ 0.3) none, unsaturated (s < 0.08) gray, a pure CSS color by a fixed table, else the
|
|
@@ -14,7 +14,7 @@ import { BODY, COLORS } from "../../../../shared/colors.mjs";
|
|
|
14
14
|
|
|
15
15
|
// The page's light values (src/shared/colors.mjs).
|
|
16
16
|
const TEXT = COLORS.map(({ name, text }) => [name, text[0]]);
|
|
17
|
-
const BACKGROUND = COLORS.
|
|
17
|
+
const BACKGROUND = COLORS.flatMap(({ name, fill, mark }) => [[name, fill[0]], [name, mark[0]]]);
|
|
18
18
|
const BODY_TEXT = BODY.text[0];
|
|
19
19
|
const BODY_BACKGROUND = BODY.background[0];
|
|
20
20
|
|
|
@@ -332,7 +332,11 @@ function equationOf(el) {
|
|
|
332
332
|
return el.getAttribute(ATTR.equation) || el.getAttribute(ATTR.inlineEquation) || annotation || /^\$\$([\s\S]+?)\$\$\s*$/.exec(text)?.[1].trim() || /^\$([\s\S]+?)\$$/.exec(text)?.[1].trim();
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
-
|
|
335
|
+
// Besides Notion's: a picture in a table's cell (`pictures`) is a token of its own, PICTURE annotated
|
|
336
|
+
// ["img", its address, its alt, "", its width] (inline.mjs's pieces, the width of an <img width>), which
|
|
337
|
+
// a cell of the page shows (to-blocks.mjs richHtml).
|
|
338
|
+
const PICTURE = String.fromCodePoint(0xfffc);
|
|
339
|
+
function richTextOf(node, { stripText = false, stripSurroundingWhitespace = false, ignoreCodeBlock = false, preserveLineBreaks = false, pictures = false } = {}) {
|
|
336
340
|
const doc = node.ownerDocument;
|
|
337
341
|
if (!stripText) {
|
|
338
342
|
// Paragraphs, headings and items as lines with their bullets (the structure kept in one text).
|
|
@@ -354,17 +358,18 @@ function richTextOf(node, { stripText = false, stripSurroundingWhitespace = fals
|
|
|
354
358
|
all.push(n);
|
|
355
359
|
for (const child of n.childNodes) walk(child);
|
|
356
360
|
})(node);
|
|
357
|
-
const
|
|
361
|
+
const picture = (n) => pictures && tagOf(n) === "img" && Boolean(n.getAttribute("src"));
|
|
362
|
+
const nodes = all.filter((n) => (n.nodeType !== 3 ? (preserveLineBreaks && tagOf(n) === "br") || picture(n) : !(stripText && BLANK_LINES.test(n.data))));
|
|
358
363
|
const tokens = [];
|
|
359
364
|
const seenEquations = new Set();
|
|
360
365
|
nodes.forEach((n, i) => {
|
|
361
|
-
let text = n.nodeType === 3 ? n.data : "\n";
|
|
366
|
+
let text = n.nodeType === 3 ? n.data : picture(n) ? PICTURE : "\n";
|
|
362
367
|
if (stripText) text = text.replace(/\[ \] /g, "").replace(/\[x\] /g, "").replace(/^[-*•]\s?/g, "").replace(/(\s)+/g, "$1");
|
|
363
368
|
if (i === 0 && stripSurroundingWhitespace && !node.hasAttribute?.("confluenceTabSpaces")) text = text.trimStart();
|
|
364
369
|
text = clean(text);
|
|
365
370
|
if (i === nodes.length - 1 && stripSurroundingWhitespace) text = text.trimEnd();
|
|
366
371
|
const up = ancestors(n).filter((a) => a.nodeType === 1);
|
|
367
|
-
const annotations = [];
|
|
372
|
+
const annotations = picture(n) ? [["img", n.getAttribute("src"), n.getAttribute("alt") ?? "", "", n.getAttribute("width") ?? ""]] : [];
|
|
368
373
|
if (!stripText && up.some((a) => HEADINGS.includes(tagOf(a)))) annotations.push(["b"]);
|
|
369
374
|
if (up.some((a) => tagOf(a) === "strong")) annotations.push(["b"]);
|
|
370
375
|
if (up.some((a) => tagOf(a) === "em")) annotations.push(["i"]);
|
|
@@ -526,7 +531,8 @@ const int = (value, fallback) => {
|
|
|
526
531
|
};
|
|
527
532
|
|
|
528
533
|
// 760354 table: row and column spans spread into empty cells; a first row all th a header row, every
|
|
529
|
-
// row starting with a th a header column (both: the side with more th's).
|
|
534
|
+
// row starting with a th a header column (both: the side with more th's). Its cells' pictures kept
|
|
535
|
+
// (richTextOf `pictures`, besides Notion's).
|
|
530
536
|
function tableBlock(node) {
|
|
531
537
|
const rows = [...node.querySelectorAll("tr")].filter((row) => row.closest("table") === node);
|
|
532
538
|
let headerRow = false;
|
|
@@ -550,7 +556,7 @@ function tableBlock(node) {
|
|
|
550
556
|
while (taken[r][c]) c++;
|
|
551
557
|
const rowSpan = int(cell.getAttribute("rowspan"), 1);
|
|
552
558
|
const colSpan = int(cell.getAttribute("colspan"), 1);
|
|
553
|
-
grid[r][c] = richTextOf(cell, { stripSurroundingWhitespace: true, preserveLineBreaks: true });
|
|
559
|
+
grid[r][c] = richTextOf(cell, { stripSurroundingWhitespace: true, preserveLineBreaks: true, pictures: true });
|
|
554
560
|
taken[r][c] = true;
|
|
555
561
|
for (let dr = 0; dr < rowSpan && r + dr < rows.length; dr++) {
|
|
556
562
|
for (let dc = 0; dc < colSpan; dc++) {
|
|
@@ -716,6 +722,23 @@ function blockOf(node) {
|
|
|
716
722
|
|
|
717
723
|
const blocksOf = (nodes) => nodes.flatMap(blockOf);
|
|
718
724
|
|
|
725
|
+
/**
|
|
726
|
+
* Besides Notion's (another program's cells pasted into a table's: page/clipboard/ cellsOf): the
|
|
727
|
+
* HTML's table, when it holds one and no words outside it, as rows of rich text, its cells' as
|
|
728
|
+
* tableBlock reads them (spans spread into empty cells, pictures kept); a table of one column stays
|
|
729
|
+
* one (normalizing makes Notion's paragraphs of it). Null for anything else.
|
|
730
|
+
*/
|
|
731
|
+
export function tableRows(root, options = {}) {
|
|
732
|
+
const tables = [...root.querySelectorAll("table")].filter((table) => !table.parentElement?.closest("table"));
|
|
733
|
+
const outside = (n) => (n.nodeType === 3 ? n.data.trim() !== "" : n.nodeType === 1 && tagOf(n) !== "table" && !REMOVED.has(tagOf(n)) && [...n.childNodes].some(outside));
|
|
734
|
+
if (tables.length !== 1 || [...root.childNodes].some(outside)) return null;
|
|
735
|
+
tables[0].classList.add("simple-table"); // kept a table (firstPass)
|
|
736
|
+
normalizeHTML(root, { ...options, inline: false });
|
|
737
|
+
const table = root.querySelector("table");
|
|
738
|
+
const block = table ? tableBlock(table) : null;
|
|
739
|
+
return block ? block.children.map((row) => block.props.table_block_column_order.map((column) => row.props.cells[column] ?? [])) : null;
|
|
740
|
+
}
|
|
741
|
+
|
|
719
742
|
// ---------- entry points ----------
|
|
720
743
|
|
|
721
744
|
/** 760354 U: the HTML's blocks. */
|
|
@@ -27,8 +27,14 @@
|
|
|
27
27
|
// and a bare a@b.c (GFM's); $$…$$ amid words a display formula (annotated display too, which
|
|
28
28
|
// markdown.mjs makes a block of its own in a paragraph).
|
|
29
29
|
// Besides Notion's annotations, these three: sup (superscript), sub (subscript) and display.
|
|
30
|
+
//
|
|
31
|
+
// Yuque's Markdown (its toolbar's 复制为 Markdown, read as a whole document with `yuque`: yuque.mjs)
|
|
32
|
+
// reads two more: a formula as Yuque writes one, $ … $ with a space inside each $ (Pandoc's rule
|
|
33
|
+
// refuses those), and the colors of a <font style="color: …; background-color: …"> (or a <span> so
|
|
34
|
+
// styled) as the page's nearest (colors.mjs: Yuque's colors are meant, as Word's are).
|
|
30
35
|
|
|
31
36
|
import { addressOf } from "../../links/address.mjs";
|
|
37
|
+
import { backgroundColor, textColor } from "./colors.mjs";
|
|
32
38
|
|
|
33
39
|
const WORD = /[\p{L}\p{N}]/u;
|
|
34
40
|
const TRAILING = /[.,:;!?'")\]}>,。:;!?、)】」』]+$/u;
|
|
@@ -100,6 +106,20 @@ const attribute = (tag, name) => {
|
|
|
100
106
|
};
|
|
101
107
|
const decodeEntities = (text) => text.replace(/&(#\d{1,7}|#[xX][0-9a-fA-F]{1,6}|[A-Za-z][A-Za-z0-9]{1,31});/g, (all, name) => entity(name) ?? all);
|
|
102
108
|
|
|
109
|
+
// Yuque's Markdown: $ … $ with a space inside each $ a formula (its words trimmed), and a <font> or
|
|
110
|
+
// <span> whose style colors its words those colors, the nearest of the page's (none: its words alone).
|
|
111
|
+
const styleValue = (style, name) => new RegExp(`(?:^|;)\\s*${name}\\s*:\\s*([^;]+)`, "i").exec(style ?? "")?.[1].trim() ?? "";
|
|
112
|
+
const YUQUE_RULES = [
|
|
113
|
+
[/^\$ +([^$\n]*?[^\s$]) +\$(?!\d)/, (m) => ["⁍", ["e", m[1]], false]],
|
|
114
|
+
[/^<(font|span)\s([^<>]*)>([\s\S]*?)<\/\1\s*>/i, (m) => {
|
|
115
|
+
const style = attribute(`<${m[1]} ${m[2]}>`, "style");
|
|
116
|
+
const text = textColor(styleValue(style, "color"), { nearest: true });
|
|
117
|
+
const background = backgroundColor(styleValue(style, "background(?:-color)?"), { nearest: true });
|
|
118
|
+
const colors = [text, background].filter(Boolean).map((name) => ["h", name]);
|
|
119
|
+
return [m[3], colors.length ? colors : null, true];
|
|
120
|
+
}],
|
|
121
|
+
];
|
|
122
|
+
|
|
103
123
|
/** A picture's piece: U+FFFC annotated ["img", its address, its alt, its title]. */
|
|
104
124
|
const picture = (src, alt, title) => ["\u{FFFC}", ["img", src.replace(/^<|>$/g, ""), alt ?? "", title ?? ""], false];
|
|
105
125
|
const unquoted = (text) => (text ? text.slice(1, -1) : "");
|
|
@@ -123,6 +143,7 @@ function documentRules(doc) {
|
|
|
123
143
|
}
|
|
124
144
|
};
|
|
125
145
|
const rules = [
|
|
146
|
+
...(doc.yuque ? YUQUE_RULES : []),
|
|
126
147
|
RULES[0], RULES[1],
|
|
127
148
|
// $$ … $$ amid words: a display formula (markdown.mjs makes it a block of its own in a paragraph).
|
|
128
149
|
[/^\$\$(.+?)\$\$/, (m) => ["⁍", [["e", m[1].trim()], ["display"]], false]],
|
|
@@ -185,6 +206,17 @@ export const parseInlineMath = (text) => parseInline(text, MATH_RULES);
|
|
|
185
206
|
*/
|
|
186
207
|
export const parseInlineMarkdown = (text, doc = null) => parseInline(text, doc ? (doc.rules ??= documentRules(doc)) : RULES); // a document's made once
|
|
187
208
|
|
|
209
|
+
// A table cell's pictures, a linked one's too (its link left: the cell's picture is what it shows),
|
|
210
|
+
// ahead of Notion's rules (a paste's Markdown table: 单元格里的图片, which a cell holds).
|
|
211
|
+
const CELL_RULES = [
|
|
212
|
+
[new RegExp(String.raw`^\[!\[([^\]]*)\]${LINK_TARGET}\]${LINK_TARGET}`), (m) => picture(m[2], m[1], unquoted(m[3]))],
|
|
213
|
+
[new RegExp(String.raw`^!\[([^\]]*)\]${LINK_TARGET}`), (m) => picture(m[2], m[1], unquoted(m[3]))],
|
|
214
|
+
...RULES,
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
/** A pasted Markdown table's cell as rich text: Notion's rules, and its pictures  (inline.mjs's picture pieces). */
|
|
218
|
+
export const parseCellMarkdown = (text) => parseInline(text, CELL_RULES);
|
|
219
|
+
|
|
188
220
|
/** HTML entities in text as their characters (& —), one it does not know as written. */
|
|
189
221
|
export { decodeEntities };
|
|
190
222
|
|