matterviz 0.4.1 → 0.4.3

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 (499) hide show
  1. package/dist/EmptyState.svelte +10 -4
  2. package/dist/FilePicker.svelte +48 -60
  3. package/dist/Icon.svelte +7 -4
  4. package/dist/MillerIndexInput.svelte +2 -2
  5. package/dist/api/optimade.js +10 -7
  6. package/dist/app.css +68 -0
  7. package/dist/brillouin/BrillouinZone.svelte +90 -91
  8. package/dist/brillouin/BrillouinZone.svelte.d.ts +5 -7
  9. package/dist/brillouin/BrillouinZoneControls.svelte +3 -6
  10. package/dist/brillouin/BrillouinZoneExportPane.svelte +18 -14
  11. package/dist/brillouin/BrillouinZoneInfoPane.svelte +6 -10
  12. package/dist/brillouin/BrillouinZoneScene.svelte +46 -68
  13. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  14. package/dist/brillouin/compute.js +10 -16
  15. package/dist/brillouin/geometry.js +2 -2
  16. package/dist/chempot-diagram/ChemPotDiagram.svelte +48 -50
  17. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +61 -169
  18. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +1 -1
  19. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +559 -755
  20. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +1 -1
  21. package/dist/chempot-diagram/async-compute.svelte.js +13 -14
  22. package/dist/chempot-diagram/color.d.ts +21 -1
  23. package/dist/chempot-diagram/color.js +70 -1
  24. package/dist/chempot-diagram/compute.d.ts +7 -0
  25. package/dist/chempot-diagram/compute.js +85 -26
  26. package/dist/chempot-diagram/controls-state.svelte.js +1 -1
  27. package/dist/chempot-diagram/export.js +1 -6
  28. package/dist/chempot-diagram/temperature.js +9 -10
  29. package/dist/colors/index.d.ts +0 -4
  30. package/dist/colors/index.js +19 -20
  31. package/dist/composition/BarChart.svelte +30 -26
  32. package/dist/composition/BubbleChart.svelte +17 -17
  33. package/dist/composition/Composition.svelte +10 -19
  34. package/dist/composition/Formula.svelte +20 -27
  35. package/dist/composition/FormulaFilter.svelte +115 -184
  36. package/dist/composition/PieChart.svelte +55 -41
  37. package/dist/composition/format.js +7 -9
  38. package/dist/composition/index.d.ts +2 -0
  39. package/dist/composition/index.js +14 -0
  40. package/dist/composition/parse.d.ts +2 -2
  41. package/dist/composition/parse.js +61 -115
  42. package/dist/constants.d.ts +0 -1
  43. package/dist/constants.js +17 -26
  44. package/dist/convex-hull/ConvexHull.svelte +12 -15
  45. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
  46. package/dist/convex-hull/ConvexHull2D.svelte +93 -94
  47. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  48. package/dist/convex-hull/ConvexHull3D.svelte +127 -186
  49. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  50. package/dist/convex-hull/ConvexHull4D.svelte +131 -180
  51. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  52. package/dist/convex-hull/ConvexHullChrome.svelte +36 -40
  53. package/dist/convex-hull/ConvexHullControls.svelte +46 -48
  54. package/dist/convex-hull/ConvexHullStats.svelte +193 -195
  55. package/dist/convex-hull/ConvexHullTooltip.svelte +5 -12
  56. package/dist/convex-hull/GasPressureControls.svelte +5 -12
  57. package/dist/convex-hull/StructurePopup.svelte +18 -22
  58. package/dist/convex-hull/StructurePopup.svelte.d.ts +2 -0
  59. package/dist/convex-hull/TemperatureSlider.svelte +4 -10
  60. package/dist/convex-hull/canvas-interactions.svelte.js +2 -1
  61. package/dist/convex-hull/gas-thermodynamics.js +21 -53
  62. package/dist/convex-hull/helpers.d.ts +8 -10
  63. package/dist/convex-hull/helpers.js +37 -43
  64. package/dist/convex-hull/hull-state.svelte.d.ts +1 -1
  65. package/dist/convex-hull/thermodynamics.js +37 -44
  66. package/dist/coordination/CoordinationBarPlot.svelte +49 -53
  67. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
  68. package/dist/coordination/calc-coordination.d.ts +1 -1
  69. package/dist/coordination/calc-coordination.js +28 -25
  70. package/dist/element/BohrAtom.svelte +5 -9
  71. package/dist/element/ElementHeading.svelte +4 -1
  72. package/dist/element/ElementPhoto.svelte +11 -9
  73. package/dist/element/ElementStats.svelte +12 -10
  74. package/dist/element/ElementTile.svelte +44 -67
  75. package/dist/element/Nucleus.svelte +4 -2
  76. package/dist/element/data.d.ts +3 -2
  77. package/dist/element/data.js +5 -1
  78. package/dist/element/helpers.d.ts +4 -0
  79. package/dist/element/helpers.js +18 -0
  80. package/dist/element/index.d.ts +2 -5
  81. package/dist/element/index.js +4 -19
  82. package/dist/feedback/DragOverlay.svelte +5 -5
  83. package/dist/feedback/DragOverlay.svelte.d.ts +2 -2
  84. package/dist/feedback/StatusMessage.svelte +7 -4
  85. package/dist/fermi-surface/FermiSlice.svelte +21 -18
  86. package/dist/fermi-surface/FermiSurface.svelte +35 -44
  87. package/dist/fermi-surface/FermiSurface.svelte.d.ts +7 -13
  88. package/dist/fermi-surface/FermiSurfaceControls.svelte +6 -20
  89. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  90. package/dist/fermi-surface/FermiSurfaceScene.svelte +64 -136
  91. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  92. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +9 -6
  93. package/dist/fermi-surface/compute.js +25 -58
  94. package/dist/fermi-surface/parse.js +54 -88
  95. package/dist/file-viewer/JsonBrowser.svelte +1043 -0
  96. package/dist/file-viewer/JsonBrowser.svelte.d.ts +9 -0
  97. package/dist/file-viewer/PlotPanel.svelte +350 -0
  98. package/dist/file-viewer/PlotPanel.svelte.d.ts +9 -0
  99. package/dist/file-viewer/TrajectoryWithDos.svelte +30 -0
  100. package/dist/file-viewer/TrajectoryWithDos.svelte.d.ts +10 -0
  101. package/dist/file-viewer/detect.d.ts +11 -0
  102. package/dist/file-viewer/detect.js +381 -0
  103. package/dist/file-viewer/eligibility.d.ts +4 -0
  104. package/dist/file-viewer/eligibility.js +53 -0
  105. package/dist/file-viewer/host-protocol.d.ts +50 -0
  106. package/dist/file-viewer/host-transfer.d.ts +25 -0
  107. package/dist/file-viewer/host-transfer.js +42 -0
  108. package/dist/file-viewer/index.d.ts +5 -0
  109. package/dist/file-viewer/index.js +5 -0
  110. package/dist/file-viewer/main.d.ts +44 -0
  111. package/dist/file-viewer/main.js +535 -0
  112. package/dist/file-viewer/parse.d.ts +9 -0
  113. package/dist/file-viewer/parse.js +170 -0
  114. package/dist/file-viewer/plot-utils.d.ts +24 -0
  115. package/dist/file-viewer/plot-utils.js +191 -0
  116. package/dist/file-viewer/types.d.ts +4 -0
  117. package/dist/file-viewer/types.js +5 -0
  118. package/dist/heatmap-matrix/HeatmapMatrix.svelte +153 -219
  119. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +2 -2
  120. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +9 -7
  121. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
  122. package/dist/heatmap-matrix/index.d.ts +5 -0
  123. package/dist/icons.d.ts +4 -0
  124. package/dist/icons.js +4 -0
  125. package/dist/index.d.ts +2 -2
  126. package/dist/index.js +1 -1
  127. package/dist/io/ExportPane.svelte +11 -7
  128. package/dist/io/decompress.d.ts +4 -1
  129. package/dist/io/decompress.js +24 -36
  130. package/dist/io/export.d.ts +11 -4
  131. package/dist/io/export.js +75 -19
  132. package/dist/io/fetch.d.ts +0 -3
  133. package/dist/io/fetch.js +0 -11
  134. package/dist/io/file-drop.js +60 -35
  135. package/dist/io/index.d.ts +0 -1
  136. package/dist/io/index.js +2 -9
  137. package/dist/io/is-binary.d.ts +9 -0
  138. package/dist/io/is-binary.js +45 -1
  139. package/dist/io/url-drop.d.ts +2 -0
  140. package/dist/io/url-drop.js +40 -40
  141. package/dist/isosurface/Isosurface.svelte +700 -215
  142. package/dist/isosurface/Isosurface.svelte.d.ts +7 -1
  143. package/dist/isosurface/IsosurfaceControls.svelte +590 -116
  144. package/dist/isosurface/IsosurfaceControls.svelte.d.ts +1 -1
  145. package/dist/isosurface/VolumeSlice.svelte +224 -0
  146. package/dist/isosurface/VolumeSlice.svelte.d.ts +28 -0
  147. package/dist/isosurface/coloring.d.ts +20 -0
  148. package/dist/isosurface/coloring.js +118 -0
  149. package/dist/isosurface/geometry-worker-types.d.ts +38 -0
  150. package/dist/isosurface/geometry.worker.d.ts +1 -0
  151. package/dist/isosurface/geometry.worker.js +59 -0
  152. package/dist/isosurface/grid.d.ts +10 -0
  153. package/dist/isosurface/grid.js +31 -0
  154. package/dist/isosurface/index.d.ts +4 -0
  155. package/dist/isosurface/index.js +4 -0
  156. package/dist/isosurface/parse-vaspwave.d.ts +3 -0
  157. package/dist/isosurface/parse-vaspwave.js +138 -0
  158. package/dist/isosurface/parse.js +6 -6
  159. package/dist/isosurface/profile.d.ts +12 -0
  160. package/dist/isosurface/profile.js +19 -0
  161. package/dist/isosurface/sampling.d.ts +34 -0
  162. package/dist/isosurface/sampling.js +408 -0
  163. package/dist/isosurface/slice-rendering.d.ts +13 -0
  164. package/dist/isosurface/slice-rendering.js +79 -0
  165. package/dist/isosurface/slice.d.ts +22 -2
  166. package/dist/isosurface/slice.js +200 -116
  167. package/dist/isosurface/types.d.ts +24 -1
  168. package/dist/isosurface/types.js +120 -8
  169. package/dist/json-path.d.ts +4 -0
  170. package/dist/json-path.js +89 -0
  171. package/dist/labels.d.ts +6 -2
  172. package/dist/labels.js +44 -14
  173. package/dist/layout/FullscreenButton.svelte +2 -1
  174. package/dist/layout/FullscreenToggle.svelte +10 -4
  175. package/dist/layout/InfoCard.svelte +8 -21
  176. package/dist/layout/InfoTag.svelte +1 -3
  177. package/dist/layout/NumberRangeInput.svelte +46 -0
  178. package/dist/layout/NumberRangeInput.svelte.d.ts +12 -0
  179. package/dist/layout/PropertyFilter.svelte +2 -6
  180. package/dist/layout/SettingsSection.svelte +57 -62
  181. package/dist/layout/SettingsSection.svelte.d.ts +6 -7
  182. package/dist/layout/SubpageGrid.svelte +3 -1
  183. package/dist/layout/ViewerChrome.svelte +16 -11
  184. package/dist/layout/ViewerChrome.svelte.d.ts +2 -1
  185. package/dist/layout/fullscreen.js +3 -5
  186. package/dist/layout/fullscreen.svelte.js +1 -2
  187. package/dist/layout/index.d.ts +1 -0
  188. package/dist/layout/index.js +1 -0
  189. package/dist/layout/json-tree/JsonNode.svelte +22 -59
  190. package/dist/layout/json-tree/JsonTree.svelte +101 -172
  191. package/dist/layout/json-tree/JsonValue.svelte +9 -32
  192. package/dist/layout/json-tree/utils.d.ts +0 -3
  193. package/dist/layout/json-tree/utils.js +50 -188
  194. package/dist/marching-cubes.d.ts +8 -1
  195. package/dist/marching-cubes.js +115 -48
  196. package/dist/math.d.ts +5 -2
  197. package/dist/math.js +48 -38
  198. package/dist/overlays/ContextMenu.svelte +19 -34
  199. package/dist/overlays/CopyButton.svelte +11 -5
  200. package/dist/overlays/DragControlTab.svelte +6 -1
  201. package/dist/overlays/DraggablePane.svelte +110 -74
  202. package/dist/overlays/DraggablePane.svelte.d.ts +2 -1
  203. package/dist/overlays/GlassChip.svelte +32 -0
  204. package/dist/overlays/GlassChip.svelte.d.ts +8 -0
  205. package/dist/overlays/InfoPaneCards.svelte +11 -23
  206. package/dist/overlays/index.d.ts +7 -0
  207. package/dist/overlays/index.js +26 -0
  208. package/dist/overlays/portal.d.ts +2 -0
  209. package/dist/overlays/portal.js +14 -0
  210. package/dist/periodic-table/PeriodicTable.svelte +113 -145
  211. package/dist/periodic-table/PeriodicTable.svelte.d.ts +5 -3
  212. package/dist/periodic-table/PeriodicTableControls.svelte +37 -115
  213. package/dist/periodic-table/TableInset.svelte +9 -4
  214. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +68 -105
  215. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -8
  216. package/dist/phase-diagram/PhaseDiagramControls.svelte +70 -94
  217. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  218. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
  219. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +12 -12
  220. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +54 -58
  221. package/dist/phase-diagram/TdbInfoPanel.svelte +21 -15
  222. package/dist/phase-diagram/build-diagram.js +4 -9
  223. package/dist/phase-diagram/diagram-input.d.ts +1 -2
  224. package/dist/phase-diagram/parse.js +15 -15
  225. package/dist/phase-diagram/svg-to-diagram.js +28 -27
  226. package/dist/phase-diagram/utils.js +2 -3
  227. package/dist/plot/bar/BarPlot.svelte +461 -426
  228. package/dist/plot/bar/BarPlot.svelte.d.ts +2 -0
  229. package/dist/plot/bar/BarPlotControls.svelte +1 -3
  230. package/dist/plot/bar/BarPlotControls.svelte.d.ts +4 -6
  231. package/dist/plot/bar/SpacegroupBarPlot.svelte +46 -77
  232. package/dist/plot/bar/data.d.ts +5 -4
  233. package/dist/plot/bar/data.js +2 -1
  234. package/dist/plot/box/BoxPlot.svelte +322 -226
  235. package/dist/plot/box/BoxPlot.svelte.d.ts +2 -0
  236. package/dist/plot/box/Violin.svelte.d.ts +1 -0
  237. package/dist/plot/box/box-plot.js +1 -1
  238. package/dist/plot/core/auto-place.d.ts +1 -1
  239. package/dist/plot/core/auto-place.js +2 -2
  240. package/dist/plot/core/axis-utils.d.ts +12 -7
  241. package/dist/plot/core/axis-utils.js +48 -48
  242. package/dist/plot/core/components/AxisLabel.svelte +82 -20
  243. package/dist/plot/core/components/AxisLabel.svelte.d.ts +1 -0
  244. package/dist/plot/core/components/ColorBar.svelte +101 -106
  245. package/dist/plot/core/components/ColorScaleSelect.svelte +1 -1
  246. package/dist/plot/core/components/FillArea.svelte +10 -17
  247. package/dist/plot/core/components/HierarchyControls.svelte +249 -0
  248. package/dist/plot/{sunburst/SunburstControls.svelte.d.ts → core/components/HierarchyControls.svelte.d.ts} +12 -8
  249. package/dist/plot/core/components/InteractiveAxisLabel.svelte +1 -1
  250. package/dist/plot/core/components/InteractiveAxisLabel.svelte.d.ts +1 -1
  251. package/dist/plot/core/components/Line.svelte +18 -9
  252. package/dist/plot/core/components/Line.svelte.d.ts +2 -0
  253. package/dist/plot/core/components/PlotAxis.svelte +40 -17
  254. package/dist/plot/core/components/PlotControls.svelte +65 -41
  255. package/dist/plot/core/components/PlotLegend.svelte +31 -35
  256. package/dist/plot/core/components/PlotMarginals.svelte +616 -0
  257. package/dist/plot/core/components/PlotMarginals.svelte.d.ts +15 -0
  258. package/dist/plot/core/components/PlotTooltip.svelte +1 -1
  259. package/dist/plot/core/components/PortalSelect.svelte +4 -8
  260. package/dist/plot/core/components/ReferenceLine.svelte +27 -24
  261. package/dist/plot/core/components/ReferenceLine3D.svelte +54 -57
  262. package/dist/plot/core/components/ReferencePlane.svelte +7 -8
  263. package/dist/plot/core/components/ZeroLines.svelte +4 -8
  264. package/dist/plot/core/components/ZoomRect.svelte +1 -2
  265. package/dist/plot/core/components/index.d.ts +1 -0
  266. package/dist/plot/core/components/index.js +1 -0
  267. package/dist/plot/core/data-cleaning-signal.d.ts +46 -0
  268. package/dist/plot/core/data-cleaning-signal.js +467 -0
  269. package/dist/plot/core/data-cleaning.d.ts +2 -42
  270. package/dist/plot/core/data-cleaning.js +27 -474
  271. package/dist/plot/core/data-transform.d.ts +1 -2
  272. package/dist/plot/core/data-transform.js +9 -15
  273. package/dist/plot/core/fill-utils.d.ts +3 -1
  274. package/dist/plot/core/fill-utils.js +28 -6
  275. package/dist/plot/core/index.d.ts +1 -0
  276. package/dist/plot/core/index.js +1 -0
  277. package/dist/plot/core/interactions.js +0 -2
  278. package/dist/plot/core/layout.d.ts +15 -6
  279. package/dist/plot/core/layout.js +57 -38
  280. package/dist/plot/core/marginals.d.ts +170 -0
  281. package/dist/plot/core/marginals.js +436 -0
  282. package/dist/plot/core/pan-zoom.svelte.d.ts +2 -4
  283. package/dist/plot/core/pan-zoom.svelte.js +34 -17
  284. package/dist/plot/core/placed-tween.svelte.d.ts +3 -0
  285. package/dist/plot/core/placed-tween.svelte.js +68 -21
  286. package/dist/plot/core/reference-line.js +1 -1
  287. package/dist/plot/core/scales.d.ts +23 -0
  288. package/dist/plot/core/scales.js +39 -13
  289. package/dist/plot/core/svg.js +0 -1
  290. package/dist/plot/core/types/fills.d.ts +101 -0
  291. package/dist/plot/core/types/fills.js +15 -0
  292. package/dist/plot/core/types/plot-3d.d.ts +87 -0
  293. package/dist/plot/core/types/plot-3d.js +4 -0
  294. package/dist/plot/core/types/reference-lines.d.ts +140 -0
  295. package/dist/plot/core/types/reference-lines.js +9 -0
  296. package/dist/plot/core/types.d.ts +29 -324
  297. package/dist/plot/core/types.js +23 -20
  298. package/dist/plot/core/utils/hierarchy-chart.d.ts +52 -0
  299. package/dist/plot/core/utils/hierarchy-chart.js +191 -0
  300. package/dist/plot/core/utils/hierarchy-labels.d.ts +20 -0
  301. package/dist/plot/core/utils/hierarchy-labels.js +100 -0
  302. package/dist/plot/core/utils/label-placement.js +2 -2
  303. package/dist/plot/histogram/Histogram.svelte +314 -340
  304. package/dist/plot/histogram/Histogram.svelte.d.ts +7 -7
  305. package/dist/plot/histogram/HistogramControls.svelte +30 -28
  306. package/dist/plot/histogram/histogram.d.ts +31 -0
  307. package/dist/plot/histogram/histogram.js +70 -0
  308. package/dist/plot/histogram/index.d.ts +1 -0
  309. package/dist/plot/histogram/index.js +1 -0
  310. package/dist/plot/index.d.ts +1 -0
  311. package/dist/plot/index.js +1 -0
  312. package/dist/plot/sankey/Sankey.svelte +78 -69
  313. package/dist/plot/sankey/Sankey.svelte.d.ts +2 -2
  314. package/dist/plot/sankey/SankeyControls.svelte +22 -16
  315. package/dist/plot/sankey/sankey.js +13 -9
  316. package/dist/plot/scatter/BinnedScatterPlot.svelte +311 -141
  317. package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +7 -0
  318. package/dist/plot/scatter/ElementScatter.svelte +4 -1
  319. package/dist/plot/scatter/ScatterPlot.svelte +517 -410
  320. package/dist/plot/scatter/ScatterPlot.svelte.d.ts +2 -0
  321. package/dist/plot/scatter/ScatterPlotControls.svelte +18 -19
  322. package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
  323. package/dist/plot/scatter/ScatterPoint.svelte +16 -9
  324. package/dist/plot/scatter/adaptive-density.d.ts +1 -1
  325. package/dist/plot/scatter/adaptive-density.js +36 -20
  326. package/dist/plot/scatter/binned-scatter-types.d.ts +3 -2
  327. package/dist/plot/scatter/binned-scatter-types.js +6 -1
  328. package/dist/plot/scatter/scatter-data.d.ts +1 -1
  329. package/dist/plot/scatter/scatter-data.js +8 -7
  330. package/dist/plot/scatter-3d/ScatterPlot3D.svelte +25 -34
  331. package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +2 -2
  332. package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +8 -5
  333. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +113 -116
  334. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +2 -2
  335. package/dist/plot/scatter-3d/Surface3D.svelte +4 -13
  336. package/dist/plot/sunburst/Sunburst.svelte +269 -347
  337. package/dist/plot/sunburst/Sunburst.svelte.d.ts +2 -2
  338. package/dist/plot/sunburst/index.d.ts +1 -1
  339. package/dist/plot/sunburst/index.js +2 -1
  340. package/dist/plot/sunburst/render.d.ts +2 -2
  341. package/dist/plot/sunburst/render.js +47 -22
  342. package/dist/plot/sunburst/sunburst.d.ts +5 -1
  343. package/dist/plot/sunburst/sunburst.js +10 -3
  344. package/dist/plot/treemap/Treemap.svelte +1022 -0
  345. package/dist/plot/treemap/Treemap.svelte.d.ts +90 -0
  346. package/dist/plot/treemap/index.d.ts +4 -0
  347. package/dist/plot/treemap/index.js +4 -0
  348. package/dist/plot/treemap/labels.d.ts +38 -0
  349. package/dist/plot/treemap/labels.js +80 -0
  350. package/dist/plot/treemap/treemap.d.ts +28 -0
  351. package/dist/plot/treemap/treemap.js +102 -0
  352. package/dist/rdf/RdfPlot.svelte +37 -59
  353. package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
  354. package/dist/rdf/calc-rdf.js +63 -52
  355. package/dist/rdf/index.d.ts +0 -1
  356. package/dist/sanitize.js +85 -27
  357. package/dist/scene/SceneCamera.svelte +1 -1
  358. package/dist/scene/SceneCamera.svelte.d.ts +1 -1
  359. package/dist/scene/bind-renderer.svelte.js +14 -6
  360. package/dist/scene/index.d.ts +1 -2
  361. package/dist/scene/index.js +1 -1
  362. package/dist/scene/{props.js → props.svelte.js} +15 -1
  363. package/dist/settings.d.ts +19 -9
  364. package/dist/settings.js +229 -525
  365. package/dist/spectral/Bands.svelte +207 -221
  366. package/dist/spectral/BandsAndDos.svelte +11 -9
  367. package/dist/spectral/BrillouinBandsDos.svelte +19 -42
  368. package/dist/spectral/Dos.svelte +92 -93
  369. package/dist/spectral/helpers.d.ts +3 -3
  370. package/dist/spectral/helpers.js +65 -140
  371. package/dist/state.svelte.js +5 -18
  372. package/dist/structure/Arrow.svelte +5 -18
  373. package/dist/structure/ArrowInstances.svelte +160 -0
  374. package/dist/structure/ArrowInstances.svelte.d.ts +16 -0
  375. package/dist/structure/AtomLegend.svelte +120 -85
  376. package/dist/structure/AtomLegend.svelte.d.ts +2 -3
  377. package/dist/structure/Bond.svelte +31 -23
  378. package/dist/structure/CanvasTooltip.svelte +15 -3
  379. package/dist/structure/CellSelect.svelte +45 -35
  380. package/dist/structure/Cylinder.svelte +24 -40
  381. package/dist/structure/InstancedAtoms.svelte +114 -0
  382. package/dist/structure/InstancedAtoms.svelte.d.ts +15 -0
  383. package/dist/structure/Lattice.svelte +85 -149
  384. package/dist/structure/SiteLabels.svelte +122 -0
  385. package/dist/structure/SiteLabels.svelte.d.ts +18 -0
  386. package/dist/structure/Structure.svelte +636 -504
  387. package/dist/structure/Structure.svelte.d.ts +4 -2
  388. package/dist/structure/StructureCarousel.svelte +637 -0
  389. package/dist/structure/StructureCarousel.svelte.d.ts +19 -0
  390. package/dist/structure/StructureControls.svelte +165 -425
  391. package/dist/structure/StructureControls.svelte.d.ts +1 -1
  392. package/dist/structure/StructureExportPane.svelte +17 -21
  393. package/dist/structure/StructureInfoPane.svelte +128 -133
  394. package/dist/structure/StructureInfoPane.svelte.d.ts +1 -1
  395. package/dist/structure/StructureScene.svelte +535 -578
  396. package/dist/structure/StructureScene.svelte.d.ts +6 -2
  397. package/dist/structure/StructureViewport.svelte +451 -0
  398. package/dist/structure/StructureViewport.svelte.d.ts +65 -0
  399. package/dist/structure/atom-label-placement.d.ts +16 -12
  400. package/dist/structure/atom-label-placement.js +70 -37
  401. package/dist/structure/atom-properties.d.ts +2 -0
  402. package/dist/structure/atom-properties.js +105 -38
  403. package/dist/structure/bond-order-perception.js +3 -8
  404. package/dist/structure/bonding.d.ts +9 -3
  405. package/dist/structure/bonding.js +95 -46
  406. package/dist/structure/edit-history.d.ts +6 -0
  407. package/dist/structure/edit-history.js +27 -0
  408. package/dist/structure/export.d.ts +1 -0
  409. package/dist/structure/export.js +89 -105
  410. package/dist/structure/format-detect.d.ts +1 -0
  411. package/dist/structure/format-detect.js +20 -0
  412. package/dist/structure/geometry.d.ts +9 -0
  413. package/dist/structure/geometry.js +27 -0
  414. package/dist/structure/index.d.ts +16 -1
  415. package/dist/structure/index.js +15 -10
  416. package/dist/structure/measure.d.ts +1 -1
  417. package/dist/structure/measure.js +6 -12
  418. package/dist/structure/parse.d.ts +2 -1
  419. package/dist/structure/parse.js +272 -313
  420. package/dist/structure/partial-occupancy.js +10 -5
  421. package/dist/structure/pbc.js +85 -107
  422. package/dist/structure/polyhedra.d.ts +0 -1
  423. package/dist/structure/polyhedra.js +7 -21
  424. package/dist/structure/prop-groups.d.ts +85 -0
  425. package/dist/structure/prop-groups.js +18 -0
  426. package/dist/structure/supercell.d.ts +1 -2
  427. package/dist/structure/supercell.js +7 -13
  428. package/dist/symmetry/SymmetryElements.svelte +11 -15
  429. package/dist/symmetry/SymmetryStats.svelte +55 -71
  430. package/dist/symmetry/WyckoffTable.svelte +10 -28
  431. package/dist/symmetry/cell-transform.js +6 -14
  432. package/dist/symmetry/index.d.ts +1 -0
  433. package/dist/symmetry/index.js +13 -10
  434. package/dist/symmetry/spacegroups.js +3 -2
  435. package/dist/table/HeatmapTable.svelte +1142 -447
  436. package/dist/table/HeatmapTable.svelte.d.ts +12 -2
  437. package/dist/table/ToggleMenu.svelte +168 -53
  438. package/dist/table/ToggleMenu.svelte.d.ts +1 -1
  439. package/dist/table/index.d.ts +21 -6
  440. package/dist/table/index.js +34 -21
  441. package/dist/theme/ThemeControl.svelte +16 -8
  442. package/dist/theme/embedded.d.ts +18 -0
  443. package/dist/theme/embedded.js +206 -0
  444. package/dist/theme/index.d.ts +5 -5
  445. package/dist/theme/index.js +5 -12
  446. package/dist/theme/themes.mjs +44 -66
  447. package/dist/tooltip/KCoords.svelte +4 -1
  448. package/dist/tooltip/TooltipContent.svelte +3 -6
  449. package/dist/tooltip/TooltipContent.svelte.d.ts +1 -1
  450. package/dist/tooltip/index.d.ts +8 -1
  451. package/dist/trajectory/Trajectory.svelte +613 -386
  452. package/dist/trajectory/Trajectory.svelte.d.ts +1 -1
  453. package/dist/trajectory/TrajectoryError.svelte +12 -74
  454. package/dist/trajectory/TrajectoryExportPane.svelte +14 -32
  455. package/dist/trajectory/TrajectoryInfoPane.svelte +127 -164
  456. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +2 -1
  457. package/dist/trajectory/extract.js +61 -49
  458. package/dist/trajectory/format-detect.d.ts +2 -0
  459. package/dist/trajectory/format-detect.js +17 -13
  460. package/dist/trajectory/frame-reader.d.ts +2 -0
  461. package/dist/trajectory/frame-reader.js +35 -32
  462. package/dist/trajectory/helpers.d.ts +2 -0
  463. package/dist/trajectory/helpers.js +34 -56
  464. package/dist/trajectory/index.d.ts +1 -0
  465. package/dist/trajectory/index.js +5 -8
  466. package/dist/trajectory/parse/ase.js +1 -1
  467. package/dist/trajectory/parse/h5-utils.d.ts +13 -0
  468. package/dist/trajectory/parse/h5-utils.js +109 -0
  469. package/dist/trajectory/parse/hdf5.d.ts +1 -1
  470. package/dist/trajectory/parse/hdf5.js +116 -106
  471. package/dist/trajectory/parse/index.d.ts +6 -6
  472. package/dist/trajectory/parse/index.js +25 -33
  473. package/dist/trajectory/parse/lammps.js +8 -12
  474. package/dist/trajectory/parse/vasp.js +10 -7
  475. package/dist/trajectory/parse/vaspout-electronic.d.ts +13 -0
  476. package/dist/trajectory/parse/vaspout-electronic.js +207 -0
  477. package/dist/trajectory/parse/vaspout-h5.d.ts +4 -0
  478. package/dist/trajectory/parse/vaspout-h5.js +281 -0
  479. package/dist/trajectory/parse/xyz.js +59 -9
  480. package/dist/trajectory/plotting.d.ts +8 -9
  481. package/dist/trajectory/plotting.js +113 -64
  482. package/dist/utils.d.ts +3 -0
  483. package/dist/utils.js +7 -0
  484. package/dist/xrd/XrdPlot.svelte +79 -118
  485. package/dist/xrd/broadening.js +2 -1
  486. package/dist/xrd/calc-xrd.js +24 -62
  487. package/dist/xrd/parse.d.ts +0 -1
  488. package/dist/xrd/parse.js +69 -95
  489. package/package.json +94 -34
  490. package/readme.md +6 -5
  491. package/dist/api/mp.d.ts +0 -6
  492. package/dist/api/mp.js +0 -22
  493. package/dist/plot/sunburst/SunburstControls.svelte +0 -200
  494. package/dist/scene/types.d.ts +0 -26
  495. package/dist/tooltip/types.d.ts +0 -8
  496. package/dist/trajectory/constants.d.ts +0 -6
  497. package/dist/trajectory/constants.js +0 -11
  498. /package/dist/{scene/types.js → file-viewer/host-protocol.js} +0 -0
  499. /package/dist/{tooltip/types.js → isosurface/geometry-worker-types.js} +0 -0
