@docs.plus/extension-hyperlink 1.5.2 → 2.0.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/helpers/autoHyperlink.ts","../src/helpers/tippyHelper.ts","../src/helpers/clickHandler.ts","../src/helpers/pasteHandler.ts","../src/helpers/editHyperlink.ts","../src/hyperlink.ts","../src/modals/editeHyperlink.ts","../src/modals/icons.ts","../src/modals/previewHyperlink.ts","../src/modals/setHyperlink.ts"],"sourcesContent":["import {\n combineTransactionSteps,\n findChildrenInRange,\n getChangedRanges,\n getMarksBetween,\n NodeWithPos,\n} from \"@tiptap/core\";\nimport { MarkType } from \"@tiptap/pm/model\";\nimport { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport { find, test } from \"linkifyjs\";\n\ntype AutoHyperlinkOptions = {\n type: MarkType;\n validate?: (url: string) => boolean;\n};\n\nexport default function autoHyperlink(options: AutoHyperlinkOptions): Plugin {\n return new Plugin({\n key: new PluginKey(\"autoHyperlink\"),\n appendTransaction: (transactions, oldState, newState) => {\n const docChanges =\n transactions.some((transaction) => transaction.docChanged) &&\n !oldState.doc.eq(newState.doc);\n const preventAutoHyperlink = transactions.some((transaction) =>\n transaction.getMeta(\"preventAutoHyperlink\")\n );\n\n if (!docChanges || preventAutoHyperlink) {\n return;\n }\n\n const { tr } = newState;\n const transform = combineTransactionSteps(oldState.doc, [\n ...transactions,\n ]);\n const { mapping } = transform;\n const changes = getChangedRanges(transform);\n\n changes.forEach(({ oldRange, newRange }) => {\n // at first we check if we have to remove links\n getMarksBetween(oldRange.from, oldRange.to, oldState.doc)\n .filter((item) => item.mark.type === options.type)\n .forEach((oldMark) => {\n const newFrom = mapping.map(oldMark.from);\n const newTo = mapping.map(oldMark.to);\n const newMarks = getMarksBetween(\n newFrom,\n newTo,\n newState.doc\n ).filter((item) => item.mark.type === options.type);\n\n if (!newMarks.length) {\n return;\n }\n\n const newMark = newMarks[0];\n const oldLinkText = oldState.doc.textBetween(\n oldMark.from,\n oldMark.to,\n undefined,\n \" \"\n );\n const newLinkText = newState.doc.textBetween(\n newMark.from,\n newMark.to,\n undefined,\n \" \"\n );\n const wasLink = test(oldLinkText);\n const isLink = test(newLinkText);\n\n // remove only the link, if it was a link before too\n // because we don’t want to remove links that were set manually\n if (wasLink && !isLink) {\n tr.removeMark(newMark.from, newMark.to, options.type);\n }\n });\n\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 (\n nodesInChangedRanges.length &&\n // We want to make sure to include the block seperator argument to treat hard breaks like spaces\n newState.doc\n .textBetween(newRange.from, newRange.to, \" \", \" \")\n .endsWith(\" \")\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(\" \")\n .filter((s) => s !== \"\");\n\n if (wordsBeforeWhitespace.length <= 0) {\n return false;\n }\n\n const lastWordBeforeSpace =\n wordsBeforeWhitespace[wordsBeforeWhitespace.length - 1];\n const lastWordAndBlockOffset =\n textBlock.pos +\n textBeforeWhitespace.lastIndexOf(lastWordBeforeSpace);\n\n if (!lastWordBeforeSpace) {\n return false;\n }\n\n find(lastWordBeforeSpace)\n .filter((link) => link.isLink)\n .filter((link) => {\n if (options.validate) {\n return options.validate(link.value);\n }\n return true;\n })\n // calculate link position\n .map((link) => ({\n ...link,\n from: lastWordAndBlockOffset + link.start + 1,\n to: lastWordAndBlockOffset + link.end + 1,\n }))\n // add link mark\n .forEach((link) => {\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","import tippy, { Instance, Props, roundArrow } from \"tippy.js\";\nimport { Editor } from \"@tiptap/core\";\nimport { EditorView } from \"@tiptap/pm/view\";\nimport { posToDOMRect } from \"@tiptap/core\";\n\nexport interface TippyInitOptions {\n editor: Editor;\n validate?: (url: string) => boolean;\n}\n\nclass Tooltip {\n private tippyInstance?: Instance;\n private preventHide: boolean = false;\n private tippyWrapper: HTMLDivElement;\n private editor: Editor;\n private view: EditorView;\n\n constructor(options: TippyInitOptions) {\n this.editor = options.editor;\n this.view = this.editor.view;\n this.tippyWrapper = document.createElement(\"div\");\n this.tippyWrapper.addEventListener(\"mousedown\", this.mousedownHandler, {\n capture: true,\n });\n this.view.dom.addEventListener(\"dragstart\", this.dragstartHandler);\n this.editor.on(\"blur\", this.blurHandler);\n }\n\n init() {\n this.tippyWrapper.innerHTML = \"\";\n\n return { tippyModal: this.tippyWrapper, tippyInstance: this.tippyInstance };\n }\n\n show() {\n this.tippyInstance?.show();\n return true;\n }\n\n hide() {\n setTimeout(() => this.tippyInstance?.hide());\n return false;\n }\n\n private mousedownHandler = () => {\n this.preventHide = true;\n };\n\n private dragstartHandler = () => {\n this.hide();\n };\n\n private blurHandler = ({ event }: { event: FocusEvent }) => {\n if (this.preventHide) {\n this.preventHide = false;\n return;\n }\n if (\n event?.relatedTarget &&\n this.tippyWrapper.parentNode?.contains(event.relatedTarget as Node)\n ) {\n return;\n }\n this.hide();\n };\n\n private tippyBlurHandler = (event: FocusEvent) => {\n this.blurHandler({ event });\n };\n\n private createTooltip() {\n if (!this.editor || !this.editor.options) return;\n const { element: editorElement } = this.editor.options;\n const editorIsAttached = !!editorElement.parentElement;\n\n if (this.tippyInstance || !editorIsAttached) {\n return;\n }\n\n this.tippyInstance = tippy(editorElement, {\n duration: 0,\n getReferenceClientRect: null,\n content: this.tippyWrapper,\n interactive: true,\n trigger: \"manual\",\n placement: \"bottom\",\n hideOnClick: true,\n onClickOutside: (instance, event) => {\n this.hide();\n },\n onAfterUpdate: (instance, partialProps) => {\n this.show();\n },\n });\n\n if (this.tippyInstance.popper.firstChild) {\n (this.tippyInstance.popper.firstChild as HTMLElement).addEventListener(\n \"blur\",\n this.tippyBlurHandler\n );\n }\n }\n\n update(view: EditorView, option: any = {}) {\n this.createTooltip();\n\n option.arrow = option?.arrow ?? false;\n\n if (this.tippyInstance) {\n this.tippyInstance.setProps({\n ...option,\n getReferenceClientRect: () => {\n const pos = view.state.selection.from;\n // width: 0 is a hack to prevent tippy display in the wrong position\n return { ...posToDOMRect(view, pos, pos), width: 0 };\n },\n });\n }\n\n return {};\n }\n\n destroyTooltip() {\n if (this.tippyInstance) {\n this.tippyInstance.destroy();\n this.tippyInstance = undefined;\n this.tippyWrapper.removeEventListener(\"mousedown\", this.mousedownHandler, {\n capture: true,\n });\n this.view.dom.removeEventListener(\"dragstart\", this.dragstartHandler);\n this.editor.off(\"blur\", this.blurHandler);\n }\n }\n}\n\nexport default Tooltip;\n","import { getAttributes } from \"@tiptap/core\";\nimport { MarkType } from \"@tiptap/pm/model\";\nimport { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport { Editor } from \"@tiptap/core\";\nimport { EditorView } from \"@tiptap/pm/view\";\nimport Tooltip from \"./tippyHelper\";\n\n// Define type for the ClickHandlerOptions\ntype ClickHandlerOptions = {\n type: MarkType;\n editor: Editor;\n validate?: (url: string) => boolean;\n modal?: ((options: any) => void | HTMLElement) | null;\n};\n\nexport default function clickHandler(options: ClickHandlerOptions): Plugin {\n // Create the tooltip instance\n let tooltip = new Tooltip(options);\n\n // Initialize the tooltip\n let { tippyModal, tippyInstance } = tooltip.init();\n\n return new Plugin({\n key: new PluginKey(\"handleClickHyperlink\"),\n props: {\n handleClick: (view, pos, event) => {\n if (event.button !== 0) return false;\n\n // Get the target HTML element and its position\n const nodeTarget: HTMLElement = event.target as HTMLElement;\n const nodePos = view.posAtDOM(nodeTarget, 0);\n\n // Find the closest link element to the target element\n const link = nodeTarget?.closest(\"a\");\n\n // Extract attributes from the state\n const attrs = getAttributes(view.state, options.type.name);\n\n // Extract href and target attributes from the link element or the state\n const href = link?.href ?? attrs.href;\n const target = link?.target ?? attrs.target;\n\n // If there is no previewHyperlink modal provided, then open the link in new window\n if (!options.modal) {\n if (link && href) {\n window.open(href, target);\n }\n return true;\n }\n\n // if the link does not contain href attribute, hide the tooltip\n if (!link?.href) return tooltip.hide();\n\n // Create a preview of the hyperlink\n const hyperlinkPreview = options.modal({\n link,\n nodePos,\n tippy: tooltip,\n ...options,\n });\n\n // If there is no hyperlink preview, hide the modal\n if (!hyperlinkPreview) return tooltip.hide();\n\n // Empty the modal and append the hyperlink preview box\n\n while (tippyModal.firstChild) {\n tippyModal.removeChild(tippyModal.firstChild);\n }\n\n tippyModal.append(hyperlinkPreview);\n\n // Update the modal position\n tooltip.update(options.editor.view);\n\n return false;\n },\n },\n });\n}\n","import { Editor } from \"@tiptap/core\";\nimport { MarkType } from \"@tiptap/pm/model\";\nimport { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport { find } from \"linkifyjs\";\n\ntype PasteHandlerOptions = {\n editor: Editor;\n type: MarkType;\n};\n\nexport function pasteHandler(options: PasteHandlerOptions): Plugin {\n return new Plugin({\n key: new PluginKey(\"handlePasteHyperlink\"),\n props: {\n handlePaste: (view, event, slice) => {\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).find(\n (item) => item.isLink && item.value === textContent\n );\n\n if (!textContent || !link) {\n return false;\n }\n\n options.editor.commands.setMark(options.type, {\n href: link.href,\n });\n\n return true;\n },\n },\n });\n}\n","import { Editor } from \"@tiptap/core\";\nimport { find } from \"linkifyjs\";\n\ntype EditHyperlinkOptions = {\n editor: Editor;\n validate?: (url: string) => boolean;\n newURL?: string;\n newText?: string;\n};\n\nexport default function editHyperlink(options: EditHyperlinkOptions) {\n const { state, dispatch } = options.editor.view;\n const { from, to } = state.selection;\n let link: HTMLAnchorElement | null = null;\n\n const selectedNode = options.editor.view.domAtPos(from - 1).node as HTMLElement;\n const nodeName = selectedNode?.nodeName;\n\n if (nodeName === \"#text\") {\n link = (selectedNode.parentNode as HTMLElement)?.closest(\"a\");\n } else {\n link = selectedNode?.closest(\"a\");\n }\n\n // If no link found and node is paragraph, try finding link in sibling/parent\n if (!link && options.editor.view.domAtPos(from).node.nodeName === \"P\" && selectedNode.nextSibling)\n link =\n (selectedNode.nextSibling as HTMLAnchorElement) ||\n (selectedNode.parentElement as HTMLAnchorElement);\n\n if (!link) return true;\n\n const text = options.newText || link?.innerText;\n // Get the position of the link in the editor view\n const nodePos = options.editor.view.posAtDOM(link, 0);\n\n const sanitizeURL = find(options.newURL || link.href)\n .filter((link) => link.isLink)\n .filter((link) => (options.validate ? options.validate(link.value) : true))\n .at(0);\n\n return options.editor\n .chain()\n .focus()\n .command(({ tr }) => {\n tr.deleteRange(nodePos, nodePos + (link?.innerText || \"\")?.length).replaceWith(\n nodePos,\n nodePos,\n options.editor.schema.text(text, [\n options.editor.schema.marks.hyperlink.create({\n href: sanitizeURL?.href,\n }),\n ])\n );\n\n return true;\n })\n .run();\n}\n","import { Mark, markPasteRule, mergeAttributes } from \"@tiptap/core\";\nimport { Plugin } from \"@tiptap/pm/state\";\nimport { find, registerCustomProtocol, reset } from \"linkifyjs\";\nimport autoHyperlink from \"./helpers/autoHyperlink\";\nimport clickHandler from \"./helpers/clickHandler\";\nimport { pasteHandler } from \"./helpers/pasteHandler\";\nimport editHyperlinkHelper from \"./helpers/editHyperlink\";\nimport Tooltip from \"./helpers/tippyHelper\";\nimport { roundArrow } from \"tippy.js\";\nimport { TSetHyperlinkModalOptions } from \"./modals/setHyperlink\";\nimport { THyperlinkPreviewModalOptions } from \"./modals/previewHyperlink\";\n\nexport interface LinkProtocolOptions {\n scheme: string;\n optionalSlashes?: boolean;\n}\n\nexport interface HyperlinkOptions {\n /**\n * If enabled, it adds links as you type.\n */\n autoHyperlink: boolean;\n /**\n * An array of custom protocols to be registered with linkifyjs.\n */\n protocols: Array<LinkProtocolOptions | string>;\n /**\n * If enabled, links will be opened on click.\n */\n openOnClick: boolean;\n /**\n * Adds a link to the current selection if the pasted content only contains an url.\n */\n hyperlinkOnPaste: boolean;\n /**\n * A list of HTML attributes to be rendered.\n */\n HTMLAttributes: Record<string, any>;\n /**\n * A list of modals to be rendered.\n * @default null\n * @example\n */\n modals: {\n previewHyperlink?: ((options: THyperlinkPreviewModalOptions) => void | HTMLElement) | null;\n setHyperlink?: ((options: TSetHyperlinkModalOptions) => void | HTMLElement) | null;\n };\n /**\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\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n link: {\n /**\n * Edit the hyperlink's text\n */\n editHyperLinkText: (text: string) => ReturnType;\n\n /**\n * Edit the hyperlink's href value\n */\n editHyperLinkHref: (href: string) => ReturnType;\n\n /**\n * Edit the hyperlink's\n */\n editHyperlink: (attributes?: { newText?: string; newURL?: string }) => ReturnType;\n\n /**\n * Set a hyperlink\n */\n setHyperlink: (attributes?: { href: string; target?: string | null }) => ReturnType;\n\n /**\n * Unset a link mark\n */\n unsetHyperlink: () => ReturnType;\n };\n }\n}\n\nexport const Hyperlink = Mark.create<HyperlinkOptions>({\n name: \"hyperlink\",\n\n priority: 1000,\n\n keepOnSplit: false,\n\n onCreate() {\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.autoHyperlink;\n },\n\n addOptions() {\n return {\n openOnClick: true,\n hyperlinkOnPaste: true,\n autoHyperlink: true,\n protocols: [],\n HTMLAttributes: {\n target: \"_blank\",\n rel: \"noopener noreferrer nofollow\",\n class: null,\n },\n modals: {\n previewHyperlink: null,\n setHyperlink: null,\n },\n validate: undefined,\n };\n },\n\n addAttributes() {\n return {\n href: {\n default: null,\n },\n target: {\n default: this.options.HTMLAttributes.target,\n },\n class: {\n default: this.options.HTMLAttributes.class,\n },\n };\n },\n\n parseHTML() {\n return [{ tag: 'a[href]:not([href *= \"javascript:\" i])' }];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\"a\", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];\n },\n\n addCommands() {\n return {\n setHyperlink:\n (attributes) =>\n ({ editor, chain }) => {\n if (!this.options.modals.setHyperlink) {\n return chain()\n .setMark(this.name, attributes)\n .setMeta(\"preventAutohyperlink\", true)\n .run();\n } else {\n this.options.modals.setHyperlink({\n editor,\n validate: this.options.validate,\n extentionName: this.name,\n attributes,\n Tooltip,\n roundArrow,\n });\n return true;\n }\n },\n\n editHyperlink:\n (attributes) =>\n ({ editor }) => {\n return editHyperlinkHelper({\n ...attributes,\n editor,\n validate: this.options.validate,\n });\n },\n\n editHyperLinkText:\n (newText) =>\n ({ editor }) => {\n return editHyperlinkHelper({\n editor,\n newText,\n validate: this.options.validate,\n });\n },\n\n editHyperLinkHref:\n (newURL) =>\n ({ editor }) => {\n return editHyperlinkHelper({\n editor,\n validate: this.options.validate,\n newURL,\n });\n },\n\n unsetHyperlink:\n () =>\n ({ chain }) => {\n return chain()\n .unsetMark(this.name, { extendEmptyMarkRange: true })\n .setMeta(\"preventAutohyperlink\", true)\n .run();\n },\n };\n },\n\n addPasteRules() {\n return [\n markPasteRule({\n find: (text) =>\n find(text)\n .filter((link) => {\n if (this.options.validate) {\n return this.options.validate(link.value);\n }\n\n return true;\n })\n .filter((link) => link.isLink)\n .map((link) => ({\n text: link.value,\n index: link.start,\n data: link,\n })),\n type: this.type,\n getAttributes: (match) => ({\n href: match.data?.href,\n }),\n }),\n ];\n },\n\n addProseMirrorPlugins() {\n const plugins: Plugin[] = [];\n\n if (this.options.autoHyperlink) {\n plugins.push(\n autoHyperlink({\n type: this.type,\n validate: this.options.validate,\n })\n );\n }\n\n if (this.options.openOnClick) {\n plugins.push(\n clickHandler({\n type: this.type,\n editor: this.editor,\n validate: this.options.validate,\n modal: this.options.modals.previewHyperlink,\n })\n );\n }\n\n if (this.options.hyperlinkOnPaste) {\n plugins.push(\n pasteHandler({\n editor: this.editor,\n type: this.type,\n })\n );\n }\n\n return plugins;\n },\n});\n","import { Editor } from \"@tiptap/core\";\nimport { roundArrow } from \"tippy.js\";\nimport { find } from \"linkifyjs\";\nimport Tooltip from \"../helpers/tippyHelper\";\n\ntype EditHyperlinkModalOptions = {\n editor: Editor;\n validate?: (url: string) => boolean;\n link: HTMLAnchorElement;\n hyperlinkModal: HTMLElement;\n tippy: Tooltip;\n};\n\nexport const editHyperlinkHandler = (options: EditHyperlinkModalOptions) => {\n // Create the form\n const form = document.createElement(\"form\");\n\n const buttonsWrapper = document.createElement(\"div\");\n const inputsWrapper = document.createElement(\"div\");\n\n const linkTextInput = document.createElement(\"input\");\n const hrefInput = document.createElement(\"input\");\n const applyButton = document.createElement(\"button\");\n\n buttonsWrapper.classList.add(\"hyperlink-edit-modal__buttons-wrapper\");\n inputsWrapper.classList.add(\"hyperlink-edit-modal__inputs-wrapper\");\n\n linkTextInput.type = \"text\";\n linkTextInput.value = options.link?.innerText || \"\";\n linkTextInput.placeholder = \"Enter link text\";\n\n hrefInput.type = \"text\";\n hrefInput.value = options.link.href;\n hrefInput.placeholder = \"Enter href\";\n\n applyButton.type = \"submit\";\n applyButton.classList.add(\"hyperlink-edit-modal__apply-button\");\n applyButton.innerText = \"Apply\";\n\n buttonsWrapper.append(applyButton);\n inputsWrapper.append(linkTextInput, hrefInput);\n\n // Append to form\n form.append(inputsWrapper, buttonsWrapper);\n\n options.hyperlinkModal.innerHTML = \"\";\n options.hyperlinkModal.appendChild(form);\n\n hrefInput.addEventListener(\"keydown\", () => {\n hrefInput.style.outlineColor = \" #dadce0\";\n });\n\n hrefInput.addEventListener(\"keydown\", () => {\n linkTextInput.style.outlineColor = \" #dadce0\";\n });\n\n // Handle form submission\n form.addEventListener(\"submit\", (e) => {\n e.preventDefault();\n\n const newLinkText = linkTextInput.value;\n const newHref = hrefInput.value;\n\n if (!newHref || !newLinkText) {\n if (!newHref) hrefInput.style.outlineColor = \"red\";\n if (!newLinkText) linkTextInput.style.outlineColor = \"red\";\n return;\n }\n\n const sanitizeURL = find(newHref)\n .filter((link) => link.isLink)\n .filter((link) => {\n if (options.validate) {\n return options.validate(link.value);\n }\n return true;\n })\n .at(0);\n\n if (!sanitizeURL?.href) {\n hrefInput.style.outlineColor = \"red\";\n return;\n }\n\n options.editor.chain().focus().extendMarkRange(\"hyperlink\").editHyperlink({\n newURL: newHref,\n newText: newLinkText,\n });\n\n options.tippy.hide();\n });\n\n // Show tooltip\n options.tippy.update(options.editor.view, {\n arrow: roundArrow,\n });\n\n setTimeout(() => linkTextInput.focus());\n};\n","interface IconProps {\n size?: number;\n fill?: string;\n}\n\n// prettier-ignore\nexport const Copy = ({ size = 24, fill = 'rgb(104, 81, 255)' }: IconProps = {}) => {\n return `\n <svg fill=${fill} viewBox=\"0 0 24 24\" width=${size} xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"m13 20a5.006 5.006 0 0 0 5-5v-8.757a3.972 3.972 0 0 0 -1.172-2.829l-2.242-2.242a3.972 3.972 0 0 0 -2.829-1.172h-4.757a5.006 5.006 0 0 0 -5 5v10a5.006 5.006 0 0 0 5 5zm-9-5v-10a3 3 0 0 1 3-3s4.919.014 5 .024v1.976a2 2 0 0 0 2 2h1.976c.01.081.024 9 .024 9a3 3 0 0 1 -3 3h-6a3 3 0 0 1 -3-3zm18-7v11a5.006 5.006 0 0 1 -5 5h-9a1 1 0 0 1 0-2h9a3 3 0 0 0 3-3v-11a1 1 0 0 1 2 0z\"/>\n </svg>\n `\n}\n\nexport const LinkSlash = ({\n size = 24,\n fill = \"rgb(104, 81, 255)\",\n}: IconProps = {}) => {\n return `\n <svg fill=${fill} viewBox=\"0 0 24 24\" width=${size} xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.953,17.993c-1.557-.074-3.021-.722-4.121-1.823-.23-.23-.446-.482-.641-.748-.325-.446-.227-1.072,.22-1.397,.446-.325,1.071-.227,1.397,.219,.129,.178,.274,.349,.437,.511,.749,.75,1.744,1.19,2.802,1.24,.552,.026,.979,.495,.952,1.046-.025,.536-.468,.953-.998,.953h-.048ZM1.831,13.331C.65,14.511,0,16.081,0,17.75c0,1.669,.65,3.239,1.831,4.419,1.18,1.181,2.749,1.831,4.419,1.831s3.239-.65,4.419-1.831l1.058-1.058c.391-.391,.391-1.023,0-1.414s-1.023-.391-1.414,0l-1.058,1.058c-.803,.803-1.87,1.245-3.005,1.245s-2.202-.442-3.005-1.245-1.245-1.87-1.245-3.005,.442-2.203,1.245-3.005l3.037-3.038c.391-.391,.391-1.024,0-1.414-.391-.391-1.023-.391-1.414,0l-3.037,3.038ZM.293,1.707L22.293,23.707c.195,.195,.451,.293,.707,.293s.512-.098,.707-.293c.391-.391,.391-1.023,0-1.414l-6.581-6.581,5.043-5.043c1.181-1.18,1.831-2.75,1.831-4.419,0-1.669-.65-3.239-1.831-4.419C20.989,.65,19.42,0,17.75,0s-3.239,.65-4.419,1.831l-1.058,1.058c-.391,.391-.391,1.023,0,1.414s1.023,.391,1.414,0l1.058-1.058c.803-.803,1.87-1.245,3.005-1.245s2.202,.442,3.005,1.245,1.245,1.87,1.245,3.005-.442,2.203-1.245,3.005l-5.043,5.043-5.852-5.852c1.612-.808,3.575-.52,4.894,.798,.162,.162,.308,.333,.437,.511,.196,.269,.501,.411,.81,.411,.204,0,.41-.063,.588-.192,.446-.325,.545-.951,.22-1.397-.194-.266-.41-.518-.641-.748-2.095-2.095-5.297-2.408-7.76-.835L1.707,.293c-.391-.391-1.023-.391-1.414,0s-.391,1.023,0,1.414Z\"/>\n </svg>\n `;\n};\n\nexport const Pencil = ({\n size = 24,\n fill = \"rgb(104, 81, 255)\",\n}: IconProps = {}) => {\n return `\n <svg fill=${fill} viewBox=\"0 0 24 24\" width=${size} xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M22.853,1.148a3.626,3.626,0,0,0-5.124,0L1.465,17.412A4.968,4.968,0,0,0,0,20.947V23a1,1,0,0,0,1,1H3.053a4.966,4.966,0,0,0,3.535-1.464L22.853,6.271A3.626,3.626,0,0,0,22.853,1.148ZM5.174,21.122A3.022,3.022,0,0,1,3.053,22H2V20.947a2.98,2.98,0,0,1,.879-2.121L15.222,6.483l2.3,2.3ZM21.438,4.857,18.932,7.364l-2.3-2.295,2.507-2.507a1.623,1.623,0,1,1,2.295,2.3Z\"/>\n </svg>\n `;\n};\n\nexport const AngleUp = ({\n size = 32,\n fill = \"rgb(104, 81, 255)\",\n}: IconProps = {}) => {\n return `\n <svg fill=${fill} viewBox=\"0 0 24 24\" width=${size} xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M17.293,15.207,12,9.914,6.707,15.207,5.293,13.793,10.586,8.5a2,2,0,0,1,2.828,0l5.293,5.293Z\"/>\n </svg>\n `;\n};\n","import { Editor } from \"@tiptap/core\";\nimport { editHyperlinkHandler } from \"./editeHyperlink\";\nimport { Copy, LinkSlash, Pencil } from \"./icons\";\nimport Tooltip from \"../helpers/tippyHelper\";\n\nexport type THyperlinkPreviewModalOptions = {\n editor: Editor;\n validate?: (url: string) => boolean;\n link: HTMLAnchorElement;\n node?: any;\n nodePos: number;\n tippy: Tooltip;\n};\n\nexport function previewHyperlinkModal(options: THyperlinkPreviewModalOptions): HTMLElement {\n const href = options.link.href;\n\n const hyperlinkModal = document.createElement(\"div\");\n const removeButton = document.createElement(\"button\");\n const copyButton = document.createElement(\"button\");\n const editButton = document.createElement(\"button\");\n\n const newBubble = document.createElement(\"div\");\n newBubble.classList.add(\"hyperlink-preview-modal__metadata\");\n\n const hrefTitle = document.createElement(\"a\");\n hrefTitle.setAttribute(\"target\", \"_blank\");\n hrefTitle.setAttribute(\"rel\", \"noreferrer\");\n hrefTitle.setAttribute(\"href\", href);\n hrefTitle.innerText = href;\n\n newBubble.append(hrefTitle);\n\n fetch(\"/api/metadata\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ url: href }),\n })\n .then((response) => response.json())\n .then((data) => {\n // Create a new bubble with the title\n hrefTitle.setAttribute(\"href\", href);\n\n hrefTitle.innerText = data.title || data[\"og:title\"] || href;\n newBubble.replaceChildren(hrefTitle);\n\n // Create an image element if image exists in metadata\n if (data.icon || data.image || data[\"og:image\"]) {\n const img = document.createElement(\"img\");\n img.src = data.icon || data.image || data[\"og:image\"];\n img.alt = data.title || data[\"og:title\"] || \"hyperlink image\";\n newBubble.appendChild(img);\n }\n })\n .catch((error) => {\n console.error(\"Error fetching metadata:\", error);\n });\n\n hyperlinkModal.classList.add(\"hyperlink-preview-modal\");\n\n removeButton.classList.add(\"hyperlink-preview-modal__remove-button\");\n removeButton.innerHTML = LinkSlash();\n\n editButton.classList.add(\"hyperlink-preview-modal__edit-button\");\n editButton.innerHTML = Pencil();\n\n copyButton.classList.add(\"hyperlink-preview-modal__copy-button\");\n copyButton.innerHTML = Copy();\n\n removeButton.addEventListener(\"click\", () => {\n options.tippy.hide();\n return options.editor.chain().focus().unsetHyperlink().run();\n });\n\n editButton.addEventListener(\"click\", () => editHyperlinkHandler({ ...options, hyperlinkModal }));\n\n copyButton.addEventListener(\"click\", () => {\n options.tippy.hide();\n navigator.clipboard.writeText(href);\n });\n\n hyperlinkModal.append(newBubble, copyButton, editButton, removeButton);\n\n return hyperlinkModal;\n}\n","import { Editor } from \"@tiptap/core\";\nimport Tooltip, { TippyInitOptions } from \"../helpers/tippyHelper\";\nimport { find } from \"linkifyjs\";\n\nexport type TSetHyperlinkModalOptions = {\n editor: Editor;\n validate?: (url: string) => boolean;\n extentionName: string;\n attributes?: { href: string; target?: string | null };\n Tooltip: new (options: TippyInitOptions) => Tooltip;\n roundArrow: string;\n};\n\nlet tooltip: Tooltip | undefined = undefined;\n\nexport function setHyperlinkModal(options: TSetHyperlinkModalOptions): void {\n // Create the tooltip instance\n if (!tooltip) tooltip = new options.Tooltip(options);\n\n // Initialize the tooltip\n let { tippyModal } = tooltip.init();\n\n const hyperlinkModal = document.createElement(\"div\");\n const buttonsWrapper = document.createElement(\"div\");\n const inputsWrapper = document.createElement(\"div\");\n\n hyperlinkModal.classList.add(\"hyperlink-set-modal\");\n\n buttonsWrapper.classList.add(\"hyperlink-set-modal__buttons-wrapper\");\n inputsWrapper.classList.add(\"hyperlink-set-modal__inputs-wrapper\");\n\n // create a form that contain url input and a button for submit\n const form = document.createElement(\"form\");\n const input = document.createElement(\"input\");\n const button = document.createElement(\"button\");\n\n input.setAttribute(\"type\", \"text\");\n input.setAttribute(\"placeholder\", \"https://example.com\");\n button.setAttribute(\"type\", \"submit\");\n button.innerText = \"Submit\";\n\n inputsWrapper.append(input);\n buttonsWrapper.append(button);\n form.append(inputsWrapper, buttonsWrapper);\n\n hyperlinkModal.append(form);\n\n tippyModal.innerHTML = \"\";\n tippyModal.append(hyperlinkModal);\n tooltip.update(options.editor.view, {\n arrow: options.roundArrow,\n });\n\n // make sure\n setTimeout(() => {\n input.focus();\n input.style.outlineColor = \" #dadce0\";\n }, 100);\n\n input.addEventListener(\"keydown\", () => {\n input.style.outlineColor = \" #dadce0\";\n });\n\n // event listenr for submit button\n form.addEventListener(\"submit\", (event) => {\n event.preventDefault();\n const url = input.value;\n\n if (!url) {\n input.style.outlineColor = \"red\";\n return;\n }\n\n const sanitizeURL = find(url)\n .filter((link) => link.isLink)\n .filter((link) => {\n if (options.validate) {\n return options.validate(link.value);\n }\n return true;\n })\n .at(0);\n\n if (!sanitizeURL?.href) {\n input.style.outlineColor = \"red\";\n return;\n }\n\n tooltip?.hide();\n\n return options.editor\n .chain()\n .setMark(options.extentionName, { href: sanitizeURL.href })\n .setMeta(\"preventautohyperlink\", true)\n .run();\n });\n}\n"],"names":["Plugin","PluginKey","combineTransactionSteps","getChangedRanges","getMarksBetween","test","findChildrenInRange","find","posToDOMRect","getAttributes","Mark","registerCustomProtocol","reset","mergeAttributes","roundArrow","editHyperlinkHelper","markPasteRule"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/index.ts","../src/hyperlink.ts","../src/constants.ts","../src/commands/engine.ts","../../../packages/floating-tooltip/src/tooltip.ts","../../../packages/floating-popover/src/controller.ts","../../../packages/floating-popover/src/createPopover.ts","../src/utils/logger.ts","../src/utils/copyToClipboard.ts","../src/utils/createHTMLElement.ts","../src/utils/icons.ts","../src/utils/normalizeHref.ts","../src/utils/phone.ts","../src/utils/specialUrls.ts","../src/utils/validateURL.ts","../src/popovers/createHyperlinkPopover.ts","../src/openers/getHyperlinkOptions.ts","../src/openers/popoverOwnership.ts","../src/openers/openCreateHyperlink.ts","../src/commands/editHyperlinkCommand.ts","../src/utils/findLinks.ts","../src/url-decisions/index.ts","../src/commands/families.ts","../src/commands/index.ts","../src/interactions/autolink.ts","../src/interactions/clickHandler.ts","../src/openers/liveAnchor.ts","../src/openers/buildPreviewOptionsFromAnchor.ts","../src/popovers/editHyperlinkPopover.ts","../src/openers/openEditHyperlink.ts","../src/popovers/previewHyperlinkPopover.ts","../src/openers/openPreviewHyperlink.ts","../src/interactions/inputRule.ts","../src/interactions/pasteHandler.ts","../src/interactions/pasteRule.ts","../src/interactions/createLinkContext.ts","../src/interactions/index.ts"],"sourcesContent":["import { Hyperlink } from './hyperlink'\n\n// Layer 1 — three named openers (the 90% case).\nexport {\n buildPreviewOptionsFromAnchor,\n type BuildPreviewOptionsFromAnchorArgs,\n openCreateHyperlink,\n openEditHyperlink,\n openPreviewHyperlink\n} from './openers'\n\n// Layer 2 — generic controller for lifecycle observation (the 10% case).\nexport {\n type AdoptMetadata,\n type ControllerState,\n getDefaultController,\n type PopoverController,\n type PopoverKind,\n type VirtualCoordinates\n} from './floating-popover'\n\n// Primitive — fully custom popover that still participates in the\n// singleton lifecycle (the <1% case).\nexport {\n createPopover,\n DEFAULT_OFFSET,\n type Popover,\n type PopoverOptions\n} from './floating-popover'\n\n// Tooltip primitive — the same hover/focus bubble the prebuilt popovers\n// put on their icon buttons, re-exported for BYO popover parity.\n// The bubble is per-bundle: pair attach and hide from the same package.\nexport { attachTooltip, hideTooltip } from '@docs.plus/floating-tooltip'\n\n// Extension + factories + option types\nexport * from './hyperlink'\nexport { createHyperlinkPopover, editHyperlinkPopover, previewHyperlinkPopover } from './popovers'\n\n// Utilities (validateURL, isSafeHref, …) re-exported for BYO popovers.\nexport * from './utils'\n\n// Linkify protocol registration — kept for parity with v1.\nexport { registerCustomProtocol } from 'linkifyjs'\n\nexport default Hyperlink\n","import {\n Editor,\n type JSONContent,\n Mark,\n type MarkdownParseHelpers,\n type MarkdownRendererHelpers,\n type MarkdownToken,\n mergeAttributes,\n type RenderContext\n} from '@tiptap/core'\nimport { MarkType } from '@tiptap/pm/model'\nimport { registerCustomProtocol } from 'linkifyjs'\n\nimport { buildHyperlinkCommands } from './commands'\nimport { HYPERLINK_MARK_NAME } from './constants'\nimport { createInteractions, createLinkContext, type LinkContext } from './interactions'\nimport { closeOwnedPopover } from './openers/popoverOwnership'\nimport { isSafeHref } from './url-decisions'\nimport { DEFAULT_PROTOCOL, normalizeHref } from './utils/normalizeHref'\n\n// Re-export keeps the v2.0.0 import paths for downstream consumers.\nexport type {\n EditHyperlinkAttributes,\n HyperlinkPublicCommands,\n SetHyperlinkAttributes\n} from './commands'\n\nexport interface LinkProtocolOptions {\n scheme: string\n optionalSlashes?: boolean\n}\n\n/** Context for the user `isAllowedUri` hook; mirrors `@tiptap/extension-link`. */\nexport type IsAllowedUriContext = {\n /** Built-in safety gate (`isSafeHref`). */\n defaultValidate: (uri: string) => boolean\n /** Protocols registered via the `protocols` option. */\n protocols: Array<LinkProtocolOptions | string>\n defaultProtocol: string\n}\n\n/**\n * `Extra` extends the built-ins with consumer-typed fields; it defaults to\n * `Record<string, unknown>` to keep the v2 open index signature. Example: README → TypeScript.\n */\nexport type HyperlinkAttributes<Extra extends Record<string, unknown> = Record<string, unknown>> = {\n href: string | null\n target: string | null\n rel: string | null\n class: string | null\n title: string | null\n image: string | null\n} & Extra\n\nexport type PreviewHyperlinkOptions = {\n editor: Editor\n link: HTMLAnchorElement\n nodePos: number\n attrs: HyperlinkAttributes\n validate?: (url: string) => boolean\n /** Composed XSS + `isAllowedUri` gate; BYO popovers must call this before any `window.open`. */\n isAllowedUri?: (uri: string) => boolean\n}\n\nexport type CreateHyperlinkOptions = {\n editor: Editor\n extensionName: string\n attributes: Partial<HyperlinkAttributes>\n validate?: (url: string) => boolean\n}\n\nexport type EditHyperlinkOptions = {\n editor: Editor\n link: HTMLAnchorElement\n /** Optional mark position; lets edit/back recover from ProseMirror replacing duplicate link DOM. */\n nodePos?: number\n validate?: (url: string) => boolean\n /** Composed XSS + `isAllowedUri` gate to preserve preview policy across edit/back. */\n isAllowedUri?: (uri: string) => boolean\n /** Override the default Back behaviour. Default re-opens the preview popover via `openPreviewHyperlink`. */\n onBack?: () => void\n /** Mark name; defaults to `HYPERLINK_MARK_NAME`. */\n markName?: string\n}\n\nexport interface HyperlinkOptions {\n autolink: boolean\n protocols: Array<LinkProtocolOptions | string>\n openOnClick: boolean\n linkOnPaste: boolean\n HTMLAttributes: Partial<HyperlinkAttributes>\n popovers: {\n previewHyperlink?: ((options: PreviewHyperlinkOptions) => HTMLElement | null) | null\n editHyperlink?: ((options: EditHyperlinkOptions) => HTMLElement | null) | null\n createHyperlink?: ((options: CreateHyperlinkOptions) => HTMLElement | null) | null\n }\n validate?: (url: string) => boolean\n /** Scheme used by `normalizeHref` to promote bare domains. Default `'https'`. See README → Options. */\n defaultProtocol: string\n /** URI policy hook — runs AFTER `isSafeHref`, BEFORE the mark is written. Mirrors `@tiptap/extension-link`. */\n isAllowedUri?: (uri: string, ctx: IsAllowedUriContext) => boolean\n /** Per-link autolink veto. Return `false` to skip autolinking a specific URI (manual `setHyperlink` still works). */\n shouldAutoLink?: (uri: string) => boolean\n /** Click inside a link selects the whole mark range (editable mode only). Mirrors `@tiptap/extension-link`. */\n enableClickSelection: boolean\n /** ArrowRight at the right edge of a link exits the mark. Mirrors `@tiptap/extension-link`. */\n exitable: boolean\n}\n\n/** Extension storage; one slot per editor instance. */\nexport interface HyperlinkStorage {\n /**\n * Cached `LinkContext`; populated on first access so all four `add*`\n * hooks share one URL Decisions pipeline instead of allocating per hook.\n */\n context: LinkContext | null\n}\n\n// linkifyjs has one process-global scheme registry that warns once it auto-inits\n// (first find/test). Coexisting editors share it, so register each scheme once —\n// a second editor re-registering post-init is what logs the warning. No reset().\nconst registeredLinkifyProtocols = new Set<string>()\n\nfunction registerProtocolOnce(scheme: string, optionalSlashes?: boolean): void {\n if (registeredLinkifyProtocols.has(scheme)) return\n registeredLinkifyProtocols.add(scheme)\n registerCustomProtocol(scheme, optionalSlashes)\n}\n\nexport const Hyperlink = Mark.create<HyperlinkOptions, HyperlinkStorage>({\n name: HYPERLINK_MARK_NAME,\n\n priority: 1000,\n\n keepOnSplit: false,\n\n // Markdown import/export lives with the mark itself (inert unless the host\n // also loads a Markdown extension). Parsing applies the locked `hyperlink` mark name.\n markdownTokenName: 'link',\n\n parseMarkdown: (token: MarkdownToken, helpers: MarkdownParseHelpers) => {\n // Markdown import is a write boundary like any other: normalize for\n // canonical parity, then blank unsafe schemes (mirrors parseHTML).\n const href = normalizeHref(token.href || '')\n return helpers.applyMark(HYPERLINK_MARK_NAME, helpers.parseInline(token.tokens ?? []), {\n href: isSafeHref(href) ? href : ''\n })\n },\n\n renderMarkdown: (node: JSONContent, helpers: MarkdownRendererHelpers, _ctx: RenderContext) => {\n // Serialize is a write boundary too: blank an unsafe href (mirrors renderHTML)\n // and percent-encode what marked.js cannot tokenise. The marked.js href grammar\n // stops at whitespace and the first `)`. The label is untouchable from here:\n // the serializer keeps only the slices around `renderChildren()`.\n const content = helpers.renderChildren(node)\n const raw = node.attrs?.href || ''\n const href = (isSafeHref(raw) ? raw : '').replace(/\\)/g, '%29').replace(/\\s/g, '%20')\n return `[${content}](${href})`\n },\n\n addStorage() {\n return { context: null }\n },\n\n onCreate() {\n this.options.protocols.forEach((protocol) => {\n if (typeof protocol === 'string') {\n registerProtocolOnce(protocol)\n } else {\n registerProtocolOnce(protocol.scheme, protocol.optionalSlashes)\n }\n })\n },\n\n // No linkifyjs.reset() here — it clears the global registry and breaks\n // coexisting editors. Close only this editor's open popover so its\n // body-appended host + document listeners + floating-ui observers don't\n // outlive the editor.\n onDestroy() {\n closeOwnedPopover(this.editor)\n },\n\n inclusive() {\n return this.options.autolink\n },\n\n addOptions() {\n return {\n openOnClick: true,\n linkOnPaste: true,\n autolink: true,\n protocols: [],\n HTMLAttributes: {\n target: null,\n rel: 'noopener noreferrer nofollow',\n class: null\n },\n popovers: {\n previewHyperlink: null,\n editHyperlink: null,\n createHyperlink: null\n },\n validate: undefined,\n defaultProtocol: DEFAULT_PROTOCOL,\n isAllowedUri: undefined,\n shouldAutoLink: undefined,\n enableClickSelection: false,\n exitable: false\n }\n },\n\n addAttributes() {\n return {\n href: {\n default: null\n },\n // `target` stays on the mark (Yjs back-compat) but `rendered: false`.\n // Emitting `<a target=\"_blank\">` would let the browser bypass the click-handler\n // guard and revive the historical `target=\"_blank\"` phishing surface.\n // Pinned by AGENTS.md.\n target: {\n default: this.options.HTMLAttributes.target,\n rendered: false\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 // `image` is preview-popover metadata (favicon / OG); `<a>` has no such attr, so don't emit.\n image: {\n default: null,\n rendered: false\n }\n }\n },\n\n parseHTML() {\n // `isSafeHref` is the single XSS gate at every boundary (parseHTML,\n // input/paste rules, command, click, preview). Returning `false`\n // here tells ProseMirror to skip the mark.\n return [\n {\n tag: 'a[href]',\n getAttrs: (node: HTMLElement | string) => {\n if (typeof node === 'string') return false\n const href = node.getAttribute('href') ?? ''\n return isSafeHref(href) ? null : false\n }\n }\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n // Defense-in-depth on READ — a hostile mark could reach here via\n // Yjs replay, foreign `addMark`, or schema migration. Blank the\n // href so a bad mark never round-trips into a clickable\n // `javascript:` anchor downstream. (Matches @tiptap/extension-link v3.)\n const safe = isSafeHref(HTMLAttributes.href as string | null | undefined)\n ? HTMLAttributes\n : { ...HTMLAttributes, href: '' }\n return ['a', mergeAttributes(this.options.HTMLAttributes, safe), 0]\n },\n\n addCommands() {\n return buildHyperlinkCommands({\n markName: this.name,\n options: this.options,\n urls: getContext(this).urls\n })\n },\n\n addKeyboardShortcuts() {\n // Mod-k routes to `openCreateHyperlinkPopover` (was overloaded `setHyperlink()`).\n const shortcuts: Record<string, () => boolean> = {\n 'Mod-k': () => this.editor.commands.openCreateHyperlinkPopover()\n }\n\n if (this.options.exitable) {\n shortcuts.ArrowRight = () => exitMarkOnArrowRight(this.editor, this.type)\n }\n\n return shortcuts\n },\n\n addInputRules() {\n return createInteractions(getContext(this)).inputRules\n },\n\n addPasteRules() {\n return createInteractions(getContext(this)).pasteRules\n },\n\n addProseMirrorPlugins() {\n return createInteractions(getContext(this)).plugins\n }\n})\n\n// One `LinkContext` per editor, cached on `storage.context` and shared across\n// the four `add*` hooks. The URL Decisions pipeline (and its validate /\n// autolink / shouldAutoLink closures) are allocated once.\nfunction getContext(self: {\n editor: Editor\n type: MarkType\n options: HyperlinkOptions\n storage: HyperlinkStorage\n}): LinkContext {\n if (self.storage.context) return self.storage.context\n const ctx = createLinkContext({ editor: self.editor, type: self.type, options: self.options })\n self.storage.context = ctx\n return ctx\n}\n\n// `exitable` ArrowRight handler — clears the link mark from `storedMarks` so the next\n// typed char lands outside the link. Returns `false` so ProseMirror still moves the caret.\nfunction exitMarkOnArrowRight(editor: Editor, type: MarkType): boolean {\n const { state } = editor\n const { selection, tr } = state\n if (!selection.empty) return false\n const $pos = selection.$from\n const after = $pos.nodeAfter\n const before = $pos.nodeBefore\n const inMark = before?.marks.some((m) => m.type === type) ?? false\n const exiting = inMark && (!after || !after.marks.some((m) => m.type === type))\n if (!exiting) return false\n tr.setStoredMarks((state.storedMarks ?? $pos.marks()).filter((m) => m.type !== type))\n editor.view.dispatch(tr)\n return false\n}\n","// Package-level constants. `SAFE_WINDOW_FEATURES` is re-exported from\n// `utils/index.ts`; the rest stay module-internal.\n\n/** Hyperlink mark name. Load-bearing: stored in every Yjs doc; renaming is breaking. */\nexport const HYPERLINK_MARK_NAME = 'hyperlink' as const\n\n/** Tx meta stamped by every hyperlink write so `autolinkPlugin` skips the same tick. */\nexport const PREVENT_AUTOLINK_META = 'preventAutolink' as const\n\n/** Bail-out rect returned by an opener's coords callback while `popover.hide()` is queued. */\nexport const OFFSCREEN_COORD_PX = -9999\n\n/**\n * `window.open` features string for safe navigation — every\n * `window.open(href, '_blank', …)` call needs this explicit arg or the\n * opened tab can read `window.opener` and the Referer leaks. Re-exported\n * so downstream popovers pin the same value.\n */\nexport const SAFE_WINDOW_FEATURES = 'noopener,noreferrer' as const\n","// Returns composable Tiptap `Command` thunks acting on the shared `tr`, so\n// callers can chain `extendMarkRange` etc. without a nested\n// `editor.chain().run()`. The nested form produced \"Applying a mismatched transaction\".\n\nimport type { Command, CommandProps } from '@tiptap/core'\n\nimport { PREVENT_AUTOLINK_META } from '../constants'\nimport type { URLDecisions } from '../url-decisions'\nimport type { SetHyperlinkAttributes } from './surface'\n\nexport interface HyperlinkEngineDeps {\n markName: string\n urls: URLDecisions\n}\n\nexport interface HyperlinkEngine {\n /** Write the mark at the current selection. Honors the URL Decisions gate. */\n set(attributes: SetHyperlinkAttributes): Command\n /** Remove the mark at the current selection (extends empty mark range). */\n unset(): Command\n /** Unset when active, set otherwise. Same gate stack as `set`. */\n toggle(attributes: SetHyperlinkAttributes): Command\n}\n\n/** Build an engine over `(markName, urls)`; thunks re-read `tr`/`state` so no stale snapshot escapes. */\nexport function createHyperlinkEngine({ markName, urls }: HyperlinkEngineDeps): HyperlinkEngine {\n const apply = (\n attrs: SetHyperlinkAttributes,\n { commands, tr, dispatch }: CommandProps\n ): boolean => {\n if (!attrs.href) return false\n const [decision] = urls.forWrite({ kind: 'href', href: attrs.href })\n if (!decision) return false\n const ok = commands.setMark(markName, { ...attrs, href: decision.href })\n if (ok && dispatch) tr.setMeta(PREVENT_AUTOLINK_META, true)\n return ok\n }\n\n const remove = ({ commands, tr, dispatch }: CommandProps): boolean => {\n const ok = commands.unsetMark(markName, { extendEmptyMarkRange: true })\n if (ok && dispatch) tr.setMeta(PREVENT_AUTOLINK_META, true)\n return ok\n }\n\n return {\n set: (attrs) => (props) => apply(attrs, props),\n unset: () => (props) => remove(props),\n toggle: (attrs) => (props) => {\n if (props.editor.isActive(markName)) return remove(props)\n return apply(attrs, props)\n }\n }\n}\n","import { computePosition, flip, offset, shift } from '@floating-ui/dom'\n\n/*\n * Built on raw `@floating-ui/dom`, deliberately not `createPopover`: the engine\n * self-adopts into the one-popover-at-a-time controller, so showing a tooltip\n * would dismiss an open menu or dialog. One shared bubble serves every button.\n */\n\nconst SHOW_DELAY_MS = 400\nconst VISIBLE_CLASS = 'visible'\n\nlet bubble: HTMLDivElement | null = null\nlet showTimer: ReturnType<typeof setTimeout> | null = null\n\nfunction ensureBubble(): HTMLDivElement {\n if (!bubble) {\n bubble = document.createElement('div')\n bubble.className = 'floating-tooltip'\n bubble.setAttribute('role', 'tooltip')\n document.body.append(bubble)\n }\n return bubble\n}\n\nfunction cancelShow(): void {\n if (showTimer !== null) {\n clearTimeout(showTimer)\n showTimer = null\n }\n}\n\n// No autoUpdate: tooltips are ephemeral, every hide/re-show re-positions.\nasync function show(target: HTMLElement, label: string): Promise<void> {\n if (!target.isConnected) return\n const el = ensureBubble()\n el.textContent = label\n const { x, y } = await computePosition(target, el, {\n strategy: 'fixed',\n placement: 'top',\n middleware: [offset(6), flip(), shift({ padding: 8 })]\n })\n el.style.left = `${x}px`\n el.style.top = `${y}px`\n el.classList.add(VISIBLE_CLASS)\n}\n\n/** Hide the shared tooltip bubble and cancel any pending show. */\nexport function hideTooltip(): void {\n cancelShow()\n bubble?.classList.remove(VISIBLE_CLASS)\n}\n\n/** Show `label` above `target` after a short hover/focus delay. Returns a detach function for surfaces that re-render in place. */\nexport function attachTooltip(target: HTMLElement, label: string): () => void {\n const schedule = (): void => {\n cancelShow()\n showTimer = setTimeout(() => {\n showTimer = null\n void show(target, label)\n }, SHOW_DELAY_MS)\n }\n // Keyboard focus only: click-focus would re-show over the popover the click opened.\n const scheduleOnFocus = (): void => {\n if (target.matches(':focus-visible')) schedule()\n }\n target.addEventListener('mouseenter', schedule)\n target.addEventListener('focus', scheduleOnFocus)\n target.addEventListener('mouseleave', hideTooltip)\n target.addEventListener('blur', hideTooltip)\n // Activation opens popovers; the tooltip must not linger over them.\n // `click` covers keyboard Enter/Space, which fire no pointerdown.\n target.addEventListener('pointerdown', hideTooltip)\n target.addEventListener('click', hideTooltip)\n return () => {\n target.removeEventListener('mouseenter', schedule)\n target.removeEventListener('focus', scheduleOnFocus)\n target.removeEventListener('mouseleave', hideTooltip)\n target.removeEventListener('blur', hideTooltip)\n target.removeEventListener('pointerdown', hideTooltip)\n target.removeEventListener('click', hideTooltip)\n hideTooltip()\n }\n}\n","// Extension-agnostic single-popover lifecycle owner. `adopt` takes\n// ownership of a built popover (destroying the previous owner), `close`\n// hides + idles, `reposition` re-anchors, `subscribe` observes\n// idle ↔ mounted transitions.\n\nexport type PopoverKind = 'preview' | 'edit' | 'create' | (string & {})\n\nexport type VirtualCoordinates = {\n getBoundingClientRect: () => { x: number; y: number; width: number; height: number }\n contextElement?: HTMLElement\n}\n\nexport interface ManagedPopover {\n hide: () => void\n destroy: () => void\n updateReference: (referenceElement?: HTMLElement, coordinates?: VirtualCoordinates) => void\n}\n\nexport type AdoptMetadata = {\n /** The popover's root element — what subscribers attach focus rings, scroll-freezes, or DOM observers to. */\n element: HTMLElement\n /** The anchor the popover is glued to — `null` for virtual-coords popovers (e.g. selection-anchored create). */\n referenceElement: HTMLElement | null\n}\n\nexport type ControllerState =\n { kind: 'idle' } | ({ kind: 'mounted'; popoverKind: PopoverKind } & AdoptMetadata)\n\nexport interface PopoverController {\n adopt(popover: ManagedPopover, kind: PopoverKind, metadata: AdoptMetadata): () => void\n close(): void\n reposition(referenceElement?: HTMLElement, coordinates?: VirtualCoordinates): void\n getState(): ControllerState\n subscribe(listener: (state: ControllerState) => void): () => void\n}\n\nexport function createPopoverController(): PopoverController {\n let current: { popover: ManagedPopover; kind: PopoverKind; metadata: AdoptMetadata } | null = null\n const listeners = new Set<(state: ControllerState) => void>()\n\n const snapshot = (): ControllerState =>\n current === null\n ? { kind: 'idle' }\n : {\n kind: 'mounted',\n popoverKind: current.kind,\n element: current.metadata.element,\n referenceElement: current.metadata.referenceElement\n }\n\n const notify = (): void => {\n const state = snapshot()\n listeners.forEach((listener) => listener(state))\n }\n\n return {\n adopt(popover, kind, metadata) {\n const previous = current\n current = { popover, kind, metadata }\n if (previous && previous.popover !== popover) previous.popover.destroy()\n notify()\n return () => {\n if (current?.popover === popover) {\n current = null\n notify()\n }\n }\n },\n close() {\n if (current === null) return\n const { popover } = current\n current = null\n popover.hide()\n notify()\n },\n reposition(referenceElement, coordinates) {\n current?.popover.updateReference(referenceElement, coordinates)\n },\n getState: snapshot,\n subscribe(listener) {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n }\n }\n}\n\nlet defaultController: PopoverController = createPopoverController()\n\nexport function getDefaultController(): PopoverController {\n return defaultController\n}\n\nexport function setDefaultController(controller: PopoverController): void {\n defaultController = controller\n}\n\nexport function resetDefaultController(): void {\n defaultController = createPopoverController()\n}\n","import {\n arrow,\n autoUpdate,\n computePosition,\n flip,\n hide as hideMiddleware,\n offset,\n type Placement,\n type ReferenceElement,\n shift,\n type VirtualElement\n} from '@floating-ui/dom'\n\nimport { getDefaultController, type VirtualCoordinates } from './controller'\n\ntype PopoverAnchor =\n | { referenceElement: HTMLElement; coordinates?: never }\n | { referenceElement?: never; coordinates: VirtualCoordinates }\n\ntype PopoverShellOptions = {\n content: HTMLElement\n placement?: Placement\n offset?: number\n showArrow?: boolean\n className?: string\n zIndex?: number\n /**\n * ARIA has no popover role — the shell carries its content's role\n * (`toolbar`, `dialog`, …) and stays role-less when omitted.\n */\n role?: string\n /** Same ARIA axis as `role` — shell-level so BYO content inherits the accessible name. */\n ariaLabel?: string\n /**\n * Nodes that must not light-dismiss (toggle triggers). When set, only these\n * are ignored — not `referenceElement` — so a larger position surface (e.g.\n * a toolbar bar) can still dismiss on sibling clicks. When omitted, the\n * HTMLElement `referenceElement` is ignored instead.\n */\n ignoreOutsideClickOn?: HTMLElement | HTMLElement[]\n /**\n * When false, `shift` only moves on the main axis so end-aligned menus\n * (e.g. toolbar overflow) stay pinned to the reference’s end edge.\n * @default true\n */\n crossAxisShift?: boolean\n onShow?: () => void\n onHide?: () => void\n}\n\nexport type PopoverOptions = PopoverAnchor & PopoverShellOptions\n\n/**\n * One-shot once opened: hiding releases the controller's ownership and nothing\n * re-adopts, so `show()` will not reopen it. Build a new popover instead — a\n * re-shown one would sit outside the single-popover invariant, invisible to\n * `close()` and never evicted by the next `adopt()`.\n */\nexport interface Popover {\n element: HTMLElement\n /** No-op once the popover has been hidden or destroyed. */\n show: () => void\n /** Terminal once shown. Before the first `show()` it no-ops and keeps ownership. */\n hide: () => void\n destroy: () => void\n isVisible: () => boolean\n setContent: (content: HTMLElement) => void\n updateReference: (referenceElement?: HTMLElement, coordinates?: VirtualCoordinates) => void\n}\n\nexport const DEFAULT_OFFSET = 8\nconst DEFAULT_Z_INDEX = 9999\nconst SHIFT_PADDING = 8\nconst ARROW_STATIC_OFFSET = '-5px'\nconst OUTSIDE_CLICK_DEFER_MS = 50\n// Covers the skins' 80ms exit; transitionend never fires under display:none or\n// prefers-reduced-motion `transition: none`, so removal cannot rely on it alone.\nconst EXIT_FALLBACK_MS = 150\n\nconst ORIGIN_BY_SIDE: Record<string, string> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left'\n}\n\nfunction createVirtualReference(coords: VirtualCoordinates): VirtualElement {\n return {\n getBoundingClientRect: () => {\n const { x, y, width, height } = coords.getBoundingClientRect()\n return { width, height, top: y, right: x + width, bottom: y + height, left: x, x, y }\n },\n contextElement: coords.contextElement || document.body\n }\n}\n\n// Wraps focusables in a Tab cycle. Returns removers so each `setContent`\n// can drop the prior batch before re-binding — without it the per-focusable\n// `keydown` listeners leaked across content swaps and on destroy.\nfunction setupKeyboardNav(container: HTMLElement): Array<() => void> {\n const focusable = container.querySelectorAll<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n )\n if (!focusable.length) return []\n const removers: Array<() => void> = []\n focusable.forEach((el, i) => {\n const onKeydown = (e: KeyboardEvent) => {\n if (e.key !== 'Tab') return\n e.preventDefault()\n const next = e.shiftKey\n ? (i - 1 + focusable.length) % focusable.length\n : (i + 1) % focusable.length\n focusable[next].focus()\n }\n el.addEventListener('keydown', onKeydown)\n removers.push(() => el.removeEventListener('keydown', onKeydown))\n })\n return removers\n}\n\nexport function createPopover(options: PopoverOptions): Popover {\n const controller = getDefaultController()\n\n const {\n referenceElement,\n coordinates,\n content,\n placement = 'bottom-start',\n offset: offsetVal = DEFAULT_OFFSET,\n showArrow = false,\n className = '',\n zIndex = DEFAULT_Z_INDEX,\n role,\n ariaLabel,\n ignoreOutsideClickOn,\n crossAxisShift = true,\n onShow,\n onHide\n } = options\n\n // Defence-in-depth for `any`-typed and JS-only callers; the discriminated\n // union in `PopoverOptions` already makes this case a compile error.\n if (!referenceElement && !coordinates) {\n throw new Error('Either referenceElement or coordinates must be provided')\n }\n\n let reference: ReferenceElement = referenceElement || createVirtualReference(coordinates!)\n // Prefer an explicit ignore list (position ref ≠ toggle trigger). Otherwise\n // the HTMLElement reference is the toggle target and must not light-dismiss.\n const outsideIgnore: HTMLElement[] = ignoreOutsideClickOn\n ? Array.isArray(ignoreOutsideClickOn)\n ? [...ignoreOutsideClickOn]\n : [ignoreOutsideClickOn]\n : referenceElement\n ? [referenceElement]\n : []\n const cleanups: (() => void)[] = []\n let visible = false\n let terminated = false\n let autoUpdateCleanup: (() => void) | null = null\n\n const isOutsideDismissTarget = (target: Node | null): boolean => {\n if (!target) return true\n if (root.contains(target)) return false\n return !outsideIgnore.some((el) => el === target || el.contains(target))\n }\n\n const root = document.createElement('div')\n root.className = `floating-popover ${className}`.trim()\n if (role) root.setAttribute('role', role)\n if (ariaLabel) root.setAttribute('aria-label', ariaLabel)\n root.setAttribute('tabindex', '-1')\n root.style.zIndex = String(zIndex)\n root.style.position = 'fixed'\n\n let arrowEl: HTMLElement | null = null\n if (showArrow) {\n arrowEl = document.createElement('div')\n arrowEl.className = 'floating-popover-arrow'\n root.appendChild(arrowEl)\n }\n\n const contentContainer = document.createElement('div')\n contentContainer.className = 'floating-popover-content'\n root.appendChild(contentContainer)\n\n const navListeners: Array<() => void> = []\n const clearNavListeners = (): void => {\n while (navListeners.length) navListeners.pop()!()\n }\n\n const setContent = (el: HTMLElement): void => {\n clearNavListeners()\n contentContainer.innerHTML = ''\n contentContainer.appendChild(el)\n navListeners.push(...setupKeyboardNav(root))\n }\n\n setContent(content)\n\n const updatePosition = async (): Promise<void> => {\n if (!visible) return\n const middleware = [\n offset(offsetVal),\n flip(),\n shift({ padding: SHIFT_PADDING, crossAxis: crossAxisShift })\n ]\n if (arrowEl) middleware.push(arrow({ element: arrowEl }))\n middleware.push(hideMiddleware({ strategy: 'referenceHidden' }))\n\n const {\n x,\n y,\n placement: actual,\n middlewareData\n } = await computePosition(reference, root, {\n placement,\n strategy: 'fixed',\n middleware\n })\n if (!visible) return\n Object.assign(root.style, { left: `${x}px`, top: `${y}px` })\n root.style.visibility = middlewareData.hide?.referenceHidden ? 'hidden' : 'visible'\n\n const side = actual.split('-')[0]\n // Scale blooms from the anchored side instead of center.\n root.style.transformOrigin = ORIGIN_BY_SIDE[side] ?? 'center'\n\n if (arrowEl && middlewareData.arrow) {\n const { x: ax, y: ay } = middlewareData.arrow\n // Arrow pins to the side opposite the placement — the same mapping.\n const staticSide = ORIGIN_BY_SIDE[side]!\n arrowEl.className = `floating-popover-arrow floating-popover-arrow-${side}`\n Object.assign(arrowEl.style, {\n left: ax != null ? `${ax}px` : '',\n top: ay != null ? `${ay}px` : '',\n right: '',\n bottom: '',\n [staticSide]: ARROW_STATIC_OFFSET\n })\n }\n }\n\n let unregister: (() => void) | null = null\n let removalTimer: ReturnType<typeof setTimeout> | null = null\n let onExitEnd: ((e: TransitionEvent) => void) | null = null\n\n const cancelPendingRemoval = (): void => {\n if (removalTimer) {\n clearTimeout(removalTimer)\n removalTimer = null\n }\n if (onExitEnd) {\n root.removeEventListener('transitionend', onExitEnd)\n onExitEnd = null\n }\n }\n\n const finishHide = (): void => {\n cancelPendingRemoval()\n root.remove()\n }\n\n const hide = (): void => {\n if (!visible) return\n visible = false\n terminated = true\n autoUpdateCleanup?.()\n autoUpdateCleanup = null\n clearNavListeners()\n cleanups.forEach((fn) => fn())\n cleanups.length = 0\n unregister?.()\n unregister = null\n // Removing .visible plays the skin's exit transition; the DOM node leaves on\n // transitionend, with the fallback timer as the guarantee.\n root.classList.remove('visible')\n onExitEnd = (e) => {\n if (e.target === root) finishHide()\n }\n root.addEventListener('transitionend', onExitEnd)\n removalTimer = setTimeout(finishHide, EXIT_FALLBACK_MS)\n onHide?.()\n }\n\n const show = (): void => {\n // A removal is only ever armed after `terminated` is set, so this can never\n // find one pending — the re-show/removal race is gone rather than guarded.\n if (visible || terminated) return\n document.body.appendChild(root)\n visible = true\n autoUpdateCleanup = autoUpdate(reference, root, updatePosition)\n requestAnimationFrame(() => root.classList.add('visible'))\n setTimeout(() => {\n if (!visible) return\n const onMouseDown = (e: MouseEvent) => {\n if (isOutsideDismissTarget(e.target as Node)) hide()\n }\n const onTouchStart = (e: TouchEvent) => {\n if (!e.touches.length) return\n const target = document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY)\n if (isOutsideDismissTarget(target)) hide()\n }\n document.addEventListener('mousedown', onMouseDown, { passive: true })\n document.addEventListener('touchstart', onTouchStart, { passive: true })\n cleanups.push(\n () => document.removeEventListener('mousedown', onMouseDown),\n () => document.removeEventListener('touchstart', onTouchStart)\n )\n }, OUTSIDE_CLICK_DEFER_MS)\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault()\n hide()\n }\n }\n root.addEventListener('keydown', onKeyDown)\n cleanups.push(() => root.removeEventListener('keydown', onKeyDown))\n onShow?.()\n }\n\n const destroy = (): void => {\n hide()\n // `hide()` no-ops when the popover was never shown; destroying is terminal either way.\n terminated = true\n // Teardown is immediate — destroy callers replace or unmount the surface.\n finishHide()\n }\n\n const popover: Popover = {\n element: root,\n show,\n hide,\n destroy,\n isVisible: () => visible,\n setContent,\n updateReference: (ref?: HTMLElement, coords?: VirtualCoordinates) => {\n if (ref) reference = ref\n else if (coords) reference = createVirtualReference(coords)\n if (visible) {\n autoUpdateCleanup?.()\n autoUpdateCleanup = autoUpdate(reference, root, updatePosition)\n } else {\n updatePosition()\n }\n }\n }\n\n unregister = controller.adopt(popover, 'unknown', {\n element: root,\n referenceElement: referenceElement ?? null\n })\n return popover\n}\n","// Internal logger — single greppable prefix for every package diagnostic.\n// Only wraps `warn` / `error` because the shared tsup `pure` policy\n// strips `console.log` / `console.debug` from production bundles.\nconst PREFIX = '[extension-hyperlink]'\n\nexport const logger = {\n warn: (...args: unknown[]): void => console.warn(PREFIX, ...args),\n error: (...args: unknown[]): void => console.error(PREFIX, ...args)\n}\n","import { logger } from './logger'\n\nexport const copyToClipboard = async (\n text: string,\n callback?: (success: boolean) => void\n): Promise<boolean> => {\n try {\n if (navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(text)\n } else {\n const textArea = document.createElement('textarea')\n textArea.value = text\n document.body.appendChild(textArea)\n let ok = false\n try {\n textArea.select()\n ok = document.execCommand('copy')\n } finally {\n document.body.removeChild(textArea)\n }\n if (!ok) {\n logger.warn('copyToClipboard failed', 'execCommand returned false')\n callback?.(false)\n return false\n }\n }\n\n callback?.(true)\n return true\n } catch (error) {\n logger.warn('copyToClipboard failed', error)\n callback?.(false)\n return false\n }\n}\n","export const createHTMLElement = <K extends keyof HTMLElementTagNameMap>(\n type: K,\n props?: Partial<HTMLElementTagNameMap[K]>\n): HTMLElementTagNameMap[K] => {\n const element = document.createElement(type)\n\n if (props) {\n Object.assign(element, props)\n }\n\n return element\n}\n","export interface IconProps {\n size?: number\n fill?: string\n}\n\nexport const Copy = ({ size = 24, fill = 'currentColor' }: IconProps = {}): string => {\n return `\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"${size}\" viewBox=\"0 -960 960 960\" width=\"${size}\" fill=\"${fill}\" aria-hidden=\"true\">\n <path d=\"M360-240q-33 0-56.5-23.5T280-320v-480q0-33 23.5-56.5T360-880h360q33 0 56.5 23.5T800-800v480q0 33-23.5 56.5T720-240H360Zm0-80h360v-480H360v480ZM200-80q-33 0-56.5-23.5T120-160v-560h80v560h440v80H200Zm160-240v-480 480Z\"/>\n </svg>\n `\n}\n\nexport const LinkOff = ({ size = 24, fill = 'currentColor' }: IconProps = {}): string => {\n return `\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"${size}\" viewBox=\"0 -960 960 960\" width=\"${size}\" fill=\"${fill}\" aria-hidden=\"true\">\n <path d=\"m770-302-60-62q40-11 65-42.5t25-73.5q0-50-35-85t-85-35H520v-80h160q83 0 141.5 58.5T880-480q0 57-29.5 105T770-302ZM634-440l-80-80h86v80h-6ZM792-56 56-792l56-56 736 736-56 56ZM440-280H280q-83 0-141.5-58.5T80-480q0-69 42-123t108-71l74 74h-24q-50 0-85 35t-35 85q0 50 35 85t85 35h160v80ZM320-440v-80h65l79 80H320Z\"/>\n </svg>\n `\n}\n\nexport const Link = ({ size = 24, fill = 'currentColor' }: IconProps = {}): string => {\n return `\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"${size}\" viewBox=\"0 -960 960 960\" width=\"${size}\" fill=\"${fill}\" aria-hidden=\"true\">\n <path d=\"M440-280H280q-83 0-141.5-58.5T80-480q0-83 58.5-141.5T280-680h160v80H280q-50 0-85 35t-35 85q0 50 35 85t85 35h160v80ZM320-440v-80h320v80H320Zm200 160v-80h160q50 0 85-35t35-85q0-50-35-85t-85-35H520v-80h160q83 0 141.5 58.5T880-480q0 83-58.5 141.5T680-280H520Z\"/>\n </svg>\n `\n}\n\nexport const Pencil = ({ size = 24, fill = 'currentColor' }: IconProps = {}): string => {\n return `\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"${size}\" viewBox=\"0 -960 960 960\" width=\"${size}\" fill=\"${fill}\" aria-hidden=\"true\">\n <path d=\"M200-200h57l391-391-57-57-391 391v57Zm-80 80v-170l528-527q12-11 26.5-17t30.5-6q16 0 31 6t26 18l55 56q12 11 17.5 26t5.5 30q0 16-5.5 30.5T817-647L290-120H120Zm640-584-56-56 56 56Zm-141 85-28-29 57 57-29-28Z\"/>\n </svg>\n `\n}\n\nexport const Title = ({ size = 24, fill = 'currentColor' }: IconProps = {}): string => {\n return `\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"${size}\" viewBox=\"0 -960 960 960\" width=\"${size}\" fill=\"${fill}\" aria-hidden=\"true\">\n <path d=\"M160-560v-80h360v80H160Zm0 160v-80h640v80H160Z\"/>\n </svg>\n `\n}\n","import { find } from 'linkifyjs'\n\nimport { isBarePhone } from './phone'\n\nconst SCHEME_RE = /^([a-z][a-z0-9+.-]*):/i\n\n/** Fragment / query / absolute-path / dot-relative refs. `//host` is handled by `hasRealScheme`. */\nconst RELATIVE_REF_RE = /^([#?/]|\\.\\.?\\/)/\n\n/**\n * Distinguish `scheme:opaque` (real URL) from `host:port` (relative ref\n * the browser would mis-resolve). `SCHEME_RE` alone matches both\n * `mailto:foo` and `localhost:3000`; the candidate-scheme check below\n * vetoes the latter.\n */\nconst hasRealScheme = (raw: string): boolean => {\n if (raw.startsWith('//')) return true\n const m = raw.match(SCHEME_RE)\n if (!m) return false\n if (raw.includes('://')) return true\n const candidate = m[1].toLowerCase()\n if (candidate === 'localhost' || candidate.includes('.')) return false\n return true\n}\n\n/**\n * Strict full-string email match. Multi-token inputs like\n * `hello user@example.com` are not bare emails — that's a sentence.\n * The `@` pre-check avoids paying the linkify cost on plain URLs.\n */\nconst isBareEmail = (\n trimmed: string\n): { ok: true; href: string } | { ok: false; href?: undefined } => {\n if (!trimmed.includes('@')) return { ok: false }\n const matches = find(trimmed)\n if (matches.length !== 1) return { ok: false }\n const only = matches[0]\n if (only.type !== 'email' || only.value !== trimmed) return { ok: false }\n return { ok: true, href: only.href }\n}\n\nexport const DEFAULT_PROTOCOL = 'https' as const\n\n/**\n * Canonicalize a user-supplied href so stored marks point somewhere\n * absolute (bare `google.com` would otherwise resolve against\n * `document.baseURI` at render time). See README → Normalization for\n * the full pipeline order.\n */\nexport const normalizeHref = (raw: string, defaultProtocol: string = DEFAULT_PROTOCOL): string => {\n const trimmed = raw.trim()\n if (!trimmed) return ''\n\n const phone = isBarePhone(trimmed)\n if (phone.ok) return phone.href\n\n const email = isBareEmail(trimmed)\n if (email.ok) return email.href\n\n if (hasRealScheme(trimmed)) return trimmed\n // Relative refs are legitimate stored hrefs (markdown import, migrations);\n // promoting them yields `https://#intro`, which `new URL` rejects outright.\n if (RELATIVE_REF_RE.test(trimmed)) return trimmed\n return `${defaultProtocol}://${trimmed}`\n}\n\n/**\n * Shape `findLinks` produces (linkifyjs match + our synthetic\n * special-scheme / phone entries). Loosened so linkifyjs types don't\n * leak across the public boundary.\n */\nexport type LinkifyMatchLike = {\n type: string\n value: string\n href: string\n}\n\n/** Canonicalize a linkifyjs match for storage; non-URL matches pass through unchanged. */\nexport const normalizeLinkifyHref = (\n link: LinkifyMatchLike,\n defaultProtocol: string = DEFAULT_PROTOCOL\n): string => {\n return link.type === 'url' ? normalizeHref(link.value, defaultProtocol) : link.href\n}\n","// E.164 phone detection + `tel:` canonicalization. `+`-prefix and\n// 8–15 digits required so years, ZIPs, and bare numerics don't autolink.\n// Formatting (space, dash, dot, parens) is stripped per RFC 3966.\n\n// Anchored at both ends so the caller-must-trim contract is enforced.\nconst PHONE_SHAPE_RE = /^\\+\\d[\\d\\s.\\-()]{4,18}\\d$/\n\nconst NON_DIGIT_RE = /\\D/g\n\n/**\n * True iff the entire trimmed input is one E.164-compatible phone\n * number. Returns the canonical `tel:+CCNSN` href on success. Strict\n * full-match only — autolink handles embedded phones.\n */\nexport const isBarePhone = (\n trimmed: string\n): { ok: true; href: string } | { ok: false; href?: undefined } => {\n if (!PHONE_SHAPE_RE.test(trimmed)) return { ok: false }\n const digits = trimmed.replace(NON_DIGIT_RE, '')\n // E.164 §6.2.1: total length 8–15 digits including country code.\n if (digits.length < 8 || digits.length > 15) return { ok: false }\n return { ok: true, href: `tel:+${digits}` }\n}\n","/**\n * Special URL schemes and well-known domains the extension classifies\n * for the preview popover.\n *\n * Catalog source: https://github.com/bhagyas/app-urls\n */\n\n/**\n * String-literal union so consumers can declare a\n * `Partial<Record<SpecialUrlType, …>>` icon map with exhaustive\n * autocomplete — type-only, zero runtime bytes. Naming convention lives\n * in this package's AGENTS.md.\n */\nexport type SpecialUrlType =\n // Communication\n | 'email'\n | 'phone'\n | 'sms'\n | 'facetime'\n | 'facetime-audio'\n // Messaging\n | 'whatsapp'\n | 'telegram'\n | 'discord'\n | 'skype'\n | 'slack'\n // Social networks\n | 'twitter'\n | 'facebook'\n | 'instagram'\n | 'linkedin'\n | 'snapchat'\n | 'reddit'\n | 'tiktok'\n // Video conferencing\n | 'zoom'\n | 'teams'\n | 'webex'\n | 'meet'\n // Apple\n | 'calendar'\n | 'reminders'\n | 'contacts'\n | 'maps'\n | 'music'\n | 'apple-tv'\n | 'notes'\n | 'photos'\n | 'shortcuts'\n | 'app-store'\n // Dev / productivity\n | 'github'\n | 'gitlab'\n | 'vscode'\n | 'notion'\n | 'obsidian'\n | 'figma'\n // Entertainment\n | 'youtube'\n | 'spotify'\n | 'netflix'\n | 'twitch'\n // Shopping / other\n | 'amazon'\n | 'uber'\n | 'lyft'\n\nexport type SpecialUrlInfo = {\n type: SpecialUrlType\n title: string\n category:\n | 'communication'\n | 'social'\n | 'productivity'\n | 'entertainment'\n | 'shopping'\n | 'development'\n | 'apple'\n | 'other'\n}\n\n// Communication & Phone\nconst COMMUNICATION_URLS: Record<string, SpecialUrlInfo> = {\n 'mailto:': { type: 'email', title: 'Email', category: 'communication' },\n 'tel:': { type: 'phone', title: 'Phone', category: 'communication' },\n 'telprompt:': { type: 'phone', title: 'Phone', category: 'communication' },\n 'sms:': { type: 'sms', title: 'SMS', category: 'communication' },\n 'facetime:': { type: 'facetime', title: 'FaceTime', category: 'communication' },\n 'facetime-audio:': {\n type: 'facetime-audio',\n title: 'FaceTime Audio',\n category: 'communication'\n }\n}\n\n// Social Media & Messaging\nconst SOCIAL_URLS: Record<string, SpecialUrlInfo> = {\n 'whatsapp:': { type: 'whatsapp', title: 'WhatsApp', category: 'social' },\n 'tg:': { type: 'telegram', title: 'Telegram', category: 'social' },\n 'discord:': { type: 'discord', title: 'Discord', category: 'social' },\n 'skype:': { type: 'skype', title: 'Skype', category: 'social' },\n 'slack:': { type: 'slack', title: 'Slack', category: 'social' },\n 'twitter:': { type: 'twitter', title: 'Twitter', category: 'social' },\n 'fb:': { type: 'facebook', title: 'Facebook', category: 'social' },\n 'instagram:': { type: 'instagram', title: 'Instagram', category: 'social' },\n 'linkedin:': { type: 'linkedin', title: 'LinkedIn', category: 'social' },\n 'snapchat:': { type: 'snapchat', title: 'Snapchat', category: 'social' },\n 'reddit:': { type: 'reddit', title: 'Reddit', category: 'social' },\n 'tiktok:': { type: 'tiktok', title: 'TikTok', category: 'social' }\n}\n\n// Video Conferencing & Meeting\nconst MEETING_URLS: Record<string, SpecialUrlInfo> = {\n 'zoommtg:': { type: 'zoom', title: 'Zoom Meeting', category: 'communication' },\n 'zoomus:': { type: 'zoom', title: 'Zoom', category: 'communication' },\n 'msteams:': { type: 'teams', title: 'Microsoft Teams', category: 'communication' },\n 'webex:': { type: 'webex', title: 'Cisco Webex', category: 'communication' }\n}\n\n// Apple Apps\nconst APPLE_URLS: Record<string, SpecialUrlInfo> = {\n 'calshow:': { type: 'calendar', title: 'Calendar', category: 'apple' },\n 'x-apple-calevent:': { type: 'calendar', title: 'Calendar Event', category: 'apple' },\n 'x-apple-reminder:': { type: 'reminders', title: 'Reminders', category: 'apple' },\n 'contacts:': { type: 'contacts', title: 'Contacts', category: 'apple' },\n 'maps:': { type: 'maps', title: 'Maps', category: 'apple' },\n 'map:': { type: 'maps', title: 'Maps', category: 'apple' },\n 'music:': { type: 'music', title: 'Apple Music', category: 'apple' },\n 'videos:': { type: 'apple-tv', title: 'Apple TV', category: 'apple' },\n 'mobilenotes:': { type: 'notes', title: 'Notes', category: 'apple' },\n 'photos-redirect:': { type: 'photos', title: 'Photos', category: 'apple' },\n 'shortcuts:': { type: 'shortcuts', title: 'Shortcuts', category: 'apple' },\n 'itms-apps:': { type: 'app-store', title: 'App Store', category: 'apple' }\n}\n\n// Development & Productivity\nconst PRODUCTIVITY_URLS: Record<string, SpecialUrlInfo> = {\n 'github:': { type: 'github', title: 'GitHub', category: 'development' },\n 'gitlab:': { type: 'gitlab', title: 'GitLab', category: 'development' },\n 'vscode:': { type: 'vscode', title: 'VS Code', category: 'development' },\n 'notion:': { type: 'notion', title: 'Notion', category: 'productivity' },\n 'obsidian:': { type: 'obsidian', title: 'Obsidian', category: 'productivity' },\n 'figma:': { type: 'figma', title: 'Figma', category: 'development' }\n}\n\n// Entertainment & Media\nconst ENTERTAINMENT_URLS: Record<string, SpecialUrlInfo> = {\n 'youtube:': { type: 'youtube', title: 'YouTube', category: 'entertainment' },\n 'spotify:': { type: 'spotify', title: 'Spotify', category: 'entertainment' },\n 'netflix:': { type: 'netflix', title: 'Netflix', category: 'entertainment' },\n 'twitch:': { type: 'twitch', title: 'Twitch', category: 'entertainment' }\n}\n\n// Shopping & Commerce\nconst SHOPPING_URLS: Record<string, SpecialUrlInfo> = {\n 'amazon:': { type: 'amazon', title: 'Amazon', category: 'shopping' },\n 'uber:': { type: 'uber', title: 'Uber', category: 'other' },\n 'lyft:': { type: 'lyft', title: 'Lyft', category: 'other' }\n}\n\nconst ALL_SPECIAL_URLS = {\n ...COMMUNICATION_URLS,\n ...SOCIAL_URLS,\n ...MEETING_URLS,\n ...APPLE_URLS,\n ...PRODUCTIVITY_URLS,\n ...ENTERTAINMENT_URLS,\n ...SHOPPING_URLS\n}\n\n// Domain-based detection for short links and well-known web URLs.\nconst DOMAIN_MAPPINGS: Record<string, SpecialUrlInfo> = {\n 'wa.me': { type: 'whatsapp', title: 'WhatsApp', category: 'social' },\n 't.me': { type: 'telegram', title: 'Telegram', category: 'social' },\n 'discord.gg': { type: 'discord', title: 'Discord Invite', category: 'social' },\n 'zoom.us': { type: 'zoom', title: 'Zoom Meeting', category: 'communication' },\n 'meet.google.com': { type: 'meet', title: 'Google Meet', category: 'communication' },\n 'teams.microsoft.com': {\n type: 'teams',\n title: 'Microsoft Teams',\n category: 'communication'\n },\n 'github.com': { type: 'github', title: 'GitHub', category: 'development' },\n 'gitlab.com': { type: 'gitlab', title: 'GitLab', category: 'development' },\n 'figma.com': { type: 'figma', title: 'Figma', category: 'development' },\n 'notion.so': { type: 'notion', title: 'Notion', category: 'productivity' },\n 'twitter.com': { type: 'twitter', title: 'Twitter', category: 'social' },\n 'x.com': { type: 'twitter', title: 'X (Twitter)', category: 'social' },\n 'instagram.com': { type: 'instagram', title: 'Instagram', category: 'social' },\n 'linkedin.com': { type: 'linkedin', title: 'LinkedIn', category: 'social' },\n 'youtube.com': { type: 'youtube', title: 'YouTube', category: 'entertainment' },\n 'spotify.com': { type: 'spotify', title: 'Spotify', category: 'entertainment' }\n}\n\n/**\n * Classify `url` against the catalog (scheme prefix or host suffix).\n * Returns `null` for plain web URLs — the consumer should fall back to\n * a generic favicon. Mapping `type`/`category` to an icon is the\n * consumer's job; the extension stays brand-neutral on purpose.\n */\nexport const getSpecialUrlInfo = (url: string): SpecialUrlInfo | null => {\n const lowerUrl = url.toLowerCase()\n\n for (const [scheme, info] of Object.entries(ALL_SPECIAL_URLS)) {\n if (lowerUrl.startsWith(scheme)) {\n return info\n }\n }\n\n try {\n const urlObj = new URL(url)\n const hostname = urlObj.hostname.toLowerCase()\n const cleanHostname = hostname.startsWith('www.') ? hostname.slice(4) : hostname\n\n // Loop covers both exact matches (`cleanHostname === domain`) and\n // subdomain suffixes (`api.github.com` → `github.com`); a separate\n // direct-lookup fast path was redundant and dropped.\n for (const [domain, info] of Object.entries(DOMAIN_MAPPINGS)) {\n if (cleanHostname === domain || cleanHostname.endsWith(`.${domain}`)) {\n return info\n }\n }\n } catch {\n /* malformed URL: no domain match possible, fall through to null */\n }\n\n return null\n}\n","import { find } from 'linkifyjs'\n\nimport { logger } from './logger'\nimport { isBarePhone } from './phone'\nimport { getSpecialUrlInfo } from './specialUrls'\n\n/**\n * Schemes blocked at every write boundary: `javascript:` / `vbscript:`\n * (script execution), `data:` (arbitrary HTML), `file:` (local FS),\n * `blob:` (in-page memory; never legitimate in stored content).\n *\n * Twin of `extension-hypermultimedia`'s copy. Adding a scheme to one and not\n * the other opens a hole in the twin, so preflight diffs them byte-for-byte.\n */\nexport const DANGEROUS_SCHEME_RE = /^\\s*(javascript|data|vbscript|file|blob):/i\n\n/**\n * Single XSS gate used at every read/write boundary. Returns `false`\n * for nullish/empty hrefs and any scheme matched by\n * {@link DANGEROUS_SCHEME_RE}. See README → Security.\n */\nexport const isSafeHref = (href: string | null | undefined): href is string => {\n if (typeof href !== 'string' || href.length === 0) return false\n // Test a control-stripped copy. `new URL()` discards ASCII tab/LF/CR and C0\n // controls, so `java\\tscript:` navigates as `javascript:`. Embedded controls\n // must not smuggle a dangerous scheme past the regex.\n // eslint-disable-next-line no-control-regex -- matching C0 controls is the point\n return !DANGEROUS_SCHEME_RE.test(href.replace(/[\\u0000-\\u0020]+/g, ''))\n}\n\n/** Web schemes whose host must look like a real domain (TLD / localhost / IP). */\nconst STANDARD_WEB_SCHEMES = new Set(['http', 'https', 'ftp', 'ftps'])\n\n/** IPv4 dotted quad. Deliberately loose on octet range — we only need a shape check. */\nconst IPV4_RE = /^\\d{1,3}(\\.\\d{1,3}){3}$/\n\nexport type ValidateURLOptions = {\n customValidator?: (url: string) => boolean\n}\n\n/**\n * Catalog membership only (`whatsapp:`, `wa.me`, …) — NOT a security gate,\n * and it says nothing about whether the URL is safe to render. Web schemes\n * (`http(s)`/`ftp(s)`) are checked by `hasPlausibleHost` instead.\n */\nconst isRecognizedSpecialScheme = (url: string): boolean => {\n return getSpecialUrlInfo(url) !== null\n}\n\n/**\n * linkifyjs accepts any `scheme://host` string, so typos like\n * `https://googlecom` pass its own validation. For http(s)/ftp additionally\n * require a dotted host (any TLD, IDN and punycode included), `localhost`,\n * or an IP literal. Non-standard schemes skip this gate.\n */\nconst hasPlausibleHost = (url: string): boolean => {\n let parsed: URL\n try {\n parsed = new URL(url)\n } catch {\n return false\n }\n const host = parsed.hostname\n if (!host) return false\n if (host === 'localhost') return true\n if (IPV4_RE.test(host)) return true\n // `new URL()` strips IPv6 brackets on most engines and leaves the raw\n // `::1`-style string, which contains a colon that can't appear in any\n // real hostname. Cheap and robust enough.\n if (host.includes(':')) return true\n return host.includes('.')\n}\n\n/**\n * Shape-validate a URL: web schemes with a plausible host, app schemes from\n * the `getSpecialUrlInfo` catalog, and bare E.164 phones. Rejects schemes\n * matched by {@link DANGEROUS_SCHEME_RE}. See README → Validation.\n */\nexport const validateURL = (url: string, options?: ValidateURLOptions): boolean => {\n const trimmed = url.trim()\n if (!trimmed) return false\n\n // Security floor: dangerous schemes must NEVER pass shape validation,\n // however linkifyjs evolves or whichever custom protocols a host registers.\n // `composeGate` re-checks at the write boundary, but pinning it here makes\n // the create form reject a newly-banned scheme immediately.\n if (!isSafeHref(trimmed)) return false\n\n try {\n // E.164 phones have no scheme prefix and would otherwise fall\n // through to linkifyjs, which has no phone matcher.\n if (isBarePhone(trimmed).ok) {\n if (options?.customValidator) return options.customValidator(url)\n return true\n }\n\n if (isRecognizedSpecialScheme(url)) {\n if (options?.customValidator) return options.customValidator(url)\n return true\n }\n\n const validURL = find(url).find(\n (link) =>\n link.isLink && (options?.customValidator ? options.customValidator(link.value) : true)\n )\n if (!validURL?.href) return false\n\n // linkifyjs waves through anything scheme-shaped — require a plausible\n // host for web schemes so typos like `https://googlecom` are rejected.\n if (isStandardWebScheme(validURL.href)) {\n return hasPlausibleHost(validURL.href)\n }\n return true\n } catch (error) {\n logger.error('validateURL threw', error)\n return false\n }\n}\n\n/** Lowercased scheme component of `url`, or `null` if it has no `:`. Module-internal; exported for unit tests only. */\nexport const getURLScheme = (url: string): string | null => {\n if (!url.trim()) return null\n\n const colonIndex = url.indexOf(':')\n if (colonIndex === -1) return null\n\n return url.substring(0, colonIndex).toLowerCase()\n}\n\n/** Single http/https/ftp/ftps predicate — keeps `validateURL` and `url-decisions` on one policy. Module-internal. */\nconst isStandardWebScheme = (url: string): boolean => {\n const scheme = getURLScheme(url)\n return scheme !== null && STANDARD_WEB_SCHEMES.has(scheme)\n}\n","import { getDefaultController } from '../floating-popover'\nimport type { CreateHyperlinkOptions } from '../hyperlink'\nimport { createHTMLElement, validateURL } from '../utils'\nimport { Link } from '../utils/icons'\n\ntype HyperlinkElements = {\n root: HTMLElement\n form: HTMLFormElement\n input: HTMLInputElement\n button: HTMLButtonElement\n inputsWrapper: HTMLElement\n errorMessage: HTMLElement\n}\n\nconst createHyperlinkElements = (prefillHref: string): HyperlinkElements => {\n const root = createHTMLElement('div', { className: 'hyperlink-create-popover' })\n const buttonsWrapper = createHTMLElement('div', { className: 'buttons-wrapper' })\n const inputsWrapper = createHTMLElement('div', { className: 'inputs-wrapper' })\n const form = createHTMLElement('form', {})\n\n const input = createHTMLElement('input', {\n type: 'text',\n inputMode: 'url',\n name: 'hyperlink-url',\n placeholder: 'https://example.com',\n autocomplete: 'new-password',\n spellcheck: false,\n value: prefillHref\n })\n\n const button = createHTMLElement('button', {\n type: 'submit',\n textContent: 'Apply',\n disabled: prefillHref.trim().length === 0\n })\n\n const errorMessage = createHTMLElement('div', {\n className: 'error-message',\n textContent: 'Please enter a valid URL'\n })\n\n const searchIcon = createHTMLElement('div', {\n className: 'search-icon',\n innerHTML: Link({ size: 24 })\n })\n\n inputsWrapper.append(searchIcon, input, errorMessage)\n buttonsWrapper.append(button)\n form.append(inputsWrapper, buttonsWrapper)\n root.append(form)\n\n return { root, form, input, button, inputsWrapper, errorMessage }\n}\n\nconst setupEventListeners = (elements: HyperlinkElements, options: CreateHyperlinkOptions) => {\n const { form, input, button, inputsWrapper, errorMessage } = elements\n const { editor } = options\n\n const showError = () => {\n inputsWrapper.classList.add('error')\n errorMessage.classList.add('show')\n }\n\n const hideError = () => {\n inputsWrapper.classList.remove('error')\n errorMessage.classList.remove('show')\n }\n\n const updateButtonState = () => {\n const hasValue = input.value.trim().length > 0\n button.disabled = !hasValue\n if (hasValue) hideError()\n }\n\n input.addEventListener('input', updateButtonState)\n input.addEventListener('paste', () => setTimeout(updateButtonState, 0))\n inputsWrapper.addEventListener('click', () => input.focus())\n\n input.addEventListener('keydown', (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n getDefaultController().close()\n editor.commands.focus()\n }\n })\n\n form.addEventListener('submit', (event: Event) => {\n event.preventDefault()\n if (button.disabled) return\n\n const url = input.value.trim()\n // Pre-submit UX gate: shape + user `validate` only. The full XSS +\n // `isAllowedUri` policy runs inside `setHyperlink`; on rejection the\n // command returns `false` and the popover stays open for correction.\n if (!validateURL(url, { customValidator: options.validate })) {\n showError()\n return\n }\n\n // Gate before the chain: `chain().run()` dispatches its `tr` even when a\n // command returns false, so a rejected href must not reach the insert.\n if (!editor.can().setHyperlink({ href: url })) {\n showError()\n return\n }\n\n // Delegate to the canonical command — it normalizes, runs the composed\n // gate, and stamps `PREVENT_AUTOLINK_META`, so policy changes flow here.\n const chain = editor.chain().setHyperlink({ href: url })\n // With nothing selected the mark would only reach `storedMarks` and the\n // document would not change, so give the link its own text.\n if (editor.state.selection.empty) chain.insertContent({ type: 'text', text: url })\n if (!chain.run()) {\n showError()\n return\n }\n getDefaultController().close()\n editor.commands.focus()\n })\n}\n\nexport default function createHyperlinkPopover(options: CreateHyperlinkOptions): HTMLElement {\n const elements = createHyperlinkElements(options.attributes?.href ?? '')\n setupEventListeners(elements, options)\n return elements.root\n}\n","import type { Editor } from '@tiptap/core'\n\nimport { HYPERLINK_MARK_NAME } from '../constants'\nimport type { HyperlinkOptions } from '../hyperlink'\n\n/**\n * Internal — resolve the live `HyperlinkOptions` from a registered editor.\n * Throws when the extension is missing so the failure points at the\n * misconfiguration rather than at a downstream `undefined` access.\n */\nexport function getHyperlinkOptions(editor: Editor, callerName: string): HyperlinkOptions {\n const ext = editor.extensionManager.extensions.find((e) => e.name === HYPERLINK_MARK_NAME)\n if (!ext) throw new Error(`${callerName}: Hyperlink extension not registered on editor`)\n return ext.options as HyperlinkOptions\n}\n","import type { Editor } from '@tiptap/core'\n\nimport { getDefaultController, type Popover } from '../floating-popover'\n\n// The popover controller is a process-wide singleton, so it can't tell which\n// editor owns the popover it holds. Track the `{ editor, popover }` pair so\n// the mark's `onDestroy` closes only the popover this editor opened. Never a\n// sibling's, never one a host adopted by hand after ours closed.\nlet owned: { editor: Editor; popover: Popover } | null = null\nlet unsubscribe: (() => void) | null = null\n\n/** Record the editor and popover instance behind the popover an opener just adopted. */\nexport function setActivePopoverOwner(editor: Editor, popover: Popover): void {\n owned = { editor, popover }\n watchForRelease()\n}\n\n// Clear ownership the moment the controller stops holding our popover (outside\n// click, Escape, replacement adopt). Stale ownership can then never close a\n// popover we didn't open. Lazy: subscribed only while owning.\nfunction watchForRelease(): void {\n if (unsubscribe) return\n unsubscribe = getDefaultController().subscribe((state) => {\n if (owned && state.kind === 'mounted' && state.element === owned.popover.element) return\n owned = null\n unsubscribe?.()\n unsubscribe = null\n })\n}\n\n/** Close the open popover only when `editor` owns it. Called from the mark's `onDestroy`. */\nexport function closeOwnedPopover(editor: Editor): void {\n if (!owned || owned.editor !== editor) return\n const { popover } = owned\n owned = null\n unsubscribe?.()\n unsubscribe = null\n const controller = getDefaultController()\n const state = controller.getState()\n if (state.kind === 'mounted' && state.element === popover.element) {\n controller.close()\n }\n}\n","import { hideTooltip } from '@docs.plus/floating-tooltip'\nimport type { Editor } from '@tiptap/core'\n\nimport { HYPERLINK_MARK_NAME, OFFSCREEN_COORD_PX } from '../constants'\nimport { createPopover, getDefaultController } from '../floating-popover'\nimport type { CreateHyperlinkOptions, HyperlinkAttributes } from '../hyperlink'\nimport createHyperlinkPopover from '../popovers/createHyperlinkPopover'\nimport { getHyperlinkOptions } from './getHyperlinkOptions'\nimport { setActivePopoverOwner } from './popoverOwnership'\n\nconst INPUT_FOCUS_DELAY_MS = 100\n\n/**\n * Open the create-hyperlink popover anchored to the current selection.\n * Returns `false` when the host opted out (factory returned `null`).\n */\nexport function openCreateHyperlink(\n editor: Editor,\n attributes: Partial<HyperlinkAttributes> = {}\n): boolean {\n const options = getHyperlinkOptions(editor, 'openCreateHyperlink')\n const factory = options.popovers.createHyperlink ?? createHyperlinkPopover\n\n const popoverOptions: CreateHyperlinkOptions = {\n editor,\n validate: options.validate,\n extensionName: HYPERLINK_MARK_NAME,\n attributes\n }\n\n const content = factory(popoverOptions)\n if (!content) return false\n\n const { from, to } = editor.state.selection\n\n // Deferred input focus, owned by the popover lifecycle. `onShow` arms the timer\n // and `onHide` clears it, so the timer can never fire `focus()` on a detached\n // node. `onHide` fires on every teardown path: outside-click, Escape, editor destroy.\n let focusTimer: ReturnType<typeof setTimeout> | null = null\n\n // `popover` is forward-referenced inside the coords callback so the\n // stale-anchor guard below can call `popover.hide()` once the\n // controller has handed it back to us.\n const popover = createPopover({\n coordinates: {\n getBoundingClientRect: () => {\n // Remote collab ops (Yjs) can shrink the doc and make `from`/`to`\n // out-of-range. Then `coordsAtPos` throws, so dismiss (microtask-deferred;\n // the off-screen rect bridges the gap until teardown).\n try {\n const start = editor.view.coordsAtPos(from)\n const end = editor.view.coordsAtPos(to)\n // Wrapped multi-line selections can put `end` left of `start`;\n // clamp so the virtual rect never has negative width.\n return {\n x: Math.min(start.left, end.left),\n y: start.top,\n width: Math.abs(end.left - start.left),\n height: end.bottom - start.top\n }\n } catch {\n queueMicrotask(() => popover.hide())\n return { x: OFFSCREEN_COORD_PX, y: OFFSCREEN_COORD_PX, width: 0, height: 0 }\n }\n },\n contextElement: editor.view.dom\n },\n content,\n placement: 'bottom',\n showArrow: true,\n role: 'dialog',\n ariaLabel: 'Add link',\n onShow: () => {\n const input = content.querySelector('input')\n if (input) focusTimer = setTimeout(() => input.focus(), INPUT_FOCUS_DELAY_MS)\n },\n onHide: () => {\n if (focusTimer != null) {\n clearTimeout(focusTimer)\n focusTimer = null\n }\n // BYO content can attach tooltips; the surface must not strand one.\n hideTooltip()\n }\n })\n\n getDefaultController().adopt(popover, 'create', {\n element: popover.element,\n referenceElement: null\n })\n setActivePopoverOwner(editor, popover)\n popover.show()\n return true\n}\n","import { type Command, getMarkRange } from '@tiptap/core'\n\nimport { HYPERLINK_MARK_NAME } from '../constants'\nimport { createURLDecisions, type URLDecisions } from '../url-decisions'\nimport { logger } from '../utils/logger'\nimport { validateURL } from '../utils/validateURL'\nimport type { EditHyperlinkAttributes } from './surface'\n\ntype EditHyperlinkCommandArgs = EditHyperlinkAttributes & {\n markName?: string\n validate?: (url: string) => boolean\n /** URL Decisions instance; defaults to a vanilla one so manual/test callers work standalone. */\n urls?: URLDecisions\n}\n\n// Returns a composable `Command`: a nested chain here historically produced\n// \"Applying a mismatched transaction\" under `extendMarkRange`. `newURL` flows\n// through `urls.forWrite` (normalize + gate) so the edit surface stays in\n// lock-step with `setHyperlink`.\nexport const editHyperlinkCommand =\n (attributes: EditHyperlinkCommandArgs = {}): Command =>\n ({ tr, dispatch }) => {\n const {\n newURL,\n newText,\n title,\n image,\n validate,\n markName = HYPERLINK_MARK_NAME,\n urls = createURLDecisions()\n } = attributes\n\n if (newURL && !validateURL(newURL, { customValidator: validate })) {\n return false\n }\n\n const markType = tr.doc.type.schema.marks[markName]\n if (!markType) return false\n\n const { from } = tr.selection\n const $pos = tr.doc.resolve(from)\n const range = getMarkRange($pos, markType)\n if (!range) return false\n\n let currentMark\n try {\n currentMark = tr.doc.nodeAt(range.from)?.marks.find((m) => m.type === markType)\n } catch (error) {\n logger.warn('editHyperlink: failed to read mark at position', error)\n return false\n }\n if (!currentMark) return false\n\n // Runs above the dry-run exit (`forWrite` is pure) so `can()` and the real\n // command agree when `isAllowedUri` rejects the new URL.\n let href: string = currentMark.attrs.href\n if (newURL) {\n // `validate` is re-passed for defense-in-depth against a permissive `validateURL`.\n const [decision] = urls.forWrite({ kind: 'href', href: newURL }, { validate })\n if (!decision) return false\n href = decision.href\n }\n\n if (!dispatch) return true\n\n const currentText = tr.doc.textBetween(range.from, range.to)\n const text = newText || currentText\n\n const newMark = markType.create({\n ...currentMark.attrs,\n href,\n ...(title !== undefined && { title }),\n ...(image !== undefined && { image })\n })\n\n // Unchanged text: swap only the hyperlink mark in place so co-located\n // marks (bold/italic/code) survive the edit untouched.\n if (text === currentText) {\n tr.removeMark(range.from, range.to, markType)\n tr.addMark(range.from, range.to, newMark)\n return true\n }\n\n // Text changed: the range is rebuilt, so carry the first text node's\n // non-hyperlink marks onto the replacement.\n const carried = tr.doc.nodeAt(range.from)?.marks.filter((mark) => mark.type !== markType) ?? []\n tr.replaceWith(range.from, range.to, tr.doc.type.schema.text(text, [...carried, newMark]))\n return true\n }\n","import { find } from 'linkifyjs'\n\nimport { isBarePhone } from './phone'\nimport { validateURL } from './validateURL'\n\nconst SPECIAL_SCHEME_REGEX_GLOBAL = /\\b[a-zA-Z][a-zA-Z0-9+.-]*:[^\\s]+/g\nconst TRAILING_PUNCTUATION_RE = /[.,;:!?)\\]}]+$/\n\n/** Shape every `findLinks` entry satisfies. Mirrors linkifyjs match shape plus our synthetic special-scheme / bare-phone entries. */\nexport type FoundLink = {\n type: string\n href: string\n value: string\n start: number\n end: number\n isLink: boolean\n}\n\n/**\n * Trim trailing punctuation from the match range so \"Visit google.com.\"\n * autolinks `google.com`, not `google.com.`. Only trims `href` when it\n * shares the trailing chars (i.e. plain URL matches, not `mailto:` etc.).\n */\nconst stripTrailingPunctuation = <T extends { value: string; href: string; end: number }>(\n link: T\n): T => {\n const tail = link.value.match(TRAILING_PUNCTUATION_RE)\n if (!tail) return link\n const len = tail[0].length\n return {\n ...link,\n value: link.value.slice(0, -len),\n href: link.href.endsWith(tail[0]) ? link.href.slice(0, -len) : link.href,\n end: link.end - len\n }\n}\n\n/**\n * Merges linkifyjs matches with special-scheme matches (gated through\n * `validateURL` — linkifyjs has no app-deep-link matchers) and bare E.164\n * phones. The synthesized `type` is load-bearing: `normalizeLinkifyHref`\n * keys off it to decide whether to re-canonicalize or pass through.\n */\nexport const findLinks = (text: string): FoundLink[] => {\n const links: FoundLink[] = []\n\n const standardLinks = (find(text) as FoundLink[]).filter((link) => link.isLink)\n links.push(...standardLinks)\n\n // The special-scheme regex requires a `:`; skip the iterator entirely\n // on common keyword-token inputs that can't contain a scheme.\n if (text.includes(':')) {\n for (const match of text.matchAll(SPECIAL_SCHEME_REGEX_GLOBAL)) {\n const url = match[0]\n const start = match.index\n const end = start + url.length\n const alreadyCovered = standardLinks.some((link) => start >= link.start && end <= link.end)\n if (!alreadyCovered && validateURL(url)) {\n links.push({ type: 'url', href: url, value: url, start, end, isLink: true })\n }\n }\n }\n\n // Phones. `text` is a single whitespace-delimited token at the\n // autolink call site, so neither an inline scan nor an\n // `alreadyCovered` check is needed here.\n const phone = isBarePhone(text)\n if (phone.ok) {\n links.push({\n type: 'phone',\n href: phone.href,\n value: text,\n start: 0,\n end: text.length,\n isLink: true\n })\n }\n\n return links.map(stripTrailingPunctuation)\n}\n","// Single source of truth for every URL decision the extension makes.\n// Composes the `utils/*` primitives (detect / normalize / gate) into\n// `forWrite` (every write boundary) and `forRead` (every navigation\n// surface) so drift becomes a compile error.\n\nimport { findLinks } from '../utils/findLinks'\nimport {\n DEFAULT_PROTOCOL,\n type LinkifyMatchLike,\n normalizeHref,\n normalizeLinkifyHref\n} from '../utils/normalizeHref'\nimport { isSafeHref } from '../utils/validateURL'\n\n// The gate default, re-exported so callers take it from the decision module\n// they already import rather than reaching into `utils/validateURL`.\nexport { isSafeHref }\n\n/** Discriminated input to {@link URLDecisions.forWrite}. */\nexport type WriteInput =\n // `text` runs full extraction (returns 0..N).\n | { kind: 'text'; text: string }\n // `href` is an explicit user write — `shouldAutoLink` is NOT applied (returns 0..1).\n | { kind: 'href'; href: string }\n // `match` is a pre-detected linkify match (returns 0..1).\n | { kind: 'match'; match: LinkifyMatchLike }\n\nexport type WriteResult = {\n /** Canonical, gated, write-safe href ready to set on the mark. */\n href: string\n /** Source offset; `0` for `href`/`match` inputs. */\n start: number\n end: number\n}\n\nexport type ReadDecision = {\n /** Passes the full gate (`isSafeHref` + `isAllowedUri`) — required before any `window.open`. */\n navigable: boolean\n}\n\nexport type WriteOptions = {\n /** Per-call override of the controller's `validate`. */\n validate?: (url: string) => boolean\n}\n\nexport type URLDecisionsOptions = {\n /** Bare-domain promotion target (e.g. `https`). */\n defaultProtocol?: string\n /** Composed safety + policy gate. Defaults to {@link isSafeHref}; compose via {@link composeGate}. */\n gate?: (href: string | null | undefined) => href is string\n validate?: (url: string) => boolean\n shouldAutoLink?: (uri: string) => boolean\n}\n\nexport interface URLDecisions {\n /** Resolve a write candidate to its canonical, gated href(s). Returns `[]` when nothing passes. */\n forWrite(input: WriteInput, opts?: WriteOptions): WriteResult[]\n /** Read-side gate for render + navigation. */\n forRead(href: string | null | undefined): ReadDecision\n /**\n * Pure shape check — skips the gate stack on purpose. That keeps a tightened\n * `isAllowedUri` policy out of autolink's \"is the existing link still\n * link-shaped?\" cleanup pass.\n */\n detect(text: string): boolean\n}\n\n/** Context passed to a user-supplied `isAllowedUri` policy hook. Mirrors `@tiptap/extension-link`. */\nexport type IsAllowedUriContext<P = unknown> = {\n defaultValidate: (uri: string) => boolean\n protocols: Array<P>\n defaultProtocol: string\n}\n\nexport type ComposeGateOptions<P = unknown> = {\n isAllowedUri?: (uri: string, ctx: IsAllowedUriContext<P>) => boolean\n protocols?: ReadonlyArray<P>\n defaultProtocol?: string\n}\n\n/**\n * Compose {@link isSafeHref} with a user-supplied `isAllowedUri` hook.\n * Wired at every write boundary so the safety floor (no dangerous\n * schemes) is impossible to bypass.\n */\nexport function composeGate<P = unknown>(\n opts: ComposeGateOptions<P> = {}\n): (href: string | null | undefined) => href is string {\n const defaultProtocol = opts.defaultProtocol ?? DEFAULT_PROTOCOL\n const protocols = opts.protocols ?? []\n const userPolicy = opts.isAllowedUri\n return (href): href is string => {\n if (!isSafeHref(href)) return false\n if (!userPolicy) return true\n // Cast to mutable for `@tiptap/extension-link` parity — gate never mutates.\n return userPolicy(href, {\n defaultValidate: isSafeHref,\n protocols: protocols as Array<P>,\n defaultProtocol\n })\n }\n}\n\nexport function createURLDecisions(options: URLDecisionsOptions = {}): URLDecisions {\n const defaultProtocol = options.defaultProtocol ?? DEFAULT_PROTOCOL\n const gate = options.gate ?? isSafeHref\n\n /** Run the full gate stack used by autolink-flavored writes. */\n const passesAutoGates = (href: string, opts?: WriteOptions): boolean => {\n if (!gate(href)) return false\n const validate = opts?.validate ?? options.validate\n if (validate && !validate(href)) return false\n const veto = options.shouldAutoLink\n if (veto && !veto(href)) return false\n return true\n }\n\n return {\n forWrite(input, opts) {\n if (input.kind === 'href') {\n const trimmed = input.href.trim()\n if (!trimmed) return []\n const href = normalizeHref(trimmed, defaultProtocol)\n // Explicit-href path: full gate stack MINUS `shouldAutoLink` —\n // explicit writes are user intent, not autolink.\n if (!gate(href)) return []\n const validate = opts?.validate ?? options.validate\n if (validate && !validate(href)) return []\n return [{ href, start: 0, end: input.href.length }]\n }\n\n if (input.kind === 'match') {\n const href = normalizeLinkifyHref(input.match, defaultProtocol)\n if (!passesAutoGates(href, opts)) return []\n return [{ href, start: 0, end: input.match.value.length }]\n }\n\n // kind === 'text' — full extraction.\n return findLinks(input.text)\n .filter((link) => link.isLink)\n .map((link) => ({\n href: normalizeLinkifyHref(link, defaultProtocol),\n start: link.start,\n end: link.end\n }))\n .filter((r) => passesAutoGates(r.href, opts))\n },\n\n forRead(rawHref) {\n const href = typeof rawHref === 'string' ? rawHref : ''\n // Defense-in-depth: a misconfigured `gate` that skips `isSafeHref`\n // still can't make an unsafe href navigable.\n return { navigable: isSafeHref(href) && gate(href) }\n },\n\n detect(text) {\n return findLinks(text).some((l) => l.isLink)\n }\n }\n}\n","// UI commands stay separate from the pure schema commands per Tiptap\n// canon: `setHyperlink` never opens dialogs. The Link-named migration\n// aliases share the canonical references so policy changes flow through\n// both names.\n\nimport { openCreateHyperlink } from '../openers/openCreateHyperlink'\nimport type { URLDecisions } from '../url-decisions'\nimport { editHyperlinkCommand } from './editHyperlinkCommand'\nimport type { HyperlinkEngine } from './engine'\nimport type { HyperlinkRawCommands } from './surface'\n\ntype CanonicalFamily = Pick<\n HyperlinkRawCommands,\n 'setHyperlink' | 'unsetHyperlink' | 'toggleHyperlink' | 'setLink' | 'unsetLink' | 'toggleLink'\n>\n\nexport function canonicalCommands(engine: HyperlinkEngine): CanonicalFamily {\n return {\n setHyperlink: engine.set,\n unsetHyperlink: engine.unset,\n toggleHyperlink: engine.toggle,\n setLink: engine.set,\n unsetLink: engine.unset,\n toggleLink: engine.toggle\n }\n}\n\nexport interface EditCommandsDeps {\n markName: string\n urls: URLDecisions\n validate?: (url: string) => boolean\n}\n\ntype EditFamily = Pick<\n HyperlinkRawCommands,\n 'editHyperlink' | 'editHyperlinkText' | 'editHyperlinkHref'\n>\n\nexport function editCommands(deps: EditCommandsDeps): EditFamily {\n const base = { markName: deps.markName, urls: deps.urls, validate: deps.validate }\n return {\n editHyperlink: (attrs) => editHyperlinkCommand({ ...attrs, ...base }),\n editHyperlinkText: (newText) => editHyperlinkCommand({ newText, ...base }),\n editHyperlinkHref: (newURL) => editHyperlinkCommand({ newURL, ...base })\n }\n}\n\ntype UIFamily = Pick<HyperlinkRawCommands, 'openCreateHyperlinkPopover'>\n\nexport function uiCommands(): UIFamily {\n return {\n // Opening UI is a side effect, so a dry run (`editor.can()`) must report\n // availability without mounting a popover and evicting the open one.\n openCreateHyperlinkPopover:\n (attributes) =>\n ({ editor, dispatch }) =>\n dispatch ? openCreateHyperlink(editor, attributes ?? {}) : true\n }\n}\n","// Hyperlink command façade — composes canonical / edit / UI families\n// over a shared engine + URL Decisions pipeline. The `satisfies` clause\n// in `buildHyperlinkCommands` pins the runtime shape against\n// `HyperlinkPublicCommands` (surface.ts) so adding a public command\n// without implementing it is a compile error.\n\nimport type { HyperlinkOptions } from '../hyperlink'\nimport type { URLDecisions } from '../url-decisions'\nimport { createHyperlinkEngine } from './engine'\nimport { canonicalCommands, editCommands, uiCommands } from './families'\nimport type { HyperlinkRawCommands } from './surface'\n\nexport type {\n EditHyperlinkAttributes,\n HyperlinkPublicCommands,\n SetHyperlinkAttributes\n} from './surface'\n\nexport interface BuildHyperlinkCommandsCtx {\n markName: string\n options: HyperlinkOptions\n urls: URLDecisions\n}\n\n/** Compose every command family into the Tiptap-shaped command map. */\nexport function buildHyperlinkCommands(ctx: BuildHyperlinkCommandsCtx): HyperlinkRawCommands {\n const engine = createHyperlinkEngine({ markName: ctx.markName, urls: ctx.urls })\n return {\n ...canonicalCommands(engine),\n ...editCommands({ markName: ctx.markName, urls: ctx.urls, validate: ctx.options.validate }),\n ...uiCommands()\n } satisfies HyperlinkRawCommands\n}\n","// Autolink interaction — bare URL text becomes a hyperlink mark\n// when the user types whitespace; marks whose text was mutated past\n// recognition get stripped.\n\nimport {\n combineTransactionSteps,\n findChildrenInRange,\n getChangedRanges,\n getMarksBetween,\n type NodeWithPos\n} from '@tiptap/core'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\n\nimport { PREVENT_AUTOLINK_META } from '../constants'\nimport type { LinkContext } from './types'\n\nconst TRAILING_WHITESPACE_RE = /\\s$/\nconst IMAGE_MARKDOWN_CONTEXT_CHARS = 15\n\n// `\\s+` (not `' '`) is required so NBSP / narrow NBSP / tab / ideographic-space\n// also fire the autolink boundary that the user expects.\nconst tokenizeWords = (text: string): string[] => text.split(/\\s+/).filter((s) => s !== '')\n\nexport function createAutolinkInteraction(ctx: LinkContext): Plugin {\n const { urls, type } = ctx\n return new Plugin({\n key: new PluginKey('hyperlinkAutolink'),\n appendTransaction: (transactions, oldState, newState) => {\n const docChanges =\n transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc)\n const shouldSkipAutolink = transactions.some((transaction) =>\n transaction.getMeta(PREVENT_AUTOLINK_META)\n )\n\n if (!docChanges || shouldSkipAutolink) {\n return\n }\n\n const { tr } = newState\n const transform = combineTransactionSteps(oldState.doc, [...transactions])\n const { mapping } = transform\n const changes = getChangedRanges(transform)\n // `?? null` keeps the plugin working in schemas without a `code` mark.\n const codeMarkType = newState.schema.marks.code ?? null\n\n for (const { oldRange, newRange } of changes) {\n for (const oldMark of getMarksBetween(oldRange.from, oldRange.to, oldState.doc).filter(\n (item) => item.mark.type === type\n )) {\n const newFrom = mapping.map(oldMark.from)\n const newTo = mapping.map(oldMark.to)\n const newMarks = getMarksBetween(newFrom, newTo, newState.doc).filter(\n (item) => item.mark.type === type\n )\n\n if (!newMarks.length) continue\n\n const newMark = newMarks[0]\n const oldLinkText = oldState.doc.textBetween(oldMark.from, oldMark.to, undefined, ' ')\n const newLinkText = newState.doc.textBetween(newMark.from, newMark.to, undefined, ' ')\n // `detect` (no gating) so a tightened `isAllowedUri` can't retroactively strip valid marks.\n const wasLink = urls.detect(oldLinkText)\n const isLink = urls.detect(newLinkText)\n\n if (wasLink && !isLink) {\n tr.removeMark(newMark.from, newMark.to, type)\n }\n }\n\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 textBlock = nodesInChangedRanges[0]\n textBeforeWhitespace = newState.doc.textBetween(\n textBlock.pos,\n textBlock.pos + textBlock.node.nodeSize,\n undefined,\n ' '\n )\n } else if (\n nodesInChangedRanges.length &&\n TRAILING_WHITESPACE_RE.test(\n newState.doc.textBetween(newRange.from, newRange.to, ' ', ' ')\n )\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) continue\n\n const wordsBeforeWhitespace = tokenizeWords(textBeforeWhitespace)\n if (!wordsBeforeWhitespace.length) continue\n\n const lastWordBeforeSpace = wordsBeforeWhitespace[wordsBeforeWhitespace.length - 1]\n const lastWordAndBlockOffset =\n textBlock.pos + textBeforeWhitespace.lastIndexOf(lastWordBeforeSpace)\n\n // The image-markdown and code-mark filters below are document-context, not URL gates — they stay local.\n urls\n .forWrite({ kind: 'text', text: lastWordBeforeSpace })\n .map((result) => ({\n href: result.href,\n from: lastWordAndBlockOffset + result.start + 1,\n to: lastWordAndBlockOffset + result.end + 1\n }))\n .filter(({ from }) => {\n const contextStart = Math.max(0, from - IMAGE_MARKDOWN_CONTEXT_CHARS)\n const beforeLink = newState.doc.textBetween(contextStart, from, ' ', ' ')\n const isInsideImageMarkdown = beforeLink.includes('![') && beforeLink.endsWith('](')\n return !isInsideImageMarkdown\n })\n // Skip ranges already inside an inline `code` mark — matches `@tiptap/extension-link` v3.\n .filter(({ from }) => {\n if (!codeMarkType) return true\n const node = newState.doc.nodeAt(from)\n return !node?.marks.some((m) => m.type === codeMarkType)\n })\n .forEach(({ from, to, href }) => {\n tr.addMark(from, to, type.create({ href }))\n })\n }\n\n if (!tr.steps.length) {\n return\n }\n\n return tr\n }\n })\n}\n","// Pointer interaction — owns every click/touch surface that opens\n// the preview popover or routes navigation through the safety gate\n// (mousedown swallow, click-to-popover, middle-click new-tab,\n// touchend-to-popover).\n\nimport { getMarkRange } from '@tiptap/core'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport type { EditorView } from '@tiptap/pm/view'\n\nimport { SAFE_WINDOW_FEATURES } from '../constants'\nimport { getDefaultController } from '../floating-popover'\nimport { buildPreviewOptionsFromAnchor } from '../openers/buildPreviewOptionsFromAnchor'\nimport { openPreviewHyperlink } from '../openers/openPreviewHyperlink'\nimport type { LinkContext } from './types'\n\nfunction findLinkFromEvent(\n event: MouseEvent | TouchEvent,\n root: HTMLElement\n): HTMLAnchorElement | null {\n const target = event.target as HTMLElement | null\n if (!target) return null\n\n const link = target.closest<HTMLAnchorElement>('a')\n if (!link || !root.contains(link)) return null\n\n return link\n}\n\n/** Single navigation gate for every surface (readonly window.open, middle-click). */\nfunction isNavigable(href: string | null | undefined, ctx: LinkContext): href is string {\n return ctx.urls.forRead(href).navigable\n}\n\n// `null` from the popover slot is the host opt-out signal (mobile bottom\n// sheet). With no slot configured at all, a read-only editor falls back to\n// a gated `window.open`.\nfunction openPreviewPopoverFromClick(\n view: EditorView,\n link: HTMLAnchorElement,\n ctx: LinkContext,\n clickPos: number | undefined\n): boolean {\n const opts = buildPreviewOptionsFromAnchor({\n editor: ctx.editor,\n link,\n validate: ctx.validate,\n // Synthesize from `forRead` so the popover's \"Open\" honours the same composed gate as click/aux.\n isAllowedUri: (uri: string) => ctx.urls.forRead(uri).navigable\n })\n // Use the stored attr; `link.href` resolves against `document.baseURI` and would leak the host origin.\n const href = opts.attrs.href ?? link.getAttribute('href')\n // `||` not `??` — `link.target` is `''` when unset, and we want `_blank` (matches auxclick + intent).\n const targetAttr = link.target || opts.attrs.target || '_blank'\n\n if (!ctx.previewPopover) {\n if (!view.editable && isNavigable(href, ctx)) {\n window.open(href, targetAttr, SAFE_WINDOW_FEATURES)\n }\n return !view.editable\n }\n\n if (!href) {\n getDefaultController().close()\n return true\n }\n\n // Route through the canonical opener (slot resolution + `'preview'` adopt).\n // Caret placement is gated on a successful mount: focusing the editor on\n // host opt-out scrolls the contenteditable into view on iOS Safari.\n const mounted = openPreviewHyperlink(opts)\n\n if (!mounted) return true\n\n if (clickPos !== undefined) {\n const { from, to } = view.state.selection\n // `enableClickSelection` expands caret-into-link to the full mark range; read-only\n // editors bypass this (mutating selection there would surprise selection-driven UIs).\n if (ctx.options.enableClickSelection && view.editable && from === to) {\n const range = getMarkRange(view.state.doc.resolve(clickPos), ctx.type)\n if (range) {\n ctx.editor.chain().focus(clickPos).setTextSelection(range).run()\n } else {\n ctx.editor\n .chain()\n .focus(clickPos === 0 ? 'start' : clickPos)\n .run()\n }\n } else {\n // A non-empty selection survives the click (capture-phase mousedown is swallowed),\n // so restore the selection only when it overlaps the clicked link. Otherwise\n // edit/remove would target a stale range somewhere else in the document.\n const clickedRange = getMarkRange(view.state.doc.resolve(clickPos), ctx.type)\n const overlaps = !!clickedRange && from < clickedRange.to && to > clickedRange.from\n const pos = from === to || !overlaps ? clickPos : { from, to }\n ctx.editor\n .chain()\n .focus(clickPos === 0 ? 'start' : clickPos)\n .setTextSelection(pos)\n .run()\n }\n }\n\n return true\n}\n\nexport function createClickHandlerInteraction(ctx: LinkContext): Plugin {\n return new Plugin({\n key: new PluginKey('hyperlinkClickHandler'),\n\n // Three capture-phase listeners (mousedown / click / auxclick) intercept\n // ProseMirror's default link-handling. The listeners own the click semantics,\n // prevent default navigation (tabnabbing, `javascript:`), and route\n // middle-click through the navigation gate.\n view(editorView) {\n const preventMouseDown = (event: MouseEvent) => {\n if (event.button !== 0) return\n const link = findLinkFromEvent(event, editorView.dom)\n if (!link) return\n event.preventDefault()\n event.stopPropagation()\n }\n\n const preventClick = (event: MouseEvent) => {\n if (event.button !== 0) return\n const link = findLinkFromEvent(event, editorView.dom)\n if (link) event.preventDefault()\n }\n\n const handleAuxClick = (event: MouseEvent) => {\n // Middle-button only (button === 2 = right; let the native context menu fire).\n if (event.button !== 1) return\n const link = findLinkFromEvent(event, editorView.dom)\n if (!link) return\n event.preventDefault()\n event.stopPropagation()\n const { attrs } = buildPreviewOptionsFromAnchor({ editor: ctx.editor, link })\n const href = attrs.href ?? link.getAttribute('href')\n if (isNavigable(href, ctx)) {\n window.open(href, '_blank', SAFE_WINDOW_FEATURES)\n }\n }\n\n editorView.dom.addEventListener('mousedown', preventMouseDown, true)\n editorView.dom.addEventListener('click', preventClick, true)\n editorView.dom.addEventListener('auxclick', handleAuxClick, true)\n return {\n destroy() {\n editorView.dom.removeEventListener('mousedown', preventMouseDown, true)\n editorView.dom.removeEventListener('click', preventClick, true)\n editorView.dom.removeEventListener('auxclick', handleAuxClick, true)\n }\n }\n },\n\n props: {\n handleDOMEvents: {\n touchend: (view: EditorView, event: TouchEvent) => {\n const link = findLinkFromEvent(event, view.dom)\n if (!link) return false\n\n event.preventDefault()\n const { clientX, clientY } = event.changedTouches[0]\n const pos = view.posAtCoords({ left: clientX, top: clientY })\n return openPreviewPopoverFromClick(view, link, ctx, pos?.pos)\n },\n\n click: (view: EditorView, event: MouseEvent) => {\n if (event.button !== 0) return false\n\n const link = findLinkFromEvent(event, view.dom)\n if (!link) return false\n\n event.preventDefault()\n const pos = view.posAtCoords({ left: event.clientX, top: event.clientY })\n return openPreviewPopoverFromClick(view, link, ctx, pos?.pos)\n }\n }\n }\n })\n}\n","import type { Editor } from '@tiptap/core'\n\n/** Best-effort recovery for anchors ProseMirror replaced during a popover transition. */\nexport function findLiveEquivalentAnchor(\n editor: Editor,\n link: HTMLAnchorElement,\n nodePos?: number\n): HTMLAnchorElement | null {\n if (link.isConnected) return link\n if (typeof nodePos === 'number') {\n try {\n const { node } = editor.view.domAtPos(nodePos)\n const element = 'closest' in node ? (node as Element) : node.parentElement\n const anchor = element?.closest<HTMLAnchorElement>('a')\n if (anchor && editor.view.dom.contains(anchor)) return anchor\n } catch {\n // Fall through to href+text recovery below.\n }\n }\n\n const href = link.getAttribute('href')\n const text = link.textContent\n const links = Array.from(editor.view.dom.querySelectorAll<HTMLAnchorElement>('a'))\n return (\n links.find(\n (candidate) => candidate.getAttribute('href') === href && candidate.textContent === text\n ) ?? null\n )\n}\n","import type { Editor } from '@tiptap/core'\n\nimport { HYPERLINK_MARK_NAME } from '../constants'\nimport type { PreviewHyperlinkOptions } from '../hyperlink'\nimport { findLiveEquivalentAnchor } from './liveAnchor'\n\nexport interface BuildPreviewOptionsFromAnchorArgs {\n editor: Editor\n link: HTMLAnchorElement\n /** Prefer this ProseMirror position before falling back to DOM similarity. */\n nodePos?: number\n /** Forwarded onto the returned options; usually the configured `validate` option. */\n validate?: (url: string) => boolean\n /** Preserve the host's composed navigation gate when rebuilding preview from edit/back. */\n isAllowedUri?: (uri: string) => boolean\n /** Mark name to look up; defaults to `'hyperlink'`. Override only if the schema mark was renamed. */\n markName?: string\n}\n\n/**\n * Exists so the edit popover's Back button and BYO `editHyperlink` factories\n * share one `posAtDOM → mark.attrs` lookup. The DOM `link.href` property is\n * never the raw-href fallback — it resolves relative hrefs against\n * `document.baseURI`, leaking the host origin into a stored attribute.\n */\nexport function buildPreviewOptionsFromAnchor({\n editor,\n link,\n nodePos: preferredNodePos,\n validate,\n isAllowedUri,\n markName = HYPERLINK_MARK_NAME\n}: BuildPreviewOptionsFromAnchorArgs): PreviewHyperlinkOptions {\n const view = editor.view\n const liveLink = findLiveEquivalentAnchor(editor, link, preferredNodePos) ?? link\n let nodePos = preferredNodePos ?? -1\n let node: ReturnType<typeof view.state.doc.nodeAt> | null = null\n try {\n nodePos = view.posAtDOM(liveLink, 0)\n if (nodePos >= 0) node = view.state.doc.nodeAt(nodePos)\n } catch {\n node = null\n }\n const mark = node?.marks.find((m) => m.type.name === markName)\n const attrs = (mark?.attrs ?? {\n href: liveLink.getAttribute('href'),\n target: null,\n rel: null,\n class: null,\n title: null,\n image: null\n }) as PreviewHyperlinkOptions['attrs']\n return { editor, link: liveLink, nodePos, attrs, validate, isAllowedUri }\n}\n","import { HYPERLINK_MARK_NAME } from '../constants'\nimport { getDefaultController } from '../floating-popover'\nimport type { EditHyperlinkOptions } from '../hyperlink'\nimport { buildPreviewOptionsFromAnchor } from '../openers/buildPreviewOptionsFromAnchor'\nimport { openPreviewHyperlink } from '../openers/openPreviewHyperlink'\nimport { createHTMLElement, validateURL } from '../utils'\nimport { Link, Title } from '../utils/icons'\n\nexport default function editHyperlinkPopover(options: EditHyperlinkOptions): HTMLElement {\n const { editor, link, validate } = options\n\n const form = createHTMLElement('form', { className: 'hyperlink-edit-popover' })\n const inputsWrapper = createHTMLElement('div', { className: 'inputs-wrapper' })\n const buttonsWrapper = createHTMLElement('div', { className: 'buttons-wrapper' })\n\n const textWrapper = createHTMLElement('div', { className: 'text-wrapper' })\n const titleIcon = createHTMLElement('div', {\n className: 'search-icon',\n innerHTML: Title({ size: 24 })\n })\n const linkTextInput = createHTMLElement('input', {\n type: 'text',\n value: link.innerText || '',\n placeholder: 'Enter link text'\n })\n const textError = createHTMLElement('div', {\n className: 'error-message',\n textContent: 'Please enter link text'\n })\n\n const hrefWrapper = createHTMLElement('div', { className: 'href-wrapper' })\n const anchorIcon = createHTMLElement('div', {\n className: 'search-icon',\n innerHTML: Link({ size: 24 })\n })\n const hrefInput = createHTMLElement('input', {\n type: 'text',\n inputMode: 'url',\n value: link.getAttribute('href') ?? '',\n placeholder: 'Enter URL',\n autocomplete: 'new-password',\n spellcheck: false\n })\n const hrefError = createHTMLElement('div', {\n className: 'error-message',\n textContent: 'Please enter a valid URL'\n })\n\n const backButton = createHTMLElement('button', {\n type: 'button',\n textContent: 'Back',\n className: 'back-button'\n })\n const applyButton = createHTMLElement('button', {\n type: 'submit',\n textContent: 'Apply',\n className: 'apply-button'\n })\n\n const showError = (wrapper: HTMLElement, errorEl: HTMLElement) => {\n wrapper.classList.add('error')\n errorEl.classList.add('show')\n }\n const hideError = (wrapper: HTMLElement, errorEl: HTMLElement) => {\n wrapper.classList.remove('error')\n errorEl.classList.remove('show')\n }\n\n linkTextInput.addEventListener('input', () => hideError(textWrapper, textError))\n hrefInput.addEventListener('input', () => hideError(hrefWrapper, hrefError))\n\n // Mirror the create popover: Escape dismisses AND hands focus back to\n // the editor (the shell's own Escape handler only hides the popover).\n form.addEventListener('keydown', (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n getDefaultController().close()\n editor.commands.focus()\n }\n })\n\n // Back button — re-opens the preview popover for this popover's own\n // options. `onBack` is an opt-in escape hatch (e.g. mobile sheet).\n backButton.addEventListener('click', () => {\n if (options.onBack) {\n options.onBack()\n return\n }\n openPreviewHyperlink(\n buildPreviewOptionsFromAnchor({\n editor,\n link,\n validate,\n isAllowedUri: options.isAllowedUri,\n nodePos: options.nodePos,\n markName: options.markName\n })\n )\n })\n\n form.addEventListener('submit', (e) => {\n e.preventDefault()\n const newText = linkTextInput.value.trim()\n const newHref = hrefInput.value.trim()\n let hasErrors = false\n if (!newText) {\n showError(textWrapper, textError)\n hasErrors = true\n }\n if (!validateURL(newHref, { customValidator: validate })) {\n showError(hrefWrapper, hrefError)\n hasErrors = true\n }\n if (hasErrors) return\n\n // `editHyperlink` returns `false` on two paths. First, the URL fails the\n // composed XSS + `isAllowedUri` gate (inline error, popover stays open).\n // Second, the mark is gone at the stored selection (e.g. a collab peer removed\n // the link). Then there is nothing left to edit, so close instead of blaming the URL.\n const markName = options.markName ?? HYPERLINK_MARK_NAME\n const ok = editor\n .chain()\n .focus()\n .extendMarkRange(markName)\n .editHyperlink({ newURL: newHref, newText })\n .run()\n if (!ok) {\n if (!editor.isActive(markName)) {\n getDefaultController().close()\n return\n }\n showError(hrefWrapper, hrefError)\n return\n }\n\n getDefaultController().close()\n })\n\n textWrapper.append(titleIcon, linkTextInput, textError)\n hrefWrapper.append(anchorIcon, hrefInput, hrefError)\n inputsWrapper.append(textWrapper, hrefWrapper)\n buttonsWrapper.append(backButton, applyButton)\n form.append(inputsWrapper, buttonsWrapper)\n\n // Auto-focus the text input on first show. Caller (the opener) is\n // responsible for `popover.show()`; we don't know when that is here.\n queueMicrotask(() => linkTextInput.focus())\n\n return form\n}\n","import { hideTooltip } from '@docs.plus/floating-tooltip'\n\nimport { OFFSCREEN_COORD_PX } from '../constants'\nimport { createPopover, getDefaultController } from '../floating-popover'\nimport type { EditHyperlinkOptions } from '../hyperlink'\nimport editHyperlinkPopover from '../popovers/editHyperlinkPopover'\nimport { getHyperlinkOptions } from './getHyperlinkOptions'\nimport { findLiveEquivalentAnchor } from './liveAnchor'\nimport { setActivePopoverOwner } from './popoverOwnership'\n\n/**\n * Open the edit popover anchored to a hyperlink. The prebuilt popover's\n * Back button closes over `opts`, so no extra wiring is needed to\n * return to the preview.\n */\nexport function openEditHyperlink(opts: EditHyperlinkOptions): void {\n const { editor } = opts\n const { popovers } = getHyperlinkOptions(editor, 'openEditHyperlink')\n const factory = popovers.editHyperlink ?? editHyperlinkPopover\n const content = factory(opts)\n if (!content) return\n let referenceLink = findLiveEquivalentAnchor(editor, opts.link, opts.nodePos)\n let hideQueued = false\n const popover = createPopover({\n coordinates: {\n getBoundingClientRect: () => {\n referenceLink = referenceLink\n ? findLiveEquivalentAnchor(editor, referenceLink, opts.nodePos)\n : null\n if (!referenceLink) {\n if (!hideQueued) {\n hideQueued = true\n queueMicrotask(() => popover.hide())\n }\n return { x: OFFSCREEN_COORD_PX, y: OFFSCREEN_COORD_PX, width: 0, height: 0 }\n }\n const rect = referenceLink.getBoundingClientRect()\n return { x: rect.left, y: rect.top, width: rect.width, height: rect.height }\n },\n contextElement: editor.view.dom\n },\n content,\n placement: 'bottom',\n showArrow: true,\n role: 'dialog',\n ariaLabel: 'Edit link',\n // No prebuilt icon buttons here, but BYO content can attach tooltips —\n // the orphan guard is a property of the surface, not of its content.\n onHide: hideTooltip\n })\n getDefaultController().adopt(popover, 'edit', {\n element: popover.element,\n referenceElement: null\n })\n setActivePopoverOwner(editor, popover)\n popover.show()\n}\n","import { attachTooltip } from '@docs.plus/floating-tooltip'\n\nimport { SAFE_WINDOW_FEATURES } from '../constants'\nimport { getDefaultController } from '../floating-popover'\nimport type { PreviewHyperlinkOptions } from '../hyperlink'\nimport { openEditHyperlink } from '../openers/openEditHyperlink'\nimport { Copy, copyToClipboard, createHTMLElement, isSafeHref, LinkOff, Pencil } from '../utils'\n\n// Icon-only action button: explicit `type` (the popover lives outside any\n// form, but defaults are surprising). The floating tooltip replaces the\n// native `title` — keeping both would show two labels at once.\nconst iconButton = (className: string, label: string, icon: string): HTMLButtonElement => {\n const button = createHTMLElement('button', {\n type: 'button',\n className,\n innerHTML: icon\n })\n button.setAttribute('aria-label', label)\n attachTooltip(button, label)\n return button\n}\n\nexport default function previewHyperlinkPopover(options: PreviewHyperlinkOptions): HTMLElement {\n const { link, editor } = options\n // `attrs.href` is the only gate-validated source — DOM `link.href`\n // resolves relative hrefs against `document.baseURI` (origin leak) and\n // `getAttribute` returns whatever raw value escaped validation.\n const href = options.attrs.href ?? ''\n // Blank unsafe schemes on render (mirrors `renderHTML`): a middle-click\n // on the rendered anchor would bypass the JS click guard otherwise.\n // `innerText` stays honest so the user sees what was stored.\n const safeHref = isSafeHref(href) ? href : ''\n // Composed `isAllowedUri` policy for JS-driven navigation; falls back to\n // `isSafeHref` when mounted outside the click-handler plugin (BYO factory).\n const isOpenable = options.isAllowedUri ?? isSafeHref\n\n const root = createHTMLElement('div', { className: 'hyperlink-preview-popover' })\n const removeButton = iconButton('remove', 'Remove link', LinkOff())\n const copyButton = iconButton('copy', 'Copy link', Copy())\n const editButton = iconButton('edit', 'Edit link', Pencil())\n\n // `noopener noreferrer` matches the Hyperlink default `HTMLAttributes` and is\n // the belt to the click-handler's braces. If JS ever fails to attach\n // (CSP, host strips listeners, factory throws), the browser's default\n // `target=\"_blank\"` navigation still cannot reach `window.opener`.\n const hrefAnchor = createHTMLElement('a', {\n target: '_blank',\n rel: 'noopener noreferrer',\n href: safeHref,\n innerText: href\n })\n\n hrefAnchor.addEventListener('click', (event) => {\n event.preventDefault()\n if (safeHref && isOpenable(safeHref)) {\n window.open(safeHref, '_blank', SAFE_WINDOW_FEATURES)\n }\n })\n\n removeButton.addEventListener('click', () => {\n getDefaultController().close()\n editor.chain().focus().unsetHyperlink().run()\n })\n\n editButton.addEventListener('click', () => {\n // Route through the canonical opener so slot resolution stays in one\n // place. The prebuilt edit popover's Back closes over these options\n // and re-opens the preview itself, so no `onBack` override is needed.\n openEditHyperlink({\n editor,\n link,\n nodePos: options.nodePos,\n validate: options.validate,\n isAllowedUri: options.isAllowedUri\n })\n })\n\n copyButton.addEventListener('click', () => {\n copyToClipboard(href, (success) => {\n if (success) getDefaultController().close()\n })\n })\n\n root.append(hrefAnchor, copyButton, editButton, removeButton)\n return root\n}\n","import { hideTooltip } from '@docs.plus/floating-tooltip'\n\nimport { createPopover, getDefaultController } from '../floating-popover'\nimport type { PreviewHyperlinkOptions } from '../hyperlink'\nimport previewHyperlinkPopover from '../popovers/previewHyperlinkPopover'\nimport { getHyperlinkOptions } from './getHyperlinkOptions'\nimport { setActivePopoverOwner } from './popoverOwnership'\n\n/**\n * Returns `false` when the host opted out (factory returned `null`, e.g. a\n * mobile bottom sheet). The click handler gates caret placement on it —\n * `.focus()` on an opting-out host makes iOS Safari scroll the editor.\n */\nexport function openPreviewHyperlink(opts: PreviewHyperlinkOptions): boolean {\n const { editor } = opts\n const { popovers } = getHyperlinkOptions(editor, 'openPreviewHyperlink')\n const factory = popovers.previewHyperlink ?? previewHyperlinkPopover\n const content = factory(opts)\n if (!content) return false\n\n const popover = createPopover({\n referenceElement: opts.link,\n content,\n placement: 'bottom',\n showArrow: true,\n role: 'toolbar',\n // Outside-click teardown removes the icon buttons without a mouseleave —\n // the shared tooltip must die with the surface or it lingers on screen.\n onHide: hideTooltip\n })\n getDefaultController().adopt(popover, 'preview', {\n element: popover.element,\n referenceElement: opts.link\n })\n setActivePopoverOwner(editor, popover)\n popover.show()\n return true\n}\n","// Markdown link input rule — `[text](url)` at the cursor becomes a\n// hyperlink mark over `text` with `url` (post-gate) as href.\n\nimport { InputRule } from '@tiptap/core'\n\nimport type { LinkContext } from './types'\n\nconst MARKDOWN_LINK_RE = /(\\[([^\\]]+)\\]\\(([^)]+)\\))$/\n\nexport function createMarkdownLinkInputRule(ctx: LinkContext): InputRule {\n return new InputRule({\n find: MARKDOWN_LINK_RE,\n handler: ({ state, range, match }) => {\n const [, , linkText, url] = match\n const { tr } = state\n const start = range.from\n const end = range.to\n\n // Gate fails → leave the markdown literal as typed (so `[x](javascript:…)` doesn't silently disappear).\n const [decision] = ctx.urls.forWrite({ kind: 'href', href: url })\n if (!decision) return\n\n // `nodeAt(start)`, not `resolve(start).marks()` — the latter reads the node\n // BEFORE the position and misses a mark toggled on at the `[`.\n const carried = state.doc.nodeAt(start)?.marks.filter((m) => m.type !== ctx.type) ?? []\n tr.replaceWith(start, end, state.schema.text(linkText, carried))\n tr.addMark(start, start + linkText.length, ctx.type.create({ href: decision.href }))\n }\n })\n}\n","// Paste-over-selection — pasting a single URL with a non-empty\n// selection wraps the selection in a hyperlink mark instead of\n// replacing it.\n\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { find } from 'linkifyjs'\n\nimport type { LinkContext } from './types'\n\nexport function createPasteHandlerInteraction(ctx: LinkContext): Plugin {\n return new Plugin({\n key: new PluginKey('hyperlinkPasteHandler'),\n props: {\n handlePaste: (view, _event, slice) => {\n const { selection } = view.state\n if (selection.empty) return false\n\n let textContent = ''\n slice.content.forEach((node) => {\n textContent += node.textContent\n })\n\n // Historical contract: only fire when the clipboard IS one URL, not when it merely contains one.\n const link = find(textContent).find((item) => item.isLink && item.value === textContent)\n if (!textContent || !link) return false\n\n const [decision] = ctx.urls.forWrite({ kind: 'match', match: link })\n if (!decision) return false\n\n return ctx.editor.chain().setHyperlink({ href: decision.href }).run()\n }\n }\n })\n}\n","// Linkify paste mark rule — auto-marks bare URLs found anywhere\n// inside pasted text. Distinct from `pasteHandler` (paste-over-selection):\n// this fires for plain paste-into-doc.\n\nimport { markPasteRule, type PasteRule } from '@tiptap/core'\nimport { find } from 'linkifyjs'\n\nimport type { LinkContext } from './types'\n\nexport function createLinkifyPasteRule(ctx: LinkContext): PasteRule {\n return markPasteRule({\n // Detection stays linkify-only (historical behaviour); the gate stack still runs via `forWrite('match')`.\n find: (text) =>\n find(text)\n .filter((link) => link.isLink)\n .flatMap((link) => {\n const [decision] = ctx.urls.forWrite({ kind: 'match', match: link })\n if (!decision) return []\n return [{ text: link.value, index: link.start, data: { href: decision.href } }]\n }),\n type: ctx.type,\n getAttributes: (match) => ({\n href: (match.data as { href: string }).href\n })\n })\n}\n","// Factory for `LinkContext` — the dependency bag every interaction\n// consumes. One seam, so input rule, paste rule, autolink, paste\n// handler, and click handler all share the same URL Decisions stack.\n\nimport type { Editor } from '@tiptap/core'\nimport type { MarkType } from '@tiptap/pm/model'\n\nimport type { HyperlinkOptions, LinkProtocolOptions } from '../hyperlink'\nimport { composeGate, createURLDecisions, type URLDecisions } from '../url-decisions'\nimport type { LinkContext } from './types'\n\nexport interface CreateLinkContextArgs {\n editor: Editor\n type: MarkType\n options: HyperlinkOptions\n}\n\n/** Build the URL Decisions instance for a hyperlink extension. Prefer `createLinkContext` in production. */\nexport function buildUrlDecisions(options: HyperlinkOptions): URLDecisions {\n return createURLDecisions({\n defaultProtocol: options.defaultProtocol,\n gate: composeGate<LinkProtocolOptions | string>({\n isAllowedUri: options.isAllowedUri,\n protocols: options.protocols,\n defaultProtocol: options.defaultProtocol\n }),\n validate: options.validate,\n shouldAutoLink: options.shouldAutoLink\n })\n}\n\nexport function createLinkContext({ editor, type, options }: CreateLinkContextArgs): LinkContext {\n return {\n type,\n editor,\n urls: buildUrlDecisions(options),\n options,\n validate: options.validate,\n previewPopover: options.popovers.previewHyperlink ?? null\n }\n}\n","// Interactions barrel — single composition point for everything the\n// extension binds into ProseMirror's lifecycle (input rules + paste\n// rules + plugins). All rules and plugins share one `LinkContext`\n// (so one URL Decisions instance, one options view).\n\nimport type { InputRule, PasteRule } from '@tiptap/core'\nimport type { Plugin } from '@tiptap/pm/state'\n\nimport { createAutolinkInteraction } from './autolink'\nimport { createClickHandlerInteraction } from './clickHandler'\nimport { createMarkdownLinkInputRule } from './inputRule'\nimport { createPasteHandlerInteraction } from './pasteHandler'\nimport { createLinkifyPasteRule } from './pasteRule'\nimport type { LinkContext } from './types'\n\nexport { createLinkContext } from './createLinkContext'\nexport type { LinkContext } from './types'\n\nexport interface HyperlinkInteractions {\n inputRules: InputRule[]\n pasteRules: PasteRule[]\n plugins: Plugin[]\n}\n\n/** Build every interaction from a single context; plugin gating (`autolink`, `openOnClick`, `linkOnPaste`) lives here. */\nexport function createInteractions(ctx: LinkContext): HyperlinkInteractions {\n const plugins: Plugin[] = []\n if (ctx.options.autolink) plugins.push(createAutolinkInteraction(ctx))\n if (ctx.options.openOnClick) plugins.push(createClickHandlerInteraction(ctx))\n if (ctx.options.linkOnPaste) plugins.push(createPasteHandlerInteraction(ctx))\n\n return {\n inputRules: [createMarkdownLinkInputRule(ctx)],\n pasteRules: [createLinkifyPasteRule(ctx)],\n plugins\n }\n}\n"],"mappings":"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","names":["index_exports","__export","Copy","DANGEROUS_SCHEME_RE","z","Hyperlink","LinkOff","Pencil","SAFE_WINDOW_FEATURES","a","buildPreviewOptionsFromAnchor","copyToClipboard","createHTMLElement","createHyperlinkPopover","ve","index_default","editHyperlinkPopover","O","getSpecialUrlInfo","n","isSafeHref","normalizeHref","openCreateHyperlink","openEditHyperlink","openPreviewHyperlink","previewHyperlinkPopover","validateURL","__toCommonJS","import_core","import_linkifyjs","HYPERLINK_MARK_NAME","PREVENT_AUTOLINK_META","SAFE_WINDOW_FEATURES","createHyperlinkEngine","markName","urls","apply","attrs","commands","tr","dispatch","decision","ok","PREVENT_AUTOLINK_META","remove","props","import_dom","SHOW_DELAY_MS","VISIBLE_CLASS","bubble","showTimer","ensureBubble","cancelShow","show","target","label","el","x","y","computePosition","offset","flip","shift","hideTooltip","attachTooltip","schedule","scheduleOnFocus","import_dom","createPopoverController","current","listeners","snapshot","notify","state","listener","popover","kind","metadata","previous","referenceElement","coordinates","defaultController","getDefaultController","DEFAULT_OFFSET","DEFAULT_Z_INDEX","SHIFT_PADDING","ARROW_STATIC_OFFSET","OUTSIDE_CLICK_DEFER_MS","EXIT_FALLBACK_MS","ORIGIN_BY_SIDE","createVirtualReference","coords","x","y","width","height","setupKeyboardNav","container","focusable","removers","el","i","onKeydown","e","next","createPopover","options","controller","getDefaultController","referenceElement","coordinates","content","placement","offsetVal","showArrow","className","zIndex","role","ariaLabel","ignoreOutsideClickOn","crossAxisShift","onShow","onHide","reference","outsideIgnore","cleanups","visible","terminated","autoUpdateCleanup","isOutsideDismissTarget","target","root","arrowEl","contentContainer","navListeners","clearNavListeners","setContent","updatePosition","middleware","offset","flip","shift","arrow","hideMiddleware","actual","middlewareData","computePosition","side","ax","ay","staticSide","unregister","removalTimer","onExitEnd","cancelPendingRemoval","finishHide","hide","fn","popover","autoUpdate","onMouseDown","onTouchStart","onKeyDown","ref","PREFIX","logger","args","copyToClipboard","text","callback","textArea","ok","logger","error","createHTMLElement","type","props","element","Copy","size","fill","LinkOff","Link","Pencil","Title","import_linkifyjs","PHONE_SHAPE_RE","NON_DIGIT_RE","isBarePhone","trimmed","digits","SCHEME_RE","RELATIVE_REF_RE","hasRealScheme","raw","m","candidate","isBareEmail","trimmed","matches","only","DEFAULT_PROTOCOL","normalizeHref","defaultProtocol","phone","isBarePhone","email","normalizeLinkifyHref","link","COMMUNICATION_URLS","SOCIAL_URLS","MEETING_URLS","APPLE_URLS","PRODUCTIVITY_URLS","ENTERTAINMENT_URLS","SHOPPING_URLS","ALL_SPECIAL_URLS","DOMAIN_MAPPINGS","getSpecialUrlInfo","url","lowerUrl","scheme","info","hostname","cleanHostname","domain","import_linkifyjs","DANGEROUS_SCHEME_RE","isSafeHref","href","STANDARD_WEB_SCHEMES","IPV4_RE","isRecognizedSpecialScheme","url","getSpecialUrlInfo","hasPlausibleHost","parsed","host","validateURL","options","trimmed","isBarePhone","validURL","link","isStandardWebScheme","error","logger","getURLScheme","colonIndex","scheme","createHyperlinkElements","prefillHref","root","createHTMLElement","buttonsWrapper","inputsWrapper","form","input","button","errorMessage","searchIcon","Link","setupEventListeners","elements","options","editor","showError","hideError","updateButtonState","hasValue","event","O","url","validateURL","chain","createHyperlinkPopover","getHyperlinkOptions","editor","callerName","ext","e","HYPERLINK_MARK_NAME","owned","unsubscribe","setActivePopoverOwner","editor","popover","watchForRelease","O","state","closeOwnedPopover","controller","INPUT_FOCUS_DELAY_MS","openCreateHyperlink","editor","attributes","options","getHyperlinkOptions","factory","createHyperlinkPopover","popoverOptions","HYPERLINK_MARK_NAME","content","from","to","focusTimer","popover","ve","start","end","input","n","O","setActivePopoverOwner","import_core","import_linkifyjs","SPECIAL_SCHEME_REGEX_GLOBAL","TRAILING_PUNCTUATION_RE","stripTrailingPunctuation","link","tail","len","findLinks","text","links","standardLinks","match","url","start","end","validateURL","phone","isBarePhone","composeGate","opts","defaultProtocol","DEFAULT_PROTOCOL","protocols","userPolicy","href","isSafeHref","createURLDecisions","options","gate","passesAutoGates","validate","veto","input","trimmed","normalizeHref","normalizeLinkifyHref","findLinks","link","r","rawHref","text","l","editHyperlinkCommand","attributes","tr","dispatch","newURL","newText","title","image","validate","markName","HYPERLINK_MARK_NAME","urls","createURLDecisions","validateURL","markType","from","$pos","range","currentMark","m","error","logger","href","decision","currentText","text","newMark","carried","mark","canonicalCommands","engine","editCommands","deps","base","attrs","editHyperlinkCommand","newText","newURL","uiCommands","attributes","editor","dispatch","openCreateHyperlink","buildHyperlinkCommands","ctx","engine","createHyperlinkEngine","canonicalCommands","editCommands","uiCommands","import_core","import_state","TRAILING_WHITESPACE_RE","IMAGE_MARKDOWN_CONTEXT_CHARS","tokenizeWords","text","s","createAutolinkInteraction","ctx","urls","type","transactions","oldState","newState","docChanges","transaction","shouldSkipAutolink","PREVENT_AUTOLINK_META","tr","transform","mapping","changes","codeMarkType","oldRange","newRange","oldMark","item","newFrom","newTo","newMarks","newMark","oldLinkText","newLinkText","wasLink","isLink","nodesInChangedRanges","node","textBlock","textBeforeWhitespace","wordsBeforeWhitespace","lastWordBeforeSpace","lastWordAndBlockOffset","result","from","contextStart","beforeLink","m","to","href","import_core","import_state","findLiveEquivalentAnchor","editor","link","nodePos","node","anchor","href","text","candidate","buildPreviewOptionsFromAnchor","editor","link","preferredNodePos","validate","isAllowedUri","markName","HYPERLINK_MARK_NAME","view","liveLink","findLiveEquivalentAnchor","nodePos","node","attrs","m","editHyperlinkPopover","options","editor","link","validate","form","createHTMLElement","inputsWrapper","buttonsWrapper","textWrapper","titleIcon","Title","linkTextInput","textError","hrefWrapper","anchorIcon","Link","hrefInput","hrefError","backButton","applyButton","showError","wrapper","errorEl","hideError","event","O","openPreviewHyperlink","buildPreviewOptionsFromAnchor","e","newText","newHref","hasErrors","validateURL","markName","HYPERLINK_MARK_NAME","openEditHyperlink","opts","editor","popovers","getHyperlinkOptions","content","editHyperlinkPopover","referenceLink","findLiveEquivalentAnchor","hideQueued","popover","ve","rect","n","O","setActivePopoverOwner","iconButton","className","label","icon","button","createHTMLElement","a","previewHyperlinkPopover","options","link","editor","href","safeHref","isSafeHref","isOpenable","root","removeButton","LinkOff","copyButton","Copy","editButton","Pencil","hrefAnchor","event","SAFE_WINDOW_FEATURES","O","openEditHyperlink","copyToClipboard","success","openPreviewHyperlink","opts","editor","popovers","getHyperlinkOptions","content","previewHyperlinkPopover","popover","ve","n","O","setActivePopoverOwner","findLinkFromEvent","event","root","target","link","isNavigable","href","ctx","openPreviewPopoverFromClick","view","clickPos","opts","buildPreviewOptionsFromAnchor","uri","targetAttr","SAFE_WINDOW_FEATURES","O","openPreviewHyperlink","from","to","range","clickedRange","overlaps","pos","createClickHandlerInteraction","editorView","preventMouseDown","preventClick","handleAuxClick","attrs","clientX","clientY","import_core","MARKDOWN_LINK_RE","createMarkdownLinkInputRule","ctx","state","range","match","linkText","url","tr","start","end","decision","carried","import_state","import_linkifyjs","createPasteHandlerInteraction","ctx","view","_event","slice","selection","textContent","node","link","item","decision","import_core","import_linkifyjs","createLinkifyPasteRule","ctx","text","link","decision","match","buildUrlDecisions","options","createURLDecisions","composeGate","createLinkContext","editor","type","createInteractions","ctx","plugins","createAutolinkInteraction","createClickHandlerInteraction","createPasteHandlerInteraction","createMarkdownLinkInputRule","createLinkifyPasteRule","registeredLinkifyProtocols","registerProtocolOnce","scheme","optionalSlashes","Hyperlink","HYPERLINK_MARK_NAME","token","helpers","href","normalizeHref","isSafeHref","node","_ctx","content","raw","protocol","closeOwnedPopover","DEFAULT_PROTOCOL","HTMLAttributes","safe","buildHyperlinkCommands","getContext","shortcuts","exitMarkOnArrowRight","createInteractions","self","ctx","createLinkContext","editor","type","state","selection","tr","$pos","after","m","import_linkifyjs","index_default","Hyperlink"]}