@tetrascience-npm/tetrascience-react-ui 0.7.0-beta.108.1 → 0.7.0-beta.128.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 (439) hide show
  1. package/README.md +2 -2
  2. package/dist/components/ai/chain-of-thought.cjs +1 -1
  3. package/dist/components/ai/chain-of-thought.cjs.map +1 -1
  4. package/dist/components/ai/chain-of-thought.js +1 -1
  5. package/dist/components/ai/chain-of-thought.js.map +1 -1
  6. package/dist/components/ai/confirmation.cjs +1 -1
  7. package/dist/components/ai/confirmation.cjs.map +1 -1
  8. package/dist/components/ai/confirmation.js +1 -1
  9. package/dist/components/ai/confirmation.js.map +1 -1
  10. package/dist/components/ai/context.cjs +1 -1
  11. package/dist/components/ai/context.cjs.map +1 -1
  12. package/dist/components/ai/context.js +36 -35
  13. package/dist/components/ai/context.js.map +1 -1
  14. package/dist/components/ai/message.cjs +1 -1
  15. package/dist/components/ai/message.cjs.map +1 -1
  16. package/dist/components/ai/message.js +68 -68
  17. package/dist/components/ai/message.js.map +1 -1
  18. package/dist/components/ai/prompt-input.cjs +1 -1
  19. package/dist/components/ai/prompt-input.cjs.map +1 -1
  20. package/dist/components/ai/prompt-input.js +4 -2
  21. package/dist/components/ai/prompt-input.js.map +1 -1
  22. package/dist/components/ai/queue.cjs +1 -1
  23. package/dist/components/ai/queue.cjs.map +1 -1
  24. package/dist/components/ai/queue.js +9 -9
  25. package/dist/components/ai/queue.js.map +1 -1
  26. package/dist/components/ai/reasoning.cjs +1 -1
  27. package/dist/components/ai/reasoning.cjs.map +1 -1
  28. package/dist/components/ai/reasoning.js +67 -67
  29. package/dist/components/ai/reasoning.js.map +1 -1
  30. package/dist/components/ai/stream-status.cjs +1 -1
  31. package/dist/components/ai/stream-status.cjs.map +1 -1
  32. package/dist/components/ai/stream-status.js +41 -39
  33. package/dist/components/ai/stream-status.js.map +1 -1
  34. package/dist/components/ai/streamdown-code-plugin.cjs +2 -0
  35. package/dist/components/ai/streamdown-code-plugin.cjs.map +1 -0
  36. package/dist/components/ai/streamdown-code-plugin.js +42 -0
  37. package/dist/components/ai/streamdown-code-plugin.js.map +1 -0
  38. package/dist/components/ai/streamdown-plugins.cjs +2 -0
  39. package/dist/components/ai/streamdown-plugins.cjs.map +1 -0
  40. package/dist/components/ai/streamdown-plugins.js +14 -0
  41. package/dist/components/ai/streamdown-plugins.js.map +1 -0
  42. package/dist/components/ai/task.cjs +1 -1
  43. package/dist/components/ai/task.cjs.map +1 -1
  44. package/dist/components/ai/task.js +18 -11
  45. package/dist/components/ai/task.js.map +1 -1
  46. package/dist/components/ai/tool.cjs +1 -1
  47. package/dist/components/ai/tool.cjs.map +1 -1
  48. package/dist/components/ai/tool.js +51 -55
  49. package/dist/components/ai/tool.js.map +1 -1
  50. package/dist/components/ai/use-streamdown-plugins.cjs +2 -0
  51. package/dist/components/ai/use-streamdown-plugins.cjs.map +1 -0
  52. package/dist/components/ai/use-streamdown-plugins.js +25 -0
  53. package/dist/components/ai/use-streamdown-plugins.js.map +1 -0
  54. package/dist/components/charts/AreaPlot/AreaPlot.cjs +2 -0
  55. package/dist/components/charts/AreaPlot/AreaPlot.cjs.map +1 -0
  56. package/dist/components/charts/AreaPlot/AreaPlot.js +270 -0
  57. package/dist/components/charts/AreaPlot/AreaPlot.js.map +1 -0
  58. package/dist/components/charts/BarChart/BarChart.cjs +2 -0
  59. package/dist/components/charts/BarChart/BarChart.cjs.map +1 -0
  60. package/dist/components/charts/BarChart/BarChart.js +219 -0
  61. package/dist/components/charts/BarChart/BarChart.js.map +1 -0
  62. package/dist/components/charts/BoxPlot/BoxPlot.cjs +2 -0
  63. package/dist/components/charts/BoxPlot/BoxPlot.cjs.map +1 -0
  64. package/dist/components/charts/{Boxplot/Boxplot.js → BoxPlot/BoxPlot.js} +78 -79
  65. package/dist/components/charts/BoxPlot/BoxPlot.js.map +1 -0
  66. package/dist/components/charts/ChartTooltip/ChartTooltip.cjs +1 -1
  67. package/dist/components/charts/ChartTooltip/ChartTooltip.cjs.map +1 -1
  68. package/dist/components/charts/ChartTooltip/ChartTooltip.js +22 -22
  69. package/dist/components/charts/ChartTooltip/ChartTooltip.js.map +1 -1
  70. package/dist/components/charts/Chromatogram/Chromatogram.cjs +1 -1
  71. package/dist/components/charts/Chromatogram/Chromatogram.cjs.map +1 -1
  72. package/dist/components/charts/Chromatogram/Chromatogram.js +232 -170
  73. package/dist/components/charts/Chromatogram/Chromatogram.js.map +1 -1
  74. package/dist/components/charts/Chromatogram/annotations.cjs +2 -0
  75. package/dist/components/charts/Chromatogram/annotations.cjs.map +1 -0
  76. package/dist/components/charts/Chromatogram/annotations.js +137 -0
  77. package/dist/components/charts/Chromatogram/annotations.js.map +1 -0
  78. package/dist/components/charts/Chromatogram/boundaryMarkers.cjs.map +1 -0
  79. package/dist/components/charts/Chromatogram/boundaryMarkers.js.map +1 -0
  80. package/dist/components/charts/Chromatogram/constants.cjs.map +1 -0
  81. package/dist/components/charts/Chromatogram/constants.js.map +1 -0
  82. package/dist/components/charts/Chromatogram/dataProcessing.cjs.map +1 -0
  83. package/dist/components/charts/Chromatogram/dataProcessing.js.map +1 -0
  84. package/dist/components/charts/Chromatogram/peakDetection.cjs.map +1 -0
  85. package/dist/components/charts/Chromatogram/peakDetection.js.map +1 -0
  86. package/dist/components/charts/Chromatogram/plotBuilder.cjs +2 -0
  87. package/dist/components/charts/Chromatogram/plotBuilder.cjs.map +1 -0
  88. package/dist/components/charts/Chromatogram/plotBuilder.js +216 -0
  89. package/dist/components/charts/Chromatogram/plotBuilder.js.map +1 -0
  90. package/dist/components/charts/Chromatogram/regionOverlays.cjs.map +1 -0
  91. package/dist/components/charts/Chromatogram/regionOverlays.js.map +1 -0
  92. package/dist/components/charts/Electropherogram/Electropherogram.cjs +2 -0
  93. package/dist/components/charts/Electropherogram/Electropherogram.cjs.map +1 -0
  94. package/dist/components/charts/Electropherogram/Electropherogram.js +180 -0
  95. package/dist/components/charts/Electropherogram/Electropherogram.js.map +1 -0
  96. package/dist/components/charts/Histogram/Histogram.cjs +1 -1
  97. package/dist/components/charts/Histogram/Histogram.cjs.map +1 -1
  98. package/dist/components/charts/Histogram/Histogram.js +107 -108
  99. package/dist/components/charts/Histogram/Histogram.js.map +1 -1
  100. package/dist/components/charts/LinePlot/LinePlot.cjs +2 -0
  101. package/dist/components/charts/LinePlot/LinePlot.cjs.map +1 -0
  102. package/dist/components/charts/LinePlot/LinePlot.js +224 -0
  103. package/dist/components/charts/LinePlot/LinePlot.js.map +1 -0
  104. package/dist/components/charts/PieChart/PieChart.cjs +1 -1
  105. package/dist/components/charts/PieChart/PieChart.cjs.map +1 -1
  106. package/dist/components/charts/PieChart/PieChart.js +62 -61
  107. package/dist/components/charts/PieChart/PieChart.js.map +1 -1
  108. package/dist/components/charts/PlateMap/PlateMap.cjs +1 -1
  109. package/dist/components/charts/PlateMap/PlateMap.cjs.map +1 -1
  110. package/dist/components/charts/PlateMap/PlateMap.js +246 -242
  111. package/dist/components/charts/PlateMap/PlateMap.js.map +1 -1
  112. package/dist/components/charts/ScatterPlot/ScatterPlot.cjs +2 -0
  113. package/dist/components/charts/ScatterPlot/ScatterPlot.cjs.map +1 -0
  114. package/dist/components/charts/ScatterPlot/ScatterPlot.js +252 -0
  115. package/dist/components/charts/ScatterPlot/ScatterPlot.js.map +1 -0
  116. package/dist/components/charts/ScatterPlotInteractive/ScatterPlotInteractive.cjs +2 -0
  117. package/dist/components/charts/ScatterPlotInteractive/ScatterPlotInteractive.cjs.map +1 -0
  118. package/dist/components/charts/ScatterPlotInteractive/ScatterPlotInteractive.js +215 -0
  119. package/dist/components/charts/ScatterPlotInteractive/ScatterPlotInteractive.js.map +1 -0
  120. package/dist/components/charts/ScatterPlotInteractive/constants.cjs +2 -0
  121. package/dist/components/charts/ScatterPlotInteractive/constants.cjs.map +1 -0
  122. package/dist/components/charts/ScatterPlotInteractive/constants.js +38 -0
  123. package/dist/components/charts/ScatterPlotInteractive/constants.js.map +1 -0
  124. package/dist/components/charts/ScatterPlotInteractive/utils.cjs +2 -0
  125. package/dist/components/charts/ScatterPlotInteractive/utils.cjs.map +1 -0
  126. package/dist/components/charts/ScatterPlotInteractive/utils.js +261 -0
  127. package/dist/components/charts/ScatterPlotInteractive/utils.js.map +1 -0
  128. package/dist/components/charts/StackedChromatogram/StackedChromatogram.cjs +2 -0
  129. package/dist/components/charts/StackedChromatogram/StackedChromatogram.cjs.map +1 -0
  130. package/dist/components/charts/StackedChromatogram/StackedChromatogram.js +40 -0
  131. package/dist/components/charts/StackedChromatogram/StackedChromatogram.js.map +1 -0
  132. package/dist/components/charts/StackedChromatogram/transforms.cjs.map +1 -0
  133. package/dist/components/charts/StackedChromatogram/transforms.js.map +1 -0
  134. package/dist/components/charts/plotly-loader.cjs +2 -0
  135. package/dist/components/charts/plotly-loader.cjs.map +1 -0
  136. package/dist/components/charts/plotly-loader.js +22 -0
  137. package/dist/components/charts/plotly-loader.js.map +1 -0
  138. package/dist/components/composed/AssistantLayout/AssistantLayout.cjs +2 -0
  139. package/dist/components/composed/AssistantLayout/AssistantLayout.cjs.map +1 -0
  140. package/dist/components/composed/AssistantLayout/AssistantLayout.js +142 -0
  141. package/dist/components/composed/AssistantLayout/AssistantLayout.js.map +1 -0
  142. package/dist/components/composed/AssistantLayout/dockLayout.cjs +2 -0
  143. package/dist/components/composed/AssistantLayout/dockLayout.cjs.map +1 -0
  144. package/dist/components/composed/AssistantLayout/dockLayout.js +10 -0
  145. package/dist/components/composed/AssistantLayout/dockLayout.js.map +1 -0
  146. package/dist/components/composed/Chat/Chat.cjs +1 -1
  147. package/dist/components/composed/Chat/Chat.cjs.map +1 -1
  148. package/dist/components/composed/Chat/Chat.js +23 -23
  149. package/dist/components/composed/Chat/Chat.js.map +1 -1
  150. package/dist/components/composed/ConfirmDialog/ConfirmDialog.cjs +1 -1
  151. package/dist/components/composed/ConfirmDialog/ConfirmDialog.cjs.map +1 -1
  152. package/dist/components/composed/ConfirmDialog/ConfirmDialog.js +33 -29
  153. package/dist/components/composed/ConfirmDialog/ConfirmDialog.js.map +1 -1
  154. package/dist/components/composed/DataAppShell/CollapseButton.cjs +2 -0
  155. package/dist/components/composed/DataAppShell/CollapseButton.cjs.map +1 -0
  156. package/dist/components/composed/DataAppShell/CollapseButton.js +42 -0
  157. package/dist/components/composed/DataAppShell/CollapseButton.js.map +1 -0
  158. package/dist/components/composed/DataAppShell/DataAppShell.cjs +1 -1
  159. package/dist/components/composed/DataAppShell/DataAppShell.cjs.map +1 -1
  160. package/dist/components/composed/DataAppShell/DataAppShell.js +349 -313
  161. package/dist/components/composed/DataAppShell/DataAppShell.js.map +1 -1
  162. package/dist/components/composed/DataAppShell/PrimaryNav.cjs +2 -0
  163. package/dist/components/composed/DataAppShell/PrimaryNav.cjs.map +1 -0
  164. package/dist/components/composed/DataAppShell/PrimaryNav.js +268 -0
  165. package/dist/components/composed/DataAppShell/PrimaryNav.js.map +1 -0
  166. package/dist/components/composed/DataAppShell/RightPanel.cjs +2 -0
  167. package/dist/components/composed/DataAppShell/RightPanel.cjs.map +1 -0
  168. package/dist/components/composed/DataAppShell/RightPanel.js +282 -0
  169. package/dist/components/composed/DataAppShell/RightPanel.js.map +1 -0
  170. package/dist/components/composed/DataAppShell/SecondaryNav.cjs +2 -0
  171. package/dist/components/composed/DataAppShell/SecondaryNav.cjs.map +1 -0
  172. package/dist/components/composed/DataAppShell/SecondaryNav.js +364 -0
  173. package/dist/components/composed/DataAppShell/SecondaryNav.js.map +1 -0
  174. package/dist/components/composed/DataAppShell/ShellContext.cjs +2 -0
  175. package/dist/components/composed/DataAppShell/ShellContext.cjs.map +1 -0
  176. package/dist/components/composed/DataAppShell/ShellContext.js +23 -0
  177. package/dist/components/composed/DataAppShell/ShellContext.js.map +1 -0
  178. package/dist/components/composed/MoleculeStructure/MoleculeStructure.cjs +2 -0
  179. package/dist/components/composed/MoleculeStructure/MoleculeStructure.cjs.map +1 -0
  180. package/dist/components/composed/MoleculeStructure/MoleculeStructure.js +87 -0
  181. package/dist/components/composed/MoleculeStructure/MoleculeStructure.js.map +1 -0
  182. package/dist/components/composed/MoleculeStructure/rdkit-loader.cjs +2 -0
  183. package/dist/components/composed/MoleculeStructure/rdkit-loader.cjs.map +1 -0
  184. package/dist/components/composed/MoleculeStructure/rdkit-loader.js +89 -0
  185. package/dist/components/composed/MoleculeStructure/rdkit-loader.js.map +1 -0
  186. package/dist/components/composed/MoleculeStructure/use-rdkit.cjs +2 -0
  187. package/dist/components/composed/MoleculeStructure/use-rdkit.cjs.map +1 -0
  188. package/dist/components/composed/MoleculeStructure/use-rdkit.js +19 -0
  189. package/dist/components/composed/MoleculeStructure/use-rdkit.js.map +1 -0
  190. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.cjs +1 -1
  191. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.cjs.map +1 -1
  192. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.js +17 -17
  193. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.js.map +1 -1
  194. package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.cjs +1 -1
  195. package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.cjs.map +1 -1
  196. package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.js +33 -33
  197. package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.js.map +1 -1
  198. package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.cjs +1 -1
  199. package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.cjs.map +1 -1
  200. package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.js +7 -7
  201. package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.js.map +1 -1
  202. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.cjs +1 -1
  203. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.cjs.map +1 -1
  204. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.js +1 -1
  205. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.js.map +1 -1
  206. package/dist/components/composed/PlateMapEditor/WellLegend.cjs +1 -1
  207. package/dist/components/composed/PlateMapEditor/WellLegend.cjs.map +1 -1
  208. package/dist/components/composed/PlateMapEditor/WellLegend.js +24 -12
  209. package/dist/components/composed/PlateMapEditor/WellLegend.js.map +1 -1
  210. package/dist/components/composed/PlateMapEditor/WellManifestTable.cjs +1 -1
  211. package/dist/components/composed/PlateMapEditor/WellManifestTable.cjs.map +1 -1
  212. package/dist/components/composed/PlateMapEditor/WellManifestTable.js +1 -1
  213. package/dist/components/composed/PlateMapEditor/WellManifestTable.js.map +1 -1
  214. package/dist/components/composed/TdpSearch/components/DefaultFilters.cjs +1 -1
  215. package/dist/components/composed/TdpSearch/components/DefaultFilters.cjs.map +1 -1
  216. package/dist/components/composed/TdpSearch/components/DefaultFilters.js +3 -3
  217. package/dist/components/composed/TdpSearch/components/DefaultFilters.js.map +1 -1
  218. package/dist/components/composed/TopBar/TopBar.cjs +2 -0
  219. package/dist/components/composed/TopBar/TopBar.cjs.map +1 -0
  220. package/dist/components/composed/TopBar/TopBar.js +56 -0
  221. package/dist/components/composed/TopBar/TopBar.js.map +1 -0
  222. package/dist/components/composed/UserMenu/UserMenu.cjs +2 -0
  223. package/dist/components/composed/UserMenu/UserMenu.cjs.map +1 -0
  224. package/dist/components/composed/UserMenu/UserMenu.js +99 -0
  225. package/dist/components/composed/UserMenu/UserMenu.js.map +1 -0
  226. package/dist/components/composed/tdp-link.cjs +1 -1
  227. package/dist/components/composed/tdp-link.cjs.map +1 -1
  228. package/dist/components/composed/tdp-link.js +5 -5
  229. package/dist/components/composed/tdp-link.js.map +1 -1
  230. package/dist/components/ui/alert.cjs +1 -1
  231. package/dist/components/ui/alert.cjs.map +1 -1
  232. package/dist/components/ui/alert.js +12 -12
  233. package/dist/components/ui/alert.js.map +1 -1
  234. package/dist/components/ui/badge.cjs +1 -1
  235. package/dist/components/ui/badge.cjs.map +1 -1
  236. package/dist/components/ui/badge.js +14 -14
  237. package/dist/components/ui/badge.js.map +1 -1
  238. package/dist/components/ui/banner.cjs +1 -1
  239. package/dist/components/ui/banner.cjs.map +1 -1
  240. package/dist/components/ui/banner.js +17 -17
  241. package/dist/components/ui/banner.js.map +1 -1
  242. package/dist/components/ui/button.cjs +1 -1
  243. package/dist/components/ui/button.cjs.map +1 -1
  244. package/dist/components/ui/button.js +16 -16
  245. package/dist/components/ui/button.js.map +1 -1
  246. package/dist/components/ui/calendar.cjs +1 -1
  247. package/dist/components/ui/calendar.cjs.map +1 -1
  248. package/dist/components/ui/calendar.js +3 -3
  249. package/dist/components/ui/calendar.js.map +1 -1
  250. package/dist/components/ui/code-block.cjs +3 -3
  251. package/dist/components/ui/code-block.cjs.map +1 -1
  252. package/dist/components/ui/code-block.js +136 -118
  253. package/dist/components/ui/code-block.js.map +1 -1
  254. package/dist/components/ui/code-editor.cjs +1 -1
  255. package/dist/components/ui/code-editor.cjs.map +1 -1
  256. package/dist/components/ui/code-editor.js +14 -12
  257. package/dist/components/ui/code-editor.js.map +1 -1
  258. package/dist/components/ui/combobox.cjs +1 -1
  259. package/dist/components/ui/combobox.cjs.map +1 -1
  260. package/dist/components/ui/combobox.js +33 -29
  261. package/dist/components/ui/combobox.js.map +1 -1
  262. package/dist/components/ui/command.cjs +1 -1
  263. package/dist/components/ui/command.cjs.map +1 -1
  264. package/dist/components/ui/command.js +81 -77
  265. package/dist/components/ui/command.js.map +1 -1
  266. package/dist/components/ui/context-menu.cjs +1 -1
  267. package/dist/components/ui/context-menu.cjs.map +1 -1
  268. package/dist/components/ui/context-menu.js +13 -13
  269. package/dist/components/ui/context-menu.js.map +1 -1
  270. package/dist/components/ui/data-table/data-table-column-toggle.cjs +1 -1
  271. package/dist/components/ui/data-table/data-table-column-toggle.cjs.map +1 -1
  272. package/dist/components/ui/data-table/data-table-column-toggle.js +70 -62
  273. package/dist/components/ui/data-table/data-table-column-toggle.js.map +1 -1
  274. package/dist/components/ui/data-table/data-table-filter.cjs +1 -1
  275. package/dist/components/ui/data-table/data-table-filter.cjs.map +1 -1
  276. package/dist/components/ui/data-table/data-table-filter.js +24 -23
  277. package/dist/components/ui/data-table/data-table-filter.js.map +1 -1
  278. package/dist/components/ui/data-table/data-table-group.cjs +1 -1
  279. package/dist/components/ui/data-table/data-table-group.cjs.map +1 -1
  280. package/dist/components/ui/data-table/data-table-group.js +17 -16
  281. package/dist/components/ui/data-table/data-table-group.js.map +1 -1
  282. package/dist/components/ui/data-table/data-table-pagination.cjs +1 -1
  283. package/dist/components/ui/data-table/data-table-pagination.cjs.map +1 -1
  284. package/dist/components/ui/data-table/data-table-pagination.js +15 -15
  285. package/dist/components/ui/data-table/data-table-pagination.js.map +1 -1
  286. package/dist/components/ui/data-table/data-table.cjs +1 -1
  287. package/dist/components/ui/data-table/data-table.cjs.map +1 -1
  288. package/dist/components/ui/data-table/data-table.js +191 -190
  289. package/dist/components/ui/data-table/data-table.js.map +1 -1
  290. package/dist/components/ui/dialog.cjs +1 -1
  291. package/dist/components/ui/dialog.cjs.map +1 -1
  292. package/dist/components/ui/dialog.js +1 -1
  293. package/dist/components/ui/dialog.js.map +1 -1
  294. package/dist/components/ui/dropdown-menu.cjs +1 -1
  295. package/dist/components/ui/dropdown-menu.cjs.map +1 -1
  296. package/dist/components/ui/dropdown-menu.js +12 -4
  297. package/dist/components/ui/dropdown-menu.js.map +1 -1
  298. package/dist/components/ui/hover-card.cjs +1 -1
  299. package/dist/components/ui/hover-card.cjs.map +1 -1
  300. package/dist/components/ui/hover-card.js +3 -3
  301. package/dist/components/ui/hover-card.js.map +1 -1
  302. package/dist/components/ui/item.cjs +1 -1
  303. package/dist/components/ui/item.cjs.map +1 -1
  304. package/dist/components/ui/item.js +44 -36
  305. package/dist/components/ui/item.js.map +1 -1
  306. package/dist/components/ui/menubar.cjs +1 -1
  307. package/dist/components/ui/menubar.cjs.map +1 -1
  308. package/dist/components/ui/menubar.js +2 -2
  309. package/dist/components/ui/menubar.js.map +1 -1
  310. package/dist/components/ui/navigation-menu.cjs +1 -1
  311. package/dist/components/ui/navigation-menu.cjs.map +1 -1
  312. package/dist/components/ui/navigation-menu.js +1 -1
  313. package/dist/components/ui/navigation-menu.js.map +1 -1
  314. package/dist/components/ui/popover.cjs +1 -1
  315. package/dist/components/ui/popover.cjs.map +1 -1
  316. package/dist/components/ui/popover.js +1 -1
  317. package/dist/components/ui/popover.js.map +1 -1
  318. package/dist/components/ui/scroll-area.cjs +1 -1
  319. package/dist/components/ui/scroll-area.cjs.map +1 -1
  320. package/dist/components/ui/scroll-area.js +1 -0
  321. package/dist/components/ui/scroll-area.js.map +1 -1
  322. package/dist/components/ui/select.cjs +1 -1
  323. package/dist/components/ui/select.cjs.map +1 -1
  324. package/dist/components/ui/select.js +1 -1
  325. package/dist/components/ui/select.js.map +1 -1
  326. package/dist/components/ui/sheet.cjs +1 -1
  327. package/dist/components/ui/sheet.cjs.map +1 -1
  328. package/dist/components/ui/sheet.js +5 -5
  329. package/dist/components/ui/sheet.js.map +1 -1
  330. package/dist/components/ui/sidebar.cjs +1 -1
  331. package/dist/components/ui/sidebar.cjs.map +1 -1
  332. package/dist/components/ui/sidebar.js +2 -2
  333. package/dist/components/ui/sidebar.js.map +1 -1
  334. package/dist/components/ui/slider.cjs +1 -1
  335. package/dist/components/ui/slider.cjs.map +1 -1
  336. package/dist/components/ui/slider.js +10 -9
  337. package/dist/components/ui/slider.js.map +1 -1
  338. package/dist/components/ui/sonner.cjs +1 -1
  339. package/dist/components/ui/sonner.cjs.map +1 -1
  340. package/dist/components/ui/sonner.js +25 -10
  341. package/dist/components/ui/sonner.js.map +1 -1
  342. package/dist/components/ui/table.cjs +1 -1
  343. package/dist/components/ui/table.cjs.map +1 -1
  344. package/dist/components/ui/table.js +1 -0
  345. package/dist/components/ui/table.js.map +1 -1
  346. package/dist/components/ui/tabs.cjs +1 -1
  347. package/dist/components/ui/tabs.cjs.map +1 -1
  348. package/dist/components/ui/tabs.js +18 -18
  349. package/dist/components/ui/tabs.js.map +1 -1
  350. package/dist/components/ui/tetra-molecule-icon.cjs +2 -0
  351. package/dist/components/ui/tetra-molecule-icon.cjs.map +1 -0
  352. package/dist/components/ui/tetra-molecule-icon.js +49 -0
  353. package/dist/components/ui/tetra-molecule-icon.js.map +1 -0
  354. package/dist/components/ui/toggle-group.cjs +1 -1
  355. package/dist/components/ui/toggle-group.cjs.map +1 -1
  356. package/dist/components/ui/toggle-group.js +35 -31
  357. package/dist/components/ui/toggle-group.js.map +1 -1
  358. package/dist/hooks/use-plotly-theme.cjs +1 -1
  359. package/dist/hooks/use-plotly-theme.cjs.map +1 -1
  360. package/dist/hooks/use-plotly-theme.js +4 -3
  361. package/dist/hooks/use-plotly-theme.js.map +1 -1
  362. package/dist/index.cjs +1 -1
  363. package/dist/index.css +1 -1
  364. package/dist/index.d.ts +1073 -136
  365. package/dist/index.js +698 -647
  366. package/dist/index.js.map +1 -1
  367. package/dist/index.tailwind.css +1 -1
  368. package/dist/lib/shiki.cjs +2 -0
  369. package/dist/lib/shiki.cjs.map +1 -0
  370. package/dist/lib/shiki.js +72 -0
  371. package/dist/lib/shiki.js.map +1 -0
  372. package/package.json +23 -12
  373. package/dist/components/charts/AreaGraph/AreaGraph.cjs +0 -2
  374. package/dist/components/charts/AreaGraph/AreaGraph.cjs.map +0 -1
  375. package/dist/components/charts/AreaGraph/AreaGraph.js +0 -271
  376. package/dist/components/charts/AreaGraph/AreaGraph.js.map +0 -1
  377. package/dist/components/charts/BarGraph/BarGraph.cjs +0 -2
  378. package/dist/components/charts/BarGraph/BarGraph.cjs.map +0 -1
  379. package/dist/components/charts/BarGraph/BarGraph.js +0 -220
  380. package/dist/components/charts/BarGraph/BarGraph.js.map +0 -1
  381. package/dist/components/charts/Boxplot/Boxplot.cjs +0 -2
  382. package/dist/components/charts/Boxplot/Boxplot.cjs.map +0 -1
  383. package/dist/components/charts/Boxplot/Boxplot.js.map +0 -1
  384. package/dist/components/charts/ChromatogramChart/ChromatogramChart.cjs +0 -2
  385. package/dist/components/charts/ChromatogramChart/ChromatogramChart.cjs.map +0 -1
  386. package/dist/components/charts/ChromatogramChart/ChromatogramChart.js +0 -241
  387. package/dist/components/charts/ChromatogramChart/ChromatogramChart.js.map +0 -1
  388. package/dist/components/charts/ChromatogramChart/annotations.cjs +0 -2
  389. package/dist/components/charts/ChromatogramChart/annotations.cjs.map +0 -1
  390. package/dist/components/charts/ChromatogramChart/annotations.js +0 -136
  391. package/dist/components/charts/ChromatogramChart/annotations.js.map +0 -1
  392. package/dist/components/charts/ChromatogramChart/boundaryMarkers.cjs.map +0 -1
  393. package/dist/components/charts/ChromatogramChart/boundaryMarkers.js.map +0 -1
  394. package/dist/components/charts/ChromatogramChart/constants.cjs.map +0 -1
  395. package/dist/components/charts/ChromatogramChart/constants.js.map +0 -1
  396. package/dist/components/charts/ChromatogramChart/dataProcessing.cjs.map +0 -1
  397. package/dist/components/charts/ChromatogramChart/dataProcessing.js.map +0 -1
  398. package/dist/components/charts/ChromatogramChart/peakDetection.cjs.map +0 -1
  399. package/dist/components/charts/ChromatogramChart/peakDetection.js.map +0 -1
  400. package/dist/components/charts/ChromatogramChart/plotBuilder.cjs +0 -2
  401. package/dist/components/charts/ChromatogramChart/plotBuilder.cjs.map +0 -1
  402. package/dist/components/charts/ChromatogramChart/plotBuilder.js +0 -207
  403. package/dist/components/charts/ChromatogramChart/plotBuilder.js.map +0 -1
  404. package/dist/components/charts/ChromatogramChart/regionOverlays.cjs.map +0 -1
  405. package/dist/components/charts/ChromatogramChart/regionOverlays.js.map +0 -1
  406. package/dist/components/charts/DotPlot/DotPlot.cjs +0 -2
  407. package/dist/components/charts/DotPlot/DotPlot.cjs.map +0 -1
  408. package/dist/components/charts/DotPlot/DotPlot.js +0 -208
  409. package/dist/components/charts/DotPlot/DotPlot.js.map +0 -1
  410. package/dist/components/charts/Heatmap/Heatmap.cjs +0 -2
  411. package/dist/components/charts/Heatmap/Heatmap.cjs.map +0 -1
  412. package/dist/components/charts/Heatmap/Heatmap.js +0 -67
  413. package/dist/components/charts/Heatmap/Heatmap.js.map +0 -1
  414. package/dist/components/charts/LineGraph/LineGraph.cjs +0 -2
  415. package/dist/components/charts/LineGraph/LineGraph.cjs.map +0 -1
  416. package/dist/components/charts/LineGraph/LineGraph.js +0 -225
  417. package/dist/components/charts/LineGraph/LineGraph.js.map +0 -1
  418. package/dist/components/charts/ScatterGraph/ScatterGraph.cjs +0 -2
  419. package/dist/components/charts/ScatterGraph/ScatterGraph.cjs.map +0 -1
  420. package/dist/components/charts/ScatterGraph/ScatterGraph.js +0 -234
  421. package/dist/components/charts/ScatterGraph/ScatterGraph.js.map +0 -1
  422. package/dist/components/charts/StackedChromatogramChart/StackedChromatogramChart.cjs +0 -2
  423. package/dist/components/charts/StackedChromatogramChart/StackedChromatogramChart.cjs.map +0 -1
  424. package/dist/components/charts/StackedChromatogramChart/StackedChromatogramChart.js +0 -40
  425. package/dist/components/charts/StackedChromatogramChart/StackedChromatogramChart.js.map +0 -1
  426. package/dist/components/charts/StackedChromatogramChart/transforms.cjs.map +0 -1
  427. package/dist/components/charts/StackedChromatogramChart/transforms.js.map +0 -1
  428. /package/dist/components/charts/{ChromatogramChart → Chromatogram}/boundaryMarkers.cjs +0 -0
  429. /package/dist/components/charts/{ChromatogramChart → Chromatogram}/boundaryMarkers.js +0 -0
  430. /package/dist/components/charts/{ChromatogramChart → Chromatogram}/constants.cjs +0 -0
  431. /package/dist/components/charts/{ChromatogramChart → Chromatogram}/constants.js +0 -0
  432. /package/dist/components/charts/{ChromatogramChart → Chromatogram}/dataProcessing.cjs +0 -0
  433. /package/dist/components/charts/{ChromatogramChart → Chromatogram}/dataProcessing.js +0 -0
  434. /package/dist/components/charts/{ChromatogramChart → Chromatogram}/peakDetection.cjs +0 -0
  435. /package/dist/components/charts/{ChromatogramChart → Chromatogram}/peakDetection.js +0 -0
  436. /package/dist/components/charts/{ChromatogramChart → Chromatogram}/regionOverlays.cjs +0 -0
  437. /package/dist/components/charts/{ChromatogramChart → Chromatogram}/regionOverlays.js +0 -0
  438. /package/dist/components/charts/{StackedChromatogramChart → StackedChromatogram}/transforms.cjs +0 -0
  439. /package/dist/components/charts/{StackedChromatogramChart → StackedChromatogram}/transforms.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"PlateMap.js","sources":["../../../../src/components/charts/PlateMap/PlateMap.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport \"./PlateMap.scss\";\nimport { useChartTooltip } from \"../ChartTooltip\";\n\nimport {\n PLATE_CONFIGS,\n DEFAULT_COLOR_SCALE,\n COLORS,\n DEFAULT_CATEGORY_COLORS,\n PLATEMAP_CONSTANTS,\n NAMED_COLORSCALES,\n} from \"./constants\";\nimport {\n PLATE_FORMAT_96,\n PLATE_FORMAT_CUSTOM,\n} from \"./types\";\nimport {\n generateRowLabels,\n generateColumnLabels,\n wellDataToGrid,\n calculateValueRange,\n hasMultiValueWells,\n extractLayers,\n parseRegionWells,\n buildWellHoverText,\n buildColorbarConfig,\n buildPlotMargins,\n calculateTitleX,\n calculateAxisDomain,\n flattenGridData,\n calculateMarkerSize,\n} from \"./utils\";\n\nimport type {\n PlateMapProps,\n LayerConfig,\n WellData,\n} from \"./types\";\n\n// Re-export types and constants for external consumers\nexport * from \"./types\";\nexport { DEFAULT_CATEGORY_COLORS } from \"./constants\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\n\n/**\n * PlateMap component for visualizing well plate data as a heatmap or categorical display.\n *\n * **Supported Plate Formats:**\n * - 96-well (8 rows × 12 columns, wells A1-H12)\n * - 384-well (16 rows × 24 columns, wells A1-P24)\n * - 1536-well (32 rows × 48 columns, wells A1-AF48)\n * - Custom dimensions with user-specified rows/columns\n *\n * **Visualization Modes:**\n * - `\"heatmap\"`: Continuous color gradient for quantitative values\n * - `\"categorical\"`: Discrete colors for well types (sample, control, empty)\n *\n * **Features:**\n * - Multiple data layers with independent visualization settings\n * - Control region highlighting with borders and fill colors\n * - Configurable color scales, tooltips, and click interactions\n * - Support for WellData arrays with multi-layer visualization\n *\n * **Data Format:**\n * - **WellData array**: `[{ wellId: \"A1\", values: { RFU: 100 }, tooltipData: {...} }, ...]`\n *\n */\nconst PlateMap: React.FC<PlateMapProps> = ({\n data,\n layerConfigs,\n initialLayerId,\n onLayerChange,\n plateFormat = PLATE_FORMAT_96,\n rows: customRows,\n columns: customColumns,\n visualizationMode: propVisualizationMode = \"heatmap\",\n categoryColors: customCategoryColors,\n regions,\n title,\n xTitle,\n yTitle,\n xLabels: customXLabels,\n yLabels: customYLabels,\n colorScale: propColorScale = DEFAULT_COLOR_SCALE,\n valueMin: propValueMin,\n valueMax: propValueMax,\n emptyWellColor = COLORS.emptyWell,\n showColorBar = true,\n showLegend = true,\n legendConfig,\n width = 800,\n height = 500,\n precision = 0,\n markerShape = \"circle\",\n onWellClick,\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const onWellClickRef = useRef(onWellClick);\n onWellClickRef.current = onWellClick;\n\n // Internal state for layer toggling, initialized with initialLayerId\n const [activeLayerId, setActiveLayerId] = useState<string | undefined>(initialLayerId);\n\n // Determine plate dimensions\n let rows: number;\n let columns: number;\n\n if (plateFormat === PLATE_FORMAT_CUSTOM) {\n rows = customRows ?? 8;\n columns = customColumns ?? 12;\n } else {\n const config = PLATE_CONFIGS[plateFormat];\n rows = config.rows;\n columns = config.columns;\n }\n\n // Diameter (px) of each well marker; also drives the hover hit radius so the\n // whole circle is hoverable instead of just a small zone around its center\n const markerSize = useMemo(\n () => calculateMarkerSize(width, height, rows, columns, markerShape, !!title, !!yTitle),\n [width, height, rows, columns, markerShape, title, yTitle],\n );\n const { bindTooltip, tooltipElement } = useChartTooltip({\n hoverDistance: Math.ceil(markerSize / 2),\n });\n\n // Auto-generate layers from multi-value WellData\n const effectiveLayers = useMemo((): LayerConfig[] | null => {\n // Check if data contains multi-value wells\n if (Array.isArray(data) && data.length > 0 && \"wellId\" in (data[0] as WellData)) {\n const wellDataArray = data as WellData[];\n if (hasMultiValueWells(wellDataArray)) {\n return extractLayers(wellDataArray, layerConfigs);\n }\n }\n\n return null;\n }, [data, layerConfigs]);\n\n // Handle layer toggling - determine active layer\n const activeLayer = useMemo((): LayerConfig | null => {\n if (!effectiveLayers || effectiveLayers.length === 0) return null;\n if (activeLayerId) {\n return effectiveLayers.find((l) => l.id === activeLayerId) ?? effectiveLayers[0];\n }\n return effectiveLayers[0];\n }, [effectiveLayers, activeLayerId]);\n\n // Get effective props from active layer or default props\n // Data is always the same - we just change which layer is being visualized\n const visualizationMode = activeLayer?.visualizationMode ?? propVisualizationMode;\n const colorScale = activeLayer?.colorScale ?? propColorScale;\n const valueMin = activeLayer?.valueMin ?? propValueMin;\n const valueMax = activeLayer?.valueMax ?? propValueMax;\n // Derive valueUnit from layer config\n const valueUnit = activeLayer?.valueUnit ? ` ${activeLayer.valueUnit}` : \"\";\n\n // Merge custom category colors with defaults, including layer-specific colors\n const categoryColors = useMemo(\n () => ({ ...DEFAULT_CATEGORY_COLORS, ...customCategoryColors, ...activeLayer?.categoryColors }),\n [customCategoryColors, activeLayer?.categoryColors]\n );\n\n // Convert data to grid format - memoize to prevent re-render issues\n // Use activeLayer.id to extract the appropriate value from multi-value wells\n const activeLayerId_ = activeLayer?.id;\n const { grid, categoriesGrid, allValuesMap, tooltipDataMap } = useMemo(() => {\n let resultGrid: (number | null)[][];\n let resultCategories: (string | null)[][] = Array.from({ length: rows }, () =>\n Array(columns).fill(null)\n );\n let resultAllValues = new Map<string, Record<string, string | number | null>>();\n let resultTooltipData = new Map<string, Record<string, unknown>>();\n\n if (Array.isArray(data) && data.length > 0) {\n // WellData array format - pass activeLayerId to extract the right layer\n const result = wellDataToGrid(data, rows, columns, activeLayerId_);\n resultGrid = result.grid;\n resultCategories = result.categories;\n resultAllValues = result.allValues;\n resultTooltipData = result.tooltipData;\n } else {\n // Generate random data for demonstration when no data provided\n resultGrid = Array.from({ length: rows }, () =>\n Array.from({ length: columns }, () => Math.random() * PLATEMAP_CONSTANTS.MAX_RANDOM_VALUE)\n );\n }\n\n return { grid: resultGrid, categoriesGrid: resultCategories, allValuesMap: resultAllValues, tooltipDataMap: resultTooltipData };\n }, [data, rows, columns, activeLayerId_]);\n\n // Generate labels - use custom labels if provided, otherwise auto-generate.\n // Memoized so a tooltip-driven re-render doesn't change their identity and\n // needlessly rebuild the plot (which would clear the open tooltip).\n const rowLabels = useMemo(\n () => customYLabels ?? generateRowLabels(rows),\n [customYLabels, rows],\n );\n const colLabels = useMemo(\n () => customXLabels ?? generateColumnLabels(columns),\n [customXLabels, columns],\n );\n\n // Calculate value range if not provided\n const range = calculateValueRange(grid);\n const zMin = valueMin ?? range.min;\n const zMax = valueMax ?? range.max;\n\n // Check if grid has any null values\n const hasNullValues = grid.some(row => row.includes(null));\n\n // Create sentinel value for empty wells (below the data range)\n // This allows us to show emptyWellColor for null cells\n const sentinelValue = zMin - (zMax - zMin) * PLATEMAP_CONSTANTS.SENTINEL_RATIO - 1;\n\n // Replace null values with sentinel for Plotly rendering\n const displayGrid = useMemo(\n () =>\n hasNullValues\n ? grid.map((row) => row.map((val) => (val === null ? sentinelValue : val)))\n : grid,\n [hasNullValues, grid, sentinelValue],\n );\n\n // Extend colorscale to include emptyWellColor at the bottom for null values\n const effectiveColorScale = useMemo(() => {\n if (!hasNullValues) return colorScale;\n\n // Convert colorScale to array format if it's a named string scale\n let arrayColorScale: Array<[number, string]>;\n if (typeof colorScale === \"string\") {\n // Look up the named scale in our mapping\n const namedScale = NAMED_COLORSCALES[colorScale];\n if (namedScale) {\n arrayColorScale = namedScale;\n } else {\n // Unknown named scale - can't extend it, return as-is\n // This is a fallback for custom/unknown Plotly scale names\n return colorScale;\n }\n } else {\n arrayColorScale = colorScale;\n }\n\n // For array colorscales, prepend emptyWellColor at position 0\n // and shift all other positions proportionally\n const totalRange = zMax - sentinelValue;\n const dataStartRatio = (zMin - sentinelValue) / totalRange;\n\n // Create new colorscale with emptyWellColor at the bottom\n const extendedScale: Array<[number, string]> = [\n [0, emptyWellColor],\n [dataStartRatio * PLATEMAP_CONSTANTS.COLOR_SCALE_THRESHOLD, emptyWellColor], // Small band for empty wells\n ];\n\n // Remap original colorscale positions to the remaining range\n for (const [pos, color] of arrayColorScale) {\n const newPos = dataStartRatio + pos * (1 - dataStartRatio);\n extendedScale.push([newPos, color]);\n }\n\n return extendedScale;\n }, [colorScale, hasNullValues, zMin, zMax, sentinelValue, emptyWellColor]);\n\n // Effective zMin includes sentinel value if we have nulls\n const effectiveZMin = hasNullValues ? sentinelValue : zMin;\n\n // Create a lookup map for layer configs to get valueUnit for each layer\n const layerConfigMap = useMemo(() => {\n const map = new Map<string, LayerConfig>();\n if (effectiveLayers) {\n for (const layer of effectiveLayers) {\n map.set(layer.id, layer);\n }\n }\n return map;\n }, [effectiveLayers]);\n\n // Build custom hover text matrix - shows ALL values regardless of active layer.\n // Memoized so its identity is stable across tooltip-driven re-renders.\n const hoverText = useMemo<string[][]>(\n () =>\n grid.map((row, rowIdx) =>\n row.map((val, colIdx) => {\n const wellId = `${rowLabels[rowIdx]}${colLabels[colIdx]}`;\n const wellIdUpper = String(wellId).toUpperCase();\n return buildWellHoverText({\n wellId,\n value: val,\n allValues: allValuesMap.get(wellIdUpper),\n tooltipExtra: tooltipDataMap.get(wellIdUpper),\n activeLayerId: activeLayer?.id,\n layerConfigMap,\n precision,\n valueUnit,\n });\n })\n ),\n [grid, rowLabels, colLabels, allValuesMap, tooltipDataMap, activeLayer?.id, layerConfigMap, precision, valueUnit],\n );\n\n // Build categorical data for categorical mode\n const { categoricalGrid, categoricalColorScale, uniqueTypes, catMax } = useMemo(() => {\n if (visualizationMode !== \"categorical\") {\n return { categoricalGrid: null, categoricalColorScale: null, uniqueTypes: [], catMax: 0 };\n }\n\n // Collect unique categories from the categoriesGrid\n const typesSet = new Set<string>();\n let hasNullCategory = false;\n for (const row of categoriesGrid) {\n for (const category of row) {\n if (category) {\n typesSet.add(category);\n } else {\n hasNullCategory = true;\n }\n }\n }\n // Only include \"empty\" if there are actual null wells\n if (hasNullCategory) {\n typesSet.add(\"empty\");\n }\n const types = [...typesSet].sort();\n\n // Create numeric grid where each category maps to an index\n const typeToIndex = new Map<string, number>();\n types.forEach((type, idx) => typeToIndex.set(type, idx));\n\n const catGrid: number[][] = categoriesGrid.map((row) =>\n row.map((category) => {\n if (category === null) {\n return typeToIndex.get(\"empty\") ?? 0;\n }\n return typeToIndex.get(category) ?? typeToIndex.get(\"empty\") ?? 0;\n })\n );\n\n // Build discrete colorscale for categories\n // The grid contains integer indices 0, 1, 2, ... (numTypes - 1)\n // With cmin=0 and cmax=numTypes-1, Plotly maps:\n // index 0 -> normalized 0.0\n // index (numTypes-1) -> normalized 1.0\n // We need each index to map to a distinct color band\n const numTypes = types.length;\n const catColorScale: Array<[number, string]> = [];\n\n if (numTypes === 1) {\n // Single type: entire range is one color\n const color = categoryColors[types[0]] || emptyWellColor;\n catColorScale.push([0, color]);\n catColorScale.push([1, color]);\n } else {\n // Multiple types: create bands for each index\n // Index i maps to normalized value i / (numTypes - 1)\n types.forEach((type, idx) => {\n const color = categoryColors[type] || emptyWellColor;\n const normalizedPos = idx / (numTypes - 1);\n // Create a small band around each position\n const bandHalf = 0.5 / (numTypes - 1);\n const start = Math.max(0, normalizedPos - bandHalf);\n const end = Math.min(1, normalizedPos + bandHalf - PLATEMAP_CONSTANTS.COLOR_SCALE_EPSILON);\n catColorScale.push([start, color]);\n catColorScale.push([end, color]);\n });\n }\n\n // cmax should be numTypes - 1 to match the index range\n return { categoricalGrid: catGrid, categoricalColorScale: catColorScale, uniqueTypes: types, catMax: numTypes - 1 };\n }, [visualizationMode, categoriesGrid, categoryColors, emptyWellColor]);\n\n // Build Plotly shapes for highlighted regions\n const regionShapes = useMemo(() => {\n if (!regions || regions.length === 0) {\n return [];\n }\n\n const shapes: Array<Partial<Plotly.Shape>> = [];\n\n for (const region of regions) {\n const bounds = parseRegionWells(region.wells, rowLabels, colLabels);\n if (!bounds) continue;\n\n // Plotly heatmap uses the actual label values for positioning.\n // colLabels are 1-indexed (1, 2, 3, ...), so we need to convert from 0-indexed bounds.\n // Each cell is centered on its label, so we offset by inset to cover the cell.\n // For columns: bounds.minCol=0 means column label 1, so x0 = 1 - inset\n // For rows: bounds.minRow=0 means row index 0, which is correct for y-axis\n //\n // Use 0.49 inset to place boundary just inside cell edge,\n // avoiding line doubling when adjacent regions share a border\n const inset = 0.49;\n const x0 = (bounds.minCol + 1) - inset;\n const x1 = (bounds.maxCol + 1) + inset;\n const y0 = bounds.minRow - inset;\n const y1 = bounds.maxRow + inset;\n\n shapes.push({\n type: \"rect\",\n xref: \"x\",\n yref: \"y\",\n x0,\n x1,\n y0,\n y1,\n line: {\n color: region.borderColor || COLORS.textDark,\n width: region.borderWidth ?? 2,\n },\n fillcolor: region.fillColor || \"transparent\",\n layer: \"above\",\n });\n }\n\n return shapes;\n }, [regions, rowLabels, colLabels]);\n\n useEffect(() => {\n const currentRef = plotRef.current;\n if (!currentRef) return;\n\n // Determine which grid and colorscale to use based on mode\n const isCategorical = visualizationMode === \"categorical\";\n const plotZ = isCategorical && categoricalGrid ? categoricalGrid : displayGrid;\n const plotColorScale = isCategorical && categoricalColorScale ? categoricalColorScale : effectiveColorScale;\n const plotZMin = isCategorical ? 0 : effectiveZMin;\n const plotZMax = isCategorical ? (catMax || 1) : zMax;\n const plotShowScale = isCategorical ? false : showColorBar;\n\n // Flatten 2D grid data into arrays for scatter plot\n const { xData, yData, colorData, textData } = flattenGridData(\n plotZ,\n rowLabels,\n hoverText,\n rows,\n columns,\n plotZMin\n );\n\n // Create scatter plot with markers\n const plotData: Plotly.Data[] = [\n {\n x: xData,\n y: yData,\n mode: \"markers\" as const,\n type: \"scatter\" as const,\n marker: {\n symbol: markerShape,\n size: markerSize,\n color: colorData,\n colorscale: plotColorScale,\n cmin: plotZMin,\n cmax: plotZMax,\n showscale: plotShowScale,\n colorbar: buildColorbarConfig(\n legendConfig?.position ?? \"right\",\n valueUnit,\n legendConfig?.title\n ),\n line: {\n color: theme.gridColor,\n width: 1,\n },\n },\n hoverinfo: \"none\" as const,\n text: textData,\n },\n ];\n\n const legendPosition = legendConfig?.position ?? \"right\";\n\n const layout = {\n autosize: false, // Prevent auto-sizing to maintain consistent layout\n title: title\n ? {\n text: title,\n font: {\n family: \"Inter, sans-serif\",\n size: 20,\n color: theme.textSecondary,\n },\n x: calculateTitleX(legendPosition),\n xanchor: \"center\" as const,\n y: 0.98,\n yanchor: \"top\" as const,\n }\n : undefined,\n width,\n height,\n margin: buildPlotMargins(legendPosition, !!title, !!yTitle),\n xaxis: {\n title: {\n text: xTitle || \"\",\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n },\n standoff: 15,\n },\n side: \"top\" as const,\n fixedrange: true,\n dtick: 1,\n range: [0.5, columns + 0.5], // Explicit range to prevent auto-padding\n automargin: false, // Prevent auto margin adjustment\n tickmode: \"array\" as const,\n tickvals: Array.from({ length: columns }, (_, i) => i + 1),\n ticktext: colLabels.map(String),\n tickangle: 0, // Keep labels horizontal\n tickfont: { size: columns > 24 ? 8 : PLATEMAP_CONSTANTS.FONT_SIZE_LARGE }, // Smaller font for high-density plates\n // Adjust domain based on legend position to prevent colorbar overlap\n domain: calculateAxisDomain(legendPosition),\n },\n yaxis: {\n title: {\n text: yTitle || \"\",\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n },\n standoff: 15,\n },\n fixedrange: true,\n dtick: 1,\n range: [rows + PLATEMAP_CONSTANTS.LABEL_CENTER_OFFSET, PLATEMAP_CONSTANTS.LABEL_CENTER_OFFSET], // Reversed range: high to low puts row A at top\n automargin: false, // Prevent auto margin adjustment\n tickmode: \"array\" as const,\n tickvals: Array.from({ length: rows }, (_, i) => i),\n ticktext: rowLabels.map(String),\n tickfont: { size: rows > 16 ? 8 : PLATEMAP_CONSTANTS.FONT_SIZE_LARGE }, // Smaller font for high-density plates\n },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: \"Inter, sans-serif\",\n color: theme.textSecondary,\n },\n shapes: regionShapes,\n };\n\n const config = {\n responsive: true,\n displayModeBar: false,\n displaylogo: false,\n };\n\n Plotly.newPlot(currentRef, plotData, layout, config);\n bindTooltip(currentRef);\n\n // Always attach click handler - check onWellClickRef.current inside callback\n // This ensures handler is registered even if onWellClick is provided after initial render\n (currentRef as unknown as Plotly.PlotlyHTMLElement).on(\"plotly_click\", (eventData: Plotly.PlotMouseEvent) => {\n if (!onWellClickRef.current) return;\n const point = eventData.points[0];\n if (point) {\n // Cast labels to handle union type\n const rowLabelsArr = rowLabels as (string | number)[];\n const colLabelsArr = colLabels as (string | number)[];\n const rowIdx = rowLabelsArr.indexOf(point.y as string | number);\n const colIdx = colLabelsArr.indexOf(point.x as string | number);\n if (rowIdx >= 0 && colIdx >= 0) {\n const wellId = `${rowLabelsArr[rowIdx]}${colLabelsArr[colIdx]}`;\n const wellIdUpper = String(wellId).toUpperCase();\n // Get all values and tooltipData for this well\n const allValues = allValuesMap.get(wellIdUpper);\n const tooltipData = tooltipDataMap.get(wellIdUpper);\n const wellData: WellData = {\n wellId,\n values: allValues,\n tooltipData,\n };\n onWellClickRef.current?.(wellData);\n }\n }\n });\n\n return () => {\n if (currentRef) {\n Plotly.purge(currentRef);\n }\n };\n }, [\n displayGrid,\n colLabels,\n rowLabels,\n effectiveColorScale,\n showColorBar,\n effectiveZMin,\n zMax,\n valueUnit,\n title,\n xTitle,\n yTitle,\n width,\n height,\n hoverText,\n precision,\n tooltipDataMap,\n allValuesMap,\n grid,\n visualizationMode,\n categoricalGrid,\n categoricalColorScale,\n uniqueTypes.length,\n catMax,\n regionShapes,\n rows,\n columns,\n legendConfig,\n markerShape,\n markerSize,\n theme,\n bindTooltip,\n ]);\n\n // Render layer selector tabs\n const renderLayerSelector = () => {\n if (!effectiveLayers || effectiveLayers.length <= 1) {\n return null;\n }\n\n return (\n <div className=\"platemap-layer-selector\">\n {effectiveLayers.map((layer) => {\n const isActive = activeLayer?.id === layer.id;\n return (\n <Button\n key={layer.id}\n variant={isActive ? \"default\" : \"outline\"}\n size=\"sm\"\n onClick={() => {\n setActiveLayerId(layer.id);\n onLayerChange?.(layer.id);\n }}\n >\n {layer.name}\n </Button>\n );\n })}\n </div>\n );\n };\n\n // Legend configuration with defaults\n const legendPosition = legendConfig?.position ?? \"right\";\n const legendFontSize = legendConfig?.fontSize ?? 12;\n const legendItemSpacing = legendConfig?.itemSpacing ?? 4;\n const legendSwatchSize = legendConfig?.swatchSize ?? 16;\n const legendTitle = legendConfig?.title;\n\n // Fixed width for categorical legend to prevent layout shift\n const legendWidth = 120;\n\n // Determine if legend is horizontal (top/bottom) or vertical (left/right)\n const isHorizontalLegend = legendPosition === \"top\" || legendPosition === \"bottom\";\n\n // Render legend (categorical types and/or regions)\n const renderLegend = () => {\n const hasCategoricalItems = visualizationMode === \"categorical\" && uniqueTypes.length > 0;\n const hasRegions = regions && regions.length > 0;\n\n if (!showLegend || (!hasCategoricalItems && !hasRegions)) {\n // Return empty placeholder to maintain consistent width (only for vertical legends)\n if (!isHorizontalLegend) {\n return <div className=\"platemap-legend-placeholder\" style={{ width: legendWidth }} />;\n }\n return null;\n }\n\n // Build legend class names\n const legendClassNames = [\"platemap-legend\"];\n if (isHorizontalLegend) {\n legendClassNames.push(\"platemap-legend--horizontal\");\n } else if (legendPosition === \"left\") {\n legendClassNames.push(\"platemap-legend--left\");\n } else if (legendPosition === \"right\") {\n legendClassNames.push(\"platemap-legend--right\");\n }\n\n // Dynamic styles that depend on props\n const legendStyle: React.CSSProperties = {\n gap: `${legendItemSpacing}px`,\n width: isHorizontalLegend ? undefined : legendWidth,\n };\n\n return (\n <div className={legendClassNames.join(\" \")} style={legendStyle}>\n {legendTitle && (\n <div\n className={`platemap-legend__title${isHorizontalLegend ? \" platemap-legend__title--horizontal\" : \"\"}`}\n style={{ fontSize: `${legendFontSize}px` }}\n >\n {legendTitle}\n </div>\n )}\n {/* Categorical type items */}\n {hasCategoricalItems &&\n uniqueTypes.map((type) => (\n <div key={type} className=\"platemap-legend__item\">\n <div\n className=\"platemap-legend__swatch\"\n style={{\n width: `${legendSwatchSize}px`,\n height: `${legendSwatchSize}px`,\n backgroundColor: categoryColors[type] || emptyWellColor,\n }}\n />\n <span\n className=\"platemap-legend__label platemap-legend__label--capitalize\"\n style={{ fontSize: `${legendFontSize}px` }}\n >\n {type}\n </span>\n </div>\n ))}\n {/* Region items */}\n {hasRegions &&\n regions.map((region) => (\n <div key={region.id} className=\"platemap-legend__item\">\n <div\n className=\"platemap-legend__swatch platemap-legend__swatch--region\"\n style={{\n width: `${legendSwatchSize}px`,\n height: `${legendSwatchSize}px`,\n backgroundColor: region.fillColor || \"transparent\",\n border: `${region.borderWidth || 2}px solid ${region.borderColor || COLORS.regionBorder}`,\n }}\n />\n <span\n className=\"platemap-legend__label\"\n style={{ fontSize: `${legendFontSize}px` }}\n >\n {region.name}\n </span>\n </div>\n ))}\n </div>\n );\n };\n\n // Build the plot content based on legend position\n const plotContent = (\n <div className=\"relative\">\n <div ref={plotRef} className=\"platemap-plot\" style={{ width, height }} />\n {tooltipElement}\n </div>\n );\n const legendContent = renderLegend();\n\n const renderPlotWithLegend = () => {\n switch (legendPosition) {\n case \"left\":\n return (\n <div className=\"platemap-plot-wrapper platemap-plot-wrapper--vertical\">\n {legendContent}\n {plotContent}\n </div>\n );\n case \"top\":\n return (\n <div className=\"platemap-plot-wrapper platemap-plot-wrapper--horizontal\">\n {legendContent}\n {plotContent}\n </div>\n );\n case \"bottom\":\n return (\n <div className=\"platemap-plot-wrapper platemap-plot-wrapper--horizontal\">\n {plotContent}\n {legendContent}\n </div>\n );\n case \"right\":\n default:\n return (\n <div className=\"platemap-plot-wrapper platemap-plot-wrapper--vertical\">\n {plotContent}\n {legendContent}\n </div>\n );\n }\n };\n\n return (\n <div className=\"platemap-container\" style={{ width: isHorizontalLegend ? undefined : width }}>\n {renderLayerSelector()}\n {renderPlotWithLegend()}\n </div>\n );\n};\n\nexport { PlateMap };"],"names":["PlateMap","data","layerConfigs","initialLayerId","onLayerChange","plateFormat","PLATE_FORMAT_96","customRows","customColumns","propVisualizationMode","customCategoryColors","regions","title","xTitle","yTitle","customXLabels","customYLabels","propColorScale","DEFAULT_COLOR_SCALE","propValueMin","propValueMax","emptyWellColor","COLORS","showColorBar","showLegend","legendConfig","width","height","precision","markerShape","onWellClick","plotRef","useRef","theme","usePlotlyTheme","onWellClickRef","activeLayerId","setActiveLayerId","useState","rows","columns","PLATE_FORMAT_CUSTOM","config","PLATE_CONFIGS","markerSize","useMemo","calculateMarkerSize","bindTooltip","tooltipElement","useChartTooltip","effectiveLayers","wellDataArray","hasMultiValueWells","extractLayers","activeLayer","l","visualizationMode","colorScale","valueMin","valueMax","valueUnit","categoryColors","DEFAULT_CATEGORY_COLORS","activeLayerId_","grid","categoriesGrid","allValuesMap","tooltipDataMap","resultGrid","resultCategories","resultAllValues","resultTooltipData","result","wellDataToGrid","PLATEMAP_CONSTANTS","rowLabels","generateRowLabels","colLabels","generateColumnLabels","range","calculateValueRange","zMin","zMax","hasNullValues","row","sentinelValue","displayGrid","val","effectiveColorScale","arrayColorScale","namedScale","NAMED_COLORSCALES","totalRange","dataStartRatio","extendedScale","pos","color","newPos","effectiveZMin","layerConfigMap","map","layer","hoverText","rowIdx","colIdx","wellId","wellIdUpper","buildWellHoverText","categoricalGrid","categoricalColorScale","uniqueTypes","catMax","typesSet","hasNullCategory","category","types","typeToIndex","type","idx","catGrid","numTypes","catColorScale","normalizedPos","bandHalf","start","end","regionShapes","shapes","region","bounds","parseRegionWells","inset","x0","x1","y0","y1","useEffect","currentRef","isCategorical","plotZ","plotColorScale","plotZMin","plotZMax","plotShowScale","xData","yData","colorData","textData","flattenGridData","plotData","buildColorbarConfig","legendPosition","layout","calculateTitleX","buildPlotMargins","_","i","calculateAxisDomain","Plotly","eventData","point","rowLabelsArr","colLabelsArr","allValues","tooltipData","wellData","renderLayerSelector","isActive","jsx","Button","legendFontSize","legendItemSpacing","legendSwatchSize","legendTitle","legendWidth","isHorizontalLegend","renderLegend","hasCategoricalItems","hasRegions","legendClassNames","legendStyle","jsxs","plotContent","legendContent","renderPlotWithLegend"],"mappings":"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"}
