@tiptap/extension-link 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +5 -1
  3. package/dist/index.cjs +410 -319
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/{packages/extension-link/src/link.d.ts → index.d.cts} +57 -7
  6. package/dist/index.d.ts +149 -0
  7. package/dist/index.js +383 -315
  8. package/dist/index.js.map +1 -1
  9. package/package.json +14 -12
  10. package/src/helpers/autolink.ts +19 -31
  11. package/src/helpers/clickHandler.ts +25 -9
  12. package/src/helpers/pasteHandler.ts +6 -6
  13. package/src/helpers/whitespace.ts +7 -0
  14. package/src/link.ts +195 -47
  15. package/dist/index.umd.js +0 -344
  16. package/dist/index.umd.js.map +0 -1
  17. package/dist/packages/core/src/CommandManager.d.ts +0 -20
  18. package/dist/packages/core/src/Editor.d.ts +0 -161
  19. package/dist/packages/core/src/EventEmitter.d.ts +0 -11
  20. package/dist/packages/core/src/Extension.d.ts +0 -343
  21. package/dist/packages/core/src/ExtensionManager.d.ts +0 -55
  22. package/dist/packages/core/src/InputRule.d.ts +0 -42
  23. package/dist/packages/core/src/Mark.d.ts +0 -451
  24. package/dist/packages/core/src/Node.d.ts +0 -611
  25. package/dist/packages/core/src/NodePos.d.ts +0 -44
  26. package/dist/packages/core/src/NodeView.d.ts +0 -31
  27. package/dist/packages/core/src/PasteRule.d.ts +0 -50
  28. package/dist/packages/core/src/Tracker.d.ts +0 -11
  29. package/dist/packages/core/src/commands/blur.d.ts +0 -13
  30. package/dist/packages/core/src/commands/clearContent.d.ts +0 -14
  31. package/dist/packages/core/src/commands/clearNodes.d.ts +0 -13
  32. package/dist/packages/core/src/commands/command.d.ts +0 -18
  33. package/dist/packages/core/src/commands/createParagraphNear.d.ts +0 -13
  34. package/dist/packages/core/src/commands/cut.d.ts +0 -20
  35. package/dist/packages/core/src/commands/deleteCurrentNode.d.ts +0 -13
  36. package/dist/packages/core/src/commands/deleteNode.d.ts +0 -15
  37. package/dist/packages/core/src/commands/deleteRange.d.ts +0 -14
  38. package/dist/packages/core/src/commands/deleteSelection.d.ts +0 -13
  39. package/dist/packages/core/src/commands/enter.d.ts +0 -13
  40. package/dist/packages/core/src/commands/exitCode.d.ts +0 -13
  41. package/dist/packages/core/src/commands/extendMarkRange.d.ts +0 -25
  42. package/dist/packages/core/src/commands/first.d.ts +0 -14
  43. package/dist/packages/core/src/commands/focus.d.ts +0 -27
  44. package/dist/packages/core/src/commands/forEach.d.ts +0 -14
  45. package/dist/packages/core/src/commands/index.d.ts +0 -55
  46. package/dist/packages/core/src/commands/insertContent.d.ts +0 -34
  47. package/dist/packages/core/src/commands/insertContentAt.d.ts +0 -47
  48. package/dist/packages/core/src/commands/join.d.ts +0 -41
  49. package/dist/packages/core/src/commands/joinItemBackward.d.ts +0 -13
  50. package/dist/packages/core/src/commands/joinItemForward.d.ts +0 -13
  51. package/dist/packages/core/src/commands/joinTextblockBackward.d.ts +0 -12
  52. package/dist/packages/core/src/commands/joinTextblockForward.d.ts +0 -12
  53. package/dist/packages/core/src/commands/keyboardShortcut.d.ts +0 -14
  54. package/dist/packages/core/src/commands/lift.d.ts +0 -17
  55. package/dist/packages/core/src/commands/liftEmptyBlock.d.ts +0 -13
  56. package/dist/packages/core/src/commands/liftListItem.d.ts +0 -15
  57. package/dist/packages/core/src/commands/newlineInCode.d.ts +0 -13
  58. package/dist/packages/core/src/commands/resetAttributes.d.ts +0 -16
  59. package/dist/packages/core/src/commands/scrollIntoView.d.ts +0 -13
  60. package/dist/packages/core/src/commands/selectAll.d.ts +0 -13
  61. package/dist/packages/core/src/commands/selectNodeBackward.d.ts +0 -13
  62. package/dist/packages/core/src/commands/selectNodeForward.d.ts +0 -13
  63. package/dist/packages/core/src/commands/selectParentNode.d.ts +0 -13
  64. package/dist/packages/core/src/commands/selectTextblockEnd.d.ts +0 -13
  65. package/dist/packages/core/src/commands/selectTextblockStart.d.ts +0 -13
  66. package/dist/packages/core/src/commands/setContent.d.ts +0 -40
  67. package/dist/packages/core/src/commands/setMark.d.ts +0 -15
  68. package/dist/packages/core/src/commands/setMeta.d.ts +0 -15
  69. package/dist/packages/core/src/commands/setNode.d.ts +0 -16
  70. package/dist/packages/core/src/commands/setNodeSelection.d.ts +0 -14
  71. package/dist/packages/core/src/commands/setTextSelection.d.ts +0 -14
  72. package/dist/packages/core/src/commands/sinkListItem.d.ts +0 -15
  73. package/dist/packages/core/src/commands/splitBlock.d.ts +0 -17
  74. package/dist/packages/core/src/commands/splitListItem.d.ts +0 -15
  75. package/dist/packages/core/src/commands/toggleList.d.ts +0 -18
  76. package/dist/packages/core/src/commands/toggleMark.d.ts +0 -30
  77. package/dist/packages/core/src/commands/toggleNode.d.ts +0 -17
  78. package/dist/packages/core/src/commands/toggleWrap.d.ts +0 -16
  79. package/dist/packages/core/src/commands/undoInputRule.d.ts +0 -13
  80. package/dist/packages/core/src/commands/unsetAllMarks.d.ts +0 -13
  81. package/dist/packages/core/src/commands/unsetMark.d.ts +0 -25
  82. package/dist/packages/core/src/commands/updateAttributes.d.ts +0 -24
  83. package/dist/packages/core/src/commands/wrapIn.d.ts +0 -16
  84. package/dist/packages/core/src/commands/wrapInList.d.ts +0 -16
  85. package/dist/packages/core/src/extensions/clipboardTextSerializer.d.ts +0 -5
  86. package/dist/packages/core/src/extensions/commands.d.ts +0 -3
  87. package/dist/packages/core/src/extensions/editable.d.ts +0 -2
  88. package/dist/packages/core/src/extensions/focusEvents.d.ts +0 -2
  89. package/dist/packages/core/src/extensions/index.d.ts +0 -6
  90. package/dist/packages/core/src/extensions/keymap.d.ts +0 -2
  91. package/dist/packages/core/src/extensions/tabindex.d.ts +0 -2
  92. package/dist/packages/core/src/helpers/combineTransactionSteps.d.ts +0 -10
  93. package/dist/packages/core/src/helpers/createChainableState.d.ts +0 -10
  94. package/dist/packages/core/src/helpers/createDocument.d.ts +0 -12
  95. package/dist/packages/core/src/helpers/createNodeFromContent.d.ts +0 -15
  96. package/dist/packages/core/src/helpers/defaultBlockAt.d.ts +0 -7
  97. package/dist/packages/core/src/helpers/findChildren.d.ts +0 -9
  98. package/dist/packages/core/src/helpers/findChildrenInRange.d.ts +0 -10
  99. package/dist/packages/core/src/helpers/findParentNode.d.ts +0 -16
  100. package/dist/packages/core/src/helpers/findParentNodeClosestToPos.d.ts +0 -17
  101. package/dist/packages/core/src/helpers/generateHTML.d.ts +0 -8
  102. package/dist/packages/core/src/helpers/generateJSON.d.ts +0 -8
  103. package/dist/packages/core/src/helpers/generateText.d.ts +0 -12
  104. package/dist/packages/core/src/helpers/getAttributes.d.ts +0 -9
  105. package/dist/packages/core/src/helpers/getAttributesFromExtensions.d.ts +0 -6
  106. package/dist/packages/core/src/helpers/getChangedRanges.d.ts +0 -11
  107. package/dist/packages/core/src/helpers/getDebugJSON.d.ts +0 -8
  108. package/dist/packages/core/src/helpers/getExtensionField.d.ts +0 -9
  109. package/dist/packages/core/src/helpers/getHTMLFromFragment.d.ts +0 -2
  110. package/dist/packages/core/src/helpers/getMarkAttributes.d.ts +0 -3
  111. package/dist/packages/core/src/helpers/getMarkRange.d.ts +0 -3
  112. package/dist/packages/core/src/helpers/getMarkType.d.ts +0 -2
  113. package/dist/packages/core/src/helpers/getMarksBetween.d.ts +0 -3
  114. package/dist/packages/core/src/helpers/getNodeAtPosition.d.ts +0 -11
  115. package/dist/packages/core/src/helpers/getNodeAttributes.d.ts +0 -3
  116. package/dist/packages/core/src/helpers/getNodeType.d.ts +0 -2
  117. package/dist/packages/core/src/helpers/getRenderedAttributes.d.ts +0 -3
  118. package/dist/packages/core/src/helpers/getSchema.d.ts +0 -4
  119. package/dist/packages/core/src/helpers/getSchemaByResolvedExtensions.d.ts +0 -10
  120. package/dist/packages/core/src/helpers/getSchemaTypeByName.d.ts +0 -8
  121. package/dist/packages/core/src/helpers/getSchemaTypeNameByName.d.ts +0 -8
  122. package/dist/packages/core/src/helpers/getSplittedAttributes.d.ts +0 -9
  123. package/dist/packages/core/src/helpers/getText.d.ts +0 -15
  124. package/dist/packages/core/src/helpers/getTextBetween.d.ts +0 -14
  125. package/dist/packages/core/src/helpers/getTextContentFromNodes.d.ts +0 -8
  126. package/dist/packages/core/src/helpers/getTextSerializersFromSchema.d.ts +0 -8
  127. package/dist/packages/core/src/helpers/index.d.ts +0 -50
  128. package/dist/packages/core/src/helpers/injectExtensionAttributesToParseRule.d.ts +0 -9
  129. package/dist/packages/core/src/helpers/isActive.d.ts +0 -2
  130. package/dist/packages/core/src/helpers/isAtEndOfNode.d.ts +0 -2
  131. package/dist/packages/core/src/helpers/isAtStartOfNode.d.ts +0 -2
  132. package/dist/packages/core/src/helpers/isExtensionRulesEnabled.d.ts +0 -2
  133. package/dist/packages/core/src/helpers/isList.d.ts +0 -2
  134. package/dist/packages/core/src/helpers/isMarkActive.d.ts +0 -3
  135. package/dist/packages/core/src/helpers/isNodeActive.d.ts +0 -3
  136. package/dist/packages/core/src/helpers/isNodeEmpty.d.ts +0 -2
  137. package/dist/packages/core/src/helpers/isNodeSelection.d.ts +0 -2
  138. package/dist/packages/core/src/helpers/isTextSelection.d.ts +0 -2
  139. package/dist/packages/core/src/helpers/posToDOMRect.d.ts +0 -2
  140. package/dist/packages/core/src/helpers/resolveFocusPosition.d.ts +0 -4
  141. package/dist/packages/core/src/helpers/selectionToInsertionEnd.d.ts +0 -2
  142. package/dist/packages/core/src/helpers/splitExtensions.d.ts +0 -9
  143. package/dist/packages/core/src/index.d.ts +0 -24
  144. package/dist/packages/core/src/inputRules/index.d.ts +0 -5
  145. package/dist/packages/core/src/inputRules/markInputRule.d.ts +0 -13
  146. package/dist/packages/core/src/inputRules/nodeInputRule.d.ts +0 -23
  147. package/dist/packages/core/src/inputRules/textInputRule.d.ts +0 -10
  148. package/dist/packages/core/src/inputRules/textblockTypeInputRule.d.ts +0 -15
  149. package/dist/packages/core/src/inputRules/wrappingInputRule.d.ts +0 -28
  150. package/dist/packages/core/src/pasteRules/index.d.ts +0 -3
  151. package/dist/packages/core/src/pasteRules/markPasteRule.d.ts +0 -13
  152. package/dist/packages/core/src/pasteRules/nodePasteRule.d.ts +0 -13
  153. package/dist/packages/core/src/pasteRules/textPasteRule.d.ts +0 -10
  154. package/dist/packages/core/src/style.d.ts +0 -1
  155. package/dist/packages/core/src/types.d.ts +0 -255
  156. package/dist/packages/core/src/utilities/callOrReturn.d.ts +0 -9
  157. package/dist/packages/core/src/utilities/createStyleTag.d.ts +0 -1
  158. package/dist/packages/core/src/utilities/deleteProps.d.ts +0 -6
  159. package/dist/packages/core/src/utilities/elementFromString.d.ts +0 -1
  160. package/dist/packages/core/src/utilities/escapeForRegEx.d.ts +0 -1
  161. package/dist/packages/core/src/utilities/findDuplicates.d.ts +0 -1
  162. package/dist/packages/core/src/utilities/fromString.d.ts +0 -1
  163. package/dist/packages/core/src/utilities/index.d.ts +0 -20
  164. package/dist/packages/core/src/utilities/isAndroid.d.ts +0 -1
  165. package/dist/packages/core/src/utilities/isEmptyObject.d.ts +0 -1
  166. package/dist/packages/core/src/utilities/isFunction.d.ts +0 -1
  167. package/dist/packages/core/src/utilities/isMacOS.d.ts +0 -1
  168. package/dist/packages/core/src/utilities/isNumber.d.ts +0 -1
  169. package/dist/packages/core/src/utilities/isPlainObject.d.ts +0 -1
  170. package/dist/packages/core/src/utilities/isRegExp.d.ts +0 -1
  171. package/dist/packages/core/src/utilities/isString.d.ts +0 -1
  172. package/dist/packages/core/src/utilities/isiOS.d.ts +0 -1
  173. package/dist/packages/core/src/utilities/mergeAttributes.d.ts +0 -1
  174. package/dist/packages/core/src/utilities/mergeDeep.d.ts +0 -1
  175. package/dist/packages/core/src/utilities/minMax.d.ts +0 -1
  176. package/dist/packages/core/src/utilities/objectIncludes.d.ts +0 -8
  177. package/dist/packages/core/src/utilities/removeDuplicates.d.ts +0 -8
  178. package/dist/packages/extension-link/src/helpers/autolink.d.ts +0 -14
  179. package/dist/packages/extension-link/src/helpers/clickHandler.d.ts +0 -7
  180. package/dist/packages/extension-link/src/helpers/pasteHandler.d.ts +0 -10
  181. package/dist/packages/extension-link/src/index.d.ts +0 -3
