matterviz 0.3.0 → 0.3.2

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 (286) hide show
  1. package/dist/FilePicker.svelte +37 -20
  2. package/dist/Icon.svelte +2 -2
  3. package/dist/MillerIndexInput.svelte +60 -0
  4. package/dist/MillerIndexInput.svelte.d.ts +7 -0
  5. package/dist/app.css +38 -2
  6. package/dist/brillouin/BrillouinZone.svelte +20 -62
  7. package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
  8. package/dist/brillouin/BrillouinZoneExportPane.svelte +12 -20
  9. package/dist/brillouin/BrillouinZoneScene.svelte +2 -2
  10. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  11. package/dist/chempot-diagram/ChemPotDiagram.svelte +192 -0
  12. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
  13. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +677 -0
  14. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
  15. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +2688 -0
  16. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
  17. package/dist/chempot-diagram/ChemPotScene3D.svelte +8 -0
  18. package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
  19. package/dist/chempot-diagram/color.d.ts +10 -0
  20. package/dist/chempot-diagram/color.js +33 -0
  21. package/dist/chempot-diagram/compute.d.ts +38 -0
  22. package/dist/chempot-diagram/compute.js +650 -0
  23. package/dist/chempot-diagram/index.d.ts +5 -0
  24. package/dist/chempot-diagram/index.js +5 -0
  25. package/dist/chempot-diagram/pointer.d.ts +16 -0
  26. package/dist/chempot-diagram/pointer.js +40 -0
  27. package/dist/chempot-diagram/temperature.d.ts +15 -0
  28. package/dist/chempot-diagram/temperature.js +37 -0
  29. package/dist/chempot-diagram/types.d.ts +83 -0
  30. package/dist/chempot-diagram/types.js +27 -0
  31. package/dist/colors/index.d.ts +3 -1
  32. package/dist/colors/index.js +4 -0
  33. package/dist/composition/BarChart.svelte +13 -22
  34. package/dist/composition/BubbleChart.svelte +5 -3
  35. package/dist/composition/FormulaFilter.svelte +770 -90
  36. package/dist/composition/FormulaFilter.svelte.d.ts +37 -1
  37. package/dist/composition/PieChart.svelte +43 -18
  38. package/dist/composition/PieChart.svelte.d.ts +1 -1
  39. package/dist/constants.d.ts +1 -0
  40. package/dist/constants.js +2 -0
  41. package/dist/convex-hull/ConvexHull.svelte +14 -1
  42. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
  43. package/dist/convex-hull/ConvexHull2D.svelte +14 -45
  44. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  45. package/dist/convex-hull/ConvexHull3D.svelte +396 -134
  46. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  47. package/dist/convex-hull/ConvexHull4D.svelte +93 -42
  48. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  49. package/dist/convex-hull/ConvexHullControls.svelte +94 -31
  50. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +4 -2
  51. package/dist/convex-hull/ConvexHullStats.svelte +697 -128
  52. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +6 -1
  53. package/dist/convex-hull/ConvexHullTooltip.svelte +1 -0
  54. package/dist/convex-hull/GasPressureControls.svelte +72 -38
  55. package/dist/convex-hull/GasPressureControls.svelte.d.ts +2 -1
  56. package/dist/convex-hull/TemperatureSlider.svelte +46 -19
  57. package/dist/convex-hull/TemperatureSlider.svelte.d.ts +2 -1
  58. package/dist/convex-hull/demo-temperature.d.ts +6 -0
  59. package/dist/convex-hull/demo-temperature.js +36 -0
  60. package/dist/convex-hull/gas-thermodynamics.js +16 -5
  61. package/dist/convex-hull/helpers.d.ts +7 -1
  62. package/dist/convex-hull/helpers.js +45 -15
  63. package/dist/convex-hull/index.d.ts +15 -1
  64. package/dist/convex-hull/index.js +1 -0
  65. package/dist/convex-hull/thermodynamics.d.ts +8 -21
  66. package/dist/convex-hull/thermodynamics.js +106 -17
  67. package/dist/convex-hull/types.d.ts +7 -0
  68. package/dist/convex-hull/types.js +11 -0
  69. package/dist/coordination/CoordinationBarPlot.svelte +29 -46
  70. package/dist/element/BohrAtom.svelte +1 -1
  71. package/dist/element/data.js +2 -14
  72. package/dist/element/data.json.gz +0 -0
  73. package/dist/element/index.d.ts +1 -1
  74. package/dist/element/index.js +1 -0
  75. package/dist/element/types.d.ts +1 -0
  76. package/dist/fermi-surface/FermiSurface.svelte +21 -65
  77. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  78. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  79. package/dist/fermi-surface/FermiSurfaceScene.svelte +1 -1
  80. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  81. package/dist/fermi-surface/compute.js +1 -21
  82. package/dist/fermi-surface/marching-cubes.d.ts +2 -13
  83. package/dist/fermi-surface/marching-cubes.js +2 -519
  84. package/dist/fermi-surface/parse.js +17 -23
  85. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1273 -0
  86. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
  87. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +171 -0
  88. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +31 -0
  89. package/dist/heatmap-matrix/index.d.ts +53 -0
  90. package/dist/heatmap-matrix/index.js +100 -0
  91. package/dist/heatmap-matrix/shared.d.ts +2 -0
  92. package/dist/heatmap-matrix/shared.js +4 -0
  93. package/dist/icons.d.ts +119 -0
  94. package/dist/icons.js +119 -0
  95. package/dist/index.d.ts +6 -1
  96. package/dist/index.js +6 -1
  97. package/dist/io/export.js +15 -3
  98. package/dist/io/file-drop.d.ts +7 -0
  99. package/dist/io/file-drop.js +43 -0
  100. package/dist/io/index.d.ts +2 -2
  101. package/dist/io/index.js +2 -112
  102. package/dist/io/types.d.ts +1 -0
  103. package/dist/io/url-drop.d.ts +2 -0
  104. package/dist/io/url-drop.js +118 -0
  105. package/dist/isosurface/Isosurface.svelte +231 -0
  106. package/dist/isosurface/Isosurface.svelte.d.ts +8 -0
  107. package/dist/isosurface/IsosurfaceControls.svelte +273 -0
  108. package/dist/isosurface/IsosurfaceControls.svelte.d.ts +9 -0
  109. package/dist/isosurface/index.d.ts +5 -0
  110. package/dist/isosurface/index.js +6 -0
  111. package/dist/isosurface/parse.d.ts +6 -0
  112. package/dist/isosurface/parse.js +548 -0
  113. package/dist/isosurface/slice.d.ts +11 -0
  114. package/dist/isosurface/slice.js +145 -0
  115. package/dist/isosurface/types.d.ts +55 -0
  116. package/dist/isosurface/types.js +178 -0
  117. package/dist/labels.d.ts +2 -1
  118. package/dist/labels.js +1 -0
  119. package/dist/layout/InfoTag.svelte +62 -62
  120. package/dist/layout/SubpageGrid.svelte +74 -0
  121. package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
  122. package/dist/layout/index.d.ts +1 -0
  123. package/dist/layout/index.js +1 -0
  124. package/dist/layout/json-tree/JsonNode.svelte +226 -53
  125. package/dist/layout/json-tree/JsonTree.svelte +425 -51
  126. package/dist/layout/json-tree/JsonTree.svelte.d.ts +1 -1
  127. package/dist/layout/json-tree/JsonValue.svelte +218 -97
  128. package/dist/layout/json-tree/types.d.ts +27 -2
  129. package/dist/layout/json-tree/utils.d.ts +14 -1
  130. package/dist/layout/json-tree/utils.js +254 -0
  131. package/dist/marching-cubes.d.ts +14 -0
  132. package/dist/marching-cubes.js +519 -0
  133. package/dist/math.d.ts +8 -0
  134. package/dist/math.js +374 -7
  135. package/dist/overlays/ContextMenu.svelte +3 -2
  136. package/dist/overlays/DraggablePane.svelte +163 -58
  137. package/dist/overlays/DraggablePane.svelte.d.ts +2 -0
  138. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +232 -77
  139. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -2
  140. package/dist/phase-diagram/PhaseDiagramControls.svelte +32 -11
  141. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +3 -2
  142. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +103 -0
  143. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
  144. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +102 -95
  145. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +7 -0
  146. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +100 -26
  147. package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +6 -3
  148. package/dist/phase-diagram/index.d.ts +2 -0
  149. package/dist/phase-diagram/index.js +2 -0
  150. package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
  151. package/dist/phase-diagram/svg-to-diagram.js +865 -0
  152. package/dist/phase-diagram/types.d.ts +10 -0
  153. package/dist/phase-diagram/utils.d.ts +7 -4
  154. package/dist/phase-diagram/utils.js +149 -59
  155. package/dist/plot/AxisLabel.svelte +26 -0
  156. package/dist/plot/AxisLabel.svelte.d.ts +16 -0
  157. package/dist/plot/BarPlot.svelte +473 -228
  158. package/dist/plot/BarPlot.svelte.d.ts +3 -3
  159. package/dist/plot/BarPlotControls.svelte +3 -2
  160. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  161. package/dist/plot/ColorBar.svelte +54 -54
  162. package/dist/plot/ColorBar.svelte.d.ts +1 -1
  163. package/dist/plot/ElementScatter.svelte +4 -3
  164. package/dist/plot/FillArea.svelte +4 -1
  165. package/dist/plot/Histogram.svelte +320 -230
  166. package/dist/plot/Histogram.svelte.d.ts +2 -2
  167. package/dist/plot/HistogramControls.svelte +29 -10
  168. package/dist/plot/HistogramControls.svelte.d.ts +6 -2
  169. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +2 -2
  170. package/dist/plot/PlotControls.svelte +109 -27
  171. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  172. package/dist/plot/PlotLegend.svelte +1 -1
  173. package/dist/plot/PortalSelect.svelte +2 -1
  174. package/dist/plot/ReferenceLine.svelte +2 -1
  175. package/dist/plot/ReferenceLine.svelte.d.ts +1 -0
  176. package/dist/plot/ReferencePlane.svelte +1 -3
  177. package/dist/plot/ScatterPlot.svelte +343 -209
  178. package/dist/plot/ScatterPlot.svelte.d.ts +3 -3
  179. package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
  180. package/dist/plot/ScatterPlot3DControls.svelte +203 -250
  181. package/dist/plot/ScatterPlot3DScene.svelte +4 -7
  182. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
  183. package/dist/plot/ScatterPlotControls.svelte +95 -55
  184. package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
  185. package/dist/plot/ZeroLines.svelte +44 -0
  186. package/dist/plot/ZeroLines.svelte.d.ts +32 -0
  187. package/dist/plot/ZoomRect.svelte +21 -0
  188. package/dist/plot/ZoomRect.svelte.d.ts +8 -0
  189. package/dist/plot/axis-utils.d.ts +1 -1
  190. package/dist/plot/data-cleaning.js +1 -5
  191. package/dist/plot/index.d.ts +6 -2
  192. package/dist/plot/index.js +6 -2
  193. package/dist/plot/interactions.d.ts +8 -10
  194. package/dist/plot/interactions.js +10 -19
  195. package/dist/plot/layout.d.ts +7 -1
  196. package/dist/plot/layout.js +12 -4
  197. package/dist/plot/reference-line.d.ts +4 -21
  198. package/dist/plot/reference-line.js +7 -81
  199. package/dist/plot/types.d.ts +42 -17
  200. package/dist/plot/types.js +10 -0
  201. package/dist/plot/utils/label-placement.js +14 -11
  202. package/dist/plot/utils.d.ts +1 -0
  203. package/dist/plot/utils.js +14 -0
  204. package/dist/rdf/RdfPlot.svelte +55 -66
  205. package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
  206. package/dist/rdf/index.d.ts +1 -1
  207. package/dist/rdf/index.js +1 -1
  208. package/dist/settings.d.ts +5 -0
  209. package/dist/settings.js +37 -3
  210. package/dist/spectral/Bands.svelte +515 -143
  211. package/dist/spectral/Bands.svelte.d.ts +22 -2
  212. package/dist/spectral/helpers.d.ts +23 -1
  213. package/dist/spectral/helpers.js +65 -9
  214. package/dist/spectral/types.d.ts +2 -0
  215. package/dist/structure/AtomLegend.svelte +31 -10
  216. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  217. package/dist/structure/CellSelect.svelte +92 -22
  218. package/dist/structure/Lattice.svelte +2 -0
  219. package/dist/structure/Structure.svelte +716 -173
  220. package/dist/structure/Structure.svelte.d.ts +7 -2
  221. package/dist/structure/StructureControls.svelte +26 -14
  222. package/dist/structure/StructureControls.svelte.d.ts +5 -1
  223. package/dist/structure/StructureInfoPane.svelte +7 -1
  224. package/dist/structure/StructureScene.svelte +386 -95
  225. package/dist/structure/StructureScene.svelte.d.ts +15 -4
  226. package/dist/structure/atom-properties.d.ts +6 -2
  227. package/dist/structure/atom-properties.js +38 -25
  228. package/dist/structure/export.js +10 -7
  229. package/dist/structure/ferrox-wasm-types.d.ts +3 -2
  230. package/dist/structure/ferrox-wasm-types.js +0 -3
  231. package/dist/structure/ferrox-wasm.d.ts +3 -2
  232. package/dist/structure/ferrox-wasm.js +1 -2
  233. package/dist/structure/index.d.ts +7 -0
  234. package/dist/structure/index.js +22 -0
  235. package/dist/structure/parse.js +19 -16
  236. package/dist/structure/partial-occupancy.d.ts +25 -0
  237. package/dist/structure/partial-occupancy.js +102 -0
  238. package/dist/structure/validation.js +6 -3
  239. package/dist/symmetry/SymmetryStats.svelte +18 -4
  240. package/dist/symmetry/WyckoffTable.svelte +18 -10
  241. package/dist/symmetry/index.d.ts +7 -4
  242. package/dist/symmetry/index.js +83 -18
  243. package/dist/table/HeatmapTable.svelte +468 -69
  244. package/dist/table/HeatmapTable.svelte.d.ts +13 -1
  245. package/dist/table/ToggleMenu.svelte +291 -44
  246. package/dist/table/ToggleMenu.svelte.d.ts +4 -1
  247. package/dist/table/index.d.ts +3 -0
  248. package/dist/tooltip/index.d.ts +1 -1
  249. package/dist/tooltip/index.js +1 -0
  250. package/dist/trajectory/Trajectory.svelte +147 -145
  251. package/dist/trajectory/TrajectoryExportPane.svelte +13 -9
  252. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +1 -1
  253. package/dist/trajectory/constants.d.ts +6 -0
  254. package/dist/trajectory/constants.js +7 -0
  255. package/dist/trajectory/extract.js +3 -5
  256. package/dist/trajectory/format-detect.d.ts +9 -0
  257. package/dist/trajectory/format-detect.js +76 -0
  258. package/dist/trajectory/frame-reader.d.ts +17 -0
  259. package/dist/trajectory/frame-reader.js +339 -0
  260. package/dist/trajectory/helpers.d.ts +15 -0
  261. package/dist/trajectory/helpers.js +187 -0
  262. package/dist/trajectory/index.d.ts +1 -0
  263. package/dist/trajectory/index.js +11 -4
  264. package/dist/trajectory/parse/ase.d.ts +2 -0
  265. package/dist/trajectory/parse/ase.js +76 -0
  266. package/dist/trajectory/parse/hdf5.d.ts +2 -0
  267. package/dist/trajectory/parse/hdf5.js +121 -0
  268. package/dist/trajectory/parse/index.d.ts +12 -0
  269. package/dist/trajectory/parse/index.js +304 -0
  270. package/dist/trajectory/parse/lammps.d.ts +5 -0
  271. package/dist/trajectory/parse/lammps.js +169 -0
  272. package/dist/trajectory/parse/vasp.d.ts +2 -0
  273. package/dist/trajectory/parse/vasp.js +65 -0
  274. package/dist/trajectory/parse/xyz.d.ts +2 -0
  275. package/dist/trajectory/parse/xyz.js +109 -0
  276. package/dist/trajectory/types.d.ts +11 -0
  277. package/dist/trajectory/types.js +1 -0
  278. package/dist/utils.d.ts +2 -0
  279. package/dist/utils.js +4 -0
  280. package/dist/xrd/XrdPlot.svelte +6 -4
  281. package/dist/xrd/calc-xrd.js +0 -1
  282. package/package.json +33 -23
  283. package/readme.md +4 -4
  284. package/dist/trajectory/parse.d.ts +0 -42
  285. package/dist/trajectory/parse.js +0 -1267
  286. /package/dist/element/{data.json.d.ts → data.json.gz.d.ts} +0 -0
