@tiptap/extension-link 3.30.1 → 3.30.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,663 +1,523 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- Link: () => Link,
24
- default: () => index_default,
25
- isAllowedUri: () => isAllowedUri,
26
- pasteRegex: () => pasteRegex
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
27
4
  });
28
- module.exports = __toCommonJS(index_exports);
29
-
30
- // src/link.ts
31
- var import_core4 = require("@tiptap/core");
32
- var import_linkifyjs3 = require("linkifyjs");
33
-
34
- // src/helpers/autolink.ts
35
- var import_core = require("@tiptap/core");
36
- var import_state = require("@tiptap/pm/state");
37
- var import_linkifyjs = require("linkifyjs");
38
-
39
- // src/helpers/whitespace.ts
40
- var UNICODE_WHITESPACE_PATTERN = "[\0- \xA0\u1680\u180E\u2000-\u2029\u205F\u3000]";
41
- var UNICODE_WHITESPACE_REGEX = new RegExp(UNICODE_WHITESPACE_PATTERN);
42
- var UNICODE_WHITESPACE_REGEX_END = new RegExp(`${UNICODE_WHITESPACE_PATTERN}$`);
43
- var UNICODE_WHITESPACE_REGEX_GLOBAL = new RegExp(UNICODE_WHITESPACE_PATTERN, "g");
44
-
45
- // src/helpers/autolink.ts
5
+ let _tiptap_core = require("@tiptap/core");
6
+ let linkifyjs = require("linkifyjs");
7
+ let _tiptap_pm_state = require("@tiptap/pm/state");
8
+ //#region src/helpers/whitespace.ts
9
+ const UNICODE_WHITESPACE_PATTERN = "[\0- \xA0 ᠎ -\u2029  ]";
10
+ const UNICODE_WHITESPACE_REGEX = new RegExp(UNICODE_WHITESPACE_PATTERN);
11
+ const UNICODE_WHITESPACE_REGEX_END = new RegExp(`${UNICODE_WHITESPACE_PATTERN}$`);
12
+ const UNICODE_WHITESPACE_REGEX_GLOBAL = new RegExp(UNICODE_WHITESPACE_PATTERN, "g");
13
+ //#endregion
14
+ //#region src/helpers/autolink.ts
15
+ /**
16
+ * Check if the provided tokens form a valid link structure, which can either be a single link token
17
+ * or a link token surrounded by parentheses or square brackets.
18
+ *
19
+ * This ensures that only complete and valid text is hyperlinked, preventing cases where a valid
20
+ * top-level domain (TLD) is immediately followed by an invalid character, like a number. For
21
+ * example, with the `find` method from Linkify, entering `example.com1` would result in
22
+ * `example.com` being linked and the trailing `1` left as plain text. By using the `tokenize`
23
+ * method, we can perform more comprehensive validation on the input text.
24
+ */
46
25
  function isValidLinkStructure(tokens) {
47
- if (tokens.length === 1) {
48
- return tokens[0].isLink;
49
- }
50
- if (tokens.length === 3 && tokens[1].isLink) {
51
- return ["()", "[]"].includes(tokens[0].value + tokens[2].value);
52
- }
53
- return false;
26
+ if (tokens.length === 1) return tokens[0].isLink;
27
+ if (tokens.length === 3 && tokens[1].isLink) return ["()", "[]"].includes(tokens[0].value + tokens[2].value);
28
+ return false;
54
29
  }
