@prosekit/extensions 0.11.3 → 0.11.5
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/dist/commit/style.css +2 -0
- package/dist/commit/style.css.map +1 -0
- package/dist/commit/style.js +1 -0
- package/dist/{drop-indicator-B8P652g2.js → drop-indicator-D1eHOhSi.js} +6 -5
- package/dist/drop-indicator-D1eHOhSi.js.map +1 -0
- package/dist/enter-rule-RdhEA900.js +2 -1
- package/dist/enter-rule-RdhEA900.js.map +1 -0
- package/dist/gap-cursor/style.css +2 -0
- package/dist/gap-cursor/style.css.map +1 -0
- package/dist/gap-cursor/style.js +1 -0
- package/dist/{input-rule-Gji4N7Oe.js → input-rule-B17tpW4m.js} +3 -3
- package/dist/input-rule-B17tpW4m.js.map +1 -0
- package/dist/list/style.css +2 -0
- package/dist/list/style.css.map +1 -0
- package/dist/list/style.js +1 -0
- package/dist/loro/style.css +2 -0
- package/dist/loro/style.css.map +1 -0
- package/dist/loro/style.js +1 -0
- package/dist/{mark-rule-D7zaa32n.js → mark-rule-BCqIZMDu.js} +3 -3
- package/dist/mark-rule-BCqIZMDu.js.map +1 -0
- package/dist/{paste-rule-Cca3n5TA.js → paste-rule-DIEJKIje.js} +5 -15
- package/dist/paste-rule-DIEJKIje.js.map +1 -0
- package/dist/placeholder/style.css +2 -0
- package/dist/placeholder/style.css.map +1 -0
- package/dist/placeholder/style.js +1 -0
- package/dist/prosekit-extensions-autocomplete.d.ts +2 -1
- package/dist/prosekit-extensions-autocomplete.d.ts.map +1 -0
- package/dist/prosekit-extensions-autocomplete.js +2 -9
- package/dist/prosekit-extensions-autocomplete.js.map +1 -0
- package/dist/prosekit-extensions-blockquote.d.ts +2 -1
- package/dist/prosekit-extensions-blockquote.d.ts.map +1 -0
- package/dist/prosekit-extensions-blockquote.js +4 -4
- package/dist/prosekit-extensions-blockquote.js.map +1 -0
- package/dist/prosekit-extensions-bold.d.ts +2 -1
- package/dist/prosekit-extensions-bold.d.ts.map +1 -0
- package/dist/prosekit-extensions-bold.js +3 -2
- package/dist/prosekit-extensions-bold.js.map +1 -0
- package/dist/prosekit-extensions-code-block.d.ts +2 -1
- package/dist/prosekit-extensions-code-block.d.ts.map +1 -0
- package/dist/prosekit-extensions-code-block.js +5 -6
- package/dist/prosekit-extensions-code-block.js.map +1 -0
- package/dist/prosekit-extensions-code.d.ts +2 -1
- package/dist/prosekit-extensions-code.d.ts.map +1 -0
- package/dist/prosekit-extensions-code.js +3 -2
- package/dist/prosekit-extensions-code.js.map +1 -0
- package/dist/prosekit-extensions-commit.d.ts +2 -1
- package/dist/prosekit-extensions-commit.d.ts.map +1 -0
- package/dist/prosekit-extensions-commit.js +11 -13
- package/dist/prosekit-extensions-commit.js.map +1 -0
- package/dist/prosekit-extensions-doc.d.ts +2 -1
- package/dist/prosekit-extensions-doc.d.ts.map +1 -0
- package/dist/prosekit-extensions-doc.js +2 -1
- package/dist/prosekit-extensions-doc.js.map +1 -0
- package/dist/prosekit-extensions-drop-cursor.d.ts +2 -1
- package/dist/prosekit-extensions-drop-cursor.d.ts.map +1 -0
- package/dist/prosekit-extensions-drop-cursor.js +2 -1
- package/dist/prosekit-extensions-drop-cursor.js.map +1 -0
- package/dist/prosekit-extensions-drop-indicator.d.ts +2 -1
- package/dist/prosekit-extensions-drop-indicator.d.ts.map +1 -0
- package/dist/prosekit-extensions-drop-indicator.js +1 -1
- package/dist/prosekit-extensions-enter-rule.d.ts +2 -1
- package/dist/prosekit-extensions-enter-rule.d.ts.map +1 -0
- package/dist/prosekit-extensions-file.d.ts +2 -1
- package/dist/prosekit-extensions-file.d.ts.map +1 -0
- package/dist/prosekit-extensions-file.js +4 -16
- package/dist/prosekit-extensions-file.js.map +1 -0
- package/dist/prosekit-extensions-gap-cursor.d.ts +2 -2
- package/dist/prosekit-extensions-gap-cursor.d.ts.map +1 -0
- package/dist/prosekit-extensions-gap-cursor.js +2 -1
- package/dist/prosekit-extensions-gap-cursor.js.map +1 -0
- package/dist/prosekit-extensions-hard-break.d.ts +2 -1
- package/dist/prosekit-extensions-hard-break.d.ts.map +1 -0
- package/dist/prosekit-extensions-hard-break.js +2 -1
- package/dist/prosekit-extensions-hard-break.js.map +1 -0
- package/dist/prosekit-extensions-heading.d.ts +2 -1
- package/dist/prosekit-extensions-heading.d.ts.map +1 -0
- package/dist/prosekit-extensions-heading.js +5 -6
- package/dist/prosekit-extensions-heading.js.map +1 -0
- package/dist/prosekit-extensions-horizontal-rule.d.ts +2 -1
- package/dist/prosekit-extensions-horizontal-rule.d.ts.map +1 -0
- package/dist/prosekit-extensions-horizontal-rule.js +5 -6
- package/dist/prosekit-extensions-horizontal-rule.js.map +1 -0
- package/dist/prosekit-extensions-image.d.ts +2 -1
- package/dist/prosekit-extensions-image.d.ts.map +1 -0
- package/dist/prosekit-extensions-image.js +3 -3
- package/dist/prosekit-extensions-image.js.map +1 -0
- package/dist/prosekit-extensions-input-rule.d.ts +2 -1
- package/dist/prosekit-extensions-input-rule.d.ts.map +1 -0
- package/dist/prosekit-extensions-input-rule.js +1 -1
- package/dist/prosekit-extensions-italic.d.ts +2 -1
- package/dist/prosekit-extensions-italic.d.ts.map +1 -0
- package/dist/prosekit-extensions-italic.js +3 -2
- package/dist/prosekit-extensions-italic.js.map +1 -0
- package/dist/prosekit-extensions-link.d.ts +2 -1
- package/dist/prosekit-extensions-link.d.ts.map +1 -0
- package/dist/prosekit-extensions-link.js +6 -5
- package/dist/prosekit-extensions-link.js.map +1 -0
- package/dist/prosekit-extensions-list.d.ts +22 -21
- package/dist/prosekit-extensions-list.d.ts.map +1 -0
- package/dist/prosekit-extensions-list.js +6 -7
- package/dist/prosekit-extensions-list.js.map +1 -0
- package/dist/prosekit-extensions-loro.d.ts +14 -13
- package/dist/prosekit-extensions-loro.d.ts.map +1 -0
- package/dist/prosekit-extensions-loro.js +2 -1
- package/dist/prosekit-extensions-loro.js.map +1 -0
- package/dist/prosekit-extensions-mark-rule.d.ts +2 -1
- package/dist/prosekit-extensions-mark-rule.d.ts.map +1 -0
- package/dist/prosekit-extensions-mark-rule.js +1 -1
- package/dist/prosekit-extensions-mention.d.ts +2 -1
- package/dist/prosekit-extensions-mention.d.ts.map +1 -0
- package/dist/prosekit-extensions-mention.js +2 -1
- package/dist/prosekit-extensions-mention.js.map +1 -0
- package/dist/prosekit-extensions-mod-click-prevention.d.ts +2 -1
- package/dist/prosekit-extensions-mod-click-prevention.d.ts.map +1 -0
- package/dist/prosekit-extensions-mod-click-prevention.js +2 -1
- package/dist/prosekit-extensions-mod-click-prevention.js.map +1 -0
- package/dist/prosekit-extensions-paragraph.d.ts +2 -1
- package/dist/prosekit-extensions-paragraph.d.ts.map +1 -0
- package/dist/prosekit-extensions-paragraph.js +2 -1
- package/dist/prosekit-extensions-paragraph.js.map +1 -0
- package/dist/prosekit-extensions-paste-rule.d.ts +2 -1
- package/dist/prosekit-extensions-paste-rule.d.ts.map +1 -0
- package/dist/prosekit-extensions-paste-rule.js +1 -1
- package/dist/prosekit-extensions-placeholder.d.ts +2 -1
- package/dist/prosekit-extensions-placeholder.d.ts.map +1 -0
- package/dist/prosekit-extensions-placeholder.js +5 -4
- package/dist/prosekit-extensions-placeholder.js.map +1 -0
- package/dist/prosekit-extensions-readonly.d.ts +2 -1
- package/dist/prosekit-extensions-readonly.d.ts.map +1 -0
- package/dist/prosekit-extensions-readonly.js +2 -1
- package/dist/prosekit-extensions-readonly.js.map +1 -0
- package/dist/prosekit-extensions-search.d.ts +2 -1
- package/dist/prosekit-extensions-search.d.ts.map +1 -0
- package/dist/prosekit-extensions-search.js +3 -3
- package/dist/prosekit-extensions-search.js.map +1 -0
- package/dist/prosekit-extensions-strike.d.ts +2 -1
- package/dist/prosekit-extensions-strike.d.ts.map +1 -0
- package/dist/prosekit-extensions-strike.js +3 -2
- package/dist/prosekit-extensions-strike.js.map +1 -0
- package/dist/prosekit-extensions-table.d.ts +56 -114
- package/dist/prosekit-extensions-table.d.ts.map +1 -0
- package/dist/prosekit-extensions-table.js +3 -2
- package/dist/prosekit-extensions-text-align.d.ts +2 -1
- package/dist/prosekit-extensions-text-align.d.ts.map +1 -0
- package/dist/prosekit-extensions-text-align.js +2 -1
- package/dist/prosekit-extensions-text-align.js.map +1 -0
- package/dist/prosekit-extensions-text.d.ts +2 -1
- package/dist/prosekit-extensions-text.d.ts.map +1 -0
- package/dist/prosekit-extensions-text.js +2 -1
- package/dist/prosekit-extensions-text.js.map +1 -0
- package/dist/prosekit-extensions-underline.d.ts +2 -1
- package/dist/prosekit-extensions-underline.d.ts.map +1 -0
- package/dist/prosekit-extensions-underline.js +2 -1
- package/dist/prosekit-extensions-underline.js.map +1 -0
- package/dist/prosekit-extensions-virtual-selection.d.ts +2 -1
- package/dist/prosekit-extensions-virtual-selection.d.ts.map +1 -0
- package/dist/prosekit-extensions-virtual-selection.js +3 -3
- package/dist/prosekit-extensions-virtual-selection.js.map +1 -0
- package/dist/prosekit-extensions-yjs.d.ts +2 -1
- package/dist/prosekit-extensions-yjs.d.ts.map +1 -0
- package/dist/prosekit-extensions-yjs.js +2 -1
- package/dist/prosekit-extensions-yjs.js.map +1 -0
- package/dist/prosekit-extensions.d.ts +1 -1
- package/dist/prosekit-extensions.js +1 -0
- package/dist/search/style.css +2 -0
- package/dist/search/style.css.map +1 -0
- package/dist/search/style.js +1 -0
- package/dist/shiki-highlighter-chunk-DSPM0T27.d.ts +2 -1
- package/dist/shiki-highlighter-chunk-DSPM0T27.d.ts.map +1 -0
- package/dist/shiki-highlighter-chunk.js +3 -5
- package/dist/shiki-highlighter-chunk.js.map +1 -0
- package/dist/table/style.css +2 -0
- package/dist/table/style.css.map +1 -0
- package/dist/table/style.js +1 -0
- package/dist/table-Bi7WsMI3.js +297 -0
- package/dist/table-Bi7WsMI3.js.map +1 -0
- package/dist/virtual-selection/style.css +2 -0
- package/dist/virtual-selection/style.css.map +1 -0
- package/dist/virtual-selection/style.js +1 -0
- package/dist/yjs/style.css +2 -0
- package/dist/yjs/style.css.map +1 -0
- package/dist/yjs/style.js +1 -0
- package/package.json +10 -9
- package/src/autocomplete/autocomplete-helpers.ts +74 -0
- package/src/autocomplete/autocomplete-plugin.ts +186 -0
- package/src/autocomplete/autocomplete-rule.ts +117 -0
- package/src/autocomplete/autocomplete.spec.ts +132 -0
- package/src/autocomplete/autocomplete.ts +29 -0
- package/src/autocomplete/index.ts +9 -0
- package/src/blockquote/blockquote-commands.ts +32 -0
- package/src/blockquote/blockquote-input-rule.ts +14 -0
- package/src/blockquote/blockquote-keymap.spec.ts +45 -0
- package/src/blockquote/blockquote-keymap.ts +31 -0
- package/src/blockquote/blockquote-spec.ts +24 -0
- package/src/blockquote/blockquote.ts +34 -0
- package/src/blockquote/index.ts +14 -0
- package/src/bold/bold-commands.ts +23 -0
- package/src/bold/bold-input-rule.spec.ts +51 -0
- package/src/bold/bold-input-rule.ts +18 -0
- package/src/bold/bold-keymap.ts +14 -0
- package/src/bold/bold-spec.ts +53 -0
- package/src/bold/bold.ts +32 -0
- package/src/bold/index.ts +14 -0
- package/src/code/code-commands.ts +23 -0
- package/src/code/code-input-rule.ts +18 -0
- package/src/code/code-keymap.ts +14 -0
- package/src/code/code-spec.ts +28 -0
- package/src/code/code.ts +32 -0
- package/src/code/index.ts +14 -0
- package/src/code-block/code-block-commands.ts +44 -0
- package/src/code-block/code-block-highlight.ts +40 -0
- package/src/code-block/code-block-input-rule.ts +36 -0
- package/src/code-block/code-block-keymap.ts +61 -0
- package/src/code-block/code-block-shiki.ts +58 -0
- package/src/code-block/code-block-spec.spec.ts +164 -0
- package/src/code-block/code-block-spec.ts +71 -0
- package/src/code-block/code-block-types.ts +8 -0
- package/src/code-block/code-block.ts +46 -0
- package/src/code-block/index.ts +32 -0
- package/src/code-block/shiki-bundle.ts +8 -0
- package/src/code-block/shiki-highlighter-chunk.ts +84 -0
- package/src/code-block/shiki-highlighter.ts +22 -0
- package/src/code-block/shiki-parser.ts +36 -0
- package/src/commit/index.ts +330 -0
- package/src/commit/style.css +7 -0
- package/src/doc/index.ts +21 -0
- package/src/drop-cursor/drop-cursor.ts +46 -0
- package/src/drop-cursor/index.ts +5 -0
- package/src/drop-indicator/drop-indicator-facet.ts +84 -0
- package/src/drop-indicator/drop-indicator-plugin.ts +147 -0
- package/src/drop-indicator/drop-indicator.ts +37 -0
- package/src/drop-indicator/drop-target.ts +168 -0
- package/src/drop-indicator/index.ts +14 -0
- package/src/drop-indicator/types.ts +90 -0
- package/src/enter-rule/index.ts +241 -0
- package/src/file/file-drop-handler.ts +75 -0
- package/src/file/file-paste-handler.spec.ts +95 -0
- package/src/file/file-paste-handler.ts +59 -0
- package/src/file/file-upload.ts +119 -0
- package/src/file/helpers.ts +39 -0
- package/src/file/index.ts +16 -0
- package/src/gap-cursor/gap-cursor.ts +28 -0
- package/src/gap-cursor/index.ts +4 -0
- package/src/gap-cursor/style.css +25 -0
- package/src/hard-break/hard-break-commands.ts +31 -0
- package/src/hard-break/hard-break-keymap.spec.ts +45 -0
- package/src/hard-break/hard-break-keymap.ts +16 -0
- package/src/hard-break/hard-break-spec.ts +31 -0
- package/src/hard-break/hard-break.ts +32 -0
- package/src/hard-break/index.ts +13 -0
- package/src/heading/heading-commands.ts +37 -0
- package/src/heading/heading-input-rule.ts +22 -0
- package/src/heading/heading-keymap.spec.ts +53 -0
- package/src/heading/heading-keymap.ts +40 -0
- package/src/heading/heading-spec.ts +39 -0
- package/src/heading/heading-types.ts +3 -0
- package/src/heading/heading.ts +34 -0
- package/src/heading/index.ts +15 -0
- package/src/horizontal-rule/horizontal-rule-commands.spec.ts +61 -0
- package/src/horizontal-rule/horizontal-rule-commands.ts +37 -0
- package/src/horizontal-rule/horizontal-rule-input-rule.spec.ts +61 -0
- package/src/horizontal-rule/horizontal-rule-input-rule.ts +26 -0
- package/src/horizontal-rule/horizontal-rule-spec.ts +21 -0
- package/src/horizontal-rule/horizontal-rule.ts +29 -0
- package/src/horizontal-rule/index.ts +14 -0
- package/src/image/image-commands.ts +27 -0
- package/src/image/image-spec.ts +72 -0
- package/src/image/image.ts +25 -0
- package/src/image/index.ts +13 -0
- package/src/index.ts +1 -0
- package/src/input-rule/index.ts +237 -0
- package/src/italic/index.ts +14 -0
- package/src/italic/italic-commands.spec.ts +75 -0
- package/src/italic/italic-commands.ts +23 -0
- package/src/italic/italic-input-rule.spec.ts +25 -0
- package/src/italic/italic-input-rule.ts +18 -0
- package/src/italic/italic-keymap.ts +14 -0
- package/src/italic/italic-spec.ts +35 -0
- package/src/italic/italic.ts +34 -0
- package/src/link/index.spec.ts +88 -0
- package/src/link/index.ts +156 -0
- package/src/link/link-paste-rule.spec.ts +194 -0
- package/src/link/link-paste-rule.ts +22 -0
- package/src/link/link-regex.spec.ts +82 -0
- package/src/link/link-regex.ts +79 -0
- package/src/link/link-types.ts +8 -0
- package/src/list/index.ts +25 -0
- package/src/list/list-commands.ts +61 -0
- package/src/list/list-drop-indicator.ts +37 -0
- package/src/list/list-input-rules.ts +14 -0
- package/src/list/list-keymap.spec.ts +39 -0
- package/src/list/list-keymap.ts +48 -0
- package/src/list/list-plugins.ts +35 -0
- package/src/list/list-serializer.ts +38 -0
- package/src/list/list-spec.ts +60 -0
- package/src/list/list-types.spec.ts +10 -0
- package/src/list/list-types.ts +23 -0
- package/src/list/list.spec.ts +134 -0
- package/src/list/list.ts +38 -0
- package/src/list/style.css +128 -0
- package/src/loro/index.ts +17 -0
- package/src/loro/loro-commands.ts +27 -0
- package/src/loro/loro-cursor-plugin.ts +28 -0
- package/src/loro/loro-keymap.ts +23 -0
- package/src/loro/loro-sync-plugin.ts +14 -0
- package/src/loro/loro-undo-plugin.ts +12 -0
- package/src/loro/loro.ts +75 -0
- package/src/loro/style.css +33 -0
- package/src/mark-rule/apply.ts +129 -0
- package/src/mark-rule/index.ts +2 -0
- package/src/mark-rule/mark-rule.spec.ts +123 -0
- package/src/mark-rule/mark-rule.ts +48 -0
- package/src/mark-rule/range.ts +107 -0
- package/src/mark-rule/types.ts +30 -0
- package/src/mention/index.ts +90 -0
- package/src/mod-click-prevention/index.ts +35 -0
- package/src/paragraph/index.ts +7 -0
- package/src/paragraph/paragraph-commands.ts +29 -0
- package/src/paragraph/paragraph-keymap.ts +15 -0
- package/src/paragraph/paragraph-spec.ts +31 -0
- package/src/paragraph/paragraph.ts +37 -0
- package/src/paste-rule/index.ts +10 -0
- package/src/paste-rule/mark-paste-rule.spec.ts +112 -0
- package/src/paste-rule/mark-paste-rule.ts +194 -0
- package/src/paste-rule/paste-rule-plugin.ts +53 -0
- package/src/paste-rule/paste-rule.spec.ts +96 -0
- package/src/paste-rule/paste-rule.ts +60 -0
- package/src/paste-rule/split-text-by-regex.spec.ts +97 -0
- package/src/paste-rule/split-text-by-regex.ts +44 -0
- package/src/placeholder/index.ts +113 -0
- package/src/placeholder/style.css +7 -0
- package/src/readonly/index.ts +22 -0
- package/src/search/index.ts +140 -0
- package/src/search/style.css +13 -0
- package/src/strike/index.ts +101 -0
- package/src/table/index.ts +53 -0
- package/src/table/style.css +42 -0
- package/src/table/table-commands/delete-cell-selection.spec.ts +41 -0
- package/src/table/table-commands/delete-cell-selection.ts +1 -0
- package/src/table/table-commands/exit-table.spec.ts +45 -0
- package/src/table/table-commands/exit-table.ts +49 -0
- package/src/table/table-commands/insert-table.spec.ts +39 -0
- package/src/table/table-commands/insert-table.ts +80 -0
- package/src/table/table-commands/move-table-column.spec.ts +618 -0
- package/src/table/table-commands/move-table-column.ts +4 -0
- package/src/table/table-commands/move-table-row.spec.ts +380 -0
- package/src/table/table-commands/move-table-row.ts +4 -0
- package/src/table/table-commands/select-table-cell.spec.ts +34 -0
- package/src/table/table-commands/select-table-cell.ts +35 -0
- package/src/table/table-commands/select-table-column.spec.ts +33 -0
- package/src/table/table-commands/select-table-column.ts +39 -0
- package/src/table/table-commands/select-table-row.spec.ts +32 -0
- package/src/table/table-commands/select-table-row.ts +39 -0
- package/src/table/table-commands/select-table.spec.ts +36 -0
- package/src/table/table-commands/select-table.ts +50 -0
- package/src/table/table-commands.ts +110 -0
- package/src/table/table-drop-indicator.ts +40 -0
- package/src/table/table-plugins.ts +15 -0
- package/src/table/table-spec.spec.ts +113 -0
- package/src/table/table-spec.ts +109 -0
- package/src/table/table-utils.ts +16 -0
- package/src/table/table.ts +49 -0
- package/src/table/test-utils.ts +28 -0
- package/src/testing/clipboard.ts +58 -0
- package/src/testing/format-html.ts +5 -0
- package/src/testing/index.ts +161 -0
- package/src/testing/keyboard.ts +36 -0
- package/src/testing/markdown.ts +23 -0
- package/src/text/index.ts +24 -0
- package/src/text-align/index.ts +133 -0
- package/src/types/assert-type-equal.ts +8 -0
- package/src/underline/index.ts +83 -0
- package/src/virtual-selection/index.ts +100 -0
- package/src/virtual-selection/style.css +5 -0
- package/src/yjs/index.ts +22 -0
- package/src/yjs/style.css +31 -0
- package/src/yjs/yjs-commands.ts +27 -0
- package/src/yjs/yjs-cursor-plugin.ts +25 -0
- package/src/yjs/yjs-keymap.ts +23 -0
- package/src/yjs/yjs-sync-plugin.ts +23 -0
- package/src/yjs/yjs-undo-plugin.ts +87 -0
- package/src/yjs/yjs.ts +84 -0
- package/dist/table-C_qAMj5-.js +0 -734
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { EditorState } from '@prosekit/pm/state'
|
|
2
|
+
|
|
3
|
+
import { defaultCanMatch } from './autocomplete-helpers'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Options for the {@link MatchHandler} callback.
|
|
7
|
+
*/
|
|
8
|
+
export interface MatchHandlerOptions {
|
|
9
|
+
/**
|
|
10
|
+
* The editor state.
|
|
11
|
+
*/
|
|
12
|
+
state: EditorState
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The result of `RegExp.exec`.
|
|
16
|
+
*/
|
|
17
|
+
match: RegExpExecArray
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The start position of the matched text.
|
|
21
|
+
*/
|
|
22
|
+
from: number
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The end position of the matched text.
|
|
26
|
+
*/
|
|
27
|
+
to: number
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Call this function to ignore the match. You probably want to call this
|
|
31
|
+
* function when the user presses the `Escape` key.
|
|
32
|
+
*/
|
|
33
|
+
ignoreMatch: () => void
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Call this function to delete the matched text. For example, in a slash
|
|
37
|
+
* menu, you might want to delete the matched text first then do something
|
|
38
|
+
* else when the user presses the `Enter` key.
|
|
39
|
+
*/
|
|
40
|
+
deleteMatch: () => void
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A callback that is called when the rule starts to match, and also on
|
|
45
|
+
* subsequent updates while the rule continues to match.
|
|
46
|
+
*/
|
|
47
|
+
export type MatchHandler = (options: MatchHandlerOptions) => void
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Options for the {@link CanMatchPredicate} callback.
|
|
51
|
+
*/
|
|
52
|
+
export interface CanMatchOptions {
|
|
53
|
+
/**
|
|
54
|
+
* The editor state.
|
|
55
|
+
*/
|
|
56
|
+
state: EditorState
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A predicate to determine if the rule can be applied in the current editor state.
|
|
61
|
+
*/
|
|
62
|
+
export type CanMatchPredicate = (options: CanMatchOptions) => boolean
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Options for creating an {@link AutocompleteRule}
|
|
66
|
+
*/
|
|
67
|
+
export interface AutocompleteRuleOptions {
|
|
68
|
+
/**
|
|
69
|
+
* The regular expression to match against the text before the cursor. The
|
|
70
|
+
* last match before the cursor is used.
|
|
71
|
+
*
|
|
72
|
+
* For a slash menu, you might use `/(?<!\S)\/(|\S.*)$/u`.
|
|
73
|
+
* For a mention, you might use `/@\w*$/`
|
|
74
|
+
*/
|
|
75
|
+
regex: RegExp
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A callback that is called when the rule starts to match, and also on
|
|
79
|
+
* subsequent updates while the rule continues to match.
|
|
80
|
+
*/
|
|
81
|
+
onEnter: MatchHandler
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* A callback that is called when the rule stops matching.
|
|
85
|
+
*/
|
|
86
|
+
onLeave?: VoidFunction
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* A predicate to determine if the rule can be applied in the current editor
|
|
90
|
+
* state. If not provided, it defaults to only allowing matches in empty
|
|
91
|
+
* selections that are not inside a code block or code mark.
|
|
92
|
+
*/
|
|
93
|
+
canMatch?: CanMatchPredicate
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* An autocomplete rule that can be used to create an autocomplete extension.
|
|
98
|
+
*
|
|
99
|
+
* @public
|
|
100
|
+
*/
|
|
101
|
+
export class AutocompleteRule {
|
|
102
|
+
/** @internal */
|
|
103
|
+
readonly regex: RegExp
|
|
104
|
+
/** @internal */
|
|
105
|
+
readonly onMatch: MatchHandler
|
|
106
|
+
/** @internal */
|
|
107
|
+
readonly onLeave?: VoidFunction
|
|
108
|
+
/** @internal */
|
|
109
|
+
readonly canMatch: (options: { state: EditorState }) => boolean
|
|
110
|
+
|
|
111
|
+
constructor(options: AutocompleteRuleOptions) {
|
|
112
|
+
this.regex = options.regex
|
|
113
|
+
this.onMatch = options.onEnter
|
|
114
|
+
this.onLeave = options.onLeave
|
|
115
|
+
this.canMatch = options.canMatch ?? defaultCanMatch
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import {
|
|
2
|
+
canUseRegexLookbehind,
|
|
3
|
+
union,
|
|
4
|
+
} from '@prosekit/core'
|
|
5
|
+
import {
|
|
6
|
+
describe,
|
|
7
|
+
expect,
|
|
8
|
+
it,
|
|
9
|
+
vi,
|
|
10
|
+
} from 'vitest'
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
defineTestExtension,
|
|
14
|
+
setupTestFromExtension,
|
|
15
|
+
} from '../testing'
|
|
16
|
+
import {
|
|
17
|
+
inputText,
|
|
18
|
+
pressKey,
|
|
19
|
+
} from '../testing/keyboard'
|
|
20
|
+
|
|
21
|
+
import { defineAutocomplete } from './autocomplete'
|
|
22
|
+
import {
|
|
23
|
+
AutocompleteRule,
|
|
24
|
+
type MatchHandler,
|
|
25
|
+
type MatchHandlerOptions,
|
|
26
|
+
} from './autocomplete-rule'
|
|
27
|
+
|
|
28
|
+
function setupSlashMenu() {
|
|
29
|
+
const regex = canUseRegexLookbehind() ? /(?<!\S)\/(|\S.*)$/u : /\/(|\S.*)$/u
|
|
30
|
+
|
|
31
|
+
const onEnter = vi.fn<MatchHandler>()
|
|
32
|
+
const onLeave = vi.fn<VoidFunction>()
|
|
33
|
+
|
|
34
|
+
const rule = new AutocompleteRule({ regex, onEnter, onLeave })
|
|
35
|
+
const extension = union(defineTestExtension(), defineAutocomplete(rule))
|
|
36
|
+
const { editor, n, m } = setupTestFromExtension(extension)
|
|
37
|
+
|
|
38
|
+
const doc = n.doc(n.paragraph('<a>'))
|
|
39
|
+
editor.set(doc)
|
|
40
|
+
|
|
41
|
+
const getOnEnterOptions = (): MatchHandlerOptions => {
|
|
42
|
+
const parameters = onEnter.mock.calls.at(-1)
|
|
43
|
+
const options = parameters?.[0]
|
|
44
|
+
if (!options) {
|
|
45
|
+
throw new Error('No onEnter options found')
|
|
46
|
+
}
|
|
47
|
+
return options
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return { editor, n, m, onEnter, onLeave, getOnEnterOptions }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
describe('defineAutocomplete', () => {
|
|
54
|
+
it('can trigger onEnter', async () => {
|
|
55
|
+
const { onEnter, onLeave } = setupSlashMenu()
|
|
56
|
+
|
|
57
|
+
expect(onEnter).not.toHaveBeenCalled()
|
|
58
|
+
expect(onLeave).not.toHaveBeenCalled()
|
|
59
|
+
|
|
60
|
+
await inputText('/')
|
|
61
|
+
expect(onEnter).toHaveBeenCalledTimes(1)
|
|
62
|
+
|
|
63
|
+
await inputText('order')
|
|
64
|
+
expect(onEnter).toHaveBeenCalledTimes(6)
|
|
65
|
+
|
|
66
|
+
await inputText(' ')
|
|
67
|
+
expect(onEnter).toHaveBeenCalledTimes(7)
|
|
68
|
+
|
|
69
|
+
await inputText('list')
|
|
70
|
+
expect(onEnter).toHaveBeenCalledTimes(11)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('can trigger onLeave', async () => {
|
|
74
|
+
const { onEnter, onLeave } = setupSlashMenu()
|
|
75
|
+
|
|
76
|
+
expect(onEnter).not.toHaveBeenCalled()
|
|
77
|
+
expect(onLeave).not.toHaveBeenCalled()
|
|
78
|
+
|
|
79
|
+
// Slash menu should be triggered when typing "/"
|
|
80
|
+
await inputText('/')
|
|
81
|
+
expect(onEnter).toHaveBeenCalledTimes(1)
|
|
82
|
+
expect(onLeave).toHaveBeenCalledTimes(0)
|
|
83
|
+
|
|
84
|
+
// Slash menu should not be triggered when typing "/ "
|
|
85
|
+
await pressKey('Space')
|
|
86
|
+
expect(onEnter).toHaveBeenCalledTimes(1)
|
|
87
|
+
expect(onLeave).toHaveBeenCalledTimes(1)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('can delete the matched text', async () => {
|
|
91
|
+
const { editor, onEnter, getOnEnterOptions } = setupSlashMenu()
|
|
92
|
+
|
|
93
|
+
expect(onEnter).not.toHaveBeenCalled()
|
|
94
|
+
|
|
95
|
+
await inputText('/')
|
|
96
|
+
expect(onEnter).toHaveBeenCalledTimes(1)
|
|
97
|
+
|
|
98
|
+
const options = getOnEnterOptions()
|
|
99
|
+
expect(editor.state.doc.textContent).toBe('/')
|
|
100
|
+
options.deleteMatch()
|
|
101
|
+
expect(editor.state.doc.textContent).toBe('')
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('can ignore the match', async () => {
|
|
105
|
+
const { editor, onEnter, onLeave, getOnEnterOptions } = setupSlashMenu()
|
|
106
|
+
|
|
107
|
+
expect(onEnter).not.toHaveBeenCalled()
|
|
108
|
+
|
|
109
|
+
await inputText('/')
|
|
110
|
+
expect(onEnter).toHaveBeenCalledTimes(1)
|
|
111
|
+
expect(onLeave).toHaveBeenCalledTimes(0)
|
|
112
|
+
expect(editor.state.doc.textContent).toBe('/')
|
|
113
|
+
|
|
114
|
+
// Typing should trigger autocomplete
|
|
115
|
+
await inputText('a')
|
|
116
|
+
expect(onEnter).toHaveBeenCalledTimes(2)
|
|
117
|
+
expect(onLeave).toHaveBeenCalledTimes(0)
|
|
118
|
+
expect(editor.state.doc.textContent).toBe('/a')
|
|
119
|
+
|
|
120
|
+
// Call `ignoreMatch` to dismiss the match
|
|
121
|
+
const options = getOnEnterOptions()
|
|
122
|
+
options.ignoreMatch()
|
|
123
|
+
expect(onEnter).toHaveBeenCalledTimes(2)
|
|
124
|
+
expect(onLeave).toHaveBeenCalledTimes(1)
|
|
125
|
+
|
|
126
|
+
// Typing should not trigger autocomplete anymore
|
|
127
|
+
await inputText('a')
|
|
128
|
+
expect(onEnter).toHaveBeenCalledTimes(2)
|
|
129
|
+
expect(onLeave).toHaveBeenCalledTimes(1)
|
|
130
|
+
expect(editor.state.doc.textContent).toBe('/aa')
|
|
131
|
+
})
|
|
132
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineFacet,
|
|
3
|
+
defineFacetPayload,
|
|
4
|
+
pluginFacet,
|
|
5
|
+
type Extension,
|
|
6
|
+
type PluginPayload,
|
|
7
|
+
} from '@prosekit/core'
|
|
8
|
+
|
|
9
|
+
import { createAutocompletePlugin } from './autocomplete-plugin'
|
|
10
|
+
import type { AutocompleteRule } from './autocomplete-rule'
|
|
11
|
+
|
|
12
|
+
export function defineAutocomplete(rule: AutocompleteRule): Extension {
|
|
13
|
+
return defineFacetPayload(autocompleteFacet, [rule])
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const autocompleteFacet = defineFacet<AutocompleteRule, PluginPayload>({
|
|
17
|
+
reduce: () => {
|
|
18
|
+
let rules: AutocompleteRule[] = []
|
|
19
|
+
const getRules = () => rules
|
|
20
|
+
const plugin = createAutocompletePlugin({ getRules })
|
|
21
|
+
|
|
22
|
+
return function reducer(inputs) {
|
|
23
|
+
rules = inputs
|
|
24
|
+
return plugin
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
parent: pluginFacet,
|
|
28
|
+
singleton: true,
|
|
29
|
+
})
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineCommands,
|
|
3
|
+
insertNode,
|
|
4
|
+
toggleWrap,
|
|
5
|
+
wrap,
|
|
6
|
+
type Extension,
|
|
7
|
+
} from '@prosekit/core'
|
|
8
|
+
|
|
9
|
+
export type BlockquoteCommandsExtension = Extension<{
|
|
10
|
+
Commands: {
|
|
11
|
+
setBlockquote: []
|
|
12
|
+
insertBlockquote: []
|
|
13
|
+
toggleBlockquote: []
|
|
14
|
+
}
|
|
15
|
+
}>
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export function defineBlockquoteCommands(): BlockquoteCommandsExtension {
|
|
21
|
+
return defineCommands({
|
|
22
|
+
setBlockquote: () => {
|
|
23
|
+
return wrap({ type: 'blockquote' })
|
|
24
|
+
},
|
|
25
|
+
insertBlockquote: () => {
|
|
26
|
+
return insertNode({ type: 'blockquote' })
|
|
27
|
+
},
|
|
28
|
+
toggleBlockquote: () => {
|
|
29
|
+
return toggleWrap({ type: 'blockquote' })
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PlainExtension } from '@prosekit/core'
|
|
2
|
+
|
|
3
|
+
import { defineWrappingInputRule } from '../input-rule'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Wraps the text block in a blockquote when `>` is typed at the start of a new
|
|
7
|
+
* line followed by a space.
|
|
8
|
+
*/
|
|
9
|
+
export function defineBlockquoteInputRule(): PlainExtension {
|
|
10
|
+
return defineWrappingInputRule({
|
|
11
|
+
regex: /^>\s/,
|
|
12
|
+
type: 'blockquote',
|
|
13
|
+
})
|
|
14
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
describe,
|
|
3
|
+
expect,
|
|
4
|
+
it,
|
|
5
|
+
} from 'vitest'
|
|
6
|
+
|
|
7
|
+
import { setupTest } from '../testing'
|
|
8
|
+
import { pressKey } from '../testing/keyboard'
|
|
9
|
+
|
|
10
|
+
describe('blockquote keymap', () => {
|
|
11
|
+
it('should wrap paragraph into blockquote with shortcut', async () => {
|
|
12
|
+
const { editor, n } = setupTest()
|
|
13
|
+
|
|
14
|
+
const doc1 = n.doc(n.p('hel<a>lo'))
|
|
15
|
+
editor.set(doc1)
|
|
16
|
+
|
|
17
|
+
await pressKey('mod-shift-b')
|
|
18
|
+
|
|
19
|
+
const doc2 = n.doc(n.blockquote(n.p('hello')))
|
|
20
|
+
expect(editor.state.doc.toJSON()).toEqual(doc2.toJSON())
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('should lift blockquote up with shortcut', async () => {
|
|
24
|
+
const { editor, n } = setupTest()
|
|
25
|
+
const doc1 = n.doc(n.blockquote(n.p('hello')))
|
|
26
|
+
editor.set(doc1)
|
|
27
|
+
|
|
28
|
+
await pressKey('mod-shift-b')
|
|
29
|
+
|
|
30
|
+
const doc2 = n.doc(n.p('hello'))
|
|
31
|
+
expect(editor.state.doc.toJSON()).toEqual(doc2.toJSON())
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('should unset blockquote when press backspace at the beginning of blockquote', async () => {
|
|
35
|
+
const { editor, n } = setupTest()
|
|
36
|
+
const doc1 = n.doc(n.blockquote(n.p('<a>hello')))
|
|
37
|
+
|
|
38
|
+
editor.set(doc1)
|
|
39
|
+
|
|
40
|
+
await pressKey('Backspace')
|
|
41
|
+
|
|
42
|
+
const doc2 = n.doc(n.p('hello'))
|
|
43
|
+
expect(editor.state.doc.toJSON()).toEqual(doc2.toJSON())
|
|
44
|
+
})
|
|
45
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineKeymap,
|
|
3
|
+
isAtBlockStart,
|
|
4
|
+
toggleWrap,
|
|
5
|
+
type PlainExtension,
|
|
6
|
+
} from '@prosekit/core'
|
|
7
|
+
import { joinBackward } from '@prosekit/pm/commands'
|
|
8
|
+
import type { Command } from '@prosekit/pm/state'
|
|
9
|
+
|
|
10
|
+
function toggleBlockquoteKeybinding(): Command {
|
|
11
|
+
return toggleWrap({ type: 'blockquote' })
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function backspaceUnsetBlockquote(): Command {
|
|
15
|
+
return (state, dispatch, view) => {
|
|
16
|
+
const $pos = isAtBlockStart(state, view)
|
|
17
|
+
if ($pos?.node(-1).type.name === 'blockquote') {
|
|
18
|
+
return joinBackward(state, dispatch, view)
|
|
19
|
+
}
|
|
20
|
+
return false
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export function defineBlockquoteKeymap(): PlainExtension {
|
|
27
|
+
return defineKeymap({
|
|
28
|
+
'mod-shift-b': toggleBlockquoteKeybinding(),
|
|
29
|
+
'Backspace': backspaceUnsetBlockquote(),
|
|
30
|
+
})
|
|
31
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineNodeSpec,
|
|
3
|
+
type Extension,
|
|
4
|
+
} from '@prosekit/core'
|
|
5
|
+
import type { Attrs } from '@prosekit/pm/model'
|
|
6
|
+
|
|
7
|
+
export type BlockquoteSpecExtension = Extension<{
|
|
8
|
+
Nodes: {
|
|
9
|
+
blockquote: Attrs
|
|
10
|
+
}
|
|
11
|
+
}>
|
|
12
|
+
|
|
13
|
+
export function defineBlockquoteSpec(): BlockquoteSpecExtension {
|
|
14
|
+
return defineNodeSpec({
|
|
15
|
+
name: 'blockquote',
|
|
16
|
+
content: 'block+',
|
|
17
|
+
group: 'block',
|
|
18
|
+
defining: true,
|
|
19
|
+
parseDOM: [{ tag: 'blockquote' }],
|
|
20
|
+
toDOM() {
|
|
21
|
+
return ['blockquote', 0]
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
union,
|
|
3
|
+
type Union,
|
|
4
|
+
} from '@prosekit/core'
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
defineBlockquoteCommands,
|
|
8
|
+
type BlockquoteCommandsExtension,
|
|
9
|
+
} from './blockquote-commands'
|
|
10
|
+
import { defineBlockquoteInputRule } from './blockquote-input-rule'
|
|
11
|
+
import { defineBlockquoteKeymap } from './blockquote-keymap'
|
|
12
|
+
import {
|
|
13
|
+
defineBlockquoteSpec,
|
|
14
|
+
type BlockquoteSpecExtension,
|
|
15
|
+
} from './blockquote-spec'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export type BlockquoteExtension = Union<
|
|
21
|
+
[BlockquoteSpecExtension, BlockquoteCommandsExtension]
|
|
22
|
+
>
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export function defineBlockquote(): BlockquoteExtension {
|
|
28
|
+
return union(
|
|
29
|
+
defineBlockquoteSpec(),
|
|
30
|
+
defineBlockquoteInputRule(),
|
|
31
|
+
defineBlockquoteCommands(),
|
|
32
|
+
defineBlockquoteKeymap(),
|
|
33
|
+
)
|
|
34
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export {
|
|
2
|
+
defineBlockquote,
|
|
3
|
+
type BlockquoteExtension,
|
|
4
|
+
} from './blockquote'
|
|
5
|
+
export {
|
|
6
|
+
defineBlockquoteCommands,
|
|
7
|
+
type BlockquoteCommandsExtension,
|
|
8
|
+
} from './blockquote-commands'
|
|
9
|
+
export { defineBlockquoteInputRule } from './blockquote-input-rule'
|
|
10
|
+
export { defineBlockquoteKeymap } from './blockquote-keymap'
|
|
11
|
+
export {
|
|
12
|
+
defineBlockquoteSpec,
|
|
13
|
+
type BlockquoteSpecExtension,
|
|
14
|
+
} from './blockquote-spec'
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineCommands,
|
|
3
|
+
toggleMark,
|
|
4
|
+
type Extension,
|
|
5
|
+
} from '@prosekit/core'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export type BoldCommandsExtension = Extension<{
|
|
11
|
+
Commands: {
|
|
12
|
+
toggleBold: []
|
|
13
|
+
}
|
|
14
|
+
}>
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export function defineBoldCommands(): BoldCommandsExtension {
|
|
20
|
+
return defineCommands({
|
|
21
|
+
toggleBold: () => toggleMark({ type: 'bold' }),
|
|
22
|
+
})
|
|
23
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
describe,
|
|
3
|
+
expect,
|
|
4
|
+
it,
|
|
5
|
+
} from 'vitest'
|
|
6
|
+
|
|
7
|
+
import { setupTest } from '../testing'
|
|
8
|
+
import { inputText } from '../testing/keyboard'
|
|
9
|
+
|
|
10
|
+
describe('defineBoldInputRule', () => {
|
|
11
|
+
const { editor, n, m } = setupTest()
|
|
12
|
+
it('should add bold marks when typing "**"', async () => {
|
|
13
|
+
const doc = n.doc(n.p('<a>'))
|
|
14
|
+
editor.set(doc)
|
|
15
|
+
|
|
16
|
+
await inputText('**word')
|
|
17
|
+
expect(editor.view.state.doc.toJSON()).toEqual(
|
|
18
|
+
n.doc(n.p('**word')).toJSON(),
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
await inputText('*')
|
|
22
|
+
expect(editor.view.state.doc.toJSON()).toEqual(
|
|
23
|
+
n.doc(n.p('**word*')).toJSON(),
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
await inputText('*')
|
|
27
|
+
expect(editor.view.state.doc.toJSON()).toEqual(
|
|
28
|
+
n.doc(n.p(m.bold('word'))).toJSON(),
|
|
29
|
+
)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('should not add bold marks when typing "**" inside a code block', async () => {
|
|
33
|
+
const doc = n.doc(n.codeBlock('<a>'))
|
|
34
|
+
editor.set(doc)
|
|
35
|
+
|
|
36
|
+
await inputText('**word** ')
|
|
37
|
+
expect(editor.view.state.doc.toJSON()).toEqual(
|
|
38
|
+
n.doc(n.codeBlock('**word** ')).toJSON(),
|
|
39
|
+
)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('should not add bold marks when typing "**" inside a code mark', async () => {
|
|
43
|
+
const doc = n.doc(n.p(m.code('code <a>')))
|
|
44
|
+
editor.set(doc)
|
|
45
|
+
|
|
46
|
+
await inputText('**word** ')
|
|
47
|
+
expect(editor.view.state.doc.toJSON()).toEqual(
|
|
48
|
+
n.doc(n.p(m.code('code **word** '))).toJSON(),
|
|
49
|
+
)
|
|
50
|
+
})
|
|
51
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
canUseRegexLookbehind,
|
|
3
|
+
type PlainExtension,
|
|
4
|
+
} from '@prosekit/core'
|
|
5
|
+
|
|
6
|
+
import { defineMarkInputRule } from '../input-rule'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export function defineBoldInputRule(): PlainExtension {
|
|
12
|
+
return defineMarkInputRule({
|
|
13
|
+
regex: canUseRegexLookbehind()
|
|
14
|
+
? /(?<=\s|^)\*\*([^\s*]|[^\s*][^*]*[^\s*])\*\*$/
|
|
15
|
+
: /\*\*([^\s*]|[^\s*][^*]*[^\s*])\*\*$/,
|
|
16
|
+
type: 'bold',
|
|
17
|
+
})
|
|
18
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineMarkSpec,
|
|
3
|
+
type Extension,
|
|
4
|
+
} from '@prosekit/core'
|
|
5
|
+
import type { Attrs } from '@prosekit/pm/model'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export type BoldSpecExtension = Extension<{
|
|
11
|
+
Marks: {
|
|
12
|
+
bold: Attrs
|
|
13
|
+
}
|
|
14
|
+
}>
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export function defineBoldSpec(): BoldSpecExtension {
|
|
20
|
+
return defineMarkSpec({
|
|
21
|
+
name: 'bold',
|
|
22
|
+
parseDOM: [
|
|
23
|
+
{ tag: 'strong' },
|
|
24
|
+
// This works around a Google Docs misbehavior where
|
|
25
|
+
// pasted content will be inexplicably wrapped in `<b>`
|
|
26
|
+
// tags with a font-weight normal.
|
|
27
|
+
{
|
|
28
|
+
tag: 'b',
|
|
29
|
+
getAttrs: (node: string | HTMLElement): null | false => {
|
|
30
|
+
return (
|
|
31
|
+
typeof node !== 'string'
|
|
32
|
+
&& node.style.fontWeight !== 'normal'
|
|
33
|
+
&& null
|
|
34
|
+
)
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{ style: 'font-weight=400', clearMark: (m) => m.type.name == 'strong' },
|
|
38
|
+
{
|
|
39
|
+
style: 'font-weight',
|
|
40
|
+
getAttrs: (value: string | HTMLElement): null | false => {
|
|
41
|
+
return (
|
|
42
|
+
typeof value === 'string'
|
|
43
|
+
&& /^(bold(er)?|[5-9]\d{2,})$/.test(value)
|
|
44
|
+
&& null
|
|
45
|
+
)
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
toDOM() {
|
|
50
|
+
return ['strong', 0]
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
}
|
package/src/bold/bold.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {
|
|
2
|
+
union,
|
|
3
|
+
type Union,
|
|
4
|
+
} from '@prosekit/core'
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
defineBoldCommands,
|
|
8
|
+
type BoldCommandsExtension,
|
|
9
|
+
} from './bold-commands'
|
|
10
|
+
import { defineBoldInputRule } from './bold-input-rule'
|
|
11
|
+
import { defineBoldKeymap } from './bold-keymap'
|
|
12
|
+
import {
|
|
13
|
+
defineBoldSpec,
|
|
14
|
+
type BoldSpecExtension,
|
|
15
|
+
} from './bold-spec'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export type BoldExtension = Union<[BoldSpecExtension, BoldCommandsExtension]>
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
export function defineBold(): BoldExtension {
|
|
26
|
+
return union(
|
|
27
|
+
defineBoldSpec(),
|
|
28
|
+
defineBoldCommands(),
|
|
29
|
+
defineBoldKeymap(),
|
|
30
|
+
defineBoldInputRule(),
|
|
31
|
+
)
|
|
32
|
+
}
|