import { DecoratorNode, ElementNode, type LexicalNode, type SerializedElementNode, type SerializedLexicalNode, type Spread } from "lexical"; import { FocusableNode } from "./focusable_node"; import type { ReactNode } from "react"; import { LinkIcon } from "~/components/editor/link_icon"; type SerializedLinkNode = Spread; export class LinkNode extends FocusableNode { __url: string; getUrl(): string { const self = this.getLatest(); return self.__url; } static getType() { return "link"; } static clone(node: LinkNode) { return new LinkNode(node.__url, node.__key, node.__hasFocus); } constructor(url: string, key?: string, hasFocus?: boolean) { super(key, hasFocus); this.__url = url; } isInline(): boolean { return true; } createDOM(): HTMLElement { const element = super.createDOM(); element.classList.add("link"); return element; } updateDOM(old: LinkNode, dom: HTMLElement): boolean { return super.updateDOM(old, dom); } exportJSON(): SerializedLinkNode { return { ...super.exportJSON(), type: "link", url: this.__url, }; } static importJSON(serializedNode: SerializedLinkNode) { return $createLinkNode(serializedNode.url); } } export function $createLinkNode(url: string) { return new LinkNode(url); } export function $isLinkNode(node?: LexicalNode | null): node is LinkNode { return node instanceof LinkNode; } export class LinkMarkerNode extends ElementNode { static getType() { return "link-marker"; } static clone(node: LinkMarkerNode) { return new LinkMarkerNode(node.__key); } isInline(): boolean { return true; } createDOM(): HTMLElement { const element = document.createElement("span"); element.classList.add("link-marker"); return element; } updateDOM(): boolean { return false; } exportJSON(): SerializedElementNode { return { ...super.exportJSON(), type: "link-marker", }; } static importJSON() { return $createLinkMarkerNode(); } } export function $createLinkMarkerNode() { return new LinkMarkerNode(); } export function $isLinkMarkerNode(node?: LexicalNode | null): node is LinkMarkerNode { return node instanceof LinkMarkerNode; } export class LinkUrlNode extends ElementNode { static getType() { return "link-url"; } static clone(node: LinkUrlNode) { return new LinkUrlNode(node.__key); } isInline(): boolean { return true; } createDOM(): HTMLElement { const element = document.createElement("span"); element.classList.add("link-url"); return element; } updateDOM(): boolean { return false; } exportJSON(): SerializedElementNode { return { ...super.exportJSON(), type: "link-url", }; } static importJSON() { return $createLinkUrlNode(); } } export function $createLinkUrlNode() { return new LinkUrlNode(); } export function $isLinkUrlNode(node?: LexicalNode | null): node is LinkUrlNode { return node instanceof LinkUrlNode; } type SerializedLinkIconNode = Spread; export class LinkIconNode extends DecoratorNode { __url: string; getUrl() { const self = this.getLatest(); return self.__url; } static getType() { return "link-icon"; } static clone(node: LinkIconNode) { return new LinkIconNode(node.__url, node.__key); } constructor(url: string, key?: string) { super(key); this.__url = url; } createDOM(): HTMLElement { return document.createElement("span"); } updateDOM(): boolean { return false; } decorate(): ReactNode { return (); } exportJSON(): SerializedLinkIconNode { return { ...super.exportJSON(), type: "link-icon", url: this.__url, } } static importJSON(serializedNode: SerializedLinkIconNode) { return $createLinkIconNode(serializedNode.url); } } export function $createLinkIconNode(url: string) { return new LinkIconNode(url); } export function $isLinkIconNode(node?: LexicalNode | null): node is LinkIconNode { return node instanceof LinkIconNode; }