@xom11/whiteboard 0.29.0 → 0.31.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 (93) hide show
  1. package/dist/ai.d.mts +259 -33
  2. package/dist/ai.d.ts +259 -33
  3. package/dist/ai.js +5424 -470
  4. package/dist/ai.js.map +1 -1
  5. package/dist/ai.mjs +4971 -351
  6. package/dist/ai.mjs.map +1 -1
  7. package/dist/catalog.json +5 -5
  8. package/dist/{chunk-V3YJ6JFL.mjs → chunk-44JY2AKC.mjs} +3 -3
  9. package/dist/{chunk-V3YJ6JFL.mjs.map → chunk-44JY2AKC.mjs.map} +1 -1
  10. package/dist/{chunk-GEC2D2EQ.mjs → chunk-BMYC2ILT.mjs} +4 -4
  11. package/dist/{chunk-GEC2D2EQ.mjs.map → chunk-BMYC2ILT.mjs.map} +1 -1
  12. package/dist/{chunk-PPKHCRRE.mjs → chunk-C76SOFXF.mjs} +3 -3
  13. package/dist/{chunk-PPKHCRRE.mjs.map → chunk-C76SOFXF.mjs.map} +1 -1
  14. package/dist/{chunk-IHUFOV7L.mjs → chunk-CH6SFONH.mjs} +15 -3
  15. package/dist/chunk-CH6SFONH.mjs.map +1 -0
  16. package/dist/{chunk-E6EDOPGT.mjs → chunk-DWIEVCGK.mjs} +254 -16
  17. package/dist/chunk-DWIEVCGK.mjs.map +1 -0
  18. package/dist/{chunk-SZDAS7LK.mjs → chunk-IE2GGHNF.mjs} +131 -81
  19. package/dist/chunk-IE2GGHNF.mjs.map +1 -0
  20. package/dist/{chunk-ZTQBUKLJ.mjs → chunk-JJ4FPCBE.mjs} +142 -22
  21. package/dist/chunk-JJ4FPCBE.mjs.map +1 -0
  22. package/dist/{chunk-QRUAEXLR.mjs → chunk-K5BS2H56.mjs} +5 -5
  23. package/dist/{chunk-QRUAEXLR.mjs.map → chunk-K5BS2H56.mjs.map} +1 -1
  24. package/dist/{chunk-BNBOIDO5.mjs → chunk-K7VJU7LQ.mjs} +3 -3
  25. package/dist/{chunk-BNBOIDO5.mjs.map → chunk-K7VJU7LQ.mjs.map} +1 -1
  26. package/dist/{chunk-H22OZYTW.mjs → chunk-KOXOC2FI.mjs} +48 -39
  27. package/dist/chunk-KOXOC2FI.mjs.map +1 -0
  28. package/dist/{chunk-CXHNVYMD.mjs → chunk-KWDBVLST.mjs} +5 -5
  29. package/dist/{chunk-CXHNVYMD.mjs.map → chunk-KWDBVLST.mjs.map} +1 -1
  30. package/dist/{chunk-OQIQNKPQ.mjs → chunk-LTLLQUMN.mjs} +4 -4
  31. package/dist/{chunk-OQIQNKPQ.mjs.map → chunk-LTLLQUMN.mjs.map} +1 -1
  32. package/dist/chunk-QK6OVDLC.mjs +103 -0
  33. package/dist/chunk-QK6OVDLC.mjs.map +1 -0
  34. package/dist/{chunk-QGNU34T7.mjs → chunk-QLQ4MJNO.mjs} +10 -4
  35. package/dist/chunk-QLQ4MJNO.mjs.map +1 -0
  36. package/dist/{chunk-BU5KLO3P.mjs → chunk-T3N4BSJV.mjs} +4 -4
  37. package/dist/{chunk-BU5KLO3P.mjs.map → chunk-T3N4BSJV.mjs.map} +1 -1
  38. package/dist/{chunk-5JM35CXV.mjs → chunk-TMRFSOM7.mjs} +4 -4
  39. package/dist/{chunk-5JM35CXV.mjs.map → chunk-TMRFSOM7.mjs.map} +1 -1
  40. package/dist/geometry-2d.d.mts +1 -1
  41. package/dist/geometry-2d.d.ts +1 -1
  42. package/dist/geometry-2d.js +841 -204
  43. package/dist/geometry-2d.js.map +1 -1
  44. package/dist/geometry-2d.mjs +5 -5
  45. package/dist/geometry-3d.d.mts +1 -1
  46. package/dist/geometry-3d.d.ts +1 -1
  47. package/dist/geometry-3d.js +172 -22
  48. package/dist/geometry-3d.js.map +1 -1
  49. package/dist/geometry-3d.mjs +4 -4
  50. package/dist/graph-2d.d.mts +1 -1
  51. package/dist/graph-2d.d.ts +1 -1
  52. package/dist/graph-2d.js +307 -100
  53. package/dist/graph-2d.js.map +1 -1
  54. package/dist/graph-2d.mjs +7 -7
  55. package/dist/handleExtractProblem-BrDY9ifM.d.mts +58 -0
  56. package/dist/handleExtractProblem-BrDY9ifM.d.ts +58 -0
  57. package/dist/{host-HOSJHQ5H.mjs → host-4FIUNIDQ.mjs} +13 -12
  58. package/dist/host-4FIUNIDQ.mjs.map +1 -0
  59. package/dist/{host-2ISGVO7O.mjs → host-4ZB4XD4S.mjs} +9 -8
  60. package/dist/host-4ZB4XD4S.mjs.map +1 -0
  61. package/dist/{host-ZQCDAT6O.mjs → host-H2IGOKJU.mjs} +3 -3
  62. package/dist/{host-ZQCDAT6O.mjs.map → host-H2IGOKJU.mjs.map} +1 -1
  63. package/dist/{host-HKMZSCIT.mjs → host-KMWP7KBT.mjs} +286 -74
  64. package/dist/host-KMWP7KBT.mjs.map +1 -0
  65. package/dist/index.d.mts +3 -2
  66. package/dist/index.d.ts +3 -2
  67. package/dist/index.js +849 -206
  68. package/dist/index.js.map +1 -1
  69. package/dist/index.mjs +22 -21
  70. package/dist/index.mjs.map +1 -1
  71. package/dist/latex.d.mts +1 -1
  72. package/dist/latex.d.ts +1 -1
  73. package/dist/latex.js +8 -2
  74. package/dist/latex.js.map +1 -1
  75. package/dist/latex.mjs +1 -1
  76. package/dist/render-NMS7OAV6.mjs +10 -0
  77. package/dist/{render-ZX2O2IK7.mjs.map → render-NMS7OAV6.mjs.map} +1 -1
  78. package/dist/serialize-PGHQZEPV.mjs +9 -0
  79. package/dist/{serialize-N4G6RFBB.mjs.map → serialize-PGHQZEPV.mjs.map} +1 -1
  80. package/dist/{types-C3FjpoUi.d.ts → types-tePd94vW.d.mts} +8 -0
  81. package/dist/{types-C3FjpoUi.d.mts → types-tePd94vW.d.ts} +8 -0
  82. package/package.json +2 -1
  83. package/dist/chunk-E6EDOPGT.mjs.map +0 -1
  84. package/dist/chunk-H22OZYTW.mjs.map +0 -1
  85. package/dist/chunk-IHUFOV7L.mjs.map +0 -1
  86. package/dist/chunk-QGNU34T7.mjs.map +0 -1
  87. package/dist/chunk-SZDAS7LK.mjs.map +0 -1
  88. package/dist/chunk-ZTQBUKLJ.mjs.map +0 -1
  89. package/dist/host-2ISGVO7O.mjs.map +0 -1
  90. package/dist/host-HKMZSCIT.mjs.map +0 -1
  91. package/dist/host-HOSJHQ5H.mjs.map +0 -1
  92. package/dist/render-ZX2O2IK7.mjs +0 -10
  93. package/dist/serialize-N4G6RFBB.mjs +0 -9
@@ -1,13 +1,13 @@
1
1
  "use client";
2
- import { renderGraphSvgFromState } from './chunk-CXHNVYMD.mjs';
2
+ import { renderGraphSvgFromState } from './chunk-KWDBVLST.mjs';
3
3
  import { isGraph2DCustomData } from './chunk-O4WIZFRQ.mjs';
