@prosekit/extensions 0.4.1 → 0.4.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.
@@ -5,6 +5,7 @@ import { bundledLanguagesInfo } from 'shiki';
5
5
  import { BundledTheme } from 'shiki';
6
6
  import { BundledThemeInfo } from 'shiki';
7
7
  import { bundledThemesInfo } from 'shiki';
8
+ import { Command } from '@prosekit/pm/state';
8
9
  import { CommandArgs } from '@prosekit/core';
9
10
  import { DedentListOptions } from 'prosemirror-flat-list';
10
11
  import { EditorState } from '@prosekit/pm/state';
@@ -15,6 +16,7 @@ import { IndentListOptions } from 'prosemirror-flat-list';
15
16
  import { InputRule } from '@prosekit/pm/inputrules';
16
17
  import { ListAttributes } from 'prosemirror-flat-list';
17
18
  import { ListDOMSerializer } from 'prosemirror-flat-list';
19
+ import { MarkType } from '@prosekit/pm/model';
18
20
  import { NodeRange } from 'prosemirror-model';
19
21
  import { NodeType } from '@prosekit/pm/model';
20
22
  import { Options } from 'tsup';
@@ -27,6 +29,8 @@ import { ToggleCollapsedOptions } from 'prosemirror-flat-list';
27
29
  import { Transaction } from '@prosekit/pm/state';
28
30
  import { UnwrapListOptions } from 'prosemirror-flat-list';
29
31
 