@@ -6,6 +6,7 @@
6
6
  import type { AxisConfig } from '../plot'
7
7
  import ColorBar from '../plot/core/components/ColorBar.svelte'
8
8
  import { quickselect } from '../plot/box/quantile'
9
+ import { clamp01 } from '../utils'
9
10
  import { type ComponentProps, onDestroy, onMount, type Snippet } from 'svelte'
10
11
  import type { HTMLAttributes } from 'svelte/elements'
11
12
  import { SvelteMap, SvelteSet } from 'svelte/reactivity'
@@ -17,6 +18,7 @@
17
18
  HeatmapExportFormat,
18
19
  HeatmapTooltipProp,
19
20
  LegendPosition,
21
+ MissingCellStyle,
20
22
  NormalizeMode,
21
23
  SymmetricMode,
22
24
  } from './index'
@@ -38,7 +40,7 @@
38
40
  color_scale = $bindable(`interpolateViridis`),
39
41
  color_scale_range = [null, null],
40
42
  color_overrides = {},
41
- missing_color = `transparent`,
43
+ missing = {},
42
44
  log = false,
43
45
  value_transform,
44
46
  normalize = `linear`,
@@ -113,13 +115,11 @@
113
115
  }: Omit<HTMLAttributes<HTMLDivElement>, `onclick` | `ondblclick`> & {
114
116
  x_items: AxisItem[]
115
117
  y_items: AxisItem[]
116
- values?:
117
- | CellValue[][]
118
- | Record<string, Record<string, CellValue>>
118
+ values?: CellValue[][] | Record<string, Record<string, CellValue>>
119
119
  color_scale?: D3InterpolateName | ((val: number) => string)
120
120
  color_scale_range?: [number | null, number | null]
121
121
  color_overrides?: Record<string, string>
122
- missing_color?: string
122
+ missing?: MissingCellStyle
123
123
  log?: boolean
124
124
  value_transform?: (
125
125
  value: number,
@@ -145,11 +145,7 @@
145
145
  onpin?: (cell: CellPos | null) => void
146
146
  oncontextmenu?: (cell: CellContext, event: MouseEvent) => void
147
147
  enable_brush?: boolean
148
- onbrush?: (payload: {
149
- x_range: Vec2
150
- y_range: Vec2
151
- cells: CellContext[]
152
- }) => void
148
+ onbrush?: (payload: { x_range: Vec2; y_range: Vec2; cells: CellContext[] }) => void
153
149
  tile_size?: string
154
150
  gap?: string
155
151
  // false: show all rows/cols. 'compact': remove all-null rows/cols.
@@ -199,9 +195,7 @@
199
195
  } = $props()
200
196
 
201
197
  // Normalize symmetric prop: true→'lower', otherwise pass through
202
- const symmetric = $derived(
203
- symmetric_prop === true ? `lower` : symmetric_prop,
204
- )
198
+ const symmetric = $derived(symmetric_prop === true ? `lower` : symmetric_prop)
205
199
 
206
200
  // Check if a cell should be skipped in symmetric mode
207
201
  function is_hidden_cell(x_idx: number, y_idx: number): boolean {
@@ -220,8 +214,7 @@
220
214
  let get_value = $derived.by(() => {
221
215
  if (Array.isArray(values)) {
222
216
  const matrix_values = values as CellValue[][]
223
- return (x_idx: number, y_idx: number): CellValue =>
224
- matrix_values[y_idx]?.[x_idx] ?? null
217
+ return (x_idx: number, y_idx: number): CellValue => matrix_values[y_idx]?.[x_idx] ?? null
225
218
  }
226
219
  // Record<y_key, Record<x_key, value>>
227
220
  const record = values as Record<string, Record<string, CellValue>>
@@ -261,25 +254,22 @@
261
254
  return sorted
262
255
  }
263
256
 
257
+ const filter_by_search = (indices: number[], items: AxisItem[]): number[] =>
258
+ search_query_norm
259
+ ? indices.filter((idx) => {
260
+ const item = items[idx]
261
+ return (
262
+ (item.key ?? item.label).toLowerCase().includes(search_query_norm) ||
263
+ item.label.toLowerCase().includes(search_query_norm)
264
+ )
265
+ })
266
+ : indices
267
+
264
268
  let { vis_x, vis_y } = $derived.by(() => {
265
269
  const all_x = Array.from({ length: x_items.length }, (_, idx) => idx)
266
270
  const all_y = Array.from({ length: y_items.length }, (_, idx) => idx)
267
- const filtered_x = search_query_norm
268
- ? all_x.filter((idx) => {
269
- const item = x_items[idx]
270
- const key = item.key ?? item.label
271
- return key.toLowerCase().includes(search_query_norm) ||
272
- item.label.toLowerCase().includes(search_query_norm)
273
- })
274
- : all_x
275
- const filtered_y = search_query_norm
276
- ? all_y.filter((idx) => {
277
- const item = y_items[idx]
278
- const key = item.key ?? item.label
279
- return key.toLowerCase().includes(search_query_norm) ||
280
- item.label.toLowerCase().includes(search_query_norm)
281
- })
282
- : all_y
271
+ const filtered_x = filter_by_search(all_x, x_items)
272
+ const filtered_y = filter_by_search(all_y, y_items)
283
273
  if (!hide_empty) {
284
274
  return {
285
275
  vis_x: sort_indices(filtered_x, x_items, x_order),
@@ -345,7 +335,7 @@
345
335
  // Interpolated quantile via quickselect (O(n) avg vs full sort); reorders `scratch_values` in place so callers must pass a copy they own
346
336
  function get_quantile(scratch_values: number[], quantile: number): number {
347
337
  if (scratch_values.length === 0) return 0
348
- const clipped_quantile = Math.max(0, Math.min(1, quantile))
338
+ const clipped_quantile = clamp01(quantile)
349
339
  const float_idx = (scratch_values.length - 1) * clipped_quantile
350
340
  const low_idx = Math.floor(float_idx)
351
341
  const high_idx = Math.ceil(float_idx)
@@ -390,8 +380,8 @@
390
380
  const clipped_min = get_quantile(scratch, q_low)
391
381
  const clipped_max = get_quantile(scratch, q_high)
392
382
  return clipped_min <= clipped_max
393
- ? [clipped_min, clipped_max] as const
394
- : [clipped_max, clipped_min] as const
383
+ ? ([clipped_min, clipped_max] as const)
384
+ : ([clipped_max, clipped_min] as const)
395
385
  })
396
386
 
397
387
  let [domain_min, domain_max] = $derived.by(() => {
@@ -410,41 +400,44 @@
410
400
  let cs_max = $derived(color_scale_range[1] ?? domain_max)
411
401
  let use_log_norm = $derived(normalize === `log` || log)
412
402
 
403
+ // fill for cells with no mappable value (default transparent)
404
+ let missing_fill = $derived(missing.color ?? `transparent`)
405
+
406
+ // whether a value lacks a mappable scale color (-> missing fill + label/style decorations)
407
+ function cell_is_missing(val: CellValue): boolean {
408
+ if (val === null) return true
409
+ if (typeof val === `string`) return !is_color(val)
410
+ return !Number.isFinite(val) || (use_log_norm && val <= 0)
411
+ }
412
+
413
413
  // Map a single value to a background color
414
414
  function value_to_color(val: CellValue): string | null {
415
- if (val === null) return missing_color || null
416
- if (typeof val === `string`) {
417
- if (is_color(val)) return val
418
- return missing_color || null
419
- }
420
- if (!Number.isFinite(val) || !color_scale_fn) return missing_color || null
421
- if (use_log_norm && val <= 0) return missing_color || null
415
+ if (typeof val === `string`) return is_color(val) ? val : missing_fill || null
416
+ // null/string excluded above -> val narrows to number past this guard
417
+ if (val === null || !color_scale_fn || cell_is_missing(val)) return missing_fill || null
422
418
 
423
419
  const span = cs_max - cs_min
424
420
  if (!Number.isFinite(span) || span === 0) return color_scale_fn(0.5)
425
421
 
426
- let normalized = typeof normalize === `function`
427
- ? normalize(val, cs_min, cs_max)
428
- : (val - cs_min) / span
422
+ let normalized =
423
+ typeof normalize === `function` ? normalize(val, cs_min, cs_max) : (val - cs_min) / span
429
424
  if (use_log_norm) {
430
425
  const is_descending_range = cs_min > cs_max
431
426
  const lower_bound = Math.min(cs_min, cs_max)
432
427
  const upper_bound = Math.max(cs_min, cs_max)
433
- if (upper_bound <= 0) return missing_color || null
428
+ if (upper_bound <= 0) return missing_fill || null
434
429
  const safe_lower_bound = lower_bound > 0 ? lower_bound : (min_pos ?? upper_bound)
435
430
  const safe_value = Math.max(val, safe_lower_bound)
436
431
  const log_min = Math.log(safe_lower_bound)
437
432
  const log_max = Math.log(upper_bound)
438
- if (
439
- !Number.isFinite(log_min) || !Number.isFinite(log_max) || log_max === log_min
440
- ) {
433
+ if (!Number.isFinite(log_min) || !Number.isFinite(log_max) || log_max === log_min) {
441
434
  return color_scale_fn(0.5)
442
435
  }
443
436
  const log_normalized = (Math.log(safe_value) - log_min) / (log_max - log_min)
444
437
  normalized = is_descending_range ? 1 - log_normalized : log_normalized
445
438
  }
446
- if (!Number.isFinite(normalized)) return missing_color || null
447
- return color_scale_fn(Math.max(0, Math.min(1, normalized)))
439
+ if (!Number.isFinite(normalized)) return missing_fill || null
440
+ return color_scale_fn(clamp01(normalized))
448
441
  }
449
442
 
450
443
  // Batch compute background colors as a flat array indexed by y_idx * n_x + x_idx.
@@ -462,21 +455,19 @@
462
455
  }
463
456
  const override_key = make_color_override_key(x_keys[x_idx], y_keys[y_idx])
464
457
  const raw_value = get_value(x_idx, y_idx)
465
- const transformed_value = typeof raw_value === `number`
466
- ? get_transformed_value(x_idx, y_idx)
467
- : raw_value
468
- colors[row_offset + x_idx] = override_key in color_overrides
469
- ? color_overrides[override_key]
470
- : value_to_color(transformed_value)
458
+ const transformed_value =
459
+ typeof raw_value === `number` ? get_transformed_value(x_idx, y_idx) : raw_value
460
+ colors[row_offset + x_idx] =
461
+ override_key in color_overrides
462
+ ? color_overrides[override_key]
463
+ : value_to_color(transformed_value)
471
464
  }
472
465
  }
473
466
  return colors
474
467
  })
475
468
 
476
469
  const to_contrast_colors = (bg_values: (string | null)[]): (string | null)[] =>
477
- bg_values.map((bg_color) =>
478
- bg_color ? pick_contrast_color({ bg_color }) : null
479
- )
470
+ bg_values.map((bg_color) => (bg_color ? pick_contrast_color({ bg_color }) : null))
480
471
 
481
472
  // Compute text colors when cells render content that needs contrast (cell snippet or show_values)
482
473
  let text_flat = $derived.by(() => {
@@ -485,14 +476,10 @@
485
476
  })
486
477
 
487
478
  // Keep selected outlines visible against each cell's background.
488
- let selected_outline_flat = $derived.by(() => to_contrast_colors(bg_flat))
479
+ let selected_outline_flat = $derived(to_contrast_colors(bg_flat))
489
480
 
490
481
  const get_flat_idx = (x_idx: number, y_idx: number): number => y_idx * n_x + x_idx
491
482
 
492
- // Look up bg color by indices
493
- const get_bg = (x_idx: number, y_idx: number): string | null =>
494
- bg_flat[get_flat_idx(x_idx, y_idx)]
495
-
496
483
  // === Cell context builder (only called for clicks, not per-hover) ===
497
484
  const build_cell_context = (x_idx: number, y_idx: number): CellContext => ({
498
485
  x_item: x_items[x_idx],
@@ -500,16 +487,16 @@
500
487
  x_idx,
501
488
  y_idx,
502
489
  value: get_value(x_idx, y_idx),
503
- bg_color: get_bg(x_idx, y_idx),
490
+ bg_color: bg_flat[get_flat_idx(x_idx, y_idx)],
504
491
  })
505
492
 
506
493
  // === Fully imperative hover management ===
507
494
  // ZERO $state writes during mouseover — all DOM updates are direct.
508
495
  // This avoids Svelte's reactive flush which would re-evaluate effects.
509
- const is_browser = typeof window !== `undefined`
510
496
  let tooltip_div: HTMLDivElement | undefined = $state()
511
497
  let active_cell_raf = 0 // rAF handle for deferred active_cell update
512
498
  let click_timeout_id: ReturnType<typeof setTimeout> | null = null
499
+ let pending_click_key: string | null = null
513
500
  const dblclick_delay_ms = 250
514
501
  let last_hover_x = -1
515
502
  let last_hover_y = -1
@@ -530,12 +517,10 @@
530
517
  symmetric && symmetric_label_position === `diagonal`,
531
518
  )
532
519
  let use_staggered_x_labels = $derived(
533
- stagger_axis_labels === true ||
534
- (stagger_axis_labels === `auto` && vis_x.length >= 24),
520
+ stagger_axis_labels === true || (stagger_axis_labels === `auto` && vis_x.length >= 24),
535
521
  )
536
522
  let use_staggered_y_labels = $derived(
537
- stagger_axis_labels === true ||
538
- (stagger_axis_labels === `auto` && vis_y.length >= 24),
523
+ stagger_axis_labels === true || (stagger_axis_labels === `auto` && vis_y.length >= 24),
539
524
  )
540
525
  let use_side_split_x_labels = $derived(
541
526
  use_staggered_x_labels && !use_diagonal_symmetric_labels,
@@ -560,7 +545,7 @@
560
545
  )
561
546
 
562
547
  function parse_px_size(size: string): number {
563
- const parsed = Number.parseFloat(size)
548
+ const parsed = Number(size.replace(`px`, ``))
564
549
  return Number.isFinite(parsed) && parsed > 0 ? parsed : 12
565
550
  }
566
551
 
@@ -573,8 +558,7 @@
573
558
  Math.floor((scroll_left - grid_offset_left) / tile_stride_px) - overscan
574
559
  const start_pos = Math.max(0, raw_start_pos)
575
560
  const raw_end_pos =
576
- Math.ceil((scroll_left - grid_offset_left + viewport_width) / tile_stride_px) +
577
- overscan
561
+ Math.ceil((scroll_left - grid_offset_left + viewport_width) / tile_stride_px) + overscan
578
562
  const end_pos = Math.min(vis_x.length, raw_end_pos)
579
563
  return vis_x.slice(start_pos, end_pos)
580
564
  })
@@ -584,8 +568,7 @@
584
568
  Math.floor((scroll_top - grid_offset_top) / tile_stride_px) - overscan
585
569
  const start_pos = Math.max(0, raw_start_pos)
586
570
  const raw_end_pos =
587
- Math.ceil((scroll_top - grid_offset_top + viewport_height) / tile_stride_px) +
588
- overscan
571
+ Math.ceil((scroll_top - grid_offset_top + viewport_height) / tile_stride_px) + overscan
589
572
  const end_pos = Math.min(vis_y.length, raw_end_pos)
590
573
  return vis_y.slice(start_pos, end_pos)
591
574
  })
