@prosekit/extensions 0.0.0-next-20240427200701 → 0.0.0-next-20240427204211

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.
@@ -415,10 +415,21 @@ expandLink: [];
415
415
  };
416
416
  }>;
417
417
 
418
+ /**
419
+ * Apply link marks after typing Enter.
420
+ */
418
421
  export declare function defineLinkEnterRule(): Extension<ExtensionTyping<string, string, CommandArgs>>;
419
422
 
423
+ /**
424
+ * Apply link marks after pressing Space.
425
+ */
420
426
  export declare function defineLinkInputRule(): Extension<ExtensionTyping<string, string, CommandArgs>>;
421
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
+
422
433
  export declare function defineLinkSpec(): Extension< {
423
434
  MARKS: "link";
424
435
  }>;
@@ -810,9 +821,11 @@ export declare function insertTable({ row, col, header, }: {
810
821
  header: boolean;
811
822
  }): Command;
812
823
 
813
- export declare const LINK_RE: RegExp;
824
+ export declare const LINK_ENTER_RE: RegExp;
825
+
826
+ export declare const LINK_INPUT_RE: RegExp;
814
827
 
815
- export declare const LINK_SPACE_RE: RegExp;
828
+ export declare const LINK_MARK_RE: RegExp;
816
829
 
817
830
  /**
818
831
  * @public
@@ -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
+ };
@@ -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,3 +1,6 @@
1
+ import {
2
+ defineMarkRule
3
+ } from "./chunk-TXF4SPMB.js";
1
4
  import {
2
5
  defineEnterRule
3
6
  } from "./chunk-ASTUC4KT.js";
@@ -24,10 +27,12 @@ var LINK_RE_BASE_PATTERN = (
24
27
  "((?:(?:(?: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*)?)"
25
28
  );
26
29
  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");
30
+ var LINK_ENTER_PATTERN = LINK_RE_BASE_PATTERN + LINK_STOP_PATTERN + "$";
31
+ var LINK_INPUT_PATTERN = LINK_RE_BASE_PATTERN + LINK_STOP_PATTERN + "\\s$";
32
+ var LINK_MARK_PATTERN = LINK_RE_BASE_PATTERN + LINK_STOP_PATTERN;
33
+ var LINK_ENTER_RE = new RegExp(LINK_ENTER_PATTERN, "gi");
34
+ var LINK_INPUT_RE = new RegExp(LINK_INPUT_PATTERN, "gi");
35
+ var LINK_MARK_RE = new RegExp(LINK_MARK_PATTERN, "gi");
31
36
 
32
37
  // src/link/index.ts
33
38
  function defineLinkSpec() {
@@ -63,7 +68,7 @@ function defineLinkCommands() {
63
68
  }
64
69
  function defineLinkInputRule() {
65
70
  return defineInputRule(
66
- new InputRule(LINK_SPACE_RE, (state, match, from) => {
71
+ new InputRule(LINK_INPUT_RE, (state, match, from) => {
67
72
  const href = match[1];
68
73
  if (!href)
69
74
  return null;
@@ -74,7 +79,7 @@ function defineLinkInputRule() {
74
79
  }
75
80
  function defineLinkEnterRule() {
76
81
  return defineEnterRule({
77
- regex: LINK_RE,
82
+ regex: LINK_ENTER_RE,
78
83
  handler: ({ state, from, match }) => {
79
84
  const href = match[1];
80
85
  if (!href)
@@ -85,6 +90,13 @@ function defineLinkEnterRule() {
85
90
  }
86
91
  });
87
92
  }
93
+ function defineLinkMarkRule() {
94
+ return defineMarkRule({
95
+ regex: LINK_MARK_RE,
96
+ type: "link",
97
+ attrs: (match) => ({ href: match[1] })
98
+ });
99
+ }
88
100
  function defineLink() {
89
101
  return union([
90
102
  defineLinkSpec(),
@@ -98,5 +110,6 @@ export {
98
110
  defineLinkCommands,
99
111
  defineLinkEnterRule,
100
112
  defineLinkInputRule,
113
+ defineLinkMarkRule,
101
114
  defineLinkSpec
102
115
  };
@@ -1,184 +1,6 @@
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
- });
1
+ import {
2
+ defineMarkRule
3
+ } from "./chunk-TXF4SPMB.js";
182
4
  export {
183
5
  defineMarkRule
184
6
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@prosekit/extensions",
3
3
  "type": "module",
4
- "version": "0.0.0-next-20240427200701",
4
+ "version": "0.0.0-next-20240427204211",
5
5
  "private": false,
6
6
  "author": {
7
7
  "name": "ocavue",
@@ -152,8 +152,8 @@
152
152
  "dist"
153
153
  ],
154
154
  "dependencies": {
155
- "@prosekit/core": "0.0.0-next-20240427200701",
156
- "@prosekit/pm": "0.0.0-next-20240427200701",
155
+ "@prosekit/core": "0.0.0-next-20240427204211",
156
+ "@prosekit/pm": "0.0.0-next-20240427204211",
157
157
  "prosemirror-dropcursor": "^1.8.1",
158
158
  "prosemirror-flat-list": "^0.5.0",
159
159
  "prosemirror-highlight": "^0.5.0",