@prosekit/extensions 0.2.0 → 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 +198 -29
- 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 +218 -14
- 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 +20 -3
@@ -1,15 +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
9
|
import { IndentListOptions } from 'prosemirror-flat-list';
|
10
|
+
import { InputRule } from '@prosekit/pm/inputrules';
|
7
11
|
import { ListAttributes } from 'prosemirror-flat-list';
|
8
12
|
import { NodeRange } from 'prosemirror-model';
|
13
|
+
import { NodeType } from '@prosekit/pm/model';
|
14
|
+
import { NodeType as NodeType_2 } from 'prosemirror-model';
|
9
15
|
import { Options } from 'tsup';
|
10
16
|
import { Parser } from 'prosemirror-highlight';
|
11
17
|
import { Plugin as Plugin_2 } from '@prosekit/pm/state';
|
12
18
|
import { PluginKey } from '@prosekit/pm/state';
|
19
|
+
import { ProseMirrorNode } from '@prosekit/pm/model';
|
13
20
|
import { ToggleCollapsedOptions } from 'prosemirror-flat-list';
|
14
21
|
import { Transaction } from '@prosekit/pm/state';
|
15
22
|
import { UnwrapListOptions } from 'prosemirror-flat-list';
|
@@ -56,6 +63,8 @@ export declare const default_alias_1: {
|
|
56
63
|
};
|
57
64
|
};
|
58
65
|
|
66
|
+
export declare function defaultBlockAt(match: ContentMatch): NodeType_2 | null;
|
67
|
+
|
59
68
|
export declare function defaultCanMatch({ state }: {
|
60
69
|
state: EditorState;
|
61
70
|
}): boolean;
|
@@ -110,6 +119,8 @@ toggleCode: [];
|
|
110
119
|
*
|
111
120
|
* - {@link defineCodeBlockSpec}
|
112
121
|
* - {@link defineCodeBlockInputRule}
|
122
|
+
* - {@link defineCodeBlockEnterRule}
|
123
|
+
* - {@link defineCodeBlockKeymap}
|
113
124
|
* - {@link defineCodeBlockCommands}.
|
114
125
|
*
|
115
126
|
* @public
|
@@ -134,6 +145,15 @@ setCodeBlockLanguage: [language: string];
|
|
134
145
|
export { defineCodeBlockCommands }
|
135
146
|
export { defineCodeBlockCommands as defineCodeBlockCommands_alias_1 }
|
136
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
|
+
|
137
157
|
/**
|
138
158
|
* Adds syntax highlighting to code blocks. This function requires a `Parser`
|
139
159
|
* instance from the `prosemirror-highlight` package. See the
|
@@ -157,6 +177,27 @@ declare function defineCodeBlockInputRule(): Extension<ExtensionTyping<string, s
|
|
157
177
|
export { defineCodeBlockInputRule }
|
158
178
|
export { defineCodeBlockInputRule as defineCodeBlockInputRule_alias_1 }
|
159
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
|
+
|
160
201
|
/**
|
161
202
|
* Defines the `codeBlock` node spec.
|
162
203
|
*
|
@@ -181,6 +222,15 @@ export declare function defineCodeSpec(): Extension< {
|
|
181
222
|
MARKS: "code";
|
182
223
|
}>;
|
183
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
|
+
|
184
234
|
/**
|
185
235
|
* @public
|
186
236
|
*/
|
@@ -229,6 +279,15 @@ export declare function defineImageSpec(): Extension< {
|
|
229
279
|
NODES: "image";
|
230
280
|
}>;
|
231
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
|
+
|
232
291
|
/**
|
233
292
|
* @public
|
234
293
|
*/
|
@@ -278,36 +337,36 @@ MARKS: "link";
|
|
278
337
|
/**
|
279
338
|
* @public
|
280
339
|
*/
|
281
|
-
export declare function defineList(): Extension<
|
282
|
-
NODES: "list";
|
283
|
-
COMMAND_ARGS: {
|
284
|
-
dedentList: [options?: DedentListOptions | undefined];
|
285
|
-
indentList: [options?: IndentListOptions | undefined];
|
286
|
-
moveList: [direction: "up" | "down"];
|
287
|
-
splitList: [];
|
288
|
-
toggleCollapsed: [(ToggleCollapsedOptions | undefined)?];
|
289
|
-
toggleList: [attrs: ListAttributes];
|
290
|
-
unwrapList: [options?: UnwrapListOptions | undefined];
|
291
|
-
wrapInList: [getAttrs: ListAttributes | ((range: NodeRange) => ListAttributes | null)];
|
292
|
-
insertList: [attrs?: ListAttributes | undefined];
|
293
|
-
};
|
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
|
+
};
|
294
353
|
}>;
|
295
354
|
|
296
|
-
export declare function defineListCommands(): Extension<
|
297
|
-
COMMAND_ARGS: {
|
298
|
-
dedentList: [options?: DedentListOptions | undefined];
|
299
|
-
indentList: [options?: IndentListOptions | undefined];
|
300
|
-
moveList: [direction: "up" | "down"];
|
301
|
-
splitList: [];
|
302
|
-
toggleCollapsed: [(ToggleCollapsedOptions | undefined)?];
|
303
|
-
toggleList: [attrs: ListAttributes];
|
304
|
-
unwrapList: [options?: UnwrapListOptions | undefined];
|
305
|
-
wrapInList: [getAttrs: ListAttributes | ((range: NodeRange) => ListAttributes | null)];
|
306
|
-
insertList: [attrs?: ListAttributes | undefined];
|
307
|
-
};
|
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
|
+
};
|
308
367
|
}>;
|
309
368
|
|
310
|
-
export declare function defineListInputRules(): Extension
|
369
|
+
export declare function defineListInputRules(): Extension;
|
311
370
|
|
312
371
|
/**
|
313
372
|
* Returns a extension that adds key bindings for list.
|
@@ -318,8 +377,8 @@ export declare function defineListKeymap(): Extension<ExtensionTyping<string, st
|
|
318
377
|
|
319
378
|
export declare function defineListPlugins(): Extension<ExtensionTyping<string, string, CommandArgs>>;
|
320
379
|
|
321
|
-
export declare function defineListSpec(): Extension<
|
322
|
-
NODES: "list";
|
380
|
+
export declare function defineListSpec(): Extension<{
|
381
|
+
NODES: "list";
|
323
382
|
}>;
|
324
383
|
|
325
384
|
/**
|
@@ -378,6 +437,37 @@ export declare function defineStrikeSpec(): Extension< {
|
|
378
437
|
MARKS: "strike";
|
379
438
|
}>;
|
380
439
|
|
440
|
+
/**
|
441
|
+
* Defines an enter rule that replaces the matched text with a block node.
|
442
|
+
*
|
443
|
+
* See also {@link defineEnterRule}.
|
444
|
+
*
|
445
|
+
* @public
|
446
|
+
*/
|
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;
|
470
|
+
|
381
471
|
/**
|
382
472
|
* @public
|
383
473
|
*/
|
@@ -400,6 +490,63 @@ export declare function defineUnderlineSpec(): Extension< {
|
|
400
490
|
MARKS: "underline";
|
401
491
|
}>;
|
402
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
|
+
|
403
550
|
export declare function getPluginState(state: EditorState): PredictionPluginState | undefined;
|
404
551
|
|
405
552
|
export declare function getTrMeta(tr: Transaction): PredictionPluginState;
|
@@ -445,7 +592,9 @@ export declare interface MentionAttrs {
|
|
445
592
|
value: string;
|
446
593
|
}
|
447
594
|
|
448
|
-
export declare const
|
595
|
+
export declare const NO_BREAK_SPACE = "\u00A0";
|
596
|
+
|
597
|
+
export declare const OBJECT_REPLACEMENT_CHARACTER = "\uFFFC";
|
449
598
|
|
450
599
|
export declare interface PlaceholderOptions {
|
451
600
|
/**
|
@@ -477,4 +626,24 @@ export declare interface PredictionPluginState {
|
|
477
626
|
|
478
627
|
export declare function setTrMeta(tr: Transaction, meta: PredictionPluginState): Transaction;
|
479
628
|
|
629
|
+
/**
|
630
|
+
* Options for {@link createTextBlockEnterRule}.
|
631
|
+
*
|
632
|
+
* @public
|
633
|
+
*/
|
634
|
+
export declare type TextBlockEnterRuleOptions = {
|
635
|
+
/**
|
636
|
+
* The regular expression to match against. It should end with `$`.
|
637
|
+
*/
|
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
|
+
};
|
648
|
+
|
480
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,18 +37,216 @@ function defineCodeBlockHighlight({
|
|
30
37
|
);
|
31
38
|
}
|
32
39
|
|
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;
|
66
|
+
}
|
67
|
+
const nodeAttrs = attrs && typeof attrs === "function" ? attrs(match) : attrs;
|
68
|
+
return state.tr.delete(from, to).setBlockType(from, from, nodeType, nodeAttrs);
|
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;
|
121
|
+
}
|
122
|
+
var MAX_MATCH = 200;
|
123
|
+
|
33
124
|
// src/code-block/code-block-input-rule.ts
|
34
|
-
import { defineInputRule, getNodeType } from "@prosekit/core";
|
35
|
-
import { textblockTypeInputRule } from "@prosekit/pm/inputrules";
|
36
125
|
function defineCodeBlockInputRule() {
|
37
|
-
return
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
};
|
42
|
-
return textblockTypeInputRule(/^```(\S*)\s$/, nodeType, getAttrs);
|
126
|
+
return defineTextBlockInputRule({
|
127
|
+
regex: /^```(\S*)\s$/,
|
128
|
+
type: "codeBlock",
|
129
|
+
attrs: getAttrs
|
43
130
|
});
|
44
131
|
}
|
132
|
+
function defineCodeBlockEnterRule() {
|
133
|
+
return defineTextBlockEnterRule({
|
134
|
+
regex: /^```(\S*)$/,
|
135
|
+
type: "codeBlock",
|
136
|
+
attrs: getAttrs
|
137
|
+
});
|
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
|
+
}
|
45
250
|
|
46
251
|
// src/code-block/code-block-spec.ts
|
47
252
|
import { defineNodeSpec } from "@prosekit/core";
|
@@ -65,12 +270,7 @@ function defineCodeBlockSpec() {
|
|
65
270
|
],
|
66
271
|
toDOM(node) {
|
67
272
|
const attrs = node.attrs;
|
68
|
-
return [
|
69
|
-
"pre",
|
70
|
-
// TODO: remove class 'hljs'
|
71
|
-
{ "data-language": attrs.language, class: "hljs" },
|
72
|
-
["code", 0]
|
73
|
-
];
|
273
|
+
return ["pre", { "data-language": attrs.language }, ["code", 0]];
|
74
274
|
}
|
75
275
|
});
|
76
276
|
}
|
@@ -80,13 +280,17 @@ function defineCodeBlock() {
|
|
80
280
|
return union([
|
81
281
|
defineCodeBlockSpec(),
|
82
282
|
defineCodeBlockInputRule(),
|
283
|
+
defineCodeBlockEnterRule(),
|
284
|
+
defineCodeBlockKeymap(),
|
83
285
|
defineCodeBlockCommands()
|
84
286
|
]);
|
85
287
|
}
|
86
288
|
export {
|
87
289
|
defineCodeBlock,
|
88
290
|
defineCodeBlockCommands,
|
291
|
+
defineCodeBlockEnterRule,
|
89
292
|
defineCodeBlockHighlight,
|
90
293
|
defineCodeBlockInputRule,
|
294
|
+
defineCodeBlockShikiji,
|
91
295
|
defineCodeBlockSpec
|
92
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.2.
|
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",
|
@@ -119,13 +124,22 @@
|
|
119
124
|
"@prosekit/core": "^0.2.0",
|
120
125
|
"@prosekit/pm": "^0.1.1",
|
121
126
|
"prosemirror-flat-list": "^0.4.5",
|
122
|
-
"prosemirror-highlight": "^0.
|
127
|
+
"prosemirror-highlight": "^0.4.0"
|
128
|
+
},
|
129
|
+
"peerDependencies": {
|
130
|
+
"shikiji": ">= 0.9.0"
|
131
|
+
},
|
132
|
+
"peerDependenciesMeta": {
|
133
|
+
"shikiji": {
|
134
|
+
"optional": true
|
135
|
+
}
|
123
136
|
},
|
124
137
|
"devDependencies": {
|
125
138
|
"@prosekit/dev": "*",
|
139
|
+
"shikiji": "^0.9.16",
|
126
140
|
"tsup": "^8.0.1",
|
127
141
|
"typescript": "^5.3.3",
|
128
|
-
"vitest": "^1.1.
|
142
|
+
"vitest": "^1.1.1"
|
129
143
|
},
|
130
144
|
"scripts": {
|
131
145
|
"build:tsup": "tsup",
|
@@ -158,6 +172,9 @@
|
|
158
172
|
"image": [
|
159
173
|
"./dist/prosekit-extensions-image.d.ts"
|
160
174
|
],
|
175
|
+
"input-rule": [
|
176
|
+
"./dist/prosekit-extensions-input-rule.d.ts"
|
177
|
+
],
|
161
178
|
"italic": [
|
162
179
|
"./dist/prosekit-extensions-italic.d.ts"
|
163
180
|
],
|