@prosekit/extensions 0.1.6 → 0.2.1
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 +193 -91
- package/dist/chunk-DYFRBXUX.js +56 -0
- package/dist/chunk-HQZORKGY.js +6 -0
- package/dist/prosekit-extensions-autocomplete.js +11 -4
- package/dist/prosekit-extensions-code-block.d.ts +2 -0
- package/dist/prosekit-extensions-code-block.js +215 -61
- package/dist/prosekit-extensions-heading.js +9 -7
- package/dist/prosekit-extensions-input-rule.d.ts +3 -0
- package/dist/prosekit-extensions-input-rule.js +10 -0
- package/dist/prosekit-extensions-list.js +5 -2
- package/package.json +21 -14
- package/dist/prosekit-extensions-suggestion.d.ts +0 -3
- package/dist/prosekit-extensions-suggestion.js +0 -161
@@ -1,16 +1,22 @@
|
|
1
|
+
import { Attrs } from '@prosekit/pm/model';
|
2
|
+
import type { BundledTheme } from 'shikiji';
|
1
3
|
import { CommandArgs } from '@prosekit/core';
|
4
|
+
import type { ContentMatch } from '@prosekit/pm/model';
|
2
5
|
import { DedentListOptions } from 'prosemirror-flat-list';
|
3
6
|
import { EditorState } from '@prosekit/pm/state';
|
4
7
|
import { Extension } from '@prosekit/core';
|
5
8
|
import { ExtensionTyping } from '@prosekit/core';
|
6
|
-
import type { HLJSApi } from 'highlight.js';
|
7
9
|
import { IndentListOptions } from 'prosemirror-flat-list';
|
10
|
+
import { InputRule } from '@prosekit/pm/inputrules';
|
8
11
|
import { ListAttributes } from 'prosemirror-flat-list';
|
9
12
|
import { NodeRange } from 'prosemirror-model';
|
13
|
+
import { NodeType } from '@prosekit/pm/model';
|
14
|
+
import { NodeType as NodeType_2 } from 'prosemirror-model';
|
10
15
|
import { Options } from 'tsup';
|
11
16
|
import { Parser } from 'prosemirror-highlight';
|
12
17
|
import { Plugin as Plugin_2 } from '@prosekit/pm/state';
|
13
18
|
import { PluginKey } from '@prosekit/pm/state';
|
19
|
+
import { ProseMirrorNode } from '@prosekit/pm/model';
|
14
20
|
import { ToggleCollapsedOptions } from 'prosemirror-flat-list';
|
15
21
|
import { Transaction } from '@prosekit/pm/state';
|
16
22
|
import { UnwrapListOptions } from 'prosemirror-flat-list';
|
@@ -49,8 +55,6 @@ export declare function createAutocompletePlugin({ getRules, }: {
|
|
49
55
|
getRules: () => AutocompleteRule[];
|
50
56
|
}): Plugin_2;
|
51
57
|
|
52
|
-
export declare function createPredictionPlugin(options: SuggestionOptions): Plugin_2;
|
53
|
-
|
54
58
|
export declare const default_alias: Options | Options[] | ((overrideOptions: Options) => Options | Options[] | Promise<Options | Options[]>);
|
55
59
|
|
56
60
|
export declare const default_alias_1: {
|
@@ -59,11 +63,9 @@ export declare const default_alias_1: {
|
|
59
63
|
};
|
60
64
|
};
|
61
65
|
|
62
|
-
export declare function
|
63
|
-
state: EditorState;
|
64
|
-
}): boolean;
|
66
|
+
export declare function defaultBlockAt(match: ContentMatch): NodeType_2 | null;
|
65
67
|
|
66
|
-
export declare function
|
68
|
+
export declare function defaultCanMatch({ state }: {
|
67
69
|
state: EditorState;
|
68
70
|
}): boolean;
|
69
71
|
|
@@ -117,22 +119,13 @@ toggleCode: [];
|
|
117
119
|
*
|
118
120
|
* - {@link defineCodeBlockSpec}
|
119
121
|
* - {@link defineCodeBlockInputRule}
|
122
|
+
* - {@link defineCodeBlockEnterRule}
|
123
|
+
* - {@link defineCodeBlockKeymap}
|
120
124
|
* - {@link defineCodeBlockCommands}.
|
121
125
|
*
|
122
126
|
* @public
|
123
127
|
*/
|
124
|
-
export declare function defineCodeBlock(
|
125
|
-
/**
|
126
|
-
* @deprecated Use `defineCodeBlockHighlight` function instead.
|
127
|
-
*/
|
128
|
-
hljs?: HLJSApi;
|
129
|
-
/**
|
130
|
-
* A parser for the `prosemirror-highlight` package to use for syntax highlighting.
|
131
|
-
*
|
132
|
-
* @deprecated Use the standalone `defineCodeBlockHighlight` function instead.
|
133
|
-
*/
|
134
|
-
parser?: HighlightParser;
|
135
|
-
}): Extension< {
|
128
|
+
export declare function defineCodeBlock(): Extension< {
|
136
129
|
NODES: "codeBlock";
|
137
130
|
COMMAND_ARGS: {
|
138
131
|
setCodeBlockLanguage: [language: string];
|
@@ -152,6 +145,15 @@ setCodeBlockLanguage: [language: string];
|
|
152
145
|
export { defineCodeBlockCommands }
|
153
146
|
export { defineCodeBlockCommands as defineCodeBlockCommands_alias_1 }
|
154
147
|
|
148
|
+
/**
|
149
|
+
* Adds enter rules for `codeBlock` nodes.
|
150
|
+
*
|
151
|
+
* @public
|
152
|
+
*/
|
153
|
+
declare function defineCodeBlockEnterRule(): Extension<ExtensionTyping<string, string, CommandArgs>>;
|
154
|
+
export { defineCodeBlockEnterRule }
|
155
|
+
export { defineCodeBlockEnterRule as defineCodeBlockEnterRule_alias_1 }
|
156
|
+
|
155
157
|
/**
|
156
158
|
* Adds syntax highlighting to code blocks. This function requires a `Parser`
|
157
159
|
* instance from the `prosemirror-highlight` package. See the
|
@@ -166,13 +168,6 @@ declare function defineCodeBlockHighlight({ parser, }: {
|
|
166
168
|
export { defineCodeBlockHighlight }
|
167
169
|
export { defineCodeBlockHighlight as defineCodeBlockHighlight_alias_1 }
|
168
170
|
|
169
|
-
/**
|
170
|
-
* @deprecated
|
171
|
-
*/
|
172
|
-
export declare function defineCodeBlockHighlightDeprecated(options: {
|
173
|
-
hljs?: HLJSApi;
|
174
|
-
}): Extension<ExtensionTyping<string, string, CommandArgs>>;
|
175
|
-
|
176
171
|
/**
|
177
172
|
* Adds input rules for `codeBlock` nodes.
|
178
173
|
*
|
@@ -182,6 +177,27 @@ declare function defineCodeBlockInputRule(): Extension<ExtensionTyping<string, s
|
|
182
177
|
export { defineCodeBlockInputRule }
|
183
178
|
export { defineCodeBlockInputRule as defineCodeBlockInputRule_alias_1 }
|
184
179
|
|
180
|
+
/**
|
181
|
+
* Defines the keymap for code blocks.
|
182
|
+
*/
|
183
|
+
export declare function defineCodeBlockKeymap(): Extension<ExtensionTyping<string, string, CommandArgs>>;
|
184
|
+
|
185
|
+
/**
|
186
|
+
* Adds syntax highlighting to code blocks using the [shikiji](https://github.com/antfu/shikiji) package.
|
187
|
+
*
|
188
|
+
* @public
|
189
|
+
*/
|
190
|
+
declare function defineCodeBlockShikiji(options?: {
|
191
|
+
/**
|
192
|
+
* The shikiji theme to use.
|
193
|
+
*
|
194
|
+
* @default 'github-light'
|
195
|
+
*/
|
196
|
+
theme?: BundledTheme;
|
197
|
+
}): Extension;
|
198
|
+
export { defineCodeBlockShikiji }
|
199
|
+
export { defineCodeBlockShikiji as defineCodeBlockShikiji_alias_1 }
|
200
|
+
|
185
201
|
/**
|
186
202
|
* Defines the `codeBlock` node spec.
|
187
203
|
*
|
@@ -206,6 +222,15 @@ export declare function defineCodeSpec(): Extension< {
|
|
206
222
|
MARKS: "code";
|
207
223
|
}>;
|
208
224
|
|
225
|
+
/**
|
226
|
+
* Defines an enter rule. An enter rule applies when the text directly in front of
|
227
|
+
* the cursor matches `regex` and user presses Enter. The `regex` should end
|
228
|
+
* with `$`.
|
229
|
+
*
|
230
|
+
* @public
|
231
|
+
*/
|
232
|
+
export declare function defineEnterRule({ regex, handler, }: EnterRuleOptions): Extension;
|
233
|
+
|
209
234
|
/**
|
210
235
|
* @public
|
211
236
|
*/
|
@@ -254,6 +279,15 @@ export declare function defineImageSpec(): Extension< {
|
|
254
279
|
NODES: "image";
|
255
280
|
}>;
|
256
281
|
|
282
|
+
/**
|
283
|
+
* Defines an input rule extension.
|
284
|
+
*
|
285
|
+
* @param rule - The ProseMirror input rule to add.
|
286
|
+
*
|
287
|
+
* @public
|
288
|
+
*/
|
289
|
+
export declare function defineInputRule(rule: InputRule): Extension;
|
290
|
+
|
257
291
|
/**
|
258
292
|
* @public
|
259
293
|
*/
|
@@ -303,36 +337,36 @@ MARKS: "link";
|
|
303
337
|
/**
|
304
338
|
* @public
|
305
339
|
*/
|
306
|
-
export declare function defineList(): Extension<
|
307
|
-
NODES: "list";
|
308
|
-
COMMAND_ARGS: {
|
309
|
-
dedentList: [options?: DedentListOptions | undefined];
|
310
|
-
indentList: [options?: IndentListOptions | undefined];
|
311
|
-
moveList: [direction: "up" | "down"];
|
312
|
-
splitList: [];
|
313
|
-
toggleCollapsed: [(ToggleCollapsedOptions | undefined)?];
|
314
|
-
toggleList: [attrs: ListAttributes];
|
315
|
-
unwrapList: [options?: UnwrapListOptions | undefined];
|
316
|
-
wrapInList: [getAttrs: ListAttributes | ((range: NodeRange) => ListAttributes | null)];
|
317
|
-
insertList: [attrs?: ListAttributes | undefined];
|
318
|
-
};
|
340
|
+
export declare function defineList(): Extension<{
|
341
|
+
NODES: "list";
|
342
|
+
COMMAND_ARGS: {
|
343
|
+
dedentList: [options?: DedentListOptions | undefined];
|
344
|
+
indentList: [options?: IndentListOptions | undefined];
|
345
|
+
moveList: [direction: "up" | "down"];
|
346
|
+
splitList: [];
|
347
|
+
toggleCollapsed: [(ToggleCollapsedOptions | undefined)?];
|
348
|
+
toggleList: [attrs: ListAttributes];
|
349
|
+
unwrapList: [options?: UnwrapListOptions | undefined];
|
350
|
+
wrapInList: [getAttrs: ListAttributes | ((range: NodeRange) => ListAttributes | null)];
|
351
|
+
insertList: [attrs?: ListAttributes | undefined];
|
352
|
+
};
|
319
353
|
}>;
|
320
354
|
|
321
|
-
export declare function defineListCommands(): Extension<
|
322
|
-
COMMAND_ARGS: {
|
323
|
-
dedentList: [options?: DedentListOptions | undefined];
|
324
|
-
indentList: [options?: IndentListOptions | undefined];
|
325
|
-
moveList: [direction: "up" | "down"];
|
326
|
-
splitList: [];
|
327
|
-
toggleCollapsed: [(ToggleCollapsedOptions | undefined)?];
|
328
|
-
toggleList: [attrs: ListAttributes];
|
329
|
-
unwrapList: [options?: UnwrapListOptions | undefined];
|
330
|
-
wrapInList: [getAttrs: ListAttributes | ((range: NodeRange) => ListAttributes | null)];
|
331
|
-
insertList: [attrs?: ListAttributes | undefined];
|
332
|
-
};
|
355
|
+
export declare function defineListCommands(): Extension<{
|
356
|
+
COMMAND_ARGS: {
|
357
|
+
dedentList: [options?: DedentListOptions | undefined];
|
358
|
+
indentList: [options?: IndentListOptions | undefined];
|
359
|
+
moveList: [direction: "up" | "down"];
|
360
|
+
splitList: [];
|
361
|
+
toggleCollapsed: [(ToggleCollapsedOptions | undefined)?];
|
362
|
+
toggleList: [attrs: ListAttributes];
|
363
|
+
unwrapList: [options?: UnwrapListOptions | undefined];
|
364
|
+
wrapInList: [getAttrs: ListAttributes | ((range: NodeRange) => ListAttributes | null)];
|
365
|
+
insertList: [attrs?: ListAttributes | undefined];
|
366
|
+
};
|
333
367
|
}>;
|
334
368
|
|
335
|
-
export declare function defineListInputRules(): Extension
|
369
|
+
export declare function defineListInputRules(): Extension;
|
336
370
|
|
337
371
|
/**
|
338
372
|
* Returns a extension that adds key bindings for list.
|
@@ -343,8 +377,8 @@ export declare function defineListKeymap(): Extension<ExtensionTyping<string, st
|
|
343
377
|
|
344
378
|
export declare function defineListPlugins(): Extension<ExtensionTyping<string, string, CommandArgs>>;
|
345
379
|
|
346
|
-
export declare function defineListSpec(): Extension<
|
347
|
-
NODES: "list";
|
380
|
+
export declare function defineListSpec(): Extension<{
|
381
|
+
NODES: "list";
|
348
382
|
}>;
|
349
383
|
|
350
384
|
/**
|
@@ -404,9 +438,35 @@ MARKS: "strike";
|
|
404
438
|
}>;
|
405
439
|
|
406
440
|
/**
|
407
|
-
*
|
441
|
+
* Defines an enter rule that replaces the matched text with a block node.
|
442
|
+
*
|
443
|
+
* See also {@link defineEnterRule}.
|
444
|
+
*
|
445
|
+
* @public
|
408
446
|
*/
|
409
|
-
export declare function
|
447
|
+
export declare function defineTextBlockEnterRule({ regex, type, attrs, }: TextBlockEnterRuleOptions): Extension;
|
448
|
+
|
449
|
+
/**
|
450
|
+
* Defines an input rule that changes the type of a textblock when the matched
|
451
|
+
* text is typed into it.
|
452
|
+
*
|
453
|
+
* See also [textblockTypeInputRule](https://prosemirror.net/docs/ref/#inputrules.textblockTypeInputRule)
|
454
|
+
*/
|
455
|
+
export declare function defineTextBlockInputRule({ regex, type, attrs, }: {
|
456
|
+
/**
|
457
|
+
* The regular expression to match against. You'll usually want to start it
|
458
|
+
* with `^` to that it is only matched at the start of a textblock.
|
459
|
+
*/
|
460
|
+
regex: RegExp;
|
461
|
+
/**
|
462
|
+
* The node type to replace the matched text with.
|
463
|
+
*/
|
464
|
+
type: string | NodeType;
|
465
|
+
/**
|
466
|
+
* Attributes to set on the node.
|
467
|
+
*/
|
468
|
+
attrs?: Attrs | null | ((match: RegExpMatchArray) => Attrs | null);
|
469
|
+
}): Extension;
|
410
470
|
|
411
471
|
/**
|
412
472
|
* @public
|
@@ -430,6 +490,63 @@ export declare function defineUnderlineSpec(): Extension< {
|
|
430
490
|
MARKS: "underline";
|
431
491
|
}>;
|
432
492
|
|
493
|
+
/**
|
494
|
+
* Defines an input rule for automatically wrapping a textblock when a given
|
495
|
+
* string is typed.
|
496
|
+
*
|
497
|
+
* See also [wrappingInputRule](https://prosemirror.net/docs/ref/#inputrules.wrappingInputRule)
|
498
|
+
*/
|
499
|
+
export declare function defineWrappingInputRule({ regex, type, attrs, join, }: {
|
500
|
+
/**
|
501
|
+
* The regular expression to match against. You'll usually want to start it
|
502
|
+
* with `^` to that it is only matched at the start of a textblock.
|
503
|
+
*/
|
504
|
+
regex: RegExp;
|
505
|
+
/**
|
506
|
+
* The type of node to wrap in.
|
507
|
+
*/
|
508
|
+
type: string | NodeType;
|
509
|
+
/**
|
510
|
+
* Attributes to set on the node.
|
511
|
+
*/
|
512
|
+
attrs?: Attrs | null | ((match: RegExpMatchArray) => Attrs | null);
|
513
|
+
/**
|
514
|
+
* By default, if there's a node with the same type above the newly wrapped
|
515
|
+
* node, the rule will try to
|
516
|
+
* [join](https://prosemirror.net/docs/ref/#transform.Transform.join) those
|
517
|
+
* two nodes. You can pass a join predicate, which takes a regular expression
|
518
|
+
* match and the node before the wrapped node, and can return a boolean to
|
519
|
+
* indicate whether a join should happen.
|
520
|
+
*/
|
521
|
+
join?: (match: RegExpMatchArray, node: ProseMirrorNode) => boolean;
|
522
|
+
}): Extension;
|
523
|
+
|
524
|
+
/**
|
525
|
+
* @public
|
526
|
+
*/
|
527
|
+
export declare type EnterRuleHandler = (options: {
|
528
|
+
state: EditorState;
|
529
|
+
from: number;
|
530
|
+
to: number;
|
531
|
+
match: RegExpExecArray;
|
532
|
+
}) => Transaction | null;
|
533
|
+
|
534
|
+
/**
|
535
|
+
* Options for {@link createEnterRule}.
|
536
|
+
*
|
537
|
+
* @public
|
538
|
+
*/
|
539
|
+
export declare type EnterRuleOptions = {
|
540
|
+
/**
|
541
|
+
* The regular expression to match against. It should end with `$`.
|
542
|
+
*/
|
543
|
+
regex: RegExp;
|
544
|
+
/**
|
545
|
+
* A handler function to be called when an enter rule is triggered.
|
546
|
+
*/
|
547
|
+
handler: EnterRuleHandler;
|
548
|
+
};
|
549
|
+
|
433
550
|
export declare function getPluginState(state: EditorState): PredictionPluginState | undefined;
|
434
551
|
|
435
552
|
export declare function getTrMeta(tr: Transaction): PredictionPluginState;
|
@@ -469,25 +586,15 @@ declare type MatchHandler = (options: {
|
|
469
586
|
export { MatchHandler }
|
470
587
|
export { MatchHandler as MatchHandler_alias_1 }
|
471
588
|
|
472
|
-
/**
|
473
|
-
* @returns Return a Transaction object if you want to append a transaction to current state (using )
|
474
|
-
*/
|
475
|
-
declare type MatchHandler_2 = (options: {
|
476
|
-
rule: PredictionRule;
|
477
|
-
match: RegExpMatchArray;
|
478
|
-
matchAfter: RegExpMatchArray | null;
|
479
|
-
state: EditorState;
|
480
|
-
dismiss: VoidFunction;
|
481
|
-
deleteMatch: VoidFunction;
|
482
|
-
}) => void;
|
483
|
-
|
484
589
|
export declare interface MentionAttrs {
|
485
590
|
id: string;
|
486
591
|
kind: string;
|
487
592
|
value: string;
|
488
593
|
}
|
489
594
|
|
490
|
-
export declare const
|
595
|
+
export declare const NO_BREAK_SPACE = "\u00A0";
|
596
|
+
|
597
|
+
export declare const OBJECT_REPLACEMENT_CHARACTER = "\uFFFC";
|
491
598
|
|
492
599
|
export declare interface PlaceholderOptions {
|
493
600
|
/**
|
@@ -517,31 +624,26 @@ export declare interface PredictionPluginState {
|
|
517
624
|
} | null;
|
518
625
|
}
|
519
626
|
|
520
|
-
declare interface PredictionRule {
|
521
|
-
match: RegExp;
|
522
|
-
matchAfter?: RegExp;
|
523
|
-
}
|
524
|
-
export { PredictionRule }
|
525
|
-
export { PredictionRule as PredictionRule_alias_1 }
|
526
|
-
|
527
627
|
export declare function setTrMeta(tr: Transaction, meta: PredictionPluginState): Transaction;
|
528
628
|
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
629
|
+
/**
|
630
|
+
* Options for {@link createTextBlockEnterRule}.
|
631
|
+
*
|
632
|
+
* @public
|
633
|
+
*/
|
634
|
+
export declare type TextBlockEnterRuleOptions = {
|
533
635
|
/**
|
534
|
-
*
|
535
|
-
* By default, the plugin will only run the matching if the current selection
|
536
|
-
* is empty, and the selection is not inside a
|
537
|
-
* [code](https://prosemirror.net/docs/ref/#model.NodeSpec.code) node nor
|
538
|
-
* inside a mark with the name as `code`.
|
636
|
+
* The regular expression to match against. It should end with `$`.
|
539
637
|
*/
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
638
|
+
regex: RegExp;
|
639
|
+
/**
|
640
|
+
* The node type to replace the matched text with.
|
641
|
+
*/
|
642
|
+
type: string | NodeType;
|
643
|
+
/**
|
644
|
+
* Attributes to set on the node.
|
645
|
+
*/
|
646
|
+
attrs?: Attrs | null | ((match: RegExpMatchArray) => Attrs | null);
|
647
|
+
};
|
546
648
|
|
547
649
|
export { }
|
@@ -0,0 +1,56 @@
|
|
1
|
+
// src/input-rule/index.ts
|
2
|
+
import {
|
3
|
+
Facet,
|
4
|
+
getNodeType,
|
5
|
+
pluginFacet
|
6
|
+
} from "@prosekit/core";
|
7
|
+
import {
|
8
|
+
inputRules,
|
9
|
+
textblockTypeInputRule,
|
10
|
+
wrappingInputRule
|
11
|
+
} from "@prosekit/pm/inputrules";
|
12
|
+
import "@prosekit/pm/model";
|
13
|
+
import "@prosekit/pm/state";
|
14
|
+
function defineInputRule(rule) {
|
15
|
+
return inputRuleFacet.extension([() => rule]);
|
16
|
+
}
|
17
|
+
function defineTextBlockInputRule({
|
18
|
+
regex,
|
19
|
+
type,
|
20
|
+
attrs
|
21
|
+
}) {
|
22
|
+
return inputRuleFacet.extension([
|
23
|
+
({ schema }) => {
|
24
|
+
const nodeType = getNodeType(schema, type);
|
25
|
+
return textblockTypeInputRule(regex, nodeType, attrs);
|
26
|
+
}
|
27
|
+
]);
|
28
|
+
}
|
29
|
+
function defineWrappingInputRule({
|
30
|
+
regex,
|
31
|
+
type,
|
32
|
+
attrs,
|
33
|
+
join
|
34
|
+
}) {
|
35
|
+
return inputRuleFacet.extension([
|
36
|
+
({ schema }) => {
|
37
|
+
const nodeType = getNodeType(schema, type);
|
38
|
+
return wrappingInputRule(regex, nodeType, attrs, join);
|
39
|
+
}
|
40
|
+
]);
|
41
|
+
}
|
42
|
+
var inputRuleFacet = Facet.define({
|
43
|
+
convert: (inputs) => {
|
44
|
+
return (context) => {
|
45
|
+
const rules = inputs.flatMap((callback) => callback(context));
|
46
|
+
return [inputRules({ rules })];
|
47
|
+
};
|
48
|
+
},
|
49
|
+
next: pluginFacet
|
50
|
+
});
|
51
|
+
|
52
|
+
export {
|
53
|
+
defineInputRule,
|
54
|
+
defineTextBlockInputRule,
|
55
|
+
defineWrappingInputRule
|
56
|
+
};
|
@@ -1,3 +1,7 @@
|
|
1
|
+
import {
|
2
|
+
OBJECT_REPLACEMENT_CHARACTER
|
3
|
+
} from "./chunk-HQZORKGY.js";
|
4
|
+
|
1
5
|
// src/autocomplete/index.ts
|
2
6
|
import {
|
3
7
|
Facet,
|
@@ -22,7 +26,6 @@ function isInsideCode($pos) {
|
|
22
26
|
}
|
23
27
|
return $pos.marks().some((mark) => mark.type.name === "code");
|
24
28
|
}
|
25
|
-
var OBJECT_REPLACEMENT = "\uFFFC";
|
26
29
|
function getPluginState(state) {
|
27
30
|
return pluginKey.getState(state);
|
28
31
|
}
|
@@ -75,10 +78,14 @@ function createAutocompletePlugin({
|
|
75
78
|
const textContent = view.state.doc.textBetween(
|
76
79
|
from,
|
77
80
|
to,
|
78
|
-
|
81
|
+
OBJECT_REPLACEMENT_CHARACTER
|
79
82
|
);
|
80
83
|
const deleteMatch = () => {
|
81
|
-
if (view.state.doc.textBetween(
|
84
|
+
if (view.state.doc.textBetween(
|
85
|
+
from,
|
86
|
+
to,
|
87
|
+
OBJECT_REPLACEMENT_CHARACTER
|
88
|
+
) === textContent) {
|
82
89
|
view.dispatch(view.state.tr.delete(from, to));
|
83
90
|
}
|
84
91
|
};
|
@@ -125,7 +132,7 @@ function calcPluginState(state, rules) {
|
|
125
132
|
Math.max(0, parentOffset - MAX_MATCH),
|
126
133
|
parentOffset,
|
127
134
|
null,
|
128
|
-
|
135
|
+
OBJECT_REPLACEMENT_CHARACTER
|
129
136
|
);
|
130
137
|
for (const rule of rules) {
|
131
138
|
if (!rule.canMatch({ state })) {
|
@@ -1,7 +1,9 @@
|
|
1
1
|
export { defineCodeBlock } from './_tsup-dts-rollup';
|
2
2
|
export { defineCodeBlockCommands_alias_1 as defineCodeBlockCommands } from './_tsup-dts-rollup';
|
3
|
+
export { defineCodeBlockEnterRule_alias_1 as defineCodeBlockEnterRule } from './_tsup-dts-rollup';
|
3
4
|
export { defineCodeBlockHighlight_alias_1 as defineCodeBlockHighlight } from './_tsup-dts-rollup';
|
4
5
|
export { defineCodeBlockInputRule_alias_1 as defineCodeBlockInputRule } from './_tsup-dts-rollup';
|
6
|
+
export { defineCodeBlockShikiji_alias_1 as defineCodeBlockShikiji } from './_tsup-dts-rollup';
|
5
7
|
export { defineCodeBlockSpec_alias_1 as defineCodeBlockSpec } from './_tsup-dts-rollup';
|
6
8
|
export { CodeBlockAttrs_alias_1 as CodeBlockAttrs } from './_tsup-dts-rollup';
|
7
9
|
export { HighlightParser_alias_1 as HighlightParser } from './_tsup-dts-rollup';
|
@@ -1,3 +1,10 @@
|
|
1
|
+
import {
|
2
|
+
OBJECT_REPLACEMENT_CHARACTER
|
3
|
+
} from "./chunk-HQZORKGY.js";
|
4
|
+
import {
|
5
|
+
defineTextBlockInputRule
|
6
|
+
} from "./chunk-DYFRBXUX.js";
|
7
|
+
|
1
8
|
// src/code-block/index.ts
|
2
9
|
import { union } from "@prosekit/core";
|
3
10
|
|
@@ -30,59 +37,216 @@ function defineCodeBlockHighlight({
|
|
30
37
|
);
|
31
38
|
}
|
32
39
|
|
33
|
-
// src/
|
34
|
-
import {
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
},
|
60
|
-
props: {
|
61
|
-
decorations(state) {
|
62
|
-
return key.getState(state);
|
40
|
+
// src/enter-rule/index.ts
|
41
|
+
import {
|
42
|
+
Facet,
|
43
|
+
getNodeType,
|
44
|
+
isTextSelection,
|
45
|
+
keymapFacet
|
46
|
+
} from "@prosekit/core";
|
47
|
+
function defineEnterRule({
|
48
|
+
regex,
|
49
|
+
handler
|
50
|
+
}) {
|
51
|
+
const rule = new EnterRule(regex, handler);
|
52
|
+
return inputRuleFacet.extension([rule]);
|
53
|
+
}
|
54
|
+
function defineTextBlockEnterRule({
|
55
|
+
regex,
|
56
|
+
type,
|
57
|
+
attrs
|
58
|
+
}) {
|
59
|
+
return defineEnterRule({
|
60
|
+
regex,
|
61
|
+
handler: ({ state, from, to, match }) => {
|
62
|
+
const nodeType = getNodeType(state.schema, type);
|
63
|
+
const $start = state.doc.resolve(from);
|
64
|
+
if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), nodeType)) {
|
65
|
+
return null;
|
63
66
|
}
|
67
|
+
const nodeAttrs = attrs && typeof attrs === "function" ? attrs(match) : attrs;
|
68
|
+
return state.tr.delete(from, to).setBlockType(from, from, nodeType, nodeAttrs);
|
64
69
|
}
|
65
70
|
});
|
66
|
-
return definePlugin2(plugin);
|
67
71
|
}
|
68
|
-
var
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
+
var EnterRule = class {
|
73
|
+
constructor(regex, handler) {
|
74
|
+
this.regex = regex;
|
75
|
+
this.handler = handler;
|
76
|
+
}
|
77
|
+
};
|
78
|
+
var inputRuleFacet = Facet.define({
|
79
|
+
convert: (inputs) => {
|
80
|
+
return {
|
81
|
+
Enter: (state, dispatch, view) => {
|
82
|
+
if (!view)
|
83
|
+
return false;
|
84
|
+
return execRules(view, inputs, dispatch);
|
85
|
+
}
|
86
|
+
};
|
87
|
+
},
|
88
|
+
next: keymapFacet
|
89
|
+
});
|
90
|
+
function execRules(view, rules, dispatch) {
|
91
|
+
if (view.composing)
|
92
|
+
return false;
|
93
|
+
const state = view.state;
|
94
|
+
const selection = state.selection;
|
95
|
+
if (!isTextSelection(selection))
|
96
|
+
return false;
|
97
|
+
const $cursor = selection.$cursor;
|
98
|
+
if (!$cursor || $cursor.parent.type.spec.code)
|
99
|
+
return false;
|
100
|
+
const textBefore = $cursor.parent.textBetween(
|
101
|
+
Math.max(0, $cursor.parentOffset - MAX_MATCH),
|
102
|
+
$cursor.parentOffset,
|
103
|
+
null,
|
104
|
+
OBJECT_REPLACEMENT_CHARACTER
|
105
|
+
);
|
106
|
+
for (const rule of rules) {
|
107
|
+
rule.regex.lastIndex = 0;
|
108
|
+
const match = rule.regex.exec(textBefore);
|
109
|
+
const tr = match && rule.handler({
|
110
|
+
state,
|
111
|
+
from: $cursor.pos - match[0].length,
|
112
|
+
to: $cursor.pos,
|
113
|
+
match
|
114
|
+
});
|
115
|
+
if (!tr)
|
116
|
+
continue;
|
117
|
+
dispatch == null ? void 0 : dispatch(tr);
|
118
|
+
return true;
|
119
|
+
}
|
120
|
+
return false;
|
72
121
|
}
|
122
|
+
var MAX_MATCH = 200;
|
73
123
|
|
74
124
|
// src/code-block/code-block-input-rule.ts
|
75
|
-
import { defineInputRule, getNodeType } from "@prosekit/core";
|
76
|
-
import { textblockTypeInputRule } from "@prosekit/pm/inputrules";
|
77
125
|
function defineCodeBlockInputRule() {
|
78
|
-
return
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
126
|
+
return defineTextBlockInputRule({
|
127
|
+
regex: /^```(\S*)\s$/,
|
128
|
+
type: "codeBlock",
|
129
|
+
attrs: getAttrs
|
130
|
+
});
|
131
|
+
}
|
132
|
+
function defineCodeBlockEnterRule() {
|
133
|
+
return defineTextBlockEnterRule({
|
134
|
+
regex: /^```(\S*)$/,
|
135
|
+
type: "codeBlock",
|
136
|
+
attrs: getAttrs
|
84
137
|
});
|
85
138
|
}
|
139
|
+
function getAttrs(match) {
|
140
|
+
return { language: match[1] || "" };
|
141
|
+
}
|
142
|
+
|
143
|
+
// src/code-block/code-block-keymap.ts
|
144
|
+
import { defineKeymap } from "@prosekit/core";
|
145
|
+
import { TextSelection } from "@prosekit/pm/state";
|
146
|
+
|
147
|
+
// src/utils/default-block-at.ts
|
148
|
+
function defaultBlockAt(match) {
|
149
|
+
for (let i = 0; i < match.edgeCount; i++) {
|
150
|
+
const { type } = match.edge(i);
|
151
|
+
if (type.isTextblock && !type.hasRequiredAttrs())
|
152
|
+
return type;
|
153
|
+
}
|
154
|
+
return null;
|
155
|
+
}
|
156
|
+
|
157
|
+
// src/code-block/code-block-keymap.ts
|
158
|
+
function defineCodeBlockKeymap() {
|
159
|
+
return defineKeymap({
|
160
|
+
Enter: existCodeBlock
|
161
|
+
});
|
162
|
+
}
|
163
|
+
var existCodeBlock = (state, dispatch) => {
|
164
|
+
if (!state.selection.empty) {
|
165
|
+
return false;
|
166
|
+
}
|
167
|
+
const { $head } = state.selection;
|
168
|
+
const parent = $head.parent;
|
169
|
+
if (parent.isTextblock && parent.type.spec.code && $head.parentOffset === parent.content.size && parent.textContent.endsWith("\n\n")) {
|
170
|
+
const grandParent = $head.node(-1);
|
171
|
+
const insertIndex = $head.indexAfter(-1);
|
172
|
+
const type = defaultBlockAt(grandParent.contentMatchAt(insertIndex));
|
173
|
+
if (!type || !grandParent.canReplaceWith(insertIndex, insertIndex, type)) {
|
174
|
+
return false;
|
175
|
+
}
|
176
|
+
if (dispatch) {
|
177
|
+
const { tr } = state;
|
178
|
+
tr.delete($head.pos - 2, $head.pos);
|
179
|
+
const pos = tr.selection.$head.after();
|
180
|
+
const node = type.createAndFill();
|
181
|
+
if (node) {
|
182
|
+
tr.replaceWith(pos, pos, node);
|
183
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve(pos), 1));
|
184
|
+
dispatch(tr.scrollIntoView());
|
185
|
+
}
|
186
|
+
}
|
187
|
+
return true;
|
188
|
+
}
|
189
|
+
return false;
|
190
|
+
};
|
191
|
+
|
192
|
+
// src/code-block/code-block-shikiji.ts
|
193
|
+
import { createParser } from "prosemirror-highlight/shikiji";
|
194
|
+
function createHighlighterLoader() {
|
195
|
+
let shikijiImport;
|
196
|
+
let highlighter;
|
197
|
+
const languages = /* @__PURE__ */ new Set();
|
198
|
+
const themes = /* @__PURE__ */ new Set();
|
199
|
+
return function highlighterLoader(lang, theme) {
|
200
|
+
if (!shikijiImport) {
|
201
|
+
shikijiImport = import("shikiji").then(async ({ getHighlighter }) => {
|
202
|
+
const fallbackLang = "md";
|
203
|
+
highlighter = await getHighlighter({
|
204
|
+
langs: [fallbackLang],
|
205
|
+
themes: []
|
206
|
+
});
|
207
|
+
});
|
208
|
+
return { promise: shikijiImport };
|
209
|
+
}
|
210
|
+
if (!highlighter) {
|
211
|
+
return { promise: shikijiImport };
|
212
|
+
}
|
213
|
+
if (!languages.has(lang)) {
|
214
|
+
const promise = highlighter.loadLanguage(lang).then(() => {
|
215
|
+
languages.add(lang);
|
216
|
+
}).catch(() => {
|
217
|
+
});
|
218
|
+
return { promise };
|
219
|
+
}
|
220
|
+
if (!themes.has(theme)) {
|
221
|
+
const promise = highlighter.loadTheme(theme).then(() => {
|
222
|
+
themes.add(theme);
|
223
|
+
}).catch(() => {
|
224
|
+
});
|
225
|
+
return { promise };
|
226
|
+
}
|
227
|
+
return { highlighter };
|
228
|
+
};
|
229
|
+
}
|
230
|
+
function createLazyParser(theme) {
|
231
|
+
let parser;
|
232
|
+
const highlighterLoader = createHighlighterLoader();
|
233
|
+
return function lazyParser(options) {
|
234
|
+
const language = options.language || "";
|
235
|
+
const { highlighter, promise } = highlighterLoader(language, theme);
|
236
|
+
if (!highlighter) {
|
237
|
+
return promise || [];
|
238
|
+
}
|
239
|
+
if (!parser) {
|
240
|
+
parser = createParser(highlighter);
|
241
|
+
}
|
242
|
+
return parser(options);
|
243
|
+
};
|
244
|
+
}
|
245
|
+
function defineCodeBlockShikiji(options) {
|
246
|
+
const theme = (options == null ? void 0 : options.theme) || "github-light";
|
247
|
+
const parser = createLazyParser(theme);
|
248
|
+
return defineCodeBlockHighlight({ parser });
|
249
|
+
}
|
86
250
|
|
87
251
|
// src/code-block/code-block-spec.ts
|
88
252
|
import { defineNodeSpec } from "@prosekit/core";
|
@@ -106,37 +270,27 @@ function defineCodeBlockSpec() {
|
|
106
270
|
],
|
107
271
|
toDOM(node) {
|
108
272
|
const attrs = node.attrs;
|
109
|
-
return [
|
110
|
-
"pre",
|
111
|
-
// TODO: remove class 'hljs'
|
112
|
-
{ "data-language": attrs.language, class: "hljs" },
|
113
|
-
["code", 0]
|
114
|
-
];
|
273
|
+
return ["pre", { "data-language": attrs.language }, ["code", 0]];
|
115
274
|
}
|
116
275
|
});
|
117
276
|
}
|
118
277
|
|
119
278
|
// src/code-block/index.ts
|
120
|
-
function defineCodeBlock(
|
121
|
-
|
279
|
+
function defineCodeBlock() {
|
280
|
+
return union([
|
122
281
|
defineCodeBlockSpec(),
|
123
282
|
defineCodeBlockInputRule(),
|
283
|
+
defineCodeBlockEnterRule(),
|
284
|
+
defineCodeBlockKeymap(),
|
124
285
|
defineCodeBlockCommands()
|
125
|
-
];
|
126
|
-
const parser = options == null ? void 0 : options.parser;
|
127
|
-
if (parser) {
|
128
|
-
extensions.push(defineCodeBlockHighlight({ parser }));
|
129
|
-
}
|
130
|
-
const hljs = options == null ? void 0 : options.hljs;
|
131
|
-
if (hljs) {
|
132
|
-
extensions.push(defineCodeBlockHighlightDeprecated({ hljs }));
|
133
|
-
}
|
134
|
-
return union(extensions);
|
286
|
+
]);
|
135
287
|
}
|
136
288
|
export {
|
137
289
|
defineCodeBlock,
|
138
290
|
defineCodeBlockCommands,
|
291
|
+
defineCodeBlockEnterRule,
|
139
292
|
defineCodeBlockHighlight,
|
140
293
|
defineCodeBlockInputRule,
|
294
|
+
defineCodeBlockShikiji,
|
141
295
|
defineCodeBlockSpec
|
142
296
|
};
|
@@ -1,16 +1,17 @@
|
|
1
|
+
import {
|
2
|
+
defineTextBlockInputRule
|
3
|
+
} from "./chunk-DYFRBXUX.js";
|
4
|
+
|
1
5
|
// src/heading/index.ts
|
2
6
|
import {
|
3
7
|
defineCommands,
|
4
|
-
defineInputRule,
|
5
8
|
defineKeymap,
|
6
9
|
defineNodeSpec,
|
7
|
-
getNodeType,
|
8
10
|
insertNode,
|
9
11
|
setBlockType,
|
10
12
|
toggleNode,
|
11
13
|
union
|
12
14
|
} from "@prosekit/core";
|
13
|
-
import { textblockTypeInputRule } from "@prosekit/pm/inputrules";
|
14
15
|
function defineHeadingSpec() {
|
15
16
|
return defineNodeSpec({
|
16
17
|
name: "heading",
|
@@ -42,13 +43,14 @@ function defineHeadingKeymap() {
|
|
42
43
|
});
|
43
44
|
}
|
44
45
|
function defineHeadingInputRule() {
|
45
|
-
return
|
46
|
-
|
47
|
-
|
46
|
+
return defineTextBlockInputRule({
|
47
|
+
regex: /^(#{1,6})\s$/,
|
48
|
+
type: "heading",
|
49
|
+
attrs: (match) => {
|
48
50
|
var _a, _b;
|
49
51
|
const level = (_b = (_a = match[1]) == null ? void 0 : _a.length) != null ? _b : 1;
|
50
52
|
return { level };
|
51
|
-
}
|
53
|
+
}
|
52
54
|
});
|
53
55
|
}
|
54
56
|
function defineHeadingCommands() {
|
@@ -1,8 +1,11 @@
|
|
1
|
+
import {
|
2
|
+
defineInputRule
|
3
|
+
} from "./chunk-DYFRBXUX.js";
|
4
|
+
|
1
5
|
// src/list/index.ts
|
2
6
|
import {
|
3
7
|
Priority,
|
4
8
|
defineCommands,
|
5
|
-
defineInputRule,
|
6
9
|
defineKeymap,
|
7
10
|
defineNodeSpec,
|
8
11
|
definePlugin,
|
@@ -34,7 +37,7 @@ function defineListKeymap() {
|
|
34
37
|
return defineKeymap(listKeymap);
|
35
38
|
}
|
36
39
|
function defineListInputRules() {
|
37
|
-
return
|
40
|
+
return union(listInputRules.map(defineInputRule));
|
38
41
|
}
|
39
42
|
function defineListCommands() {
|
40
43
|
return defineCommands({
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@prosekit/extensions",
|
3
3
|
"type": "module",
|
4
|
-
"version": "0.1
|
4
|
+
"version": "0.2.1",
|
5
5
|
"private": false,
|
6
6
|
"author": {
|
7
7
|
"name": "ocavue",
|
@@ -65,6 +65,11 @@
|
|
65
65
|
"import": "./dist/prosekit-extensions-image.js",
|
66
66
|
"default": "./dist/prosekit-extensions-image.js"
|
67
67
|
},
|
68
|
+
"./input-rule": {
|
69
|
+
"types": "./dist/prosekit-extensions-input-rule.d.ts",
|
70
|
+
"import": "./dist/prosekit-extensions-input-rule.js",
|
71
|
+
"default": "./dist/prosekit-extensions-input-rule.js"
|
72
|
+
},
|
68
73
|
"./italic": {
|
69
74
|
"types": "./dist/prosekit-extensions-italic.d.ts",
|
70
75
|
"import": "./dist/prosekit-extensions-italic.js",
|
@@ -106,11 +111,6 @@
|
|
106
111
|
"import": "./dist/prosekit-extensions-strike.js",
|
107
112
|
"default": "./dist/prosekit-extensions-strike.js"
|
108
113
|
},
|
109
|
-
"./suggestion": {
|
110
|
-
"types": "./dist/prosekit-extensions-suggestion.d.ts",
|
111
|
-
"import": "./dist/prosekit-extensions-suggestion.js",
|
112
|
-
"default": "./dist/prosekit-extensions-suggestion.js"
|
113
|
-
},
|
114
114
|
"./underline": {
|
115
115
|
"types": "./dist/prosekit-extensions-underline.d.ts",
|
116
116
|
"import": "./dist/prosekit-extensions-underline.js",
|
@@ -121,18 +121,25 @@
|
|
121
121
|
"dist"
|
122
122
|
],
|
123
123
|
"dependencies": {
|
124
|
-
"@prosekit/core": "^0.
|
124
|
+
"@prosekit/core": "^0.2.0",
|
125
125
|
"@prosekit/pm": "^0.1.1",
|
126
|
-
"highlight.js": "^11.9.0",
|
127
126
|
"prosemirror-flat-list": "^0.4.5",
|
128
|
-
"prosemirror-highlight": "^0.
|
129
|
-
|
127
|
+
"prosemirror-highlight": "^0.4.0"
|
128
|
+
},
|
129
|
+
"peerDependencies": {
|
130
|
+
"shikiji": ">= 0.9.0"
|
131
|
+
},
|
132
|
+
"peerDependenciesMeta": {
|
133
|
+
"shikiji": {
|
134
|
+
"optional": true
|
135
|
+
}
|
130
136
|
},
|
131
137
|
"devDependencies": {
|
132
138
|
"@prosekit/dev": "*",
|
139
|
+
"shikiji": "^0.9.16",
|
133
140
|
"tsup": "^8.0.1",
|
134
141
|
"typescript": "^5.3.3",
|
135
|
-
"vitest": "^1.
|
142
|
+
"vitest": "^1.1.1"
|
136
143
|
},
|
137
144
|
"scripts": {
|
138
145
|
"build:tsup": "tsup",
|
@@ -165,6 +172,9 @@
|
|
165
172
|
"image": [
|
166
173
|
"./dist/prosekit-extensions-image.d.ts"
|
167
174
|
],
|
175
|
+
"input-rule": [
|
176
|
+
"./dist/prosekit-extensions-input-rule.d.ts"
|
177
|
+
],
|
168
178
|
"italic": [
|
169
179
|
"./dist/prosekit-extensions-italic.d.ts"
|
170
180
|
],
|
@@ -186,9 +196,6 @@
|
|
186
196
|
"strike": [
|
187
197
|
"./dist/prosekit-extensions-strike.d.ts"
|
188
198
|
],
|
189
|
-
"suggestion": [
|
190
|
-
"./dist/prosekit-extensions-suggestion.d.ts"
|
191
|
-
],
|
192
199
|
"underline": [
|
193
200
|
"./dist/prosekit-extensions-underline.d.ts"
|
194
201
|
]
|
@@ -1,161 +0,0 @@
|
|
1
|
-
// src/suggestion/index.ts
|
2
|
-
import { definePlugin } from "@prosekit/core";
|
3
|
-
|
4
|
-
// src/suggestion/plugin.ts
|
5
|
-
import { ProseKitError } from "@prosekit/core";
|
6
|
-
import { Plugin, PluginKey } from "@prosekit/pm/state";
|
7
|
-
import { Decoration, DecorationSet } from "@prosekit/pm/view";
|
8
|
-
|
9
|
-
// src/suggestion/is-valid.ts
|
10
|
-
import "@prosekit/pm/model";
|
11
|
-
import "@prosekit/pm/state";
|
12
|
-
function defaultIsValid({ state }) {
|
13
|
-
return state.selection.empty && !isInsideCode(state.selection.$from);
|
14
|
-
}
|
15
|
-
function isInsideCode($pos) {
|
16
|
-
for (let d = $pos.depth; d > 0; d--) {
|
17
|
-
if ($pos.node(d).type.spec.code) {
|
18
|
-
return true;
|
19
|
-
}
|
20
|
-
}
|
21
|
-
return $pos.marks().some((mark) => mark.type.name === "code");
|
22
|
-
}
|
23
|
-
|
24
|
-
// src/suggestion/plugin.ts
|
25
|
-
var pluginKey = new PluginKey("prosemirror-prediction");
|
26
|
-
function getPluginState(state) {
|
27
|
-
return pluginKey.getState(state);
|
28
|
-
}
|
29
|
-
function getTrMeta(tr) {
|
30
|
-
return tr.getMeta(pluginKey);
|
31
|
-
}
|
32
|
-
function setTrMeta(tr, meta) {
|
33
|
-
return tr.setMeta(pluginKey, meta);
|
34
|
-
}
|
35
|
-
function createPredictionPlugin(options) {
|
36
|
-
if (options.rules.length === 0) {
|
37
|
-
throw new ProseKitError(
|
38
|
-
"You can't create a prediction plugin without rules"
|
39
|
-
);
|
40
|
-
}
|
41
|
-
const { onMatch, onDeactivate, isValid = defaultIsValid } = options;
|
42
|
-
return new Plugin({
|
43
|
-
key: pluginKey,
|
44
|
-
state: {
|
45
|
-
init: () => {
|
46
|
-
return { active: false, ignore: null, matching: null };
|
47
|
-
},
|
48
|
-
apply: (tr, prevValue, oldState, newState) => {
|
49
|
-
var _a;
|
50
|
-
const meta = getTrMeta(tr);
|
51
|
-
if (!tr.docChanged && oldState.selection.eq(newState.selection) && !meta) {
|
52
|
-
return prevValue;
|
53
|
-
}
|
54
|
-
if (meta) {
|
55
|
-
return meta;
|
56
|
-
}
|
57
|
-
if (!isValid({ state: newState })) {
|
58
|
-
return { active: false, ignore: null, matching: null };
|
59
|
-
}
|
60
|
-
const nextValue = calcPluginState(newState, options.rules);
|
61
|
-
if (nextValue.active && prevValue.ignore != null && ((_a = nextValue.matching) == null ? void 0 : _a.from) === prevValue.ignore) {
|
62
|
-
return prevValue;
|
63
|
-
}
|
64
|
-
return nextValue;
|
65
|
-
}
|
66
|
-
},
|
67
|
-
view: () => ({
|
68
|
-
update: (view, prevState) => {
|
69
|
-
const prevPluginState = getPluginState(prevState);
|
70
|
-
const currPluginState = getPluginState(view.state);
|
71
|
-
if ((currPluginState == null ? void 0 : currPluginState.active) && currPluginState.matching && currPluginState.matching.from !== currPluginState.ignore) {
|
72
|
-
const { from, to } = currPluginState.matching;
|
73
|
-
const dismiss = () => {
|
74
|
-
view.dispatch(
|
75
|
-
setTrMeta(view.state.tr, {
|
76
|
-
active: false,
|
77
|
-
ignore: from,
|
78
|
-
matching: null
|
79
|
-
})
|
80
|
-
);
|
81
|
-
};
|
82
|
-
const textContent = view.state.doc.textBetween(from, to, "\uFFFC");
|
83
|
-
const deleteMatch = () => {
|
84
|
-
if (view.state.doc.textBetween(from, to, "\uFFFC") === textContent) {
|
85
|
-
view.dispatch(view.state.tr.delete(from, to));
|
86
|
-
}
|
87
|
-
};
|
88
|
-
onMatch({
|
89
|
-
rule: currPluginState.matching.rule,
|
90
|
-
match: currPluginState.matching.match,
|
91
|
-
matchAfter: currPluginState.matching.matchAfter,
|
92
|
-
state: view.state,
|
93
|
-
dismiss,
|
94
|
-
deleteMatch
|
95
|
-
});
|
96
|
-
} else if (prevPluginState == null ? void 0 : prevPluginState.active) {
|
97
|
-
onDeactivate();
|
98
|
-
}
|
99
|
-
}
|
100
|
-
}),
|
101
|
-
props: {
|
102
|
-
decorations: (state) => {
|
103
|
-
const pluginState = getPluginState(state);
|
104
|
-
if ((pluginState == null ? void 0 : pluginState.active) && pluginState.matching) {
|
105
|
-
const { from, to } = pluginState.matching;
|
106
|
-
const deco = Decoration.inline(from, to, {
|
107
|
-
class: "prosemirror-prediction-match"
|
108
|
-
});
|
109
|
-
return DecorationSet.create(state.doc, [deco]);
|
110
|
-
}
|
111
|
-
return null;
|
112
|
-
}
|
113
|
-
}
|
114
|
-
});
|
115
|
-
}
|
116
|
-
function calcPluginState(state, rules) {
|
117
|
-
const { $anchor } = state.selection;
|
118
|
-
const matchAfter = rules.some((rule) => rule.matchAfter);
|
119
|
-
const parentOffset = $anchor.parentOffset;
|
120
|
-
const textBefore = $anchor.parent.textBetween(
|
121
|
-
Math.max(0, parentOffset - MAX_MATCH),
|
122
|
-
parentOffset,
|
123
|
-
null,
|
124
|
-
"\uFFFC"
|
125
|
-
);
|
126
|
-
const textAfter = matchAfter ? $anchor.parent.textBetween(
|
127
|
-
parentOffset,
|
128
|
-
Math.min(parentOffset + MAX_MATCH, $anchor.parent.content.size),
|
129
|
-
null
|
130
|
-
) : "";
|
131
|
-
for (const rule of rules) {
|
132
|
-
const match = textBefore.match(rule.match);
|
133
|
-
const matchAfter2 = rule.matchAfter ? textAfter.match(rule.matchAfter) : null;
|
134
|
-
if ((match == null ? void 0 : match.index) != null) {
|
135
|
-
const from = $anchor.pos - textBefore.length + match.index;
|
136
|
-
const to = $anchor.pos + (matchAfter2 ? matchAfter2[0].length : 0);
|
137
|
-
return {
|
138
|
-
active: true,
|
139
|
-
ignore: null,
|
140
|
-
matching: {
|
141
|
-
rule,
|
142
|
-
from,
|
143
|
-
to,
|
144
|
-
match,
|
145
|
-
matchAfter: matchAfter2
|
146
|
-
}
|
147
|
-
};
|
148
|
-
}
|
149
|
-
}
|
150
|
-
return { active: false };
|
151
|
-
}
|
152
|
-
var MAX_MATCH = 200;
|
153
|
-
|
154
|
-
// src/suggestion/index.ts
|
155
|
-
function defineSuggestion(options) {
|
156
|
-
const plugin = createPredictionPlugin(options);
|
157
|
-
return definePlugin(plugin);
|
158
|
-
}
|
159
|
-
export {
|
160
|
-
defineSuggestion
|
161
|
-
};
|