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
@@ -8,6 +8,7 @@
8
8
  import Spinner from '../feedback/Spinner.svelte'
9
9
  import Icon from '../Icon.svelte'
10
10
  import { create_file_drop_handler, load_from_url } from '../io'
11
+ import { forward_window_keydown, handle_and_prevent } from '../keyboard'
11
12
  import { parse_volumetric_file } from '../isosurface/parse'
12
13
  import type { IsosurfaceSettings, VolumetricData } from '../isosurface/types'
13
14
  import {
@@ -56,7 +57,7 @@
56
57
  import { get_property_colors } from './atom-properties'
57
58
  import AtomLegend from './AtomLegend.svelte'
58
59
  import CellSelect from './CellSelect.svelte'
59
- import { BOND_ORDER_OPTIONS, merge_bond_edits } from './bonding'
60
+ import { BOND_ORDER_OPTIONS, merge_bond_edits, remap_bonds_after_deletion } from './bonding'
60
61
  import type { StructureHandlerData } from './index'
61
62
  import { MAX_SELECTED_SITES } from './measure'
62
63
  import { normalize_fractional_coords, parse_any_structure } from './parse'
@@ -64,6 +65,7 @@
64
65
  import StructureExportPane from './StructureExportPane.svelte'
65
66
  import StructureInfoPane from './StructureInfoPane.svelte'
66
67
  import StructureScene from './StructureScene.svelte'
68
+ import { to_error } from '../utils'
67
69
 
68
70
  // Type alias for event handlers to reduce verbosity
69
71
  type EventHandler = (data: StructureHandlerData) => void
@@ -302,7 +304,7 @@
302
304
  emit_file_load_event(parsed, filename, content)
303
305
  } catch (error) {
304
306
  error_msg = `Failed to parse structure: ${
305
- error instanceof Error ? error.message : String(error)
307
+ to_error(error).message
306
308
  }`
307
309
  on_error?.({ error_msg, filename })
308
310
  }
@@ -333,7 +335,7 @@
333
335
  }
334
336
  } catch (err) {
335
337
  error_msg = `Failed to parse structure from string: ${
336
- err instanceof Error ? err.message : String(err)
338
+ to_error(err).message
337
339
  }`
338
340
  untrack(() => on_error?.({ error_msg, filename: `string` }))
339
341
  } finally {
@@ -467,10 +469,13 @@
467
469
  let bond_order_overrides = $state<StructureBond[]>([])
468
470
  let bond_undo_stack = $state<BondEditHistorySnapshot[]>([])
469
471
  let bond_redo_stack = $state<BondEditHistorySnapshot[]>([])
470
- let bond_history_context = $state<BondEditContext>()
471
- let last_bond_structure_identity = $state(structure)
472
+ // These hold object-identity tokens (structure_identity) compared with ===/!==,
473
+ // so they must stay raw — proxying them via $state would break identity comparisons
474
+ // (state_proxy_equality_mismatch) against the raw `structure` prop.
475
+ let bond_history_context = $state.raw<BondEditContext>()
476
+ let last_bond_structure_identity = $state.raw(structure)
472
477
  let last_emitted_bond_signature = $state<string>()
473
- let bond_edit_snapshot = $state<BondEditSnapshot>()
478
+ let bond_edit_snapshot = $state.raw<BondEditSnapshot>()
474
479
  let has_bond_edits = $derived(
475
480
  added_bonds.length > 0 || removed_bonds.length > 0 ||
476
481
  bond_order_overrides.length > 0,
@@ -776,7 +781,13 @@
776
781
  })
777
782
 
778
783
  let controls_config = $derived(normalize_show_controls(show_controls))
779
- let viewer_active = $derived(hovered || focused)
784
+ // $effect instead of `$derived(hovered || focused)`: the $derived reading the $bindable
785
+ // `hovered` prop went stale after the first hover/leave cycle, so the gizmo + mode toggle only
786
+ // appeared on the first mouseenter until reload.
787
+ let viewer_active = $state(false)
788
+ $effect(() => {
789
+ viewer_active = hovered || focused
790
+ })
780
791
  let scene_gizmo = $derived(viewer_active && (scene_props.gizmo ?? scene_props.show_gizmo))
