matterviz 0.3.7 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. package/dist/Icon.svelte +7 -4
  2. package/dist/MillerIndexInput.svelte +1 -1
  3. package/dist/api/optimade.js +32 -26
  4. package/dist/app.css +0 -3
  5. package/dist/brillouin/BrillouinZone.svelte +8 -3
  6. package/dist/brillouin/BrillouinZone.svelte.d.ts +2 -1
  7. package/dist/brillouin/BrillouinZoneScene.svelte +52 -6
  8. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -0
  9. package/dist/brillouin/BrillouinZoneTooltip.svelte +16 -25
  10. package/dist/brillouin/compute.js +10 -14
  11. package/dist/chempot-diagram/ChemPotDiagram.svelte +14 -13
  12. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +12 -15
  13. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +8 -10
  14. package/dist/chempot-diagram/async-compute.svelte.js +3 -1
  15. package/dist/chempot-diagram/chempot-worker.js +2 -1
  16. package/dist/chempot-diagram/compute.d.ts +1 -1
  17. package/dist/chempot-diagram/compute.js +17 -19
  18. package/dist/colors/index.js +6 -5
  19. package/dist/composition/FormulaFilter.svelte +12 -6
  20. package/dist/composition/PieChart.svelte +6 -5
  21. package/dist/composition/chem-sys.d.ts +8 -0
  22. package/dist/composition/chem-sys.js +85 -0
  23. package/dist/composition/format.js +4 -2
  24. package/dist/composition/index.d.ts +1 -0
  25. package/dist/composition/index.js +1 -0
  26. package/dist/composition/parse.js +25 -13
  27. package/dist/convex-hull/ConvexHull2D.svelte +12 -10
  28. package/dist/convex-hull/ConvexHull3D.svelte +5 -5
  29. package/dist/convex-hull/ConvexHull4D.svelte +5 -9
  30. package/dist/convex-hull/ConvexHullStats.svelte +12 -12
  31. package/dist/convex-hull/GasPressureControls.svelte +4 -4
  32. package/dist/convex-hull/TemperatureSlider.svelte +2 -2
  33. package/dist/convex-hull/demo-temperature.d.ts +1 -1
  34. package/dist/convex-hull/demo-temperature.js +20 -22
  35. package/dist/convex-hull/gas-thermodynamics.d.ts +2 -2
  36. package/dist/convex-hull/gas-thermodynamics.js +22 -30
  37. package/dist/convex-hull/helpers.d.ts +3 -0
  38. package/dist/convex-hull/helpers.js +17 -9
  39. package/dist/convex-hull/index.d.ts +1 -1
  40. package/dist/convex-hull/thermodynamics.js +83 -78
  41. package/dist/convex-hull/types.d.ts +1 -1
  42. package/dist/coordination/CoordinationBarPlot.svelte +23 -23
  43. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
  44. package/dist/element/ElementTile.svelte.d.ts +1 -1
  45. package/dist/fermi-surface/FermiSlice.svelte +13 -5
  46. package/dist/fermi-surface/FermiSurface.svelte +11 -5
  47. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  48. package/dist/fermi-surface/FermiSurfaceControls.svelte +1 -1
  49. package/dist/fermi-surface/FermiSurfaceScene.svelte +3 -0
  50. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +8 -34
  51. package/dist/fermi-surface/compute.js +59 -59
  52. package/dist/fermi-surface/export.js +3 -2
  53. package/dist/fermi-surface/parse.js +7 -4
  54. package/dist/fermi-surface/types.d.ts +1 -0
  55. package/dist/heatmap-matrix/HeatmapMatrix.svelte +23 -21
  56. package/dist/heatmap-matrix/index.js +1 -1
  57. package/dist/io/decompress.js +4 -2
  58. package/dist/io/export.d.ts +4 -4
  59. package/dist/io/export.js +47 -25
  60. package/dist/io/fetch.js +5 -1
  61. package/dist/io/file-drop.d.ts +1 -1
  62. package/dist/io/file-drop.js +35 -36
  63. package/dist/io/url-drop.js +64 -33
  64. package/dist/isosurface/parse.js +6 -7
  65. package/dist/isosurface/slice.js +5 -4
  66. package/dist/isosurface/types.js +1 -1
  67. package/dist/keyboard.d.ts +3 -0
  68. package/dist/keyboard.js +23 -0
  69. package/dist/labels.d.ts +1 -1
  70. package/dist/labels.js +8 -7
  71. package/dist/layout/PropertyFilter.svelte +3 -2
  72. package/dist/layout/SettingsSection.svelte +1 -1
  73. package/dist/layout/json-tree/JsonNode.svelte +1 -1
  74. package/dist/layout/json-tree/JsonTree.svelte +2 -2
  75. package/dist/layout/json-tree/utils.js +5 -4
  76. package/dist/marching-cubes.js +8 -13
  77. package/dist/math.d.ts +5 -1
  78. package/dist/math.js +24 -9
  79. package/dist/overlays/DraggablePane.svelte +4 -4
  80. package/dist/periodic-table/PeriodicTable.svelte +20 -9
  81. package/dist/periodic-table/PropertySelect.svelte +1 -0
  82. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +9 -3
  83. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
  84. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  85. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
  86. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +1 -1
  87. package/dist/phase-diagram/build-diagram.js +2 -2
  88. package/dist/phase-diagram/parse.js +6 -5
  89. package/dist/phase-diagram/types.d.ts +1 -1
  90. package/dist/phase-diagram/utils.d.ts +3 -3
  91. package/dist/phase-diagram/utils.js +8 -12
  92. package/dist/plot/{BarPlot.svelte → bar/BarPlot.svelte} +229 -587
  93. package/dist/plot/{BarPlot.svelte.d.ts → bar/BarPlot.svelte.d.ts} +5 -5
  94. package/dist/plot/{BarPlotControls.svelte → bar/BarPlotControls.svelte} +6 -5
  95. package/dist/plot/{BarPlotControls.svelte.d.ts → bar/BarPlotControls.svelte.d.ts} +3 -3
  96. package/dist/plot/{SpacegroupBarPlot.svelte → bar/SpacegroupBarPlot.svelte} +6 -6
  97. package/dist/plot/{SpacegroupBarPlot.svelte.d.ts → bar/SpacegroupBarPlot.svelte.d.ts} +1 -1
  98. package/dist/plot/bar/data.d.ts +40 -0
  99. package/dist/plot/bar/data.js +154 -0
  100. package/dist/plot/bar/geometry.d.ts +39 -0
  101. package/dist/plot/bar/geometry.js +60 -0
  102. package/dist/plot/bar/index.d.ts +3 -0
  103. package/dist/plot/bar/index.js +3 -0
  104. package/dist/plot/box/BoxPlot.svelte +1462 -0
  105. package/dist/plot/box/BoxPlot.svelte.d.ts +94 -0
  106. package/dist/plot/box/BoxPlotControls.svelte +109 -0
  107. package/dist/plot/box/BoxPlotControls.svelte.d.ts +19 -0
  108. package/dist/plot/box/Violin.svelte +14 -0
  109. package/dist/plot/box/Violin.svelte.d.ts +70 -0
  110. package/dist/plot/box/box-plot.d.ts +55 -0
  111. package/dist/plot/box/box-plot.js +126 -0
  112. package/dist/plot/box/index.d.ts +5 -0
  113. package/dist/plot/box/index.js +5 -0
  114. package/dist/plot/box/kde.d.ts +16 -0
  115. package/dist/plot/box/kde.js +160 -0
  116. package/dist/plot/box/quantile.d.ts +3 -0
  117. package/dist/plot/box/quantile.js +53 -0
  118. package/dist/plot/{auto-place.js → core/auto-place.js} +2 -2
  119. package/dist/plot/core/axis-utils.d.ts +46 -0
  120. package/dist/plot/core/axis-utils.js +110 -0
  121. package/dist/plot/{AxisLabel.svelte → core/components/AxisLabel.svelte} +2 -2
  122. package/dist/plot/{AxisLabel.svelte.d.ts → core/components/AxisLabel.svelte.d.ts} +1 -1
  123. package/dist/plot/{ColorBar.svelte → core/components/ColorBar.svelte} +36 -33
  124. package/dist/plot/{ColorBar.svelte.d.ts → core/components/ColorBar.svelte.d.ts} +2 -2
  125. package/dist/plot/{ColorScaleSelect.svelte → core/components/ColorScaleSelect.svelte} +4 -3
  126. package/dist/plot/{ColorScaleSelect.svelte.d.ts → core/components/ColorScaleSelect.svelte.d.ts} +2 -2
  127. package/dist/plot/core/components/ControlPane.svelte +46 -0
  128. package/dist/plot/core/components/ControlPane.svelte.d.ts +13 -0
  129. package/dist/plot/{FillArea.svelte → core/components/FillArea.svelte} +17 -6
  130. package/dist/plot/{FillArea.svelte.d.ts → core/components/FillArea.svelte.d.ts} +1 -1
  131. package/dist/plot/{InteractiveAxisLabel.svelte → core/components/InteractiveAxisLabel.svelte} +3 -3
  132. package/dist/plot/{InteractiveAxisLabel.svelte.d.ts → core/components/InteractiveAxisLabel.svelte.d.ts} +2 -2
  133. package/dist/plot/{Line.svelte → core/components/Line.svelte} +30 -13
  134. package/dist/plot/{PlotAxis.svelte → core/components/PlotAxis.svelte} +7 -5
  135. package/dist/plot/{PlotAxis.svelte.d.ts → core/components/PlotAxis.svelte.d.ts} +3 -2
  136. package/dist/plot/{PlotControls.svelte → core/components/PlotControls.svelte} +17 -29
  137. package/dist/plot/core/components/PlotControls.svelte.d.ts +4 -0
  138. package/dist/plot/{PlotLegend.svelte → core/components/PlotLegend.svelte} +21 -10
  139. package/dist/plot/{PlotLegend.svelte.d.ts → core/components/PlotLegend.svelte.d.ts} +3 -2
  140. package/dist/plot/{PlotTooltip.svelte → core/components/PlotTooltip.svelte} +17 -1
  141. package/dist/plot/{PlotTooltip.svelte.d.ts → core/components/PlotTooltip.svelte.d.ts} +8 -0
  142. package/dist/plot/{PortalSelect.svelte → core/components/PortalSelect.svelte} +11 -7
  143. package/dist/plot/{ReferenceLine.svelte → core/components/ReferenceLine.svelte} +3 -3
  144. package/dist/plot/{ReferenceLine.svelte.d.ts → core/components/ReferenceLine.svelte.d.ts} +1 -1
  145. package/dist/plot/{ReferenceLine3D.svelte → core/components/ReferenceLine3D.svelte} +4 -4
  146. package/dist/plot/{ReferenceLine3D.svelte.d.ts → core/components/ReferenceLine3D.svelte.d.ts} +2 -2
  147. package/dist/plot/{ReferencePlane.svelte → core/components/ReferencePlane.svelte} +7 -7
  148. package/dist/plot/{ReferencePlane.svelte.d.ts → core/components/ReferencePlane.svelte.d.ts} +2 -2
  149. package/dist/plot/{ZeroLines.svelte → core/components/ZeroLines.svelte} +3 -3
  150. package/dist/plot/{ZeroLines.svelte.d.ts → core/components/ZeroLines.svelte.d.ts} +3 -3
  151. package/dist/plot/{ZoomRect.svelte → core/components/ZoomRect.svelte} +1 -1
  152. package/dist/plot/{ZoomRect.svelte.d.ts → core/components/ZoomRect.svelte.d.ts} +1 -1
  153. package/dist/plot/core/components/index.d.ts +17 -0
  154. package/dist/plot/core/components/index.js +17 -0
  155. package/dist/plot/{data-cleaning.d.ts → core/data-cleaning.d.ts} +71 -1
  156. package/dist/plot/{data-cleaning.js → core/data-cleaning.js} +3 -5
  157. package/dist/plot/{data-transform.d.ts → core/data-transform.d.ts} +2 -2
  158. package/dist/plot/{data-transform.js → core/data-transform.js} +3 -3
  159. package/dist/plot/core/fill-utils.d.ts +33 -0
  160. package/dist/plot/core/fill-utils.js +388 -0
  161. package/dist/plot/{hover-lock.svelte.js → core/hover-lock.svelte.js} +5 -6
  162. package/dist/plot/core/index.d.ts +10 -0
  163. package/dist/plot/core/index.js +11 -0
  164. package/dist/plot/core/interactions.d.ts +35 -0
  165. package/dist/plot/core/interactions.js +195 -0
  166. package/dist/plot/{layout.d.ts → core/layout.d.ts} +1 -0
  167. package/dist/plot/{layout.js → core/layout.js} +16 -8
  168. package/dist/plot/{reference-line.d.ts → core/reference-line.d.ts} +1 -1
  169. package/dist/plot/{reference-line.js → core/reference-line.js} +23 -36
  170. package/dist/plot/{scales.d.ts → core/scales.d.ts} +2 -2
  171. package/dist/plot/{scales.js → core/scales.js} +84 -85
  172. package/dist/plot/core/svg.d.ts +2 -0
  173. package/dist/plot/core/svg.js +41 -0
  174. package/dist/plot/{types.d.ts → core/types.d.ts} +19 -79
  175. package/dist/plot/{types.js → core/types.js} +1 -1
  176. package/dist/plot/{utils → core/utils}/label-placement.d.ts +2 -2
  177. package/dist/plot/core/utils/series-visibility.d.ts +26 -0
  178. package/dist/plot/{utils → core/utils}/series-visibility.js +29 -2
  179. package/dist/plot/core/utils.d.ts +11 -0
  180. package/dist/plot/core/utils.js +27 -0
  181. package/dist/plot/{Histogram.svelte → histogram/Histogram.svelte} +154 -294
  182. package/dist/plot/{Histogram.svelte.d.ts → histogram/Histogram.svelte.d.ts} +2 -2
  183. package/dist/plot/{HistogramControls.svelte → histogram/HistogramControls.svelte} +6 -6
  184. package/dist/plot/{HistogramControls.svelte.d.ts → histogram/HistogramControls.svelte.d.ts} +4 -4
  185. package/dist/plot/histogram/index.d.ts +2 -0
  186. package/dist/plot/histogram/index.js +2 -0
  187. package/dist/plot/index.d.ts +8 -41
  188. package/dist/plot/index.js +10 -39
  189. package/dist/plot/sankey/Sankey.svelte +700 -0
  190. package/dist/plot/sankey/Sankey.svelte.d.ts +74 -0
  191. package/dist/plot/sankey/SankeyControls.svelte +98 -0
  192. package/dist/plot/sankey/SankeyControls.svelte.d.ts +19 -0
  193. package/dist/plot/sankey/index.d.ts +4 -0
  194. package/dist/plot/sankey/index.js +3 -0
  195. package/dist/plot/sankey/sankey-types.d.ts +42 -0
  196. package/dist/plot/sankey/sankey-types.js +4 -0
  197. package/dist/plot/sankey/sankey.d.ts +52 -0
  198. package/dist/plot/sankey/sankey.js +187 -0
  199. package/dist/plot/{BinnedScatterPlot.svelte → scatter/BinnedScatterPlot.svelte} +61 -59
  200. package/dist/plot/{BinnedScatterPlot.svelte.d.ts → scatter/BinnedScatterPlot.svelte.d.ts} +4 -4
  201. package/dist/plot/{ElementScatter.svelte → scatter/ElementScatter.svelte} +6 -6
  202. package/dist/plot/{ElementScatter.svelte.d.ts → scatter/ElementScatter.svelte.d.ts} +2 -2
  203. package/dist/plot/{ScatterPlot.svelte → scatter/ScatterPlot.svelte} +221 -642
  204. package/dist/plot/{ScatterPlot.svelte.d.ts → scatter/ScatterPlot.svelte.d.ts} +7 -7
  205. package/dist/plot/{ScatterPlotControls.svelte → scatter/ScatterPlotControls.svelte} +6 -5
  206. package/dist/plot/{ScatterPlotControls.svelte.d.ts → scatter/ScatterPlotControls.svelte.d.ts} +1 -1
  207. package/dist/plot/{ScatterPoint.svelte → scatter/ScatterPoint.svelte} +7 -7
  208. package/dist/plot/{ScatterPoint.svelte.d.ts → scatter/ScatterPoint.svelte.d.ts} +3 -3
  209. package/dist/plot/{adaptive-density.d.ts → scatter/adaptive-density.d.ts} +14 -4
  210. package/dist/plot/{adaptive-density.js → scatter/adaptive-density.js} +46 -20
  211. package/dist/plot/{binned-scatter-types.d.ts → scatter/binned-scatter-types.d.ts} +3 -3
  212. package/dist/plot/scatter/index.d.ts +7 -0
  213. package/dist/plot/scatter/index.js +5 -0
  214. package/dist/plot/scatter/scatter-data.d.ts +19 -0
  215. package/dist/plot/scatter/scatter-data.js +212 -0
  216. package/dist/plot/{ScatterPlot3D.svelte → scatter-3d/ScatterPlot3D.svelte} +12 -10
  217. package/dist/plot/{ScatterPlot3D.svelte.d.ts → scatter-3d/ScatterPlot3D.svelte.d.ts} +7 -7
  218. package/dist/plot/{ScatterPlot3DControls.svelte → scatter-3d/ScatterPlot3DControls.svelte} +5 -4
  219. package/dist/plot/{ScatterPlot3DControls.svelte.d.ts → scatter-3d/ScatterPlot3DControls.svelte.d.ts} +2 -2
  220. package/dist/plot/{ScatterPlot3DScene.svelte → scatter-3d/ScatterPlot3DScene.svelte} +11 -11
  221. package/dist/plot/{ScatterPlot3DScene.svelte.d.ts → scatter-3d/ScatterPlot3DScene.svelte.d.ts} +3 -3
  222. package/dist/plot/{Surface3D.svelte → scatter-3d/Surface3D.svelte} +1 -1
  223. package/dist/plot/{Surface3D.svelte.d.ts → scatter-3d/Surface3D.svelte.d.ts} +1 -1
  224. package/dist/plot/scatter-3d/index.d.ts +4 -0
  225. package/dist/plot/scatter-3d/index.js +4 -0
  226. package/dist/plot/sunburst/Sunburst.svelte +1045 -0
  227. package/dist/plot/sunburst/Sunburst.svelte.d.ts +96 -0
  228. package/dist/plot/sunburst/SunburstControls.svelte +200 -0
  229. package/dist/plot/sunburst/SunburstControls.svelte.d.ts +26 -0
  230. package/dist/plot/sunburst/index.d.ts +4 -0
  231. package/dist/plot/sunburst/index.js +4 -0
  232. package/dist/plot/sunburst/render.d.ts +34 -0
  233. package/dist/plot/sunburst/render.js +122 -0
  234. package/dist/plot/sunburst/sunburst.d.ts +62 -0
  235. package/dist/plot/sunburst/sunburst.js +266 -0
  236. package/dist/rdf/RdfPlot.svelte +2 -1
  237. package/dist/rdf/calc-rdf.js +11 -24
  238. package/dist/sanitize.js +1 -1
  239. package/dist/settings.d.ts +65 -1
  240. package/dist/settings.js +262 -0
  241. package/dist/spectral/Bands.svelte +39 -29
  242. package/dist/spectral/Bands.svelte.d.ts +3 -4
  243. package/dist/spectral/BandsAndDos.svelte +1 -1
  244. package/dist/spectral/BrillouinBandsDos.svelte +39 -27
  245. package/dist/spectral/Dos.svelte +10 -19
  246. package/dist/spectral/Dos.svelte.d.ts +2 -2
  247. package/dist/spectral/helpers.d.ts +3 -1
  248. package/dist/spectral/helpers.js +95 -29
  249. package/dist/structure/AtomLegend.svelte +8 -9
  250. package/dist/structure/CellSelect.svelte +1 -2
  251. package/dist/structure/Cylinder.svelte +12 -8
  252. package/dist/structure/Cylinder.svelte.d.ts +4 -1
  253. package/dist/structure/Structure.svelte +78 -72
  254. package/dist/structure/Structure.svelte.d.ts +1 -1
  255. package/dist/structure/StructureInfoPane.svelte +5 -6
  256. package/dist/structure/StructureScene.svelte +11 -10
  257. package/dist/structure/atom-properties.js +6 -6
  258. package/dist/structure/bond-order-perception.js +1 -1
  259. package/dist/structure/bonding.d.ts +1 -0
  260. package/dist/structure/bonding.js +43 -15
  261. package/dist/structure/export.js +27 -23
  262. package/dist/structure/index.d.ts +2 -4
  263. package/dist/structure/index.js +1 -3
  264. package/dist/structure/label-placement.js +4 -4
  265. package/dist/structure/measure.d.ts +3 -2
  266. package/dist/structure/measure.js +6 -5
  267. package/dist/structure/parse.js +121 -103
  268. package/dist/structure/pbc.js +4 -0
  269. package/dist/symmetry/SymmetryStats.svelte +2 -2
  270. package/dist/symmetry/index.d.ts +1 -1
  271. package/dist/symmetry/index.js +22 -24
  272. package/dist/symmetry/spacegroups.d.ts +7 -0
  273. package/dist/symmetry/spacegroups.js +48 -13
  274. package/dist/table/HeatmapTable.svelte +63 -11
  275. package/dist/table/HeatmapTable.svelte.d.ts +1 -1
  276. package/dist/table/index.d.ts +1 -3
  277. package/dist/table/index.js +1 -1
  278. package/dist/theme/index.js +8 -8
  279. package/dist/tooltip/KCoords.svelte +45 -0
  280. package/dist/tooltip/KCoords.svelte.d.ts +8 -0
  281. package/dist/tooltip/index.d.ts +1 -0
  282. package/dist/tooltip/index.js +1 -0
  283. package/dist/trajectory/Trajectory.svelte +66 -40
  284. package/dist/trajectory/Trajectory.svelte.d.ts +2 -1
  285. package/dist/trajectory/TrajectoryExportPane.svelte +2 -1
  286. package/dist/trajectory/TrajectoryInfoPane.svelte +2 -1
  287. package/dist/trajectory/format-detect.d.ts +1 -0
  288. package/dist/trajectory/format-detect.js +25 -11
  289. package/dist/trajectory/frame-reader.js +17 -50
  290. package/dist/trajectory/helpers.js +1 -1
  291. package/dist/trajectory/index.js +1 -1
  292. package/dist/trajectory/parse/hdf5.js +1 -1
  293. package/dist/trajectory/parse/index.js +14 -6
  294. package/dist/trajectory/parse/vasp.js +36 -17
  295. package/dist/trajectory/parse/xyz.d.ts +24 -0
  296. package/dist/trajectory/parse/xyz.js +102 -89
  297. package/dist/trajectory/plotting.d.ts +1 -1
  298. package/dist/trajectory/plotting.js +15 -15
  299. package/dist/utils.d.ts +1 -0
  300. package/dist/utils.js +6 -4
  301. package/dist/xrd/XrdPlot.svelte +2 -1
  302. package/dist/xrd/calc-xrd.js +15 -12
  303. package/dist/xrd/parse.js +2 -2
  304. package/package.json +22 -18
  305. package/dist/plot/PlotControls.svelte.d.ts +0 -4
  306. package/dist/plot/axis-utils.d.ts +0 -19
  307. package/dist/plot/axis-utils.js +0 -78
  308. package/dist/plot/defaults.d.ts +0 -19
  309. package/dist/plot/defaults.js +0 -9
  310. package/dist/plot/fill-utils.d.ts +0 -46
  311. package/dist/plot/fill-utils.js +0 -322
  312. package/dist/plot/interactions.d.ts +0 -12
  313. package/dist/plot/interactions.js +0 -101
  314. package/dist/plot/svg.d.ts +0 -1
  315. package/dist/plot/svg.js +0 -11
  316. package/dist/plot/utils/series-visibility.d.ts +0 -15
  317. package/dist/plot/utils.d.ts +0 -1
  318. package/dist/plot/utils.js +0 -14
  319. /package/dist/plot/{auto-place.d.ts → core/auto-place.d.ts} +0 -0
  320. /package/dist/plot/{Line.svelte.d.ts → core/components/Line.svelte.d.ts} +0 -0
  321. /package/dist/plot/{PortalSelect.svelte.d.ts → core/components/PortalSelect.svelte.d.ts} +0 -0
  322. /package/dist/plot/{hover-lock.svelte.d.ts → core/hover-lock.svelte.d.ts} +0 -0
  323. /package/dist/plot/{utils → core/utils}/label-placement.js +0 -0
  324. /package/dist/plot/{binned-scatter-types.js → scatter/binned-scatter-types.js} +0 -0
