v3/src/editor/nodes/term_node.tsx

142 lines
3.6 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 { TermIcon } from "~/components/editor/term_icon";
type SerializedTermNode = Spread<SerializedElementNode, {
term: string;
}>;
export class TermNode extends FocusableNode {
__term: string;
getTerm() {
const self = this.getLatest();
return self.__term;
}
static getType() {
return "term";
}
static clone(node: TermNode) {
return new TermNode(node.__term, node.__key, node.__hasFocus);
}
constructor(term: string, key?: string, hasFocus?: boolean) {
super(key, hasFocus);
this.__term = term;
}
isInline() {
return true;
}
createDOM() {
const element = super.createDOM();
element.classList.add("term");
return element;
}
updateDOM(old: TermNode, dom: HTMLElement) {
return super.updateDOM(old, dom);
}
exportJSON(): SerializedTermNode {
return {
...super.exportJSON(),
type: "term",
term: this.__term,
};
}
static importJSON(serializedNode: SerializedTermNode) {
return $createTermNode(serializedNode.term);
}
}
export function $createTermNode(term: string) {
return new TermNode(term);
}
export function $isTermNode(node?: LexicalNode | null): node is TermNode {
return node instanceof TermNode;
}
export class TermMarkerNode extends ElementNode {
static getType() {
return "term-marker";
}
static clone(node: TermMarkerNode) {
return new TermMarkerNode(node.__key);
}
isInline() {
return true;
}
createDOM() {
const element = document.createElement("span");
element.classList.add("term-marker");
return element;
}
updateDOM() {
return false;
}
exportJSON() {
return {
...super.exportJSON(),
type: "term-marker",
};
}
static importJSON() {
return $createTermMarkerNode();
}
}
export function $createTermMarkerNode() {
return new TermMarkerNode();
}
export function $isTermMarkerNode(node?: LexicalNode | null): node is TermMarkerNode {
return node instanceof TermMarkerNode;
}
type SerializedTermIconNode = Spread<SerializedLexicalNode, {
term: string;
}>;
export class TermIconNode extends DecoratorNode<ReactNode> {
__term: string;
getTerm() {
const self = this.getLatest();
return self.__term;
}
static getType() {
return "term-icon";
}
static clone(node: TermIconNode) {
return new TermIconNode(node.__term, node.__key);
}
constructor(term: string, key?: string) {
super(key);
this.__term = term;
}
createDOM() {
return document.createElement("span");
}
updateDOM() {
return false;
}
decorate(): ReactNode {
return (<TermIcon term={this.__term} />);
}
exportJSON(): SerializedTermIconNode {
return {
...super.exportJSON(),
type: "term-icon",
term: this.__term,
};
}
static importJSON(serializedNode: SerializedTermIconNode) {
return $createTermIconNode(serializedNode.term);
}
}
export function $createTermIconNode(term: string) {
return new TermIconNode(term);
}
export function $isTermIconNode(node?: LexicalNode | null): node is TermIconNode {
return node instanceof TermIconNode;
}