@@ -186,10 +186,7 @@ export function pasteHandler(options: PasteHandlerOptions): Plugin {
186186 }
187187 : null
188188
189- const unpackedHmId =
190- isHypermediaScheme ( textContent ) || isPublicGatewayLink ( textContent , options . gwUrl )
191- ? unpackHmId ( textContent )
192- : null
189+ const unpackedHmId = getPastedHypermediaId ( textContent , options . gwUrl )
193190
194191 if ( ! selection . empty && options . linkOnPaste ) {
195192 const pastedLink = unpackedHmId
@@ -231,7 +228,13 @@ export function pasteHandler(options: PasteHandlerOptions): Plugin {
231228
232229 // If transformPasted already added a link mark, skip further processing
233230 // unless we have a link that might need special handling (twitter, instagram, video, etc)
234- if ( firstChildIsText && firstChildContainsLinkMark && ! ( link && selection . empty && ! unpackedHmId ) ) {
231+ // or a hypermedia URL that should be canonicalized into an hm:// link.
232+ if (
233+ firstChildIsText &&
234+ firstChildContainsLinkMark &&
235+ ! ( link && selection . empty && ! unpackedHmId ) &&
236+ ! ( selection . empty && unpackedHmId )
237+ ) {
235238 return false
236239 }
237240
@@ -329,6 +332,31 @@ export function pasteHandler(options: PasteHandlerOptions): Plugin {
329332
330333 return true
331334 }
335+
336+ const normalizedHmUrl = packHmId ( hmId ( unpackedHmId . uid , unpackedHmId ) )
337+ view . dispatch (
338+ tr . insertText ( normalizedHmUrl , pos ) . addMark (
339+ pos ,
340+ pos + normalizedHmUrl . length ,
341+ options . editor . schema . mark ( 'link' , {
342+ href : normalizedHmUrl ,
343+ } ) ,
344+ ) ,
345+ )
346+
347+ view . dispatch (
348+ view . state . tr . scrollIntoView ( ) . setMeta ( linkMenuPluginKey , {
349+ activate : true ,
350+ ref : normalizedHmUrl ,
351+ items : getLinkMenuItems ( {
352+ isLoading : false ,
353+ sourceUrl : normalizedHmUrl ,
354+ hmId : unpackHmId ( normalizedHmUrl ) ,
355+ gwUrl : options . gwUrl ,
356+ } ) ,
357+ } ) ,
358+ )
359+ return true
332360 }
333361
334362 // Check if the link is hm link or web URL
@@ -673,6 +701,26 @@ export function restoreBlockRangeSuffix(href: string, fullText: string): string
673701 return match ? href + match [ 0 ] : href
674702}
675703
704+ export function getPastedHypermediaId ( text : string , gwUrl : StateStream < string > ) : UnpackedHypermediaId | null {
705+ const trimmed = text . trim ( )
706+ if ( ! trimmed ) return null
707+
708+ if ( isHypermediaScheme ( trimmed ) || isPublicGatewayLink ( trimmed , gwUrl ) || isPublicHypermediaLink ( trimmed ) ) {
709+ return unpackHmId ( trimmed )
710+ }
711+
712+ return null
713+ }
714+
715+ function isPublicHypermediaLink ( text : string ) {
716+ try {
717+ const url = new URL ( text )
718+ return ( url . protocol === 'https:' || url . protocol === 'http:' ) && url . hostname === 'hyper.media'
719+ } catch {
720+ return false
721+ }
722+ }
723+
676724async function fetchEntityTitle ( hmId : UnpackedHypermediaId , grpcClient : GRPCClient , blockRef ?: string | null ) {
677725 const document = await grpcClient . documents . getDocument ( {
678726 account : hmId . uid ,
0 commit comments