184 lines
4.5 KiB
TypeScript
184 lines
4.5 KiB
TypeScript
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<SerializedElementNode, {
|
|
url: string;
|
|
}>;
|
|
|
|
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<SerializedLexicalNode, {
|
|
url: string;
|
|
}>;
|
|
|
|
export class LinkIconNode extends DecoratorNode<ReactNode> {
|
|
__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 (<LinkIcon url={this.__url} />);
|
|
}
|
|
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;
|
|
}
|
|
|