@xom11/whiteboard 0.11.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +67 -0
  2. package/dist/{ExcalidrawWithMenus-EAVPOPJZ.mjs → ExcalidrawWithMenus-KBLDWPM2.mjs} +2 -3
  3. package/dist/ExcalidrawWithMenus-KBLDWPM2.mjs.map +1 -0
  4. package/dist/catalog.json +57 -0
  5. package/dist/{chunk-PWIMZIB6.mjs → chunk-2SKXRBGS.mjs} +7 -8
  6. package/dist/chunk-2SKXRBGS.mjs.map +1 -0
  7. package/dist/chunk-33PEN2WC.mjs +57 -0
  8. package/dist/chunk-33PEN2WC.mjs.map +1 -0
  9. package/dist/chunk-3KBL77M6.mjs +127 -0
  10. package/dist/chunk-3KBL77M6.mjs.map +1 -0
  11. package/dist/chunk-5UTGXHLJ.mjs +57 -0
  12. package/dist/chunk-5UTGXHLJ.mjs.map +1 -0
  13. package/dist/chunk-6XUPIGVD.mjs +467 -0
  14. package/dist/chunk-6XUPIGVD.mjs.map +1 -0
  15. package/dist/chunk-7WG2KDRF.mjs +28 -0
  16. package/dist/chunk-7WG2KDRF.mjs.map +1 -0
  17. package/dist/chunk-FZY33J6Z.mjs +95 -0
  18. package/dist/chunk-FZY33J6Z.mjs.map +1 -0
  19. package/dist/chunk-HNQLZIEP.mjs +78 -0
  20. package/dist/chunk-HNQLZIEP.mjs.map +1 -0
  21. package/dist/chunk-NVJ7K3DK.mjs +29 -0
  22. package/dist/chunk-NVJ7K3DK.mjs.map +1 -0
  23. package/dist/chunk-O4WIZFRQ.mjs +11 -0
  24. package/dist/chunk-O4WIZFRQ.mjs.map +1 -0
  25. package/dist/{chunk-YVJP7NRG.mjs → chunk-O6QTYAKE.mjs} +7 -9
  26. package/dist/chunk-O6QTYAKE.mjs.map +1 -0
  27. package/dist/chunk-R5FL6S7L.mjs +22 -0
  28. package/dist/chunk-R5FL6S7L.mjs.map +1 -0
  29. package/dist/chunk-RBUILBX3.mjs +388 -0
  30. package/dist/chunk-RBUILBX3.mjs.map +1 -0
  31. package/dist/chunk-RD34F5PM.mjs +57 -0
  32. package/dist/chunk-RD34F5PM.mjs.map +1 -0
  33. package/dist/{chunk-7P7SQFOW.mjs → chunk-RXOFO64U.mjs} +3 -3
  34. package/dist/chunk-RXOFO64U.mjs.map +1 -0
  35. package/dist/chunk-TOOHCAWP.mjs +1167 -0
  36. package/dist/chunk-TOOHCAWP.mjs.map +1 -0
  37. package/dist/{chunk-C6SCVOMC.mjs → chunk-TQYQVXNW.mjs} +5 -41
  38. package/dist/chunk-TQYQVXNW.mjs.map +1 -0
  39. package/dist/chunk-VBJLUHCY.mjs +23 -0
  40. package/dist/chunk-VBJLUHCY.mjs.map +1 -0
  41. package/dist/chunk-VRWZILTG.mjs +205 -0
  42. package/dist/chunk-VRWZILTG.mjs.map +1 -0
  43. package/dist/chunk-XVSO7FBM.mjs +61 -0
  44. package/dist/chunk-XVSO7FBM.mjs.map +1 -0
  45. package/dist/geometry-2d.d.mts +3 -6
  46. package/dist/geometry-2d.d.ts +3 -6
  47. package/dist/geometry-2d.js +5069 -2651
  48. package/dist/geometry-2d.js.map +1 -1
  49. package/dist/geometry-2d.mjs +8 -4
  50. package/dist/geometry-3d.d.mts +4 -7
  51. package/dist/geometry-3d.d.ts +4 -7
  52. package/dist/geometry-3d.js +3053 -2150
  53. package/dist/geometry-3d.js.map +1 -1
  54. package/dist/geometry-3d.mjs +7 -4
  55. package/dist/graph-2d.d.mts +4 -7
  56. package/dist/graph-2d.d.ts +4 -7
  57. package/dist/graph-2d.js +3363 -1670
  58. package/dist/graph-2d.js.map +1 -1
  59. package/dist/graph-2d.mjs +10 -3
  60. package/dist/host-3N4E4KJH.mjs +1142 -0
  61. package/dist/host-3N4E4KJH.mjs.map +1 -0
  62. package/dist/{host-Z3TEJKZA.mjs → host-6SNSZ332.mjs} +4 -4
  63. package/dist/{host-Z3TEJKZA.mjs.map → host-6SNSZ332.mjs.map} +1 -1
  64. package/dist/host-EVJT3LIF.mjs +3198 -0
  65. package/dist/host-EVJT3LIF.mjs.map +1 -0
  66. package/dist/host-HN4X3TBC.mjs +2374 -0
  67. package/dist/host-HN4X3TBC.mjs.map +1 -0
  68. package/dist/index.css +4 -1
  69. package/dist/index.css.map +1 -1
  70. package/dist/index.d.mts +659 -19
  71. package/dist/index.d.ts +659 -19
  72. package/dist/index.js +11741 -9420
  73. package/dist/index.js.map +1 -1
  74. package/dist/index.mjs +1467 -336
  75. package/dist/index.mjs.map +1 -1
  76. package/dist/latex.d.mts +3 -4
  77. package/dist/latex.d.ts +3 -4
  78. package/dist/latex.js +33 -18
  79. package/dist/latex.js.map +1 -1
  80. package/dist/latex.mjs +2 -3
  81. package/dist/render-OCVGDKK6.mjs +8 -0
  82. package/dist/render-OCVGDKK6.mjs.map +1 -0
  83. package/dist/serialize-GKN6OVPM.mjs +6 -0
  84. package/dist/serialize-GKN6OVPM.mjs.map +1 -0
  85. package/dist/{types-CinstD7T.d.mts → types-rA4slL08.d.mts} +69 -4
  86. package/dist/{types-CinstD7T.d.ts → types-rA4slL08.d.ts} +69 -4
  87. package/package.json +24 -5
  88. package/dist/ExcalidrawWithMenus-EAVPOPJZ.mjs.map +0 -1
  89. package/dist/chunk-74VEEZBV.mjs +0 -619
  90. package/dist/chunk-74VEEZBV.mjs.map +0 -1
  91. package/dist/chunk-7P7SQFOW.mjs.map +0 -1
  92. package/dist/chunk-BJTO5JO5.mjs +0 -11
  93. package/dist/chunk-BJTO5JO5.mjs.map +0 -1
  94. package/dist/chunk-C6SCVOMC.mjs.map +0 -1
  95. package/dist/chunk-D257NCQW.mjs +0 -58
  96. package/dist/chunk-D257NCQW.mjs.map +0 -1
  97. package/dist/chunk-G7FR3AIV.mjs +0 -193
  98. package/dist/chunk-G7FR3AIV.mjs.map +0 -1
  99. package/dist/chunk-HTBLO5JO.mjs +0 -41
  100. package/dist/chunk-HTBLO5JO.mjs.map +0 -1
  101. package/dist/chunk-PWIMZIB6.mjs.map +0 -1
  102. package/dist/chunk-SBDMF4NQ.mjs +0 -212
  103. package/dist/chunk-SBDMF4NQ.mjs.map +0 -1
  104. package/dist/chunk-WQOABS6N.mjs +0 -197
  105. package/dist/chunk-WQOABS6N.mjs.map +0 -1
  106. package/dist/chunk-YVJP7NRG.mjs.map +0 -1
  107. package/dist/host-N6ACNJKI.mjs +0 -3226
  108. package/dist/host-N6ACNJKI.mjs.map +0 -1
  109. package/dist/host-NKGV6RF2.mjs +0 -1134
  110. package/dist/host-NKGV6RF2.mjs.map +0 -1
  111. package/dist/host-XVK7UCRE.mjs +0 -2908
  112. package/dist/host-XVK7UCRE.mjs.map +0 -1
