matterviz 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/dist/FilePicker.svelte +40 -50
  2. package/dist/api/optimade.js +10 -7
  3. package/dist/app.css +15 -0
  4. package/dist/brillouin/BrillouinZone.svelte +18 -9
  5. package/dist/brillouin/BrillouinZoneScene.svelte +20 -29
  6. package/dist/brillouin/compute.js +10 -16
  7. package/dist/brillouin/geometry.js +2 -2
  8. package/dist/chempot-diagram/ChemPotDiagram.svelte +18 -15
  9. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +17 -113
  10. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +104 -264
  11. package/dist/chempot-diagram/async-compute.svelte.js +12 -13
  12. package/dist/chempot-diagram/color.d.ts +21 -1
  13. package/dist/chempot-diagram/color.js +70 -1
  14. package/dist/chempot-diagram/compute.d.ts +7 -0
  15. package/dist/chempot-diagram/compute.js +85 -26
  16. package/dist/chempot-diagram/export.js +1 -6
  17. package/dist/chempot-diagram/temperature.js +9 -10
  18. package/dist/composition/BarChart.svelte +7 -9
  19. package/dist/composition/Composition.svelte +3 -8
  20. package/dist/composition/Formula.svelte +2 -2
  21. package/dist/composition/FormulaFilter.svelte +27 -93
  22. package/dist/composition/format.js +6 -8
  23. package/dist/composition/parse.js +50 -105
  24. package/dist/constants.d.ts +0 -1
  25. package/dist/constants.js +6 -17
  26. package/dist/convex-hull/ConvexHull2D.svelte +0 -2
  27. package/dist/convex-hull/ConvexHull3D.svelte +19 -47
  28. package/dist/convex-hull/ConvexHull4D.svelte +65 -95
  29. package/dist/convex-hull/StructurePopup.svelte +1 -1
  30. package/dist/convex-hull/gas-thermodynamics.js +21 -53
  31. package/dist/convex-hull/helpers.js +1 -7
  32. package/dist/convex-hull/thermodynamics.js +19 -27
  33. package/dist/coordination/CoordinationBarPlot.svelte +12 -21
  34. package/dist/element/BohrAtom.svelte +0 -1
  35. package/dist/element/ElementTile.svelte +26 -44
  36. package/dist/element/data.d.ts +2 -0
  37. package/dist/element/data.js +5 -1
  38. package/dist/element/index.d.ts +1 -1
  39. package/dist/element/index.js +1 -1
  40. package/dist/fermi-surface/FermiSurface.svelte +22 -23
  41. package/dist/fermi-surface/FermiSurface.svelte.d.ts +2 -6
  42. package/dist/fermi-surface/FermiSurfaceScene.svelte +32 -77
  43. package/dist/fermi-surface/compute.js +22 -55
  44. package/dist/fermi-surface/parse.js +38 -70
  45. package/dist/file-viewer/JsonBrowser.svelte +1043 -0
  46. package/dist/file-viewer/JsonBrowser.svelte.d.ts +9 -0
  47. package/dist/file-viewer/PlotPanel.svelte +350 -0
  48. package/dist/file-viewer/PlotPanel.svelte.d.ts +9 -0
  49. package/dist/file-viewer/TrajectoryWithDos.svelte +30 -0
  50. package/dist/file-viewer/TrajectoryWithDos.svelte.d.ts +10 -0
  51. package/dist/file-viewer/detect.d.ts +11 -0
  52. package/dist/file-viewer/detect.js +381 -0
  53. package/dist/file-viewer/eligibility.d.ts +4 -0
  54. package/dist/file-viewer/eligibility.js +53 -0
  55. package/dist/file-viewer/host-protocol.d.ts +50 -0
  56. package/dist/file-viewer/host-transfer.d.ts +25 -0
  57. package/dist/file-viewer/host-transfer.js +42 -0
  58. package/dist/file-viewer/index.d.ts +5 -0
  59. package/dist/file-viewer/index.js +5 -0
  60. package/dist/file-viewer/main.d.ts +44 -0
  61. package/dist/file-viewer/main.js +535 -0
  62. package/dist/file-viewer/parse.d.ts +9 -0
  63. package/dist/file-viewer/parse.js +170 -0
  64. package/dist/file-viewer/plot-utils.d.ts +24 -0
  65. package/dist/file-viewer/plot-utils.js +191 -0
  66. package/dist/file-viewer/types.d.ts +4 -0
  67. package/dist/file-viewer/types.js +5 -0
  68. package/dist/heatmap-matrix/HeatmapMatrix.svelte +57 -84
  69. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
  70. package/dist/index.d.ts +2 -2
  71. package/dist/index.js +1 -1
  72. package/dist/io/ExportPane.svelte +1 -1
  73. package/dist/io/decompress.d.ts +2 -0
  74. package/dist/io/decompress.js +3 -2
  75. package/dist/io/export.d.ts +7 -4
  76. package/dist/io/export.js +70 -18
  77. package/dist/io/file-drop.js +60 -35
  78. package/dist/io/url-drop.d.ts +2 -0
  79. package/dist/io/url-drop.js +28 -16
  80. package/dist/isosurface/Isosurface.svelte +687 -196
  81. package/dist/isosurface/Isosurface.svelte.d.ts +7 -1
  82. package/dist/isosurface/IsosurfaceControls.svelte +564 -85
  83. package/dist/isosurface/IsosurfaceControls.svelte.d.ts +1 -1
  84. package/dist/isosurface/VolumeSlice.svelte +224 -0
  85. package/dist/isosurface/VolumeSlice.svelte.d.ts +28 -0
  86. package/dist/isosurface/coloring.d.ts +20 -0
  87. package/dist/isosurface/coloring.js +118 -0
  88. package/dist/isosurface/geometry-worker-types.d.ts +38 -0
  89. package/dist/isosurface/geometry.worker.d.ts +1 -0
  90. package/dist/isosurface/geometry.worker.js +59 -0
  91. package/dist/isosurface/grid.d.ts +10 -0
  92. package/dist/isosurface/grid.js +31 -0
  93. package/dist/isosurface/index.d.ts +4 -0
  94. package/dist/isosurface/index.js +4 -0
  95. package/dist/isosurface/profile.d.ts +12 -0
  96. package/dist/isosurface/profile.js +19 -0
  97. package/dist/isosurface/sampling.d.ts +34 -0
  98. package/dist/isosurface/sampling.js +408 -0
  99. package/dist/isosurface/slice-rendering.d.ts +13 -0
  100. package/dist/isosurface/slice-rendering.js +79 -0
  101. package/dist/isosurface/slice.d.ts +22 -2
  102. package/dist/isosurface/slice.js +200 -116
  103. package/dist/isosurface/types.d.ts +24 -1
  104. package/dist/isosurface/types.js +120 -8
  105. package/dist/json-path.d.ts +4 -0
  106. package/dist/json-path.js +89 -0
  107. package/dist/labels.js +1 -1
  108. package/dist/layout/InfoCard.svelte +1 -3
  109. package/dist/layout/SettingsSection.svelte +52 -61
  110. package/dist/layout/SettingsSection.svelte.d.ts +6 -7
  111. package/dist/layout/ViewerChrome.svelte +7 -1
  112. package/dist/layout/json-tree/JsonNode.svelte +14 -48
  113. package/dist/layout/json-tree/JsonTree.svelte +48 -95
  114. package/dist/layout/json-tree/JsonValue.svelte +3 -18
  115. package/dist/layout/json-tree/utils.d.ts +0 -3
  116. package/dist/layout/json-tree/utils.js +50 -179
  117. package/dist/marching-cubes.d.ts +8 -1
  118. package/dist/marching-cubes.js +115 -48
  119. package/dist/math.d.ts +3 -2
  120. package/dist/math.js +29 -38
  121. package/dist/overlays/ContextMenu.svelte +15 -32
  122. package/dist/overlays/DraggablePane.svelte +39 -58
  123. package/dist/overlays/DraggablePane.svelte.d.ts +1 -1
  124. package/dist/overlays/GlassChip.svelte +3 -1
  125. package/dist/periodic-table/PeriodicTableControls.svelte +26 -52
  126. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +18 -34
  127. package/dist/phase-diagram/build-diagram.js +1 -6
  128. package/dist/phase-diagram/svg-to-diagram.js +9 -14
  129. package/dist/plot/bar/BarPlot.svelte +38 -42
  130. package/dist/plot/bar/SpacegroupBarPlot.svelte +18 -42
  131. package/dist/plot/box/BoxPlot.svelte +27 -23
  132. package/dist/plot/core/auto-place.d.ts +1 -1
  133. package/dist/plot/core/auto-place.js +1 -1
  134. package/dist/plot/core/data-transform.d.ts +1 -2
  135. package/dist/plot/core/data-transform.js +0 -10
  136. package/dist/plot/core/layout.d.ts +12 -5
  137. package/dist/plot/core/layout.js +37 -27
  138. package/dist/plot/core/pan-zoom.svelte.d.ts +2 -4
  139. package/dist/plot/core/pan-zoom.svelte.js +34 -17
  140. package/dist/plot/core/placed-tween.svelte.d.ts +3 -0
  141. package/dist/plot/core/placed-tween.svelte.js +68 -21
  142. package/dist/plot/core/svg.js +0 -1
  143. package/dist/plot/core/utils/hierarchy-chart.d.ts +1 -0
  144. package/dist/plot/core/utils/hierarchy-chart.js +12 -0
  145. package/dist/plot/core/utils/hierarchy-labels.js +3 -2
  146. package/dist/plot/histogram/Histogram.svelte +21 -26
  147. package/dist/plot/sankey/sankey.js +13 -9
  148. package/dist/plot/scatter/BinnedScatterPlot.svelte +59 -43
  149. package/dist/plot/scatter/ScatterPlot.svelte +67 -52
  150. package/dist/plot/scatter/adaptive-density.d.ts +1 -1
  151. package/dist/plot/scatter/adaptive-density.js +36 -20
  152. package/dist/plot/sunburst/Sunburst.svelte +20 -20
  153. package/dist/plot/treemap/Treemap.svelte +175 -60
  154. package/dist/plot/treemap/Treemap.svelte.d.ts +6 -0
  155. package/dist/plot/treemap/index.d.ts +1 -0
  156. package/dist/plot/treemap/labels.d.ts +38 -0
  157. package/dist/plot/treemap/labels.js +80 -0
  158. package/dist/plot/treemap/treemap.d.ts +4 -2
  159. package/dist/plot/treemap/treemap.js +5 -2
  160. package/dist/rdf/RdfPlot.svelte +17 -35
  161. package/dist/rdf/calc-rdf.js +59 -44
  162. package/dist/rdf/index.d.ts +0 -1
  163. package/dist/sanitize.js +84 -26
  164. package/dist/scene/SceneCamera.svelte +1 -1
  165. package/dist/scene/SceneCamera.svelte.d.ts +1 -1
  166. package/dist/scene/index.d.ts +1 -2
  167. package/dist/scene/index.js +1 -1
  168. package/dist/scene/{props.js → props.svelte.js} +15 -1
  169. package/dist/settings.js +159 -482
  170. package/dist/spectral/Bands.svelte +151 -158
  171. package/dist/spectral/BrillouinBandsDos.svelte +4 -19
  172. package/dist/spectral/Dos.svelte +26 -24
  173. package/dist/spectral/helpers.js +40 -105
  174. package/dist/structure/AtomLegend.svelte +8 -13
  175. package/dist/structure/AtomLegend.svelte.d.ts +2 -3
  176. package/dist/structure/CellSelect.svelte +35 -10
  177. package/dist/structure/Structure.svelte +177 -99
  178. package/dist/structure/Structure.svelte.d.ts +1 -1
  179. package/dist/structure/StructureCarousel.svelte +10 -3
  180. package/dist/structure/StructureControls.svelte +8 -26
  181. package/dist/structure/StructureControls.svelte.d.ts +1 -1
  182. package/dist/structure/StructureInfoPane.svelte +65 -76
  183. package/dist/structure/StructureScene.svelte +75 -109
  184. package/dist/structure/StructureScene.svelte.d.ts +3 -1
  185. package/dist/structure/StructureViewport.svelte +120 -55
  186. package/dist/structure/StructureViewport.svelte.d.ts +3 -1
  187. package/dist/structure/atom-properties.d.ts +1 -1
  188. package/dist/structure/atom-properties.js +4 -3
  189. package/dist/structure/bond-order-perception.js +3 -8
  190. package/dist/structure/bonding.d.ts +0 -1
  191. package/dist/structure/bonding.js +16 -23
  192. package/dist/structure/export.js +50 -74
  193. package/dist/structure/format-detect.js +5 -7
  194. package/dist/structure/index.js +6 -12
  195. package/dist/structure/parse.js +38 -100
  196. package/dist/structure/partial-occupancy.js +7 -4
  197. package/dist/structure/pbc.js +8 -10
  198. package/dist/structure/polyhedra.js +5 -4
  199. package/dist/structure/prop-groups.d.ts +85 -0
  200. package/dist/structure/prop-groups.js +18 -0
  201. package/dist/symmetry/SymmetryStats.svelte +0 -4
  202. package/dist/symmetry/WyckoffTable.svelte +5 -4
  203. package/dist/symmetry/cell-transform.js +5 -14
  204. package/dist/symmetry/index.js +6 -9
  205. package/dist/table/HeatmapTable.svelte +61 -103
  206. package/dist/table/ToggleMenu.svelte +166 -44
  207. package/dist/table/ToggleMenu.svelte.d.ts +1 -1
  208. package/dist/theme/embedded.d.ts +18 -0
  209. package/dist/theme/embedded.js +206 -0
  210. package/dist/theme/index.d.ts +4 -0
  211. package/dist/theme/index.js +1 -2
  212. package/dist/theme/themes.mjs +31 -60
  213. package/dist/tooltip/TooltipContent.svelte +1 -1
  214. package/dist/tooltip/TooltipContent.svelte.d.ts +1 -1
  215. package/dist/tooltip/index.d.ts +8 -1
  216. package/dist/trajectory/Trajectory.svelte +140 -120
  217. package/dist/trajectory/TrajectoryError.svelte +1 -66
  218. package/dist/trajectory/TrajectoryExportPane.svelte +0 -1
  219. package/dist/trajectory/TrajectoryInfoPane.svelte +55 -80
  220. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +2 -1
  221. package/dist/trajectory/extract.js +19 -29
  222. package/dist/trajectory/format-detect.d.ts +2 -0
  223. package/dist/trajectory/format-detect.js +7 -5
  224. package/dist/trajectory/frame-reader.js +3 -4
  225. package/dist/trajectory/helpers.js +16 -49
  226. package/dist/trajectory/index.js +2 -8
  227. package/dist/trajectory/parse/ase.js +1 -1
  228. package/dist/trajectory/parse/index.d.ts +4 -3
  229. package/dist/trajectory/parse/index.js +12 -17
  230. package/dist/trajectory/parse/vaspout-h5.d.ts +0 -1
  231. package/dist/trajectory/parse/vaspout-h5.js +1 -4
  232. package/dist/trajectory/parse/xyz.js +48 -2
  233. package/dist/trajectory/plotting.js +14 -37
  234. package/dist/xrd/XrdPlot.svelte +43 -68
  235. package/dist/xrd/calc-xrd.js +22 -58
  236. package/dist/xrd/parse.js +13 -22
  237. package/package.json +40 -8
  238. package/readme.md +6 -5
  239. package/dist/scene/types.d.ts +0 -26
  240. package/dist/tooltip/types.d.ts +0 -8
  241. package/dist/trajectory/constants.d.ts +0 -6
  242. package/dist/trajectory/constants.js +0 -11
  243. /package/dist/{scene/types.js → file-viewer/host-protocol.js} +0 -0
  244. /package/dist/{tooltip/types.js → isosurface/geometry-worker-types.js} +0 -0