package/dist/index.cjs CHANGED
@@ -1,342 +1,433 @@
1
- 'use strict';
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);
2
19
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
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
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+
30
+ // src/link.ts
31
+ var import_core3 = 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");
4
38
 
5
- var core = require('@tiptap/core');
6
- var linkifyjs = require('linkifyjs');
7
- var state = require('@tiptap/pm/state');
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");
8
44
 
9
- /**
10
- * Check if the provided tokens form a valid link structure, which can either be a single link token
11
- * or a link token surrounded by parentheses or square brackets.
12
- *
13
- * This ensures that only complete and valid text is hyperlinked, preventing cases where a valid
14
- * top-level domain (TLD) is immediately followed by an invalid character, like a number. For
15
- * example, with the `find` method from Linkify, entering `example.com1` would result in
16
- * `example.com` being linked and the trailing `1` left as plain text. By using the `tokenize`
17
- * method, we can perform more comprehensive validation on the input text.
18
- */
45
+ // src/helpers/autolink.ts
19
46
  function isValidLinkStructure(tokens) {
20
- if (tokens.length === 1) {
21
- return tokens[0].isLink;
22
- }
23
- if (tokens.length === 3 && tokens[1].isLink) {
24
- return ['()', '[]'].includes(tokens[0].value + tokens[2].value);
25
- }
26
- return false;
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;
27
54
  }
