@heycys/gallery 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +50 -2
- package/THIRD-PARTY-NOTICES.md +3303 -0
- package/assets/writing-preferences.md +107 -0
- package/bin/gallery.mjs +10 -0
- package/browser/editor/components/bookmark/icons.mjs +6 -0
- package/browser/editor/components/bookmark/index.mjs +80 -0
- package/browser/editor/components/bookmark/page.mjs +147 -0
- package/browser/editor/components/builders.mjs +19 -0
- package/browser/editor/components/callout/index.mjs +64 -0
- package/browser/editor/components/code/index.mjs +327 -0
- package/browser/editor/components/code/page.mjs +561 -0
- package/browser/editor/components/colors.mjs +50 -0
- package/browser/editor/components/columns/index.mjs +104 -0
- package/browser/editor/components/columns/page.mjs +310 -0
- package/browser/editor/components/details/index.mjs +73 -0
- package/browser/editor/components/details/page.mjs +86 -0
- package/browser/editor/components/dialog/index.mjs +84 -0
- package/browser/editor/components/dialog/page.mjs +201 -0
- package/browser/editor/components/divider/index.mjs +48 -0
- package/browser/editor/components/embed/icons.mjs +11 -0
- package/browser/editor/components/embed/index.mjs +123 -0
- package/browser/editor/components/embed/page.mjs +309 -0
- package/browser/editor/components/figure/index.mjs +87 -0
- package/browser/editor/components/figure/page.mjs +42 -0
- package/browser/editor/components/file/icons.mjs +14 -0
- package/browser/editor/components/file/index.mjs +77 -0
- package/browser/editor/components/file/page.mjs +114 -0
- package/browser/editor/components/flowchart/add.mjs +123 -0
- package/browser/editor/components/flowchart/index.mjs +246 -0
- package/browser/editor/components/flowchart/page.mjs +453 -0
- package/browser/editor/components/heading/index.mjs +53 -0
- package/browser/editor/components/heading/page.mjs +6 -0
- package/browser/editor/components/highlight/index.mjs +63 -0
- package/browser/editor/components/icon/index.mjs +57 -0
- package/browser/editor/components/icon/page.mjs +286 -0
- package/browser/editor/components/icons.mjs +48 -0
- package/browser/editor/components/image/crop.mjs +189 -0
- package/browser/editor/components/image/index.mjs +104 -0
- package/browser/editor/components/image/page.mjs +385 -0
- package/browser/editor/components/image/viewer.mjs +213 -0
- package/browser/editor/components/installed/index.mjs +179 -0
- package/browser/editor/components/installed/page.mjs +523 -0
- package/browser/editor/components/installed/served.mjs +35 -0
- package/browser/editor/components/kit.mjs +67 -0
- package/browser/editor/components/list/index.mjs +194 -0
- package/browser/editor/components/list/join.mjs +68 -0
- package/browser/editor/components/list/numbers.mjs +107 -0
- package/browser/editor/components/list/page.mjs +632 -0
- package/browser/editor/components/math/index.mjs +88 -0
- package/browser/editor/components/math/page.mjs +236 -0
- package/browser/editor/components/math/tex-logo.mjs +6 -0
- package/browser/editor/components/media/icons.mjs +19 -0
- package/browser/editor/components/media/page.mjs +192 -0
- package/browser/editor/components/media/parts.mjs +60 -0
- package/browser/editor/components/media/size.mjs +20 -0
- package/browser/editor/components/media/toolbar.mjs +37 -0
- package/browser/editor/components/media/write.mjs +7 -0
- package/browser/editor/components/pages.mjs +46 -0
- package/browser/editor/components/paragraph/index.mjs +43 -0
- package/browser/editor/components/paragraph/page.mjs +52 -0
- package/browser/editor/components/placeholder-bar.mjs +17 -0
- package/browser/editor/components/placeholder.mjs +128 -0
- package/browser/editor/components/quote/index.mjs +33 -0
- package/browser/editor/components/registry.mjs +859 -0
- package/browser/editor/components/rows.mjs +16 -0
- package/browser/editor/components/section/index.mjs +42 -0
- package/browser/editor/components/section/page.mjs +141 -0
- package/browser/editor/components/set-apart.mjs +24 -0
- package/browser/editor/components/sheets/index.mjs +137 -0
- package/browser/editor/components/sheets/page.mjs +227 -0
- package/browser/editor/components/sheets/pills.mjs +226 -0
- package/browser/editor/components/table/grid.mjs +73 -0
- package/browser/editor/components/table/index.mjs +308 -0
- package/browser/editor/components/table/page.mjs +683 -0
- package/browser/editor/components/table/slots.mjs +41 -0
- package/browser/editor/components/widget/index.mjs +50 -0
- package/browser/editor/page/annotate/anchors.mjs +230 -0
- package/browser/editor/page/annotate/card.mjs +102 -0
- package/browser/editor/page/annotate/index.mjs +1656 -0
- package/browser/editor/page/at-menu/index.mjs +317 -0
- package/browser/editor/page/autosave.mjs +1023 -0
- package/browser/editor/page/beside.mjs +21 -0
- package/browser/editor/page/block-info.mjs +63 -0
- package/browser/editor/page/block-menu/colors.mjs +84 -0
- package/browser/editor/page/block-menu/index.mjs +217 -0
- package/browser/editor/page/blocks.mjs +255 -0
- package/browser/editor/page/caret.mjs +682 -0
- package/browser/editor/page/changes/bar.mjs +102 -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/chip-fills.mjs +126 -0
- package/browser/editor/page/clipboard/import/colors.mjs +192 -0
- package/browser/editor/page/clipboard/import/html.mjs +792 -0
- package/browser/editor/page/clipboard/import/inline.mjs +232 -0
- package/browser/editor/page/clipboard/import/languages.mjs +42 -0
- package/browser/editor/page/clipboard/import/markdown.mjs +760 -0
- package/browser/editor/page/clipboard/import/math.mjs +100 -0
- package/browser/editor/page/clipboard/import/office.mjs +245 -0
- package/browser/editor/page/clipboard/import/read.mjs +120 -0
- package/browser/editor/page/clipboard/import/rich.mjs +29 -0
- package/browser/editor/page/clipboard/import/to-blocks.mjs +290 -0
- package/browser/editor/page/clipboard/index.mjs +816 -0
- package/browser/editor/page/clipboard/own/blocks.mjs +211 -0
- package/browser/editor/page/clipboard/own/chart-keys.mjs +58 -0
- package/browser/editor/page/clipboard/own/describe.mjs +124 -0
- package/browser/editor/page/clipboard/own/export.mjs +167 -0
- package/browser/editor/page/clipboard/own/ids.mjs +39 -0
- package/browser/editor/page/clipboard/own/index.mjs +13 -0
- package/browser/editor/page/clipboard/own/rules.mjs +44 -0
- package/browser/editor/page/clipboard/own/selection.mjs +159 -0
- package/browser/editor/page/clipboard/own/writers.mjs +315 -0
- package/browser/editor/page/columns/index.mjs +360 -0
- package/browser/editor/page/commit.mjs +1813 -0
- package/browser/editor/page/conflicts.mjs +249 -0
- package/browser/editor/page/convert.mjs +831 -0
- package/browser/editor/page/core.mjs +1693 -0
- package/browser/editor/page/drag/drop.mjs +307 -0
- package/browser/editor/page/drag/index.mjs +351 -0
- package/browser/editor/page/drag/preview.mjs +126 -0
- package/browser/editor/page/edge-scroll.mjs +50 -0
- package/browser/editor/page/editor.mjs +1780 -0
- package/browser/editor/page/emoji-picker/emoji-tab.mjs +287 -0
- package/browser/editor/page/emoji-picker/glyph-html.mjs +26 -0
- package/browser/editor/page/emoji-picker/grid.mjs +81 -0
- package/browser/editor/page/emoji-picker/icon-tab.mjs +217 -0
- package/browser/editor/page/emoji-picker/icons.mjs +31 -0
- package/browser/editor/page/emoji-picker/index.mjs +166 -0
- package/browser/editor/page/emoji-picker/styles.mjs +161 -0
- package/browser/editor/page/emoji-picker/support.mjs +204 -0
- package/browser/editor/page/emoji-picker/upload.mjs +236 -0
- package/browser/editor/page/export-report.mjs +23 -0
- package/browser/editor/page/fills.mjs +62 -0
- package/browser/editor/page/find/index.mjs +107 -0
- package/browser/editor/page/flags.mjs +70 -0
- 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 +449 -0
- package/browser/editor/page/format-bar/brush.mjs +77 -0
- package/browser/editor/page/format-bar/colors.mjs +46 -0
- package/browser/editor/page/format-bar/index.mjs +404 -0
- package/browser/editor/page/formula/index.mjs +236 -0
- package/browser/editor/page/formula/panel.mjs +336 -0
- package/browser/editor/page/formula/symbols.mjs +156 -0
- package/browser/editor/page/frame.mjs +74 -0
- package/browser/editor/page/frames.mjs +196 -0
- package/browser/editor/page/geometry.mjs +402 -0
- package/browser/editor/page/gesture.mjs +45 -0
- package/browser/editor/page/handle/index.mjs +650 -0
- package/browser/editor/page/handle-sizes.mjs +14 -0
- package/browser/editor/page/hints/index.mjs +84 -0
- package/browser/editor/page/history.mjs +401 -0
- package/browser/editor/page/insert/index.mjs +256 -0
- package/browser/editor/page/kept.mjs +38 -0
- package/browser/editor/page/links/address.mjs +40 -0
- package/browser/editor/page/links/index.mjs +866 -0
- package/browser/editor/page/links/pages.mjs +131 -0
- package/browser/editor/page/links/views.mjs +369 -0
- package/browser/editor/page/long-runs.mjs +75 -0
- package/browser/editor/page/look.mjs +77 -0
- package/browser/editor/page/made.mjs +24 -0
- package/browser/editor/page/margin.mjs +373 -0
- package/browser/editor/page/markdown/index.mjs +88 -0
- package/browser/editor/page/markdown/rules.mjs +33 -0
- package/browser/editor/page/marks.mjs +377 -0
- package/browser/editor/page/media-menu/index.mjs +158 -0
- package/browser/editor/page/menu.mjs +544 -0
- package/browser/editor/page/merge.mjs +124 -0
- package/browser/editor/page/notices.mjs +142 -0
- package/browser/editor/page/offered.mjs +32 -0
- package/browser/editor/page/outline/folds.mjs +53 -0
- package/browser/editor/page/outline/index.mjs +783 -0
- package/browser/editor/page/outline/list.mjs +184 -0
- package/browser/editor/page/outline/read.mjs +201 -0
- package/browser/editor/page/outline/strip.mjs +287 -0
- package/browser/editor/page/outline/tree.mjs +248 -0
- package/browser/editor/page/overlay-layer.mjs +227 -0
- package/browser/editor/page/overlays.mjs +205 -0
- package/browser/editor/page/own.mjs +28 -0
- package/browser/editor/page/pads.mjs +71 -0
- package/browser/editor/page/page-objects.mjs +105 -0
- package/browser/editor/page/panel.mjs +65 -0
- package/browser/editor/page/placement.mjs +58 -0
- package/browser/editor/page/post.mjs +41 -0
- package/browser/editor/page/present-links.mjs +50 -0
- package/browser/editor/page/quiet.mjs +48 -0
- package/browser/editor/page/resize/index.mjs +327 -0
- package/browser/editor/page/select-all/index.mjs +262 -0
- package/browser/editor/page/selection/delete.mjs +61 -0
- package/browser/editor/page/selection/index.mjs +164 -0
- package/browser/editor/page/selection/marquee.mjs +174 -0
- package/browser/editor/page/session.mjs +168 -0
- package/browser/editor/page/slash-menu/index.mjs +291 -0
- package/browser/editor/page/storage.mjs +48 -0
- package/browser/editor/page/sync-state.mjs +267 -0
- package/browser/editor/page/table/aligns.mjs +29 -0
- package/browser/editor/page/table/cell-bar.mjs +141 -0
- package/browser/editor/page/table/cells.mjs +527 -0
- package/browser/editor/page/table/icons.mjs +40 -0
- package/browser/editor/page/table/index.mjs +990 -0
- package/browser/editor/page/table/lists.mjs +187 -0
- package/browser/editor/page/table/widths.mjs +313 -0
- package/browser/editor/page/tex.mjs +32 -0
- package/browser/editor/page/text-select/index.mjs +671 -0
- package/browser/editor/page/tooltip.mjs +98 -0
- package/browser/editor/page/type-grid.mjs +83 -0
- package/browser/editor/page/typing/code-edges.mjs +274 -0
- package/browser/editor/page/typing/index.mjs +282 -0
- package/browser/editor/page/typing/leave.mjs +68 -0
- package/browser/editor/page/ui.mjs +160 -0
- package/browser/shared/annotations.mjs +569 -0
- package/browser/shared/code-folds.mjs +14 -0
- package/browser/shared/code-languages.mjs +70 -0
- package/browser/shared/code-lines.mjs +30 -0
- package/browser/shared/colors.mjs +30 -0
- package/browser/shared/component-catalog.mjs +573 -0
- package/browser/shared/components/bookmark.mjs +26 -0
- package/browser/shared/components/callout.mjs +9 -0
- package/browser/shared/components/chart.mjs +20 -0
- package/browser/shared/components/code.mjs +37 -0
- package/browser/shared/components/columns.mjs +16 -0
- package/browser/shared/components/details.mjs +15 -0
- package/browser/shared/components/dialog.mjs +28 -0
- package/browser/shared/components/diff.mjs +18 -0
- package/browser/shared/components/divider.mjs +6 -0
- package/browser/shared/components/embed.mjs +25 -0
- package/browser/shared/components/figure.mjs +14 -0
- package/browser/shared/components/file.mjs +23 -0
- package/browser/shared/components/heading.mjs +6 -0
- package/browser/shared/components/highlight.mjs +9 -0
- package/browser/shared/components/icon.mjs +18 -0
- package/browser/shared/components/image.mjs +39 -0
- package/browser/shared/components/index.mjs +396 -0
- package/browser/shared/components/installed.mjs +232 -0
- package/browser/shared/components/list.mjs +146 -0
- package/browser/shared/components/math.mjs +49 -0
- package/browser/shared/components/mention.mjs +33 -0
- package/browser/shared/components/page.mjs +46 -0
- package/browser/shared/components/paragraph.mjs +9 -0
- package/browser/shared/components/quote.mjs +6 -0
- package/browser/shared/components/section.mjs +8 -0
- package/browser/shared/components/sheets.mjs +80 -0
- package/browser/shared/components/state.mjs +20 -0
- package/browser/shared/components/table.mjs +49 -0
- package/browser/shared/components/text.mjs +14 -0
- package/browser/shared/components/widget.mjs +10 -0
- package/browser/shared/copy-ids.mjs +72 -0
- package/browser/shared/css-references.mjs +110 -0
- package/browser/shared/document-look.mjs +178 -0
- package/browser/shared/emoji/custom.mjs +91 -0
- package/browser/shared/emoji/data/LICENSE-lucide.txt +43 -0
- package/browser/shared/emoji/data/LICENSE-mingcute.txt +202 -0
- package/browser/shared/emoji/data/LICENSE-tabler.txt +21 -0
- package/browser/shared/emoji/data/README.md +28 -0
- package/browser/shared/emoji/data/categories.json +1 -0
- package/browser/shared/emoji/data/icons.json +1 -0
- package/browser/shared/emoji/data/keywords-en.json +1 -0
- package/browser/shared/emoji/data/keywords-zh.json +1 -0
- package/browser/shared/emoji/data/names.json +1 -0
- package/browser/shared/emoji/data/positions.json +1 -0
- package/browser/shared/emoji/data/twemoji-index.json +1 -0
- package/browser/shared/emoji/data/twemoji-svg.bin +0 -0
- package/browser/shared/emoji/data.mjs +194 -0
- package/browser/shared/emoji/emoji.mjs +38 -0
- package/browser/shared/emoji/glyphs.mjs +134 -0
- package/browser/shared/emoji/icon-value.mjs +91 -0
- package/browser/shared/escape.mjs +20 -0
- package/browser/shared/export-wrap.mjs +89 -0
- package/browser/shared/files.mjs +33 -0
- package/browser/shared/html-tree.mjs +59 -0
- package/browser/shared/http.mjs +22 -0
- package/browser/shared/i18n/en.mjs +1223 -0
- package/browser/shared/i18n/index.mjs +132 -0
- package/browser/shared/ids.mjs +24 -0
- package/browser/shared/import-types.mjs +23 -0
- package/browser/shared/inline-spacing.mjs +97 -0
- package/browser/shared/layers.mjs +42 -0
- package/browser/shared/long-runs.mjs +39 -0
- package/browser/shared/media.mjs +162 -0
- package/browser/shared/new-names.mjs +67 -0
- package/browser/shared/number-reading.mjs +92 -0
- package/browser/shared/old-names.mjs +143 -0
- package/browser/shared/outline.mjs +194 -0
- package/browser/shared/page-address.mjs +140 -0
- package/browser/shared/page-links.mjs +86 -0
- package/browser/shared/paths.mjs +73 -0
- package/browser/shared/preferences.mjs +116 -0
- package/browser/shared/preview-server.mjs +247 -0
- package/browser/shared/qa-levels.mjs +93 -0
- package/browser/shared/reading-place.mjs +91 -0
- package/browser/shared/renamed-storage.mjs +220 -0
- package/browser/shared/reports.mjs +46 -0
- package/browser/shared/search.mjs +85 -0
- package/browser/shared/session.mjs +77 -0
- package/browser/shared/table-chart.mjs +113 -0
- package/browser/shared/table-hides.mjs +120 -0
- package/browser/shared/table-slots.mjs +75 -0
- package/browser/shared/words.mjs +23 -0
- package/browser/shared/workspace-look.mjs +91 -0
- package/browser/shared/workspace.mjs +535 -0
- package/browser/shared/writing-preferences.mjs +68 -0
- package/browser/shared/zoom.mjs +57 -0
- package/dist/chunk-2B5E4CDJ.mjs +2 -0
- package/dist/chunk-342HXE3Q.mjs +2 -0
- package/dist/chunk-3HIRPVLU.mjs +2 -0
- package/dist/chunk-43B75J5T.mjs +2 -0
- package/dist/chunk-4FS7Z7WR.mjs +2 -0
- package/dist/chunk-4K5KC6V2.mjs +2 -0
- package/dist/chunk-5L7RYZCL.mjs +2 -0
- package/dist/chunk-5MHMDLZD.mjs +4 -0
- package/dist/chunk-5ZKJ3H4P.mjs +8 -0
- package/dist/chunk-64K7IPLO.mjs +255 -0
- package/dist/chunk-6QXGZM36.mjs +8 -0
- package/dist/chunk-6RGJOMJP.mjs +16 -0
- package/dist/chunk-742D2WWJ.mjs +19 -0
- package/dist/chunk-7DTINW6U.mjs +48 -0
- package/dist/chunk-A55HN5OK.mjs +2 -0
- package/dist/chunk-AGDILNWB.mjs +2 -0
- package/dist/chunk-AJ73XJF3.mjs +2 -0
- package/dist/chunk-AUZGSZJH.mjs +13 -0
- package/dist/chunk-BFE45AKL.mjs +2 -0
- package/dist/chunk-BGGDRNYQ.mjs +10 -0
- package/dist/chunk-BXO2ZY5P.mjs +2 -0
- package/dist/chunk-C564NU2H.mjs +77 -0
- package/dist/chunk-CEH4MRCC.mjs +2 -0
- package/dist/chunk-CY2FNNAB.mjs +16 -0
- package/dist/chunk-DFUDV4LX.mjs +2 -0
- package/dist/chunk-DKXG4XDG.mjs +2 -0
- package/dist/chunk-E7LWZRXY.mjs +4 -0
- package/dist/chunk-EZQ34M3F.mjs +124 -0
- package/dist/chunk-EZY3WC6Z.mjs +15 -0
- package/dist/chunk-FDLXYYG4.mjs +4 -0
- package/dist/chunk-FUKQNOQS.mjs +9 -0
- package/dist/chunk-GB5SOYQJ.mjs +7 -0
- package/dist/chunk-GRAXKKG4.mjs +2 -0
- package/dist/chunk-HYMEEXKN.mjs +4 -0
- package/dist/chunk-IVDLMMBD.mjs +2 -0
- package/dist/chunk-JPOSLGOC.mjs +6 -0
- package/dist/chunk-JVHHHGEA.mjs +3 -0
- package/dist/chunk-L3QKH4OK.mjs +26 -0
- package/dist/chunk-LAE5NQ4B.mjs +2 -0
- package/dist/chunk-LCTHTZIL.mjs +960 -0
- package/dist/chunk-LEF6DRCK.mjs +59 -0
- package/dist/chunk-LKX55H76.mjs +2 -0
- package/dist/chunk-LS4F7JUM.mjs +2 -0
- package/dist/chunk-MAFIGVXY.mjs +2 -0
- package/dist/chunk-NO5NJCHO.mjs +2 -0
- package/dist/chunk-NQPVAU63.mjs +2 -0
- package/dist/chunk-NSKUTQ5J.mjs +5 -0
- package/dist/chunk-O35FIXRB.mjs +2 -0
- package/dist/chunk-P2CAZPDP.mjs +3 -0
- package/dist/chunk-PL6GHLGD.mjs +15 -0
- package/dist/chunk-QAIHRH3I.mjs +13 -0
- package/dist/chunk-QJIR2BLP.mjs +6 -0
- package/dist/chunk-QR6A54KJ.mjs +3 -0
- package/dist/chunk-QUPLVPB2.mjs +7 -0
- package/dist/chunk-R7BNENLY.mjs +4 -0
- package/dist/chunk-S6O4UHLC.mjs +2 -0
- package/dist/chunk-SGJWQKEI.mjs +2 -0
- package/dist/chunk-SYGN7GLU.mjs +2 -0
- package/dist/chunk-TMYZB6AV.mjs +2 -0
- package/dist/chunk-TX6JH7TR.mjs +2 -0
- package/dist/chunk-TYK6VNAB.mjs +10 -0
- package/dist/chunk-U3SSPL4K.mjs +8 -0
- package/dist/chunk-U6KNPJPR.mjs +2 -0
- package/dist/chunk-UALRNVSE.mjs +4 -0
- package/dist/chunk-UH4SIXTR.mjs +2 -0
- package/dist/chunk-UMHUSOPJ.mjs +2 -0
- package/dist/chunk-V3HXVQEM.mjs +2 -0
- package/dist/chunk-V5JTW2LH.mjs +27 -0
- package/dist/chunk-V5VXUJKG.mjs +2 -0
- package/dist/chunk-V6XZ4VIR.mjs +2 -0
- package/dist/chunk-VBXMADMP.mjs +2 -0
- package/dist/chunk-VNV55RUA.mjs +2 -0
- package/dist/chunk-VPD2PS35.mjs +2 -0
- package/dist/chunk-W3BGBJQW.mjs +2 -0
- package/dist/chunk-W4VKN3GF.mjs +7 -0
- package/dist/chunk-W5BXXPDJ.mjs +3 -0
- package/dist/chunk-W7XHE4CT.mjs +2 -0
- package/dist/chunk-XNROSH2T.mjs +4 -0
- package/dist/chunk-XUNHRCOG.mjs +6 -0
- package/dist/chunk-Y34NR5JL.mjs +2 -0
- package/dist/chunk-Y6RLRPG3.mjs +3 -0
- package/dist/chunk-YEY3RSFQ.mjs +2 -0
- package/dist/cli.mjs +2 -0
- package/dist/server.mjs +2 -0
- package/dist/worker.mjs +5 -0
- package/kit/charts.js +355 -0
- package/kit/code.js +164 -0
- package/kit/dialogs.js +157 -0
- package/kit/math.js +2004 -0
- package/kit/report.css +2932 -0
- package/kit/runtime.js +1782 -0
- package/kit/sheets.js +123 -0
- package/kit/state.js +217 -0
- package/kit/tables.js +1499 -0
- package/kit/tokens.js +29 -0
- package/kit/ui.js +658 -0
- package/package.json +41 -4
- package/release.json +25 -0
- package/sdk/column-widths.d.ts +56 -0
- package/sdk/doc-charts.d.ts +82 -0
- package/sdk/doc-code.d.ts +28 -0
- package/sdk/doc-dialogs.d.ts +4 -0
- package/sdk/doc-kit.d.ts +147 -0
- package/sdk/doc-math.d.ts +3 -0
- package/sdk/doc-sheets.d.ts +15 -0
- package/sdk/doc-state.d.ts +41 -0
- package/sdk/doc-tables.d.ts +24 -0
- package/sdk/doc-tokens.d.ts +22 -0
- package/sdk/index.d.ts +30 -0
- package/skill/SKILL.md +150 -0
- package/skill/agents/openai.yaml +5 -0
- package/skill/references/building-components.md +367 -0
- package/skill/references/example-report.html +356 -0
- package/skill/references/writing-html.md +187 -0
- package/skill/sdk/column-widths.d.ts +56 -0
- package/skill/sdk/doc-charts.d.ts +82 -0
- package/skill/sdk/doc-code.d.ts +28 -0
- package/skill/sdk/doc-dialogs.d.ts +4 -0
- package/skill/sdk/doc-kit.d.ts +147 -0
- package/skill/sdk/doc-math.d.ts +3 -0
- package/skill/sdk/doc-sheets.d.ts +15 -0
- package/skill/sdk/doc-state.d.ts +41 -0
- package/skill/sdk/doc-tables.d.ts +24 -0
- package/skill/sdk/doc-tokens.d.ts +22 -0
- package/skill/sdk/index.d.ts +30 -0
- package/starter/doc.html +21 -0
- package/starter/doc.json +5 -0
- package/vendor/d3.v7.9.0.min.js +2 -0
- package/vendor/katex/auto-render.min.js +1 -0
- package/vendor/katex/contrib/mhchem.min.js +1 -0
- package/vendor/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- package/vendor/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- package/vendor/katex/katex.min.css +1 -0
- package/vendor/katex/katex.min.js +1 -0
- package/vendor/pdfjs/LICENSE +177 -0
- package/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
- package/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
- package/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
- package/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
- package/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
- package/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
- package/vendor/pdfjs/cmaps/LICENSE +36 -0
- package/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
- package/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/V.bcmap +0 -0
- package/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
- package/vendor/pdfjs/legacy/build/pdf.min.mjs +27 -0
- package/vendor/pdfjs/legacy/build/pdf.worker.min.mjs +27 -0
- package/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
- package/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
- package/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
- package/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
- package/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
- package/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
- package/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
- package/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
- package/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
- package/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
- package/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
- package/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +363 -0
- package/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
- package/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
- package/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
- package/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
- package/vendor/types/@types/d3/LICENSE +21 -0
- package/vendor/types/@types/d3/index.d.ts +39 -0
- package/vendor/types/@types/d3/package.json +81 -0
- package/vendor/types/@types/d3-array/LICENSE +21 -0
- package/vendor/types/@types/d3-array/index.d.ts +1118 -0
- package/vendor/types/@types/d3-array/package.json +56 -0
- package/vendor/types/@types/d3-axis/LICENSE +21 -0
- package/vendor/types/@types/d3-axis/index.d.ts +293 -0
- package/vendor/types/@types/d3-axis/package.json +47 -0
- package/vendor/types/@types/d3-brush/LICENSE +21 -0
- package/vendor/types/@types/d3-brush/index.d.ts +255 -0
- package/vendor/types/@types/d3-brush/package.json +42 -0
- package/vendor/types/@types/d3-chord/LICENSE +21 -0
- package/vendor/types/@types/d3-chord/index.d.ts +471 -0
- package/vendor/types/@types/d3-chord/package.json +40 -0
- package/vendor/types/@types/d3-color/LICENSE +21 -0
- package/vendor/types/@types/d3-color/index.d.ts +669 -0
- package/vendor/types/@types/d3-color/package.json +55 -0
- package/vendor/types/@types/d3-contour/LICENSE +21 -0
- package/vendor/types/@types/d3-contour/index.d.ts +222 -0
- package/vendor/types/@types/d3-contour/package.json +38 -0
- package/vendor/types/@types/d3-delaunay/LICENSE +21 -0
- package/vendor/types/@types/d3-delaunay/index.d.ts +316 -0
- package/vendor/types/@types/d3-delaunay/package.json +30 -0
- package/vendor/types/@types/d3-dispatch/LICENSE +21 -0
- package/vendor/types/@types/d3-dispatch/index.d.ts +96 -0
- package/vendor/types/@types/d3-dispatch/package.json +51 -0
- package/vendor/types/@types/d3-drag/LICENSE +21 -0
- package/vendor/types/@types/d3-drag/index.d.ts +395 -0
- package/vendor/types/@types/d3-drag/package.json +42 -0
- package/vendor/types/@types/d3-dsv/LICENSE +21 -0
- package/vendor/types/@types/d3-dsv/index.d.ts +482 -0
- package/vendor/types/@types/d3-dsv/package.json +45 -0
- package/vendor/types/@types/d3-ease/LICENSE +21 -0
- package/vendor/types/@types/d3-ease/index.d.ts +316 -0
- package/vendor/types/@types/d3-ease/package.json +40 -0
- package/vendor/types/@types/d3-fetch/LICENSE +21 -0
- package/vendor/types/@types/d3-fetch/index.d.ts +282 -0
- package/vendor/types/@types/d3-fetch/package.json +37 -0
- package/vendor/types/@types/d3-force/LICENSE +21 -0
- package/vendor/types/@types/d3-force/index.d.ts +899 -0
- package/vendor/types/@types/d3-force/package.json +45 -0
- package/vendor/types/@types/d3-format/LICENSE +21 -0
- package/vendor/types/@types/d3-format/index.d.ts +337 -0
- package/vendor/types/@types/d3-format/package.json +45 -0
- package/vendor/types/@types/d3-geo/LICENSE +21 -0
- package/vendor/types/@types/d3-geo/index.d.ts +1371 -0
- package/vendor/types/@types/d3-geo/package.json +48 -0
- package/vendor/types/@types/d3-hierarchy/LICENSE +21 -0
- package/vendor/types/@types/d3-hierarchy/index.d.ts +928 -0
- package/vendor/types/@types/d3-hierarchy/package.json +50 -0
- package/vendor/types/@types/d3-interpolate/LICENSE +21 -0
- package/vendor/types/@types/d3-interpolate/index.d.ts +387 -0
- package/vendor/types/@types/d3-interpolate/package.json +47 -0
- package/vendor/types/@types/d3-path/LICENSE +21 -0
- package/vendor/types/@types/d3-path/index.d.ts +108 -0
- package/vendor/types/@types/d3-path/package.json +41 -0
- package/vendor/types/@types/d3-polygon/LICENSE +21 -0
- package/vendor/types/@types/d3-polygon/index.d.ts +41 -0
- package/vendor/types/@types/d3-polygon/package.json +40 -0
- package/vendor/types/@types/d3-quadtree/LICENSE +21 -0
- package/vendor/types/@types/d3-quadtree/index.d.ts +204 -0
- package/vendor/types/@types/d3-quadtree/package.json +45 -0
- package/vendor/types/@types/d3-random/LICENSE +21 -0
- package/vendor/types/@types/d3-random/index.d.ts +313 -0
- package/vendor/types/@types/d3-random/package.json +41 -0
- package/vendor/types/@types/d3-scale/LICENSE +21 -0
- package/vendor/types/@types/d3-scale/index.d.ts +2669 -0
- package/vendor/types/@types/d3-scale/package.json +53 -0
- package/vendor/types/@types/d3-scale-chromatic/LICENSE +21 -0
- package/vendor/types/@types/d3-scale-chromatic/index.d.ts +520 -0
- package/vendor/types/@types/d3-scale-chromatic/package.json +46 -0
- package/vendor/types/@types/d3-selection/LICENSE +21 -0
- package/vendor/types/@types/d3-selection/index.d.ts +1210 -0
- package/vendor/types/@types/d3-selection/package.json +56 -0
- package/vendor/types/@types/d3-shape/LICENSE +21 -0
- package/vendor/types/@types/d3-shape/index.d.ts +2792 -0
- package/vendor/types/@types/d3-shape/package.json +53 -0
- package/vendor/types/@types/d3-time/LICENSE +21 -0
- package/vendor/types/@types/d3-time/index.d.ts +697 -0
- package/vendor/types/@types/d3-time/package.json +46 -0
- package/vendor/types/@types/d3-time-format/LICENSE +21 -0
- package/vendor/types/@types/d3-time-format/index.d.ts +202 -0
- package/vendor/types/@types/d3-time-format/package.json +40 -0
- package/vendor/types/@types/d3-timer/LICENSE +21 -0
- package/vendor/types/@types/d3-timer/index.d.ts +68 -0
- package/vendor/types/@types/d3-timer/package.json +45 -0
- package/vendor/types/@types/d3-transition/LICENSE +21 -0
- package/vendor/types/@types/d3-transition/index.d.ts +664 -0
- package/vendor/types/@types/d3-transition/package.json +47 -0
- package/vendor/types/@types/d3-zoom/LICENSE +21 -0
- package/vendor/types/@types/d3-zoom/index.d.ts +611 -0
- package/vendor/types/@types/d3-zoom/package.json +48 -0
- package/vendor/types/@types/geojson/LICENSE +21 -0
- package/vendor/types/@types/geojson/index.d.ts +202 -0
- package/vendor/types/@types/geojson/package.json +46 -0
- package/vendor/typescript/LICENSE.txt +55 -0
- package/vendor/typescript/lib.decorators.d.ts +384 -0
- package/vendor/typescript/lib.decorators.legacy.d.ts +22 -0
- package/vendor/typescript/lib.dom.d.ts +39429 -0
- package/vendor/typescript/lib.dom.iterable.d.ts +571 -0
- package/vendor/typescript/lib.es2015.collection.d.ts +147 -0
- package/vendor/typescript/lib.es2015.core.d.ts +597 -0
- package/vendor/typescript/lib.es2015.d.ts +28 -0
- package/vendor/typescript/lib.es2015.generator.d.ts +77 -0
- package/vendor/typescript/lib.es2015.iterable.d.ts +605 -0
- package/vendor/typescript/lib.es2015.promise.d.ts +81 -0
- package/vendor/typescript/lib.es2015.proxy.d.ts +128 -0
- package/vendor/typescript/lib.es2015.reflect.d.ts +144 -0
- package/vendor/typescript/lib.es2015.symbol.d.ts +46 -0
- package/vendor/typescript/lib.es2015.symbol.wellknown.d.ts +326 -0
- package/vendor/typescript/lib.es2016.array.include.d.ts +116 -0
- package/vendor/typescript/lib.es2016.d.ts +21 -0
- package/vendor/typescript/lib.es2016.intl.d.ts +31 -0
- package/vendor/typescript/lib.es2017.arraybuffer.d.ts +21 -0
- package/vendor/typescript/lib.es2017.d.ts +26 -0
- package/vendor/typescript/lib.es2017.date.d.ts +31 -0
- package/vendor/typescript/lib.es2017.intl.d.ts +44 -0
- package/vendor/typescript/lib.es2017.object.d.ts +49 -0
- package/vendor/typescript/lib.es2017.sharedmemory.d.ts +135 -0
- package/vendor/typescript/lib.es2017.string.d.ts +45 -0
- package/vendor/typescript/lib.es2017.typedarrays.d.ts +53 -0
- package/vendor/typescript/lib.es2018.asyncgenerator.d.ts +77 -0
- package/vendor/typescript/lib.es2018.asynciterable.d.ts +53 -0
- package/vendor/typescript/lib.es2018.d.ts +24 -0
- package/vendor/typescript/lib.es2018.intl.d.ts +83 -0
- package/vendor/typescript/lib.es2018.promise.d.ts +30 -0
- package/vendor/typescript/lib.es2018.regexp.d.ts +37 -0
- package/vendor/typescript/lib.es2019.array.d.ts +79 -0
- package/vendor/typescript/lib.es2019.d.ts +24 -0
- package/vendor/typescript/lib.es2019.intl.d.ts +23 -0
- package/vendor/typescript/lib.es2019.object.d.ts +33 -0
- package/vendor/typescript/lib.es2019.string.d.ts +37 -0
- package/vendor/typescript/lib.es2019.symbol.d.ts +24 -0
- package/vendor/typescript/lib.es2020.bigint.d.ts +765 -0
- package/vendor/typescript/lib.es2020.d.ts +27 -0
- package/vendor/typescript/lib.es2020.date.d.ts +42 -0
- package/vendor/typescript/lib.es2020.intl.d.ts +474 -0
- package/vendor/typescript/lib.es2020.number.d.ts +28 -0
- package/vendor/typescript/lib.es2020.promise.d.ts +47 -0
- package/vendor/typescript/lib.es2020.sharedmemory.d.ts +99 -0
- package/vendor/typescript/lib.es2020.string.d.ts +44 -0
- package/vendor/typescript/lib.es2020.symbol.wellknown.d.ts +41 -0
- package/vendor/typescript/lib.es2021.d.ts +23 -0
- package/vendor/typescript/lib.es2021.intl.d.ts +166 -0
- package/vendor/typescript/lib.es2021.promise.d.ts +48 -0
- package/vendor/typescript/lib.es2021.string.d.ts +33 -0
- package/vendor/typescript/lib.es2021.weakref.d.ts +78 -0
- package/vendor/typescript/lib.es2022.array.d.ts +121 -0
- package/vendor/typescript/lib.es2022.d.ts +25 -0
- package/vendor/typescript/lib.es2022.error.d.ts +75 -0
- package/vendor/typescript/lib.es2022.intl.d.ts +145 -0
- package/vendor/typescript/lib.es2022.object.d.ts +26 -0
- package/vendor/typescript/lib.es2022.regexp.d.ts +39 -0
- package/vendor/typescript/lib.es2022.string.d.ts +25 -0
- package/vendor/typescript/lib.es5.d.ts +4601 -0
- package/vendor/typescript/package.json +4 -0
- package/vendor/typescript/typescript.js +446 -0
- package/web/assets/index-Bh74DfsV.css +1 -0
- package/web/assets/index-UW0RyFFt.js +13 -0
- package/web/index.html +14 -0
|
@@ -0,0 +1,866 @@
|
|
|
1
|
+
import { Z } from "../../../shared/layers.mjs";
|
|
2
|
+
import { can, isMention, limitText, mentionOf, newEmptyLink, ownHTML } from "../core.mjs";
|
|
3
|
+
import { editable, followPress, pointRange, select } from "../caret.mjs";
|
|
4
|
+
import { joinMarks, rangeAt, rangeOffsets } from "../marks.mjs";
|
|
5
|
+
import { wholeAddress } from "../clipboard/own/export.mjs";
|
|
6
|
+
import { ICONS, createMenu } from "../menu.mjs";
|
|
7
|
+
import { own } from "../overlays.mjs";
|
|
8
|
+
import { placeBox } from "../placement.mjs";
|
|
9
|
+
import { tooltip } from "../tooltip.mjs";
|
|
10
|
+
import { addStyle, copyAddress, element, fadeIn, mount, swallowNext } from "../ui.mjs";
|
|
11
|
+
import { typedHref } from "./address.mjs";
|
|
12
|
+
import { findPages, heldList, pageRows, placeIn, readPages, titleIn, trashed } from "./pages.mjs";
|
|
13
|
+
import { DIALOG_TRIGGER } from "../../components/dialog/index.mjs";
|
|
14
|
+
import { DIALOG_ICON } from "../../components/icons.mjs";
|
|
15
|
+
import { VIEWS, closeOffer, closeViews, hasViews, hrefOf, isPageChip, offerViews, openViews, pageChip, refetch, viewNodes, viewOf, viewsHold } from "./views.mjs";
|
|
16
|
+
import { t } from "../../../shared/i18n/index.mjs";
|
|
17
|
+
import { referencedFile } from "../../../shared/media.mjs";
|
|
18
|
+
import { decoded, elsewhere, fileLink, fromFile, fullAddress, pageAddress, workbenchHash } from "../../../shared/page-address.mjs";
|
|
19
|
+
import { inTrash } from "../../../shared/page-links.mjs";
|
|
20
|
+
|
|
21
|
+
// Links in the text (docs/editor.md, "Browser side"): the link card that adds, changes or removes a
|
|
22
|
+
// link, and following a link while editing. The card (as Notion's link editor): a field for the
|
|
23
|
+
// address (a blue ring while it has the focus), a button that copies it and one that takes the link
|
|
24
|
+
// away; for a link to a web page, after a line, the view it is shown in with ▾ (Feishu's 链接视图 ▾:
|
|
25
|
+
// its views, views.mjs). Ctrl+K or the format bar's link button opens it below the selected text,
|
|
26
|
+
// the field taking the focus while the text stays marked (the selection's own color, drawn over
|
|
27
|
+
// it); resting on a link in the text for 0.6s opens it below the link, the focus staying where it
|
|
28
|
+
// was, unless something else is open that a press would close. What is typed in the field looks for
|
|
29
|
+
// a page (pages.mjs), its results under the field, in the card; what is pasted looks for nothing, so
|
|
30
|
+
// that an address pasted stays one. ↑/↓ move in them, and a row clicked or Enter links to its page.
|
|
31
|
+
// Enter takes the row the keys moved to, else what reads as a whole address, else the first row, and
|
|
32
|
+
// with no row says so, the card staying; a press anywhere else keeps what the field says when that is
|
|
33
|
+
// an address, and gives up words that are none; an emptied field takes the link away; Esc gives up. A
|
|
34
|
+
// link to a document shows the document's title, the card keeping the link's own address beside
|
|
35
|
+
// it: left as it is, nothing changes, and 复制 copies the address that opens it from anywhere. Resting
|
|
36
|
+
// is a pointer's that moved onto the link: one that came under a still pointer opens nothing. A card
|
|
37
|
+
// opened by resting goes again 0.3s after the pointer leaves the link and the card (and its views),
|
|
38
|
+
// unless its field was clicked. A
|
|
39
|
+
// plain click on a link opens it, as for a reader: in a new tab, in front of the page (one to a file
|
|
40
|
+
// of the report's folder, which the text writes assets/… as the file does, where the preview hands
|
|
41
|
+
// the file out), a link to a detail card (href="#dialog id") by opening the card, one to a block of
|
|
42
|
+
// the page (#<block id>) by going to it or saying it is gone, one to a document of the workspace or
|
|
43
|
+
// a block of one, in any form an address takes (shared/page-address.mjs), by going there in this
|
|
44
|
+
// tab (`go`, the editor's), one with no address not at all; an address on another port is asked of
|
|
45
|
+
// the list, a document's if it holds it (shared/page-address.mjs addressOn), there on this server,
|
|
46
|
+
// another program's if not, in a new tab as any web address (followElsewhere); a middle click, or Ctrl
|
|
47
|
+
// or ⌘ held, opens it in a tab of its own, a middle click behind the page, which the browser leaves to
|
|
48
|
+
// links outside editable text. The press stays the browser's, so a drag
|
|
49
|
+
// in a link selects its text, and the click that ends it opens nothing, nor does a Shift click (a
|
|
50
|
+
// drag from which selects on as over any text), the second click of a double click, or the press
|
|
51
|
+
// that closes something open: this card being filled in, a formula's editor, a menu or a picker. Its
|
|
52
|
+
// words are edited by going in with the arrow keys; an input method over text that starts in a link
|
|
53
|
+
// keeps the link (compositionEnded). A link outside editable text opens in a new tab too, the page
|
|
54
|
+
// staying (followOutside). A link shown with its icon (图标视图) is a whole, as a formula is: a click
|
|
55
|
+
// opens it, and only resting brings its card; its field changed, the page is read again; taken away,
|
|
56
|
+
// its title stays as text. The "/" menu's 链接 puts a gray 链接 where it goes (as 公式 puts 新公式:
|
|
57
|
+
// core.mjs newEmptyLink, components/placeholder.mjs), tinted while the card asks for the address: Enter makes the link, its address its text, and
|
|
58
|
+
// offers its views at its end (显示为); a press elsewhere makes it too; nothing given, or Esc, leaves
|
|
59
|
+
// the gray 链接 there, a link left empty (written so, shown to no reader), a whole as a character is;
|
|
60
|
+
// a click on it asks for its address again. The "/" menu's 页面 does the same with a gray 页面, for a
|
|
61
|
+
// page block: the same element, a document's address (views.mjs pageChip), its title and icon what
|
|
62
|
+
// the server draws (render/page-chips.mjs); nothing but a click on it, which opens the document, and
|
|
63
|
+
// no card on resting, so that it is deleted to go elsewhere. The card asks in its way: the pages are
|
|
64
|
+
// listed at once, Enter takes the page an address names (another address says it is no page, the
|
|
65
|
+
// card staying), else the row highlighted, and with no row makes a page of the words under this one
|
|
66
|
+
// (a new subpage: 写作偏好, ?solo, has none); a press elsewhere keeps the page an address
|
|
67
|
+
// names and nothing else, leaving the gray 页面. A detail card's entry (a link to it, the kit's chip)
|
|
68
|
+
// has a card of its own instead: 打开 and 移除 (no address: an id is no reader's business; no name:
|
|
69
|
+
// the entry's words are it). Nothing is committed while the card is open (linkPending). connectLinks()
|
|
70
|
+
// gives them what they need from the editor.
|
|
71
|
+
|
|
72
|
+
const STYLE = `
|
|
73
|
+
.ge-link {
|
|
74
|
+
position: fixed; left: 0; top: 0; z-index: ${Z.card}; display: flex; flex-wrap: wrap; align-items: center; gap: 2px; width: 246px; max-width: calc(100vw - 16px); padding: 6px;
|
|
75
|
+
border-radius: 10px; background: var(--ge-bg); color: var(--ge-tx);
|
|
76
|
+
box-shadow: var(--ge-shadow);
|
|
77
|
+
font: 14px/1.2 ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
|
|
78
|
+
}
|
|
79
|
+
.ge-link[data-views] { width: 346px; }
|
|
80
|
+
.ge-link-field { display: flex; align-items: center; flex: 1; min-width: 0; height: 28px; margin-right: 4px; padding: 3px 6px; border-radius: 6px; background: var(--ge-field); box-shadow: 0 0 0 1px var(--ge-edge); cursor: text; }
|
|
81
|
+
.ge-link-field:focus-within { box-shadow: inset 0 0 0 1px var(--ge-focus), 0 0 0 1px var(--ge-focus); }
|
|
82
|
+
.ge-link-field input { flex: 1; min-width: 0; padding: 0; border: 0; outline: none; background: transparent; color: inherit; font: inherit; line-height: 20px; }
|
|
83
|
+
.ge-link-field input::placeholder { color: var(--ge-tx3); }
|
|
84
|
+
.ge-link-tool { display: flex; align-items: center; justify-content: center; flex: none; width: 28px; height: 28px; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--ge-ico); cursor: pointer; transition: background 20ms ease-in; }
|
|
85
|
+
.ge-link-tool:hover, .ge-link-view:hover, .ge-link-view[aria-expanded="true"] { background: var(--ge-hover); }
|
|
86
|
+
.ge-link-tool:active, .ge-link-view:active { background: var(--ge-press); }
|
|
87
|
+
.ge-link-tool svg { display: block; width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; }
|
|
88
|
+
.ge-link-sep { flex: none; width: 1px; height: 20px; margin: 0 4px; background: var(--ge-line); }
|
|
89
|
+
.ge-link-view { display: flex; align-items: center; gap: 2px; flex: none; height: 28px; padding: 0 4px 0 8px; border: 0; border-radius: 6px; background: transparent; color: inherit; font: inherit; white-space: nowrap; cursor: pointer; transition: background 20ms ease-in; }
|
|
90
|
+
.ge-link-view svg { display: block; width: 16px; height: 16px; fill: none; stroke: var(--ge-tx3); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
|
|
91
|
+
.ge-link-mark { position: fixed; left: 0; top: 0; z-index: ${Z.mark}; pointer-events: none; background: var(--ge-select); }
|
|
92
|
+
/* A link in editable text is one to click on, where the browser shows a text cursor. */
|
|
93
|
+
[data-ge-editing] a[href] { cursor: pointer; }
|
|
94
|
+
.ge-link[data-entry] { width: auto; padding: 4px; }
|
|
95
|
+
.ge-link-open { display: flex; align-items: center; gap: 6px; flex: none; height: 28px; padding: 0 8px 0 6px; border: 0; border-radius: 6px; background: transparent; color: inherit; font: inherit; cursor: pointer; transition: background 20ms ease-in; }
|
|
96
|
+
.ge-link-open svg { display: block; width: 18px; height: 18px; fill: none; stroke: var(--ge-ico); stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; }
|
|
97
|
+
.ge-link-open:hover { background: var(--ge-hover); }
|
|
98
|
+
.ge-link-open:active { background: var(--ge-press); }
|
|
99
|
+
`;
|
|
100
|
+
const HOVER_DELAY = 600; // resting on a link this long opens its card
|
|
101
|
+
const LEAVE = 300; // a card opened by resting goes this long after the pointer leaves link and card
|
|
102
|
+
const DRAGGED = 4; // a pointer released this far from its press has dragged, not clicked
|
|
103
|
+
const CHEVRON = '<svg viewBox="0 0 16 16" aria-hidden="true"><path d="m4.5 6.25 3.5 3.5 3.5-3.5"/></svg>';
|
|
104
|
+
|
|
105
|
+
let use = null; // { say, recordStep, hideFormatBar, active, served(file), closing(), slug, own(): this page, as pages.mjs readPages takes it, reveal(id), go(place, href), subpage(title): a new page under this one, the answer's report, null where it has none }
|
|
106
|
+
|
|
107
|
+
export function connectLinks(editor) {
|
|
108
|
+
use = editor;
|
|
109
|
+
addStyle(STYLE);
|
|
110
|
+
// Resting on a link in the text opens its card, and only for a pointer that moved there, as on a
|
|
111
|
+
// 批注's marker: a link that came under a still pointer (the next page, shown where a link was just
|
|
112
|
+
// clicked; the page scrolled) hears an over and no move, and its card would stand over the lines
|
|
113
|
+
// below, in the way of the next click. Leaving the link and the card closes it (not while its views
|
|
114
|
+
// are open).
|
|
115
|
+
document.addEventListener("mouseover", (event) => {
|
|
116
|
+
const rested = use.active() && !event.buttons ? linkOf(event.target) : null;
|
|
117
|
+
const link = rested && !isPageChip(rested) ? rested : null; // a page block has no card
|
|
118
|
+
clearTimeout(hoverTimer);
|
|
119
|
+
reached = null;
|
|
120
|
+
if (linkBox && !linkBox.pinned && (linkBox.held || link === linkBox.link || linkBox.node.contains(event.target) || viewsHold(event.target))) return;
|
|
121
|
+
if (linkBox && !linkBox.pinned) hoverTimer = setTimeout(() => closeLink(false), LEAVE);
|
|
122
|
+
reached = link;
|
|
123
|
+
}, true);
|
|
124
|
+
document.addEventListener("mousemove", (event) => {
|
|
125
|
+
const moved = !pointer || pointer.x !== event.clientX || pointer.y !== event.clientY;
|
|
126
|
+
pointer = { x: event.clientX, y: event.clientY };
|
|
127
|
+
if (!moved || !reached || !use.active()) return;
|
|
128
|
+
const link = reached;
|
|
129
|
+
reached = null;
|
|
130
|
+
if (!linkBox?.pinned && linkBox?.link !== link) hoverTimer = setTimeout(() => { if (!use.closing()) openLinkAt(link); }, HOVER_DELAY);
|
|
131
|
+
}, { passive: true, capture: true });
|
|
132
|
+
// What a press came down on, for the click it ends in (opens), on the window to see what it closes
|
|
133
|
+
// before that goes; a press on a link leaves no card on its way to open over a drag.
|
|
134
|
+
addEventListener("pointerdown", (event) => {
|
|
135
|
+
press = { x: event.clientX, y: event.clientY, selection: selectionNow(), keeps: (Boolean(linkBox?.pinned) && !linkHolds(event.target)) || use.closing() };
|
|
136
|
+
if (linkOf(event.target)) {
|
|
137
|
+
clearTimeout(hoverTimer);
|
|
138
|
+
reached = null;
|
|
139
|
+
}
|
|
140
|
+
}, true);
|
|
141
|
+
// Shift on a link in the block of the caret: the selection reaches it and follows the pointer, as
|
|
142
|
+
// over any other text, where the browser moves the caret there.
|
|
143
|
+
document.addEventListener("mousedown", (event) => {
|
|
144
|
+
const host = use.active() && event.button === 0 && event.shiftKey && linkOf(event.target) ? editable(event.target) : null;
|
|
145
|
+
const selection = getSelection();
|
|
146
|
+
const at = host && editable(selection.anchorNode) === host ? pointRange(event.clientX, event.clientY) : null;
|
|
147
|
+
if (!at) return;
|
|
148
|
+
event.preventDefault();
|
|
149
|
+
const from = document.createRange();
|
|
150
|
+
from.setStart(selection.anchorNode, selection.anchorOffset);
|
|
151
|
+
selection.extend(at.startContainer, at.startOffset);
|
|
152
|
+
followPress(host, from);
|
|
153
|
+
}, true);
|
|
154
|
+
// A middle click, which a browser takes for a link only outside editable text: here for all of
|
|
155
|
+
// them (a chip is such a link, and would open twice), its press starting no scrolling by the pointer.
|
|
156
|
+
document.addEventListener("mousedown", (event) => {
|
|
157
|
+
if (event.button === 1 && use.active() && linkOf(event.target)) event.preventDefault();
|
|
158
|
+
}, true);
|
|
159
|
+
document.addEventListener("auxclick", (event) => {
|
|
160
|
+
const link = event.button === 1 && use.active() ? linkOf(event.target) : null;
|
|
161
|
+
if (!link) return;
|
|
162
|
+
event.preventDefault();
|
|
163
|
+
if (leadsAway(link)) follow(hrefOf(link), true);
|
|
164
|
+
}, true);
|
|
165
|
+
// A link shown with its icon is a whole: a press puts no caret in it, and selects nothing with Ctrl
|
|
166
|
+
// or ⌘ held. One left empty asks for its address at a click, here, ahead of the editor's listener,
|
|
167
|
+
// which follows those that have one.
|
|
168
|
+
const chipAt = (target) => {
|
|
169
|
+
const chip = use.active() ? target?.closest?.(".doc-link-mention[data-ge-atom]") : null;
|
|
170
|
+
return chip && editable(chip) ? chip : null;
|
|
171
|
+
};
|
|
172
|
+
document.addEventListener("mousedown", (event) => {
|
|
173
|
+
if (event.button === 0 && !event.shiftKey && chipAt(event.target)) event.preventDefault();
|
|
174
|
+
}, true);
|
|
175
|
+
document.addEventListener("click", (event) => {
|
|
176
|
+
const chip = event.ctrlKey || event.metaKey || event.shiftKey ? null : chipAt(event.target);
|
|
177
|
+
if (!chip?.hasAttribute("data-ge-empty")) return;
|
|
178
|
+
event.preventDefault();
|
|
179
|
+
if (linkBox?.fresh?.chip !== chip) openLinkAt(chip);
|
|
180
|
+
}, true);
|
|
181
|
+
document.addEventListener("click", followOutside);
|
|
182
|
+
document.addEventListener("compositionstart", compositionBegun, true);
|
|
183
|
+
document.addEventListener("compositionend", compositionEnded, true);
|
|
184
|
+
addEventListener("scroll", () => { if (linkBox) linkBox.paint(); }, { passive: true, capture: true });
|
|
185
|
+
addEventListener("resize", () => { if (linkBox) linkBox.paint(); });
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ---------- the link card ----------
|
|
189
|
+
|
|
190
|
+
// { node, host, range, link, input, marks, pinned, held (its views open), paint, fresh: the gray 链接 the
|
|
191
|
+
// card asks the address of ({ chip, before, made: the "/" menu's, new }) or null, shown: what the field
|
|
192
|
+
// was given for the link, reading: the reading of the list of pages, once it is asked for, workspace:
|
|
193
|
+
// what it read (pages.mjs readPages; null until then, and for a list that cannot be read), asksPage: it
|
|
194
|
+
// fills a page block, making: a new page is on its way, entered: an Enter waits for the list, pasted:
|
|
195
|
+
// what the field holds was pasted, place(): the card put by the text, tallest: the most it has been high }
|
|
196
|
+
let linkBox = null;
|
|
197
|
+
let results = null; // the pages found, under the field (a menu of the card's, made when first needed)
|
|
198
|
+
let hoverTimer = 0;
|
|
199
|
+
let reached = null; // the link the pointer came over, until a move starts the wait for its card
|
|
200
|
+
let pointer = null; // where the pointer last moved to: { x, y } (a move the browser makes up goes nowhere)
|
|
201
|
+
let pasted = null; // the list of pages being read for what was just pasted
|
|
202
|
+
let press = null; // the last press: { x, y, selection: where it found the selection (selectionNow), keeps: it closes something open, and does no more }
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Close the card; `restore`: the selection goes back to the text it was opened on (after the gray
|
|
206
|
+
* 链接, which stays when given up).
|
|
207
|
+
*/
|
|
208
|
+
export function closeLink(restore = true) {
|
|
209
|
+
clearTimeout(hoverTimer);
|
|
210
|
+
closeViews();
|
|
211
|
+
if (!linkBox) return;
|
|
212
|
+
const { node, host, range, marks, fresh } = linkBox;
|
|
213
|
+
results?.close();
|
|
214
|
+
node.remove();
|
|
215
|
+
marks.forEach((mark) => mark.remove());
|
|
216
|
+
linkBox = null;
|
|
217
|
+
if (!host.isConnected) return;
|
|
218
|
+
if (fresh) return leaveEmpty(host, fresh, restore);
|
|
219
|
+
if (restore) {
|
|
220
|
+
host.focus({ preventScroll: true });
|
|
221
|
+
select(range);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** A press outside the card: what its field says is kept, when that is an address (words that are none are given up; a card opened by resting just goes). */
|
|
226
|
+
export function dismissLink() {
|
|
227
|
+
if (!linkBox || linkBox.making) return;
|
|
228
|
+
const typed = linkBox.input.value;
|
|
229
|
+
if (linkBox.asksPage) {
|
|
230
|
+
const page = listed(typedHref(typed.trim()));
|
|
231
|
+
return page ? keepPage(page, false) : closeLink(false);
|
|
232
|
+
}
|
|
233
|
+
if (linkBox.pinned && normalizeHref(typed) !== null) setLink(typed, false);
|
|
234
|
+
else closeLink(false);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Ctrl+K: add a link to the selected text, or change or remove the link under the caret; `fresh`
|
|
238
|
+
// (the "/" menu's 链接): a new link at the caret, a gray 链接 there, its address asked for; with
|
|
239
|
+
// `page` (its 页面) a page block, the gray 页面.
|
|
240
|
+
export function openLink(host, { fresh = false, page = false } = {}) {
|
|
241
|
+
if (!can(host, "links")) {
|
|
242
|
+
use.say(limitText(host, "links"));
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const selection = getSelection();
|
|
246
|
+
if (!selection.rangeCount) return;
|
|
247
|
+
const range = selection.getRangeAt(0).cloneRange();
|
|
248
|
+
if (fresh) {
|
|
249
|
+
closeLink(false);
|
|
250
|
+
closeOffer();
|
|
251
|
+
const before = ownHTML(host);
|
|
252
|
+
range.deleteContents();
|
|
253
|
+
const chip = newEmptyLink(document, page);
|
|
254
|
+
range.insertNode(chip);
|
|
255
|
+
askAddress(host, chip, before, true);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
const link = linkAround(host, range);
|
|
259
|
+
if (!link && range.collapsed) {
|
|
260
|
+
use.say(t("先选中要加链接的文字,再按 Ctrl+K。"));
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (link && range.collapsed) range.selectNode(link);
|
|
264
|
+
showCard(host, range, link, true);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// The card asking the address of a gray 链接 (`made`: just now, by the "/" menu; else one left empty,
|
|
268
|
+
// clicked), `host`'s html `before` it; the chip tinted meanwhile.
|
|
269
|
+
function askAddress(host, chip, before, made) {
|
|
270
|
+
chip.setAttribute("data-ge-link-edit", "");
|
|
271
|
+
const at = document.createRange();
|
|
272
|
+
at.selectNode(chip);
|
|
273
|
+
showCard(host, at, null, true, { chip, before, made });
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// The gray 链接 given no address stays (one undo step when the "/" menu made it); `restore`: the
|
|
277
|
+
// caret after it.
|
|
278
|
+
function leaveEmpty(host, { chip, before, made }, restore) {
|
|
279
|
+
chip.removeAttribute("data-ge-link-edit");
|
|
280
|
+
if (!chip.isConnected) return;
|
|
281
|
+
if (made) use.recordStep(host, before);
|
|
282
|
+
if (restore) {
|
|
283
|
+
host.focus({ preventScroll: true });
|
|
284
|
+
const after = document.createRange();
|
|
285
|
+
after.setStartAfter(chip);
|
|
286
|
+
after.collapse(true);
|
|
287
|
+
select(after);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Resting on a link: its card, below it; the focus stays where it is until the field is clicked. A
|
|
292
|
+
// link left empty (a click on it): its address asked for.
|
|
293
|
+
function openLinkAt(link) {
|
|
294
|
+
const host = editable(link);
|
|
295
|
+
if (!host || !link.isConnected || !can(host, "links")) return;
|
|
296
|
+
if (link.hasAttribute("data-ge-empty")) {
|
|
297
|
+
closeLink(false);
|
|
298
|
+
closeOffer();
|
|
299
|
+
return askAddress(host, link, ownHTML(host), false);
|
|
300
|
+
}
|
|
301
|
+
const range = document.createRange();
|
|
302
|
+
range.selectNode(link);
|
|
303
|
+
showCard(host, range, link, false);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// A button of the card; a press on it leaves the focus where it is (the field keeps it).
|
|
307
|
+
function tool(label, icon, action) {
|
|
308
|
+
const node = element("button", { type: "button", class: "ge-link-tool", "aria-label": label, html: icon });
|
|
309
|
+
node.addEventListener("mousedown", (event) => event.preventDefault());
|
|
310
|
+
node.addEventListener("click", action);
|
|
311
|
+
tooltip(node, label);
|
|
312
|
+
return node;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Open the detail card a link to it opens (dialogs.js), as a reader's `click` would; the card now
|
|
317
|
+
* under the pointer, or its backdrop, takes no second press of a double click.
|
|
318
|
+
*/
|
|
319
|
+
export function openEntry(link, click) {
|
|
320
|
+
const card = targetOf(link);
|
|
321
|
+
if (!(card instanceof HTMLDialogElement)) return;
|
|
322
|
+
swallowNext(click, () => card.open);
|
|
323
|
+
if (globalThis.DocDialogs?.open) globalThis.DocDialogs.open(card, link);
|
|
324
|
+
else card.showModal?.();
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// A detail card's entry: 打开 and 移除 (the words stay as text; the detail card is no longer saved,
|
|
328
|
+
// core.mjs nodeOf). Below the entry, the focus staying in the text.
|
|
329
|
+
function showEntry(host, range, link) {
|
|
330
|
+
const open = element("button", { type: "button", class: "ge-link-open", html: DIALOG_ICON }, element("span", {}, t("打开")));
|
|
331
|
+
open.addEventListener("mousedown", (event) => event.preventDefault());
|
|
332
|
+
open.addEventListener("click", (event) => {
|
|
333
|
+
closeLink(false);
|
|
334
|
+
openEntry(link, event);
|
|
335
|
+
});
|
|
336
|
+
const remove = tool(t("移除入口"), ICONS.trash, () => setLink(null));
|
|
337
|
+
const node = element("div", { class: "ge-link", role: "dialog", "aria-label": t("详情卡片"), "data-entry": "" }, open, remove);
|
|
338
|
+
tooltip(open, t("打开详情卡片"));
|
|
339
|
+
linkBox = { node, host, range, link, input: { value: hrefOf(link) }, marks: [], pinned: false, held: false, paint: () => {}, fresh: null };
|
|
340
|
+
mount(node);
|
|
341
|
+
fadeIn(node, 120);
|
|
342
|
+
const rect = range.getClientRects()[0] ?? host.getBoundingClientRect();
|
|
343
|
+
const { left, top } = placeBox(rect, { width: node.offsetWidth, height: node.offsetHeight }, { gap: 6 });
|
|
344
|
+
node.style.left = `${Math.round(left)}px`;
|
|
345
|
+
node.style.top = `${Math.round(top)}px`;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function showCard(host, range, link, focus, fresh = null) {
|
|
349
|
+
closeLink(false);
|
|
350
|
+
use.hideFormatBar();
|
|
351
|
+
if (link?.classList.contains(DIALOG_TRIGGER) && !fresh) return showEntry(host, range, link);
|
|
352
|
+
const asksPage = fresh?.chip.getAttribute("data-ge-empty") === "page";
|
|
353
|
+
const input = element("input", { type: "text", placeholder: asksPage ? t("输入页面标题") : t("输入链接或页面标题"), "aria-label": asksPage ? t("页面标题") : t("链接地址"), spellcheck: "false" });
|
|
354
|
+
// A link to a document shows its title, once the list is read.
|
|
355
|
+
const toPage = link ? wholeAddress(hrefOf(link)) : null;
|
|
356
|
+
input.value = link && !toPage ? hrefOf(link) : "";
|
|
357
|
+
const copy = tool(t("复制链接"), ICONS.copy, () => copyLink(input.value, link));
|
|
358
|
+
const remove = tool(t("移除链接"), ICONS.trash, () => setLink(null));
|
|
359
|
+
const views = link && hasViews(link) ? viewButton(link) : null;
|
|
360
|
+
const node = element("div", { class: "ge-link", role: "dialog", "aria-label": t("链接") }, element("label", { class: "ge-link-field" }, input), copy, remove);
|
|
361
|
+
if (views) {
|
|
362
|
+
node.setAttribute("data-views", "");
|
|
363
|
+
node.append(element("div", { class: "ge-link-sep", role: "separator" }), views);
|
|
364
|
+
}
|
|
365
|
+
input.addEventListener("keydown", (event) => {
|
|
366
|
+
if (event.isComposing || event.keyCode === 229) return; // an input method's: its letters filter, and its Enter commits them
|
|
367
|
+
if (box.making) event.preventDefault();
|
|
368
|
+
else if (results?.isOpen && results.arrow(event)) event.preventDefault();
|
|
369
|
+
else if (event.key === "Enter") {
|
|
370
|
+
event.preventDefault();
|
|
371
|
+
enterField(box);
|
|
372
|
+
} else if (event.key === "Escape") {
|
|
373
|
+
event.preventDefault();
|
|
374
|
+
event.stopPropagation();
|
|
375
|
+
closeLink();
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
// What is typed looks for a page (an input method's letters too, as they come), what is pasted does not.
|
|
379
|
+
input.addEventListener("input", (event) => {
|
|
380
|
+
box.pasted = event.inputType === "insertFromPaste";
|
|
381
|
+
if (!box.pasted) return search(box, event.isComposing);
|
|
382
|
+
results?.close();
|
|
383
|
+
place();
|
|
384
|
+
});
|
|
385
|
+
input.addEventListener("compositionend", () => search(box));
|
|
386
|
+
// Clicking into the field keeps the card until Enter or a press elsewhere.
|
|
387
|
+
input.addEventListener("focus", () => {
|
|
388
|
+
if (!linkBox) return;
|
|
389
|
+
linkBox.pinned = true;
|
|
390
|
+
clearTimeout(hoverTimer);
|
|
391
|
+
readList(linkBox);
|
|
392
|
+
linkBox.paint();
|
|
393
|
+
});
|
|
394
|
+
const marks = [];
|
|
395
|
+
// The text the card is about, marked as the selection is while the field has the focus (not the
|
|
396
|
+
// "/" menu's gray 链接, which shows where it goes).
|
|
397
|
+
const paint = () => {
|
|
398
|
+
marks.forEach((mark) => mark.remove());
|
|
399
|
+
marks.length = 0;
|
|
400
|
+
if (!linkBox?.pinned || linkBox.fresh || !range.startContainer.isConnected) return;
|
|
401
|
+
for (const rect of range.getClientRects()) {
|
|
402
|
+
if (rect.width < 1) continue;
|
|
403
|
+
const mark = mount(own(element("div", { class: "ge-link-mark" }), "link mark", { alive: () => marks.includes(mark) }));
|
|
404
|
+
Object.assign(mark.style, { transform: `translate(${rect.left}px, ${rect.top}px)`, width: `${rect.width}px`, height: `${rect.height}px` });
|
|
405
|
+
marks.push(mark);
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
const box = { node, host, range, link, input, marks, pinned: focus, held: false, paint, fresh, asksPage, making: false, entered: false, shown: input.value, reading: null, workspace: null, tallest: 0, place: () => {} };
|
|
409
|
+
linkBox = box;
|
|
410
|
+
mount(node);
|
|
411
|
+
fadeIn(node, 120);
|
|
412
|
+
// Below the text, its left edge with the text's (above it when there is no room below), where the
|
|
413
|
+
// pages found under the field stay clear of the window's end: by the most it has been high in this
|
|
414
|
+
// opening, so that the field does not move back and forth as rows come and go.
|
|
415
|
+
const rect = range.getClientRects()[0] ?? host.getBoundingClientRect();
|
|
416
|
+
const place = () => {
|
|
417
|
+
box.tallest = Math.max(box.tallest, node.offsetHeight);
|
|
418
|
+
const { left, top } = placeBox(rect, { width: node.offsetWidth, height: box.tallest }, { gap: 6 });
|
|
419
|
+
node.style.left = `${Math.round(left)}px`;
|
|
420
|
+
node.style.top = `${Math.round(top)}px`;
|
|
421
|
+
};
|
|
422
|
+
box.place = place;
|
|
423
|
+
place();
|
|
424
|
+
if (focus) {
|
|
425
|
+
input.focus();
|
|
426
|
+
input.select();
|
|
427
|
+
paint();
|
|
428
|
+
}
|
|
429
|
+
if (toPage) readList(box).then(() => {
|
|
430
|
+
if (linkBox !== box || input.value) return;
|
|
431
|
+
input.value = box.shown = titleIn(box.workspace ?? heldList(), fromFile(hrefOf(link), use.slug, location.origin)) || hrefOf(link);
|
|
432
|
+
if (document.activeElement === input) input.select();
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// The list of pages, read once for each opening of the card (for what is typed in its field, or the
|
|
437
|
+
// title of the page it is about); what was typed before it came is looked for then.
|
|
438
|
+
function readList(box) {
|
|
439
|
+
box.reading ??= readPages(use.own()).then((list) => {
|
|
440
|
+
box.workspace = list;
|
|
441
|
+
if (linkBox === box && (box.asksPage || (box.input.value !== box.shown && !box.pasted))) search(box);
|
|
442
|
+
});
|
|
443
|
+
return box.reading;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// The pages the field's words find, in the card under it (a page block's, with no words the first of
|
|
447
|
+
// them): looked for as they are typed (`composing`: an input method's letters, which it may show with
|
|
448
|
+
// its syllables apart, as "/" reads them), the first highlighted unless the words read as an address,
|
|
449
|
+
// which Enter keeps.
|
|
450
|
+
function search(box, composing = false) {
|
|
451
|
+
if (linkBox !== box) return;
|
|
452
|
+
const written = box.input.value;
|
|
453
|
+
const query = (composing ? written.replace(/['\s]/g, "") : written).trim();
|
|
454
|
+
const found = box.workspace && (query || box.asksPage) ? findPages(box.workspace.pages, query) : [];
|
|
455
|
+
if (found.length === 0) {
|
|
456
|
+
results?.close();
|
|
457
|
+
return box.place();
|
|
458
|
+
}
|
|
459
|
+
results ??= createMenu();
|
|
460
|
+
const rows = pageRows(found, (page) => { if (linkBox === box) keepPage(page); });
|
|
461
|
+
const first = Boolean(query) && !normalizeHref(query);
|
|
462
|
+
if (results.isOpen) results.update(rows, undefined, { first });
|
|
463
|
+
else results.open(rows, null, { inside: box.node, label: t("页面"), highlight: first });
|
|
464
|
+
box.place();
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Enter in the field, once the list is read (a moment, at the very start, in which another Enter is
|
|
468
|
+
// nothing more): nothing changed for a link
|
|
469
|
+
// left as it was; else the row highlighted (the one the keys moved to, or the first of what is no
|
|
470
|
+
// address); else what reads as an address, or a page block's own rule; else it says so and the card stays.
|
|
471
|
+
async function enterField(box) {
|
|
472
|
+
if (box.entered) return;
|
|
473
|
+
box.entered = true;
|
|
474
|
+
readList(box);
|
|
475
|
+
await box.reading;
|
|
476
|
+
box.entered = false;
|
|
477
|
+
if (linkBox !== box) return;
|
|
478
|
+
const value = box.input.value.trim();
|
|
479
|
+
if (box.link && value === box.shown) return setLink(value);
|
|
480
|
+
if (!results?.isOpen) search(box); // what a paste did not look for
|
|
481
|
+
if (results?.isOpen && results.hasChoice) return void results.choose();
|
|
482
|
+
if (box.asksPage) return enterPage(box, value);
|
|
483
|
+
if (normalizeHref(value) === null && !unsafe(value)) return use.say(t("没有找到这个页面。"), "error");
|
|
484
|
+
setLink(value);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Enter in a page block's field with no row to take: nothing typed is Esc; an address is the page it
|
|
488
|
+
// names, or no page of the workspace, said with the card staying; words found nothing, and make a
|
|
489
|
+
// new page of them under this one, the card holding what was typed until the answer comes. The page
|
|
490
|
+
// stays as it is, the caret too, and undo takes the block away, not the new page. What fails is said,
|
|
491
|
+
// the gray 页面 staying and the card open on the words.
|
|
492
|
+
async function enterPage(box, value) {
|
|
493
|
+
if (!value) return closeLink();
|
|
494
|
+
const address = typedHref(value);
|
|
495
|
+
const page = address && box.workspace ? placeIn(box.workspace, address) : null;
|
|
496
|
+
if (page) return keepPage(page);
|
|
497
|
+
if (address || !use.subpage) return use.say(address ? t("这个地址不是工作区里的页面。") : t("没有找到这个页面。"), "error");
|
|
498
|
+
box.making = box.input.readOnly = true;
|
|
499
|
+
try {
|
|
500
|
+
const report = await use.subpage(value);
|
|
501
|
+
if (linkBox !== box) return;
|
|
502
|
+
keepPage({ ...report, block: null }, document.activeElement === box.input);
|
|
503
|
+
use.say(t("已新建子页面:{0}", report.title));
|
|
504
|
+
} catch (error) {
|
|
505
|
+
box.making = box.input.readOnly = false;
|
|
506
|
+
use.say(error.message, "error");
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// The card's view button: the link's view and ▾; a click opens its views below it (views.mjs), a
|
|
511
|
+
// pick closing the card and switching the link.
|
|
512
|
+
function viewButton(link) {
|
|
513
|
+
const button = element("button", { type: "button", class: "ge-link-view", "aria-haspopup": "menu", "aria-label": t("显示为"), html: `<span>${VIEWS[viewOf(link)].label}</span>${CHEVRON}` });
|
|
514
|
+
button.addEventListener("mousedown", (event) => event.preventDefault());
|
|
515
|
+
button.addEventListener("click", () => {
|
|
516
|
+
if (button.getAttribute("aria-expanded") === "true") return closeViews();
|
|
517
|
+
if (!linkBox) return;
|
|
518
|
+
linkBox.held = true;
|
|
519
|
+
clearTimeout(hoverTimer);
|
|
520
|
+
button.setAttribute("aria-expanded", "true");
|
|
521
|
+
const rect = button.getBoundingClientRect();
|
|
522
|
+
openViews(link, { left: rect.left, right: rect.right, top: rect.top, bottom: rect.bottom }, () => closeLink(false), () => {
|
|
523
|
+
button.setAttribute("aria-expanded", "false");
|
|
524
|
+
if (linkBox) linkBox.held = false;
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
tooltip(button, t("显示为"));
|
|
528
|
+
return button;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// What the link leads to, as an address that opens it from anywhere (a document's, a block's), else as it stands.
|
|
532
|
+
function copyLink(value, link) {
|
|
533
|
+
const href = fieldHref(value, link);
|
|
534
|
+
if (!href) return use.say(t("还没有链接地址。"));
|
|
535
|
+
copyAddress(wholeAddress(href) ?? href, use.say);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// The link the whole range sits in, if any.
|
|
539
|
+
export function linkAround(host, range) {
|
|
540
|
+
const start = range.commonAncestorContainer;
|
|
541
|
+
const anchor = (start.nodeType === 1 ? start : start.parentElement).closest("a");
|
|
542
|
+
return anchor && host.contains(anchor) ? anchor : null;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
const unsafe = (value) => /^(javascript|vbscript|data):/i.test(value.replace(/[\u0000- ]/g, ""));
|
|
546
|
+
|
|
547
|
+
// The list a card goes by: its own, or the one held until that comes.
|
|
548
|
+
const listOf = () => linkBox?.workspace ?? heldList();
|
|
549
|
+
|
|
550
|
+
// A document that a card's address names in its list, or null (#<id> within a page stays a link to it).
|
|
551
|
+
const listed = (href) => (href && !href.startsWith("#") ? placeIn(listOf(), href) : null);
|
|
552
|
+
|
|
553
|
+
// The words for a link to `href`, where there is nothing to say of it but what it leads to: `page`'s
|
|
554
|
+
// title, the title of a page in the trash, else the address.
|
|
555
|
+
const wordsFor = (href, page) => page?.title ?? (href && titleIn(listOf(), href)) ?? href;
|
|
556
|
+
|
|
557
|
+
// The href of what is typed in the card (links/address.mjs typedHref), "" for an empty field, null
|
|
558
|
+
// for what is no address or is unsafe; the address of a document of the workspace as a file writes it
|
|
559
|
+
// (one on another server only if the list holds it, pages.mjs placeIn, for it may be another program's,
|
|
560
|
+
// and a click asks the list; so is a workbench's address, which only the list reads).
|
|
561
|
+
export function normalizeHref(value) {
|
|
562
|
+
const href = value.trim();
|
|
563
|
+
if (unsafe(href)) return null;
|
|
564
|
+
const typed = typedHref(href);
|
|
565
|
+
const place = listed(typed) ?? (use && elsewhere(typed, location.origin) ? null : pageAddress(typed));
|
|
566
|
+
return place ? fileLink(place, use?.slug) : typed;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// The href of what the card's field says for `link`: what the field was given for it stands.
|
|
570
|
+
const fieldHref = (value, link) => (link && value.trim() === linkBox?.shown ? hrefOf(link) : normalizeHref(value));
|
|
571
|
+
|
|
572
|
+
/** Keep what the card's field says (`null`: take the link away) and close the card; `restore`: the
|
|
573
|
+
* selection goes back to the text (not after a press elsewhere, which puts the caret there). */
|
|
574
|
+
export function setLink(value, restore = true) {
|
|
575
|
+
const href = value === null ? "" : fieldHref(value, linkBox.link);
|
|
576
|
+
if (href === null) {
|
|
577
|
+
use.say(t("不支持这种链接地址。"), "error");
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
keep(href, restore, listed(href));
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// A page chosen from the list (a row, Enter): the link leads to it.
|
|
584
|
+
const keepPage = (page, restore = true) => keep(fileLink(page, use.slug), restore, page);
|
|
585
|
+
|
|
586
|
+
// The link leads to `href` (`page`: the document of the list it is an address of), the card closing.
|
|
587
|
+
function keep(href, restore, page) {
|
|
588
|
+
const { host, range, link, fresh } = linkBox;
|
|
589
|
+
if (fresh) return setFresh(href, restore, page);
|
|
590
|
+
closeLink(restore);
|
|
591
|
+
if (link && href === hrefOf(link)) return; // nothing changed
|
|
592
|
+
// A link shown with its icon: taken away, its title stays; its address changed, read again.
|
|
593
|
+
if (link && isMention(link)) {
|
|
594
|
+
if (href) return void refetch(link, href, page);
|
|
595
|
+
const before = ownHTML(host);
|
|
596
|
+
link.replaceWith(mentionOf(link).title);
|
|
597
|
+
use.recordStep(host, before);
|
|
598
|
+
use.say(t("链接已移除。"));
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
const before = ownHTML(host);
|
|
602
|
+
const entry = link?.classList.contains(DIALOG_TRIGGER);
|
|
603
|
+
if (link && !href) link.replaceWith(...link.childNodes);
|
|
604
|
+
else if (link) link.setAttribute("href", href);
|
|
605
|
+
else if (href) {
|
|
606
|
+
const anchor = document.createElement("a");
|
|
607
|
+
anchor.setAttribute("href", href);
|
|
608
|
+
const content = range.extractContents();
|
|
609
|
+
content.querySelectorAll("a").forEach((inner) => inner.replaceWith(...(isMention(inner) ? [mentionOf(inner).title] : inner.childNodes)));
|
|
610
|
+
anchor.append(content.textContent ? content : document.createTextNode(wordsFor(href, page))); // at a caret: its address, or a page's title
|
|
611
|
+
range.insertNode(anchor);
|
|
612
|
+
if (restore) {
|
|
613
|
+
const after = document.createRange();
|
|
614
|
+
after.setStartAfter(anchor);
|
|
615
|
+
select(after);
|
|
616
|
+
}
|
|
617
|
+
} else return;
|
|
618
|
+
use.recordStep(host, before);
|
|
619
|
+
use.say(href ? t("链接:{0}", wordsFor(href, page)) : entry ? t("入口已移除:页面上没有地方能打开这张详情卡片了 · Ctrl+Z 撤销") : t("链接已移除。"));
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// The gray 链接 given its address: a link of it in its place, its words the address or a page's title
|
|
623
|
+
// (`page`), one undo step; Enter (restore) puts the caret after it and offers its views. Nothing
|
|
624
|
+
// given: it stays (leaveEmpty).
|
|
625
|
+
function setFresh(href, restore, page = null) {
|
|
626
|
+
const { host, fresh, asksPage } = linkBox;
|
|
627
|
+
linkBox.fresh = null; // closed as it is now
|
|
628
|
+
closeLink(false);
|
|
629
|
+
if (!host.isConnected || !fresh.chip.isConnected) return;
|
|
630
|
+
if (!href) return leaveEmpty(host, fresh, restore);
|
|
631
|
+
let link = asksPage ? pageChip(page) : null;
|
|
632
|
+
if (!link) {
|
|
633
|
+
link = document.createElement("a");
|
|
634
|
+
link.setAttribute("href", href);
|
|
635
|
+
link.textContent = wordsFor(href, page);
|
|
636
|
+
}
|
|
637
|
+
fresh.chip.replaceWith(link);
|
|
638
|
+
if (restore) {
|
|
639
|
+
host.focus({ preventScroll: true });
|
|
640
|
+
const after = document.createRange();
|
|
641
|
+
after.setStartAfter(link);
|
|
642
|
+
after.collapse(true);
|
|
643
|
+
select(after);
|
|
644
|
+
}
|
|
645
|
+
use.recordStep(host, fresh.before);
|
|
646
|
+
use.say(t("链接:{0}", wordsFor(href, page)));
|
|
647
|
+
if (restore) offerViews(link);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/** The open link card, if any (the editor's UI moves it into an open dialog). */
|
|
651
|
+
export const linkBoxNode = () => linkBox?.node ?? null;
|
|
652
|
+
|
|
653
|
+
/** The card and its views' menus (the editor's UI moves them into an open dialog). */
|
|
654
|
+
export const linkNodes = () => [linkBox?.node, ...viewNodes()].filter(Boolean);
|
|
655
|
+
|
|
656
|
+
/** Whether a press on `target` is one on the card or its views (no press elsewhere). */
|
|
657
|
+
export const linkHolds = (target) => Boolean(linkBox?.node.contains(target) || viewsHold(target));
|
|
658
|
+
|
|
659
|
+
/** Whether a gray 链接 or 页面 waits for its address (nothing is committed meanwhile). */
|
|
660
|
+
export const linkPending = () => Boolean(linkBox?.fresh);
|
|
661
|
+
|
|
662
|
+
// What an address of this computer names in the list the server gives: a page (pages.mjs placeIn), or
|
|
663
|
+
// null for any other address, or no answer.
|
|
664
|
+
async function listedPage(address) {
|
|
665
|
+
const list = await readPages(use.own());
|
|
666
|
+
return list && placeIn(list, address);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Whether a page alone in a tab may leave for a workbench's `hash`, which only the list reads: not for
|
|
671
|
+
* one that names no document, said as the workbench says it, the page staying. With no answer it goes,
|
|
672
|
+
* for the workbench to say.
|
|
673
|
+
*/
|
|
674
|
+
export async function leadsToPage(hash) {
|
|
675
|
+
const list = await readPages(use.own());
|
|
676
|
+
if (!list || placeIn(list, `#${hash}`)) return true;
|
|
677
|
+
use.say(inTrash(list.trash, hash) ? t("这个页面已删除。") : t("没有找到这个页面。"));
|
|
678
|
+
return false;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* A page block just pasted, shown as the server draws one (render/page-chips.mjs): the title its
|
|
683
|
+
* document has now and its icon, from the list. What the file says of it stays what was copied, and
|
|
684
|
+
* one the list does not hold stays as it came. The blocks of one paste read the list once.
|
|
685
|
+
*/
|
|
686
|
+
export async function drawPasted(chip) {
|
|
687
|
+
if (!isPageChip(chip)) return;
|
|
688
|
+
pasted ??= readPages(use.own()).finally(() => { pasted = null; });
|
|
689
|
+
const list = await pasted;
|
|
690
|
+
const page = list && placeIn(list, fromFile(hrefOf(chip), use.slug, location.origin));
|
|
691
|
+
if (page && chip.isConnected) chip.replaceChildren(...pageChip(page).childNodes);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* What an address of this computer is when it is a document's, in the list (a paste, which can wait: a
|
|
696
|
+
* workbench's address needs the list): the page and its block (placeIn) with `href`, the link this
|
|
697
|
+
* document's file writes to it; null for any other address, or no answer.
|
|
698
|
+
*/
|
|
699
|
+
export async function pageLinkOf(address) {
|
|
700
|
+
const page = await listedPage(address);
|
|
701
|
+
return page && { ...page, href: fileLink(page, use.slug) };
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// ---------- following links ----------
|
|
705
|
+
|
|
706
|
+
export const linkOf = (target) => target?.nodeType === 1 && editable(target) ? target.closest("a[href]") : null;
|
|
707
|
+
|
|
708
|
+
// What a link's #<id> says, or null for a link that is no such thing.
|
|
709
|
+
function anchorOf(link) {
|
|
710
|
+
const href = hrefOf(link);
|
|
711
|
+
return href.startsWith("#") && href.length > 1 ? decoded(href.slice(1)) : null;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const targetOf = (link) => {
|
|
715
|
+
const id = anchorOf(link);
|
|
716
|
+
return id === null ? null : document.getElementById(id);
|
|
717
|
+
};
|
|
718
|
+
|
|
719
|
+
// The document of the workspace, or block of one, that `address` is the address of, as `go` takes it,
|
|
720
|
+
// or null. A workbench's address comes with its hash, for only the list can say what that names.
|
|
721
|
+
function placeOf(address) {
|
|
722
|
+
const hash = workbenchHash(address);
|
|
723
|
+
const place = pageAddress(address);
|
|
724
|
+
return place || hash !== null ? { ...place, hash } : null;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// A new tab. A plain click brings it to the front; with Ctrl or ⌘ held the browser leaves it behind
|
|
728
|
+
// the page, as for any link.
|
|
729
|
+
const openTab = (url) => window.open(url, "_blank", "noopener");
|
|
730
|
+
|
|
731
|
+
// Where the selection stands.
|
|
732
|
+
function selectionNow() {
|
|
733
|
+
const { anchorNode, anchorOffset, focusNode, focusOffset } = getSelection();
|
|
734
|
+
return [anchorNode, anchorOffset, focusNode, focusOffset];
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// Whether a click on a link in the text is one that opens it: not the end of a drag in it (a pointer
|
|
738
|
+
// moved, or a selection the press made: a selection it came down on stands until after the click,
|
|
739
|
+
// and a press on a whole touches none), not a Shift or Alt click, not the second click of a double
|
|
740
|
+
// click, not the press that closed something open.
|
|
741
|
+
function opens(event) {
|
|
742
|
+
if (event.shiftKey || event.altKey || event.detail > 1) return false;
|
|
743
|
+
if (!press || event.detail === 0) return true;
|
|
744
|
+
if (press.keeps || Math.hypot(event.clientX - press.x, event.clientY - press.y) > DRAGGED) return false;
|
|
745
|
+
return getSelection().isCollapsed || selectionNow().every((part, index) => part === press.selection[index]);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// An address of this computer on another server: on this one if the list holds its document in the
|
|
749
|
+
// words it has now, a link outliving the server it was copied from; else another program's, or another
|
|
750
|
+
// workspace's page of one folder name, opened as any web address. A tab
|
|
751
|
+
// of its own opens with the click, the list read after, for only what the click itself opens does the
|
|
752
|
+
// browser leave behind the page.
|
|
753
|
+
async function followElsewhere(address, tab) {
|
|
754
|
+
const opened = tab ? window.open("", "_blank") : null;
|
|
755
|
+
const list = await readPages(use.own());
|
|
756
|
+
const page = list && placeIn(list, address);
|
|
757
|
+
const here = page && fullAddress(location.origin, page, list.links);
|
|
758
|
+
if (opened) {
|
|
759
|
+
opened.opener = null;
|
|
760
|
+
opened.location.replace(here ?? address);
|
|
761
|
+
} else if (page) use.go(page, here);
|
|
762
|
+
else openTab(address);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// Go where `href`, a link of this page that is no anchor, leads, read as its file reads it, so that
|
|
766
|
+
// doc.html beside it is this document: a document's address there, with `tab` in a tab of its own, a
|
|
767
|
+
// workbench at its link, by the list held (an id, with none, opens it all the same); a file of the
|
|
768
|
+
// report's folder (assets/<file>) in a new tab, where the preview serves it, and any other address too.
|
|
769
|
+
function follow(href, tab) {
|
|
770
|
+
const address = fromFile(href, use.slug, location.origin);
|
|
771
|
+
if (!address) return;
|
|
772
|
+
if (elsewhere(address, location.origin)) return void followElsewhere(address, tab);
|
|
773
|
+
const place = placeOf(address);
|
|
774
|
+
const file = referencedFile(href);
|
|
775
|
+
if (place && !tab) use.go(place, address);
|
|
776
|
+
else if (place?.slug) openTab(fullAddress(location.origin, place, heldList().named));
|
|
777
|
+
else openTab(file ? use.served(file) : address);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// A page block whose document is not there: deleted when the trash holds it, else there never was
|
|
781
|
+
// one, as the workbench and a presentation say it.
|
|
782
|
+
async function sayGone(link) {
|
|
783
|
+
const slug = pageAddress(fromFile(hrefOf(link), use.slug))?.slug ?? "";
|
|
784
|
+
use.say((await trashed(slug)) ? t("这个页面已删除。") : t("没有找到这个页面。"));
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// Whether a link in the text is one that leads away: not an anchor, nor a link with no address.
|
|
788
|
+
const leadsAway = (link) => hrefOf(link) !== "" && !hrefOf(link).startsWith("#");
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* Follow a link in the text being edited (its click): a detail card's opens it, an anchor's goes to
|
|
792
|
+
* its block or says it is gone, a document's goes there, any other opens in a new tab.
|
|
793
|
+
*/
|
|
794
|
+
export function followLink(event, link) {
|
|
795
|
+
clearTimeout(hoverTimer);
|
|
796
|
+
event.preventDefault();
|
|
797
|
+
if (!opens(event)) return;
|
|
798
|
+
if (link.hasAttribute("data-doc-gone")) sayGone(link);
|
|
799
|
+
else if (targetOf(link) instanceof HTMLDialogElement) openEntry(link, event);
|
|
800
|
+
else if (anchorOf(link) !== null) use.reveal(anchorOf(link));
|
|
801
|
+
else if (leadsAway(link)) follow(hrefOf(link), event.ctrlKey || event.metaKey);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// A click on a link of the page outside editable text (a block the page does not edit, a card an
|
|
805
|
+
// Agent wrote, a figure drawn in SVG, whose links have an object for an href, and may write it
|
|
806
|
+
// xlink:href) while editing, last of all (the document, as it bubbles; what took the click is left
|
|
807
|
+
// alone), by the rules of a link in the text: a document's goes there and a web address to a new tab,
|
|
808
|
+
// or it would take the page with it, and in a workbench the frame (not by the press that closed
|
|
809
|
+
// something open); a link to a block of the page goes to it; a link with no address goes nowhere,
|
|
810
|
+
// where it would load the page again. What the browser or the kit does with a click stays theirs: a
|
|
811
|
+
// link to save (a file block's), one of a target of its own (a bookmark's card), any other anchor,
|
|
812
|
+
// any click with a key held.
|
|
813
|
+
function followOutside(event) {
|
|
814
|
+
if (!use.active() || event.defaultPrevented || event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) return;
|
|
815
|
+
const link = event.target.closest?.("main a[*|href]");
|
|
816
|
+
if (!link || link.matches("[download], [target]")) return;
|
|
817
|
+
if (link.matches("[*|href='']")) return event.preventDefault();
|
|
818
|
+
const href = link.href.baseVal ?? link.getAttribute("href");
|
|
819
|
+
const url = URL.parse(fromFile(href, use.slug, location.origin) ?? "");
|
|
820
|
+
if (!url || !/^https?:$/.test(url.protocol)) return;
|
|
821
|
+
const anchor = link.matches("[*|href^='#']") ? decoded(url.hash.slice(1)) : null;
|
|
822
|
+
if (anchor !== null && !document.querySelector(`[data-block-id="${CSS.escape(anchor)}"]`)) return;
|
|
823
|
+
event.preventDefault();
|
|
824
|
+
if (event.detail > 1 || press?.keeps) return;
|
|
825
|
+
if (anchor !== null) use.reveal(anchor);
|
|
826
|
+
else follow(href, false);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// ---------- an input method over a link ----------
|
|
830
|
+
|
|
831
|
+
// What replaces selected text takes the marks of its start (notion-lite's caretAnnotations), and what
|
|
832
|
+
// an input method puts in goes in as one. The browser takes a link for gone once its words are, and
|
|
833
|
+
// an entry's card with it: the link the selection starts in is kept here when a composition begins
|
|
834
|
+
// and put back around what it put in (a copy, as the one on the page may be gone by then).
|
|
835
|
+
let replacing = null; // { host, from: where the selection starts in its text, link: a copy of the link there }
|
|
836
|
+
|
|
837
|
+
function compositionBegun() {
|
|
838
|
+
replacing = null;
|
|
839
|
+
const selection = getSelection();
|
|
840
|
+
const range = selection.rangeCount && !selection.isCollapsed ? selection.getRangeAt(0) : null;
|
|
841
|
+
const host = range ? editable(range.startContainer) : null;
|
|
842
|
+
if (!host?.contains(range.endContainer)) return;
|
|
843
|
+
const [from] = rangeOffsets(host, range);
|
|
844
|
+
const { startContainer: first } = rangeAt(host, [from, from + 1]);
|
|
845
|
+
const link = (first.nodeType === 1 ? first : first.parentElement).closest("a[href]");
|
|
846
|
+
if (link && host.contains(link)) replacing = { host, from, link: link.cloneNode(false) };
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
function compositionEnded() {
|
|
850
|
+
const kept = replacing;
|
|
851
|
+
replacing = null;
|
|
852
|
+
const selection = getSelection();
|
|
853
|
+
if (!kept?.host.isConnected || !selection.rangeCount) return;
|
|
854
|
+
const { host, from, link } = kept;
|
|
855
|
+
const [, to] = rangeOffsets(host, selection.getRangeAt(0));
|
|
856
|
+
if (to <= from) return;
|
|
857
|
+
const words = rangeAt(host, [from, to]);
|
|
858
|
+
if (linkAround(host, words)) return; // the browser kept it
|
|
859
|
+
link.append(words.extractContents());
|
|
860
|
+
link.querySelectorAll("a").forEach((inner) => inner.replaceWith(...inner.childNodes));
|
|
861
|
+
words.insertNode(link);
|
|
862
|
+
link.parentNode.normalize();
|
|
863
|
+
joinMarks(link, link.nextSibling);
|
|
864
|
+
joinMarks(link.previousSibling, link);
|
|
865
|
+
select(rangeAt(host, [to, to]));
|
|
866
|
+
}
|