@@ -1,6 +1,7 @@
1
1
  // Async wrapper for compute_chempot_diagram via Web Worker.
2
2
  // Falls back to synchronous main-thread computation during SSR.
3
3
  import { compute_chempot_diagram, formula_key_from_composition } from './compute';
4
+ import { to_error } from '../utils';
4
5
  let worker = null;
5
6
  let next_id = 0;
6
7
  const pending = new Map();
@@ -28,6 +29,7 @@ function get_worker() {
28
29
  if (typeof Worker === `undefined`)
29
30
  return null;
30
31
  if (!worker) {
32
+ // oxlint-disable-next-line eslint-plugin-unicorn/relative-url-style -- Vite worker detection requires the `./` prefix
31
33
  worker = new Worker(new URL(`./chempot-worker.js`, import.meta.url), { type: `module` });
32
34
  worker.addEventListener(`message`, ({ data: { id, result, error } }) => {
33
35
  const req = pending.get(id);
@@ -71,7 +73,7 @@ export function compute_chempot_async(entries, config = {}) {
71
73
  }
72
74
  catch (err) {
73
75
  pending.delete(id);
74
- reject(err instanceof Error ? err : new Error(String(err)));
76
+ reject(to_error(err));
75
77
  }
76
78
  });
77
79
  return track_pending(request_key, promise);
@@ -1,4 +1,5 @@
1
1
  import { compute_chempot_diagram } from './compute';
2
+ import { to_error } from '../utils';
2
3
  self.addEventListener(`message`, (event) => {
3
4
  const { id, entries, config } = event.data;
4
5
  try {
@@ -6,6 +7,6 @@ self.addEventListener(`message`, (event) => {
6
7
  postMessage({ id, result, error: null });
7
8
  }
8
9
  catch (err) {
9
- postMessage({ id, result: null, error: err instanceof Error ? err.message : String(err) });
10
+ postMessage({ id, result: null, error: to_error(err).message });
10
11
  }
11
12
  });
@@ -8,7 +8,7 @@ export declare function get_min_entries_and_el_refs(entries: PhaseData[]): {
8
8
  };
9
9
  export declare function compute_form_energy_per_atom(entry: PhaseData, el_refs: Record<string, PhaseData>): number;
10
10
  export declare function best_form_energy_for_formula(entries: PhaseData[], formula: string, el_refs: Record<string, PhaseData>): number | undefined;
11
- export declare function renormalize_entries(entries: PhaseData[], el_refs: Record<string, PhaseData>, elements: string[]): PhaseData[];
11
+ export declare const renormalize_entries: (entries: PhaseData[], el_refs: Record<string, PhaseData>, elements: string[]) => PhaseData[];
12
12
  export declare function build_hyperplanes(min_entries: PhaseData[], el_refs: Record<string, PhaseData>, elements: string[]): {
13
13
  hyperplanes: number[][];
14
14
  hyperplane_entries: PhaseData[];
@@ -112,24 +112,22 @@ export function best_form_energy_for_formula(entries, formula, el_refs) {
112
112
  }
113
113
  // Renormalize entry energies to be relative to elemental references (formal chemical potentials).
114
114
  // For each entry, subtracts sum(x_i * E_ref_i) from its energy per atom.
115
- export function renormalize_entries(entries, el_refs, elements) {
116
- return entries.map((entry) => {
117
- const atoms = count_atoms_in_composition(entry.composition);
118
- let renorm_energy = 0;
119
- for (const el of elements) {
120
- const frac = atoms > 0 ? (entry.composition[el] ?? 0) / atoms : 0;
121
- const ref = el_refs[el];
122
- if (ref)
123
- renorm_energy += frac * get_energy_per_atom(ref);
124
- }
125
- const new_energy_per_atom = get_energy_per_atom(entry) - renorm_energy;
126
- return {
127
- ...entry,
128
- energy: new_energy_per_atom * atoms,
129
- energy_per_atom: new_energy_per_atom,
130
- };
131
- });
132
- }
115
+ export const renormalize_entries = (entries, el_refs, elements) => entries.map((entry) => {
116
+ const atoms = count_atoms_in_composition(entry.composition);
117
+ let renorm_energy = 0;
118
+ for (const el of elements) {
119
+ const frac = atoms > 0 ? (entry.composition[el] ?? 0) / atoms : 0;
120
+ const ref = el_refs[el];
121
+ if (ref)
122
+ renorm_energy += frac * get_energy_per_atom(ref);
123
+ }
124
+ const new_energy_per_atom = get_energy_per_atom(entry) - renorm_energy;
125
+ return {
126
+ ...entry,
127
+ energy: new_energy_per_atom * atoms,
128
+ energy_per_atom: new_energy_per_atom,
129
+ };
130
+ });
133
131
  // Build hyperplane representation for minimum entries.
134
132
  // Each row is [x_1, ..., x_n, -E_per_atom].
135
133
  // Filters to entries with negative formation energy plus all elemental refs.
@@ -782,7 +780,7 @@ export function compute_chempot_diagram(entries, config = {}) {
782
780
  if (is_projection) {
783
781
  const col_indices = display_elements.map((element) => {
784
782
  const idx = compute_elements.indexOf(element);
785
- if (idx < 0) {
783
+ if (idx === -1) {
786
784
  throw new Error(`Display element ${element} not present in compute element set`);
787
785
  }
788
786
  return idx;
@@ -1,4 +1,4 @@
1
- import { rgb } from 'd3-color';
1
+ import { color as d3_color, rgb } from 'd3-color';
2
2
  import * as d3_sc from 'd3-scale-chromatic';
3
3
  import alloy_colors from './alloy-colors.json' with { type: 'json' };
4
4
  import dark_mode_colors from './dark-mode-colors.json' with { type: 'json' };
@@ -55,13 +55,14 @@ export const ELEMENT_COLOR_SCHEMES = {
55
55
  'Dark Mode': dark_mode_hex,
56
56
  };
57
57
  export const default_element_colors = { ...vesta_hex };
58
- // Helper function to detect if a value is a color string
58
+ // Detect if a value is a CSS color string. d3-color parses hex, rgb()/rgba(),
59
+ // hsl()/hsla(), and named colors case-insensitively, rejecting arbitrary words like
60
+ // `pending`. It doesn't parse var()/color()/currentcolor, so match those explicitly.
59
61
  export const is_color = (val) => {
60
62
  if (typeof val !== `string`)
61
63
  return false;
62
- // Check for hex colors, rgb/rgba, hsl/hsla, color(), var(), and named colors
63
- // Exclude incomplete function prefixes like 'rgb', 'hsl', 'var', 'color'
64
- return /^(#[0-9a-f]{3,8}|rgba?\([^)]+\)|hsla?\([^)]+\)|color\([^)]+\)|var\([^)]+\)|(?!rgb$|hsl$|var$|color$)[a-z]+)$/i.test(val.trim());
64
+ const trimmed = val.trim();
65
+ return /^(?:var|color)\([^)]+\)$|^currentcolor$/i.test(trimmed) || d3_color(trimmed) !== null;
65
66
  };
66
67
  export const PLOT_COLORS = [
67
68
  // Color series for e.g. line plots
@@ -338,10 +338,10 @@
338
338
  normalized = normalized.replaceAll(superscript, ascii)
339
339
  }
340
340
  return normalized
341
- .replaceAll(`·`, ``)
342
- .replaceAll(`⋅`, ``)
341
+ // keep hydrate dots (deleting would glue digits: CuSO4·5H2O -> CuSO45H2O)
342
+ .replaceAll(`⋅`, `·`)
343
343
  .replaceAll(`−`, `-`)
344
- .replace(/\s+/g, ``)
344
+ .replaceAll(/\s+/g, ``)
345
345
  }
346
346
 
347
347
  function normalize_exact_formula(input: string): string {
@@ -361,7 +361,7 @@
361
361
  const wildcard_tokens = tokens.filter((token) => token.element === null)
362
362
 
363
363
  // Merge explicit element counts before sorting.
364
- const merged_explicit: Array<{ element: string; count: number }> = []
364
+ const merged_explicit: { element: string; count: number }[] = []
365
365
  for (const token of explicit) {
366
366
  const existing = merged_explicit.find((item) =>
367
367
  item.element === token.element
@@ -609,14 +609,20 @@
609
609
  const reformatted = format_for_mode(elements, next_mode)
610
610
 
611
611
  search_mode = next_mode
612
- last_synced = value = input_value = reformatted // update last_synced to prevent effect re-inference
612
+ // set last_synced too to prevent effect re-inference
613
+ last_synced = reformatted
614
+ value = reformatted
615
+ input_value = reformatted
613
616
  run_validation(reformatted, next_mode)
614
617
  onchange?.(reformatted, next_mode)
615
618
  }
616
619
 
617
620
  function set_value(new_value: string, forced_mode?: FormulaSearchMode): void {
618
621
  const mode = forced_mode ?? (mode_locked ? search_mode : infer_mode(new_value))
619
- last_synced = value = input_value = new_value // update last_synced to prevent effect re-inference
622
+ // set last_synced too to prevent effect re-inference
623
+ last_synced = new_value
624
+ value = new_value
625
+ input_value = new_value
620
626
  search_mode = mode
621
627
  if (new_value.trim()) add_to_history(new_value)
622
628
  close_history()
@@ -151,11 +151,9 @@
151
151
  } else if (is_medium_slice) {
152
152
  // Medium slices: place closer to outer edge, proportional to chart size
153
153
  label_radius = outer_radius - outer_radius * 0.3
154
- is_outside_slice = false
155
154
  } else {
156
155
  // Large slices: place in middle of ring
157
156
  label_radius = (outer_radius + inner_radius_adjusted) / 2
158
- is_outside_slice = false
159
157
  }
160
158
 
161
159
  // Calculate font scale based on slice size and smart text fitting
@@ -293,9 +291,15 @@
293
291
  .pie-segment.interactive:focus {
294
292
  outline: none;
295
293
  }
294
+ svg {
295
+ /* very thin slices place their labels outside the pie at 1.2x the outer radius,
296
+ past the square viewBox - the default svg overflow: hidden would clip them */
297
+ overflow: visible;
298
+ }
296
299
  foreignobject {
297
300
  pointer-events: none;
298
301
  transition: all 0.2s ease;
302
+ overflow: visible;
299
303
  }
300
304
  foreignobject.hovered {
301
305
  font-weight: 700;
@@ -310,9 +314,6 @@
310
314
  transition: all 0.2s ease;
311
315
  white-space: nowrap;
312
316
  }
313
- foreignobject {
314
- overflow: visible;
315
- }
316
317
  .pie-label.hovered {
317
318
  font-weight: 700;
318
319
  }
@@ -0,0 +1,8 @@
1
+ import type { SunburstNode } from '../plot/core/types';
2
+ export interface ChemSysSunburstMetadata {
3
+ chem_sys: string;
4
+ arity: number;
5
+ [key: string]: unknown;
6
+ }
7
+ export declare const arity_name: (arity: number) => string;
8
+ export declare function chem_sys_sunburst_data(entries: readonly string[]): SunburstNode<ChemSysSunburstMetadata>[];
@@ -0,0 +1,85 @@
1
+ // Build arity -> chemical-system hierarchy data for the Sunburst component
2
+ // (counterpart to pymatviz's chem_sys_sunburst).
3
+ import { is_valid_element, parse_formula } from './parse';
4
+ const ARITY_NAMES = [
5
+ ``,
6
+ `unary`,
7
+ `binary`,
8
+ `ternary`,
9
+ `quaternary`,
10
+ `quinary`,
11
+ `senary`,
12
+ `septenary`,
13
+ `octonary`,
14
+ `nonary`,
15
+ `denary`,
16
+ ];
17
+ // || (not ??) so the empty index-0 placeholder also falls through to "0-ary"
18
+ export const arity_name = (arity) => ARITY_NAMES[arity] || `${arity}-ary`;
19
+ // Build arity -> chemical-system sunburst data from a list of chemical systems
20
+ // ("Li-Fe-O") and/or formulas ("LiFePO4"), one entry per occurrence (counts become
21
+ // leaf values). Systems are normalized to alphabetical element order, so "O-Li" and
22
+ // "Li2O" both count toward "Li-O". Ids follow the "<arity>/<system>" scheme.
23
+ export function chem_sys_sunburst_data(entries) {
24
+ // Inputs are one entry per occurrence, so the same formula typically repeats many
25
+ // times - memoize raw entry -> normalized system (null = invalid) to parse each
26
+ // distinct string only once
27
+ const normalized = new Map();
28
+ const normalize = (entry) => {
29
+ let elements;
30
+ if (entry.includes(`-`)) {
31
+ elements = entry.split(`-`).map((el) => el.trim());
32
+ if (!elements.every(is_valid_element))
33
+ return null;
34
+ }
35
+ else {
36
+ try {
37
+ elements = Object.keys(parse_formula(entry));
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ if (elements.length === 0)
44
+ return null;
45
+ return [...new Set(elements)].sort().join(`-`);
46
+ };
47
+ const counts = new Map();
48
+ let n_invalid = 0;
49
+ for (const entry of entries) {
50
+ let chem_sys = normalized.get(entry);
51
+ if (chem_sys === undefined) {
52
+ chem_sys = normalize(entry);
53
+ normalized.set(entry, chem_sys);
54
+ }
55
+ if (chem_sys === null) {
56
+ n_invalid += 1;
57
+ continue;
58
+ }
59
+ counts.set(chem_sys, (counts.get(chem_sys) ?? 0) + 1);
60
+ }
61
+ if (n_invalid > 0) {
62
+ console.warn(`chem_sys_sunburst_data: skipped ${n_invalid} invalid entr${n_invalid === 1 ? `y` : `ies`} (expected chemical systems like "Li-Fe-O" or formulas like "LiFePO4")`);
63
+ }
64
+ // One composite sort (arity ascending, then count descending) puts systems in
65
+ // final order; consecutive same-arity runs then collapse into one branch each
66
+ const sorted = [...counts]
67
+ .map(([chem_sys, count]) => ({ chem_sys, count, arity: chem_sys.split(`-`).length }))
68
+ .sort((sys_a, sys_b) => sys_a.arity - sys_b.arity || sys_b.count - sys_a.count);
69
+ const roots = [];
70
+ let branch;
71
+ for (const { chem_sys, count, arity } of sorted) {
72
+ const name = arity_name(arity);
73
+ if (branch?.id !== name) {
74
+ branch = { id: name, label: name, children: [] };
75
+ roots.push(branch);
76
+ }
77
+ branch.children?.push({
78
+ id: `${name}/${chem_sys}`,
79
+ label: chem_sys,
80
+ value: count,
81
+ metadata: { chem_sys, arity },
82
+ });
83
+ }
84
+ return roots;
85
+ }
@@ -24,10 +24,12 @@ export const format_composition_formula = (composition, sort_fn, plain_text = fa
24
24
  return sort_fn(symbols)
25
25
  .filter((el) => composition[el] && composition[el] > 0)
26
26
  .map((el) => {
27
- const amount = composition[el];
27
+ const amount = Number(composition[el]);
28
28
  if (amount === 1)
29
29
  return el;
30
- const formatted_amount = format_num(Number(amount), amount_format);
30
+ // avoid d3 SI prefixes for sub-1 amounts (`s` formats render 0.5 as 500m)
31
+ const fmt = amount_format.endsWith(`s`) && Math.abs(amount) < 1 ? `.3~g` : amount_format;
32
+ const formatted_amount = format_num(amount, fmt);
31
33
  return plain_text ? `${el}${formatted_amount}` : `${el}<sub>${formatted_amount}</sub>`;
32
34
  })
33
35
  .join(delim);
@@ -1,6 +1,7 @@
1
1
  import type { ElementSymbol } from '../element';
2
2
  export { default as BarChart } from './BarChart.svelte';
3
3
  export { default as BubbleChart } from './BubbleChart.svelte';
4
+ export * from './chem-sys';
4
5
  export { default as Composition } from './Composition.svelte';
5
6
  export * from './format';
6
7
  export { default as Formula } from './Formula.svelte';
@@ -1,5 +1,6 @@
1
1
  export { default as BarChart } from './BarChart.svelte';
2
2
  export { default as BubbleChart } from './BubbleChart.svelte';
3
+ export * from './chem-sys';
3
4
  export { default as Composition } from './Composition.svelte';
4
5
  export * from './format';
5
6
  export { default as Formula } from './Formula.svelte';
@@ -65,26 +65,38 @@ export const atomic_symbol_to_num = (symbol_composition) => {
65
65
  // Expand parentheses in chemical formulas
66
66
  const expand_parentheses = (formula) => {
67
67
  while (formula.includes(`(`)) {
68
- formula = formula.replace(/\(([^()]+)\)(\d+(?:\.\d+)?|\.\d+)?/g, (_match, group, multiplier) => {
68
+ const expanded = formula.replaceAll(/\(([^()]+)\)(\d+(?:\.\d+)?|\.\d+)?/g, (_match, group, multiplier) => {
69
69
  const mult = parse_count(multiplier);
70
- return group.replace(/([A-Z][a-z]?)(\d+(?:\.\d+)?|\.\d+)?/g, (_m, element, count) => {
70
+ return group.replaceAll(/([A-Z][a-z]?)(\d+(?:\.\d+)?|\.\d+)?/g, (_m, element, count) => {
71
71
  const count_str = format_count(parse_count(count) * mult);
72
72
  return element + (count_str === `1` ? `` : count_str);
73
73
  });
74
74
  });
75
+ if (expanded === formula) {
76
+ // unclosed/empty parens match nothing -> would loop forever
77
+ throw new Error(`Unbalanced or empty parentheses in formula: ${formula}`);
78
+ }
79
+ formula = expanded;
75
80
  }
76
81
  return formula;
77
82
  };
78
- // Parse chemical formula string into composition object
83
+ // Parse chemical formula string into composition object. Hydrate/adduct segments
84
+ // joined by ·, ⋅, or * are scaled by their leading coefficient (CuSO4·5H2O -> Cu S O9 H10)
79
85
  export const parse_formula = (formula) => {
80
86
  const composition = {};
81
- const cleaned_formula = expand_parentheses(formula.replace(/\s/g, ``));
82
- for (const match of cleaned_formula.matchAll(/([A-Z][a-z]?)(\d+(?:\.\d+)?|\.\d+)?/g)) {
83
- const element = match[1];
84
- const count = parse_count(match[2]);
85
- if (!is_valid_element(element))
86
- throw new Error(`Invalid element symbol: ${element}`);
87
- composition[element] = (composition[element] ?? 0) + count;
87
+ const cleaned = formula.replaceAll(/\s/g, ``);
88
+ const segments = cleaned.split(/[·⋅*]/).filter(Boolean);
89
+ for (const [seg_idx, segment] of segments.entries()) {
90
+ // only hydrate segments (after a separator) carry a leading multiplier
91
+ const coeff = seg_idx > 0 ? /^(?:\d+(?:\.\d+)?|\.\d+)/.exec(segment)?.[0] : undefined;
92
+ const multiplier = coeff ? parseFloat(coeff) : 1;
93
+ const expanded = expand_parentheses(segment.slice(coeff?.length ?? 0));
94
+ for (const match of expanded.matchAll(/([A-Z][a-z]?)(\d+(?:\.\d+)?|\.\d+)?/g)) {
95
+ const [, element, count] = match;
96
+ if (!is_valid_element(element))
97
+ throw new Error(`Invalid element symbol: ${element}`);
98
+ composition[element] = (composition[element] ?? 0) + parse_count(count) * multiplier;
99
+ }
88
100
  }
89
101
  return composition;
90
102
  };
@@ -210,7 +222,7 @@ const parse_oxidation_state = (oxidation_str) => {
210
222
  // When strict=true, throws on conflicting oxidation states for the same element.
211
223
  export const parse_formula_with_oxidation = (formula, strict = false) => {
212
224
  const elements = [];
213
- const cleaned_formula = expand_parentheses(formula.replace(/\s/g, ``));
225
+ const cleaned_formula = expand_parentheses(formula.replaceAll(/\s/g, ``));
214
226
  // Regex to match: Element, optional oxidation state and/or count in either order
215
227
  // Pattern: ([A-Z][a-z]?) - element symbol
216
228
  // Followed by one of:
@@ -332,7 +344,7 @@ export const has_wildcards = (input) => input.includes(`*`);
332
344
  // Throws if any non-wildcard token is not a valid element symbol.
333
345
  export function parse_chemsys_with_wildcards(input) {
334
346
  const tokens = input
335
- .replace(/-/g, `,`)
347
+ .replaceAll('-', `,`)
336
348
  .split(`,`)
337
349
  .map((tok) => tok.trim())
338
350
  .filter(Boolean);
@@ -368,7 +380,7 @@ export const ELEM_WILDCARD = {
368
380
  export function parse_formula_with_wildcards(formula) {
369
381
  const tokens = [];
370
382
  // Expand parentheses, treating * as a pseudo-element (temporarily replace to protect it)
371
- let cleaned = formula.replace(/\s/g, ``);
383
+ let cleaned = formula.replaceAll(/\s/g, ``);
372
384
  // Protect wildcards from parentheses expansion by replacing * with placeholder
373
385
  cleaned = cleaned.replace(ELEM_WILDCARD.to_placeholder, ELEM_WILDCARD.placeholder);
374
386
  cleaned = expand_parentheses(cleaned);
@@ -320,7 +320,7 @@
320
320
  let copy_feedback = $state({ visible: false, position: { x: 0, y: 0 } })
321
321
 
322
322
  // Structure popup state
323
- let structure_popup = $state<{
323
+ let structure_popup = $state.raw<{
324
324
  open: boolean
325
325
  structure: AnyStructure | null
326
326
  entry: ConvexHullEntry | null
@@ -381,17 +381,17 @@
381
381
  const hl = is_highlighted(entry) ? merged_highlight_style : null
382
382
 
383
383
  point_style[idx] = {
384
- fill: hl && (hl.effect === `color` || hl.effect === `both`)
385
- ? hl.color
384
+ fill: hl?.effect === `color` || hl?.effect === `both`
385
+ ? hl?.color
386
386
  : is_energy_mode
387
387
  ? undefined
388
388
  : merged_config.colors?.[is_stable ? `stable` : `unstable`],
389
389
  stroke: is_stable ? `#ffffff` : `#000000`,
390
- radius: hl && (hl.effect === `size` || hl.effect === `both`)
391
- ? base_radius * hl.size_multiplier
390
+ radius: hl?.effect === `size` || hl?.effect === `both`
391
+ ? base_radius * (hl?.size_multiplier ?? 1)
392
392
  : base_radius,
393
393
  symbol_type: marker_to_d3_symbol(entry.marker),
394
- is_highlighted: !!hl,
394
+ is_highlighted: Boolean(hl),
395
395
  highlight_effect: hl?.effect,
396
396
  highlight_color: hl?.color,
397
397
  }
@@ -436,8 +436,10 @@
436
436
  const selected_scatter_point = $derived.by(() => {
437
437
  const entry = selected_entry
438
438
  if (!entry) return null
439
- const idx = visible_entries.findIndex((vis_entry) => vis_entry === entry)
440
- return idx >= 0 ? { series_idx: 0, point_idx: idx } : null
439
+ // match by entry_id (same_entry), not reference: selected_entry may be a proxied/
440
+ // different instance than visible_entries elements when bound to a parent $state
441
+ const idx = visible_entries.findIndex((vis_entry) => helpers.same_entry(vis_entry, entry))
442
+ return idx === -1 ? null : { series_idx: 0, point_idx: idx }
441
443
  })
442
444
 
443
445
  // Convex hull statistics - compute internally and expose via bindable prop
@@ -489,11 +491,11 @@
489
491
  )
490
492
 
491
493
  // Custom hover tooltip state used with ScatterPlot events
492
- let hover_data = $state<HoverData3D<ConvexHullEntry> | null>(null)
494
+ let hover_data = $state.raw<HoverData3D<ConvexHullEntry> | null>(null)
493
495
  $effect(() => {
494
496
  const current_selection = helpers.current_entry(selected_entry, plot_entries)
495
497
  if (selected_entry && !current_selection) selected_entry = null
496
- else if (current_selection && current_selection !== selected_entry) {
498
+ else if (current_selection && !helpers.same_entry(current_selection, selected_entry)) {
497
499
  selected_entry = current_selection
498
500
  }
499
501
  const current_hover = helpers.current_entry(hover_data?.entry, plot_entries)
@@ -23,8 +23,8 @@
23
23
  } from '../layout'
24
24
  import { to_radians, type Point3D, type Vec3 } from '../math'
25
25
  import { ColorBar, PlotTooltip } from '../plot'
26
- import { centered_rect, pad_rect, rects_overlap, rect_within_rect } from '../plot/layout'
27
- import type { Rect } from '../plot/layout'
26
+ import { centered_rect, pad_rect, rects_overlap, rect_within_rect } from '../plot/core/layout'
27
+ import type { Rect } from '../plot/core/layout'
28
28
  import { create_pulse_animation } from '../effects.svelte'
29
29
  import { DEFAULTS } from '../settings'
30
30
  import type { AnyStructure } from '../structure'
@@ -422,7 +422,7 @@
422
422
  let is_dragging = $state(false)
423
423
  let drag_started = $state(false)
424
424
  let last_mouse = $state({ x: 0, y: 0 })
425
- let hover_data = $state<HoverData3D<ConvexHullEntry> | null>(null)
425
+ let hover_data = $state.raw<HoverData3D<ConvexHullEntry> | null>(null)
426
426
  let copy_feedback = $state({ visible: false, position: { x: 0, y: 0 } })
427
427
 
428
428
  // Drag and drop state
@@ -436,7 +436,7 @@
436
436
  const current_selection = helpers.current_entry(selected_entry, plot_entries)
437
437
  const stale_selection = selected_entry && !current_selection
438
438
  if (stale_selection) selected_entry = null
439
- else if (current_selection && current_selection !== selected_entry) {
439
+ else if (current_selection && !helpers.same_entry(current_selection, selected_entry)) {
440
440
  selected_entry = current_selection
441
441
  }
442
442
  const current_hover = helpers.current_entry(hover_data?.entry, plot_entries)
@@ -963,7 +963,7 @@
963
963
 
964
964
  // Formation energy color bar helpers
965
965
  const e_form_range = $derived.by((): [number, number] => {
966
- const min_fe = plot_entries.length ? energy_range.min : -1
966
+ const min_fe = plot_entries.length > 0 ? energy_range.min : -1
967
967
  return [min_fe, 0]
968
968
  })
969
969
 
@@ -326,7 +326,7 @@
326
326
  let is_dragging = $state(false)
327
327
  let drag_started = $state(false)
328
328
  let last_mouse = $state({ x: 0, y: 0 })
329
- let hover_data = $state<HoverData3D<ConvexHullEntry> | null>(null)
329
+ let hover_data = $state.raw<HoverData3D<ConvexHullEntry> | null>(null)
330
330
  let copy_feedback = $state({ visible: false, position: { x: 0, y: 0 } })
331
331
 
332
332
  // Drag and drop state
@@ -340,7 +340,7 @@
340
340
  const current_selection = helpers.current_entry(selected_entry, plot_entries)
341
341
  const stale_selection = selected_entry && !current_selection
342
342
  if (stale_selection) selected_entry = null
343
- else if (current_selection && current_selection !== selected_entry) {
343
+ else if (current_selection && !helpers.same_entry(current_selection, selected_entry)) {
344
344
  selected_entry = current_selection
345
345
  }
346
346
  const current_hover = helpers.current_entry(hover_data?.entry, plot_entries)
@@ -394,12 +394,11 @@
394
394
  const total_entries = effective_entries.length
395
395
  if (total_entries > label_threshold) {
396
396
  show_stable_labels = false
397
- show_unstable_labels = false
398
397
  } else {
399
398
  // For smaller datasets, show stable labels by default
400
399
  show_stable_labels = true
401
- show_unstable_labels = false
402
400
  }
401
+ show_unstable_labels = false
403
402
  })
404
403
 
405
404
  // Function to extract structure data from a convex hull entry
@@ -630,11 +629,8 @@
630
629
  for (let idx = 0; idx < 4; idx++) {
631
630
  const vx = vertices[idx]
632
631
  // Direction from centroid to vertex
633
- const dir = {
634
- x: vx.x - centroid.x,
635
- y: vx.y - centroid.y,
636
- z: vx.z - centroid.z,
637
- }
632
+ const { x: cx, y: cy, z: cz } = centroid
633
+ const dir = { x: vx.x - cx, y: vx.y - cy, z: vx.z - cz }
638
634
  const len = Math.hypot(dir.x, dir.y, dir.z) || 1
639
635
  const label_pos = {
640
636
  x: vx.x + (dir.x / len) * distance,
@@ -7,7 +7,7 @@
7
7
  import Icon from '../Icon.svelte'
8
8
  import { format_num } from '../labels'
9
9
  import { sanitize_html } from '../sanitize'
10
- import Histogram from '../plot/Histogram.svelte'
10
+ import Histogram from '../plot/histogram/Histogram.svelte'
11
11
  import type { Label, RowData } from '../table'
12
12
  import HeatmapTable from '../table/HeatmapTable.svelte'
13
13
  import type { HTMLAttributes } from 'svelte/elements'
@@ -254,20 +254,20 @@
254
254
  // Escape HTML special chars to prevent XSS when rendering user-supplied strings via {@html}
255
255
  const escape_html = (str: string): string =>
256
256
  str
257
- .replace(/&/g, `&amp;`)
258
- .replace(/</g, `&lt;`)
259
- .replace(/>/g, `&gt;`)
260
- .replace(/"/g, `&quot;`)
261
- .replace(/'/g, `&#39;`)
257
+ .replaceAll('&', `&amp;`)
258
+ .replaceAll('<', `&lt;`)
259
+ .replaceAll('>', `&gt;`)
260
+ .replaceAll('"', `&quot;`)
261
+ .replaceAll('\'', `&#39;`)
262
262
  const unescape_html = (str: string, max_rounds = 5): string => {
263
263
  let decoded = str
264
264
  for (let round_idx = 0; round_idx < max_rounds; round_idx++) {
265
265
  const next_decoded = decoded
266
- .replace(/&amp;/g, `&`)
267
- .replace(/&lt;/g, `<`)
268
- .replace(/&gt;/g, `>`)
269
- .replace(/&quot;/g, `"`)
270
- .replace(/&#39;/g, `'`)
266
+ .replaceAll('&amp;', `&`)
267
+ .replaceAll('&lt;', `<`)
268
+ .replaceAll('&gt;', `>`)
269
+ .replaceAll('&quot;', `"`)
270
+ .replaceAll('&#39;', `'`)
271
271
  if (next_decoded === decoded) break
272
272
  decoded = next_decoded
273
273
  }
@@ -336,7 +336,7 @@
336
336
  // Match by entry_id or common data fields (mat_id, structure_id)
337
337
  // since entry_id may be wrapped in HTML (e.g. <a> tags)
338
338
  const entry_data = entry.data as Record<string, unknown> | undefined
339
- const is_highlighted = !!(highlighted_entry_id && (
339
+ const is_highlighted = Boolean(highlighted_entry_id && (
340
340
  entry.entry_id === highlighted_entry_id ||
341
341
  entry_data?.mat_id === highlighted_entry_id ||
342
342
  entry_data?.structure_id === highlighted_entry_id
@@ -64,7 +64,7 @@
64
64
 
65
65
  // Convert slider position (0-100) to pressure
66
66
  const slider_to_pressure = (value: number): number =>
67
- Math.pow(10, LOG_P_MIN + (value / 100) * LOG_P_RANGE)
67
+ 10 ** (LOG_P_MIN + (value / 100) * LOG_P_RANGE)
68
68
 
69
69
  // Format gas name for display (subscript numbers)
70
70
  const format_gas_name = (gas: GasSpecies): string =>
@@ -94,7 +94,7 @@
94
94
  gas: GasSpecies,
95
95
  event: Event & { currentTarget: HTMLInputElement },
96
96
  ): void {
97
- const P = slider_to_pressure(+event.currentTarget.value)
97
+ const P = slider_to_pressure(Number(event.currentTarget.value))
98
98
  pressures = { ...pressures, [gas]: P }
99
99
  // Clear only this gas's preview (don't reset other sliders being dragged simultaneously)
100
100
  const { [gas]: _removed_preview, ...remaining_previews } = preview_pressures
@@ -103,8 +103,8 @@
103
103
 
104
104
  function set_pressure_direct(gas: GasSpecies, value: number): void {
105
105
  const clamped = Math.max(
106
- Math.pow(10, LOG_P_MIN),
107
- Math.min(Math.pow(10, LOG_P_MAX), value),
106
+ 10 ** LOG_P_MIN,
107
+ Math.min(10 ** LOG_P_MAX, value),
108
108
  )
109
109
  pressures = { ...pressures, [gas]: clamped }
110
110
  }