@prosekit/extensions 0.7.2 → 0.7.4
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/_tsup-dts-rollup.d.ts +393 -83
- package/dist/chunk-GPSAJOJA.js +188 -0
- package/dist/{chunk-PYT3MOTF.js → chunk-LVMTQOWG.js} +31 -14
- package/dist/{chunk-2JYT2MT7.js → chunk-OJCMRVEY.js} +36 -21
- package/dist/list/style.css +9 -5
- package/dist/placeholder/style.css +1 -1
- package/dist/prosekit-extensions-autocomplete.js +62 -33
- package/dist/prosekit-extensions-blockquote.js +2 -2
- package/dist/prosekit-extensions-bold.js +7 -3
- package/dist/prosekit-extensions-code-block.js +77 -41
- package/dist/prosekit-extensions-code.js +1 -1
- package/dist/prosekit-extensions-commit.js +70 -30
- package/dist/prosekit-extensions-enter-rule.js +1 -1
- package/dist/prosekit-extensions-heading.js +18 -8
- package/dist/prosekit-extensions-image.js +14 -5
- package/dist/prosekit-extensions-input-rule.js +1 -1
- package/dist/prosekit-extensions-italic.js +1 -1
- package/dist/prosekit-extensions-link.js +30 -17
- package/dist/prosekit-extensions-list.d.ts +4 -4
- package/dist/prosekit-extensions-list.js +33 -22
- package/dist/prosekit-extensions-mark-rule.js +1 -1
- package/dist/prosekit-extensions-mention.js +6 -4
- package/dist/prosekit-extensions-placeholder.js +16 -7
- package/dist/prosekit-extensions-readonly.js +1 -1
- package/dist/prosekit-extensions-search.js +8 -5
- package/dist/prosekit-extensions-strike.js +1 -1
- package/dist/prosekit-extensions-table.js +68 -31
- package/dist/prosekit-extensions-text-align.d.ts +1 -0
- package/dist/prosekit-extensions-text-align.js +4 -2
- package/dist/prosekit-extensions-virtual-selection.js +11 -6
- package/package.json +9 -8
- package/dist/chunk-ZPEMHYTU.js +0 -140
@@ -1,18 +1,9 @@
|
|
1
1
|
import {
|
2
2
|
defineInputRule
|
3
|
-
} from "./chunk-
|
3
|
+
} from "./chunk-LVMTQOWG.js";
|
4
4
|
|
5
5
|
// src/list/index.ts
|
6
|
-
import {
|
7
|
-
defineNodeSpec,
|
8
|
-
definePlugin,
|
9
|
-
union
|
10
|
-
} from "@prosekit/core";
|
11
|
-
import {
|
12
|
-
createListPlugins,
|
13
|
-
createListSpec,
|
14
|
-
listInputRules
|
15
|
-
} from "prosemirror-flat-list";
|
6
|
+
import { union as union2 } from "@prosekit/core";
|
16
7
|
|
17
8
|
// src/list/commands.ts
|
18
9
|
import { defineCommands, insertNode } from "@prosekit/core";
|
@@ -43,6 +34,13 @@ function defineListCommands() {
|
|
43
34
|
});
|
44
35
|
}
|
45
36
|
|
37
|
+
// src/list/input-rules.ts
|
38
|
+
import { union } from "@prosekit/core";
|
39
|
+
import { listInputRules } from "prosemirror-flat-list";
|
40
|
+
function defineListInputRules() {
|
41
|
+
return union(listInputRules.map(defineInputRule));
|
42
|
+
}
|
43
|
+
|
46
44
|
// src/list/keymap.ts
|
47
45
|
import { defineKeymap } from "@prosekit/core";
|
48
46
|
import { chainCommands, deleteSelection } from "@prosekit/pm/commands";
|
@@ -60,30 +58,43 @@ var backspaceCommand = chainCommands(
|
|
60
58
|
deleteSelection,
|
61
59
|
joinListUp,
|
62
60
|
joinCollapsedListBackward
|
63
|
-
)
|
61
|
+
);
|
62
|
+
var dedentListCommand = createDedentListCommand();
|
63
|
+
var indentListCommand = createIndentListCommand();
|
64
|
+
var listKeymap = {
|
64
65
|
Enter: enterCommand,
|
65
66
|
Backspace: backspaceCommand,
|
66
67
|
Delete: deleteCommand,
|
67
|
-
"Mod-
|
68
|
-
"Mod-
|
68
|
+
"Mod-]": indentListCommand,
|
69
|
+
"Mod-[": dedentListCommand,
|
70
|
+
Tab: indentListCommand,
|
71
|
+
"Shift-Tab": dedentListCommand
|
69
72
|
};
|
70
73
|
function defineListKeymap() {
|
71
74
|
return defineKeymap(listKeymap);
|
72
75
|
}
|
73
76
|
|
74
|
-
// src/list/
|
75
|
-
import {
|
76
|
-
|
77
|
-
return defineNodeSpec({ ...createListSpec(), name: "list" });
|
78
|
-
}
|
77
|
+
// src/list/plugins.ts
|
78
|
+
import { definePlugin } from "@prosekit/core";
|
79
|
+
import { createListPlugins } from "prosemirror-flat-list";
|
79
80
|
function defineListPlugins() {
|
80
81
|
return definePlugin(({ schema }) => createListPlugins({ schema }));
|
81
82
|
}
|
82
|
-
|
83
|
-
|
83
|
+
|
84
|
+
// src/list/spec.ts
|
85
|
+
import { defineNodeSpec } from "@prosekit/core";
|
86
|
+
import { createListSpec } from "prosemirror-flat-list";
|
87
|
+
function defineListSpec() {
|
88
|
+
return defineNodeSpec({
|
89
|
+
...createListSpec(),
|
90
|
+
name: "list"
|
91
|
+
});
|
84
92
|
}
|
93
|
+
|
94
|
+
// src/list/index.ts
|
95
|
+
import { ListDOMSerializer } from "prosemirror-flat-list";
|
85
96
|
function defineList() {
|
86
|
-
return
|
97
|
+
return union2([
|
87
98
|
defineListSpec(),
|
88
99
|
defineListPlugins(),
|
89
100
|
defineListKeymap(),
|
@@ -8,18 +8,18 @@ import {
|
|
8
8
|
function defineMentionSpec() {
|
9
9
|
return defineNodeSpec({
|
10
10
|
name: "mention",
|
11
|
-
atom:
|
11
|
+
atom: true,
|
12
12
|
group: "inline",
|
13
13
|
attrs: {
|
14
14
|
id: {},
|
15
15
|
value: {},
|
16
16
|
kind: { default: "" }
|
17
17
|
},
|
18
|
-
inline:
|
18
|
+
inline: true,
|
19
19
|
leafText: (node) => node.attrs.value.toString(),
|
20
20
|
parseDOM: [
|
21
21
|
{
|
22
|
-
tag:
|
22
|
+
tag: `span[data-mention]`,
|
23
23
|
getAttrs: (dom) => ({
|
24
24
|
id: dom.getAttribute("data-id") || "",
|
25
25
|
kind: dom.getAttribute("data-mention") || "",
|
@@ -41,7 +41,9 @@ function defineMentionSpec() {
|
|
41
41
|
}
|
42
42
|
function defineMentionCommands() {
|
43
43
|
return defineCommands({
|
44
|
-
insertMention: (attrs) =>
|
44
|
+
insertMention: (attrs) => {
|
45
|
+
return insertNode({ type: "mention", attrs });
|
46
|
+
}
|
45
47
|
});
|
46
48
|
}
|
47
49
|
function defineMention() {
|
@@ -11,24 +11,33 @@ function createPlaceholderPlugin(options) {
|
|
11
11
|
key: new PluginKey("prosekit-placeholder"),
|
12
12
|
props: {
|
13
13
|
decorations: (state) => {
|
14
|
-
if (options.strategy === "doc" && !isDocEmpty(state.doc)
|
14
|
+
if (options.strategy === "doc" && !isDocEmpty(state.doc)) {
|
15
15
|
return null;
|
16
|
-
|
17
|
-
|
16
|
+
}
|
17
|
+
if (isInCodeBlock(state.selection)) {
|
18
|
+
return null;
|
19
|
+
}
|
20
|
+
const placeholderText = options.placeholder;
|
21
|
+
const deco = createPlaceholderDecoration(state, placeholderText);
|
22
|
+
if (!deco) {
|
23
|
+
return null;
|
24
|
+
}
|
25
|
+
return DecorationSet.create(state.doc, [deco]);
|
18
26
|
}
|
19
27
|
}
|
20
28
|
});
|
21
29
|
}
|
22
30
|
function isDocEmpty(doc) {
|
23
31
|
var _a;
|
24
|
-
return doc.childCount <= 1 && !((_a = doc.firstChild)
|
32
|
+
return doc.childCount <= 1 && !((_a = doc.firstChild) == null ? void 0 : _a.content.size);
|
25
33
|
}
|
26
34
|
function createPlaceholderDecoration(state, placeholderText) {
|
27
|
-
|
35
|
+
const { selection } = state;
|
28
36
|
if (!selection.empty) return null;
|
29
|
-
|
37
|
+
const $pos = selection.$anchor;
|
38
|
+
const node = $pos.parent;
|
30
39
|
if (node.content.size > 0) return null;
|
31
|
-
|
40
|
+
const before = $pos.before();
|
32
41
|
return Decoration.node(before, before + node.nodeSize, {
|
33
42
|
class: "prosekit-placeholder",
|
34
43
|
"data-placeholder": placeholderText
|
@@ -13,13 +13,13 @@ import {
|
|
13
13
|
search
|
14
14
|
} from "prosemirror-search";
|
15
15
|
function defineSearchQuery(options) {
|
16
|
-
|
16
|
+
const query = new SearchQuery(options);
|
17
17
|
return definePlugin(search({ initialQuery: query }));
|
18
18
|
}
|
19
19
|
function scrollActiveIntoView(view) {
|
20
20
|
if (view.isDestroyed) return;
|
21
|
-
|
22
|
-
active == null
|
21
|
+
const active = view.dom.querySelector(".ProseMirror-active-search-match");
|
22
|
+
active == null ? void 0 : active.scrollIntoView({
|
23
23
|
block: "nearest",
|
24
24
|
inline: "nearest",
|
25
25
|
behavior: "smooth"
|
@@ -27,8 +27,11 @@ function scrollActiveIntoView(view) {
|
|
27
27
|
}
|
28
28
|
function withScrollActiveIntoView(command) {
|
29
29
|
return (state, dispatch, view) => {
|
30
|
-
|
31
|
-
|
30
|
+
const result = command(state, dispatch, view);
|
31
|
+
if (result && dispatch && view) {
|
32
|
+
setTimeout(() => scrollActiveIntoView(view), 50);
|
33
|
+
}
|
34
|
+
return result;
|
32
35
|
};
|
33
36
|
}
|
34
37
|
function defineSearchCommands() {
|
@@ -10,13 +10,23 @@ import {
|
|
10
10
|
} from "@prosekit/core";
|
11
11
|
import { TextSelection } from "@prosekit/pm/state";
|
12
12
|
function createEmptyTable(schema, row, col, header) {
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
const table = getNodeType(schema, "table");
|
14
|
+
const tableRow = getNodeType(schema, "tableRow");
|
15
|
+
const tableCell = getNodeType(schema, "tableCell");
|
16
|
+
const tableHeaderCell = getNodeType(schema, "tableHeaderCell");
|
17
|
+
const createHeaderRow = () => {
|
18
|
+
return tableRow.createAndFill(
|
19
|
+
null,
|
20
|
+
Array.from({ length: col }, () => tableHeaderCell.createAndFill())
|
21
|
+
);
|
22
|
+
};
|
23
|
+
const createBodyRow = () => {
|
24
|
+
return tableRow.createAndFill(
|
25
|
+
null,
|
26
|
+
Array.from({ length: col }, () => tableCell.createAndFill())
|
27
|
+
);
|
28
|
+
};
|
29
|
+
const rows = [
|
20
30
|
...Array.from({ length: header ? 1 : 0 }, createHeaderRow),
|
21
31
|
...Array.from({ length: header ? row - 1 : row }, createBodyRow)
|
22
32
|
];
|
@@ -28,27 +38,41 @@ function insertTable({
|
|
28
38
|
header
|
29
39
|
}) {
|
30
40
|
return (state, dispatch, view) => {
|
31
|
-
|
41
|
+
const table = createEmptyTable(state.schema, row, col, header);
|
32
42
|
return insertNode({ node: table })(state, dispatch, view);
|
33
43
|
};
|
34
44
|
}
|
35
45
|
var exitTable = (state, dispatch) => {
|
36
|
-
|
37
|
-
if (!$head.sameParent($anchor))
|
38
|
-
return
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
46
|
+
const { $head, $anchor } = state.selection;
|
47
|
+
if (!$head.sameParent($anchor)) {
|
48
|
+
return false;
|
49
|
+
}
|
50
|
+
let tableStart = -1;
|
51
|
+
let tableDepth = -1;
|
52
|
+
for (let depth = $head.depth; depth >= 0; depth--) {
|
53
|
+
const node2 = $head.node(depth);
|
54
|
+
if (node2.type.spec.tableRole === "table") {
|
55
|
+
tableStart = $head.before(depth);
|
56
|
+
tableDepth = depth;
|
57
|
+
}
|
58
|
+
}
|
59
|
+
if (tableStart < 0 || tableDepth <= 0) {
|
60
|
+
return false;
|
61
|
+
}
|
62
|
+
const above = $head.node(tableDepth - 1);
|
63
|
+
const after = $head.indexAfter(tableDepth - 1);
|
64
|
+
const type = defaultBlockAt(above.contentMatchAt(after));
|
65
|
+
const node = type == null ? void 0 : type.createAndFill();
|
66
|
+
if (!type || !node || !above.canReplaceWith(after, after, type)) {
|
67
|
+
return false;
|
68
|
+
}
|
47
69
|
if (dispatch) {
|
48
|
-
|
49
|
-
tr.
|
70
|
+
const pos = $head.after(tableDepth);
|
71
|
+
const tr = state.tr.replaceWith(pos, pos, node);
|
72
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve(pos), 1));
|
73
|
+
dispatch(tr.scrollIntoView());
|
50
74
|
}
|
51
|
-
return
|
75
|
+
return true;
|
52
76
|
};
|
53
77
|
function defineTableCommands() {
|
54
78
|
return defineCommands({
|
@@ -66,16 +90,19 @@ function defineTablePlugins() {
|
|
66
90
|
|
67
91
|
// src/table/table-spec.ts
|
68
92
|
import { defineNodeSpec } from "@prosekit/core";
|
69
|
-
import "prosemirror-tables";
|
70
93
|
var cellAttrs = {
|
71
94
|
colspan: { default: 1 },
|
72
95
|
rowspan: { default: 1 },
|
73
96
|
colwidth: { default: null }
|
74
|
-
}
|
97
|
+
};
|
98
|
+
var cellContent = "block+";
|
75
99
|
function getCellAttrs(dom) {
|
76
|
-
if (typeof dom
|
100
|
+
if (typeof dom === "string") {
|
77
101
|
return {};
|
78
|
-
|
102
|
+
}
|
103
|
+
const widthAttr = dom.getAttribute("data-colwidth");
|
104
|
+
const widths = widthAttr && /^\d+(,\d+)*$/.test(widthAttr) ? widthAttr.split(",").map((s) => Number(s)) : null;
|
105
|
+
const colspan = Number(dom.getAttribute("colspan") || 1);
|
79
106
|
return {
|
80
107
|
colspan,
|
81
108
|
rowspan: Number(dom.getAttribute("rowspan") || 1),
|
@@ -83,15 +110,25 @@ function getCellAttrs(dom) {
|
|
83
110
|
};
|
84
111
|
}
|
85
112
|
function setCellAttrs(node) {
|
86
|
-
|
87
|
-
|
113
|
+
const pmAttrs = node.attrs;
|
114
|
+
const domAttrs = {};
|
115
|
+
if (pmAttrs.colspan !== 1) {
|
116
|
+
domAttrs.colspan = pmAttrs.colspan;
|
117
|
+
}
|
118
|
+
if (pmAttrs.rowspan !== 1) {
|
119
|
+
domAttrs.rowspan = pmAttrs.rowspan;
|
120
|
+
}
|
121
|
+
if (pmAttrs.colwidth) {
|
122
|
+
domAttrs["data-colwidth"] = pmAttrs.colwidth.join(",");
|
123
|
+
}
|
124
|
+
return domAttrs;
|
88
125
|
}
|
89
126
|
function defineTableSpec() {
|
90
127
|
return defineNodeSpec({
|
91
128
|
name: "table",
|
92
129
|
tableRole: "table",
|
93
130
|
content: "tableRow+",
|
94
|
-
isolating:
|
131
|
+
isolating: true,
|
95
132
|
group: "block",
|
96
133
|
parseDOM: [{ tag: "table" }],
|
97
134
|
toDOM() {
|
@@ -116,7 +153,7 @@ function defineTableCellSpec() {
|
|
116
153
|
tableRole: "cell",
|
117
154
|
content: cellContent,
|
118
155
|
attrs: cellAttrs,
|
119
|
-
isolating:
|
156
|
+
isolating: true,
|
120
157
|
parseDOM: [{ tag: "td", getAttrs: (dom) => getCellAttrs(dom) }],
|
121
158
|
toDOM(node) {
|
122
159
|
return ["td", setCellAttrs(node), 0];
|
@@ -129,7 +166,7 @@ function defineTableHeaderCellSpec() {
|
|
129
166
|
tableRole: "header_cell",
|
130
167
|
content: cellContent,
|
131
168
|
attrs: cellAttrs,
|
132
|
-
isolating:
|
169
|
+
isolating: true,
|
133
170
|
parseDOM: [{ tag: "th", getAttrs: (dom) => getCellAttrs(dom) }],
|
134
171
|
toDOM(node) {
|
135
172
|
return ["th", setCellAttrs(node), 0];
|
@@ -3,3 +3,4 @@ export { defineTextAlignCommands } from './_tsup-dts-rollup';
|
|
3
3
|
export { defineTextAlignKeymap } from './_tsup-dts-rollup';
|
4
4
|
export { defineTextAlign } from './_tsup-dts-rollup';
|
5
5
|
export { TextAlignOptions } from './_tsup-dts-rollup';
|
6
|
+
export { TextAlignCommandTyping } from './_tsup-dts-rollup';
|
@@ -11,9 +11,11 @@ function defineTextAlignAttr(type, defaultValue) {
|
|
11
11
|
type,
|
12
12
|
attr: "textAlign",
|
13
13
|
default: defaultValue,
|
14
|
-
splittable:
|
14
|
+
splittable: true,
|
15
15
|
toDOM: (value) => value ? ["style", `text-align:${value};`] : null,
|
16
|
-
parseDOM: (node) =>
|
16
|
+
parseDOM: (node) => {
|
17
|
+
return node.style.getPropertyValue("text-align") || null;
|
18
|
+
}
|
17
19
|
});
|
18
20
|
}
|
19
21
|
function defineTextAlignAttrs(types, defaultValue) {
|
@@ -21,7 +21,7 @@ function getFocusState(state) {
|
|
21
21
|
var virtualSelectionPlugin = new ProseMirrorPlugin({
|
22
22
|
key,
|
23
23
|
state: {
|
24
|
-
init: () =>
|
24
|
+
init: () => false,
|
25
25
|
apply: (tr, value) => {
|
26
26
|
var _a;
|
27
27
|
return (_a = getFocusMeta(tr)) != null ? _a : value;
|
@@ -30,16 +30,21 @@ var virtualSelectionPlugin = new ProseMirrorPlugin({
|
|
30
30
|
props: {
|
31
31
|
handleDOMEvents: {
|
32
32
|
focus: (view) => {
|
33
|
-
view.dispatch(setFocusMeta(view.state.tr,
|
33
|
+
view.dispatch(setFocusMeta(view.state.tr, false));
|
34
34
|
},
|
35
35
|
blur: (view) => {
|
36
|
-
|
37
|
-
|
36
|
+
const { dom, root } = view;
|
37
|
+
const activeElement = root.activeElement;
|
38
|
+
if (activeElement === dom) return;
|
39
|
+
view.dispatch(setFocusMeta(view.state.tr, true));
|
38
40
|
}
|
39
41
|
},
|
40
42
|
decorations: (state) => {
|
41
|
-
|
42
|
-
|
43
|
+
const { selection, doc } = state;
|
44
|
+
if (selection.empty || !getFocusState(state)) {
|
45
|
+
return null;
|
46
|
+
}
|
47
|
+
return DecorationSet.create(doc, [
|
43
48
|
Decoration.inline(selection.from, selection.to, {
|
44
49
|
class: "prosekit-virtual-selection"
|
45
50
|
})
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@prosekit/extensions",
|
3
3
|
"type": "module",
|
4
|
-
"version": "0.7.
|
4
|
+
"version": "0.7.4",
|
5
5
|
"private": false,
|
6
6
|
"author": {
|
7
7
|
"name": "ocavue",
|
@@ -180,19 +180,20 @@
|
|
180
180
|
"dependencies": {
|
181
181
|
"prosemirror-changeset": "^2.2.1",
|
182
182
|
"prosemirror-dropcursor": "^1.8.1",
|
183
|
-
"prosemirror-flat-list": "^0.5.
|
183
|
+
"prosemirror-flat-list": "^0.5.3",
|
184
184
|
"prosemirror-highlight": "^0.8.0",
|
185
|
-
"prosemirror-search": "^
|
185
|
+
"prosemirror-search": "^1.0.0",
|
186
186
|
"prosemirror-tables": "^1.3.7",
|
187
187
|
"shiki": "^1.10.3",
|
188
|
-
"@prosekit/core": "^0.7.
|
189
|
-
"@prosekit/pm": "^0.1.
|
188
|
+
"@prosekit/core": "^0.7.4",
|
189
|
+
"@prosekit/pm": "^0.1.6"
|
190
190
|
},
|
191
191
|
"devDependencies": {
|
192
|
-
"@vitest/browser": "^2.0.
|
193
|
-
"tsup": "^8.1.
|
192
|
+
"@vitest/browser": "^2.0.3",
|
193
|
+
"tsup": "^8.1.2",
|
194
|
+
"type-fest": "^4.22.1",
|
194
195
|
"typescript": "^5.5.3",
|
195
|
-
"vitest": "^2.0.
|
196
|
+
"vitest": "^2.0.3",
|
196
197
|
"@prosekit/dev": "0.0.0"
|
197
198
|
},
|
198
199
|
"scripts": {
|
package/dist/chunk-ZPEMHYTU.js
DELETED
@@ -1,140 +0,0 @@
|
|
1
|
-
// src/mark-rule/extension.ts
|
2
|
-
import {
|
3
|
-
defineFacet,
|
4
|
-
defineFacetPayload,
|
5
|
-
pluginFacet
|
6
|
-
} from "@prosekit/core";
|
7
|
-
import {
|
8
|
-
PluginKey,
|
9
|
-
ProseMirrorPlugin
|
10
|
-
} from "@prosekit/pm/state";
|
11
|
-
|
12
|
-
// src/mark-rule/apply.ts
|
13
|
-
import {
|
14
|
-
OBJECT_REPLACEMENT_CHARACTER,
|
15
|
-
getMarkType,
|
16
|
-
maybeRun
|
17
|
-
} from "@prosekit/core";
|
18
|
-
import "@prosekit/pm/model";
|
19
|
-
import "@prosekit/pm/state";
|
20
|
-
|
21
|
-
// src/mark-rule/range.ts
|
22
|
-
import "@prosekit/pm/state";
|
23
|
-
function getSpanTextRanges($from, $to) {
|
24
|
-
let nodeRange = $from.blockRange($to);
|
25
|
-
if (!nodeRange)
|
26
|
-
return [];
|
27
|
-
let stack = [], start = nodeRange.start;
|
28
|
-
for (let i = nodeRange.startIndex; i < nodeRange.endIndex; i++) {
|
29
|
-
let child = nodeRange.parent.child(i);
|
30
|
-
stack.push([start, child]), start += child.nodeSize;
|
31
|
-
}
|
32
|
-
let ranges = [];
|
33
|
-
for (; stack.length > 0; ) {
|
34
|
-
let [start2, node] = stack.pop();
|
35
|
-
if (!node.type.spec.code) {
|
36
|
-
if (node.type.isTextblock) {
|
37
|
-
ranges.push([start2 + 1, start2 + 1 + node.content.size]);
|
38
|
-
continue;
|
39
|
-
}
|
40
|
-
node.forEach((child, offset) => {
|
41
|
-
stack.push([start2 + offset + 1, child]);
|
42
|
-
});
|
43
|
-
}
|
44
|
-
}
|
45
|
-
return ranges;
|
46
|
-
}
|
47
|
-
function getInlineTextRange($from, $to) {
|
48
|
-
return [$from.start(), $to.end()];
|
49
|
-
}
|
50
|
-
function getTextRanges(doc, from, to) {
|
51
|
-
let $from = doc.resolve(from), $to = doc.resolve(to);
|
52
|
-
return $from.sameParent($to) && $from.parent.isTextblock ? [getInlineTextRange($from, $to)] : $from.blockRange($to) ? getSpanTextRanges($from, $to) : [];
|
53
|
-
}
|
54
|
-
function getMapRange(transactions, oldState, newState) {
|
55
|
-
let lo = oldState.selection.from, hi = oldState.selection.to;
|
56
|
-
for (let tr of transactions)
|
57
|
-
for (let map of tr.mapping.maps)
|
58
|
-
lo = map.map(lo), hi = map.map(hi), map.forEach((_oldStart, _oldEnd, newStart, newEnd) => {
|
59
|
-
lo = Math.min(lo, hi, newStart), hi = Math.max(lo, hi, newEnd);
|
60
|
-
});
|
61
|
-
return lo = Math.min(lo, hi, newState.selection.from), hi = Math.min(lo, hi, newState.selection.to), [lo, hi];
|
62
|
-
}
|
63
|
-
function getCheckRanges(transactions, oldState, newState) {
|
64
|
-
let [from, to] = getMapRange(transactions, oldState, newState);
|
65
|
-
return getTextRanges(newState.doc, from, to);
|
66
|
-
}
|
67
|
-
|
68
|
-
// src/mark-rule/apply.ts
|
69
|
-
function getExpectedMarkings(rules, doc, from, to) {
|
70
|
-
let text = doc.textBetween(from, to, null, OBJECT_REPLACEMENT_CHARACTER), ranges = [];
|
71
|
-
for (let rule of rules) {
|
72
|
-
rule.regex.lastIndex = 0;
|
73
|
-
let matches = text.matchAll(rule.regex), markType = getMarkType(doc.type.schema, rule.type);
|
74
|
-
for (let match of matches) {
|
75
|
-
let index = match.index;
|
76
|
-
if (index == null) continue;
|
77
|
-
let attrs = maybeRun(rule.attrs, match), mark = markType.create(attrs);
|
78
|
-
ranges.push([from + index, from + index + match[0].length, mark]);
|
79
|
-
}
|
80
|
-
}
|
81
|
-
ranges.sort((a, b) => a[0] - b[0] || b[1] - a[1]);
|
82
|
-
let result = [], freeIndex = 0;
|
83
|
-
for (let range of ranges)
|
84
|
-
range[0] >= freeIndex && (result.push(range), freeIndex = range[1]);
|
85
|
-
return result;
|
86
|
-
}
|
87
|
-
function getReceivedMarkings(rules, doc, from, to) {
|
88
|
-
let result = [], schema = doc.type.schema, markTypes = rules.map((rule) => getMarkType(schema, rule.type));
|
89
|
-
return doc.nodesBetween(from, to, (node, pos) => {
|
90
|
-
if (node.isInline)
|
91
|
-
for (let markType of markTypes) {
|
92
|
-
let mark = node.marks.find((mark2) => mark2.type === markType);
|
93
|
-
mark && result.push([pos, pos + node.nodeSize, mark]);
|
94
|
-
}
|
95
|
-
}), result;
|
96
|
-
}
|
97
|
-
function markRangeEquals(a, b) {
|
98
|
-
return a[0] === b[0] && a[1] === b[1] && a[2].eq(b[2]);
|
99
|
-
}
|
100
|
-
function markRangeDiffs(a, b) {
|
101
|
-
return a.filter((x) => !b.some((y) => markRangeEquals(x, y)));
|
102
|
-
}
|
103
|
-
function applyMarkRules(rules, transactions, oldState, newState) {
|
104
|
-
if (transactions.length === 0 || transactions.every((tr2) => !tr2.docChanged))
|
105
|
-
return null;
|
106
|
-
let ranges = getCheckRanges(transactions, oldState, newState), toRemove = [], toCreate = [];
|
107
|
-
for (let [from, to] of ranges) {
|
108
|
-
let expected = getExpectedMarkings(rules, newState.doc, from, to), received = getReceivedMarkings(rules, newState.doc, from, to);
|
109
|
-
toRemove.push(...markRangeDiffs(received, expected)), toCreate.push(...markRangeDiffs(expected, received));
|
110
|
-
}
|
111
|
-
if (toCreate.length === 0 && toRemove.length === 0)
|
112
|
-
return null;
|
113
|
-
let tr = newState.tr;
|
114
|
-
for (let [from, to, mark] of toRemove)
|
115
|
-
tr.removeMark(from, to, mark);
|
116
|
-
for (let [from, to, mark] of toCreate)
|
117
|
-
tr.addMark(from, to, mark);
|
118
|
-
return tr;
|
119
|
-
}
|
120
|
-
|
121
|
-
// src/mark-rule/extension.ts
|
122
|
-
function defineMarkRule(options) {
|
123
|
-
return defineFacetPayload(markRuleFacet, [options]);
|
124
|
-
}
|
125
|
-
var markRuleFacet = defineFacet({
|
126
|
-
reduce: () => {
|
127
|
-
let rules = [], plugin = new ProseMirrorPlugin({
|
128
|
-
key: new PluginKey("prosekit-mark-rule"),
|
129
|
-
appendTransaction: (transactions, oldState, newState) => applyMarkRules(rules, transactions, oldState, newState)
|
130
|
-
});
|
131
|
-
return function(input) {
|
132
|
-
return rules = input, plugin;
|
133
|
-
};
|
134
|
-
},
|
135
|
-
parent: pluginFacet
|
136
|
-
});
|
137
|
-
|
138
|
-
export {
|
139
|
-
defineMarkRule
|
140
|
-
};
|