@prosekit/extensions 0.8.0 → 0.9.0
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 -1
- package/dist/commit/style.js +0 -0
- package/dist/enter-rule-RdhEA900.js +96 -0
- package/dist/gap-cursor/style.css +8 -5
- package/dist/gap-cursor/style.js +0 -0
- package/dist/input-rule-Gji4N7Oe.js +93 -0
- package/dist/list/style.css +7 -7
- package/dist/list/style.js +0 -0
- package/dist/loro/style.css +21 -17
- package/dist/loro/style.js +0 -0
- package/dist/mark-rule-wEOcDt6i.js +160 -0
- package/dist/placeholder/style.css +5 -5
- package/dist/placeholder/style.js +0 -0
- package/dist/prosekit-extensions-autocomplete.d.ts +33 -3
- package/dist/prosekit-extensions-autocomplete.js +122 -174
- package/dist/prosekit-extensions-blockquote.d.ts +51 -8
- package/dist/prosekit-extensions-blockquote.js +64 -78
- package/dist/prosekit-extensions-bold.d.ts +61 -8
- package/dist/prosekit-extensions-bold.js +61 -73
- package/dist/prosekit-extensions-code-block.d.ts +172 -20
- package/dist/prosekit-extensions-code-block.js +201 -184
- package/dist/prosekit-extensions-code.d.ts +61 -8
- package/dist/prosekit-extensions-code.js +44 -56
- package/dist/prosekit-extensions-commit.d.ts +53 -4
- package/dist/prosekit-extensions-commit.js +142 -183
- package/dist/prosekit-extensions-doc.d.ts +22 -2
- package/dist/prosekit-extensions-doc.js +14 -12
- package/dist/prosekit-extensions-drop-cursor.d.ts +34 -3
- package/dist/prosekit-extensions-drop-cursor.js +14 -8
- package/dist/prosekit-extensions-enter-rule.d.ts +106 -5
- package/dist/prosekit-extensions-enter-rule.js +3 -8
- package/dist/prosekit-extensions-file.d.ts +126 -8
- package/dist/prosekit-extensions-file.js +111 -132
- package/dist/prosekit-extensions-gap-cursor.d.ts +29 -2
- package/dist/prosekit-extensions-gap-cursor.js +21 -9
- package/dist/prosekit-extensions-hard-break.d.ts +58 -0
- package/dist/prosekit-extensions-hard-break.js +58 -0
- package/dist/prosekit-extensions-heading.d.ts +69 -9
- package/dist/prosekit-extensions-heading.js +121 -95
- package/dist/prosekit-extensions-horizontal-rule.d.ts +41 -8
- package/dist/prosekit-extensions-horizontal-rule.js +53 -71
- package/dist/prosekit-extensions-image.d.ts +53 -7
- package/dist/prosekit-extensions-image.js +71 -62
- package/dist/prosekit-extensions-input-rule.d.ts +134 -6
- package/dist/prosekit-extensions-input-rule.js +3 -14
- package/dist/prosekit-extensions-italic.d.ts +61 -8
- package/dist/prosekit-extensions-italic.js +51 -63
- package/dist/prosekit-extensions-link.d.ts +65 -10
- package/dist/prosekit-extensions-link.js +95 -100
- package/dist/prosekit-extensions-list.d.ts +114 -17
- package/dist/prosekit-extensions-list.js +115 -158
- package/dist/prosekit-extensions-loro.d.ts +78 -11
- package/dist/prosekit-extensions-loro.js +49 -77
- package/dist/prosekit-extensions-mark-rule.d.ts +41 -2
- package/dist/prosekit-extensions-mark-rule.js +3 -6
- package/dist/prosekit-extensions-mention.d.ts +40 -4
- package/dist/prosekit-extensions-mention.js +52 -50
- package/dist/prosekit-extensions-mod-click-prevention.d.ts +20 -2
- package/dist/prosekit-extensions-mod-click-prevention.js +20 -16
- package/dist/prosekit-extensions-paragraph.d.ts +65 -7
- package/dist/prosekit-extensions-paragraph.js +46 -45
- package/dist/prosekit-extensions-placeholder.d.ts +32 -2
- package/dist/prosekit-extensions-placeholder.js +39 -56
- package/dist/prosekit-extensions-readonly.d.ts +13 -1
- package/dist/prosekit-extensions-readonly.js +13 -14
- package/dist/prosekit-extensions-search.d.ts +77 -3
- package/dist/prosekit-extensions-search.js +48 -47
- package/dist/prosekit-extensions-strike.d.ts +50 -8
- package/dist/prosekit-extensions-strike.js +44 -49
- package/dist/prosekit-extensions-table.d.ts +237 -26
- package/dist/prosekit-extensions-table.js +3 -34
- package/dist/prosekit-extensions-text-align.d.ts +72 -8
- package/dist/prosekit-extensions-text-align.js +63 -44
- package/dist/prosekit-extensions-text.d.ts +22 -2
- package/dist/prosekit-extensions-text.js +13 -11
- package/dist/prosekit-extensions-underline.d.ts +46 -7
- package/dist/prosekit-extensions-underline.js +33 -37
- package/dist/prosekit-extensions-virtual-selection.d.ts +24 -2
- package/dist/prosekit-extensions-virtual-selection.js +49 -52
- package/dist/prosekit-extensions-yjs.d.ts +99 -14
- package/dist/prosekit-extensions-yjs.js +88 -131
- package/dist/prosekit-extensions.d.ts +1 -1
- package/dist/search/style.css +5 -5
- package/dist/search/style.js +0 -0
- package/dist/shiki-highlighter-chunk-Cd3WeOKL.d.ts +19 -0
- package/dist/shiki-highlighter-chunk.d.ts +2 -0
- package/dist/shiki-highlighter-chunk.js +32 -39
- package/dist/table/style.css +18 -17
- package/dist/table/style.js +0 -0
- package/dist/table-DnVliJ6E.js +287 -0
- package/dist/virtual-selection/style.css +2 -2
- package/dist/virtual-selection/style.js +0 -0
- package/dist/yjs/style.css +15 -17
- package/dist/yjs/style.js +0 -0
- package/package.json +80 -53
- package/dist/_tsup-dts-rollup.d.ts +0 -2459
- package/dist/chunk-6UYLCVBX.js +0 -185
- package/dist/chunk-D54VSLLS.js +0 -105
- package/dist/chunk-I2UMHK3L.js +0 -99
- package/dist/chunk-QVFEYPQ6.js +0 -306
package/dist/chunk-6UYLCVBX.js
DELETED
@@ -1,185 +0,0 @@
|
|
1
|
-
// src/mark-rule/mark-rule.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
|
-
getMarkType,
|
15
|
-
maybeRun,
|
16
|
-
OBJECT_REPLACEMENT_CHARACTER
|
17
|
-
} from "@prosekit/core";
|
18
|
-
|
19
|
-
// src/mark-rule/range.ts
|
20
|
-
function getSpanTextRanges($from, $to) {
|
21
|
-
const nodeRange = $from.blockRange($to);
|
22
|
-
if (!nodeRange) {
|
23
|
-
return [];
|
24
|
-
}
|
25
|
-
const stack = [];
|
26
|
-
let start = nodeRange.start;
|
27
|
-
for (let i = nodeRange.startIndex; i < nodeRange.endIndex; i++) {
|
28
|
-
const child = nodeRange.parent.child(i);
|
29
|
-
stack.push([start, child]);
|
30
|
-
start += child.nodeSize;
|
31
|
-
}
|
32
|
-
const ranges = [];
|
33
|
-
while (stack.length > 0) {
|
34
|
-
const [start2, node] = stack.pop();
|
35
|
-
if (node.type.spec.code) {
|
36
|
-
continue;
|
37
|
-
}
|
38
|
-
if (node.type.isTextblock) {
|
39
|
-
ranges.push([start2 + 1, start2 + 1 + node.content.size]);
|
40
|
-
continue;
|
41
|
-
}
|
42
|
-
node.forEach((child, offset) => {
|
43
|
-
stack.push([start2 + offset + 1, child]);
|
44
|
-
});
|
45
|
-
}
|
46
|
-
return ranges;
|
47
|
-
}
|
48
|
-
function getInlineTextRange($from, $to) {
|
49
|
-
return [$from.start(), $to.end()];
|
50
|
-
}
|
51
|
-
function getTextRanges(doc, from, to) {
|
52
|
-
const $from = doc.resolve(from);
|
53
|
-
const $to = doc.resolve(to);
|
54
|
-
if ($from.sameParent($to) && $from.parent.isTextblock) {
|
55
|
-
return [getInlineTextRange($from, $to)];
|
56
|
-
} else {
|
57
|
-
const nodeRange = $from.blockRange($to);
|
58
|
-
if (!nodeRange) {
|
59
|
-
return [];
|
60
|
-
}
|
61
|
-
return getSpanTextRanges($from, $to);
|
62
|
-
}
|
63
|
-
}
|
64
|
-
function getMapRange(transactions, oldState, newState) {
|
65
|
-
let lo = oldState.selection.from;
|
66
|
-
let hi = oldState.selection.to;
|
67
|
-
for (const tr of transactions) {
|
68
|
-
for (const map of tr.mapping.maps) {
|
69
|
-
lo = map.map(lo);
|
70
|
-
hi = map.map(hi);
|
71
|
-
map.forEach((_oldStart, _oldEnd, newStart, newEnd) => {
|
72
|
-
lo = Math.min(lo, hi, newStart);
|
73
|
-
hi = Math.max(lo, hi, newEnd);
|
74
|
-
});
|
75
|
-
}
|
76
|
-
}
|
77
|
-
lo = Math.min(lo, hi, newState.selection.from);
|
78
|
-
hi = Math.min(lo, hi, newState.selection.to);
|
79
|
-
return [lo, hi];
|
80
|
-
}
|
81
|
-
function getCheckRanges(transactions, oldState, newState) {
|
82
|
-
const [from, to] = getMapRange(transactions, oldState, newState);
|
83
|
-
return getTextRanges(newState.doc, from, to);
|
84
|
-
}
|
85
|
-
|
86
|
-
// src/mark-rule/apply.ts
|
87
|
-
function getExpectedMarkings(rules, doc, from, to) {
|
88
|
-
const text = doc.textBetween(from, to, null, OBJECT_REPLACEMENT_CHARACTER);
|
89
|
-
const ranges = [];
|
90
|
-
for (const rule of rules) {
|
91
|
-
rule.regex.lastIndex = 0;
|
92
|
-
const matches = text.matchAll(rule.regex);
|
93
|
-
const markType = getMarkType(doc.type.schema, rule.type);
|
94
|
-
for (const match of matches) {
|
95
|
-
const index = match.index;
|
96
|
-
if (index == null) continue;
|
97
|
-
const attrs = maybeRun(rule.attrs, match);
|
98
|
-
const mark = markType.create(attrs);
|
99
|
-
ranges.push([from + index, from + index + match[0].length, mark]);
|
100
|
-
}
|
101
|
-
}
|
102
|
-
ranges.sort((a, b) => a[0] - b[0] || b[1] - a[1]);
|
103
|
-
const result = [];
|
104
|
-
let freeIndex = 0;
|
105
|
-
for (const range of ranges) {
|
106
|
-
if (range[0] >= freeIndex) {
|
107
|
-
result.push(range);
|
108
|
-
freeIndex = range[1];
|
109
|
-
}
|
110
|
-
}
|
111
|
-
return result;
|
112
|
-
}
|
113
|
-
function getReceivedMarkings(rules, doc, from, to) {
|
114
|
-
const result = [];
|
115
|
-
const schema = doc.type.schema;
|
116
|
-
const markTypes = rules.map((rule) => getMarkType(schema, rule.type));
|
117
|
-
doc.nodesBetween(from, to, (node, pos) => {
|
118
|
-
if (!node.isInline) {
|
119
|
-
return;
|
120
|
-
}
|
121
|
-
for (const markType of markTypes) {
|
122
|
-
const mark = node.marks.find((mark2) => mark2.type === markType);
|
123
|
-
if (mark) {
|
124
|
-
result.push([pos, pos + node.nodeSize, mark]);
|
125
|
-
}
|
126
|
-
}
|
127
|
-
});
|
128
|
-
return result;
|
129
|
-
}
|
130
|
-
function markRangeEquals(a, b) {
|
131
|
-
return a[0] === b[0] && a[1] === b[1] && a[2].eq(b[2]);
|
132
|
-
}
|
133
|
-
function markRangeDiffs(a, b) {
|
134
|
-
return a.filter((x) => !b.some((y) => markRangeEquals(x, y)));
|
135
|
-
}
|
136
|
-
function applyMarkRules(rules, transactions, oldState, newState) {
|
137
|
-
if (transactions.length === 0 || transactions.every((tr2) => !tr2.docChanged)) {
|
138
|
-
return null;
|
139
|
-
}
|
140
|
-
const ranges = getCheckRanges(transactions, oldState, newState);
|
141
|
-
const toRemove = [];
|
142
|
-
const toCreate = [];
|
143
|
-
for (const [from, to] of ranges) {
|
144
|
-
const expected = getExpectedMarkings(rules, newState.doc, from, to);
|
145
|
-
const received = getReceivedMarkings(rules, newState.doc, from, to);
|
146
|
-
toRemove.push(...markRangeDiffs(received, expected));
|
147
|
-
toCreate.push(...markRangeDiffs(expected, received));
|
148
|
-
}
|
149
|
-
if (toCreate.length === 0 && toRemove.length === 0) {
|
150
|
-
return null;
|
151
|
-
}
|
152
|
-
const tr = newState.tr;
|
153
|
-
for (const [from, to, mark] of toRemove) {
|
154
|
-
tr.removeMark(from, to, mark);
|
155
|
-
}
|
156
|
-
for (const [from, to, mark] of toCreate) {
|
157
|
-
tr.addMark(from, to, mark);
|
158
|
-
}
|
159
|
-
return tr;
|
160
|
-
}
|
161
|
-
|
162
|
-
// src/mark-rule/mark-rule.ts
|
163
|
-
function defineMarkRule(options) {
|
164
|
-
return defineFacetPayload(markRuleFacet, [options]);
|
165
|
-
}
|
166
|
-
var markRuleFacet = defineFacet({
|
167
|
-
reduce: () => {
|
168
|
-
let rules = [];
|
169
|
-
const plugin = new ProseMirrorPlugin({
|
170
|
-
key: new PluginKey("prosekit-mark-rule"),
|
171
|
-
appendTransaction: (transactions, oldState, newState) => {
|
172
|
-
return applyMarkRules(rules, transactions, oldState, newState);
|
173
|
-
}
|
174
|
-
});
|
175
|
-
return function reducer(input) {
|
176
|
-
rules = input;
|
177
|
-
return plugin;
|
178
|
-
};
|
179
|
-
},
|
180
|
-
parent: pluginFacet
|
181
|
-
});
|
182
|
-
|
183
|
-
export {
|
184
|
-
defineMarkRule
|
185
|
-
};
|
package/dist/chunk-D54VSLLS.js
DELETED
@@ -1,105 +0,0 @@
|
|
1
|
-
// src/enter-rule/index.ts
|
2
|
-
import {
|
3
|
-
defineFacet,
|
4
|
-
defineFacetPayload,
|
5
|
-
getNodeType,
|
6
|
-
isTextSelection,
|
7
|
-
maybeRun,
|
8
|
-
OBJECT_REPLACEMENT_CHARACTER,
|
9
|
-
pluginFacet
|
10
|
-
} from "@prosekit/core";
|
11
|
-
import { keydownHandler } from "@prosekit/pm/keymap";
|
12
|
-
import {
|
13
|
-
PluginKey,
|
14
|
-
ProseMirrorPlugin
|
15
|
-
} from "@prosekit/pm/state";
|
16
|
-
function defineEnterRule({
|
17
|
-
regex,
|
18
|
-
handler,
|
19
|
-
stop = false
|
20
|
-
}) {
|
21
|
-
const rule = new EnterRule(regex, handler, stop);
|
22
|
-
return defineFacetPayload(enterRule, [rule]);
|
23
|
-
}
|
24
|
-
function defineTextBlockEnterRule({
|
25
|
-
regex,
|
26
|
-
type,
|
27
|
-
attrs,
|
28
|
-
stop = true
|
29
|
-
}) {
|
30
|
-
return defineEnterRule({
|
31
|
-
regex,
|
32
|
-
handler: ({ state, from, to, match }) => {
|
33
|
-
const nodeType = getNodeType(state.schema, type);
|
34
|
-
const $start = state.doc.resolve(from);
|
35
|
-
if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), nodeType)) {
|
36
|
-
return null;
|
37
|
-
}
|
38
|
-
const nodeAttrs = maybeRun(attrs, match);
|
39
|
-
return state.tr.delete(from, to).setBlockType(from, from, nodeType, nodeAttrs);
|
40
|
-
},
|
41
|
-
stop
|
42
|
-
});
|
43
|
-
}
|
44
|
-
var EnterRule = class {
|
45
|
-
constructor(regex, handler, stop) {
|
46
|
-
this.regex = regex;
|
47
|
-
this.handler = handler;
|
48
|
-
this.stop = stop;
|
49
|
-
}
|
50
|
-
};
|
51
|
-
var enterRule = defineFacet({
|
52
|
-
reduce: () => {
|
53
|
-
let rules = [];
|
54
|
-
const command = (state, dispatch, view) => {
|
55
|
-
if (!view) return false;
|
56
|
-
return execRules(view, rules, dispatch);
|
57
|
-
};
|
58
|
-
const handler = keydownHandler({ Enter: command });
|
59
|
-
const plugin = new ProseMirrorPlugin({
|
60
|
-
key: new PluginKey("prosekit-enter-rule"),
|
61
|
-
props: { handleKeyDown: handler }
|
62
|
-
});
|
63
|
-
return function reducer(inputs) {
|
64
|
-
rules = inputs;
|
65
|
-
return plugin;
|
66
|
-
};
|
67
|
-
},
|
68
|
-
parent: pluginFacet
|
69
|
-
});
|
70
|
-
function execRules(view, rules, dispatch) {
|
71
|
-
if (view.composing) return false;
|
72
|
-
const state = view.state;
|
73
|
-
const selection = state.selection;
|
74
|
-
if (!isTextSelection(selection)) return false;
|
75
|
-
const $cursor = selection.$cursor;
|
76
|
-
if (!$cursor || $cursor.parent.type.spec.code) return false;
|
77
|
-
const textBefore = $cursor.parent.textBetween(
|
78
|
-
Math.max(0, $cursor.parentOffset - MAX_MATCH),
|
79
|
-
$cursor.parentOffset,
|
80
|
-
null,
|
81
|
-
OBJECT_REPLACEMENT_CHARACTER
|
82
|
-
);
|
83
|
-
for (const rule of rules) {
|
84
|
-
rule.regex.lastIndex = 0;
|
85
|
-
const match = rule.regex.exec(textBefore);
|
86
|
-
const tr = match && rule.handler({
|
87
|
-
state,
|
88
|
-
from: $cursor.pos - match[0].length,
|
89
|
-
to: $cursor.pos,
|
90
|
-
match
|
91
|
-
});
|
92
|
-
if (!tr) continue;
|
93
|
-
dispatch?.(tr);
|
94
|
-
if (rule.stop) {
|
95
|
-
return true;
|
96
|
-
}
|
97
|
-
}
|
98
|
-
return false;
|
99
|
-
}
|
100
|
-
var MAX_MATCH = 200;
|
101
|
-
|
102
|
-
export {
|
103
|
-
defineEnterRule,
|
104
|
-
defineTextBlockEnterRule
|
105
|
-
};
|
package/dist/chunk-I2UMHK3L.js
DELETED
@@ -1,99 +0,0 @@
|
|
1
|
-
// src/input-rule/index.ts
|
2
|
-
import {
|
3
|
-
defineFacet,
|
4
|
-
defineFacetPayload,
|
5
|
-
getMarkType,
|
6
|
-
getNodeType,
|
7
|
-
isMarkAbsent,
|
8
|
-
maybeRun,
|
9
|
-
pluginFacet
|
10
|
-
} from "@prosekit/core";
|
11
|
-
import {
|
12
|
-
InputRule,
|
13
|
-
inputRules,
|
14
|
-
textblockTypeInputRule,
|
15
|
-
wrappingInputRule
|
16
|
-
} from "@prosekit/pm/inputrules";
|
17
|
-
import "@prosekit/pm/state";
|
18
|
-
function defineInputRule(rule) {
|
19
|
-
return defineInputRuleFacetPayload(() => rule);
|
20
|
-
}
|
21
|
-
function createMarkInputRule({
|
22
|
-
regex,
|
23
|
-
type,
|
24
|
-
attrs = null,
|
25
|
-
inCodeMark = false
|
26
|
-
}) {
|
27
|
-
const rule = new InputRule(regex, (state, match, start, end) => {
|
28
|
-
const { tr, schema } = state;
|
29
|
-
const [fullText, markText] = match;
|
30
|
-
if (!markText) {
|
31
|
-
return null;
|
32
|
-
}
|
33
|
-
const markStart = start + fullText.indexOf(markText);
|
34
|
-
const markEnd = markStart + markText.length;
|
35
|
-
if (!(start <= markStart && markStart < markEnd && markEnd <= end)) {
|
36
|
-
return null;
|
37
|
-
}
|
38
|
-
const markType = getMarkType(schema, type);
|
39
|
-
const mark = markType.create(maybeRun(attrs, match));
|
40
|
-
if (!isMarkAbsent(tr.doc, markStart, markEnd, markType, attrs)) {
|
41
|
-
return null;
|
42
|
-
}
|
43
|
-
const initialStoredMarks = tr.storedMarks ?? [];
|
44
|
-
tr.addMark(markStart, markEnd, mark);
|
45
|
-
if (markEnd < end) {
|
46
|
-
tr.delete(markEnd, end);
|
47
|
-
}
|
48
|
-
if (start < markStart) {
|
49
|
-
tr.delete(start, markStart);
|
50
|
-
}
|
51
|
-
tr.setStoredMarks(initialStoredMarks);
|
52
|
-
return tr;
|
53
|
-
}, { inCodeMark });
|
54
|
-
return rule;
|
55
|
-
}
|
56
|
-
function defineMarkInputRule(options) {
|
57
|
-
return defineInputRule(createMarkInputRule(options));
|
58
|
-
}
|
59
|
-
function defineTextBlockInputRule({
|
60
|
-
regex,
|
61
|
-
type,
|
62
|
-
attrs
|
63
|
-
}) {
|
64
|
-
return defineInputRuleFacetPayload(({ schema }) => {
|
65
|
-
const nodeType = getNodeType(schema, type);
|
66
|
-
return textblockTypeInputRule(regex, nodeType, attrs);
|
67
|
-
});
|
68
|
-
}
|
69
|
-
function defineWrappingInputRule({
|
70
|
-
regex,
|
71
|
-
type,
|
72
|
-
attrs,
|
73
|
-
join
|
74
|
-
}) {
|
75
|
-
return defineInputRuleFacetPayload(({ schema }) => {
|
76
|
-
const nodeType = getNodeType(schema, type);
|
77
|
-
return wrappingInputRule(regex, nodeType, attrs, join);
|
78
|
-
});
|
79
|
-
}
|
80
|
-
function defineInputRuleFacetPayload(input) {
|
81
|
-
return defineFacetPayload(inputRuleFacet, [input]);
|
82
|
-
}
|
83
|
-
var inputRuleFacet = defineFacet({
|
84
|
-
reducer: (inputs) => {
|
85
|
-
return (context) => {
|
86
|
-
const rules = inputs.flatMap((callback) => callback(context));
|
87
|
-
return [inputRules({ rules })];
|
88
|
-
};
|
89
|
-
},
|
90
|
-
parent: pluginFacet
|
91
|
-
});
|
92
|
-
|
93
|
-
export {
|
94
|
-
defineInputRule,
|
95
|
-
createMarkInputRule,
|
96
|
-
defineMarkInputRule,
|
97
|
-
defineTextBlockInputRule,
|
98
|
-
defineWrappingInputRule
|
99
|
-
};
|
package/dist/chunk-QVFEYPQ6.js
DELETED
@@ -1,306 +0,0 @@
|
|
1
|
-
// src/table/table.ts
|
2
|
-
import {
|
3
|
-
union
|
4
|
-
} from "@prosekit/core";
|
5
|
-
|
6
|
-
// src/table/table-commands.ts
|
7
|
-
import {
|
8
|
-
defaultBlockAt,
|
9
|
-
defineCommands,
|
10
|
-
getNodeType,
|
11
|
-
insertNode
|
12
|
-
} from "@prosekit/core";
|
13
|
-
import {
|
14
|
-
TextSelection
|
15
|
-
} from "@prosekit/pm/state";
|
16
|
-
import {
|
17
|
-
addColumnAfter,
|
18
|
-
addColumnBefore,
|
19
|
-
addRowAfter,
|
20
|
-
addRowBefore,
|
21
|
-
CellSelection as CellSelection2,
|
22
|
-
deleteCellSelection,
|
23
|
-
deleteColumn,
|
24
|
-
deleteRow,
|
25
|
-
deleteTable,
|
26
|
-
mergeCells,
|
27
|
-
splitCell,
|
28
|
-
TableMap
|
29
|
-
} from "prosemirror-tables";
|
30
|
-
|
31
|
-
// src/table/table-utils.ts
|
32
|
-
import {
|
33
|
-
findParentNode
|
34
|
-
} from "@prosekit/core";
|
35
|
-
import {
|
36
|
-
cellAround,
|
37
|
-
cellNear,
|
38
|
-
CellSelection,
|
39
|
-
inSameTable
|
40
|
-
} from "prosemirror-tables";
|
41
|
-
function isCellSelection(value) {
|
42
|
-
return value instanceof CellSelection;
|
43
|
-
}
|
44
|
-
function findTable($pos) {
|
45
|
-
return findParentNode((node) => node.type.spec.tableRole === "table", $pos);
|
46
|
-
}
|
47
|
-
function findCellRange(selection, anchorHit, headHit) {
|
48
|
-
if (anchorHit == null && headHit == null && isCellSelection(selection)) {
|
49
|
-
return [selection.$anchorCell, selection.$headCell];
|
50
|
-
}
|
51
|
-
const anchor = anchorHit ?? headHit ?? selection.anchor;
|
52
|
-
const head = headHit ?? anchorHit ?? selection.head;
|
53
|
-
const doc = selection.$head.doc;
|
54
|
-
const $anchorCell = findCellPos(doc, anchor);
|
55
|
-
const $headCell = findCellPos(doc, head);
|
56
|
-
if ($anchorCell && $headCell && inSameTable($anchorCell, $headCell)) {
|
57
|
-
return [$anchorCell, $headCell];
|
58
|
-
}
|
59
|
-
}
|
60
|
-
function findCellPos(doc, pos) {
|
61
|
-
const $pos = doc.resolve(pos);
|
62
|
-
return cellAround($pos) || cellNear($pos);
|
63
|
-
}
|
64
|
-
|
65
|
-
// src/table/table-commands.ts
|
66
|
-
function createEmptyTable(schema, row, col, header) {
|
67
|
-
const tableType = getNodeType(schema, "table");
|
68
|
-
const tableRowType = getNodeType(schema, "tableRow");
|
69
|
-
const tableCellType = getNodeType(schema, "tableCell");
|
70
|
-
const tableHeaderCellType = getNodeType(schema, "tableHeaderCell");
|
71
|
-
if (header) {
|
72
|
-
const headerCell = tableHeaderCellType.createAndFill();
|
73
|
-
const headerCells = repeat(headerCell, col);
|
74
|
-
const headerRow = tableRowType.createAndFill(null, headerCells);
|
75
|
-
const bodyCell = tableCellType.createAndFill();
|
76
|
-
const bodyCells = repeat(bodyCell, col);
|
77
|
-
const bodyRow = tableRowType.createAndFill(null, bodyCells);
|
78
|
-
const bodyRows = repeat(bodyRow, row - 1);
|
79
|
-
return tableType.createAndFill(null, [headerRow, ...bodyRows]);
|
80
|
-
} else {
|
81
|
-
const bodyCell = tableCellType.createAndFill();
|
82
|
-
const bodyCells = repeat(bodyCell, col);
|
83
|
-
const bodyRow = tableRowType.createAndFill(null, bodyCells);
|
84
|
-
const bodyRows = repeat(bodyRow, row);
|
85
|
-
return tableType.createAndFill(null, bodyRows);
|
86
|
-
}
|
87
|
-
}
|
88
|
-
function repeat(node, length) {
|
89
|
-
return Array(length).fill(node);
|
90
|
-
}
|
91
|
-
function insertTable(options) {
|
92
|
-
return (state, dispatch, view) => {
|
93
|
-
const { row, col, header = false } = options;
|
94
|
-
const table = createEmptyTable(state.schema, row, col, header);
|
95
|
-
return insertNode({ node: table })(state, dispatch, view);
|
96
|
-
};
|
97
|
-
}
|
98
|
-
var exitTable = (state, dispatch) => {
|
99
|
-
const { $head, $anchor } = state.selection;
|
100
|
-
if (!$head.sameParent($anchor)) {
|
101
|
-
return false;
|
102
|
-
}
|
103
|
-
let tableStart = -1;
|
104
|
-
let tableDepth = -1;
|
105
|
-
for (let depth = $head.depth; depth >= 0; depth--) {
|
106
|
-
const node2 = $head.node(depth);
|
107
|
-
if (node2.type.spec.tableRole === "table") {
|
108
|
-
tableStart = $head.before(depth);
|
109
|
-
tableDepth = depth;
|
110
|
-
}
|
111
|
-
}
|
112
|
-
if (tableStart < 0 || tableDepth <= 0) {
|
113
|
-
return false;
|
114
|
-
}
|
115
|
-
const above = $head.node(tableDepth - 1);
|
116
|
-
const after = $head.indexAfter(tableDepth - 1);
|
117
|
-
const type = defaultBlockAt(above.contentMatchAt(after));
|
118
|
-
const node = type?.createAndFill();
|
119
|
-
if (!type || !node || !above.canReplaceWith(after, after, type)) {
|
120
|
-
return false;
|
121
|
-
}
|
122
|
-
if (dispatch) {
|
123
|
-
const pos = $head.after(tableDepth);
|
124
|
-
const tr = state.tr.replaceWith(pos, pos, node);
|
125
|
-
tr.setSelection(TextSelection.near(tr.doc.resolve(pos), 1));
|
126
|
-
dispatch(tr.scrollIntoView());
|
127
|
-
}
|
128
|
-
return true;
|
129
|
-
};
|
130
|
-
function selectTableColumn(options) {
|
131
|
-
return (state, dispatch) => {
|
132
|
-
const range = findCellRange(state.selection, options?.anchor, options?.head);
|
133
|
-
if (!range) {
|
134
|
-
return false;
|
135
|
-
}
|
136
|
-
if (dispatch) {
|
137
|
-
const [$anchorCell, $headCell] = range;
|
138
|
-
const selection = CellSelection2.colSelection($anchorCell, $headCell);
|
139
|
-
dispatch(state.tr.setSelection(selection));
|
140
|
-
}
|
141
|
-
return true;
|
142
|
-
};
|
143
|
-
}
|
144
|
-
function selectTableRow(options) {
|
145
|
-
return (state, dispatch) => {
|
146
|
-
const range = findCellRange(state.selection, options?.anchor, options?.head);
|
147
|
-
if (!range) {
|
148
|
-
return false;
|
149
|
-
}
|
150
|
-
if (dispatch) {
|
151
|
-
const [$anchorCell, $headCell] = range;
|
152
|
-
const selection = CellSelection2.rowSelection($anchorCell, $headCell);
|
153
|
-
dispatch(state.tr.setSelection(selection));
|
154
|
-
}
|
155
|
-
return true;
|
156
|
-
};
|
157
|
-
}
|
158
|
-
function selectTableCell(options) {
|
159
|
-
return (state, dispatch) => {
|
160
|
-
const $cellPos = findCellPos(
|
161
|
-
state.doc,
|
162
|
-
options?.pos ?? state.selection.anchor
|
163
|
-
);
|
164
|
-
if (!$cellPos) {
|
165
|
-
return false;
|
166
|
-
}
|
167
|
-
if (dispatch) {
|
168
|
-
const selection = new CellSelection2($cellPos);
|
169
|
-
dispatch(state.tr.setSelection(selection));
|
170
|
-
}
|
171
|
-
return true;
|
172
|
-
};
|
173
|
-
}
|
174
|
-
function selectTable(options) {
|
175
|
-
return (state, dispatch) => {
|
176
|
-
const $pos = options?.pos ? state.doc.resolve(options.pos) : state.selection.$anchor;
|
177
|
-
const table = findTable($pos);
|
178
|
-
if (!table) {
|
179
|
-
return false;
|
180
|
-
}
|
181
|
-
const map = TableMap.get(table.node);
|
182
|
-
if (map.map.length === 0) {
|
183
|
-
return false;
|
184
|
-
}
|
185
|
-
if (dispatch) {
|
186
|
-
let tr = state.tr;
|
187
|
-
const firstCellPosInTable = map.map[0];
|
188
|
-
const lastCellPosInTable = map.map[map.map.length - 1];
|
189
|
-
const firstCellPos = table.pos + firstCellPosInTable + 1;
|
190
|
-
const lastCellPos = table.pos + lastCellPosInTable + 1;
|
191
|
-
const $firstCellPos = tr.doc.resolve(firstCellPos);
|
192
|
-
const $lastCellPos = tr.doc.resolve(lastCellPos);
|
193
|
-
const selection = new CellSelection2($firstCellPos, $lastCellPos);
|
194
|
-
tr = tr.setSelection(selection);
|
195
|
-
dispatch?.(tr);
|
196
|
-
}
|
197
|
-
return true;
|
198
|
-
};
|
199
|
-
}
|
200
|
-
function defineTableCommands() {
|
201
|
-
return defineCommands({
|
202
|
-
insertTable,
|
203
|
-
exitTable: () => exitTable,
|
204
|
-
selectTable,
|
205
|
-
selectTableCell,
|
206
|
-
selectTableColumn,
|
207
|
-
selectTableRow,
|
208
|
-
addTableColumnBefore: () => addColumnBefore,
|
209
|
-
addTableColumnAfter: () => addColumnAfter,
|
210
|
-
addTableRowAbove: () => addRowBefore,
|
211
|
-
addTableRowBelow: () => addRowAfter,
|
212
|
-
deleteTable: () => deleteTable,
|
213
|
-
deleteTableColumn: () => deleteColumn,
|
214
|
-
deleteTableRow: () => deleteRow,
|
215
|
-
deleteCellSelection: () => deleteCellSelection,
|
216
|
-
mergeTableCells: () => mergeCells,
|
217
|
-
splitTableCell: () => splitCell
|
218
|
-
});
|
219
|
-
}
|
220
|
-
|
221
|
-
// src/table/table-plugins.ts
|
222
|
-
import {
|
223
|
-
definePlugin
|
224
|
-
} from "@prosekit/core";
|
225
|
-
import {
|
226
|
-
columnResizing,
|
227
|
-
tableEditing
|
228
|
-
} from "prosemirror-tables";
|
229
|
-
function defineTablePlugins() {
|
230
|
-
return definePlugin([tableEditing(), columnResizing()]);
|
231
|
-
}
|
232
|
-
|
233
|
-
// src/table/table-spec.ts
|
234
|
-
import {
|
235
|
-
defineNodeSpec
|
236
|
-
} from "@prosekit/core";
|
237
|
-
import { tableNodes } from "prosemirror-tables";
|
238
|
-
var cellContent = "block+";
|
239
|
-
var cellAttrs = {
|
240
|
-
colspan: { default: 1 },
|
241
|
-
rowspan: { default: 1 },
|
242
|
-
colwidth: { default: null }
|
243
|
-
};
|
244
|
-
var specs = tableNodes({
|
245
|
-
tableGroup: "block",
|
246
|
-
cellContent,
|
247
|
-
cellAttributes: {}
|
248
|
-
});
|
249
|
-
function defineTableSpec() {
|
250
|
-
return defineNodeSpec({
|
251
|
-
...specs["table"],
|
252
|
-
content: "tableRow+",
|
253
|
-
name: "table"
|
254
|
-
});
|
255
|
-
}
|
256
|
-
function defineTableRowSpec() {
|
257
|
-
return defineNodeSpec({
|
258
|
-
...specs["table_row"],
|
259
|
-
content: "(tableCell | tableHeaderCell)*",
|
260
|
-
name: "tableRow"
|
261
|
-
});
|
262
|
-
}
|
263
|
-
function defineTableCellSpec() {
|
264
|
-
return defineNodeSpec({
|
265
|
-
...specs["table_cell"],
|
266
|
-
name: "tableCell",
|
267
|
-
attrs: cellAttrs
|
268
|
-
});
|
269
|
-
}
|
270
|
-
function defineTableHeaderCellSpec() {
|
271
|
-
return defineNodeSpec({
|
272
|
-
...specs["table_header"],
|
273
|
-
name: "tableHeaderCell",
|
274
|
-
attrs: cellAttrs
|
275
|
-
});
|
276
|
-
}
|
277
|
-
|
278
|
-
// src/table/table.ts
|
279
|
-
function defineTable() {
|
280
|
-
return union(
|
281
|
-
defineTableSpec(),
|
282
|
-
defineTableRowSpec(),
|
283
|
-
defineTableCellSpec(),
|
284
|
-
defineTableHeaderCellSpec(),
|
285
|
-
defineTablePlugins(),
|
286
|
-
defineTableCommands()
|
287
|
-
);
|
288
|
-
}
|
289
|
-
|
290
|
-
export {
|
291
|
-
isCellSelection,
|
292
|
-
findTable,
|
293
|
-
insertTable,
|
294
|
-
exitTable,
|
295
|
-
selectTableColumn,
|
296
|
-
selectTableRow,
|
297
|
-
selectTableCell,
|
298
|
-
selectTable,
|
299
|
-
defineTableCommands,
|
300
|
-
defineTablePlugins,
|
301
|
-
defineTableSpec,
|
302
|
-
defineTableRowSpec,
|
303
|
-
defineTableCellSpec,
|
304
|
-
defineTableHeaderCellSpec,
|
305
|
-
defineTable
|
306
|
-
};
|