@tiptap/extension-link 3.23.5 → 3.24.0

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
@@ -57,7 +57,9 @@ function autolink(options) {
57
57
  key: new import_state.PluginKey("autolink"),
58
58
  appendTransaction: (transactions, oldState, newState) => {
59
59
  const docChanges = transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc);
60
- const preventAutolink = transactions.some((transaction) => transaction.getMeta("preventAutolink"));
60
+ const preventAutolink = transactions.some(
61
+ (transaction) => transaction.getMeta("preventAutolink")
62
+ );
61
63
  if (!docChanges || preventAutolink) {
62
64
  return;
63
65
  }
@@ -65,7 +67,11 @@ function autolink(options) {
65
67
  const transform = (0, import_core.combineTransactionSteps)(oldState.doc, [...transactions]);
66
68
  const changes = (0, import_core.getChangedRanges)(transform);
67
69
  changes.forEach(({ newRange }) => {
68
- const nodesInChangedRanges = (0, import_core.findChildrenInRange)(newState.doc, newRange, (node) => node.isTextblock);
70
+ const nodesInChangedRanges = (0, import_core.findChildrenInRange)(
71
+ newState.doc,
72
+ newRange,
73
+ (node) => node.isTextblock
74
+ );
69
75
  let textBlock;
70
76
  let textBeforeWhitespace;
71
77
  if (nodesInChangedRanges.length > 1) {
@@ -82,7 +88,12 @@ function autolink(options) {
82
88
  return;
83
89
  }
84
90
  textBlock = nodesInChangedRanges[0];
85
- textBeforeWhitespace = newState.doc.textBetween(textBlock.pos, newRange.to, void 0, " ");
91
+ textBeforeWhitespace = newState.doc.textBetween(
92
+ textBlock.pos,
93
+ newRange.to,
94
+ void 0,
95
+ " "
96
+ );
86
97
  }
87
98
  if (textBlock && textBeforeWhitespace) {
88
99
  const wordsBeforeWhitespace = textBeforeWhitespace.split(UNICODE_WHITESPACE_REGEX).filter(Boolean);
@@ -94,7 +105,9 @@ function autolink(options) {
94
105
  if (!lastWordBeforeSpace) {
95
106
  return false;
96
107
  }
97
- const linksBeforeSpace = (0, import_linkifyjs.tokenize)(lastWordBeforeSpace).map((t) => t.toObject(options.defaultProtocol));
108
+ const linksBeforeSpace = (0, import_linkifyjs.tokenize)(lastWordBeforeSpace).map(
109
+ (t) => t.toObject(options.defaultProtocol)
110
+ );
98
111
  if (!isValidLinkStructure(linksBeforeSpace)) {
99
112
  return false;
100
113
  }
@@ -108,7 +121,9 @@ function autolink(options) {
108
121
  }
109
122
  return !newState.doc.rangeHasMark(link.from, link.to, newState.schema.marks.code);
110
123
  }).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)) {
124
+ if ((0, import_core.getMarksBetween)(link.from, link.to, newState.doc).some(
125
+ (item) => item.mark.type === options.type
126
+ )) {
112
127
  return;
113
128
  }
114
129
  tr.addMark(
@@ -217,7 +232,18 @@ function pasteHandler(options) {
217
232
  // src/link.ts
218
233
  var pasteRegex = /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)/gi;
219
234
  function isAllowedUri(uri, protocols) {
220
- const allowedProtocols = ["http", "https", "ftp", "ftps", "mailto", "tel", "callto", "sms", "cid", "xmpp"];
235
+ const allowedProtocols = [
236
+ "http",
237
+ "https",
238
+ "ftp",
239
+ "ftps",
240
+ "mailto",
241
+ "tel",
242
+ "callto",
243
+ "sms",
244
+ "cid",
245
+ "xmpp"
246
+ ];
221
247
  if (protocols) {
222
248
  protocols.forEach((protocol) => {
223
249
  const nextProtocol = typeof protocol === "string" ? protocol : protocol.scheme;
@@ -228,7 +254,7 @@ function isAllowedUri(uri, protocols) {
228
254
  }
229
255
  return !uri || uri.replace(UNICODE_WHITESPACE_REGEX_GLOBAL, "").match(
230
256
  new RegExp(
231
- // eslint-disable-next-line no-useless-escape
257
+ // oxlint-disable-next-line no-useless-escape
232
258
  `^(?:(?:${allowedProtocols.join("|")}):|[^a-z]|[a-z0-9+.-]+(?:[^a-z+.-:]|$))`,
233
259
  "i"
234
260
  )
@@ -242,7 +268,9 @@ var Link = import_core3.Mark.create({
242
268
  onCreate() {
243
269
  if (this.options.validate && !this.options.shouldAutoLink) {
244
270
  this.options.shouldAutoLink = this.options.validate;
245
- console.warn("The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead.");
271
+ console.warn(
272
+ "The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead."
273
+ );
246
274
  }
247
275
  this.options.protocols.forEach((protocol) => {
248
276
  if (typeof protocol === "string") {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/link.ts","../src/helpers/autolink.ts","../src/helpers/whitespace.ts","../src/helpers/clickHandler.ts","../src/helpers/pasteHandler.ts"],"sourcesContent":["import { Link } from './link.js'\n\nexport * from './link.js'\n\nexport default Link\n","import type { PasteRuleMatch } from '@tiptap/core'\nimport { Mark, markPasteRule, mergeAttributes } from '@tiptap/core'\nimport type { Plugin } from '@tiptap/pm/state'\nimport { find, registerCustomProtocol, reset } from 'linkifyjs'\n\nimport { autolink } from './helpers/autolink.js'\nimport { clickHandler } from './helpers/clickHandler.js'\nimport { pasteHandler } from './helpers/pasteHandler.js'\nimport { UNICODE_WHITESPACE_REGEX_GLOBAL } from './helpers/whitespace.js'\n\nexport interface LinkProtocolOptions {\n /**\n * The protocol scheme to be registered.\n * @default '''\n * @example 'ftp'\n * @example 'git'\n */\n scheme: string\n\n /**\n * If enabled, it allows optional slashes after the protocol.\n * @default false\n * @example true\n */\n optionalSlashes?: boolean\n}\n\nexport const pasteRegex =\n /https?:\\/\\/(?:www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z]{2,}\\b(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)/gi\n\n/**\n * @deprecated The default behavior is now to open links when the editor is not editable.\n */\ntype DeprecatedOpenWhenNotEditable = 'whenNotEditable'\n\nexport interface LinkOptions {\n /**\n * If enabled, the extension will automatically add links as you type.\n * @default true\n * @example false\n */\n autolink: boolean\n\n /**\n * An array of custom protocols to be registered with linkifyjs.\n * @default []\n * @example ['ftp', 'git']\n */\n protocols: Array<LinkProtocolOptions | string>\n\n /**\n * Default protocol to use when no protocol is specified.\n * @default 'http'\n */\n defaultProtocol: string\n /**\n * If enabled, links will be opened on click.\n * @default true\n * @example false\n */\n openOnClick: boolean | DeprecatedOpenWhenNotEditable\n /**\n * If enabled, the link will be selected when clicked.\n * @default false\n * @example true\n */\n enableClickSelection: boolean\n /**\n * Adds a link to the current selection if the pasted content only contains an url.\n * @default true\n * @example false\n */\n linkOnPaste: boolean\n\n /**\n * HTML attributes to add to the link element.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>\n\n /**\n * @deprecated Use the `shouldAutoLink` option instead.\n * A validation function that modifies link verification for the auto linker.\n * @param url - The url to be validated.\n * @returns - True if the url is valid, false otherwise.\n */\n validate: (url: string) => boolean\n\n /**\n * A validation function which is used for configuring link verification for preventing XSS attacks.\n * Only modify this if you know what you're doing.\n *\n * @returns {boolean} `true` if the URL is valid, `false` otherwise.\n *\n * @example\n * isAllowedUri: (url, { defaultValidate, protocols, defaultProtocol }) => {\n * return url.startsWith('./') || defaultValidate(url)\n * }\n */\n isAllowedUri: (\n /**\n * The URL to be validated.\n */\n url: string,\n ctx: {\n /**\n * The default validation function.\n */\n defaultValidate: (url: string) => boolean\n /**\n * An array of allowed protocols for the URL (e.g., \"http\", \"https\"). As defined in the `protocols` option.\n */\n protocols: Array<LinkProtocolOptions | string>\n /**\n * A string that represents the default protocol (e.g., 'http'). As defined in the `defaultProtocol` option.\n */\n defaultProtocol: string\n },\n ) => boolean\n\n /**\n * Determines whether a valid link should be automatically linked in the content.\n *\n * @param {string} url - The URL that has already been validated.\n * @returns {boolean} - True if the link should be auto-linked; false if it should not be auto-linked.\n */\n shouldAutoLink: (url: string) => boolean\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n link: {\n /**\n * Set a link mark\n * @param attributes The link attributes\n * @example editor.commands.setLink({ href: 'https://tiptap.dev' })\n */\n setLink: (attributes: {\n href: string\n target?: string | null\n rel?: string | null\n class?: string | null\n title?: string | null\n }) => ReturnType\n /**\n * Toggle a link mark\n * @param attributes The link attributes\n * @example editor.commands.toggleLink({ href: 'https://tiptap.dev' })\n */\n toggleLink: (attributes?: {\n href: string\n target?: string | null\n rel?: string | null\n class?: string | null\n title?: string | null\n }) => ReturnType\n /**\n * Unset a link mark\n * @example editor.commands.unsetLink()\n */\n unsetLink: () => ReturnType\n }\n }\n}\n\nexport function isAllowedUri(uri: string | undefined, protocols?: LinkOptions['protocols']) {\n const allowedProtocols: string[] = ['http', 'https', 'ftp', 'ftps', 'mailto', 'tel', 'callto', 'sms', 'cid', 'xmpp']\n\n if (protocols) {\n protocols.forEach(protocol => {\n const nextProtocol = typeof protocol === 'string' ? protocol : protocol.scheme\n\n if (nextProtocol) {\n allowedProtocols.push(nextProtocol)\n }\n })\n }\n\n return (\n !uri ||\n uri.replace(UNICODE_WHITESPACE_REGEX_GLOBAL, '').match(\n new RegExp(\n // eslint-disable-next-line no-useless-escape\n `^(?:(?:${allowedProtocols.join('|')}):|[^a-z]|[a-z0-9+.\\-]+(?:[^a-z+.\\-:]|$))`,\n 'i',\n ),\n )\n )\n}\n\n/**\n * This extension allows you to create links.\n * @see https://www.tiptap.dev/api/marks/link\n */\nexport const Link = Mark.create<LinkOptions>({\n name: 'link',\n\n priority: 1000,\n\n keepOnSplit: false,\n\n exitable: true,\n\n onCreate() {\n // TODO: v4 - remove validate option\n if (this.options.validate && !this.options.shouldAutoLink) {\n // Copy the validate function to the shouldAutoLink option\n this.options.shouldAutoLink = this.options.validate\n console.warn('The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead.')\n }\n this.options.protocols.forEach(protocol => {\n if (typeof protocol === 'string') {\n registerCustomProtocol(protocol)\n return\n }\n registerCustomProtocol(protocol.scheme, protocol.optionalSlashes)\n })\n },\n\n onDestroy() {\n reset()\n },\n\n inclusive() {\n return this.options.autolink\n },\n\n addOptions() {\n return {\n openOnClick: true,\n enableClickSelection: false,\n linkOnPaste: true,\n autolink: true,\n protocols: [],\n defaultProtocol: 'http',\n HTMLAttributes: {\n target: '_blank',\n rel: 'noopener noreferrer nofollow',\n class: null,\n },\n isAllowedUri: (url, ctx) => !!isAllowedUri(url, ctx.protocols),\n validate: url => !!url,\n shouldAutoLink: url => {\n // URLs with explicit protocols (e.g., https://) should be auto-linked\n // But not if @ appears before :// (that would be userinfo like user:pass@host)\n const hasProtocol = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(url)\n const hasMaybeProtocol = /^[a-z][a-z0-9+.-]*:/i.test(url)\n\n if (hasProtocol || (hasMaybeProtocol && !url.includes('@'))) {\n return true\n }\n // Strip userinfo (user:pass@) if present, then extract hostname\n const urlWithoutUserinfo = url.includes('@') ? url.split('@').pop()! : url\n const hostname = urlWithoutUserinfo.split(/[/?#:]/)[0]\n\n // Don't auto-link IP addresses without protocol\n if (/^\\d{1,3}(\\.\\d{1,3}){3}$/.test(hostname)) {\n return false\n }\n // Don't auto-link single-word hostnames without TLD (e.g., \"localhost\")\n if (!/\\./.test(hostname)) {\n return false\n }\n return true\n },\n }\n },\n\n addAttributes() {\n return {\n href: {\n default: null,\n parseHTML(element) {\n return element.getAttribute('href')\n },\n },\n target: {\n default: this.options.HTMLAttributes.target,\n },\n rel: {\n default: this.options.HTMLAttributes.rel,\n },\n class: {\n default: this.options.HTMLAttributes.class,\n },\n title: {\n default: null,\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'a[href]',\n getAttrs: dom => {\n const href = (dom as HTMLElement).getAttribute('href')\n\n // prevent XSS attacks\n if (\n !href ||\n !this.options.isAllowedUri(href, {\n defaultValidate: url => !!isAllowedUri(url, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n return false\n }\n return null\n },\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n // prevent XSS attacks\n if (\n !this.options.isAllowedUri(HTMLAttributes.href, {\n defaultValidate: href => !!isAllowedUri(href, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n // strip out the href\n return ['a', mergeAttributes(this.options.HTMLAttributes, { ...HTMLAttributes, href: '' }), 0]\n }\n\n return ['a', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]\n },\n\n markdownTokenName: 'link',\n\n parseMarkdown: (token, helpers) => {\n return helpers.applyMark('link', helpers.parseInline(token.tokens || []), {\n href: token.href,\n title: token.title || null,\n })\n },\n\n renderMarkdown: (node, h) => {\n const href = node.attrs?.href ?? ''\n const title = node.attrs?.title ?? ''\n const text = h.renderChildren(node)\n\n return title ? `[${text}](${href} \"${title}\")` : `[${text}](${href})`\n },\n\n addCommands() {\n return {\n setLink:\n attributes =>\n ({ chain }) => {\n const { href } = attributes\n\n if (\n !this.options.isAllowedUri(href, {\n defaultValidate: url => !!isAllowedUri(url, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n return false\n }\n\n return chain().setMark(this.name, attributes).setMeta('preventAutolink', true).run()\n },\n\n toggleLink:\n attributes =>\n ({ chain }) => {\n const { href } = attributes || {}\n\n if (\n href &&\n !this.options.isAllowedUri(href, {\n defaultValidate: url => !!isAllowedUri(url, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n return false\n }\n\n return chain()\n .toggleMark(this.name, attributes, { extendEmptyMarkRange: true })\n .setMeta('preventAutolink', true)\n .run()\n },\n\n unsetLink:\n () =>\n ({ chain }) => {\n return chain().unsetMark(this.name, { extendEmptyMarkRange: true }).setMeta('preventAutolink', true).run()\n },\n }\n },\n\n addPasteRules() {\n return [\n markPasteRule({\n find: text => {\n const foundLinks: PasteRuleMatch[] = []\n\n if (text) {\n const { protocols, defaultProtocol } = this.options\n const links = find(text).filter(\n item =>\n item.isLink &&\n this.options.isAllowedUri(item.value, {\n defaultValidate: href => !!isAllowedUri(href, protocols),\n protocols,\n defaultProtocol,\n }),\n )\n\n if (links.length) {\n links.forEach(link => {\n if (!this.options.shouldAutoLink(link.value)) {\n return\n }\n\n foundLinks.push({\n text: link.value,\n data: {\n href: link.href,\n },\n index: link.start,\n })\n })\n }\n }\n\n return foundLinks\n },\n type: this.type,\n getAttributes: match => {\n return {\n href: match.data?.href,\n }\n },\n }),\n ]\n },\n\n addProseMirrorPlugins() {\n const plugins: Plugin[] = []\n const { protocols, defaultProtocol } = this.options\n\n if (this.options.autolink) {\n plugins.push(\n autolink({\n type: this.type,\n defaultProtocol: this.options.defaultProtocol,\n validate: url =>\n this.options.isAllowedUri(url, {\n defaultValidate: href => !!isAllowedUri(href, protocols),\n protocols,\n defaultProtocol,\n }),\n shouldAutoLink: this.options.shouldAutoLink,\n }),\n )\n }\n\n plugins.push(\n clickHandler({\n type: this.type,\n editor: this.editor,\n openOnClick: this.options.openOnClick === 'whenNotEditable' ? true : this.options.openOnClick,\n enableClickSelection: this.options.enableClickSelection,\n }),\n )\n\n if (this.options.linkOnPaste) {\n plugins.push(\n pasteHandler({\n editor: this.editor,\n defaultProtocol: this.options.defaultProtocol,\n type: this.type,\n shouldAutoLink: this.options.shouldAutoLink,\n }),\n )\n }\n\n return plugins\n },\n})\n","import type { NodeWithPos } from '@tiptap/core'\nimport { combineTransactionSteps, findChildrenInRange, getChangedRanges, getMarksBetween } from '@tiptap/core'\nimport type { MarkType } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport type { MultiToken } from 'linkifyjs'\nimport { tokenize } from 'linkifyjs'\n\nimport { UNICODE_WHITESPACE_REGEX, UNICODE_WHITESPACE_REGEX_END } from './whitespace.js'\n\n/**\n * Check if the provided tokens form a valid link structure, which can either be a single link token\n * or a link token surrounded by parentheses or square brackets.\n *\n * This ensures that only complete and valid text is hyperlinked, preventing cases where a valid\n * top-level domain (TLD) is immediately followed by an invalid character, like a number. For\n * example, with the `find` method from Linkify, entering `example.com1` would result in\n * `example.com` being linked and the trailing `1` left as plain text. By using the `tokenize`\n * method, we can perform more comprehensive validation on the input text.\n */\nfunction isValidLinkStructure(tokens: Array<ReturnType<MultiToken['toObject']>>) {\n if (tokens.length === 1) {\n return tokens[0].isLink\n }\n\n if (tokens.length === 3 && tokens[1].isLink) {\n return ['()', '[]'].includes(tokens[0].value + tokens[2].value)\n }\n\n return false\n}\n\ntype AutolinkOptions = {\n type: MarkType\n defaultProtocol: string\n validate: (url: string) => boolean\n shouldAutoLink: (url: string) => boolean\n}\n\n/**\n * This plugin allows you to automatically add links to your editor.\n * @param options The plugin options\n * @returns The plugin instance\n */\nexport function autolink(options: AutolinkOptions): Plugin {\n return new Plugin({\n key: new PluginKey('autolink'),\n appendTransaction: (transactions, oldState, newState) => {\n /**\n * Does the transaction change the document?\n */\n const docChanges = transactions.some(transaction => transaction.docChanged) && !oldState.doc.eq(newState.doc)\n\n /**\n * Prevent autolink if the transaction is not a document change or if the transaction has the meta `preventAutolink`.\n */\n const preventAutolink = transactions.some(transaction => transaction.getMeta('preventAutolink'))\n\n /**\n * Prevent autolink if the transaction is not a document change\n * or if the transaction has the meta `preventAutolink`.\n */\n if (!docChanges || preventAutolink) {\n return\n }\n\n const { tr } = newState\n const transform = combineTransactionSteps(oldState.doc, [...transactions])\n const changes = getChangedRanges(transform)\n\n changes.forEach(({ newRange }) => {\n // Now let’s see if we can add new links.\n const nodesInChangedRanges = findChildrenInRange(newState.doc, newRange, node => node.isTextblock)\n\n let textBlock: NodeWithPos | undefined\n let textBeforeWhitespace: string | undefined\n\n if (nodesInChangedRanges.length > 1) {\n // Grab the first node within the changed ranges (ex. the first of two paragraphs when hitting enter).\n textBlock = nodesInChangedRanges[0]\n textBeforeWhitespace = newState.doc.textBetween(\n textBlock.pos,\n textBlock.pos + textBlock.node.nodeSize,\n undefined,\n ' ',\n )\n } else if (nodesInChangedRanges.length) {\n const endText = newState.doc.textBetween(newRange.from, newRange.to, ' ', ' ')\n if (!UNICODE_WHITESPACE_REGEX_END.test(endText)) {\n return\n }\n textBlock = nodesInChangedRanges[0]\n textBeforeWhitespace = newState.doc.textBetween(textBlock.pos, newRange.to, undefined, ' ')\n }\n\n if (textBlock && textBeforeWhitespace) {\n const wordsBeforeWhitespace = textBeforeWhitespace.split(UNICODE_WHITESPACE_REGEX).filter(Boolean)\n\n if (wordsBeforeWhitespace.length <= 0) {\n return false\n }\n\n const lastWordBeforeSpace = wordsBeforeWhitespace[wordsBeforeWhitespace.length - 1]\n const lastWordAndBlockOffset = textBlock.pos + textBeforeWhitespace.lastIndexOf(lastWordBeforeSpace)\n\n if (!lastWordBeforeSpace) {\n return false\n }\n\n const linksBeforeSpace = tokenize(lastWordBeforeSpace).map(t => t.toObject(options.defaultProtocol))\n\n if (!isValidLinkStructure(linksBeforeSpace)) {\n return false\n }\n\n linksBeforeSpace\n .filter(link => link.isLink)\n // Calculate link position.\n .map(link => ({\n ...link,\n from: lastWordAndBlockOffset + link.start + 1,\n to: lastWordAndBlockOffset + link.end + 1,\n }))\n // ignore link inside code mark\n .filter(link => {\n if (!newState.schema.marks.code) {\n return true\n }\n\n return !newState.doc.rangeHasMark(link.from, link.to, newState.schema.marks.code)\n })\n // validate link\n .filter(link => options.validate(link.value))\n // check whether should autolink\n .filter(link => options.shouldAutoLink(link.value))\n // Add link mark.\n .forEach(link => {\n if (getMarksBetween(link.from, link.to, newState.doc).some(item => item.mark.type === options.type)) {\n return\n }\n\n tr.addMark(\n link.from,\n link.to,\n options.type.create({\n href: link.href,\n }),\n )\n })\n }\n })\n\n if (!tr.steps.length) {\n return\n }\n\n return tr\n },\n })\n}\n","// From DOMPurify\n// https://github.com/cure53/DOMPurify/blob/main/src/regexp.ts\nexport const UNICODE_WHITESPACE_PATTERN = '[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]'\n\nexport const UNICODE_WHITESPACE_REGEX = new RegExp(UNICODE_WHITESPACE_PATTERN)\nexport const UNICODE_WHITESPACE_REGEX_END = new RegExp(`${UNICODE_WHITESPACE_PATTERN}$`)\nexport const UNICODE_WHITESPACE_REGEX_GLOBAL = new RegExp(UNICODE_WHITESPACE_PATTERN, 'g')\n","import type { Editor } from '@tiptap/core'\nimport { getAttributes } from '@tiptap/core'\nimport type { MarkType } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\n\ntype ClickHandlerOptions = {\n type: MarkType\n editor: Editor\n openOnClick?: boolean\n enableClickSelection?: boolean\n}\n\nexport function clickHandler(options: ClickHandlerOptions): Plugin {\n return new Plugin({\n key: new PluginKey('handleClickLink'),\n props: {\n handleClick: (view, pos, event) => {\n if (event.button !== 0) {\n return false\n }\n\n if (!view.editable) {\n return false\n }\n\n let link: HTMLAnchorElement | null = null\n\n if (event.target instanceof HTMLAnchorElement) {\n link = event.target\n } else {\n const target = event.target as HTMLElement | null\n if (!target) {\n return false\n }\n\n const root = options.editor.view.dom\n\n // Tntentionally limit the lookup to the editor root.\n // Using tag names like DIV as boundaries breaks with custom NodeViews,\n link = target.closest<HTMLAnchorElement>('a')\n\n if (link && !root.contains(link)) {\n link = null\n }\n }\n\n if (!link) {\n return false\n }\n\n let handled = false\n\n if (options.enableClickSelection) {\n const commandResult = options.editor.commands.extendMarkRange(options.type.name)\n handled = commandResult\n }\n\n if (options.openOnClick) {\n const attrs = getAttributes(view.state, options.type.name)\n const href = link.href ?? attrs.href\n const target = link.target ?? attrs.target\n\n if (href) {\n window.open(href, target)\n handled = true\n }\n }\n\n return handled\n },\n },\n })\n}\n","import type { Editor } from '@tiptap/core'\nimport type { MarkType } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { find } from 'linkifyjs'\n\nimport type { LinkOptions } from '../link.js'\n\ntype PasteHandlerOptions = {\n editor: Editor\n defaultProtocol: string\n type: MarkType\n shouldAutoLink?: LinkOptions['shouldAutoLink']\n}\n\nexport function pasteHandler(options: PasteHandlerOptions): Plugin {\n return new Plugin({\n key: new PluginKey('handlePasteLink'),\n props: {\n handlePaste: (view, _event, slice) => {\n const { shouldAutoLink } = options\n const { state } = view\n const { selection } = state\n const { empty } = selection\n\n if (empty) {\n return false\n }\n\n let textContent = ''\n\n slice.content.forEach(node => {\n textContent += node.textContent\n })\n\n const link = find(textContent, { defaultProtocol: options.defaultProtocol }).find(\n item => item.isLink && item.value === textContent,\n )\n\n if (!textContent || !link || (shouldAutoLink !== undefined && !shouldAutoLink(link.value))) {\n return false\n }\n\n return options.editor.commands.setMark(options.type, {\n href: link.href,\n })\n },\n },\n })\n}\n"],"mappings":"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","names":["import_core","import_linkifyjs","import_core","import_state","import_state","import_linkifyjs"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/link.ts","../src/helpers/autolink.ts","../src/helpers/whitespace.ts","../src/helpers/clickHandler.ts","../src/helpers/pasteHandler.ts"],"sourcesContent":["import { Link } from './link.js'\n\nexport * from './link.js'\n\nexport default Link\n","import type { PasteRuleMatch } from '@tiptap/core'\nimport { Mark, markPasteRule, mergeAttributes } from '@tiptap/core'\nimport type { Plugin } from '@tiptap/pm/state'\nimport { find, registerCustomProtocol, reset } from 'linkifyjs'\n\nimport { autolink } from './helpers/autolink.js'\nimport { clickHandler } from './helpers/clickHandler.js'\nimport { pasteHandler } from './helpers/pasteHandler.js'\nimport { UNICODE_WHITESPACE_REGEX_GLOBAL } from './helpers/whitespace.js'\n\nexport interface LinkProtocolOptions {\n /**\n * The protocol scheme to be registered.\n * @default '''\n * @example 'ftp'\n * @example 'git'\n */\n scheme: string\n\n /**\n * If enabled, it allows optional slashes after the protocol.\n * @default false\n * @example true\n */\n optionalSlashes?: boolean\n}\n\nexport const pasteRegex =\n /https?:\\/\\/(?:www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z]{2,}\\b(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)/gi\n\n/**\n * @deprecated The default behavior is now to open links when the editor is not editable.\n */\ntype DeprecatedOpenWhenNotEditable = 'whenNotEditable'\n\nexport interface LinkOptions {\n /**\n * If enabled, the extension will automatically add links as you type.\n * @default true\n * @example false\n */\n autolink: boolean\n\n /**\n * An array of custom protocols to be registered with linkifyjs.\n * @default []\n * @example ['ftp', 'git']\n */\n protocols: Array<LinkProtocolOptions | string>\n\n /**\n * Default protocol to use when no protocol is specified.\n * @default 'http'\n */\n defaultProtocol: string\n /**\n * If enabled, links will be opened on click.\n * @default true\n * @example false\n */\n openOnClick: boolean | DeprecatedOpenWhenNotEditable\n /**\n * If enabled, the link will be selected when clicked.\n * @default false\n * @example true\n */\n enableClickSelection: boolean\n /**\n * Adds a link to the current selection if the pasted content only contains an url.\n * @default true\n * @example false\n */\n linkOnPaste: boolean\n\n /**\n * HTML attributes to add to the link element.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>\n\n /**\n * @deprecated Use the `shouldAutoLink` option instead.\n * A validation function that modifies link verification for the auto linker.\n * @param url - The url to be validated.\n * @returns - True if the url is valid, false otherwise.\n */\n validate: (url: string) => boolean\n\n /**\n * A validation function which is used for configuring link verification for preventing XSS attacks.\n * Only modify this if you know what you're doing.\n *\n * @returns {boolean} `true` if the URL is valid, `false` otherwise.\n *\n * @example\n * isAllowedUri: (url, { defaultValidate, protocols, defaultProtocol }) => {\n * return url.startsWith('./') || defaultValidate(url)\n * }\n */\n isAllowedUri: (\n /**\n * The URL to be validated.\n */\n url: string,\n ctx: {\n /**\n * The default validation function.\n */\n defaultValidate: (url: string) => boolean\n /**\n * An array of allowed protocols for the URL (e.g., \"http\", \"https\"). As defined in the `protocols` option.\n */\n protocols: Array<LinkProtocolOptions | string>\n /**\n * A string that represents the default protocol (e.g., 'http'). As defined in the `defaultProtocol` option.\n */\n defaultProtocol: string\n },\n ) => boolean\n\n /**\n * Determines whether a valid link should be automatically linked in the content.\n *\n * @param {string} url - The URL that has already been validated.\n * @returns {boolean} - True if the link should be auto-linked; false if it should not be auto-linked.\n */\n shouldAutoLink: (url: string) => boolean\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n link: {\n /**\n * Set a link mark\n * @param attributes The link attributes\n * @example editor.commands.setLink({ href: 'https://tiptap.dev' })\n */\n setLink: (attributes: {\n href: string\n target?: string | null\n rel?: string | null\n class?: string | null\n title?: string | null\n }) => ReturnType\n /**\n * Toggle a link mark\n * @param attributes The link attributes\n * @example editor.commands.toggleLink({ href: 'https://tiptap.dev' })\n */\n toggleLink: (attributes?: {\n href: string\n target?: string | null\n rel?: string | null\n class?: string | null\n title?: string | null\n }) => ReturnType\n /**\n * Unset a link mark\n * @example editor.commands.unsetLink()\n */\n unsetLink: () => ReturnType\n }\n }\n}\n\nexport function isAllowedUri(uri: string | undefined, protocols?: LinkOptions['protocols']) {\n const allowedProtocols: string[] = [\n 'http',\n 'https',\n 'ftp',\n 'ftps',\n 'mailto',\n 'tel',\n 'callto',\n 'sms',\n 'cid',\n 'xmpp',\n ]\n\n if (protocols) {\n protocols.forEach(protocol => {\n const nextProtocol = typeof protocol === 'string' ? protocol : protocol.scheme\n\n if (nextProtocol) {\n allowedProtocols.push(nextProtocol)\n }\n })\n }\n\n return (\n !uri ||\n uri.replace(UNICODE_WHITESPACE_REGEX_GLOBAL, '').match(\n new RegExp(\n // oxlint-disable-next-line no-useless-escape\n `^(?:(?:${allowedProtocols.join('|')}):|[^a-z]|[a-z0-9+.\\-]+(?:[^a-z+.\\-:]|$))`,\n 'i',\n ),\n )\n )\n}\n\n/**\n * This extension allows you to create links.\n * @see https://www.tiptap.dev/api/marks/link\n */\nexport const Link = Mark.create<LinkOptions>({\n name: 'link',\n\n priority: 1000,\n\n keepOnSplit: false,\n\n exitable: true,\n\n onCreate() {\n // TODO: v4 - remove validate option\n if (this.options.validate && !this.options.shouldAutoLink) {\n // Copy the validate function to the shouldAutoLink option\n this.options.shouldAutoLink = this.options.validate\n console.warn(\n 'The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead.',\n )\n }\n this.options.protocols.forEach(protocol => {\n if (typeof protocol === 'string') {\n registerCustomProtocol(protocol)\n return\n }\n registerCustomProtocol(protocol.scheme, protocol.optionalSlashes)\n })\n },\n\n onDestroy() {\n reset()\n },\n\n inclusive() {\n return this.options.autolink\n },\n\n addOptions() {\n return {\n openOnClick: true,\n enableClickSelection: false,\n linkOnPaste: true,\n autolink: true,\n protocols: [],\n defaultProtocol: 'http',\n HTMLAttributes: {\n target: '_blank',\n rel: 'noopener noreferrer nofollow',\n class: null,\n },\n isAllowedUri: (url, ctx) => !!isAllowedUri(url, ctx.protocols),\n validate: url => !!url,\n shouldAutoLink: url => {\n // URLs with explicit protocols (e.g., https://) should be auto-linked\n // But not if @ appears before :// (that would be userinfo like user:pass@host)\n const hasProtocol = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(url)\n const hasMaybeProtocol = /^[a-z][a-z0-9+.-]*:/i.test(url)\n\n if (hasProtocol || (hasMaybeProtocol && !url.includes('@'))) {\n return true\n }\n // Strip userinfo (user:pass@) if present, then extract hostname\n const urlWithoutUserinfo = url.includes('@') ? url.split('@').pop()! : url\n const hostname = urlWithoutUserinfo.split(/[/?#:]/)[0]\n\n // Don't auto-link IP addresses without protocol\n if (/^\\d{1,3}(\\.\\d{1,3}){3}$/.test(hostname)) {\n return false\n }\n // Don't auto-link single-word hostnames without TLD (e.g., \"localhost\")\n if (!/\\./.test(hostname)) {\n return false\n }\n return true\n },\n }\n },\n\n addAttributes() {\n return {\n href: {\n default: null,\n parseHTML(element) {\n return element.getAttribute('href')\n },\n },\n target: {\n default: this.options.HTMLAttributes.target,\n },\n rel: {\n default: this.options.HTMLAttributes.rel,\n },\n class: {\n default: this.options.HTMLAttributes.class,\n },\n title: {\n default: null,\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'a[href]',\n getAttrs: dom => {\n const href = (dom as HTMLElement).getAttribute('href')\n\n // prevent XSS attacks\n if (\n !href ||\n !this.options.isAllowedUri(href, {\n defaultValidate: url => !!isAllowedUri(url, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n return false\n }\n return null\n },\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n // prevent XSS attacks\n if (\n !this.options.isAllowedUri(HTMLAttributes.href, {\n defaultValidate: href => !!isAllowedUri(href, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n // strip out the href\n return ['a', mergeAttributes(this.options.HTMLAttributes, { ...HTMLAttributes, href: '' }), 0]\n }\n\n return ['a', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]\n },\n\n markdownTokenName: 'link',\n\n parseMarkdown: (token, helpers) => {\n return helpers.applyMark('link', helpers.parseInline(token.tokens || []), {\n href: token.href,\n title: token.title || null,\n })\n },\n\n renderMarkdown: (node, h) => {\n const href = node.attrs?.href ?? ''\n const title = node.attrs?.title ?? ''\n const text = h.renderChildren(node)\n\n return title ? `[${text}](${href} \"${title}\")` : `[${text}](${href})`\n },\n\n addCommands() {\n return {\n setLink:\n attributes =>\n ({ chain }) => {\n const { href } = attributes\n\n if (\n !this.options.isAllowedUri(href, {\n defaultValidate: url => !!isAllowedUri(url, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n return false\n }\n\n return chain().setMark(this.name, attributes).setMeta('preventAutolink', true).run()\n },\n\n toggleLink:\n attributes =>\n ({ chain }) => {\n const { href } = attributes || {}\n\n if (\n href &&\n !this.options.isAllowedUri(href, {\n defaultValidate: url => !!isAllowedUri(url, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n return false\n }\n\n return chain()\n .toggleMark(this.name, attributes, { extendEmptyMarkRange: true })\n .setMeta('preventAutolink', true)\n .run()\n },\n\n unsetLink:\n () =>\n ({ chain }) => {\n return chain()\n .unsetMark(this.name, { extendEmptyMarkRange: true })\n .setMeta('preventAutolink', true)\n .run()\n },\n }\n },\n\n addPasteRules() {\n return [\n markPasteRule({\n find: text => {\n const foundLinks: PasteRuleMatch[] = []\n\n if (text) {\n const { protocols, defaultProtocol } = this.options\n const links = find(text).filter(\n item =>\n item.isLink &&\n this.options.isAllowedUri(item.value, {\n defaultValidate: href => !!isAllowedUri(href, protocols),\n protocols,\n defaultProtocol,\n }),\n )\n\n if (links.length) {\n links.forEach(link => {\n if (!this.options.shouldAutoLink(link.value)) {\n return\n }\n\n foundLinks.push({\n text: link.value,\n data: {\n href: link.href,\n },\n index: link.start,\n })\n })\n }\n }\n\n return foundLinks\n },\n type: this.type,\n getAttributes: match => {\n return {\n href: match.data?.href,\n }\n },\n }),\n ]\n },\n\n addProseMirrorPlugins() {\n const plugins: Plugin[] = []\n const { protocols, defaultProtocol } = this.options\n\n if (this.options.autolink) {\n plugins.push(\n autolink({\n type: this.type,\n defaultProtocol: this.options.defaultProtocol,\n validate: url =>\n this.options.isAllowedUri(url, {\n defaultValidate: href => !!isAllowedUri(href, protocols),\n protocols,\n defaultProtocol,\n }),\n shouldAutoLink: this.options.shouldAutoLink,\n }),\n )\n }\n\n plugins.push(\n clickHandler({\n type: this.type,\n editor: this.editor,\n openOnClick:\n this.options.openOnClick === 'whenNotEditable' ? true : this.options.openOnClick,\n enableClickSelection: this.options.enableClickSelection,\n }),\n )\n\n if (this.options.linkOnPaste) {\n plugins.push(\n pasteHandler({\n editor: this.editor,\n defaultProtocol: this.options.defaultProtocol,\n type: this.type,\n shouldAutoLink: this.options.shouldAutoLink,\n }),\n )\n }\n\n return plugins\n },\n})\n","import type { NodeWithPos } from '@tiptap/core'\nimport {\n combineTransactionSteps,\n findChildrenInRange,\n getChangedRanges,\n getMarksBetween,\n} from '@tiptap/core'\nimport type { MarkType } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport type { MultiToken } from 'linkifyjs'\nimport { tokenize } from 'linkifyjs'\n\nimport { UNICODE_WHITESPACE_REGEX, UNICODE_WHITESPACE_REGEX_END } from './whitespace.js'\n\n/**\n * Check if the provided tokens form a valid link structure, which can either be a single link token\n * or a link token surrounded by parentheses or square brackets.\n *\n * This ensures that only complete and valid text is hyperlinked, preventing cases where a valid\n * top-level domain (TLD) is immediately followed by an invalid character, like a number. For\n * example, with the `find` method from Linkify, entering `example.com1` would result in\n * `example.com` being linked and the trailing `1` left as plain text. By using the `tokenize`\n * method, we can perform more comprehensive validation on the input text.\n */\nfunction isValidLinkStructure(tokens: Array<ReturnType<MultiToken['toObject']>>) {\n if (tokens.length === 1) {\n return tokens[0].isLink\n }\n\n if (tokens.length === 3 && tokens[1].isLink) {\n return ['()', '[]'].includes(tokens[0].value + tokens[2].value)\n }\n\n return false\n}\n\ntype AutolinkOptions = {\n type: MarkType\n defaultProtocol: string\n validate: (url: string) => boolean\n shouldAutoLink: (url: string) => boolean\n}\n\n/**\n * This plugin allows you to automatically add links to your editor.\n * @param options The plugin options\n * @returns The plugin instance\n */\nexport function autolink(options: AutolinkOptions): Plugin {\n return new Plugin({\n key: new PluginKey('autolink'),\n appendTransaction: (transactions, oldState, newState) => {\n /**\n * Does the transaction change the document?\n */\n const docChanges =\n transactions.some(transaction => transaction.docChanged) && !oldState.doc.eq(newState.doc)\n\n /**\n * Prevent autolink if the transaction is not a document change or if the transaction has the meta `preventAutolink`.\n */\n const preventAutolink = transactions.some(transaction =>\n transaction.getMeta('preventAutolink'),\n )\n\n /**\n * Prevent autolink if the transaction is not a document change\n * or if the transaction has the meta `preventAutolink`.\n */\n if (!docChanges || preventAutolink) {\n return\n }\n\n const { tr } = newState\n const transform = combineTransactionSteps(oldState.doc, [...transactions])\n const changes = getChangedRanges(transform)\n\n changes.forEach(({ newRange }) => {\n // Now let’s see if we can add new links.\n const nodesInChangedRanges = findChildrenInRange(\n newState.doc,\n newRange,\n node => node.isTextblock,\n )\n\n let textBlock: NodeWithPos | undefined\n let textBeforeWhitespace: string | undefined\n\n if (nodesInChangedRanges.length > 1) {\n // Grab the first node within the changed ranges (ex. the first of two paragraphs when hitting enter).\n textBlock = nodesInChangedRanges[0]\n textBeforeWhitespace = newState.doc.textBetween(\n textBlock.pos,\n textBlock.pos + textBlock.node.nodeSize,\n undefined,\n ' ',\n )\n } else if (nodesInChangedRanges.length) {\n const endText = newState.doc.textBetween(newRange.from, newRange.to, ' ', ' ')\n if (!UNICODE_WHITESPACE_REGEX_END.test(endText)) {\n return\n }\n textBlock = nodesInChangedRanges[0]\n textBeforeWhitespace = newState.doc.textBetween(\n textBlock.pos,\n newRange.to,\n undefined,\n ' ',\n )\n }\n\n if (textBlock && textBeforeWhitespace) {\n const wordsBeforeWhitespace = textBeforeWhitespace\n .split(UNICODE_WHITESPACE_REGEX)\n .filter(Boolean)\n\n if (wordsBeforeWhitespace.length <= 0) {\n return false\n }\n\n const lastWordBeforeSpace = wordsBeforeWhitespace[wordsBeforeWhitespace.length - 1]\n const lastWordAndBlockOffset =\n textBlock.pos + textBeforeWhitespace.lastIndexOf(lastWordBeforeSpace)\n\n if (!lastWordBeforeSpace) {\n return false\n }\n\n const linksBeforeSpace = tokenize(lastWordBeforeSpace).map(t =>\n t.toObject(options.defaultProtocol),\n )\n\n if (!isValidLinkStructure(linksBeforeSpace)) {\n return false\n }\n\n linksBeforeSpace\n .filter(link => link.isLink)\n // Calculate link position.\n .map(link => ({\n ...link,\n from: lastWordAndBlockOffset + link.start + 1,\n to: lastWordAndBlockOffset + link.end + 1,\n }))\n // ignore link inside code mark\n .filter(link => {\n if (!newState.schema.marks.code) {\n return true\n }\n\n return !newState.doc.rangeHasMark(link.from, link.to, newState.schema.marks.code)\n })\n // validate link\n .filter(link => options.validate(link.value))\n // check whether should autolink\n .filter(link => options.shouldAutoLink(link.value))\n // Add link mark.\n .forEach(link => {\n if (\n getMarksBetween(link.from, link.to, newState.doc).some(\n item => item.mark.type === options.type,\n )\n ) {\n return\n }\n\n tr.addMark(\n link.from,\n link.to,\n options.type.create({\n href: link.href,\n }),\n )\n })\n }\n })\n\n if (!tr.steps.length) {\n return\n }\n\n return tr\n },\n })\n}\n","// From DOMPurify\n// https://github.com/cure53/DOMPurify/blob/main/src/regexp.ts\nexport const UNICODE_WHITESPACE_PATTERN =\n '[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]'\n\nexport const UNICODE_WHITESPACE_REGEX = new RegExp(UNICODE_WHITESPACE_PATTERN)\nexport const UNICODE_WHITESPACE_REGEX_END = new RegExp(`${UNICODE_WHITESPACE_PATTERN}$`)\nexport const UNICODE_WHITESPACE_REGEX_GLOBAL = new RegExp(UNICODE_WHITESPACE_PATTERN, 'g')\n","import type { Editor } from '@tiptap/core'\nimport { getAttributes } from '@tiptap/core'\nimport type { MarkType } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\n\ntype ClickHandlerOptions = {\n type: MarkType\n editor: Editor\n openOnClick?: boolean\n enableClickSelection?: boolean\n}\n\nexport function clickHandler(options: ClickHandlerOptions): Plugin {\n return new Plugin({\n key: new PluginKey('handleClickLink'),\n props: {\n handleClick: (view, pos, event) => {\n if (event.button !== 0) {\n return false\n }\n\n if (!view.editable) {\n return false\n }\n\n let link: HTMLAnchorElement | null = null\n\n if (event.target instanceof HTMLAnchorElement) {\n link = event.target\n } else {\n const target = event.target as HTMLElement | null\n if (!target) {\n return false\n }\n\n const root = options.editor.view.dom\n\n // Tntentionally limit the lookup to the editor root.\n // Using tag names like DIV as boundaries breaks with custom NodeViews,\n link = target.closest<HTMLAnchorElement>('a')\n\n if (link && !root.contains(link)) {\n link = null\n }\n }\n\n if (!link) {\n return false\n }\n\n let handled = false\n\n if (options.enableClickSelection) {\n const commandResult = options.editor.commands.extendMarkRange(options.type.name)\n handled = commandResult\n }\n\n if (options.openOnClick) {\n const attrs = getAttributes(view.state, options.type.name)\n const href = link.href ?? attrs.href\n const target = link.target ?? attrs.target\n\n if (href) {\n window.open(href, target)\n handled = true\n }\n }\n\n return handled\n },\n },\n })\n}\n","import type { Editor } from '@tiptap/core'\nimport type { MarkType } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { find } from 'linkifyjs'\n\nimport type { LinkOptions } from '../link.js'\n\ntype PasteHandlerOptions = {\n editor: Editor\n defaultProtocol: string\n type: MarkType\n shouldAutoLink?: LinkOptions['shouldAutoLink']\n}\n\nexport function pasteHandler(options: PasteHandlerOptions): Plugin {\n return new Plugin({\n key: new PluginKey('handlePasteLink'),\n props: {\n handlePaste: (view, _event, slice) => {\n const { shouldAutoLink } = options\n const { state } = view\n const { selection } = state\n const { empty } = selection\n\n if (empty) {\n return false\n }\n\n let textContent = ''\n\n slice.content.forEach(node => {\n textContent += node.textContent\n })\n\n const link = find(textContent, { defaultProtocol: options.defaultProtocol }).find(\n item => item.isLink && item.value === textContent,\n )\n\n if (\n !textContent ||\n !link ||\n (shouldAutoLink !== undefined && !shouldAutoLink(link.value))\n ) {\n return false\n }\n\n return options.editor.commands.setMark(options.type, {\n href: link.href,\n })\n },\n },\n })\n}\n"],"mappings":"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","names":["import_core","import_linkifyjs","import_core","import_state","import_state","import_linkifyjs"]}
package/dist/index.js CHANGED
@@ -3,7 +3,12 @@ import { Mark, markPasteRule, mergeAttributes } from "@tiptap/core";
3
3
  import { find as find2, registerCustomProtocol, reset } from "linkifyjs";
4
4
 
5
5
  // src/helpers/autolink.ts
6
- import { combineTransactionSteps, findChildrenInRange, getChangedRanges, getMarksBetween } from "@tiptap/core";
6
+ import {
7
+ combineTransactionSteps,
8
+ findChildrenInRange,
9
+ getChangedRanges,
10
+ getMarksBetween
11
+ } from "@tiptap/core";
7
12
  import { Plugin, PluginKey } from "@tiptap/pm/state";
8
13
  import { tokenize } from "linkifyjs";
9
14
 
@@ -28,7 +33,9 @@ function autolink(options) {
28
33
  key: new PluginKey("autolink"),
29
34
  appendTransaction: (transactions, oldState, newState) => {
30
35
  const docChanges = transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc);
31
- const preventAutolink = transactions.some((transaction) => transaction.getMeta("preventAutolink"));
36
+ const preventAutolink = transactions.some(
37
+ (transaction) => transaction.getMeta("preventAutolink")
38
+ );
32
39
  if (!docChanges || preventAutolink) {
33
40
  return;
34
41
  }
@@ -36,7 +43,11 @@ function autolink(options) {
36
43
  const transform = combineTransactionSteps(oldState.doc, [...transactions]);
37
44
  const changes = getChangedRanges(transform);
38
45
  changes.forEach(({ newRange }) => {
39
- const nodesInChangedRanges = findChildrenInRange(newState.doc, newRange, (node) => node.isTextblock);
46
+ const nodesInChangedRanges = findChildrenInRange(
47
+ newState.doc,
48
+ newRange,
49
+ (node) => node.isTextblock
50
+ );
40
51
  let textBlock;
41
52
  let textBeforeWhitespace;
42
53
  if (nodesInChangedRanges.length > 1) {
@@ -53,7 +64,12 @@ function autolink(options) {
53
64
  return;
54
65
  }
55
66
  textBlock = nodesInChangedRanges[0];
56
- textBeforeWhitespace = newState.doc.textBetween(textBlock.pos, newRange.to, void 0, " ");
67
+ textBeforeWhitespace = newState.doc.textBetween(
68
+ textBlock.pos,
69
+ newRange.to,
70
+ void 0,
71
+ " "
72
+ );
57
73
  }
58
74
  if (textBlock && textBeforeWhitespace) {
59
75
  const wordsBeforeWhitespace = textBeforeWhitespace.split(UNICODE_WHITESPACE_REGEX).filter(Boolean);
@@ -65,7 +81,9 @@ function autolink(options) {
65
81
  if (!lastWordBeforeSpace) {
66
82
  return false;
67
83
  }
68
- const linksBeforeSpace = tokenize(lastWordBeforeSpace).map((t) => t.toObject(options.defaultProtocol));
84
+ const linksBeforeSpace = tokenize(lastWordBeforeSpace).map(
85
+ (t) => t.toObject(options.defaultProtocol)
86
+ );
69
87
  if (!isValidLinkStructure(linksBeforeSpace)) {
70
88
  return false;
71
89
  }
@@ -79,7 +97,9 @@ function autolink(options) {
79
97
  }
80
98
  return !newState.doc.rangeHasMark(link.from, link.to, newState.schema.marks.code);
81
99
  }).filter((link) => options.validate(link.value)).filter((link) => options.shouldAutoLink(link.value)).forEach((link) => {
82
- if (getMarksBetween(link.from, link.to, newState.doc).some((item) => item.mark.type === options.type)) {
100
+ if (getMarksBetween(link.from, link.to, newState.doc).some(
101
+ (item) => item.mark.type === options.type
102
+ )) {
83
103
  return;
84
104
  }
85
105
  tr.addMark(
@@ -188,7 +208,18 @@ function pasteHandler(options) {
188
208
  // src/link.ts
189
209
  var pasteRegex = /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)/gi;
190
210
  function isAllowedUri(uri, protocols) {
191
- const allowedProtocols = ["http", "https", "ftp", "ftps", "mailto", "tel", "callto", "sms", "cid", "xmpp"];
211
+ const allowedProtocols = [
212
+ "http",
213
+ "https",
214
+ "ftp",
215
+ "ftps",
216
+ "mailto",
217
+ "tel",
218
+ "callto",
219
+ "sms",
220
+ "cid",
221
+ "xmpp"
222
+ ];
192
223
  if (protocols) {
193
224
  protocols.forEach((protocol) => {
194
225
  const nextProtocol = typeof protocol === "string" ? protocol : protocol.scheme;
@@ -199,7 +230,7 @@ function isAllowedUri(uri, protocols) {
199
230
  }
200
231
  return !uri || uri.replace(UNICODE_WHITESPACE_REGEX_GLOBAL, "").match(
201
232
  new RegExp(
202
- // eslint-disable-next-line no-useless-escape
233
+ // oxlint-disable-next-line no-useless-escape
203
234
  `^(?:(?:${allowedProtocols.join("|")}):|[^a-z]|[a-z0-9+.-]+(?:[^a-z+.-:]|$))`,
204
235
  "i"
205
236
  )
@@ -213,7 +244,9 @@ var Link = Mark.create({
213
244
  onCreate() {
214
245
  if (this.options.validate && !this.options.shouldAutoLink) {
215
246
  this.options.shouldAutoLink = this.options.validate;
216
- console.warn("The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead.");
247
+ console.warn(
248
+ "The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead."
249
+ );
217
250
  }
218
251
  this.options.protocols.forEach((protocol) => {
219
252
  if (typeof protocol === "string") {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/link.ts","../src/helpers/autolink.ts","../src/helpers/whitespace.ts","../src/helpers/clickHandler.ts","../src/helpers/pasteHandler.ts","../src/index.ts"],"sourcesContent":["import type { PasteRuleMatch } from '@tiptap/core'\nimport { Mark, markPasteRule, mergeAttributes } from '@tiptap/core'\nimport type { Plugin } from '@tiptap/pm/state'\nimport { find, registerCustomProtocol, reset } from 'linkifyjs'\n\nimport { autolink } from './helpers/autolink.js'\nimport { clickHandler } from './helpers/clickHandler.js'\nimport { pasteHandler } from './helpers/pasteHandler.js'\nimport { UNICODE_WHITESPACE_REGEX_GLOBAL } from './helpers/whitespace.js'\n\nexport interface LinkProtocolOptions {\n /**\n * The protocol scheme to be registered.\n * @default '''\n * @example 'ftp'\n * @example 'git'\n */\n scheme: string\n\n /**\n * If enabled, it allows optional slashes after the protocol.\n * @default false\n * @example true\n */\n optionalSlashes?: boolean\n}\n\nexport const pasteRegex =\n /https?:\\/\\/(?:www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z]{2,}\\b(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)/gi\n\n/**\n * @deprecated The default behavior is now to open links when the editor is not editable.\n */\ntype DeprecatedOpenWhenNotEditable = 'whenNotEditable'\n\nexport interface LinkOptions {\n /**\n * If enabled, the extension will automatically add links as you type.\n * @default true\n * @example false\n */\n autolink: boolean\n\n /**\n * An array of custom protocols to be registered with linkifyjs.\n * @default []\n * @example ['ftp', 'git']\n */\n protocols: Array<LinkProtocolOptions | string>\n\n /**\n * Default protocol to use when no protocol is specified.\n * @default 'http'\n */\n defaultProtocol: string\n /**\n * If enabled, links will be opened on click.\n * @default true\n * @example false\n */\n openOnClick: boolean | DeprecatedOpenWhenNotEditable\n /**\n * If enabled, the link will be selected when clicked.\n * @default false\n * @example true\n */\n enableClickSelection: boolean\n /**\n * Adds a link to the current selection if the pasted content only contains an url.\n * @default true\n * @example false\n */\n linkOnPaste: boolean\n\n /**\n * HTML attributes to add to the link element.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>\n\n /**\n * @deprecated Use the `shouldAutoLink` option instead.\n * A validation function that modifies link verification for the auto linker.\n * @param url - The url to be validated.\n * @returns - True if the url is valid, false otherwise.\n */\n validate: (url: string) => boolean\n\n /**\n * A validation function which is used for configuring link verification for preventing XSS attacks.\n * Only modify this if you know what you're doing.\n *\n * @returns {boolean} `true` if the URL is valid, `false` otherwise.\n *\n * @example\n * isAllowedUri: (url, { defaultValidate, protocols, defaultProtocol }) => {\n * return url.startsWith('./') || defaultValidate(url)\n * }\n */\n isAllowedUri: (\n /**\n * The URL to be validated.\n */\n url: string,\n ctx: {\n /**\n * The default validation function.\n */\n defaultValidate: (url: string) => boolean\n /**\n * An array of allowed protocols for the URL (e.g., \"http\", \"https\"). As defined in the `protocols` option.\n */\n protocols: Array<LinkProtocolOptions | string>\n /**\n * A string that represents the default protocol (e.g., 'http'). As defined in the `defaultProtocol` option.\n */\n defaultProtocol: string\n },\n ) => boolean\n\n /**\n * Determines whether a valid link should be automatically linked in the content.\n *\n * @param {string} url - The URL that has already been validated.\n * @returns {boolean} - True if the link should be auto-linked; false if it should not be auto-linked.\n */\n shouldAutoLink: (url: string) => boolean\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n link: {\n /**\n * Set a link mark\n * @param attributes The link attributes\n * @example editor.commands.setLink({ href: 'https://tiptap.dev' })\n */\n setLink: (attributes: {\n href: string\n target?: string | null\n rel?: string | null\n class?: string | null\n title?: string | null\n }) => ReturnType\n /**\n * Toggle a link mark\n * @param attributes The link attributes\n * @example editor.commands.toggleLink({ href: 'https://tiptap.dev' })\n */\n toggleLink: (attributes?: {\n href: string\n target?: string | null\n rel?: string | null\n class?: string | null\n title?: string | null\n }) => ReturnType\n /**\n * Unset a link mark\n * @example editor.commands.unsetLink()\n */\n unsetLink: () => ReturnType\n }\n }\n}\n\nexport function isAllowedUri(uri: string | undefined, protocols?: LinkOptions['protocols']) {\n const allowedProtocols: string[] = ['http', 'https', 'ftp', 'ftps', 'mailto', 'tel', 'callto', 'sms', 'cid', 'xmpp']\n\n if (protocols) {\n protocols.forEach(protocol => {\n const nextProtocol = typeof protocol === 'string' ? protocol : protocol.scheme\n\n if (nextProtocol) {\n allowedProtocols.push(nextProtocol)\n }\n })\n }\n\n return (\n !uri ||\n uri.replace(UNICODE_WHITESPACE_REGEX_GLOBAL, '').match(\n new RegExp(\n // eslint-disable-next-line no-useless-escape\n `^(?:(?:${allowedProtocols.join('|')}):|[^a-z]|[a-z0-9+.\\-]+(?:[^a-z+.\\-:]|$))`,\n 'i',\n ),\n )\n )\n}\n\n/**\n * This extension allows you to create links.\n * @see https://www.tiptap.dev/api/marks/link\n */\nexport const Link = Mark.create<LinkOptions>({\n name: 'link',\n\n priority: 1000,\n\n keepOnSplit: false,\n\n exitable: true,\n\n onCreate() {\n // TODO: v4 - remove validate option\n if (this.options.validate && !this.options.shouldAutoLink) {\n // Copy the validate function to the shouldAutoLink option\n this.options.shouldAutoLink = this.options.validate\n console.warn('The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead.')\n }\n this.options.protocols.forEach(protocol => {\n if (typeof protocol === 'string') {\n registerCustomProtocol(protocol)\n return\n }\n registerCustomProtocol(protocol.scheme, protocol.optionalSlashes)\n })\n },\n\n onDestroy() {\n reset()\n },\n\n inclusive() {\n return this.options.autolink\n },\n\n addOptions() {\n return {\n openOnClick: true,\n enableClickSelection: false,\n linkOnPaste: true,\n autolink: true,\n protocols: [],\n defaultProtocol: 'http',\n HTMLAttributes: {\n target: '_blank',\n rel: 'noopener noreferrer nofollow',\n class: null,\n },\n isAllowedUri: (url, ctx) => !!isAllowedUri(url, ctx.protocols),\n validate: url => !!url,\n shouldAutoLink: url => {\n // URLs with explicit protocols (e.g., https://) should be auto-linked\n // But not if @ appears before :// (that would be userinfo like user:pass@host)\n const hasProtocol = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(url)\n const hasMaybeProtocol = /^[a-z][a-z0-9+.-]*:/i.test(url)\n\n if (hasProtocol || (hasMaybeProtocol && !url.includes('@'))) {\n return true\n }\n // Strip userinfo (user:pass@) if present, then extract hostname\n const urlWithoutUserinfo = url.includes('@') ? url.split('@').pop()! : url\n const hostname = urlWithoutUserinfo.split(/[/?#:]/)[0]\n\n // Don't auto-link IP addresses without protocol\n if (/^\\d{1,3}(\\.\\d{1,3}){3}$/.test(hostname)) {\n return false\n }\n // Don't auto-link single-word hostnames without TLD (e.g., \"localhost\")\n if (!/\\./.test(hostname)) {\n return false\n }\n return true\n },\n }\n },\n\n addAttributes() {\n return {\n href: {\n default: null,\n parseHTML(element) {\n return element.getAttribute('href')\n },\n },\n target: {\n default: this.options.HTMLAttributes.target,\n },\n rel: {\n default: this.options.HTMLAttributes.rel,\n },\n class: {\n default: this.options.HTMLAttributes.class,\n },\n title: {\n default: null,\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'a[href]',\n getAttrs: dom => {\n const href = (dom as HTMLElement).getAttribute('href')\n\n // prevent XSS attacks\n if (\n !href ||\n !this.options.isAllowedUri(href, {\n defaultValidate: url => !!isAllowedUri(url, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n return false\n }\n return null\n },\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n // prevent XSS attacks\n if (\n !this.options.isAllowedUri(HTMLAttributes.href, {\n defaultValidate: href => !!isAllowedUri(href, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n // strip out the href\n return ['a', mergeAttributes(this.options.HTMLAttributes, { ...HTMLAttributes, href: '' }), 0]\n }\n\n return ['a', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]\n },\n\n markdownTokenName: 'link',\n\n parseMarkdown: (token, helpers) => {\n return helpers.applyMark('link', helpers.parseInline(token.tokens || []), {\n href: token.href,\n title: token.title || null,\n })\n },\n\n renderMarkdown: (node, h) => {\n const href = node.attrs?.href ?? ''\n const title = node.attrs?.title ?? ''\n const text = h.renderChildren(node)\n\n return title ? `[${text}](${href} \"${title}\")` : `[${text}](${href})`\n },\n\n addCommands() {\n return {\n setLink:\n attributes =>\n ({ chain }) => {\n const { href } = attributes\n\n if (\n !this.options.isAllowedUri(href, {\n defaultValidate: url => !!isAllowedUri(url, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n return false\n }\n\n return chain().setMark(this.name, attributes).setMeta('preventAutolink', true).run()\n },\n\n toggleLink:\n attributes =>\n ({ chain }) => {\n const { href } = attributes || {}\n\n if (\n href &&\n !this.options.isAllowedUri(href, {\n defaultValidate: url => !!isAllowedUri(url, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n return false\n }\n\n return chain()\n .toggleMark(this.name, attributes, { extendEmptyMarkRange: true })\n .setMeta('preventAutolink', true)\n .run()\n },\n\n unsetLink:\n () =>\n ({ chain }) => {\n return chain().unsetMark(this.name, { extendEmptyMarkRange: true }).setMeta('preventAutolink', true).run()\n },\n }\n },\n\n addPasteRules() {\n return [\n markPasteRule({\n find: text => {\n const foundLinks: PasteRuleMatch[] = []\n\n if (text) {\n const { protocols, defaultProtocol } = this.options\n const links = find(text).filter(\n item =>\n item.isLink &&\n this.options.isAllowedUri(item.value, {\n defaultValidate: href => !!isAllowedUri(href, protocols),\n protocols,\n defaultProtocol,\n }),\n )\n\n if (links.length) {\n links.forEach(link => {\n if (!this.options.shouldAutoLink(link.value)) {\n return\n }\n\n foundLinks.push({\n text: link.value,\n data: {\n href: link.href,\n },\n index: link.start,\n })\n })\n }\n }\n\n return foundLinks\n },\n type: this.type,\n getAttributes: match => {\n return {\n href: match.data?.href,\n }\n },\n }),\n ]\n },\n\n addProseMirrorPlugins() {\n const plugins: Plugin[] = []\n const { protocols, defaultProtocol } = this.options\n\n if (this.options.autolink) {\n plugins.push(\n autolink({\n type: this.type,\n defaultProtocol: this.options.defaultProtocol,\n validate: url =>\n this.options.isAllowedUri(url, {\n defaultValidate: href => !!isAllowedUri(href, protocols),\n protocols,\n defaultProtocol,\n }),\n shouldAutoLink: this.options.shouldAutoLink,\n }),\n )\n }\n\n plugins.push(\n clickHandler({\n type: this.type,\n editor: this.editor,\n openOnClick: this.options.openOnClick === 'whenNotEditable' ? true : this.options.openOnClick,\n enableClickSelection: this.options.enableClickSelection,\n }),\n )\n\n if (this.options.linkOnPaste) {\n plugins.push(\n pasteHandler({\n editor: this.editor,\n defaultProtocol: this.options.defaultProtocol,\n type: this.type,\n shouldAutoLink: this.options.shouldAutoLink,\n }),\n )\n }\n\n return plugins\n },\n})\n","import type { NodeWithPos } from '@tiptap/core'\nimport { combineTransactionSteps, findChildrenInRange, getChangedRanges, getMarksBetween } from '@tiptap/core'\nimport type { MarkType } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport type { MultiToken } from 'linkifyjs'\nimport { tokenize } from 'linkifyjs'\n\nimport { UNICODE_WHITESPACE_REGEX, UNICODE_WHITESPACE_REGEX_END } from './whitespace.js'\n\n/**\n * Check if the provided tokens form a valid link structure, which can either be a single link token\n * or a link token surrounded by parentheses or square brackets.\n *\n * This ensures that only complete and valid text is hyperlinked, preventing cases where a valid\n * top-level domain (TLD) is immediately followed by an invalid character, like a number. For\n * example, with the `find` method from Linkify, entering `example.com1` would result in\n * `example.com` being linked and the trailing `1` left as plain text. By using the `tokenize`\n * method, we can perform more comprehensive validation on the input text.\n */\nfunction isValidLinkStructure(tokens: Array<ReturnType<MultiToken['toObject']>>) {\n if (tokens.length === 1) {\n return tokens[0].isLink\n }\n\n if (tokens.length === 3 && tokens[1].isLink) {\n return ['()', '[]'].includes(tokens[0].value + tokens[2].value)\n }\n\n return false\n}\n\ntype AutolinkOptions = {\n type: MarkType\n defaultProtocol: string\n validate: (url: string) => boolean\n shouldAutoLink: (url: string) => boolean\n}\n\n/**\n * This plugin allows you to automatically add links to your editor.\n * @param options The plugin options\n * @returns The plugin instance\n */\nexport function autolink(options: AutolinkOptions): Plugin {\n return new Plugin({\n key: new PluginKey('autolink'),\n appendTransaction: (transactions, oldState, newState) => {\n /**\n * Does the transaction change the document?\n */\n const docChanges = transactions.some(transaction => transaction.docChanged) && !oldState.doc.eq(newState.doc)\n\n /**\n * Prevent autolink if the transaction is not a document change or if the transaction has the meta `preventAutolink`.\n */\n const preventAutolink = transactions.some(transaction => transaction.getMeta('preventAutolink'))\n\n /**\n * Prevent autolink if the transaction is not a document change\n * or if the transaction has the meta `preventAutolink`.\n */\n if (!docChanges || preventAutolink) {\n return\n }\n\n const { tr } = newState\n const transform = combineTransactionSteps(oldState.doc, [...transactions])\n const changes = getChangedRanges(transform)\n\n changes.forEach(({ newRange }) => {\n // Now let’s see if we can add new links.\n const nodesInChangedRanges = findChildrenInRange(newState.doc, newRange, node => node.isTextblock)\n\n let textBlock: NodeWithPos | undefined\n let textBeforeWhitespace: string | undefined\n\n if (nodesInChangedRanges.length > 1) {\n // Grab the first node within the changed ranges (ex. the first of two paragraphs when hitting enter).\n textBlock = nodesInChangedRanges[0]\n textBeforeWhitespace = newState.doc.textBetween(\n textBlock.pos,\n textBlock.pos + textBlock.node.nodeSize,\n undefined,\n ' ',\n )\n } else if (nodesInChangedRanges.length) {\n const endText = newState.doc.textBetween(newRange.from, newRange.to, ' ', ' ')\n if (!UNICODE_WHITESPACE_REGEX_END.test(endText)) {\n return\n }\n textBlock = nodesInChangedRanges[0]\n textBeforeWhitespace = newState.doc.textBetween(textBlock.pos, newRange.to, undefined, ' ')\n }\n\n if (textBlock && textBeforeWhitespace) {\n const wordsBeforeWhitespace = textBeforeWhitespace.split(UNICODE_WHITESPACE_REGEX).filter(Boolean)\n\n if (wordsBeforeWhitespace.length <= 0) {\n return false\n }\n\n const lastWordBeforeSpace = wordsBeforeWhitespace[wordsBeforeWhitespace.length - 1]\n const lastWordAndBlockOffset = textBlock.pos + textBeforeWhitespace.lastIndexOf(lastWordBeforeSpace)\n\n if (!lastWordBeforeSpace) {\n return false\n }\n\n const linksBeforeSpace = tokenize(lastWordBeforeSpace).map(t => t.toObject(options.defaultProtocol))\n\n if (!isValidLinkStructure(linksBeforeSpace)) {\n return false\n }\n\n linksBeforeSpace\n .filter(link => link.isLink)\n // Calculate link position.\n .map(link => ({\n ...link,\n from: lastWordAndBlockOffset + link.start + 1,\n to: lastWordAndBlockOffset + link.end + 1,\n }))\n // ignore link inside code mark\n .filter(link => {\n if (!newState.schema.marks.code) {\n return true\n }\n\n return !newState.doc.rangeHasMark(link.from, link.to, newState.schema.marks.code)\n })\n // validate link\n .filter(link => options.validate(link.value))\n // check whether should autolink\n .filter(link => options.shouldAutoLink(link.value))\n // Add link mark.\n .forEach(link => {\n if (getMarksBetween(link.from, link.to, newState.doc).some(item => item.mark.type === options.type)) {\n return\n }\n\n tr.addMark(\n link.from,\n link.to,\n options.type.create({\n href: link.href,\n }),\n )\n })\n }\n })\n\n if (!tr.steps.length) {\n return\n }\n\n return tr\n },\n })\n}\n","// From DOMPurify\n// https://github.com/cure53/DOMPurify/blob/main/src/regexp.ts\nexport const UNICODE_WHITESPACE_PATTERN = '[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]'\n\nexport const UNICODE_WHITESPACE_REGEX = new RegExp(UNICODE_WHITESPACE_PATTERN)\nexport const UNICODE_WHITESPACE_REGEX_END = new RegExp(`${UNICODE_WHITESPACE_PATTERN}$`)\nexport const UNICODE_WHITESPACE_REGEX_GLOBAL = new RegExp(UNICODE_WHITESPACE_PATTERN, 'g')\n","import type { Editor } from '@tiptap/core'\nimport { getAttributes } from '@tiptap/core'\nimport type { MarkType } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\n\ntype ClickHandlerOptions = {\n type: MarkType\n editor: Editor\n openOnClick?: boolean\n enableClickSelection?: boolean\n}\n\nexport function clickHandler(options: ClickHandlerOptions): Plugin {\n return new Plugin({\n key: new PluginKey('handleClickLink'),\n props: {\n handleClick: (view, pos, event) => {\n if (event.button !== 0) {\n return false\n }\n\n if (!view.editable) {\n return false\n }\n\n let link: HTMLAnchorElement | null = null\n\n if (event.target instanceof HTMLAnchorElement) {\n link = event.target\n } else {\n const target = event.target as HTMLElement | null\n if (!target) {\n return false\n }\n\n const root = options.editor.view.dom\n\n // Tntentionally limit the lookup to the editor root.\n // Using tag names like DIV as boundaries breaks with custom NodeViews,\n link = target.closest<HTMLAnchorElement>('a')\n\n if (link && !root.contains(link)) {\n link = null\n }\n }\n\n if (!link) {\n return false\n }\n\n let handled = false\n\n if (options.enableClickSelection) {\n const commandResult = options.editor.commands.extendMarkRange(options.type.name)\n handled = commandResult\n }\n\n if (options.openOnClick) {\n const attrs = getAttributes(view.state, options.type.name)\n const href = link.href ?? attrs.href\n const target = link.target ?? attrs.target\n\n if (href) {\n window.open(href, target)\n handled = true\n }\n }\n\n return handled\n },\n },\n })\n}\n","import type { Editor } from '@tiptap/core'\nimport type { MarkType } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { find } from 'linkifyjs'\n\nimport type { LinkOptions } from '../link.js'\n\ntype PasteHandlerOptions = {\n editor: Editor\n defaultProtocol: string\n type: MarkType\n shouldAutoLink?: LinkOptions['shouldAutoLink']\n}\n\nexport function pasteHandler(options: PasteHandlerOptions): Plugin {\n return new Plugin({\n key: new PluginKey('handlePasteLink'),\n props: {\n handlePaste: (view, _event, slice) => {\n const { shouldAutoLink } = options\n const { state } = view\n const { selection } = state\n const { empty } = selection\n\n if (empty) {\n return false\n }\n\n let textContent = ''\n\n slice.content.forEach(node => {\n textContent += node.textContent\n })\n\n const link = find(textContent, { defaultProtocol: options.defaultProtocol }).find(\n item => item.isLink && item.value === textContent,\n )\n\n if (!textContent || !link || (shouldAutoLink !== undefined && !shouldAutoLink(link.value))) {\n return false\n }\n\n return options.editor.commands.setMark(options.type, {\n href: link.href,\n })\n },\n },\n })\n}\n","import { Link } from './link.js'\n\nexport * from './link.js'\n\nexport default Link\n"],"mappings":"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","names":["find","Plugin","PluginKey","Plugin","PluginKey","find"]}
1
+ {"version":3,"sources":["../src/link.ts","../src/helpers/autolink.ts","../src/helpers/whitespace.ts","../src/helpers/clickHandler.ts","../src/helpers/pasteHandler.ts","../src/index.ts"],"sourcesContent":["import type { PasteRuleMatch } from '@tiptap/core'\nimport { Mark, markPasteRule, mergeAttributes } from '@tiptap/core'\nimport type { Plugin } from '@tiptap/pm/state'\nimport { find, registerCustomProtocol, reset } from 'linkifyjs'\n\nimport { autolink } from './helpers/autolink.js'\nimport { clickHandler } from './helpers/clickHandler.js'\nimport { pasteHandler } from './helpers/pasteHandler.js'\nimport { UNICODE_WHITESPACE_REGEX_GLOBAL } from './helpers/whitespace.js'\n\nexport interface LinkProtocolOptions {\n /**\n * The protocol scheme to be registered.\n * @default '''\n * @example 'ftp'\n * @example 'git'\n */\n scheme: string\n\n /**\n * If enabled, it allows optional slashes after the protocol.\n * @default false\n * @example true\n */\n optionalSlashes?: boolean\n}\n\nexport const pasteRegex =\n /https?:\\/\\/(?:www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z]{2,}\\b(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)/gi\n\n/**\n * @deprecated The default behavior is now to open links when the editor is not editable.\n */\ntype DeprecatedOpenWhenNotEditable = 'whenNotEditable'\n\nexport interface LinkOptions {\n /**\n * If enabled, the extension will automatically add links as you type.\n * @default true\n * @example false\n */\n autolink: boolean\n\n /**\n * An array of custom protocols to be registered with linkifyjs.\n * @default []\n * @example ['ftp', 'git']\n */\n protocols: Array<LinkProtocolOptions | string>\n\n /**\n * Default protocol to use when no protocol is specified.\n * @default 'http'\n */\n defaultProtocol: string\n /**\n * If enabled, links will be opened on click.\n * @default true\n * @example false\n */\n openOnClick: boolean | DeprecatedOpenWhenNotEditable\n /**\n * If enabled, the link will be selected when clicked.\n * @default false\n * @example true\n */\n enableClickSelection: boolean\n /**\n * Adds a link to the current selection if the pasted content only contains an url.\n * @default true\n * @example false\n */\n linkOnPaste: boolean\n\n /**\n * HTML attributes to add to the link element.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>\n\n /**\n * @deprecated Use the `shouldAutoLink` option instead.\n * A validation function that modifies link verification for the auto linker.\n * @param url - The url to be validated.\n * @returns - True if the url is valid, false otherwise.\n */\n validate: (url: string) => boolean\n\n /**\n * A validation function which is used for configuring link verification for preventing XSS attacks.\n * Only modify this if you know what you're doing.\n *\n * @returns {boolean} `true` if the URL is valid, `false` otherwise.\n *\n * @example\n * isAllowedUri: (url, { defaultValidate, protocols, defaultProtocol }) => {\n * return url.startsWith('./') || defaultValidate(url)\n * }\n */\n isAllowedUri: (\n /**\n * The URL to be validated.\n */\n url: string,\n ctx: {\n /**\n * The default validation function.\n */\n defaultValidate: (url: string) => boolean\n /**\n * An array of allowed protocols for the URL (e.g., \"http\", \"https\"). As defined in the `protocols` option.\n */\n protocols: Array<LinkProtocolOptions | string>\n /**\n * A string that represents the default protocol (e.g., 'http'). As defined in the `defaultProtocol` option.\n */\n defaultProtocol: string\n },\n ) => boolean\n\n /**\n * Determines whether a valid link should be automatically linked in the content.\n *\n * @param {string} url - The URL that has already been validated.\n * @returns {boolean} - True if the link should be auto-linked; false if it should not be auto-linked.\n */\n shouldAutoLink: (url: string) => boolean\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n link: {\n /**\n * Set a link mark\n * @param attributes The link attributes\n * @example editor.commands.setLink({ href: 'https://tiptap.dev' })\n */\n setLink: (attributes: {\n href: string\n target?: string | null\n rel?: string | null\n class?: string | null\n title?: string | null\n }) => ReturnType\n /**\n * Toggle a link mark\n * @param attributes The link attributes\n * @example editor.commands.toggleLink({ href: 'https://tiptap.dev' })\n */\n toggleLink: (attributes?: {\n href: string\n target?: string | null\n rel?: string | null\n class?: string | null\n title?: string | null\n }) => ReturnType\n /**\n * Unset a link mark\n * @example editor.commands.unsetLink()\n */\n unsetLink: () => ReturnType\n }\n }\n}\n\nexport function isAllowedUri(uri: string | undefined, protocols?: LinkOptions['protocols']) {\n const allowedProtocols: string[] = [\n 'http',\n 'https',\n 'ftp',\n 'ftps',\n 'mailto',\n 'tel',\n 'callto',\n 'sms',\n 'cid',\n 'xmpp',\n ]\n\n if (protocols) {\n protocols.forEach(protocol => {\n const nextProtocol = typeof protocol === 'string' ? protocol : protocol.scheme\n\n if (nextProtocol) {\n allowedProtocols.push(nextProtocol)\n }\n })\n }\n\n return (\n !uri ||\n uri.replace(UNICODE_WHITESPACE_REGEX_GLOBAL, '').match(\n new RegExp(\n // oxlint-disable-next-line no-useless-escape\n `^(?:(?:${allowedProtocols.join('|')}):|[^a-z]|[a-z0-9+.\\-]+(?:[^a-z+.\\-:]|$))`,\n 'i',\n ),\n )\n )\n}\n\n/**\n * This extension allows you to create links.\n * @see https://www.tiptap.dev/api/marks/link\n */\nexport const Link = Mark.create<LinkOptions>({\n name: 'link',\n\n priority: 1000,\n\n keepOnSplit: false,\n\n exitable: true,\n\n onCreate() {\n // TODO: v4 - remove validate option\n if (this.options.validate && !this.options.shouldAutoLink) {\n // Copy the validate function to the shouldAutoLink option\n this.options.shouldAutoLink = this.options.validate\n console.warn(\n 'The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead.',\n )\n }\n this.options.protocols.forEach(protocol => {\n if (typeof protocol === 'string') {\n registerCustomProtocol(protocol)\n return\n }\n registerCustomProtocol(protocol.scheme, protocol.optionalSlashes)\n })\n },\n\n onDestroy() {\n reset()\n },\n\n inclusive() {\n return this.options.autolink\n },\n\n addOptions() {\n return {\n openOnClick: true,\n enableClickSelection: false,\n linkOnPaste: true,\n autolink: true,\n protocols: [],\n defaultProtocol: 'http',\n HTMLAttributes: {\n target: '_blank',\n rel: 'noopener noreferrer nofollow',\n class: null,\n },\n isAllowedUri: (url, ctx) => !!isAllowedUri(url, ctx.protocols),\n validate: url => !!url,\n shouldAutoLink: url => {\n // URLs with explicit protocols (e.g., https://) should be auto-linked\n // But not if @ appears before :// (that would be userinfo like user:pass@host)\n const hasProtocol = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(url)\n const hasMaybeProtocol = /^[a-z][a-z0-9+.-]*:/i.test(url)\n\n if (hasProtocol || (hasMaybeProtocol && !url.includes('@'))) {\n return true\n }\n // Strip userinfo (user:pass@) if present, then extract hostname\n const urlWithoutUserinfo = url.includes('@') ? url.split('@').pop()! : url\n const hostname = urlWithoutUserinfo.split(/[/?#:]/)[0]\n\n // Don't auto-link IP addresses without protocol\n if (/^\\d{1,3}(\\.\\d{1,3}){3}$/.test(hostname)) {\n return false\n }\n // Don't auto-link single-word hostnames without TLD (e.g., \"localhost\")\n if (!/\\./.test(hostname)) {\n return false\n }\n return true\n },\n }\n },\n\n addAttributes() {\n return {\n href: {\n default: null,\n parseHTML(element) {\n return element.getAttribute('href')\n },\n },\n target: {\n default: this.options.HTMLAttributes.target,\n },\n rel: {\n default: this.options.HTMLAttributes.rel,\n },\n class: {\n default: this.options.HTMLAttributes.class,\n },\n title: {\n default: null,\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'a[href]',\n getAttrs: dom => {\n const href = (dom as HTMLElement).getAttribute('href')\n\n // prevent XSS attacks\n if (\n !href ||\n !this.options.isAllowedUri(href, {\n defaultValidate: url => !!isAllowedUri(url, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n return false\n }\n return null\n },\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n // prevent XSS attacks\n if (\n !this.options.isAllowedUri(HTMLAttributes.href, {\n defaultValidate: href => !!isAllowedUri(href, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n // strip out the href\n return ['a', mergeAttributes(this.options.HTMLAttributes, { ...HTMLAttributes, href: '' }), 0]\n }\n\n return ['a', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]\n },\n\n markdownTokenName: 'link',\n\n parseMarkdown: (token, helpers) => {\n return helpers.applyMark('link', helpers.parseInline(token.tokens || []), {\n href: token.href,\n title: token.title || null,\n })\n },\n\n renderMarkdown: (node, h) => {\n const href = node.attrs?.href ?? ''\n const title = node.attrs?.title ?? ''\n const text = h.renderChildren(node)\n\n return title ? `[${text}](${href} \"${title}\")` : `[${text}](${href})`\n },\n\n addCommands() {\n return {\n setLink:\n attributes =>\n ({ chain }) => {\n const { href } = attributes\n\n if (\n !this.options.isAllowedUri(href, {\n defaultValidate: url => !!isAllowedUri(url, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n return false\n }\n\n return chain().setMark(this.name, attributes).setMeta('preventAutolink', true).run()\n },\n\n toggleLink:\n attributes =>\n ({ chain }) => {\n const { href } = attributes || {}\n\n if (\n href &&\n !this.options.isAllowedUri(href, {\n defaultValidate: url => !!isAllowedUri(url, this.options.protocols),\n protocols: this.options.protocols,\n defaultProtocol: this.options.defaultProtocol,\n })\n ) {\n return false\n }\n\n return chain()\n .toggleMark(this.name, attributes, { extendEmptyMarkRange: true })\n .setMeta('preventAutolink', true)\n .run()\n },\n\n unsetLink:\n () =>\n ({ chain }) => {\n return chain()\n .unsetMark(this.name, { extendEmptyMarkRange: true })\n .setMeta('preventAutolink', true)\n .run()\n },\n }\n },\n\n addPasteRules() {\n return [\n markPasteRule({\n find: text => {\n const foundLinks: PasteRuleMatch[] = []\n\n if (text) {\n const { protocols, defaultProtocol } = this.options\n const links = find(text).filter(\n item =>\n item.isLink &&\n this.options.isAllowedUri(item.value, {\n defaultValidate: href => !!isAllowedUri(href, protocols),\n protocols,\n defaultProtocol,\n }),\n )\n\n if (links.length) {\n links.forEach(link => {\n if (!this.options.shouldAutoLink(link.value)) {\n return\n }\n\n foundLinks.push({\n text: link.value,\n data: {\n href: link.href,\n },\n index: link.start,\n })\n })\n }\n }\n\n return foundLinks\n },\n type: this.type,\n getAttributes: match => {\n return {\n href: match.data?.href,\n }\n },\n }),\n ]\n },\n\n addProseMirrorPlugins() {\n const plugins: Plugin[] = []\n const { protocols, defaultProtocol } = this.options\n\n if (this.options.autolink) {\n plugins.push(\n autolink({\n type: this.type,\n defaultProtocol: this.options.defaultProtocol,\n validate: url =>\n this.options.isAllowedUri(url, {\n defaultValidate: href => !!isAllowedUri(href, protocols),\n protocols,\n defaultProtocol,\n }),\n shouldAutoLink: this.options.shouldAutoLink,\n }),\n )\n }\n\n plugins.push(\n clickHandler({\n type: this.type,\n editor: this.editor,\n openOnClick:\n this.options.openOnClick === 'whenNotEditable' ? true : this.options.openOnClick,\n enableClickSelection: this.options.enableClickSelection,\n }),\n )\n\n if (this.options.linkOnPaste) {\n plugins.push(\n pasteHandler({\n editor: this.editor,\n defaultProtocol: this.options.defaultProtocol,\n type: this.type,\n shouldAutoLink: this.options.shouldAutoLink,\n }),\n )\n }\n\n return plugins\n },\n})\n","import type { NodeWithPos } from '@tiptap/core'\nimport {\n combineTransactionSteps,\n findChildrenInRange,\n getChangedRanges,\n getMarksBetween,\n} from '@tiptap/core'\nimport type { MarkType } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport type { MultiToken } from 'linkifyjs'\nimport { tokenize } from 'linkifyjs'\n\nimport { UNICODE_WHITESPACE_REGEX, UNICODE_WHITESPACE_REGEX_END } from './whitespace.js'\n\n/**\n * Check if the provided tokens form a valid link structure, which can either be a single link token\n * or a link token surrounded by parentheses or square brackets.\n *\n * This ensures that only complete and valid text is hyperlinked, preventing cases where a valid\n * top-level domain (TLD) is immediately followed by an invalid character, like a number. For\n * example, with the `find` method from Linkify, entering `example.com1` would result in\n * `example.com` being linked and the trailing `1` left as plain text. By using the `tokenize`\n * method, we can perform more comprehensive validation on the input text.\n */\nfunction isValidLinkStructure(tokens: Array<ReturnType<MultiToken['toObject']>>) {\n if (tokens.length === 1) {\n return tokens[0].isLink\n }\n\n if (tokens.length === 3 && tokens[1].isLink) {\n return ['()', '[]'].includes(tokens[0].value + tokens[2].value)\n }\n\n return false\n}\n\ntype AutolinkOptions = {\n type: MarkType\n defaultProtocol: string\n validate: (url: string) => boolean\n shouldAutoLink: (url: string) => boolean\n}\n\n/**\n * This plugin allows you to automatically add links to your editor.\n * @param options The plugin options\n * @returns The plugin instance\n */\nexport function autolink(options: AutolinkOptions): Plugin {\n return new Plugin({\n key: new PluginKey('autolink'),\n appendTransaction: (transactions, oldState, newState) => {\n /**\n * Does the transaction change the document?\n */\n const docChanges =\n transactions.some(transaction => transaction.docChanged) && !oldState.doc.eq(newState.doc)\n\n /**\n * Prevent autolink if the transaction is not a document change or if the transaction has the meta `preventAutolink`.\n */\n const preventAutolink = transactions.some(transaction =>\n transaction.getMeta('preventAutolink'),\n )\n\n /**\n * Prevent autolink if the transaction is not a document change\n * or if the transaction has the meta `preventAutolink`.\n */\n if (!docChanges || preventAutolink) {\n return\n }\n\n const { tr } = newState\n const transform = combineTransactionSteps(oldState.doc, [...transactions])\n const changes = getChangedRanges(transform)\n\n changes.forEach(({ newRange }) => {\n // Now let’s see if we can add new links.\n const nodesInChangedRanges = findChildrenInRange(\n newState.doc,\n newRange,\n node => node.isTextblock,\n )\n\n let textBlock: NodeWithPos | undefined\n let textBeforeWhitespace: string | undefined\n\n if (nodesInChangedRanges.length > 1) {\n // Grab the first node within the changed ranges (ex. the first of two paragraphs when hitting enter).\n textBlock = nodesInChangedRanges[0]\n textBeforeWhitespace = newState.doc.textBetween(\n textBlock.pos,\n textBlock.pos + textBlock.node.nodeSize,\n undefined,\n ' ',\n )\n } else if (nodesInChangedRanges.length) {\n const endText = newState.doc.textBetween(newRange.from, newRange.to, ' ', ' ')\n if (!UNICODE_WHITESPACE_REGEX_END.test(endText)) {\n return\n }\n textBlock = nodesInChangedRanges[0]\n textBeforeWhitespace = newState.doc.textBetween(\n textBlock.pos,\n newRange.to,\n undefined,\n ' ',\n )\n }\n\n if (textBlock && textBeforeWhitespace) {\n const wordsBeforeWhitespace = textBeforeWhitespace\n .split(UNICODE_WHITESPACE_REGEX)\n .filter(Boolean)\n\n if (wordsBeforeWhitespace.length <= 0) {\n return false\n }\n\n const lastWordBeforeSpace = wordsBeforeWhitespace[wordsBeforeWhitespace.length - 1]\n const lastWordAndBlockOffset =\n textBlock.pos + textBeforeWhitespace.lastIndexOf(lastWordBeforeSpace)\n\n if (!lastWordBeforeSpace) {\n return false\n }\n\n const linksBeforeSpace = tokenize(lastWordBeforeSpace).map(t =>\n t.toObject(options.defaultProtocol),\n )\n\n if (!isValidLinkStructure(linksBeforeSpace)) {\n return false\n }\n\n linksBeforeSpace\n .filter(link => link.isLink)\n // Calculate link position.\n .map(link => ({\n ...link,\n from: lastWordAndBlockOffset + link.start + 1,\n to: lastWordAndBlockOffset + link.end + 1,\n }))\n // ignore link inside code mark\n .filter(link => {\n if (!newState.schema.marks.code) {\n return true\n }\n\n return !newState.doc.rangeHasMark(link.from, link.to, newState.schema.marks.code)\n })\n // validate link\n .filter(link => options.validate(link.value))\n // check whether should autolink\n .filter(link => options.shouldAutoLink(link.value))\n // Add link mark.\n .forEach(link => {\n if (\n getMarksBetween(link.from, link.to, newState.doc).some(\n item => item.mark.type === options.type,\n )\n ) {\n return\n }\n\n tr.addMark(\n link.from,\n link.to,\n options.type.create({\n href: link.href,\n }),\n )\n })\n }\n })\n\n if (!tr.steps.length) {\n return\n }\n\n return tr\n },\n })\n}\n","// From DOMPurify\n// https://github.com/cure53/DOMPurify/blob/main/src/regexp.ts\nexport const UNICODE_WHITESPACE_PATTERN =\n '[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]'\n\nexport const UNICODE_WHITESPACE_REGEX = new RegExp(UNICODE_WHITESPACE_PATTERN)\nexport const UNICODE_WHITESPACE_REGEX_END = new RegExp(`${UNICODE_WHITESPACE_PATTERN}$`)\nexport const UNICODE_WHITESPACE_REGEX_GLOBAL = new RegExp(UNICODE_WHITESPACE_PATTERN, 'g')\n","import type { Editor } from '@tiptap/core'\nimport { getAttributes } from '@tiptap/core'\nimport type { MarkType } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\n\ntype ClickHandlerOptions = {\n type: MarkType\n editor: Editor\n openOnClick?: boolean\n enableClickSelection?: boolean\n}\n\nexport function clickHandler(options: ClickHandlerOptions): Plugin {\n return new Plugin({\n key: new PluginKey('handleClickLink'),\n props: {\n handleClick: (view, pos, event) => {\n if (event.button !== 0) {\n return false\n }\n\n if (!view.editable) {\n return false\n }\n\n let link: HTMLAnchorElement | null = null\n\n if (event.target instanceof HTMLAnchorElement) {\n link = event.target\n } else {\n const target = event.target as HTMLElement | null\n if (!target) {\n return false\n }\n\n const root = options.editor.view.dom\n\n // Tntentionally limit the lookup to the editor root.\n // Using tag names like DIV as boundaries breaks with custom NodeViews,\n link = target.closest<HTMLAnchorElement>('a')\n\n if (link && !root.contains(link)) {\n link = null\n }\n }\n\n if (!link) {\n return false\n }\n\n let handled = false\n\n if (options.enableClickSelection) {\n const commandResult = options.editor.commands.extendMarkRange(options.type.name)\n handled = commandResult\n }\n\n if (options.openOnClick) {\n const attrs = getAttributes(view.state, options.type.name)\n const href = link.href ?? attrs.href\n const target = link.target ?? attrs.target\n\n if (href) {\n window.open(href, target)\n handled = true\n }\n }\n\n return handled\n },\n },\n })\n}\n","import type { Editor } from '@tiptap/core'\nimport type { MarkType } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { find } from 'linkifyjs'\n\nimport type { LinkOptions } from '../link.js'\n\ntype PasteHandlerOptions = {\n editor: Editor\n defaultProtocol: string\n type: MarkType\n shouldAutoLink?: LinkOptions['shouldAutoLink']\n}\n\nexport function pasteHandler(options: PasteHandlerOptions): Plugin {\n return new Plugin({\n key: new PluginKey('handlePasteLink'),\n props: {\n handlePaste: (view, _event, slice) => {\n const { shouldAutoLink } = options\n const { state } = view\n const { selection } = state\n const { empty } = selection\n\n if (empty) {\n return false\n }\n\n let textContent = ''\n\n slice.content.forEach(node => {\n textContent += node.textContent\n })\n\n const link = find(textContent, { defaultProtocol: options.defaultProtocol }).find(\n item => item.isLink && item.value === textContent,\n )\n\n if (\n !textContent ||\n !link ||\n (shouldAutoLink !== undefined && !shouldAutoLink(link.value))\n ) {\n return false\n }\n\n return options.editor.commands.setMark(options.type, {\n href: link.href,\n })\n },\n },\n })\n}\n","import { Link } from './link.js'\n\nexport * from './link.js'\n\nexport default Link\n"],"mappings":"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","names":["find","Plugin","PluginKey","Plugin","PluginKey","find"]}
package/package.json CHANGED
@@ -1,18 +1,30 @@
1
1
  {
2
2
  "name": "@tiptap/extension-link",
3
+ "version": "3.24.0",
3
4
  "description": "link extension for tiptap",
4
- "version": "3.23.5",
5
- "homepage": "https://tiptap.dev",
6
5
  "keywords": [
7
6
  "tiptap",
8
7
  "tiptap extension"
9
8
  ],
9
+ "homepage": "https://tiptap.dev",
10
10
  "license": "MIT",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/ueberdosis/tiptap",
14
+ "directory": "packages/extension-link"
15
+ },
11
16
  "funding": {
12
17
  "type": "github",
13
18
  "url": "https://github.com/sponsors/ueberdosis"
14
19
  },
20
+ "files": [
21
+ "src",
22
+ "dist"
23
+ ],
15
24
  "type": "module",
25
+ "main": "dist/index.cjs",
26
+ "module": "dist/index.js",
27
+ "types": "dist/index.d.ts",
16
28
  "exports": {
17
29
  ".": {
18
30
  "types": {
@@ -23,31 +35,18 @@
23
35
  "require": "./dist/index.cjs"
24
36
  }
25
37
  },
26
- "main": "dist/index.cjs",
27
- "module": "dist/index.js",
28
- "types": "dist/index.d.ts",
29
- "files": [
30
- "src",
31
- "dist"
32
- ],
33
38
  "dependencies": {
34
39
  "linkifyjs": "^4.3.3"
35
40
  },
36
41
  "devDependencies": {
37
- "@tiptap/core": "^3.23.5",
38
- "@tiptap/pm": "^3.23.5"
42
+ "@tiptap/core": "^3.24.0",
43
+ "@tiptap/pm": "^3.24.0"
39
44
  },
40
45
  "peerDependencies": {
41
- "@tiptap/pm": "3.23.5",
42
- "@tiptap/core": "3.23.5"
43
- },
44
- "repository": {
45
- "type": "git",
46
- "url": "https://github.com/ueberdosis/tiptap",
47
- "directory": "packages/extension-link"
46
+ "@tiptap/core": "3.24.0",
47
+ "@tiptap/pm": "3.24.0"
48
48
  },
49
49
  "scripts": {
50
- "build": "tsup",
51
- "lint": "prettier ./src/ --check && eslint --cache --quiet --no-error-on-unmatched-pattern ./src/"
50
+ "build": "tsup"
52
51
  }
53
52
  }
@@ -1,5 +1,10 @@
1
1
  import type { NodeWithPos } from '@tiptap/core'
2
- import { combineTransactionSteps, findChildrenInRange, getChangedRanges, getMarksBetween } from '@tiptap/core'
2
+ import {
3
+ combineTransactionSteps,
4
+ findChildrenInRange,
5
+ getChangedRanges,
6
+ getMarksBetween,
7
+ } from '@tiptap/core'
3
8
  import type { MarkType } from '@tiptap/pm/model'
4
9
  import { Plugin, PluginKey } from '@tiptap/pm/state'
5
10
  import type { MultiToken } from 'linkifyjs'
@@ -48,12 +53,15 @@ export function autolink(options: AutolinkOptions): Plugin {
48
53
  /**
49
54
  * Does the transaction change the document?
50
55
  */
51
- const docChanges = transactions.some(transaction => transaction.docChanged) && !oldState.doc.eq(newState.doc)
56
+ const docChanges =
57
+ transactions.some(transaction => transaction.docChanged) && !oldState.doc.eq(newState.doc)
52
58
 
53
59
  /**
54
60
  * Prevent autolink if the transaction is not a document change or if the transaction has the meta `preventAutolink`.
55
61
  */
56
- const preventAutolink = transactions.some(transaction => transaction.getMeta('preventAutolink'))
62
+ const preventAutolink = transactions.some(transaction =>
63
+ transaction.getMeta('preventAutolink'),
64
+ )
57
65
 
58
66
  /**
59
67
  * Prevent autolink if the transaction is not a document change
@@ -69,7 +77,11 @@ export function autolink(options: AutolinkOptions): Plugin {
69
77
 
70
78
  changes.forEach(({ newRange }) => {
71
79
  // Now let’s see if we can add new links.
72
- const nodesInChangedRanges = findChildrenInRange(newState.doc, newRange, node => node.isTextblock)
80
+ const nodesInChangedRanges = findChildrenInRange(
81
+ newState.doc,
82
+ newRange,
83
+ node => node.isTextblock,
84
+ )
73
85
 
74
86
  let textBlock: NodeWithPos | undefined
75
87
  let textBeforeWhitespace: string | undefined
@@ -89,24 +101,34 @@ export function autolink(options: AutolinkOptions): Plugin {
89
101
  return
90
102
  }
91
103
  textBlock = nodesInChangedRanges[0]
92
- textBeforeWhitespace = newState.doc.textBetween(textBlock.pos, newRange.to, undefined, ' ')
104
+ textBeforeWhitespace = newState.doc.textBetween(
105
+ textBlock.pos,
106
+ newRange.to,
107
+ undefined,
108
+ ' ',
109
+ )
93
110
  }
94
111
 
95
112
  if (textBlock && textBeforeWhitespace) {
96
- const wordsBeforeWhitespace = textBeforeWhitespace.split(UNICODE_WHITESPACE_REGEX).filter(Boolean)
113
+ const wordsBeforeWhitespace = textBeforeWhitespace
114
+ .split(UNICODE_WHITESPACE_REGEX)
115
+ .filter(Boolean)
97
116
 
98
117
  if (wordsBeforeWhitespace.length <= 0) {
99
118
  return false
100
119
  }
101
120
 
102
121
  const lastWordBeforeSpace = wordsBeforeWhitespace[wordsBeforeWhitespace.length - 1]
103
- const lastWordAndBlockOffset = textBlock.pos + textBeforeWhitespace.lastIndexOf(lastWordBeforeSpace)
122
+ const lastWordAndBlockOffset =
123
+ textBlock.pos + textBeforeWhitespace.lastIndexOf(lastWordBeforeSpace)
104
124
 
105
125
  if (!lastWordBeforeSpace) {
106
126
  return false
107
127
  }
108
128
 
109
- const linksBeforeSpace = tokenize(lastWordBeforeSpace).map(t => t.toObject(options.defaultProtocol))
129
+ const linksBeforeSpace = tokenize(lastWordBeforeSpace).map(t =>
130
+ t.toObject(options.defaultProtocol),
131
+ )
110
132
 
111
133
  if (!isValidLinkStructure(linksBeforeSpace)) {
112
134
  return false
@@ -134,7 +156,11 @@ export function autolink(options: AutolinkOptions): Plugin {
134
156
  .filter(link => options.shouldAutoLink(link.value))
135
157
  // Add link mark.
136
158
  .forEach(link => {
137
- if (getMarksBetween(link.from, link.to, newState.doc).some(item => item.mark.type === options.type)) {
159
+ if (
160
+ getMarksBetween(link.from, link.to, newState.doc).some(
161
+ item => item.mark.type === options.type,
162
+ )
163
+ ) {
138
164
  return
139
165
  }
140
166
 
@@ -36,7 +36,11 @@ export function pasteHandler(options: PasteHandlerOptions): Plugin {
36
36
  item => item.isLink && item.value === textContent,
37
37
  )
38
38
 
39
- if (!textContent || !link || (shouldAutoLink !== undefined && !shouldAutoLink(link.value))) {
39
+ if (
40
+ !textContent ||
41
+ !link ||
42
+ (shouldAutoLink !== undefined && !shouldAutoLink(link.value))
43
+ ) {
40
44
  return false
41
45
  }
42
46
 
@@ -1,6 +1,7 @@
1
1
  // From DOMPurify
2
2
  // https://github.com/cure53/DOMPurify/blob/main/src/regexp.ts
3
- export const UNICODE_WHITESPACE_PATTERN = '[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]'
3
+ export const UNICODE_WHITESPACE_PATTERN =
4
+ '[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]'
4
5
 
5
6
  export const UNICODE_WHITESPACE_REGEX = new RegExp(UNICODE_WHITESPACE_PATTERN)
6
7
  export const UNICODE_WHITESPACE_REGEX_END = new RegExp(`${UNICODE_WHITESPACE_PATTERN}$`)
package/src/link.ts CHANGED
@@ -165,7 +165,18 @@ declare module '@tiptap/core' {
165
165
  }
166
166
 
167
167
  export function isAllowedUri(uri: string | undefined, protocols?: LinkOptions['protocols']) {
168
- const allowedProtocols: string[] = ['http', 'https', 'ftp', 'ftps', 'mailto', 'tel', 'callto', 'sms', 'cid', 'xmpp']
168
+ const allowedProtocols: string[] = [
169
+ 'http',
170
+ 'https',
171
+ 'ftp',
172
+ 'ftps',
173
+ 'mailto',
174
+ 'tel',
175
+ 'callto',
176
+ 'sms',
177
+ 'cid',
178
+ 'xmpp',
179
+ ]
169
180
 
170
181
  if (protocols) {
171
182
  protocols.forEach(protocol => {
@@ -181,7 +192,7 @@ export function isAllowedUri(uri: string | undefined, protocols?: LinkOptions['p
181
192
  !uri ||
182
193
  uri.replace(UNICODE_WHITESPACE_REGEX_GLOBAL, '').match(
183
194
  new RegExp(
184
- // eslint-disable-next-line no-useless-escape
195
+ // oxlint-disable-next-line no-useless-escape
185
196
  `^(?:(?:${allowedProtocols.join('|')}):|[^a-z]|[a-z0-9+.\-]+(?:[^a-z+.\-:]|$))`,
186
197
  'i',
187
198
  ),
@@ -207,7 +218,9 @@ export const Link = Mark.create<LinkOptions>({
207
218
  if (this.options.validate && !this.options.shouldAutoLink) {
208
219
  // Copy the validate function to the shouldAutoLink option
209
220
  this.options.shouldAutoLink = this.options.validate
210
- console.warn('The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead.')
221
+ console.warn(
222
+ 'The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead.',
223
+ )
211
224
  }
212
225
  this.options.protocols.forEach(protocol => {
213
226
  if (typeof protocol === 'string') {
@@ -392,7 +405,10 @@ export const Link = Mark.create<LinkOptions>({
392
405
  unsetLink:
393
406
  () =>
394
407
  ({ chain }) => {
395
- return chain().unsetMark(this.name, { extendEmptyMarkRange: true }).setMeta('preventAutolink', true).run()
408
+ return chain()
409
+ .unsetMark(this.name, { extendEmptyMarkRange: true })
410
+ .setMeta('preventAutolink', true)
411
+ .run()
396
412
  },
397
413
  }
398
414
  },
@@ -468,7 +484,8 @@ export const Link = Mark.create<LinkOptions>({
468
484
  clickHandler({
469
485
  type: this.type,
470
486
  editor: this.editor,
471
- openOnClick: this.options.openOnClick === 'whenNotEditable' ? true : this.options.openOnClick,
487
+ openOnClick:
488
+ this.options.openOnClick === 'whenNotEditable' ? true : this.options.openOnClick,
472
489
  enableClickSelection: this.options.enableClickSelection,
473
490
  }),
474
491
  )