142 lines
3.6 KiB
TypeScript
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;
|
|
}
|
|
|