matterviz 0.3.6 → 0.3.7

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 (863) hide show
  1. package/dist/EmptyState.svelte.d.ts +9 -0
  2. package/dist/FilePicker.svelte +360 -0
  3. package/dist/FilePicker.svelte.d.ts +17 -0
  4. package/dist/Icon.svelte.d.ts +13 -0
  5. package/dist/MillerIndexInput.svelte +66 -0
  6. package/dist/MillerIndexInput.svelte.d.ts +7 -0
  7. package/dist/api/mp.d.ts +6 -0
  8. package/dist/api/mp.js +22 -0
  9. package/dist/api/optimade.d.ts +45 -0
  10. package/dist/api/optimade.js +135 -0
  11. package/dist/brillouin/BrillouinZone.svelte +549 -0
  12. package/dist/brillouin/BrillouinZone.svelte.d.ts +83 -0
  13. package/dist/brillouin/BrillouinZoneControls.svelte +144 -0
  14. package/dist/brillouin/BrillouinZoneControls.svelte.d.ts +17 -0
  15. package/dist/brillouin/BrillouinZoneExportPane.svelte +146 -0
  16. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +15 -0
  17. package/dist/brillouin/BrillouinZoneInfoPane.svelte +146 -0
  18. package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +13 -0
  19. package/dist/brillouin/BrillouinZoneScene.svelte +476 -0
  20. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +48 -0
  21. package/dist/brillouin/BrillouinZoneTooltip.svelte +92 -0
  22. package/dist/brillouin/BrillouinZoneTooltip.svelte.d.ts +8 -0
  23. package/dist/brillouin/compute.d.ts +17 -0
  24. package/dist/brillouin/compute.js +426 -0
  25. package/dist/brillouin/index.d.ts +8 -0
  26. package/dist/brillouin/index.js +7 -0
  27. package/dist/brillouin/types.d.ts +43 -0
  28. package/dist/brillouin/types.js +1 -0
  29. package/dist/chempot-diagram/ChemPotDiagram.svelte +327 -0
  30. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
  31. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +846 -0
  32. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
  33. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +3193 -0
  34. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
  35. package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
  36. package/dist/chempot-diagram/async-compute.svelte.d.ts +3 -0
  37. package/dist/chempot-diagram/async-compute.svelte.js +78 -0
  38. package/dist/chempot-diagram/chempot-worker.d.ts +1 -0
  39. package/dist/chempot-diagram/chempot-worker.js +11 -0
  40. package/dist/chempot-diagram/color.d.ts +10 -0
  41. package/dist/chempot-diagram/color.js +32 -0
  42. package/dist/chempot-diagram/compute.d.ts +48 -0
  43. package/dist/chempot-diagram/compute.js +806 -0
  44. package/dist/chempot-diagram/index.d.ts +6 -0
  45. package/dist/chempot-diagram/index.js +6 -0
  46. package/dist/chempot-diagram/pointer.d.ts +16 -0
  47. package/dist/chempot-diagram/pointer.js +40 -0
  48. package/dist/chempot-diagram/temperature.d.ts +15 -0
  49. package/dist/chempot-diagram/temperature.js +34 -0
  50. package/dist/chempot-diagram/types.d.ts +81 -0
  51. package/dist/chempot-diagram/types.js +28 -0
  52. package/dist/colors/index.d.ts +47 -0
  53. package/dist/colors/index.js +203 -0
  54. package/dist/composition/BarChart.svelte +297 -0
  55. package/dist/composition/BarChart.svelte.d.ts +39 -0
  56. package/dist/composition/BubbleChart.svelte +218 -0
  57. package/dist/composition/BubbleChart.svelte.d.ts +28 -0
  58. package/dist/composition/Composition.svelte +165 -0
  59. package/dist/composition/Composition.svelte.d.ts +15 -0
  60. package/dist/composition/Formula.svelte +268 -0
  61. package/dist/composition/Formula.svelte.d.ts +19 -0
  62. package/dist/composition/FormulaFilter.svelte +1257 -0
  63. package/dist/composition/FormulaFilter.svelte.d.ts +51 -0
  64. package/dist/composition/PieChart.svelte +323 -0
  65. package/dist/composition/PieChart.svelte.d.ts +37 -0
  66. package/dist/composition/format.d.ts +15 -0
  67. package/dist/composition/format.js +109 -0
  68. package/dist/composition/index.d.ts +20 -0
  69. package/dist/composition/index.js +14 -0
  70. package/dist/composition/parse.d.ts +56 -0
  71. package/dist/composition/parse.js +474 -0
  72. package/dist/constants.d.ts +29 -0
  73. package/dist/constants.js +99 -0
  74. package/dist/controls.d.ts +14 -0
  75. package/dist/controls.js +30 -0
  76. package/dist/convex-hull/ConvexHull.svelte +157 -0
  77. package/dist/convex-hull/ConvexHull.svelte.d.ts +13 -0
  78. package/dist/convex-hull/ConvexHull2D.svelte +825 -0
  79. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +11 -0
  80. package/dist/convex-hull/ConvexHull3D.svelte +1801 -0
  81. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +8 -0
  82. package/dist/convex-hull/ConvexHull4D.svelte +1398 -0
  83. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +8 -0
  84. package/dist/convex-hull/ConvexHullControls.svelte +535 -0
  85. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +48 -0
  86. package/dist/convex-hull/ConvexHullInfoPane.svelte +125 -0
  87. package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +20 -0
  88. package/dist/convex-hull/ConvexHullStats.svelte +929 -0
  89. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +17 -0
  90. package/dist/convex-hull/ConvexHullTooltip.svelte +131 -0
  91. package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +33 -0
  92. package/dist/convex-hull/GasPressureControls.svelte +247 -0
  93. package/dist/convex-hull/GasPressureControls.svelte.d.ts +11 -0
  94. package/dist/convex-hull/StructurePopup.svelte +151 -0
  95. package/dist/convex-hull/StructurePopup.svelte.d.ts +18 -0
  96. package/dist/convex-hull/TemperatureSlider.svelte.d.ts +8 -0
  97. package/dist/convex-hull/barycentric-coords.d.ts +18 -0
  98. package/dist/convex-hull/barycentric-coords.js +182 -0
  99. package/dist/convex-hull/demo-temperature.d.ts +6 -0
  100. package/dist/convex-hull/demo-temperature.js +40 -0
  101. package/dist/convex-hull/gas-thermodynamics.d.ts +16 -0
  102. package/dist/convex-hull/gas-thermodynamics.js +314 -0
  103. package/dist/convex-hull/helpers.d.ts +114 -0
  104. package/dist/convex-hull/helpers.js +710 -0
  105. package/dist/convex-hull/index.d.ts +119 -0
  106. package/dist/convex-hull/index.js +58 -0
  107. package/dist/convex-hull/thermodynamics.d.ts +67 -0
  108. package/dist/convex-hull/thermodynamics.js +1752 -0
  109. package/dist/convex-hull/types.d.ts +162 -0
  110. package/dist/convex-hull/types.js +36 -0
  111. package/dist/coordination/CoordinationBarPlot.svelte +311 -0
  112. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +30 -0
  113. package/dist/coordination/calc-coordination.d.ts +15 -0
  114. package/dist/coordination/calc-coordination.js +63 -0
  115. package/dist/coordination/index.d.ts +8 -0
  116. package/dist/coordination/index.js +7 -0
  117. package/dist/effects.svelte.d.ts +12 -0
  118. package/dist/effects.svelte.js +37 -0
  119. package/dist/element/BohrAtom.svelte.d.ts +20 -0
  120. package/dist/element/ElementHeading.svelte +26 -0
  121. package/dist/element/ElementHeading.svelte.d.ts +8 -0
  122. package/dist/element/ElementPhoto.svelte +57 -0
  123. package/dist/element/ElementPhoto.svelte.d.ts +9 -0
  124. package/dist/element/ElementStats.svelte +80 -0
  125. package/dist/element/ElementStats.svelte.d.ts +8 -0
  126. package/dist/element/ElementTile.svelte +484 -0
  127. package/dist/element/ElementTile.svelte.d.ts +29 -0
  128. package/dist/element/Nucleus.svelte.d.ts +17 -0
  129. package/dist/element/data.d.ts +2 -0
  130. package/dist/element/data.js +2 -0
  131. package/dist/element/index.d.ts +8 -0
  132. package/dist/element/index.js +7 -0
  133. package/dist/element/types.d.ts +57 -0
  134. package/dist/element/types.js +1 -0
  135. package/dist/feedback/ClickFeedback.svelte +58 -0
  136. package/dist/feedback/ClickFeedback.svelte.d.ts +12 -0
  137. package/dist/feedback/DragOverlay.svelte +42 -0
  138. package/dist/feedback/DragOverlay.svelte.d.ts +7 -0
  139. package/dist/feedback/Spinner.svelte.d.ts +7 -0
  140. package/dist/feedback/StatusMessage.svelte.d.ts +9 -0
  141. package/dist/feedback/index.d.ts +4 -0
  142. package/dist/feedback/index.js +4 -0
  143. package/dist/fermi-surface/FermiSlice.svelte +189 -0
  144. package/dist/fermi-surface/FermiSlice.svelte.d.ts +24 -0
  145. package/dist/fermi-surface/FermiSurface.svelte +600 -0
  146. package/dist/fermi-surface/FermiSurface.svelte.d.ts +83 -0
  147. package/dist/fermi-surface/FermiSurfaceControls.svelte +448 -0
  148. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +35 -0
  149. package/dist/fermi-surface/FermiSurfaceScene.svelte +794 -0
  150. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +50 -0
  151. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +111 -0
  152. package/dist/fermi-surface/FermiSurfaceTooltip.svelte.d.ts +8 -0
  153. package/dist/fermi-surface/compute.d.ts +5 -0
  154. package/dist/fermi-surface/compute.js +538 -0
  155. package/dist/fermi-surface/constants.d.ts +9 -0
  156. package/dist/fermi-surface/constants.js +27 -0
  157. package/dist/fermi-surface/export.d.ts +5 -0
  158. package/dist/fermi-surface/export.js +50 -0
  159. package/dist/fermi-surface/index.d.ts +12 -0
  160. package/dist/fermi-surface/index.js +13 -0
  161. package/dist/fermi-surface/marching-cubes.d.ts +2 -0
  162. package/dist/fermi-surface/marching-cubes.js +2 -0
  163. package/dist/fermi-surface/parse.d.ts +2 -0
  164. package/dist/fermi-surface/parse.js +491 -0
  165. package/dist/fermi-surface/symmetry.d.ts +3 -0
  166. package/dist/fermi-surface/symmetry.js +46 -0
  167. package/dist/fermi-surface/types.d.ts +110 -0
  168. package/dist/fermi-surface/types.js +4 -0
  169. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1545 -0
  170. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
  171. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +225 -0
  172. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +30 -0
  173. package/dist/heatmap-matrix/index.d.ts +53 -0
  174. package/dist/heatmap-matrix/index.js +100 -0
  175. package/dist/heatmap-matrix/shared.d.ts +2 -0
  176. package/dist/heatmap-matrix/shared.js +4 -0
  177. package/dist/icons.d.ts +569 -0
  178. package/dist/icons.js +648 -0
  179. package/dist/index.d.ts +39 -0
  180. package/dist/index.js +39 -0
  181. package/dist/io/decompress.d.ts +11 -0
  182. package/dist/io/decompress.js +74 -0
  183. package/dist/io/export.d.ts +16 -0
  184. package/dist/io/export.js +316 -0
  185. package/dist/io/fetch.d.ts +5 -0
  186. package/dist/io/fetch.js +39 -0
  187. package/dist/io/file-drop.d.ts +7 -0
  188. package/dist/io/file-drop.js +43 -0
  189. package/dist/io/index.d.ts +7 -0
  190. package/dist/io/index.js +6 -0
  191. package/dist/io/is-binary.d.ts +1 -0
  192. package/dist/io/is-binary.js +20 -0
  193. package/dist/io/types.d.ts +8 -0
  194. package/dist/io/types.js +1 -0
  195. package/dist/io/url-drop.d.ts +2 -0
  196. package/dist/io/url-drop.js +123 -0
  197. package/dist/isosurface/Isosurface.svelte +285 -0
  198. package/dist/isosurface/Isosurface.svelte.d.ts +8 -0
  199. package/dist/isosurface/IsosurfaceControls.svelte +277 -0
  200. package/dist/isosurface/IsosurfaceControls.svelte.d.ts +9 -0
  201. package/dist/isosurface/index.d.ts +5 -0
  202. package/dist/isosurface/index.js +6 -0
  203. package/dist/isosurface/parse.d.ts +6 -0
  204. package/dist/isosurface/parse.js +553 -0
  205. package/dist/isosurface/slice.d.ts +11 -0
  206. package/dist/isosurface/slice.js +140 -0
  207. package/dist/isosurface/types.d.ts +56 -0
  208. package/dist/isosurface/types.js +227 -0
  209. package/dist/labels.d.ts +53 -0
  210. package/dist/labels.js +277 -0
  211. package/dist/layout/FullscreenToggle.svelte +50 -0
  212. package/dist/layout/FullscreenToggle.svelte.d.ts +7 -0
  213. package/dist/layout/InfoCard.svelte +120 -0
  214. package/dist/layout/InfoCard.svelte.d.ts +21 -0
  215. package/dist/layout/InfoTag.svelte +185 -0
  216. package/dist/layout/InfoTag.svelte.d.ts +19 -0
  217. package/dist/layout/PropertyFilter.svelte +246 -0
  218. package/dist/layout/PropertyFilter.svelte.d.ts +24 -0
  219. package/dist/layout/SettingsSection.svelte +148 -0
  220. package/dist/layout/SettingsSection.svelte.d.ts +17 -0
  221. package/dist/layout/SubpageGrid.svelte +82 -0
  222. package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
  223. package/dist/layout/fullscreen.d.ts +9 -0
  224. package/dist/layout/fullscreen.js +53 -0
  225. package/dist/layout/index.d.ts +10 -0
  226. package/dist/layout/index.js +8 -0
  227. package/dist/layout/json-tree/JsonNode.svelte +548 -0
  228. package/dist/layout/json-tree/JsonNode.svelte.d.ts +11 -0
  229. package/dist/layout/json-tree/JsonTree.svelte +1230 -0
  230. package/dist/layout/json-tree/JsonTree.svelte.d.ts +6 -0
  231. package/dist/layout/json-tree/JsonValue.svelte.d.ts +9 -0
  232. package/dist/layout/json-tree/index.d.ts +3 -0
  233. package/dist/layout/json-tree/index.js +3 -0
  234. package/dist/layout/json-tree/types.d.ts +74 -0
  235. package/dist/layout/json-tree/types.js +2 -0
  236. package/dist/layout/json-tree/utils.d.ts +29 -0
  237. package/dist/layout/json-tree/utils.js +641 -0
  238. package/dist/marching-cubes.d.ts +14 -0
  239. package/dist/marching-cubes.js +540 -0
  240. package/dist/math.d.ts +101 -0
  241. package/dist/math.js +905 -0
  242. package/dist/overlays/ContextMenu.svelte +162 -0
  243. package/dist/overlays/ContextMenu.svelte.d.ts +25 -0
  244. package/dist/overlays/CopyButton.svelte +45 -0
  245. package/dist/overlays/CopyButton.svelte.d.ts +8 -0
  246. package/dist/overlays/DragControlTab.svelte +98 -0
  247. package/dist/overlays/DragControlTab.svelte.d.ts +8 -0
  248. package/dist/overlays/DraggablePane.svelte +487 -0
  249. package/dist/overlays/DraggablePane.svelte.d.ts +36 -0
  250. package/dist/overlays/InfoPaneCards.svelte +149 -0
  251. package/dist/overlays/InfoPaneCards.svelte.d.ts +22 -0
  252. package/dist/overlays/index.d.ts +3 -0
  253. package/dist/overlays/index.js +3 -0
  254. package/dist/periodic-table/PeriodicTable.svelte +469 -0
  255. package/dist/periodic-table/PeriodicTable.svelte.d.ts +55 -0
  256. package/dist/periodic-table/PeriodicTableControls.svelte +557 -0
  257. package/dist/periodic-table/PeriodicTableControls.svelte.d.ts +24 -0
  258. package/dist/periodic-table/PropertySelect.svelte +37 -0
  259. package/dist/periodic-table/PropertySelect.svelte.d.ts +13 -0
  260. package/dist/periodic-table/TableInset.svelte.d.ts +9 -0
  261. package/dist/periodic-table/index.d.ts +10 -0
  262. package/dist/periodic-table/index.js +4 -0
  263. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +1086 -0
  264. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +44 -0
  265. package/dist/phase-diagram/PhaseDiagramControls.svelte +444 -0
  266. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +30 -0
  267. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +126 -0
  268. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
  269. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +184 -0
  270. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +19 -0
  271. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +391 -0
  272. package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +16 -0
  273. package/dist/phase-diagram/TdbInfoPanel.svelte +203 -0
  274. package/dist/phase-diagram/TdbInfoPanel.svelte.d.ts +12 -0
  275. package/dist/phase-diagram/build-diagram.d.ts +11 -0
  276. package/dist/phase-diagram/build-diagram.js +160 -0
  277. package/dist/phase-diagram/colors.d.ts +35 -0
  278. package/dist/phase-diagram/colors.js +51 -0
  279. package/dist/phase-diagram/diagram-input.d.ts +29 -0
  280. package/dist/phase-diagram/diagram-input.js +3 -0
  281. package/dist/phase-diagram/index.d.ts +13 -0
  282. package/dist/phase-diagram/index.js +11 -0
  283. package/dist/phase-diagram/parse.d.ts +55 -0
  284. package/dist/phase-diagram/parse.js +272 -0
  285. package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
  286. package/dist/phase-diagram/svg-to-diagram.js +867 -0
  287. package/dist/phase-diagram/types.d.ts +93 -0
  288. package/dist/phase-diagram/types.js +1 -0
  289. package/dist/phase-diagram/utils.d.ts +118 -0
  290. package/dist/phase-diagram/utils.js +604 -0
  291. package/dist/plot/AxisLabel.svelte +51 -0
  292. package/dist/plot/AxisLabel.svelte.d.ts +16 -0
  293. package/dist/plot/BarPlot.svelte +2113 -0
  294. package/dist/plot/BarPlot.svelte.d.ts +84 -0
  295. package/dist/plot/BarPlotControls.svelte +66 -0
  296. package/dist/plot/BarPlotControls.svelte.d.ts +18 -0
  297. package/dist/plot/BinnedScatterPlot.svelte +1114 -0
  298. package/dist/plot/BinnedScatterPlot.svelte.d.ts +66 -0
  299. package/dist/plot/ColorBar.svelte +721 -0
  300. package/dist/plot/ColorBar.svelte.d.ts +31 -0
  301. package/dist/plot/ColorScaleSelect.svelte +54 -0
  302. package/dist/plot/ColorScaleSelect.svelte.d.ts +15 -0
  303. package/dist/plot/ElementScatter.svelte +63 -0
  304. package/dist/plot/ElementScatter.svelte.d.ts +14 -0
  305. package/dist/plot/FillArea.svelte.d.ts +21 -0
  306. package/dist/plot/Histogram.svelte +1558 -0
  307. package/dist/plot/Histogram.svelte.d.ts +50 -0
  308. package/dist/plot/HistogramControls.svelte +212 -0
  309. package/dist/plot/HistogramControls.svelte.d.ts +22 -0
  310. package/dist/plot/InteractiveAxisLabel.svelte +96 -0
  311. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +14 -0
  312. package/dist/plot/Line.svelte +84 -0
  313. package/dist/plot/Line.svelte.d.ts +15 -0
  314. package/dist/plot/PlotAxis.svelte +169 -0
  315. package/dist/plot/PlotAxis.svelte.d.ts +24 -0
  316. package/dist/plot/PlotControls.svelte +537 -0
  317. package/dist/plot/PlotControls.svelte.d.ts +4 -0
  318. package/dist/plot/PlotLegend.svelte +569 -0
  319. package/dist/plot/PlotLegend.svelte.d.ts +29 -0
  320. package/dist/plot/PlotTooltip.svelte +67 -0
  321. package/dist/plot/PlotTooltip.svelte.d.ts +17 -0
  322. package/dist/plot/PortalSelect.svelte +253 -0
  323. package/dist/plot/PortalSelect.svelte.d.ts +16 -0
  324. package/dist/plot/ReferenceLine.svelte.d.ts +20 -0
  325. package/dist/plot/ReferenceLine3D.svelte +156 -0
  326. package/dist/plot/ReferenceLine3D.svelte.d.ts +14 -0
  327. package/dist/plot/ReferencePlane.svelte +175 -0
  328. package/dist/plot/ReferencePlane.svelte.d.ts +14 -0
  329. package/dist/plot/ScatterPlot.svelte +2778 -0
  330. package/dist/plot/ScatterPlot.svelte.d.ts +96 -0
  331. package/dist/plot/ScatterPlot3D.svelte +529 -0
  332. package/dist/plot/ScatterPlot3D.svelte.d.ts +95 -0
  333. package/dist/plot/ScatterPlot3DControls.svelte +437 -0
  334. package/dist/plot/ScatterPlot3DControls.svelte.d.ts +20 -0
  335. package/dist/plot/ScatterPlot3DScene.svelte +912 -0
  336. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +74 -0
  337. package/dist/plot/ScatterPlotControls.svelte +306 -0
  338. package/dist/plot/ScatterPlotControls.svelte.d.ts +17 -0
  339. package/dist/plot/ScatterPoint.svelte +182 -0
  340. package/dist/plot/ScatterPoint.svelte.d.ts +22 -0
  341. package/dist/plot/SpacegroupBarPlot.svelte +293 -0
  342. package/dist/plot/SpacegroupBarPlot.svelte.d.ts +9 -0
  343. package/dist/plot/Surface3D.svelte +197 -0
  344. package/dist/plot/Surface3D.svelte.d.ts +13 -0
  345. package/dist/plot/ZeroLines.svelte +97 -0
  346. package/dist/plot/ZeroLines.svelte.d.ts +33 -0
  347. package/dist/plot/ZoomRect.svelte +23 -0
  348. package/dist/plot/ZoomRect.svelte.d.ts +8 -0
  349. package/dist/plot/adaptive-density.d.ts +69 -0
  350. package/dist/plot/adaptive-density.js +191 -0
  351. package/dist/plot/auto-place.d.ts +43 -0
  352. package/dist/plot/auto-place.js +122 -0
  353. package/dist/plot/axis-utils.d.ts +19 -0
  354. package/dist/plot/axis-utils.js +78 -0
  355. package/dist/plot/binned-scatter-types.d.ts +59 -0
  356. package/dist/plot/binned-scatter-types.js +1 -0
  357. package/dist/plot/data-cleaning.d.ts +37 -0
  358. package/dist/plot/data-cleaning.js +855 -0
  359. package/dist/plot/data-transform.d.ts +16 -0
  360. package/dist/plot/data-transform.js +45 -0
  361. package/dist/plot/defaults.d.ts +19 -0
  362. package/dist/plot/defaults.js +9 -0
  363. package/dist/plot/fill-utils.d.ts +46 -0
  364. package/dist/plot/fill-utils.js +322 -0
  365. package/dist/plot/hover-lock.svelte.d.ts +14 -0
  366. package/dist/plot/hover-lock.svelte.js +46 -0
  367. package/dist/plot/index.d.ts +41 -0
  368. package/dist/plot/index.js +39 -0
  369. package/dist/plot/interactions.d.ts +12 -0
  370. package/dist/plot/interactions.js +101 -0
  371. package/dist/plot/layout.d.ts +78 -0
  372. package/dist/plot/layout.js +273 -0
  373. package/dist/plot/reference-line.d.ts +60 -0
  374. package/dist/plot/reference-line.js +314 -0
  375. package/dist/plot/scales.d.ts +48 -0
  376. package/dist/plot/scales.js +481 -0
  377. package/dist/plot/svg.d.ts +1 -0
  378. package/dist/plot/svg.js +11 -0
  379. package/dist/plot/types.d.ts +831 -0
  380. package/dist/plot/types.js +99 -0
  381. package/dist/plot/utils/label-placement.d.ts +68 -0
  382. package/dist/plot/utils/label-placement.js +326 -0
  383. package/dist/plot/utils/series-visibility.d.ts +15 -0
  384. package/dist/plot/utils/series-visibility.js +85 -0
  385. package/dist/plot/utils.d.ts +1 -0
  386. package/dist/plot/utils.js +14 -0
  387. package/dist/rdf/RdfPlot.svelte +247 -0
  388. package/dist/rdf/RdfPlot.svelte.d.ts +27 -0
  389. package/dist/rdf/calc-rdf.d.ts +4 -0
  390. package/dist/rdf/calc-rdf.js +111 -0
  391. package/dist/rdf/index.d.ts +23 -0
  392. package/dist/rdf/index.js +2 -0
  393. package/dist/sanitize.d.ts +6 -0
  394. package/dist/sanitize.js +116 -0
  395. package/dist/settings.d.ts +255 -0
  396. package/dist/settings.js +1132 -0
  397. package/dist/spectral/Bands.svelte +1040 -0
  398. package/dist/spectral/Bands.svelte.d.ts +40 -0
  399. package/dist/spectral/BandsAndDos.svelte +134 -0
  400. package/dist/spectral/BandsAndDos.svelte.d.ts +18 -0
  401. package/dist/spectral/BrillouinBandsDos.svelte +252 -0
  402. package/dist/spectral/BrillouinBandsDos.svelte.d.ts +20 -0
  403. package/dist/spectral/Dos.svelte +697 -0
  404. package/dist/spectral/Dos.svelte.d.ts +29 -0
  405. package/dist/spectral/helpers.d.ts +119 -0
  406. package/dist/spectral/helpers.js +1032 -0
  407. package/dist/spectral/index.d.ts +6 -0
  408. package/dist/spectral/index.js +6 -0
  409. package/dist/spectral/types.d.ts +84 -0
  410. package/dist/spectral/types.js +2 -0
  411. package/dist/state.svelte.d.ts +25 -0
  412. package/dist/state.svelte.js +45 -0
  413. package/dist/structure/Arrow.svelte +72 -0
  414. package/dist/structure/Arrow.svelte.d.ts +15 -0
  415. package/dist/structure/AtomLegend.svelte +815 -0
  416. package/dist/structure/AtomLegend.svelte.d.ts +35 -0
  417. package/dist/structure/Bond.svelte +140 -0
  418. package/dist/structure/Bond.svelte.d.ts +9 -0
  419. package/dist/structure/CanvasTooltip.svelte +33 -0
  420. package/dist/structure/CanvasTooltip.svelte.d.ts +12 -0
  421. package/dist/structure/CellSelect.svelte +349 -0
  422. package/dist/structure/CellSelect.svelte.d.ts +13 -0
  423. package/dist/structure/Cylinder.svelte +45 -0
  424. package/dist/structure/Cylinder.svelte.d.ts +10 -0
  425. package/dist/structure/Lattice.svelte +196 -0
  426. package/dist/structure/Lattice.svelte.d.ts +17 -0
  427. package/dist/structure/Structure.svelte +2248 -0
  428. package/dist/structure/Structure.svelte.d.ts +89 -0
  429. package/dist/structure/StructureControls.svelte +1273 -0
  430. package/dist/structure/StructureControls.svelte.d.ts +31 -0
  431. package/dist/structure/StructureExportPane.svelte +252 -0
  432. package/dist/structure/StructureExportPane.svelte.d.ts +17 -0
  433. package/dist/structure/StructureInfoPane.svelte +737 -0
  434. package/dist/structure/StructureInfoPane.svelte.d.ts +19 -0
  435. package/dist/structure/StructureScene.svelte +2255 -0
  436. package/dist/structure/StructureScene.svelte.d.ts +111 -0
  437. package/dist/structure/atom-properties.d.ts +37 -0
  438. package/dist/structure/atom-properties.js +200 -0
  439. package/dist/structure/bond-order-perception.d.ts +13 -0
  440. package/dist/structure/bond-order-perception.js +384 -0
  441. package/dist/structure/bonding.d.ts +68 -0
  442. package/dist/structure/bonding.js +696 -0
  443. package/dist/structure/export.d.ts +20 -0
  444. package/dist/structure/export.js +727 -0
  445. package/dist/structure/index.d.ts +126 -0
  446. package/dist/structure/index.js +169 -0
  447. package/dist/structure/label-placement.d.ts +14 -0
  448. package/dist/structure/label-placement.js +72 -0
  449. package/dist/structure/measure.d.ts +6 -0
  450. package/dist/structure/measure.js +29 -0
  451. package/dist/structure/parse.d.ts +66 -0
  452. package/dist/structure/parse.js +1392 -0
  453. package/dist/structure/partial-occupancy.d.ts +25 -0
  454. package/dist/structure/partial-occupancy.js +99 -0
  455. package/dist/structure/pbc.d.ts +9 -0
  456. package/dist/structure/pbc.js +123 -0
  457. package/dist/structure/supercell.d.ts +8 -0
  458. package/dist/structure/supercell.js +170 -0
  459. package/dist/structure/validation.d.ts +2 -0
  460. package/dist/structure/validation.js +10 -0
  461. package/dist/symmetry/SymmetryStats.svelte +226 -0
  462. package/dist/symmetry/SymmetryStats.svelte.d.ts +21 -0
  463. package/dist/symmetry/WyckoffTable.svelte +120 -0
  464. package/dist/symmetry/WyckoffTable.svelte.d.ts +11 -0
  465. package/dist/symmetry/cell-transform.d.ts +12 -0
  466. package/dist/symmetry/cell-transform.js +91 -0
  467. package/dist/symmetry/index.d.ts +43 -0
  468. package/dist/symmetry/index.js +228 -0
  469. package/dist/symmetry/spacegroups.d.ts +9 -0
  470. package/dist/symmetry/spacegroups.js +394 -0
  471. package/dist/table/HeatmapTable.svelte +1833 -0
  472. package/dist/table/HeatmapTable.svelte.d.ts +49 -0
  473. package/dist/table/ToggleMenu.svelte +385 -0
  474. package/dist/table/ToggleMenu.svelte.d.ts +11 -0
  475. package/dist/table/index.d.ts +74 -0
  476. package/dist/table/index.js +38 -0
  477. package/dist/theme/ThemeControl.svelte +53 -0
  478. package/dist/theme/ThemeControl.svelte.d.ts +9 -0
  479. package/dist/theme/index.d.ts +29 -0
  480. package/dist/theme/index.js +79 -0
  481. package/dist/time.d.ts +4 -0
  482. package/dist/time.js +70 -0
  483. package/dist/tooltip/TooltipContent.svelte +58 -0
  484. package/dist/tooltip/TooltipContent.svelte.d.ts +31 -0
  485. package/dist/tooltip/index.d.ts +2 -0
  486. package/dist/tooltip/index.js +1 -0
  487. package/dist/tooltip/types.d.ts +8 -0
  488. package/dist/tooltip/types.js +1 -0
  489. package/dist/trajectory/Trajectory.svelte +1545 -0
  490. package/dist/trajectory/Trajectory.svelte.d.ts +77 -0
  491. package/dist/trajectory/TrajectoryError.svelte +128 -0
  492. package/dist/trajectory/TrajectoryError.svelte.d.ts +13 -0
  493. package/dist/trajectory/TrajectoryExportPane.svelte +357 -0
  494. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +17 -0
  495. package/dist/trajectory/TrajectoryInfoPane.svelte +313 -0
  496. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +17 -0
  497. package/dist/trajectory/constants.d.ts +6 -0
  498. package/dist/trajectory/constants.js +7 -0
  499. package/dist/trajectory/extract.d.ts +5 -0
  500. package/dist/trajectory/extract.js +162 -0
  501. package/dist/trajectory/format-detect.d.ts +9 -0
  502. package/dist/trajectory/format-detect.js +76 -0
  503. package/dist/trajectory/frame-reader.d.ts +17 -0
  504. package/dist/trajectory/frame-reader.js +332 -0
  505. package/dist/trajectory/helpers.d.ts +15 -0
  506. package/dist/trajectory/helpers.js +164 -0
  507. package/dist/trajectory/index.d.ts +63 -0
  508. package/dist/trajectory/index.js +126 -0
  509. package/dist/trajectory/parse/ase.d.ts +2 -0
  510. package/dist/trajectory/parse/ase.js +73 -0
  511. package/dist/trajectory/parse/hdf5.d.ts +2 -0
  512. package/dist/trajectory/parse/hdf5.js +127 -0
  513. package/dist/trajectory/parse/index.d.ts +12 -0
  514. package/dist/trajectory/parse/index.js +298 -0
  515. package/dist/trajectory/parse/lammps.d.ts +5 -0
  516. package/dist/trajectory/parse/lammps.js +179 -0
  517. package/dist/trajectory/parse/vasp.d.ts +2 -0
  518. package/dist/trajectory/parse/vasp.js +68 -0
  519. package/dist/trajectory/parse/xyz.d.ts +2 -0
  520. package/dist/trajectory/parse/xyz.js +110 -0
  521. package/dist/trajectory/plotting.d.ts +28 -0
  522. package/dist/trajectory/plotting.js +423 -0
  523. package/dist/trajectory/types.d.ts +11 -0
  524. package/dist/trajectory/types.js +1 -0
  525. package/dist/utils.d.ts +6 -0
  526. package/dist/utils.js +45 -0
  527. package/dist/xrd/XrdPlot.svelte +615 -0
  528. package/dist/xrd/XrdPlot.svelte.d.ts +28 -0
  529. package/dist/xrd/broadening.d.ts +20 -0
  530. package/dist/xrd/broadening.js +97 -0
  531. package/dist/xrd/calc-xrd.d.ts +37 -0
  532. package/dist/xrd/calc-xrd.js +336 -0
  533. package/dist/xrd/index.d.ts +37 -0
  534. package/dist/xrd/index.js +4 -0
  535. package/dist/xrd/parse.d.ts +13 -0
  536. package/dist/xrd/parse.js +749 -0
  537. package/license +1 -1
  538. package/package.json +232 -1457
  539. package/readme.md +98 -171
  540. package/.vscode/launch.json +0 -13
  541. package/.vscodeignore +0 -7
  542. package/dist/assets/STLExporter-BpTH3YHE.js +0 -8
  543. package/dist/assets/browser-DdDecX_W.js +0 -1
  544. package/dist/assets/export-qgn-H9y6.js +0 -2
  545. package/dist/assets/main-DiKYzti2.css +0 -1
  546. package/dist/assets/moyo_wasm_bg-0ocwg7xY.wasm +0 -0
  547. package/dist/extension.js +0 -31293
  548. package/dist/src/lib/FilePicker.svelte +0 -360
  549. package/dist/src/lib/MillerIndexInput.svelte +0 -66
  550. package/dist/src/lib/api/mp.ts +0 -26
  551. package/dist/src/lib/api/optimade.ts +0 -204
  552. package/dist/src/lib/brillouin/BrillouinZone.svelte +0 -549
  553. package/dist/src/lib/brillouin/BrillouinZoneControls.svelte +0 -144
  554. package/dist/src/lib/brillouin/BrillouinZoneExportPane.svelte +0 -146
  555. package/dist/src/lib/brillouin/BrillouinZoneInfoPane.svelte +0 -146
  556. package/dist/src/lib/brillouin/BrillouinZoneScene.svelte +0 -476
  557. package/dist/src/lib/brillouin/BrillouinZoneTooltip.svelte +0 -92
  558. package/dist/src/lib/brillouin/compute.ts +0 -529
  559. package/dist/src/lib/brillouin/index.ts +0 -8
  560. package/dist/src/lib/brillouin/types.ts +0 -51
  561. package/dist/src/lib/chempot-diagram/ChemPotDiagram.svelte +0 -327
  562. package/dist/src/lib/chempot-diagram/ChemPotDiagram2D.svelte +0 -846
  563. package/dist/src/lib/chempot-diagram/ChemPotDiagram3D.svelte +0 -3193
  564. package/dist/src/lib/chempot-diagram/async-compute.svelte.ts +0 -94
  565. package/dist/src/lib/chempot-diagram/chempot-worker.ts +0 -11
  566. package/dist/src/lib/chempot-diagram/color.ts +0 -42
  567. package/dist/src/lib/chempot-diagram/compute.ts +0 -1014
  568. package/dist/src/lib/chempot-diagram/index.ts +0 -6
  569. package/dist/src/lib/chempot-diagram/pointer.ts +0 -56
  570. package/dist/src/lib/chempot-diagram/temperature.ts +0 -77
  571. package/dist/src/lib/chempot-diagram/types.ts +0 -130
  572. package/dist/src/lib/colors/index.ts +0 -249
  573. package/dist/src/lib/composition/BarChart.svelte +0 -297
  574. package/dist/src/lib/composition/BubbleChart.svelte +0 -218
  575. package/dist/src/lib/composition/Composition.svelte +0 -165
  576. package/dist/src/lib/composition/Formula.svelte +0 -268
  577. package/dist/src/lib/composition/FormulaFilter.svelte +0 -1257
  578. package/dist/src/lib/composition/PieChart.svelte +0 -323
  579. package/dist/src/lib/composition/format.ts +0 -155
  580. package/dist/src/lib/composition/index.ts +0 -37
  581. package/dist/src/lib/composition/parse.ts +0 -605
  582. package/dist/src/lib/constants.ts +0 -134
  583. package/dist/src/lib/controls.ts +0 -42
  584. package/dist/src/lib/convex-hull/ConvexHull.svelte +0 -157
  585. package/dist/src/lib/convex-hull/ConvexHull2D.svelte +0 -825
  586. package/dist/src/lib/convex-hull/ConvexHull3D.svelte +0 -1801
  587. package/dist/src/lib/convex-hull/ConvexHull4D.svelte +0 -1398
  588. package/dist/src/lib/convex-hull/ConvexHullControls.svelte +0 -535
  589. package/dist/src/lib/convex-hull/ConvexHullInfoPane.svelte +0 -125
  590. package/dist/src/lib/convex-hull/ConvexHullStats.svelte +0 -929
  591. package/dist/src/lib/convex-hull/ConvexHullTooltip.svelte +0 -131
  592. package/dist/src/lib/convex-hull/GasPressureControls.svelte +0 -247
  593. package/dist/src/lib/convex-hull/StructurePopup.svelte +0 -151
  594. package/dist/src/lib/convex-hull/barycentric-coords.ts +0 -246
  595. package/dist/src/lib/convex-hull/demo-temperature.ts +0 -63
  596. package/dist/src/lib/convex-hull/gas-thermodynamics.ts +0 -405
  597. package/dist/src/lib/convex-hull/helpers.ts +0 -932
  598. package/dist/src/lib/convex-hull/index.ts +0 -202
  599. package/dist/src/lib/convex-hull/thermodynamics.ts +0 -2192
  600. package/dist/src/lib/convex-hull/types.ts +0 -267
  601. package/dist/src/lib/coordination/CoordinationBarPlot.svelte +0 -311
  602. package/dist/src/lib/coordination/calc-coordination.ts +0 -93
  603. package/dist/src/lib/coordination/index.ts +0 -9
  604. package/dist/src/lib/effects.svelte.ts +0 -48
  605. package/dist/src/lib/element/ElementHeading.svelte +0 -26
  606. package/dist/src/lib/element/ElementPhoto.svelte +0 -57
  607. package/dist/src/lib/element/ElementStats.svelte +0 -80
  608. package/dist/src/lib/element/ElementTile.svelte +0 -484
  609. package/dist/src/lib/element/data.ts +0 -14
  610. package/dist/src/lib/element/index.ts +0 -8
  611. package/dist/src/lib/element/types.ts +0 -62
  612. package/dist/src/lib/feedback/ClickFeedback.svelte +0 -58
  613. package/dist/src/lib/feedback/DragOverlay.svelte +0 -42
  614. package/dist/src/lib/feedback/index.ts +0 -4
  615. package/dist/src/lib/fermi-surface/FermiSlice.svelte +0 -189
  616. package/dist/src/lib/fermi-surface/FermiSurface.svelte +0 -600
  617. package/dist/src/lib/fermi-surface/FermiSurfaceControls.svelte +0 -448
  618. package/dist/src/lib/fermi-surface/FermiSurfaceScene.svelte +0 -794
  619. package/dist/src/lib/fermi-surface/FermiSurfaceTooltip.svelte +0 -111
  620. package/dist/src/lib/fermi-surface/compute.ts +0 -728
  621. package/dist/src/lib/fermi-surface/constants.ts +0 -32
  622. package/dist/src/lib/fermi-surface/export.ts +0 -64
  623. package/dist/src/lib/fermi-surface/index.ts +0 -14
  624. package/dist/src/lib/fermi-surface/marching-cubes.ts +0 -3
  625. package/dist/src/lib/fermi-surface/parse.ts +0 -574
  626. package/dist/src/lib/fermi-surface/symmetry.ts +0 -56
  627. package/dist/src/lib/fermi-surface/types.ts +0 -159
  628. package/dist/src/lib/heatmap-matrix/HeatmapMatrix.svelte +0 -1545
  629. package/dist/src/lib/heatmap-matrix/HeatmapMatrixControls.svelte +0 -225
  630. package/dist/src/lib/heatmap-matrix/index.ts +0 -167
  631. package/dist/src/lib/heatmap-matrix/shared.ts +0 -7
  632. package/dist/src/lib/icons.ts +0 -650
  633. package/dist/src/lib/index.ts +0 -61
  634. package/dist/src/lib/io/decompress.ts +0 -92
  635. package/dist/src/lib/io/export.ts +0 -385
  636. package/dist/src/lib/io/fetch.ts +0 -46
  637. package/dist/src/lib/io/file-drop.ts +0 -51
  638. package/dist/src/lib/io/index.ts +0 -7
  639. package/dist/src/lib/io/is-binary.ts +0 -24
  640. package/dist/src/lib/io/types.ts +0 -8
  641. package/dist/src/lib/io/url-drop.ts +0 -141
  642. package/dist/src/lib/isosurface/Isosurface.svelte +0 -285
  643. package/dist/src/lib/isosurface/IsosurfaceControls.svelte +0 -277
  644. package/dist/src/lib/isosurface/index.ts +0 -7
  645. package/dist/src/lib/isosurface/parse.ts +0 -656
  646. package/dist/src/lib/isosurface/slice.ts +0 -175
  647. package/dist/src/lib/isosurface/types.ts +0 -309
  648. package/dist/src/lib/labels.ts +0 -320
  649. package/dist/src/lib/layout/FullscreenToggle.svelte +0 -50
  650. package/dist/src/lib/layout/InfoCard.svelte +0 -120
  651. package/dist/src/lib/layout/InfoTag.svelte +0 -185
  652. package/dist/src/lib/layout/PropertyFilter.svelte +0 -246
  653. package/dist/src/lib/layout/SettingsSection.svelte +0 -148
  654. package/dist/src/lib/layout/SubpageGrid.svelte +0 -82
  655. package/dist/src/lib/layout/fullscreen.ts +0 -65
  656. package/dist/src/lib/layout/index.ts +0 -11
  657. package/dist/src/lib/layout/json-tree/JsonNode.svelte +0 -548
  658. package/dist/src/lib/layout/json-tree/JsonTree.svelte +0 -1230
  659. package/dist/src/lib/layout/json-tree/index.ts +0 -3
  660. package/dist/src/lib/layout/json-tree/types.ts +0 -126
  661. package/dist/src/lib/layout/json-tree/utils.ts +0 -682
  662. package/dist/src/lib/marching-cubes.ts +0 -614
  663. package/dist/src/lib/math.ts +0 -1081
  664. package/dist/src/lib/overlays/ContextMenu.svelte +0 -162
  665. package/dist/src/lib/overlays/CopyButton.svelte +0 -45
  666. package/dist/src/lib/overlays/DragControlTab.svelte +0 -98
  667. package/dist/src/lib/overlays/DraggablePane.svelte +0 -487
  668. package/dist/src/lib/overlays/InfoPaneCards.svelte +0 -149
  669. package/dist/src/lib/overlays/index.ts +0 -3
  670. package/dist/src/lib/periodic-table/PeriodicTable.svelte +0 -469
  671. package/dist/src/lib/periodic-table/PeriodicTableControls.svelte +0 -557
  672. package/dist/src/lib/periodic-table/PropertySelect.svelte +0 -37
  673. package/dist/src/lib/periodic-table/index.ts +0 -12
  674. package/dist/src/lib/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +0 -1086
  675. package/dist/src/lib/phase-diagram/PhaseDiagramControls.svelte +0 -444
  676. package/dist/src/lib/phase-diagram/PhaseDiagramEditorPane.svelte +0 -126
  677. package/dist/src/lib/phase-diagram/PhaseDiagramExportPane.svelte +0 -184
  678. package/dist/src/lib/phase-diagram/PhaseDiagramTooltip.svelte +0 -391
  679. package/dist/src/lib/phase-diagram/TdbInfoPanel.svelte +0 -203
  680. package/dist/src/lib/phase-diagram/build-diagram.ts +0 -186
  681. package/dist/src/lib/phase-diagram/colors.ts +0 -58
  682. package/dist/src/lib/phase-diagram/diagram-input.ts +0 -40
  683. package/dist/src/lib/phase-diagram/index.ts +0 -13
  684. package/dist/src/lib/phase-diagram/parse.ts +0 -348
  685. package/dist/src/lib/phase-diagram/svg-to-diagram.ts +0 -1023
  686. package/dist/src/lib/phase-diagram/types.ts +0 -144
  687. package/dist/src/lib/phase-diagram/utils.ts +0 -775
  688. package/dist/src/lib/plot/AxisLabel.svelte +0 -51
  689. package/dist/src/lib/plot/BarPlot.svelte +0 -2113
  690. package/dist/src/lib/plot/BarPlotControls.svelte +0 -66
  691. package/dist/src/lib/plot/BinnedScatterPlot.svelte +0 -1114
  692. package/dist/src/lib/plot/ColorBar.svelte +0 -721
  693. package/dist/src/lib/plot/ColorScaleSelect.svelte +0 -54
  694. package/dist/src/lib/plot/ElementScatter.svelte +0 -63
  695. package/dist/src/lib/plot/Histogram.svelte +0 -1558
  696. package/dist/src/lib/plot/HistogramControls.svelte +0 -212
  697. package/dist/src/lib/plot/InteractiveAxisLabel.svelte +0 -96
  698. package/dist/src/lib/plot/Line.svelte +0 -84
  699. package/dist/src/lib/plot/PlotAxis.svelte +0 -169
  700. package/dist/src/lib/plot/PlotControls.svelte +0 -537
  701. package/dist/src/lib/plot/PlotLegend.svelte +0 -569
  702. package/dist/src/lib/plot/PlotTooltip.svelte +0 -67
  703. package/dist/src/lib/plot/PortalSelect.svelte +0 -253
  704. package/dist/src/lib/plot/ReferenceLine3D.svelte +0 -156
  705. package/dist/src/lib/plot/ReferencePlane.svelte +0 -175
  706. package/dist/src/lib/plot/ScatterPlot.svelte +0 -2778
  707. package/dist/src/lib/plot/ScatterPlot3D.svelte +0 -529
  708. package/dist/src/lib/plot/ScatterPlot3DControls.svelte +0 -437
  709. package/dist/src/lib/plot/ScatterPlot3DScene.svelte +0 -912
  710. package/dist/src/lib/plot/ScatterPlotControls.svelte +0 -306
  711. package/dist/src/lib/plot/ScatterPoint.svelte +0 -182
  712. package/dist/src/lib/plot/SpacegroupBarPlot.svelte +0 -293
  713. package/dist/src/lib/plot/Surface3D.svelte +0 -197
  714. package/dist/src/lib/plot/ZeroLines.svelte +0 -97
  715. package/dist/src/lib/plot/ZoomRect.svelte +0 -23
  716. package/dist/src/lib/plot/adaptive-density.ts +0 -316
  717. package/dist/src/lib/plot/auto-place.ts +0 -184
  718. package/dist/src/lib/plot/axis-utils.ts +0 -122
  719. package/dist/src/lib/plot/binned-scatter-types.ts +0 -83
  720. package/dist/src/lib/plot/data-cleaning.ts +0 -1069
  721. package/dist/src/lib/plot/data-transform.ts +0 -69
  722. package/dist/src/lib/plot/defaults.ts +0 -9
  723. package/dist/src/lib/plot/fill-utils.ts +0 -494
  724. package/dist/src/lib/plot/hover-lock.svelte.ts +0 -60
  725. package/dist/src/lib/plot/index.ts +0 -53
  726. package/dist/src/lib/plot/interactions.ts +0 -119
  727. package/dist/src/lib/plot/layout.ts +0 -425
  728. package/dist/src/lib/plot/reference-line.ts +0 -426
  729. package/dist/src/lib/plot/scales.ts +0 -654
  730. package/dist/src/lib/plot/svg.ts +0 -23
  731. package/dist/src/lib/plot/types.ts +0 -1144
  732. package/dist/src/lib/plot/utils/label-placement.ts +0 -541
  733. package/dist/src/lib/plot/utils/series-visibility.ts +0 -140
  734. package/dist/src/lib/plot/utils.ts +0 -11
  735. package/dist/src/lib/rdf/RdfPlot.svelte +0 -247
  736. package/dist/src/lib/rdf/calc-rdf.ts +0 -167
  737. package/dist/src/lib/rdf/index.ts +0 -27
  738. package/dist/src/lib/sanitize.ts +0 -126
  739. package/dist/src/lib/settings.ts +0 -1479
  740. package/dist/src/lib/spectral/Bands.svelte +0 -1040
  741. package/dist/src/lib/spectral/BandsAndDos.svelte +0 -134
  742. package/dist/src/lib/spectral/BrillouinBandsDos.svelte +0 -252
  743. package/dist/src/lib/spectral/Dos.svelte +0 -697
  744. package/dist/src/lib/spectral/helpers.ts +0 -1381
  745. package/dist/src/lib/spectral/index.ts +0 -8
  746. package/dist/src/lib/spectral/types.ts +0 -112
  747. package/dist/src/lib/state.svelte.ts +0 -64
  748. package/dist/src/lib/structure/Arrow.svelte +0 -72
  749. package/dist/src/lib/structure/AtomLegend.svelte +0 -815
  750. package/dist/src/lib/structure/Bond.svelte +0 -140
  751. package/dist/src/lib/structure/CanvasTooltip.svelte +0 -33
  752. package/dist/src/lib/structure/CellSelect.svelte +0 -349
  753. package/dist/src/lib/structure/Cylinder.svelte +0 -45
  754. package/dist/src/lib/structure/Lattice.svelte +0 -196
  755. package/dist/src/lib/structure/Structure.svelte +0 -2248
  756. package/dist/src/lib/structure/StructureControls.svelte +0 -1273
  757. package/dist/src/lib/structure/StructureExportPane.svelte +0 -252
  758. package/dist/src/lib/structure/StructureInfoPane.svelte +0 -737
  759. package/dist/src/lib/structure/StructureScene.svelte +0 -2255
  760. package/dist/src/lib/structure/atom-properties.ts +0 -316
  761. package/dist/src/lib/structure/bond-order-perception.ts +0 -447
  762. package/dist/src/lib/structure/bonding.ts +0 -944
  763. package/dist/src/lib/structure/export.ts +0 -861
  764. package/dist/src/lib/structure/index.ts +0 -291
  765. package/dist/src/lib/structure/label-placement.ts +0 -130
  766. package/dist/src/lib/structure/measure.ts +0 -45
  767. package/dist/src/lib/structure/parse.ts +0 -1705
  768. package/dist/src/lib/structure/partial-occupancy.ts +0 -183
  769. package/dist/src/lib/structure/pbc.ts +0 -164
  770. package/dist/src/lib/structure/supercell.ts +0 -226
  771. package/dist/src/lib/structure/validation.ts +0 -11
  772. package/dist/src/lib/symmetry/SymmetryStats.svelte +0 -226
  773. package/dist/src/lib/symmetry/WyckoffTable.svelte +0 -120
  774. package/dist/src/lib/symmetry/cell-transform.ts +0 -118
  775. package/dist/src/lib/symmetry/index.ts +0 -348
  776. package/dist/src/lib/symmetry/spacegroups.ts +0 -404
  777. package/dist/src/lib/table/HeatmapTable.svelte +0 -1833
  778. package/dist/src/lib/table/ToggleMenu.svelte +0 -385
  779. package/dist/src/lib/table/index.ts +0 -139
  780. package/dist/src/lib/theme/ThemeControl.svelte +0 -53
  781. package/dist/src/lib/theme/index.ts +0 -107
  782. package/dist/src/lib/time.ts +0 -71
  783. package/dist/src/lib/tooltip/TooltipContent.svelte +0 -58
  784. package/dist/src/lib/tooltip/index.ts +0 -2
  785. package/dist/src/lib/tooltip/types.ts +0 -13
  786. package/dist/src/lib/trajectory/Trajectory.svelte +0 -1545
  787. package/dist/src/lib/trajectory/TrajectoryError.svelte +0 -128
  788. package/dist/src/lib/trajectory/TrajectoryExportPane.svelte +0 -357
  789. package/dist/src/lib/trajectory/TrajectoryInfoPane.svelte +0 -313
  790. package/dist/src/lib/trajectory/constants.ts +0 -7
  791. package/dist/src/lib/trajectory/extract.ts +0 -196
  792. package/dist/src/lib/trajectory/format-detect.ts +0 -96
  793. package/dist/src/lib/trajectory/frame-reader.ts +0 -456
  794. package/dist/src/lib/trajectory/helpers.ts +0 -217
  795. package/dist/src/lib/trajectory/index.ts +0 -218
  796. package/dist/src/lib/trajectory/parse/ase.ts +0 -109
  797. package/dist/src/lib/trajectory/parse/hdf5.ts +0 -173
  798. package/dist/src/lib/trajectory/parse/index.ts +0 -411
  799. package/dist/src/lib/trajectory/parse/lammps.ts +0 -215
  800. package/dist/src/lib/trajectory/parse/vasp.ts +0 -102
  801. package/dist/src/lib/trajectory/parse/xyz.ts +0 -143
  802. package/dist/src/lib/trajectory/plotting.ts +0 -599
  803. package/dist/src/lib/trajectory/types.ts +0 -13
  804. package/dist/src/lib/utils.ts +0 -56
  805. package/dist/src/lib/xrd/XrdPlot.svelte +0 -615
  806. package/dist/src/lib/xrd/broadening.ts +0 -130
  807. package/dist/src/lib/xrd/calc-xrd.ts +0 -397
  808. package/dist/src/lib/xrd/index.ts +0 -38
  809. package/dist/src/lib/xrd/parse.ts +0 -858
  810. package/dist/webview.js +0 -29421
  811. package/icon.png +0 -0
  812. package/matterviz-0.3.2.vsix +0 -0
  813. package/matterviz-0.3.4.vsix +0 -0
  814. package/matterviz-0.3.5.vsix +0 -0
  815. package/scripts/sync-config.ts +0 -101
  816. package/src/declarations.d.ts +0 -2
  817. package/src/extension.ts +0 -972
  818. package/src/node-io.ts +0 -65
  819. package/src/types.ts +0 -17
  820. package/src/webview/JsonBrowser.svelte +0 -1079
  821. package/src/webview/PlotPanel.svelte +0 -346
  822. package/src/webview/detect.ts +0 -444
  823. package/src/webview/main.ts +0 -764
  824. package/src/webview/plot-utils.ts +0 -250
  825. package/test-fixtures/all-viz-types.json.gz +0 -0
  826. package/test-fixtures/plot-demo-data.json.gz +0 -0
  827. package/tests/detect.test.ts +0 -604
  828. package/tests/extension.test.ts +0 -2041
  829. package/tests/node-io.test.ts +0 -39
  830. package/tests/plot-utils.test.ts +0 -302
  831. package/tests/vite-plugin-json-gz.test.ts +0 -114
  832. package/tests/vscode-mock.ts +0 -18
  833. package/tests/webview.test.ts +0 -231
  834. package/tsconfig.json +0 -20
  835. package/vite-plugin-json-gz.ts +0 -29
  836. package/vite.config.ts +0 -34
  837. package/vite.extension.config.ts +0 -34
  838. /package/dist/{src/lib/EmptyState.svelte → EmptyState.svelte} +0 -0
  839. /package/dist/{src/lib/Icon.svelte → Icon.svelte} +0 -0
  840. /package/dist/{src/lib/app.css → app.css} +0 -0
  841. /package/dist/{src/lib/chempot-diagram → chempot-diagram}/ChemPotScene3D.svelte +0 -0
  842. /package/dist/{src/lib/colors → colors}/alloy-colors.json +0 -0
  843. /package/dist/{src/lib/colors → colors}/dark-mode-colors.json +0 -0
  844. /package/dist/{src/lib/colors → colors}/jmol-colors.json +0 -0
  845. /package/dist/{src/lib/colors → colors}/muted-colors.json +0 -0
  846. /package/dist/{src/lib/colors → colors}/pastel-colors.json +0 -0
  847. /package/dist/{src/lib/colors → colors}/vesta-colors.json +0 -0
  848. /package/dist/{src/lib/convex-hull → convex-hull}/TemperatureSlider.svelte +0 -0
  849. /package/dist/{src/lib/element → element}/BohrAtom.svelte +0 -0
  850. /package/dist/{src/lib/element → element}/Nucleus.svelte +0 -0
  851. /package/dist/{src/lib/element → element}/data.json +0 -0
  852. /package/dist/{src/lib/element → element}/data.json.gz +0 -0
  853. /package/dist/{src/lib/element → element}/data.json.gz.d.ts +0 -0
  854. /package/dist/{src/lib/element → element}/data.schema.json +0 -0
  855. /package/dist/{src/lib/element-image-urls.json → element-image-urls.json} +0 -0
  856. /package/dist/{src/lib/feedback → feedback}/Spinner.svelte +0 -0
  857. /package/dist/{src/lib/feedback → feedback}/StatusMessage.svelte +0 -0
  858. /package/dist/{src/lib/layout → layout}/json-tree/JsonValue.svelte +0 -0
  859. /package/dist/{src/lib/periodic-table → periodic-table}/TableInset.svelte +0 -0
  860. /package/dist/{src/lib/plot → plot}/FillArea.svelte +0 -0
  861. /package/dist/{src/lib/plot → plot}/ReferenceLine.svelte +0 -0
  862. /package/dist/{src/lib/theme → theme}/themes.mjs +0 -0
  863. /package/dist/{src/lib/xrd → xrd}/atomic_scattering_params.json +0 -0