@@ -1,6 +1,69 @@
1
1
  import { ReactNode, ComponentType, RefAttributes } from 'react';
2
2
  import { ExcalidrawElement } from '@excalidraw/excalidraw/element/types';
3
3
 
4
+ type SceneObject<A = Record<string, unknown>> = {
5
+ id: string;
6
+ kind: string;
7
+ label: string;
8
+ visible: boolean;
9
+ locked: boolean;
10
+ layer: string;
11
+ schemaVersion: number;
12
+ attrs: A;
13
+ };
14
+ type View2D = {
15
+ readonly bbox: readonly [number, number, number, number];
16
+ readonly showAxis: boolean;
17
+ readonly showGrid: boolean;
18
+ };
19
+ type View3D = {
20
+ readonly bbox3D: readonly [number, number, number, number, number, number];
21
+ readonly azimuth: number;
22
+ readonly elevation: number;
23
+ };
24
+ type ViewGraph2D = {
25
+ readonly xMin: number;
26
+ readonly xMax: number;
27
+ readonly yMin: number;
28
+ readonly yMax: number;
29
+ readonly showAxis: boolean;
30
+ readonly showGrid: boolean;
31
+ };
32
+ type StateMeta = {
33
+ readonly domain: '2d';
34
+ readonly version: number;
35
+ readonly view: View2D;
36
+ } | {
37
+ readonly domain: '3d';
38
+ readonly version: number;
39
+ readonly view: View3D;
40
+ } | {
41
+ readonly domain: 'graph2d';
42
+ readonly version: number;
43
+ readonly view: ViewGraph2D;
44
+ };
45
+ type State = {
46
+ readonly objects: Readonly<Record<string, SceneObject>>;
47
+ readonly order: readonly string[];
48
+ readonly counter: number;
49
+ readonly meta: StateMeta;
50
+ };
51
+
52
+ /** Minimal client-safe response required by the geometry AI editor. */
53
+ type AiFigureUiResult = {
54
+ ok: true;
55
+ state: State;
56
+ } | {
57
+ ok: false;
58
+ message: string;
59
+ };
60
+ /**
61
+ * Consumer-provided bridge to a server-side `generateFigure()` call.
62
+ * Implementations must keep API credentials outside the browser bundle.
63
+ */
64
+ type GenerateGeometryFigure = (problem: string, options: {
65
+ signal: AbortSignal;
66
+ }) => Promise<AiFigureUiResult>;
4
67
  /**
5
68
  * Kết quả trả về từ `restoreFileFromCustomData`. Chứa đủ thông tin để
6
69
  * consumer gọi `api.addFiles(...)`.
@@ -37,6 +100,8 @@ interface StampHostProps {
37
100
  onClose: () => void;
38
101
  /** Dark theme flag. */