@@ -0,0 +1,170 @@
1
+ // Worker-safe file parsing with no Svelte or DOM imports.
2
+ import { COMPRESSION_EXTENSIONS_REGEX } from '../constants';
3
+ import { parse_fermi_file } from '../fermi-surface/parse';
4
+ import { decompress_data, decompress_data_binary, detect_compression_format, } from '../io/decompress';
5
+ import { parse_volumetric_file } from '../isosurface/parse';
6
+ import { is_vaspwave_filename, parse_vaspwave_charge } from '../isosurface/parse-vaspwave';
7
+ import { parse_structure_file } from '../structure/parse';
8
+ import { is_trajectory_file, parse_trajectory_data } from '../trajectory/parse';
9
+ import { FERMI_FILE_RE, VOLUMETRIC_EXT_RE, VOLUMETRIC_VASP_RE } from './types';
10
+ import { detect_view_type } from './detect';
11
+ // Maps detect.ts RenderableType to ViewType for direct rendering.
12
+ // Types not listed here fall through to json_browser (which can render all types
13
+ // via its internal mount_into, giving the user a tree view alongside the viz).
14
+ // structure and volumetric have special handling in parse_file_content below.
15
+ const DETECTION_TO_VIEW_TYPE = {
16
+ fermi_surface: `fermi_surface`,
17
+ band_grid: `fermi_surface`,
18
+ convex_hull: `convex_hull`,
19
+ phase_diagram: `phase_diagram`,
20
+ };
21
+ // Convert base64 to ArrayBuffer for binary files
22
+ export function base64_to_array_buffer(base64) {
23
+ const binary = atob(base64);
24
+ const bytes = new Uint8Array(binary.length);
25
+ for (let idx = 0; idx < binary.length; idx++) {
26
+ bytes[idx] = binary.charCodeAt(idx);
27
+ }
28
+ return bytes.buffer;
29
+ }
30
+ // Parse file content and determine if it's a structure or trajectory
31
+ export const parse_file_content = async (content, filename, is_base64 = false) => {
32
+ // Handle base64-encoded compressed/binary files by converting them first
33
+ if (is_base64) {
34
+ let buffer = base64_to_array_buffer(content);
35
+ const compression_format = detect_compression_format(filename);
36
+ if (compression_format) {
37
+ const normalized_filename = filename.replace(COMPRESSION_EXTENSIONS_REGEX, ``);
38
+ if (detect_compression_format(normalized_filename)) {
39
+ throw new Error(`Nested compression is not supported: ${filename}`);
40
+ }
41
+ filename = normalized_filename;
42
+ }
43
+ // Compressed binary formats (e.g. vaspwave.h5.gz as ferrox stores them on S3,
44
+ // or compressed ASE .traj files): decompress to binary first — generic text
45
+ // decompression would corrupt their bytes — so routing sees the inner name.
46
+ const is_binary_format = /\.(?:h5|hdf5|traj)$/i.test(filename);
47
+ if (compression_format === `zip`) {
48
+ const { unzipSync } = await import(`fflate`);
49
+ const payload = Object.entries(unzipSync(new Uint8Array(buffer))).find(([entry_name]) => !entry_name.endsWith(`/`))?.[1];
50
+ if (!payload)
51
+ throw new Error(`ZIP archive contains no files: ${filename}`);
52
+ if (is_binary_format)
53
+ buffer = payload.slice().buffer;
54
+ else
55
+ content = new TextDecoder().decode(payload);
56
+ }
57
+ else if (compression_format) {
58
+ // Unified handling for all supported compression formats
59
+ // Unsupported formats fail here with a clear extraction error
60
+ if (is_binary_format)
61
+ buffer = await decompress_data_binary(buffer, compression_format);
62
+ else
63
+ content = await decompress_data(buffer, compression_format);
64
+ }
65
+ // vaspwave.h5 holds charge density (+ wavefunctions), not a trajectory —
66
+ // route to the volumetric parser so it renders as an isosurface.
67
+ if (is_vaspwave_filename(filename)) {
68
+ const data = await parse_vaspwave_charge(buffer, filename);
69
+ return { type: `isosurface`, data, filename };
70
+ }
71
+ // Binary trajectory formats: pass buffer directly to trajectory parser
72
+ if (is_binary_format) {
73
+ const data = await parse_trajectory_data(buffer, filename);
74
+ // DOS/bands-only vaspout.h5 (e.g. phelel band paths): no frames to animate,
75
+ // route the electronic results to the spectral components instead.
76
+ // Require at least one renderable result rather than trusting the
77
+ // parser's invariant (the metadata cast is unchecked): an empty
78
+ // electronic object would otherwise mount <Dos doses={null}>.
79
+ const electronic = data.metadata?.electronic;
80
+ if (data.frames.length === 0 && (electronic?.dos || electronic?.bands)) {
81
+ return { type: `vaspout_electronic`, filename, data: electronic };
82
+ }
83
+ return { type: `trajectory`, filename, data };
84
+ }
85
+ }
86
+ // Fermi surface files (.bxsf, .frmsf)
87
+ // Use basename for regex matching in case filename retains a directory prefix
88
+ const basename = filename.split(`/`).pop() ?? filename;
89
+ if (FERMI_FILE_RE.test(basename)) {
90
+ // parse_fermi_file throws a descriptive error when parsing fails
91
+ return { type: `fermi_surface`, data: parse_fermi_file(content, filename), filename };
92
+ }
93
+ // Volumetric data files (.cube, CHGCAR, AECCAR*, ELFCAR, LOCPOT, PARCHG)
94
+ if (VOLUMETRIC_EXT_RE.test(basename) || VOLUMETRIC_VASP_RE.test(basename)) {
95
+ const data = parse_volumetric_file(content, filename);
96
+ if (data)
97
+ return { type: `isosurface`, data, filename };
98
+ throw new Error(`Failed to parse volumetric file: ${filename}`);
99
+ }
100
+ let parsed_json;
101
+ let has_parsed_json = false;
102
+ // JSON files: render typed JSON before filename heuristics. Otherwise names like
103
+ // convex-hull.json can be mistaken for trajectory keywords such as nve.
104
+ if (/\.json$/i.test(filename)) {
105
+ try {
106
+ parsed_json = JSON.parse(content);
107
+ has_parsed_json = true;
108
+ // Check if the top-level value matches a known visualization type
109
+ const detected = detect_view_type(parsed_json);
110
+ if (detected) {
111
+ // Structure JSON needs normalization (OPTIMADE, fractional coords, etc.)
112
+ if (detected === `structure`) {
113
+ try {
114
+ const structure = parse_structure_file(content, filename);
115
+ return {
116
+ type: `structure`,
117
+ data: { ...structure, id: filename.replace(/\.[^/.]+$/, ``) },
118
+ filename,
119
+ };
120
+ }
121
+ catch {
122
+ // Detailed parse failed despite structure-like shape — fall through to
123
+ // generic JSON handling below
124
+ }
125
+ }
126
+ // Volumetric JSON needs wrapping in { structure, volumes } for the isosurface renderer
127
+ if (detected === `volumetric`) {
128
+ const vol = parsed_json;
129
+ return {
130
+ type: `isosurface`,
131
+ data: { structure: { sites: [], lattice: vol.lattice }, volumes: [parsed_json] },
132
+ filename,
133
+ };
134
+ }
135
+ return {
136
+ type: DETECTION_TO_VIEW_TYPE[detected] ?? `json_browser`,
137
+ data: parsed_json,
138
+ filename,
139
+ };
140
+ }
141
+ }
142
+ catch {
143
+ // JSON parse failed, fall through to structure parser
144
+ }
145
+ }
146
+ // Try trajectory parsing if it looks like a trajectory
147
+ if (is_trajectory_file(filename, content)) {
148
+ try {
149
+ const data = await parse_trajectory_data(content, filename);
150
+ return { type: `trajectory`, data, filename };
151
+ }
152
+ catch (error) {
153
+ // Trajectory-looking filename but not trajectory-shaped JSON (e.g. nve-config.json):
154
+ // fall through to the JSON browser instead of failing the render
155
+ if (!has_parsed_json)
156
+ throw error;
157
+ }
158
+ }
159
+ // No top-level match -- show JSON browser for navigation
160
+ if (has_parsed_json)
161
+ return { type: `json_browser`, data: parsed_json, filename };
162
+ // Parse as structure (CIF, POSCAR, XYZ, etc.) — throws descriptive reasons on failure
163
+ const structure = parse_structure_file(content, filename);
164
+ // parse_structure_file throws on parse failure but can still return zero atoms (e.g. a
165
+ // CIF with cell params but no _atom_site records), which is invalid downstream
166
+ if (!structure.sites?.length)
167
+ throw new Error(`No atoms found in ${filename}`);
168
+ const data = { ...structure, id: filename.replace(/\.[^/.]+$/, ``) };
169
+ return { type: `structure`, data, filename };
170
+ };
@@ -0,0 +1,24 @@
1
+ import type { BarSeries, DataSeries, DataSeries3D } from '../plot';
2
+ export type PlotType = `scatter` | `scatter3d` | `bar` | `histogram` | `table`;
3
+ export interface ColumnInfo {
4
+ values: unknown[];
5
+ type: `numeric` | `string` | `mixed`;
6
+ n_valid: number;
7
+ }
8
+ export interface AxisMapping {
9
+ x?: string;
10
+ y?: string;
11
+ z?: string;
12
+ color?: string;
13
+ size?: string;
14
+ }
15
+ export declare function extract_columns(data: unknown): Map<string, ColumnInfo>;
16
+ export declare const col_keys: (columns: Map<string, ColumnInfo>, type: ColumnInfo[`type`]) => string[];
17
+ export declare function suggest_mapping(columns: Map<string, ColumnInfo>): {
18
+ plot_type: PlotType;
19
+ mapping: AxisMapping;
20
+ };
21
+ export declare function build_scatter_series(columns: Map<string, ColumnInfo>, mapping: AxisMapping): DataSeries;
22
+ export declare function build_scatter3d_series(columns: Map<string, ColumnInfo>, mapping: AxisMapping): DataSeries3D;
23
+ export declare function build_bar_series(columns: Map<string, ColumnInfo>, mapping: AxisMapping): BarSeries;
24
+ export declare function build_histogram_series(columns: Map<string, ColumnInfo>, mapping: AxisMapping): DataSeries;
@@ -0,0 +1,191 @@
1
+ // Utilities for extracting plottable columns from JSON data and building plot series.
2
+ // Extract columns from row-based or column-based tabular data
3
+ export function extract_columns(data) {
4
+ const columns = new Map();
5
+ if (Array.isArray(data) &&
6
+ data.length > 0 &&
7
+ typeof data[0] === `object` &&
8
+ data[0] !== null) {
9
+ // Row-based: [{ a: 1, b: 'x' }, ...]
10
+ const sample = data.slice(0, 100);
11
+ const all_keys = new Set();
12
+ for (const row of sample) {
13
+ if (row && typeof row === `object`) {
14
+ for (const key of Object.keys(row))
15
+ all_keys.add(key);
16
+ }
17
+ }
18
+ for (const key of all_keys) {
19
+ columns.set(key, classify_column(data.map((row) => row && typeof row === `object` ? row[key] : undefined)));
20
+ }
21
+ }
22
+ else if (data && typeof data === `object` && !Array.isArray(data)) {
23
+ // Column-based: { a: [1,2,3], b: ['x','y','z'] }
24
+ const array_entries = Object.entries(data).filter(([, val]) => Array.isArray(val) && val.length > 0);
25
+ if (array_entries.length < 1)
26
+ return columns;
27
+ const target_len = array_entries[0][1].length;
28
+ for (const [key, val] of array_entries) {
29
+ const arr = val;
30
+ if (arr.length === target_len) {
31
+ columns.set(key, classify_column(arr));
32
+ }
33
+ }
34
+ }
35
+ return columns;
36
+ }
37
+ function classify_column(values) {
38
+ let n_numeric = 0;
39
+ let n_string = 0;
40
+ let n_valid = 0;
41
+ for (const val of values) {
42
+ if (val == null || (typeof val === `number` && !isFinite(val)))
43
+ continue;
44
+ n_valid++;
45
+ if (typeof val === `number`)
46
+ n_numeric++;
47
+ else if (typeof val === `string`)
48
+ n_string++;
49
+ }
50
+ let type = `mixed`;
51
+ if (n_valid > 0) {
52
+ if (n_numeric >= n_valid * 0.8)
53
+ type = `numeric`;
54
+ else if (n_string >= n_valid * 0.8)
55
+ type = `string`;
56
+ }
57
+ return { values, type, n_valid };
58
+ }
59
+ // Extract column keys of a given type from a column map
60
+ export const col_keys = (columns, type) => [...columns.entries()].filter(([, col]) => col.type === type).map(([key]) => key);
61
+ // Well-known column name patterns for heuristic axis assignment
62
+ const X_NAMES = new Set([`x`, `time`, `step`, `index`, `iteration`, `frame`, `epoch`]);
63
+ const Y_NAMES = new Set([`y`, `energy`, `value`, `force`, `stress`, `loss`, `score`]);
64
+ const Z_NAMES = new Set([`z`, `altitude`, `depth`, `height`]);
65
+ // Heuristic: suggest initial axis mapping and plot type from columns
66
+ export function suggest_mapping(columns) {
67
+ const numeric_cols = col_keys(columns, `numeric`);
68
+ const string_cols = col_keys(columns, `string`);
69
+ const mapping = {};
70
+ // Assign x: prefer named numeric match, then string column (bar chart), then first numeric
71
+ const x_match = numeric_cols.find((key) => X_NAMES.has(key.toLowerCase()));
72
+ const x_string_match = string_cols.find((key) => !Y_NAMES.has(key.toLowerCase()));
73
+ mapping.x =
74
+ x_match ?? x_string_match ?? (numeric_cols.length >= 2 ? numeric_cols[0] : undefined);
75
+ // Assign y
76
+ const remaining_numeric = numeric_cols.filter((key) => key !== mapping.x);
77
+ const y_match = remaining_numeric.find((key) => Y_NAMES.has(key.toLowerCase()));
78
+ mapping.y = y_match ?? remaining_numeric[0];
79
+ // Assign z (only if 3+ numeric columns and one matches z-like name)
80
+ const after_xy = remaining_numeric.filter((key) => key !== mapping.y);
81
+ const z_match = after_xy.find((key) => Z_NAMES.has(key.toLowerCase()));
82
+ if (z_match && numeric_cols.length >= 3)
83
+ mapping.z = z_match;
84
+ // Assign color (first unassigned numeric column)
85
+ const used = new Set([mapping.x, mapping.y, mapping.z].filter(Boolean));
86
+ const color_candidate = numeric_cols.find((key) => !used.has(key));
87
+ if (color_candidate)
88
+ mapping.color = color_candidate;
89
+ // Determine plot type
90
+ let plot_type = `scatter`;
91
+ if (mapping.z) {
92
+ plot_type = `scatter3d`;
93
+ }
94
+ else if (mapping.x && columns.get(mapping.x)?.type === `string`) {
95
+ plot_type = `bar`;
96
+ }
97
+ else if ((!mapping.x || !mapping.y) && numeric_cols.length >= 1) {
98
+ plot_type = `histogram`;
99
+ mapping.x ??= mapping.y ?? numeric_cols[0];
100
+ }
101
+ else if (!mapping.x || !mapping.y) {
102
+ plot_type = `table`;
103
+ }
104
+ return { plot_type, mapping };
105
+ }
106
+ // Convert to numbers, preserving array length (non-finite values become NaN)
107
+ const to_numbers = (values) => values.map((val) => (typeof val === `number` && isFinite(val) ? val : NaN));
108
+ // Convert an arbitrary cell value to a display label, JSON-encoding objects so
109
+ // they don't stringify to the useless "[object Object]".
110
+ const to_label = (val) => {
111
+ if (val == null)
112
+ return ``;
113
+ if (typeof val === `string` ||
114
+ typeof val === `number` ||
115
+ typeof val === `boolean` ||
116
+ typeof val === `bigint`)
117
+ return String(val);
118
+ return JSON.stringify(val);
119
+ };
120
+ // Look up a column by its mapping key, returning undefined if unmapped or missing
121
+ const get_col = (columns, key) => key ? columns.get(key) : undefined;
122
+ // Optional numeric conversion for color/size channels
123
+ const optional_numbers = (col) => col ? to_numbers(col.values) : undefined;
124
+ // Filter N axis arrays to only include indices where all axes are finite,
125
+ // keeping optional color/size arrays aligned
126
+ function filter_finite(axes, color, size) {
127
+ const out = axes.map(() => []);
128
+ const color_values = color ? [] : undefined;
129
+ const size_values = size ? [] : undefined;
130
+ for (let idx = 0; idx < axes[0].length; idx++) {
131
+ if (axes.some((arr) => !isFinite(arr[idx])))
132
+ continue;
133
+ for (let dim = 0; dim < axes.length; dim++)
134
+ out[dim].push(axes[dim][idx]);
135
+ if (color && color_values)
136
+ color_values.push(color[idx]);
137
+ if (size && size_values)
138
+ size_values.push(size[idx]);
139
+ }
140
+ return { axes: out, color_values, size_values };
141
+ }
142
+ export function build_scatter_series(columns, mapping) {
143
+ const x_col = get_col(columns, mapping.x);
144
+ const y_col = get_col(columns, mapping.y);
145
+ if (!x_col || !y_col)
146
+ return { x: [], y: [] };
147
+ const { axes: [x, y], color_values, size_values, } = filter_finite([to_numbers(x_col.values), to_numbers(y_col.values)], optional_numbers(get_col(columns, mapping.color)), optional_numbers(get_col(columns, mapping.size)));
148
+ return {
149
+ x,
150
+ y,
151
+ markers: `points`,
152
+ color_values,
153
+ size_values,
154
+ point_style: { radius: 4, fill: `#4c6ef5`, stroke: `white`, stroke_width: 1 },
155
+ };
156
+ }
157
+ export function build_scatter3d_series(columns, mapping) {
158
+ const x_col = get_col(columns, mapping.x);
159
+ const y_col = get_col(columns, mapping.y);
160
+ const z_col = get_col(columns, mapping.z);
161
+ if (!x_col || !y_col || !z_col)
162
+ return { x: [], y: [], z: [] };
163
+ const { axes: [x, y, z], color_values, size_values, } = filter_finite([to_numbers(x_col.values), to_numbers(y_col.values), to_numbers(z_col.values)], optional_numbers(get_col(columns, mapping.color)), optional_numbers(get_col(columns, mapping.size)));
164
+ return { x, y, z, markers: `points`, color_values, size_values };
165
+ }
166
+ export function build_bar_series(columns, mapping) {
167
+ const x_col = get_col(columns, mapping.x);
168
+ const y_col = get_col(columns, mapping.y);
169
+ if (!x_col || !y_col)
170
+ return { x: [], y: [] };
171
+ const raw_y = to_numbers(y_col.values);
172
+ const x = [];
173
+ const y = [];
174
+ for (let idx = 0; idx < raw_y.length; idx++) {
175
+ if (!isFinite(raw_y[idx]))
176
+ continue;
177
+ x.push(to_label(x_col.values[idx]));
178
+ y.push(raw_y[idx]);
179
+ }
180
+ return { x, y, color: `#4c6ef5` };
181
+ }
182
+ export function build_histogram_series(columns, mapping) {
183
+ const col = get_col(columns, mapping.x ?? mapping.y);
184
+ if (!col)
185
+ return { x: [], y: [] };
186
+ const values = to_numbers(col.values).filter(isFinite);
187
+ return {
188
+ x: values.map((_, idx) => idx),
189
+ y: values,
190
+ };
191
+ }
@@ -0,0 +1,4 @@
1
+ export type ViewType = `trajectory` | `structure` | `fermi_surface` | `isosurface` | `convex_hull` | `phase_diagram` | `json_browser` | `vaspout_electronic`;
2
+ export declare const FERMI_FILE_RE: RegExp;
3
+ export declare const VOLUMETRIC_EXT_RE: RegExp;
4
+ export declare const VOLUMETRIC_VASP_RE: RegExp;
@@ -0,0 +1,5 @@
1
+ // Shared file-viewer types and filename patterns.
2
+ // Filename patterns for specialized file types (shared between extension host and webview)
3
+ export const FERMI_FILE_RE = /\.(?:bxsf|frmsf)$/i;
4
+ export const VOLUMETRIC_EXT_RE = /\.cube$/i;
5
+ export const VOLUMETRIC_VASP_RE = /(?:^|[\\/_.-])(?:chgcar|aeccar[012]?|elfcar|locpot|parchg)(?:[\\/_.-]|$)/i;
@@ -254,29 +254,22 @@
254
254
  return sorted