@@ -1,8 +1,9 @@
1
- <script lang="ts">import { getContext, onMount } from 'svelte';
1
+ <script lang="ts">import Icon from '../../Icon.svelte';
2
+ import { getContext, onMount } from 'svelte';
2
3
  import JsonNode from './JsonNode.svelte';
3
4
  import JsonValue from './JsonValue.svelte';
4
5
  import { JSON_TREE_CONTEXT_KEY } from './types';
5
- import { build_path, format_preview, get_child_count, get_value_type, is_expandable, } from './utils';
6
+ import { build_path, estimate_byte_size, format_byte_size, format_preview, get_child_count, get_value_type, is_expandable, } from './utils';
6
7
  let { node_key = null, value, path, depth, is_last = true, } = $props();
7
8
  const ctx = getContext(JSON_TREE_CONTEXT_KEY);
8
9
  onMount(() => {
@@ -50,6 +51,12 @@ let is_collapsed = $derived.by(() => {
50
51
  let is_focused = $derived(ctx?.focused_path === path);
51
52
  // Check if this is the current search match being navigated
52
53
  let is_current_match = $derived(ctx?.current_match_path === path);
54
+ // Check if this node is selected
55
+ let is_selected = $derived(ctx?.selected_paths.has(path) ?? false);
56
+ // Diff status for this node (null if no diff or unchanged)
57
+ let diff_status = $derived(ctx?.diff_map?.get(path)?.status ?? null);
58
+ // Estimated byte size for collapsed preview (only compute when collapsed)
59
+ let byte_size = $derived(expandable && is_collapsed ? format_byte_size(estimate_byte_size(value)) : ``);
53
60
  // Toggle collapse state
54
61
  function toggle_collapse(event) {
55
62
  event?.stopPropagation();
@@ -102,6 +109,17 @@ function get_children() {
102
109
  return [];
103
110
  }
104
111
  let children = $derived(get_children());
112
+ // Ghost children: removed entries from diff (pre-computed in JsonTree for O(1) lookup)
113
+ let ghost_children = $derived.by(() => {
114
+ if (!expandable || is_collapsed)
115
+ return [];
116
+ const all_ghosts = ctx?.ghost_map.get(path) ?? [];
117
+ if (all_ghosts.length === 0)
118
+ return [];
119
+ // Filter out ghosts whose keys already exist in current children
120
+ const existing_keys = new Set(children.map((child) => String(child.key)));
121
+ return all_ghosts.filter((ghost) => !existing_keys.has(String(ghost.key)));
122
+ });
105
123
  // Get bracket characters based on type
106
124
  let open_bracket = $derived(value_type === `array` ? `[` : `{`);
107
125
  let close_bracket = $derived(value_type === `array` ? `]` : `}`);
@@ -114,6 +132,9 @@ function handle_keydown(event) {
114
132
  if (expandable) {
115
133
  toggle_collapse();
116
134
  }
135
+ else {
136
+ ctx?.copy_value(path, value);
137
+ }
117
138
  }
118
139
  else if (event.key === `ArrowRight`) {
119
140
  event.preventDefault();
@@ -128,7 +149,11 @@ function handle_keydown(event) {
128
149
  }
129
150
  }
130
151
  else if ((event.key === `c` || event.key === `C`) && (event.ctrlKey || event.metaKey)) {
152
+ // When nodes are selected, let the tree-level handler do bulk copy
153
+ if (ctx?.selected_paths.size)
154
+ return;
131
155
  event.preventDefault();
156
+ event.stopPropagation();
132
157
  ctx?.copy_value(path, value);
133
158
  }
134
159
  }
@@ -147,13 +172,35 @@ $effect(() => {
147
172
  class:collapsed={is_collapsed}
148
173
  class:expandable
149
174
  class:focused={is_focused}
175
+ class:selected={is_selected}
150
176
  class:current-match={is_current_match}
177
+ class:diff-added={diff_status === `added`}
178
+ class:diff-removed={diff_status === `removed`}
179
+ class:diff-changed={diff_status === `changed`}
180
+ class:sticky-header={expandable && !is_collapsed && depth <= 2}
181
+ style:--jt-sticky-depth={depth}
151
182
  data-path={path}
152
183
  role="treeitem"
153
184
  aria-expanded={expandable ? !is_collapsed : undefined}
154
- aria-selected={is_focused}
185
+ aria-selected={is_selected}
155
186
  tabindex={is_focused ? 0 : -1}
156
- onclick={focus_node}
187
+ onclick={(event) => {
188
+ if (event.ctrlKey || event.metaKey) {
189
+ event.stopPropagation()
190
+ ctx?.toggle_select(path, event.shiftKey)
191
+ } else {
192
+ focus_node()
193
+ }
194
+ }}
195
+ onauxclick={(event) => {
196
+ if (event.button === 1) {
197
+ event.preventDefault()
198
+ ctx?.copy_path(path, event)
199
+ }
200
+ }}
201
+ oncontextmenu={(event) => {
202
+ ctx?.show_context_menu(event, path, value, expandable, is_collapsed)
203
+ }}
157
204
  ondblclick={toggle_collapse_recursive}
158
205
  onkeydown={handle_keydown}
159
206
  >
@@ -176,11 +223,25 @@ $effect(() => {
176
223
  type="button"
177
224
  class="node-key"
178
225
  class:array-index={typeof node_key === `number`}
179
- title="Click to copy path: {path}"
180
226
  tabindex="-1"
181
227
  onclick={(event) => {
182
228
  event.stopPropagation()
183
- ctx?.copy_path(path)
229
+ if (event.ctrlKey || event.metaKey) {
230
+ ctx?.toggle_select(path, event.shiftKey)
231
+ } else if (event.shiftKey) {
232
+ ctx?.copy_path(path, event)
233
+ } else if (expandable && is_collapsed) {
234
+ ctx?.toggle_collapse(path, true)
235
+ } else {
236
+ ctx?.copy_value(path, value, event)
237
+ }
238
+ }}
239
+ onauxclick={(event) => {
240
+ if (event.button === 1) {
241
+ event.preventDefault()
242
+ event.stopPropagation()
243
+ ctx?.copy_path(path, event)
244
+ }
184
245
  }}
185
246
  >
186
247
  {#if typeof node_key === `number` && ctx?.settings.show_array_indices}
@@ -188,6 +249,16 @@ $effect(() => {
188
249
  {:else if typeof node_key === `string`}
189
250
  "{node_key}"
190
251
  {/if}
252
+ <span class="action-hint">
253
+ {#if expandable && is_collapsed}
254
+
255
+ {:else}
256
+ <Icon
257
+ icon="Copy"
258
+ style="width: 10px; height: 10px; vertical-align: baseline"
259
+ />
260
+ {/if}
261
+ </span>
191
262
  </button>
192
263
  <span class="colon">:</span>
193
264
  {/if}
@@ -198,11 +269,27 @@ $effect(() => {
198
269
  <button type="button" class="preview" tabindex="-1" onclick={toggle_collapse}>
199
270
  {format_preview(value)}
200
271
  </button>
272
+ <span class="size-hint">{byte_size}</span>
201
273
  <span class="bracket close">{close_bracket}</span>
202
274
  {/if}
203
275
  {:else}
204
276
  <JsonValue {value} {value_type} {path} />
205
277
  {/if}
278
+
279
+ {#if expandable && !is_collapsed}
280
+ <button
281
+ type="button"
282
+ class="collapse-level-btn"
283
+ title="Collapse children to this level"
284
+ tabindex="-1"
285
+ onclick={(event) => {
286
+ event.stopPropagation()
287
+ ctx?.collapse_children_only(path)
288
+ }}
289
+ >
290
+
291
+ </button>
292
+ {/if}
206
293
  </span>
207
294
 
208
295
  {#if !is_last && (!expandable || is_collapsed)}
@@ -217,9 +304,33 @@ $effect(() => {
217
304
  value={child.value}
218
305
  path={build_path(path, child.key)}
219
306
  depth={depth + 1}
220
- is_last={idx === children.length - 1}
307
+ is_last={idx === children.length - 1 && ghost_children.length === 0}
221
308
  />
222
309
  {/each}
310
+ {#each ghost_children as ghost (ghost.key)}
311
+ <div
312
+ class="json-node ghost"
313
+ data-path={ghost.path}
314
+ role="treeitem"
315
+ aria-selected="false"
316
+ aria-disabled="true"
317
+ >
318
+ <span class="node-content">
319
+ <span class="no-toggle"></span>
320
+ <span style="color: var(--jt-key)">
321
+ {#if typeof ghost.key === `number`}
322
+ <span class="index">{ghost.key}</span>
323
+ {:else}
324
+ "{ghost.key}"
325
+ {/if}
326
+ </span>
327
+ <span class="colon">:</span>
328
+ <span style="color: var(--jt-preview); font-style: italic">{
329
+ format_preview(ghost.value)
330
+ }</span>
331
+ </span>
332
+ </div>
333
+ {/each}
223
334
  </div>
224
335
  <span class="bracket close">{close_bracket}</span>
225
336
  {#if !is_last}
@@ -234,17 +345,50 @@ $effect(() => {
234
345
  font-size: var(--jt-font-size, 13px);
235
346
  line-height: var(--jt-line-height, 1.5);
236
347
  outline: none;
237
- }
238
- .json-node:focus {
239
- outline: none;
240
- }
241
- .json-node.focused > .node-content {
242
- background: var(--jt-focus-bg, light-dark(#e3f2fd, #0d3a58));
243
- border-radius: 2px;
244
- }
245
- .json-node.current-match > .node-content {
246
- background: var(--jt-current-match-bg, light-dark(#ffcc80, #8a5600));
247
- border-radius: 2px;
348
+ &:focus {
349
+ outline: none;
350
+ }
351
+ &.focused > .node-content {
352
+ background: var(--jt-focus-bg, light-dark(#e3f2fd, #0d3a58));
353
+ border-radius: 2px;
354
+ }
355
+ &.current-match > .node-content {
356
+ background: var(--jt-current-match-bg, light-dark(#ffcc80, #8a5600));
357
+ border-radius: 2px;
358
+ }
359
+ &.selected > .node-content {
360
+ background: var(--jt-select-bg, light-dark(#bbdefb, #0a3050));
361
+ }
362
+ &.diff-added > .node-content {
363
+ background: var(
364
+ --jt-diff-added,
365
+ light-dark(rgba(76, 175, 80, 0.15), rgba(76, 175, 80, 0.2))
366
+ );
367
+ }
368
+ &.diff-removed > .node-content {
369
+ background: var(
370
+ --jt-diff-removed,
371
+ light-dark(rgba(244, 67, 54, 0.12), rgba(244, 67, 54, 0.18))
372
+ );
373
+ text-decoration: line-through;
374
+ opacity: 0.7;
375
+ }
376
+ &.diff-changed > .node-content {
377
+ background: var(
378
+ --jt-diff-changed,
379
+ light-dark(rgba(255, 193, 7, 0.15), rgba(255, 193, 7, 0.2))
380
+ );
381
+ }
382
+ &.sticky-header > .node-content {
383
+ position: sticky;
384
+ top: calc(var(--jt-sticky-depth) * 20px);
385
+ z-index: calc(100 - var(--jt-sticky-depth));
386
+ background: var(--jt-sticky-bg, var(--jt-bg, transparent));
387
+ display: flex;
388
+ }
389
+ &:hover > .node-content > .collapse-level-btn {
390
+ opacity: 0.5;
391
+ }
248
392
  }
249
393
  .node-content {
250
394
  display: inline-flex;
@@ -252,6 +396,22 @@ $effect(() => {
252
396
  gap: 2px;
253
397
  padding: 1px 2px;
254
398
  border-radius: 2px;
399
+ /* Higher specificity than DraggablePane's :where(button) so our reset wins when nested */
400
+ button {
401
+ background: none;
402
+ border: none;
403
+ padding: 0;
404
+ cursor: pointer;
405
+ font: inherit;
406
+ color: inherit;
407
+ }
408
+ }
409
+ .ghost .node-content {
410
+ background: var(
411
+ --jt-diff-removed,
412
+ light-dark(rgba(244, 67, 54, 0.12), rgba(244, 67, 54, 0.18))
413
+ );
414
+ text-decoration: line-through;
255
415
  }
256
416
  .collapse-toggle {
257
417
  display: inline-flex;
@@ -259,24 +419,20 @@ $effect(() => {
259
419
  justify-content: center;
260
420
  width: 1em;
261
421
  height: 1em;
262
- padding: 0;
263
422
  margin: 0;
264
- border: none;
265
- background: none;
266
- cursor: pointer;
267
423
  color: var(--jt-arrow, light-dark(#6e6e6e, #858585));
268
424
  flex-shrink: 0;
269
- }
270
- .collapse-toggle:hover {
271
- color: light-dark(#000, #fff);
425
+ &:hover {
426
+ color: light-dark(#000, #fff);
427
+ }
272
428
  }
273
429
  .arrow {
274
430
  display: inline-block;
275
431
  font-size: 0.7em;
276
432
  transition: transform 0.15s ease;
277
- }
278
- .arrow.collapsed {
279
- transform: rotate(-90deg);
433
+ &.collapsed {
434
+ transform: rotate(-90deg);
435
+ }
280
436
  }
281
437
  .no-toggle {
282
438
  display: inline-block;
@@ -285,40 +441,29 @@ $effect(() => {
285
441
  }
286
442
  .node-key {
287
443
  color: var(--jt-key, light-dark(#001080, #9cdcfe));
288
- cursor: pointer;
289
- background: none;
290
- border: none;
291
- padding: 0;
292
- font: inherit;
293
- }
294
- .node-key:hover {
295
- text-decoration: underline;
444
+ &:hover {
445
+ text-decoration: underline;
446
+ .action-hint {
447
+ opacity: 0.6;
448
+ }
449
+ }
450
+ &.array-index .index {
451
+ color: var(--jt-number, light-dark(#098658, #b5cea8));
452
+ }
296
453
  }
297
- .node-key.array-index .index {
298
- color: var(--jt-number, light-dark(#098658, #b5cea8));
454
+ .colon, .comma, .bracket {
455
+ color: var(--jt-punctuation, light-dark(#000, #d4d4d4));
299
456
  }
300
457
  .colon {
301
- color: var(--jt-punctuation, light-dark(#000, #d4d4d4));
302
458
  margin-right: 4px;
303
459
  }
304
- .bracket {
305
- color: var(--jt-punctuation, light-dark(#000, #d4d4d4));
306
- }
307
460
  .preview {
308
461
  color: var(--jt-preview, light-dark(#808080, #808080));
309
462
  font-style: italic;
310
- cursor: pointer;
311
463
  margin: 0 4px;
312
- background: none;
313
- border: none;
314
- padding: 0;
315
- font: inherit;
316
- }
317
- .preview:hover {
318
- text-decoration: underline;
319
- }
320
- .comma {
321
- color: var(--jt-punctuation, light-dark(#000, #d4d4d4));
464
+ &:hover {
465
+ text-decoration: underline;
466
+ }
322
467
  }
323
468
  .children {
324
469
  padding-left: var(--jt-indent, 1.2em);
@@ -326,4 +471,32 @@ $effect(() => {
326
471
  var(--jt-indent-guide, light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1)));
327
472
  margin-left: 0.5em;
328
473
  }
474
+ .action-hint {
475
+ opacity: 0;
476
+ font-size: 0.8em;
477
+ margin-left: 2px;
478
+ transition: opacity 0.15s;
479
+ color: var(--jt-arrow, light-dark(#6e6e6e, #858585));
480
+ }
481
+ .size-hint {
482
+ font-size: 0.8em;
483
+ color: var(--jt-preview, light-dark(#808080, #808080));
484
+ margin-left: 4px;
485
+ opacity: 0.6;
486
+ }
487
+ .collapse-level-btn {
488
+ opacity: 0;
489
+ padding: 0 2px;
490
+ font-size: 0.85em;
491
+ color: var(--jt-arrow, light-dark(#6e6e6e, #858585));
492
+ transition: opacity 0.15s;
493
+ margin-left: 4px;
494
+ &:hover {
495
+ opacity: 1;
496
+ color: light-dark(#000, #fff);
497
+ }
498
+ }
499
+ .ghost {
500
+ opacity: 0.5;
501
+ }
329
502
  </style>