28
- /**
29
- * This plugin allows you to automatically add links to your editor.
30
- * @param options The plugin options
31
- * @returns The plugin instance
32
- */
33
55
  function autolink(options) {
34
- return new state.Plugin({
35
- key: new state.PluginKey('autolink'),
36
- appendTransaction: (transactions, oldState, newState) => {
37
- /**
38
- * Does the transaction change the document?
39
- */
40
- const docChanges = transactions.some(transaction => transaction.docChanged) && !oldState.doc.eq(newState.doc);
41
- /**
42
- * Prevent autolink if the transaction is not a document change or if the transaction has the meta `preventAutolink`.
43
- */
44
- const preventAutolink = transactions.some(transaction => transaction.getMeta('preventAutolink'));
45
- /**
46
- * Prevent autolink if the transaction is not a document change
47
- * or if the transaction has the meta `preventAutolink`.
48
- */
49
- if (!docChanges || preventAutolink) {
50
- return;
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((transaction) => transaction.getMeta("preventAutolink"));
61
+ if (!docChanges || preventAutolink) {
62
+ return;
63
+ }
64
+ const { tr } = newState;
65
+ const transform = (0, import_core.combineTransactionSteps)(oldState.doc, [...transactions]);
66
+ const changes = (0, import_core.getChangedRanges)(transform);
67
+ changes.forEach(({ newRange }) => {
68
+ const nodesInChangedRanges = (0, import_core.findChildrenInRange)(newState.doc, newRange, (node) => node.isTextblock);
69
+ let textBlock;
70
+ let textBeforeWhitespace;
71
+ if (nodesInChangedRanges.length > 1) {
72
+ textBlock = nodesInChangedRanges[0];
73
+ textBeforeWhitespace = newState.doc.textBetween(
74
+ textBlock.pos,
75
+ textBlock.pos + textBlock.node.nodeSize,
76
+ void 0,
77
+ " "
78
+ );
79
+ } else if (nodesInChangedRanges.length) {
80
+ const endText = newState.doc.textBetween(newRange.from, newRange.to, " ", " ");
81
+ if (!UNICODE_WHITESPACE_REGEX_END.test(endText)) {
82
+ return;
83
+ }
84
+ textBlock = nodesInChangedRanges[0];
85
+ textBeforeWhitespace = newState.doc.textBetween(textBlock.pos, newRange.to, void 0, " ");
86
+ }
87
+ if (textBlock && textBeforeWhitespace) {
88
+ const wordsBeforeWhitespace = textBeforeWhitespace.split(UNICODE_WHITESPACE_REGEX).filter(Boolean);
89
+ if (wordsBeforeWhitespace.length <= 0) {
90
+ return false;
91
+ }
92
+ const lastWordBeforeSpace = wordsBeforeWhitespace[wordsBeforeWhitespace.length - 1];
93
+ const lastWordAndBlockOffset = textBlock.pos + textBeforeWhitespace.lastIndexOf(lastWordBeforeSpace);
94
+ if (!lastWordBeforeSpace) {
95
+ return false;
96
+ }
97
+ const linksBeforeSpace = (0, import_linkifyjs.tokenize)(lastWordBeforeSpace).map((t) => t.toObject(options.defaultProtocol));
98
+ if (!isValidLinkStructure(linksBeforeSpace)) {
99
+ return false;
100
+ }
101
+ linksBeforeSpace.filter((link) => link.isLink).map((link) => ({
102
+ ...link,
103
+ from: lastWordAndBlockOffset + link.start + 1,
104
+ to: lastWordAndBlockOffset + link.end + 1
105
+ })).filter((link) => {
106
+ if (!newState.schema.marks.code) {
107
+ return true;
51
108
  }
52
- const { tr } = newState;
53
- const transform = core.combineTransactionSteps(oldState.doc, [...transactions]);
54
- const changes = core.getChangedRanges(transform);
55
- changes.forEach(({ newRange }) => {
56
- // Now let’s see if we can add new links.
57
- const nodesInChangedRanges = core.findChildrenInRange(newState.doc, newRange, node => node.isTextblock);
58
- let textBlock;
59
- let textBeforeWhitespace;
60
- if (nodesInChangedRanges.length > 1) {
61
- // Grab the first node within the changed ranges (ex. the first of two paragraphs when hitting enter).
62
- textBlock = nodesInChangedRanges[0];
63
- textBeforeWhitespace = newState.doc.textBetween(textBlock.pos, textBlock.pos + textBlock.node.nodeSize, undefined, ' ');
64
- }
65
- else if (nodesInChangedRanges.length
66
- // We want to make sure to include the block seperator argument to treat hard breaks like spaces.
67
- && newState.doc.textBetween(newRange.from, newRange.to, ' ', ' ').endsWith(' ')) {
68
- textBlock = nodesInChangedRanges[0];
69
- textBeforeWhitespace = newState.doc.textBetween(textBlock.pos, newRange.to, undefined, ' ');
70
- }
71
- if (textBlock && textBeforeWhitespace) {
72
- const wordsBeforeWhitespace = textBeforeWhitespace.split(' ').filter(s => s !== '');
73
- if (wordsBeforeWhitespace.length <= 0) {
74
- return false;
75
- }
76
- const lastWordBeforeSpace = wordsBeforeWhitespace[wordsBeforeWhitespace.length - 1];
77
- const lastWordAndBlockOffset = textBlock.pos + textBeforeWhitespace.lastIndexOf(lastWordBeforeSpace);
78
- if (!lastWordBeforeSpace) {
79
- return false;
80
- }
81
- const linksBeforeSpace = linkifyjs.tokenize(lastWordBeforeSpace).map(t => t.toObject(options.defaultProtocol));
82
- if (!isValidLinkStructure(linksBeforeSpace)) {
83
- return false;
84
- }
85
- linksBeforeSpace
86
- .filter(link => link.isLink)
87
- // Calculate link position.
88
- .map(link => ({
89
- ...link,
90
- from: lastWordAndBlockOffset + link.start + 1,
91
- to: lastWordAndBlockOffset + link.end + 1,
92
- }))
93
- // ignore link inside code mark
94
- .filter(link => {
95
- if (!newState.schema.marks.code) {
96
- return true;
97
- }
98
- return !newState.doc.rangeHasMark(link.from, link.to, newState.schema.marks.code);
99
- })
100
- // validate link
101
- .filter(link => options.validate(link.value))
102
- // Add link mark.
103
- .forEach(link => {
104
- if (core.getMarksBetween(link.from, link.to, newState.doc).some(item => item.mark.type === options.type)) {
105
- return;
106
- }
107
- tr.addMark(link.from, link.to, options.type.create({
108
- href: link.href,
109
- }));
110
- });
111
- }
112
- });
113
- if (!tr.steps.length) {
114
- return;
109
+ return !newState.doc.rangeHasMark(link.from, link.to, newState.schema.marks.code);
110
+ }).filter((link) => options.validate(link.value)).filter((link) => options.shouldAutoLink(link.value)).forEach((link) => {
111
+ if ((0, import_core.getMarksBetween)(link.from, link.to, newState.doc).some((item) => item.mark.type === options.type)) {
112
+ return;
115
113
  }
116
- return tr;
117
- },
118
- });
114
+ tr.addMark(
115
+ link.from,
116
+ link.to,
117
+ options.type.create({
118
+ href: link.href
119
+ })
120
+ );
121
+ });
122
+ }
123
+ });
124
+ if (!tr.steps.length) {
125
+ return;
126
+ }
127
+ return tr;
128
+ }
129
+ });
119
130
  }