30
+ /**
31
+ * This plugin allows you to automatically add links to your editor.
32
+ * @param options The plugin options
33
+ * @returns The plugin instance
34
+ */
55
35
  function autolink(options) {
56
- return new import_state.Plugin({
57
- key: new import_state.PluginKey("autolink"),
58
- appendTransaction: (transactions, oldState, newState) => {
59
- const docChanges = transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc);
60
- const preventAutolink = transactions.some(
61
- (transaction) => transaction.getMeta("preventAutolink")
62
- );
63
- if (!docChanges || preventAutolink) {
64
- return;
65
- }
66
- const { tr } = newState;
67
- const transform = (0, import_core.combineTransactionSteps)(oldState.doc, [...transactions]);
68
- const changes = (0, import_core.getChangedRanges)(transform);
69
- changes.forEach(({ newRange }) => {
70
- const nodesInChangedRanges = (0, import_core.findChildrenInRange)(
71
- newState.doc,
72
- newRange,
73
- (node) => node.isTextblock
74
- );
75
- let textBlock;
76
- let textBeforeWhitespace;
77
- if (nodesInChangedRanges.length > 1) {
78
- textBlock = nodesInChangedRanges[0];
79
- textBeforeWhitespace = newState.doc.textBetween(
80
- textBlock.pos,
81
- textBlock.pos + textBlock.node.nodeSize,
82
- void 0,
83
- " "
84
- );
85
- } else if (nodesInChangedRanges.length) {
86
- const endText = newState.doc.textBetween(newRange.from, newRange.to, " ", " ");
87
- if (!UNICODE_WHITESPACE_REGEX_END.test(endText)) {
88
- return;
89
- }
90
- textBlock = nodesInChangedRanges[0];
91
- textBeforeWhitespace = newState.doc.textBetween(
92
- textBlock.pos,
93
- newRange.to,
94
- void 0,
95
- " "
96
- );
97
- }
98
- if (textBlock && textBeforeWhitespace) {
99
- const wordsBeforeWhitespace = textBeforeWhitespace.split(UNICODE_WHITESPACE_REGEX).filter(Boolean);
100
- if (wordsBeforeWhitespace.length <= 0) {
101
- return false;
102
- }
103
- const lastWordBeforeSpace = wordsBeforeWhitespace[wordsBeforeWhitespace.length - 1];
104
- const lastWordAndBlockOffset = textBlock.pos + textBeforeWhitespace.lastIndexOf(lastWordBeforeSpace);
105
- if (!lastWordBeforeSpace) {
106
- return false;
107
- }
108
- const linksBeforeSpace = (0, import_linkifyjs.tokenize)(lastWordBeforeSpace).map(
109
- (t) => t.toObject(options.defaultProtocol)
110
- );
111
- if (!isValidLinkStructure(linksBeforeSpace)) {
112
- return false;
113
- }
114
- linksBeforeSpace.filter((link) => link.isLink).map((link) => ({
115
- ...link,
116
- from: lastWordAndBlockOffset + link.start + 1,
117
- to: lastWordAndBlockOffset + link.end + 1
118
- })).filter((link) => {
119
- if (!newState.schema.marks.code) {
120
- return true;
121
- }
122
- return !newState.doc.rangeHasMark(link.from, link.to, newState.schema.marks.code);
123
- }).filter((link) => options.validate(link.value)).filter((link) => options.shouldAutoLink(link.value)).forEach((link) => {
124
- if ((0, import_core.getMarksBetween)(link.from, link.to, newState.doc).some(
125
- (item) => item.mark.type === options.type
126
- )) {
127
- return;
128
- }
129
- tr.addMark(
130
- link.from,
131
- link.to,
132
- options.type.create({
133
- href: link.href
134
- })
135
- );
136
- });
137
- }
138
- });
139
- if (!tr.steps.length) {
140
- return;
141
- }
142
- return tr;
143
- }
144
- });
36
+ return new _tiptap_pm_state.Plugin({
37
+ key: new _tiptap_pm_state.PluginKey("autolink"),
38
+ appendTransaction: (transactions, oldState, newState) => {
39
+ /**
40
+ * Does the transaction change the document?
41
+ */
42
+ const docChanges = transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc);
43
+ /**
44
+ * Prevent autolink if the transaction is not a document change or if the transaction has the meta `preventAutolink`.
45
+ */
46
+ const preventAutolink = transactions.some((transaction) => transaction.getMeta("preventAutolink"));
47
+ /**
48
+ * Prevent autolink if the transaction is not a document change
49
+ * or if the transaction has the meta `preventAutolink`.
50
+ */
51
+ if (!docChanges || preventAutolink) return;
52
+ const { tr } = newState;
53
+ (0, _tiptap_core.getChangedRanges)((0, _tiptap_core.combineTransactionSteps)(oldState.doc, [...transactions])).forEach(({ newRange }) => {
54
+ const nodesInChangedRanges = (0, _tiptap_core.findChildrenInRange)(newState.doc, newRange, (node) => node.isTextblock);
55
+ let textBlock;
56
+ let textBeforeWhitespace;
57
+ if (nodesInChangedRanges.length > 1) {
58
+ textBlock = nodesInChangedRanges[0];
59
+ textBeforeWhitespace = newState.doc.textBetween(textBlock.pos, textBlock.pos + textBlock.node.nodeSize, void 0, " ");
60
+ } else if (nodesInChangedRanges.length) {
61
+ const endText = newState.doc.textBetween(newRange.from, newRange.to, " ", " ");
62
+ if (!UNICODE_WHITESPACE_REGEX_END.test(endText)) return;
63
+ textBlock = nodesInChangedRanges[0];
64
+ textBeforeWhitespace = newState.doc.textBetween(textBlock.pos, newRange.to, void 0, " ");
65
+ }
66
+ if (textBlock && textBeforeWhitespace) {
67
+ const wordsBeforeWhitespace = textBeforeWhitespace.split(UNICODE_WHITESPACE_REGEX).filter(Boolean);
68
+ if (wordsBeforeWhitespace.length <= 0) return false;
69
+ const lastWordBeforeSpace = wordsBeforeWhitespace[wordsBeforeWhitespace.length - 1];
70
+ const lastWordAndBlockOffset = textBlock.pos + textBeforeWhitespace.lastIndexOf(lastWordBeforeSpace);
71
+ if (!lastWordBeforeSpace) return false;
72
+ const linksBeforeSpace = (0, linkifyjs.tokenize)(lastWordBeforeSpace).map((t) => t.toObject(options.defaultProtocol));
73
+ if (!isValidLinkStructure(linksBeforeSpace)) return false;
74
+ linksBeforeSpace.filter((link) => link.isLink).map((link) => ({
75
+ ...link,
76
+ from: lastWordAndBlockOffset + link.start + 1,
77
+ to: lastWordAndBlockOffset + link.end + 1
78
+ })).filter((link) => {
79
+ if (!newState.schema.marks.code) return true;
80
+ return !newState.doc.rangeHasMark(link.from, link.to, newState.schema.marks.code);
81
+ }).filter((link) => options.validate(link.value)).filter((link) => options.shouldAutoLink(link.value)).forEach((link) => {
82
+ if ((0, _tiptap_core.getMarksBetween)(link.from, link.to, newState.doc).some((item) => item.mark.type === options.type)) return;
83
+ tr.addMark(link.from, link.to, options.type.create({ href: link.href }));
84
+ });
85
+ }
86
+ });
87
+ if (!tr.steps.length) return;
88
+ return tr;
89
+ }
90
+ });
145
91
  }
146
-
147
- // src/helpers/clickHandler.ts
148
- var import_core2 = require("@tiptap/core");
149
- var import_state2 = require("@tiptap/pm/state");
92
+ //#endregion
93
+ //#region src/helpers/clickHandler.ts
150
94
  function clickHandler(options) {
151
- return new import_state2.Plugin({
152
- key: new import_state2.PluginKey("handleClickLink"),
153
- props: {
154
- handleClick: (view, pos, event) => {
155
- var _a, _b;
156
- if (event.button !== 0) {
157
- return false;
158
- }
159
- if (!view.editable) {
160
- return false;
161
- }
162
- let link = null;
163
- if (event.target instanceof HTMLAnchorElement) {
164
- link = event.target;
165
- } else {
166
- const target = event.target;
167
- if (!target) {
168
- return false;
169
- }
170
- const root = options.editor.view.dom;
171
- link = target.closest("a");
172
- if (link && !root.contains(link)) {
173
- link = null;
174
- }
175
- }
176
- if (!link) {
177
- return false;
178
- }
179
- let handled = false;
180
- if (options.enableClickSelection) {
181
- const commandResult = options.editor.commands.extendMarkRange(options.type.name);
182
- handled = commandResult;
183
- }
184
- if (options.openOnClick) {
185
- const attrs = (0, import_core2.getAttributes)(view.state, options.type.name);
186
- const href = (_a = link.href) != null ? _a : attrs.href;
187
- const target = (_b = link.target) != null ? _b : attrs.target;
188
- if (href) {
189
- window.open(href, target);
190
- handled = true;
191
- }
192
- }
193
- return handled;
194
- }
195
- }
196
- });
95
+ return new _tiptap_pm_state.Plugin({
96
+ key: new _tiptap_pm_state.PluginKey("handleClickLink"),
97
+ props: { handleClick: (view, pos, event) => {
98
+ if (event.button !== 0) return false;
99
+ if (!view.editable) return false;
100
+ let link = null;
101
+ if (event.target instanceof HTMLAnchorElement) link = event.target;
102
+ else {
103
+ const target = event.target;
104
+ if (!target) return false;
105
+ const root = options.editor.view.dom;
106
+ link = target.closest("a");
107
+ if (link && !root.contains(link)) link = null;
108
+ }
109
+ if (!link) return false;
110
+ let handled = false;
111
+ if (options.enableClickSelection) handled = options.editor.commands.extendMarkRange(options.type.name);
112
+ if (options.openOnClick) {
113
+ var _link$href, _link$target;
114
+ const attrs = (0, _tiptap_core.getAttributes)(view.state, options.type.name);
115
+ const href = (_link$href = link.href) !== null && _link$href !== void 0 ? _link$href : attrs.href;
116
+ const target = (_link$target = link.target) !== null && _link$target !== void 0 ? _link$target : attrs.target;
117
+ if (href) {
118
+ window.open(href, target);
119
+ handled = true;
120
+ }
121
+ }
122
+ return handled;
123
+ } }
124
+ });
197
125
  }
