33 * SPDX-License-Identifier: AGPL-3.0-or-later
44 */
55
6+ import type { Editor } from '@tiptap/core'
7+ import type { ResolvedPos } from '@tiptap/pm/model'
8+ import type { Command } from '@tiptap/pm/state'
9+
610import { Plugin , PluginKey } from '@tiptap/pm/state'
711import { isLinkToSelfWithHash } from '../helpers/links.js'
812import LinkBubblePluginView from './LinkBubblePluginView.js'
@@ -12,25 +16,27 @@ import { activeLinkFromSelection } from './linkHelpers.js'
1216
1317/* Set resolved to be the active element (if it has a link mark)
1418 *
15- * @params {ResolvedPos} resolved position of the action
19+ * @params resolved - resolved position of the action
1620 */
17- export const setActiveLink = ( resolved ) => ( state , dispatch ) => {
18- const mark = resolved . marks ( ) . find ( ( m ) => m . type . name === 'link' )
19- if ( ! mark ) {
20- return false
21- }
22- const nodeStart = resolved . pos - resolved . textOffset
23- const active = { mark, nodeStart }
24- if ( dispatch ) {
25- dispatch ( state . tr . setMeta ( linkBubbleKey , { active } ) )
21+ export const setActiveLink =
22+ ( resolved : ResolvedPos ) : Command =>
23+ ( state , dispatch ) => {
24+ const mark = resolved . marks ( ) . find ( ( m ) => m . type . name === 'link' )
25+ if ( ! mark ) {
26+ return false
27+ }
28+ const nodeStart = resolved . pos - resolved . textOffset
29+ const active = { mark, nodeStart }
30+ if ( dispatch ) {
31+ dispatch ( state . tr . setMeta ( linkBubbleKey , { active } ) )
32+ }
33+ return true
2634 }
27- return true
28- }
2935
3036/* Hide the link bubble by setting active state to null
3137 *
3238 */
33- export const hideLinkBubble = ( state , dispatch ) => {
39+ export const hideLinkBubble : Command = ( state , dispatch ) => {
3440 const pluginState = linkBubbleKey . getState ( state )
3541 if ( ! pluginState ?. active ) {
3642 return false
@@ -44,10 +50,12 @@ export const hideLinkBubble = (state, dispatch) => {
4450export const linkBubbleKey = new PluginKey ( 'linkBubble' )
4551/**
4652 * Prosemirror link bubble plugin
47- * @param {object } options - options for the link bubble plugin view
53+ *
54+ * @param options - options for the link bubble plugin view
55+ * @param options.editor - the editor
4856 */
49- export function linkBubble ( options ) {
50- const linkBubblePlugin = new Plugin ( {
57+ export function linkBubble ( options : { editor : Editor } ) {
58+ const linkBubblePlugin : Plugin = new Plugin ( {
5159 key : linkBubbleKey ,
5260 state : {
5361 init : ( ) => ( { active : null } ) ,
@@ -79,7 +87,7 @@ export function linkBubble(options) {
7987 const sameDoc = oldState ?. doc . eq ( state . doc )
8088 // Don't open bubble on changes by other session members
8189 const noHistory = transactions . every (
82- ( tr ) => tr . meta . addToHistory === false ,
90+ ( tr ) => tr . getMeta ( ' addToHistory' ) === false ,
8391 )
8492 if ( sameSelection && ( noHistory || sameDoc ) ) {
8593 return
@@ -137,33 +145,32 @@ export function linkClicking() {
137145 handleDOMEvents : {
138146 // Open link in new tab on middle click
139147 auxclick : ( view , event ) => {
148+ const linkEl = ( event . target as Element | null ) ?. closest ( 'a' )
140149 if (
141- event . target . closest ( 'a' )
150+ linkEl
142151 && event . button === 1
143152 && ! event . ctrlKey
144153 && ! event . metaKey
145154 && ! event . shiftKey
146155 ) {
147156 event . preventDefault ( )
148157 event . stopImmediatePropagation ( )
149-
150- const linkElement = event . target . closest ( 'a' )
151- window . open ( linkElement . href , '_blank' )
158+ window . open ( linkEl . href , '_blank' )
152159 }
153160 } ,
154161 // Prevent paste into links
155162 // On Linux, middle click pastes, which breaks "open in new tab" on middle click
156163 // Pasting into links will break the link anyway, so just disable it altogether.
157164 paste : ( view , event ) => {
158- if ( event . target . closest ( 'a' ) ) {
165+ if ( ( event . target as Element | null ) ? .closest ( 'a' ) ) {
159166 event . stopPropagation ( )
160167 event . preventDefault ( )
161168 event . stopImmediatePropagation ( )
162169 }
163170 } ,
164171 // Prevent open link for text-only links on left click. Required for read-only mode.
165172 click : ( view , event ) => {
166- const linkEl = event . target . closest ( 'a' )
173+ const linkEl = ( event . target as Element | null ) ? .closest ( 'a' )
167174 // Only text-only links need special handling (e.g. don't handle links inside preview or mermaid diagrams)
168175 if (
169176 ! linkEl
@@ -176,9 +183,9 @@ export function linkClicking() {
176183 // Stop browser from opening the link
177184 event . preventDefault ( )
178185
179- if ( isLinkToSelfWithHash ( linkEl . attributes . href ?. value ) ) {
186+ if ( isLinkToSelfWithHash ( linkEl . href ) ) {
180187 // Open anchor links directly
181- location . href = linkEl . attributes . href . value
188+ location . href = linkEl . href
182189 } else if ( event . ctrlKey || event . metaKey ) {
183190 // Open link in new tab on Ctrl/Cmd + left click
184191 window . open ( linkEl . href , '_blank' )
0 commit comments