@prosekit/extensions 0.5.2 → 0.5.3
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 +173 -0
- package/dist/{chunk-DZAKXWWF.js → chunk-2JYT2MT7.js} +21 -41
- package/dist/{chunk-LVMTQOWG.js → chunk-PYT3MOTF.js} +14 -31
- package/dist/chunk-ZPEMHYTU.js +140 -0
- package/dist/list/style.css +4 -8
- package/dist/placeholder/style.css +1 -1
- package/dist/prosekit-extensions-autocomplete.js +33 -62
- package/dist/prosekit-extensions-blockquote.js +2 -2
- package/dist/prosekit-extensions-bold.js +3 -7
- package/dist/prosekit-extensions-code-block.js +37 -77
- package/dist/prosekit-extensions-code.js +1 -1
- package/dist/prosekit-extensions-enter-rule.js +1 -1
- package/dist/prosekit-extensions-heading.js +6 -13
- package/dist/prosekit-extensions-image.js +5 -14
- package/dist/prosekit-extensions-input-rule.js +1 -1
- package/dist/prosekit-extensions-italic.js +1 -1
- package/dist/prosekit-extensions-link.js +16 -31
- package/dist/prosekit-extensions-list.js +2 -4
- package/dist/prosekit-extensions-mark-rule.js +1 -1
- package/dist/prosekit-extensions-mention.js +4 -6
- package/dist/prosekit-extensions-placeholder.js +9 -20
- package/dist/prosekit-extensions-readonly.js +1 -1
- package/dist/prosekit-extensions-search.d.ts +3 -0
- package/dist/prosekit-extensions-search.js +382 -0
- package/dist/prosekit-extensions-strike.js +1 -1
- package/dist/prosekit-extensions-table.js +30 -68
- package/dist/prosekit-extensions-text-align.js +2 -4
- package/dist/prosekit-extensions-virtual-selection.js +6 -12
- package/dist/search/style.css +13 -0
- package/package.json +16 -5
- package/dist/chunk-ZOBSD7ZH.js +0 -189
@@ -22,6 +22,7 @@ import { Parser } from 'prosemirror-highlight';
|
|
22
22
|
import { Plugin as Plugin_2 } from '@prosekit/pm/state';
|
23
23
|
import { PluginKey } from '@prosekit/pm/state';
|
24
24
|
import { ProseMirrorNode } from '@prosekit/pm/model';
|
25
|
+
import { Slice } from '@prosekit/pm/model';
|
25
26
|
import type { SpecialLanguage } from 'shiki';
|
26
27
|
import { ToggleCollapsedOptions } from 'prosemirror-flat-list';
|
27
28
|
import { Transaction } from '@prosekit/pm/state';
|
@@ -583,6 +584,33 @@ export declare function definePlaceholder(options: PlaceholderOptions): Extensio
|
|
583
584
|
*/
|
584
585
|
export declare function defineReadonly(): Extension<any>;
|
585
586
|
|
587
|
+
/**
|
588
|
+
* Defines commands for search and replace.
|
589
|
+
*
|
590
|
+
* @public
|
591
|
+
*/
|
592
|
+
export declare function defineSearchCommands(): Extension< {
|
593
|
+
Commands: {
|
594
|
+
findNext: [];
|
595
|
+
findPrev: [];
|
596
|
+
findNextNoWrap: [];
|
597
|
+
findPrevNoWrap: [];
|
598
|
+
replaceNext: [];
|
599
|
+
replaceNextNoWrap: [];
|
600
|
+
replaceCurrent: [];
|
601
|
+
replaceAll: [];
|
602
|
+
};
|
603
|
+
Nodes: never;
|
604
|
+
Marks: never;
|
605
|
+
}>;
|
606
|
+
|
607
|
+
/**
|
608
|
+
* Defines an extension that stores a current search query and replace string.
|
609
|
+
*
|
610
|
+
* @public
|
611
|
+
*/
|
612
|
+
export declare function defineSearchQuery(options: SearchQueryOptions): Extension<any>;
|
613
|
+
|
586
614
|
/**
|
587
615
|
* @public
|
588
616
|
*/
|
@@ -890,12 +918,38 @@ export declare type EnterRuleOptions = {
|
|
890
918
|
*/
|
891
919
|
export declare const exitTable: Command;
|
892
920
|
|
921
|
+
declare const findNext: Command;
|
922
|
+
export { findNext }
|
923
|
+
export { findNext as findNext_alias_1 }
|
924
|
+
|
925
|
+
declare const findNextNoWrap: Command;
|
926
|
+
export { findNextNoWrap }
|
927
|
+
export { findNextNoWrap as findNextNoWrap_alias_1 }
|
928
|
+
|
929
|
+
declare const findPrev: Command;
|
930
|
+
export { findPrev }
|
931
|
+
export { findPrev as findPrev_alias_1 }
|
932
|
+
|
933
|
+
declare const findPrevNoWrap: Command;
|
934
|
+
export { findPrevNoWrap }
|
935
|
+
export { findPrevNoWrap as findPrevNoWrap_alias_1 }
|
936
|
+
|
893
937
|
export declare function getCheckRanges(transactions: readonly Transaction[], oldState: EditorState, newState: EditorState): Array<[number, number]>;
|
894
938
|
|
895
939
|
export { getHighlighter }
|
896
940
|
|
897
941
|
export declare function getPluginState(state: EditorState): PredictionPluginState | undefined;
|
898
942
|
|
943
|
+
declare function getSearchState(state: EditorState): {
|
944
|
+
query: SearchQuery;
|
945
|
+
range: {
|
946
|
+
from: number;
|
947
|
+
to: number;
|
948
|
+
} | null;
|
949
|
+
} | undefined;
|
950
|
+
export { getSearchState }
|
951
|
+
export { getSearchState as getSearchState_alias_1 }
|
952
|
+
|
899
953
|
export declare function getTrMeta(tr: Transaction): PredictionPluginState;
|
900
954
|
|
901
955
|
export declare interface HeadingAttrs {
|
@@ -1041,6 +1095,123 @@ export declare interface PredictionPluginState {
|
|
1041
1095
|
} | null;
|
1042
1096
|
}
|
1043
1097
|
|
1098
|
+
declare interface QueryImpl {
|
1099
|
+
findNext(state: EditorState, from: number, to: number): SearchResult | null;
|
1100
|
+
findPrev(state: EditorState, from: number, to: number): SearchResult | null;
|
1101
|
+
}
|
1102
|
+
|
1103
|
+
declare const replaceAll: Command;
|
1104
|
+
export { replaceAll }
|
1105
|
+
export { replaceAll as replaceAll_alias_1 }
|
1106
|
+
|
1107
|
+
declare const replaceCurrent: Command;
|
1108
|
+
export { replaceCurrent }
|
1109
|
+
export { replaceCurrent as replaceCurrent_alias_1 }
|
1110
|
+
|
1111
|
+
declare const replaceNext: Command;
|
1112
|
+
export { replaceNext }
|
1113
|
+
export { replaceNext as replaceNext_alias_1 }
|
1114
|
+
|
1115
|
+
declare const replaceNextNoWrap: Command;
|
1116
|
+
export { replaceNextNoWrap }
|
1117
|
+
export { replaceNextNoWrap as replaceNextNoWrap_alias_1 }
|
1118
|
+
|
1119
|
+
declare function search(options?: {
|
1120
|
+
initialQuery?: SearchQuery;
|
1121
|
+
initialRange?: {
|
1122
|
+
from: number;
|
1123
|
+
to: number;
|
1124
|
+
};
|
1125
|
+
}): Plugin_2;
|
1126
|
+
export { search }
|
1127
|
+
export { search as search_alias_1 }
|
1128
|
+
|
1129
|
+
declare class SearchQuery {
|
1130
|
+
readonly search: string;
|
1131
|
+
readonly caseSensitive: boolean;
|
1132
|
+
readonly literal: boolean;
|
1133
|
+
readonly regexp: boolean;
|
1134
|
+
readonly replace: string;
|
1135
|
+
readonly valid: boolean;
|
1136
|
+
readonly wholeWord: boolean;
|
1137
|
+
impl: QueryImpl;
|
1138
|
+
constructor(config: {
|
1139
|
+
search: string;
|
1140
|
+
caseSensitive?: boolean;
|
1141
|
+
literal?: boolean;
|
1142
|
+
regexp?: boolean;
|
1143
|
+
replace?: string;
|
1144
|
+
wholeWord?: boolean;
|
1145
|
+
});
|
1146
|
+
eq(other: SearchQuery): boolean;
|
1147
|
+
findNext(state: EditorState, from?: number, to?: number): SearchResult | null;
|
1148
|
+
findPrev(state: EditorState, from?: number, to?: number): SearchResult | null;
|
1149
|
+
checkResult(state: EditorState, result: SearchResult): boolean;
|
1150
|
+
unquote(string: string): string;
|
1151
|
+
getReplacement(state: EditorState, result: SearchResult): Slice;
|
1152
|
+
}
|
1153
|
+
export { SearchQuery }
|
1154
|
+
export { SearchQuery as SearchQuery_alias_1 }
|
1155
|
+
export { SearchQuery as SearchQuery_alias_2 }
|
1156
|
+
|
1157
|
+
/**
|
1158
|
+
* Options for {@link defineSearchQuery}
|
1159
|
+
*
|
1160
|
+
* @public
|
1161
|
+
*/
|
1162
|
+
export declare interface SearchQueryOptions {
|
1163
|
+
/**
|
1164
|
+
* The search string (or regular expression).
|
1165
|
+
*/
|
1166
|
+
search: string;
|
1167
|
+
/**
|
1168
|
+
* The replace text.
|
1169
|
+
*/
|
1170
|
+
replace?: string;
|
1171
|
+
/**
|
1172
|
+
* Indicates whether the search is case-sensitive
|
1173
|
+
*
|
1174
|
+
* @default false
|
1175
|
+
*/
|
1176
|
+
caseSensitive?: boolean;
|
1177
|
+
/**
|
1178
|
+
* By default, string search will replace `\n`, `\r`, and `\t` in the query
|
1179
|
+
* with newline, return, and tab characters. When this is set to true, that
|
1180
|
+
* behavior is disabled.
|
1181
|
+
*
|
1182
|
+
* @default false
|
1183
|
+
*/
|
1184
|
+
literal?: boolean;
|
1185
|
+
/**
|
1186
|
+
* When true, the search string is interpreted as a regular expression.
|
1187
|
+
*
|
1188
|
+
* @default false
|
1189
|
+
*/
|
1190
|
+
regexp?: boolean;
|
1191
|
+
/**
|
1192
|
+
* Enable whole-word matching.
|
1193
|
+
*
|
1194
|
+
* @default false
|
1195
|
+
*/
|
1196
|
+
wholeWord?: boolean;
|
1197
|
+
}
|
1198
|
+
|
1199
|
+
declare interface SearchResult {
|
1200
|
+
from: number;
|
1201
|
+
to: number;
|
1202
|
+
match: RegExpMatchArray | null;
|
1203
|
+
}
|
1204
|
+
export { SearchResult }
|
1205
|
+
export { SearchResult as SearchResult_alias_1 }
|
1206
|
+
export { SearchResult as SearchResult_alias_2 }
|
1207
|
+
|
1208
|
+
declare function setSearchState(tr: Transaction, query: SearchQuery, range?: {
|
1209
|
+
from: number;
|
1210
|
+
to: number;
|
1211
|
+
} | null): Transaction;
|
1212
|
+
export { setSearchState }
|
1213
|
+
export { setSearchState as setSearchState_alias_1 }
|
1214
|
+
|
1044
1215
|
/**
|
1045
1216
|
* @internal
|
1046
1217
|
*/
|
@@ -1095,4 +1266,6 @@ export declare type TextBlockEnterRuleOptions = {
|
|
1095
1266
|
stop?: boolean;
|
1096
1267
|
};
|
1097
1268
|
|
1269
|
+
export declare function validRegExp(source: string): boolean;
|
1270
|
+
|
1098
1271
|
export { }
|
@@ -16,26 +16,24 @@ import {
|
|
16
16
|
function defineEnterRule({
|
17
17
|
regex,
|
18
18
|
handler,
|
19
|
-
stop =
|
19
|
+
stop = !1
|
20
20
|
}) {
|
21
|
-
|
21
|
+
let rule = new EnterRule(regex, handler, stop);
|
22
22
|
return defineFacetPayload(enterRule, [rule]);
|
23
23
|
}
|
24
24
|
function defineTextBlockEnterRule({
|
25
25
|
regex,
|
26
26
|
type,
|
27
27
|
attrs,
|
28
|
-
stop =
|
28
|
+
stop = !0
|
29
29
|
}) {
|
30
30
|
return defineEnterRule({
|
31
31
|
regex,
|
32
32
|
handler: ({ state, from, to, match }) => {
|
33
|
-
|
34
|
-
|
35
|
-
if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), nodeType)) {
|
33
|
+
let nodeType = getNodeType(state.schema, type), $start = state.doc.resolve(from);
|
34
|
+
if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), nodeType))
|
36
35
|
return null;
|
37
|
-
|
38
|
-
const nodeAttrs = maybeRun(attrs, match);
|
36
|
+
let nodeAttrs = maybeRun(attrs, match);
|
39
37
|
return state.tr.delete(from, to).setBlockType(from, from, nodeType, nodeAttrs);
|
40
38
|
},
|
41
39
|
stop
|
@@ -47,60 +45,42 @@ var EnterRule = class {
|
|
47
45
|
this.handler = handler;
|
48
46
|
this.stop = stop;
|
49
47
|
}
|
50
|
-
}
|
51
|
-
var enterRule = defineFacet({
|
48
|
+
}, enterRule = defineFacet({
|
52
49
|
reduce: () => {
|
53
|
-
let rules = []
|
54
|
-
const command = (state, dispatch, view) => {
|
55
|
-
if (!view)
|
56
|
-
return false;
|
57
|
-
return execRules(view, rules, dispatch);
|
58
|
-
};
|
59
|
-
const handler = keydownHandler({ Enter: command });
|
60
|
-
const plugin = new ProseMirrorPlugin({
|
50
|
+
let rules = [], handler = keydownHandler({ Enter: (state, dispatch, view) => view ? execRules(view, rules, dispatch) : !1 }), plugin = new ProseMirrorPlugin({
|
61
51
|
key: new PluginKey("prosekit-enter-rule"),
|
62
52
|
props: { handleKeyDown: handler }
|
63
53
|
});
|
64
|
-
return function
|
65
|
-
rules = inputs;
|
66
|
-
return plugin;
|
54
|
+
return function(inputs) {
|
55
|
+
return rules = inputs, plugin;
|
67
56
|
};
|
68
57
|
},
|
69
58
|
parent: pluginFacet
|
70
59
|
});
|
71
60
|
function execRules(view, rules, dispatch) {
|
72
|
-
if (view.composing)
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
if (!
|
77
|
-
|
78
|
-
const $cursor = selection.$cursor;
|
79
|
-
if (!$cursor || $cursor.parent.type.spec.code)
|
80
|
-
return false;
|
81
|
-
const textBefore = $cursor.parent.textBetween(
|
61
|
+
if (view.composing) return !1;
|
62
|
+
let state = view.state, selection = state.selection;
|
63
|
+
if (!isTextSelection(selection)) return !1;
|
64
|
+
let $cursor = selection.$cursor;
|
65
|
+
if (!$cursor || $cursor.parent.type.spec.code) return !1;
|
66
|
+
let textBefore = $cursor.parent.textBetween(
|
82
67
|
Math.max(0, $cursor.parentOffset - MAX_MATCH),
|
83
68
|
$cursor.parentOffset,
|
84
69
|
null,
|
85
70
|
OBJECT_REPLACEMENT_CHARACTER
|
86
71
|
);
|
87
|
-
for (
|
72
|
+
for (let rule of rules) {
|
88
73
|
rule.regex.lastIndex = 0;
|
89
|
-
|
90
|
-
const tr = match && rule.handler({
|
74
|
+
let match = rule.regex.exec(textBefore), tr = match && rule.handler({
|
91
75
|
state,
|
92
76
|
from: $cursor.pos - match[0].length,
|
93
77
|
to: $cursor.pos,
|
94
78
|
match
|
95
79
|
});
|
96
|
-
if (
|
97
|
-
|
98
|
-
dispatch == null ? void 0 : dispatch(tr);
|
99
|
-
if (rule.stop) {
|
100
|
-
return true;
|
101
|
-
}
|
80
|
+
if (tr && (dispatch == null || dispatch(tr), rule.stop))
|
81
|
+
return !0;
|
102
82
|
}
|
103
|
-
return
|
83
|
+
return !1;
|
104
84
|
}
|
105
85
|
var MAX_MATCH = 200;
|
106
86
|
|
@@ -24,35 +24,20 @@ function createMarkInputRule({
|
|
24
24
|
type,
|
25
25
|
attrs = null
|
26
26
|
}) {
|
27
|
-
|
27
|
+
return new InputRule(regex, (state, match, start, end) => {
|
28
28
|
var _a;
|
29
|
-
|
30
|
-
|
31
|
-
if (!markText) {
|
29
|
+
let { tr, schema } = state, [fullText, markText] = match;
|
30
|
+
if (!markText)
|
32
31
|
return null;
|
33
|
-
|
34
|
-
|
35
|
-
const markEnd = markStart + markText.length;
|
36
|
-
if (!(start <= markStart && markStart < markEnd && markEnd <= end)) {
|
32
|
+
let markStart = start + fullText.indexOf(markText), markEnd = markStart + markText.length;
|
33
|
+
if (!(start <= markStart && markStart < markEnd && markEnd <= end))
|
37
34
|
return null;
|
38
|
-
|
39
|
-
|
40
|
-
const mark = markType.create(maybeRun(attrs, match));
|
41
|
-
if (!isMarkAbsent(tr.doc, markStart, markEnd, markType, attrs)) {
|
35
|
+
let markType = getMarkType(schema, type), mark = markType.create(maybeRun(attrs, match));
|
36
|
+
if (!isMarkAbsent(tr.doc, markStart, markEnd, markType, attrs))
|
42
37
|
return null;
|
43
|
-
|
44
|
-
|
45
|
-
tr.addMark(markStart, markEnd, mark);
|
46
|
-
if (markEnd < end) {
|
47
|
-
tr.delete(markEnd, end);
|
48
|
-
}
|
49
|
-
if (start < markStart) {
|
50
|
-
tr.delete(start, markStart);
|
51
|
-
}
|
52
|
-
tr.setStoredMarks(initialStoredMarks);
|
53
|
-
return tr;
|
38
|
+
let initialStoredMarks = (_a = tr.storedMarks) != null ? _a : [];
|
39
|
+
return tr.addMark(markStart, markEnd, mark), markEnd < end && tr.delete(markEnd, end), start < markStart && tr.delete(start, markStart), tr.setStoredMarks(initialStoredMarks), tr;
|
54
40
|
});
|
55
|
-
return rule;
|
56
41
|
}
|
57
42
|
function defineMarkInputRule(options) {
|
58
43
|
return defineInputRule(createMarkInputRule(options));
|
@@ -64,7 +49,7 @@ function defineTextBlockInputRule({
|
|
64
49
|
}) {
|
65
50
|
return defineFacetPayload(inputRuleFacet, [
|
66
51
|
({ schema }) => {
|
67
|
-
|
52
|
+
let nodeType = getNodeType(schema, type);
|
68
53
|
return textblockTypeInputRule(regex, nodeType, attrs);
|
69
54
|
}
|
70
55
|
]);
|
@@ -77,17 +62,15 @@ function defineWrappingInputRule({
|
|
77
62
|
}) {
|
78
63
|
return defineFacetPayload(inputRuleFacet, [
|
79
64
|
({ schema }) => {
|
80
|
-
|
65
|
+
let nodeType = getNodeType(schema, type);
|
81
66
|
return wrappingInputRule(regex, nodeType, attrs, join);
|
82
67
|
}
|
83
68
|
]);
|
84
69
|
}
|
85
70
|
var inputRuleFacet = defineFacet({
|
86
|
-
reducer: (inputs) => {
|
87
|
-
|
88
|
-
|
89
|
-
return [inputRules({ rules })];
|
90
|
-
};
|
71
|
+
reducer: (inputs) => (context) => {
|
72
|
+
let rules = inputs.flatMap((callback) => callback(context));
|
73
|
+
return [inputRules({ rules })];
|
91
74
|
},
|
92
75
|
parent: pluginFacet
|
93
76
|
});
|
@@ -0,0 +1,140 @@
|
|
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
|
+
};
|
package/dist/list/style.css
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
.prosemirror-flat-list {
|
3
3
|
padding: 0;
|
4
4
|
margin-top: 0;
|
5
|
-
margin-bottom: 0;
|
6
5
|
margin-left: 32px;
|
7
6
|
margin-bottom: 0;
|
8
7
|
position: relative;
|
@@ -15,10 +14,7 @@
|
|
15
14
|
.prosemirror-flat-list.ProseMirror-selectednode:after {
|
16
15
|
content: "";
|
17
16
|
position: absolute;
|
18
|
-
|
19
|
-
right: -2px;
|
20
|
-
top: -2px;
|
21
|
-
bottom: -2px;
|
17
|
+
inset: -2px -2px -2px -32px;
|
22
18
|
border: 2px solid #8cf;
|
23
19
|
pointer-events: none;
|
24
20
|
}
|
@@ -31,7 +27,7 @@
|
|
31
27
|
.prosemirror-flat-list[data-list-kind=ordered] > * {
|
32
28
|
contain: style;
|
33
29
|
}
|
34
|
-
.prosemirror-flat-list[data-list-kind=ordered]
|
30
|
+
.prosemirror-flat-list[data-list-kind=ordered]:before {
|
35
31
|
position: absolute;
|
36
32
|
right: 100%;
|
37
33
|
font-variant-numeric: tabular-nums;
|
@@ -69,10 +65,10 @@
|
|
69
65
|
width: 1.5em;
|
70
66
|
width: 1lh;
|
71
67
|
}
|
72
|
-
.prosemirror-flat-list[data-list-kind=toggle] > .list-marker
|
68
|
+
.prosemirror-flat-list[data-list-kind=toggle] > .list-marker:before {
|
73
69
|
content: "\23f7";
|
74
70
|
}
|
75
|
-
.prosemirror-flat-list[data-list-kind=toggle][data-list-collapsable][data-list-collapsed] > .list-marker
|
71
|
+
.prosemirror-flat-list[data-list-kind=toggle][data-list-collapsable][data-list-collapsed] > .list-marker:before {
|
76
72
|
content: "\23f5";
|
77
73
|
}
|
78
74
|
.prosemirror-flat-list[data-list-kind=toggle][data-list-collapsable] > .list-marker {
|