74 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
			
		
		
	
	
			74 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
import {
 | 
						|
    $getSelection, BaseSelection,
 | 
						|
    COMMAND_PRIORITY_NORMAL,
 | 
						|
    KEY_ENTER_COMMAND,
 | 
						|
    KEY_SPACE_COMMAND,
 | 
						|
    LexicalEditor,
 | 
						|
    TextNode
 | 
						|
} from "lexical";
 | 
						|
import {$getTextNodeFromSelection} from "../utils/selection";
 | 
						|
import {$createLinkNode, LinkNode} from "@lexical/link";
 | 
						|
 | 
						|
 | 
						|
function isLinkText(text: string): boolean {
 | 
						|
    const lower = text.toLowerCase();
 | 
						|
    if (!lower.startsWith('http')) {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    const linkRegex = /(http|https):\/\/(\S+)\.\S+$/;
 | 
						|
    return linkRegex.test(text);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
function handlePotentialLinkEvent(node: TextNode, selection: BaseSelection, editor: LexicalEditor) {
 | 
						|
    const selectionRange = selection.getStartEndPoints();
 | 
						|
    if (!selectionRange) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    const cursorPoint = selectionRange[0].offset;
 | 
						|
    const nodeText = node.getTextContent();
 | 
						|
    const rTrimText = nodeText.slice(0, cursorPoint);
 | 
						|
    const priorSpaceIndex = rTrimText.lastIndexOf(' ');
 | 
						|
    const startIndex = priorSpaceIndex + 1;
 | 
						|
    const textSegment = nodeText.slice(startIndex, cursorPoint);
 | 
						|
 | 
						|
    if (!isLinkText(textSegment)) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    editor.update(() => {
 | 
						|
        const linkNode: LinkNode = $createLinkNode(textSegment);
 | 
						|
        linkNode.append(new TextNode(textSegment));
 | 
						|
 | 
						|
        const splits = node.splitText(startIndex, cursorPoint);
 | 
						|
        const targetIndex = splits.length === 3 ? 1 : 0;
 | 
						|
        const targetText = splits[targetIndex];
 | 
						|
        if (targetText) {
 | 
						|
            targetText.replace(linkNode);
 | 
						|
        }
 | 
						|
    });
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
export function registerAutoLinks(editor: LexicalEditor): () => void {
 | 
						|
 | 
						|
    const handler = (payload: KeyboardEvent): boolean => {
 | 
						|
        const selection = $getSelection();
 | 
						|
        const textNode = $getTextNodeFromSelection(selection);
 | 
						|
        if (textNode && selection) {
 | 
						|
            handlePotentialLinkEvent(textNode, selection, editor);
 | 
						|
        }
 | 
						|
 | 
						|
        return false;
 | 
						|
    };
 | 
						|
 | 
						|
    const unregisterSpace = editor.registerCommand(KEY_SPACE_COMMAND, handler, COMMAND_PRIORITY_NORMAL);
 | 
						|
    const unregisterEnter = editor.registerCommand(KEY_ENTER_COMMAND, handler, COMMAND_PRIORITY_NORMAL);
 | 
						|
 | 
						|
    return (): void => {
 | 
						|
        unregisterSpace();
 | 
						|
        unregisterEnter();
 | 
						|
    };
 | 
						|
} |