120
131
 
132
+ // src/helpers/clickHandler.ts
133
+ var import_core2 = require("@tiptap/core");
134
+ var import_state2 = require("@tiptap/pm/state");
121
135
  function clickHandler(options) {
122
- return new state.Plugin({
123
- key: new state.PluginKey('handleClickLink'),
124
- props: {
125
- handleClick: (view, pos, event) => {
126
- var _a, _b;
127
- if (event.button !== 0) {
128
- return false;
129
- }
130
- let a = event.target;
131
- const els = [];
132
- while (a.nodeName !== 'DIV') {
133
- els.push(a);
134
- a = a.parentNode;
135
- }
136
- if (!els.find(value => value.nodeName === 'A')) {
137
- return false;
138
- }
139
- const attrs = core.getAttributes(view.state, options.type.name);
140
- const link = event.target;
141
- const href = (_a = link === null || link === void 0 ? void 0 : link.href) !== null && _a !== void 0 ? _a : attrs.href;
142
- const target = (_b = link === null || link === void 0 ? void 0 : link.target) !== null && _b !== void 0 ? _b : attrs.target;
143
- if (link && href) {
144
- window.open(href, target);
145
- return true;
146
- }
147
- return false;
148
- },
149
- },
150
- });
136
+ return new import_state2.Plugin({
137
+ key: new import_state2.PluginKey("handleClickLink"),
138
+ props: {
139
+ handleClick: (view, pos, event) => {
140
+ var _a, _b;
141
+ if (event.button !== 0) {
142
+ return false;
143
+ }
144
+ if (!view.editable) {
145
+ return false;
146
+ }
147
+ let link = null;
148
+ if (event.target instanceof HTMLAnchorElement) {
149
+ link = event.target;
150
+ } else {
151
+ let a = event.target;
152
+ const els = [];
153
+ while (a.nodeName !== "DIV") {
154
+ els.push(a);
155
+ a = a.parentNode;
156
+ }
157
+ link = els.find((value) => value.nodeName === "A");
158
+ }
159
+ if (!link) {
160
+ return false;
161
+ }
162
+ const attrs = (0, import_core2.getAttributes)(view.state, options.type.name);
163
+ const href = (_a = link == null ? void 0 : link.href) != null ? _a : attrs.href;
164
+ const target = (_b = link == null ? void 0 : link.target) != null ? _b : attrs.target;
165
+ if (options.enableClickSelection) {
166
+ options.editor.commands.extendMarkRange(options.type.name);
167
+ }
168
+ if (link && href) {
169
+ window.open(href, target);
170
+ return true;
171
+ }
172
+ return false;
173
+ }
174
+ }
175
+ });
151
176
  }
