web based infinite canvas
1import type { Action } from "../actions";
2import { createId, ShapeRecord } from "../model";
3import type { EditorState, ToolId } from "../reactivity";
4import { getCurrentPage } from "../reactivity";
5import type { Tool } from "./base";
6
7export class MarkdownTool implements Tool {
8 readonly id: ToolId = "markdown";
9
10 onEnter(state: EditorState): EditorState {
11 return state;
12 }
13
14 onExit(state: EditorState): EditorState {
15 return state;
16 }
17
18 onAction(state: EditorState, action: Action): EditorState {
19 switch (action.type) {
20 case "pointer-down": {
21 return this.handlePointerDown(state, action);
22 }
23 default: {
24 return state;
25 }
26 }
27 }
28
29 private handlePointerDown(state: EditorState, action: Action): EditorState {
30 if (action.type !== "pointer-down") return state;
31
32 const currentPage = getCurrentPage(state);
33 if (!currentPage) return state;
34
35 const shapeId = createId("shape");
36
37 const shape = ShapeRecord.createMarkdown(currentPage.id, action.world.x, action.world.y, {
38 md: "# Markdown\n\nEdit me...",
39 w: 300,
40 h: 200,
41 fontSize: 16,
42 fontFamily: "Inter",
43 color: "#1f2933",
44 }, shapeId);
45
46 const newPage = { ...currentPage, shapeIds: [...currentPage.shapeIds, shapeId] };
47
48 return {
49 ...state,
50 doc: {
51 ...state.doc,
52 shapes: { ...state.doc.shapes, [shapeId]: shape },
53 pages: { ...state.doc.pages, [currentPage.id]: newPage },
54 },
55 ui: { ...state.ui, selectionIds: [shapeId] },
56 };
57 }
58}