@@ -610,16 +593,12 @@
610
593
  })
611
594
  let highlight_x_by_idx = $derived(
612
595
  new SvelteSet(
613
- vis_x.filter((idx) =>
614
- highlight_x_key_set.has(x_items[idx].key ?? x_items[idx].label)
615
- ),
596
+ vis_x.filter((idx) => highlight_x_key_set.has(x_items[idx].key ?? x_items[idx].label)),
616
597
  ),
617
598
  )
618
599
  let highlight_y_by_idx = $derived(
619
600
  new SvelteSet(
620
- vis_y.filter((idx) =>
621
- highlight_y_key_set.has(y_items[idx].key ?? y_items[idx].label)
622
- ),
601
+ vis_y.filter((idx) => highlight_y_key_set.has(y_items[idx].key ?? y_items[idx].label)),
623
602
  ),
624
603
  )
625
604
 
@@ -644,23 +623,6 @@
644
623
  return Math.max(1, vis_row + 1)
645
624
  }
646
625
 
647
- function x_label_diag_grid_col(x_idx: number): number | undefined {
648
- const vis_col = get_vis_col(x_idx)
649
- if (vis_col === null) return undefined
650
- return vis_col + 2
651
- }
652
-
653
- function y_label_edge_grid_row(y_idx: number): number | undefined {
654
- const vis_row = get_vis_row(y_idx)
655
- if (vis_row === null) return undefined
656
- return vis_row + 2
657
- }
658
-
659
- function x_label_grid_col(x_idx: number): number | undefined {
660
- if (use_diagonal_symmetric_labels) return x_label_diag_grid_col(x_idx)
661
- return cell_grid_col(x_idx)
662
- }
663
-
664
626
  function x_label_grid_row(x_idx: number): number | undefined {
665
627
  if (use_diagonal_symmetric_labels) return x_label_diag_grid_row(x_idx)
666
628
  if (use_side_split_x_labels && x_idx % 2 !== 0) {
@@ -689,37 +651,36 @@
689
651
  return vis_row + 2
690
652
  }
691
653
 
692
- function schedule_raf(callback: () => void): number {
693
- if (!is_browser) {
694
- callback()
695
- return 0
696
- }
697
- return globalThis.requestAnimationFrame(callback)
698
- }
699
-
654
+ // Called by event handlers, the axis-key-change effect, and onDestroy; the 0-handle
655
+ // guard prevents invalid cancelAnimationFrame calls.
700
656
  function cancel_raf(raf_handle: number): void {
701
- if (!is_browser || raf_handle === 0) return
702
- globalThis.cancelAnimationFrame(raf_handle)
657
+ if (raf_handle !== 0) globalThis.cancelAnimationFrame(raf_handle)
703
658
  }
704
659
 
705
660
  function clear_pending_click(): void {
706
- if (click_timeout_id === null) return
707
- clearTimeout(click_timeout_id)
661
+ if (click_timeout_id !== null) clearTimeout(click_timeout_id)
708
662
  click_timeout_id = null
663
+ pending_click_key = null
664
+ }
665
+
666
+ function schedule_single_click(cell_context: CellContext): void {
667
+ if (!onclick) return
668
+ clear_pending_click()
669
+ pending_click_key = cell_pos_key(cell_context.x_idx, cell_context.y_idx)
670
+ click_timeout_id = setTimeout(() => {
671
+ onclick(cell_context)
672
+ clear_pending_click()
673
+ }, dblclick_delay_ms)
709
674
  }
710
675
 
711
- function parse_cell_indices(
712
- cell_el: HTMLElement,
713
- ): { x_idx: number; y_idx: number } | null {
676
+ function parse_cell_indices(cell_el: HTMLElement): { x_idx: number; y_idx: number } | null {
714
677
  const x_value = Number(cell_el.dataset.x)
715
678
  const y_value = Number(cell_el.dataset.y)
716
679
  if (!Number.isInteger(x_value) || !Number.isInteger(y_value)) return null
717
680
  return { x_idx: x_value, y_idx: y_value }
718
681
  }
719
682
 
720
- function get_cell_context_from_target(
721
- event_target: EventTarget | null,
722
- ): CellContext | null {
683
+ function get_cell_context_from_target(event_target: EventTarget | null): CellContext | null {
723
684
  const cell_el = get_cell_el_from_target(event_target)
724
685
  if (!cell_el) return null
725
686
  const indices = parse_cell_indices(cell_el)
@@ -729,44 +690,24 @@
729
690
 
730
691
  function trigger_click(cell_context: CellContext): void {
731
692
  if (!onclick) return
732
- if (!ondblclick) {
733
- onclick(cell_context)
734
- return
735
- }
736
- clear_pending_click()
737
- click_timeout_id = setTimeout(() => {
738
- onclick(cell_context)
739
- click_timeout_id = null
740
- }, dblclick_delay_ms)
693
+ if (ondblclick) schedule_single_click(cell_context)
694
+ else onclick(cell_context)
741
695
  }
742
696
 
743
- function get_cell_el_from_target(
744
- event_target: EventTarget | null,
745
- ): HTMLElement | null {
746
- const target_node = event_target
747
- if (!(target_node instanceof Element)) return null
748
- if (target_node instanceof HTMLElement && target_node.dataset.x !== undefined) {
749
- return target_node
750
- }
751
- const closest_cell = target_node.closest(`[data-x][data-y]`)
752
- return closest_cell instanceof HTMLElement ? closest_cell : null
697
+ function get_cell_el_from_target(event_target: EventTarget | null): HTMLElement | null {
698
+ if (!(event_target instanceof Element)) return null
699
+ const cell_el = event_target.closest(`[data-x][data-y]`) // matches self too
700
+ return cell_el instanceof HTMLElement ? cell_el : null
753
701
  }
754
702
 
755
- function update_selected_cells(
756
- event: MouseEvent,
757
- clicked_cell: CellPos,
758
- ): void {
703
+ function update_selected_cells(event: MouseEvent, clicked_cell: CellPos): void {
759
704
  if (selection_mode === `single`) {
760
705
  selected_cells = [clicked_cell]
761
706
  last_selected_cell = clicked_cell
762
707
  onselect?.(selected_cells)
763
708
  return
764
709
  }
765
- if (
766
- selection_mode === `range` &&
767
- event.shiftKey &&
768
- last_selected_cell
769
- ) {
710
+ if (selection_mode === `range` && event.shiftKey && last_selected_cell) {
770
711
  const x_min = Math.min(last_selected_cell.x_idx, clicked_cell.x_idx)
771
712
  const x_max = Math.max(last_selected_cell.x_idx, clicked_cell.x_idx)
772
713
  const y_min = Math.min(last_selected_cell.y_idx, clicked_cell.y_idx)
@@ -784,12 +725,13 @@
784
725
  }
785
726
  const clicked_key = cell_pos_key(clicked_cell.x_idx, clicked_cell.y_idx)
786
727
  const next_cells = [...selected_cells]
787
- const existing_idx = next_cells.findIndex((pos) =>
788
- cell_pos_key(pos.x_idx, pos.y_idx) === clicked_key
728
+ const existing_idx = next_cells.findIndex(
729
+ (pos) => cell_pos_key(pos.x_idx, pos.y_idx) === clicked_key,
789
730
  )
731
+ // multi mode with Cmd/Ctrl toggles the clicked cell, otherwise replace selection
790
732
  const toggle_mode = selection_mode === `multi` && (event.metaKey || event.ctrlKey)
791
- if (existing_idx !== -1 && toggle_mode) next_cells.splice(existing_idx, 1)
792
- else if (selection_mode === `multi` && toggle_mode) next_cells.push(clicked_cell)
733
+ if (toggle_mode && existing_idx !== -1) next_cells.splice(existing_idx, 1)
734
+ else if (toggle_mode) next_cells.push(clicked_cell)
793
735
  else next_cells.splice(0, next_cells.length, clicked_cell)
794
736
  selected_cells = next_cells
795
737
  last_selected_cell = clicked_cell
@@ -801,8 +743,10 @@
801
743
  const tw = tooltip_div.offsetWidth
802
744
  const th = tooltip_div.offsetHeight
803
745
  // Flip to opposite side of cursor when near viewport edges
804
- const left = client_x + 10 + tw > globalThis.innerWidth ? client_x - 10 - tw : client_x + 10
805
- const top = client_y + 12 + th > globalThis.innerHeight ? client_y - 12 - th : client_y + 12
746
+ const left =
747
+ client_x + 10 + tw > globalThis.innerWidth ? client_x - 10 - tw : client_x + 10
748
+ const top =
749
+ client_y + 12 + th > globalThis.innerHeight ? client_y - 12 - th : client_y + 12
806
750
  tooltip_div.style.left = `${Math.max(0, left)}px`
807
751
  tooltip_div.style.top = `${Math.max(0, top)}px`
808
752
  }
@@ -813,19 +757,12 @@
813
757
  }
814
758
 
815
759
  // Write default tooltip content imperatively (no reactive state)
816
- function update_tooltip_content(
817
- td: HTMLElement,
818
- x_idx: number,
819
- y_idx: number,
820
- ): void {
760
+ function update_tooltip_content(td: HTMLElement, x_idx: number, y_idx: number): void {
821
761
  const x_label = x_items[x_idx]?.label ?? ``
822
762
  const y_label = y_items[y_idx]?.label ?? ``
823
763
  const val = get_value(x_idx, y_idx)
824
- const value_str = val == null
825
- ? ``
826
- : typeof val === `number`
827
- ? format_num(val)
828
- : String(val)
764
+ const value_str =
765
+ val == null ? `` : typeof val === `number` ? format_num(val) : String(val)
829
766
  td.textContent = value_str
830
767
  ? `${x_label} - ${y_label}: ${value_str}`
831
768
  : `${x_label} - ${y_label}`
@@ -848,7 +785,7 @@
848
785
 
849
786
  // Defer bindable writes out of the hot mouseover path
850
787
  cancel_raf(active_cell_raf)
851
- active_cell_raf = schedule_raf(() => {
788
+ active_cell_raf = globalThis.requestAnimationFrame(() => {
852
789
  active_cell = { x_idx, y_idx }
853
790
  })
854
791
 
@@ -873,14 +810,14 @@
873
810
  // Clear active state imperatively
874
811
  last_hover_x = -1
875
812
  last_hover_y = -1
876
- const keep_tooltip_visible = tooltip_mode === `pinned` ||
877
- (tooltip_mode === `both` && pinned_cell !== null)
813
+ const keep_tooltip_visible =
814
+ tooltip_mode === `pinned` || (tooltip_mode === `both` && pinned_cell !== null)
878
815
  if (!keep_tooltip_visible) {
879
816
  tooltip_div?.classList.remove(`visible`)
880
817
  }
881
818
  // Defer reactive cleanup to rAF
882
819
  cancel_raf(active_cell_raf)
883
- active_cell_raf = schedule_raf(() => {
820
+ active_cell_raf = globalThis.requestAnimationFrame(() => {
884
821
  active_cell = null
885
822
  if (!keep_tooltip_visible) tooltip_cell = null
886
823
  })
@@ -901,7 +838,6 @@
901
838
  else update_tooltip_content(tooltip_div, x_idx, y_idx)
902
839
  }
903
840
  }
904
- if (!onclick) return
905
841
  trigger_click(cell_context)
906
842
  }
907
843
 
@@ -909,8 +845,20 @@
909
845
  if (disabled || !ondblclick) return
910
846
  const cell_context = get_cell_context_from_target(event.target)
911
847
  if (!cell_context) return
848
+ // With onclick, require a matching pending click (FilePicker pattern).
849
+ // ondblclick-only stays direct so orphaned dblclicks still work.
850
+ if (!onclick) {
851
+ clear_pending_click()
852
+ ondblclick(cell_context)
853
+ return
854
+ }
855
+ const pending = pending_click_key
912
856
  clear_pending_click()
913
- ondblclick(cell_context)
857
+ if (pending === cell_pos_key(cell_context.x_idx, cell_context.y_idx)) {
858
+ ondblclick(cell_context)
859
+ } else {
860
+ schedule_single_click(cell_context)
861
+ }
914
862
  }
915
863
 
916
864
  function handle_contextmenu(event: MouseEvent): void {
@@ -982,10 +930,7 @@
982
930
  for (let step_idx = 0; step_idx < max_steps; step_idx++) {
983
931
  next_x += x_step
984
932
  next_y += y_step
985
- if (
986
- next_x < 0 || next_y < 0 || next_x >= x_items.length ||
987
- next_y >= y_items.length
988
- ) {
933
+ if (next_x < 0 || next_y < 0 || next_x >= x_items.length || next_y >= y_items.length) {
989
934
  return
990
935
  }
991
936
  if (is_hidden_cell(next_x, next_y)) continue
@@ -1075,26 +1020,22 @@
1075
1020
  let legend_orientation = $derived<ColorBarOrientation>(
1076
1021
  legend_position === `right` ? `vertical` : `horizontal`,
1077
1022
  )
1078
- let legend_wrapper_style = $derived.by(() =>
1023
+ let legend_wrapper_style = $derived(
1079
1024
  legend_position === `right`
1080
1025
  ? `--cbar-height: 120px; --cbar-min-height: 120px; --cbar-max-height: 120px;`
1081
- : `--cbar-width: 180px;`
1026
+ : `--cbar-width: 180px;`,
1082
1027
  )
1083
1028
 
1084
1029
  let has_interaction_handlers = $derived(
1085
1030
  !disabled &&
1086
- (
1087
- Boolean(onclick) ||
1031
+ (Boolean(onclick) ||
1088
1032
  Boolean(ondblclick) ||
1089
1033
  Boolean(oncontextmenu) ||
1090
1034
  selection_mode !== `single` ||
1091
- tooltip_mode !== `hover`
1092
- ),
1035
+ tooltip_mode !== `hover`),
1093
1036
  )
1094
1037
  let cell_tag_name = $derived(has_interaction_handlers ? `button` : `div`)
1095
- let cell_class_name = $derived(
1096
- has_interaction_handlers ? `cell interactive` : `cell`,
1097
- )
1038
+ let cell_class_name = $derived(has_interaction_handlers ? `cell interactive` : `cell`)
1098
1039
 
1099
1040
  // Tooltip state: only used for custom tooltip snippets (function tooltips)
1100
1041
  let tooltip_cell: CellContext | null = $state(null)
@@ -1103,7 +1044,8 @@
1103
1044
  keys_a.length === keys_b.length && keys_a.every((key, idx) => key === keys_b[idx])
1104
1045
  let prev_axis_keys: { x: string[]; y: string[] } | null = null
1105
1046
  $effect(() => {
1106
- const changed = prev_axis_keys !== null &&
1047
+ const changed =
1048
+ prev_axis_keys !== null &&
1107
1049
  !(keys_equal(x_keys, prev_axis_keys.x) && keys_equal(y_keys, prev_axis_keys.y))
1108
1050
  prev_axis_keys = { x: x_keys, y: y_keys }
1109
1051
  if (!changed) return
@@ -1124,11 +1066,8 @@
1124
1066
 
1125
1067
  onMount(() => {
1126
1068
  update_viewport_state()
1127
- if (!is_browser) return
1128
1069
  globalThis.addEventListener(`mouseup`, handle_mouseup)
1129
- return () => {
1130
- globalThis.removeEventListener(`mouseup`, handle_mouseup)
1131
- }
1070
+ return () => globalThis.removeEventListener(`mouseup`, handle_mouseup)
1132
1071
  })
1133
1072
 
1134
1073
  onDestroy(() => {
@@ -1151,8 +1090,8 @@
1151
1090
  bind:search_query
1152
1091
  {export_formats}
1153
1092
  onexport={onexport
1154
- ? (fmt: HeatmapExportFormat) => onexport(fmt, build_export_payload(fmt))
1155
- : undefined}
1093
+ ? (fmt: HeatmapExportFormat) => onexport(fmt, build_export_payload(fmt))
1094
+ : undefined}
1156
1095
  toggle_visible
1157
1096
  children={controls_children}
1158
1097
  {...controls_props}
@@ -1161,12 +1100,14 @@
1161
1100
  <div
1162
1101
  {...rest}
1163
1102
  bind:this={matrix_el}
1164
- class="grid theme-{theme} {rest.class ?? ``}"
1103
+ class={[`grid`, `theme-${theme}`, rest.class]}
1165
1104
  style:--n-cols={gaps_mode ? x_items.length : grid_col_count}
1166
1105
  style:--n-rows={gaps_mode ? y_items.length : grid_row_count}
1167
- style:--extra-right-y={(use_side_split_y_labels || symmetric === `upper`) ? 1 : 0}
1106
+ style:--extra-right-y={use_side_split_y_labels || symmetric === `upper` ? 1 : 0}
1168
1107
  style:--extra-bottom-x={use_side_split_x_labels ? 1 : 0}
1169
- style:--right-y-track={(use_side_split_y_labels || symmetric === `upper`) ? `max-content` : `0`}
1108
+ style:--right-y-track={use_side_split_y_labels || symmetric === `upper`
1109
+ ? `max-content`
1110
+ : `0`}
1170
1111
  style:--bottom-x-track={use_side_split_x_labels ? `max-content` : `0`}
1171
1112
  style:--tile-size={tile_size}
1172
1113
  style:--heatmap-gridline-color={gridline_color}
@@ -1199,7 +1140,7 @@
1199
1140
  class:highlighted={highlight_x_by_idx.has(x_idx)}
1200
1141
  class:sticky={sticky_x_labels}
1201
1142
  style={label_style || undefined}
1202
- style:grid-column={x_label_grid_col(x_idx)}
1143
+ style:grid-column={cell_grid_col(x_idx)}
1203
1144
  style:grid-row={x_label_grid_row(x_idx)}
1204
1145
  title={x_label_cell ? undefined : item.label}
1205
1146
  >
@@ -1223,7 +1164,7 @@
1223
1164
  class:highlighted={highlight_y_by_idx.has(y_idx)}
1224
1165
  class:sticky={sticky_y_labels}
1225
1166
  style={label_style || undefined}
1226
- style:grid-row={y_label_edge_grid_row(y_idx)}
1167
+ style:grid-row={cell_grid_row(y_idx)}
1227
1168
  style:grid-column={y_label_grid_col(y_idx)}
1228
1169
  title={y_label_cell ? undefined : y_item.label}
1229
1170
  >
@@ -1241,6 +1182,11 @@
1241
1182
  {@const bg = bg_flat[flat_idx]}
1242
1183
  {@const should_render = !is_hidden_cell(x_idx, y_idx)}
1243
1184
  {#if should_render}
1185
+ {@const raw = get_value(x_idx, y_idx)}
1186
+ <!-- missing-state must match bg_flat, which colors from the transformed value -->
1187
+ {@const cell_missing = cell_is_missing(
1188
+ typeof raw === `number` ? get_transformed_value(x_idx, y_idx) : raw,
1189
+ )}
1244
1190
  <svelte:element
1245
1191
  this={cell_tag_name}
1246
1192
  class={cell_class_name}
@@ -1249,6 +1195,7 @@
1249
1195
  class:animated={animate_updates}
1250
1196
  data-x={x_idx}
1251
1197
  data-y={y_idx}
1198
+ style={cell_missing ? missing.style : undefined}
1252
1199
  style:background-color={bg}
1253
1200
  style:color={text_flat?.[flat_idx]}
1254
1201
  style:--heatmap-selected-outline-color={selected_outline_flat[flat_idx]}
@@ -1257,15 +1204,14 @@
1257
1204
  >
1258
1205
  {#if cell}
1259
1206
  {@render cell(build_cell_context(x_idx, y_idx))}
1260
- {:else if show_values}
1261
- {@const raw = get_value(x_idx, y_idx)}
1262
- {#if raw !== null}
1263
- <span class="cell-value">{
1264
- typeof raw === `number`
1207
+ {:else if cell_missing}
1208
+ {#if missing.label}<span class="cell-value">{missing.label}</span>{/if}
1209
+ {:else if show_values && raw !== null}
1210
+ <span class="cell-value"
1211
+ >{typeof raw === `number`
1265
1212
  ? format_num(raw, show_values === true ? `.3~g` : show_values)
1266
- : raw
1267
- }</span>
1268
- {/if}
1213
+ : raw}</span
1214
+ >
1269
1215
  {/if}
1270
1216
  </svelte:element>
1271
1217
  {:else}
@@ -1273,8 +1219,7 @@
1273
1219
  class="cell empty"
1274
1220
  style:grid-column={cell_grid_col(x_idx)}
1275
1221
  style:grid-row={cell_grid_row(y_idx)}
1276
- >
1277
- </div>
1222
+ ></div>
1278
1223
  {/if}
1279
1224
  {/each}
1280
1225
  {/each}
@@ -1379,25 +1324,17 @@
1379
1324
  .grid {
1380
1325
  display: grid;
1381
1326
  grid-template-columns:
1382
- max-content repeat(
1383
- var(--n-cols),
1384
- minmax(var(--tile-size, 6px), 1fr)
1385
- ) var(--right-y-track, 0);
1327
+ max-content repeat(var(--n-cols), minmax(var(--tile-size, 6px), 1fr))
1328
+ var(--right-y-track, 0);
1386
1329
  grid-template-rows:
1387
- max-content repeat(
1388
- var(--n-rows),
1389
- minmax(var(--tile-size, 6px), 1fr)
1390
- ) var(--bottom-x-track, 0);
1330
+ max-content repeat(var(--n-rows), minmax(var(--tile-size, 6px), 1fr))
1331
+ var(--bottom-x-track, 0);
1391
1332
  position: relative;
1392
1333
  width: min(100%, var(--heatmap-max-width, 1200px));
1393
1334
  max-width: var(--heatmap-max-width, 1200px);
1394
1335
  aspect-ratio: calc(
1395
- (
1396
- var(--n-cols) + 1 + var(--extra-right-y, 0)
1397
- )
1398
- / (
1399
- var(--n-rows) + 1 + var(--extra-bottom-x, 0)
1400
- )
1336
+ (var(--n-cols) + 1 + var(--extra-right-y, 0)) /
1337
+ (var(--n-rows) + 1 + var(--extra-bottom-x, 0))
1401
1338
  );
1402
1339
  overflow: auto;
1403
1340
  &.theme-publication {
@@ -1527,10 +1464,7 @@
1527
1464
  display: none;
1528
1465
  position: fixed;
1529
1466
  transform: none;
1530
- background: var(
1531
- --tooltip-bg,
1532
- light-dark(rgba(255, 255, 255, 0.95), rgba(0, 0, 0, 0.85))
1533
- );
1467
+ background: var(--tooltip-bg, light-dark(rgba(255, 255, 255, 0.95), rgba(0, 0, 0, 0.85)));
1534
1468
  color: var(--tooltip-color, light-dark(#222, #eee));
1535
1469
  padding: var(--tooltip-padding, 4px 6px);
1536
1470
  border-radius: var(--tooltip-border-radius, var(--border-radius, 3pt));