198
-
199
- // src/helpers/markdownLink.ts
200
- var import_core3 = require("@tiptap/core");
201
- var MARKDOWN_LINK_INPUT_REGEX = /\[([^[\]]+)\]\(((?:[^\s()]|\([^\s()]*\))+)(?:\s+(?:(["'])(.*?)\3|“(.*?)”|‘(.*?)’))?\)$/;
202
- var MARKDOWN_LINK_PASTE_REGEX = /\[([^[\]]+)\]\(((?:[^\s()]|\([^\s()]*\))+)(?:\s+(?:(["'])(.*?)\3|“(.*?)”|‘(.*?)’))?\)/g;
126
+ //#endregion
127
+ //#region src/helpers/markdownLink.ts
128
+ /**
129
+ * Matches a Markdown link with an optional quoted title.
130
+ * for ex: [Tiptap](https://tiptap.dev) or [Tiptap](https://tiptap.dev "some title")
131
+ * the URL may also contain one level of balanced parentheses, as in CommonMark
132
+ * (titles accept curly quotes too, the Typography extension swaps them in while typing)
133
+ * the title delimiters must come in matching pairs
134
+ */
135
+ const MARKDOWN_LINK_INPUT_REGEX = /\[([^[\]]+)\]\(((?:[^\s()]|\([^\s()]*\))+)(?:\s+(?:(["'])(.*?)\3|“(.*?)”|‘(.*?)’))?\)$/;
136
+ /**
137
+ * Same as the input regex but global, to find every Markdown link in pasted text.
138
+ */
139
+ const MARKDOWN_LINK_PASTE_REGEX = /\[([^[\]]+)\]\(((?:[^\s()]|\([^\s()]*\))+)(?:\s+(?:(["'])(.*?)\3|“(.*?)”|‘(.*?)’))?\)/g;
203
140
  function isEscaped(text, index) {
204
- let backslashes = 0;
205
- for (let position = index - 1; position >= 0 && text[position] === "\\"; position -= 1) {
206
- backslashes += 1;
207
- }
208
- return backslashes % 2 === 1;
141
+ let backslashes = 0;
142
+ for (let position = index - 1; position >= 0 && text[position] === "\\"; position -= 1) backslashes += 1;
143
+ return backslashes % 2 === 1;
209
144
  }
145
+ /**
146
+ * Pairs the backtick runs before the match by length, as CommonMark does.
147
+ * A run left open means the match sits in an unfinished code span.
148
+ */
210
149
  function isInsideCodeSpan(text, matchIndex) {
211
- let openRunLength = 0;
212
- let index = 0;
213
- while (index < matchIndex) {
214
- if (text[index] !== "`") {
215
- index += 1;
216
- continue;
217
- }
218
- if (openRunLength === 0 && isEscaped(text, index)) {
219
- index += 1;
220
- continue;
221
- }
222
- let runLength = 0;
223
- while (index < matchIndex && text[index] === "`") {
224
- runLength += 1;
225
- index += 1;
226
- }
227
- if (openRunLength === 0) {
228
- openRunLength = runLength;
229
- } else if (runLength === openRunLength) {
230
- openRunLength = 0;
231
- }
232
- }
233
- return openRunLength > 0;
150
+ let openRunLength = 0;
151
+ let index = 0;
152
+ while (index < matchIndex) {
153
+ if (text[index] !== "`") {
154
+ index += 1;
155
+ continue;
156
+ }
157
+ if (openRunLength === 0 && isEscaped(text, index)) {
158
+ index += 1;
159
+ continue;
160
+ }
161
+ let runLength = 0;
162
+ while (index < matchIndex && text[index] === "`") {
163
+ runLength += 1;
164
+ index += 1;
165
+ }
166
+ if (openRunLength === 0) openRunLength = runLength;
167
+ else if (runLength === openRunLength) openRunLength = 0;
168
+ }
169
+ return openRunLength > 0;
234
170
  }
235
171
  function isConvertibleLink(text, match, isAllowedHref) {
236
- var _a, _b;
237
- const [, linkText, href] = match;
238
- const characterBefore = match.index ? text[match.index - 1] : void 0;
239
- if (characterBefore === "!" || isEscaped(text, (_a = match.index) != null ? _a : 0)) {
240
- return false;
241
- }
242
- if (isInsideCodeSpan(text, (_b = match.index) != null ? _b : 0)) {
243
- return false;
244
- }
245
- return !!linkText.trim() && isAllowedHref(href);
172
+ var _match$index, _match$index2;
173
+ const [, linkText, href] = match;
174
+ if ((match.index ? text[match.index - 1] : void 0) === "!" || isEscaped(text, (_match$index = match.index) !== null && _match$index !== void 0 ? _match$index : 0)) return false;
175
+ if (isInsideCodeSpan(text, (_match$index2 = match.index) !== null && _match$index2 !== void 0 ? _match$index2 : 0)) return false;
176
+ return !!linkText.trim() && isAllowedHref(href);
246
177
  }
247
178
  function toRuleMatch(match) {
248
- var _a, _b;
249
- const [linkSyntax, linkText, href, , straightQuotedTitle, curlyDoubleTitle, curlySingleTitle] = match;
250
- const title = (_a = straightQuotedTitle != null ? straightQuotedTitle : curlyDoubleTitle) != null ? _a : curlySingleTitle;
251
- return {
252
- index: (_b = match.index) != null ? _b : 0,
253
- text: linkSyntax,
254
- replaceWith: linkText,
255
- data: {
256
- href,
257
- // an empty title ("") counts as no title, as in CommonMark
258
- title: title || null,
259
- markdown: true
260
- }
261
- };
179
+ var _ref, _match$index3;
180
+ const [linkSyntax, linkText, href, , straightQuotedTitle, curlyDoubleTitle, curlySingleTitle] = match;
181
+ const title = (_ref = straightQuotedTitle !== null && straightQuotedTitle !== void 0 ? straightQuotedTitle : curlyDoubleTitle) !== null && _ref !== void 0 ? _ref : curlySingleTitle;
182
+ return {
183
+ index: (_match$index3 = match.index) !== null && _match$index3 !== void 0 ? _match$index3 : 0,
184
+ text: linkSyntax,
185
+ replaceWith: linkText,
186
+ data: {
187
+ href,
188
+ title: title || null,
189
+ markdown: true
190
+ }
191
+ };
262
192
  }
263
193
  function matchesOverlap(a, b) {
264
- return a.index < b.index + b.text.length && b.index < a.index + a.text.length;
194
+ return a.index < b.index + b.text.length && b.index < a.index + a.text.length;
265
195
  }
266
196
  function getMarkdownLinkAttributes(match) {
267
- var _a, _b, _c;
268
- return {
269
- href: (_a = match.data) == null ? void 0 : _a.href,
270
- title: (_c = (_b = match.data) == null ? void 0 : _b.title) != null ? _c : null
271
- };
197
+ var _match$data, _match$data$title, _match$data2;
198
+ return {
199
+ href: (_match$data = match.data) === null || _match$data === void 0 ? void 0 : _match$data.href,
200
+ title: (_match$data$title = (_match$data2 = match.data) === null || _match$data2 === void 0 ? void 0 : _match$data2.title) !== null && _match$data$title !== void 0 ? _match$data$title : null
201
+ };
272
202
  }
203
+ /**
204
+ * Turns typed Markdown link syntax into a link mark as soon as the closing `)` comes in.
205
+ * The transaction gets flagged so autolink doesn't touch the converted text again.
206
+ */
273
207
  function markdownLinkInputRule(config) {
274
- const rule = (0, import_core3.markInputRule)({
275
- find: (text) => {
276
- const match = MARKDOWN_LINK_INPUT_REGEX.exec(text);
277
- if (!match || !isConvertibleLink(text, match, config.isAllowedHref)) {
278
- return null;
279
- }
280
- return toRuleMatch(match);
281
- },
282
- type: config.type,
283
- getAttributes: getMarkdownLinkAttributes
284
- });
285
- return new import_core3.InputRule({
286
- find: rule.find,
287
- handler: (props) => {
288
- const result = rule.handler(props);
289
- if (result !== null && props.state.tr.steps.length) {
290
- props.state.tr.setMeta("preventAutolink", true);
291
- }
292
- return result;
293
- }
294
- });
208
+ const rule = (0, _tiptap_core.markInputRule)({
209
+ find: (text) => {
210
+ const match = MARKDOWN_LINK_INPUT_REGEX.exec(text);
211
+ if (!match || !isConvertibleLink(text, match, config.isAllowedHref)) return null;
212
+ return toRuleMatch(match);
213
+ },
214
+ type: config.type,
215
+ getAttributes: getMarkdownLinkAttributes
216
+ });
217
+ return new _tiptap_core.InputRule({
218
+ find: rule.find,
219
+ handler: (props) => {
220
+ const result = rule.handler(props);
221
+ if (result !== null && props.state.tr.steps.length) props.state.tr.setMeta("preventAutolink", true);
222
+ return result;
223
+ }
224
+ });
295
225
  }
226
+ /**
227
+ * Same for pasting, converts every Markdown link found in the pasted text
228
+ * and links the plain URLs from `findPlainUrls`.
229
+ */
296
230
  function markdownLinkPasteRule(config) {
297
- const rule = (0, import_core3.markPasteRule)({
298
- find: (text) => {
299
- var _a, _b;
300
- const markdownMatches = [];
301
- for (const match of text.matchAll(MARKDOWN_LINK_PASTE_REGEX)) {
302
- if (isConvertibleLink(text, match, config.isAllowedHref)) {
303
- markdownMatches.push(toRuleMatch(match));
304
- }
305
- }
306
- const plainUrlMatches = ((_b = (_a = config.findPlainUrls) == null ? void 0 : _a.call(config, text)) != null ? _b : []).filter(
307
- (urlMatch) => !markdownMatches.some((markdownMatch) => matchesOverlap(markdownMatch, urlMatch))
308
- );
309
- return [...markdownMatches, ...plainUrlMatches];
310
- },
311
- type: config.type,
312
- getAttributes: getMarkdownLinkAttributes
313
- });
314
- return new import_core3.PasteRule({
315
- find: rule.find,
316
- handler: (props) => {
317
- var _a;
318
- const result = rule.handler(props);
319
- if (result !== null && props.state.tr.steps.length && ((_a = props.match.data) == null ? void 0 : _a.markdown)) {
320
- props.state.tr.setMeta("preventAutolink", true);
321
- }
322
- return result;
323
- }
324
- });
231
+ const rule = (0, _tiptap_core.markPasteRule)({
232
+ find: (text) => {
233
+ var _config$findPlainUrls, _config$findPlainUrls2;
234
+ const markdownMatches = [];
235
+ for (const match of text.matchAll(MARKDOWN_LINK_PASTE_REGEX)) if (isConvertibleLink(text, match, config.isAllowedHref)) markdownMatches.push(toRuleMatch(match));
236
+ const plainUrlMatches = ((_config$findPlainUrls = (_config$findPlainUrls2 = config.findPlainUrls) === null || _config$findPlainUrls2 === void 0 ? void 0 : _config$findPlainUrls2.call(config, text)) !== null && _config$findPlainUrls !== void 0 ? _config$findPlainUrls : []).filter((urlMatch) => !markdownMatches.some((markdownMatch) => matchesOverlap(markdownMatch, urlMatch)));
237
+ return [...markdownMatches, ...plainUrlMatches];
238
+ },
239
+ type: config.type,
240
+ getAttributes: getMarkdownLinkAttributes
241
+ });
242
+ return new _tiptap_core.PasteRule({
243
+ find: rule.find,
244
+ handler: (props) => {
245
+ var _props$match$data;
246
+ const result = rule.handler(props);
247
+ if (result !== null && props.state.tr.steps.length && ((_props$match$data = props.match.data) === null || _props$match$data === void 0 ? void 0 : _props$match$data.markdown)) props.state.tr.setMeta("preventAutolink", true);
248
+ return result;
249
+ }
250
+ });
325
251
  }
326
-
327
- // src/helpers/pasteHandler.ts
328
- var import_state3 = require("@tiptap/pm/state");
329
- var import_linkifyjs2 = require("linkifyjs");
252
+ //#endregion
253
+ //#region src/helpers/pasteHandler.ts
330
254
  function pasteHandler(options) {
331
- return new import_state3.Plugin({
332
- key: new import_state3.PluginKey("handlePasteLink"),
333
- props: {
334
- handlePaste: (view, _event, slice) => {
335
- const { shouldAutoLink } = options;
336
- const { state } = view;
337
- const { selection } = state;
338
- const { empty } = selection;
339
- if (empty) {
340
- return false;
341
- }
342
- let textContent = "";
343
- slice.content.forEach((node) => {
344
- textContent += node.textContent;
345
- });
346
- const link = (0, import_linkifyjs2.find)(textContent, { defaultProtocol: options.defaultProtocol }).find(
347
- (item) => item.isLink && item.value === textContent
348
- );
349
- if (!textContent || !link || shouldAutoLink !== void 0 && !shouldAutoLink(link.value)) {
350
- return false;
351
- }
352
- return options.editor.commands.setMark(options.type, {
353
- href: link.href
354
- });
355
- }
356
- }
357
- });
255
+ return new _tiptap_pm_state.Plugin({
256
+ key: new _tiptap_pm_state.PluginKey("handlePasteLink"),
257
+ props: { handlePaste: (view, _event, slice) => {
258
+ const { shouldAutoLink } = options;
259
+ const { state } = view;
260
+ const { selection } = state;
261
+ const { empty } = selection;
262
+ if (empty) return false;
263
+ let textContent = "";
264
+ slice.content.forEach((node) => {
265
+ textContent += node.textContent;
266
+ });
267
+ const link = (0, linkifyjs.find)(textContent, { defaultProtocol: options.defaultProtocol }).find((item) => item.isLink && item.value === textContent);
268
+ if (!textContent || !link || shouldAutoLink !== void 0 && !shouldAutoLink(link.value)) return false;
269
+ return options.editor.commands.setMark(options.type, { href: link.href });
270
+ } }
271
+ });
358
272
  }
359
-
360
- // src/link.ts
361
- var pasteRegex = /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)/gi;
273
+ //#endregion
274
+ //#region src/link.ts
275
+ const pasteRegex = /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)/gi;
362
276
  function isAllowedUri(uri, protocols) {
363
- const allowedProtocols = [
364
- "http",
365
- "https",
366
- "ftp",
367
- "ftps",
368
- "mailto",
369
- "tel",
370
- "callto",
371
- "sms",
372
- "cid",
373
- "xmpp"
374
- ];
375
- if (protocols) {
376
- protocols.forEach((protocol) => {
377
- const nextProtocol = typeof protocol === "string" ? protocol : protocol.scheme;
378
- if (nextProtocol) {
379
- allowedProtocols.push(nextProtocol);
380
- }
381
- });
382
- }
383
- return !uri || uri.replace(UNICODE_WHITESPACE_REGEX_GLOBAL, "").match(
384
- new RegExp(
385
- `^(?:(?:${allowedProtocols.map((protocol) => protocol.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&")).join("|")}):|[^a-z]|[a-z0-9+.\\-]+(?:[^a-z+.\\-:]|$))`,
386
- "i"
387
- )
388
- );
277
+ const allowedProtocols = [
278
+ "http",
279
+ "https",
280
+ "ftp",
281
+ "ftps",
282
+ "mailto",
283
+ "tel",
284
+ "callto",
285
+ "sms",
286
+ "cid",
287
+ "xmpp"
288
+ ];
289
+ if (protocols) protocols.forEach((protocol) => {
290
+ const nextProtocol = typeof protocol === "string" ? protocol : protocol.scheme;
291
+ if (nextProtocol) allowedProtocols.push(nextProtocol);
292
+ });
293
+ return !uri || uri.replace(UNICODE_WHITESPACE_REGEX_GLOBAL, "").match(new RegExp(`^(?:(?:${allowedProtocols.map((protocol) => protocol.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&")).join("|")}):|[^a-z]|[a-z0-9+.\\-]+(?:[^a-z+.\\-:]|$))`, "i"));
389
294
  }
390
- var Link = import_core4.Mark.create({
391
- name: "link",
392
- priority: 1e3,
393
- keepOnSplit: false,
394
- exitable: true,
395
- onCreate() {
396
- if (this.options.validate && !this.options.shouldAutoLink) {
397
- this.options.shouldAutoLink = this.options.validate;
398
- console.warn(
399
- "The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead."
400
- );
401
- }
402
- this.options.protocols.forEach((protocol) => {
403
- if (typeof protocol === "string") {
404
- (0, import_linkifyjs3.registerCustomProtocol)(protocol);
405
- return;
406
- }
407
- (0, import_linkifyjs3.registerCustomProtocol)(protocol.scheme, protocol.optionalSlashes);
408
- });
409
- },
410
- onDestroy() {
411
- (0, import_linkifyjs3.reset)();
412
- },
413
- inclusive() {
414
- return this.options.autolink;
415
- },
416
- addOptions() {
417
- return {
418
- openOnClick: true,
419
- enableClickSelection: false,
420
- linkOnPaste: true,
421
- markdownLinks: false,
422
- // TODO (major) - default to true on next major version
423
- autolink: true,
424
- protocols: [],
425
- defaultProtocol: "http",
426
- HTMLAttributes: {
427
- target: "_blank",
428
- rel: "noopener noreferrer nofollow",
429
- class: null
430
- },
431
- isAllowedUri: (url, ctx) => !!isAllowedUri(url, ctx.protocols),
432
- validate: (url) => !!url,
433
- shouldAutoLink: (url) => {
434
- const hasProtocol = /^[a-z][a-z0-9+.-]*:\/\//i.test(url);
435
- const hasMaybeProtocol = /^[a-z][a-z0-9+.-]*:/i.test(url);
436
- if (hasProtocol || hasMaybeProtocol && !url.includes("@")) {
437
- return true;
438
- }
439
- const urlWithoutUserinfo = url.includes("@") ? url.split("@").pop() : url;
440
- const hostname = urlWithoutUserinfo.split(/[/?#:]/)[0];
441
- if (/^\d{1,3}(\.\d{1,3}){3}$/.test(hostname)) {
442
- return false;
443
- }
444
- if (!/\./.test(hostname)) {
445
- return false;
446
- }
447
- return true;
448
- }
449
- };
450
- },
451
- addAttributes() {
452
- var _a, _b, _c;
453
- return {
454
- href: {
455
- default: null,
456
- parseHTML(element) {
457
- return element.getAttribute("href");
458
- }
459
- },
460
- target: {
461
- // Coerce `undefined` to `null` because `undefined` is an invalid attribute value
462
- default: (_a = this.options.HTMLAttributes.target) != null ? _a : null
463
- },
464
- rel: {
465
- // Coerce `undefined` to `null` because `undefined` is an invalid attribute value
466
- default: (_b = this.options.HTMLAttributes.rel) != null ? _b : null
467
- },
468
- class: {
469
- // Coerce `undefined` to `null` because `undefined` is an invalid attribute value
470
- default: (_c = this.options.HTMLAttributes.class) != null ? _c : null
471
- },
472
- title: {
473
- default: null
474
- }
475
- };
476
- },
477
- parseHTML() {
478
- return [
479
- {
480
- tag: "a[href]",
481
- getAttrs: (dom) => {
482
- const href = dom.getAttribute("href");
483
- if (!href || !this.options.isAllowedUri(href, {
484
- defaultValidate: (url) => !!isAllowedUri(url, this.options.protocols),
485
- protocols: this.options.protocols,
486
- defaultProtocol: this.options.defaultProtocol
487
- })) {
488
- return false;
489
- }
490
- return null;
491
- }
492
- }
493
- ];
494
- },
495
- renderHTML({ HTMLAttributes }) {
496
- if (!this.options.isAllowedUri(HTMLAttributes.href, {
497
- defaultValidate: (href) => !!isAllowedUri(href, this.options.protocols),
498
- protocols: this.options.protocols,
499
- defaultProtocol: this.options.defaultProtocol
500
- })) {
501
- return ["a", (0, import_core4.mergeAttributes)(this.options.HTMLAttributes, { ...HTMLAttributes, href: "" }), 0];
502
- }
503
- return ["a", (0, import_core4.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes), 0];
504
- },
505
- markdownTokenName: "link",
506
- parseMarkdown: (token, helpers) => {
507
- return helpers.applyMark("link", helpers.parseInline(token.tokens || []), {
508
- href: token.href,
509
- title: token.title || null
510
- });
511
- },
512
- renderMarkdown: (node, h) => {
513
- var _a, _b, _c, _d;
514
- const href = (_b = (_a = node.attrs) == null ? void 0 : _a.href) != null ? _b : "";
515
- const title = (_d = (_c = node.attrs) == null ? void 0 : _c.title) != null ? _d : "";
516
- const text = h.renderChildren(node);
517
- return title ? `[${text}](${href} "${title}")` : `[${text}](${href})`;
518
- },
519
- addCommands() {
520
- return {
521
- setLink: (attributes) => ({ chain }) => {
522
- const { href } = attributes;
523
- if (!this.options.isAllowedUri(href, {
524
- defaultValidate: (url) => !!isAllowedUri(url, this.options.protocols),
525
- protocols: this.options.protocols,
526
- defaultProtocol: this.options.defaultProtocol
527
- })) {
528
- return false;
529
- }
530
- return chain().setMark(this.name, attributes).setMeta("preventAutolink", true).run();
531
- },
532
- toggleLink: (attributes) => ({ chain }) => {
533
- const { href } = attributes || {};
534
- if (href && !this.options.isAllowedUri(href, {
535
- defaultValidate: (url) => !!isAllowedUri(url, this.options.protocols),
536
- protocols: this.options.protocols,
537
- defaultProtocol: this.options.defaultProtocol
538
- })) {
539
- return false;
540
- }
541
- return chain().toggleMark(this.name, attributes, { extendEmptyMarkRange: true }).setMeta("preventAutolink", true).run();
542
- },
543
- unsetLink: () => ({ chain }) => {
544
- return chain().unsetMark(this.name, { extendEmptyMarkRange: true }).setMeta("preventAutolink", true).run();
545
- }
546
- };
547
- },
548
- addInputRules() {
549
- if (!this.options.markdownLinks) {
550
- return [];
551
- }
552
- return [
553
- markdownLinkInputRule({
554
- type: this.type,
555
- isAllowedHref: (href) => this.options.isAllowedUri(href, {
556
- defaultValidate: (url) => !!isAllowedUri(url, this.options.protocols),
557
- protocols: this.options.protocols,
558
- defaultProtocol: this.options.defaultProtocol
559
- })
560
- })
561
- ];
562
- },
563
- addPasteRules() {
564
- const findPlainUrls = (text) => {
565
- const foundLinks = [];
566
- if (text) {
567
- const { protocols, defaultProtocol } = this.options;
568
- const links = (0, import_linkifyjs3.find)(text).filter(
569
- (item) => item.isLink && this.options.isAllowedUri(item.value, {
570
- defaultValidate: (href) => !!isAllowedUri(href, protocols),
571
- protocols,
572
- defaultProtocol
573
- })
574
- );
575
- links.forEach((link) => {
576
- if (!this.options.shouldAutoLink(link.value)) {
577
- return;
578
- }
579
- foundLinks.push({
580
- text: link.value,
581
- data: {
582
- href: link.href
583
- },
584
- index: link.start
585
- });
586
- });
587
- }
588
- return foundLinks;
589
- };
590
- if (this.options.markdownLinks) {
591
- return [
592
- markdownLinkPasteRule({
593
- type: this.type,
594
- isAllowedHref: (href) => this.options.isAllowedUri(href, {
595
- defaultValidate: (url) => !!isAllowedUri(url, this.options.protocols),
596
- protocols: this.options.protocols,
597
- defaultProtocol: this.options.defaultProtocol
598
- }),
599
- findPlainUrls
600
- })
601
- ];
602
- }
603
- return [
604
- (0, import_core4.markPasteRule)({
605
- find: findPlainUrls,
606
- type: this.type,
607
- getAttributes: (match) => {
608
- var _a;
609
- return {
610
- href: (_a = match.data) == null ? void 0 : _a.href
611
- };
612
- }
613
- })
614
- ];
615
- },
616
- addProseMirrorPlugins() {
617
- const plugins = [];
618
- const { protocols, defaultProtocol } = this.options;
619
- if (this.options.autolink) {
620
- plugins.push(
621
- autolink({
622
- type: this.type,
623
- defaultProtocol: this.options.defaultProtocol,
624
- validate: (url) => this.options.isAllowedUri(url, {
625
- defaultValidate: (href) => !!isAllowedUri(href, protocols),
626
- protocols,
627
- defaultProtocol
628
- }),
629
- shouldAutoLink: this.options.shouldAutoLink
630
- })
631
- );
632
- }
633
- plugins.push(
634
- clickHandler({
635
- type: this.type,
636
- editor: this.editor,
637
- openOnClick: this.options.openOnClick === "whenNotEditable" ? true : this.options.openOnClick,
638
- enableClickSelection: this.options.enableClickSelection
639
- })
640
- );
641
- if (this.options.linkOnPaste) {
642
- plugins.push(
643
- pasteHandler({
644
- editor: this.editor,
645
- defaultProtocol: this.options.defaultProtocol,
646
- type: this.type,
647
- shouldAutoLink: this.options.shouldAutoLink
648
- })
649
- );
650
- }
651
- return plugins;
652
- }
295
+ /**
296
+ * This extension allows you to create links.
297
+ * @see https://www.tiptap.dev/api/marks/link
298
+ */
299
+ const Link = _tiptap_core.Mark.create({
300
+ name: "link",
301
+ priority: 1e3,
302
+ keepOnSplit: false,
303
+ exitable: true,
304
+ onCreate() {
305
+ if (this.options.validate && !this.options.shouldAutoLink) {
306
+ this.options.shouldAutoLink = this.options.validate;
307
+ console.warn("The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead.");
308
+ }
309
+ this.options.protocols.forEach((protocol) => {
310
+ if (typeof protocol === "string") {
311
+ (0, linkifyjs.registerCustomProtocol)(protocol);
312
+ return;
313
+ }
314
+ (0, linkifyjs.registerCustomProtocol)(protocol.scheme, protocol.optionalSlashes);
315
+ });
316
+ },
317
+ onDestroy() {
318
+ (0, linkifyjs.reset)();
319
+ },
320
+ inclusive() {
321
+ return this.options.autolink;
322
+ },
323
+ addOptions() {
324
+ return {
325
+ openOnClick: true,
326
+ enableClickSelection: false,
327
+ linkOnPaste: true,
328
+ markdownLinks: false,
329
+ autolink: true,
330
+ protocols: [],
331
+ defaultProtocol: "http",
332
+ HTMLAttributes: {
333
+ target: "_blank",
334
+ rel: "noopener noreferrer nofollow",
335
+ class: null
336
+ },
337
+ isAllowedUri: (url, ctx) => !!isAllowedUri(url, ctx.protocols),
338
+ validate: (url) => !!url,
339
+ shouldAutoLink: (url) => {
340
+ const hasProtocol = /^[a-z][a-z0-9+.-]*:\/\//i.test(url);
341
+ const hasMaybeProtocol = /^[a-z][a-z0-9+.-]*:/i.test(url);
342
+ if (hasProtocol || hasMaybeProtocol && !url.includes("@")) return true;
343
+ const hostname = (url.includes("@") ? url.split("@").pop() : url).split(/[/?#:]/)[0];
344
+ if (/^\d{1,3}(\.\d{1,3}){3}$/.test(hostname)) return false;
345
+ if (!/\./.test(hostname)) return false;
346
+ return true;
347
+ }
348
+ };
349
+ },
350
+ addAttributes() {
351
+ var _this$options$HTMLAtt, _this$options$HTMLAtt2, _this$options$HTMLAtt3;
352
+ return {
353
+ href: {
354
+ default: null,
355
+ parseHTML(element) {
356
+ return element.getAttribute("href");
357
+ }
358
+ },
359
+ target: { default: (_this$options$HTMLAtt = this.options.HTMLAttributes.target) !== null && _this$options$HTMLAtt !== void 0 ? _this$options$HTMLAtt : null },
360
+ rel: { default: (_this$options$HTMLAtt2 = this.options.HTMLAttributes.rel) !== null && _this$options$HTMLAtt2 !== void 0 ? _this$options$HTMLAtt2 : null },
361
+ class: { default: (_this$options$HTMLAtt3 = this.options.HTMLAttributes.class) !== null && _this$options$HTMLAtt3 !== void 0 ? _this$options$HTMLAtt3 : null },
362
+ title: { default: null }
363
+ };
364
+ },
365
+ parseHTML() {
366
+ return [{
367
+ tag: "a[href]",
368
+ getAttrs: (dom) => {
369
+ const href = dom.getAttribute("href");
370
+ if (!href || !this.options.isAllowedUri(href, {
371
+ defaultValidate: (url) => !!isAllowedUri(url, this.options.protocols),
372
+ protocols: this.options.protocols,
373
+ defaultProtocol: this.options.defaultProtocol
374
+ })) return false;
375
+ return null;
376
+ }
377
+ }];
378
+ },
379
+ renderHTML({ HTMLAttributes }) {
380
+ if (!this.options.isAllowedUri(HTMLAttributes.href, {
381
+ defaultValidate: (href) => !!isAllowedUri(href, this.options.protocols),
382
+ protocols: this.options.protocols,
383
+ defaultProtocol: this.options.defaultProtocol
384
+ })) return [
385
+ "a",
386
+ (0, _tiptap_core.mergeAttributes)(this.options.HTMLAttributes, {
387
+ ...HTMLAttributes,
388
+ href: ""
389
+ }),
390
+ 0
391
+ ];
392
+ return [
393
+ "a",
394
+ (0, _tiptap_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes),
395
+ 0
396
+ ];
397
+ },
398
+ markdownTokenName: "link",
399
+ parseMarkdown: (token, helpers) => {
400
+ return helpers.applyMark("link", helpers.parseInline(token.tokens || []), {
401
+ href: token.href,
402
+ title: token.title || null
403
+ });
404
+ },
405
+ renderMarkdown: (node, h) => {
406
+ var _node$attrs$href, _node$attrs, _node$attrs$title, _node$attrs2;
407
+ const href = (_node$attrs$href = (_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.href) !== null && _node$attrs$href !== void 0 ? _node$attrs$href : "";
408
+ const title = (_node$attrs$title = (_node$attrs2 = node.attrs) === null || _node$attrs2 === void 0 ? void 0 : _node$attrs2.title) !== null && _node$attrs$title !== void 0 ? _node$attrs$title : "";
409
+ const text = h.renderChildren(node);
410
+ return title ? `[${text}](${href} "${title}")` : `[${text}](${href})`;
411
+ },
412
+ addCommands() {
413
+ return {
414
+ setLink: (attributes) => ({ chain }) => {
415
+ const { href } = attributes;
416
+ if (!this.options.isAllowedUri(href, {
417
+ defaultValidate: (url) => !!isAllowedUri(url, this.options.protocols),
418
+ protocols: this.options.protocols,
419
+ defaultProtocol: this.options.defaultProtocol
420
+ })) return false;
421
+ return chain().setMark(this.name, attributes).setMeta("preventAutolink", true).run();
422
+ },
423
+ toggleLink: (attributes) => ({ chain }) => {
424
+ const { href } = attributes || {};
425
+ if (href && !this.options.isAllowedUri(href, {
426
+ defaultValidate: (url) => !!isAllowedUri(url, this.options.protocols),
427
+ protocols: this.options.protocols,
428
+ defaultProtocol: this.options.defaultProtocol
429
+ })) return false;
430
+ return chain().toggleMark(this.name, attributes, { extendEmptyMarkRange: true }).setMeta("preventAutolink", true).run();
431
+ },
432
+ unsetLink: () => ({ chain }) => {
433
+ return chain().unsetMark(this.name, { extendEmptyMarkRange: true }).setMeta("preventAutolink", true).run();
434
+ }
435
+ };
436
+ },
437
+ addInputRules() {
438
+ if (!this.options.markdownLinks) return [];
439
+ return [markdownLinkInputRule({
440
+ type: this.type,
441
+ isAllowedHref: (href) => this.options.isAllowedUri(href, {
442
+ defaultValidate: (url) => !!isAllowedUri(url, this.options.protocols),
443
+ protocols: this.options.protocols,
444
+ defaultProtocol: this.options.defaultProtocol
445
+ })
446
+ })];
447
+ },
448
+ addPasteRules() {
449
+ const findPlainUrls = (text) => {
450
+ const foundLinks = [];
451
+ if (text) {
452
+ const { protocols, defaultProtocol } = this.options;
453
+ (0, linkifyjs.find)(text).filter((item) => item.isLink && this.options.isAllowedUri(item.value, {
454
+ defaultValidate: (href) => !!isAllowedUri(href, protocols),
455
+ protocols,
456
+ defaultProtocol
457
+ })).forEach((link) => {
458
+ if (!this.options.shouldAutoLink(link.value)) return;
459
+ foundLinks.push({
460
+ text: link.value,
461
+ data: { href: link.href },
462
+ index: link.start
463
+ });
464
+ });
465
+ }
466
+ return foundLinks;
467
+ };
468
+ if (this.options.markdownLinks) return [markdownLinkPasteRule({
469
+ type: this.type,
470
+ isAllowedHref: (href) => this.options.isAllowedUri(href, {
471
+ defaultValidate: (url) => !!isAllowedUri(url, this.options.protocols),
472
+ protocols: this.options.protocols,
473
+ defaultProtocol: this.options.defaultProtocol
474
+ }),
475
+ findPlainUrls
476
+ })];
477
+ return [(0, _tiptap_core.markPasteRule)({
478
+ find: findPlainUrls,
479
+ type: this.type,
480
+ getAttributes: (match) => {
481
+ var _match$data;
482
+ return { href: (_match$data = match.data) === null || _match$data === void 0 ? void 0 : _match$data.href };
483
+ }
484
+ })];
485
+ },
486
+ addProseMirrorPlugins() {
487
+ const plugins = [];
488
+ const { protocols, defaultProtocol } = this.options;
489
+ if (this.options.autolink) plugins.push(autolink({
490
+ type: this.type,
491
+ defaultProtocol: this.options.defaultProtocol,
492
+ validate: (url) => this.options.isAllowedUri(url, {
493
+ defaultValidate: (href) => !!isAllowedUri(href, protocols),
494
+ protocols,
495
+ defaultProtocol
496
+ }),
497
+ shouldAutoLink: this.options.shouldAutoLink
498
+ }));
499
+ plugins.push(clickHandler({
500
+ type: this.type,
501
+ editor: this.editor,
502
+ openOnClick: this.options.openOnClick === "whenNotEditable" ? true : this.options.openOnClick,
503
+ enableClickSelection: this.options.enableClickSelection
504
+ }));
505
+ if (this.options.linkOnPaste) plugins.push(pasteHandler({
506
+ editor: this.editor,
507
+ defaultProtocol: this.options.defaultProtocol,
508
+ type: this.type,
509
+ shouldAutoLink: this.options.shouldAutoLink
510
+ }));
511
+ return plugins;
512
+ }
653
513
  });
514
+ //#endregion
515
+ //#region src/index.ts
516
+ var src_default = Link;
517
+ //#endregion
518
+ exports.Link = Link;
519
+ exports.default = src_default;
520
+ exports.isAllowedUri = isAllowedUri;
521
+ exports.pasteRegex = pasteRegex;
654
522
 
655
- // src/index.ts
656
- var index_default = Link;
657
- // Annotate the CommonJS export names for ESM import in node:
658
- 0 && (module.exports = {
659
- Link,
660
- isAllowedUri,
661
- pasteRegex
662
- });
663
523
  //# sourceMappingURL=index.cjs.map