@@ -1,2248 +0,0 @@
1
- <script lang="ts">
2
- import type { ColorSchemeName } from '$lib/colors'
3
- import { ELEMENT_COLOR_SCHEMES } from '$lib/colors'
4
- import type { ShowControlsProp } from '$lib/controls'
5
- import { normalize_show_controls } from '$lib/controls'
6
- import type { ElementSymbol } from '$lib/element'
7
- import { StatusMessage } from '$lib/feedback'
8
- import Spinner from '$lib/feedback/Spinner.svelte'
9
- import Icon from '$lib/Icon.svelte'
10
- import { create_file_drop_handler, load_from_url } from '$lib/io'
11
- import { parse_volumetric_file } from '$lib/isosurface/parse'
12
- import type { IsosurfaceSettings, VolumetricData } from '$lib/isosurface/types'
13
- import {
14
- auto_isosurface_settings,
15
- DEFAULT_ISOSURFACE_SETTINGS,
16
- tile_volumetric_data,
17
- } from '$lib/isosurface/types'
18
- import { ELEM_SYMBOLS } from '$lib/labels'
19
- import { set_fullscreen_bg, toggle_fullscreen } from '$lib/layout'
20
- import type { Vec3 } from '$lib/math'
21
- import { create_cart_to_frac, create_frac_to_cart } from '$lib/math'
22
- import { DEFAULTS } from '$lib/settings'
23
- import { colors } from '$lib/state.svelte'
24
- import type {
25
- AnyStructure,
26
- BondEditMode,
27
- BondOrder,
28
- Crystal,
29
- MeasureMode,
30
- StructureBond,
31
- } from '$lib/structure'
32
- import {
33
- default_vector_configs,
34
- get_element_counts,
35
- get_pbc_image_sites,
36
- get_structure_vector_keys,
37
- } from '$lib/structure'
38
- import { wrap_to_unit_cell } from '$lib/structure/pbc'
39
- import {
40
- is_valid_supercell_input,
41
- make_supercell,
42
- parse_supercell_scaling,
43
- } from '$lib/structure/supercell'
44
- import type { CellType, SymmetrySettings } from '$lib/symmetry'
45
- import * as symmetry from '$lib/symmetry'
46
- import { transform_cell } from '$lib/symmetry'
47
- import type { MoyoDataset } from '@spglib/moyo-wasm'
48
- import { Canvas } from '@threlte/core'
49
- import type { ComponentProps, Snippet } from 'svelte'
50
- import { untrack } from 'svelte'
51
- import { click_outside, tooltip } from 'svelte-multiselect/attachments'
52
- import type { HTMLAttributes } from 'svelte/elements'
53
- import { SvelteMap, SvelteSet } from 'svelte/reactivity'
54
- import type { Camera, OrthographicCamera, Scene } from 'three'
55
- import type { AtomColorConfig } from './atom-properties'
56
- import { get_property_colors } from './atom-properties'
57
- import AtomLegend from './AtomLegend.svelte'
58
- import CellSelect from './CellSelect.svelte'
59
- import { BOND_ORDER_OPTIONS, merge_bond_edits } from './bonding'
60
- import type { StructureHandlerData } from './index'
61
- import { MAX_SELECTED_SITES } from './measure'
62
- import { normalize_fractional_coords, parse_any_structure } from './parse'
63
- import StructureControls from './StructureControls.svelte'
64
- import StructureExportPane from './StructureExportPane.svelte'
65
- import StructureInfoPane from './StructureInfoPane.svelte'
66
- import StructureScene from './StructureScene.svelte'
67
-
68
- // Type alias for event handlers to reduce verbosity
69
- type EventHandler = (data: StructureHandlerData) => void
70
- type BondEditContext = {
71
- structure_identity: AnyStructure | undefined
72
- source_bond_signature: string
73
- cell_type: CellType
74
- supercell_scaling: string
75
- show_image_atoms: boolean
76
- }
77
- type BondEditSnapshot = {
78
- bonds: StructureBond[] | undefined
79
- context: BondEditContext
80
- }
81
- type BondEditHistorySnapshot = {
82
- added_bonds: StructureBond[]
83
- removed_bonds: StructureBond[]
84
- bond_order_overrides: StructureBond[]
85
- bond_edit_mode: BondEditMode
86
- bond_edit_order: BondOrder
87
- }
88
- type SceneProps = ComponentProps<typeof StructureScene> & typeof DEFAULTS.structure
89
-
90
- // Local reactive state for scene and lattice props. Deeply reactive so nested mutations propagate.
91
- // Deep-clone to prevent mutations from leaking to global defaults across component instances.
92
- let scene_props = $state(structuredClone(DEFAULTS.structure) as SceneProps)
93
- let lattice_props = $state({
94
- cell_edge_opacity: DEFAULTS.structure.cell_edge_opacity,
95
- cell_surface_opacity: DEFAULTS.structure.cell_surface_opacity,
96
- cell_edge_color: DEFAULTS.structure.cell_edge_color,
97
- cell_surface_color: DEFAULTS.structure.cell_surface_color,
98
- cell_edge_width: DEFAULTS.structure.cell_edge_width,
99
- show_cell_vectors: DEFAULTS.structure.show_cell_vectors,
100
- })
101
-
102
- let {
103
- structure = $bindable(),
104
- bonds = $bindable(),
105
- scene_props: scene_props_in = $bindable(),
106
- lattice_props: lattice_props_in = $bindable(),
107
- controls_open = $bindable(false),
108
- info_pane_open = $bindable(false),
109
- enable_measure_mode = $bindable(true),
110
- measure_mode = $bindable<MeasureMode>(`distance`),
111
- bond_edit_mode = $bindable<BondEditMode>(`add`),
112
- bond_edit_order = $bindable<BondOrder>(1),
113
- background_color = $bindable(),
114
- background_opacity = $bindable(0.1),
115
- show_controls,
116
- fullscreen = $bindable(false),
117
- wrapper = $bindable(),
118
- width = $bindable(0),
119
- height = $bindable(0),
120
- reset_text = `Reset camera (or double-click)`,
121
- color_scheme = $bindable(`Vesta`),
122
- atom_color_config = $bindable({
123
- mode: DEFAULTS.structure.atom_color_mode,
124
- scale: DEFAULTS.structure.atom_color_scale,
125
- scale_type: DEFAULTS.structure.atom_color_scale_type,
126
- }),
127
- hovered = $bindable(false),
128
- dragover = $bindable(false),
129
- allow_file_drop = true,
130
- enable_info_pane = true,
131
- png_dpi = $bindable(150),
132
- show_image_atoms = $bindable(true),
133
- supercell_scaling = $bindable(`1x1x1`),
134
- fullscreen_toggle = DEFAULTS.structure.fullscreen_toggle,
135
- bottom_left,
136
- data_url,
137
- structure_string,
138
- on_file_drop,
139
- spinner_props = {},
140
- loading = $bindable(false),
141
- error_msg = $bindable(),
142
- performance_mode = $bindable(`quality`),
143
- // expose selected site indices for external control/highlighting
144
- selected_sites = $bindable([]),
145
- highlighted_sites = $bindable([]),
146
- hovered_site_idx = $bindable(null),
147
- // expose measured site indices for overlays/labels
148
- measured_sites = $bindable([]),
149
- // expose the displayed structure (with image atoms and supercell) for external use
150
- displayed_structure = $bindable(),
151
- // Track hidden elements across component lifecycle
152
- hidden_elements = $bindable(new SvelteSet<ElementSymbol>()),
153
- // Track hidden property values (e.g. Wyckoff positions, coordination numbers)
154
- hidden_prop_vals = $bindable(new SvelteSet<number | string>()),
155
- // Per-element radius overrides (absolute values in Angstroms)
156
- element_radius_overrides = $bindable<Partial<Record<ElementSymbol, number>>>({}),
157
- // Per-site radius overrides (absolute values in Angstroms)
158
- site_radius_overrides = $bindable<SvelteMap<number, number>>(new SvelteMap()),
159
- // Symmetry analysis data (bindable for external access)
160
- sym_data = $bindable(null),
161
- // Symmetry analysis settings (bindable for external control)
162
- symmetry_settings = $bindable(symmetry.default_sym_settings),
163
- // Map element symbols to different elements (e.g. {'H': 'Na', 'He': 'Cl'})
164
- // Useful for LAMMPS files where atom types are mapped to H, He, Li by default
165
- element_mapping = $bindable(),
166
- // Cell type: original, conventional, or primitive (requires symmetry analysis)
167
- cell_type = $bindable(`original`),
168
- // Volumetric data for isosurface rendering (parsed from CHGCAR or .cube files)
169
- volumetric_data = $bindable<VolumetricData[]>(),
170
- // Isosurface rendering settings
171
- isosurface_settings = $bindable<IsosurfaceSettings>({
172
- ...DEFAULT_ISOSURFACE_SETTINGS,
173
- }),
174
- // Active volume index when multiple volumes are present
175
- active_volume_idx = $bindable(0),
176
- children,
177
- top_right_controls,
178
- on_file_load,
179
- on_error,
180
- on_fullscreen_change,
181
- on_camera_move,
182
- on_camera_reset,
183
- on_bonds_change,
184
- ...rest
185
- }:
186
- & {
187
- structure?: AnyStructure
188
- bonds?: StructureBond[]
189
- scene_props?: ComponentProps<typeof StructureScene>
190
- /**
191
- * Controls visibility configuration.
192
- * - 'always': controls always visible
193
- * - 'hover': controls visible on component hover (default)
194
- * - 'never': controls never visible
195
- * - object: { mode, hidden, style } for fine-grained control
196
- *
197
- * Control names: 'reset-camera', 'fullscreen', 'measure-mode', 'info-pane', 'export-pane', 'controls'
198
- */
199
- show_controls?: ShowControlsProp
200
- fullscreen?: boolean
201
- // bindable width of the canvas
202
- width?: number
203
- // bindable height of the canvas
204
- height?: number
205
- // Canvas wrapper element (for export pane)
206
- wrapper?: HTMLDivElement
207
- // PNG export DPI setting
208
- png_dpi?: number
209
- reset_text?: string
210
- hovered?: boolean
211
- dragover?: boolean
212
- allow_file_drop?: boolean
213
- enable_info_pane?: boolean
214
- enable_measure_mode?: boolean
215
- measure_mode?: MeasureMode
216
- bond_edit_mode?: BondEditMode
217
- bond_edit_order?: BondOrder
218
- info_pane_open?: boolean
219
- fullscreen_toggle?: Snippet<[{ fullscreen: boolean }]> | boolean
220
- bottom_left?: Snippet<[{ structure?: AnyStructure }]>
221
- top_right_controls?: Snippet // Additional controls to render at the end of the control buttons row
222
- data_url?: string // URL to load structure from (alternative to providing structure directly)
223
- // Generic callback for when files are dropped - receives raw content and filename
224
- on_file_drop?: (content: string | ArrayBuffer, filename: string) => void
225
- // spinner props (passed to Spinner component)
226
- spinner_props?: ComponentProps<typeof Spinner>
227
- loading?: boolean
228
- error_msg?: string
229
- // Performance mode: 'quality' (default) or 'speed' for large structures
230
- performance_mode?: `quality` | `speed`
231
- // allow parent components to control highlighted/selected site indices
232
- selected_sites?: number[]
233
- highlighted_sites?: number[]
234
- hovered_site_idx?: number | null
235
- // explicit measured sites for distance/angle overlays
236
- measured_sites?: number[]
237
- // expose the displayed structure (with image atoms and/or supercell) for external use
238
- displayed_structure?: AnyStructure
239
- // Track which elements are hidden (bindable across frames in trajectories)
240
- hidden_elements?: Set<ElementSymbol>
241
- // Track which property values are hidden (e.g. Wyckoff positions, coordination numbers)
242
- hidden_prop_vals?: Set<number | string>
243
- // Per-element radius overrides (absolute values in Angstroms)
244
- element_radius_overrides?: Partial<Record<ElementSymbol, number>>
245
- // Per-site radius overrides (absolute values in Angstroms)
246
- // Accepts Map or SvelteMap for flexibility with external callers
247
- site_radius_overrides?: Map<number, number> | SvelteMap<number, number>
248
- // Symmetry analysis data (bindable for external access)
249
- sym_data?: MoyoDataset | null
250
- // Symmetry analysis settings (bindable for external control)
251
- symmetry_settings?: Partial<SymmetrySettings>
252
- // Map element symbols to different elements (e.g. {'H': 'Na', 'He': 'Cl'})
253
- element_mapping?: Partial<Record<ElementSymbol, ElementSymbol>>
254
- // Cell type: original, conventional, or primitive (requires symmetry analysis)
255
- cell_type?: CellType
256
- // Volumetric data for isosurface rendering (parsed from CHGCAR or .cube files)
257
- volumetric_data?: VolumetricData[]
258
- // Isosurface rendering settings
259
- isosurface_settings?: IsosurfaceSettings
260
- // Active volume index when multiple volumes are present
261
- active_volume_idx?: number
262
- // structure content as string (alternative to providing structure directly or via data_url)
263
- structure_string?: string
264
- // Atom coloring configuration
265
- atom_color_config?: Partial<AtomColorConfig>
266
- children?: Snippet<[{ structure?: AnyStructure; fullscreen: boolean }]>
267
- on_file_load?: EventHandler
268
- on_error?: EventHandler
269
- on_fullscreen_change?: EventHandler
270
- on_camera_move?: EventHandler
271
- on_camera_reset?: EventHandler
272
- on_bonds_change?: (bonds: StructureBond[] | undefined) => void
273
- }
274
- & Omit<ComponentProps<typeof StructureControls>, `children` | `onclose`>
275
- & Omit<HTMLAttributes<HTMLDivElement>, `children`> = $props()
276
-
277
- // Initialize models from incoming props; mutations come from UI controls; we mirror into local dicts (NOTE only doing shallow merge)
278
- $effect.pre(() => {
279
- if (scene_props_in && typeof scene_props_in === `object`) {
280
- Object.assign(scene_props, scene_props_in)
281
- }
282
- if (lattice_props_in && typeof lattice_props_in === `object`) {
283
- Object.assign(lattice_props, lattice_props_in)
284
- }
285
- })
286
-
287
- // Load structure from URL when data_url is provided
288
- $effect(() => {
289
- if (data_url && !structure) {
290
- loading = true
291
- error_msg = undefined
292
-
293
- load_from_url(data_url, (content, filename) => {
294
- if (on_file_drop) on_file_drop(content, filename)
295
- else {
296
- // Parse structure internally when no handler provided
297
- try {
298
- const text_content = content instanceof ArrayBuffer
299
- ? new TextDecoder().decode(content)
300
- : content
301
- const parsed = parse_file_content(text_content, filename)
302
- emit_file_load_event(parsed, filename, content)
303
- } catch (error) {
304
- error_msg = `Failed to parse structure: ${
305
- error instanceof Error ? error.message : String(error)
306
- }`
307
- on_error?.({ error_msg, filename })
308
- }
309
- }
310
- })
311
- .then(() => loading = false)
312
- .catch((error: Error) => {
313
- console.error(`Failed to load structure from URL:`, error)
314
- error_msg = `Failed to load structure: ${error.message}`
315
- loading = false
316
- on_error?.({ error_msg, filename: data_url })
317
- })
318
- }
319
- })
320
-
321
- $effect(() => { // Parse structure from string when structure_string is provided
322
- if (!structure_string || data_url) return
323
- loading = true
324
- error_msg = undefined
325
- clear_camera_state()
326
- try {
327
- const parsed = parse_any_structure(structure_string, `string`)
328
- if (parsed) {
329
- structure = parsed
330
- untrack(() => emit_file_load_event(parsed, `string`, structure_string))
331
- } else {
332
- throw new Error(`Failed to parse structure from string`)
333
- }
334
- } catch (err) {
335
- error_msg = `Failed to parse structure from string: ${
336
- err instanceof Error ? err.message : String(err)
337
- }`
338
- untrack(() => on_error?.({ error_msg, filename: `string` }))
339
- } finally {
340
- loading = false
341
- }
342
- })
343
-
344
- // Auto-populate vector_configs when structure has vector data (force, magmom, spin, etc.)
345
- // Skip if configs were externally provided. Clear auto-generated configs on structure change.
346
- let vectors_auto_populated_for: AnyStructure | undefined = undefined
347
- let last_auto_configs: Record<string, unknown> | undefined = undefined
348
-
349
- $effect(() => {
350
- if (!structure?.sites || structure === vectors_auto_populated_for) return
351
- const keys = get_structure_vector_keys(structure)
352
- // Clear auto-generated configs from previous structure; preserve externally-modified ones
353
- const existing = scene_props.vector_configs
354
- if (last_auto_configs && existing === last_auto_configs) {
355
- scene_props.vector_configs = {}
356
- last_auto_configs = undefined
357
- } else if (existing && Object.keys(existing).length > 0) {
358
- vectors_auto_populated_for = structure
359
- return
360
- }
361
- vectors_auto_populated_for = structure
362
- if (keys.length === 0) return
363
- const configs = default_vector_configs(keys)
364
- scene_props.vector_configs = configs
365
- // Read back the proxied reference — Svelte 5 $state wraps objects in
366
- // proxies, so `scene_props.vector_configs !== configs`. Storing the proxy
367
- // lets the identity check above detect unmodified auto-configs.
368
- // See https://svelte.dev/e/state_proxy_equality_mismatch
369
- last_auto_configs = scene_props.vector_configs
370
- scene_props.vector_scale ??= DEFAULTS.structure.vector_scale
371
- scene_props.vector_color ??= DEFAULTS.structure.vector_color
372
- })
373
-
374
- // Optimize scene props for performance based on structure size and mode
375
- $effect(() => {
376
- if (structure?.sites && performance_mode === `speed`) {
377
- const site_count = structure.sites.length
378
- const current_sphere_segments = scene_props.sphere_segments || 20
379
-
380
- // Reduce sphere segments for large structures in speed mode
381
- if (site_count > 200) {
382
- scene_props.sphere_segments = Math.min(current_sphere_segments, 12)
383
- }
384
- }
385
- })
386
-
387
- $effect(() => {
388
- colors.element = ELEMENT_COLOR_SCHEMES[color_scheme as ColorSchemeName]
389
- })
390
-
391
- // Compute property-based colors for legend display
392
- let property_colors = $derived(
393
- get_property_colors(
394
- structure,
395
- atom_color_config,
396
- scene_props.bonding_strategy,
397
- sym_data,
398
- ),
399
- )
400
-
401
- let symmetry_run_id = 0
402
- let symmetry_error = $state<string>()
403
- let last_symmetry_structure_ref: AnyStructure | null = null
404
-
405
- // Trigger symmetry analysis when structure is loaded or settings change.
406
- // Skip during atom drags — symmetry doesn't change from moving atoms,
407
- // and WASM analysis on every drag frame causes severe frame drops.
408
- $effect(() => {
409
- if (dragging_atoms) return
410
- if (!structure || !(`lattice` in structure)) {
411
- untrack(() => {
412
- sym_data = null
413
- symmetry_error = undefined
414
- })
415
- last_symmetry_structure_ref = null
416
- return
417
- }
418
-
419
- const current_structure = structure
420
- const structure_changed = current_structure !== last_symmetry_structure_ref
421
- if (structure_changed) {
422
- untrack(() => {
423
- sym_data = null
424
- symmetry_error = undefined
425
- })
426
- last_symmetry_structure_ref = current_structure
427
- } else {
428
- // Keep previous symmetry data while recomputing so bound consumers
429
- // (e.g. SymmetryStats inputs) do not unmount and lose focus.
430
- untrack(() => symmetry_error = undefined)
431
- }
432
- const run_id = ++symmetry_run_id
433
- // Destructure symmetry_settings to ensure Svelte tracks changes to symprec and algo
434
- // (reading just the object reference isn't sufficient for fine-grained reactivity)
435
- const { symprec, algo } = symmetry_settings ?? symmetry.default_sym_settings
436
- const current_settings = { symprec, algo }
437
- // Skip symmetry auto-analysis in unit tests; happy-dom can't fetch WASM assets
438
- if (typeof process !== `undefined` && process.env?.VITEST) return
439
-
440
- symmetry.ensure_moyo_wasm_ready()
441
- .then(() =>
442
- run_id === symmetry_run_id
443
- ? symmetry.analyze_structure_symmetry(current_structure, current_settings)
444
- : null
445
- )
446
- .then((data) => {
447
- if (data && run_id === symmetry_run_id) {
448
- untrack(() => sym_data = data)
449
- }
450
- })
451
- .catch((err) => {
452
- if (run_id === symmetry_run_id) {
453
- untrack(() => sym_data = null)
454
- symmetry_error = `Symmetry analysis failed: ${err?.message || err}`
455
- console.error(`Symmetry analysis failed:`, err)
456
- }
457
- })
458
- })
459
-
460
- let measure_menu_open = $state(false)
461
- let export_pane_open = $state(false)
462
- let focused = $state(false)
463
-
464
- // Bond customization state
465
- let added_bonds = $state<StructureBond[]>([])
466
- let removed_bonds = $state<StructureBond[]>([])
467
- let bond_order_overrides = $state<StructureBond[]>([])
468
- let bond_undo_stack = $state<BondEditHistorySnapshot[]>([])
469
- let bond_redo_stack = $state<BondEditHistorySnapshot[]>([])
470
- let bond_history_context = $state<BondEditContext>()
471
- let last_bond_structure_identity = $state(structure)
472
- let last_emitted_bond_signature = $state<string>()
473
- let bond_edit_snapshot = $state<BondEditSnapshot>()
474
- let has_bond_edits = $derived(
475
- added_bonds.length > 0 || removed_bonds.length > 0 ||
476
- bond_order_overrides.length > 0,
477
- )
478
-
479
- const clone_bonds = (edit_bonds: StructureBond[]): StructureBond[] =>
480
- edit_bonds.map((bond) => ({
481
- ...bond,
482
- cell_shift: bond.cell_shift && ([...bond.cell_shift] as Vec3),
483
- }))
484
-
485
- const snapshot_bond_edits = (): BondEditHistorySnapshot => ({
486
- added_bonds: clone_bonds(added_bonds),
487
- removed_bonds: clone_bonds(removed_bonds),
488
- bond_order_overrides: clone_bonds(bond_order_overrides),
489
- bond_edit_mode,
490
- bond_edit_order,
491
- })
492
-
493
- function restore_bond_edit_snapshot(snapshot: BondEditHistorySnapshot) {
494
- added_bonds = clone_bonds(snapshot.added_bonds)
495
- removed_bonds = clone_bonds(snapshot.removed_bonds)
496
- bond_order_overrides = clone_bonds(snapshot.bond_order_overrides)
497
- bond_edit_mode = snapshot.bond_edit_mode
498
- bond_edit_order = snapshot.bond_edit_order
499
- clear_selection()
500
- }
501
-
502
- function clear_bond_history() {
503
- bond_undo_stack = []
504
- bond_redo_stack = []
505
- bond_history_context = undefined
506
- }
507
-
508
- function push_bond_undo() {
509
- if (bond_undo_stack.length >= MAX_HISTORY) {
510
- bond_undo_stack.splice(0, bond_undo_stack.length - MAX_HISTORY + 1)
511
- }
512
- bond_history_context ??= current_bond_edit_context()
513
- bond_undo_stack.push(snapshot_bond_edits())
514
- bond_redo_stack = []
515
- }
516
-
517
- function undo_bond_edit() {
518
- if (bond_undo_stack.length === 0) return
519
- const restored = bond_undo_stack.pop()
520
- if (!restored) return
521
- bond_redo_stack.push(snapshot_bond_edits())
522
- restore_bond_edit_snapshot(restored)
523
- }
524
-
525
- function redo_bond_edit() {
526
- if (bond_redo_stack.length === 0) return
527
- const restored = bond_redo_stack.pop()
528
- if (!restored) return
529
- bond_undo_stack.push(snapshot_bond_edits())
530
- restore_bond_edit_snapshot(restored)
531
- }
532
-
533
- function clear_bond_edits() {
534
- added_bonds = []
535
- removed_bonds = []
536
- bond_order_overrides = []
537
- clear_bond_history()
538
- }
539
-
540
- function emit_bonds(next_bonds: StructureBond[] | undefined) {
541
- const signature = bond_signature(next_bonds)
542
- if (signature === last_emitted_bond_signature) return
543
- last_emitted_bond_signature = signature
544
- bonds = next_bonds
545
- on_bonds_change?.(next_bonds)
546
- }
547
-
548
- const bond_signature = (edit_bonds: StructureBond[] | undefined): string =>
549
- edit_bonds === undefined ? `undefined` : JSON.stringify(edit_bonds)
550
-
551
- const current_source_bonds = (): StructureBond[] | undefined =>
552
- bonds ?? structure?.properties?.bonds
553
-
554
- const current_source_bond_signature = (): string => {
555
- const raw_signature = bond_signature(current_source_bonds())
556
- if (raw_signature !== last_emitted_bond_signature) return raw_signature
557
- return bond_history_context?.source_bond_signature ??
558
- (bond_edit_snapshot
559
- ? bond_signature(bond_edit_snapshot.bonds)
560
- : raw_signature)
561
- }
562
-
563
- const current_bond_edit_context = (): BondEditContext => ({
564
- structure_identity: structure,
565
- source_bond_signature: current_source_bond_signature(),
566
- cell_type,
567
- supercell_scaling,
568
- show_image_atoms,
569
- })
570
-
571
- const bond_edit_context_changed = (
572
- previous: BondEditContext,
573
- current: BondEditContext,
574
- ): boolean =>
575
- previous.structure_identity !== current.structure_identity ||
576
- previous.source_bond_signature !== current.source_bond_signature ||
577
- previous.cell_type !== current.cell_type ||
578
- previous.supercell_scaling !== current.supercell_scaling ||
579
- previous.show_image_atoms !== current.show_image_atoms
580
-
581
- const resolve_bond_edit_reset_bonds = (
582
- snapshot: BondEditSnapshot,
583
- ): StructureBond[] | undefined =>
584
- snapshot.context.structure_identity === structure
585
- ? snapshot.bonds
586
- : structure?.properties?.bonds
587
-
588
- $effect(() => {
589
- const next_structure_identity = structure
590
- untrack(() => {
591
- if (
592
- last_bond_structure_identity !== next_structure_identity &&
593
- bond_signature(bonds) === last_emitted_bond_signature
594
- ) {
595
- emit_bonds(structure?.properties?.bonds)
596
- }
597
- last_bond_structure_identity = next_structure_identity
598
- })
599
- })
600
-
601
- $effect(() => {
602
- const history_context = bond_history_context
603
- if (history_context === undefined) return
604
- if (bond_edit_context_changed(history_context, current_bond_edit_context())) {
605
- untrack(clear_bond_history)
606
- }
607
- })
608
-
609
- $effect(() => {
610
- const snapshot = bond_edit_snapshot
611
- if (snapshot === undefined) return
612
- const context = current_bond_edit_context()
613
- if (!bond_edit_context_changed(snapshot.context, context)) return
614
- untrack(() => {
615
- emit_bonds(resolve_bond_edit_reset_bonds(snapshot))
616
- clear_bond_edits()
617
- bond_edit_snapshot = undefined
618
- })
619
- })
620
-
621
- $effect(() => {
622
- if (!has_bond_edits) {
623
- if (bond_edit_snapshot === undefined) return
624
- emit_bonds(resolve_bond_edit_reset_bonds(bond_edit_snapshot))
625
- bond_edit_snapshot = undefined
626
- return
627
- }
628
- bond_edit_snapshot ??= {
629
- bonds: current_source_bonds(),
630
- context: current_bond_edit_context(),
631
- }
632
- const edited_bonds = merge_bond_edits(
633
- bond_edit_snapshot.bonds ?? [],
634
- added_bonds,
635
- removed_bonds,
636
- bond_order_overrides,
637
- )
638
- emit_bonds(edited_bonds)
639
- })
640
-
641
- // === Edit-atoms mode state ===
642
- let dragging_atoms = $state(false)
643
- let undo_stack = $state<AnyStructure[]>([])
644
- let redo_stack = $state<AnyStructure[]>([])
645
- const MAX_HISTORY = 20
646
- // Flag set before internal edits (undo/redo/delete/add/move) to distinguish
647
- // them from external structure changes (file load, trajectory step, etc.)
648
- let is_internal_edit = false
649
- // Add-atom sub-mode state (bound to StructureScene)
650
- let add_atom_mode = $state(false)
651
- let add_element = $state<ElementSymbol>(`C` as ElementSymbol)
652
- let canvas_cursor = $state(`default`)
653
- let is_measure_selection_mode = $derived(
654
- measure_mode === `distance` || measure_mode === `angle`,
655
- )
656
- let show_measure_selection_limit = $derived(
657
- is_measure_selection_mode && measured_sites.length >= MAX_SELECTED_SITES,
658
- )
659
- let show_selection_reset = $derived(
660
- has_bond_edits ||
661
- (is_measure_selection_mode && measured_sites.length > 0) ||
662
- (measure_mode === `edit-atoms` && selected_sites.length > 0),
663
- )
664
- let atom_legend_selected_sites = $derived(
665
- measure_mode === `edit-atoms` ? selected_sites : [],
666
- )
667
- let change_element_mode = $state(false)
668
- let change_element_value = $state(``)
669
- // Ephemeral toast message for edit operations
670
- let toast_msg = $state<string | null>(null)
671
- let toast_timer: ReturnType<typeof setTimeout> | undefined
672
- function show_toast(msg: string, duration_ms = 2000) {
673
- clearTimeout(toast_timer)
674
- toast_msg = msg
675
- toast_timer = setTimeout(() => (toast_msg = null), duration_ms)
676
- }
677
-
678
- // Normalize and validate element symbol (e.g. "fe" → "Fe", "Xx" → null)
679
- function normalize_element(input: string): ElementSymbol | null {
680
- const normalized = (input.charAt(0).toUpperCase() +
681
- input.slice(1).toLowerCase()) as ElementSymbol
682
- return ELEM_SYMBOLS.includes(normalized) ? normalized : null
683
- }
684
-
685
- function clear_selection() {
686
- selected_sites = []
687
- measured_sites = []
688
- dragging_atoms = false
689
- }
690
-
691
- function push_undo() {
692
- if (!structure) return
693
- if (undo_stack.length >= MAX_HISTORY) {
694
- undo_stack.splice(0, undo_stack.length - MAX_HISTORY + 1)
695
- }
696
- undo_stack.push($state.snapshot(structure) as AnyStructure)
697
- redo_stack.length = 0
698
- }
699
-
700
- // Shared undo/redo: pop from `source`, push current state onto `target`
701
- function apply_history(source: AnyStructure[], target: AnyStructure[]) {
702
- if (source.length === 0 || !structure) return
703
- const restored = source.pop()
704
- if (!restored) return
705
- is_internal_edit = true
706
- target.push($state.snapshot(structure) as AnyStructure)
707
- structure = restored
708
- clear_selection()
709
- }
710
-
711
- const undo = () => apply_history(undo_stack, redo_stack)
712
- const redo = () => apply_history(redo_stack, undo_stack)
713
-
714
- // Clear undo/redo stacks when structure changes externally (file load, etc.)
715
- // Internal edits set is_internal_edit=true before modifying structure.
716
- // This $effect runs after microtask, so the flag is still set from the edit.
717
- $effect(() => {
718
- // Track structure to re-run when it changes
719
- void structure
720
- if (is_internal_edit) {
721
- is_internal_edit = false
722
- return
723
- }
724
- // External change — clear history and stale edit-atoms state
725
- untrack(() => {
726
- if (undo_stack.length > 0 || redo_stack.length > 0) {
727
- undo_stack = []
728
- redo_stack = []
729
- }
730
- if (highlighted_sites.length > 0) highlighted_sites = []
731
- if (measure_mode === `edit-atoms`) {
732
- if (selected_sites.length > 0 || measured_sites.length > 0) clear_selection()
733
- if (site_radius_overrides?.size > 0) site_radius_overrides.clear()
734
- }
735
- })
736
- })
737
-
738
- // Clear selection when switching measure/edit mode so stale state doesn't carry over
739
- let mode_first_run = true
740
- $effect(() => {
741
- void measure_mode // track reactively
742
- if (mode_first_run) {
743
- mode_first_run = false
744
- return
745
- }
746
- untrack(() => {
747
- if (selected_sites.length > 0 || measured_sites.length > 0) clear_selection()
748
- if (measure_mode === `edit-bonds`) bond_edit_mode = `add`
749
- })
750
- })
751
-
752
- $effect(() => {
753
- void bond_edit_mode
754
- untrack(() => {
755
- if (measure_mode === `edit-bonds` && (selected_sites.length > 0 || measured_sites.length > 0)) {
756
- clear_selection()
757
- }
758
- })
759
- })
760
-
761
- // Auto-bake cell type transform and clear stale state when entering edit-atoms mode
762
- $effect(() => {
763
- if (measure_mode !== `edit-atoms`) return
764
- untrack(() => {
765
- // Clear bond edits from edit-bonds mode to avoid stale state
766
- if (has_bond_edits) clear_bond_edits()
767
- else clear_bond_history()
768
- if (cell_type !== `original` && cell_transformed_structure && structure) {
769
- // Bake the transformed cell: push original to undo, replace structure
770
- is_internal_edit = true
771
- push_undo()
772
- structure = $state.snapshot(cell_transformed_structure) as AnyStructure
773
- cell_type = `original`
774
- }
775
- })
776
- })
777
-
778
- let controls_config = $derived(normalize_show_controls(show_controls))
779
- let viewer_active = $derived(hovered || focused)
780
- let scene_gizmo = $derived(viewer_active && (scene_props.gizmo ?? scene_props.show_gizmo))
781
- let active_scene_sites = $derived([
782
- ...new SvelteSet([...(scene_props.active_sites ?? []), ...highlighted_sites]),
783
- ])
784
-
785
- // Normalize structure coordinates: wrap fractional coords to [0,1) and recompute Cartesian
786
- // This ensures atoms are rendered inside the unit cell regardless of data source
787
- let normalized_structure = $derived.by(() => {
788
- if (!structure || !(`lattice` in structure)) return structure
789
- return normalize_fractional_coords(structure) as AnyStructure
790
- })
791
-
792
- let structure_with_bonds = $derived.by(() => {
793
- if (!normalized_structure || bonds === undefined) return normalized_structure
794
- return {
795
- ...normalized_structure,
796
- properties: { ...normalized_structure.properties, bonds },
797
- } as AnyStructure
798
- })
799
-
800
- // Apply cell type transformation (original, conventional, or primitive)
801
- // This must happen BEFORE supercell transformation
802
- let cell_transformed_structure = $derived.by(() => {
803
- if (
804
- !structure_with_bonds || !(`lattice` in structure_with_bonds) ||
805
- cell_type === `original`
806
- ) {
807
- return structure_with_bonds
808
- }
809
- // Cell type transformation requires symmetry data
810
- if (!sym_data) {
811
- return structure_with_bonds
812
- }
813
- try {
814
- return transform_cell(structure_with_bonds as Crystal, cell_type, sym_data)
815
- } catch (error) {
816
- console.error(`Failed to transform cell to ${cell_type}:`, error)
817
- return structure_with_bonds
818
- }
819
- })
820
-
821
- // Create supercell if needed (uses cell_transformed_structure as base)
822
- let supercell_structure = $state(structure)
823
- let supercell_loading = $state(false)
824
- let has_supercell = $derived(
825
- !!supercell_scaling && ![``, `1x1x1`, `1`].includes(supercell_scaling),
826
- )
827
- let bond_edits_enabled = $derived(
828
- cell_type === `original` && !has_supercell && !supercell_loading,
829
- )
830
-
831
- $effect(() => {
832
- if (measure_mode !== `edit-bonds` || bond_edits_enabled) return
833
- untrack(() => {
834
- clear_selection()
835
- clear_bond_edits()
836
- measure_mode = `distance`
837
- show_toast(`Bond editing is only available for the original 1x1x1 cell`)
838
- })
839
- })
840
-
841
- // Tile volumetric data to match supercell when active.
842
- // Gate on !supercell_loading so the tiled volume and supercell structure update
843
- // in the same frame (large supercells defer structure via setTimeout).
844
- let supercell_volume = $derived.by(() => {
845
- const vol = volumetric_data?.[active_volume_idx]
846
- if (!vol || !has_supercell || supercell_loading) return vol
847
- try {
848
- return tile_volumetric_data(vol, parse_supercell_scaling(supercell_scaling))
849
- } catch {
850
- return vol
851
- }
852
- })
853
-
854
- let supercell_timeout: ReturnType<typeof setTimeout> | undefined
855
- $effect(() => {
856
- const base_structure = cell_transformed_structure
857
- clearTimeout(supercell_timeout)
858
- if (!base_structure || !(`lattice` in base_structure) || !has_supercell) {
859
- supercell_structure = base_structure
860
- supercell_loading = false
861
- } else if (!is_valid_supercell_input(supercell_scaling)) {
862
- supercell_structure = base_structure
863
- supercell_loading = false
864
- } else {
865
- // For large supercells, show loading state and use async generation
866
- const sites_count = base_structure.sites?.length || 0
867
- 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)
870
- const estimated_sites = sites_count * scaling_mult
871
-
872
- // Show spinner for supercells with >1000 estimated sites or scaling >8
873
- const show_loading = estimated_sites > 1000 || scaling_mult > 8
874
-
875
- if (show_loading) {
876
- supercell_loading = true
877
- // Use setTimeout to allow UI to update before heavy computation
878
- supercell_timeout = setTimeout(() => {
879
- try {
880
- if (base_structure && `lattice` in base_structure) {
881
- supercell_structure = make_supercell(
882
- base_structure as Crystal,
883
- supercell_scaling,
884
- )
885
- }
886
- } catch (error) {
887
- console.error(`Failed to create supercell:`, error)
888
- supercell_structure = base_structure
889
- } finally {
890
- supercell_loading = false
891
- }
892
- }, 10)
893
- } else {
894
- if (base_structure && `lattice` in base_structure) {
895
- supercell_structure = make_supercell(
896
- base_structure as Crystal,
897
- supercell_scaling,
898
- )
899
- }
900
- supercell_loading = false
901
- }
902
- }
903
- })
904
-
905
- // Clear selections, site overrides, and stale camera target when transformations
906
- // change site indices (skip first run to preserve parent-provided selections)
907
- let first_run = true
908
- $effect(() => {
909
- void [supercell_scaling, show_image_atoms, structure, cell_type] // track reactively
910
- if (first_run) {
911
- first_run = false
912
- return
913
- }
914
- untrack(() => {
915
- // In edit-atoms mode, structure changes are intentional user edits
916
- // (move/add/delete) — preserve the selection so TransformControls stays active
917
- if (measure_mode === `edit-atoms`) return
918
- if (selected_sites.length > 0 || measured_sites.length > 0) clear_selection()
919
- // Clear site radius overrides since site indices are no longer valid
920
- if (site_radius_overrides?.size > 0) site_radius_overrides.clear()
921
- // Clear stale camera target so orbit controls re-center on the new cell
922
- scene_props.camera_target = undefined
923
- })
924
- })
925
-
926
- // Apply element mapping then image atoms to the supercell structure.
927
- // Skip get_pbc_image_sites during atom drags — the vector math + doubled site
928
- // count causes frame drops. Image atoms reappear instantly on drag release.
929
- $effect(() => {
930
- let struct = supercell_structure
931
- if (struct && element_mapping && Object.keys(element_mapping).length > 0) {
932
- const mapping = element_mapping // capture for TypeScript narrowing
933
- struct = {
934
- ...struct,
935
- sites: struct.sites.map((site) => ({
936
- ...site,
937
- species: site.species.map((sp) => ({
938
- ...sp,
939
- element: mapping[sp.element as ElementSymbol] ?? sp.element,
940
- })),
941
- label: mapping[site.label as ElementSymbol] ?? site.label,
942
- })),
943
- }
944
- }
945
- displayed_structure =
946
- !dragging_atoms && show_image_atoms && struct && `lattice` in struct &&
947
- struct.lattice
948
- ? get_pbc_image_sites(struct)
949
- : struct
950
- })
951
-
952
- // Track if camera has ever been moved from initial position
953
- let camera_has_moved = $state(false)
954
- let camera_is_moving = $state(false)
955
- let scene = $state<Scene | undefined>(undefined)
956
- let camera = $state<Camera | undefined>(undefined)
957
- let orbit_controls = $state<
958
- ComponentProps<typeof StructureScene>[`orbit_controls`]
959
- >(undefined)
960
- let rotation_target_ref = $state<Vec3 | undefined>(undefined)
961
- let initial_computed_zoom = $state<number | undefined>(undefined)
962
-
963
- // Mutual exclusion: opening one pane closes others
964
- $effect(() => {
965
- if (info_pane_open) {
966
- untrack(() => [controls_open, export_pane_open] = [false, false])
967
- }
968
- })
969
- $effect(() => {
970
- if (controls_open) {
971
- untrack(() => [info_pane_open, export_pane_open] = [false, false])
972
- }
973
- })
974
- $effect(() => {
975
- if (export_pane_open) {
976
- untrack(() => [info_pane_open, controls_open] = [false, false])
977
- }
978
- })
979
-
980
- // Reset tracking when structure changes
981
- $effect(() => {
982
- if (structure) camera_has_moved = false
983
- })
984
-
985
- // Clear stale camera target and position so StructureScene uses the new
986
- // structure's rotation_target (unit cell center) and auto-positions the camera.
987
- function clear_camera_state() {
988
- scene_props.camera_target = undefined
989
- scene_props.camera_position = [0, 0, 0]
990
- }
991
-
992
- const read_orbit_target = (): Vec3 | undefined => {
993
- if (!orbit_controls?.target) return
994
- const { x, y, z } = orbit_controls.target
995
- return [x, y, z]
996
- }
997
-
998
- const read_camera_position = (): Vec3 | undefined =>
999
- camera
1000
- ? [camera.position.x, camera.position.y, camera.position.z]
1001
- : scene_props.camera_position
1002
-
1003
- // Emit debounced camera updates while controls are active.
1004
- $effect(() => {
1005
- if (!camera_is_moving) return
1006
- camera_has_moved = true
1007
-
1008
- const emit_camera_move = () => {
1009
- const camera_position = read_camera_position()
1010
- if (camera_position === undefined) return
1011
- const camera_target = read_orbit_target()
1012
- scene_props.camera_position = camera_position
1013
- scene_props.camera_target = camera_target
1014
- on_camera_move?.({
1015
- structure,
1016
- camera_has_moved,
1017
- camera_position,
1018
- camera_target,
1019
- })
1020
- }
1021
-
1022
- emit_camera_move()
1023
- const emit_interval = setInterval(emit_camera_move, 200)
1024
- return () => clearInterval(emit_interval)
1025
- })
1026
-
1027
- function reset_camera() {
1028
- // Reset camera position to trigger automatic positioning.
1029
- scene_props.camera_position = [0, 0, 0]
1030
- scene_props.camera_target = rotation_target_ref
1031
- camera_has_moved = false
1032
-
1033
- let camera_position: Vec3 = [0, 0, 0]
1034
- let camera_target: Vec3 | undefined = rotation_target_ref
1035
-
1036
- // Reset pan/zoom and ensure controls target returns to structure center.
1037
- if (orbit_controls && camera) {
1038
- if (
1039
- `reset` in orbit_controls &&
1040
- typeof orbit_controls.reset === `function`
1041
- ) orbit_controls.reset()
1042
- if (orbit_controls.target && rotation_target_ref) {
1043
- const [target_x, target_y, target_z] = rotation_target_ref
1044
- orbit_controls.target.set(target_x, target_y, target_z)
1045
- }
1046
-
1047
- // Reset zoom for orthographic camera
1048
- if (`zoom` in camera && initial_computed_zoom !== undefined) {
1049
- const ortho_camera = camera as OrthographicCamera
1050
- ortho_camera.zoom = initial_computed_zoom
1051
- ortho_camera.updateProjectionMatrix()
1052
- }
1053
-
1054
- // Call update to apply changes immediately
1055
- if (typeof orbit_controls.update === `function`) orbit_controls.update()
1056
- camera_position = read_camera_position() ?? camera_position
1057
- camera_target = read_orbit_target()
1058
- }
1059
-
1060
- scene_props.camera_position = camera_position
1061
- scene_props.camera_target = camera_target
1062
- on_camera_reset?.({ structure, camera_has_moved, camera_position, camera_target })
1063
- }
1064
-
1065
- const emit_file_load_event = (
1066
- loaded_structure: AnyStructure,
1067
- filename: string,
1068
- content: string | ArrayBuffer,
1069
- ) =>
1070
- on_file_load?.({
1071
- structure: loaded_structure,
1072
- filename,
1073
- file_size: typeof content === `string`
1074
- ? new Blob([content]).size
1075
- : content.byteLength,
1076
- total_atoms: loaded_structure.sites?.length || 0,
1077
- })
1078
-
1079
- // Try to parse content as a volumetric file, setting both structure and volumetric data.
1080
- // Delegates format detection entirely to parse_volumetric_file (filename + content sniffing).
1081
- // Returns the parsed structure on success, or null if the file isn't a volumetric format.
1082
- function try_parse_volumetric(
1083
- text_content: string,
1084
- filename: string,
1085
- ): AnyStructure | null {
1086
- const vol_result = parse_volumetric_file(text_content, filename)
1087
- if (!vol_result) return null
1088
- // parse_volumetric_file extracts structure from file header;
1089
- // parsers set pbc so the lattice conforms to Crystal's LatticeType
1090
- structure = vol_result.structure as AnyStructure
1091
- volumetric_data = vol_result.volumes
1092
- // Auto-compute reasonable isosurface settings from data range
1093
- const vol = vol_result.volumes[0]
1094
- if (vol) {
1095
- isosurface_settings = auto_isosurface_settings(vol.data_range)
1096
- active_volume_idx = 0
1097
- }
1098
- return structure
1099
- }
1100
-
1101
- // Parse file content, trying volumetric format first then falling back to plain structure.
1102
- // Returns the parsed structure on success, throws on failure.
1103
- function parse_file_content(text_content: string, filename: string): AnyStructure {
1104
- clear_camera_state()
1105
- const vol_struct = try_parse_volumetric(text_content, filename)
1106
- if (vol_struct) return vol_struct
1107
- // Clear stale volumetric data when loading a non-volumetric file
1108
- volumetric_data = []
1109
- const parsed = parse_any_structure(text_content, filename)
1110
- if (!parsed) throw new Error(`Failed to parse structure from ${filename}`)
1111
- structure = parsed
1112
- return parsed
1113
- }
1114
-
1115
- const handle_file_drop = create_file_drop_handler({
1116
- allow: () => allow_file_drop,
1117
- on_drop: (content, filename) => {
1118
- if (on_file_drop) return on_file_drop(content, filename)
1119
- try {
1120
- const text_content = content instanceof ArrayBuffer
1121
- ? new TextDecoder().decode(content)
1122
- : content
1123
- const parsed = parse_file_content(text_content, filename)
1124
- emit_file_load_event(parsed, filename, content)
1125
- } catch (err) {
1126
- error_msg = `Failed to parse structure: ${
1127
- err instanceof Error ? err.message : String(err)
1128
- }`
1129
- on_error?.({ error_msg, filename })
1130
- }
1131
- },
1132
- on_error: (msg) => {
1133
- error_msg = msg
1134
- on_error?.({ error_msg: msg })
1135
- },
1136
- set_loading: (val) => {
1137
- loading = val
1138
- if (val) [error_msg, dragover] = [undefined, false]
1139
- },
1140
- })
1141
-
1142
- function handle_keydown(event: KeyboardEvent) {
1143
- // Don't handle shortcuts if user is typing in an input field
1144
- const target = event.target
1145
- const is_input_focused =
1146
- target instanceof HTMLElement &&
1147
- (target.tagName === `INPUT` ||
1148
- target.tagName === `TEXTAREA` ||
1149
- target.tagName === `SELECT` ||
1150
- target.isContentEditable)
1151
-
1152
- // Allow Escape to cancel add-atom mode even when the element input is focused
1153
- if (event.key === `Escape` && measure_mode === `edit-atoms` && add_atom_mode) {
1154
- event.preventDefault()
1155
- add_atom_mode = false
1156
- return
1157
- }
1158
-
1159
- if (is_input_focused) return
1160
-
1161
- if (measure_mode === `edit-bonds`) {
1162
- const key = event.key.toLowerCase()
1163
- const plain = !event.ctrlKey && !event.metaKey && !event.altKey
1164
- if (event.ctrlKey || event.metaKey) {
1165
- if (key === `z` && !event.shiftKey) {
1166
- if (bond_undo_stack.length === 0) return
1167
- event.preventDefault()
1168
- undo_bond_edit()
1169
- show_toast(`Undo bond edit (${bond_undo_stack.length} left)`)
1170
- return
1171
- } else if (key === `y` || (key === `z` && event.shiftKey)) {
1172
- if (bond_redo_stack.length === 0) return
1173
- event.preventDefault()
1174
- redo_bond_edit()
1175
- show_toast(`Redo bond edit (${bond_redo_stack.length} left)`)
1176
- return
1177
- }
1178
- }
1179
- if (key === `a` && plain) {
1180
- event.preventDefault()
1181
- bond_edit_mode = `add`
1182
- return
1183
- }
1184
- if (key === `d` && plain) {
1185
- event.preventDefault()
1186
- bond_edit_mode = `delete`
1187
- return
1188
- }
1189
- if (event.key === `Escape` && selected_sites.length > 0) {
1190
- event.preventDefault()
1191
- clear_selection()
1192
- return
1193
- }
1194
- }
1195
-
1196
- // Edit-atoms mode shortcuts (including undo/redo)
1197
- if (measure_mode === `edit-atoms`) {
1198
- // Undo/redo shortcuts (Ctrl/Cmd + Z/Y) — only active in edit-atoms mode
1199
- if (event.ctrlKey || event.metaKey) {
1200
- const key = event.key.toLowerCase()
1201
- if (key === `z` && !event.shiftKey) {
1202
- if (undo_stack.length === 0) return
1203
- event.preventDefault()
1204
- undo()
1205
- show_toast(`Undo (${undo_stack.length} left)`)
1206
- return
1207
- } else if (key === `y` || (key === `z` && event.shiftKey)) {
1208
- if (redo_stack.length === 0) return
1209
- event.preventDefault()
1210
- redo()
1211
- show_toast(`Redo (${redo_stack.length} left)`)
1212
- return
1213
- }
1214
- }
1215
-
1216
- if (event.key === `Delete` || event.key === `Backspace`) {
1217
- // Delete selected atoms
1218
- if (selected_sites.length > 0 && structure?.sites) {
1219
- event.preventDefault()
1220
- is_internal_edit = true
1221
- push_undo()
1222
- const to_delete = scene_to_structure_indices(selected_sites, true)
1223
- const n_deleted = to_delete.size
1224
- clear_selection()
1225
- structure = {
1226
- ...structure,
1227
- sites: structure.sites.filter((_, idx) => !to_delete.has(idx)),
1228
- }
1229
- // Clear per-site overrides since indices shifted after deletion
1230
- if (site_radius_overrides?.size > 0) site_radius_overrides.clear()
1231
- clear_bond_edits()
1232
- show_toast(`Deleted ${n_deleted} site${n_deleted > 1 ? `s` : ``}`)
1233
- }
1234
- return
1235
- }
1236
- const key = event.key.toLowerCase()
1237
- const plain = !event.ctrlKey && !event.metaKey && !event.altKey
1238
-
1239
- if (key === `a` && plain) {
1240
- // Enter add-atom sub-mode (plain 'a' only, not Ctrl+A/Cmd+A/Alt+A)
1241
- event.preventDefault()
1242
- add_atom_mode = !add_atom_mode
1243
- return
1244
- }
1245
- // Change element of selected atoms
1246
- if (key === `e` && plain && selected_sites.length > 0) {
1247
- event.preventDefault()
1248
- change_element_mode = !change_element_mode
1249
- return
1250
- }
1251
- // Duplicate selected atoms at a small offset
1252
- if (
1253
- key === `d` && (event.ctrlKey || event.metaKey) &&
1254
- selected_sites.length > 0 && structure?.sites
1255
- ) {
1256
- event.preventDefault()
1257
- is_internal_edit = true
1258
- push_undo()
1259
- const orig_indices = scene_to_structure_indices(selected_sites)
1260
- const cart_to_frac = get_cart_to_frac()
1261
- const new_sites = structure.sites
1262
- .filter((_, idx) => orig_indices.has(idx))
1263
- .map((site) => {
1264
- const new_xyz: Vec3 = [
1265
- site.xyz[0] + 0.5,
1266
- site.xyz[1] + 0.5,
1267
- site.xyz[2] + 0.5,
1268
- ]
1269
- return {
1270
- ...site,
1271
- xyz: new_xyz,
1272
- abc: cart_to_frac?.(new_xyz) ?? new_xyz,
1273
- properties: { ...site.properties },
1274
- }
1275
- })
1276
- const base_idx = structure.sites.length
1277
- structure = {
1278
- ...structure,
1279
- sites: [...structure.sites, ...new_sites],
1280
- }
1281
- // Select the newly duplicated atoms
1282
- selected_sites = new_sites.map((_, idx) => base_idx + idx)
1283
- measured_sites = [...selected_sites]
1284
- show_toast(
1285
- `Duplicated ${new_sites.length} site${new_sites.length > 1 ? `s` : ``}`,
1286
- )
1287
- return
1288
- }
1289
-
1290
- // add_atom_mode Escape is already handled above (before is_input_focused guard)
1291
- if (event.key === `Escape`) {
1292
- if (change_element_mode) {
1293
- change_element_mode = false
1294
- return
1295
- }
1296
- if (selected_sites.length > 0) {
1297
- clear_selection()
1298
- return
1299
- }
1300
- }
1301
- }
1302
-
1303
- // Interface shortcuts (require Ctrl/Cmd modifier to avoid accidental triggers)
1304
- const has_modifier = event.ctrlKey || event.metaKey
1305
- if (event.key === `f` && has_modifier && fullscreen_toggle) {
1306
- event.preventDefault()
1307
- toggle_fullscreen(wrapper)
1308
- } else if (event.key === `i` && has_modifier && enable_info_pane) {
1309
- event.preventDefault()
1310
- info_pane_open = !info_pane_open
1311
- } else if (event.key === `Escape`) {
1312
- // Prioritize closing panes, then exit edit modes, then exit fullscreen
1313
- if (info_pane_open) info_pane_open = false
1314
- else if (controls_open) controls_open = false
1315
- else if (export_pane_open) export_pane_open = false
1316
- else if (measure_mode === `edit-bonds` || measure_mode === `edit-atoms`) {
1317
- measure_mode = `distance`
1318
- }
1319
- }
1320
- }
1321
-
1322
- // === Edit-atoms mode helpers ===
1323
-
1324
- // Map scene indices (into displayed_structure) back to raw structure indices.
1325
- // Handles supercell atoms via orig_unit_cell_idx property.
1326
- // skip_image_atoms: when true, image atoms (PBC ghosts) are excluded from the result.
1327
- function scene_to_structure_indices(
1328
- scene_indices: number[],
1329
- skip_image_atoms = false,
1330
- ): SvelteSet<number> {
1331
- const result = new SvelteSet<number>()
1332
- for (const scene_idx of scene_indices) {
1333
- const displayed_site = displayed_structure?.sites?.[scene_idx]
1334
- if (!displayed_site) continue
1335
- if (skip_image_atoms && displayed_site.properties?.orig_site_idx != null) {
1336
- continue
1337
- }
1338
-
1339
- if (has_supercell && displayed_site.properties?.orig_unit_cell_idx != null) {
1340
- result.add(displayed_site.properties.orig_unit_cell_idx as number)
1341
- } else if (displayed_site.properties?.orig_site_idx != null) {
1342
- // Image atom (PBC ghost) — map back to its original site index
1343
- result.add(displayed_site.properties.orig_site_idx as number)
1344
- } else {
1345
- result.add(scene_idx)
1346
- }
1347
- }
1348
- return result
1349
- }
1350
-
1351
- // Try to create a Cartesian→fractional converter for the current structure's lattice
1352
- function get_cart_to_frac(): ((xyz: Vec3) => Vec3) | undefined {
1353
- if (!structure || !(`lattice` in structure)) return undefined
1354
- try {
1355
- return create_cart_to_frac((structure as Crystal).lattice.matrix)
1356
- } catch {
1357
- console.warn(`Failed to compute lattice inverse for fractional coordinates`)
1358
- return undefined
1359
- }
1360
- }
1361
-
1362
- // Handle atom moves from TransformControls. Applies Cartesian delta and wraps
1363
- // fractional coords inline so normalize_fractional_coords hits its fast path.
1364
- function handle_sites_moved(scene_indices: number[], delta: Vec3) {
1365
- if (!structure?.sites) return
1366
- is_internal_edit = true
1367
-
1368
- const orig_indices = scene_to_structure_indices(scene_indices)
1369
- // For crystals, wrap to [0,1) inline so normalize_fractional_coords fast-paths.
1370
- // For molecules (no lattice), just apply the Cartesian delta directly.
1371
- const lattice = `lattice` in structure
1372
- ? (structure as Crystal).lattice.matrix
1373
- : null
1374
- const cart_to_frac = lattice ? create_cart_to_frac(lattice) : null
1375
- const frac_to_cart = lattice ? create_frac_to_cart(lattice) : null
1376
- structure = {
1377
- ...structure,
1378
- sites: structure.sites.map((site, idx) => {
1379
- if (!orig_indices.has(idx)) return site
1380
- const new_xyz: Vec3 = [
1381
- site.xyz[0] + delta[0],
1382
- site.xyz[1] + delta[1],
1383
- site.xyz[2] + delta[2],
1384
- ]
1385
- if (!cart_to_frac || !frac_to_cart) {
1386
- return { ...site, xyz: new_xyz, abc: new_xyz }
1387
- }
1388
- const wrapped_abc = wrap_to_unit_cell(cart_to_frac(new_xyz))
1389
- return { ...site, xyz: frac_to_cart(wrapped_abc), abc: wrapped_abc }
1390
- }),
1391
- }
1392
- }
1393
-
1394
- // Change element symbol of selected atoms
1395
- function handle_change_element(new_element: string) {
1396
- if (!structure?.sites || selected_sites.length === 0) return
1397
- const elem = normalize_element(new_element)
1398
- if (!elem) return
1399
- is_internal_edit = true
1400
- push_undo()
1401
- const orig_indices = scene_to_structure_indices(selected_sites)
1402
- structure = {
1403
- ...structure,
1404
- sites: structure.sites.map((site, idx) => {
1405
- if (!orig_indices.has(idx)) return site
1406
- return {
1407
- ...site,
1408
- species: [{ element: elem, occu: 1, oxidation_state: 0 }],
1409
- label: elem,
1410
- }
1411
- }),
1412
- }
1413
- change_element_mode = false
1414
- change_element_value = ``
1415
- show_toast(
1416
- `Changed ${orig_indices.size} site${
1417
- orig_indices.size > 1 ? `s` : ``
1418
- } to ${elem}`,
1419
- )
1420
- }
1421
-
1422
- // Handle add-atom from StructureScene click-to-place
1423
- function handle_add_atom(xyz: Vec3, element: ElementSymbol) {
1424
- if (!structure) return
1425
- const elem = normalize_element(element)
1426
- if (!elem) {
1427
- return console.warn(`Invalid element symbol "${element}", ignoring add-atom`)
1428
- }
1429
- is_internal_edit = true
1430
- push_undo()
1431
- structure = {
1432
- ...structure,
1433
- sites: [...structure.sites, {
1434
- species: [{ element: elem, occu: 1, oxidation_state: 0 }],
1435
- xyz,
1436
- abc: get_cart_to_frac()?.(xyz) ?? xyz,
1437
- label: elem,
1438
- properties: {},
1439
- }],
1440
- }
1441
- show_toast(`Added ${elem} at (${xyz.map((coord) => coord.toFixed(2)).join(`, `)})`)
1442
- }
1443
-
1444
- // Only set background override when background_color is explicitly provided
1445
- $effect(() => {
1446
- if (typeof window !== `undefined` && wrapper && background_color) {
1447
- // Convert opacity (0-1) to hex alpha value (00-FF)
1448
- const alpha_hex = Math.round(background_opacity * 255)
1449
- .toString(16)
1450
- .padStart(2, `0`)
1451
- wrapper.style.setProperty(
1452
- `--struct-bg-override`,
1453
- `${background_color}${alpha_hex}`,
1454
- )
1455
- } else if (typeof window !== `undefined` && wrapper) {
1456
- // Remove override to use theme system
1457
- wrapper.style.removeProperty(`--struct-bg-override`)
1458
- }
1459
- })
1460
-
1461
- $effect(() => { // fullscreen and background
1462
- if (typeof window !== `undefined`) {
1463
- if (fullscreen && !document.fullscreenElement && wrapper) {
1464
- wrapper.requestFullscreen().catch(console.error)
1465
- } else if (!fullscreen && document.fullscreenElement) {
1466
- document.exitFullscreen()
1467
- }
1468
- }
1469
- set_fullscreen_bg(wrapper, fullscreen, `--struct-bg-fullscreen`)
1470
- })
1471
- </script>
1472
-
1473
- <svelte:document
1474
- onfullscreenchange={() => {
1475
- fullscreen = Boolean(document.fullscreenElement)
1476
- on_fullscreen_change?.({ structure, fullscreen })
1477
- }}
1478
- />
1479
-
1480
- <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
1481
- <div
1482
- class:dragover
1483
- class:active={info_pane_open || controls_open || export_pane_open}
1484
- class:gizmo-visible={Boolean(scene_gizmo)}
1485
- role="application"
1486
- tabindex="0"
1487
- style:--canvas-cursor={canvas_cursor}
1488
- aria-label="Structure viewer"
1489
- bind:this={wrapper}
1490
- bind:clientWidth={width}
1491
- bind:clientHeight={height}
1492
- onmouseenter={() => (hovered = true)}
1493
- onmouseleave={() => (hovered = false)}
1494
- onfocusin={() => (focused = true)}
1495
- onfocusout={(event) => {
1496
- if (!(event.relatedTarget instanceof Node) || !wrapper?.contains(event.relatedTarget)) {
1497
- focused = false
1498
- }
1499
- }}
1500
- ondblclick={(event) => {
1501
- const target = event.target
1502
- if (!(target instanceof HTMLElement)) return
1503
- // Don't reset if double-click was on UI controls/panes/legend
1504
- 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`
1514
- ) return
1515
- // Reset camera for double-clicks on the 3D scene
1516
- reset_camera()
1517
- }}
1518
- ondrop={handle_file_drop}
1519
- ondragover={(event) => {
1520
- event.preventDefault()
1521
- if (!allow_file_drop) return
1522
- dragover = true
1523
- }}
1524
- ondragleave={(event) => {
1525
- event.preventDefault()
1526
- dragover = false
1527
- }}
1528
- onkeydown={handle_keydown}
1529
- {...rest}
1530
- class="structure {rest.class ?? ``}"
1531
- >
1532
- {@render children?.({ structure, fullscreen })}
1533
- {#if loading}
1534
- <Spinner
1535
- text="Loading structure..."
1536
- {...spinner_props}
1537
- style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%)"
1538
- />
1539
- {:else if error_msg}
1540
- <StatusMessage bind:message={error_msg} type="error" dismissible />
1541
- {:else if (structure?.sites?.length ?? 0) > 0}
1542
- <section
1543
- class="control-buttons {controls_config.class}"
1544
- style={controls_config.style}
1545
- >
1546
- {#if controls_config.mode !== `never`}
1547
- {#if camera_has_moved && controls_config.visible(`reset-camera`)}
1548
- <button class="reset-camera" onclick={reset_camera} title={reset_text}>
1549
- <!-- Target/Focus icon for reset camera -->
1550
- <Icon icon="Reset" />
1551
- </button>
1552
- {/if}
1553
- {#if fullscreen_toggle && controls_config.visible(`fullscreen`)}
1554
- <button
1555
- type="button"
1556
- onclick={() => fullscreen_toggle && toggle_fullscreen(wrapper)}
1557
- title="{fullscreen ? `Exit` : `Enter`} fullscreen"
1558
- aria-pressed={fullscreen}
1559
- class="fullscreen-toggle"
1560
- style="padding: 0 3px"
1561
- {@attach tooltip()}
1562
- >
1563
- {#if typeof fullscreen_toggle === `function`}
1564
- {@render fullscreen_toggle({ fullscreen })}
1565
- {:else}
1566
- <Icon icon="{fullscreen ? `Exit` : ``}Fullscreen" />
1567
- {/if}
1568
- </button>
1569
- {/if}
1570
-
1571
- {#if enable_measure_mode && controls_config.visible(`measure-mode`)}
1572
- <div
1573
- class="measure-mode-dropdown"
1574
- {@attach click_outside({ callback: () => measure_menu_open = false })}
1575
- >
1576
- <button
1577
- onclick={() => (measure_menu_open = !measure_menu_open)}
1578
- title="Measure / Edit"
1579
- class="view-mode-button"
1580
- class:active={measure_menu_open}
1581
- aria-expanded={measure_menu_open}
1582
- style="transform: scale(1.2)"
1583
- >
1584
- {#if show_measure_selection_limit}
1585
- <span class="selection-limit-text">
1586
- {measured_sites.length}/{MAX_SELECTED_SITES}
1587
- </span>
1588
- {:else}
1589
- <Icon
1590
- icon={({
1591
- distance: `Ruler`,
1592
- angle: `Angle`,
1593
- 'edit-bonds': `Link`,
1594
- 'edit-atoms': `Edit`,
1595
- } as const)[measure_mode]}
1596
- />
1597
- {/if}
1598
- <Icon
1599
- icon="Arrow{measure_menu_open ? `Up` : `Down`}"
1600
- style="margin-left: -2px"
1601
- />
1602
- </button>
1603
- {#if show_selection_reset}
1604
- <button
1605
- type="button"
1606
- aria-label="Reset selection and bond edits"
1607
- onclick={() => {
1608
- clear_selection()
1609
- clear_bond_edits()
1610
- }}
1611
- >
1612
- <Icon icon="Reset" style="margin-left: -4px" />
1613
- </button>
1614
- {/if}
1615
- {#if measure_menu_open}
1616
- <div class="view-mode-dropdown">
1617
- {#each [
1618
- { mode: `distance`, icon: `Ruler`, label: `Distance`, scale: 1.1 },
1619
- { 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
- }
1636
- <button
1637
- class="view-mode-option"
1638
- class:selected={measure_mode === mode}
1639
- disabled={mode === `edit-bonds` && !bond_edits_enabled}
1640
- title={mode === `edit-bonds` && !bond_edits_enabled
1641
- ? `Bond editing is only available for the original 1x1x1 cell`
1642
- : label}
1643
- onclick={() => {
1644
- if (mode === `edit-bonds` && !bond_edits_enabled) return
1645
- ;[measure_mode, measure_menu_open] = [mode, false]
1646
- }}
1647
- >
1648
- <Icon {icon} style="transform: scale({scale})" />
1649
- <span>{label}</span>
1650
- </button>
1651
- {/each}
1652
- </div>
1653
- {/if}
1654
- </div>
1655
-
1656
- <!-- Undo/redo buttons (only in edit-atoms mode) -->
1657
- {#if measure_mode === `edit-atoms`}
1658
- <div class="undo-redo-container">
1659
- <button
1660
- type="button"
1661
- aria-label="Undo (Cmd/Ctrl+Z)"
1662
- disabled={undo_stack.length === 0}
1663
- onclick={undo}
1664
- title="Undo (Cmd/Ctrl+Z)"
1665
- class="undo-redo-btn"
1666
- >
1667
- <Icon icon="Undo" />
1668
- {#if undo_stack.length > 0}
1669
- <span class="history-count">{undo_stack.length}</span>
1670
- {/if}
1671
- </button>
1672
- <button
1673
- type="button"
1674
- aria-label="Redo (Cmd/Ctrl+Y or Cmd+Shift+Z)"
1675
- disabled={redo_stack.length === 0}
1676
- onclick={redo}
1677
- title="Redo (Cmd/Ctrl+Y or Cmd+Shift+Z)"
1678
- class="undo-redo-btn"
1679
- >
1680
- <Icon icon="Redo" />
1681
- {#if redo_stack.length > 0}
1682
- <span class="history-count">{redo_stack.length}</span>
1683
- {/if}
1684
- </button>
1685
- </div>
1686
- {/if}
1687
-
1688
- {#if measure_mode === `edit-bonds`}
1689
- <div class="bond-edit-toolbar" aria-label="Bond editing controls">
1690
- {#if bond_edit_mode === `add`}
1691
- <label>
1692
- <span>Bond order</span>
1693
- <select bind:value={bond_edit_order}>
1694
- {#each BOND_ORDER_OPTIONS as { order, label } (label)}
1695
- <option value={order}>{label}</option>
1696
- {/each}
1697
- </select>
1698
- </label>
1699
- {/if}
1700
- <div class="bond-edit-mode-toggle">
1701
- {#each [
1702
- { mode: `add`, label: `Add`, title: `Add: click two atoms` },
1703
- { mode: `delete`, label: `Delete`, title: `Delete: click a bond` },
1704
- ] as const as { mode, label, title } (mode)}
1705
- <button
1706
- type="button"
1707
- class:selected={bond_edit_mode === mode}
1708
- aria-pressed={bond_edit_mode === mode}
1709
- title="{title} ({label[0]})"
1710
- onclick={() => (bond_edit_mode = mode)}
1711
- >
1712
- {label}
1713
- </button>
1714
- {/each}
1715
- </div>
1716
- </div>
1717
- <div class="undo-redo-container">
1718
- <button
1719
- type="button"
1720
- aria-label="Undo bond edit (Cmd/Ctrl+Z)"
1721
- disabled={bond_undo_stack.length === 0}
1722
- onclick={undo_bond_edit}
1723
- title="Undo bond edit (Cmd/Ctrl+Z)"
1724
- class="undo-redo-btn"
1725
- >
1726
- <Icon icon="Undo" />
1727
- {#if bond_undo_stack.length > 0}
1728
- <span class="history-count">{bond_undo_stack.length}</span>
1729
- {/if}
1730
- </button>
1731
- <button
1732
- type="button"
1733
- aria-label="Redo bond edit (Cmd/Ctrl+Y or Cmd+Shift+Z)"
1734
- disabled={bond_redo_stack.length === 0}
1735
- onclick={redo_bond_edit}
1736
- title="Redo bond edit (Cmd/Ctrl+Y or Cmd+Shift+Z)"
1737
- class="undo-redo-btn"
1738
- >
1739
- <Icon icon="Redo" />
1740
- {#if bond_redo_stack.length > 0}
1741
- <span class="history-count">{bond_redo_stack.length}</span>
1742
- {/if}
1743
- </button>
1744
- </div>
1745
- {/if}
1746
-
1747
- <!-- Add-atom element input (shown when add_atom_mode is active) -->
1748
- {#if measure_mode === `edit-atoms` && add_atom_mode}
1749
- <div class="add-atom-input">
1750
- <label>
1751
- <span>Element:</span>
1752
- <input
1753
- type="text"
1754
- bind:value={add_element}
1755
- maxlength="2"
1756
- placeholder="C"
1757
- style="width: 3em; text-align: center"
1758
- />
1759
- </label>
1760
- <span style="font-size: 0.75em; opacity: 0.7">Click to place</span>
1761
- </div>
1762
- {/if}
1763
-
1764
- <!-- Change-element input (shown when 'e' pressed with selection) -->
1765
- {#if measure_mode === `edit-atoms` && change_element_mode &&
1766
- selected_sites.length > 0}
1767
- <div class="add-atom-input">
1768
- <label>
1769
- <span>New element:</span>
1770
- <input
1771
- type="text"
1772
- bind:value={change_element_value}
1773
- maxlength="2"
1774
- placeholder="Fe"
1775
- style="width: 3em; text-align: center"
1776
- onkeydown={(event: KeyboardEvent) => {
1777
- if (event.key === `Enter`) {
1778
- handle_change_element(change_element_value)
1779
- } else if (event.key === `Escape`) {
1780
- change_element_mode = false
1781
- }
1782
- event.stopPropagation()
1783
- }}
1784
- {@attach (node: HTMLInputElement) => {
1785
- node.focus()
1786
- }}
1787
- />
1788
- </label>
1789
- <span style="font-size: 0.75em; opacity: 0.7">Enter to apply</span>
1790
- </div>
1791
- {/if}
1792
- {/if}
1793
-
1794
- {#if enable_info_pane && normalized_structure &&
1795
- controls_config.visible(`info-pane`)}
1796
- <StructureInfoPane
1797
- structure={normalized_structure}
1798
- bind:pane_open={info_pane_open}
1799
- bind:highlighted_sites
1800
- bind:hovered_site_idx
1801
- bind:selected_sites
1802
- {sym_data}
1803
- {@attach tooltip({ content: `Structure info pane` })}
1804
- />
1805
- {/if}
1806
-
1807
- {#if controls_config.visible(`export-pane`)}
1808
- <StructureExportPane
1809
- bind:export_pane_open
1810
- structure={normalized_structure}
1811
- {wrapper}
1812
- {scene}
1813
- {camera}
1814
- bind:png_dpi
1815
- pane_props={{ style: `max-height: calc(${height}px - 50px)` }}
1816
- />
1817
- {/if}
1818
-
1819
- {#if controls_config.visible(`controls`)}
1820
- <StructureControls
1821
- bind:controls_open
1822
- bind:scene_props
1823
- bind:lattice_props
1824
- bind:show_image_atoms
1825
- bind:supercell_scaling
1826
- bind:background_color
1827
- bind:background_opacity
1828
- bind:color_scheme
1829
- bind:atom_color_config
1830
- bind:cell_type
1831
- bind:volumetric_data
1832
- bind:isosurface_settings
1833
- bind:active_volume_idx
1834
- {structure}
1835
- {supercell_loading}
1836
- {sym_data}
1837
- />
1838
- {/if}
1839
-
1840
- {@render top_right_controls?.()}
1841
- {/if}
1842
- </section>
1843
-
1844
- <AtomLegend
1845
- bind:atom_color_config
1846
- {property_colors}
1847
- elements={get_element_counts(supercell_structure ?? structure!)}
1848
- bind:hidden_elements
1849
- bind:hidden_prop_vals
1850
- bind:element_mapping
1851
- bind:element_radius_overrides
1852
- bind:site_radius_overrides
1853
- selected_sites={atom_legend_selected_sites}
1854
- structure={displayed_structure}
1855
- show_mode_toggle={viewer_active}
1856
- {sym_data}
1857
- >
1858
- {#if structure && `lattice` in structure}
1859
- <CellSelect
1860
- bind:supercell_scaling
1861
- bind:cell_type
1862
- {sym_data}
1863
- loading={supercell_loading}
1864
- direction="up"
1865
- />
1866
- {/if}
1867
- </AtomLegend>
1868
-
1869
- <!-- prevent from rendering in vitest runner since WebGLRenderingContext not available -->
1870
- {#if typeof WebGLRenderingContext !== `undefined`}
1871
- <!-- prevent HTML labels from rendering outside of the canvas -->
1872
- <div style="overflow: hidden; height: 100%; width: 100%">
1873
- <Canvas>
1874
- <StructureScene
1875
- structure={displayed_structure}
1876
- base_structure={cell_transformed_structure}
1877
- {...scene_props}
1878
- gizmo={scene_gizmo}
1879
- {lattice_props}
1880
- volumetric_data={supercell_volume}
1881
- {isosurface_settings}
1882
- bind:camera_is_moving
1883
- bind:selected_sites
1884
- active_sites={active_scene_sites}
1885
- bind:hovered_idx={hovered_site_idx}
1886
- bind:measured_sites
1887
- bind:scene
1888
- bind:camera
1889
- bind:orbit_controls
1890
- bind:rotation_target_ref
1891
- bind:initial_computed_zoom
1892
- bind:hidden_elements
1893
- bind:hidden_prop_vals
1894
- bind:element_radius_overrides
1895
- bind:site_radius_overrides
1896
- bind:added_bonds
1897
- bind:removed_bonds
1898
- bind:bond_order_overrides
1899
- {bond_edits_enabled}
1900
- bind:bond_edit_mode
1901
- {bond_edit_order}
1902
- {measure_mode}
1903
- {width}
1904
- {height}
1905
- {atom_color_config}
1906
- {sym_data}
1907
- on_sites_moved={handle_sites_moved}
1908
- on_operation_start={push_undo}
1909
- on_bond_edit_start={push_bond_undo}
1910
- on_add_atom={handle_add_atom}
1911
- bind:add_atom_mode
1912
- bind:add_element
1913
- bind:cursor={canvas_cursor}
1914
- bind:dragging_atoms
1915
- />
1916
- </Canvas>
1917
- </div>
1918
- {/if}
1919
-
1920
- <div class="bottom-left">
1921
- {@render bottom_left?.({ structure: displayed_structure })}
1922
- </div>
1923
-
1924
- {#if toast_msg}
1925
- <div class="edit-toast">{toast_msg}</div>
1926
- {/if}
1927
-
1928
- {#if symmetry_error}
1929
- <div class="symmetry-error">
1930
- <span>{symmetry_error}</span>
1931
- <button onclick={() => (symmetry_error = undefined)} aria-label="Dismiss">
1932
- ×
1933
- </button>
1934
- </div>
1935
- {/if}
1936
- {:else if structure}
1937
- <p class="warn">No sites found in structure</p>
1938
- {:else}
1939
- <p class="warn">No structure provided</p>
1940
- {/if}
1941
- </div>
1942
-
1943
- <style>
1944
- .structure {
1945
- position: relative;
1946
- container-type: size; /* enable cqh/cqw for internal panes */
1947
- height: var(--struct-height, 500px);
1948
- width: var(--struct-width, 100%);
1949
- max-width: var(--struct-max-width, 100%);
1950
- min-width: var(--struct-min-width, 300px);
1951
- border-radius: var(--struct-border-radius, var(--border-radius, 3pt));
1952
- background: var(--struct-bg-override, var(--struct-bg));
1953
- color: var(--struct-text-color);
1954
- display: flex;
1955
- }
1956
- .structure.active {
1957
- z-index: var(--struct-active-z-index, 2);
1958
- }
1959
- .structure:fullscreen {
1960
- background: var(--struct-bg-fullscreen, var(--struct-bg));
1961
- overflow: hidden;
1962
- }
1963
- .structure:fullscreen :global(canvas) {
1964
- height: 100vh !important;
1965
- width: 100vw !important;
1966
- }
1967
- .structure.dragover {
1968
- background: var(--struct-dragover-bg, var(--dragover-bg));
1969
- border: var(--struct-dragover-border, var(--dragover-border));
1970
- }
1971
- /* Ensure canvas is transparent so the themed --struct-bg shows through */
1972
- .structure :global(canvas) {
1973
- background: transparent;
1974
- cursor: var(--canvas-cursor, default);
1975
- }
1976
- .structure:not(.gizmo-visible) :global(.responsive-gizmo) {
1977
- opacity: 0;
1978
- pointer-events: none;
1979
- visibility: hidden;
1980
- }
1981
- /* Avoid accidental text selection while interacting with the viewer */
1982
- .structure :global(canvas),
1983
- .structure section.control-buttons,
1984
- .structure .bottom-left {
1985
- user-select: none;
1986
- }
1987
- div.bottom-left {
1988
- position: absolute;
1989
- bottom: 0;
1990
- left: 0;
1991
- font-size: var(--struct-bottom-left-font-size, 1.2em);
1992
- padding: var(--struct-bottom-left-padding, 1pt 5pt);
1993
- }
1994
- section.control-buttons {
1995
- position: absolute;
1996
- display: flex;
1997
- top: var(--struct-buttons-top, var(--ctrl-btn-top, 1ex));
1998
- right: var(--struct-buttons-right, var(--ctrl-btn-right, 1ex));
1999
- gap: 4pt;
2000
- /* buttons need higher z-index than AtomLegend to make info/controls panes occlude legend */
2001
- /* we also need crazy high z-index to make info/control pane occlude threlte/extras' <HTML> elements for site labels */
2002
- z-index: var(
2003
- --struct-buttons-z-index,
2004
- var(--z-index-overlay-controls, 100000000)
2005
- );
2006
- opacity: 0;
2007
- pointer-events: none;
2008
- transition: opacity 0.2s ease;
2009
- }
2010
- /* Mode: always - controls always visible */
2011
- section.control-buttons.always-visible {
2012
- opacity: 1;
2013
- pointer-events: auto;
2014
- }
2015
- /* Mode: hover - controls visible on component hover */
2016
- .structure:hover section.control-buttons.hover-visible,
2017
- .structure:focus-within section.control-buttons.hover-visible {
2018
- opacity: 1;
2019
- pointer-events: auto;
2020
- }
2021
- /* Mode: never - stays hidden (default state, no additional CSS needed) */
2022
- section.control-buttons > :global(button) {
2023
- background-color: transparent;
2024
- display: flex;
2025
- padding: 1px 6px;
2026
- border-radius: var(--border-radius, 3pt);
2027
- font-size: clamp(0.85em, 2cqmin, 1.3em);
2028
- }
2029
- section.control-buttons :global(button:hover) {
2030
- background-color: color-mix(in srgb, currentColor 8%, transparent);
2031
- }
2032
- /* Match Trajectory dropdown UI */
2033
- .view-mode-dropdown {
2034
- position: absolute;
2035
- top: 115%;
2036
- right: 0;
2037
- background: var(--surface-bg);
2038
- border-radius: var(--border-radius, 3pt);
2039
- box-shadow: 0 8px 16px -4px rgba(0, 0, 0, 0.3), 0 4px 8px -2px rgba(0, 0, 0, 0.1);
2040
- display: flex;
2041
- flex-direction: column;
2042
- }
2043
- .view-mode-option {
2044
- display: flex;
2045
- align-items: center;
2046
- gap: 1ex;
2047
- width: 100%;
2048
- padding: var(--trajectory-view-mode-option-padding, 5pt);
2049
- box-sizing: border-box;
2050
- background: transparent;
2051
- border-radius: 0;
2052
- text-align: left;
2053
- transition: background-color 0.15s ease;
2054
- }
2055
- .view-mode-option:first-child {
2056
- border-top-left-radius: 3px;
2057
- border-top-right-radius: 3px;
2058
- }
2059
- .view-mode-option.selected {
2060
- color: var(--accent-color);
2061
- }
2062
- .view-mode-option span {
2063
- font-weight: 500;
2064
- white-space: nowrap;
2065
- overflow: hidden;
2066
- text-overflow: ellipsis;
2067
- flex: 1;
2068
- }
2069
- .measure-mode-dropdown {
2070
- display: flex;
2071
- position: relative;
2072
- height: fit-content;
2073
- place-self: center;
2074
- }
2075
- .measure-mode-dropdown > button {
2076
- background: transparent;
2077
- padding: 1px 6px;
2078
- font-size: clamp(0.85em, 2cqmin, 1.3em);
2079
- }
2080
- .selection-limit-text {
2081
- font-weight: bold;
2082
- font-size: 0.9em;
2083
- color: var(--accent-color, #ff6b6b);
2084
- min-width: 2.5em;
2085
- text-align: center;
2086
- }
2087
- p.warn {
2088
- position: absolute;
2089
- inset: 0;
2090
- display: grid;
2091
- place-content: center;
2092
- }
2093
- .symmetry-error {
2094
- position: absolute;
2095
- bottom: 1rem;
2096
- right: 1rem;
2097
- background: rgba(255, 165, 0, 0.95);
2098
- color: #000;
2099
- padding: 0.75rem 1rem;
2100
- border-radius: var(--border-radius, 3pt);
2101
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
2102
- display: flex;
2103
- gap: 1rem;
2104
- max-width: min(90%, 400px);
2105
- font-size: 0.9rem;
2106
- z-index: 1000;
2107
- }
2108
- .symmetry-error span {
2109
- flex: 1;
2110
- }
2111
- .symmetry-error button {
2112
- background: transparent;
2113
- border: none;
2114
- font-size: 1.5rem;
2115
- line-height: 1;
2116
- padding: 0;
2117
- cursor: pointer;
2118
- opacity: 0.7;
2119
- }
2120
- .symmetry-error button:hover {
2121
- opacity: 1;
2122
- }
2123
- .edit-toast {
2124
- position: absolute;
2125
- bottom: 3rem;
2126
- left: 50%;
2127
- transform: translateX(-50%);
2128
- background: color-mix(in srgb, var(--page-bg, Canvas) 85%, currentColor);
2129
- color: var(--text-color, currentColor);
2130
- padding: 0.4rem 0.8rem;
2131
- border-radius: var(--border-radius, 3pt);
2132
- font-size: 0.8rem;
2133
- z-index: 100;
2134
- pointer-events: none;
2135
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
2136
- animation: toast-fade 2s ease-in-out;
2137
- opacity: 0;
2138
- }
2139
- @keyframes toast-fade {
2140
- 0%, 70% {
2141
- opacity: 1;
2142
- }
2143
- 100% {
2144
- opacity: 0;
2145
- }
2146
- }
2147
- /* CellSelect: position at left of legend, show on hover */
2148
- .structure :global(.cell-select) {
2149
- order: -1; /* Move to left side of AtomLegend flex container */
2150
- opacity: 0;
2151
- pointer-events: none;
2152
- transition: opacity 0.3s ease;
2153
- }
2154
- .structure:hover :global(.cell-select) {
2155
- opacity: 1;
2156
- pointer-events: auto;
2157
- }
2158
- .undo-redo-container {
2159
- display: flex;
2160
- }
2161
- .undo-redo-btn {
2162
- position: relative;
2163
- display: flex;
2164
- align-items: center;
2165
- justify-content: center;
2166
- }
2167
- .bond-edit-toolbar {
2168
- --bond-edit-control-height: 1.8em;
2169
- display: flex;
2170
- align-items: center;
2171
- gap: 0.4em;
2172
- font-size: 0.8em;
2173
- }
2174
- .bond-edit-mode-toggle,
2175
- .bond-edit-toolbar label {
2176
- display: flex;
2177
- align-items: center;
2178
- }
2179
- .bond-edit-mode-toggle {
2180
- gap: 0.35em;
2181
- }
2182
- .bond-edit-mode-toggle button,
2183
- .bond-edit-toolbar label,
2184
- .bond-edit-toolbar select {
2185
- height: var(--bond-edit-control-height);
2186
- line-height: 1;
2187
- }
2188
- .bond-edit-mode-toggle button {
2189
- min-width: 3.5em;
2190
- font: inherit;
2191
- }
2192
- .bond-edit-mode-toggle button.selected {
2193
- background: var(--accent-color, #007acc);
2194
- color: white;
2195
- }
2196
- .bond-edit-mode-toggle button.selected:hover {
2197
- background-color: color-mix(in srgb, var(--accent-color, #007acc) 70%, black);
2198
- }
2199
- .bond-edit-toolbar label {
2200
- gap: 0.25em;
2201
- }
2202
- .bond-edit-toolbar select {
2203
- max-width: 8em;
2204
- font: inherit;
2205
- }
2206
- .history-count {
2207
- position: absolute;
2208
- bottom: -2px;
2209
- right: -2px;
2210
- background: var(--accent-color, #007acc);
2211
- color: white;
2212
- border-radius: 50%;
2213
- width: 12px;
2214
- height: 12px;
2215
- font-size: 8px;
2216
- font-weight: bold;
2217
- display: flex;
2218
- align-items: center;
2219
- justify-content: center;
2220
- line-height: 1;
2221
- pointer-events: none;
2222
- z-index: 1;
2223
- }
2224
- .add-atom-input {
2225
- display: flex;
2226
- align-items: center;
2227
- gap: 0.5em;
2228
- background: color-mix(in srgb, var(--page-bg, Canvas) 85%, currentColor);
2229
- color: var(--text-color, currentColor);
2230
- padding: 0.3em 0.6em;
2231
- border-radius: var(--border-radius, 3pt);
2232
- font-size: 0.8rem;
2233
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
2234
- label {
2235
- display: flex;
2236
- align-items: center;
2237
- gap: 0.3em;
2238
- }
2239
- input {
2240
- background: color-mix(in srgb, currentColor 10%, transparent);
2241
- border: 1px solid color-mix(in srgb, currentColor 20%, transparent);
2242
- border-radius: 3px;
2243
- color: inherit;
2244
- font-size: 0.85rem;
2245
- padding: 0.1em 0.3em;
2246
- }
2247
- }
2248
- </style>