781
792
  let active_scene_sites = $derived([
782
793
  ...new SvelteSet([...(scene_props.active_sites ?? []), ...highlighted_sites]),
@@ -822,7 +833,7 @@
822
833
  let supercell_structure = $state(structure)
823
834
  let supercell_loading = $state(false)
824
835
  let has_supercell = $derived(
825
- !!supercell_scaling && ![``, `1x1x1`, `1`].includes(supercell_scaling),
836
+ Boolean(supercell_scaling) && ![``, `1x1x1`, `1`].includes(supercell_scaling),
826
837
  )
827
838
  let bond_edits_enabled = $derived(
828
839
  cell_type === `original` && !has_supercell && !supercell_loading,
@@ -865,8 +876,8 @@
865
876
  // For large supercells, show loading state and use async generation
866
877
  const sites_count = base_structure.sites?.length || 0
867
878
  const [nx_str, ny_str, nz_str] = supercell_scaling.split(/[x×]/)
868
- const scaling_mult = (parseInt(nx_str) || 1) * (parseInt(ny_str) || 1) *
869
- (parseInt(nz_str) || 1)
879
+ const scaling_mult = (parseInt(nx_str, 10) || 1) * (parseInt(ny_str, 10) || 1) *
880
+ (parseInt(nz_str, 10) || 1)
870
881
  const estimated_sites = sites_count * scaling_mult
871
882
 
872
883
  // Show spinner for supercells with >1000 estimated sites or scaling >8
@@ -1124,7 +1135,7 @@
1124
1135
  emit_file_load_event(parsed, filename, content)
1125
1136
  } catch (err) {
1126
1137
  error_msg = `Failed to parse structure: ${
1127
- err instanceof Error ? err.message : String(err)
1138
+ to_error(err).message
1128
1139
  }`
1129
1140
  on_error?.({ error_msg, filename })
1130
1141
  }
@@ -1139,7 +1150,9 @@
1139
1150
  },
1140
1151
  })
1141
1152
 