152
177
 
178
+ // src/helpers/pasteHandler.ts
179
+ var import_state3 = require("@tiptap/pm/state");
180
+ var import_linkifyjs2 = require("linkifyjs");
153
181
  function pasteHandler(options) {
154
- return new state.Plugin({
155
- key: new state.PluginKey('handlePasteLink'),
156
- props: {
157
- handlePaste: (view, event, slice) => {
158
- const { state } = view;
159
- const { selection } = state;
160
- const { empty } = selection;
161
- if (empty) {
162
- return false;
163
- }
164
- let textContent = '';
165
- slice.content.forEach(node => {
166
- textContent += node.textContent;
167
- });
168
- const link = linkifyjs.find(textContent, { defaultProtocol: options.defaultProtocol }).find(item => item.isLink && item.value === textContent);
169
- if (!textContent || !link) {
170
- return false;
171
- }
172
- options.editor.commands.setMark(options.type, {
173
- href: link.href,
174
- });
175
- return true;
176
- },
177
- },
178
- });
182
+ return new import_state3.Plugin({
183
+ key: new import_state3.PluginKey("handlePasteLink"),
184
+ props: {
185
+ handlePaste: (view, event, slice) => {
186
+ const { state } = view;
187
+ const { selection } = state;
188
+ const { empty } = selection;
189
+ if (empty) {
190
+ return false;
191
+ }
192
+ let textContent = "";
193
+ slice.content.forEach((node) => {
194
+ textContent += node.textContent;
195
+ });
196
+ const link = (0, import_linkifyjs2.find)(textContent, { defaultProtocol: options.defaultProtocol }).find(
197
+ (item) => item.isLink && item.value === textContent
198
+ );
199
+ if (!textContent || !link) {
200
+ return false;
201
+ }
202
+ return options.editor.commands.setMark(options.type, {
203
+ href: link.href
204
+ });
205
+ }
206
+ }
207
+ });
179
208
  }