32
+ export declare function applyMarkRules(rules: MarkRule[], transactions: readonly Transaction[], oldState: EditorState, newState: EditorState): Transaction | null;
33
+
30
34
  declare class AutocompleteRule {
31
35
  readonly regex: RegExp;
32
36
  readonly onMatch: MatchHandler;
@@ -64,6 +68,12 @@ export { BundledThemeInfo as ShikiBundledThemeInfo_alias_1 }
64
68
  export { bundledThemesInfo as shikiBundledThemesInfo }
65
69
  export { bundledThemesInfo as shikiBundledThemesInfo_alias_1 }
66
70
 
71
+ export declare interface CellAttrs {
72
+ colspan: number;
73
+ rowspan: number;
74
+ colwidth: number[] | null;
75
+ }
76
+
67
77
  /**
68
78
  * The attributes for the `codeBlock` node.
69
79
  *
@@ -405,10 +415,21 @@ expandLink: [];
405
415
  };
406
416
  }>;
407
417
 
418
+ /**
419
+ * Apply link marks after typing Enter.
420
+ */
408
421
  export declare function defineLinkEnterRule(): Extension<ExtensionTyping<string, string, CommandArgs>>;
409
422
 
423
+ /**
424
+ * Apply link marks after pressing Space.
425
+ */
410
426
  export declare function defineLinkInputRule(): Extension<ExtensionTyping<string, string, CommandArgs>>;
411
427
 
428
+ /**
429
+ * Apply and remove link marks to the text during typing.
430
+ */
431
+ export declare function defineLinkMarkRule(): Extension<ExtensionTyping<string, string, CommandArgs>>;
432
+
412
433
  export declare function defineLinkSpec(): Extension< {
413
434
  MARKS: "link";
414
435
  }>;
@@ -460,6 +481,12 @@ export declare function defineListSpec(): Extension<{
460
481
  NODES: "list";
461
482
  }>;
462
483
 
484
+ /**
485
+ * A mark rule is something that can automatically apply marks to text if it
486
+ * matches a certain pattern, and remove them if it doesn't match anymore.
487
+ */
488
+ export declare function defineMarkRule(options: MarkRuleOptions): Extension<ExtensionTyping<string, string, CommandArgs>>;
489
+
463
490
  /**
464
491
  * @public
465
492
  */
@@ -516,6 +543,70 @@ export declare function defineStrikeSpec(): Extension< {
516
543
  MARKS: "strike";
517
544
  }>;
518
545
 
546
+ /**
547
+ * @public
548
+ */
549
+ export declare function defineTable(): Extension< {
550
+ NODES: "table" | "tableRow" | "tableCell" | "tableHeaderCell";
551
+ COMMAND_ARGS: {
552
+ insertTable: [{
553
+ row: number;
554
+ col: number;
555
+ header: boolean;
556
+ }];
557
+ exitTable: [];
558
+ };
559
+ }>;
560
+
561
+ declare function defineTableCellSpec(): Extension< {
562
+ NODES: "tableCell";
563
+ }>;
564
+ export { defineTableCellSpec }
565
+ export { defineTableCellSpec as defineTableCellSpec_alias_1 }
566
+
567
+ /**
568
+ * Adds commands for working with `table` nodes.
569
+ *
570
+ * @public
571
+ */
572
+ declare function defineTableCommands(): Extension< {
573
+ COMMAND_ARGS: {
574
+ insertTable: [{
575
+ row: number;
576
+ col: number;
577
+ header: boolean;
578
+ }];
579
+ exitTable: [];
580
+ };
581
+ }>;
582
+ export { defineTableCommands }
583
+ export { defineTableCommands as defineTableCommands_alias_1 }
584
+
585
+ declare function defineTableHeaderCellSpec(): Extension< {
586
+ NODES: "tableHeaderCell";
587
+ }>;
588
+ export { defineTableHeaderCellSpec }
589
+ export { defineTableHeaderCellSpec as defineTableHeaderCellSpec_alias_1 }
590
+
591
+ /**
592
+ * @public
593
+ */
594
+ declare function defineTablePlugins(): Extension<ExtensionTyping<string, string, CommandArgs>>;
595
+ export { defineTablePlugins }
596
+ export { defineTablePlugins as defineTablePlugins_alias_1 }
597
+
598
+ declare function defineTableRowSpec(): Extension< {
599
+ NODES: "tableRow";
600
+ }>;
601
+ export { defineTableRowSpec }
602
+ export { defineTableRowSpec as defineTableRowSpec_alias_1 }
603
+
604
+ declare function defineTableSpec(): Extension< {
605
+ NODES: "table";
606
+ }>;
607
+ export { defineTableSpec }
608
+ export { defineTableSpec as defineTableSpec_alias_1 }
609
+
519
610
  /**
520
611
  * Defines an enter rule that replaces the matched text with a block node.
521
612
  *
@@ -679,6 +770,16 @@ export declare type EnterRuleOptions = {
679
770
  stop?: boolean;
680
771
  };
681
772
 
773
+ /**
774
+ * When the selection is in a table node, create a default block after the table
775
+ * table, and move the cursor there.
776
+ *
777
+ * @public
778
+ */
779
+ export declare const exitTable: Command;
780
+
781
+ export declare function getCheckRanges(transactions: readonly Transaction[], oldState: EditorState, newState: EditorState): Array<[number, number]>;
782
+
682
783
  export { getHighlighter }
683
784
 
684
785
  export declare function getPluginState(state: EditorState): PredictionPluginState | undefined;
@@ -708,9 +809,23 @@ export declare interface ImageAttrs {
708
809
  src?: string | null;
709
810
  }
710
811
 
711
- export declare const LINK_RE: RegExp;
812
+ /**
813
+ * Insert a table node with the given number of rows and columns, and optionally
814
+ * a header row.
815
+ *
816
+ * @public
817
+ */
818
+ export declare function insertTable({ row, col, header, }: {
819
+ row: number;
820
+ col: number;
821
+ header: boolean;
822
+ }): Command;
823
+
824
+ export declare const LINK_ENTER_RE: RegExp;
825
+
826
+ export declare const LINK_INPUT_RE: RegExp;
712
827
 
713
- export declare const LINK_SPACE_RE: RegExp;
828
+ export declare const LINK_MARK_RE: RegExp;
714
829
 
715
830
  /**
716
831
  * @public
@@ -721,6 +836,42 @@ export declare interface LinkAttrs {
721
836
 
722
837
  export { ListDOMSerializer }
723
838
 
839
+ /**
840
+ * @internal
841
+ */
842
+ export declare class MarkRule {
843
+ readonly regex: RegExp;
844
+ readonly type: string | MarkType;
845
+ readonly getAttrs: (match: RegExpMatchArray) => Attrs | null;
846
+ constructor({ regex, type, attrs }: MarkRuleOptions);
847
+ }
848
+
849
+ /**
850
+ * The options for {@link defineMarkRule}.
851
+ *
852
+ * @public
853
+ */
854
+ declare interface MarkRuleOptions {
855
+ /**
856
+ * The regular expression to match against. It must has a `g` flag to match
857
+ * all instances of the mark.
858
+ */
859
+ regex: RegExp;
860
+ /**
861
+ * The mark type to apply to the matched text.
862
+ */
863
+ type: string | MarkType;
864
+ /**
865
+ * Attributes to set on the mark. If a function is provided, it will be called
866
+ * with the matched result from the regular expression.
867
+ *
868
+ * @default null
869
+ */
870
+ attrs?: Attrs | null | ((match: RegExpMatchArray) => Attrs | null);
871
+ }
872
+ export { MarkRuleOptions }
873
+ export { MarkRuleOptions as MarkRuleOptions_alias_1 }
874
+
724
875
  declare type MatchHandler = (options: {
725
876
  state: EditorState;
726
877
  match: RegExpExecArray;
@@ -0,0 +1,185 @@
1
+ // src/mark-rule/index.ts
2
+ import { Facet, pluginFacet } from "@prosekit/core";
3
+ import { ProseMirrorPlugin } from "@prosekit/pm/state";
4
+
5
+ // src/mark-rule/apply.ts
6
+ import { OBJECT_REPLACEMENT_CHARACTER, getMarkType } from "@prosekit/core";
7
+ import "@prosekit/pm/model";
8
+ import "@prosekit/pm/state";
9
+
10
+ // src/mark-rule/range.ts
11
+ import "@prosekit/pm/state";
12
+ function getSpanTextRanges($from, $to) {
13
+ const nodeRange = $from.blockRange($to);
14
+ if (!nodeRange) {
15
+ return [];
16
+ }
17
+ const stack = [];
18
+ let start = nodeRange.start;
19
+ for (let i = nodeRange.startIndex; i < nodeRange.endIndex; i++) {
20
+ const child = nodeRange.parent.child(i);
21
+ stack.push([start, child]);
22
+ start += child.nodeSize;
23
+ }
24
+ const ranges = [];
25
+ while (stack.length > 0) {
26
+ const [start2, node] = stack.pop();
27
+ if (node.type.spec.code) {
28
+ continue;
29
+ }
30
+ if (node.type.isTextblock) {
31
+ ranges.push([start2 + 1, start2 + 1 + node.content.size]);
32
+ continue;
33
+ }
34
+ node.forEach((child, offset) => {
35
+ stack.push([start2 + offset + 1, child]);
36
+ });
37
+ }
38
+ return ranges;
39
+ }
40
+ function getInlineTextRange($from, $to) {
41
+ return [$from.start(), $to.end()];
42
+ }
43
+ function getTextRanges(doc, from, to) {
44
+ const $from = doc.resolve(from);
45
+ const $to = doc.resolve(to);
46
+ if ($from.sameParent($to) && $from.parent.isTextblock) {
47
+ return [getInlineTextRange($from, $to)];
48
+ } else {
49
+ const nodeRange = $from.blockRange($to);
50
+ if (!nodeRange) {
51
+ return [];
52
+ }
53
+ return getSpanTextRanges($from, $to);
54
+ }
55
+ }
56
+ function getMapRange(transactions, oldState, newState) {
57
+ let lo = oldState.selection.from;
58
+ let hi = oldState.selection.to;
59
+ for (const tr of transactions) {
60
+ for (const map of tr.mapping.maps) {
61
+ lo = map.map(lo);
62
+ hi = map.map(hi);
63
+ map.forEach((_oldStart, _oldEnd, newStart, newEnd) => {
64
+ lo = Math.min(lo, hi, newStart);
65
+ hi = Math.max(hi, hi, newEnd);
66
+ });
67
+ }
68
+ }
69
+ lo = Math.min(lo, hi, newState.selection.from);
70
+ hi = Math.min(lo, hi, newState.selection.to);
71
+ return [lo, hi];
72
+ }
73
+ function getCheckRanges(transactions, oldState, newState) {
74
+ const [from, to] = getMapRange(transactions, oldState, newState);
75
+ return getTextRanges(newState.doc, from, to);
76
+ }
77
+
78
+ // src/mark-rule/apply.ts
79
+ function getExpectedMarkings(rules, doc, from, to) {
80
+ const text = doc.textBetween(from, to, OBJECT_REPLACEMENT_CHARACTER);
81
+ const result = [];
82
+ for (const rule of rules) {
83
+ rule.regex.lastIndex = 0;
84
+ const matches = text.matchAll(rule.regex);
85
+ const markType = getMarkType(doc.type.schema, rule.type);
86
+ for (const match of matches) {
87
+ const index = match.index;
88
+ if (index == null)
89
+ continue;
90
+ const attrs = rule.getAttrs(match);
91
+ const mark = markType.create(attrs);
92
+ result.push([mark, from + index, from + index + match[0].length]);
93
+ }
94
+ }
95
+ return result;
96
+ }
97
+ function getReceivedMarkings(rules, doc, from, to) {
98
+ const result = [];
99
+ const schema = doc.type.schema;
100
+ const markTypes = rules.map((rule) => getMarkType(schema, rule.type));
101
+ doc.nodesBetween(from, to, (node, pos) => {
102
+ if (!node.isInline) {
103
+ return;
104
+ }
105
+ for (const markType of markTypes) {
106
+ const mark = node.marks.find((mark2) => mark2.type === markType);
107
+ if (mark) {
108
+ result.push([mark, pos, pos + node.nodeSize]);
109
+ }
110
+ }
111
+ });
112
+ return result;
113
+ }
114
+ function markingEquals(a, b) {
115
+ return a[1] === b[1] && a[2] === b[2] && a[0].eq(b[0]);
116
+ }
117
+ function markingDiffs(a, b) {
118
+ return a.filter((x) => !b.some((y) => markingEquals(x, y)));
119
+ }
120
+ function applyMarkRules(rules, transactions, oldState, newState) {
121
+ if (transactions.length === 0 || transactions.every((tr2) => !tr2.docChanged)) {
122
+ return null;
123
+ }
124
+ const ranges = getCheckRanges(transactions, oldState, newState);
125
+ const toRemove = [];
126
+ const toCreate = [];
127
+ for (const [from, to] of ranges) {
128
+ const expected = getExpectedMarkings(rules, newState.doc, from, to);
129
+ const received = getReceivedMarkings(rules, newState.doc, from, to);
130
+ toRemove.push(...markingDiffs(received, expected));
131
+ toCreate.push(...markingDiffs(expected, received));
132
+ }
133
+ if (toCreate.length === 0 && toRemove.length === 0) {
134
+ return null;
135
+ }
136
+ const tr = newState.tr;
137
+ for (const [mark, from, to] of toRemove) {
138
+ tr.removeMark(from, to, mark);
139
+ }
140
+ for (const [mark, from, to] of toCreate) {
141
+ tr.addMark(from, to, mark);
142
+ }
143
+ return tr;
144
+ }
145
+
146
+ // src/mark-rule/rule.ts
147
+ import "@prosekit/pm/model";
148
+ var MarkRule = class {
149
+ constructor({ regex, type, attrs = null }) {
150
+ this.regex = regex;
151
+ this.type = type;
152
+ this.getAttrs = typeof attrs === "function" ? attrs : () => attrs;
153
+ }
154
+ };
155
+
156
+ // src/mark-rule/index.ts
157
+ function defineMarkRule(options) {
158
+ return markRuleFacet.extension([new MarkRule(options)]);
159
+ }
160
+ var markRuleFacet = Facet.define({
161
+ converter: () => {
162
+ let rules = [];
163
+ const plugin = new ProseMirrorPlugin({
164
+ appendTransaction: (transactions, oldState, newState) => {
165
+ return applyMarkRules(rules, transactions, oldState, newState);
166
+ }
167
+ });
168
+ const pluginFunc = () => [plugin];
169
+ return {
170
+ create: (inputs) => {
171
+ rules = inputs;
172
+ return pluginFunc;
173
+ },
174
+ update: (inputs) => {
175
+ rules = inputs;
176
+ return null;
177
+ }
178
+ };
179
+ },
180
+ next: pluginFacet
181
+ });
182
+
183
+ export {
184
+ defineMarkRule
185
+ };
@@ -1,4 +1,4 @@
1
- /* ../../node_modules/.pnpm/prosemirror-flat-list@0.4.6/node_modules/prosemirror-flat-list/dist/style.css */
1
+ /* ../../node_modules/.pnpm/prosemirror-flat-list@0.5.0/node_modules/prosemirror-flat-list/dist/style.css */
2
2
  .prosemirror-flat-list {
3
3
  padding: 0;
4
4
  margin-top: 0;
@@ -1,9 +1,9 @@
1
- import {
2
- defineTextBlockInputRule
3
- } from "./chunk-DYFRBXUX.js";
4
1
  import {
5
2
  defineTextBlockEnterRule
6
3
  } from "./chunk-ASTUC4KT.js";
4
+ import {
5
+ defineTextBlockInputRule
6
+ } from "./chunk-DYFRBXUX.js";
7
7
 
8
8
  // src/code-block/code-block.ts
9
9
  import { union } from "@prosekit/core";
@@ -2,5 +2,6 @@ export { defineLinkSpec } from './_tsup-dts-rollup';
2
2
  export { defineLinkCommands } from './_tsup-dts-rollup';
3
3
  export { defineLinkInputRule } from './_tsup-dts-rollup';
4
4
  export { defineLinkEnterRule } from './_tsup-dts-rollup';
5
+ export { defineLinkMarkRule } from './_tsup-dts-rollup';
5
6
  export { defineLink } from './_tsup-dts-rollup';
6
7
  export { LinkAttrs } from './_tsup-dts-rollup';
@@ -1,9 +1,12 @@
1
1
  import {
2
- defineInputRule
3
- } from "./chunk-DYFRBXUX.js";
2
+ defineMarkRule
3
+ } from "./chunk-TXF4SPMB.js";
4
4
  import {
5
5
  defineEnterRule
6
6
  } from "./chunk-ASTUC4KT.js";
7
+ import {
8
+ defineInputRule
9
+ } from "./chunk-DYFRBXUX.js";
7
10
 
8
11
  // src/link/index.ts
9
12
  import {
@@ -19,15 +22,19 @@ import { InputRule } from "@prosekit/pm/inputrules";
19
22
 
20
23
  // src/link/link-regex.ts
21
24
  var TLD_RE_PATTERN = "a(?:a(?:a|rp)|b(?:arth|b(?:ott|vie)?|c|le|ogado|udhabi)|c(?:ademy|c(?:enture|ountants?)|o|tor)?|d(?:s|ult)?|e(?:g|ro|tna)?|f(?:l|rica)?|g(?:akhan|ency)?|i(?:g|r(?:bus|force|tel))?|kdn|l(?:faromeo|i(?:baba|pay)|l(?:finanz|state|y)|s(?:ace|tom))?|m(?:azon|e(?:rican(?:express|family)|x)|fam|ica|sterdam)?|n(?:alytics|droid|quan|z)|ol?|p(?:artments|p(?:le)?)|q(?:uarelle)?|r(?:a(?:b|mco)|chi|my|pa|te?)?|s(?:da|ia|sociates)?|t(?:hleta|torney)?|u(?:ction|di(?:ble|o)?|spost|t(?:hor|os?))?|vianca|ws?|xa?|z(?:ure)?)|b(?:a(?:by|idu|n(?:a(?:mex|narepublic)|d|k)|r(?:c(?:elona|lay(?:card|s))|efoot|gains)?|s(?:eball|ketball)|uhaus|yern)?|b(?:c|t|va)?|c[gn]|d|e(?:a(?:ts|uty)|er|ntley|rlin|st(?:buy)?|t)?|f|g|h(?:arti)?|i(?:ble|d|ke|ngo?|o|z)?|j|l(?:ack(?:friday)?|o(?:ckbuster|g|omberg)|ue)|m[sw]?|n(?:pparibas)?|o(?:ats|ehringer|fa|m|nd|o(?:k(?:ing)?)?|s(?:ch|t(?:ik|on))|t|utique|x)?|r(?:adesco|idgestone|o(?:adway|ker|ther)|ussels)?|s|t|u(?:ild(?:ers)?|siness|y|zz)|v|w|y|zh?)|c(?:a(?:b|fe|l(?:l|vinklein)?|m(?:era|p)?|non|p(?:etown|ital(?:one)?)|r(?:avan|ds|e(?:ers?)?|s)?|s(?:a|e|h|ino)|t(?:ering|holic)?)?|b(?:a|n|re|s)|c|d|e(?:nter|o|rn)|f[ad]?|g|h(?:a(?:n(?:el|nel)|rity|se|t)|eap|intai|r(?:istmas|ome)|urch)?|i(?:priani|rcle|sco|t(?:adel|ic?|y(?:eats)?))?|k|l(?:aims|eaning|i(?:ck|ni(?:c|que))|o(?:thing|ud)|ub(?:med)?)?|m|n|o(?:ach|des|ffee|l(?:lege|ogne)|m(?:cast|m(?:bank|unity)|p(?:a(?:ny|re)|uter)|sec)?|n(?:dos|s(?:truction|ulting)|t(?:act|ractors))|o(?:king(?:channel)?|l|p)|rsica|u(?:ntry|pons?|rses))?|pa|r(?:edit(?:card|union)?|icket|own|s|uises?)?|u(?:isinella)?|v|w|x|y(?:mru|ou)?|z)|d(?:a(?:bur|d|nce|t(?:a|e|ing|sun)|y)|clk|ds|e(?:al(?:er|s)?|gree|l(?:ivery|l|oitte|ta)|mocrat|nt(?:al|ist)|si(?:gn)?|v)?|hl|i(?:amonds|et|gital|rect(?:ory)?|s(?:co(?:unt|ver)|h)|y)|j|k|m|np|o(?:c(?:s|tor)|g|mains|t|wnload)?|rive|tv|u(?:bai|nlop|pont|rban)|v(?:ag|r)|z)|e(?:a(?:rth|t)|co?|d(?:eka|u(?:cation)?)|e|g|m(?:ail|erck)|n(?:ergy|gineer(?:ing)?|terprises)|pson|quipment|r(?:icsson|ni)?|s(?:q|tate)?|t(?:isalat)?|u(?:rovision|s)?|vents|x(?:change|p(?:ert|osed|ress)|traspace))|f(?:a(?:ge|i(?:l|rwinds|th)|mily|ns?|rm(?:ers)?|s(?:hion|t))|e(?:dex|edback|rr(?:ari|ero))|i(?:at|d(?:elity|o)|lm|na(?:l|nc(?:e|ial))|r(?:e(?:stone)?|mdale)|sh(?:ing)?|t(?:ness)?)?|j|k|l(?:i(?:ckr|ghts|r)|o(?:rist|wers)|y)|m|o(?:o(?:d(?:network)?|tball)?|r(?:d|ex|sale|um)|undation|x)?|r(?:e(?:e|senius)|l|o(?:gans|nt(?:door|ier)))?|tr|u(?:jitsu|nd?|rniture|tbol)|yi)|g(?:a(?:l(?:l(?:ery|o|up))?|mes?|p|rden|y)?|b(?:iz)?|dn?|e(?:a|nt(?:ing)?|orge)?|f|g(?:ee)?|h|i(?:fts?|v(?:es|ing))?|l(?:ass|e|ob(?:al|o))?|m(?:ail|bh|o|x)?|n|o(?:daddy|l(?:d(?:point)?|f)|o(?:dyear|g(?:le)?)?|p|t|v)|p|q|r(?:a(?:inger|phics|tis)|een|ipe|o(?:cery|up))?|s|t|u(?:ardian|cci|ge|i(?:de|tars)|ru)?|w|y)|h(?:a(?:ir|mburg|ngout|us)|bo|dfc(?:bank)?|e(?:alth(?:care)?|l(?:p|sinki)|r(?:e|mes))|gtv|i(?:phop|samitsu|tachi|v)|kt?|m|n|o(?:ckey|l(?:dings|iday)|me(?:depot|goods|s(?:ense)?)|nda|rse|s(?:pital|t(?:ing)?)|t(?:el(?:es|s)|mail)?|use|w)|r|sbc|t|u(?:ghes)?|y(?:att|undai))|i(?:bm|c(?:bc|e|u)|d|e(?:ee)?|fm|kano|l|m(?:amat|db|mo(?:bilien)?)?|n(?:c|dustries|f(?:initi|o)|g|k|s(?:titute|ur(?:ance|e))|t(?:ernational|uit)?|vestments)?|o|piranga|q|r(?:ish)?|s(?:maili|t(?:anbul)?)?|t(?:au|v)?)|j(?:a(?:guar|va)|cb|e(?:ep|tzt|welry)?|io|ll|mp?|nj|o(?:b(?:s|urg)|t|y)?|p(?:morgan|rs)?|u(?:egos|niper))|k(?:aufen|ddi|e(?:rry(?:hotels|logistics|properties))?|fh|g|h|i(?:a|ds|m|nd(?:er|le)|tchen|wi)?|m|n|o(?:eln|matsu|sher)|p(?:mg|n)?|r(?:d|ed)?|uokgroup|w|y(?:oto)?|z)|l(?:a(?:caixa|m(?:borghini|er)|n(?:c(?:aster|ia)|d(?:rover)?|xess)|salle|t(?:ino|robe)?|w(?:yer)?)?|b|c|ds|e(?:ase|clerc|frak|g(?:al|o)|xus)|gbt|i(?:dl|fe(?:insurance|style)?|ghting|ke|lly|m(?:ited|o)|n(?:coln|de|k)|psy|v(?:e|ing))?|k|l[cp]|o(?:ans?|c(?:ker|us)|l|ndon|tt[eo]|ve)|pl(?:financial)?|r|s|t(?:da?)?|u(?:ndbeck|x(?:e|ury))?|v|y)|m(?:a(?:cys|drid|i(?:f|son)|keup|n(?:agement|go)?|p|r(?:ket(?:ing|s)?|riott|shalls)|serati|ttel)?|ba|c(?:kinsey)?|d|e(?:d(?:ia)?|et|lbourne|m(?:e|orial)|nu?|rckmsd)?|g|h|i(?:ami|crosoft|l|n[it]|t(?:subishi)?)|k|l[bs]?|ma?|n|o(?:bi(?:le)?|da|e|i|m|n(?:ash|ey|ster)|r(?:mon|tgage)|scow|to(?:rcycles)?|v(?:ie)?)?|p|q|r|sd?|t[nr]?|u(?:s(?:eum|ic)|tual)?|v|w|x|y|z)|n(?:a(?:b|goya|me|tura|vy)?|ba|c|e(?:c|t(?:bank|flix|work)?|ustar|ws?|x(?:t(?:direct)?|us))?|fl?|go?|hk|i(?:co|k(?:e|on)|nja|ssa[ny])?|l|o(?:kia|rt(?:hwesternmutual|on)|w(?:ruz|tv)?)?|p|r[aw]?|tt|u|yc|z)|o(?:b(?:i|server)|ffice|kinawa|l(?:ayan(?:group)?|dnavy|lo)|m(?:ega)?|n(?:e|g|l(?:ine)?)|oo|pen|r(?:a(?:cle|nge)|g(?:anic)?|igins)|saka|t(?:suka|t)|vh)|p(?:a(?:ge|nasonic|r(?:is|s|t(?:ners|s|y))|ssagens|y)?|ccw|et?|f(?:izer)?|g|h(?:armacy|d|ilips|o(?:ne|to(?:graphy|s)?)|ysio)?|i(?:c(?:s|t(?:et|ures))|d|n[gk]?|oneer|zza)|k|l(?:a(?:ce|y(?:station)?)|u(?:mbing|s))?|m|nc?|o(?:hl|ker|litie|rn|st)|r(?:a(?:merica|xi)|ess|ime|o(?:d(?:uctions)?|f|gressive|mo|pert(?:ies|y)|tection)?|u(?:dential)?)?|s|t|ub|wc?|y)|q(?:a|pon|ue(?:bec|st))|r(?:a(?:cing|dio)|e(?:a(?:d|l(?:estate|t(?:or|y)))|cipes|d(?:stone|umbrella)?|hab|i(?:sen?|t)|liance|n(?:t(?:als)?)?|p(?:air|ort|ublican)|st(?:aurant)?|views?|xroth)?|i(?:c(?:h(?:ardli)?|oh)|l|o|p)|o(?:c(?:her|ks)|deo|gers|om)?|s(?:vp)?|u(?:gby|hr|n)?|we?|yukyu)|s(?:a(?:arland|fe(?:ty)?|kura|l(?:e|on)|ms(?:club|ung)|n(?:dvik(?:coromant)?|ofi)|p|rl|s|ve|xo)?|b[is]?|c(?:a|b|h(?:aeffler|midt|o(?:larships|ol)|ule|warz)|ience|ot)?|d|e(?:a(?:rch|t)|cur(?:e|ity)|ek|lect|ner|rvices|ven|w|xy?)?|fr|g|h(?:a(?:ngrila|rp|w)|ell|i(?:a|ksha)|o(?:es|p(?:ping)?|uji|w(?:time)?))?|i(?:lk|n(?:a|gles)|te)?|j|k(?:in?|y(?:pe)?)?|l(?:ing)?|m(?:art|ile)?|n(?:cf)?|o(?:c(?:cer|ial)|ft(?:bank|ware)|hu|l(?:ar|utions)|n[gy]|y)?|p(?:a(?:ce)?|o(?:rt|t))|rl?|s|t(?:a(?:da|ples|r|te(?:bank|farm))|c(?:group)?|o(?:ckholm|r(?:age|e))|ream|ud(?:io|y)|yle)?|u(?:cks|pp(?:l(?:ies|y)|ort)|r(?:f|gery)|zuki)?|v|w(?:atch|iss)|x|y(?:dney|stems)?|z)|t(?:a(?:b|ipei|lk|obao|rget|t(?:a(?:motors|r)|too)|xi?)|ci?|dk?|e(?:am|ch(?:nology)?|l|masek|nnis|va)|f|g|h(?:d|eat(?:er|re))?|i(?:aa|ckets|enda|ffany|ps|r(?:es|ol))|j(?:maxx|x)?|k(?:maxx)?|l|m(?:all)?|n|o(?:day|kyo|ols|p|ray|shiba|tal|urs|wn|y(?:ota|s))?|r(?:a(?:d(?:e|ing)|ining|vel(?:channel|ers(?:insurance)?)?)|ust|v)?|t|u(?:be|i|nes|shu)|vs?|w|z)|u(?:a|b(?:ank|s)|g|k|n(?:i(?:com|versity)|o)|ol|ps|s|y|z)|v(?:a(?:cations|n(?:a|guard))?|c|e(?:gas|ntures|r(?:isign|sicherung)|t)?|g|i(?:ajes|deo|g|king|llas|n|p|rgin|s(?:a|ion)|v[ao])?|laanderen|n|o(?:dka|l(?:kswagen|vo)|t(?:e|ing|o)|yage)|u(?:elos)?)|w(?:a(?:l(?:es|mart|ter)|ng(?:gou)?|tch(?:es)?)|e(?:ather(?:channel)?|b(?:cam|er|site)|d(?:ding)?|i(?:bo|r))|f|hoswho|i(?:en|ki|lliamhill|n(?:dows|e|ners)?)|me|o(?:lterskluwer|odside|r(?:ks?|ld)|w)|s|t[cf])|x(?:box|erox|finity|i(?:huan|n)|xx|yz)|y(?:a(?:chts|hoo|maxun|ndex)|e|o(?:dobashi|ga|kohama|u(?:tube)?)|t|un)|z(?:a(?:ppos|ra)?|ero|ip|m|one|uerich|w)";
25
+ var PUNCTUATION_CHAR_PATTERN = "\\.\\,\\;\\!\\?";
26
+ var STOP_CHAR_PATTERN = "[" + PUNCTUATION_CHAR_PATTERN + "]";
27
+ var END_CHAR_PATTERN = "[^\\s" + PUNCTUATION_CHAR_PATTERN + "]";
22
28
  var LINK_RE_BASE_PATTERN = (
23
29
  // start of the link group
24
- "((?:(?:(?:https?:)?\\/\\/)?(?:(?:[a-z0-9\\u00a1-\\uffff][a-z0-9\\u00a1-\\uffff_-]{0,62})?[a-z0-9\\u00a1-\\uffff]\\.)+(?:" + TLD_RE_PATTERN + "))(?::\\d{2,5})?(?:[/?#]\\S*)?)"
30
+ "((?:(?:(?:https?:)?\\/\\/)?(?:(?:[a-z0-9\\u00a1-\\uffff][a-z0-9\\u00a1-\\uffff_-]{0,62})?[a-z0-9\\u00a1-\\uffff]\\.)+(?:" + TLD_RE_PATTERN + "))(?::\\d{2,5})?(?:/(?:\\S*" + END_CHAR_PATTERN + ")?)?(?:\\?(?:\\S*" + END_CHAR_PATTERN + "))?(?:\\#(?:\\S*" + END_CHAR_PATTERN + ")?)?)"
25
31
  );
26
- var LINK_STOP_PATTERN = "(?:\\.|\\,|\\;\\!)?";
27
- var LINK_RE_PATTERN = LINK_RE_BASE_PATTERN + LINK_STOP_PATTERN + "$";
28
- var LINK_SPACE_RE_PATTERN = LINK_RE_BASE_PATTERN + LINK_STOP_PATTERN + "\\s$";
29
- var LINK_RE = new RegExp(LINK_RE_PATTERN, "gi");
30
- var LINK_SPACE_RE = new RegExp(LINK_SPACE_RE_PATTERN, "gi");
32
+ var LINK_ENTER_PATTERN = LINK_RE_BASE_PATTERN + STOP_CHAR_PATTERN + "?$";
33
+ var LINK_INPUT_PATTERN = LINK_RE_BASE_PATTERN + STOP_CHAR_PATTERN + "?\\s$";
34
+ var LINK_MARK_PATTERN = LINK_RE_BASE_PATTERN + "(?=" + STOP_CHAR_PATTERN + "|\\s|$)";
35
+ var LINK_ENTER_RE = new RegExp(LINK_ENTER_PATTERN, "gi");
36
+ var LINK_INPUT_RE = new RegExp(LINK_INPUT_PATTERN, "gi");
37
+ var LINK_MARK_RE = new RegExp(LINK_MARK_PATTERN, "gi");
31
38
 
32
39
  // src/link/index.ts
33
40
  function defineLinkSpec() {
@@ -63,7 +70,7 @@ function defineLinkCommands() {
63
70
  }
64
71
  function defineLinkInputRule() {
65
72
  return defineInputRule(
66
- new InputRule(LINK_SPACE_RE, (state, match, from) => {
73
+ new InputRule(LINK_INPUT_RE, (state, match, from) => {
67
74
  const href = match[1];
68
75
  if (!href)
69
76
  return null;
@@ -74,7 +81,7 @@ function defineLinkInputRule() {
74
81
  }
75
82
  function defineLinkEnterRule() {
76
83
  return defineEnterRule({
77
- regex: LINK_RE,
84
+ regex: LINK_ENTER_RE,
78
85
  handler: ({ state, from, match }) => {
79
86
  const href = match[1];
80
87
  if (!href)
@@ -85,6 +92,13 @@ function defineLinkEnterRule() {
85
92
  }
86
93
  });
87
94
  }
95
+ function defineLinkMarkRule() {
96
+ return defineMarkRule({
97
+ regex: LINK_MARK_RE,
98
+ type: "link",
99
+ attrs: (match) => ({ href: match[1] })
100
+ });
101
+ }
88
102
  function defineLink() {
89
103
  return union([
90
104
  defineLinkSpec(),
@@ -98,5 +112,6 @@ export {
98
112
  defineLinkCommands,
99
113
  defineLinkEnterRule,
100
114
  defineLinkInputRule,
115
+ defineLinkMarkRule,
101
116
  defineLinkSpec
102
117
  };
@@ -0,0 +1,2 @@
1
+ export { defineMarkRule } from './_tsup-dts-rollup';
2
+ export { MarkRuleOptions } from './_tsup-dts-rollup';
@@ -0,0 +1,6 @@
1
+ import {
2
+ defineMarkRule
3
+ } from "./chunk-TXF4SPMB.js";
4
+ export {
5
+ defineMarkRule
6
+ };
@@ -0,0 +1,7 @@
1
+ export { defineTable } from './_tsup-dts-rollup';
2
+ export { defineTableCellSpec } from './_tsup-dts-rollup';
3
+ export { defineTableCommands } from './_tsup-dts-rollup';
4
+ export { defineTableHeaderCellSpec } from './_tsup-dts-rollup';
5
+ export { defineTablePlugins } from './_tsup-dts-rollup';
6
+ export { defineTableRowSpec } from './_tsup-dts-rollup';
7
+ export { defineTableSpec } from './_tsup-dts-rollup';
@@ -0,0 +1,197 @@
1
+ // src/table/index.ts
2
+ import { union } from "@prosekit/core";
3
+
4
+ // src/table/table-commands.ts
5
+ import {
6
+ defaultBlockAt,
7
+ defineCommands,
8
+ getNodeType,
9
+ insertNode
10
+ } from "@prosekit/core";
11
+ import { TextSelection } from "@prosekit/pm/state";
12
+ function createEmptyTable(schema, row, col, header) {
13
+ const table = getNodeType(schema, "table");
14
+ const tableRow = getNodeType(schema, "tableRow");
15
+ const tableCell = getNodeType(schema, "tableCell");
16
+ const tableHeaderCell = getNodeType(schema, "tableHeaderCell");
17
+ const createHeaderRow = () => {
18
+ return tableRow.createAndFill(
19
+ null,
20
+ Array.from({ length: col }, () => tableHeaderCell.createAndFill())
21
+ );
22
+ };
23
+ const createBodyRow = () => {
24
+ return tableRow.createAndFill(
25
+ null,
26
+ Array.from({ length: col }, () => tableCell.createAndFill())
27
+ );
28
+ };
29
+ const rows = [
30
+ ...Array.from({ length: header ? 1 : 0 }, createHeaderRow),
31
+ ...Array.from({ length: header ? row - 1 : row }, createBodyRow)
32
+ ];
33
+ return table.createAndFill(null, rows);
34
+ }
35
+ function insertTable({
36
+ row,
37
+ col,
38
+ header
39
+ }) {
40
+ return (state, dispatch, view) => {
41
+ const table = createEmptyTable(state.schema, row, col, header);
42
+ return insertNode({ node: table })(state, dispatch, view);
43
+ };
44
+ }
45
+ var exitTable = (state, dispatch) => {
46
+ const { $head, $anchor } = state.selection;
47
+ if (!$head.sameParent($anchor)) {
48
+ return false;
49
+ }
50
+ let tableStart = -1;
51
+ let tableDepth = -1;
52
+ for (let depth = $head.depth; depth >= 0; depth--) {
53
+ const node2 = $head.node(depth);
54
+ if (node2.type.spec.tableRole === "table") {
55
+ tableStart = $head.before(depth);
56
+ tableDepth = depth;
57
+ }
58
+ }
59
+ if (tableStart < 0 || tableDepth <= 0) {
60
+ return false;
61
+ }
62
+ const above = $head.node(tableDepth - 1);
63
+ const after = $head.indexAfter(tableDepth - 1);
64
+ const type = defaultBlockAt(above.contentMatchAt(after));
65
+ const node = type == null ? void 0 : type.createAndFill();
66
+ if (!type || !node || !above.canReplaceWith(after, after, type)) {
67
+ return false;
68
+ }
69
+ if (dispatch) {
70
+ const pos = $head.after(tableDepth);
71
+ const tr = state.tr.replaceWith(pos, pos, node);
72
+ tr.setSelection(TextSelection.near(tr.doc.resolve(pos), 1));
73
+ dispatch(tr.scrollIntoView());
74
+ }
75
+ return true;
76
+ };
77
+ function defineTableCommands() {
78
+ return defineCommands({
79
+ insertTable,
80
+ exitTable: () => exitTable
81
+ });
82
+ }
83
+
84
+ // src/table/table-plugins.ts
85
+ import { definePlugin } from "@prosekit/core";
86
+ import { tableEditing, columnResizing } from "prosemirror-tables";
87
+ function defineTablePlugins() {
88
+ return definePlugin([tableEditing(), columnResizing()]);
89
+ }
90
+
91
+ // src/table/table-spec.ts
92
+ import { defineNodeSpec } from "@prosekit/core";
93
+ import "prosemirror-tables";
94
+ var cellAttrs = {
95
+ colspan: { default: 1 },
96
+ rowspan: { default: 1 },
97
+ colwidth: { default: null }
98
+ };
99
+ var cellContent = "block+";
100
+ function getCellAttrs(dom) {
101
+ if (typeof dom === "string") {
102
+ return {};
103
+ }
104
+ const widthAttr = dom.getAttribute("data-colwidth");
105
+ const widths = widthAttr && /^\d+(,\d+)*$/.test(widthAttr) ? widthAttr.split(",").map((s) => Number(s)) : null;
106
+ const colspan = Number(dom.getAttribute("colspan") || 1);
107
+ return {
108
+ colspan,
109
+ rowspan: Number(dom.getAttribute("rowspan") || 1),
110
+ colwidth: widths && widths.length == colspan ? widths : null
111
+ };
112
+ }
113
+ function setCellAttrs(node) {
114
+ const pmAttrs = node.attrs;
115
+ const domAttrs = {};
116
+ if (pmAttrs.colspan !== 1) {
117
+ domAttrs.colspan = pmAttrs.colspan;
118
+ }
119
+ if (pmAttrs.rowspan !== 1) {
120
+ domAttrs.rowspan = pmAttrs.rowspan;
121
+ }
122
+ if (pmAttrs.colwidth) {
123
+ domAttrs["data-colwidth"] = pmAttrs.colwidth.join(",");
124
+ }
125
+ return domAttrs;
126
+ }
127
+ function defineTableSpec() {
128
+ return defineNodeSpec({
129
+ name: "table",
130
+ tableRole: "table",
131
+ content: "tableRow+",
132
+ isolating: true,
133
+ group: "block",
134
+ parseDOM: [{ tag: "table" }],
135
+ toDOM() {
136
+ return ["table", ["tbody", 0]];
137
+ }
138
+ });
139
+ }
140
+ function defineTableRowSpec() {
141
+ return defineNodeSpec({
142
+ name: "tableRow",
143
+ tableRole: "row",
144
+ content: "(tableCell | tableHeaderCell)*",
145
+ parseDOM: [{ tag: "tr" }],
146
+ toDOM() {
147
+ return ["tr", 0];
148
+ }
149
+ });
150
+ }
151
+ function defineTableCellSpec() {
152
+ return defineNodeSpec({
153
+ name: "tableCell",
154
+ tableRole: "cell",
155
+ content: cellContent,
156
+ attrs: cellAttrs,
157
+ isolating: true,
158
+ parseDOM: [{ tag: "td", getAttrs: (dom) => getCellAttrs(dom) }],
159
+ toDOM(node) {
160
+ return ["td", setCellAttrs(node), 0];
161
+ }
162
+ });
163
+ }
164
+ function defineTableHeaderCellSpec() {
165
+ return defineNodeSpec({
166
+ name: "tableHeaderCell",
167
+ tableRole: "header_cell",
168
+ content: cellContent,
169
+ attrs: cellAttrs,
170
+ isolating: true,
171
+ parseDOM: [{ tag: "th", getAttrs: (dom) => getCellAttrs(dom) }],
172
+ toDOM(node) {
173
+ return ["th", setCellAttrs(node), 0];
174
+ }
175
+ });
176
+ }
177
+
178
+ // src/table/index.ts
179
+ function defineTable() {
180
+ return union([
181
+ defineTableSpec(),
182
+ defineTableRowSpec(),
183
+ defineTableCellSpec(),
184
+ defineTableHeaderCellSpec(),
185
+ defineTablePlugins(),
186
+ defineTableCommands()
187
+ ]);
188
+ }
189
+ export {
190
+ defineTable,
191
+ defineTableCellSpec,
192
+ defineTableCommands,
193
+ defineTableHeaderCellSpec,
194
+ defineTablePlugins,
195
+ defineTableRowSpec,
196
+ defineTableSpec
197
+ };
@@ -0,0 +1,34 @@
1
+ /* src/table/style.css */
2
+ .ProseMirror .tableWrapper {
3
+ overflow-x: auto;
4
+ }
5
+ .ProseMirror table {
6
+ border-collapse: collapse;
7
+ table-layout: fixed;
8
+ width: 100%;
9
+ overflow: hidden;
10
+ }
11
+ .ProseMirror td,
12
+ .ProseMirror th {
13
+ vertical-align: top;
14
+ box-sizing: border-box;
15
+ position: relative;
16
+ border-width: 1px;
17
+ }
18
+ .ProseMirror .column-resize-handle {
19
+ position: absolute;
20
+ right: -2px;
21
+ top: 0;
22
+ bottom: 0;
23
+ width: 4px;
24
+ z-index: 20;
25
+ background-color: HighlightText;
26
+ pointer-events: none;
27
+ }
28
+ .ProseMirror.resize-cursor {
29
+ cursor: ew-resize;
30
+ cursor: col-resize;
31
+ }
32
+ .ProseMirror .selectedCell {
33
+ background-color: Highlight;
34
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@prosekit/extensions",
3
3
  "type": "module",
4
- "version": "0.4.1",
4
+ "version": "0.4.3",
5
5
  "private": false,
6
6
  "author": {
7
7
  "name": "ocavue",
@@ -30,6 +30,11 @@
30
30
  "import": "./dist/prosekit-extensions.js",
31
31
  "default": "./dist/prosekit-extensions.js"
32
32
  },
33
+ "./mark-rule": {
34
+ "types": "./dist/prosekit-extensions-mark-rule.d.ts",
35
+ "import": "./dist/prosekit-extensions-mark-rule.js",
36
+ "default": "./dist/prosekit-extensions-mark-rule.js"
37
+ },
33
38
  "./autocomplete": {
34
39
  "types": "./dist/prosekit-extensions-autocomplete.d.ts",
35
40
  "import": "./dist/prosekit-extensions-autocomplete.js",
@@ -121,6 +126,14 @@
121
126
  "import": "./dist/prosekit-extensions-strike.js",
122
127
  "default": "./dist/prosekit-extensions-strike.js"
123
128
  },
129
+ "./table": {
130
+ "types": "./dist/prosekit-extensions-table.d.ts",
131
+ "import": "./dist/prosekit-extensions-table.js",
132
+ "default": "./dist/prosekit-extensions-table.js"
133
+ },
134
+ "./table/style.css": {
135
+ "default": "./dist/table/style.css"
136
+ },
124
137
  "./underline": {
125
138
  "types": "./dist/prosekit-extensions-underline.d.ts",
126
139
  "import": "./dist/prosekit-extensions-underline.js",
@@ -142,15 +155,16 @@
142
155
  "@prosekit/core": "^0.4.0",
143
156
  "@prosekit/pm": "^0.1.2",
144
157
  "prosemirror-dropcursor": "^1.8.1",
145
- "prosemirror-flat-list": "^0.4.6",
158
+ "prosemirror-flat-list": "^0.5.0",
146
159
  "prosemirror-highlight": "^0.5.0",
147
- "shiki": "^1.1.2"
160
+ "prosemirror-tables": "^1.3.7",
161
+ "shiki": "^1.3.0"
148
162
  },
149
163
  "devDependencies": {
150
164
  "@prosekit/dev": "*",
151
165
  "tsup": "^8.0.2",
152
- "typescript": "^5.3.3",
153
- "vitest": "^1.2.2"
166
+ "typescript": "^5.4.5",
167
+ "vitest": "^1.5.2"
154
168
  },
155
169
  "scripts": {
156
170
  "build:tsup": "tsup",
@@ -162,6 +176,9 @@
162
176
  ".": [
163
177
  "./dist/prosekit-extensions.d.ts"
164
178
  ],
179
+ "mark-rule": [
180
+ "./dist/prosekit-extensions-mark-rule.d.ts"
181
+ ],
165
182
  "autocomplete": [
166
183
  "./dist/prosekit-extensions-autocomplete.d.ts"
167
184
  ],
@@ -213,6 +230,9 @@
213
230
  "strike": [
214
231
  "./dist/prosekit-extensions-strike.d.ts"
215
232
  ],
233
+ "table": [
234
+ "./dist/prosekit-extensions-table.d.ts"
235
+ ],
216
236
  "underline": [
217
237
  "./dist/prosekit-extensions-underline.d.ts"
218
238
  ],