1
+ {"version":3,"file":"PlateMap.js","sources":["../../../../src/components/charts/PlateMap/PlateMap.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport \"./PlateMap.scss\";\nimport { useChartTooltip } from \"../ChartTooltip\";\nimport { getLoadedPlotly, loadPlotly } from \"../plotly-loader\";\n\nimport {\n PLATE_CONFIGS,\n DEFAULT_COLOR_SCALE,\n COLORS,\n DEFAULT_CATEGORY_COLORS,\n PLATEMAP_CONSTANTS,\n NAMED_COLORSCALES,\n} from \"./constants\";\nimport {\n PLATE_FORMAT_96,\n PLATE_FORMAT_CUSTOM,\n} from \"./types\";\nimport {\n generateRowLabels,\n generateColumnLabels,\n wellDataToGrid,\n calculateValueRange,\n hasMultiValueWells,\n extractLayers,\n parseRegionWells,\n buildWellHoverText,\n buildColorbarConfig,\n buildPlotMargins,\n calculateTitleX,\n calculateAxisDomain,\n flattenGridData,\n calculateMarkerSize,\n} from \"./utils\";\n\nimport type {\n PlateMapProps,\n LayerConfig,\n WellData,\n} from \"./types\";\nimport type Plotly from \"plotly.js-dist\";\n\n// Re-export types and constants for external consumers\nexport * from \"./types\";\nexport { DEFAULT_CATEGORY_COLORS } from \"./constants\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { CHART_FONT_FAMILY, usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\n\n/**\n * PlateMap component for visualizing well plate data as a heatmap or categorical display.\n *\n * **Supported Plate Formats:**\n * - 96-well (8 rows × 12 columns, wells A1-H12)\n * - 384-well (16 rows × 24 columns, wells A1-P24)\n * - 1536-well (32 rows × 48 columns, wells A1-AF48)\n * - Custom dimensions with user-specified rows/columns\n *\n * **Visualization Modes:**\n * - `\"heatmap\"`: Continuous color gradient for quantitative values\n * - `\"categorical\"`: Discrete colors for well types (sample, control, empty)\n *\n * **Features:**\n * - Multiple data layers with independent visualization settings\n * - Control region highlighting with borders and fill colors\n * - Configurable color scales, tooltips, and click interactions\n * - Support for WellData arrays with multi-layer visualization\n *\n * **Data Format:**\n * - **WellData array**: `[{ wellId: \"A1\", values: { RFU: 100 }, tooltipData: {...} }, ...]`\n *\n */\nconst PlateMap: React.FC<PlateMapProps> = ({\n data,\n layerConfigs,\n initialLayerId,\n onLayerChange,\n plateFormat = PLATE_FORMAT_96,\n rows: customRows,\n columns: customColumns,\n visualizationMode: propVisualizationMode = \"heatmap\",\n categoryColors: customCategoryColors,\n regions,\n title,\n xTitle,\n yTitle,\n xLabels: customXLabels,\n yLabels: customYLabels,\n colorScale: propColorScale = DEFAULT_COLOR_SCALE,\n valueMin: propValueMin,\n valueMax: propValueMax,\n emptyWellColor = COLORS.emptyWell,\n showColorBar = true,\n showLegend = true,\n legendConfig,\n width = 800,\n height = 500,\n precision = 0,\n markerShape = \"circle\",\n onWellClick,\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const onWellClickRef = useRef(onWellClick);\n onWellClickRef.current = onWellClick;\n\n // Internal state for layer toggling, initialized with initialLayerId\n const [activeLayerId, setActiveLayerId] = useState<string | undefined>(initialLayerId);\n\n // Determine plate dimensions\n let rows: number;\n let columns: number;\n\n if (plateFormat === PLATE_FORMAT_CUSTOM) {\n rows = customRows ?? 8;\n columns = customColumns ?? 12;\n } else {\n const config = PLATE_CONFIGS[plateFormat];\n rows = config.rows;\n columns = config.columns;\n }\n\n // Diameter (px) of each well marker; also drives the hover hit radius so the\n // whole circle is hoverable instead of just a small zone around its center\n const markerSize = useMemo(\n () => calculateMarkerSize(width, height, rows, columns, markerShape, !!title, !!yTitle),\n [width, height, rows, columns, markerShape, title, yTitle],\n );\n const { bindTooltip, tooltipElement } = useChartTooltip({\n hoverDistance: Math.ceil(markerSize / 2),\n });\n\n // Auto-generate layers from multi-value WellData\n const effectiveLayers = useMemo((): LayerConfig[] | null => {\n // Check if data contains multi-value wells\n if (Array.isArray(data) && data.length > 0 && \"wellId\" in (data[0] as WellData)) {\n const wellDataArray = data as WellData[];\n if (hasMultiValueWells(wellDataArray)) {\n return extractLayers(wellDataArray, layerConfigs);\n }\n }\n\n return null;\n }, [data, layerConfigs]);\n\n // Handle layer toggling - determine active layer\n const activeLayer = useMemo((): LayerConfig | null => {\n if (!effectiveLayers || effectiveLayers.length === 0) return null;\n if (activeLayerId) {\n return effectiveLayers.find((l) => l.id === activeLayerId) ?? effectiveLayers[0];\n }\n return effectiveLayers[0];\n }, [effectiveLayers, activeLayerId]);\n\n // Get effective props from active layer or default props\n // Data is always the same - we just change which layer is being visualized\n const visualizationMode = activeLayer?.visualizationMode ?? propVisualizationMode;\n const colorScale = activeLayer?.colorScale ?? propColorScale;\n const valueMin = activeLayer?.valueMin ?? propValueMin;\n const valueMax = activeLayer?.valueMax ?? propValueMax;\n // Derive valueUnit from layer config\n const valueUnit = activeLayer?.valueUnit ? ` ${activeLayer.valueUnit}` : \"\";\n\n // Merge custom category colors with defaults, including layer-specific colors\n const categoryColors = useMemo(\n () => ({ ...DEFAULT_CATEGORY_COLORS, ...customCategoryColors, ...activeLayer?.categoryColors }),\n [customCategoryColors, activeLayer?.categoryColors]\n );\n\n // Convert data to grid format - memoize to prevent re-render issues\n // Use activeLayer.id to extract the appropriate value from multi-value wells\n const activeLayerId_ = activeLayer?.id;\n const { grid, categoriesGrid, allValuesMap, tooltipDataMap } = useMemo(() => {\n let resultGrid: (number | null)[][];\n let resultCategories: (string | null)[][] = Array.from({ length: rows }, () =>\n Array(columns).fill(null)\n );\n let resultAllValues = new Map<string, Record<string, string | number | null>>();\n let resultTooltipData = new Map<string, Record<string, unknown>>();\n\n if (Array.isArray(data) && data.length > 0) {\n // WellData array format - pass activeLayerId to extract the right layer\n const result = wellDataToGrid(data, rows, columns, activeLayerId_);\n resultGrid = result.grid;\n resultCategories = result.categories;\n resultAllValues = result.allValues;\n resultTooltipData = result.tooltipData;\n } else {\n // Generate random data for demonstration when no data provided\n resultGrid = Array.from({ length: rows }, () =>\n Array.from({ length: columns }, () => Math.random() * PLATEMAP_CONSTANTS.MAX_RANDOM_VALUE)\n );\n }\n\n return { grid: resultGrid, categoriesGrid: resultCategories, allValuesMap: resultAllValues, tooltipDataMap: resultTooltipData };\n }, [data, rows, columns, activeLayerId_]);\n\n // Generate labels - use custom labels if provided, otherwise auto-generate.\n // Memoized so a tooltip-driven re-render doesn't change their identity and\n // needlessly rebuild the plot (which would clear the open tooltip).\n const rowLabels = useMemo(\n () => customYLabels ?? generateRowLabels(rows),\n [customYLabels, rows],\n );\n const colLabels = useMemo(\n () => customXLabels ?? generateColumnLabels(columns),\n [customXLabels, columns],\n );\n\n // Calculate value range if not provided\n const range = calculateValueRange(grid);\n const zMin = valueMin ?? range.min;\n const zMax = valueMax ?? range.max;\n\n // Check if grid has any null values\n const hasNullValues = grid.some(row => row.includes(null));\n\n // Create sentinel value for empty wells (below the data range)\n // This allows us to show emptyWellColor for null cells\n const sentinelValue = zMin - (zMax - zMin) * PLATEMAP_CONSTANTS.SENTINEL_RATIO - 1;\n\n // Replace null values with sentinel for Plotly rendering\n const displayGrid = useMemo(\n () =>\n hasNullValues\n ? grid.map((row) => row.map((val) => (val === null ? sentinelValue : val)))\n : grid,\n [hasNullValues, grid, sentinelValue],\n );\n\n // Extend colorscale to include emptyWellColor at the bottom for null values\n const effectiveColorScale = useMemo(() => {\n if (!hasNullValues) return colorScale;\n\n // Convert colorScale to array format if it's a named string scale\n let arrayColorScale: Array<[number, string]>;\n if (typeof colorScale === \"string\") {\n // Look up the named scale in our mapping\n const namedScale = NAMED_COLORSCALES[colorScale];\n if (namedScale) {\n arrayColorScale = namedScale;\n } else {\n // Unknown named scale - can't extend it, return as-is\n // This is a fallback for custom/unknown Plotly scale names\n return colorScale;\n }\n } else {\n arrayColorScale = colorScale;\n }\n\n // For array colorscales, prepend emptyWellColor at position 0\n // and shift all other positions proportionally\n const totalRange = zMax - sentinelValue;\n const dataStartRatio = (zMin - sentinelValue) / totalRange;\n\n // Create new colorscale with emptyWellColor at the bottom\n const extendedScale: Array<[number, string]> = [\n [0, emptyWellColor],\n [dataStartRatio * PLATEMAP_CONSTANTS.COLOR_SCALE_THRESHOLD, emptyWellColor], // Small band for empty wells\n ];\n\n // Remap original colorscale positions to the remaining range\n for (const [pos, color] of arrayColorScale) {\n const newPos = dataStartRatio + pos * (1 - dataStartRatio);\n extendedScale.push([newPos, color]);\n }\n\n return extendedScale;\n }, [colorScale, hasNullValues, zMin, zMax, sentinelValue, emptyWellColor]);\n\n // Effective zMin includes sentinel value if we have nulls\n const effectiveZMin = hasNullValues ? sentinelValue : zMin;\n\n // Create a lookup map for layer configs to get valueUnit for each layer\n const layerConfigMap = useMemo(() => {\n const map = new Map<string, LayerConfig>();\n if (effectiveLayers) {\n for (const layer of effectiveLayers) {\n map.set(layer.id, layer);\n }\n }\n return map;\n }, [effectiveLayers]);\n\n // Build custom hover text matrix - shows ALL values regardless of active layer.\n // Memoized so its identity is stable across tooltip-driven re-renders.\n const hoverText = useMemo<string[][]>(\n () =>\n grid.map((row, rowIdx) =>\n row.map((val, colIdx) => {\n const wellId = `${rowLabels[rowIdx]}${colLabels[colIdx]}`;\n const wellIdUpper = String(wellId).toUpperCase();\n return buildWellHoverText({\n wellId,\n value: val,\n allValues: allValuesMap.get(wellIdUpper),\n tooltipExtra: tooltipDataMap.get(wellIdUpper),\n activeLayerId: activeLayer?.id,\n layerConfigMap,\n precision,\n valueUnit,\n });\n })\n ),\n [grid, rowLabels, colLabels, allValuesMap, tooltipDataMap, activeLayer?.id, layerConfigMap, precision, valueUnit],\n );\n\n // Build categorical data for categorical mode\n const { categoricalGrid, categoricalColorScale, uniqueTypes, catMax } = useMemo(() => {\n if (visualizationMode !== \"categorical\") {\n return { categoricalGrid: null, categoricalColorScale: null, uniqueTypes: [], catMax: 0 };\n }\n\n // Collect unique categories from the categoriesGrid\n const typesSet = new Set<string>();\n let hasNullCategory = false;\n for (const row of categoriesGrid) {\n for (const category of row) {\n if (category) {\n typesSet.add(category);\n } else {\n hasNullCategory = true;\n }\n }\n }\n // Only include \"empty\" if there are actual null wells\n if (hasNullCategory) {\n typesSet.add(\"empty\");\n }\n const types = [...typesSet].sort();\n\n // Create numeric grid where each category maps to an index\n const typeToIndex = new Map<string, number>();\n types.forEach((type, idx) => typeToIndex.set(type, idx));\n\n const catGrid: number[][] = categoriesGrid.map((row) =>\n row.map((category) => {\n if (category === null) {\n return typeToIndex.get(\"empty\") ?? 0;\n }\n return typeToIndex.get(category) ?? typeToIndex.get(\"empty\") ?? 0;\n })\n );\n\n // Build discrete colorscale for categories\n // The grid contains integer indices 0, 1, 2, ... (numTypes - 1)\n // With cmin=0 and cmax=numTypes-1, Plotly maps:\n // index 0 -> normalized 0.0\n // index (numTypes-1) -> normalized 1.0\n // We need each index to map to a distinct color band\n const numTypes = types.length;\n const catColorScale: Array<[number, string]> = [];\n\n if (numTypes === 1) {\n // Single type: entire range is one color\n const color = categoryColors[types[0]] || emptyWellColor;\n catColorScale.push([0, color]);\n catColorScale.push([1, color]);\n } else {\n // Multiple types: create bands for each index\n // Index i maps to normalized value i / (numTypes - 1)\n types.forEach((type, idx) => {\n const color = categoryColors[type] || emptyWellColor;\n const normalizedPos = idx / (numTypes - 1);\n // Create a small band around each position\n const bandHalf = 0.5 / (numTypes - 1);\n const start = Math.max(0, normalizedPos - bandHalf);\n const end = Math.min(1, normalizedPos + bandHalf - PLATEMAP_CONSTANTS.COLOR_SCALE_EPSILON);\n catColorScale.push([start, color]);\n catColorScale.push([end, color]);\n });\n }\n\n // cmax should be numTypes - 1 to match the index range\n return { categoricalGrid: catGrid, categoricalColorScale: catColorScale, uniqueTypes: types, catMax: numTypes - 1 };\n }, [visualizationMode, categoriesGrid, categoryColors, emptyWellColor]);\n\n // Build Plotly shapes for highlighted regions\n const regionShapes = useMemo(() => {\n if (!regions || regions.length === 0) {\n return [];\n }\n\n const shapes: Array<Partial<Plotly.Shape>> = [];\n\n for (const region of regions) {\n const bounds = parseRegionWells(region.wells, rowLabels, colLabels);\n if (!bounds) continue;\n\n // Plotly heatmap uses the actual label values for positioning.\n // colLabels are 1-indexed (1, 2, 3, ...), so we need to convert from 0-indexed bounds.\n // Each cell is centered on its label, so we offset by inset to cover the cell.\n // For columns: bounds.minCol=0 means column label 1, so x0 = 1 - inset\n // For rows: bounds.minRow=0 means row index 0, which is correct for y-axis\n //\n // Use 0.49 inset to place boundary just inside cell edge,\n // avoiding line doubling when adjacent regions share a border\n const inset = 0.49;\n const x0 = (bounds.minCol + 1) - inset;\n const x1 = (bounds.maxCol + 1) + inset;\n const y0 = bounds.minRow - inset;\n const y1 = bounds.maxRow + inset;\n\n shapes.push({\n type: \"rect\",\n xref: \"x\",\n yref: \"y\",\n x0,\n x1,\n y0,\n y1,\n line: {\n color: region.borderColor || COLORS.textDark,\n width: region.borderWidth ?? 2,\n },\n fillcolor: region.fillColor || \"transparent\",\n layer: \"above\",\n });\n }\n\n return shapes;\n }, [regions, rowLabels, colLabels]);\n\n useEffect(() => {\n if (!plotRef.current) return;\n\n // Determine which grid and colorscale to use based on mode\n const isCategorical = visualizationMode === \"categorical\";\n const plotZ = isCategorical && categoricalGrid ? categoricalGrid : displayGrid;\n const plotColorScale = isCategorical && categoricalColorScale ? categoricalColorScale : effectiveColorScale;\n const plotZMin = isCategorical ? 0 : effectiveZMin;\n const plotZMax = isCategorical ? (catMax || 1) : zMax;\n const plotShowScale = isCategorical ? false : showColorBar;\n\n // Flatten 2D grid data into arrays for scatter plot\n const { xData, yData, colorData, textData } = flattenGridData(\n plotZ,\n rowLabels,\n hoverText,\n rows,\n columns,\n plotZMin\n );\n\n // Create scatter plot with markers\n const plotData: Plotly.Data[] = [\n {\n x: xData,\n y: yData,\n mode: \"markers\" as const,\n type: \"scatter\" as const,\n marker: {\n symbol: markerShape,\n size: markerSize,\n color: colorData,\n colorscale: plotColorScale,\n cmin: plotZMin,\n cmax: plotZMax,\n showscale: plotShowScale,\n colorbar: buildColorbarConfig(\n legendConfig?.position ?? \"right\",\n valueUnit,\n legendConfig?.title\n ),\n line: {\n color: theme.gridColor,\n width: 1,\n },\n },\n hoverinfo: \"none\" as const,\n text: textData,\n },\n ];\n\n const legendPosition = legendConfig?.position ?? \"right\";\n\n const layout = {\n autosize: false, // Prevent auto-sizing to maintain consistent layout\n title: title\n ? {\n text: title,\n font: {\n family: CHART_FONT_FAMILY,\n size: 20,\n color: theme.textSecondary,\n },\n x: calculateTitleX(legendPosition),\n xanchor: \"center\" as const,\n y: 0.98,\n yanchor: \"top\" as const,\n }\n : undefined,\n width,\n height,\n margin: buildPlotMargins(legendPosition, !!title, !!yTitle),\n xaxis: {\n title: {\n text: xTitle || \"\",\n font: {\n size: 16,\n color: theme.textSecondary,\n family: CHART_FONT_FAMILY,\n },\n standoff: 15,\n },\n side: \"top\" as const,\n fixedrange: true,\n dtick: 1,\n range: [0.5, columns + 0.5], // Explicit range to prevent auto-padding\n automargin: false, // Prevent auto margin adjustment\n tickmode: \"array\" as const,\n tickvals: Array.from({ length: columns }, (_, i) => i + 1),\n ticktext: colLabels.map(String),\n tickangle: 0, // Keep labels horizontal\n tickfont: { size: columns > 24 ? 8 : PLATEMAP_CONSTANTS.FONT_SIZE_LARGE }, // Smaller font for high-density plates\n // Adjust domain based on legend position to prevent colorbar overlap\n domain: calculateAxisDomain(legendPosition),\n },\n yaxis: {\n title: {\n text: yTitle || \"\",\n font: {\n size: 16,\n color: theme.textSecondary,\n family: CHART_FONT_FAMILY,\n },\n standoff: 15,\n },\n fixedrange: true,\n dtick: 1,\n range: [rows + PLATEMAP_CONSTANTS.LABEL_CENTER_OFFSET, PLATEMAP_CONSTANTS.LABEL_CENTER_OFFSET], // Reversed range: high to low puts row A at top\n automargin: false, // Prevent auto margin adjustment\n tickmode: \"array\" as const,\n tickvals: Array.from({ length: rows }, (_, i) => i),\n ticktext: rowLabels.map(String),\n tickfont: { size: rows > 16 ? 8 : PLATEMAP_CONSTANTS.FONT_SIZE_LARGE }, // Smaller font for high-density plates\n },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: CHART_FONT_FAMILY,\n color: theme.textSecondary,\n },\n shapes: regionShapes,\n };\n\n const config = {\n responsive: true,\n displayModeBar: false,\n displaylogo: false,\n };\n\n // Plotly is loaded lazily so it stays out of the consumer's main chunk\n // (SW-2007); the draw is skipped if the effect re-runs or unmounts first.\n let cancelled = false;\n let plotElement: HTMLDivElement | null = null;\n void loadPlotly().then((plotly) => {\n if (cancelled || !plotRef.current) return;\n const currentRef = plotRef.current;\n plotly.newPlot(currentRef, plotData, layout, config);\n bindTooltip(currentRef);\n\n // Always attach click handler - check onWellClickRef.current inside callback\n // This ensures handler is registered even if onWellClick is provided after initial render\n (currentRef as unknown as Plotly.PlotlyHTMLElement).on(\"plotly_click\", (eventData: Plotly.PlotMouseEvent) => {\n if (!onWellClickRef.current) return;\n const point = eventData.points[0];\n if (point) {\n // Cast labels to handle union type\n const rowLabelsArr = rowLabels as (string | number)[];\n const colLabelsArr = colLabels as (string | number)[];\n const rowIdx = rowLabelsArr.indexOf(point.y as string | number);\n const colIdx = colLabelsArr.indexOf(point.x as string | number);\n if (rowIdx >= 0 && colIdx >= 0) {\n const wellId = `${rowLabelsArr[rowIdx]}${colLabelsArr[colIdx]}`;\n const wellIdUpper = String(wellId).toUpperCase();\n // Get all values and tooltipData for this well\n const allValues = allValuesMap.get(wellIdUpper);\n const tooltipData = tooltipDataMap.get(wellIdUpper);\n const wellData: WellData = {\n wellId,\n values: allValues,\n tooltipData,\n };\n onWellClickRef.current?.(wellData);\n }\n }\n });\n\n plotElement = currentRef;\n });\n\n return () => {\n cancelled = true;\n if (plotElement) {\n getLoadedPlotly().purge(plotElement);\n }\n };\n }, [\n displayGrid,\n colLabels,\n rowLabels,\n effectiveColorScale,\n showColorBar,\n effectiveZMin,\n zMax,\n valueUnit,\n title,\n xTitle,\n yTitle,\n width,\n height,\n hoverText,\n precision,\n tooltipDataMap,\n allValuesMap,\n grid,\n visualizationMode,\n categoricalGrid,\n categoricalColorScale,\n uniqueTypes.length,\n catMax,\n regionShapes,\n rows,\n columns,\n legendConfig,\n markerShape,\n markerSize,\n theme,\n bindTooltip,\n ]);\n\n // Render layer selector tabs\n const renderLayerSelector = () => {\n if (!effectiveLayers || effectiveLayers.length <= 1) {\n return null;\n }\n\n return (\n <div className=\"platemap-layer-selector\">\n {effectiveLayers.map((layer) => {\n const isActive = activeLayer?.id === layer.id;\n return (\n <Button\n key={layer.id}\n variant={isActive ? \"default\" : \"outline\"}\n size=\"sm\"\n onClick={() => {\n setActiveLayerId(layer.id);\n onLayerChange?.(layer.id);\n }}\n >\n {layer.name}\n </Button>\n );\n })}\n </div>\n );\n };\n\n // Legend configuration with defaults\n const legendPosition = legendConfig?.position ?? \"right\";\n const legendFontSize = legendConfig?.fontSize ?? 12;\n const legendItemSpacing = legendConfig?.itemSpacing ?? 4;\n const legendSwatchSize = legendConfig?.swatchSize ?? 16;\n const legendTitle = legendConfig?.title;\n\n // Fixed width for categorical legend to prevent layout shift\n const legendWidth = 120;\n\n // Determine if legend is horizontal (top/bottom) or vertical (left/right)\n const isHorizontalLegend = legendPosition === \"top\" || legendPosition === \"bottom\";\n\n // Render legend (categorical types and/or regions)\n const renderLegend = () => {\n const hasCategoricalItems = visualizationMode === \"categorical\" && uniqueTypes.length > 0;\n const hasRegions = regions && regions.length > 0;\n\n if (!showLegend || (!hasCategoricalItems && !hasRegions)) {\n // Return empty placeholder to maintain consistent width (only for vertical legends)\n if (!isHorizontalLegend) {\n return <div className=\"platemap-legend-placeholder\" style={{ width: legendWidth }} />;\n }\n return null;\n }\n\n // Build legend class names\n const legendClassNames = [\"platemap-legend\"];\n if (isHorizontalLegend) {\n legendClassNames.push(\"platemap-legend--horizontal\");\n } else if (legendPosition === \"left\") {\n legendClassNames.push(\"platemap-legend--left\");\n } else if (legendPosition === \"right\") {\n legendClassNames.push(\"platemap-legend--right\");\n }\n\n // Dynamic styles that depend on props\n const legendStyle: React.CSSProperties = {\n gap: `${legendItemSpacing}px`,\n width: isHorizontalLegend ? undefined : legendWidth,\n };\n\n return (\n <div className={legendClassNames.join(\" \")} style={legendStyle}>\n {legendTitle && (\n <div\n className={`platemap-legend__title${isHorizontalLegend ? \" platemap-legend__title--horizontal\" : \"\"}`}\n style={{ fontSize: `${legendFontSize}px` }}\n >\n {legendTitle}\n </div>\n )}\n {/* Categorical type items */}\n {hasCategoricalItems &&\n uniqueTypes.map((type) => (\n <div key={type} className=\"platemap-legend__item\">\n <div\n className=\"platemap-legend__swatch\"\n style={{\n width: `${legendSwatchSize}px`,\n height: `${legendSwatchSize}px`,\n backgroundColor: categoryColors[type] || emptyWellColor,\n }}\n />\n <span\n className=\"platemap-legend__label platemap-legend__label--capitalize\"\n style={{ fontSize: `${legendFontSize}px` }}\n >\n {type}\n </span>\n </div>\n ))}\n {/* Region items */}\n {hasRegions &&\n regions.map((region) => (\n <div key={region.id} className=\"platemap-legend__item\">\n <div\n className=\"platemap-legend__swatch platemap-legend__swatch--region\"\n style={{\n width: `${legendSwatchSize}px`,\n height: `${legendSwatchSize}px`,\n backgroundColor: region.fillColor || \"transparent\",\n border: `${region.borderWidth || 2}px solid ${region.borderColor || COLORS.regionBorder}`,\n }}\n />\n <span\n className=\"platemap-legend__label\"\n style={{ fontSize: `${legendFontSize}px` }}\n >\n {region.name}\n </span>\n </div>\n ))}\n </div>\n );\n };\n\n // Build the plot content based on legend position\n const plotContent = (\n <div className=\"relative\">\n <div ref={plotRef} className=\"platemap-plot\" style={{ width, height }} />\n {tooltipElement}\n </div>\n );\n const legendContent = renderLegend();\n\n const renderPlotWithLegend = () => {\n switch (legendPosition) {\n case \"left\":\n return (\n <div className=\"platemap-plot-wrapper platemap-plot-wrapper--vertical\">\n {legendContent}\n {plotContent}\n </div>\n );\n case \"top\":\n return (\n <div className=\"platemap-plot-wrapper platemap-plot-wrapper--horizontal\">\n {legendContent}\n {plotContent}\n </div>\n );\n case \"bottom\":\n return (\n <div className=\"platemap-plot-wrapper platemap-plot-wrapper--horizontal\">\n {plotContent}\n {legendContent}\n </div>\n );\n case \"right\":\n default:\n return (\n <div className=\"platemap-plot-wrapper platemap-plot-wrapper--vertical\">\n {plotContent}\n {legendContent}\n </div>\n );\n }\n };\n\n return (\n <div className=\"platemap-container\" style={{ width: isHorizontalLegend ? undefined : width }}>\n {renderLayerSelector()}\n {renderPlotWithLegend()}\n </div>\n );\n};\n\nexport { PlateMap };"],"names":["PlateMap","data","layerConfigs","initialLayerId","onLayerChange","plateFormat","PLATE_FORMAT_96","customRows","customColumns","propVisualizationMode","customCategoryColors","regions","title","xTitle","yTitle","customXLabels","customYLabels","propColorScale","DEFAULT_COLOR_SCALE","propValueMin","propValueMax","emptyWellColor","COLORS","showColorBar","showLegend","legendConfig","width","height","precision","markerShape","onWellClick","plotRef","useRef","theme","usePlotlyTheme","onWellClickRef","activeLayerId","setActiveLayerId","useState","rows","columns","PLATE_FORMAT_CUSTOM","config","PLATE_CONFIGS","markerSize","useMemo","calculateMarkerSize","bindTooltip","tooltipElement","useChartTooltip","effectiveLayers","wellDataArray","hasMultiValueWells","extractLayers","activeLayer","l","visualizationMode","colorScale","valueMin","valueMax","valueUnit","categoryColors","DEFAULT_CATEGORY_COLORS","activeLayerId_","grid","categoriesGrid","allValuesMap","tooltipDataMap","resultGrid","resultCategories","resultAllValues","resultTooltipData","result","wellDataToGrid","PLATEMAP_CONSTANTS","rowLabels","generateRowLabels","colLabels","generateColumnLabels","range","calculateValueRange","zMin","zMax","hasNullValues","row","sentinelValue","displayGrid","val","effectiveColorScale","arrayColorScale","namedScale","NAMED_COLORSCALES","totalRange","dataStartRatio","extendedScale","pos","color","newPos","effectiveZMin","layerConfigMap","map","layer","hoverText","rowIdx","colIdx","wellId","wellIdUpper","buildWellHoverText","categoricalGrid","categoricalColorScale","uniqueTypes","catMax","typesSet","hasNullCategory","category","types","typeToIndex","type","idx","catGrid","numTypes","catColorScale","normalizedPos","bandHalf","start","end","regionShapes","shapes","region","bounds","parseRegionWells","inset","x0","x1","y0","y1","useEffect","isCategorical","plotZ","plotColorScale","plotZMin","plotZMax","plotShowScale","xData","yData","colorData","textData","flattenGridData","plotData","buildColorbarConfig","legendPosition","layout","CHART_FONT_FAMILY","calculateTitleX","buildPlotMargins","_","i","calculateAxisDomain","cancelled","plotElement","loadPlotly","plotly","currentRef","eventData","point","rowLabelsArr","colLabelsArr","allValues","tooltipData","wellData","getLoadedPlotly","renderLayerSelector","isActive","jsx","Button","legendFontSize","legendItemSpacing","legendSwatchSize","legendTitle","legendWidth","isHorizontalLegend","renderLegend","hasCategoricalItems","hasRegions","legendClassNames","legendStyle","jsxs","plotContent","legendContent","renderPlotWithLegend"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const X=require("react/jsx-runtime"),n=require("react"),Q=require("../ChartTooltip/ChartTooltip.cjs"),b=require("../plotly-loader.cjs"),V=require("../../../hooks/use-element-size.cjs"),f=require("../../../hooks/use-plotly-theme.cjs"),Z=require("../../../lib/utils.cjs"),$=require("../../../utils/colors.cjs"),D=["circle","square","diamond","triangle-up","triangle-down","star"],ee=({dataSeries:x,width:F,height:z,xRange:p,yRange:g,xTitle:C,yTitle:T,title:P="Scatter Plot",variant:E="default",markerSize:I=10})=>{const h=n.useRef(null),o=f.usePlotlyTheme(),{bindTooltip:R,tooltipElement:W}=Q.useChartTooltip({xLabel:C,yLabel:T}),[U,S]=V.useElementSize(),s=F??S.width,a=z??S.height,Y=s>0&&a>0,G=F===void 0,J=z===void 0,w=n.useRef({width:s,height:a});w.current={width:s,height:a};const _=n.useRef(!1),v=n.useRef({width:0,height:0}),k=n.useMemo(()=>Array.isArray(x)?x:[x],[x]),{xMin:q,xMax:O,yMin:H,yMax:N}=n.useMemo(()=>{let t=1/0,e=-1/0,l=1/0,r=-1/0;k.forEach(c=>{c.x.forEach(u=>{t=Math.min(t,u),e=Math.max(e,u)}),c.y.forEach(u=>{l=Math.min(l,u),r=Math.max(r,u)})});const m=(e-t)*.1,i=(r-l)*.1;return{xMin:t-m,xMax:e+m,yMin:l-i,yMax:r+i}},[k]),d=n.useMemo(()=>p||[q,O],[p,q,O]),y=n.useMemo(()=>g||[H,N],[g,H,N]),A=n.useMemo(()=>{const t=d[1]-d[0];let e=Math.pow(10,Math.floor(Math.log10(t)));t/e>10&&(e=e*2),t/e<4&&(e=e/2);const l=[];let r=Math.ceil(d[0]/e)*e;for(;r<=d[1];)l.push(r),r+=e;return l},[d]),B=n.useMemo(()=>{const t=y[1]-y[0];let e=Math.pow(10,Math.floor(Math.log10(t)));t/e>10&&(e=e*2),t/e<4&&(e=e/2);const l=[];let r=Math.ceil(y[0]/e)*e;for(;r<=y[1];)l.push(r),r+=e;return l},[y]),L=n.useMemo(()=>({tickcolor:o.tickColor,ticklen:12,tickwidth:1,ticks:"outside",tickfont:{size:16,color:o.textColor,family:f.CHART_FONT_FAMILY,weight:400},linecolor:o.lineColor,linewidth:1,position:0,zeroline:!1}),[o]);return n.useEffect(()=>{if(!h.current||!Y)return;const t=k.map((i,c)=>({x:i.x,y:i.y,type:"scatter",mode:"markers",name:i.name,marker:{color:$.seriesColor(c,i.color),size:i.size??I,symbol:i.symbol??(E==="stacked"?D[c%D.length]:"circle"),line:{color:o.paperBg,width:1}},hoverinfo:"none"})),e={title:{text:P,font:{size:32,family:f.CHART_FONT_FAMILY,color:o.textColor}},width:w.current.width,height:w.current.height,margin:{l:80,r:30,b:96,t:60,pad:10},paper_bgcolor:o.paperBg,plot_bgcolor:o.plotBg,font:{family:f.CHART_FONT_FAMILY},dragmode:!1,xaxis:{title:{text:C,font:{size:16,color:o.textSecondary,family:f.CHART_FONT_FAMILY,weight:400},standoff:32},gridcolor:o.gridColor,range:p,autorange:!p,tickmode:"array",tickvals:A,ticktext:A.map(String),showgrid:!0,automargin:!0,...L},yaxis:{title:{text:T,font:{size:16,color:o.textSecondary,family:f.CHART_FONT_FAMILY,weight:400},standoff:30},gridcolor:o.gridColor,range:g,autorange:!g,tickmode:"array",tickvals:B,showgrid:!0,automargin:!0,...L},legend:{x:.5,y:0,xanchor:"center",yanchor:"bottom",yref:"container",orientation:"h",font:{size:16,color:o.legendColor,family:f.CHART_FONT_FAMILY,weight:500}},showlegend:!0,hovermode:"closest"},l={responsive:!1,displayModeBar:!1,displaylogo:!1};let r=!1,m=null;return b.loadPlotly().then(i=>{if(r||!h.current)return;i.newPlot(h.current,t,e,l),R(h.current);const c=h.current;m=c,_.current=!0,v.current={...w.current};const u=c,j={color:o.spikeColor,width:2};u.on("plotly_hover",K=>{const M=K.points[0];M&&i.relayout(c,{shapes:[{type:"line",xref:"x",yref:"paper",x0:M.x,x1:M.x,y0:0,y1:1,line:j,layer:"below"},{type:"line",xref:"paper",yref:"y",x0:0,x1:1,y0:M.y,y1:M.y,line:j,layer:"below"}]})}),u.on("plotly_unhover",()=>{i.relayout(c,{shapes:[]})})}),()=>{r=!0,m&&(b.getLoadedPlotly().purge(m),_.current=!1)}},[k,Y,p,g,C,T,P,E,I,d,y,A,B,L,o,R]),n.useEffect(()=>{const t=h.current;!t||!_.current||s<=0||a<=0||v.current.width===s&&v.current.height===a||(v.current={width:s,height:a},b.getLoadedPlotly().relayout(t,{width:s,height:a}).catch(()=>{}))},[s,a]),X.jsxs("div",{ref:U,className:Z.cn("relative",G&&"w-full",J&&"h-full"),children:[X.jsx("div",{ref:h,style:{width:"100%",height:"100%"}}),W]})};exports.ScatterPlot=ee;
2
+ //# sourceMappingURL=ScatterPlot.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScatterPlot.cjs","sources":["../../../../src/components/charts/ScatterPlot/ScatterPlot.tsx"],"sourcesContent":["import React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { useChartTooltip } from \"../ChartTooltip\";\nimport { getLoadedPlotly, loadPlotly } from \"../plotly-loader\";\n\nimport type Plotly from \"plotly.js-dist\";\n\nimport { useElementSize } from \"@/hooks/use-element-size\";\nimport { CHART_FONT_FAMILY, usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { cn } from \"@/lib/utils\";\nimport { seriesColor } from \"@/utils/colors\";\n\ntype MarkerSymbol =\n | \"circle\"\n | \"square\"\n | \"diamond\"\n | \"triangle-up\"\n | \"triangle-down\"\n | \"star\";\n\ninterface ScatterPlotDataSeries {\n x: number[];\n y: number[];\n name: string;\n /** Optional color override (auto-assigned from CHART_COLORS if not provided) */\n color?: string;\n /** Optional marker symbol override (auto-assigned in the `stacked` variant) */\n symbol?: MarkerSymbol;\n /** Optional per-series marker size override (falls back to `markerSize`) */\n size?: number;\n}\n\ntype ScatterPlotVariant = \"default\" | \"stacked\";\n\ninterface ScatterPlotProps {\n /** One or more data series to plot */\n dataSeries: ScatterPlotDataSeries | ScatterPlotDataSeries[];\n /**\n * Fixed width in pixels. When omitted, the chart fills its container and\n * tracks the container's width via a `ResizeObserver`.\n */\n width?: number;\n /**\n * Fixed height in pixels. When omitted, the chart fills its container and\n * tracks the container's height via a `ResizeObserver`.\n */\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n xTitle?: string;\n yTitle?: string;\n title?: string;\n /**\n * `default` renders every series as circles; `stacked` cycles through\n * distinct marker symbols per series so overlapping series stay legible.\n */\n variant?: ScatterPlotVariant;\n /** Default marker size in pixels (per-series `size` takes precedence) */\n markerSize?: number;\n}\n\nconst DEFAULT_SYMBOLS: MarkerSymbol[] = [\n \"circle\",\n \"square\",\n \"diamond\",\n \"triangle-up\",\n \"triangle-down\",\n \"star\",\n];\n\nconst ScatterPlot: React.FC<ScatterPlotProps> = ({\n dataSeries,\n width,\n height,\n xRange,\n yRange,\n xTitle,\n yTitle,\n title = \"Scatter Plot\",\n variant = \"default\",\n markerSize = 10,\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const { bindTooltip, tooltipElement } = useChartTooltip({ xLabel: xTitle, yLabel: yTitle });\n\n // Omitted width/height → fill the container and track its measured size;\n // explicit pixel values override. See AreaPlot for the reference pattern.\n const [containerRef, measured] = useElementSize<HTMLDivElement>();\n const resolvedWidth = width ?? measured.width;\n const resolvedHeight = height ?? measured.height;\n const hasSize = resolvedWidth > 0 && resolvedHeight > 0;\n // Fill is per-dimension: omit width to fill the container width, omit height\n // to fill its height (so e.g. a fixed width with a container-driven height works).\n const fillWidth = width === undefined;\n const fillHeight = height === undefined;\n const sizeRef = useRef({ width: resolvedWidth, height: resolvedHeight });\n sizeRef.current = { width: resolvedWidth, height: resolvedHeight };\n const plotInitedRef = useRef(false);\n // Size last applied to the plot, so the resize effect can skip a redundant\n // relayout right after newPlot already drew at that size.\n const appliedSizeRef = useRef({ width: 0, height: 0 });\n\n const seriesArray = useMemo(\n () => (Array.isArray(dataSeries) ? dataSeries : [dataSeries]),\n [dataSeries],\n );\n\n const { xMin, xMax, yMin, yMax } = useMemo(() => {\n // Seed with ±Infinity, not MAX_VALUE/MIN_VALUE — MIN_VALUE is the smallest\n // positive number, so it would clamp the max for all-negative data.\n let minX = Infinity;\n let maxX = -Infinity;\n let minY = Infinity;\n let maxY = -Infinity;\n\n seriesArray.forEach((series) => {\n series.x.forEach((x) => {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n });\n series.y.forEach((y) => {\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n });\n });\n\n const xPadding = (maxX - minX) * 0.1;\n const yPadding = (maxY - minY) * 0.1;\n\n return {\n xMin: minX - xPadding,\n xMax: maxX + xPadding,\n yMin: minY - yPadding,\n yMax: maxY + yPadding,\n };\n }, [seriesArray]);\n\n const effectiveXRange = useMemo(\n () => xRange || [xMin, xMax],\n [xRange, xMin, xMax],\n );\n\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const xTicks = useMemo(() => {\n const range = effectiveXRange[1] - effectiveXRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveXRange[0] / step) * step;\n while (current <= effectiveXRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveXRange]);\n\n const yTicks = useMemo(() => {\n const range = effectiveYRange[1] - effectiveYRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveYRange[0] / step) * step;\n while (current <= effectiveYRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveYRange]);\n\n const tickOptions = useMemo(\n () => ({\n tickcolor: theme.tickColor,\n ticklen: 12,\n tickwidth: 1,\n ticks: \"outside\" as const,\n tickfont: {\n size: 16,\n color: theme.textColor,\n family: CHART_FONT_FAMILY,\n weight: 400,\n },\n linecolor: theme.lineColor,\n linewidth: 1,\n position: 0,\n zeroline: false,\n }),\n [theme],\n );\n\n useEffect(() => {\n if (!plotRef.current || !hasSize) return;\n\n const plotData = seriesArray.map((series, index) => ({\n x: series.x,\n y: series.y,\n type: \"scatter\" as const,\n mode: \"markers\" as const,\n name: series.name,\n marker: {\n color: seriesColor(index, series.color),\n size: series.size ?? markerSize,\n symbol:\n series.symbol ??\n (variant === \"stacked\"\n ? DEFAULT_SYMBOLS[index % DEFAULT_SYMBOLS.length]\n : (\"circle\" as const)),\n line: {\n color: theme.paperBg,\n width: 1,\n },\n },\n hoverinfo: \"none\" as const,\n }));\n\n const layout = {\n title: {\n text: title,\n font: {\n size: 32,\n family: CHART_FONT_FAMILY,\n color: theme.textColor,\n },\n },\n width: sizeRef.current.width,\n height: sizeRef.current.height,\n // Bottom margin reserves room for tick labels, the x-axis title, and the\n // container-anchored bottom legend stacked beneath them.\n margin: { l: 80, r: 30, b: 96, t: 60, pad: 10 },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: CHART_FONT_FAMILY,\n },\n dragmode: false as const,\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: CHART_FONT_FAMILY,\n weight: 400,\n },\n standoff: 32,\n },\n gridcolor: theme.gridColor,\n range: xRange,\n autorange: !xRange,\n tickmode: \"array\" as const,\n tickvals: xTicks,\n ticktext: xTicks.map(String),\n showgrid: true,\n // Reserve space for tick labels + the axis title so the bottom legend\n // can't overlap them at small sizes (SW-2157).\n automargin: true,\n ...tickOptions,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: CHART_FONT_FAMILY,\n weight: 400,\n },\n standoff: 30,\n },\n gridcolor: theme.gridColor,\n range: yRange,\n autorange: !yRange,\n tickmode: \"array\" as const,\n tickvals: yTicks,\n showgrid: true,\n automargin: true,\n ...tickOptions,\n },\n legend: {\n // Anchor to the bottom of the container (not the plot area) so the\n // legend always clears the x-axis tick labels + title — a paper-relative\n // fractional offset collapses into the ticks at small heights (SW-2157).\n x: 0.5,\n y: 0,\n xanchor: \"center\" as const,\n yanchor: \"bottom\" as const,\n yref: \"container\" as const,\n orientation: \"h\" as const,\n font: {\n size: 16,\n color: theme.legendColor,\n family: CHART_FONT_FAMILY,\n weight: 500,\n },\n },\n showlegend: true,\n hovermode: \"closest\" as const,\n };\n\n const config = {\n // Sizing is driven from the measured container; disable Plotly's own\n // window-resize responsiveness (it can't see container resizes).\n responsive: false,\n displayModeBar: false,\n displaylogo: false,\n };\n\n // Plotly is loaded lazily so it stays out of the consumer's main chunk\n // (SW-2007); the draw is skipped if the effect re-runs or unmounts first.\n let cancelled = false;\n let plotElement: HTMLDivElement | null = null;\n void loadPlotly().then((plotly) => {\n if (cancelled || !plotRef.current) return;\n plotly.newPlot(plotRef.current, plotData, layout, config);\n bindTooltip(plotRef.current);\n\n // Capture ref value for cleanup\n const element = plotRef.current;\n plotElement = element;\n plotInitedRef.current = true;\n appliedSizeRef.current = { ...sizeRef.current };\n\n // Crosshair guide lines through the hovered point. Drawn as layout shapes\n // with `layer: \"below\"` so they sit behind the markers — native Plotly\n // spikelines always render on top and can't be moved behind.\n const emitter = element as unknown as Plotly.PlotlyHTMLElement;\n const crosshairLine = { color: theme.spikeColor, width: 2 };\n emitter.on(\"plotly_hover\", (eventData) => {\n const point = eventData.points[0];\n if (!point) return;\n void plotly.relayout(element, {\n shapes: [\n {\n type: \"line\",\n xref: \"x\",\n yref: \"paper\",\n x0: point.x,\n x1: point.x,\n y0: 0,\n y1: 1,\n line: crosshairLine,\n layer: \"below\",\n },\n {\n type: \"line\",\n xref: \"paper\",\n yref: \"y\",\n x0: 0,\n x1: 1,\n y0: point.y,\n y1: point.y,\n line: crosshairLine,\n layer: \"below\",\n },\n ],\n });\n });\n emitter.on(\"plotly_unhover\", () => {\n void plotly.relayout(element, { shapes: [] });\n });\n });\n\n return () => {\n cancelled = true;\n if (plotElement) {\n getLoadedPlotly().purge(plotElement);\n plotInitedRef.current = false;\n }\n };\n }, [seriesArray, hasSize, xRange, yRange, xTitle, yTitle, title, variant, markerSize, effectiveXRange, effectiveYRange, xTicks, yTicks, tickOptions, theme, bindTooltip]);\n\n // Resize in place when the measured/overridden size changes — cheaper than\n // recreating the plot, and it preserves the hover/crosshair event bindings.\n useEffect(() => {\n const plotElement = plotRef.current;\n if (!plotElement || !plotInitedRef.current || resolvedWidth <= 0 || resolvedHeight <= 0) {\n return;\n }\n // newPlot already drew at the current size; skip the redundant relayout\n // (it would queue an automargin redraw that can reject if we unmount first).\n if (\n appliedSizeRef.current.width === resolvedWidth &&\n appliedSizeRef.current.height === resolvedHeight\n ) {\n return;\n }\n appliedSizeRef.current = { width: resolvedWidth, height: resolvedHeight };\n // Swallow rejections from a relayout that races an unmount/purge.\n // plotInitedRef guarantees Plotly finished loading, so sync access is safe.\n void getLoadedPlotly()\n .relayout(plotElement, { width: resolvedWidth, height: resolvedHeight })\n .catch(() => {});\n }, [resolvedWidth, resolvedHeight]);\n\n return (\n <div ref={containerRef} className={cn(\"relative\", fillWidth && \"w-full\", fillHeight && \"h-full\")}>\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { ScatterPlot };\nexport type {\n MarkerSymbol,\n ScatterPlotDataSeries,\n ScatterPlotProps,\n ScatterPlotVariant,\n};\n"],"names":["DEFAULT_SYMBOLS","ScatterPlot","dataSeries","width","height","xRange","yRange","xTitle","yTitle","title","variant","markerSize","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","containerRef","measured","useElementSize","resolvedWidth","resolvedHeight","hasSize","fillWidth","fillHeight","sizeRef","plotInitedRef","appliedSizeRef","seriesArray","useMemo","xMin","xMax","yMin","yMax","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveXRange","effectiveYRange","xTicks","range","step","ticks","current","yTicks","tickOptions","CHART_FONT_FAMILY","useEffect","plotData","index","seriesColor","layout","config","cancelled","plotElement","loadPlotly","plotly","element","emitter","crosshairLine","eventData","point","getLoadedPlotly","jsxs","cn","jsx"],"mappings":"qYA6DMA,EAAkC,CACtC,SACA,SACA,UACA,cACA,gBACA,MACF,EAEMC,GAA0C,CAAC,CAC/C,WAAAC,EACA,MAAAC,EACA,OAAAC,EACA,OAAAC,EACA,OAAAC,EACA,OAAAC,EACA,OAAAC,EACA,MAAAC,EAAQ,eACR,QAAAC,EAAU,UACV,WAAAC,EAAa,EACf,IAAM,CACJ,MAAMC,EAAUC,EAAAA,OAAuB,IAAI,EACrCC,EAAQC,EAAAA,eAAA,EACR,CAAE,YAAAC,EAAa,eAAAC,CAAA,EAAmBC,EAAAA,gBAAgB,CAAE,OAAQX,EAAQ,OAAQC,EAAQ,EAIpF,CAACW,EAAcC,CAAQ,EAAIC,iBAAA,EAC3BC,EAAgBnB,GAASiB,EAAS,MAClCG,EAAiBnB,GAAUgB,EAAS,OACpCI,EAAUF,EAAgB,GAAKC,EAAiB,EAGhDE,EAAYtB,IAAU,OACtBuB,EAAatB,IAAW,OACxBuB,EAAUd,EAAAA,OAAO,CAAE,MAAOS,EAAe,OAAQC,EAAgB,EACvEI,EAAQ,QAAU,CAAE,MAAOL,EAAe,OAAQC,CAAA,EAClD,MAAMK,EAAgBf,EAAAA,OAAO,EAAK,EAG5BgB,EAAiBhB,EAAAA,OAAO,CAAE,MAAO,EAAG,OAAQ,EAAG,EAE/CiB,EAAcC,EAAAA,QAClB,IAAO,MAAM,QAAQ7B,CAAU,EAAIA,EAAa,CAACA,CAAU,EAC3D,CAACA,CAAU,CAAA,EAGP,CAAE,KAAA8B,EAAM,KAAAC,EAAM,KAAAC,EAAM,KAAAC,CAAA,EAASJ,EAAAA,QAAQ,IAAM,CAG/C,IAAIK,EAAO,IACPC,EAAO,KACPC,EAAO,IACPC,EAAO,KAEXT,EAAY,QAASU,GAAW,CAC9BA,EAAO,EAAE,QAASC,GAAM,CACtBL,EAAO,KAAK,IAAIA,EAAMK,CAAC,EACvBJ,EAAO,KAAK,IAAIA,EAAMI,CAAC,CACzB,CAAC,EACDD,EAAO,EAAE,QAASE,GAAM,CACtBJ,EAAO,KAAK,IAAIA,EAAMI,CAAC,EACvBH,EAAO,KAAK,IAAIA,EAAMG,CAAC,CACzB,CAAC,CACH,CAAC,EAED,MAAMC,GAAYN,EAAOD,GAAQ,GAC3BQ,GAAYL,EAAOD,GAAQ,GAEjC,MAAO,CACL,KAAMF,EAAOO,EACb,KAAMN,EAAOM,EACb,KAAML,EAAOM,EACb,KAAML,EAAOK,CAAA,CAEjB,EAAG,CAACd,CAAW,CAAC,EAEVe,EAAkBd,EAAAA,QACtB,IAAM1B,GAAU,CAAC2B,EAAMC,CAAI,EAC3B,CAAC5B,EAAQ2B,EAAMC,CAAI,CAAA,EAGfa,EAAkBf,EAAAA,QACtB,IAAMzB,GAAU,CAAC4B,EAAMC,CAAI,EAC3B,CAAC7B,EAAQ4B,EAAMC,CAAI,CAAA,EAGfY,EAAShB,EAAAA,QAAQ,IAAM,CAC3B,MAAMiB,EAAQH,EAAgB,CAAC,EAAIA,EAAgB,CAAC,EACpD,IAAII,EAAO,KAAK,IAAI,GAAI,KAAK,MAAM,KAAK,MAAMD,CAAK,CAAC,CAAC,EAEjDA,EAAQC,EAAO,KAAIA,EAAOA,EAAO,GACjCD,EAAQC,EAAO,IAAGA,EAAOA,EAAO,GAEpC,MAAMC,EAAQ,CAAA,EACd,IAAIC,EAAU,KAAK,KAAKN,EAAgB,CAAC,EAAII,CAAI,EAAIA,EACrD,KAAOE,GAAWN,EAAgB,CAAC,GACjCK,EAAM,KAAKC,CAAO,EAClBA,GAAWF,EAEb,OAAOC,CACT,EAAG,CAACL,CAAe,CAAC,EAEdO,EAASrB,EAAAA,QAAQ,IAAM,CAC3B,MAAMiB,EAAQF,EAAgB,CAAC,EAAIA,EAAgB,CAAC,EACpD,IAAIG,EAAO,KAAK,IAAI,GAAI,KAAK,MAAM,KAAK,MAAMD,CAAK,CAAC,CAAC,EAEjDA,EAAQC,EAAO,KAAIA,EAAOA,EAAO,GACjCD,EAAQC,EAAO,IAAGA,EAAOA,EAAO,GAEpC,MAAMC,EAAQ,CAAA,EACd,IAAIC,EAAU,KAAK,KAAKL,EAAgB,CAAC,EAAIG,CAAI,EAAIA,EACrD,KAAOE,GAAWL,EAAgB,CAAC,GACjCI,EAAM,KAAKC,CAAO,EAClBA,GAAWF,EAEb,OAAOC,CACT,EAAG,CAACJ,CAAe,CAAC,EAEdO,EAActB,EAAAA,QAClB,KAAO,CACL,UAAWjB,EAAM,UACjB,QAAS,GACT,UAAW,EACX,MAAO,UACP,SAAU,CACR,KAAM,GACN,MAAOA,EAAM,UACb,OAAQwC,EAAAA,kBACR,OAAQ,GAAA,EAEV,UAAWxC,EAAM,UACjB,UAAW,EACX,SAAU,EACV,SAAU,EAAA,GAEZ,CAACA,CAAK,CAAA,EAGRyC,OAAAA,EAAAA,UAAU,IAAM,CACd,GAAI,CAAC3C,EAAQ,SAAW,CAACY,EAAS,OAElC,MAAMgC,EAAW1B,EAAY,IAAI,CAACU,EAAQiB,KAAW,CACnD,EAAGjB,EAAO,EACV,EAAGA,EAAO,EACV,KAAM,UACN,KAAM,UACN,KAAMA,EAAO,KACb,OAAQ,CACN,MAAOkB,EAAAA,YAAYD,EAAOjB,EAAO,KAAK,EACtC,KAAMA,EAAO,MAAQ7B,EACrB,OACE6B,EAAO,SACN9B,IAAY,UACTV,EAAgByD,EAAQzD,EAAgB,MAAM,EAC7C,UACP,KAAM,CACJ,MAAOc,EAAM,QACb,MAAO,CAAA,CACT,EAEF,UAAW,MAAA,EACX,EAEI6C,EAAS,CACb,MAAO,CACL,KAAMlD,EACN,KAAM,CACJ,KAAM,GACN,OAAQ6C,EAAAA,kBACR,MAAOxC,EAAM,SAAA,CACf,EAEF,MAAOa,EAAQ,QAAQ,MACvB,OAAQA,EAAQ,QAAQ,OAGxB,OAAQ,CAAE,EAAG,GAAI,EAAG,GAAI,EAAG,GAAI,EAAG,GAAI,IAAK,EAAA,EAC3C,cAAeb,EAAM,QACrB,aAAcA,EAAM,OACpB,KAAM,CACJ,OAAQwC,EAAAA,iBAAA,EAEV,SAAU,GACV,MAAO,CACL,MAAO,CACL,KAAM/C,EACN,KAAM,CACJ,KAAM,GACN,MAAOO,EAAM,cACb,OAAQwC,EAAAA,kBACR,OAAQ,GAAA,EAEV,SAAU,EAAA,EAEZ,UAAWxC,EAAM,UACjB,MAAOT,EACP,UAAW,CAACA,EACZ,SAAU,QACV,SAAU0C,EACV,SAAUA,EAAO,IAAI,MAAM,EAC3B,SAAU,GAGV,WAAY,GACZ,GAAGM,CAAA,EAEL,MAAO,CACL,MAAO,CACL,KAAM7C,EACN,KAAM,CACJ,KAAM,GACN,MAAOM,EAAM,cACb,OAAQwC,EAAAA,kBACR,OAAQ,GAAA,EAEV,SAAU,EAAA,EAEZ,UAAWxC,EAAM,UACjB,MAAOR,EACP,UAAW,CAACA,EACZ,SAAU,QACV,SAAU8C,EACV,SAAU,GACV,WAAY,GACZ,GAAGC,CAAA,EAEL,OAAQ,CAIN,EAAG,GACH,EAAG,EACH,QAAS,SACT,QAAS,SACT,KAAM,YACN,YAAa,IACb,KAAM,CACJ,KAAM,GACN,MAAOvC,EAAM,YACb,OAAQwC,EAAAA,kBACR,OAAQ,GAAA,CACV,EAEF,WAAY,GACZ,UAAW,SAAA,EAGPM,EAAS,CAGb,WAAY,GACZ,eAAgB,GAChB,YAAa,EAAA,EAKf,IAAIC,EAAY,GACZC,EAAqC,KACzC,OAAKC,aAAA,EAAa,KAAMC,GAAW,CACjC,GAAIH,GAAa,CAACjD,EAAQ,QAAS,OACnCoD,EAAO,QAAQpD,EAAQ,QAAS4C,EAAUG,EAAQC,CAAM,EACxD5C,EAAYJ,EAAQ,OAAO,EAG3B,MAAMqD,EAAUrD,EAAQ,QACxBkD,EAAcG,EACdrC,EAAc,QAAU,GACxBC,EAAe,QAAU,CAAE,GAAGF,EAAQ,OAAA,EAKtC,MAAMuC,EAAUD,EACVE,EAAgB,CAAE,MAAOrD,EAAM,WAAY,MAAO,CAAA,EACxDoD,EAAQ,GAAG,eAAiBE,GAAc,CACxC,MAAMC,EAAQD,EAAU,OAAO,CAAC,EAC3BC,GACAL,EAAO,SAASC,EAAS,CAC5B,OAAQ,CACN,CACE,KAAM,OACN,KAAM,IACN,KAAM,QACN,GAAII,EAAM,EACV,GAAIA,EAAM,EACV,GAAI,EACJ,GAAI,EACJ,KAAMF,EACN,MAAO,OAAA,EAET,CACE,KAAM,OACN,KAAM,QACN,KAAM,IACN,GAAI,EACJ,GAAI,EACJ,GAAIE,EAAM,EACV,GAAIA,EAAM,EACV,KAAMF,EACN,MAAO,OAAA,CACT,CACF,CACD,CACH,CAAC,EACDD,EAAQ,GAAG,iBAAkB,IAAM,CAC5BF,EAAO,SAASC,EAAS,CAAE,OAAQ,CAAA,EAAI,CAC9C,CAAC,CACH,CAAC,EAEM,IAAM,CACXJ,EAAY,GACRC,IACFQ,kBAAA,EAAkB,MAAMR,CAAW,EACnClC,EAAc,QAAU,GAE5B,CACF,EAAG,CAACE,EAAaN,EAASnB,EAAQC,EAAQC,EAAQC,EAAQC,EAAOC,EAASC,EAAYkC,EAAiBC,EAAiBC,EAAQK,EAAQC,EAAavC,EAAOE,CAAW,CAAC,EAIxKuC,EAAAA,UAAU,IAAM,CACd,MAAMO,EAAclD,EAAQ,QACxB,CAACkD,GAAe,CAAClC,EAAc,SAAWN,GAAiB,GAAKC,GAAkB,GAMpFM,EAAe,QAAQ,QAAUP,GACjCO,EAAe,QAAQ,SAAWN,IAIpCM,EAAe,QAAU,CAAE,MAAOP,EAAe,OAAQC,CAAA,EAGpD+C,kBAAA,EACF,SAASR,EAAa,CAAE,MAAOxC,EAAe,OAAQC,EAAgB,EACtE,MAAM,IAAM,CAAC,CAAC,EACnB,EAAG,CAACD,EAAeC,CAAc,CAAC,EAGhCgD,EAAAA,KAAC,MAAA,CAAI,IAAKpD,EAAc,UAAWqD,EAAAA,GAAG,WAAY/C,GAAa,SAAUC,GAAc,QAAQ,EAC7F,SAAA,CAAA+C,EAAAA,IAAC,MAAA,CAAI,IAAK7D,EAAS,MAAO,CAAE,MAAO,OAAQ,OAAQ,MAAA,CAAO,CAAG,EAC5DK,CAAA,EACH,CAEJ"}
@@ -0,0 +1,252 @@
1
+ import { jsxs as V, jsx as Z } from "react/jsx-runtime";
2
+ import { useRef as b, useMemo as f, useEffect as W } from "react";
3
+ import { useChartTooltip as $ } from "../ChartTooltip/ChartTooltip.js";
4
+ import { loadPlotly as tt, getLoadedPlotly as q } from "../plotly-loader.js";
5
+ import { useElementSize as et } from "../../../hooks/use-element-size.js";
6
+ import { usePlotlyTheme as ot, CHART_FONT_FAMILY as p } from "../../../hooks/use-plotly-theme.js";
7
+ import { cn as rt } from "../../../lib/utils.js";
8
+ import { seriesColor as it } from "../../../utils/colors.js";
9
+ const R = [
10
+ "circle",
11
+ "square",
12
+ "diamond",
13
+ "triangle-up",
14
+ "triangle-down",
15
+ "star"
16
+ ], ut = ({
17
+ dataSeries: w,
18
+ width: _,
19
+ height: A,
20
+ xRange: y,
21
+ yRange: g,
22
+ xTitle: z,
23
+ yTitle: C,
24
+ title: I = "Scatter Plot",
25
+ variant: S = "default",
26
+ markerSize: B = 10
27
+ }) => {
28
+ const h = b(null), o = ot(), { bindTooltip: Y, tooltipElement: U } = $({ xLabel: z, yLabel: C }), [G, T] = et(), c = _ ?? T.width, a = A ?? T.height, F = c > 0 && a > 0, J = _ === void 0, K = A === void 0, M = b({ width: c, height: a });
29
+ M.current = { width: c, height: a };
30
+ const E = b(!1), k = b({ width: 0, height: 0 }), v = f(
31
+ () => Array.isArray(w) ? w : [w],
32
+ [w]
33
+ ), { xMin: H, xMax: O, yMin: X, yMax: j } = f(() => {
34
+ let e = 1 / 0, t = -1 / 0, n = 1 / 0, r = -1 / 0;
35
+ v.forEach((l) => {
36
+ l.x.forEach((s) => {
37
+ e = Math.min(e, s), t = Math.max(t, s);
38
+ }), l.y.forEach((s) => {
39
+ n = Math.min(n, s), r = Math.max(r, s);
40
+ });
41
+ });
42
+ const m = (t - e) * 0.1, i = (r - n) * 0.1;
43
+ return {
44
+ xMin: e - m,
45
+ xMax: t + m,
46
+ yMin: n - i,
47
+ yMax: r + i
48
+ };
49
+ }, [v]), d = f(
50
+ () => y || [H, O],
51
+ [y, H, O]
52
+ ), u = f(
53
+ () => g || [X, j],
54
+ [g, X, j]
55
+ ), P = f(() => {
56
+ const e = d[1] - d[0];
57
+ let t = Math.pow(10, Math.floor(Math.log10(e)));
58
+ e / t > 10 && (t = t * 2), e / t < 4 && (t = t / 2);
59
+ const n = [];
60
+ let r = Math.ceil(d[0] / t) * t;
61
+ for (; r <= d[1]; )
62
+ n.push(r), r += t;
63
+ return n;
64
+ }, [d]), D = f(() => {
65
+ const e = u[1] - u[0];
66
+ let t = Math.pow(10, Math.floor(Math.log10(e)));
67
+ e / t > 10 && (t = t * 2), e / t < 4 && (t = t / 2);
68
+ const n = [];
69
+ let r = Math.ceil(u[0] / t) * t;
70
+ for (; r <= u[1]; )
71
+ n.push(r), r += t;
72
+ return n;
73
+ }, [u]), L = f(
74
+ () => ({
75
+ tickcolor: o.tickColor,
76
+ ticklen: 12,
77
+ tickwidth: 1,
78
+ ticks: "outside",
79
+ tickfont: {
80
+ size: 16,
81
+ color: o.textColor,
82
+ family: p,
83
+ weight: 400
84
+ },
85
+ linecolor: o.lineColor,
86
+ linewidth: 1,
87
+ position: 0,
88
+ zeroline: !1
89
+ }),
90
+ [o]
91
+ );
92
+ return W(() => {
93
+ if (!h.current || !F) return;
94
+ const e = v.map((i, l) => ({
95
+ x: i.x,
96
+ y: i.y,
97
+ type: "scatter",
98
+ mode: "markers",
99
+ name: i.name,
100
+ marker: {
101
+ color: it(l, i.color),
102
+ size: i.size ?? B,
103
+ symbol: i.symbol ?? (S === "stacked" ? R[l % R.length] : "circle"),
104
+ line: {
105
+ color: o.paperBg,
106
+ width: 1
107
+ }
108
+ },
109
+ hoverinfo: "none"
110
+ })), t = {
111
+ title: {
112
+ text: I,
113
+ font: {
114
+ size: 32,
115
+ family: p,
116
+ color: o.textColor
117
+ }
118
+ },
119
+ width: M.current.width,
120
+ height: M.current.height,
121
+ // Bottom margin reserves room for tick labels, the x-axis title, and the
122
+ // container-anchored bottom legend stacked beneath them.
123
+ margin: { l: 80, r: 30, b: 96, t: 60, pad: 10 },
124
+ paper_bgcolor: o.paperBg,
125
+ plot_bgcolor: o.plotBg,
126
+ font: {
127
+ family: p
128
+ },
129
+ dragmode: !1,
130
+ xaxis: {
131
+ title: {
132
+ text: z,
133
+ font: {
134
+ size: 16,
135
+ color: o.textSecondary,
136
+ family: p,
137
+ weight: 400
138
+ },
139
+ standoff: 32
140
+ },
141
+ gridcolor: o.gridColor,
142
+ range: y,
143
+ autorange: !y,
144
+ tickmode: "array",
145
+ tickvals: P,
146
+ ticktext: P.map(String),
147
+ showgrid: !0,
148
+ // Reserve space for tick labels + the axis title so the bottom legend
149
+ // can't overlap them at small sizes (SW-2157).
150
+ automargin: !0,
151
+ ...L
152
+ },
153
+ yaxis: {
154
+ title: {
155
+ text: C,
156
+ font: {
157
+ size: 16,
158
+ color: o.textSecondary,
159
+ family: p,
160
+ weight: 400
161
+ },
162
+ standoff: 30
163
+ },
164
+ gridcolor: o.gridColor,
165
+ range: g,
166
+ autorange: !g,
167
+ tickmode: "array",
168
+ tickvals: D,
169
+ showgrid: !0,
170
+ automargin: !0,
171
+ ...L
172
+ },
173
+ legend: {
174
+ // Anchor to the bottom of the container (not the plot area) so the
175
+ // legend always clears the x-axis tick labels + title — a paper-relative
176
+ // fractional offset collapses into the ticks at small heights (SW-2157).
177
+ x: 0.5,
178
+ y: 0,
179
+ xanchor: "center",
180
+ yanchor: "bottom",
181
+ yref: "container",
182
+ orientation: "h",
183
+ font: {
184
+ size: 16,
185
+ color: o.legendColor,
186
+ family: p,
187
+ weight: 500
188
+ }
189
+ },
190
+ showlegend: !0,
191
+ hovermode: "closest"
192
+ }, n = {
193
+ // Sizing is driven from the measured container; disable Plotly's own
194
+ // window-resize responsiveness (it can't see container resizes).
195
+ responsive: !1,
196
+ displayModeBar: !1,
197
+ displaylogo: !1
198
+ };
199
+ let r = !1, m = null;
200
+ return tt().then((i) => {
201
+ if (r || !h.current) return;
202
+ i.newPlot(h.current, e, t, n), Y(h.current);
203
+ const l = h.current;
204
+ m = l, E.current = !0, k.current = { ...M.current };
205
+ const s = l, N = { color: o.spikeColor, width: 2 };
206
+ s.on("plotly_hover", (Q) => {
207
+ const x = Q.points[0];
208
+ x && i.relayout(l, {
209
+ shapes: [
210
+ {
211
+ type: "line",
212
+ xref: "x",
213
+ yref: "paper",
214
+ x0: x.x,
215
+ x1: x.x,
216
+ y0: 0,
217
+ y1: 1,
218
+ line: N,
219
+ layer: "below"
220
+ },
221
+ {
222
+ type: "line",
223
+ xref: "paper",
224
+ yref: "y",
225
+ x0: 0,
226
+ x1: 1,
227
+ y0: x.y,
228
+ y1: x.y,
229
+ line: N,
230
+ layer: "below"
231
+ }
232
+ ]
233
+ });
234
+ }), s.on("plotly_unhover", () => {
235
+ i.relayout(l, { shapes: [] });
236
+ });
237
+ }), () => {
238
+ r = !0, m && (q().purge(m), E.current = !1);
239
+ };
240
+ }, [v, F, y, g, z, C, I, S, B, d, u, P, D, L, o, Y]), W(() => {
241
+ const e = h.current;
242
+ !e || !E.current || c <= 0 || a <= 0 || k.current.width === c && k.current.height === a || (k.current = { width: c, height: a }, q().relayout(e, { width: c, height: a }).catch(() => {
243
+ }));
244
+ }, [c, a]), /* @__PURE__ */ V("div", { ref: G, className: rt("relative", J && "w-full", K && "h-full"), children: [
245
+ /* @__PURE__ */ Z("div", { ref: h, style: { width: "100%", height: "100%" } }),
246
+ U
247
+ ] });
248
+ };
249
+ export {
250
+ ut as ScatterPlot
251
+ };
252
+ //# sourceMappingURL=ScatterPlot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScatterPlot.js","sources":["../../../../src/components/charts/ScatterPlot/ScatterPlot.tsx"],"sourcesContent":["import React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { useChartTooltip } from \"../ChartTooltip\";\nimport { getLoadedPlotly, loadPlotly } from \"../plotly-loader\";\n\nimport type Plotly from \"plotly.js-dist\";\n\nimport { useElementSize } from \"@/hooks/use-element-size\";\nimport { CHART_FONT_FAMILY, usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { cn } from \"@/lib/utils\";\nimport { seriesColor } from \"@/utils/colors\";\n\ntype MarkerSymbol =\n | \"circle\"\n | \"square\"\n | \"diamond\"\n | \"triangle-up\"\n | \"triangle-down\"\n | \"star\";\n\ninterface ScatterPlotDataSeries {\n x: number[];\n y: number[];\n name: string;\n /** Optional color override (auto-assigned from CHART_COLORS if not provided) */\n color?: string;\n /** Optional marker symbol override (auto-assigned in the `stacked` variant) */\n symbol?: MarkerSymbol;\n /** Optional per-series marker size override (falls back to `markerSize`) */\n size?: number;\n}\n\ntype ScatterPlotVariant = \"default\" | \"stacked\";\n\ninterface ScatterPlotProps {\n /** One or more data series to plot */\n dataSeries: ScatterPlotDataSeries | ScatterPlotDataSeries[];\n /**\n * Fixed width in pixels. When omitted, the chart fills its container and\n * tracks the container's width via a `ResizeObserver`.\n */\n width?: number;\n /**\n * Fixed height in pixels. When omitted, the chart fills its container and\n * tracks the container's height via a `ResizeObserver`.\n */\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n xTitle?: string;\n yTitle?: string;\n title?: string;\n /**\n * `default` renders every series as circles; `stacked` cycles through\n * distinct marker symbols per series so overlapping series stay legible.\n */\n variant?: ScatterPlotVariant;\n /** Default marker size in pixels (per-series `size` takes precedence) */\n markerSize?: number;\n}\n\nconst DEFAULT_SYMBOLS: MarkerSymbol[] = [\n \"circle\",\n \"square\",\n \"diamond\",\n \"triangle-up\",\n \"triangle-down\",\n \"star\",\n];\n\nconst ScatterPlot: React.FC<ScatterPlotProps> = ({\n dataSeries,\n width,\n height,\n xRange,\n yRange,\n xTitle,\n yTitle,\n title = \"Scatter Plot\",\n variant = \"default\",\n markerSize = 10,\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const { bindTooltip, tooltipElement } = useChartTooltip({ xLabel: xTitle, yLabel: yTitle });\n\n // Omitted width/height → fill the container and track its measured size;\n // explicit pixel values override. See AreaPlot for the reference pattern.\n const [containerRef, measured] = useElementSize<HTMLDivElement>();\n const resolvedWidth = width ?? measured.width;\n const resolvedHeight = height ?? measured.height;\n const hasSize = resolvedWidth > 0 && resolvedHeight > 0;\n // Fill is per-dimension: omit width to fill the container width, omit height\n // to fill its height (so e.g. a fixed width with a container-driven height works).\n const fillWidth = width === undefined;\n const fillHeight = height === undefined;\n const sizeRef = useRef({ width: resolvedWidth, height: resolvedHeight });\n sizeRef.current = { width: resolvedWidth, height: resolvedHeight };\n const plotInitedRef = useRef(false);\n // Size last applied to the plot, so the resize effect can skip a redundant\n // relayout right after newPlot already drew at that size.\n const appliedSizeRef = useRef({ width: 0, height: 0 });\n\n const seriesArray = useMemo(\n () => (Array.isArray(dataSeries) ? dataSeries : [dataSeries]),\n [dataSeries],\n );\n\n const { xMin, xMax, yMin, yMax } = useMemo(() => {\n // Seed with ±Infinity, not MAX_VALUE/MIN_VALUE — MIN_VALUE is the smallest\n // positive number, so it would clamp the max for all-negative data.\n let minX = Infinity;\n let maxX = -Infinity;\n let minY = Infinity;\n let maxY = -Infinity;\n\n seriesArray.forEach((series) => {\n series.x.forEach((x) => {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n });\n series.y.forEach((y) => {\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n });\n });\n\n const xPadding = (maxX - minX) * 0.1;\n const yPadding = (maxY - minY) * 0.1;\n\n return {\n xMin: minX - xPadding,\n xMax: maxX + xPadding,\n yMin: minY - yPadding,\n yMax: maxY + yPadding,\n };\n }, [seriesArray]);\n\n const effectiveXRange = useMemo(\n () => xRange || [xMin, xMax],\n [xRange, xMin, xMax],\n );\n\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const xTicks = useMemo(() => {\n const range = effectiveXRange[1] - effectiveXRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveXRange[0] / step) * step;\n while (current <= effectiveXRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveXRange]);\n\n const yTicks = useMemo(() => {\n const range = effectiveYRange[1] - effectiveYRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveYRange[0] / step) * step;\n while (current <= effectiveYRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveYRange]);\n\n const tickOptions = useMemo(\n () => ({\n tickcolor: theme.tickColor,\n ticklen: 12,\n tickwidth: 1,\n ticks: \"outside\" as const,\n tickfont: {\n size: 16,\n color: theme.textColor,\n family: CHART_FONT_FAMILY,\n weight: 400,\n },\n linecolor: theme.lineColor,\n linewidth: 1,\n position: 0,\n zeroline: false,\n }),\n [theme],\n );\n\n useEffect(() => {\n if (!plotRef.current || !hasSize) return;\n\n const plotData = seriesArray.map((series, index) => ({\n x: series.x,\n y: series.y,\n type: \"scatter\" as const,\n mode: \"markers\" as const,\n name: series.name,\n marker: {\n color: seriesColor(index, series.color),\n size: series.size ?? markerSize,\n symbol:\n series.symbol ??\n (variant === \"stacked\"\n ? DEFAULT_SYMBOLS[index % DEFAULT_SYMBOLS.length]\n : (\"circle\" as const)),\n line: {\n color: theme.paperBg,\n width: 1,\n },\n },\n hoverinfo: \"none\" as const,\n }));\n\n const layout = {\n title: {\n text: title,\n font: {\n size: 32,\n family: CHART_FONT_FAMILY,\n color: theme.textColor,\n },\n },\n width: sizeRef.current.width,\n height: sizeRef.current.height,\n // Bottom margin reserves room for tick labels, the x-axis title, and the\n // container-anchored bottom legend stacked beneath them.\n margin: { l: 80, r: 30, b: 96, t: 60, pad: 10 },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: CHART_FONT_FAMILY,\n },\n dragmode: false as const,\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: CHART_FONT_FAMILY,\n weight: 400,\n },\n standoff: 32,\n },\n gridcolor: theme.gridColor,\n range: xRange,\n autorange: !xRange,\n tickmode: \"array\" as const,\n tickvals: xTicks,\n ticktext: xTicks.map(String),\n showgrid: true,\n // Reserve space for tick labels + the axis title so the bottom legend\n // can't overlap them at small sizes (SW-2157).\n automargin: true,\n ...tickOptions,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: CHART_FONT_FAMILY,\n weight: 400,\n },\n standoff: 30,\n },\n gridcolor: theme.gridColor,\n range: yRange,\n autorange: !yRange,\n tickmode: \"array\" as const,\n tickvals: yTicks,\n showgrid: true,\n automargin: true,\n ...tickOptions,\n },\n legend: {\n // Anchor to the bottom of the container (not the plot area) so the\n // legend always clears the x-axis tick labels + title — a paper-relative\n // fractional offset collapses into the ticks at small heights (SW-2157).\n x: 0.5,\n y: 0,\n xanchor: \"center\" as const,\n yanchor: \"bottom\" as const,\n yref: \"container\" as const,\n orientation: \"h\" as const,\n font: {\n size: 16,\n color: theme.legendColor,\n family: CHART_FONT_FAMILY,\n weight: 500,\n },\n },\n showlegend: true,\n hovermode: \"closest\" as const,\n };\n\n const config = {\n // Sizing is driven from the measured container; disable Plotly's own\n // window-resize responsiveness (it can't see container resizes).\n responsive: false,\n displayModeBar: false,\n displaylogo: false,\n };\n\n // Plotly is loaded lazily so it stays out of the consumer's main chunk\n // (SW-2007); the draw is skipped if the effect re-runs or unmounts first.\n let cancelled = false;\n let plotElement: HTMLDivElement | null = null;\n void loadPlotly().then((plotly) => {\n if (cancelled || !plotRef.current) return;\n plotly.newPlot(plotRef.current, plotData, layout, config);\n bindTooltip(plotRef.current);\n\n // Capture ref value for cleanup\n const element = plotRef.current;\n plotElement = element;\n plotInitedRef.current = true;\n appliedSizeRef.current = { ...sizeRef.current };\n\n // Crosshair guide lines through the hovered point. Drawn as layout shapes\n // with `layer: \"below\"` so they sit behind the markers — native Plotly\n // spikelines always render on top and can't be moved behind.\n const emitter = element as unknown as Plotly.PlotlyHTMLElement;\n const crosshairLine = { color: theme.spikeColor, width: 2 };\n emitter.on(\"plotly_hover\", (eventData) => {\n const point = eventData.points[0];\n if (!point) return;\n void plotly.relayout(element, {\n shapes: [\n {\n type: \"line\",\n xref: \"x\",\n yref: \"paper\",\n x0: point.x,\n x1: point.x,\n y0: 0,\n y1: 1,\n line: crosshairLine,\n layer: \"below\",\n },\n {\n type: \"line\",\n xref: \"paper\",\n yref: \"y\",\n x0: 0,\n x1: 1,\n y0: point.y,\n y1: point.y,\n line: crosshairLine,\n layer: \"below\",\n },\n ],\n });\n });\n emitter.on(\"plotly_unhover\", () => {\n void plotly.relayout(element, { shapes: [] });\n });\n });\n\n return () => {\n cancelled = true;\n if (plotElement) {\n getLoadedPlotly().purge(plotElement);\n plotInitedRef.current = false;\n }\n };\n }, [seriesArray, hasSize, xRange, yRange, xTitle, yTitle, title, variant, markerSize, effectiveXRange, effectiveYRange, xTicks, yTicks, tickOptions, theme, bindTooltip]);\n\n // Resize in place when the measured/overridden size changes — cheaper than\n // recreating the plot, and it preserves the hover/crosshair event bindings.\n useEffect(() => {\n const plotElement = plotRef.current;\n if (!plotElement || !plotInitedRef.current || resolvedWidth <= 0 || resolvedHeight <= 0) {\n return;\n }\n // newPlot already drew at the current size; skip the redundant relayout\n // (it would queue an automargin redraw that can reject if we unmount first).\n if (\n appliedSizeRef.current.width === resolvedWidth &&\n appliedSizeRef.current.height === resolvedHeight\n ) {\n return;\n }\n appliedSizeRef.current = { width: resolvedWidth, height: resolvedHeight };\n // Swallow rejections from a relayout that races an unmount/purge.\n // plotInitedRef guarantees Plotly finished loading, so sync access is safe.\n void getLoadedPlotly()\n .relayout(plotElement, { width: resolvedWidth, height: resolvedHeight })\n .catch(() => {});\n }, [resolvedWidth, resolvedHeight]);\n\n return (\n <div ref={containerRef} className={cn(\"relative\", fillWidth && \"w-full\", fillHeight && \"h-full\")}>\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { ScatterPlot };\nexport type {\n MarkerSymbol,\n ScatterPlotDataSeries,\n ScatterPlotProps,\n ScatterPlotVariant,\n};\n"],"names":["DEFAULT_SYMBOLS","ScatterPlot","dataSeries","width","height","xRange","yRange","xTitle","yTitle","title","variant","markerSize","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","containerRef","measured","useElementSize","resolvedWidth","resolvedHeight","hasSize","fillWidth","fillHeight","sizeRef","plotInitedRef","appliedSizeRef","seriesArray","useMemo","xMin","xMax","yMin","yMax","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveXRange","effectiveYRange","xTicks","range","step","ticks","current","yTicks","tickOptions","CHART_FONT_FAMILY","useEffect","plotData","index","seriesColor","layout","config","cancelled","plotElement","loadPlotly","plotly","element","emitter","crosshairLine","eventData","point","getLoadedPlotly","jsxs","cn","jsx"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const de=require("react/jsx-runtime"),n=require("react");;/* empty css */const Se=require("../ChartTooltip/ChartTooltip.cjs"),x=require("../plotly-loader.cjs"),E=require("./constants.cjs"),c=require("./utils.cjs"),Te=require("../../../hooks/use-plotly-theme.cjs"),fe={},Ie={enabled:!0},ve=({data:R,title:z,xAxis:u=fe,yAxis:i=fe,colorMapping:r,shapeMapping:V,sizeMapping:X,tooltip:a=Ie,enableClickSelection:$=!0,enableBoxSelection:g=!0,enableLassoSelection:p=!0,selectedIds:H,onSelectionChange:J,onPointClick:K,downsampling:N,width:w=800,height:L=600,showColorBar:Q=!0,className:W})=>{const S=n.useRef(null),Y=Te.usePlotlyTheme(),P=n.useRef(J),Z=n.useRef(K),M=n.useRef(new Set),_=n.useRef(!1);P.current=J,Z.current=K;const[me,k]=n.useState(new Set),ee=H!==void 0,q=ee?H:me;M.current=q,_.current=ee;const te=n.useMemo(()=>new Set([...q].map(String)),[q]),ne=n.useMemo(()=>new Map(R.map(e=>[String(e.id),e.id])),[R]),t=n.useMemo(()=>N?c.downsampleData(R,N):R,[R,N]),h=n.useMemo(()=>c.mapColors(t,r),[t,r]),re=n.useMemo(()=>c.mapShapes(t,V),[t,V]),se=n.useMemo(()=>c.mapSizes(t,X),[t,X]),oe=n.useMemo(()=>{if(u.range)return u.range;if(u.autoRange!==!1)return c.calculateAxisRange(t,"x",u.autoRangePadding??E.PLOT_CONSTANTS.AUTO_RANGE_PADDING,u.scale)},[t,u]),ce=n.useMemo(()=>{if(i.range)return i.range;if(i.autoRange!==!1)return c.calculateAxisRange(t,"y",i.autoRangePadding??E.PLOT_CONSTANTS.AUTO_RANGE_PADDING,i.scale)},[t,i]),f=a.enabled!==!1,C=a.native===!0,B=n.useMemo(()=>f?t.map(e=>a.content?a.content(e):c.generateTooltipContent(e,a.fields)):[],[t,a,f]),{bindTooltip:le,tooltipElement:ye}=Se.useChartTooltip({getLines:e=>{const s=e[0]?.pointIndex;return s===void 0?[]:(B[s]??"").split("<br>").filter(Boolean)}}),ue=n.useMemo(()=>r?.type==="continuous"&&r.field&&t.length>0?t.map(e=>{const s=e.metadata?.[r.field];return typeof s=="number"&&Number.isFinite(s)?s:0}):h,[t,r,h]),D=n.useMemo(()=>{if(r?.type==="continuous"){const e=r.colorScale||E.DEFAULT_COLOR_SCALE;return e}},[r]),ie=n.useMemo(()=>{const e={size:se,symbol:re,line:{width:0}};if(r?.type==="continuous"&&D){if(e.color=ue,e.colorscale=D,e.showscale=Q,r.field){const s=r.min!==void 0&&r.max!==void 0?{min:r.min,max:r.max}:c.calculateRange(t,r.field);e.cmin=s.min,e.cmax=s.max,e.colorbar={title:{text:r.field,side:"right"},thickness:20,len:.7}}}else e.color=h;return e},[se,re,r,D,ue,Q,t,h]);n.useEffect(()=>{const e=S.current;if(!e||t.length===0)return;const s=t.map(d=>d.x),T=t.map(d=>d.y),O=t.map(d=>String(d.id)),I=[{x:s,y:T,ids:O,mode:"markers",type:"scatter",marker:ie,hoverinfo:f?C?"text":"none":"skip",text:B,hovertemplate:f&&C?"%{text}<extra></extra>":void 0,showlegend:!1,unselected:{marker:{opacity:.3}},selected:{marker:{opacity:1,line:{color:E.COLORS.selected,width:2}}}}],G=c.getPlotlyLayoutConfig({title:z,xAxis:u,yAxis:i,width:w,height:L,xRange:oe,yRange:ce,enableLassoSelection:p,enableBoxSelection:g,theme:Y}),U={responsive:!0,displayModeBar:!0,displaylogo:!1,modeBarButtonsToAdd:[],modeBarButtonsToRemove:["toImage"]};g&&U.modeBarButtonsToAdd?.push("select2d"),p&&U.modeBarButtonsToAdd?.push("lasso2d");let ae=!1,b=null;return x.loadPlotly().then(d=>{if(ae||!S.current)return;d.newPlot(e,I,G,U);const j=e;$&&j.on("plotly_click",l=>{const m=l.points[0];if(m&&m.data.ids){const A=m.data.ids[m.pointIndex],y=t.find(o=>String(o.id)===A);if(y){Z.current?.(y,l.event);const o=c.getSelectionMode(l.event),v=c.applySelection(M.current,new Set([y.id]),o);_.current||k(v),P.current?.(v,o)}}}),(g||p)&&(j.on("plotly_selected",l=>{if(l&&l.points){const m=l.points.map(o=>{if(o.data.ids&&o.pointIndex!==void 0){const v=o.data.ids[o.pointIndex];return ne.get(v)??v}return null}).filter(o=>o!==null),A="replace",y=new Set(m);_.current||k(y),P.current?.(y,A)}}),j.on("plotly_deselect",()=>{const l=new Set;_.current||k(l),P.current?.(l,"replace")})),f&&!C&&le(e),b=e}),()=>{ae=!0,b&&x.getLoadedPlotly().purge(b)}},[t,ie,u,i,oe,ce,z,w,L,a,B,$,g,p,ne,f,C,le,Y]),n.useEffect(()=>{if(!S.current||t.length===0)return;let e=!1;return x.loadPlotly().then(s=>{const T=S.current;if(e||!T||!T._fullLayout)return;const O=T,F=t.map((I,G)=>te.has(String(I.id))?G:null).filter(I=>I!==null);F.length>0?s.restyle(O,{selectedpoints:[F]},[0]):s.restyle(O,{selectedpoints:[null]},[0])}),()=>{e=!0}},[te,t]);const Re=W?`scatter-plot-interactive relative ${W}`:"scatter-plot-interactive relative";return de.jsxs("div",{className:Re,children:[de.jsx("div",{ref:S,className:"scatter-plot-interactive__plot",style:{width:w,height:L}}),ye]})};exports.ScatterPlotInteractive=ve;
2
+ //# sourceMappingURL=ScatterPlotInteractive.cjs.map