4
- import { parseSceneState } from './chunk-V3YJ6JFL.mjs';
4
+ import { parseSceneState } from './chunk-44JY2AKC.mjs';
5
5
  import { svgToStampFile } from './chunk-5UTGXHLJ.mjs';
6
6
  import { lazy } from 'react';
7
7
  import { jsxs, jsx } from 'react/jsx-runtime';
8
8
 
9
9
  var Graph2DStampHost = lazy(
10
- () => import('./host-HOSJHQ5H.mjs').then((m) => ({ default: m.Graph2DStampHost }))
10
+ () => import('./host-4FIUNIDQ.mjs').then((m) => ({ default: m.Graph2DStampHost }))
11
11
  );
12
12
  var Graph2DIcon = /* @__PURE__ */ jsxs(
13
13
  "svg",
@@ -57,5 +57,5 @@ var graph2dStamp = {
57
57
  };
58
58
 
59
59
  export { graph2dStamp };
60
- //# sourceMappingURL=chunk-QRUAEXLR.mjs.map
61
- //# sourceMappingURL=chunk-QRUAEXLR.mjs.map
60
+ //# sourceMappingURL=chunk-K5BS2H56.mjs.map
61
+ //# sourceMappingURL=chunk-K5BS2H56.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stamps/graph-2d/index.tsx"],"names":[],"mappings":";;;;;;;AAUA,IAAM,gBAAA,GAAmB,IAAA;AAAA,EAAK,MAC5B,OAAO,qBAAQ,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,gBAAA,EAAiB,CAAE;AAChE,CAAA;AAEA,IAAM,WAAA,mBACJ,IAAA;AAAA,EAAC,KAAA;AAAA,EAAA;AAAA,IACC,KAAA,EAAM,IAAA;AAAA,IACN,MAAA,EAAO,IAAA;AAAA,IACP,OAAA,EAAQ,WAAA;AAAA,IACR,IAAA,EAAK,MAAA;AAAA,IACL,MAAA,EAAO,cAAA;AAAA,IACP,WAAA,EAAY,KAAA;AAAA,IACZ,aAAA,EAAc,OAAA;AAAA,IACd,cAAA,EAAe,OAAA;AAAA,IACf,aAAA,EAAY,MAAA;AAAA,IAEZ,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,GAAE,iBAAA,EAAkB,CAAA;AAAA,sBAC1B,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,4BAAA,EAA6B;AAAA;AAAA;AACvC,CAAA;AAGK,IAAM,YAAA,GAA6C;AAAA,EACxD,IAAA,EAAM,SAAA;AAAA,EACN,WAAA,EAAa,GAAA;AAAA,EACb,YAAA,EAAc,WAAA;AAAA,EACd,YAAA,EAAc,sCAAA;AAAA,EACd,WAAA,EAAa,WAAA;AAAA,EACb,aAAA,EAAe,eAAA;AAAA,EACf,YAAA,EAAc,IAAA;AAAA,EACd,iBAAA,EAAmB,mBAAA;AAAA,EAEnB,MAAM,wBAAwB,IAAA,EAAgC;AAC5D,IAAA,IAAI,CAAC,mBAAA,CAAoB,IAAI,CAAA,EAAG;AAC9B,MAAA,MAAM,IAAI,MAAM,gFAAwE,CAAA;AAAA,IAC1F;AACA,IAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,IAAA,CAAK,SAAS,CAAA;AAC5C,IAAA,IAAI,CAAC,KAAA,EAAO,MAAM,IAAI,MAAM,2EAA8D,CAAA;AAC1F,IAAA,OAAO,uBAAA,CAAwB,OAAO,KAAK,CAAA;AAAA,EAC7C,CAAA;AAAA,EAEA,MAAM,0BAA0B,OAAA,EAA4C;AAC1E,IAAA,MAAM,OAAO,OAAA,CAAQ,UAAA;AACrB,IAAA,MAAM,SAAU,OAAA,CAAuC,MAAA;AACvD,IAAA,IAAI,CAAC,MAAA,IAAU,CAAC,mBAAA,CAAoB,IAAI,GAAG,OAAO,IAAA;AAClD,IAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,IAAA,CAAK,SAAS,CAAA;AAC5C,IAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AACnB,IAAA,MAAM,SAAA,GAAY,MAAM,uBAAA,CAAwB,KAAA,EAAO,KAAK,CAAA;AAC5D,IAAA,OAAO,cAAA,CAAe,WAAW,MAAM,CAAA;AAAA,EACzC,CAAA;AAAA,EAEA,IAAA,EAAM;AACR","file":"chunk-QRUAEXLR.mjs","sourcesContent":["'use client';\nimport { lazy, type ReactNode } from 'react';\nimport { renderGraphSvgFromState } from './render';\nimport { isGraph2DCustomData, type Graph2DCustomData } from './types';\nimport { parseSceneState } from './serialize';\nimport { svgToStampFile } from '../shared/svgToStampFile';\nimport type { RestoredStampFile, StampType } from '../shared/types';\n\nexport type { Graph2DCustomData };\n\nconst Graph2DStampHost = lazy(() =>\n import('./host').then((m) => ({ default: m.Graph2DStampHost })),\n);\n\nconst Graph2DIcon: ReactNode = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M3 3L3 21L21 21\" />\n <path d=\"M6 16Q9 8 12 10Q15 12 18 6\" />\n </svg>\n);\n\nexport const graph2dStamp: StampType<Graph2DCustomData> = {\n kind: 'graph2d',\n shortcutKey: 'h',\n toolbarLabel: '📈',\n toolbarTitle: 'Chèn đồ thị 2D (H)',\n toolbarIcon: Graph2DIcon,\n toolbarTestId: 'graph2d-stamp',\n experimental: true,\n matchesCustomData: isGraph2DCustomData,\n\n async renderSvgFromCustomData(data: unknown): Promise<string> {\n if (!isGraph2DCustomData(data)) {\n throw new Error('graph2dStamp.renderSvgFromCustomData: customData không phải graph2d v2');\n }\n const state = parseSceneState(data.jsonState);\n if (!state) throw new Error('graph2dStamp.renderSvgFromCustomData: jsonState không hợp lệ');\n return renderGraphSvgFromState(state, false);\n },\n\n async restoreFileFromCustomData(element): Promise<RestoredStampFile | null> {\n const data = element.customData;\n const fileId = (element as { fileId?: string | null }).fileId;\n if (!fileId || !isGraph2DCustomData(data)) return null;\n const state = parseSceneState(data.jsonState);\n if (!state) return null;\n const svgString = await renderGraphSvgFromState(state, false);\n return svgToStampFile(svgString, fileId);\n },\n\n Host: Graph2DStampHost,\n};\n"]}
1
+ {"version":3,"sources":["../src/stamps/graph-2d/index.tsx"],"names":[],"mappings":";;;;;;;AAUA,IAAM,gBAAA,GAAmB,IAAA;AAAA,EAAK,MAC5B,OAAO,qBAAQ,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,gBAAA,EAAiB,CAAE;AAChE,CAAA;AAEA,IAAM,WAAA,mBACJ,IAAA;AAAA,EAAC,KAAA;AAAA,EAAA;AAAA,IACC,KAAA,EAAM,IAAA;AAAA,IACN,MAAA,EAAO,IAAA;AAAA,IACP,OAAA,EAAQ,WAAA;AAAA,IACR,IAAA,EAAK,MAAA;AAAA,IACL,MAAA,EAAO,cAAA;AAAA,IACP,WAAA,EAAY,KAAA;AAAA,IACZ,aAAA,EAAc,OAAA;AAAA,IACd,cAAA,EAAe,OAAA;AAAA,IACf,aAAA,EAAY,MAAA;AAAA,IAEZ,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,GAAE,iBAAA,EAAkB,CAAA;AAAA,sBAC1B,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,4BAAA,EAA6B;AAAA;AAAA;AACvC,CAAA;AAGK,IAAM,YAAA,GAA6C;AAAA,EACxD,IAAA,EAAM,SAAA;AAAA,EACN,WAAA,EAAa,GAAA;AAAA,EACb,YAAA,EAAc,WAAA;AAAA,EACd,YAAA,EAAc,sCAAA;AAAA,EACd,WAAA,EAAa,WAAA;AAAA,EACb,aAAA,EAAe,eAAA;AAAA,EACf,YAAA,EAAc,IAAA;AAAA,EACd,iBAAA,EAAmB,mBAAA;AAAA,EAEnB,MAAM,wBAAwB,IAAA,EAAgC;AAC5D,IAAA,IAAI,CAAC,mBAAA,CAAoB,IAAI,CAAA,EAAG;AAC9B,MAAA,MAAM,IAAI,MAAM,gFAAwE,CAAA;AAAA,IAC1F;AACA,IAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,IAAA,CAAK,SAAS,CAAA;AAC5C,IAAA,IAAI,CAAC,KAAA,EAAO,MAAM,IAAI,MAAM,2EAA8D,CAAA;AAC1F,IAAA,OAAO,uBAAA,CAAwB,OAAO,KAAK,CAAA;AAAA,EAC7C,CAAA;AAAA,EAEA,MAAM,0BAA0B,OAAA,EAA4C;AAC1E,IAAA,MAAM,OAAO,OAAA,CAAQ,UAAA;AACrB,IAAA,MAAM,SAAU,OAAA,CAAuC,MAAA;AACvD,IAAA,IAAI,CAAC,MAAA,IAAU,CAAC,mBAAA,CAAoB,IAAI,GAAG,OAAO,IAAA;AAClD,IAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,IAAA,CAAK,SAAS,CAAA;AAC5C,IAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AACnB,IAAA,MAAM,SAAA,GAAY,MAAM,uBAAA,CAAwB,KAAA,EAAO,KAAK,CAAA;AAC5D,IAAA,OAAO,cAAA,CAAe,WAAW,MAAM,CAAA;AAAA,EACzC,CAAA;AAAA,EAEA,IAAA,EAAM;AACR","file":"chunk-K5BS2H56.mjs","sourcesContent":["'use client';\nimport { lazy, type ReactNode } from 'react';\nimport { renderGraphSvgFromState } from './render';\nimport { isGraph2DCustomData, type Graph2DCustomData } from './types';\nimport { parseSceneState } from './serialize';\nimport { svgToStampFile } from '../shared/svgToStampFile';\nimport type { RestoredStampFile, StampType } from '../shared/types';\n\nexport type { Graph2DCustomData };\n\nconst Graph2DStampHost = lazy(() =>\n import('./host').then((m) => ({ default: m.Graph2DStampHost })),\n);\n\nconst Graph2DIcon: ReactNode = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M3 3L3 21L21 21\" />\n <path d=\"M6 16Q9 8 12 10Q15 12 18 6\" />\n </svg>\n);\n\nexport const graph2dStamp: StampType<Graph2DCustomData> = {\n kind: 'graph2d',\n shortcutKey: 'h',\n toolbarLabel: '📈',\n toolbarTitle: 'Chèn đồ thị 2D (H)',\n toolbarIcon: Graph2DIcon,\n toolbarTestId: 'graph2d-stamp',\n experimental: true,\n matchesCustomData: isGraph2DCustomData,\n\n async renderSvgFromCustomData(data: unknown): Promise<string> {\n if (!isGraph2DCustomData(data)) {\n throw new Error('graph2dStamp.renderSvgFromCustomData: customData không phải graph2d v2');\n }\n const state = parseSceneState(data.jsonState);\n if (!state) throw new Error('graph2dStamp.renderSvgFromCustomData: jsonState không hợp lệ');\n return renderGraphSvgFromState(state, false);\n },\n\n async restoreFileFromCustomData(element): Promise<RestoredStampFile | null> {\n const data = element.customData;\n const fileId = (element as { fileId?: string | null }).fileId;\n if (!fileId || !isGraph2DCustomData(data)) return null;\n const state = parseSceneState(data.jsonState);\n if (!state) return null;\n const svgString = await renderGraphSvgFromState(state, false);\n return svgToStampFile(svgString, fileId);\n },\n\n Host: Graph2DStampHost,\n};\n"]}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { DEFAULT_THEME_2D } from './chunk-SZDAS7LK.mjs';
2
+ import { DEFAULT_THEME_2D } from './chunk-IE2GGHNF.mjs';
3
3
 
4
4
  // src/stamps/graph-2d/editor/theme.ts
5
5
  var GRAPH_THEME_LIGHT = {
@@ -19,5 +19,5 @@ function paletteFor(isDark) {
19
19
  }
20
20
 
21
21
  export { paletteFor };
22
- //# sourceMappingURL=chunk-BNBOIDO5.mjs.map
23
- //# sourceMappingURL=chunk-BNBOIDO5.mjs.map
22
+ //# sourceMappingURL=chunk-K7VJU7LQ.mjs.map
23
+ //# sourceMappingURL=chunk-K7VJU7LQ.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stamps/graph-2d/editor/theme.ts"],"names":[],"mappings":";;;AAIO,IAAM,iBAAA,GAA6B;AAAA,EACxC,GAAG;AACL,CAAA;AAEO,IAAM,gBAAA,GAA4B;AAAA,EACvC,GAAG,gBAAA;AAAA,EACH,MAAA,EAAQ,SAAA;AAAA,EACR,IAAA,EAAM,SAAA;AAAA,EACN,KAAA,EAAO,SAAA;AAAA,EACP,IAAA,EAAM,SAAA;AAAA,EACN,IAAA,EAAM,SAAA;AAAA,EACN,SAAA,EAAW;AACb,CAAA;AAEO,SAAS,WAAW,MAAA,EAA0B;AACnD,EAAA,OAAO,SAAS,gBAAA,GAAmB,iBAAA;AACrC","file":"chunk-BNBOIDO5.mjs","sourcesContent":["// src/stamps/graph-2d/editor/theme.ts\nimport type { Theme2D } from '../../../core/scene/render/types2d';\nimport { DEFAULT_THEME_2D } from '../../../core/scene/render/types2d';\n\nexport const GRAPH_THEME_LIGHT: Theme2D = {\n ...DEFAULT_THEME_2D,\n};\n\nexport const GRAPH_THEME_DARK: Theme2D = {\n ...DEFAULT_THEME_2D,\n stroke: '#f1f5f9',\n fill: '#3b82f6',\n label: '#f1f5f9',\n axis: '#475569',\n grid: '#334155',\n pointFill: '#93c5fd',\n};\n\nexport function paletteFor(isDark: boolean): Theme2D {\n return isDark ? GRAPH_THEME_DARK : GRAPH_THEME_LIGHT;\n}\n\nexport const FUNCTION_COLORS = [\n '#2563eb', '#dc2626', '#16a34a', '#9333ea',\n '#ea580c', '#0891b2', '#db2777', '#65a30d',\n] as const;\n\nexport const FUNCTION_NAMES = ['f', 'g', 'h', 'i', 'j', 'k', 'l', 'm'] as const;\nexport const PARAMETER_NAMES = ['a', 'b', 'c', 'd', 'k', 't', 'm', 'n'] as const;\n"]}
1
+ {"version":3,"sources":["../src/stamps/graph-2d/editor/theme.ts"],"names":[],"mappings":";;;AAIO,IAAM,iBAAA,GAA6B;AAAA,EACxC,GAAG;AACL,CAAA;AAEO,IAAM,gBAAA,GAA4B;AAAA,EACvC,GAAG,gBAAA;AAAA,EACH,MAAA,EAAQ,SAAA;AAAA,EACR,IAAA,EAAM,SAAA;AAAA,EACN,KAAA,EAAO,SAAA;AAAA,EACP,IAAA,EAAM,SAAA;AAAA,EACN,IAAA,EAAM,SAAA;AAAA,EACN,SAAA,EAAW;AACb,CAAA;AAEO,SAAS,WAAW,MAAA,EAA0B;AACnD,EAAA,OAAO,SAAS,gBAAA,GAAmB,iBAAA;AACrC","file":"chunk-K7VJU7LQ.mjs","sourcesContent":["// src/stamps/graph-2d/editor/theme.ts\nimport type { Theme2D } from '../../../core/scene/render/types2d';\nimport { DEFAULT_THEME_2D } from '../../../core/scene/render/types2d';\n\nexport const GRAPH_THEME_LIGHT: Theme2D = {\n ...DEFAULT_THEME_2D,\n};\n\nexport const GRAPH_THEME_DARK: Theme2D = {\n ...DEFAULT_THEME_2D,\n stroke: '#f1f5f9',\n fill: '#3b82f6',\n label: '#f1f5f9',\n axis: '#475569',\n grid: '#334155',\n pointFill: '#93c5fd',\n};\n\nexport function paletteFor(isDark: boolean): Theme2D {\n return isDark ? GRAPH_THEME_DARK : GRAPH_THEME_LIGHT;\n}\n\nexport const FUNCTION_COLORS = [\n '#2563eb', '#dc2626', '#16a34a', '#9333ea',\n '#ea580c', '#0891b2', '#db2777', '#65a30d',\n] as const;\n\nexport const FUNCTION_NAMES = ['f', 'g', 'h', 'i', 'j', 'k', 'l', 'm'] as const;\nexport const PARAMETER_NAMES = ['a', 'b', 'c', 'd', 'k', 't', 'm', 'n'] as const;\n"]}
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { paletteFor } from './chunk-R5FL6S7L.mjs';
3
- import { JxgRenderer } from './chunk-SZDAS7LK.mjs';
3
+ import { JxgRenderer } from './chunk-IE2GGHNF.mjs';
4
4
  import { renderJsxgOffscreen } from './chunk-ICR4CVOE.mjs';
5
- import { serializeScene, deserializeScene } from './chunk-ZTQBUKLJ.mjs';
6
- import { createStore } from './chunk-IHUFOV7L.mjs';
5
+ import { serializeScene, deserializeScene } from './chunk-JJ4FPCBE.mjs';
6
+ import { createStore } from './chunk-CH6SFONH.mjs';
7
7
  import { DEFAULT_VIEW_2D } from './chunk-73Q7ADVL.mjs';
8
8
 
9
9
  // src/stamps/geometry-2d/serialize.ts
@@ -105,6 +105,43 @@ function computeAutoFitBbox(points, circles, aspect, padPct = 0.12) {
105
105
  return [xmin, ymax, xmax, ymin];
106
106
  }
107
107
 
108
+ // src/stamps/geometry-2d/autoFitBoard.ts
109
+ function isDefaultBbox(bbox) {
110
+ const d = DEFAULT_VIEW_2D.bbox;
111
+ return bbox.length === 4 && bbox[0] === d[0] && bbox[1] === d[1] && bbox[2] === d[2] && bbox[3] === d[3];
112
+ }
113
+ function fittedBboxFromBoard(board, aspect) {
114
+ const objs = board?.objectsList;
115
+ if (!Array.isArray(objs)) return null;
116
+ const points = [];
117
+ const circles = [];
118
+ for (const raw of objs) {
119
+ const o = raw;
120
+ if (o?.elementClass === 1 && typeof o.X === "function" && typeof o.Y === "function") {
121
+ const x = o.X(), y = o.Y();
122
+ if (Number.isFinite(x) && Number.isFinite(y)) points.push([x, y]);
123
+ } else if (o?.elementClass === 3 && o.center?.X && typeof o.Radius === "function") {
124
+ const cx = o.center.X(), cy = o.center.Y(), r = o.Radius();
125
+ if (Number.isFinite(cx) && Number.isFinite(cy) && Number.isFinite(r)) {
126
+ circles.push({ cx, cy, r });
127
+ }
128
+ }
129
+ }
130
+ const safeAspect = Number.isFinite(aspect) && aspect > 0 ? aspect : 1;
131
+ return computeAutoFitBbox(points, circles, safeAspect);
132
+ }
133
+ function autoFitBoardToContent(board, aspect) {
134
+ const bbox = fittedBboxFromBoard(board, aspect);
135
+ if (!bbox) return;
136
+ const b = board;
137
+ try {
138
+ b.setBoundingBox?.(bbox);
139
+ if (typeof b.update === "function") b.update();
140
+ if (typeof b.fullUpdate === "function") b.fullUpdate();
141
+ } catch {
142
+ }
143
+ }
144
+
108
145
  // src/stamps/geometry-2d/labelLayout.ts
109
146
  function radialLabelOffsets(points, R = 14) {
110
147
  const out = /* @__PURE__ */ new Map();
@@ -128,7 +165,7 @@ function radialLabelOffsets(points, R = 14) {
128
165
  }
129
166
 
130
167
  // src/stamps/geometry-2d/render.ts
131
- var PIXELS_PER_UNIT = 20;
168
+ var DEFAULT_VIEW_PX = 500;
132
169
  var MIN_DIM = 100;
133
170
  var MAX_DIM = 1200;
134
171
  var FALLBACK_W = 400;
@@ -140,8 +177,9 @@ function containerDimsForBbox(bbox) {
140
177
  if (!Number.isFinite(w) || !Number.isFinite(h) || w <= 0 || h <= 0) {
141
178
  return { width: FALLBACK_W, height: FALLBACK_H };
142
179
  }
143
- let width = w * PIXELS_PER_UNIT;
144
- let height = h * PIXELS_PER_UNIT;
180
+ const pxPerUnit = DEFAULT_VIEW_PX / Math.max(w, h);
181
+ let width = w * pxPerUnit;
182
+ let height = h * pxPerUnit;
145
183
  const maxAxis = Math.max(width, height);
146
184
  if (maxAxis > MAX_DIM) {
147
185
  const ratio = MAX_DIM / maxAxis;
@@ -156,31 +194,6 @@ function containerDimsForBbox(bbox) {
156
194
  }
157
195
  return { width: Math.round(width), height: Math.round(height) };
158
196
  }
159
- function autoFitBboxFromBoard(board, aspect) {
160
- const objs = board?.objectsList;
161
- if (!Array.isArray(objs)) return;
162
- const points = [];
163
- const circles = [];
164
- for (const o of objs) {
165
- if (o?.elementClass === 1 && typeof o.X === "function" && typeof o.Y === "function") {
166
- const x = o.X(), y = o.Y();
167
- if (Number.isFinite(x) && Number.isFinite(y)) points.push([x, y]);
168
- } else if (o?.elementClass === 3 && o.center?.X && typeof o.Radius === "function") {
169
- const cx = o.center.X(), cy = o.center.Y(), r = o.Radius();
170
- if (Number.isFinite(cx) && Number.isFinite(cy) && Number.isFinite(r)) {
171
- circles.push({ cx, cy, r });
172
- }
173
- }
174
- }
175
- const bbox = computeAutoFitBbox(points, circles, aspect);
176
- if (!bbox) return;
177
- try {
178
- board.setBoundingBox(bbox);
179
- if (typeof board.update === "function") board.update();
180
- if (typeof board.fullUpdate === "function") board.fullUpdate();
181
- } catch {
182
- }
183
- }
184
197
  function applyRadialLabelOffsets(board) {
185
198
  const objs = board?.objectsList;
186
199
  if (!Array.isArray(objs)) return;
@@ -206,10 +219,6 @@ function applyRadialLabelOffsets(board) {
206
219
  } catch {
207
220
  }
208
221
  }
209
- function isDefaultBbox(bbox) {
210
- const d = DEFAULT_VIEW_2D.bbox;
211
- return bbox.length === 4 && bbox[0] === d[0] && bbox[1] === d[1] && bbox[2] === d[2] && bbox[3] === d[3];
212
- }
213
222
  async function renderGeometrySvgFromState(jsonState) {
214
223
  const state = deserializeBoard(jsonState);
215
224
  const view = state.meta.domain === "2d" ? state.meta.view : DEFAULT_VIEW_2D;
@@ -244,7 +253,7 @@ async function renderGeometrySvgFromState(jsonState) {
244
253
  const store = createStore(state);
245
254
  const renderer = new JxgRenderer(store, board);
246
255
  if (shouldAutoFit) {
247
- autoFitBboxFromBoard(board, dims.width / dims.height);
256
+ autoFitBoardToContent(board, dims.width / dims.height);
248
257
  applyRadialLabelOffsets(board);
249
258
  }
250
259
  return renderer;
@@ -260,6 +269,6 @@ function isGeometryCustomData(data) {
260
269
  return d.kind === "geometry" && d.version === 1 && typeof d.jsonState === "string";
261
270
  }
262
271
 
263
- export { deserializeBoard, isGeometryCustomData, renderGeometrySvgFromState, serializeBoard };
264
- //# sourceMappingURL=chunk-H22OZYTW.mjs.map
265
- //# sourceMappingURL=chunk-H22OZYTW.mjs.map
272
+ export { autoFitBoardToContent, deserializeBoard, isDefaultBbox, isGeometryCustomData, renderGeometrySvgFromState, serializeBoard };
273
+ //# sourceMappingURL=chunk-KOXOC2FI.mjs.map
274
+ //# sourceMappingURL=chunk-KOXOC2FI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/stamps/geometry-2d/serialize.ts","../src/stamps/geometry-2d/autoFitBbox.ts","../src/stamps/geometry-2d/autoFitBoard.ts","../src/stamps/geometry-2d/labelLayout.ts","../src/stamps/geometry-2d/render.ts","../src/stamps/geometry-2d/types.ts"],"names":[],"mappings":"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","file":"chunk-KOXOC2FI.mjs","sourcesContent":["// src/stamps/geometry-2d/serialize.ts\n//\n// Sau Tier D PR 3: customData.jsonState chỉ chứa `JSON.stringify(state)`\n// (không còn envelope `{version, bbox, state, showAxis, showGrid}`).\n// View info (bbox/axis/grid) nằm trong `state.meta.view` (View2D shape).\n\nimport { serializeScene, deserializeScene } from '../shared/serializeScene';\nimport type { State, View2D } from '../../core/scene';\n\nexport function serializeBoard(state: State, view: View2D): string {\n const withView: State = {\n ...state,\n meta: { domain: '2d', version: state.meta.version, view },\n };\n return serializeScene(withView);\n}\n\nexport function deserializeBoard(raw: string): State {\n return deserializeScene('2d', raw);\n}\n","// Pure geometry helpers for auto-fitting an AI-generated figure into a viewport.\n//\n// Two concerns, both visual-quality fixes:\n// 1. Outlier-robust extent — a single far-flung point or an oversized circle\n// must not compress the main cluster into a sliver (eval cau-13, cau-04).\n// We use Tukey IQR fences per axis to trim statistical outliers.\n// 2. Aspect correction — the offscreen container is sized from the DEFAULT\n// square bbox, so the fitted bbox must be expanded to the same aspect or\n// JSXGraph's setBoundingBox stretches the units → circles become ellipses\n// (eval cau-08). We grow the shorter axis (never shrink) so everything in\n// the robust extent stays visible.\n\n/**\n * Robust [min, max] of a sample using Tukey fences (Q1 - k·IQR, Q3 + k·IQR).\n * Values outside the fence are dropped before taking min/max. With no outliers\n * this returns the raw [min, max]. For < 4 samples IQR is meaningless → raw range.\n */\nexport function robustRange(values: number[], k = 1.5): [number, number] {\n const n = values.length;\n if (n === 0) return [0, 0];\n const sorted = [...values].sort((a, b) => a - b);\n if (n < 4) return [sorted[0], sorted[n - 1]];\n const quantile = (p: number): number => {\n const idx = (n - 1) * p;\n const lo = Math.floor(idx);\n const hi = Math.ceil(idx);\n if (lo === hi) return sorted[lo];\n return sorted[lo] + (sorted[hi] - sorted[lo]) * (idx - lo);\n };\n const q1 = quantile(0.25);\n const q3 = quantile(0.75);\n const iqr = q3 - q1;\n const fenceLo = q1 - k * iqr;\n const fenceHi = q3 + k * iqr;\n let min = Infinity;\n let max = -Infinity;\n for (const v of sorted) {\n if (v < fenceLo || v > fenceHi) continue;\n if (v < min) min = v;\n if (v > max) max = v;\n }\n if (!Number.isFinite(min) || !Number.isFinite(max)) return [sorted[0], sorted[n - 1]];\n return [min, max];\n}\n\nexport interface CircleExtent {\n cx: number;\n cy: number;\n r: number;\n}\n\n// A circle whose radius exceeds this multiple of the point-cluster diagonal is\n// treated as an oversized outlier and excluded from the fit (it still draws,\n// just clipped). Keeps a normal circumcircle in-frame while preventing a single\n// degenerate giant circle from compressing the whole figure (eval cau-13).\nconst CIRCLE_MAX_FACTOR = 1.0;\n\n/**\n * Compute a JSXGraph bbox `[xmin, ymax, xmax, ymin]` fitted to the figure.\n *\n * Points are reduced to a robust extent via Tukey IQR fences (trims stray\n * intersection points that fly off to huge coords). Circles are included WHOLE\n * (never per-edge trimmed — a clipped circle looks broken) unless a circle is\n * egregiously larger than the point cluster, in which case it is excluded. The\n * result is padded and expanded to `aspect` (= container width / height) so\n * units stay square (round circles). Returns null when there is no geometry.\n */\nexport function computeAutoFitBbox(\n points: ReadonlyArray<readonly [number, number]>,\n circles: ReadonlyArray<CircleExtent>,\n aspect: number,\n padPct = 0.12,\n): [number, number, number, number] | null {\n const xs = points.map((p) => p[0]).filter(Number.isFinite);\n const ys = points.map((p) => p[1]).filter(Number.isFinite);\n\n let xmin = Infinity, xmax = -Infinity, ymin = Infinity, ymax = -Infinity;\n let clusterDiag = 0;\n if (xs.length >= 2 && ys.length >= 2) {\n [xmin, xmax] = robustRange(xs);\n [ymin, ymax] = robustRange(ys);\n clusterDiag = Math.hypot(xmax - xmin, ymax - ymin);\n }\n\n for (const c of circles) {\n if (!Number.isFinite(c.cx) || !Number.isFinite(c.cy) || !Number.isFinite(c.r)) continue;\n // Exclude an oversized circle only when we have a point cluster to compare to.\n if (clusterDiag > 0 && c.r > CIRCLE_MAX_FACTOR * clusterDiag) continue;\n xmin = Math.min(xmin, c.cx - c.r); xmax = Math.max(xmax, c.cx + c.r);\n ymin = Math.min(ymin, c.cy - c.r); ymax = Math.max(ymax, c.cy + c.r);\n }\n\n if (!Number.isFinite(xmin) || !Number.isFinite(xmax) || !Number.isFinite(ymin) || !Number.isFinite(ymax)) {\n return null;\n }\n let w = xmax - xmin;\n let h = ymax - ymin;\n\n // Degenerate (all coincident / fully collinear on one axis): floor to 1 unit.\n if (w < 0.5) { const cx = (xmin + xmax) / 2; xmin = cx - 0.5; xmax = cx + 0.5; w = 1; }\n if (h < 0.5) { const cy = (ymin + ymax) / 2; ymin = cy - 0.5; ymax = cy + 0.5; h = 1; }\n\n const padX = w * padPct;\n const padY = h * padPct;\n xmin -= padX; xmax += padX; ymin -= padY; ymax += padY;\n w = xmax - xmin; h = ymax - ymin;\n\n // Expand the shorter axis so width/height matches the container aspect.\n const curAspect = w / h;\n if (curAspect < aspect) {\n const newW = h * aspect;\n const cx = (xmin + xmax) / 2;\n xmin = cx - newW / 2; xmax = cx + newW / 2;\n } else if (curAspect > aspect) {\n const newH = w / aspect;\n const cy = (ymin + ymax) / 2;\n ymin = cy - newH / 2; ymax = cy + newH / 2;\n }\n\n return [xmin, ymax, xmax, ymin];\n}\n","import { DEFAULT_VIEW_2D } from '../../core/scene/types';\nimport { computeAutoFitBbox } from './autoFitBbox';\n\n/**\n * Auto-fit helpers chia sẻ giữa offscreen render (render.ts) và editor MiniBoard.\n *\n * Trước đây logic này CHỈ nằm trong render.ts (offscreen) → ảnh chèn vào canvas\n * được fit gọn, NHƯNG editor MiniBoard lúc re-edit boot ở bbox default (không\n * fit) → figure trong editor nhỏ/lệch so với ảnh ngoài canvas. Tách ra để cả\n * hai dùng chung → editor view khớp ảnh đã chèn.\n */\n\ntype JxgBoardLike = {\n objectsList?: unknown[];\n setBoundingBox?: (bbox: [number, number, number, number]) => void;\n update?: () => void;\n fullUpdate?: () => void;\n};\n\nexport function isDefaultBbox(bbox: readonly number[]): boolean {\n const d = DEFAULT_VIEW_2D.bbox;\n return bbox.length === 4 && bbox[0] === d[0] && bbox[1] === d[1] && bbox[2] === d[2] && bbox[3] === d[3];\n}\n\n/**\n * Thu thập toạ độ point + tâm/bán kính circle từ board rồi tính bbox fit\n * (Tukey IQR trim outlier + expand theo `aspect`). KHÔNG mutate board.\n * Trả null nếu board không có entity hợp lệ.\n */\nexport function fittedBboxFromBoard(\n board: unknown,\n aspect: number,\n): [number, number, number, number] | null {\n const objs = (board as JxgBoardLike)?.objectsList;\n if (!Array.isArray(objs)) return null;\n const points: [number, number][] = [];\n const circles: { cx: number; cy: number; r: number }[] = [];\n for (const raw of objs) {\n\n const o = raw as any;\n // OBJECT_CLASS_POINT = 1\n if (o?.elementClass === 1 && typeof o.X === 'function' && typeof o.Y === 'function') {\n const x = o.X(), y = o.Y();\n if (Number.isFinite(x) && Number.isFinite(y)) points.push([x, y]);\n } else if (o?.elementClass === 3 && o.center?.X && typeof o.Radius === 'function') {\n // OBJECT_CLASS_CIRCLE\n const cx = o.center.X(), cy = o.center.Y(), r = o.Radius();\n if (Number.isFinite(cx) && Number.isFinite(cy) && Number.isFinite(r)) {\n circles.push({ cx, cy, r });\n }\n }\n }\n const safeAspect = Number.isFinite(aspect) && aspect > 0 ? aspect : 1;\n return computeAutoFitBbox(points, circles, safeAspect);\n}\n\n/**\n * Tính bbox fit từ board rồi setBoundingBox (mutate board). No-op nếu board\n * rỗng / không tính được bbox.\n */\nexport function autoFitBoardToContent(board: unknown, aspect: number): void {\n const bbox = fittedBboxFromBoard(board, aspect);\n if (!bbox) return;\n const b = board as JxgBoardLike;\n try {\n b.setBoundingBox?.(bbox);\n if (typeof b.update === 'function') b.update();\n if (typeof b.fullUpdate === 'function') b.fullUpdate();\n } catch { /* ignore */ }\n}\n","// Anti-collision label placement for AI-generated figures.\n//\n// JSXGraph places every point label at a fixed [10,10] pixel offset (up-right).\n// When points cluster, labels overlap and overlap interior lines. We push each\n// label radially OUTWARD from the figure centroid: points on the left get a\n// left offset, points on the right get a right offset, etc. Offsets are in the\n// SAME sign convention as JSXGraph's label `offset` attribute (it negates the\n// y internally for screen space), so [dirX·R, dirY·R] in math coords maps\n// directly to a screen offset away from the centroid.\n\nexport interface LabeledPoint {\n id: string;\n x: number;\n y: number;\n}\n\nexport function radialLabelOffsets(\n points: LabeledPoint[],\n R = 14,\n): Map<string, [number, number]> {\n const out = new Map<string, [number, number]>();\n if (points.length < 2) return out;\n\n const cx = points.reduce((s, p) => s + p.x, 0) / points.length;\n const cy = points.reduce((s, p) => s + p.y, 0) / points.length;\n\n for (const p of points) {\n let dx = p.x - cx;\n let dy = p.y - cy;\n const len = Math.hypot(dx, dy);\n if (len < 1e-9) {\n // Point sits on the centroid → no meaningful direction; push up.\n dx = 0;\n dy = 1;\n } else {\n dx /= len;\n dy /= len;\n }\n out.set(p.id, [Math.round(dx * R), Math.round(dy * R)]);\n }\n return out;\n}\n","import { deserializeBoard } from './serialize';\nimport { paletteFor } from './editor/theme';\nimport { createStore } from '../../core/scene';\nimport { DEFAULT_VIEW_2D } from '../../core/scene/types';\nimport { JxgRenderer } from '../../core/scene/render/JxgRenderer';\nimport { renderJsxgOffscreen } from '../shared/jxgOffscreenRender';\nimport { autoFitBoardToContent, isDefaultBbox } from './autoFitBoard';\nimport { radialLabelOffsets } from './labelLayout';\n\n/**\n * Re-render geometry SVG từ jsonState đã serialize. Dùng cho:\n * 1. Restore math-stamp file sau khi reload page (Excalidraw mất binary files).\n * 2. Generate SVG lúc INSERT (thay vì clone DOM với màu theo theme editor).\n *\n * LƯU Ý quan trọng — luôn dùng LIGHT palette (nét đậm). Excalidraw apply CSS\n * `filter: invert(93%) hue-rotate(180deg)` lên canvas trong dark mode → nét\n * đậm tự đảo thành sáng. Nếu ta bake nét sáng vào SVG cho dark mode, filter\n * sẽ đảo thành đậm → chìm vào nền tối. Giải pháp: luôn dùng nét đậm + để\n * Excalidraw tự lo invert.\n *\n * Implementation: tạo 1 div ẩn (off-screen, real dimensions để JSXGraph render\n * chuẩn), initBoard, replay creation log từ jsonState, dump SVG, dọn dẹp.\n *\n * Container dimensions phải MATCH aspect ratio của bbox (đã được editor lưu\n * sau khi JSXGraph adjust với keepAspectRatio:true). Trước đây hardcode\n * 400×300 + keepAspectRatio:false làm shape bị kéo dãn (circle thành ellipse,\n * góc vuông lệch) khi bbox không 4:3 → ảnh hiển thị khác với editor lúc\n * double-click. Fix: tính container W/H từ bbox + keepAspectRatio:true để\n * SVG output khớp với view trong editor.\n *\n * Lý do JXG.Options.text.display = 'internal': JSXGraph mặc định render\n * label bằng HTML <div> overlay → clone SVG export sẽ thiếu label.\n */\n\n// Canvas max-axis (px) cho view tham chiếu (un-zoomed). Trước đây dùng\n// PIXELS_PER_UNIT=20 cố định → figure px BẤT BIẾN với zoom (chỉ canvas đổi),\n// và zoom-in (bbox nhỏ lại) lại cho element NHỎ hơn — ngược trực giác. Giờ\n// pxPerUnit = DEFAULT_VIEW_PX / maxSpan(bbox): max-axis canvas luôn ~constant,\n// figure bên trong scale theo zoom (zoom-in → span nhỏ → figure to ra) → ảnh\n// chèn KHỚP với view trong editor (WYSIWYG). Bump 400→500 nên figure mặc định\n// (gen ra) cũng to hơn một tí.\nconst DEFAULT_VIEW_PX = 500;\nconst MIN_DIM = 100;\nconst MAX_DIM = 1200;\nconst FALLBACK_W = 400;\nconst FALLBACK_H = 300;\n\nexport function containerDimsForBbox(bbox: [number, number, number, number]): { width: number; height: number } {\n const [xmin, ymax, xmax, ymin] = bbox;\n const w = Math.abs(xmax - xmin);\n const h = Math.abs(ymax - ymin);\n if (!Number.isFinite(w) || !Number.isFinite(h) || w <= 0 || h <= 0) {\n return { width: FALLBACK_W, height: FALLBACK_H };\n }\n const pxPerUnit = DEFAULT_VIEW_PX / Math.max(w, h);\n let width = w * pxPerUnit;\n let height = h * pxPerUnit;\n const maxAxis = Math.max(width, height);\n if (maxAxis > MAX_DIM) {\n const ratio = MAX_DIM / maxAxis;\n width *= ratio;\n height *= ratio;\n }\n const minAxis = Math.min(width, height);\n if (minAxis < MIN_DIM) {\n const ratio = MIN_DIM / minAxis;\n width *= ratio;\n height *= ratio;\n }\n return { width: Math.round(width), height: Math.round(height) };\n}\n\n/**\n * Đẩy label điểm ra xa centroid (radial) để giảm chồng nhãn. Chỉ chạy cho\n * AI-generated figure (shouldAutoFit) — stamp user-edit giữ layout nhãn mặc định.\n */\nfunction applyRadialLabelOffsets(board: any): void {\n const objs = board?.objectsList;\n if (!Array.isArray(objs)) return;\n const pts: { id: string; x: number; y: number; el: any }[] = [];\n for (const o of objs) {\n if (o?.elementClass === 1 && typeof o.X === 'function' && o.label) {\n const x = o.X(), y = o.Y();\n if (Number.isFinite(x) && Number.isFinite(y)) pts.push({ id: o.id, x, y, el: o });\n }\n }\n const offsets = radialLabelOffsets(pts.map((p) => ({ id: p.id, x: p.x, y: p.y })));\n if (offsets.size === 0) return;\n for (const p of pts) {\n const off = offsets.get(p.id);\n if (!off) continue;\n try { p.el.setAttribute({ label: { offset: off } }); } catch { /* ignore */ }\n }\n try {\n if (typeof board.update === 'function') board.update();\n } catch { /* ignore */ }\n}\n\nexport async function renderGeometrySvgFromState(jsonState: string): Promise<string> {\n const state = deserializeBoard(jsonState);\n const view = state.meta.domain === '2d' ? state.meta.view : DEFAULT_VIEW_2D;\n const bbox = view.bbox as [number, number, number, number];\n const shouldAutoFit = isDefaultBbox(bbox);\n // Stamps inserted vào Excalidraw canvas → luôn dùng light palette.\n // Excalidraw's THEME_FILTER tự đảo nét trong dark mode.\n const palette = paletteFor(false);\n const dims = containerDimsForBbox(bbox);\n const { svgString } = await renderJsxgOffscreen({\n bbox,\n dims,\n axis: view.showAxis,\n grid: view.showGrid,\n keepAspectRatio: true,\n applyOptions: (JXG) => {\n \n const opts = (JXG as any).Options;\n if (!opts) return;\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.text.strokeColor = palette.label;\n opts.label = opts.label || {};\n opts.label.display = 'internal';\n opts.label.strokeColor = palette.label;\n opts.axis = opts.axis || {};\n opts.axis.strokeColor = palette.axis;\n opts.grid = opts.grid || {};\n opts.grid.strokeColor = palette.grid;\n },\n setup: (board) => {\n const store = createStore(state);\n const renderer = new JxgRenderer(store, board);\n if (shouldAutoFit) {\n autoFitBoardToContent(board, dims.width / dims.height);\n applyRadialLabelOffsets(board);\n }\n return renderer;\n },\n });\n return svgString;\n}\n","import type { BaseStampCustomData } from '../shared/types';\n\nexport interface GeometryCustomData extends BaseStampCustomData {\n kind: 'geometry';\n version: 1;\n jsonState: string;\n}\n\nexport function isGeometryCustomData(data: unknown): data is GeometryCustomData {\n if (!data || typeof data !== 'object') return false;\n const d = data as Partial<GeometryCustomData>;\n return d.kind === 'geometry' && d.version === 1 && typeof d.jsonState === 'string';\n}\n"]}
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { paletteFor } from './chunk-BNBOIDO5.mjs';
3
- import { JxgRenderer } from './chunk-SZDAS7LK.mjs';
2
+ import { paletteFor } from './chunk-K7VJU7LQ.mjs';
3
+ import { JxgRenderer } from './chunk-IE2GGHNF.mjs';
4
4
  import { renderJsxgOffscreen } from './chunk-ICR4CVOE.mjs';
5
- import { createStore } from './chunk-IHUFOV7L.mjs';
5
+ import { createStore } from './chunk-CH6SFONH.mjs';
6
6
 
7
7
  // src/stamps/graph-2d/render.ts
8
8
  var DEFAULT_WIDTH = 600;
@@ -53,5 +53,5 @@ async function renderGraphSvgFromState(state, _isDark, width = DEFAULT_WIDTH, he
53
53
  }
54
54
 
55
55
  export { renderGraphSvgFromState };
56
- //# sourceMappingURL=chunk-CXHNVYMD.mjs.map
57
- //# sourceMappingURL=chunk-CXHNVYMD.mjs.map
56
+ //# sourceMappingURL=chunk-KWDBVLST.mjs.map
57
+ //# sourceMappingURL=chunk-KWDBVLST.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stamps/graph-2d/render.ts"],"names":[],"mappings":";;;;;;AAUA,IAAM,aAAA,GAAgB,GAAA;AACtB,IAAM,cAAA,GAAiB,GAAA;AAEvB,eAAsB,wBACpB,KAAA,EACA,OAAA,EACA,KAAA,GAAQ,aAAA,EACR,SAAS,cAAA,EACQ;AACjB,EAAA,MAAM,OAAA,GAAU,WAAW,KAAK,CAAA;AAChC,EAAA,MAAM,OAAO,KAAA,CAAM,IAAA;AACnB,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,MAAA,KAAW,SAAA,GAAY,KAAK,IAAA,GAAO,IAAA;AACrD,EAAA,MAAM,IAAA,GAAyC;AAAA,IAC7C,MAAM,IAAA,IAAQ,GAAA;AAAA,IACd,MAAM,IAAA,IAAQ,EAAA;AAAA,IACd,MAAM,IAAA,IAAQ,EAAA;AAAA,IACd,MAAM,IAAA,IAAQ;AAAA,GAChB;AACA,EAAA,IAAI;AACF,IAAA,MAAM,EAAE,SAAA,EAAU,GAAI,MAAM,mBAAA,CAAoB;AAAA,MAC9C,IAAA;AAAA,MACA,IAAA,EAAM,EAAE,KAAA,EAAO,MAAA,EAAO;AAAA,MACtB,IAAA,EAAM,MAAM,QAAA,IAAY,IAAA;AAAA,MACxB,IAAA,EAAM,MAAM,QAAA,IAAY,IAAA;AAAA,MACxB,eAAA,EAAiB,KAAA;AAAA,MACjB,YAAA,EAAc,CAAC,GAAA,KAAQ;AAErB,QAAA,MAAM,OAAQ,GAAA,CAAY,OAAA;AAC1B,QAAA,IAAI,CAAC,IAAA,EAAM;AACX,QAAA,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,IAAA,IAAQ,EAAC;AAC1B,QAAA,IAAA,CAAK,KAAK,OAAA,GAAU,UAAA;AACpB,QAAA,IAAA,CAAK,KAAK,cAAA,GAAiB,KAAA;AAC3B,QAAA,IAAA,CAAK,KAAK,UAAA,GAAa,KAAA;AACvB,QAAA,IAAA,CAAK,KAAK,QAAA,GAAW,KAAA;AACrB,QAAA,IAAA,CAAK,IAAA,CAAK,cAAc,OAAA,CAAQ,KAAA;AAChC,QAAA,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,KAAA,IAAS,EAAC;AAC5B,QAAA,IAAA,CAAK,MAAM,OAAA,GAAU,UAAA;AACrB,QAAA,IAAA,CAAK,KAAA,CAAM,cAAc,OAAA,CAAQ,KAAA;AACjC,QAAA,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,IAAA,IAAQ,EAAC;AAC1B,QAAA,IAAA,CAAK,IAAA,CAAK,cAAc,OAAA,CAAQ,IAAA;AAChC,QAAA,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,IAAA,IAAQ,EAAC;AAC1B,QAAA,IAAA,CAAK,IAAA,CAAK,cAAc,OAAA,CAAQ,IAAA;AAAA,MAClC,CAAA;AAAA,MACA,KAAA,EAAO,CAAC,KAAA,KAAU;AAChB,QAAA,MAAM,KAAA,GAAQ,YAAY,KAAK,CAAA;AAC/B,QAAA,OAAO,IAAI,WAAA,CAAY,KAAA,EAAO,KAAK,CAAA;AAAA,MACrC;AAAA,KACD,CAAA;AACD,IAAA,OAAO,SAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AAEN,IAAA,OAAO,EAAA;AAAA,EACT;AACF","file":"chunk-CXHNVYMD.mjs","sourcesContent":["// src/stamps/graph-2d/render.ts\n// Offscreen SVG export từ graph2d State. Dùng cho insert/restore stamp.\n//\n// LƯU Ý: Luôn dùng light palette — Excalidraw tự invert trong dark mode.\nimport type { State } from '../../core/scene/types';\nimport { createStore } from '../../core/scene/store';\nimport { JxgRenderer } from '../../core/scene/render/JxgRenderer';\nimport { paletteFor } from './editor/theme';\nimport { renderJsxgOffscreen } from '../shared/jxgOffscreenRender';\n\nconst DEFAULT_WIDTH = 600;\nconst DEFAULT_HEIGHT = 400;\n\nexport async function renderGraphSvgFromState(\n state: State,\n _isDark: boolean,\n width = DEFAULT_WIDTH,\n height = DEFAULT_HEIGHT,\n): Promise<string> {\n const palette = paletteFor(false);\n const meta = state.meta;\n const view = meta.domain === 'graph2d' ? meta.view : null;\n const bbox: [number, number, number, number] = [\n view?.xMin ?? -10,\n view?.yMax ?? 10,\n view?.xMax ?? 10,\n view?.yMin ?? -10,\n ];\n try {\n const { svgString } = await renderJsxgOffscreen({\n bbox,\n dims: { width, height },\n axis: view?.showAxis ?? true,\n grid: view?.showGrid ?? true,\n keepAspectRatio: false,\n applyOptions: (JXG) => {\n \n const opts = (JXG as any).Options;\n if (!opts) return;\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.text.strokeColor = palette.label;\n opts.label = opts.label || {};\n opts.label.display = 'internal';\n opts.label.strokeColor = palette.label;\n opts.axis = opts.axis || {};\n opts.axis.strokeColor = palette.axis;\n opts.grid = opts.grid || {};\n opts.grid.strokeColor = palette.grid;\n },\n setup: (board) => {\n const store = createStore(state);\n return new JxgRenderer(store, board);\n },\n });\n return svgString;\n } catch {\n // Match old contract: callers expect '' when no SVG produced.\n return '';\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/stamps/graph-2d/render.ts"],"names":[],"mappings":";;;;;;AAUA,IAAM,aAAA,GAAgB,GAAA;AACtB,IAAM,cAAA,GAAiB,GAAA;AAEvB,eAAsB,wBACpB,KAAA,EACA,OAAA,EACA,KAAA,GAAQ,aAAA,EACR,SAAS,cAAA,EACQ;AACjB,EAAA,MAAM,OAAA,GAAU,WAAW,KAAK,CAAA;AAChC,EAAA,MAAM,OAAO,KAAA,CAAM,IAAA;AACnB,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,MAAA,KAAW,SAAA,GAAY,KAAK,IAAA,GAAO,IAAA;AACrD,EAAA,MAAM,IAAA,GAAyC;AAAA,IAC7C,MAAM,IAAA,IAAQ,GAAA;AAAA,IACd,MAAM,IAAA,IAAQ,EAAA;AAAA,IACd,MAAM,IAAA,IAAQ,EAAA;AAAA,IACd,MAAM,IAAA,IAAQ;AAAA,GAChB;AACA,EAAA,IAAI;AACF,IAAA,MAAM,EAAE,SAAA,EAAU,GAAI,MAAM,mBAAA,CAAoB;AAAA,MAC9C,IAAA;AAAA,MACA,IAAA,EAAM,EAAE,KAAA,EAAO,MAAA,EAAO;AAAA,MACtB,IAAA,EAAM,MAAM,QAAA,IAAY,IAAA;AAAA,MACxB,IAAA,EAAM,MAAM,QAAA,IAAY,IAAA;AAAA,MACxB,eAAA,EAAiB,KAAA;AAAA,MACjB,YAAA,EAAc,CAAC,GAAA,KAAQ;AAErB,QAAA,MAAM,OAAQ,GAAA,CAAY,OAAA;AAC1B,QAAA,IAAI,CAAC,IAAA,EAAM;AACX,QAAA,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,IAAA,IAAQ,EAAC;AAC1B,QAAA,IAAA,CAAK,KAAK,OAAA,GAAU,UAAA;AACpB,QAAA,IAAA,CAAK,KAAK,cAAA,GAAiB,KAAA;AAC3B,QAAA,IAAA,CAAK,KAAK,UAAA,GAAa,KAAA;AACvB,QAAA,IAAA,CAAK,KAAK,QAAA,GAAW,KAAA;AACrB,QAAA,IAAA,CAAK,IAAA,CAAK,cAAc,OAAA,CAAQ,KAAA;AAChC,QAAA,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,KAAA,IAAS,EAAC;AAC5B,QAAA,IAAA,CAAK,MAAM,OAAA,GAAU,UAAA;AACrB,QAAA,IAAA,CAAK,KAAA,CAAM,cAAc,OAAA,CAAQ,KAAA;AACjC,QAAA,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,IAAA,IAAQ,EAAC;AAC1B,QAAA,IAAA,CAAK,IAAA,CAAK,cAAc,OAAA,CAAQ,IAAA;AAChC,QAAA,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,IAAA,IAAQ,EAAC;AAC1B,QAAA,IAAA,CAAK,IAAA,CAAK,cAAc,OAAA,CAAQ,IAAA;AAAA,MAClC,CAAA;AAAA,MACA,KAAA,EAAO,CAAC,KAAA,KAAU;AAChB,QAAA,MAAM,KAAA,GAAQ,YAAY,KAAK,CAAA;AAC/B,QAAA,OAAO,IAAI,WAAA,CAAY,KAAA,EAAO,KAAK,CAAA;AAAA,MACrC;AAAA,KACD,CAAA;AACD,IAAA,OAAO,SAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AAEN,IAAA,OAAO,EAAA;AAAA,EACT;AACF","file":"chunk-KWDBVLST.mjs","sourcesContent":["// src/stamps/graph-2d/render.ts\n// Offscreen SVG export từ graph2d State. Dùng cho insert/restore stamp.\n//\n// LƯU Ý: Luôn dùng light palette — Excalidraw tự invert trong dark mode.\nimport type { State } from '../../core/scene/types';\nimport { createStore } from '../../core/scene/store';\nimport { JxgRenderer } from '../../core/scene/render/JxgRenderer';\nimport { paletteFor } from './editor/theme';\nimport { renderJsxgOffscreen } from '../shared/jxgOffscreenRender';\n\nconst DEFAULT_WIDTH = 600;\nconst DEFAULT_HEIGHT = 400;\n\nexport async function renderGraphSvgFromState(\n state: State,\n _isDark: boolean,\n width = DEFAULT_WIDTH,\n height = DEFAULT_HEIGHT,\n): Promise<string> {\n const palette = paletteFor(false);\n const meta = state.meta;\n const view = meta.domain === 'graph2d' ? meta.view : null;\n const bbox: [number, number, number, number] = [\n view?.xMin ?? -10,\n view?.yMax ?? 10,\n view?.xMax ?? 10,\n view?.yMin ?? -10,\n ];\n try {\n const { svgString } = await renderJsxgOffscreen({\n bbox,\n dims: { width, height },\n axis: view?.showAxis ?? true,\n grid: view?.showGrid ?? true,\n keepAspectRatio: false,\n applyOptions: (JXG) => {\n \n const opts = (JXG as any).Options;\n if (!opts) return;\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.text.strokeColor = palette.label;\n opts.label = opts.label || {};\n opts.label.display = 'internal';\n opts.label.strokeColor = palette.label;\n opts.axis = opts.axis || {};\n opts.axis.strokeColor = palette.axis;\n opts.grid = opts.grid || {};\n opts.grid.strokeColor = palette.grid;\n },\n setup: (board) => {\n const store = createStore(state);\n return new JxgRenderer(store, board);\n },\n });\n return svgString;\n } catch {\n // Match old contract: callers expect '' when no SVG produced.\n return '';\n }\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { listObjects } from './chunk-ZTQBUKLJ.mjs';
3
- import { createStore } from './chunk-IHUFOV7L.mjs';
2
+ import { listObjects } from './chunk-JJ4FPCBE.mjs';
3
+ import { createStore } from './chunk-CH6SFONH.mjs';
4
4
  import { createEmptyState } from './chunk-73Q7ADVL.mjs';
5
5
  import { getKind } from './chunk-B4NJJZFR.mjs';
6
6
  import * as React from 'react';
@@ -1305,5 +1305,5 @@ async function initJxgBoard(target, config) {
1305
1305
  }
1306
1306
 
1307
1307
  export { ObjectRow, STAMP_PANEL_DESKTOP, StampLeftPanel, ToastHost, ToastProvider, attachJxgWheelZoom, initJxgBoard, safeJsx, useStampStore, useToast };
1308
- //# sourceMappingURL=chunk-OQIQNKPQ.mjs.map
1309
- //# sourceMappingURL=chunk-OQIQNKPQ.mjs.map
1308
+ //# sourceMappingURL=chunk-LTLLQUMN.mjs.map
1309
+ //# sourceMappingURL=chunk-LTLLQUMN.mjs.map