180
209
 
181
- const pasteRegex = /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)/gi;
182
- // From DOMPurify
183
- // https://github.com/cure53/DOMPurify/blob/main/src/regexp.js
184
- const ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g; // eslint-disable-line no-control-regex
185
- const IS_ALLOWED_URI = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i; // eslint-disable-line no-useless-escape
186
- function isAllowedUri(uri) {
187
- return !uri || uri.replace(ATTR_WHITESPACE, '').match(IS_ALLOWED_URI);
210
+ // src/link.ts
211
+ var pasteRegex = /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)/gi;
212
+ function isAllowedUri(uri, protocols) {
213
+ const allowedProtocols = ["http", "https", "ftp", "ftps", "mailto", "tel", "callto", "sms", "cid", "xmpp"];
214
+ if (protocols) {
215
+ protocols.forEach((protocol) => {
216
+ const nextProtocol = typeof protocol === "string" ? protocol : protocol.scheme;
217
+ if (nextProtocol) {
218
+ allowedProtocols.push(nextProtocol);
219
+ }
220
+ });
221
+ }
222
+ return !uri || uri.replace(UNICODE_WHITESPACE_REGEX_GLOBAL, "").match(
223
+ new RegExp(
224
+ // eslint-disable-next-line no-useless-escape
225
+ `^(?:(?:${allowedProtocols.join("|")}):|[^a-z]|[a-z0-9+.-]+(?:[^a-z+.-:]|$))`,
226
+ "i"
227
+ )
228
+ );
188
229
  }
