matterviz 0.3.5 → 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.
- package/dist/MillerIndexInput.svelte +5 -5
- package/dist/api/optimade.js +3 -3
- package/dist/brillouin/BrillouinZone.svelte +5 -2
- package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneExportPane.svelte +1 -3
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +1 -1
- package/dist/brillouin/BrillouinZoneScene.svelte +5 -5
- package/dist/brillouin/compute.js +21 -21
- package/dist/brillouin/index.d.ts +1 -1
- package/dist/brillouin/index.js +0 -1
- package/dist/brillouin/types.d.ts +8 -13
- package/dist/chempot-diagram/ChemPotDiagram.svelte +3 -3
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +3 -4
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +33 -34
- package/dist/chempot-diagram/compute.js +1 -7
- package/dist/chempot-diagram/temperature.d.ts +1 -1
- package/dist/chempot-diagram/temperature.js +1 -3
- package/dist/chempot-diagram/types.d.ts +4 -9
- package/dist/colors/index.js +5 -5
- package/dist/composition/Composition.svelte +2 -1
- package/dist/composition/Formula.svelte +7 -4
- package/dist/composition/FormulaFilter.svelte +1 -3
- package/dist/composition/format.js +4 -4
- package/dist/composition/parse.d.ts +2 -1
- package/dist/composition/parse.js +61 -46
- package/dist/convex-hull/ConvexHull2D.svelte +62 -51
- package/dist/convex-hull/ConvexHull3D.svelte +101 -90
- package/dist/convex-hull/ConvexHull4D.svelte +70 -58
- package/dist/convex-hull/ConvexHullControls.svelte +24 -35
- package/dist/convex-hull/ConvexHullInfoPane.svelte +8 -5
- package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +2 -0
- package/dist/convex-hull/ConvexHullStats.svelte +9 -2
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +2 -0
- package/dist/convex-hull/GasPressureControls.svelte +7 -7
- package/dist/convex-hull/StructurePopup.svelte +65 -30
- package/dist/convex-hull/StructurePopup.svelte.d.ts +6 -6
- package/dist/convex-hull/TemperatureSlider.svelte +8 -5
- package/dist/convex-hull/barycentric-coords.d.ts +2 -2
- package/dist/convex-hull/barycentric-coords.js +2 -2
- package/dist/convex-hull/gas-thermodynamics.js +2 -4
- package/dist/convex-hull/helpers.d.ts +13 -2
- package/dist/convex-hull/helpers.js +37 -16
- package/dist/convex-hull/index.d.ts +1 -0
- package/dist/convex-hull/index.js +1 -0
- package/dist/convex-hull/thermodynamics.d.ts +2 -1
- package/dist/convex-hull/thermodynamics.js +7 -7
- package/dist/convex-hull/types.d.ts +15 -15
- package/dist/effects.svelte.d.ts +12 -0
- package/dist/effects.svelte.js +37 -0
- package/dist/element/BohrAtom.svelte +4 -4
- package/dist/element/data.json.gz.d.ts +3 -1
- package/dist/element/index.d.ts +1 -1
- package/dist/element/index.js +0 -1
- package/dist/fermi-surface/FermiSurface.svelte +4 -4
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte +15 -19
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +8 -6
- package/dist/fermi-surface/compute.js +2 -2
- package/dist/fermi-surface/export.js +13 -26
- package/dist/fermi-surface/parse.js +8 -12
- package/dist/fermi-surface/types.d.ts +2 -5
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +21 -3
- package/dist/heatmap-matrix/index.js +6 -6
- package/dist/io/decompress.d.ts +2 -1
- package/dist/io/decompress.js +1 -1
- package/dist/io/export.js +1 -1
- package/dist/io/index.d.ts +1 -1
- package/dist/io/index.js +0 -1
- package/dist/io/url-drop.js +7 -1
- package/dist/isosurface/IsosurfaceControls.svelte +11 -25
- package/dist/isosurface/slice.js +1 -1
- package/dist/isosurface/types.js +12 -12
- package/dist/labels.d.ts +1 -1
- package/dist/labels.js +14 -11
- package/dist/layout/InfoTag.svelte +6 -4
- package/dist/layout/PropertyFilter.svelte +4 -2
- package/dist/layout/json-tree/JsonTree.svelte +22 -14
- package/dist/layout/json-tree/JsonValue.svelte +2 -2
- package/dist/layout/json-tree/types.d.ts +3 -2
- package/dist/layout/json-tree/types.js +0 -1
- package/dist/layout/json-tree/utils.d.ts +4 -4
- package/dist/layout/json-tree/utils.js +12 -20
- package/dist/marching-cubes.js +13 -15
- package/dist/math.d.ts +11 -1
- package/dist/math.js +15 -6
- package/dist/overlays/DragControlTab.svelte +98 -0
- package/dist/overlays/DragControlTab.svelte.d.ts +8 -0
- package/dist/overlays/DraggablePane.svelte +7 -84
- package/dist/overlays/index.d.ts +1 -0
- package/dist/overlays/index.js +1 -0
- package/dist/periodic-table/PeriodicTable.svelte +11 -11
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +4 -2
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramControls.svelte +4 -9
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +2 -10
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +2 -3
- package/dist/phase-diagram/TdbInfoPanel.svelte +3 -3
- package/dist/phase-diagram/build-diagram.js +11 -18
- package/dist/phase-diagram/diagram-input.d.ts +5 -9
- package/dist/phase-diagram/index.d.ts +2 -2
- package/dist/phase-diagram/index.js +0 -2
- package/dist/phase-diagram/parse.d.ts +2 -2
- package/dist/phase-diagram/parse.js +6 -10
- package/dist/phase-diagram/svg-to-diagram.js +15 -15
- package/dist/phase-diagram/types.d.ts +5 -11
- package/dist/phase-diagram/utils.d.ts +2 -2
- package/dist/phase-diagram/utils.js +9 -11
- package/dist/plot/BarPlot.svelte +162 -314
- package/dist/plot/BarPlot.svelte.d.ts +5 -4
- package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/BinnedScatterPlot.svelte +1114 -0
- package/dist/plot/BinnedScatterPlot.svelte.d.ts +66 -0
- package/dist/plot/ColorBar.svelte +19 -17
- package/dist/plot/ColorBar.svelte.d.ts +1 -1
- package/dist/plot/FillArea.svelte +2 -4
- package/dist/plot/FillArea.svelte.d.ts +1 -1
- package/dist/plot/Histogram.svelte +167 -281
- package/dist/plot/Histogram.svelte.d.ts +1 -1
- package/dist/plot/HistogramControls.svelte.d.ts +1 -1
- package/dist/plot/InteractiveAxisLabel.svelte +5 -3
- package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
- package/dist/plot/PlotAxis.svelte +169 -0
- package/dist/plot/PlotAxis.svelte.d.ts +24 -0
- package/dist/plot/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/ReferenceLine3D.svelte +53 -51
- package/dist/plot/ReferencePlane.svelte +39 -42
- package/dist/plot/ScatterPlot.svelte +300 -367
- package/dist/plot/ScatterPlot.svelte.d.ts +8 -5
- package/dist/plot/ScatterPlot3D.svelte +33 -6
- package/dist/plot/ScatterPlot3D.svelte.d.ts +3 -2
- package/dist/plot/ScatterPlot3DControls.svelte +9 -9
- package/dist/plot/ScatterPlotControls.svelte +3 -4
- package/dist/plot/ScatterPoint.svelte +18 -27
- package/dist/plot/ScatterPoint.svelte.d.ts +4 -3
- package/dist/plot/Surface3D.svelte +4 -7
- package/dist/plot/ZeroLines.svelte +2 -1
- package/dist/plot/ZeroLines.svelte.d.ts +2 -1
- package/dist/plot/ZoomRect.svelte +2 -2
- package/dist/plot/ZoomRect.svelte.d.ts +3 -3
- package/dist/plot/adaptive-density.d.ts +69 -0
- package/dist/plot/adaptive-density.js +191 -0
- package/dist/plot/auto-place.d.ts +43 -0
- package/dist/plot/auto-place.js +122 -0
- package/dist/plot/axis-utils.js +3 -5
- package/dist/plot/binned-scatter-types.d.ts +59 -0
- package/dist/plot/binned-scatter-types.js +1 -0
- package/dist/plot/data-cleaning.js +1 -1
- package/dist/plot/data-transform.js +1 -1
- package/dist/plot/fill-utils.d.ts +4 -9
- package/dist/plot/fill-utils.js +29 -44
- package/dist/plot/index.d.ts +4 -0
- package/dist/plot/index.js +2 -0
- package/dist/plot/interactions.d.ts +4 -4
- package/dist/plot/interactions.js +4 -3
- package/dist/plot/layout.d.ts +20 -2
- package/dist/plot/layout.js +59 -16
- package/dist/plot/reference-line.d.ts +1 -1
- package/dist/plot/reference-line.js +9 -11
- package/dist/plot/scales.d.ts +1 -1
- package/dist/plot/scales.js +20 -23
- package/dist/plot/types.d.ts +30 -58
- package/dist/plot/types.js +2 -6
- package/dist/plot/utils/label-placement.d.ts +24 -3
- package/dist/plot/utils/label-placement.js +82 -12
- package/dist/plot/utils/series-visibility.d.ts +8 -2
- package/dist/plot/utils/series-visibility.js +23 -5
- package/dist/rdf/RdfPlot.svelte +5 -5
- package/dist/rdf/calc-rdf.js +3 -3
- package/dist/sanitize.d.ts +2 -0
- package/dist/sanitize.js +2 -0
- package/dist/spectral/Bands.svelte +1 -1
- package/dist/spectral/BandsAndDos.svelte +22 -16
- package/dist/spectral/BrillouinBandsDos.svelte +20 -16
- package/dist/spectral/Dos.svelte +1 -1
- package/dist/spectral/helpers.d.ts +4 -2
- package/dist/spectral/helpers.js +44 -35
- package/dist/spectral/index.d.ts +1 -1
- package/dist/spectral/index.js +0 -1
- package/dist/structure/AtomLegend.svelte +23 -6
- package/dist/structure/AtomLegend.svelte.d.ts +1 -0
- package/dist/structure/CanvasTooltip.svelte +9 -9
- package/dist/structure/CanvasTooltip.svelte.d.ts +1 -1
- package/dist/structure/CellSelect.svelte +14 -16
- package/dist/structure/Structure.svelte +317 -68
- package/dist/structure/Structure.svelte.d.ts +4 -2
- package/dist/structure/StructureControls.svelte +20 -45
- package/dist/structure/StructureExportPane.svelte +2 -1
- package/dist/structure/StructureInfoPane.svelte +10 -8
- package/dist/structure/StructureScene.svelte +527 -177
- package/dist/structure/StructureScene.svelte.d.ts +5 -2
- package/dist/structure/atom-properties.js +4 -4
- package/dist/structure/bond-order-perception.js +115 -98
- package/dist/structure/bonding.d.ts +27 -1
- package/dist/structure/bonding.js +187 -16
- package/dist/structure/export.js +1 -1
- package/dist/structure/index.d.ts +3 -2
- package/dist/structure/index.js +0 -2
- package/dist/structure/parse.js +88 -59
- package/dist/symmetry/WyckoffTable.svelte +7 -0
- package/dist/symmetry/index.js +13 -14
- package/dist/table/HeatmapTable.svelte +45 -66
- package/dist/table/HeatmapTable.svelte.d.ts +1 -1
- package/dist/table/ToggleMenu.svelte +19 -10
- package/dist/theme/themes.mjs +12 -0
- package/dist/tooltip/index.d.ts +1 -1
- package/dist/tooltip/index.js +0 -1
- package/dist/trajectory/Trajectory.svelte +43 -15
- package/dist/trajectory/TrajectoryInfoPane.svelte +2 -2
- package/dist/trajectory/extract.js +1 -1
- package/dist/trajectory/frame-reader.js +4 -4
- package/dist/trajectory/helpers.d.ts +5 -4
- package/dist/trajectory/helpers.js +9 -17
- package/dist/trajectory/index.d.ts +2 -2
- package/dist/trajectory/index.js +2 -2
- package/dist/trajectory/parse/ase.js +4 -4
- package/dist/trajectory/parse/hdf5.js +1 -1
- package/dist/trajectory/parse/index.js +2 -3
- package/dist/trajectory/parse/lammps.js +1 -1
- package/dist/trajectory/parse/vasp.js +1 -1
- package/dist/trajectory/plotting.d.ts +1 -1
- package/dist/trajectory/plotting.js +38 -38
- package/dist/trajectory/types.d.ts +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +9 -0
- package/dist/xrd/calc-xrd.js +3 -4
- package/dist/xrd/parse.js +1 -1
- package/package.json +42 -22
|
@@ -2,13 +2,9 @@ import * as constants from './constants';
|
|
|
2
2
|
import { compute_vertex_normals } from './marching-cubes';
|
|
3
3
|
const parse_number_tokens = (line) => line.split(/\s+/).filter(Boolean);
|
|
4
4
|
// Parse whitespace-separated floats from a line (optimized with unary +)
|
|
5
|
-
|
|
6
|
-
return parse_number_tokens(line).map((part) => +part);
|
|
7
|
-
}
|
|
5
|
+
const parse_floats = (line) => parse_number_tokens(line).map((part) => +part);
|
|
8
6
|
// Parse whitespace-separated integers from a line
|
|
9
|
-
|
|
10
|
-
return parse_number_tokens(line).map((part) => parseInt(part, 10));
|
|
11
|
-
}
|
|
7
|
+
const parse_ints = (line) => parse_number_tokens(line).map((part) => parseInt(part, 10));
|
|
12
8
|
// Parse BXSF (Band-XSF) format used by XCrySDen, Quantum ESPRESSO, etc.
|
|
13
9
|
// Format specification: http://www.xcrysden.org/doc/XSF.html
|
|
14
10
|
function parse_bxsf(content) {
|
|
@@ -304,12 +300,12 @@ function parse_fermi_json(content) {
|
|
|
304
300
|
return data.fermi_surface;
|
|
305
301
|
}
|
|
306
302
|
if (data.band_structure?.energies || data.bands?.energies) {
|
|
307
|
-
const bs = data.band_structure
|
|
303
|
+
const bs = data.band_structure ?? data.bands;
|
|
308
304
|
return {
|
|
309
305
|
energies: bs.energies,
|
|
310
|
-
k_grid: bs.k_grid
|
|
311
|
-
k_lattice: bs.k_lattice
|
|
312
|
-
fermi_energy: bs.fermi_energy
|
|
306
|
+
k_grid: bs.k_grid ?? bs.kgrid,
|
|
307
|
+
k_lattice: bs.k_lattice ?? bs.reciprocal_lattice,
|
|
308
|
+
fermi_energy: bs.fermi_energy ?? bs.efermi ?? 0,
|
|
313
309
|
n_bands: bs.n_bands || bs.nbands || bs.energies[0]?.length || 0,
|
|
314
310
|
n_spins: bs.n_spins || bs.nspins || bs.energies.length || 1,
|
|
315
311
|
};
|
|
@@ -412,7 +408,7 @@ function parse_ifermi_surface(data) {
|
|
|
412
408
|
}
|
|
413
409
|
}
|
|
414
410
|
// Compute total surface area
|
|
415
|
-
const total_area = isosurfaces.reduce((sum, iso) => sum + (iso.area
|
|
411
|
+
const total_area = isosurfaces.reduce((sum, iso) => sum + (iso.area ?? 0), 0);
|
|
416
412
|
return {
|
|
417
413
|
isosurfaces,
|
|
418
414
|
k_lattice,
|
|
@@ -482,7 +478,7 @@ export function parse_fermi_file(content, filename) {
|
|
|
482
478
|
// FRMSF format detection (starts with grid dimensions)
|
|
483
479
|
const first_line = trimmed.split(/\r?\n/)[0];
|
|
484
480
|
const first_tokens = first_line.split(/\s+/).filter(Boolean);
|
|
485
|
-
if (first_tokens.length === 3 && first_tokens.every((
|
|
481
|
+
if (first_tokens.length === 3 && first_tokens.every((token) => /^\d+$/.test(token))) {
|
|
486
482
|
try {
|
|
487
483
|
return parse_frmsf(content);
|
|
488
484
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Matrix3x3, Vec3 } from '../math';
|
|
1
|
+
import type { Matrix3x3, Point2D, Vec3 } from '../math';
|
|
2
2
|
import type { TooltipConfig, TooltipProp } from '../tooltip';
|
|
3
3
|
export type SpinChannel = `up` | `down` | null;
|
|
4
4
|
export type RepresentationMode = `solid` | `wireframe` | `transparent`;
|
|
@@ -95,10 +95,7 @@ export interface FermiHoverData {
|
|
|
95
95
|
spin: SpinChannel;
|
|
96
96
|
position_cartesian: Vec3;
|
|
97
97
|
position_fractional: Vec3 | null;
|
|
98
|
-
screen_position:
|
|
99
|
-
x: number;
|
|
100
|
-
y: number;
|
|
101
|
-
};
|
|
98
|
+
screen_position: Point2D;
|
|
102
99
|
surface_color?: string;
|
|
103
100
|
property_value?: number;
|
|
104
101
|
property_name?: string;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { format_num } from '../labels'
|
|
5
5
|
import type { AxisConfig } from '../plot'
|
|
6
6
|
import ColorBar from '../plot/ColorBar.svelte'
|
|
7
|
+
import { make_change_detector } from '../utils'
|
|
7
8
|
import * as d3_sc from 'd3-scale-chromatic'
|
|
8
9
|
import { type ComponentProps, onDestroy, onMount, type Snippet } from 'svelte'
|
|
9
10
|
import type { HTMLAttributes } from 'svelte/elements'
|
|
@@ -212,6 +213,7 @@
|
|
|
212
213
|
// === Value resolution ===
|
|
213
214
|
let x_keys = $derived(x_items.map((item) => item.key ?? item.label))
|
|
214
215
|
let y_keys = $derived(y_items.map((item) => item.key ?? item.label))
|
|
216
|
+
let interaction_axis_signature = $derived(JSON.stringify([x_keys, y_keys]))
|
|
215
217
|
let highlight_x_key_set = $derived(new SvelteSet(highlight_x_keys))
|
|
216
218
|
let highlight_y_key_set = $derived(new SvelteSet(highlight_y_keys))
|
|
217
219
|
let search_query_norm = $derived(search_query.trim().toLowerCase())
|
|
@@ -577,9 +579,8 @@
|
|
|
577
579
|
return vis_y.slice(start_pos, end_pos)
|
|
578
580
|
})
|
|
579
581
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
}
|
|
582
|
+
const is_selected_cell = (x_idx: number, y_idx: number): boolean =>
|
|
583
|
+
selected_cell_key_set.has(cell_pos_key(x_idx, y_idx))
|
|
583
584
|
|
|
584
585
|
let vis_x_pos_map = $derived.by(() => {
|
|
585
586
|
const position_map = new SvelteMap<number, number>()
|
|
@@ -1086,6 +1087,23 @@
|
|
|
1086
1087
|
|
|
1087
1088
|
// Tooltip state: only used for custom tooltip snippets (function tooltips)
|
|
1088
1089
|
let tooltip_cell: CellContext | null = $state(null)
|
|
1090
|
+
const axis_changed = make_change_detector()
|
|
1091
|
+
$effect(() => {
|
|
1092
|
+
if (!axis_changed(interaction_axis_signature)) return
|
|
1093
|
+
cancel_raf(active_cell_raf)
|
|
1094
|
+
// Cancel delayed clicks before old cell coordinates can fire on new axes.
|
|
1095
|
+
clear_pending_click()
|
|
1096
|
+
active_cell = null
|
|
1097
|
+
pinned_cell = null
|
|
1098
|
+
selected_cells = []
|
|
1099
|
+
last_selected_cell = null
|
|
1100
|
+
brush_start = null
|
|
1101
|
+
brush_end = null
|
|
1102
|
+
last_hover_x = -1
|
|
1103
|
+
last_hover_y = -1
|
|
1104
|
+
tooltip_cell = null
|
|
1105
|
+
tooltip_div?.classList.remove(`visible`)
|
|
1106
|
+
})
|
|
1089
1107
|
|
|
1090
1108
|
onMount(() => {
|
|
1091
1109
|
update_viewport_state()
|
|
@@ -33,15 +33,15 @@ export function matrix_to_rows(x_items, y_items, values) {
|
|
|
33
33
|
return row;
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
|
+
function escape_csv_field(value) {
|
|
37
|
+
const field = String(value ?? ``);
|
|
38
|
+
if (!/[",\n\r]/.test(field))
|
|
39
|
+
return field;
|
|
40
|
+
return `"${field.replaceAll(`"`, `""`)}"`;
|
|
41
|
+
}
|
|
36
42
|
export function rows_to_csv(rows) {
|
|
37
43
|
if (!rows.length)
|
|
38
44
|
return ``;
|
|
39
|
-
const escape_csv_field = (value) => {
|
|
40
|
-
const field = String(value ?? ``);
|
|
41
|
-
if (!/[",\n\r]/.test(field))
|
|
42
|
-
return field;
|
|
43
|
-
return `"${field.replaceAll(`"`, `""`)}"`;
|
|
44
|
-
};
|
|
45
45
|
const headers = Object.keys(rows[0]);
|
|
46
46
|
const lines = [
|
|
47
47
|
headers.map((header) => escape_csv_field(header)).join(`,`),
|
package/dist/io/decompress.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { COMPRESSION_EXTENSIONS
|
|
1
|
+
import type { COMPRESSION_EXTENSIONS } from '../constants';
|
|
2
|
+
import { COMPRESSION_FORMATS } from '../constants';
|
|
2
3
|
export type CompressionFormat = keyof typeof COMPRESSION_FORMATS;
|
|
3
4
|
export type CompressionExtension = (typeof COMPRESSION_EXTENSIONS)[number];
|
|
4
5
|
export declare function detect_compression_format(filename: string): CompressionFormat | null;
|
package/dist/io/decompress.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { COMPRESSION_EXTENSIONS_REGEX, COMPRESSION_FORMATS } from '../constants';
|
|
2
2
|
export function detect_compression_format(filename) {
|
|
3
3
|
const lower = filename.toLowerCase();
|
|
4
4
|
for (const [format, extensions] of Object.entries(COMPRESSION_FORMATS)) {
|
package/dist/io/export.js
CHANGED
|
@@ -91,7 +91,7 @@ export function export_canvas_as_png(canvas, structure_or_filename, png_dpi = 15
|
|
|
91
91
|
// Helper to ensure font-family is set on SVG root
|
|
92
92
|
function set_svg_font_family(svg) {
|
|
93
93
|
const style = svg.getAttribute(`style`) || ``;
|
|
94
|
-
if (
|
|
94
|
+
if (!style.includes(`font-family`)) {
|
|
95
95
|
svg.setAttribute(`style`, `${style}${style ? `;` : ``}font-family:sans-serif;`);
|
|
96
96
|
}
|
|
97
97
|
// Also set as attribute for extra robustness
|
package/dist/io/index.d.ts
CHANGED
package/dist/io/index.js
CHANGED
package/dist/io/url-drop.js
CHANGED
|
@@ -90,6 +90,7 @@ export async function load_from_url(url, callback) {
|
|
|
90
90
|
// Skip Range requests for known text formats to avoid production server issues
|
|
91
91
|
// Include VASP files that don't have extensions (POSCAR, XDATCAR, CONTCAR)
|
|
92
92
|
const is_known_text = TEXT_EXTENSIONS.has(ext) || VASP_BASENAME_RE.test(url_basename);
|
|
93
|
+
let binary_callback_args;
|
|
93
94
|
if (!is_known_text) {
|
|
94
95
|
try {
|
|
95
96
|
// Check for magic bytes only for unknown formats
|
|
@@ -102,7 +103,10 @@ export async function load_from_url(url, callback) {
|
|
|
102
103
|
const resp = await fetch(url);
|
|
103
104
|
if (!resp.ok)
|
|
104
105
|
throw new Error(`Fetch failed: ${resp.status}`);
|
|
105
|
-
|
|
106
|
+
binary_callback_args = [
|
|
107
|
+
await resp.arrayBuffer(),
|
|
108
|
+
extract_filename(resp.headers, url_basename),
|
|
109
|
+
];
|
|
106
110
|
}
|
|
107
111
|
}
|
|
108
112
|
}
|
|
@@ -110,6 +114,8 @@ export async function load_from_url(url, callback) {
|
|
|
110
114
|
// Fall through to text fetch if HEAD request fails
|
|
111
115
|
}
|
|
112
116
|
}
|
|
117
|
+
if (binary_callback_args)
|
|
118
|
+
return callback(...binary_callback_args);
|
|
113
119
|
const resp = await fetch(url);
|
|
114
120
|
if (!resp.ok)
|
|
115
121
|
throw new Error(`Fetch failed: ${resp.status}`);
|
|
@@ -68,9 +68,7 @@
|
|
|
68
68
|
<div class="pane-row compact-row">
|
|
69
69
|
{#if volumes.length > 1}
|
|
70
70
|
<label
|
|
71
|
-
{@attach tooltip({
|
|
72
|
-
content: `Select which volume to display (e.g. charge vs magnetization)`,
|
|
73
|
-
})}
|
|
71
|
+
{@attach tooltip({ content: `Select which volume to display (e.g. charge vs magnetization)` })}
|
|
74
72
|
>
|
|
75
73
|
<span>Volume:</span>
|
|
76
74
|
<select bind:value={active_volume_idx}>
|
|
@@ -81,15 +79,13 @@
|
|
|
81
79
|
</label>
|
|
82
80
|
{/if}
|
|
83
81
|
<label
|
|
84
|
-
{@attach tooltip({
|
|
85
|
-
content: `Number of isosurface shells at different density thresholds`,
|
|
86
|
-
})}
|
|
82
|
+
{@attach tooltip({ content: `Number of isosurface shells at different density thresholds` })}
|
|
87
83
|
>
|
|
88
84
|
<span>Layers:</span>
|
|
89
85
|
<select
|
|
90
86
|
value={n_layers}
|
|
91
87
|
onchange={(event) =>
|
|
92
|
-
set_layer_count(Number(
|
|
88
|
+
set_layer_count(Number(event.currentTarget.value))}
|
|
93
89
|
>
|
|
94
90
|
{#each [1, 2, 3, 4, 5] as count (count)}
|
|
95
91
|
<option value={count}>{count}</option>
|
|
@@ -99,10 +95,7 @@
|
|
|
99
95
|
<!-- Sync both settings.show_negative (single-layer fallback) and all layer entries
|
|
100
96
|
so the toggle works consistently regardless of which mode is active -->
|
|
101
97
|
<label
|
|
102
|
-
{@attach tooltip({
|
|
103
|
-
content:
|
|
104
|
-
`Show negative lobe at −isovalue (for orbitals, ESP, magnetization)`,
|
|
105
|
-
})}
|
|
98
|
+
{@attach tooltip({ content: `Show negative lobe at −isovalue (for orbitals, ESP, magnetization)` })}
|
|
106
99
|
>
|
|
107
100
|
<span>Neg. lobe</span>
|
|
108
101
|
<input
|
|
@@ -111,7 +104,7 @@
|
|
|
111
104
|
? settings.layers?.some((layer) => layer.show_negative) ?? false
|
|
112
105
|
: settings.show_negative}
|
|
113
106
|
onchange={(event) => {
|
|
114
|
-
const checked =
|
|
107
|
+
const checked = event.currentTarget.checked
|
|
115
108
|
settings.show_negative = checked
|
|
116
109
|
if (settings.layers) {
|
|
117
110
|
settings.layers = settings.layers.map((layer) => ({
|
|
@@ -143,7 +136,7 @@
|
|
|
143
136
|
type="color"
|
|
144
137
|
value={layer.color}
|
|
145
138
|
onchange={(event) =>
|
|
146
|
-
update_layer(idx, { color:
|
|
139
|
+
update_layer(idx, { color: event.currentTarget.value })}
|
|
147
140
|
/>
|
|
148
141
|
<input
|
|
149
142
|
type="range"
|
|
@@ -153,7 +146,7 @@
|
|
|
153
146
|
value={layer.isovalue}
|
|
154
147
|
oninput={(event) =>
|
|
155
148
|
update_layer(idx, {
|
|
156
|
-
isovalue: Number(
|
|
149
|
+
isovalue: Number(event.currentTarget.value),
|
|
157
150
|
})}
|
|
158
151
|
style="flex: 1; min-width: 60px"
|
|
159
152
|
/>
|
|
@@ -166,7 +159,7 @@
|
|
|
166
159
|
value={layer.opacity}
|
|
167
160
|
oninput={(event) =>
|
|
168
161
|
update_layer(idx, {
|
|
169
|
-
opacity: Number(
|
|
162
|
+
opacity: Number(event.currentTarget.value),
|
|
170
163
|
})}
|
|
171
164
|
style="width: 50px"
|
|
172
165
|
title="Opacity: {format_num(layer.opacity, `.2f`)}"
|
|
@@ -176,9 +169,7 @@
|
|
|
176
169
|
{:else}
|
|
177
170
|
<!-- Single-layer: isovalue slider full width -->
|
|
178
171
|
<label
|
|
179
|
-
{@attach tooltip({
|
|
180
|
-
content: `Density threshold — surface is drawn where grid values equal this`,
|
|
181
|
-
})}
|
|
172
|
+
{@attach tooltip({ content: `Density threshold — surface is drawn where grid values equal this` })}
|
|
182
173
|
>
|
|
183
174
|
<span>Isovalue:</span>
|
|
184
175
|
<input
|
|
@@ -194,9 +185,7 @@
|
|
|
194
185
|
<!-- Opacity + colors on one row -->
|
|
195
186
|
<div class="pane-row compact-row">
|
|
196
187
|
<label
|
|
197
|
-
{@attach tooltip({
|
|
198
|
-
content: `Surface transparency — lower values reveal inner structure`,
|
|
199
|
-
})}
|
|
188
|
+
{@attach tooltip({ content: `Surface transparency — lower values reveal inner structure` })}
|
|
200
189
|
>
|
|
201
190
|
<span>Opacity:</span>
|
|
202
191
|
<input
|
|
@@ -226,10 +215,7 @@
|
|
|
226
215
|
|
|
227
216
|
{#if volumes?.[active_volume_idx]?.periodic}
|
|
228
217
|
<label
|
|
229
|
-
{@attach tooltip({
|
|
230
|
-
content:
|
|
231
|
-
`Extend isosurface beyond cell boundaries to close partial spheres (fraction of cell)`,
|
|
232
|
-
})}
|
|
218
|
+
{@attach tooltip({ content: `Extend isosurface beyond cell boundaries to close partial spheres (fraction of cell)` })}
|
|
233
219
|
>
|
|
234
220
|
Halo: {format_num(settings.halo, `.2f`)}
|
|
235
221
|
<input
|
package/dist/isosurface/slice.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// crystallographic plane defined by Miller indices, using trilinear interpolation.
|
|
3
3
|
import { reciprocal_lattice } from '../brillouin';
|
|
4
4
|
import * as math from '../math';
|
|
5
|
+
const safe_mod = (val, dim) => ((val % dim) + dim) % dim;
|
|
5
6
|
// Trilinear interpolation of a scalar 3D grid at fractional coordinates.
|
|
6
7
|
// Periodic grids wrap with modulo; non-periodic return 0 for out-of-bounds.
|
|
7
8
|
export function trilinear_interpolate(grid, fx, fy, fz, periodic) {
|
|
@@ -19,7 +20,6 @@ export function trilinear_interpolate(grid, fx, fy, fz, periodic) {
|
|
|
19
20
|
if (fx < 0 || fx > 1 || fy < 0 || fy > 1 || fz < 0 || fz > 1)
|
|
20
21
|
return 0;
|
|
21
22
|
}
|
|
22
|
-
const safe_mod = (val, dim) => ((val % dim) + dim) % dim;
|
|
23
23
|
const x0 = periodic
|
|
24
24
|
? safe_mod(Math.floor(gx), nx)
|
|
25
25
|
: Math.max(0, Math.min(Math.floor(gx), nx - 2));
|
package/dist/isosurface/types.js
CHANGED
|
@@ -34,6 +34,12 @@ export function grid_data_range(grid) {
|
|
|
34
34
|
const abs_max = Math.max(Math.abs(min_val), Math.abs(max_val));
|
|
35
35
|
return { min: min_val, max: max_val, abs_max, mean: count > 0 ? sum / count : 0 };
|
|
36
36
|
}
|
|
37
|
+
const wrap_grid_idx = (val, size) => ((val % size) + size) % size;
|
|
38
|
+
const clamp_dim = (src, fac) => Math.min(src, Math.max(2, Math.ceil(src / fac)));
|
|
39
|
+
const partition_ranges = (n_out, n_src) => Array.from({ length: n_out }, (_, idx) => [
|
|
40
|
+
Math.round((idx * n_src) / n_out),
|
|
41
|
+
Math.round(((idx + 1) * n_src) / n_out),
|
|
42
|
+
]);
|
|
37
43
|
// Pad a periodic 3D grid with halo cells from the opposite face so isosurfaces
|
|
38
44
|
// extend beyond the unit cell and close into complete enclosed shapes.
|
|
39
45
|
// Returns a larger grid with dims [nx+2*pad, ny+2*pad, nz+2*pad] and the
|
|
@@ -49,16 +55,15 @@ export function pad_periodic_grid(grid, dims, pad_fraction) {
|
|
|
49
55
|
const out_nx = nx + 2 * px;
|
|
50
56
|
const out_ny = ny + 2 * py;
|
|
51
57
|
const out_nz = nz + 2 * pz;
|
|
52
|
-
const wrap = (val, size) => ((val % size) + size) % size;
|
|
53
58
|
const out = Array(out_nx);
|
|
54
59
|
for (let ix = 0; ix < out_nx; ix++) {
|
|
55
60
|
const plane = Array(out_ny);
|
|
56
|
-
const src_x =
|
|
61
|
+
const src_x = wrap_grid_idx(ix - px, nx);
|
|
57
62
|
for (let iy = 0; iy < out_ny; iy++) {
|
|
58
63
|
const row = Array(out_nz);
|
|
59
|
-
const src_y =
|
|
64
|
+
const src_y = wrap_grid_idx(iy - py, ny);
|
|
60
65
|
for (let iz = 0; iz < out_nz; iz++) {
|
|
61
|
-
row[iz] = grid[src_x][src_y][
|
|
66
|
+
row[iz] = grid[src_x][src_y][wrap_grid_idx(iz - pz, nz)];
|
|
62
67
|
}
|
|
63
68
|
plane[iy] = row;
|
|
64
69
|
}
|
|
@@ -85,7 +90,6 @@ export function downsample_grid(grid, dims, max_points = MAX_GRID_POINTS) {
|
|
|
85
90
|
// A single cbrt step can overshoot for anisotropic grids where max(2,...)
|
|
86
91
|
// clamping prevents a small axis from shrinking below 2.
|
|
87
92
|
// clamp_dim: returns 1 for single-cell axes, otherwise clamps to [2, src]
|
|
88
|
-
const clamp_dim = (src, fac) => Math.min(src, Math.max(2, Math.ceil(src / fac)));
|
|
89
93
|
let factor = Math.ceil(Math.cbrt(total / max_points));
|
|
90
94
|
let new_nx = clamp_dim(nx, factor);
|
|
91
95
|
let new_ny = clamp_dim(ny, factor);
|
|
@@ -103,13 +107,9 @@ export function downsample_grid(grid, dims, max_points = MAX_GRID_POINTS) {
|
|
|
103
107
|
// Proportional partitioning: evenly divides [0, n) into new_n non-empty blocks.
|
|
104
108
|
// Unlike fixed-stride (ix * factor), this is safe when max(2,...) clamping
|
|
105
109
|
// produces more output cells than ceil(n/factor) would — no empty blocks.
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
]);
|
|
110
|
-
const x_ranges = partition(new_nx, nx);
|
|
111
|
-
const y_ranges = partition(new_ny, ny);
|
|
112
|
-
const z_ranges = partition(new_nz, nz);
|
|
110
|
+
const x_ranges = partition_ranges(new_nx, nx);
|
|
111
|
+
const y_ranges = partition_ranges(new_ny, ny);
|
|
112
|
+
const z_ranges = partition_ranges(new_nz, nz);
|
|
113
113
|
const out = Array(new_nx);
|
|
114
114
|
for (let ix = 0; ix < new_nx; ix++) {
|
|
115
115
|
const plane = Array(new_ny);
|
package/dist/labels.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import * as d3_symbols from 'd3-shape';
|
|
|
5
5
|
export type D3Symbol = keyof typeof d3_symbols & `symbol${Capitalize<string>}`;
|
|
6
6
|
export type D3SymbolName = Exclude<D3Symbol extends `symbol${infer Name}` ? Name : never, ``>;
|
|
7
7
|
export declare const symbol_names: D3SymbolName[];
|
|
8
|
-
export declare const symbol_map: Record<D3SymbolName, SymbolType
|
|
8
|
+
export declare const symbol_map: Partial<Record<D3SymbolName, SymbolType>>;
|
|
9
9
|
export declare function format_value(value: number, formatter?: string): string;
|
|
10
10
|
export declare const ELEM_PROPERTY_LABELS: Partial<Record<keyof ChemicalElement, [string, string | null]>>;
|
|
11
11
|
export declare const ELEM_HEATMAP_KEYS: (keyof ChemicalElement)[];
|
package/dist/labels.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { format } from 'd3-format';
|
|
2
2
|
import * as d3_symbols from 'd3-shape';
|
|
3
3
|
import { timeFormat } from 'd3-time-format';
|
|
4
|
+
const is_d3_symbol_name = (name) => Object.hasOwn(d3_symbols, `symbol${name}`);
|
|
4
5
|
function name_for_symbol(sym) {
|
|
5
|
-
for (const key
|
|
6
|
-
if (
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
for (const [key, symbol] of Object.entries(d3_symbols)) {
|
|
7
|
+
if (symbol === sym && /^symbol[A-Z]/.test(key)) {
|
|
8
|
+
const name = key.substring(6);
|
|
9
|
+
if (is_d3_symbol_name(name))
|
|
10
|
+
return name;
|
|
11
|
+
}
|
|
10
12
|
}
|
|
11
13
|
return null;
|
|
12
14
|
}
|
|
@@ -81,7 +83,7 @@ export const ELEM_HEATMAP_KEYS = [
|
|
|
81
83
|
export const ELEM_HEATMAP_LABELS = Object.fromEntries(ELEM_HEATMAP_KEYS.map((key) => {
|
|
82
84
|
const [label, unit] = ELEM_PROPERTY_LABELS[key] ?? [];
|
|
83
85
|
if (!label)
|
|
84
|
-
throw `Unexpected missing label ${
|
|
86
|
+
throw new Error(`Unexpected missing label for element property ${key}`);
|
|
85
87
|
return [label + (unit ? ` (${unit})` : ``), key];
|
|
86
88
|
}));
|
|
87
89
|
// Allow users to import DEFAULT_FMT and change its items in place to
|
|
@@ -134,18 +136,18 @@ export const format_bytes = (bytes) => {
|
|
|
134
136
|
export function format_fractional(value) {
|
|
135
137
|
if (!Number.isFinite(value))
|
|
136
138
|
return String(value);
|
|
137
|
-
const
|
|
139
|
+
const wrapped_value = ((value % 1) + 1) % 1; // wrap into [0,1)
|
|
138
140
|
const eps = 1e-3;
|
|
139
141
|
for (const [target, glyph] of FRACTION_GLYPHS) {
|
|
140
142
|
if (target === 0) {
|
|
141
|
-
if (Math.abs(
|
|
143
|
+
if (Math.abs(wrapped_value - target) <= eps)
|
|
142
144
|
return glyph;
|
|
143
145
|
}
|
|
144
|
-
else if (Math.abs(
|
|
146
|
+
else if (Math.abs(wrapped_value - target) < eps)
|
|
145
147
|
return glyph;
|
|
146
148
|
}
|
|
147
149
|
for (const [target, glyph] of FRACTION_GLYPHS) {
|
|
148
|
-
if (target !== 0 && Math.abs(1 -
|
|
150
|
+
if (target !== 0 && Math.abs(1 - wrapped_value - target) < eps)
|
|
149
151
|
return glyph;
|
|
150
152
|
}
|
|
151
153
|
return format_num(value, `.4~`);
|
|
@@ -216,6 +218,7 @@ export const SUPERSCRIPT_MAP = {
|
|
|
216
218
|
'+': `⁺`,
|
|
217
219
|
'-': `⁻`,
|
|
218
220
|
};
|
|
221
|
+
const is_superscript_key = (key) => key in SUPERSCRIPT_MAP;
|
|
219
222
|
export const SUBSCRIPT_MAP = {
|
|
220
223
|
'0': `₀`,
|
|
221
224
|
'1': `₁`,
|
|
@@ -229,7 +232,7 @@ export const SUBSCRIPT_MAP = {
|
|
|
229
232
|
'9': `₉`,
|
|
230
233
|
};
|
|
231
234
|
// replaces all signs and digits with their unicode superscript equivalent
|
|
232
|
-
export const superscript_digits = (input) => input.replace(/[\d+-]/g, (match) => SUPERSCRIPT_MAP[match]
|
|
235
|
+
export const superscript_digits = (input) => input.replace(/[\d+-]/g, (match) => is_superscript_key(match) ? SUPERSCRIPT_MAP[match] : match);
|
|
233
236
|
// Trajectory property configuration: clean labels and units as structured data
|
|
234
237
|
export const trajectory_property_config = {
|
|
235
238
|
// Energy properties
|
|
@@ -49,10 +49,12 @@
|
|
|
49
49
|
else void copy_to_clipboard()
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
function handle_keydown(
|
|
52
|
+
function handle_keydown(
|
|
53
|
+
event: KeyboardEvent & { currentTarget: HTMLElement },
|
|
54
|
+
): void {
|
|
53
55
|
if (disabled || (event.key !== `Enter` && event.key !== ` `)) return
|
|
54
56
|
event.preventDefault()
|
|
55
|
-
|
|
57
|
+
event.currentTarget.click()
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
function handle_remove(event: MouseEvent): void {
|
|
@@ -66,8 +68,8 @@
|
|
|
66
68
|
tabindex={disabled ? -1 : 0}
|
|
67
69
|
onclick={handle_click}
|
|
68
70
|
onkeydown={handle_keydown}
|
|
69
|
-
{title}
|
|
70
|
-
{@attach tooltip()}
|
|
71
|
+
title={sanitize_html(title)}
|
|
72
|
+
{@attach tooltip({ allow_html: true })}
|
|
71
73
|
class="info-tag {variant} {size}"
|
|
72
74
|
class:disabled
|
|
73
75
|
aria-disabled={disabled}
|
|
@@ -56,10 +56,12 @@
|
|
|
56
56
|
return histogram_data.filter((val) => val >= min && val <= max)
|
|
57
57
|
})
|
|
58
58
|
|
|
59
|
-
function onkeydown(
|
|
59
|
+
function onkeydown(
|
|
60
|
+
event: KeyboardEvent & { currentTarget: HTMLInputElement },
|
|
61
|
+
): void {
|
|
60
62
|
if (event.key === `Enter`) {
|
|
61
63
|
event.preventDefault()
|
|
62
|
-
|
|
64
|
+
event.currentTarget.blur()
|
|
63
65
|
} else if (event.key === `Escape` && active) {
|
|
64
66
|
event.preventDefault()
|
|
65
67
|
clear_filter()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import Icon from '../../Icon.svelte'
|
|
3
3
|
import { download } from '../../io/fetch'
|
|
4
|
+
import { make_change_detector } from '../../utils'
|
|
4
5
|
import { setContext, tick } from 'svelte'
|
|
5
6
|
import { highlight_matches, tooltip } from 'svelte-multiselect/attachments'
|
|
6
7
|
import type { HTMLAttributes } from 'svelte/elements'
|
|
@@ -89,24 +90,31 @@
|
|
|
89
90
|
// Copy feedback positioning (null = use default corner position)
|
|
90
91
|
let copy_feedback_pos = $state<{ x: number; y: number } | null>(null)
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
let prev_value_ref: unknown
|
|
93
|
+
const value_changed = make_change_detector()
|
|
94
94
|
$effect.pre(() => {
|
|
95
|
-
if (
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
95
|
+
if (!value_changed(value)) return
|
|
96
|
+
focused_path = null
|
|
97
|
+
registered_paths_set = new Set()
|
|
98
|
+
registered_paths_list = []
|
|
99
|
+
copy_feedback_path = null
|
|
100
|
+
copy_feedback_error = false
|
|
101
|
+
context_menu_state = null
|
|
102
|
+
force_expanded = new SvelteSet()
|
|
103
|
+
const valid_paths = new SvelteSet(collect_all_paths(value, root_label ?? ``))
|
|
104
|
+
collapsed_paths = new SvelteSet([...collapsed_paths].filter((path) => valid_paths.has(path)))
|
|
105
|
+
pinned_paths = new SvelteSet()
|
|
106
|
+
selected_paths = new SvelteSet()
|
|
107
|
+
last_selected_path = null
|
|
108
|
+
current_match_index = -1
|
|
109
|
+
prev_values.clear()
|
|
110
|
+
if (search_query) queueMicrotask(() => expand_to_matches())
|
|
102
111
|
})
|
|
103
112
|
|
|
104
113
|
// Debounce search input
|
|
105
114
|
let search_debounce_timeout: ReturnType<typeof setTimeout> | undefined
|
|
106
115
|
|
|
107
|
-
function handle_search_input(event: Event) {
|
|
108
|
-
|
|
109
|
-
search_input_value = input.value
|
|
116
|
+
function handle_search_input(event: Event & { currentTarget: HTMLInputElement }) {
|
|
117
|
+
search_input_value = event.currentTarget.value
|
|
110
118
|
|
|
111
119
|
if (search_debounce_timeout) clearTimeout(search_debounce_timeout)
|
|
112
120
|
search_debounce_timeout = setTimeout(() => {
|
|
@@ -209,7 +217,7 @@
|
|
|
209
217
|
}
|
|
210
218
|
|
|
211
219
|
// Previous values map for change detection
|
|
212
|
-
const
|
|
220
|
+
const prev_values = new Map<string, unknown>()
|
|
213
221
|
|
|
214
222
|
// Toggle collapse - tracks force_expanded to override auto-fold thresholds
|
|
215
223
|
function toggle_collapse(path: string, is_currently_collapsed: boolean): void {
|
|
@@ -471,7 +479,7 @@
|
|
|
471
479
|
get focused_path() {
|
|
472
480
|
return focused_path
|
|
473
481
|
},
|
|
474
|
-
|
|
482
|
+
prev_values,
|
|
475
483
|
toggle_collapse,
|
|
476
484
|
toggle_collapse_recursive,
|
|
477
485
|
expand_all,
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
$effect(() => {
|
|
40
40
|
if (!ctx?.settings.highlight_changes) return
|
|
41
41
|
|
|
42
|
-
const prev = ctx.
|
|
42
|
+
const prev = ctx.prev_values.get(path)
|
|
43
43
|
if (prev !== undefined && !values_equal(prev, value)) {
|
|
44
44
|
just_changed = true
|
|
45
45
|
if (change_timeout) clearTimeout(change_timeout)
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
just_changed = false
|
|
48
48
|
}, 1000)
|
|
49
49
|
}
|
|
50
|
-
ctx.
|
|
50
|
+
ctx.prev_values.set(path, value)
|
|
51
51
|
|
|
52
52
|
return () => {
|
|
53
53
|
if (change_timeout) clearTimeout(change_timeout)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { GhostEntry } from './utils';
|
|
1
2
|
export type JsonValueType = `string` | `number` | `boolean` | `null` | `undefined` | `object` | `array` | `date` | `regexp` | `map` | `set` | `symbol` | `bigint` | `error` | `function` | `circular`;
|
|
2
3
|
export interface JsonTreeProps {
|
|
3
4
|
value: unknown;
|
|
@@ -37,7 +38,7 @@ export interface JsonTreeContext {
|
|
|
37
38
|
search_matches: Set<string>;
|
|
38
39
|
current_match_path: string | null;
|
|
39
40
|
focused_path: string | null;
|
|
40
|
-
|
|
41
|
+
prev_values: Map<string, unknown>;
|
|
41
42
|
toggle_collapse: (path: string, is_currently_collapsed: boolean) => void;
|
|
42
43
|
toggle_collapse_recursive: (path: string, collapse: boolean) => void;
|
|
43
44
|
expand_all: () => void;
|
|
@@ -55,7 +56,7 @@ export interface JsonTreeContext {
|
|
|
55
56
|
toggle_select: (path: string, shift: boolean) => void;
|
|
56
57
|
copy_selected: () => void;
|
|
57
58
|
diff_map: Map<string, DiffEntry> | null;
|
|
58
|
-
ghost_map: Map<string,
|
|
59
|
+
ghost_map: Map<string, GhostEntry[]>;
|
|
59
60
|
collapse_children_only: (path: string) => void;
|
|
60
61
|
onchange?: (path: string, new_value: unknown, old_value: unknown) => void;
|
|
61
62
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { DiffEntry, JsonValueType } from './types';
|
|
2
2
|
export declare function get_value_type(value: unknown): JsonValueType;
|
|
3
|
-
export declare
|
|
4
|
-
export declare
|
|
5
|
-
export declare
|
|
3
|
+
export declare const is_expandable_type: (value_type: JsonValueType) => boolean;
|
|
4
|
+
export declare const is_primitive_type: (value_type: JsonValueType) => boolean;
|
|
5
|
+
export declare const is_expandable: (value: unknown) => boolean;
|
|
6
6
|
export declare function get_child_count(value: unknown): number;
|
|
7
7
|
export declare function format_path(segments: (string | number)[]): string;
|
|
8
8
|
export declare function build_path(parent_path: string, key: string | number): string;
|
|
@@ -16,7 +16,7 @@ export declare function parse_path(path: string): (string | number)[];
|
|
|
16
16
|
export declare function values_equal(val_a: unknown, val_b: unknown): boolean;
|
|
17
17
|
export declare function parse_edited_value(text: string): unknown;
|
|
18
18
|
export declare function set_at_path(root: unknown, path_str: string, new_value: unknown, root_label?: string): unknown;
|
|
19
|
-
export declare
|
|
19
|
+
export declare const is_url: (str: string) => boolean;
|
|
20
20
|
export declare function is_css_color(str: string): boolean;
|
|
21
21
|
export declare function estimate_byte_size(value: unknown, max_depth?: number, current_depth?: number): number;
|
|
22
22
|
export interface GhostEntry {
|