@xom11/whiteboard 0.6.5 → 0.9.1

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 (66) hide show
  1. package/README.md +87 -1
  2. package/dist/chunk-74VEEZBV.mjs +619 -0
  3. package/dist/chunk-74VEEZBV.mjs.map +1 -0
  4. package/dist/chunk-7P7SQFOW.mjs +39 -0
  5. package/dist/chunk-7P7SQFOW.mjs.map +1 -0
  6. package/dist/chunk-C6SCVOMC.mjs +111 -0
  7. package/dist/chunk-C6SCVOMC.mjs.map +1 -0
  8. package/dist/chunk-DU2NFHRR.mjs +103 -0
  9. package/dist/chunk-DU2NFHRR.mjs.map +1 -0
  10. package/dist/chunk-DU3RHKT5.mjs +44 -0
  11. package/dist/chunk-DU3RHKT5.mjs.map +1 -0
  12. package/dist/chunk-HTBLO5JO.mjs +41 -0
  13. package/dist/chunk-HTBLO5JO.mjs.map +1 -0
  14. package/dist/chunk-IUVV52HO.mjs +144 -0
  15. package/dist/chunk-IUVV52HO.mjs.map +1 -0
  16. package/dist/chunk-KEYZ5EZT.mjs +154 -0
  17. package/dist/chunk-KEYZ5EZT.mjs.map +1 -0
  18. package/dist/chunk-P2AOIF7S.mjs +40 -0
  19. package/dist/chunk-P2AOIF7S.mjs.map +1 -0
  20. package/dist/chunk-SBDMF4NQ.mjs +212 -0
  21. package/dist/chunk-SBDMF4NQ.mjs.map +1 -0
  22. package/dist/chunk-X5R72SSJ.mjs +52 -0
  23. package/dist/chunk-X5R72SSJ.mjs.map +1 -0
  24. package/dist/chunk-ZVN356JZ.mjs +58 -0
  25. package/dist/chunk-ZVN356JZ.mjs.map +1 -0
  26. package/dist/geometry-2d.d.mts +16 -0
  27. package/dist/geometry-2d.d.ts +16 -0
  28. package/dist/geometry-2d.js +3581 -0
  29. package/dist/geometry-2d.js.map +1 -0
  30. package/dist/geometry-2d.mjs +7 -0
  31. package/dist/geometry-2d.mjs.map +1 -0
  32. package/dist/geometry-3d.d.mts +16 -0
  33. package/dist/geometry-3d.d.ts +16 -0
  34. package/dist/geometry-3d.js +4105 -0
  35. package/dist/geometry-3d.js.map +1 -0
  36. package/dist/geometry-3d.mjs +7 -0
  37. package/dist/geometry-3d.mjs.map +1 -0
  38. package/dist/graph-2d.d.mts +16 -0
  39. package/dist/graph-2d.d.ts +16 -0
  40. package/dist/graph-2d.js +2019 -0
  41. package/dist/graph-2d.js.map +1 -0
  42. package/dist/graph-2d.mjs +6 -0
  43. package/dist/graph-2d.mjs.map +1 -0
  44. package/dist/host-LZH2FZ2N.mjs +1066 -0
  45. package/dist/host-LZH2FZ2N.mjs.map +1 -0
  46. package/dist/host-PIIDSMVE.mjs +3187 -0
  47. package/dist/host-PIIDSMVE.mjs.map +1 -0
  48. package/dist/host-VDNAJMLC.mjs +2864 -0
  49. package/dist/host-VDNAJMLC.mjs.map +1 -0
  50. package/dist/host-Z3TEJKZA.mjs +466 -0
  51. package/dist/host-Z3TEJKZA.mjs.map +1 -0
  52. package/dist/index.d.mts +30 -148
  53. package/dist/index.d.ts +30 -148
  54. package/dist/index.js +8370 -5614
  55. package/dist/index.js.map +1 -1
  56. package/dist/index.mjs +395 -7294
  57. package/dist/index.mjs.map +1 -1
  58. package/dist/latex.d.mts +15 -0
  59. package/dist/latex.d.ts +15 -0
  60. package/dist/latex.js +750 -0
  61. package/dist/latex.js.map +1 -0
  62. package/dist/latex.mjs +6 -0
  63. package/dist/latex.mjs.map +1 -0
  64. package/dist/types-CinstD7T.d.mts +110 -0
  65. package/dist/types-CinstD7T.d.ts +110 -0
  66. package/package.json +26 -7
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/stamps/graph-2d/serialize.ts","../src/stamps/graph-2d/evaluator.ts","../src/stamps/graph-2d/parser.ts","../src/stamps/graph-2d/editor/handlers.ts","../src/stamps/graph-2d/renderObjects.ts","../src/stamps/graph-2d/render.ts","../src/stamps/graph-2d/types.ts"],"names":["ALLOWED_FUNCTIONS"],"mappings":"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","file":"chunk-74VEEZBV.mjs","sourcesContent":["export interface SerializedGraph {\n version: 1;\n view: {\n xMin: number;\n xMax: number;\n yMin: number;\n yMax: number;\n showAxis: boolean;\n showGrid: boolean;\n };\n functions: SerializedFunction[];\n parameters: SerializedParameter[];\n points: SerializedPoint[];\n intersections: SerializedIntersection[];\n tangents: SerializedTangent[];\n}\n\nexport interface SerializedFunction {\n id: string;\n name: string;\n expression: string;\n color: string;\n visible: boolean;\n domain?: { min: number; max: number };\n}\n\nexport interface SerializedParameter {\n name: string;\n value: number;\n min: number;\n max: number;\n step: number;\n}\n\nexport interface SerializedPoint {\n id: string;\n functionId: string;\n x: number;\n label?: string;\n}\n\nexport interface SerializedIntersection {\n id: string;\n functionIdA: string;\n functionIdB: string;\n}\n\nexport interface SerializedTangent {\n id: string;\n pointId: string;\n}\n\nexport const EMPTY_GRAPH: SerializedGraph = {\n version: 1,\n view: { xMin: -10, xMax: 10, yMin: -10, yMax: 10, showAxis: true, showGrid: true },\n functions: [],\n parameters: [],\n points: [],\n intersections: [],\n tangents: [],\n};\n\nexport function stringifySerializedGraph(graph: SerializedGraph): string {\n return JSON.stringify(graph);\n}\n\nexport function parseSerializedGraph(jsonState: string): SerializedGraph | null {\n let raw: unknown;\n try {\n raw = JSON.parse(jsonState);\n } catch {\n return null;\n }\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null;\n const r = raw as Record<string, unknown>;\n if (r.version !== 1) return null;\n if (!r.view || typeof r.view !== 'object') return null;\n const v = r.view as Record<string, unknown>;\n if (\n typeof v.xMin !== 'number' ||\n typeof v.xMax !== 'number' ||\n typeof v.yMin !== 'number' ||\n typeof v.yMax !== 'number' ||\n typeof v.showAxis !== 'boolean' ||\n typeof v.showGrid !== 'boolean'\n ) {\n return null;\n }\n for (const key of ['functions', 'parameters', 'points', 'intersections', 'tangents']) {\n if (!Array.isArray(r[key])) return null;\n }\n return raw as SerializedGraph;\n}\n","/**\n * AST-based math expression evaluator — an toàn hơn `new Function`.\n *\n * Hỗ trợ:\n * - Toán tử: + - * / ^ và unary minus, dấu ngoặc ( )\n * - Số: integer, float, scientific notation (1e3, 1.2e-4)\n * - Hằng: pi → Math.PI, e → Math.E\n * - Biến: x (mặc định) + tham số đơn ký tự (a..z trừ x, e)\n * - Hàm: sin cos tan asin acos atan log ln exp sqrt abs floor ceil round\n *\n * KHÔNG dùng `new Function`, `eval`, `Function()`, hay bất kỳ dynamic code-gen nào.\n */\n\nconst ALLOWED_FUNCTIONS = {\n sin: Math.sin,\n cos: Math.cos,\n tan: Math.tan,\n asin: Math.asin,\n acos: Math.acos,\n atan: Math.atan,\n log: Math.log10, // log = log10 (khớp với rewriteToJs)\n ln: Math.log, // ln = log tự nhiên\n exp: Math.exp,\n sqrt: Math.sqrt,\n abs: Math.abs,\n floor: Math.floor,\n ceil: Math.ceil,\n round: Math.round,\n} as const;\n\nconst ALLOWED_CONSTANTS: Record<string, number> = {\n pi: Math.PI,\n e: Math.E,\n};\n\n// ----- Tokenizer ----------------------------------------------------------\n\ntype TokenType = 'NUMBER' | 'IDENT' | 'OP' | 'LPAREN' | 'RPAREN' | 'COMMA';\n\ninterface Token {\n type: TokenType;\n value: string;\n pos: number;\n}\n\nconst OPERATORS = new Set(['+', '-', '*', '/', '^']);\n\nexport function tokenize(src: string): Token[] {\n const tokens: Token[] = [];\n let i = 0;\n while (i < src.length) {\n const ch = src[i];\n\n // whitespace\n if (ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r') {\n i++;\n continue;\n }\n\n // number (int, float, scientific)\n if ((ch >= '0' && ch <= '9') || ch === '.') {\n let j = i;\n let hasDot = false;\n let hasExp = false;\n while (j < src.length) {\n const c = src[j];\n if (c >= '0' && c <= '9') {\n j++;\n } else if (c === '.' && !hasDot && !hasExp) {\n hasDot = true;\n j++;\n } else if ((c === 'e' || c === 'E') && !hasExp) {\n hasExp = true;\n j++;\n if (src[j] === '+' || src[j] === '-') j++;\n } else {\n break;\n }\n }\n const raw = src.slice(i, j);\n // raw must contain ít nhất 1 digit\n if (!/[0-9]/.test(raw)) {\n throw new Error(`Số không hợp lệ tại vị trí ${i}: \"${raw}\"`);\n }\n tokens.push({ type: 'NUMBER', value: raw, pos: i });\n i = j;\n continue;\n }\n\n // identifier (a-zA-Z, sau đó a-zA-Z0-9_)\n if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {\n let j = i;\n while (j < src.length) {\n const c = src[j];\n if (\n (c >= 'a' && c <= 'z') ||\n (c >= 'A' && c <= 'Z') ||\n (c >= '0' && c <= '9') ||\n c === '_'\n ) {\n j++;\n } else {\n break;\n }\n }\n tokens.push({ type: 'IDENT', value: src.slice(i, j), pos: i });\n i = j;\n continue;\n }\n\n if (OPERATORS.has(ch)) {\n tokens.push({ type: 'OP', value: ch, pos: i });\n i++;\n continue;\n }\n if (ch === '(') {\n tokens.push({ type: 'LPAREN', value: ch, pos: i });\n i++;\n continue;\n }\n if (ch === ')') {\n tokens.push({ type: 'RPAREN', value: ch, pos: i });\n i++;\n continue;\n }\n if (ch === ',') {\n tokens.push({ type: 'COMMA', value: ch, pos: i });\n i++;\n continue;\n }\n\n throw new Error(`Ký tự không hợp lệ tại vị trí ${i}: \"${ch}\"`);\n }\n return tokens;\n}\n\n// ----- AST ----------------------------------------------------------------\n\nexport type AstNode =\n | { kind: 'num'; value: number }\n | { kind: 'ident'; name: string }\n | { kind: 'unary'; op: '-' | '+'; arg: AstNode }\n | { kind: 'binary'; op: '+' | '-' | '*' | '/' | '^'; lhs: AstNode; rhs: AstNode }\n | { kind: 'call'; name: string; args: AstNode[] };\n\n// ----- Parser (Pratt-style precedence climbing) ---------------------------\n\nclass Parser {\n private pos = 0;\n constructor(private tokens: Token[]) {}\n\n private peek(): Token | undefined {\n return this.tokens[this.pos];\n }\n\n private consume(): Token {\n const t = this.tokens[this.pos++];\n if (!t) throw new Error('Cú pháp: hết token sớm');\n return t;\n }\n\n parseExpression(): AstNode {\n const node = this.parseAddSub();\n if (this.pos < this.tokens.length) {\n const t = this.tokens[this.pos];\n throw new Error(`Cú pháp: token thừa \"${t.value}\" tại vị trí ${t.pos}`);\n }\n return node;\n }\n\n // + - (left assoc)\n private parseAddSub(): AstNode {\n let lhs = this.parseMulDiv();\n while (true) {\n const t = this.peek();\n if (t && t.type === 'OP' && (t.value === '+' || t.value === '-')) {\n this.consume();\n const rhs = this.parseMulDiv();\n lhs = { kind: 'binary', op: t.value as '+' | '-', lhs, rhs };\n } else {\n break;\n }\n }\n return lhs;\n }\n\n // * / (left assoc)\n private parseMulDiv(): AstNode {\n let lhs = this.parseUnary();\n while (true) {\n const t = this.peek();\n if (t && t.type === 'OP' && (t.value === '*' || t.value === '/')) {\n this.consume();\n const rhs = this.parseUnary();\n lhs = { kind: 'binary', op: t.value as '*' | '/', lhs, rhs };\n } else {\n break;\n }\n }\n return lhs;\n }\n\n // unary + - (right assoc) sau đó parsePow\n private parseUnary(): AstNode {\n const t = this.peek();\n if (t && t.type === 'OP' && (t.value === '+' || t.value === '-')) {\n this.consume();\n const arg = this.parseUnary();\n return { kind: 'unary', op: t.value as '+' | '-', arg };\n }\n return this.parsePow();\n }\n\n // ^ (right assoc)\n private parsePow(): AstNode {\n const lhs = this.parsePrimary();\n const t = this.peek();\n if (t && t.type === 'OP' && t.value === '^') {\n this.consume();\n // right-assoc: parseUnary để chấp nhận `2^-x`\n const rhs = this.parseUnary();\n return { kind: 'binary', op: '^', lhs, rhs };\n }\n return lhs;\n }\n\n private parsePrimary(): AstNode {\n const t = this.peek();\n if (!t) throw new Error('Cú pháp: thiếu biểu thức');\n\n if (t.type === 'NUMBER') {\n this.consume();\n const v = Number(t.value);\n if (!Number.isFinite(v) && !Number.isNaN(v)) {\n // Vẫn cho phép Infinity literal hiếm khi xảy ra; nhưng safe-guard NaN\n }\n return { kind: 'num', value: v };\n }\n\n if (t.type === 'IDENT') {\n this.consume();\n const next = this.peek();\n if (next && next.type === 'LPAREN') {\n // Function call\n this.consume(); // (\n const args: AstNode[] = [];\n const lookahead = this.peek();\n if (!lookahead || lookahead.type !== 'RPAREN') {\n args.push(this.parseAddSub());\n while (true) {\n const nx = this.peek();\n if (nx && nx.type === 'COMMA') {\n this.consume();\n args.push(this.parseAddSub());\n } else {\n break;\n }\n }\n }\n const close = this.peek();\n if (!close || close.type !== 'RPAREN') {\n throw new Error(`Cú pháp: thiếu \")\" sau hàm \"${t.value}\"`);\n }\n this.consume(); // )\n return { kind: 'call', name: t.value, args };\n }\n return { kind: 'ident', name: t.value };\n }\n\n if (t.type === 'LPAREN') {\n this.consume();\n const inner = this.parseAddSub();\n const close = this.peek();\n if (!close || close.type !== 'RPAREN') {\n throw new Error('Cú pháp: thiếu \")\"');\n }\n this.consume();\n return inner;\n }\n\n throw new Error(`Cú pháp: token bất ngờ \"${t.value}\" tại vị trí ${t.pos}`);\n }\n}\n\nexport function parseAst(src: string): AstNode {\n const tokens = tokenize(src);\n if (tokens.length === 0) throw new Error('Biểu thức rỗng');\n const p = new Parser(tokens);\n return p.parseExpression();\n}\n\n// ----- Evaluator ----------------------------------------------------------\n\nexport interface EvalEnv {\n /** Giá trị của biến `x`. */\n x: number;\n /** Tham số đơn ký tự (a, b, c, ...) từ caller. */\n params: Record<string, number>;\n}\n\nexport function evaluate(node: AstNode, env: EvalEnv): number {\n switch (node.kind) {\n case 'num':\n return node.value;\n case 'ident': {\n const name = node.name;\n if (name === 'x') return env.x;\n if (Object.prototype.hasOwnProperty.call(ALLOWED_CONSTANTS, name)) {\n return ALLOWED_CONSTANTS[name];\n }\n // tham số 1 ký tự\n if (name.length === 1 && Object.prototype.hasOwnProperty.call(env.params, name)) {\n return env.params[name];\n }\n throw new Error(`Identifier không hợp lệ: \"${name}\"`);\n }\n case 'unary': {\n const v = evaluate(node.arg, env);\n return node.op === '-' ? -v : +v;\n }\n case 'binary': {\n const a = evaluate(node.lhs, env);\n const b = evaluate(node.rhs, env);\n switch (node.op) {\n case '+':\n return a + b;\n case '-':\n return a - b;\n case '*':\n return a * b;\n case '/':\n return a / b; // có thể trả Infinity/NaN — đúng theo IEEE 754\n case '^':\n return Math.pow(a, b);\n }\n // exhaustive — TS không bắt được vì op đã typed\n throw new Error(`Toán tử không hỗ trợ: \"${(node as { op: string }).op}\"`);\n }\n case 'call': {\n const fn = (ALLOWED_FUNCTIONS as Record<string, (...args: number[]) => number>)[node.name];\n if (typeof fn !== 'function') {\n throw new Error(`Hàm không hợp lệ: \"${node.name}\"`);\n }\n const args = node.args.map((a) => evaluate(a, env));\n return fn(...args);\n }\n }\n}\n\n/**\n * Lấy danh sách identifier đơn ký tự (ngoài `x`, `pi`, `e`) — đây là các tham số tự do.\n * Không tính identifier xuất hiện dưới dạng tên hàm (vd `sin` trong `sin(x)`).\n */\nexport function collectFreeVars(node: AstNode, out: Set<string> = new Set()): Set<string> {\n switch (node.kind) {\n case 'num':\n return out;\n case 'ident': {\n const name = node.name;\n if (name === 'x') return out;\n if (Object.prototype.hasOwnProperty.call(ALLOWED_CONSTANTS, name)) return out;\n if (name.length === 1) out.add(name);\n // identifier dài > 1 không phải hằng → caller validate sẽ catch\n return out;\n }\n case 'unary':\n return collectFreeVars(node.arg, out);\n case 'binary':\n collectFreeVars(node.lhs, out);\n collectFreeVars(node.rhs, out);\n return out;\n case 'call':\n for (const a of node.args) collectFreeVars(a, out);\n return out;\n }\n}\n\n/**\n * Kiểm tra mọi identifier xuất hiện đều thuộc whitelist (functions/constants/x/single-char-param).\n * Trả về null nếu OK, hoặc message lỗi.\n */\nexport function checkIdentifiers(node: AstNode): string | null {\n switch (node.kind) {\n case 'num':\n return null;\n case 'ident': {\n const name = node.name;\n if (name === 'x') return null;\n if (Object.prototype.hasOwnProperty.call(ALLOWED_CONSTANTS, name)) return null;\n if (name.length === 1) return null;\n return `Tên không hợp lệ: \"${name}\"`;\n }\n case 'unary':\n return checkIdentifiers(node.arg);\n case 'binary':\n return checkIdentifiers(node.lhs) ?? checkIdentifiers(node.rhs);\n case 'call': {\n if (!Object.prototype.hasOwnProperty.call(ALLOWED_FUNCTIONS, node.name)) {\n return `Tên hàm không hợp lệ: \"${node.name}\"`;\n }\n for (const a of node.args) {\n const e = checkIdentifiers(a);\n if (e) return e;\n }\n return null;\n }\n }\n}\n\nexport const ALLOWED_FUNCTION_NAMES: ReadonlySet<string> = new Set(Object.keys(ALLOWED_FUNCTIONS));\nexport const ALLOWED_CONSTANT_NAMES: ReadonlySet<string> = new Set(Object.keys(ALLOWED_CONSTANTS));\n","import {\n ALLOWED_FUNCTION_NAMES,\n checkIdentifiers,\n collectFreeVars,\n evaluate,\n parseAst,\n tokenize,\n type AstNode,\n} from './evaluator';\n\nconst ALLOWED_FUNCTIONS = ALLOWED_FUNCTION_NAMES;\n\n// Giữ whitelist ký tự để fail-closed sớm — không cho ; = [ ] ' \" ` { } \\ v.v.\nconst ALLOWED_CHARS = /^[a-zA-Z0-9_.+\\-*/^()\\s,]+$/;\n\nconst SUGGESTIONS: Record<string, string> = {\n tg: 'tan',\n arcsin: 'asin',\n arccos: 'acos',\n arctan: 'atan',\n};\n\nexport interface ParseResult {\n ok: boolean;\n error?: string;\n freeVars: Set<string>;\n}\n\nfunction errResult(message: string): ParseResult {\n return { ok: false, error: message, freeVars: new Set() };\n}\n\nexport function validate(expr: string): ParseResult {\n const trimmed = expr.trim();\n if (!trimmed) return errResult('Biểu thức rỗng');\n if (!ALLOWED_CHARS.test(trimmed)) return errResult('Ký tự không hợp lệ');\n\n // Tokenize trước để lấy danh sách IDENT thật sự (loại bỏ exponent `e` của số như `1e3`).\n // Pre-check identifier để cho ra error message thân thiện (suggestion tg→tan, ...).\n let tokens;\n try {\n tokens = tokenize(trimmed);\n } catch {\n return errResult('Lỗi cú pháp');\n }\n const earlyFree = new Set<string>();\n for (const tok of tokens) {\n if (tok.type !== 'IDENT') continue;\n const id = tok.value;\n if (id === 'x' || id === 'pi' || id === 'e') continue;\n if (ALLOWED_FUNCTIONS.has(id)) continue;\n if (id.length === 1) {\n earlyFree.add(id);\n continue;\n }\n const hint = SUGGESTIONS[id];\n return errResult(\n hint\n ? `Tên hàm không hợp lệ: \"${id}\". Bạn có ý là \"${hint}\" không?`\n : `Tên không hợp lệ: \"${id}\"`,\n );\n }\n\n let ast: AstNode;\n try {\n ast = parseAst(trimmed);\n } catch {\n return errResult('Lỗi cú pháp');\n }\n\n const idErr = checkIdentifiers(ast);\n if (idErr) return errResult(idErr);\n\n const freeVars = collectFreeVars(ast);\n // Hợp nhất với earlyFree (regex pass) — thường giống nhau, nhưng đảm bảo invariant.\n for (const v of earlyFree) freeVars.add(v);\n return { ok: true, freeVars };\n}\n\n// FUNCTION_REPLACEMENTS giữ longest-first để rewriteToJs không nhầm asin→a-sin.\nconst FUNCTION_REPLACEMENTS: Array<[string, string]> = [\n ['asin', 'Math.asin'],\n ['acos', 'Math.acos'],\n ['atan', 'Math.atan'],\n ['sqrt', 'Math.sqrt'],\n ['floor', 'Math.floor'],\n ['round', 'Math.round'],\n ['ceil', 'Math.ceil'],\n ['sin', 'Math.sin'],\n ['cos', 'Math.cos'],\n ['tan', 'Math.tan'],\n ['abs', 'Math.abs'],\n ['exp', 'Math.exp'],\n ['log', 'Math.log10'],\n ['ln', 'Math.log'],\n];\n\n/**\n * Chuyển expression user-input sang JS string tương đương.\n *\n * Function này chỉ dùng cho debug / hiển thị / tương thích ngược.\n * Runtime KHÔNG còn `eval` chuỗi này — `compile()` dùng AST evaluator.\n */\nexport function rewriteToJs(\n expr: string,\n params: Record<string, number>,\n): string {\n let s = expr.replace(/\\^/g, '**');\n s = s.replace(/\\bpi\\b/g, 'Math.PI');\n s = s.replace(/\\be\\b/g, 'Math.E');\n for (const [from, to] of FUNCTION_REPLACEMENTS) {\n s = s.replace(new RegExp(`\\\\b${from}\\\\b`, 'g'), to);\n }\n for (const [name, value] of Object.entries(params)) {\n if (name.length !== 1) continue;\n s = s.replace(new RegExp(`\\\\b${name}\\\\b`, 'g'), `(${value})`);\n }\n return s;\n}\n\nexport function compile(\n expr: string,\n paramValues: Record<string, number>,\n): ((x: number) => number) | { error: string } {\n const v = validate(expr);\n if (!v.ok) return { error: v.error ?? 'Invalid' };\n let ast: AstNode;\n try {\n ast = parseAst(expr.trim());\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) };\n }\n return (x: number) => {\n try {\n const y = evaluate(ast, { x, params: paramValues });\n return typeof y === 'number' ? y : NaN;\n } catch {\n return NaN;\n }\n };\n}\n","import type {\n SerializedGraph,\n SerializedPoint,\n SerializedIntersection,\n SerializedTangent,\n} from '../serialize';\nimport { compile } from '../parser';\n\nexport interface ClickContext {\n x: number;\n y: number;\n functionId?: string;\n}\n\nexport function addPointOnCurve(\n graph: SerializedGraph,\n ctx: ClickContext,\n idFactory: () => string,\n): SerializedGraph {\n if (!ctx.functionId) return graph;\n const point: SerializedPoint = {\n id: idFactory(),\n functionId: ctx.functionId,\n x: ctx.x,\n };\n return { ...graph, points: [...graph.points, point] };\n}\n\nexport function addIntersection(\n graph: SerializedGraph,\n functionIdA: string,\n functionIdB: string,\n idFactory: () => string,\n): SerializedGraph {\n if (functionIdA === functionIdB) return graph;\n const exists = graph.intersections.some(\n (i) =>\n (i.functionIdA === functionIdA && i.functionIdB === functionIdB) ||\n (i.functionIdA === functionIdB && i.functionIdB === functionIdA),\n );\n if (exists) return graph;\n const intersection: SerializedIntersection = {\n id: idFactory(),\n functionIdA,\n functionIdB,\n };\n return { ...graph, intersections: [...graph.intersections, intersection] };\n}\n\nexport function addTangent(\n graph: SerializedGraph,\n pointId: string,\n idFactory: () => string,\n): SerializedGraph {\n const exists = graph.tangents.some((t) => t.pointId === pointId);\n if (exists) return graph;\n const tangent: SerializedTangent = { id: idFactory(), pointId };\n return { ...graph, tangents: [...graph.tangents, tangent] };\n}\n\n/**\n * Numerical derivative via centered difference. Dùng cho tangent tool.\n */\nexport function numericalDerivative(\n expression: string,\n paramValues: Record<string, number>,\n x: number,\n h = 1e-4,\n): number {\n const fn = compile(expression, paramValues);\n if (typeof fn !== 'function') return NaN;\n const y1 = fn(x - h);\n const y2 = fn(x + h);\n return (y2 - y1) / (2 * h);\n}\n","import type { SerializedGraph } from './serialize';\nimport { compile } from './parser';\nimport { numericalDerivative } from './editor/handlers';\n\n/**\n * Render tất cả objects (functions, points, intersections, tangents) lên board JSXGraph.\n *\n * Pure function — không giữ state, dùng cho one-shot render (render.ts).\n * MiniBoard giữ syncObjects riêng để diff/track curves theo id.\n */\nexport function renderGraphObjects(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n board: any,\n graph: SerializedGraph,\n): void {\n const paramMap: Record<string, number> = {};\n for (const p of graph.parameters) paramMap[p.name] = p.value;\n\n // Functions\n for (const f of graph.functions) {\n if (!f.visible) continue;\n const compiled = compile(f.expression, paramMap);\n if (typeof compiled !== 'function') continue;\n const domain = f.domain ?? { min: graph.view.xMin, max: graph.view.xMax };\n board.create('functiongraph', [compiled, domain.min, domain.max], {\n strokeColor: f.color,\n strokeWidth: 2,\n name: f.name,\n withLabel: false,\n highlight: false,\n });\n }\n\n // Points\n for (const point of graph.points) {\n const fn = graph.functions.find((f) => f.id === point.functionId);\n if (!fn || !fn.visible) continue;\n const compiled = compile(fn.expression, paramMap);\n if (typeof compiled !== 'function') continue;\n const y = compiled(point.x);\n board.create('point', [point.x, y], {\n name: point.label ?? '',\n size: 3,\n fillColor: fn.color,\n strokeColor: fn.color,\n withLabel: !!point.label,\n });\n }\n\n // Intersections\n for (const inter of graph.intersections) {\n const fa = graph.functions.find((f) => f.id === inter.functionIdA);\n const fb = graph.functions.find((f) => f.id === inter.functionIdB);\n if (!fa || !fb || !fa.visible || !fb.visible) continue;\n const cfa = compile(fa.expression, paramMap);\n const cfb = compile(fb.expression, paramMap);\n if (typeof cfa !== 'function' || typeof cfb !== 'function') continue;\n const roots = scanRoots((x: number) => cfa(x) - cfb(x), graph.view.xMin, graph.view.xMax);\n for (const x of roots) {\n board.create('point', [x, cfa(x)], {\n size: 3,\n fillColor: '#000',\n strokeColor: '#000',\n });\n }\n }\n\n // Tangents\n for (const tan of graph.tangents) {\n const pt = graph.points.find((p) => p.id === tan.pointId);\n if (!pt) continue;\n const fn = graph.functions.find((f) => f.id === pt.functionId);\n if (!fn || !fn.visible) continue;\n const slope = numericalDerivative(fn.expression, paramMap, pt.x);\n const cfn = compile(fn.expression, paramMap);\n if (typeof cfn !== 'function' || !Number.isFinite(slope)) continue;\n const y0 = cfn(pt.x);\n const x1 = graph.view.xMin;\n const x2 = graph.view.xMax;\n board.create(\n 'line',\n [\n [x1, slope * (x1 - pt.x) + y0],\n [x2, slope * (x2 - pt.x) + y0],\n ],\n {\n strokeColor: fn.color,\n strokeWidth: 1,\n dash: 2,\n straightFirst: false,\n straightLast: false,\n },\n );\n }\n}\n\nfunction scanRoots(\n fn: (x: number) => number,\n xMin: number,\n xMax: number,\n samples = 200,\n): number[] {\n const roots: number[] = [];\n const step = (xMax - xMin) / samples;\n let prevX = xMin;\n let prevY = fn(prevX);\n for (let i = 1; i <= samples; i++) {\n const x = xMin + i * step;\n const y = fn(x);\n if (Number.isFinite(prevY) && Number.isFinite(y) && prevY * y < 0) {\n let a = prevX;\n let b = x;\n let ya = prevY;\n for (let j = 0; j < 30; j++) {\n const m = (a + b) / 2;\n const ym = fn(m);\n if (Math.abs(ym) < 1e-6) {\n a = b = m;\n break;\n }\n if (ya * ym < 0) {\n b = m;\n } else {\n a = m;\n ya = ym;\n }\n }\n roots.push((a + b) / 2);\n }\n prevX = x;\n prevY = y;\n }\n return roots;\n}\n","import { parseSerializedGraph } from './serialize';\nimport { renderGraphObjects } from './renderObjects';\n\n/**\n * Re-render SVG cho graph-2d stamp từ jsonState đã serialize.\n *\n * Dùng cho:\n * 1. Insert vào whiteboard (lúc user nhấn Chèn).\n * 2. Restore stamp file sau khi reload (Excalidraw không persist binary).\n *\n * Pattern mirror `geometry-2d/render.ts`:\n * - LUÔN dùng light palette. Excalidraw apply CSS invert filter trong dark mode.\n * - Đặt JXG.Options.text.display='internal' để label render dưới dạng SVG, không HTML overlay.\n * - Offscreen div 600×400 cố định; cleanup sau khi clone SVG outerHTML.\n */\nexport async function renderGraph2dSvgFromState(jsonState: string): Promise<string> {\n const parsed = parseSerializedGraph(jsonState);\n if (!parsed) throw new Error('renderGraph2dSvgFromState: jsonState corrupt');\n\n const JXG = (await import('jsxgraph')).default;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const opts = (JXG as any).Options;\n if (opts) {\n opts.text = opts.text || {};\n opts.text.display = 'internal';\n opts.text.useASCIIMathML = false;\n opts.text.useMathJax = false;\n opts.text.useKatex = false;\n opts.label = opts.label || {};\n opts.label.display = 'internal';\n }\n\n const container = document.createElement('div');\n container.id = `jxg_graph2d_off_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n container.style.cssText =\n 'position:absolute;top:-99999px;left:-99999px;width:600px;height:400px;visibility:hidden;pointer-events:none;';\n document.body.appendChild(container);\n\n let board: unknown = null;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n board = (JXG as any).JSXGraph.initBoard(container.id, {\n boundingbox: [parsed.view.xMin, parsed.view.yMax, parsed.view.xMax, parsed.view.yMin],\n axis: parsed.view.showAxis,\n grid: parsed.view.showGrid,\n showCopyright: false,\n showNavigation: false,\n keepAspectRatio: false,\n });\n renderGraphObjects(board, parsed);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (board as any).update();\n const svgEl = container.querySelector('svg');\n if (!svgEl) throw new Error('renderGraph2dSvgFromState: no svg generated');\n return svgEl.outerHTML;\n } finally {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (board) (JXG as any).JSXGraph.freeBoard(board);\n } catch {\n /* ignore */\n }\n if (container.parentNode) container.parentNode.removeChild(container);\n }\n}\n","import type { BaseStampCustomData } from '../shared/types';\n\nexport interface Graph2DCustomData extends BaseStampCustomData {\n kind: 'graph2d';\n version: 1;\n jsonState: string;\n svgWidth: number;\n svgHeight: number;\n}\n\nexport function isGraph2DCustomData(data: unknown): data is Graph2DCustomData {\n if (!data || typeof data !== 'object') return false;\n const d = data as Partial<Graph2DCustomData>;\n return d.kind === 'graph2d' && d.version === 1 && typeof d.jsonState === 'string';\n}\n"]}
@@ -0,0 +1,39 @@
1
+ "use client";
2
+ import { isLatexCustomData, renderLatexToSvg } from './chunk-X5R72SSJ.mjs';
3
+ import { lazy } from 'react';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ var LatexStampHost = lazy(
7
+ () => import('./host-Z3TEJKZA.mjs').then((m) => ({ default: m.LatexStampHost }))
8
+ );
9
+ var LatexIcon = /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M17 5 H7 L13 12 L7 19 H17" }) });
10
+ var latexStamp = {
11
+ kind: "latex",
12
+ shortcutKey: "l",
13
+ toolbarLabel: "L",
14
+ toolbarTitle: "Ch\xE8n c\xF4ng th\u1EE9c LaTeX (L)",
15
+ toolbarIcon: LatexIcon,
16
+ toolbarTestId: "stamp-toolbar-latex",
17
+ matchesCustomData: isLatexCustomData,
18
+ async renderSvgFromCustomData(data) {
19
+ if (!isLatexCustomData(data)) {
20
+ throw new Error("latexStamp.renderSvgFromCustomData: customData kh\xF4ng ph\u1EA3i latex");
21
+ }
22
+ return renderLatexToSvg(data.src, data.displayMode);
23
+ },
24
+ async restoreFileFromCustomData(element) {
25
+ const data = element.customData;
26
+ const fileId = element.fileId;
27
+ if (!data || !fileId) return null;
28
+ if (!isLatexCustomData(data)) return null;
29
+ const svgString = await renderLatexToSvg(data.src, data.displayMode);
30
+ const utf8 = unescape(encodeURIComponent(svgString));
31
+ const dataURL = "data:image/svg+xml;base64," + (typeof btoa !== "undefined" ? btoa(utf8) : Buffer.from(utf8).toString("base64"));
32
+ return { fileId, dataURL, mimeType: "image/svg+xml" };
33
+ },
34
+ Host: LatexStampHost
35
+ };
36
+
37
+ export { latexStamp };
38
+ //# sourceMappingURL=chunk-7P7SQFOW.mjs.map
39
+ //# sourceMappingURL=chunk-7P7SQFOW.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/stamps/latex/index.tsx"],"names":[],"mappings":";;;;AAaA,IAAM,cAAA,GAAiB,IAAA;AAAA,EAAK,MAC1B,OAAO,qBAAQ,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,cAAA,EAAe,CAAE;AAC9D,CAAA;AAEA,IAAM,SAAA,mBACJ,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,IAAA,EAAK,QAAO,IAAA,EAAK,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,MAAA,EAAO,gBAAe,WAAA,EAAY,KAAA,EAAM,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,aAAA,EAAY,MAAA,EAC3J,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,2BAAA,EAA4B,CAAA,EACtC,CAAA;AAGK,IAAM,UAAA,GAAwB;AAAA,EACnC,IAAA,EAAM,OAAA;AAAA,EACN,WAAA,EAAa,GAAA;AAAA,EACb,YAAA,EAAc,GAAA;AAAA,EACd,YAAA,EAAc,qCAAA;AAAA,EACd,WAAA,EAAa,SAAA;AAAA,EACb,aAAA,EAAe,qBAAA;AAAA,EACf,iBAAA,EAAmB,iBAAA;AAAA,EACnB,MAAM,wBAAwB,IAAA,EAAM;AAClC,IAAA,IAAI,CAAC,iBAAA,CAAkB,IAAI,CAAA,EAAG;AAC5B,MAAA,MAAM,IAAI,MAAM,yEAAiE,CAAA;AAAA,IACnF;AACA,IAAA,OAAO,gBAAA,CAAiB,IAAA,CAAK,GAAA,EAAK,IAAA,CAAK,WAAW,CAAA;AAAA,EACpD,CAAA;AAAA,EACA,MAAM,0BAA0B,OAAA,EAA4C;AAC1E,IAAA,MAAM,OAAO,OAAA,CAAQ,UAAA;AACrB,IAAA,MAAM,SAAU,OAAA,CAAuC,MAAA;AACvD,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,MAAA,EAAQ,OAAO,IAAA;AAC7B,IAAA,IAAI,CAAC,iBAAA,CAAkB,IAAI,CAAA,EAAG,OAAO,IAAA;AACrC,IAAA,MAAM,YAAY,MAAM,gBAAA,CAAiB,IAAA,CAAK,GAAA,EAAK,KAAK,WAAW,CAAA;AACnE,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,kBAAA,CAAmB,SAAS,CAAC,CAAA;AACnD,IAAA,MAAM,OAAA,GAAU,4BAAA,IACd,OAAO,IAAA,KAAS,WAAA,GAAc,IAAA,CAAK,IAAI,CAAA,GAAI,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,SAAS,QAAQ,CAAA,CAAA;AAEhF,IAAA,OAAO,EAAE,MAAA,EAAQ,OAAA,EAAS,QAAA,EAAU,eAAA,EAAgB;AAAA,EACtD,CAAA;AAAA,EACA,IAAA,EAAM;AACR","file":"chunk-7P7SQFOW.mjs","sourcesContent":["'use client';\n\nimport { lazy } from 'react';\nimport { renderLatexToSvg } from './render';\nimport type {\n RestoredStampFile,\n StampType,\n} from '../shared/types';\nimport { isLatexCustomData, type LatexCustomData } from './types';\n\nexport { isLatexCustomData };\nexport type { LatexCustomData };\n\nconst LatexStampHost = lazy(() =>\n import('./host').then((m) => ({ default: m.LatexStampHost })),\n);\n\nconst LatexIcon = (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M17 5 H7 L13 12 L7 19 H17\" />\n </svg>\n);\n\nexport const latexStamp: StampType = {\n kind: 'latex',\n shortcutKey: 'l',\n toolbarLabel: 'L',\n toolbarTitle: 'Chèn công thức LaTeX (L)',\n toolbarIcon: LatexIcon,\n toolbarTestId: 'stamp-toolbar-latex',\n matchesCustomData: isLatexCustomData,\n async renderSvgFromCustomData(data) {\n if (!isLatexCustomData(data)) {\n throw new Error('latexStamp.renderSvgFromCustomData: customData không phải latex');\n }\n return renderLatexToSvg(data.src, data.displayMode);\n },\n async restoreFileFromCustomData(element): Promise<RestoredStampFile | null> {\n const data = element.customData as LatexCustomData | undefined;\n const fileId = (element as { fileId?: string | null }).fileId;\n if (!data || !fileId) return null;\n if (!isLatexCustomData(data)) return null;\n const svgString = await renderLatexToSvg(data.src, data.displayMode);\n const utf8 = unescape(encodeURIComponent(svgString));\n const dataURL = 'data:image/svg+xml;base64,' + (\n typeof btoa !== 'undefined' ? btoa(utf8) : Buffer.from(utf8).toString('base64')\n );\n return { fileId, dataURL, mimeType: 'image/svg+xml' };\n },\n Host: LatexStampHost,\n};\n"]}
@@ -0,0 +1,111 @@
1
+ "use client";
2
+ // src/stamps/shared/svgToImage.ts
3
+ async function hashString(input) {
4
+ if (typeof crypto !== "undefined" && crypto.subtle) {
5
+ const buf = new TextEncoder().encode(input);
6
+ const digest = await crypto.subtle.digest("SHA-256", buf);
7
+ return Array.from(new Uint8Array(digest)).slice(0, 16).map((b) => b.toString(16).padStart(2, "0")).join("");
8
+ }
9
+ let h1 = 2166136261;
10
+ let h2 = 3421674724;
11
+ for (let i = 0; i < input.length; i++) {
12
+ const c = input.charCodeAt(i);
13
+ h1 ^= c;
14
+ h1 = Math.imul(h1, 16777619);
15
+ h2 ^= c + i;
16
+ h2 = Math.imul(h2, 1099511628211 & 4294967295);
17
+ }
18
+ return (h1 >>> 0).toString(16).padStart(8, "0") + (h2 >>> 0).toString(16).padStart(8, "0");
19
+ }
20
+ function parseSize(svg, attr) {
21
+ const re = new RegExp(`<svg[^>]*\\s${attr}="(\\d+(?:\\.\\d+)?)`, "i");
22
+ const m = svg.match(re);
23
+ if (m) return Math.max(1, Math.round(parseFloat(m[1])));
24
+ const vb = svg.match(/viewBox="([\d.\s-]+)"/i);
25
+ if (vb) {
26
+ const parts = vb[1].trim().split(/\s+/).map(parseFloat);
27
+ if (parts.length === 4) return Math.max(1, Math.round(attr === "width" ? parts[2] : parts[3]));
28
+ }
29
+ return attr === "width" ? 200 : 100;
30
+ }
31
+ async function svgToImageElement(svg) {
32
+ const width = parseSize(svg, "width");
33
+ const height = parseSize(svg, "height");
34
+ const utf8 = unescape(encodeURIComponent(svg));
35
+ const dataURL = "data:image/svg+xml;base64," + btoa(utf8);
36
+ const fileId = await hashString(dataURL);
37
+ return { dataURL, fileId, width, height, mimeType: "image/svg+xml" };
38
+ }
39
+
40
+ // src/stamps/shared/insertImage.ts
41
+ var clearAppStateAfterInsert = () => ({
42
+ selectedElementIds: {},
43
+ croppingElementId: null
44
+ });
45
+ function buildStampImageElement(api, fileId, width, height, customData, x, y) {
46
+ const appState = api?.getAppState() ?? { scrollX: 0, scrollY: 0, width: 800, height: 600, zoom: { value: 1 } };
47
+ const cx = x ?? appState.scrollX + (appState.width ?? 800) / 2 / (appState.zoom?.value ?? 1) - width / 2;
48
+ const cy = y ?? appState.scrollY + (appState.height ?? 600) / 2 / (appState.zoom?.value ?? 1) - height / 2;
49
+ return {
50
+ type: "image",
51
+ id: "stamp_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8),
52
+ x: cx,
53
+ y: cy,
54
+ width,
55
+ height,
56
+ fileId,
57
+ customData,
58
+ angle: 0,
59
+ strokeColor: "transparent",
60
+ backgroundColor: "transparent",
61
+ fillStyle: "solid",
62
+ strokeWidth: 1,
63
+ strokeStyle: "solid",
64
+ roughness: 0,
65
+ opacity: 100,
66
+ groupIds: [],
67
+ roundness: null,
68
+ seed: Math.floor(Math.random() * 1e9),
69
+ versionNonce: 0,
70
+ version: 1,
71
+ isDeleted: false,
72
+ boundElements: null,
73
+ updated: Date.now(),
74
+ link: null,
75
+ locked: false,
76
+ status: "saved",
77
+ scale: [1, 1]
78
+ };
79
+ }
80
+ async function insertStampImage(api, opts) {
81
+ const { dataURL, fileId, width, height, mimeType } = await svgToImageElement(opts.svgString);
82
+ api.addFiles([{ id: fileId, dataURL, mimeType, created: Date.now() }]);
83
+ const customData = opts.makeCustomData(width, height);
84
+ const elements = api.getSceneElements();
85
+ const editingId = opts.editingElementId ?? null;
86
+ if (editingId) {
87
+ const updated = elements.map(
88
+ (e) => e.id === editingId ? { ...e, fileId, customData, width, height } : e
89
+ );
90
+ api.updateScene({ elements: updated, appState: clearAppStateAfterInsert() });
91
+ return { fileId, width, height, elementId: editingId };
92
+ }
93
+ const newElement = buildStampImageElement(
94
+ api,
95
+ fileId,
96
+ width,
97
+ height,
98
+ customData,
99
+ opts.position?.x,
100
+ opts.position?.y
101
+ );
102
+ api.updateScene({
103
+ elements: [...elements, newElement],
104
+ appState: clearAppStateAfterInsert()
105
+ });
106
+ return { fileId, width, height, elementId: newElement.id };
107
+ }
108
+
109
+ export { insertStampImage };
110
+ //# sourceMappingURL=chunk-C6SCVOMC.mjs.map
111
+ //# sourceMappingURL=chunk-C6SCVOMC.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/stamps/shared/svgToImage.ts","../src/stamps/shared/insertImage.ts"],"names":[],"mappings":"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","file":"chunk-C6SCVOMC.mjs","sourcesContent":["export interface SvgImageResult {\n dataURL: string;\n fileId: string;\n width: number;\n height: number;\n mimeType: 'image/svg+xml';\n}\n\nasync function hashString(input: string): Promise<string> {\n if (typeof crypto !== 'undefined' && crypto.subtle) {\n const buf = new TextEncoder().encode(input);\n const digest = await crypto.subtle.digest('SHA-256', buf);\n return Array.from(new Uint8Array(digest)).slice(0, 16).map(b => b.toString(16).padStart(2, '0')).join('');\n }\n // Double-hash FNV-1a (32-bit chained) → 16 hex chars\n let h1 = 0x811c9dc5;\n let h2 = 0xcbf29ce4;\n for (let i = 0; i < input.length; i++) {\n const c = input.charCodeAt(i);\n h1 ^= c;\n h1 = Math.imul(h1, 0x01000193);\n h2 ^= c + i;\n h2 = Math.imul(h2, 0x100000001b3 & 0xffffffff);\n }\n return (h1 >>> 0).toString(16).padStart(8, '0') + (h2 >>> 0).toString(16).padStart(8, '0');\n}\n\nfunction parseSize(svg: string, attr: 'width' | 'height'): number {\n const re = new RegExp(`<svg[^>]*\\\\s${attr}=\"(\\\\d+(?:\\\\.\\\\d+)?)`, 'i');\n const m = svg.match(re);\n if (m) return Math.max(1, Math.round(parseFloat(m[1])));\n // Fallback: try viewBox\n const vb = svg.match(/viewBox=\"([\\d.\\s-]+)\"/i);\n if (vb) {\n const parts = vb[1].trim().split(/\\s+/).map(parseFloat);\n if (parts.length === 4) return Math.max(1, Math.round(attr === 'width' ? parts[2] : parts[3]));\n }\n return attr === 'width' ? 200 : 100;\n}\n\n// SVG → image element data. Skips canvas rasterization entirely (canvas with\n// foreignObject + external resources gets tainted by browser security model,\n// blocking toDataURL). Excalidraw renders SVG natively via mimeType 'image/svg+xml'.\nexport async function svgToImageElement(svg: string): Promise<SvgImageResult> {\n const width = parseSize(svg, 'width');\n const height = parseSize(svg, 'height');\n // Use UTF-8 safe base64 encoding (btoa fails on non-Latin1 chars)\n const utf8 = unescape(encodeURIComponent(svg));\n const dataURL = 'data:image/svg+xml;base64,' + btoa(utf8);\n const fileId = await hashString(dataURL);\n return { dataURL, fileId, width, height, mimeType: 'image/svg+xml' };\n}\n","import { svgToImageElement } from './svgToImage';\nimport type { ExcalidrawElement } from '../../types';\n\n// Excalidraw imperative API — không có public type chính xác. Giữ untyped ở\n// boundary và yêu cầu caller pass đúng instance.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype ExApi = any;\n\nexport interface InsertStampImageOptions {\n /** SVG string sẵn sàng render (geometry export hoặc katex render). */\n svgString: string;\n /**\n * Factory tạo customData từ kích thước SVG vừa đo được. Đặt làm factory để\n * các stamp loại khác nhau (geometry cần svgWidth/svgHeight, latex không cần)\n * đều có thể chèn data tuỳ ý.\n */\n makeCustomData: (width: number, height: number) => unknown;\n /** Nếu đang re-edit, id của element cũ — sẽ update thay vì tạo mới. */\n editingElementId?: string | null;\n /** Vị trí gốc (lúc tạo mới). Bỏ qua khi đang re-edit. */\n position?: { x?: number; y?: number };\n}\n\nexport interface InsertStampImageResult {\n fileId: string;\n width: number;\n height: number;\n /** Element id (mới hoặc cũ tuỳ flow). */\n elementId: string;\n}\n\n// Bỏ qua appState (selectedElementIds + croppingElementId) sau khi insert để\n// Excalidraw không tự động bật crop mode cho element vừa thêm → tránh trigger\n// crop intercept handler vô tận.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst clearAppStateAfterInsert = (): any => ({\n selectedElementIds: {},\n croppingElementId: null,\n});\n\nfunction buildStampImageElement(\n api: ExApi,\n fileId: string,\n width: number,\n height: number,\n customData: unknown,\n x?: number,\n y?: number,\n) {\n const appState =\n api?.getAppState() ?? { scrollX: 0, scrollY: 0, width: 800, height: 600, zoom: { value: 1 } };\n const cx =\n x ?? appState.scrollX + (appState.width ?? 800) / 2 / (appState.zoom?.value ?? 1) - width / 2;\n const cy =\n y ?? appState.scrollY + (appState.height ?? 600) / 2 / (appState.zoom?.value ?? 1) - height / 2;\n return {\n type: 'image' as const,\n id: 'stamp_' + Date.now() + '_' + Math.random().toString(36).slice(2, 8),\n x: cx,\n y: cy,\n width,\n height,\n fileId,\n customData,\n angle: 0,\n strokeColor: 'transparent',\n backgroundColor: 'transparent',\n fillStyle: 'solid',\n strokeWidth: 1,\n strokeStyle: 'solid',\n roughness: 0,\n opacity: 100,\n groupIds: [],\n roundness: null,\n seed: Math.floor(Math.random() * 1e9),\n versionNonce: 0,\n version: 1,\n isDeleted: false,\n boundElements: null,\n updated: Date.now(),\n link: null,\n locked: false,\n status: 'saved',\n scale: [1, 1],\n };\n}\n\n/**\n * Chèn (hoặc thay thế) một stamp image vào Excalidraw scene.\n *\n * Flow:\n * 1. svgToImageElement(svg) → fileId + dataURL + kích thước\n * 2. api.addFiles([...]) — đăng ký SVG dưới fileId\n * 3. Nếu editingElementId → update element cũ (giữ position, đổi fileId+customData+size)\n * Còn lại → tạo image element mới ở giữa viewport (hoặc position truyền vào)\n *\n * Đoạn này trước đây nằm 2 chỗ (handleGeometryInsert + handleLatexInsert),\n * chỉ khác customData. Gộp lại để: thêm stamp type mới chỉ cần truyền\n * `makeCustomData`.\n */\nexport async function insertStampImage(\n api: ExApi,\n opts: InsertStampImageOptions,\n): Promise<InsertStampImageResult> {\n const { dataURL, fileId, width, height, mimeType } = await svgToImageElement(opts.svgString);\n api.addFiles([{ id: fileId, dataURL, mimeType, created: Date.now() }]);\n const customData = opts.makeCustomData(width, height);\n\n const elements = api.getSceneElements() as readonly ExcalidrawElement[];\n const editingId = opts.editingElementId ?? null;\n\n if (editingId) {\n const updated = elements.map((e) =>\n e.id === editingId ? { ...e, fileId, customData, width, height } : e,\n );\n api.updateScene({ elements: updated, appState: clearAppStateAfterInsert() });\n return { fileId, width, height, elementId: editingId };\n }\n\n const newElement = buildStampImageElement(\n api,\n fileId,\n width,\n height,\n customData,\n opts.position?.x,\n opts.position?.y,\n );\n api.updateScene({\n elements: [...elements, newElement],\n appState: clearAppStateAfterInsert(),\n });\n return { fileId, width, height, elementId: newElement.id };\n}\n"]}
@@ -0,0 +1,103 @@
1
+ "use client";
2
+ import { paletteFor } from './chunk-HTBLO5JO.mjs';
3
+
4
+ // src/stamps/geometry-3d/serialize.ts
5
+ function isGeometry3DCustomData(data) {
6
+ if (!data || typeof data !== "object") return false;
7
+ const d = data;
8
+ return d.kind === "geometry3d" && (d.version === 1 || d.version === 2) && typeof d.jsonState === "string";
9
+ }
10
+ function serializeBoard3D(state) {
11
+ return JSON.stringify(state);
12
+ }
13
+ function parseSerializedBoard3D(json) {
14
+ const parsed = JSON.parse(json);
15
+ if (!parsed || typeof parsed !== "object") {
16
+ throw new Error("parseSerializedBoard3D: not an object");
17
+ }
18
+ const p = parsed;
19
+ if (p.version !== 1 && p.version !== 2) {
20
+ throw new Error(`parseSerializedBoard3D: unsupported version ${String(p.version)}`);
21
+ }
22
+ if (!Array.isArray(p.elements)) {
23
+ throw new Error("parseSerializedBoard3D: elements missing");
24
+ }
25
+ return parsed;
26
+ }
27
+
28
+ // src/stamps/geometry-3d/editor/theme.ts
29
+ function paletteFor2(isDark) {
30
+ const base = paletteFor(isDark);
31
+ return {
32
+ ...base,
33
+ view3dBg: isDark ? "#1a1a1a" : "#ffffff",
34
+ axisX: "#d63b3b",
35
+ axisY: "#2d8a2d",
36
+ axisZ: "#2d6dd6"
37
+ };
38
+ }
39
+ var DEFAULT_VIEW3D = {
40
+ azimuth: 0.7,
41
+ elevation: 0.4,
42
+ bbox3D: [-3, -3, -3, 3, 3, 3]
43
+ };
44
+ var VIEW3D_ATTRS = (isDark) => {
45
+ const p = paletteFor2(isDark);
46
+ const axisLabel = (color) => ({
47
+ strokeColor: color,
48
+ fontSize: 14,
49
+ offset: [10, 0]
50
+ });
51
+ return {
52
+ az: { slider: { visible: false }, point2: { visible: false } },
53
+ el: { slider: { visible: false } },
54
+ projection: "central",
55
+ // GeoGebra-style: axes pass through origin (0,0,0) instead of bbox border.
56
+ axesPosition: "center",
57
+ xAxis: {
58
+ strokeColor: p.axisX,
59
+ strokeWidth: 2,
60
+ lastArrow: { type: 2, size: 8 },
61
+ name: "x",
62
+ withLabel: true,
63
+ label: axisLabel(p.axisX)
64
+ },
65
+ yAxis: {
66
+ strokeColor: p.axisY,
67
+ strokeWidth: 2,
68
+ lastArrow: { type: 2, size: 8 },
69
+ name: "y",
70
+ withLabel: true,
71
+ label: axisLabel(p.axisY)
72
+ },
73
+ zAxis: {
74
+ strokeColor: p.axisZ,
75
+ strokeWidth: 2,
76
+ lastArrow: { type: 2, size: 8 },
77
+ name: "z",
78
+ withLabel: true,
79
+ label: axisLabel(p.axisZ)
80
+ },
81
+ // GeoGebra-style: hide ALL bbox wall planes; the XY ground plane is drawn
82
+ // explicitly at z=0 via the helper below (so it coincides with Ox/Oy).
83
+ xPlaneRear: { visible: false, mesh3d: { visible: false } },
84
+ yPlaneRear: { visible: false, mesh3d: { visible: false } },
85
+ zPlaneRear: { visible: false, mesh3d: { visible: false } }
86
+ };
87
+ };
88
+ var GROUND_PLANE_ATTRS = (isDark) => ({
89
+ fillColor: isDark ? "#2a2a2a" : "#e6e6e6",
90
+ fillOpacity: isDark ? 0.5 : 0.55,
91
+ strokeColor: isDark ? "#3a3a3a" : "#cfcfcf",
92
+ strokeOpacity: 0.7,
93
+ strokeWidth: 1,
94
+ fixed: true,
95
+ highlight: false,
96
+ withLabel: false,
97
+ layer: 0
98
+ });
99
+ var GROUND_PLANE_RANGE = [-3, 3];
100
+
101
+ export { DEFAULT_VIEW3D, GROUND_PLANE_ATTRS, GROUND_PLANE_RANGE, VIEW3D_ATTRS, isGeometry3DCustomData, paletteFor2 as paletteFor, parseSerializedBoard3D, serializeBoard3D };
102
+ //# sourceMappingURL=chunk-DU2NFHRR.mjs.map
103
+ //# sourceMappingURL=chunk-DU2NFHRR.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/stamps/geometry-3d/serialize.ts","../src/stamps/geometry-3d/editor/theme.ts"],"names":["paletteFor"],"mappings":"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","file":"chunk-DU2NFHRR.mjs","sourcesContent":["import type { BaseStampCustomData } from '../shared/types';\nimport type { Constraint } from './editor/scene/types';\n\nexport interface Geometry3DCustomData extends BaseStampCustomData {\n kind: 'geometry3d';\n version: 1 | 2;\n jsonState: string;\n svgWidth: number;\n svgHeight: number;\n}\n\nexport function isGeometry3DCustomData(data: unknown): data is Geometry3DCustomData {\n if (!data || typeof data !== 'object') return false;\n const d = data as Partial<Geometry3DCustomData>;\n return (\n d.kind === 'geometry3d' &&\n (d.version === 1 || d.version === 2) &&\n typeof d.jsonState === 'string'\n );\n}\n\nexport type Element3DType =\n | 'point3d'\n | 'line3d'\n | 'plane3d'\n | 'polygon3d'\n | 'sphere3d'\n | 'text3d';\n\nexport interface SerializedElement3D {\n type: Element3DType;\n /**\n * Parents passed to JSXGraph view.create. Either literal values (numbers,\n * strings) or `\"@id:<id>\"` placeholder strings referencing earlier created\n * objects in the log (resolved at deserialize time).\n */\n parents: unknown[];\n attributes: Record<string, unknown>;\n id: string;\n label?: string;\n /** v2 only — present on point3d elements to encode the surface constraint. */\n constraint?: Constraint;\n}\n\nexport interface SerializedBoard3D {\n version: 1 | 2;\n bbox: [number, number, number, number];\n view: {\n azimuth: number;\n elevation: number;\n bbox3D: [number, number, number, number, number, number];\n };\n showAxes: boolean;\n showMesh: boolean;\n elements: SerializedElement3D[];\n}\n\nexport function serializeBoard3D(state: SerializedBoard3D): string {\n return JSON.stringify(state);\n}\n\nexport function parseSerializedBoard3D(json: string): SerializedBoard3D {\n const parsed = JSON.parse(json) as unknown;\n if (!parsed || typeof parsed !== 'object') {\n throw new Error('parseSerializedBoard3D: not an object');\n }\n const p = parsed as Partial<SerializedBoard3D>;\n if (p.version !== 1 && p.version !== 2) {\n throw new Error(`parseSerializedBoard3D: unsupported version ${String(p.version)}`);\n }\n if (!Array.isArray(p.elements)) {\n throw new Error('parseSerializedBoard3D: elements missing');\n }\n return parsed as SerializedBoard3D;\n}\n","import {\n paletteFor as palette2D,\n type GeomPalette,\n} from '../../geometry-2d/editor/theme';\n\nexport type Geom3DPalette = GeomPalette & {\n view3dBg: string;\n axisX: string;\n axisY: string;\n axisZ: string;\n};\n\nexport function paletteFor(isDark: boolean): Geom3DPalette {\n const base = palette2D(isDark);\n return {\n ...base,\n view3dBg: isDark ? '#1a1a1a' : '#ffffff',\n axisX: '#d63b3b',\n axisY: '#2d8a2d',\n axisZ: '#2d6dd6',\n };\n}\n\nexport const DEFAULT_VIEW3D: {\n azimuth: number;\n elevation: number;\n bbox3D: [number, number, number, number, number, number];\n} = {\n azimuth: 0.7,\n elevation: 0.4,\n bbox3D: [-3, -3, -3, 3, 3, 3],\n};\n\nexport const VIEW3D_ATTRS = (isDark: boolean) => {\n const p = paletteFor(isDark);\n const axisLabel = (color: string) => ({\n strokeColor: color,\n fontSize: 14,\n offset: [10, 0] as [number, number],\n });\n return {\n az: { slider: { visible: false }, point2: { visible: false } },\n el: { slider: { visible: false } },\n projection: 'central' as const,\n // GeoGebra-style: axes pass through origin (0,0,0) instead of bbox border.\n axesPosition: 'center' as const,\n xAxis: {\n strokeColor: p.axisX,\n strokeWidth: 2,\n lastArrow: { type: 2, size: 8 },\n name: 'x',\n withLabel: true,\n label: axisLabel(p.axisX),\n },\n yAxis: {\n strokeColor: p.axisY,\n strokeWidth: 2,\n lastArrow: { type: 2, size: 8 },\n name: 'y',\n withLabel: true,\n label: axisLabel(p.axisY),\n },\n zAxis: {\n strokeColor: p.axisZ,\n strokeWidth: 2,\n lastArrow: { type: 2, size: 8 },\n name: 'z',\n withLabel: true,\n label: axisLabel(p.axisZ),\n },\n // GeoGebra-style: hide ALL bbox wall planes; the XY ground plane is drawn\n // explicitly at z=0 via the helper below (so it coincides with Ox/Oy).\n xPlaneRear: { visible: false, mesh3d: { visible: false } },\n yPlaneRear: { visible: false, mesh3d: { visible: false } },\n zPlaneRear: { visible: false, mesh3d: { visible: false } },\n };\n};\n\nexport const GROUND_PLANE_ATTRS = (isDark: boolean) => ({\n fillColor: isDark ? '#2a2a2a' : '#e6e6e6',\n fillOpacity: isDark ? 0.5 : 0.55,\n strokeColor: isDark ? '#3a3a3a' : '#cfcfcf',\n strokeOpacity: 0.7,\n strokeWidth: 1,\n fixed: true,\n highlight: false,\n withLabel: false,\n layer: 0,\n});\n\n/** XY ground plane extent (square around origin in user units). */\nexport const GROUND_PLANE_RANGE: [number, number] = [-3, 3];\n"]}
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ import { isGeometryCustomData, renderGeometrySvgFromState } from './chunk-KEYZ5EZT.mjs';
3
+ import { lazy } from 'react';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ var GeometryStampHost = lazy(
7
+ () => import('./host-VDNAJMLC.mjs').then((m) => ({ default: m.GeometryStampHost }))
8
+ );
9
+ var GeometryIcon = /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
10
+ /* @__PURE__ */ jsx("polygon", { points: "4,20 20,20 12,5" }),
11
+ /* @__PURE__ */ jsx("circle", { cx: "4", cy: "20", r: "1.4", fill: "currentColor", stroke: "none" }),
12
+ /* @__PURE__ */ jsx("circle", { cx: "20", cy: "20", r: "1.4", fill: "currentColor", stroke: "none" }),
13
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "5", r: "1.4", fill: "currentColor", stroke: "none" })
14
+ ] });
15
+ var geometryStamp = {
16
+ kind: "geometry",
17
+ shortcutKey: "g",
18
+ toolbarLabel: "G",
19
+ toolbarTitle: "Ch\xE8n h\xECnh h\u1ECDc (G)",
20
+ toolbarIcon: GeometryIcon,
21
+ toolbarTestId: "stamp-toolbar-geometry",
22
+ matchesCustomData: isGeometryCustomData,
23
+ async renderSvgFromCustomData(data) {
24
+ if (!isGeometryCustomData(data)) {
25
+ throw new Error("geometryStamp.renderSvgFromCustomData: customData kh\xF4ng ph\u1EA3i geometry");
26
+ }
27
+ return renderGeometrySvgFromState(data.jsonState);
28
+ },
29
+ async restoreFileFromCustomData(element) {
30
+ const data = element.customData;
31
+ const fileId = element.fileId;
32
+ if (!data || !fileId) return null;
33
+ if (!isGeometryCustomData(data)) return null;
34
+ const svgString = await renderGeometrySvgFromState(data.jsonState);
35
+ const utf8 = unescape(encodeURIComponent(svgString));
36
+ const dataURL = "data:image/svg+xml;base64," + (typeof btoa !== "undefined" ? btoa(utf8) : Buffer.from(utf8).toString("base64"));
37
+ return { fileId, dataURL, mimeType: "image/svg+xml" };
38
+ },
39
+ Host: GeometryStampHost
40
+ };
41
+
42
+ export { geometryStamp };
43
+ //# sourceMappingURL=chunk-DU3RHKT5.mjs.map
44
+ //# sourceMappingURL=chunk-DU3RHKT5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/stamps/geometry-2d/index.tsx"],"names":[],"mappings":";;;;AAgBA,IAAM,iBAAA,GAAoB,IAAA;AAAA,EAAK,MAC7B,OAAO,qBAAQ,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,iBAAA,EAAkB,CAAE;AACjE,CAAA;AAEA,IAAM,YAAA,wBACH,KAAA,EAAA,EAAI,KAAA,EAAM,MAAK,MAAA,EAAO,IAAA,EAAK,SAAQ,WAAA,EAAY,IAAA,EAAK,QAAO,MAAA,EAAO,cAAA,EAAe,aAAY,KAAA,EAAM,aAAA,EAAc,SAAQ,cAAA,EAAe,OAAA,EAAQ,eAAY,MAAA,EAC3J,QAAA,EAAA;AAAA,kBAAA,GAAA,CAAC,SAAA,EAAA,EAAQ,QAAO,iBAAA,EAAkB,CAAA;AAAA,kBAClC,GAAA,CAAC,QAAA,EAAA,EAAO,EAAA,EAAG,GAAA,EAAI,EAAA,EAAG,IAAA,EAAK,CAAA,EAAE,KAAA,EAAM,IAAA,EAAK,cAAA,EAAe,MAAA,EAAO,MAAA,EAAO,CAAA;AAAA,kBACjE,GAAA,CAAC,QAAA,EAAA,EAAO,EAAA,EAAG,IAAA,EAAK,EAAA,EAAG,IAAA,EAAK,CAAA,EAAE,KAAA,EAAM,IAAA,EAAK,cAAA,EAAe,MAAA,EAAO,MAAA,EAAO,CAAA;AAAA,kBAClE,GAAA,CAAC,QAAA,EAAA,EAAO,EAAA,EAAG,IAAA,EAAK,EAAA,EAAG,GAAA,EAAI,CAAA,EAAE,KAAA,EAAM,IAAA,EAAK,cAAA,EAAe,MAAA,EAAO,MAAA,EAAO;AAAA,CAAA,EACnE,CAAA;AAGK,IAAM,aAAA,GAA2B;AAAA,EACtC,IAAA,EAAM,UAAA;AAAA,EACN,WAAA,EAAa,GAAA;AAAA,EACb,YAAA,EAAc,GAAA;AAAA,EACd,YAAA,EAAc,8BAAA;AAAA,EACd,WAAA,EAAa,YAAA;AAAA,EACb,aAAA,EAAe,wBAAA;AAAA,EACf,iBAAA,EAAmB,oBAAA;AAAA,EACnB,MAAM,wBAAwB,IAAA,EAAM;AAClC,IAAA,IAAI,CAAC,oBAAA,CAAqB,IAAI,CAAA,EAAG;AAC/B,MAAA,MAAM,IAAI,MAAM,+EAAuE,CAAA;AAAA,IACzF;AACA,IAAA,OAAO,0BAAA,CAA2B,KAAK,SAAS,CAAA;AAAA,EAClD,CAAA;AAAA,EACA,MAAM,0BAA0B,OAAA,EAA4C;AAC1E,IAAA,MAAM,OAAO,OAAA,CAAQ,UAAA;AACrB,IAAA,MAAM,SAAU,OAAA,CAAuC,MAAA;AACvD,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,MAAA,EAAQ,OAAO,IAAA;AAC7B,IAAA,IAAI,CAAC,oBAAA,CAAqB,IAAI,CAAA,EAAG,OAAO,IAAA;AACxC,IAAA,MAAM,SAAA,GAAY,MAAM,0BAAA,CAA2B,IAAA,CAAK,SAAS,CAAA;AACjE,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,kBAAA,CAAmB,SAAS,CAAC,CAAA;AACnD,IAAA,MAAM,OAAA,GAAU,4BAAA,IACd,OAAO,IAAA,KAAS,WAAA,GAAc,IAAA,CAAK,IAAI,CAAA,GAAI,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,SAAS,QAAQ,CAAA,CAAA;AAEhF,IAAA,OAAO,EAAE,MAAA,EAAQ,OAAA,EAAS,QAAA,EAAU,eAAA,EAAgB;AAAA,EACtD,CAAA;AAAA,EACA,IAAA,EAAM;AACR","file":"chunk-DU3RHKT5.mjs","sourcesContent":["'use client';\n\nimport { lazy, type ReactNode } from 'react';\nimport { renderGeometrySvgFromState } from './render';\nimport type {\n RestoredStampFile,\n StampType,\n} from '../shared/types';\nimport {\n isGeometryCustomData,\n type GeometryCustomData,\n} from './types';\n\nexport { isGeometryCustomData };\nexport type { GeometryCustomData };\n\nconst GeometryStampHost = lazy(() =>\n import('./host').then((m) => ({ default: m.GeometryStampHost })),\n);\n\nconst GeometryIcon: ReactNode = (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <polygon points=\"4,20 20,20 12,5\" />\n <circle cx=\"4\" cy=\"20\" r=\"1.4\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"20\" cy=\"20\" r=\"1.4\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"12\" cy=\"5\" r=\"1.4\" fill=\"currentColor\" stroke=\"none\" />\n </svg>\n);\n\nexport const geometryStamp: StampType = {\n kind: 'geometry',\n shortcutKey: 'g',\n toolbarLabel: 'G',\n toolbarTitle: 'Chèn hình học (G)',\n toolbarIcon: GeometryIcon,\n toolbarTestId: 'stamp-toolbar-geometry',\n matchesCustomData: isGeometryCustomData,\n async renderSvgFromCustomData(data) {\n if (!isGeometryCustomData(data)) {\n throw new Error('geometryStamp.renderSvgFromCustomData: customData không phải geometry');\n }\n return renderGeometrySvgFromState(data.jsonState);\n },\n async restoreFileFromCustomData(element): Promise<RestoredStampFile | null> {\n const data = element.customData as GeometryCustomData | undefined;\n const fileId = (element as { fileId?: string | null }).fileId;\n if (!data || !fileId) return null;\n if (!isGeometryCustomData(data)) return null;\n const svgString = await renderGeometrySvgFromState(data.jsonState);\n const utf8 = unescape(encodeURIComponent(svgString));\n const dataURL = 'data:image/svg+xml;base64,' + (\n typeof btoa !== 'undefined' ? btoa(utf8) : Buffer.from(utf8).toString('base64')\n );\n return { fileId, dataURL, mimeType: 'image/svg+xml' };\n },\n Host: GeometryStampHost,\n};\n"]}
@@ -0,0 +1,41 @@
1
+ "use client";
2
+ // src/stamps/geometry-2d/editor/theme.ts
3
+ var themeStroke = (dark) => dark ? "#e2e8f0" : "#0f172a";
4
+ var themeAxis = (dark) => dark ? "#cbd5e1" : "#94a3b8";
5
+ var themeGrid = (dark) => dark ? "#475569" : "#e2e8f0";
6
+ var themeLabel = (dark) => dark ? "#e2e8f0" : "#000000";
7
+ function paletteFor(isDark) {
8
+ return {
9
+ stroke: themeStroke(isDark),
10
+ axis: themeAxis(isDark),
11
+ grid: themeGrid(isDark),
12
+ label: themeLabel(isDark)
13
+ };
14
+ }
15
+ var SENTINEL_MAP = {
16
+ "@stroke": "stroke",
17
+ "@axis": "axis",
18
+ "@grid": "grid",
19
+ "@label": "label"
20
+ };
21
+ function resolveAttrColors(attrs, palette) {
22
+ if (typeof attrs === "string") {
23
+ const key = SENTINEL_MAP[attrs];
24
+ return key ? palette[key] : attrs;
25
+ }
26
+ if (Array.isArray(attrs)) {
27
+ return attrs.map((a) => resolveAttrColors(a, palette));
28
+ }
29
+ if (attrs && typeof attrs === "object") {
30
+ const out = {};
31
+ for (const [k, v] of Object.entries(attrs)) {
32
+ out[k] = resolveAttrColors(v, palette);
33
+ }
34
+ return out;
35
+ }
36
+ return attrs;
37
+ }
38
+
39
+ export { paletteFor, resolveAttrColors, themeAxis, themeGrid, themeLabel };
40
+ //# sourceMappingURL=chunk-HTBLO5JO.mjs.map
41
+ //# sourceMappingURL=chunk-HTBLO5JO.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/stamps/geometry-2d/editor/theme.ts"],"names":[],"mappings":";AAWO,IAAM,WAAA,GAAc,CAAC,IAAA,KAAmB,IAAA,GAAO,SAAA,GAAY,SAAA;AAC3D,IAAM,SAAA,GAAY,CAAC,IAAA,KAAmB,IAAA,GAAO,SAAA,GAAY;AACzD,IAAM,SAAA,GAAY,CAAC,IAAA,KAAmB,IAAA,GAAO,SAAA,GAAY;AACzD,IAAM,UAAA,GAAa,CAAC,IAAA,KAAmB,IAAA,GAAO,SAAA,GAAY;AAS1D,SAAS,WAAW,MAAA,EAA8B;AACvD,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,YAAY,MAAM,CAAA;AAAA,IAC1B,IAAA,EAAM,UAAU,MAAM,CAAA;AAAA,IACtB,IAAA,EAAM,UAAU,MAAM,CAAA;AAAA,IACtB,KAAA,EAAO,WAAW,MAAM;AAAA,GAC1B;AACF;AAEA,IAAM,YAAA,GAAkD;AAAA,EACtD,SAAA,EAAW,QAAA;AAAA,EACX,OAAA,EAAS,MAAA;AAAA,EACT,OAAA,EAAS,MAAA;AAAA,EACT,QAAA,EAAU;AACZ,CAAA;AAOO,SAAS,iBAAA,CAAqB,OAAU,OAAA,EAAyB;AACtE,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,MAAM,GAAA,GAAM,aAAa,KAAK,CAAA;AAC9B,IAAA,OAAQ,GAAA,GAAM,OAAA,CAAQ,GAAG,CAAA,GAAI,KAAA;AAAA,EAC/B;AACA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,IAAA,OAAO,MAAM,GAAA,CAAI,CAAC,MAAM,iBAAA,CAAkB,CAAA,EAAG,OAAO,CAAC,CAAA;AAAA,EACvD;AACA,EAAA,IAAI,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACtC,IAAA,MAAM,MAA+B,EAAC;AACtC,IAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAgC,CAAA,EAAG;AACrE,MAAA,GAAA,CAAI,CAAC,CAAA,GAAI,iBAAA,CAAkB,CAAA,EAAG,OAAO,CAAA;AAAA,IACvC;AACA,IAAA,OAAO,GAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAA;AACT","file":"chunk-HTBLO5JO.mjs","sourcesContent":["// Theme-aware palette cho geometry stamps.\n//\n// Creation log của JSXGraphMiniBoard lưu attrs dưới dạng \"sentinel\" string\n// (`@stroke`, `@axis`, `@grid`, `@label`) thay vì màu cụ thể. Khi:\n// 1. Editor render real-time → resolve theo `isDark` của editor.\n// 2. Offscreen re-render (sau reload / sau khi switch theme) → resolve theo\n// `isDark` của canvas Excalidraw hiện tại.\n//\n// Nhờ vậy stamp tự đổi màu khi user switch dark/light, giống các nét vẽ\n// native của Excalidraw.\n\nexport const themeStroke = (dark: boolean) => (dark ? '#e2e8f0' : '#0f172a');\nexport const themeAxis = (dark: boolean) => (dark ? '#cbd5e1' : '#94a3b8');\nexport const themeGrid = (dark: boolean) => (dark ? '#475569' : '#e2e8f0');\nexport const themeLabel = (dark: boolean) => (dark ? '#e2e8f0' : '#000000');\n\nexport interface GeomPalette {\n stroke: string;\n axis: string;\n grid: string;\n label: string;\n}\n\nexport function paletteFor(isDark: boolean): GeomPalette {\n return {\n stroke: themeStroke(isDark),\n axis: themeAxis(isDark),\n grid: themeGrid(isDark),\n label: themeLabel(isDark),\n };\n}\n\nconst SENTINEL_MAP: Record<string, keyof GeomPalette> = {\n '@stroke': 'stroke',\n '@axis': 'axis',\n '@grid': 'grid',\n '@label': 'label',\n};\n\n/**\n * Walk attrs object/array/string và thay sentinel bằng màu thực từ palette.\n * Đệ quy để hỗ trợ nested attrs (ví dụ polygon's `borders.strokeColor`).\n * Trả về object mới — input giữ nguyên (immutable, an toàn cho log).\n */\nexport function resolveAttrColors<T>(attrs: T, palette: GeomPalette): T {\n if (typeof attrs === 'string') {\n const key = SENTINEL_MAP[attrs];\n return (key ? palette[key] : attrs) as T;\n }\n if (Array.isArray(attrs)) {\n return attrs.map((a) => resolveAttrColors(a, palette)) as unknown as T;\n }\n if (attrs && typeof attrs === 'object') {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(attrs as Record<string, unknown>)) {\n out[k] = resolveAttrColors(v, palette);\n }\n return out as T;\n }\n return attrs;\n}\n"]}