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.
- package/dist/FilePicker.svelte +40 -50
- package/dist/api/optimade.js +10 -7
- package/dist/app.css +15 -0
- package/dist/brillouin/BrillouinZone.svelte +18 -9
- package/dist/brillouin/BrillouinZoneScene.svelte +20 -29
- package/dist/brillouin/compute.js +10 -16
- package/dist/brillouin/geometry.js +2 -2
- package/dist/chempot-diagram/ChemPotDiagram.svelte +18 -15
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +17 -113
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +104 -264
- package/dist/chempot-diagram/async-compute.svelte.js +12 -13
- package/dist/chempot-diagram/color.d.ts +21 -1
- package/dist/chempot-diagram/color.js +70 -1
- package/dist/chempot-diagram/compute.d.ts +7 -0
- package/dist/chempot-diagram/compute.js +85 -26
- package/dist/chempot-diagram/export.js +1 -6
- package/dist/chempot-diagram/temperature.js +9 -10
- package/dist/composition/BarChart.svelte +7 -9
- package/dist/composition/Composition.svelte +3 -8
- package/dist/composition/Formula.svelte +2 -2
- package/dist/composition/FormulaFilter.svelte +27 -93
- package/dist/composition/format.js +6 -8
- package/dist/composition/parse.js +50 -105
- package/dist/constants.d.ts +0 -1
- package/dist/constants.js +6 -17
- package/dist/convex-hull/ConvexHull2D.svelte +0 -2
- package/dist/convex-hull/ConvexHull3D.svelte +19 -47
- package/dist/convex-hull/ConvexHull4D.svelte +65 -95
- package/dist/convex-hull/StructurePopup.svelte +1 -1
- package/dist/convex-hull/gas-thermodynamics.js +21 -53
- package/dist/convex-hull/helpers.js +1 -7
- package/dist/convex-hull/thermodynamics.js +19 -27
- package/dist/coordination/CoordinationBarPlot.svelte +12 -21
- package/dist/element/BohrAtom.svelte +0 -1
- package/dist/element/ElementTile.svelte +26 -44
- package/dist/element/data.d.ts +2 -0
- package/dist/element/data.js +5 -1
- package/dist/element/index.d.ts +1 -1
- package/dist/element/index.js +1 -1
- package/dist/fermi-surface/FermiSurface.svelte +22 -23
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +2 -6
- package/dist/fermi-surface/FermiSurfaceScene.svelte +32 -77
- package/dist/fermi-surface/compute.js +22 -55
- package/dist/fermi-surface/parse.js +38 -70
- package/dist/file-viewer/JsonBrowser.svelte +1043 -0
- package/dist/file-viewer/JsonBrowser.svelte.d.ts +9 -0
- package/dist/file-viewer/PlotPanel.svelte +350 -0
- package/dist/file-viewer/PlotPanel.svelte.d.ts +9 -0
- package/dist/file-viewer/TrajectoryWithDos.svelte +30 -0
- package/dist/file-viewer/TrajectoryWithDos.svelte.d.ts +10 -0
- package/dist/file-viewer/detect.d.ts +11 -0
- package/dist/file-viewer/detect.js +381 -0
- package/dist/file-viewer/eligibility.d.ts +4 -0
- package/dist/file-viewer/eligibility.js +53 -0
- package/dist/file-viewer/host-protocol.d.ts +50 -0
- package/dist/file-viewer/host-transfer.d.ts +25 -0
- package/dist/file-viewer/host-transfer.js +42 -0
- package/dist/file-viewer/index.d.ts +5 -0
- package/dist/file-viewer/index.js +5 -0
- package/dist/file-viewer/main.d.ts +44 -0
- package/dist/file-viewer/main.js +535 -0
- package/dist/file-viewer/parse.d.ts +9 -0
- package/dist/file-viewer/parse.js +170 -0
- package/dist/file-viewer/plot-utils.d.ts +24 -0
- package/dist/file-viewer/plot-utils.js +191 -0
- package/dist/file-viewer/types.d.ts +4 -0
- package/dist/file-viewer/types.js +5 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +57 -84
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/io/ExportPane.svelte +1 -1
- package/dist/io/decompress.d.ts +2 -0
- package/dist/io/decompress.js +3 -2
- package/dist/io/export.d.ts +7 -4
- package/dist/io/export.js +70 -18
- package/dist/io/file-drop.js +60 -35
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +28 -16
- package/dist/isosurface/Isosurface.svelte +687 -196
- package/dist/isosurface/Isosurface.svelte.d.ts +7 -1
- package/dist/isosurface/IsosurfaceControls.svelte +564 -85
- package/dist/isosurface/IsosurfaceControls.svelte.d.ts +1 -1
- package/dist/isosurface/VolumeSlice.svelte +224 -0
- package/dist/isosurface/VolumeSlice.svelte.d.ts +28 -0
- package/dist/isosurface/coloring.d.ts +20 -0
- package/dist/isosurface/coloring.js +118 -0
- package/dist/isosurface/geometry-worker-types.d.ts +38 -0
- package/dist/isosurface/geometry.worker.d.ts +1 -0
- package/dist/isosurface/geometry.worker.js +59 -0
- package/dist/isosurface/grid.d.ts +10 -0
- package/dist/isosurface/grid.js +31 -0
- package/dist/isosurface/index.d.ts +4 -0
- package/dist/isosurface/index.js +4 -0
- package/dist/isosurface/profile.d.ts +12 -0
- package/dist/isosurface/profile.js +19 -0
- package/dist/isosurface/sampling.d.ts +34 -0
- package/dist/isosurface/sampling.js +408 -0
- package/dist/isosurface/slice-rendering.d.ts +13 -0
- package/dist/isosurface/slice-rendering.js +79 -0
- package/dist/isosurface/slice.d.ts +22 -2
- package/dist/isosurface/slice.js +200 -116
- package/dist/isosurface/types.d.ts +24 -1
- package/dist/isosurface/types.js +120 -8
- package/dist/json-path.d.ts +4 -0
- package/dist/json-path.js +89 -0
- package/dist/labels.js +1 -1
- package/dist/layout/InfoCard.svelte +1 -3
- package/dist/layout/SettingsSection.svelte +52 -61
- package/dist/layout/SettingsSection.svelte.d.ts +6 -7
- package/dist/layout/ViewerChrome.svelte +7 -1
- package/dist/layout/json-tree/JsonNode.svelte +14 -48
- package/dist/layout/json-tree/JsonTree.svelte +48 -95
- package/dist/layout/json-tree/JsonValue.svelte +3 -18
- package/dist/layout/json-tree/utils.d.ts +0 -3
- package/dist/layout/json-tree/utils.js +50 -179
- package/dist/marching-cubes.d.ts +8 -1
- package/dist/marching-cubes.js +115 -48
- package/dist/math.d.ts +3 -2
- package/dist/math.js +29 -38
- package/dist/overlays/ContextMenu.svelte +15 -32
- package/dist/overlays/DraggablePane.svelte +39 -58
- package/dist/overlays/DraggablePane.svelte.d.ts +1 -1
- package/dist/overlays/GlassChip.svelte +3 -1
- package/dist/periodic-table/PeriodicTableControls.svelte +26 -52
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +18 -34
- package/dist/phase-diagram/build-diagram.js +1 -6
- package/dist/phase-diagram/svg-to-diagram.js +9 -14
- package/dist/plot/bar/BarPlot.svelte +38 -42
- package/dist/plot/bar/SpacegroupBarPlot.svelte +18 -42
- package/dist/plot/box/BoxPlot.svelte +27 -23
- package/dist/plot/core/auto-place.d.ts +1 -1
- package/dist/plot/core/auto-place.js +1 -1
- package/dist/plot/core/data-transform.d.ts +1 -2
- package/dist/plot/core/data-transform.js +0 -10
- package/dist/plot/core/layout.d.ts +12 -5
- package/dist/plot/core/layout.js +37 -27
- package/dist/plot/core/pan-zoom.svelte.d.ts +2 -4
- package/dist/plot/core/pan-zoom.svelte.js +34 -17
- package/dist/plot/core/placed-tween.svelte.d.ts +3 -0
- package/dist/plot/core/placed-tween.svelte.js +68 -21
- package/dist/plot/core/svg.js +0 -1
- package/dist/plot/core/utils/hierarchy-chart.d.ts +1 -0
- package/dist/plot/core/utils/hierarchy-chart.js +12 -0
- package/dist/plot/core/utils/hierarchy-labels.js +3 -2
- package/dist/plot/histogram/Histogram.svelte +21 -26
- package/dist/plot/sankey/sankey.js +13 -9
- package/dist/plot/scatter/BinnedScatterPlot.svelte +59 -43
- package/dist/plot/scatter/ScatterPlot.svelte +67 -52
- package/dist/plot/scatter/adaptive-density.d.ts +1 -1
- package/dist/plot/scatter/adaptive-density.js +36 -20
- package/dist/plot/sunburst/Sunburst.svelte +20 -20
- package/dist/plot/treemap/Treemap.svelte +175 -60
- package/dist/plot/treemap/Treemap.svelte.d.ts +6 -0
- package/dist/plot/treemap/index.d.ts +1 -0
- package/dist/plot/treemap/labels.d.ts +38 -0
- package/dist/plot/treemap/labels.js +80 -0
- package/dist/plot/treemap/treemap.d.ts +4 -2
- package/dist/plot/treemap/treemap.js +5 -2
- package/dist/rdf/RdfPlot.svelte +17 -35
- package/dist/rdf/calc-rdf.js +59 -44
- package/dist/rdf/index.d.ts +0 -1
- package/dist/sanitize.js +84 -26
- package/dist/scene/SceneCamera.svelte +1 -1
- package/dist/scene/SceneCamera.svelte.d.ts +1 -1
- package/dist/scene/index.d.ts +1 -2
- package/dist/scene/index.js +1 -1
- package/dist/scene/{props.js → props.svelte.js} +15 -1
- package/dist/settings.js +159 -482
- package/dist/spectral/Bands.svelte +151 -158
- package/dist/spectral/BrillouinBandsDos.svelte +4 -19
- package/dist/spectral/Dos.svelte +26 -24
- package/dist/spectral/helpers.js +40 -105
- package/dist/structure/AtomLegend.svelte +8 -13
- package/dist/structure/AtomLegend.svelte.d.ts +2 -3
- package/dist/structure/CellSelect.svelte +35 -10
- package/dist/structure/Structure.svelte +177 -99
- package/dist/structure/Structure.svelte.d.ts +1 -1
- package/dist/structure/StructureCarousel.svelte +10 -3
- package/dist/structure/StructureControls.svelte +8 -26
- package/dist/structure/StructureControls.svelte.d.ts +1 -1
- package/dist/structure/StructureInfoPane.svelte +65 -76
- package/dist/structure/StructureScene.svelte +75 -109
- package/dist/structure/StructureScene.svelte.d.ts +3 -1
- package/dist/structure/StructureViewport.svelte +120 -55
- package/dist/structure/StructureViewport.svelte.d.ts +3 -1
- package/dist/structure/atom-properties.d.ts +1 -1
- package/dist/structure/atom-properties.js +4 -3
- package/dist/structure/bond-order-perception.js +3 -8
- package/dist/structure/bonding.d.ts +0 -1
- package/dist/structure/bonding.js +16 -23
- package/dist/structure/export.js +50 -74
- package/dist/structure/format-detect.js +5 -7
- package/dist/structure/index.js +6 -12
- package/dist/structure/parse.js +38 -100
- package/dist/structure/partial-occupancy.js +7 -4
- package/dist/structure/pbc.js +8 -10
- package/dist/structure/polyhedra.js +5 -4
- package/dist/structure/prop-groups.d.ts +85 -0
- package/dist/structure/prop-groups.js +18 -0
- package/dist/symmetry/SymmetryStats.svelte +0 -4
- package/dist/symmetry/WyckoffTable.svelte +5 -4
- package/dist/symmetry/cell-transform.js +5 -14
- package/dist/symmetry/index.js +6 -9
- package/dist/table/HeatmapTable.svelte +61 -103
- package/dist/table/ToggleMenu.svelte +166 -44
- package/dist/table/ToggleMenu.svelte.d.ts +1 -1
- package/dist/theme/embedded.d.ts +18 -0
- package/dist/theme/embedded.js +206 -0
- package/dist/theme/index.d.ts +4 -0
- package/dist/theme/index.js +1 -2
- package/dist/theme/themes.mjs +31 -60
- package/dist/tooltip/TooltipContent.svelte +1 -1
- package/dist/tooltip/TooltipContent.svelte.d.ts +1 -1
- package/dist/tooltip/index.d.ts +8 -1
- package/dist/trajectory/Trajectory.svelte +140 -120
- package/dist/trajectory/TrajectoryError.svelte +1 -66
- package/dist/trajectory/TrajectoryExportPane.svelte +0 -1
- package/dist/trajectory/TrajectoryInfoPane.svelte +55 -80
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +2 -1
- package/dist/trajectory/extract.js +19 -29
- package/dist/trajectory/format-detect.d.ts +2 -0
- package/dist/trajectory/format-detect.js +7 -5
- package/dist/trajectory/frame-reader.js +3 -4
- package/dist/trajectory/helpers.js +16 -49
- package/dist/trajectory/index.js +2 -8
- package/dist/trajectory/parse/ase.js +1 -1
- package/dist/trajectory/parse/index.d.ts +4 -3
- package/dist/trajectory/parse/index.js +12 -17
- package/dist/trajectory/parse/vaspout-h5.d.ts +0 -1
- package/dist/trajectory/parse/vaspout-h5.js +1 -4
- package/dist/trajectory/parse/xyz.js +48 -2
- package/dist/trajectory/plotting.js +14 -37
- package/dist/xrd/XrdPlot.svelte +43 -68
- package/dist/xrd/calc-xrd.js +22 -58
- package/dist/xrd/parse.js +13 -22
- package/package.json +40 -8
- package/readme.md +6 -5
- package/dist/scene/types.d.ts +0 -26
- package/dist/tooltip/types.d.ts +0 -8
- package/dist/trajectory/constants.d.ts +0 -6
- package/dist/trajectory/constants.js +0 -11
- /package/dist/{scene/types.js → file-viewer/host-protocol.js} +0 -0
- /package/dist/{tooltip/types.js → isosurface/geometry-worker-types.js} +0 -0
|
@@ -327,11 +327,10 @@
|
|
|
327
327
|
|
|
328
328
|
// Normalize export_data config
|
|
329
329
|
type ExportFormat = `csv` | `json`
|
|
330
|
-
const default_formats: ExportFormat[] = [`csv`, `json`]
|
|
331
330
|
let export_config = $derived(
|
|
332
331
|
export_data
|
|
333
332
|
? {
|
|
334
|
-
formats:
|
|
333
|
+
formats: [`csv`, `json`] as ExportFormat[],
|
|
335
334
|
filename: `table-export`,
|
|
336
335
|
...(typeof export_data === `object` ? export_data : {}),
|
|
337
336
|
}
|
|
@@ -381,9 +380,7 @@
|
|
|
381
380
|
] as const
|
|
382
381
|
|
|
383
382
|
// Columns that have a color gradient
|
|
384
|
-
let colored_columns = $derived(
|
|
385
|
-
columns.filter((col) => col.color_scale !== null && col.color_scale !== undefined),
|
|
386
|
-
)
|
|
383
|
+
let colored_columns = $derived(columns.filter((col) => col.color_scale != null))
|
|
387
384
|
|
|
388
385
|
// Column resize state
|
|
389
386
|
let resize_col_id = $state<string | null>(null)
|
|
@@ -748,22 +745,19 @@
|
|
|
748
745
|
// Skip client-side sorting when using async onsort callback or sort_data is false
|
|
749
746
|
if (onsort || !sort_data) return filtered_data
|
|
750
747
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
// Build sort criteria: multi_sort takes precedence, fallback to single sort
|
|
748
|
+
// Build sort criteria: multi_sort (Shift+click) takes precedence over single sort
|
|
754
749
|
const sort_criteria =
|
|
755
750
|
multi_sort.length > 0 ? multi_sort : sort_state.column ? [sort_state] : []
|
|
756
|
-
|
|
757
751
|
if (sort_criteria.length === 0) return filtered_data
|
|
758
752
|
|
|
753
|
+
const valid_column_ids = new Set(ordered_columns.map(get_col_id))
|
|
759
754
|
return [...filtered_data].sort((row1, row2) => {
|
|
760
755
|
for (const { column, ascending } of sort_criteria) {
|
|
761
|
-
|
|
762
|
-
if (!
|
|
756
|
+
// criteria hold column IDs; skip stale entries referencing removed columns
|
|
757
|
+
if (!valid_column_ids.has(column)) continue
|
|
763
758
|
|
|
764
|
-
const
|
|
765
|
-
const
|
|
766
|
-
const val2 = row2[col_id]
|
|
759
|
+
const val1 = row1[column]
|
|
760
|
+
const val2 = row2[column]
|
|
767
761
|
|
|
768
762
|
if (val1 === val2) continue
|
|
769
763
|
|
|
@@ -934,13 +928,7 @@
|
|
|
934
928
|
}
|
|
935
929
|
} else {
|
|
936
930
|
// Add to multi-sort
|
|
937
|
-
multi_sort = [
|
|
938
|
-
...multi_sort,
|
|
939
|
-
{
|
|
940
|
-
column: col_id,
|
|
941
|
-
ascending: col.better === `lower`,
|
|
942
|
-
},
|
|
943
|
-
]
|
|
931
|
+
multi_sort = [...multi_sort, { column: col_id, ascending: col.better === `lower` }]
|
|
944
932
|
}
|
|
945
933
|
// Clear single sort when using multi-sort
|
|
946
934
|
sort = { column: ``, dir: `asc` }
|
|
@@ -1047,25 +1035,23 @@
|
|
|
1047
1035
|
visible_columns.length + (show_row_select ? 1 : 0) + (show_row_numbers ? 1 : 0),
|
|
1048
1036
|
)
|
|
1049
1037
|
|
|
1038
|
+
// Arrow (plus a numbered badge under multi-sort) for actively sorted columns
|
|
1050
1039
|
const sort_indicator = (col: Label, current_sort_state: SortState) => {
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1040
|
+
if (col.show_sort_indicator === false || col.style?.includes(`--hide-sort-indicator`)) {
|
|
1041
|
+
return ``
|
|
1042
|
+
}
|
|
1055
1043
|
const col_id = get_col_id(col)
|
|
1056
|
-
|
|
1057
|
-
// Check multi-sort first
|
|
1058
1044
|
const multi_idx = multi_sort.findIndex((sort_entry) => sort_entry.column === col_id)
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
return `<span style="font-size: 0.8em;">${
|
|
1045
|
+
const active =
|
|
1046
|
+
multi_idx !== -1
|
|
1047
|
+
? multi_sort[multi_idx]
|
|
1048
|
+
: current_sort_state.column === col_id
|
|
1049
|
+
? current_sort_state
|
|
1050
|
+
: null
|
|
1051
|
+
if (!active) return ``
|
|
1052
|
+
const badge =
|
|
1053
|
+
multi_idx !== -1 && multi_sort.length > 1 ? `<sup>${multi_idx + 1}</sup>` : ``
|
|
1054
|
+
return `<span style="font-size: 0.8em;">${active.ascending ? `↓` : `↑`}${badge}</span>`
|
|
1069
1055
|
}
|
|
1070
1056
|
|
|
1071
1057
|
// Context menu state for column right-click (headers and body cells)
|
|
@@ -1200,7 +1186,7 @@
|
|
|
1200
1186
|
// Raw cell value as clipboard text (numbers keep full precision, dates go
|
|
1201
1187
|
// ISO, HTML cells lose their markup)
|
|
1202
1188
|
const cell_copy_text = (val: CellVal): string => {
|
|
1203
|
-
if (
|
|
1189
|
+
if (is_invalid(val)) return ``
|
|
1204
1190
|
if (val instanceof Date) return val.toISOString()
|
|
1205
1191
|
if (typeof val === `object`) return JSON.stringify(val)
|
|
1206
1192
|
return strip_html(String(val)).trim()
|
|
@@ -1367,6 +1353,11 @@
|
|
|
1367
1353
|
download(JSON.stringify(rows, null, 2), `${filename}.json`, `application/json`)
|
|
1368
1354
|
}
|
|
1369
1355
|
|
|
1356
|
+
const export_actions = [
|
|
1357
|
+
[`csv`, export_csv],
|
|
1358
|
+
[`json`, export_json],
|
|
1359
|
+
] as const
|
|
1360
|
+
|
|
1370
1361
|
function copy_to_clipboard() {
|
|
1371
1362
|
navigator.clipboard.writeText(serialize_table(`\t`))
|
|
1372
1363
|
}
|
|
@@ -1532,28 +1523,20 @@
|
|
|
1532
1523
|
</button>
|
|
1533
1524
|
{#if show_export_dropdown}
|
|
1534
1525
|
<div class="dropdown-pane">
|
|
1535
|
-
{#
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
onclick={() => {
|
|
1550
|
-
export_json(export_config.filename)
|
|
1551
|
-
show_export_dropdown = false
|
|
1552
|
-
}}
|
|
1553
|
-
>
|
|
1554
|
-
<Icon icon="Download" style="width: 12px" /> JSON
|
|
1555
|
-
</button>
|
|
1556
|
-
{/if}
|
|
1526
|
+
{#each export_actions as [format, export_fn] (format)}
|
|
1527
|
+
{#if export_config.formats.includes(format)}
|
|
1528
|
+
<button
|
|
1529
|
+
class="dropdown-option"
|
|
1530
|
+
onclick={() => {
|
|
1531
|
+
export_fn(export_config.filename)
|
|
1532
|
+
show_export_dropdown = false
|
|
1533
|
+
}}
|
|
1534
|
+
>
|
|
1535
|
+
<Icon icon="Download" style="width: 12px" />
|
|
1536
|
+
{format.toUpperCase()}
|
|
1537
|
+
</button>
|
|
1538
|
+
{/if}
|
|
1539
|
+
{/each}
|
|
1557
1540
|
<button
|
|
1558
1541
|
class="dropdown-option"
|
|
1559
1542
|
onclick={() => {
|
|
@@ -1710,12 +1693,13 @@
|
|
|
1710
1693
|
{#if !col.group}
|
|
1711
1694
|
<th class:sticky-col={col.sticky}></th>
|
|
1712
1695
|
{:else}
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1696
|
+
<!-- Only render the group header once per group (on its first column) -->
|
|
1697
|
+
{#if visible_columns.find((column) => column.group === col.group) === col}
|
|
1698
|
+
<th
|
|
1699
|
+
title={col.description}
|
|
1700
|
+
colspan={visible_columns.filter((column) => column.group === col.group)
|
|
1701
|
+
.length}
|
|
1702
|
+
>
|
|
1719
1703
|
{@html sanitize_html(col.group)}
|
|
1720
1704
|
</th>
|
|
1721
1705
|
{/if}
|
|
@@ -1967,7 +1951,7 @@
|
|
|
1967
1951
|
{date_val}
|
|
1968
1952
|
{:else if typeof val === `number` && !Number.isNaN(val)}
|
|
1969
1953
|
{format_num(val, col.format ?? default_num_format)}
|
|
1970
|
-
{:else if
|
|
1954
|
+
{:else if is_invalid(val)}
|
|
1971
1955
|
<span {@attach tooltip({ content: `Not available` })}> n/a </span>
|
|
1972
1956
|
{:else}
|
|
1973
1957
|
{@html sanitize_html(val)}
|
|
@@ -2000,24 +1984,16 @@
|
|
|
2000
1984
|
</div>
|
|
2001
1985
|
{/if}
|
|
2002
1986
|
|
|
1987
|
+
{#snippet page_btn(label: string, title: string, target_page: number, disabled: boolean)}
|
|
1988
|
+
<button class="page-btn" {disabled} onclick={() => (current_page = target_page)} {title}>
|
|
1989
|
+
{label}
|
|
1990
|
+
</button>
|
|
1991
|
+
{/snippet}
|
|
1992
|
+
|
|
2003
1993
|
{#if pagination_config && total_pages > 1}
|
|
2004
1994
|
<div class="pagination">
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
disabled={current_page === 1}
|
|
2008
|
-
onclick={() => (current_page = 1)}
|
|
2009
|
-
title="First page"
|
|
2010
|
-
>
|
|
2011
|
-
«
|
|
2012
|
-
</button>
|
|
2013
|
-
<button
|
|
2014
|
-
class="page-btn"
|
|
2015
|
-
disabled={current_page === 1}
|
|
2016
|
-
onclick={() => current_page--}
|
|
2017
|
-
title="Previous page"
|
|
2018
|
-
>
|
|
2019
|
-
‹
|
|
2020
|
-
</button>
|
|
1995
|
+
{@render page_btn(`«`, `First page`, 1, current_page === 1)}
|
|
1996
|
+
{@render page_btn(`‹`, `Previous page`, current_page - 1, current_page === 1)}
|
|
2021
1997
|
<span class="page-info">
|
|
2022
1998
|
Page
|
|
2023
1999
|
<input
|
|
@@ -2035,22 +2011,8 @@
|
|
|
2035
2011
|
of {total_pages}
|
|
2036
2012
|
<span class="row-count">({sorted_data.length} rows)</span>
|
|
2037
2013
|
</span>
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
disabled={current_page === total_pages}
|
|
2041
|
-
onclick={() => current_page++}
|
|
2042
|
-
title="Next page"
|
|
2043
|
-
>
|
|
2044
|
-
›
|
|
2045
|
-
</button>
|
|
2046
|
-
<button
|
|
2047
|
-
class="page-btn"
|
|
2048
|
-
disabled={current_page === total_pages}
|
|
2049
|
-
onclick={() => (current_page = total_pages)}
|
|
2050
|
-
title="Last page"
|
|
2051
|
-
>
|
|
2052
|
-
»
|
|
2053
|
-
</button>
|
|
2014
|
+
{@render page_btn(`›`, `Next page`, current_page + 1, current_page === total_pages)}
|
|
2015
|
+
{@render page_btn(`»`, `Last page`, total_pages, current_page === total_pages)}
|
|
2054
2016
|
{#if pagination_config.page_sizes}
|
|
2055
2017
|
<select
|
|
2056
2018
|
class="page-size-select"
|
|
@@ -2450,10 +2412,6 @@
|
|
|
2450
2412
|
vertical-align: middle;
|
|
2451
2413
|
padding: 2px !important;
|
|
2452
2414
|
}
|
|
2453
|
-
.select-col :global(svg) {
|
|
2454
|
-
display: block;
|
|
2455
|
-
margin: auto;
|
|
2456
|
-
}
|
|
2457
2415
|
tr.selected {
|
|
2458
2416
|
background: var(--highlight-bg, rgba(74, 158, 255, 0.15)) !important;
|
|
2459
2417
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import Icon from '../Icon.svelte'
|
|
3
|
+
import { portal } from '../overlays/portal'
|
|
3
4
|
import { sanitize_html } from '../sanitize'
|
|
4
|
-
import type
|
|
5
|
+
import { type Label, strip_html } from './'
|
|
5
6
|
import { click_outside, tooltip } from 'svelte-multiselect/attachments'
|
|
6
7
|
import { slide } from 'svelte/transition'
|
|
7
8
|
|
|
@@ -14,7 +15,7 @@
|
|
|
14
15
|
}: {
|
|
15
16
|
columns: Label[]
|
|
16
17
|
column_panel_open?: boolean
|
|
17
|
-
//
|
|
18
|
+
// Maximum number of grid columns for toggle layout
|
|
18
19
|
n_columns?: number
|
|
19
20
|
collapsed_sections?: string[]
|
|
20
21
|
// Called after reset with the section name (or undefined for global reset)
|
|
@@ -22,6 +23,24 @@
|
|
|
22
23
|
} = $props()
|
|
23
24
|
|
|
24
25
|
const col_id = (col: Label) => col.key ?? col.label
|
|
26
|
+
const toggle_menu_id = $props.id()
|
|
27
|
+
const dropdown_selector = `[data-toggle-menu-id="${toggle_menu_id}"]`
|
|
28
|
+
const COLUMN_FILTER_THRESHOLD = 20
|
|
29
|
+
const DEFAULT_MAX_MENU_COLUMNS = 3
|
|
30
|
+
const PREFERRED_MAX_MENU_ROWS = 10
|
|
31
|
+
let column_filter = $state(``)
|
|
32
|
+
let show_column_filter = $derived(columns.length > COLUMN_FILTER_THRESHOLD)
|
|
33
|
+
let normalized_column_filter = $derived(
|
|
34
|
+
show_column_filter ? column_filter.trim().toLowerCase() : ``,
|
|
35
|
+
)
|
|
36
|
+
const column_matches_filter = (col: Label): boolean =>
|
|
37
|
+
!normalized_column_filter ||
|
|
38
|
+
[col.key, strip_html(col.label), col.description, col.group]
|
|
39
|
+
.filter(Boolean)
|
|
40
|
+
.join(` `)
|
|
41
|
+
.toLowerCase()
|
|
42
|
+
.includes(normalized_column_filter)
|
|
43
|
+
let filtered_columns = $derived(columns.filter(column_matches_filter))
|
|
25
44
|
|
|
26
45
|
// Snapshot default visibility when column set changes (new dataset).
|
|
27
46
|
// Compare by keys and visibility defaults. Internal updates opt out below.
|
|
@@ -96,6 +115,14 @@
|
|
|
96
115
|
if (ungrouped.length > 0) result.push({ name: ``, items: ungrouped })
|
|
97
116
|
return result
|
|
98
117
|
})
|
|
118
|
+
let filtered_sections = $derived(
|
|
119
|
+
sections
|
|
120
|
+
.map((section) => ({
|
|
121
|
+
...section,
|
|
122
|
+
items: section.items.filter(column_matches_filter),
|
|
123
|
+
}))
|
|
124
|
+
.filter((section) => section.items.length > 0),
|
|
125
|
+
)
|
|
99
126
|
|
|
100
127
|
// Check if any column defines a group (to decide whether to show sections)
|
|
101
128
|
let has_sections = $derived(columns.some((col) => col.group))
|
|
@@ -113,31 +140,56 @@
|
|
|
113
140
|
columns = [...columns] // trigger reactivity on parent binding
|
|
114
141
|
}
|
|
115
142
|
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
143
|
+
// Prefer two tall columns, adding more only when the item count would make them unwieldy.
|
|
144
|
+
// n_columns caps large menus rather than forcing sparse menus to fill every column.
|
|
145
|
+
const grid_column_count = (item_count: number): number => {
|
|
146
|
+
const preferred_column_count =
|
|
147
|
+
item_count <= 1 ? 1 : Math.max(2, Math.ceil(item_count / PREFERRED_MAX_MENU_ROWS))
|
|
148
|
+
return Math.min(Math.max(1, n_columns ?? DEFAULT_MAX_MENU_COLUMNS), preferred_column_count)
|
|
149
|
+
}
|
|
150
|
+
const grid_template = (item_count: number): string =>
|
|
151
|
+
`repeat(${grid_column_count(item_count)}, max-content)`
|
|
120
152
|
|
|
121
|
-
//
|
|
122
|
-
|
|
153
|
+
// Portal the dropdown to <body> so ancestor overflow/stacking contexts cannot clip it.
|
|
154
|
+
const dropdown_target = typeof document === `undefined` ? undefined : document.body
|
|
155
|
+
let details_el = $state<HTMLElement>()
|
|
156
|
+
let dropdown_el = $state<HTMLElement>()
|
|
157
|
+
const position_dropdown = (): void => {
|
|
158
|
+
const trigger = details_el?.querySelector(`summary`)
|
|
159
|
+
if (!column_panel_open || !trigger || !dropdown_el) return
|
|
160
|
+
const trigger_rect = trigger.getBoundingClientRect()
|
|
161
|
+
const dropdown_rect = dropdown_el.getBoundingClientRect()
|
|
162
|
+
const viewport_padding = 8
|
|
163
|
+
const gap = 4
|
|
164
|
+
const max_left = Math.max(
|
|
165
|
+
viewport_padding,
|
|
166
|
+
globalThis.innerWidth - dropdown_rect.width - viewport_padding,
|
|
167
|
+
)
|
|
168
|
+
const left = Math.min(
|
|
169
|
+
Math.max(viewport_padding, trigger_rect.right - dropdown_rect.width),
|
|
170
|
+
max_left,
|
|
171
|
+
)
|
|
172
|
+
const below = trigger_rect.bottom + gap
|
|
173
|
+
const top =
|
|
174
|
+
below + dropdown_rect.height <= globalThis.innerHeight - viewport_padding
|
|
175
|
+
? below
|
|
176
|
+
: Math.max(viewport_padding, trigger_rect.top - dropdown_rect.height - gap)
|
|
177
|
+
Object.assign(dropdown_el.style, {
|
|
178
|
+
left: `${left}px`,
|
|
179
|
+
right: `auto`,
|
|
180
|
+
top: `${top}px`,
|
|
181
|
+
visibility: `visible`,
|
|
182
|
+
})
|
|
183
|
+
}
|
|
123
184
|
$effect(() => {
|
|
124
|
-
if (!column_panel_open || !details_el) return
|
|
185
|
+
if (!column_panel_open || !details_el || !dropdown_el) return
|
|
125
186
|
// Re-run when section state changes while open
|
|
126
187
|
void n_columns
|
|
127
188
|
void collapsed_sections
|
|
128
|
-
void
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
dropdown.style.left = `0`
|
|
133
|
-
dropdown.style.right = `auto`
|
|
134
|
-
requestAnimationFrame(() => {
|
|
135
|
-
const rect = dropdown.getBoundingClientRect()
|
|
136
|
-
if (rect.right > window.innerWidth) {
|
|
137
|
-
dropdown.style.left = `auto`
|
|
138
|
-
dropdown.style.right = `0`
|
|
139
|
-
}
|
|
140
|
-
})
|
|
189
|
+
void filtered_columns
|
|
190
|
+
void filtered_sections
|
|
191
|
+
const frame = requestAnimationFrame(position_dropdown)
|
|
192
|
+
return () => cancelAnimationFrame(frame)
|
|
141
193
|
})
|
|
142
194
|
</script>
|
|
143
195
|
|
|
@@ -169,10 +221,19 @@
|
|
|
169
221
|
<details
|
|
170
222
|
class="column-toggles"
|
|
171
223
|
bind:this={details_el}
|
|
172
|
-
|
|
173
|
-
{@attach click_outside({
|
|
224
|
+
open={column_panel_open}
|
|
225
|
+
{@attach click_outside({
|
|
226
|
+
callback: () => (column_panel_open = false),
|
|
227
|
+
exclude: [dropdown_selector],
|
|
228
|
+
})}
|
|
174
229
|
>
|
|
175
|
-
<summary
|
|
230
|
+
<summary
|
|
231
|
+
aria-expanded={column_panel_open}
|
|
232
|
+
onclick={(event) => {
|
|
233
|
+
event.preventDefault()
|
|
234
|
+
column_panel_open = !column_panel_open
|
|
235
|
+
}}
|
|
236
|
+
>
|
|
176
237
|
Columns <Icon icon="Columns" />
|
|
177
238
|
{#if has_any_changes}
|
|
178
239
|
<button
|
|
@@ -191,11 +252,32 @@
|
|
|
191
252
|
{/if}
|
|
192
253
|
</summary>
|
|
193
254
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
255
|
+
<div
|
|
256
|
+
bind:this={dropdown_el}
|
|
257
|
+
class={has_sections ? `sections-container` : `column-menu`}
|
|
258
|
+
data-toggle-menu-id={toggle_menu_id}
|
|
259
|
+
hidden={!column_panel_open}
|
|
260
|
+
role="group"
|
|
261
|
+
style:grid-template-columns={has_sections
|
|
262
|
+
? undefined
|
|
263
|
+
: grid_template(filtered_columns.length)}
|
|
264
|
+
{@attach portal(dropdown_target)}
|
|
265
|
+
>
|
|
266
|
+
{#if show_column_filter}
|
|
267
|
+
<input
|
|
268
|
+
aria-label="Filter columns"
|
|
269
|
+
bind:value={column_filter}
|
|
270
|
+
class="column-filter"
|
|
271
|
+
placeholder="Filter columns…"
|
|
272
|
+
type="search"
|
|
273
|
+
/>
|
|
274
|
+
{/if}
|
|
275
|
+
{#if has_sections}
|
|
276
|
+
{#each filtered_sections as section (section.name)}
|
|
197
277
|
{@const is_collapsed =
|
|
198
|
-
|
|
278
|
+
!normalized_column_filter &&
|
|
279
|
+
section.name !== `` &&
|
|
280
|
+
collapsed_sections.includes(section.name)}
|
|
199
281
|
<div class="section">
|
|
200
282
|
{#if section.name}
|
|
201
283
|
<div class="section-header-row">
|
|
@@ -224,7 +306,7 @@
|
|
|
224
306
|
{#if !is_collapsed}
|
|
225
307
|
<div
|
|
226
308
|
class="section-items"
|
|
227
|
-
style:grid-template-columns={grid_template}
|
|
309
|
+
style:grid-template-columns={grid_template(section.items.length)}
|
|
228
310
|
transition:slide={{ duration: 200 }}
|
|
229
311
|
>
|
|
230
312
|
{#each section.items as col, idx (col.key ?? col.label ?? idx)}
|
|
@@ -234,14 +316,15 @@
|
|
|
234
316
|
{/if}
|
|
235
317
|
</div>
|
|
236
318
|
{/each}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
<div class="column-menu" role="group" style:grid-template-columns={grid_template}>
|
|
240
|
-
{#each columns as col, idx (col.key ?? col.label ?? idx)}
|
|
319
|
+
{:else}
|
|
320
|
+
{#each filtered_columns as col, idx (col.key ?? col.label ?? idx)}
|
|
241
321
|
{@render toggle_item(col)}
|
|
242
322
|
{/each}
|
|
243
|
-
|
|
244
|
-
|
|
323
|
+
{/if}
|
|
324
|
+
{#if filtered_columns.length === 0}
|
|
325
|
+
<span class="no-matching-columns">No matching columns</span>
|
|
326
|
+
{/if}
|
|
327
|
+
</div>
|
|
245
328
|
</details>
|
|
246
329
|
|
|
247
330
|
<style>
|
|
@@ -268,9 +351,12 @@
|
|
|
268
351
|
.column-menu,
|
|
269
352
|
.sections-container {
|
|
270
353
|
font-size: var(--tgl-font-size, 1.1em);
|
|
271
|
-
position:
|
|
354
|
+
position: fixed;
|
|
272
355
|
left: 0;
|
|
273
|
-
top:
|
|
356
|
+
top: 0;
|
|
357
|
+
visibility: hidden;
|
|
358
|
+
box-sizing: border-box;
|
|
359
|
+
width: max-content;
|
|
274
360
|
background: var(--tgl-dropdown-bg, var(--page-bg));
|
|
275
361
|
border: 1px solid
|
|
276
362
|
var(--tgl-dropdown-border, color-mix(in srgb, currentColor 10%, transparent));
|
|
@@ -280,13 +366,18 @@
|
|
|
280
366
|
0 4px 12px color-mix(in srgb, currentColor 8%, transparent)
|
|
281
367
|
);
|
|
282
368
|
min-width: 150px;
|
|
369
|
+
max-width: calc(100vw - 16px);
|
|
283
370
|
max-height: var(--tgl-dropdown-max-height, min(70vh, 600px));
|
|
284
|
-
overflow
|
|
285
|
-
z-index:
|
|
371
|
+
overflow: auto;
|
|
372
|
+
z-index: var(--tgl-dropdown-z-index, 10000);
|
|
373
|
+
}
|
|
374
|
+
.column-menu,
|
|
375
|
+
.section-items {
|
|
376
|
+
display: grid;
|
|
377
|
+
column-gap: var(--tgl-column-gap, 8px);
|
|
286
378
|
}
|
|
287
379
|
.column-menu {
|
|
288
380
|
padding: 3pt 5pt;
|
|
289
|
-
display: grid;
|
|
290
381
|
}
|
|
291
382
|
.sections-container {
|
|
292
383
|
padding: 6pt 8pt;
|
|
@@ -294,6 +385,40 @@
|
|
|
294
385
|
flex-direction: column;
|
|
295
386
|
gap: 8px;
|
|
296
387
|
}
|
|
388
|
+
.column-menu[hidden],
|
|
389
|
+
.sections-container[hidden] {
|
|
390
|
+
display: none;
|
|
391
|
+
}
|
|
392
|
+
.column-filter {
|
|
393
|
+
position: sticky;
|
|
394
|
+
z-index: 2;
|
|
395
|
+
top: 0;
|
|
396
|
+
grid-column: 1 / -1;
|
|
397
|
+
box-sizing: border-box;
|
|
398
|
+
width: 100%;
|
|
399
|
+
height: 1.35rem;
|
|
400
|
+
min-height: 0;
|
|
401
|
+
margin: 0 0 4px;
|
|
402
|
+
padding: 0 0.35rem;
|
|
403
|
+
border: 1px solid
|
|
404
|
+
var(--tgl-dropdown-border, color-mix(in srgb, currentColor 18%, transparent));
|
|
405
|
+
border-radius: var(--tgl-border-radius, 4pt);
|
|
406
|
+
outline: none;
|
|
407
|
+
background: var(--tgl-dropdown-bg, var(--page-bg));
|
|
408
|
+
color: inherit;
|
|
409
|
+
font: inherit;
|
|
410
|
+
font-size: 0.72rem;
|
|
411
|
+
line-height: 1.2;
|
|
412
|
+
&:focus {
|
|
413
|
+
border-color: var(--active-color, #6ea8ff);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
.no-matching-columns {
|
|
417
|
+
grid-column: 1 / -1;
|
|
418
|
+
padding: 4px;
|
|
419
|
+
color: color-mix(in srgb, currentColor 65%, transparent);
|
|
420
|
+
font-size: 0.9em;
|
|
421
|
+
}
|
|
297
422
|
.reset-btn {
|
|
298
423
|
display: flex;
|
|
299
424
|
align-items: center;
|
|
@@ -348,9 +473,6 @@
|
|
|
348
473
|
width: 1em;
|
|
349
474
|
flex-shrink: 0;
|
|
350
475
|
}
|
|
351
|
-
.section-items {
|
|
352
|
-
display: grid;
|
|
353
|
-
}
|
|
354
476
|
.toggle-label {
|
|
355
477
|
display: inline-block;
|
|
356
478
|
margin: 1px 2px;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ThemeType } from './';
|
|
2
|
+
import './themes.mjs';
|
|
3
|
+
declare global {
|
|
4
|
+
var jupyterlab: {
|
|
5
|
+
application?: {
|
|
6
|
+
shell?: {
|
|
7
|
+
dataset?: {
|
|
8
|
+
theme?: string;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
} | undefined;
|
|
13
|
+
}
|
|
14
|
+
type ThemeCallback = (theme_type: ThemeType) => void;
|
|
15
|
+
export declare function detect_parent_theme(target_element?: HTMLElement): ThemeType;
|
|
16
|
+
export declare function watch_theme(target_element: HTMLElement, callback: ThemeCallback): () => void;
|
|
17
|
+
export declare function get_theme_css(theme_type: ThemeType, is_shadow_dom?: boolean): string;
|
|
18
|
+
export {};
|