A world-class math input for the web
1import type { TokenFlow } from "./flow";
2import { EditorState } from "./editorState";
3import { Strand } from "./strand";
4import { VNode } from "./vdom";
5
6export abstract class Token {
7 abstract flow: TokenFlow;
8 abstract get children(): readonly Strand[];
9
10 protected _parentStrand: Strand | undefined;
11 set parentStrand(parent: Strand) {
12 if (this._parentStrand !== undefined) {
13 throw new Error("Parent token is already set");
14 }
15 this._parentStrand = parent;
16 }
17 get parentStrand(): Strand | undefined {
18 return this._parentStrand;
19 }
20
21 get editorState(): EditorState | undefined {
22 return this._parentStrand?.editorState;
23 }
24
25 /**
26 * Create a new token with its children mapped through the given function.
27 * @param fn Function to map each child strand.
28 * @returns A new token with the mapped children.
29 */
30 abstract mapChildren(fn: (child: Strand, index: number) => Strand): Token;
31
32 /**
33 * Create a deep clone of this token.
34 * @returns A deep clone of this token.
35 */
36 clone(): Token {
37 return this.mapChildren(
38 (strand, index) => new Strand(strand.tokens.map((token) => token.clone()))
39 );
40 }
41
42 /**
43 * @deprecated This function is only for debugging purposes. Actual rendering of tokens should be done via a separate rendering system.
44 */
45 renderToDebugText(): string {
46 return `${this.constructor.name}(${this.children
47 .map((child) => child.renderToDebugText())
48 .join(", ")})`;
49 }
50
51 /**
52 * @deprecated This function is only for debugging purposes. Actual rendering of tokens should be done via a separate rendering system.
53 */
54 abstract renderToDebugHTML(): VNode;
55
56 /**
57 * @deprecated This function is only for debugging purposes. Actual rendering of tokens should be done via a separate rendering system.
58 */
59 abstract renderToDebugMathML(): VNode;
60}