your personal website on atproto - mirror blento.app
at remove-extra-buttons 125 lines 3.5 kB view raw
1import { InputRule, markInputRule, markPasteRule, PasteRule } from '@tiptap/core'; 2import { Link } from '@tiptap/extension-link'; 3 4import type { LinkOptions } from '@tiptap/extension-link'; 5 6/** 7 * The input regex for Markdown links with title support, and multiple quotation marks (required 8 * in case the `Typography` extension is being included). 9 */ 10const inputRegex = /(?:^|\s)\[([^\]]*)?\]\((\S+)(?: ["“](.+)["”])?\)$/i; 11 12/** 13 * The paste regex for Markdown links with title support, and multiple quotation marks (required 14 * in case the `Typography` extension is being included). 15 */ 16const pasteRegex = /(?:^|\s)\[([^\]]*)?\]\((\S+)(?: ["“](.+)["”])?\)/gi; 17 18/** 19 * Input rule built specifically for the `Link` extension, which ignores the auto-linked URL in 20 * parentheses (e.g., `(https://doist.dev)`). 21 * 22 * @see https://github.com/ueberdosis/tiptap/discussions/1865 23 */ 24function linkInputRule(config: Parameters<typeof markInputRule>[0]) { 25 const defaultMarkInputRule = markInputRule(config); 26 27 return new InputRule({ 28 find: config.find, 29 handler(props) { 30 const { tr } = props.state; 31 32 defaultMarkInputRule.handler(props); 33 tr.setMeta('preventAutolink', true); 34 } 35 }); 36} 37 38/** 39 * Paste rule built specifically for the `Link` extension, which ignores the auto-linked URL in 40 * parentheses (e.g., `(https://doist.dev)`). This extension was inspired from the multiple 41 * implementations found in a Tiptap discussion at GitHub. 42 * 43 * @see https://github.com/ueberdosis/tiptap/discussions/1865 44 */ 45function linkPasteRule(config: Parameters<typeof markPasteRule>[0]) { 46 const defaultMarkPasteRule = markPasteRule(config); 47 48 return new PasteRule({ 49 find: config.find, 50 handler(props) { 51 const { tr } = props.state; 52 53 defaultMarkPasteRule.handler(props); 54 tr.setMeta('preventAutolink', true); 55 } 56 }); 57} 58 59/** 60 * The options available to customize the `RichTextLink` extension. 61 */ 62type RichTextLinkOptions = LinkOptions; 63 64/** 65 * Custom extension that extends the built-in `Link` extension to add additional input/paste rules 66 * for converting the Markdown link syntax (i.e. `[Doist](https://doist.com)`) into links, and also 67 * adds support for the `title` attribute. 68 */ 69const RichTextLink = Link.extend<RichTextLinkOptions>({ 70 inclusive: false, 71 addOptions(): LinkOptions { 72 return { 73 ...this.parent?.(), 74 openOnClick: 'whenNotEditable' 75 } as LinkOptions; 76 }, 77 addAttributes() { 78 return { 79 ...this.parent?.(), 80 title: { 81 default: null 82 } 83 }; 84 }, 85 addInputRules() { 86 return [ 87 linkInputRule({ 88 find: inputRegex, 89 type: this.type, 90 91 // We need to use `pop()` to remove the last capture groups from the match to 92 // satisfy Tiptap's `markPasteRule` expectation of having the content as the last 93 // capture group in the match (this makes the attribute order important) 94 getAttributes(match) { 95 return { 96 title: match.pop()?.trim(), 97 href: match.pop()?.trim() 98 }; 99 } 100 }) 101 ]; 102 }, 103 addPasteRules() { 104 return [ 105 linkPasteRule({ 106 find: pasteRegex, 107 type: this.type, 108 109 // We need to use `pop()` to remove the last capture groups from the match to 110 // satisfy Tiptap's `markInputRule` expectation of having the content as the last 111 // capture group in the match (this makes the attribute order important) 112 getAttributes(match) { 113 return { 114 title: match.pop()?.trim(), 115 href: match.pop()?.trim() 116 }; 117 } 118 }) 119 ]; 120 } 121}); 122 123export { RichTextLink }; 124 125export type { RichTextLinkOptions };