39
102
  isDark: boolean;
103
+ /** Optional client-safe bridge for the geometry-2d AI prompt editor. */
104
+ generateGeometryFigure?: GenerateGeometryFigure;
40
105
  }
41
106
  /**
42
107
  * Imperative API mà main view truy cập qua ref:
@@ -63,7 +128,7 @@ type StampHostComponent = ComponentType<StampHostProps & RefAttributes<StampHost
63
128
  *
64
129
  * Main view dispatch generic: `<stamp.Host ... />` — không cần biết kind.
65
130
  */
66
- interface StampType {
131
+ interface StampType<TCustomData extends BaseStampCustomData = BaseStampCustomData> {
67
132
  /** Unique kind. VD: 'geometry', 'latex'. Phải khớp với customData.kind. */
68
133
  kind: string;
69
134
  /** Phím tắt mở/đóng stamp (lowercase, 1 ký tự). VD: 'g', 'l'. */
@@ -77,14 +142,14 @@ interface StampType {
77
142
  /** Test data-testid cho nút toolbar (optional). */
78
143
  toolbarTestId?: string;
79
144
  /** Type guard: customData có thuộc về stamp này không. */
80
- matchesCustomData(data: unknown): boolean;
145
+ matchesCustomData(data: unknown): data is TCustomData;
81
146
  /**
82
147
  * Re-render SVG từ customData. Dùng khi restore math-stamp file sau reload
83
148
  * page (Excalidraw không persist binary file payload, chỉ giữ fileId trong
84
149
  * element). SVG render với light palette (nét đậm) — Excalidraw tự đảo
85
150
  * màu trong dark mode qua CSS filter.
86
151
  */
87
- renderSvgFromCustomData(data: unknown): Promise<string>;
152
+ renderSvgFromCustomData(data: TCustomData): Promise<string>;
88
153
  /**
89
154
  * Regenerate file SVG/PNG cho element thuộc stamp này khi reload từ persisted
90
155
  * snapshot. Trả về `RestoredStampFile` để consumer gọi `api.addFiles`, hoặc
@@ -107,4 +172,4 @@ interface StampType {
107
172
  experimental?: boolean;
108
173
  }
109
174
 
110
- export type { BaseStampCustomData as B, StampType as S };
175
+ export type { AiFigureUiResult as A, BaseStampCustomData as B, GenerateGeometryFigure as G, StampType as S, State as a };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xom11/whiteboard",
3
- "version": "0.11.0",
3
+ "version": "0.24.0",
4
4
  "private": false,
5
5
  "description": "Excalidraw + JSXGraph + KaTeX whiteboard component (drawing, geometry stamps, LaTeX stamps).",
6
6
  "license": "MIT",
@@ -47,13 +47,19 @@
47
47
  "*.css"
48
48
  ],
49
49
  "scripts": {
50
- "build": "tsup && node scripts/inject-use-client.mjs",
51
- "dev": "tsup --watch --onSuccess \"node scripts/inject-use-client.mjs\"",
50
+ "build": "tsup && node scripts/inject-use-client.mjs && node scripts/build-catalog.mjs",
51
+ "build:catalog": "node scripts/build-catalog.mjs",
52
+ "dev": "tsup --watch --onSuccess \"node scripts/inject-use-client.mjs && node scripts/build-catalog.mjs\"",
52
53
  "test": "jest",
53
54
  "test:e2e": "playwright test",
54
55
  "typecheck": "tsc --noEmit",
56
+ "lint": "eslint .",
57
+ "lint:fix": "eslint . --fix",
55
58
  "clean": "rm -rf dist .yalc yalc.lock",
56
- "demo": "vite --config scripts/demo/vite.config.ts"
59
+ "demo": "vite --config scripts/demo/vite.config.ts",
60
+ "ai:eval": "tsx scripts/eval-ai.ts",
61
+ "ai:smoke": "tsx scripts/smoke-ai.ts",
62
+ "prepublishOnly": "npm run clean && npm run build"
57
63
  },
58
64
  "peerDependencies": {
59
65
  "@excalidraw/excalidraw": "^0.18.1",
@@ -63,6 +69,7 @@
63
69
  "react-dom": ">=18.0.0"
64
70
  },
65
71
  "devDependencies": {
72
+ "@eslint/js": "^9.39.4",
66
73
  "@playwright/test": "^1.60.0",
67
74
  "@tailwindcss/vite": "^4.3.0",
68
75
  "@testing-library/jest-dom": "^6.9.1",
@@ -73,8 +80,14 @@
73
80
  "@types/node": "^22.0.0",
74
81
  "@types/react": "^19.0.0",
75
82
  "@types/react-dom": "^19.0.0",
83
+ "@typescript-eslint/eslint-plugin": "^8.59.4",
84
+ "@typescript-eslint/parser": "^8.59.4",
76
85
  "@vitejs/plugin-react": "^6.0.2",
86
+ "eslint": "^9.39.4",
87
+ "eslint-plugin-react": "^7.37.5",
88
+ "eslint-plugin-react-hooks": "^5.2.0",
77
89
  "fake-indexeddb": "^6.0.0",
90
+ "globals": "^15.15.0",
78
91
  "jest": "^29.7.0",
79
92
  "jest-environment-jsdom": "^29.7.0",
80
93
  "next": "16.1.6",
@@ -83,10 +96,16 @@
83
96
  "tailwindcss": "^4.3.0",
84
97
  "ts-jest": "^29.4.9",
85
98
  "tsup": "^8.3.5",
99
+ "tsx": "^4.22.3",
86
100
  "typescript": "^5.6.0",
101
+ "typescript-eslint": "^8.59.4",
87
102
  "vite": "^8.0.13"
88
103
  },
89
104
  "dependencies": {
90
- "pdfjs-dist": "^5.7.284"
105
+ "@anthropic-ai/sdk": "^0.98.0",
106
+ "immer": "^10.2.0",
107
+ "pdfjs-dist": "^5.7.284",
108
+ "zod": "^3.23.8",
109
+ "zod-to-json-schema": "^3.25.2"
91
110
  }
92
111
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ExcalidrawWithMenus.tsx"],"names":[],"mappings":";;;;AAiBO,SAAS,oBAAoB,KAAA,EAAwB;AAC1D,EAAA,MAAM,EAAE,QAAA,EAAU,GAAG,IAAA,EAAK,GAAI,KAAA;AAC9B,EAAA,uBACE,IAAA,CAAC,UAAA,EAAA,EAAY,GAAG,IAAA,EAEd,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,QAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,QAAA,CAAS,YAAA,CAAa,SAAA,EAAtB,EAAgC,CAAA;AAAA,sBACjC,GAAA,CAAC,QAAA,CAAS,YAAA,CAAa,WAAA,EAAtB,EAAkC,CAAA;AAAA,sBACnC,GAAA,CAAC,QAAA,CAAS,YAAA,CAAa,WAAA,EAAtB,EAAkC,CAAA;AAAA,sBACnC,GAAA,CAAC,QAAA,CAAS,YAAA,CAAa,WAAA,EAAtB,EAAkC;AAAA,KAAA,EACrC,CAAA;AAAA,oBAEA,GAAA,CAAC,MAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EACR,CAAA;AAAA,oBAGA,GAAA,CAAC,aAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EACR,CAAA;AAAA,IACC;AAAA,GAAA,EACH,CAAA;AAEJ","file":"ExcalidrawWithMenus-EAVPOPJZ.mjs","sourcesContent":["'use client';\n\n// Client-only wrapper around Excalidraw that lets us reach for static helpers\n// like `MainMenu.DefaultItems.*`. Whiteboard dynamic-imports this\n// file so SSR never evaluates @excalidraw/excalidraw, while inside this file we\n// can use plain static imports (the entire module loads on the client).\n\nimport React from 'react';\nimport {\n Excalidraw,\n MainMenu,\n Footer,\n WelcomeScreen,\n} from '@excalidraw/excalidraw';\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype ExcalidrawProps = any;\n\nexport function ExcalidrawWithMenus(props: ExcalidrawProps) {\n const { children, ...rest } = props;\n return (\n <Excalidraw {...rest}>\n {/* Replace default menu with curated items — no socials/help/branding */}\n <MainMenu>\n <MainMenu.DefaultItems.LoadScene />\n <MainMenu.DefaultItems.SaveAsImage />\n <MainMenu.DefaultItems.ClearCanvas />\n <MainMenu.DefaultItems.ToggleTheme />\n </MainMenu>\n {/* Footer slot with no content suppresses default \"Made with Excalidraw\" link */}\n <Footer>\n <span />\n </Footer>\n {/* WelcomeScreen slot (empty) prevents the default Excalidraw welcome panel\n * (which includes the Excalidraw logo and social links) from appearing. */}\n <WelcomeScreen>\n <span />\n </WelcomeScreen>\n {children}\n </Excalidraw>\n );\n}\n"]}