@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,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineCommands,
|
|
3
|
+
setBlockType,
|
|
4
|
+
type Extension,
|
|
5
|
+
} from '@prosekit/core'
|
|
6
|
+
import type { Command } from '@prosekit/pm/state'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export type ParagraphCommandsExtension = Extension<{
|
|
12
|
+
Commands: {
|
|
13
|
+
setParagraph: []
|
|
14
|
+
}
|
|
15
|
+
}>
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export function setParagraph(): Command {
|
|
21
|
+
return setBlockType({ type: 'paragraph' })
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export function defineParagraphCommands(): ParagraphCommandsExtension {
|
|
28
|
+
return defineCommands({ setParagraph })
|
|
29
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineKeymap,
|
|
3
|
+
type PlainExtension,
|
|
4
|
+
} from '@prosekit/core'
|
|
5
|
+
|
|
6
|
+
import { setParagraph } from './paragraph-commands'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export function defineParagraphKeymap(): PlainExtension {
|
|
12
|
+
return defineKeymap({
|
|
13
|
+
'mod-alt-0': setParagraph(),
|
|
14
|
+
})
|
|
15
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineNodeSpec,
|
|
3
|
+
type Extension,
|
|
4
|
+
} from '@prosekit/core'
|
|
5
|
+
import type { Attrs } from '@prosekit/pm/model'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export type ParagraphSpecExtension = Extension<{
|
|
11
|
+
Nodes: {
|
|
12
|
+
paragraph: Attrs
|
|
13
|
+
}
|
|
14
|
+
}>
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @internal
|
|
18
|
+
*
|
|
19
|
+
* Defines a paragraph node spec.
|
|
20
|
+
*/
|
|
21
|
+
export function defineParagraphSpec(): ParagraphSpecExtension {
|
|
22
|
+
return defineNodeSpec({
|
|
23
|
+
name: 'paragraph',
|
|
24
|
+
content: 'inline*',
|
|
25
|
+
group: 'block',
|
|
26
|
+
parseDOM: [{ tag: 'p' }],
|
|
27
|
+
toDOM() {
|
|
28
|
+
return ['p', 0]
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Priority,
|
|
3
|
+
union,
|
|
4
|
+
withPriority,
|
|
5
|
+
type Union,
|
|
6
|
+
} from '@prosekit/core'
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
defineParagraphCommands,
|
|
10
|
+
type ParagraphCommandsExtension,
|
|
11
|
+
} from './paragraph-commands'
|
|
12
|
+
import { defineParagraphKeymap } from './paragraph-keymap'
|
|
13
|
+
import {
|
|
14
|
+
defineParagraphSpec,
|
|
15
|
+
type ParagraphSpecExtension,
|
|
16
|
+
} from './paragraph-spec'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
export type ParagraphExtension = Union<[ParagraphSpecExtension, ParagraphCommandsExtension]>
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @public
|
|
25
|
+
*
|
|
26
|
+
* Defines a paragraph node.
|
|
27
|
+
*
|
|
28
|
+
* The paragraph node spec has the highest priority, because it should be the
|
|
29
|
+
* default block node for most cases.
|
|
30
|
+
*/
|
|
31
|
+
export function defineParagraph(): ParagraphExtension {
|
|
32
|
+
return union(
|
|
33
|
+
withPriority(defineParagraphSpec(), Priority.highest),
|
|
34
|
+
defineParagraphCommands(),
|
|
35
|
+
defineParagraphKeymap(),
|
|
36
|
+
)
|
|
37
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineMarkSpec,
|
|
3
|
+
union,
|
|
4
|
+
} from '@prosekit/core'
|
|
5
|
+
import {
|
|
6
|
+
describe,
|
|
7
|
+
expect,
|
|
8
|
+
it,
|
|
9
|
+
} from 'vitest'
|
|
10
|
+
|
|
11
|
+
import { defineBold } from '../bold'
|
|
12
|
+
import { defineDoc } from '../doc'
|
|
13
|
+
import { defineParagraph } from '../paragraph'
|
|
14
|
+
import { setupTestFromExtension } from '../testing'
|
|
15
|
+
import {
|
|
16
|
+
pasteHTML,
|
|
17
|
+
pasteText,
|
|
18
|
+
} from '../testing/clipboard'
|
|
19
|
+
import { defineText } from '../text'
|
|
20
|
+
|
|
21
|
+
import type { MarkPasteRuleOptions } from './mark-paste-rule'
|
|
22
|
+
import { defineMarkPasteRule } from './mark-paste-rule'
|
|
23
|
+
|
|
24
|
+
function setup(options?: Partial<MarkPasteRuleOptions>) {
|
|
25
|
+
return setupTestFromExtension(union(
|
|
26
|
+
defineDoc(),
|
|
27
|
+
defineText(),
|
|
28
|
+
defineParagraph(),
|
|
29
|
+
defineBold(),
|
|
30
|
+
defineMarkSpec({
|
|
31
|
+
name: 'testMark',
|
|
32
|
+
attrs: {
|
|
33
|
+
value: { validate: 'string' },
|
|
34
|
+
},
|
|
35
|
+
parseDOM: [{ tag: 'span[data-test]' }],
|
|
36
|
+
toDOM: () => ['span', { 'data-test': 'true' }, 0],
|
|
37
|
+
}),
|
|
38
|
+
defineMarkPasteRule({
|
|
39
|
+
type: 'testMark',
|
|
40
|
+
regex: /@(\w+)/g,
|
|
41
|
+
getAttrs: (match: RegExpExecArray) => ({ value: match[1] }),
|
|
42
|
+
...options,
|
|
43
|
+
}),
|
|
44
|
+
))
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
describe('defineMarkPasteRule', () => {
|
|
48
|
+
it('should match simple patterns and create marks', () => {
|
|
49
|
+
const { editor, n, m } = setup()
|
|
50
|
+
editor.set(n.doc(n.paragraph('<a>')))
|
|
51
|
+
|
|
52
|
+
pasteHTML(editor.view, '<p>Hello @alice and @bob</p>')
|
|
53
|
+
|
|
54
|
+
expect(editor.view.state.doc.toJSON()).toEqual(
|
|
55
|
+
n.doc(n.paragraph(
|
|
56
|
+
'Hello ',
|
|
57
|
+
m.testMark({ value: 'alice' }, '@alice'),
|
|
58
|
+
' and ',
|
|
59
|
+
m.testMark({ value: 'bob' }, '@bob'),
|
|
60
|
+
)).toJSON(),
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('should not match plain text', () => {
|
|
65
|
+
const { editor, n } = setup()
|
|
66
|
+
editor.set(n.doc(n.paragraph('<a>')))
|
|
67
|
+
|
|
68
|
+
pasteText(editor.view, 'Hello @alice and @bob')
|
|
69
|
+
|
|
70
|
+
expect(editor.view.state.doc.toJSON()).toEqual(
|
|
71
|
+
n.doc(n.paragraph('Hello @alice and @bob')).toJSON(),
|
|
72
|
+
)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('should skip processing when attrs returns false', () => {
|
|
76
|
+
const { editor, n, m } = setup({
|
|
77
|
+
getAttrs: (match: RegExpExecArray) => {
|
|
78
|
+
return match[1] === 'skip' ? false : { value: match[1] }
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
editor.set(n.doc(n.paragraph('<a>')))
|
|
82
|
+
|
|
83
|
+
pasteHTML(editor.view, '<p>Tags: @good @skip @also</p>')
|
|
84
|
+
|
|
85
|
+
expect(editor.view.state.doc.toJSON()).toEqual(
|
|
86
|
+
n.doc(n.paragraph(
|
|
87
|
+
'Tags: ',
|
|
88
|
+
m.testMark({ value: 'good' }, '@good'),
|
|
89
|
+
' @skip ',
|
|
90
|
+
m.testMark({ value: 'also' }, '@also'),
|
|
91
|
+
)).toJSON(),
|
|
92
|
+
)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('should use shouldSkip to skip bold text', () => {
|
|
96
|
+
const { editor, n, m } = setup({
|
|
97
|
+
shouldSkip: (node) => node.marks.some(mark => mark.type.name === 'bold'),
|
|
98
|
+
})
|
|
99
|
+
editor.set(n.doc(n.paragraph('<a>')))
|
|
100
|
+
|
|
101
|
+
pasteHTML(editor.view, '<p>Hello <strong>@alice</strong> and @bob</p>')
|
|
102
|
+
|
|
103
|
+
expect(editor.view.state.doc.toJSON()).toEqual(
|
|
104
|
+
n.doc(n.paragraph(
|
|
105
|
+
'Hello ',
|
|
106
|
+
m.bold('@alice'), // Skipped due to shouldSkip
|
|
107
|
+
' and ',
|
|
108
|
+
m.testMark({ value: 'bob' }, '@bob'), // Processed normally
|
|
109
|
+
)).toJSON(),
|
|
110
|
+
)
|
|
111
|
+
})
|
|
112
|
+
})
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getMarkType,
|
|
3
|
+
type PlainExtension,
|
|
4
|
+
} from '@prosekit/core'
|
|
5
|
+
import type {
|
|
6
|
+
Attrs,
|
|
7
|
+
MarkType,
|
|
8
|
+
ProseMirrorNode,
|
|
9
|
+
} from '@prosekit/pm/model'
|
|
10
|
+
import {
|
|
11
|
+
Fragment,
|
|
12
|
+
Slice,
|
|
13
|
+
} from '@prosekit/pm/model'
|
|
14
|
+
|
|
15
|
+
import { definePasteRule } from './paste-rule'
|
|
16
|
+
import { splitTextByRegex } from './split-text-by-regex'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The options for {@link defineMarkPasteRule}.
|
|
20
|
+
*
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
export interface MarkPasteRuleOptions {
|
|
24
|
+
/**
|
|
25
|
+
* The regular expression to match against. It must have a `g` flag to match
|
|
26
|
+
* all instances of the mark.
|
|
27
|
+
*/
|
|
28
|
+
regex: RegExp
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The mark type to apply to the matched text.
|
|
32
|
+
*/
|
|
33
|
+
type: string | MarkType
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A function used to compute attributes to set on the mark created by this
|
|
37
|
+
* rule. When it returns `false`, the rule won't match. When it returns `null`
|
|
38
|
+
* or `undefined`, that is interpreted as an empty/default set of attributes.
|
|
39
|
+
* @default null
|
|
40
|
+
*/
|
|
41
|
+
getAttrs?: (match: RegExpExecArray) => Attrs | null | undefined | false
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Optional function to determine if a text node should be skipped.
|
|
45
|
+
* Default behavior: skip code nodes and nodes that already have the target mark.
|
|
46
|
+
*/
|
|
47
|
+
shouldSkip?: (node: ProseMirrorNode) => boolean
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Defines a paste rule that applies marks based on regex patterns.
|
|
52
|
+
*
|
|
53
|
+
* @public
|
|
54
|
+
*/
|
|
55
|
+
export function defineMarkPasteRule(options: MarkPasteRuleOptions): PlainExtension {
|
|
56
|
+
return definePasteRule({
|
|
57
|
+
handler: ({ slice, view, plain }) => {
|
|
58
|
+
if (plain) {
|
|
59
|
+
return slice
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const markType = getMarkType(view.state.schema, options.type)
|
|
63
|
+
|
|
64
|
+
return replaceMarkInSlice({
|
|
65
|
+
markType,
|
|
66
|
+
regex: options.regex,
|
|
67
|
+
getAttrs: options.getAttrs,
|
|
68
|
+
shouldSkip: options.shouldSkip,
|
|
69
|
+
}, slice)
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface MarkPasteRuleHandlerOptions {
|
|
75
|
+
markType: MarkType
|
|
76
|
+
regex: RegExp
|
|
77
|
+
getAttrs?: (match: RegExpExecArray) => Attrs | null | undefined | false
|
|
78
|
+
shouldSkip?: (node: ProseMirrorNode) => boolean
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function replaceMarkInSlice(options: MarkPasteRuleHandlerOptions, slice: Slice): Slice {
|
|
82
|
+
const newFragment = replaceMarkInFragment(options, slice.content)
|
|
83
|
+
if (!newFragment) {
|
|
84
|
+
return slice
|
|
85
|
+
}
|
|
86
|
+
return new Slice(newFragment, slice.openStart, slice.openEnd)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function replaceMarkInFragment(options: MarkPasteRuleHandlerOptions, fragment: Fragment): Fragment | undefined {
|
|
90
|
+
let changed = false
|
|
91
|
+
let children: ProseMirrorNode[] = []
|
|
92
|
+
|
|
93
|
+
for (const child of fragment.content) {
|
|
94
|
+
const newChild = replaceMarkInNode(options, child)
|
|
95
|
+
if (newChild) {
|
|
96
|
+
changed = true
|
|
97
|
+
}
|
|
98
|
+
children.push(newChild || child)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (changed) {
|
|
102
|
+
return Fragment.from(children)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function replaceMarkInNode(options: MarkPasteRuleHandlerOptions, node: ProseMirrorNode): ProseMirrorNode | undefined {
|
|
109
|
+
if (node.type.spec.code) {
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
if (node.type.isInline) {
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
if (node.type.isTextblock) {
|
|
116
|
+
return replaceMarkInTextblockNode(options, node)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const newChildren = replaceMarkInFragment(options, node.content)
|
|
120
|
+
if (!newChildren) {
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
return node.copy(newChildren)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function replaceMarkInTextblockNode(options: MarkPasteRuleHandlerOptions, node: ProseMirrorNode): ProseMirrorNode | undefined {
|
|
127
|
+
const newChildren: ProseMirrorNode[] = []
|
|
128
|
+
let changed = false
|
|
129
|
+
|
|
130
|
+
for (const inlineNode of node.content.content) {
|
|
131
|
+
const newInlineNodes = replaceMarkInInlineNode(options, inlineNode)
|
|
132
|
+
if (newInlineNodes) {
|
|
133
|
+
changed = true
|
|
134
|
+
newChildren.push(...newInlineNodes)
|
|
135
|
+
} else {
|
|
136
|
+
newChildren.push(inlineNode)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (changed) {
|
|
140
|
+
return node.copy(Fragment.from(newChildren))
|
|
141
|
+
}
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function replaceMarkInInlineNode(options: MarkPasteRuleHandlerOptions, node: ProseMirrorNode): ProseMirrorNode[] | undefined {
|
|
146
|
+
const text = node.text
|
|
147
|
+
if (!text) {
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const { markType, shouldSkip } = options
|
|
152
|
+
|
|
153
|
+
// Use custom skip logic if provided, otherwise use default
|
|
154
|
+
if (shouldSkip) {
|
|
155
|
+
if (shouldSkip(node)) {
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
// Default skip logic: skip if already has the target mark or has code mark
|
|
160
|
+
if (node.marks.some((mark) => mark.type === markType)) {
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
if (node.marks.some((mark) => mark.type.spec.code)) {
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const chunks = splitTextByRegex(text, options.regex)
|
|
169
|
+
if (!chunks) {
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const schema = node.type.schema
|
|
174
|
+
const nodes: ProseMirrorNode[] = []
|
|
175
|
+
|
|
176
|
+
for (const [text, match] of chunks) {
|
|
177
|
+
if (!text) {
|
|
178
|
+
continue
|
|
179
|
+
}
|
|
180
|
+
if (match) {
|
|
181
|
+
const attrs = options.getAttrs?.(match) ?? null
|
|
182
|
+
if (attrs !== false) {
|
|
183
|
+
const mark = markType.create(attrs)
|
|
184
|
+
nodes.push(schema.text(text, [...node.marks, mark]))
|
|
185
|
+
} else {
|
|
186
|
+
nodes.push(schema.text(text, node.marks))
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
nodes.push(schema.text(text, node.marks))
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return nodes
|
|
194
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineFacet,
|
|
3
|
+
defineFacetPayload,
|
|
4
|
+
pluginFacet,
|
|
5
|
+
type PlainExtension,
|
|
6
|
+
type PluginPayload,
|
|
7
|
+
} from '@prosekit/core'
|
|
8
|
+
import type { Slice } from '@prosekit/pm/model'
|
|
9
|
+
import {
|
|
10
|
+
PluginKey,
|
|
11
|
+
ProseMirrorPlugin,
|
|
12
|
+
} from '@prosekit/pm/state'
|
|
13
|
+
import type { EditorView } from '@prosekit/pm/view'
|
|
14
|
+
|
|
15
|
+
type PasteRulePayload = (options: { slice: Slice; view: EditorView; plain: boolean }) => Slice
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
const pasteRuleFacet = defineFacet<PasteRulePayload, PluginPayload>({
|
|
21
|
+
reduce: () => {
|
|
22
|
+
let handlers: PasteRulePayload[] = []
|
|
23
|
+
|
|
24
|
+
const transformPasted = (slice: Slice, view: EditorView, plain: boolean): Slice => {
|
|
25
|
+
for (const handler of handlers) {
|
|
26
|
+
slice = handler({ slice, view, plain })
|
|
27
|
+
}
|
|
28
|
+
return slice
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const plugin = new ProseMirrorPlugin({
|
|
32
|
+
key: new PluginKey('prosekit-paste-rule'),
|
|
33
|
+
props: {
|
|
34
|
+
transformPasted,
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
return (inputs: PasteRulePayload[]) => {
|
|
39
|
+
// Last added rule (highest priority) is applied first
|
|
40
|
+
handlers = [...inputs].reverse()
|
|
41
|
+
return plugin
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
singleton: true,
|
|
45
|
+
parent: pluginFacet,
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
export function definePasteRulePlugin(payload: PasteRulePayload): PlainExtension {
|
|
52
|
+
return defineFacetPayload(pasteRuleFacet, [payload]) as PlainExtension
|
|
53
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Priority,
|
|
3
|
+
union,
|
|
4
|
+
withPriority,
|
|
5
|
+
type PlainExtension,
|
|
6
|
+
} from '@prosekit/core'
|
|
7
|
+
import type { ProseMirrorNode } from '@prosekit/pm/model'
|
|
8
|
+
import {
|
|
9
|
+
Fragment,
|
|
10
|
+
Slice,
|
|
11
|
+
} from '@prosekit/pm/model'
|
|
12
|
+
import {
|
|
13
|
+
describe,
|
|
14
|
+
expect,
|
|
15
|
+
it,
|
|
16
|
+
} from 'vitest'
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
defineTestExtension,
|
|
20
|
+
setupTestFromExtension,
|
|
21
|
+
} from '../testing'
|
|
22
|
+
|
|
23
|
+
import { definePasteRule } from './paste-rule'
|
|
24
|
+
|
|
25
|
+
function replaceTextInSlice(slice: Slice, from: string, to: string): Slice {
|
|
26
|
+
return new Slice(
|
|
27
|
+
replaceTextInFragment(slice.content, from, to),
|
|
28
|
+
slice.openStart,
|
|
29
|
+
slice.openEnd,
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function replaceTextInFragment(fragment: Fragment, from: string, to: string): Fragment {
|
|
34
|
+
return Fragment.fromArray(fragment.content.map(node => replaceTextInNode(node, from, to)))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function replaceTextInNode(node: ProseMirrorNode, from: string, to: string): ProseMirrorNode {
|
|
38
|
+
const text = node.text
|
|
39
|
+
if (text != null) {
|
|
40
|
+
return node.type.schema.text(text.replaceAll(from, to))
|
|
41
|
+
}
|
|
42
|
+
return node.copy(replaceTextInFragment(node.content, from, to))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function defineTextReplacePasteRule(from: string, to: string): PlainExtension {
|
|
46
|
+
return definePasteRule({
|
|
47
|
+
handler: ({ slice }) => {
|
|
48
|
+
return replaceTextInSlice(slice, from, to)
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
describe('paste rule', () => {
|
|
54
|
+
it('can transform pasted HTML', () => {
|
|
55
|
+
const extension = union(
|
|
56
|
+
defineTestExtension(),
|
|
57
|
+
defineTextReplacePasteRule('Foo', 'Bar'),
|
|
58
|
+
)
|
|
59
|
+
const { editor } = setupTestFromExtension(extension)
|
|
60
|
+
editor.view.pasteHTML('<div>Foo</div>')
|
|
61
|
+
expect(editor.getDocHTML()).not.toContain(`Foo`)
|
|
62
|
+
expect(editor.getDocHTML()).toContain(`Bar`)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('can transform pasted text', () => {
|
|
66
|
+
const extension = union(
|
|
67
|
+
defineTestExtension(),
|
|
68
|
+
defineTextReplacePasteRule('Foo', 'Bar'),
|
|
69
|
+
)
|
|
70
|
+
const { editor } = setupTestFromExtension(extension)
|
|
71
|
+
editor.view.pasteText('Foo')
|
|
72
|
+
expect(editor.getDocHTML()).not.toContain(`Foo`)
|
|
73
|
+
expect(editor.getDocHTML()).toContain(`Bar`)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('can order multiple paste rules', () => {
|
|
77
|
+
const extension = union(
|
|
78
|
+
defineTestExtension(),
|
|
79
|
+
withPriority(defineTextReplacePasteRule('Foo', 'Bar'), Priority.high),
|
|
80
|
+
withPriority(defineTextReplacePasteRule('Foo', 'Baz'), Priority.low),
|
|
81
|
+
)
|
|
82
|
+
const { editor } = setupTestFromExtension(extension)
|
|
83
|
+
editor.view.pasteText('Foo')
|
|
84
|
+
expect(editor.getDocHTML()).not.toContain(`Foo`)
|
|
85
|
+
expect(editor.getDocHTML()).toContain(`Bar`)
|
|
86
|
+
expect(editor.getDocHTML()).not.toContain(`Baz`)
|
|
87
|
+
|
|
88
|
+
editor.use(defineTextReplacePasteRule('Bar', 'Qux'))
|
|
89
|
+
editor.setContent('')
|
|
90
|
+
editor.view.pasteText('Foo')
|
|
91
|
+
expect(editor.getDocHTML()).not.toContain(`Foo`)
|
|
92
|
+
expect(editor.getDocHTML()).not.toContain(`Bar`)
|
|
93
|
+
expect(editor.getDocHTML()).not.toContain(`Baz`)
|
|
94
|
+
expect(editor.getDocHTML()).toContain(`Qux`)
|
|
95
|
+
})
|
|
96
|
+
})
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { PlainExtension } from '@prosekit/core'
|
|
2
|
+
import type { Slice } from '@prosekit/pm/model'
|
|
3
|
+
import type { EditorView } from '@prosekit/pm/view'
|
|
4
|
+
|
|
5
|
+
import { definePasteRulePlugin } from './paste-rule-plugin'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @public
|
|
9
|
+
*
|
|
10
|
+
* Options for {@link PasteRuleHandler}.
|
|
11
|
+
*/
|
|
12
|
+
export interface PasteRuleHandlerOptions {
|
|
13
|
+
/**
|
|
14
|
+
* The slice to be pasted.
|
|
15
|
+
*/
|
|
16
|
+
slice: Slice
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The editor view.
|
|
20
|
+
*/
|
|
21
|
+
view: EditorView
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Whether the pasted content is treated as plain text. This is true when the
|
|
25
|
+
* `Shift` key is held when pasting.
|
|
26
|
+
*/
|
|
27
|
+
plain: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @public
|
|
32
|
+
*
|
|
33
|
+
* Can be used to transform pasted or dragged-and-dropped content before it is
|
|
34
|
+
* applied to the document.
|
|
35
|
+
*/
|
|
36
|
+
export type PasteRuleHandler = (options: PasteRuleHandlerOptions) => Slice
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Options for {@link definePasteRule}.
|
|
40
|
+
*
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
export interface PasteRuleOptions {
|
|
44
|
+
/**
|
|
45
|
+
* A function to be called when a paste rule is triggered.
|
|
46
|
+
*/
|
|
47
|
+
handler: PasteRuleHandler
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Defines a paste rule. This rule allows you to modify pasted or dragged
|
|
52
|
+
* content before it is inserted into the document.
|
|
53
|
+
*
|
|
54
|
+
* @param options
|
|
55
|
+
*
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
export function definePasteRule({ handler }: PasteRuleOptions): PlainExtension {
|
|
59
|
+
return definePasteRulePlugin(handler)
|
|
60
|
+
}
|