189
- /**
190
- * This extension allows you to create links.
191
- * @see https://www.tiptap.dev/api/marks/link
192
- */
193
- const Link = core.Mark.create({
194
- name: 'link',
195
- priority: 1000,
196
- keepOnSplit: false,
197
- exitable: true,
198
- onCreate() {
199
- this.options.protocols.forEach(protocol => {
200
- if (typeof protocol === 'string') {
201
- linkifyjs.registerCustomProtocol(protocol);
202
- return;
203
- }
204
- linkifyjs.registerCustomProtocol(protocol.scheme, protocol.optionalSlashes);
205
- });
206
- },
207
- onDestroy() {
208
- linkifyjs.reset();
209
- },
210
- inclusive() {
211
- return this.options.autolink;
212
- },
213
- addOptions() {
214
- return {
215
- openOnClick: true,
216
- linkOnPaste: true,
217
- autolink: true,
218
- protocols: [],
219
- defaultProtocol: 'http',
220
- HTMLAttributes: {
221
- target: '_blank',
222
- rel: 'noopener noreferrer nofollow',
223
- class: null,
224
- },
225
- validate: url => !!url,
226
- };
227
- },
228
- addAttributes() {
229
- return {
230
- href: {
231
- default: null,
232
- },
233
- target: {
234
- default: this.options.HTMLAttributes.target,
235
- },
236
- rel: {
237
- default: this.options.HTMLAttributes.rel,
238
- },
239
- class: {
240
- default: this.options.HTMLAttributes.class,
241
- },
242
- };
243
- },
244
- parseHTML() {
245
- return [{
246
- tag: 'a[href]',
247
- getAttrs: dom => {
248
- const href = dom.getAttribute('href');
249
- // prevent XSS attacks
250
- if (!href || !isAllowedUri(href)) {
251
- return false;
252
- }
253
- return { href };
254
- },
255
- }];
256
- },
257
- renderHTML({ HTMLAttributes }) {
258
- // prevent XSS attacks
259
- if (!isAllowedUri(HTMLAttributes.href)) {
260
- // strip out the href
261
- return ['a', core.mergeAttributes(this.options.HTMLAttributes, { ...HTMLAttributes, href: '' }), 0];
230
+ var Link = import_core3.Mark.create({
231
+ name: "link",
232
+ priority: 1e3,
233
+ keepOnSplit: false,
234
+ exitable: true,
235
+ onCreate() {
236
+ if (this.options.validate && !this.options.shouldAutoLink) {
237
+ this.options.shouldAutoLink = this.options.validate;
238
+ console.warn("The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead.");
239
+ }
240
+ this.options.protocols.forEach((protocol) => {
241
+ if (typeof protocol === "string") {
242
+ (0, import_linkifyjs3.registerCustomProtocol)(protocol);
243
+ return;
244
+ }
245
+ (0, import_linkifyjs3.registerCustomProtocol)(protocol.scheme, protocol.optionalSlashes);
246
+ });
247
+ },
248
+ onDestroy() {
249
+ (0, import_linkifyjs3.reset)();
250
+ },
251
+ inclusive() {
252
+ return this.options.autolink;
253
+ },
254
+ addOptions() {
255
+ return {
256
+ openOnClick: true,
257
+ enableClickSelection: false,
258
+ linkOnPaste: true,
259
+ autolink: true,
260
+ protocols: [],
261
+ defaultProtocol: "http",
262
+ HTMLAttributes: {
263
+ target: "_blank",
264
+ rel: "noopener noreferrer nofollow",
265
+ class: null
266
+ },
267
+ isAllowedUri: (url, ctx) => !!isAllowedUri(url, ctx.protocols),
268
+ validate: (url) => !!url,
269
+ shouldAutoLink: (url) => !!url
270
+ };
271
+ },
272
+ addAttributes() {
273
+ return {
274
+ href: {
275
+ default: null,
276
+ parseHTML(element) {
277
+ return element.getAttribute("href");
278
+ }
279
+ },
280
+ target: {
281
+ default: this.options.HTMLAttributes.target
282
+ },
283
+ rel: {
284
+ default: this.options.HTMLAttributes.rel
285
+ },
286
+ class: {
287
+ default: this.options.HTMLAttributes.class
288
+ }
289
+ };
290
+ },
291
+ parseHTML() {
292
+ return [
293
+ {
294
+ tag: "a[href]",
295
+ getAttrs: (dom) => {
296
+ const href = dom.getAttribute("href");
297
+ if (!href || !this.options.isAllowedUri(href, {
298
+ defaultValidate: (url) => !!isAllowedUri(url, this.options.protocols),
299
+ protocols: this.options.protocols,
300
+ defaultProtocol: this.options.defaultProtocol
301
+ })) {
302
+ return false;
303
+ }
304
+ return null;
262
305
  }
263
- return ['a', core.mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
264
- },
265
- addCommands() {
266
- return {
267
- setLink: attributes => ({ chain }) => {
268
- return chain().setMark(this.name, attributes).setMeta('preventAutolink', true).run();
269
- },
270
- toggleLink: attributes => ({ chain }) => {
271
- return chain()
272
- .toggleMark(this.name, attributes, { extendEmptyMarkRange: true })
273
- .setMeta('preventAutolink', true)
274
- .run();
275
- },
276
- unsetLink: () => ({ chain }) => {
277
- return chain()
278
- .unsetMark(this.name, { extendEmptyMarkRange: true })
279
- .setMeta('preventAutolink', true)
280
- .run();
281
- },
282
- };
283
- },
284
- addPasteRules() {
285
- return [
286
- core.markPasteRule({
287
- find: text => {
288
- const foundLinks = [];
289
- if (text) {
290
- const { validate } = this.options;
291
- const links = linkifyjs.find(text).filter(item => item.isLink && validate(item.value));
292
- if (links.length) {
293
- links.forEach(link => (foundLinks.push({
294
- text: link.value,
295
- data: {
296
- href: link.href,
297
- },
298
- index: link.start,
299
- })));
300
- }
301
- }
302
- return foundLinks;
303
- },
304
- type: this.type,
305
- getAttributes: match => {
306
- var _a;
307
- return {
308
- href: (_a = match.data) === null || _a === void 0 ? void 0 : _a.href,
309
- };
310
- },
311
- }),
312
- ];
313
- },
314
- addProseMirrorPlugins() {
315
- const plugins = [];
316
- if (this.options.autolink) {
317
- plugins.push(autolink({
318
- type: this.type,
319
- defaultProtocol: this.options.defaultProtocol,
320
- validate: this.options.validate,
321
- }));
306
+ }
307
+ ];
308
+ },
309
+ renderHTML({ HTMLAttributes }) {
310
+ if (!this.options.isAllowedUri(HTMLAttributes.href, {
311
+ defaultValidate: (href) => !!isAllowedUri(href, this.options.protocols),
312
+ protocols: this.options.protocols,
313
+ defaultProtocol: this.options.defaultProtocol
314
+ })) {
315
+ return ["a", (0, import_core3.mergeAttributes)(this.options.HTMLAttributes, { ...HTMLAttributes, href: "" }), 0];
316
+ }
317
+ return ["a", (0, import_core3.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes), 0];
318
+ },
319
+ addCommands() {
320
+ return {
321
+ setLink: (attributes) => ({ chain }) => {
322
+ const { href } = attributes;
323
+ if (!this.options.isAllowedUri(href, {
324
+ defaultValidate: (url) => !!isAllowedUri(url, this.options.protocols),
325
+ protocols: this.options.protocols,
326
+ defaultProtocol: this.options.defaultProtocol
327
+ })) {
328
+ return false;
322
329
  }
323
- if (this.options.openOnClick) {
324
- plugins.push(clickHandler({
325
- type: this.type,
326
- }));
330
+ return chain().setMark(this.name, attributes).setMeta("preventAutolink", true).run();
331
+ },
332
+ toggleLink: (attributes) => ({ chain }) => {
333
+ const { href } = attributes || {};
334
+ if (href && !this.options.isAllowedUri(href, {
335
+ defaultValidate: (url) => !!isAllowedUri(url, this.options.protocols),
336
+ protocols: this.options.protocols,
337
+ defaultProtocol: this.options.defaultProtocol
338
+ })) {
339
+ return false;
327
340
  }
328
- if (this.options.linkOnPaste) {
329
- plugins.push(pasteHandler({
330
- editor: this.editor,
331
- defaultProtocol: this.options.defaultProtocol,
332
- type: this.type,
333
- }));
341
+ return chain().toggleMark(this.name, attributes, { extendEmptyMarkRange: true }).setMeta("preventAutolink", true).run();
342
+ },
343
+ unsetLink: () => ({ chain }) => {
344
+ return chain().unsetMark(this.name, { extendEmptyMarkRange: true }).setMeta("preventAutolink", true).run();
345
+ }
346
+ };
347
+ },
348
+ addPasteRules() {
349
+ return [
350
+ (0, import_core3.markPasteRule)({
351
+ find: (text) => {
352
+ const foundLinks = [];
353
+ if (text) {
354
+ const { protocols, defaultProtocol } = this.options;
355
+ const links = (0, import_linkifyjs3.find)(text).filter(
356
+ (item) => item.isLink && this.options.isAllowedUri(item.value, {
357
+ defaultValidate: (href) => !!isAllowedUri(href, protocols),
358
+ protocols,
359
+ defaultProtocol
360
+ })
361
+ );
362
+ if (links.length) {
363
+ links.forEach(
364
+ (link) => foundLinks.push({
365
+ text: link.value,
366
+ data: {
367
+ href: link.href
368
+ },
369
+ index: link.start
370
+ })
371
+ );
372
+ }
373
+ }
374
+ return foundLinks;
375
+ },
376
+ type: this.type,
377
+ getAttributes: (match) => {
378
+ var _a;
379
+ return {
380
+ href: (_a = match.data) == null ? void 0 : _a.href
381
+ };
334
382
  }
335
- return plugins;
336
- },
383
+ })
384
+ ];
385
+ },
386
+ addProseMirrorPlugins() {
387
+ const plugins = [];
388
+ const { protocols, defaultProtocol } = this.options;
389
+ if (this.options.autolink) {
390
+ plugins.push(
391
+ autolink({
392
+ type: this.type,
393
+ defaultProtocol: this.options.defaultProtocol,
394
+ validate: (url) => this.options.isAllowedUri(url, {
395
+ defaultValidate: (href) => !!isAllowedUri(href, protocols),
396
+ protocols,
397
+ defaultProtocol
398
+ }),
399
+ shouldAutoLink: this.options.shouldAutoLink
400
+ })
401
+ );
402
+ }
403
+ if (this.options.openOnClick === true) {
404
+ plugins.push(
405
+ clickHandler({
406
+ type: this.type,
407
+ editor: this.editor,
408
+ enableClickSelection: this.options.enableClickSelection
409
+ })
410
+ );
411
+ }
412
+ if (this.options.linkOnPaste) {
413
+ plugins.push(
414
+ pasteHandler({
415
+ editor: this.editor,
416
+ defaultProtocol: this.options.defaultProtocol,
417
+ type: this.type
418
+ })
419
+ );
420
+ }
421
+ return plugins;
422
+ }
337
423
  });
338
424
 
339
- exports.Link = Link;
340
- exports.default = Link;
341
- exports.pasteRegex = pasteRegex;
342
- //# sourceMappingURL=index.cjs.map
425
+ // src/index.ts
426
+ var index_default = Link;
427
+ // Annotate the CommonJS export names for ESM import in node:
428
+ 0 && (module.exports = {
429
+ Link,
430
+ isAllowedUri,
431
+ pasteRegex
432
+ });
433
+ //# sourceMappingURL=index.cjs.map