1142
- function handle_keydown(event: KeyboardEvent) {
1153
+ // Handle keyboard shortcuts. Returns true if the key was handled, so the caller
1154
+ // (handle_and_prevent / forward_window_keydown) can suppress the browser default.
1155
+ function handle_keydown(event: KeyboardEvent): boolean {
1143
1156
  // Don't handle shortcuts if user is typing in an input field
1144
1157
  const target = event.target
1145
1158
  const is_input_focused =
@@ -1151,45 +1164,39 @@
1151
1164
 
1152
1165
  // Allow Escape to cancel add-atom mode even when the element input is focused
1153
1166
  if (event.key === `Escape` && measure_mode === `edit-atoms` && add_atom_mode) {
1154
- event.preventDefault()
1155
1167
  add_atom_mode = false
1156
- return
1168
+ return true
1157
1169
  }
1158
1170
 
1159
- if (is_input_focused) return
1171
+ if (is_input_focused) return false
1160
1172
 
1161
1173
  if (measure_mode === `edit-bonds`) {
1162
1174
  const key = event.key.toLowerCase()
1163
1175
  const plain = !event.ctrlKey && !event.metaKey && !event.altKey
1164
1176
  if (event.ctrlKey || event.metaKey) {
1165
1177
  if (key === `z` && !event.shiftKey) {
1166
- if (bond_undo_stack.length === 0) return
1167
- event.preventDefault()
1178
+ if (bond_undo_stack.length === 0) return false
1168
1179
  undo_bond_edit()
1169
1180
  show_toast(`Undo bond edit (${bond_undo_stack.length} left)`)
1170
- return
1181
+ return true
1171
1182
  } else if (key === `y` || (key === `z` && event.shiftKey)) {
1172
- if (bond_redo_stack.length === 0) return
1173
- event.preventDefault()
1183
+ if (bond_redo_stack.length === 0) return false
1174
1184
  redo_bond_edit()
1175
1185
  show_toast(`Redo bond edit (${bond_redo_stack.length} left)`)
1176
- return
1186
+ return true
1177
1187
  }
1178
1188
  }
1179
1189
  if (key === `a` && plain) {
1180
- event.preventDefault()
1181
1190
  bond_edit_mode = `add`
1182
- return
1191
+ return true
1183
1192
  }
1184
1193
  if (key === `d` && plain) {
1185
- event.preventDefault()
1186
1194
  bond_edit_mode = `delete`
1187
- return
1195
+ return true
1188
1196
  }
1189
1197
  if (event.key === `Escape` && selected_sites.length > 0) {
1190
- event.preventDefault()
1191
1198
  clear_selection()
1192
- return
1199
+ return true
1193
1200
  }
1194
1201
  }
1195
1202
 
@@ -1199,61 +1206,66 @@
1199
1206
  if (event.ctrlKey || event.metaKey) {
1200
1207
  const key = event.key.toLowerCase()
1201
1208
  if (key === `z` && !event.shiftKey) {
1202
- if (undo_stack.length === 0) return
1203
- event.preventDefault()
1209
+ if (undo_stack.length === 0) return false
1204
1210
  undo()
1205
1211
  show_toast(`Undo (${undo_stack.length} left)`)
1206
- return
1212
+ return true
1207
1213
  } else if (key === `y` || (key === `z` && event.shiftKey)) {
1208
- if (redo_stack.length === 0) return
1209
- event.preventDefault()
1214
+ if (redo_stack.length === 0) return false
1210
1215
  redo()
1211
1216
  show_toast(`Redo (${redo_stack.length} left)`)
1212
- return
1217
+ return true
1213
1218
  }
1214
1219
  }
1215
1220
 
1216
1221
  if (event.key === `Delete` || event.key === `Backspace`) {
1217
1222
  // Delete selected atoms
1218
1223
  if (selected_sites.length > 0 && structure?.sites) {
1219
- event.preventDefault()
1220
1224
  is_internal_edit = true
1221
1225
  push_undo()
1222
1226
  const to_delete = scene_to_structure_indices(selected_sites, true)
1223
1227
  const n_deleted = to_delete.size
1224
1228
  clear_selection()
1229
+ // Remap explicit bond metadata so surviving bonds track shifted site indices.
1230
+ // structure_with_bonds prefers the bindable `bonds` prop, so remap that too.
1231
+ if (bonds !== undefined) bonds = remap_bonds_after_deletion(bonds, to_delete)
1232
+ const old_bonds = structure.properties?.bonds
1225
1233
  structure = {
1226
1234
  ...structure,
1227
1235
  sites: structure.sites.filter((_, idx) => !to_delete.has(idx)),
1236
+ ...(old_bonds && {
1237
+ properties: {
1238
+ ...structure.properties,
1239
+ bonds: remap_bonds_after_deletion(old_bonds, to_delete),
1240
+ },
1241
+ }),
1228
1242
  }
1229
1243
  // Clear per-site overrides since indices shifted after deletion
1230
1244
  if (site_radius_overrides?.size > 0) site_radius_overrides.clear()
1231
1245
  clear_bond_edits()
1232
1246
  show_toast(`Deleted ${n_deleted} site${n_deleted > 1 ? `s` : ``}`)
1247
+ return true
1233
1248
  }
1234
- return
1249
+ return false
1235
1250
  }
1236
1251
  const key = event.key.toLowerCase()
1237
1252
  const plain = !event.ctrlKey && !event.metaKey && !event.altKey
1238
1253
 
1239
1254
  if (key === `a` && plain) {
1240
1255
  // Enter add-atom sub-mode (plain 'a' only, not Ctrl+A/Cmd+A/Alt+A)
1241
- event.preventDefault()
1242
1256
  add_atom_mode = !add_atom_mode
1243
- return
1257
+ return true
1244
1258
  }
1245
1259
  // Change element of selected atoms
1246
1260
  if (key === `e` && plain && selected_sites.length > 0) {
1247
- event.preventDefault()
1248
1261
  change_element_mode = !change_element_mode
1249
- return
1262
+ return true
1250
1263
  }
1251
1264
  // Duplicate selected atoms at a small offset
1252
1265
  if (
1253
1266
  key === `d` && (event.ctrlKey || event.metaKey) &&
1254
1267
  selected_sites.length > 0 && structure?.sites
1255
1268
  ) {
1256
- event.preventDefault()
1257
1269
  is_internal_edit = true
1258
1270
  push_undo()
1259
1271
  const orig_indices = scene_to_structure_indices(selected_sites)
@@ -1284,18 +1296,18 @@
1284
1296
  show_toast(
1285
1297
  `Duplicated ${new_sites.length} site${new_sites.length > 1 ? `s` : ``}`,
1286
1298
  )
1287
- return
1299
+ return true
1288
1300
  }
1289
1301
 
1290
1302
  // add_atom_mode Escape is already handled above (before is_input_focused guard)
1291
1303
  if (event.key === `Escape`) {
1292
1304
  if (change_element_mode) {
1293
1305
  change_element_mode = false
1294
- return
1306
+ return true
1295
1307
  }
1296
1308
  if (selected_sites.length > 0) {
1297
1309
  clear_selection()
1298
- return
1310
+ return true
1299
1311
  }
1300
1312
  }
1301
1313
  }
@@ -1303,11 +1315,11 @@
1303
1315
  // Interface shortcuts (require Ctrl/Cmd modifier to avoid accidental triggers)
1304
1316
  const has_modifier = event.ctrlKey || event.metaKey
1305
1317
  if (event.key === `f` && has_modifier && fullscreen_toggle) {
1306
- event.preventDefault()
1307
1318
  toggle_fullscreen(wrapper)
1319
+ return true
1308
1320
  } else if (event.key === `i` && has_modifier && enable_info_pane) {
1309
- event.preventDefault()
1310
1321
  info_pane_open = !info_pane_open
1322
+ return true
1311
1323
  } else if (event.key === `Escape`) {
1312
1324
  // Prioritize closing panes, then exit edit modes, then exit fullscreen
1313
1325
  if (info_pane_open) info_pane_open = false
@@ -1315,10 +1327,19 @@
1315
1327
  else if (export_pane_open) export_pane_open = false
1316
1328
  else if (measure_mode === `edit-bonds` || measure_mode === `edit-atoms`) {
1317
1329
  measure_mode = `distance`
1318
- }
1330
+ } else return false
1331
+ return true
1319
1332
  }
