A world-class math input for the web
1import { Cursor } from "./cursor";
2import type { StrandPath } from "./path";
3import { Strand } from "./strand";
4import { h, VNode } from "./vdom";
5import { SelectionRange } from "./selectionRange";
6
7export class EditorState {
8 readonly content: Strand;
9 readonly selection: SelectionRange;
10
11 constructor(
12 content = new Strand([]),
13 selection: SelectionRange | Cursor = new SelectionRange()
14 ) {
15 this.content = content;
16 this.selection =
17 selection instanceof Cursor ? new SelectionRange(selection) : selection;
18 content.parent = this;
19 }
20
21 /**
22 * @deprecated This function is only for debugging purposes.
23 */
24 renderToDebugText(): string {
25 return this.content.renderToDebugText();
26 }
27
28 /**
29 * @deprecated This function is only for debugging purposes.
30 */
31 renderToDebugHTML(): VNode {
32 return h("div", { class: "math" }, this.content.renderToDebugHTML());
33 }
34
35 /**
36 * @deprecated This function is only for debugging purposes.
37 */
38 renderToDebugMathML(): VNode {
39 return h("math", {}, this.content.renderToDebugMathML());
40 }
41
42 /**
43 * Get the cursor position within a given token's child strand.
44 * @param strandPath The StrandPath of the strand to check against.
45 * @param cursor The cursor whose position is being queried.
46 * @returns The position of the cursor within the strand, or null if the cursor is not within that strand.
47 */
48 getPositionOfCursorInStrand(
49 strandPath: StrandPath,
50 cursor: Cursor
51 ): number | null {
52 if (cursor.strandPath.length !== strandPath.length) {
53 return null;
54 }
55
56 for (let i = 0; i < strandPath.length; i++) {
57 const cursorLevel = cursor.strandPath[i];
58 const targetLevel = strandPath[i];
59 if (
60 cursorLevel.tokenIndex !== targetLevel.tokenIndex ||
61 cursorLevel.childIndex !== targetLevel.childIndex
62 ) {
63 return null;
64 }
65 }
66
67 return cursor.pos;
68 }
69}