255
255
  }
256
256
 
257
- let { vis_x, vis_y } = $derived.by(() => {
258
- const all_x = Array.from({ length: x_items.length }, (_, idx) => idx)
259
- const all_y = Array.from({ length: y_items.length }, (_, idx) => idx)
260
- const filtered_x = search_query_norm
261
- ? all_x.filter((idx) => {
262
- const item = x_items[idx]
263
- const key = item.key ?? item.label
264
- return (
265
- key.toLowerCase().includes(search_query_norm) ||
266
- item.label.toLowerCase().includes(search_query_norm)
267
- )
268
- })
269
- : all_x
270
- const filtered_y = search_query_norm
271
- ? all_y.filter((idx) => {
272
- const item = y_items[idx]
273
- const key = item.key ?? item.label
257
+ const filter_by_search = (indices: number[], items: AxisItem[]): number[] =>
258
+ search_query_norm
259
+ ? indices.filter((idx) => {
260
+ const item = items[idx]
274
261
  return (
275
- key.toLowerCase().includes(search_query_norm) ||
262
+ (item.key ?? item.label).toLowerCase().includes(search_query_norm) ||
276
263
  item.label.toLowerCase().includes(search_query_norm)
277
264
  )
278
265
  })
279
- : all_y
266
+ : indices
267
+
268
+ let { vis_x, vis_y } = $derived.by(() => {
269
+ const all_x = Array.from({ length: x_items.length }, (_, idx) => idx)
270
+ const all_y = Array.from({ length: y_items.length }, (_, idx) => idx)
271
+ const filtered_x = filter_by_search(all_x, x_items)
272
+ const filtered_y = filter_by_search(all_y, y_items)
280
273
  if (!hide_empty) {
281
274
  return {
282
275
  vis_x: sort_indices(filtered_x, x_items, x_order),
@@ -483,14 +476,10 @@
483
476
  })
484
477
 
485
478
  // Keep selected outlines visible against each cell's background.
486
- let selected_outline_flat = $derived.by(() => to_contrast_colors(bg_flat))
479
+ let selected_outline_flat = $derived(to_contrast_colors(bg_flat))
487
480
 
488
481
  const get_flat_idx = (x_idx: number, y_idx: number): number => y_idx * n_x + x_idx
489
482
 
490
- // Look up bg color by indices
491
- const get_bg = (x_idx: number, y_idx: number): string | null =>
492
- bg_flat[get_flat_idx(x_idx, y_idx)]
493
-
494
483
  // === Cell context builder (only called for clicks, not per-hover) ===
495
484
  const build_cell_context = (x_idx: number, y_idx: number): CellContext => ({
496
485
  x_item: x_items[x_idx],
@@ -498,16 +487,16 @@
498
487
  x_idx,
499
488
  y_idx,
500
489
  value: get_value(x_idx, y_idx),
501
- bg_color: get_bg(x_idx, y_idx),
490
+ bg_color: bg_flat[get_flat_idx(x_idx, y_idx)],
502
491
  })
503
492
 
504
493
  // === Fully imperative hover management ===
505
494
  // ZERO $state writes during mouseover — all DOM updates are direct.
506
495
  // This avoids Svelte's reactive flush which would re-evaluate effects.
507
- const is_browser = typeof window !== `undefined`
508
496
  let tooltip_div: HTMLDivElement | undefined = $state()
509
497
  let active_cell_raf = 0 // rAF handle for deferred active_cell update
510
498
  let click_timeout_id: ReturnType<typeof setTimeout> | null = null
499
+ let pending_click_key: string | null = null
511
500
  const dblclick_delay_ms = 250
512
501
  let last_hover_x = -1
513
502
  let last_hover_y = -1
@@ -634,23 +623,6 @@
634
623
  return Math.max(1, vis_row + 1)
635
624
  }
636
625
 
637
- function x_label_diag_grid_col(x_idx: number): number | undefined {
638
- const vis_col = get_vis_col(x_idx)
639
- if (vis_col === null) return undefined
640
- return vis_col + 2
641
- }
642
-
643
- function y_label_edge_grid_row(y_idx: number): number | undefined {
644
- const vis_row = get_vis_row(y_idx)
645
- if (vis_row === null) return undefined
646
- return vis_row + 2
647
- }
648
-
649
- function x_label_grid_col(x_idx: number): number | undefined {
650
- if (use_diagonal_symmetric_labels) return x_label_diag_grid_col(x_idx)
651
- return cell_grid_col(x_idx)
652
- }
653
-
654
626
  function x_label_grid_row(x_idx: number): number | undefined {
655
627
  if (use_diagonal_symmetric_labels) return x_label_diag_grid_row(x_idx)
656
628
  if (use_side_split_x_labels && x_idx % 2 !== 0) {
@@ -679,23 +651,26 @@
679
651
  return vis_row + 2
680
652
  }
681
653
 
682
- function schedule_raf(callback: () => void): number {
683
- if (!is_browser) {
684
- callback()
685
- return 0
686
- }
687
- return globalThis.requestAnimationFrame(callback)
688
- }
689
-
654
+ // Called by event handlers, the axis-key-change effect, and onDestroy; the 0-handle
655
+ // guard prevents invalid cancelAnimationFrame calls.
690
656
  function cancel_raf(raf_handle: number): void {
691
- if (!is_browser || raf_handle === 0) return
692
- globalThis.cancelAnimationFrame(raf_handle)
657
+ if (raf_handle !== 0) globalThis.cancelAnimationFrame(raf_handle)
693
658
  }
694
659
 
695
660
  function clear_pending_click(): void {
696
- if (click_timeout_id === null) return
697
- clearTimeout(click_timeout_id)
661
+ if (click_timeout_id !== null) clearTimeout(click_timeout_id)
698
662
  click_timeout_id = null
663
+ pending_click_key = null
664
+ }
665
+
666
+ function schedule_single_click(cell_context: CellContext): void {
667
+ if (!onclick) return
668
+ clear_pending_click()
669
+ pending_click_key = cell_pos_key(cell_context.x_idx, cell_context.y_idx)
670
+ click_timeout_id = setTimeout(() => {
671
+ onclick(cell_context)
672
+ clear_pending_click()
673
+ }, dblclick_delay_ms)
699
674
  }
700
675
 
701
676
  function parse_cell_indices(cell_el: HTMLElement): { x_idx: number; y_idx: number } | null {
@@ -715,25 +690,14 @@
715
690
 
716
691
  function trigger_click(cell_context: CellContext): void {
717
692
  if (!onclick) return
718
- if (!ondblclick) {
719
- onclick(cell_context)
720
- return
721
- }
722
- clear_pending_click()
723
- click_timeout_id = setTimeout(() => {
724
- onclick(cell_context)
725
- click_timeout_id = null
726
- }, dblclick_delay_ms)
693
+ if (ondblclick) schedule_single_click(cell_context)
694
+ else onclick(cell_context)
727
695
  }
728
696
 
729
697
  function get_cell_el_from_target(event_target: EventTarget | null): HTMLElement | null {
730
- const target_node = event_target
731
- if (!(target_node instanceof Element)) return null
732
- if (target_node instanceof HTMLElement && target_node.dataset.x !== undefined) {
733
- return target_node
734
- }
735
- const closest_cell = target_node.closest(`[data-x][data-y]`)
736
- return closest_cell instanceof HTMLElement ? closest_cell : null
698
+ if (!(event_target instanceof Element)) return null
699
+ const cell_el = event_target.closest(`[data-x][data-y]`) // matches self too
700
+ return cell_el instanceof HTMLElement ? cell_el : null
737
701
  }
738
702
 
739
703
  function update_selected_cells(event: MouseEvent, clicked_cell: CellPos): void {
@@ -764,9 +728,10 @@
764
728
  const existing_idx = next_cells.findIndex(
765
729
  (pos) => cell_pos_key(pos.x_idx, pos.y_idx) === clicked_key,
766
730
  )
731
+ // multi mode with Cmd/Ctrl toggles the clicked cell, otherwise replace selection
767
732
  const toggle_mode = selection_mode === `multi` && (event.metaKey || event.ctrlKey)
768
- if (existing_idx !== -1 && toggle_mode) next_cells.splice(existing_idx, 1)
769
- else if (selection_mode === `multi` && toggle_mode) next_cells.push(clicked_cell)
733
+ if (toggle_mode && existing_idx !== -1) next_cells.splice(existing_idx, 1)
734
+ else if (toggle_mode) next_cells.push(clicked_cell)
770
735
  else next_cells.splice(0, next_cells.length, clicked_cell)
771
736
  selected_cells = next_cells
772
737
  last_selected_cell = clicked_cell
@@ -820,7 +785,7 @@
820
785
 
821
786
  // Defer bindable writes out of the hot mouseover path
822
787
  cancel_raf(active_cell_raf)
823
- active_cell_raf = schedule_raf(() => {
788
+ active_cell_raf = globalThis.requestAnimationFrame(() => {
824
789
  active_cell = { x_idx, y_idx }
825
790
  })
826
791
 
@@ -852,7 +817,7 @@
852
817
  }
853
818
  // Defer reactive cleanup to rAF
854
819
  cancel_raf(active_cell_raf)
855
- active_cell_raf = schedule_raf(() => {
820
+ active_cell_raf = globalThis.requestAnimationFrame(() => {
856
821
  active_cell = null
857
822
  if (!keep_tooltip_visible) tooltip_cell = null
858
823
  })
@@ -873,7 +838,6 @@
873
838
  else update_tooltip_content(tooltip_div, x_idx, y_idx)
874
839
  }
875
840
  }
876
- if (!onclick) return
877
841
  trigger_click(cell_context)
878
842
  }
879
843
 
@@ -881,8 +845,20 @@
881
845
  if (disabled || !ondblclick) return
882
846
  const cell_context = get_cell_context_from_target(event.target)
883
847
  if (!cell_context) return
848
+ // With onclick, require a matching pending click (FilePicker pattern).
849
+ // ondblclick-only stays direct so orphaned dblclicks still work.
850
+ if (!onclick) {
851
+ clear_pending_click()
852
+ ondblclick(cell_context)
853
+ return
854
+ }
855
+ const pending = pending_click_key
884
856
  clear_pending_click()
885
- ondblclick(cell_context)
857
+ if (pending === cell_pos_key(cell_context.x_idx, cell_context.y_idx)) {
858
+ ondblclick(cell_context)
859
+ } else {
860
+ schedule_single_click(cell_context)
861
+ }
886
862
  }
887
863
 
888
864
  function handle_contextmenu(event: MouseEvent): void {
@@ -1044,7 +1020,7 @@
1044
1020
  let legend_orientation = $derived<ColorBarOrientation>(
1045
1021
  legend_position === `right` ? `vertical` : `horizontal`,
1046
1022
  )
1047
- let legend_wrapper_style = $derived.by(() =>
1023
+ let legend_wrapper_style = $derived(
1048
1024
  legend_position === `right`
1049
1025
  ? `--cbar-height: 120px; --cbar-min-height: 120px; --cbar-max-height: 120px;`
1050
1026
  : `--cbar-width: 180px;`,
@@ -1090,11 +1066,8 @@
1090
1066
 
1091
1067
  onMount(() => {
1092
1068
  update_viewport_state()
1093
- if (!is_browser) return
1094
1069
  globalThis.addEventListener(`mouseup`, handle_mouseup)
1095
- return () => {
1096
- globalThis.removeEventListener(`mouseup`, handle_mouseup)
1097
- }
1070
+ return () => globalThis.removeEventListener(`mouseup`, handle_mouseup)
1098
1071
  })
1099
1072
 
1100
1073
  onDestroy(() => {
@@ -1167,7 +1140,7 @@
1167
1140
  class:highlighted={highlight_x_by_idx.has(x_idx)}
1168
1141
  class:sticky={sticky_x_labels}
1169
1142
  style={label_style || undefined}
1170
- style:grid-column={x_label_grid_col(x_idx)}
1143
+ style:grid-column={cell_grid_col(x_idx)}
1171
1144
  style:grid-row={x_label_grid_row(x_idx)}
1172
1145
  title={x_label_cell ? undefined : item.label}
1173
1146
  >
@@ -1191,7 +1164,7 @@
1191
1164
  class:highlighted={highlight_y_by_idx.has(y_idx)}
1192
1165
  class:sticky={sticky_y_labels}
1193
1166
  style={label_style || undefined}
1194
- style:grid-row={y_label_edge_grid_row(y_idx)}
1167
+ style:grid-row={cell_grid_row(y_idx)}
1195
1168
  style:grid-column={y_label_grid_col(y_idx)}
1196
1169
  title={y_label_cell ? undefined : y_item.label}
1197
1170
  >
@@ -25,6 +25,6 @@ type $$ComponentProps = {
25
25
  controls_open: boolean;
26
26
  }]>;
27
27
  };
28
- declare const HeatmapMatrixControls: import("svelte").Component<$$ComponentProps, {}, "normalize" | "theme" | "show_values" | "show_legend" | "controls_open" | "ordering" | "search_query" | "toggle_visible" | "domain_mode" | "legend_position" | "symmetric" | "show_row_summaries" | "show_col_summaries">;
28
+ declare const HeatmapMatrixControls: import("svelte").Component<$$ComponentProps, {}, "normalize" | "theme" | "show_values" | "show_legend" | "controls_open" | "ordering" | "symmetric" | "search_query" | "toggle_visible" | "domain_mode" | "legend_position" | "show_row_summaries" | "show_col_summaries">;
29
29
  type HeatmapMatrixControls = ReturnType<typeof HeatmapMatrixControls>;
30
30
  export default HeatmapMatrixControls;