1333
+ return false
1320
1334
  }
1321
1335
 
1336
+ // Hover (window) path: skip edit-mode mutations so destructive keys (delete/undo)
1337
+ // require focus, not just a hovering mouse.
1338
+ const handle_hover_keydown = (event: KeyboardEvent): boolean =>
1339
+ measure_mode === `edit-atoms` || measure_mode === `edit-bonds`
1340
+ ? false
1341
+ : handle_keydown(event)
1342
+
1322
1343
  // === Edit-atoms mode helpers ===
1323
1344
 
1324
1345
  // Map scene indices (into displayed_structure) back to raw structure indices.
@@ -1477,6 +1498,11 @@
1477
1498
  }}
1478
1499
  />
1479
1500
 
1501
+ <!-- Forward shortcuts to the hovered viewer when focus is on <body> (see
1502
+ forward_window_keydown). Edit modes are excluded so destructive keys
1503
+ (delete/undo) still require focus, not just a hovering mouse. -->
1504
+ <svelte:window onkeydown={forward_window_keydown(() => hovered, handle_hover_keydown)} />
1505
+
1480
1506
  <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
1481
1507
  <div
1482
1508
  class:dragover
@@ -1502,15 +1528,8 @@
1502
1528
  if (!(target instanceof HTMLElement)) return
1503
1529
  // Don't reset if double-click was on UI controls/panes/legend
1504
1530
  if (
1505
- target.closest(`.control-buttons`) ||
1506
- target.closest(`.structure-legend`) ||
1507
- target.closest(`.atom-legend`) ||
1508
- target.closest(`.info-pane`) ||
1509
- target.closest(`.export-pane`) ||
1510
- target.closest(`.controls-pane`) ||
1511
- target.tagName === `BUTTON` ||
1512
- target.tagName === `INPUT` ||
1513
- target.tagName === `SELECT`
1531
+ [`.control-buttons`, `.structure-legend`, `.atom-legend`, `.info-pane`, `.export-pane`, `.controls-pane`].some((selector) => target.closest(selector))
1532
+ || target.tagName === `BUTTON` || target.tagName === `INPUT` || target.tagName === `SELECT`
1514
1533
  ) return
1515
1534
  // Reset camera for double-clicks on the 3D scene
1516
1535
  reset_camera()
@@ -1525,7 +1544,7 @@
1525
1544
  event.preventDefault()
1526
1545
  dragover = false
1527
1546
  }}
1528
- onkeydown={handle_keydown}
1547
+ onkeydown={handle_and_prevent(handle_keydown)}
1529
1548
  {...rest}
1530
1549
  class="structure {rest.class ?? ``}"
1531
1550
  >
@@ -1617,22 +1636,9 @@
1617
1636
  {#each [
1618
1637
  { mode: `distance`, icon: `Ruler`, label: `Distance`, scale: 1.1 },
1619
1638
  { mode: `angle`, icon: `Angle`, label: `Angle`, scale: 1.3 },
1620
- {
1621
- mode: `edit-atoms`,
1622
- icon: `Edit`,
1623
- label: `Edit Atoms`,
1624
- scale: 1.0,
1625
- },
1626
- {
1627
- mode: `edit-bonds`,
1628
- icon: `Link`,
1629
- label: `Edit Bonds`,
1630
- scale: 1.0,
1631
- },
1632
- ] as const as
1633
- { mode, icon, label, scale }
1634
- (mode)
1635
- }
1639
+ { mode: `edit-atoms`, icon: `Edit`, label: `Edit Atoms`, scale: 1.0 },
1640
+ { mode: `edit-bonds`, icon: `Link`, label: `Edit Bonds`, scale: 1.0 },
1641
+ ] as const as { mode, icon, label, scale } (mode)}
1636
1642
  <button
