@prosekit/extensions 0.0.0-next-20240427133255 → 0.0.0-next-20240427200701
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.
@@ -24,13 +24,13 @@ import { Parser } from 'prosemirror-highlight';
|
|
24
24
|
import { Plugin as Plugin_2 } from '@prosekit/pm/state';
|
25
25
|
import { PluginKey } from '@prosekit/pm/state';
|
26
26
|
import { ProseMirrorNode } from '@prosekit/pm/model';
|
27
|
-
import type { ResolvedPos } from '@prosekit/pm/model';
|
28
|
-
import type { Selection as Selection_2 } from '@prosekit/pm/state';
|
29
27
|
import type { SpecialLanguage } from 'shiki';
|
30
28
|
import { ToggleCollapsedOptions } from 'prosemirror-flat-list';
|
31
29
|
import { Transaction } from '@prosekit/pm/state';
|
32
30
|
import { UnwrapListOptions } from 'prosemirror-flat-list';
|
33
31
|
|
32
|
+
export declare function applyMarkRules(rules: MarkRule[], transactions: readonly Transaction[], oldState: EditorState, newState: EditorState): Transaction | null;
|
33
|
+
|
34
34
|
declare class AutocompleteRule {
|
35
35
|
readonly regex: RegExp;
|
36
36
|
readonly onMatch: MatchHandler;
|
@@ -471,11 +471,8 @@ export declare function defineListSpec(): Extension<{
|
|
471
471
|
}>;
|
472
472
|
|
473
473
|
/**
|
474
|
-
* A mark rule is something that can automatically apply marks to text if it
|
475
|
-
*
|
476
|
-
* For every transaction that changes the document, the mark rule will be applied to the changed text.
|
477
|
-
*
|
478
|
-
*
|
474
|
+
* A mark rule is something that can automatically apply marks to text if it
|
475
|
+
* matches a certain pattern, and remove them if it doesn't match anymore.
|
479
476
|
*/
|
480
477
|
export declare function defineMarkRule(options: MarkRuleOptions): Extension<ExtensionTyping<string, string, CommandArgs>>;
|
481
478
|
|
@@ -770,20 +767,12 @@ export declare type EnterRuleOptions = {
|
|
770
767
|
*/
|
771
768
|
export declare const exitTable: Command;
|
772
769
|
|
773
|
-
|
774
|
-
* @internal
|
775
|
-
*/
|
776
|
-
export declare function findChangedTextRanges(selection: Selection_2): Array<[from: number, to: number]>;
|
777
|
-
|
778
|
-
/** @internal */
|
779
|
-
export declare function getAffectedRange(transactions: readonly Transaction[], oldState: EditorState, newState: EditorState): readonly [number, number];
|
770
|
+
export declare function getCheckRanges(transactions: readonly Transaction[], oldState: EditorState, newState: EditorState): Array<[number, number]>;
|
780
771
|
|
781
772
|
export { getHighlighter }
|
782
773
|
|
783
774
|
export declare function getPluginState(state: EditorState): PredictionPluginState | undefined;
|
784
775
|
|
785
|
-
export declare function getSpanTextRanges($from: ResolvedPos, $to: ResolvedPos): [number, number][];
|
786
|
-
|
787
776
|
export declare function getTrMeta(tr: Transaction): PredictionPluginState;
|
788
777
|
|
789
778
|
export declare interface HeadingAttrs {
|
@@ -834,9 +823,24 @@ export declare interface LinkAttrs {
|
|
834
823
|
|
835
824
|
export { ListDOMSerializer }
|
836
825
|
|
837
|
-
|
826
|
+
/**
|
827
|
+
* @internal
|
828
|
+
*/
|
829
|
+
export declare class MarkRule {
|
830
|
+
readonly regex: RegExp;
|
831
|
+
readonly type: string | MarkType;
|
832
|
+
readonly getAttrs: (match: RegExpMatchArray) => Attrs | null;
|
833
|
+
constructor({ regex, type, attrs }: MarkRuleOptions);
|
834
|
+
}
|
835
|
+
|
836
|
+
/**
|
837
|
+
* The options for {@link defineMarkRule}.
|
838
|
+
*
|
839
|
+
* @public
|
840
|
+
*/
|
841
|
+
declare interface MarkRuleOptions {
|
838
842
|
/**
|
839
|
-
* The regular expression to match against. It
|
843
|
+
* The regular expression to match against. It must has a `g` flag to match
|
840
844
|
* all instances of the mark.
|
841
845
|
*/
|
842
846
|
regex: RegExp;
|
@@ -847,9 +851,13 @@ export declare interface MarkRuleOptions {
|
|
847
851
|
/**
|
848
852
|
* Attributes to set on the mark. If a function is provided, it will be called
|
849
853
|
* with the matched result from the regular expression.
|
854
|
+
*
|
855
|
+
* @default null
|
850
856
|
*/
|
851
857
|
attrs?: Attrs | null | ((match: RegExpMatchArray) => Attrs | null);
|
852
858
|
}
|
859
|
+
export { MarkRuleOptions }
|
860
|
+
export { MarkRuleOptions as MarkRuleOptions_alias_1 }
|
853
861
|
|
854
862
|
declare type MatchHandler = (options: {
|
855
863
|
state: EditorState;
|
@@ -1,15 +1,14 @@
|
|
1
1
|
// src/mark-rule/index.ts
|
2
|
-
import {
|
3
|
-
Facet,
|
4
|
-
OBJECT_REPLACEMENT_CHARACTER,
|
5
|
-
getMarkType,
|
6
|
-
pluginFacet
|
7
|
-
} from "@prosekit/core";
|
8
|
-
import "@prosekit/pm/model";
|
2
|
+
import { Facet, pluginFacet } from "@prosekit/core";
|
9
3
|
import { ProseMirrorPlugin } from "@prosekit/pm/state";
|
10
4
|
|
11
|
-
// src/mark-rule/
|
12
|
-
import {
|
5
|
+
// src/mark-rule/apply.ts
|
6
|
+
import { OBJECT_REPLACEMENT_CHARACTER, getMarkType } from "@prosekit/core";
|
7
|
+
import "@prosekit/pm/model";
|
8
|
+
import "@prosekit/pm/state";
|
9
|
+
|
10
|
+
// src/mark-rule/range.ts
|
11
|
+
import "@prosekit/pm/state";
|
13
12
|
function getSpanTextRanges($from, $to) {
|
14
13
|
const nodeRange = $from.blockRange($to);
|
15
14
|
if (!nodeRange) {
|
@@ -38,12 +37,23 @@ function getSpanTextRanges($from, $to) {
|
|
38
37
|
}
|
39
38
|
return ranges;
|
40
39
|
}
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
function getInlineTextRange($from, $to) {
|
41
|
+
return [$from.start(), $to.end()];
|
42
|
+
}
|
43
|
+
function getTextRanges(doc, from, to) {
|
44
|
+
const $from = doc.resolve(from);
|
45
|
+
const $to = doc.resolve(to);
|
46
|
+
if ($from.sameParent($to) && $from.parent.isTextblock) {
|
47
|
+
return [getInlineTextRange($from, $to)];
|
48
|
+
} else {
|
49
|
+
const nodeRange = $from.blockRange($to);
|
50
|
+
if (!nodeRange) {
|
51
|
+
return [];
|
52
|
+
}
|
53
|
+
return getSpanTextRanges($from, $to);
|
54
|
+
}
|
45
55
|
}
|
46
|
-
function
|
56
|
+
function getMapRange(transactions, oldState, newState) {
|
47
57
|
let lo = oldState.selection.from;
|
48
58
|
let hi = oldState.selection.to;
|
49
59
|
for (const tr of transactions) {
|
@@ -60,19 +70,12 @@ function getAffectedRange(transactions, oldState, newState) {
|
|
60
70
|
hi = Math.min(lo, hi, newState.selection.to);
|
61
71
|
return [lo, hi];
|
62
72
|
}
|
63
|
-
function getCheckRanges(
|
64
|
-
const
|
65
|
-
|
66
|
-
if ($from.sameParent($to)) {
|
67
|
-
return [[$from.start(), $to.end()]];
|
68
|
-
} else {
|
69
|
-
const nodeRange = $from.blockRange($to);
|
70
|
-
if (!nodeRange) {
|
71
|
-
return [];
|
72
|
-
}
|
73
|
-
return getSpanTextRanges($from, $to);
|
74
|
-
}
|
73
|
+
function getCheckRanges(transactions, oldState, newState) {
|
74
|
+
const [from, to] = getMapRange(transactions, oldState, newState);
|
75
|
+
return getTextRanges(newState.doc, from, to);
|
75
76
|
}
|
77
|
+
|
78
|
+
// src/mark-rule/apply.ts
|
76
79
|
function getExpectedMarkings(rules, doc, from, to) {
|
77
80
|
const text = doc.textBetween(from, to, OBJECT_REPLACEMENT_CHARACTER);
|
78
81
|
const result = [];
|
@@ -80,14 +83,13 @@ function getExpectedMarkings(rules, doc, from, to) {
|
|
80
83
|
rule.regex.lastIndex = 0;
|
81
84
|
const matches = text.matchAll(rule.regex);
|
82
85
|
const markType = getMarkType(doc.type.schema, rule.type);
|
83
|
-
const getAttrs = rule.attrs;
|
84
86
|
for (const match of matches) {
|
85
87
|
const index = match.index;
|
86
88
|
if (index == null)
|
87
89
|
continue;
|
88
|
-
const attrs = getAttrs
|
90
|
+
const attrs = rule.getAttrs(match);
|
89
91
|
const mark = markType.create(attrs);
|
90
|
-
result.push([from + index, from + index + match[0].length
|
92
|
+
result.push([mark, from + index, from + index + match[0].length]);
|
91
93
|
}
|
92
94
|
}
|
93
95
|
return result;
|
@@ -96,25 +98,21 @@ function getReceivedMarkings(rules, doc, from, to) {
|
|
96
98
|
const result = [];
|
97
99
|
const schema = doc.type.schema;
|
98
100
|
const markTypes = rules.map((rule) => getMarkType(schema, rule.type));
|
99
|
-
|
100
|
-
|
101
|
-
if (!node.isTextblock || seen) {
|
101
|
+
doc.nodesBetween(from, to, (node, pos) => {
|
102
|
+
if (!node.isInline) {
|
102
103
|
return;
|
103
104
|
}
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
if (mark) {
|
109
|
-
result.push([from + offset, from + offset + child.nodeSize, mark]);
|
110
|
-
}
|
105
|
+
for (const markType of markTypes) {
|
106
|
+
const mark = node.marks.find((mark2) => mark2.type === markType);
|
107
|
+
if (mark) {
|
108
|
+
result.push([mark, pos, pos + node.nodeSize]);
|
111
109
|
}
|
112
|
-
}
|
110
|
+
}
|
113
111
|
});
|
114
112
|
return result;
|
115
113
|
}
|
116
114
|
function markingEquals(a, b) {
|
117
|
-
return a[
|
115
|
+
return a[1] === b[1] && a[2] === b[2] && a[0].eq(b[0]);
|
118
116
|
}
|
119
117
|
function markingDiffs(a, b) {
|
120
118
|
return a.filter((x) => !b.some((y) => markingEquals(x, y)));
|
@@ -123,13 +121,12 @@ function applyMarkRules(rules, transactions, oldState, newState) {
|
|
123
121
|
if (transactions.length === 0 || transactions.every((tr2) => !tr2.docChanged)) {
|
124
122
|
return null;
|
125
123
|
}
|
126
|
-
const
|
127
|
-
const ranges = getCheckRanges(newState.doc, from, to);
|
124
|
+
const ranges = getCheckRanges(transactions, oldState, newState);
|
128
125
|
const toRemove = [];
|
129
126
|
const toCreate = [];
|
130
|
-
for (const [
|
131
|
-
const expected = getExpectedMarkings(rules, newState.doc,
|
132
|
-
const received = getReceivedMarkings(rules, newState.doc,
|
127
|
+
for (const [from, to] of ranges) {
|
128
|
+
const expected = getExpectedMarkings(rules, newState.doc, from, to);
|
129
|
+
const received = getReceivedMarkings(rules, newState.doc, from, to);
|
133
130
|
toRemove.push(...markingDiffs(received, expected));
|
134
131
|
toCreate.push(...markingDiffs(expected, received));
|
135
132
|
}
|
@@ -137,14 +134,29 @@ function applyMarkRules(rules, transactions, oldState, newState) {
|
|
137
134
|
return null;
|
138
135
|
}
|
139
136
|
const tr = newState.tr;
|
140
|
-
for (const [
|
141
|
-
tr.removeMark(
|
137
|
+
for (const [mark, from, to] of toRemove) {
|
138
|
+
tr.removeMark(from, to, mark);
|
142
139
|
}
|
143
|
-
for (const [
|
144
|
-
tr.addMark(
|
140
|
+
for (const [mark, from, to] of toCreate) {
|
141
|
+
tr.addMark(from, to, mark);
|
145
142
|
}
|
146
143
|
return tr;
|
147
144
|
}
|
145
|
+
|
146
|
+
// src/mark-rule/rule.ts
|
147
|
+
import "@prosekit/pm/model";
|
148
|
+
var MarkRule = class {
|
149
|
+
constructor({ regex, type, attrs = null }) {
|
150
|
+
this.regex = regex;
|
151
|
+
this.type = type;
|
152
|
+
this.getAttrs = typeof attrs === "function" ? attrs : () => attrs;
|
153
|
+
}
|
154
|
+
};
|
155
|
+
|
156
|
+
// src/mark-rule/index.ts
|
157
|
+
function defineMarkRule(options) {
|
158
|
+
return markRuleFacet.extension([new MarkRule(options)]);
|
159
|
+
}
|
148
160
|
var markRuleFacet = Facet.define({
|
149
161
|
converter: () => {
|
150
162
|
let rules = [];
|
@@ -168,6 +180,5 @@ var markRuleFacet = Facet.define({
|
|
168
180
|
next: pluginFacet
|
169
181
|
});
|
170
182
|
export {
|
171
|
-
defineMarkRule
|
172
|
-
getAffectedRange
|
183
|
+
defineMarkRule
|
173
184
|
};
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@prosekit/extensions",
|
3
3
|
"type": "module",
|
4
|
-
"version": "0.0.0-next-
|
4
|
+
"version": "0.0.0-next-20240427200701",
|
5
5
|
"private": false,
|
6
6
|
"author": {
|
7
7
|
"name": "ocavue",
|
@@ -152,8 +152,8 @@
|
|
152
152
|
"dist"
|
153
153
|
],
|
154
154
|
"dependencies": {
|
155
|
-
"@prosekit/core": "0.0.0-next-
|
156
|
-
"@prosekit/pm": "0.0.0-next-
|
155
|
+
"@prosekit/core": "0.0.0-next-20240427200701",
|
156
|
+
"@prosekit/pm": "0.0.0-next-20240427200701",
|
157
157
|
"prosemirror-dropcursor": "^1.8.1",
|
158
158
|
"prosemirror-flat-list": "^0.5.0",
|
159
159
|
"prosemirror-highlight": "^0.5.0",
|