1637
1643
  class="view-mode-option"
1638
1644
  class:selected={measure_mode === mode}
@@ -84,6 +84,6 @@ type $$ComponentProps = {
84
84
  on_camera_reset?: EventHandler;
85
85
  on_bonds_change?: (bonds: StructureBond[] | undefined) => void;
86
86
  } & Omit<ComponentProps<typeof StructureControls>, `children` | `onclose`> & Omit<HTMLAttributes<HTMLDivElement>, `children`>;
87
- declare const Structure: import("svelte").Component<$$ComponentProps, {}, "structure" | "height" | "width" | "dragover" | "loading" | "fullscreen" | "hovered" | "controls_open" | "color_scheme" | "background_color" | "background_opacity" | "show_image_atoms" | "info_pane_open" | "wrapper" | "sym_data" | "png_dpi" | "error_msg" | "site_radius_overrides" | "atom_color_config" | "lattice_props" | "measure_mode" | "selected_sites" | "measured_sites" | "bond_edit_mode" | "bond_edit_order" | "hidden_elements" | "hidden_prop_vals" | "element_radius_overrides" | "volumetric_data" | "isosurface_settings" | "element_mapping" | "bonds" | "supercell_scaling" | "cell_type" | "active_volume_idx" | "scene_props" | "highlighted_sites" | "hovered_site_idx" | "enable_measure_mode" | "performance_mode" | "displayed_structure" | "symmetry_settings">;
87
+ declare const Structure: import("svelte").Component<$$ComponentProps, {}, "structure" | "dragover" | "height" | "width" | "fullscreen" | "hovered" | "controls_open" | "loading" | "png_dpi" | "color_scheme" | "background_color" | "background_opacity" | "show_image_atoms" | "info_pane_open" | "wrapper" | "sym_data" | "error_msg" | "site_radius_overrides" | "atom_color_config" | "lattice_props" | "measure_mode" | "selected_sites" | "measured_sites" | "bond_edit_mode" | "bond_edit_order" | "hidden_elements" | "hidden_prop_vals" | "element_radius_overrides" | "volumetric_data" | "isosurface_settings" | "element_mapping" | "bonds" | "supercell_scaling" | "cell_type" | "active_volume_idx" | "scene_props" | "highlighted_sites" | "hovered_site_idx" | "enable_measure_mode" | "performance_mode" | "displayed_structure" | "symmetry_settings">;
88
88
  type Structure = ReturnType<typeof Structure>;
89
89
  export default Structure;
@@ -168,12 +168,11 @@
168
168
  const get_element_name = (element: string): string =>
169
169
  element_data?.find((element_record) => element_record.symbol === element)?.name || element
170
170
 
171
- function site_summary(card: SiteCard): string {
172
- return [
171
+ const site_summary = (card: SiteCard): string =>
172
+ [
173
173
  card.element_name,
174
174
  ...card.details.map(({ label, value }) => `${label}: ${value}`),
175
175
  ].join(`; `)
176
- }
177
176
 
178
177
  function format_site_property(prop_key: string, prop_value: unknown): SiteDetail | null {
179
178
  if (prop_value == null) return null
@@ -232,7 +231,7 @@
232
231
  // Only display scalar values (skip arrays and objects)
233
232
  if (value == null || typeof value === `object`) continue
234
233
  structure_items.push({
235
- label: key.replace(/_/g, ` `).replace(/\b\w/g, (char) => char.toUpperCase()),
234
+ label: key.replaceAll('_', ` `).replaceAll(/\b\w/g, (char) => char.toUpperCase()),
236
235
  value: String(value),
237
236
  key: `structure-prop-${key}`,
238
237
  })
@@ -281,7 +280,7 @@
281
280
  international_short?: string
282
281
  }).international_short
283
282
  const space_group_symbol = (sym_data.hm_symbol ?? international_symbol)
284
- ?.replace(
283
+ ?.replaceAll(
285
284
  /\s+/g,
286
285
  ``,
287
286
  )
@@ -380,7 +379,7 @@
380
379
  const selected_site_idx = selected_sites[0]
381
380
  if (!pane_open || selected_site_idx === undefined) return
382
381
  const visible_idx = visible_site_cards.findIndex(({ idx }) => idx === selected_site_idx)
383
- if (visible_idx < 0) return
382
+ if (visible_idx === -1) return
384
383
  const selected_window_start = Math.floor(visible_idx / SITE_WINDOW_SIZE) *
385
384
  SITE_WINDOW_SIZE
386
385
  if (selected_window_start !== site_window_start) {
@@ -409,9 +409,8 @@
409
409
 
410
410
  // Desaturate a color by blending it toward gray (for ghosting image atoms in edit mode)
411
411
  const gray = new Color(0x999999)
412
- function desaturate(hex: string | undefined, amount = 0.4): string {
413
- return `#${new Color(hex ?? 0x999999).lerp(gray, amount).getHexString()}`
414
- }
412
+ const desaturate = (hex: string | undefined, amount = 0.4): string =>
413
+ `#${new Color(hex ?? 0x999999).lerp(gray, amount).getHexString()}`
415
414
 
416
415
  // === Edit-atoms mode state ===
417
416
  let transform_object = $state<Mesh | undefined>(undefined)
@@ -1090,7 +1089,7 @@
1090
1089
 
1091
1090
  const bond_directions_by_site = new SvelteMap<number, Vec3[]>()
1092
1091
  const add_bond_direction = (site_idx: number, pos_1: Vec3, pos_2: Vec3) => {
1093
- const direction = math.normalize_vec3(
1092
+ const direction = math.normalize_vec(
1094
1093
  math.subtract(pos_2, pos_1),
1095
1094
  [0, 0, 0],
1096
1095
  )
@@ -1253,9 +1252,9 @@
1253
1252
  let mean: Vec3 = [0, 0, 0]
1254
1253
  for (const key of site_keys) {
1255
1254
  const vec = vec_map.get(key)
1256
- if (vec) mean = math.add(mean, math.normalize_vec3(vec)) as Vec3
1255
+ if (vec) mean = math.add(mean, math.normalize_vec(vec)) as Vec3
1257
1256
  }
1258
- const mean_dir = math.normalize_vec3(mean, [0, 1, 0] as Vec3)
1257
+ const mean_dir = math.normalize_vec(mean, [0, 1, 0] as Vec3)
1259
1258
  const [u_vec, v_vec] = math.compute_in_plane_basis(mean_dir)
1260
1259
  const offsets = new SvelteMap<string, Vec3>()
1261
1260
  for (const [idx, key] of site_keys.entries()) {
@@ -1317,7 +1316,7 @@
1317
1316
 
1318
1317
  const offset = site_offsets?.[site_idx]?.get(key)
1319
1318
  const position = offset ? math.add(site.xyz, offset) as Vec3 : site.xyz
1320
- const arrow_vec = vector_normalize ? math.normalize_vec3(vec) : vec
1319
+ const arrow_vec = vector_normalize ? math.normalize_vec(vec) : vec
1321
1320
 
1322
1321
  return {
1323
1322
  site_idx,
@@ -2096,7 +2095,7 @@
2096
2095
  ] as Vec3}
2097
2096
  {@const direct = math.euclidean_dist(pos_i, pos_j)}
2098
2097
  {@const pbc = lattice
2099
- ? measure.distance_pbc(pos_i, pos_j, lattice.matrix)
2098
+ ? measure.distance_pbc(pos_i, pos_j, lattice.matrix, undefined, lattice.pbc)
2100
2099
  : direct}
2101
2100
  {@const differ = lattice ? Math.abs(pbc - direct) > 1e-6 : false}
2102
2101
  <extras.HTML center position={midpoint}>
@@ -2125,8 +2124,10 @@
2125
2124
  }
2126
2125
  {@const site_a = structure.sites[idx_a]}
2127
2126
  {@const site_b = structure.sites[idx_b]}
2128
- {@const v1 = measure.displacement_pbc(center.xyz, site_a.xyz, lattice?.matrix)}
2129
- {@const v2 = measure.displacement_pbc(center.xyz, site_b.xyz, lattice?.matrix)}
2127
+ {@const disp = (to: Vec3) =>
2128
+ measure.displacement_pbc(center.xyz, to, lattice?.matrix, undefined, lattice?.pbc)}
2129
+ {@const v1 = disp(site_a.xyz)}
2130
+ {@const v2 = disp(site_b.xyz)}
2130
2131
  {@const n1 = Math.hypot(v1[0], v1[1], v1[2])}
2131
2132
  {@const n2 = Math.hypot(v2[0], v2[1], v2[2])}
2132
2133
  {@const angle_deg = measure.angle_between_vectors(v1, v2, `degrees`)}
@@ -55,7 +55,7 @@ const build_prop_colors = (vals, colors, unique_values) => {
55
55
  return { colors, values: vals, min_value, max_value, unique_values: uniq };
56
56
  };
57
57
  export function apply_color_scale(vals, scale = DEFAULT_COLOR_SCALE, type = `continuous`) {
58
- if (!vals.length)
58
+ if (vals.length === 0)
59
59
  return { colors: [] };
60
60
  if (type === `categorical`) {
61
61
  const result = make_categorical(vals, scale, (val_a, val_b) => val_a - val_b);
@@ -74,7 +74,7 @@ export function apply_color_scale(vals, scale = DEFAULT_COLOR_SCALE, type = `con
74
74
  colors: vals.map((val) => to_hex(interp_fn, max === min ? 0.5 : (val - min) / (max - min))),
75
75
  };
76
76
  }
77
- export const apply_categorical_color_scale = (vals, scale = DEFAULT_COLOR_SCALE) => vals.length ? make_categorical(vals, scale) : { colors: [], unique_values: [] };
77
+ export const apply_categorical_color_scale = (vals, scale = DEFAULT_COLOR_SCALE) => vals.length > 0 ? make_categorical(vals, scale) : { colors: [], unique_values: [] };
78
78
  // Get original site index for property color lookup.
79
79
  // Supercell atoms use orig_unit_cell_idx, image atoms use orig_site_idx, otherwise use site_idx.
80
80
  export const get_orig_site_idx = (site, site_idx) => typeof site?.properties?.orig_unit_cell_idx === `number`
@@ -84,7 +84,7 @@ export const get_orig_site_idx = (site, site_idx) => typeof site?.properties?.or
84
84
  : site_idx;
85
85
  // Expand structure with PBC images - use minimal expansion based on atom positions
86
86
  function expand_structure_for_pbc(structure) {
87
- if (!(`lattice` in structure) || !structure.lattice || !structure.sites.length) {
87
+ if (!(`lattice` in structure) || !structure.lattice || structure.sites.length === 0) {
88
88
  return structure;
89
89
  }
90
90
  const { sites, lattice } = structure;
@@ -92,7 +92,7 @@ function expand_structure_for_pbc(structure) {
92
92
  const pbc = lattice.pbc ?? [true, true, true];
93
93
  const all_offsets = get_all_offsets(pbc);
94
94
  // Small structures: expand all atoms
95
- if (sites.length < 20 || !pbc.some((periodic) => periodic)) {
95
+ if (sites.length < 20 || !pbc.some(Boolean)) {
96
96
  const image_sites = sites.flatMap((site, orig_idx) => all_offsets.map((offset) => build_image_site(site, frac_to_cart, offset, orig_idx)));
97
97
  return { ...structure, sites: [...sites, ...image_sites] };
98
98
  }
@@ -113,7 +113,7 @@ export function get_coordination_colors(structure, strategy = `electroneg_ratio`
113
113
  // Check if structure has periodic boundary conditions
114
114
  const has_lattice = `lattice` in structure && structure.lattice !== undefined;
115
115
  const pbc = has_lattice ? structure.lattice.pbc : undefined;
116
- const has_pbc = has_lattice && (pbc === undefined || pbc.some((is_periodic) => is_periodic));
116
+ const has_pbc = has_lattice && (pbc === undefined || pbc.some(Boolean));
117
117
  // For PBC structures, expand with images from neighboring cells for accurate coordination
118
118
  const coord_structure = has_pbc ? expand_structure_for_pbc(structure) : structure;
119
119
  // Calculate coordination numbers on the (potentially expanded) structure
@@ -196,5 +196,5 @@ export function get_property_colors(structure, config, bonding_strategy, sym_dat
196
196
  if (!structure || config.mode === `element`)
197
197
  return null;
198
198
  const result = get_atom_colors(structure, config, bonding_strategy, sym_data);
199
- return result.colors.length ? result : null;
199
+ return result.colors.length > 0 ? result : null;
200
200
  }
@@ -71,7 +71,7 @@ function split_fragments(n_atoms, edges) {
71
71
  const stack = [start];
72
72
  const frag = [];
73
73
  seen.add(start);
74
- while (stack.length) {
74
+ while (stack.length > 0) {
75
75
  const node = stack.pop();
76
76
  if (node === undefined)
77
77
  break;
@@ -2,6 +2,7 @@ import type { Vec3 } from '../math';
2
2
  import type { AnyStructure, BondOrder, BondPair, Site, StructureBond } from './';
3
3
  export declare const normalize_structure_bond: (site_idx_1: number, site_idx_2: number, order: BondOrder, cell_shift?: Vec3) => StructureBond;
4
4
  export declare const get_bond_key: (idx_1: number, idx_2: number, cell_shift?: Vec3) => string;
5
+ export declare function remap_bonds_after_deletion(bonds: readonly StructureBond[], deleted_indices: ReadonlySet<number>): StructureBond[];
5
6
  export type BondEditState = {
6
7
  added_bonds: StructureBond[];
7
8
  removed_bonds: StructureBond[];
@@ -45,6 +45,31 @@ export const get_bond_key = (idx_1, idx_2, cell_shift) => {
45
45
  const normalized = normalize_bond_endpoints(idx_1, idx_2, cell_shift);
46
46
  return `${normalized.site_idx_1}-${normalized.site_idx_2}${format_cell_shift(normalized.cell_shift)}`;
47
47
  };
48
+ // Remap explicit bond metadata after site deletion: drop bonds touching deleted
49
+ // sites and shift each surviving index down by the number of deleted indices below it.
50
+ export function remap_bonds_after_deletion(bonds, deleted_indices) {
51
+ // Sort the deleted indices once; shift each surviving index down by the count of deleted
52
+ // indices below it via binary search (O(log m) per lookup vs re-filtering the set each call).
53
+ const sorted = [...deleted_indices].sort((idx_a, idx_b) => idx_a - idx_b);
54
+ const shift = (idx) => {
55
+ let [lo, hi] = [0, sorted.length];
56
+ while (lo < hi) {
57
+ const mid = (lo + hi) >> 1;
58
+ if (sorted[mid] < idx)
59
+ lo = mid + 1;
60
+ else
61
+ hi = mid;
62
+ }
63
+ return idx - lo; // lo == count of deleted indices < idx
64
+ };
65
+ return bonds
66
+ .filter((bond) => !deleted_indices.has(bond.site_idx_1) && !deleted_indices.has(bond.site_idx_2))
67
+ .map((bond) => ({
68
+ ...bond,
69
+ site_idx_1: shift(bond.site_idx_1),
70
+ site_idx_2: shift(bond.site_idx_2),
71
+ }));
72
+ }
48
73
  export const BOND_ORDER_OPTIONS = [
49
74
  { order: 1, label: `Single` },
50
75
  { order: 1.5, label: `1.5` },
@@ -364,23 +389,26 @@ export function scale_and_offset_bond_matrix(transform_matrix, offset, radius_sc
364
389
  export function get_bond_render_matrices(bond, bond_thickness) {
365
390
  const order = bond.bond_order ?? 1;
366
391
  const gap = bond_thickness * 1.8;
367
- const offsets_and_scales = order === 2
368
- ? [
392
+ // Parallel cylinder [offset, radius_scale] pairs per bond order; empty → a single
393
+ // full-width bond (handled by the fallback below)
394
+ let offsets_and_scales = [];
395
+ if (order === 2)
396
+ offsets_and_scales = [
369
397
  [-gap / 2, 0.65],
370
398
  [gap / 2, 0.65],
371
- ]
372
- : order === 3
373
- ? [
374
- [-gap, 0.55],
375
- [0, 0.55],
376
- [gap, 0.55],
377
- ]
378
- : order === 1.5 || order === `aromatic`
379
- ? [
380
- [-gap / 2, 0.75],
381
- [gap / 2, 0.4],
382
- ]
383
- : [];
399
+ ];
400
+ else if (order === 3)
401
+ offsets_and_scales = [
402
+ [-gap, 0.55],
403
+ [0, 0.55],
404
+ [gap, 0.55],
405
+ ];
406
+ else if (order === 1.5 || order === `aromatic`) {
407
+ offsets_and_scales = [
408
+ [-gap / 2, 0.75],
409
+ [gap / 2, 0.4],
410
+ ];
411
+ }
384
412
  return offsets_and_scales.length === 0
385
413
  ? [bond.transform_matrix]
386
414
  : offsets_and_scales.map(([offset, radius_scale]) => scale_and_offset_bond_matrix(bond.transform_matrix, offset, radius_scale));