@gfazioli/mantine-json-tree 2.0.2 → 2.1.0

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Mantine Json Tree Component
2
2
 
3
- <img alt="Mantine Json Tree" src="https://github.com/gfazioli/mantine-json-tree/blob/master/logo.png" />
3
+ <img alt="Mantine Json Tree" src="https://github.com/gfazioli/mantine-json-tree/blob/master/logo.jpeg" />
4
4
 
5
5
  <div align="center">
6
6
 
@@ -19,10 +19,31 @@
19
19
 
20
20
  This component is created on top of the [Mantine](https://mantine.dev/) library.
21
21
 
22
- [Mantine JsonTree](https://gfazioli.github.io/mantine-json-tree) provides a structured, interactive view of heterogeneous data—strings, numbers, booleans, nulls, objects, arrays, and even functions—organized as a collapsible tree. Developers can control initial expansion, show visual indent guides, and customize expand/collapse controls with arbitrary React nodes (e.g., emojis or styled icons) to match their design system. For function values, the component offers flexible rendering modes: show the function signature as text, hide functions entirely, or inspect them as objects when needed.
22
+ [Mantine JsonTree](https://gfazioli.github.io/mantine-json-tree) provides a structured, interactive view of heterogeneous data—strings, numbers, booleans, nulls, objects, arrays, and even functions—organized as a collapsible tree. Developers can control initial expansion, show visual indent guides, and customize expand/collapse controls with arbitrary React nodes (e.g., emojis or styled icons) to match their design system. For function values, the component offers flexible rendering modes: show the function signature as text, hide functions entirely, or inspect them as objects when needed.
23
23
 
24
24
  Wrapped with Mantine layout primitives like Paper, Stack, and SimpleGrid, JsonTree integrates cleanly into dashboards, developer tools, and documentation pages where readable, navigable data visualization is essential.
25
25
 
26
+ ## Features
27
+
28
+ - Interactive collapsible tree view for any JSON-serializable data
29
+ - Syntax highlighting with customizable colors for 16+ data types (strings, numbers, booleans, null, Date, RegExp, Map, Set, BigInt, Symbol, React elements, etc.)
30
+ - Dark mode support with automatic color adaptation
31
+ - Copy-to-clipboard on individual nodes
32
+ - Keyboard navigation (arrow keys, Space to expand, Ctrl+C to copy)
33
+ - Configurable expansion depth with expand/collapse all controls
34
+ - Controlled expand/collapse state with `expanded` and `onExpandedChange` props
35
+ - Line numbers display
36
+ - Visual indent guides with rotating color palette
37
+ - Path tooltip on hover showing full JSON path
38
+ - Max height with scrollable container
39
+ - Sticky header support with configurable offset
40
+ - Function display modes: as-string, hide, or as-object introspection
41
+ - Responsive font size via Mantine breakpoint objects (CSS-native, no re-renders)
42
+ - Full Mantine Styles API support with 13 style selectors and 25+ CSS variables
43
+ - Custom icons for expand/collapse and copy controls
44
+ - Item count badges for objects and arrays
45
+ - `onExpand`, `onCollapse`, `onNodeClick`, and `onCopy` callbacks
46
+
26
47
  > [!note]
27
48
  >
28
49
  > → [Demo and Documentation](https://gfazioli.github.io/mantine-json-tree/) → [Youtube Video](https://www.youtube.com/playlist?list=PL85tTROKkZrWyqCcmNCdWajpx05-cTal4) → [More Mantine Components](https://mantine-extensions.vercel.app/)
@@ -4,6 +4,7 @@
4
4
  var React = require('react');
5
5
  var iconsReact = require('@tabler/icons-react');
6
6
  var core = require('@mantine/core');
7
+ var JsonTreeMediaVariables = require('./JsonTreeMediaVariables.cjs');
7
8
  var utils = require('./lib/utils.cjs');
8
9
  var JsonTree_module = require('./JsonTree.module.css.cjs');
9
10
 
@@ -14,18 +15,210 @@ const defaultProps = {
14
15
  showItemsCount: false,
15
16
  withCopyToClipboard: false,
16
17
  showIndentGuides: false,
18
+ showLineNumbers: false,
19
+ showPathOnHover: false,
17
20
  stickyHeader: false,
18
21
  displayFunctions: "as-string",
19
22
  expandAllControlIcon: /* @__PURE__ */ React.createElement(iconsReact.IconLibraryPlus, { size: 16 }),
20
23
  collapseAllControlIcon: /* @__PURE__ */ React.createElement(iconsReact.IconLibraryMinus, { size: 16 }),
21
24
  copyToClipboardIcon: /* @__PURE__ */ React.createElement(iconsReact.IconCopy, { size: 12 })
22
25
  };
26
+ function renderJSONNode({ node, expanded, hasChildren, elementProps, tree }, props, ctx, onNodeClick) {
27
+ const {
28
+ getStyles,
29
+ copyToClipboardIcon,
30
+ expandControlIcon,
31
+ collapseControlIcon,
32
+ onExpand,
33
+ onCollapse,
34
+ onExpandedChange
35
+ } = ctx;
36
+ const jsonNode = node;
37
+ const {
38
+ type,
39
+ value,
40
+ key,
41
+ path,
42
+ itemCount,
43
+ depth = 0
44
+ } = jsonNode.nodeData || {
45
+ type: "null",
46
+ value: null,
47
+ path: "unknown",
48
+ depth: 0
49
+ };
50
+ const {
51
+ showItemsCount,
52
+ withCopyToClipboard,
53
+ onCopy,
54
+ showIndentGuides,
55
+ showLineNumbers,
56
+ showPathOnHover,
57
+ tooltipProps
58
+ } = props;
59
+ const handleCopy = async (e) => {
60
+ e.stopPropagation();
61
+ try {
62
+ const copy = JSON.stringify(value, null, 2);
63
+ await navigator.clipboard.writeText(copy);
64
+ onCopy?.(copy, value);
65
+ } catch (error) {
66
+ }
67
+ };
68
+ const handleClick = () => {
69
+ if (onNodeClick) {
70
+ onNodeClick(path, value);
71
+ }
72
+ };
73
+ const handleToggleExpanded = (e) => {
74
+ e.stopPropagation();
75
+ if (expanded) {
76
+ onCollapse?.(node.value);
77
+ } else {
78
+ onExpand?.(node.value);
79
+ }
80
+ if (onExpandedChange) {
81
+ const newState = { ...tree.expandedState, [node.value]: !expanded };
82
+ onExpandedChange(Object.keys(newState).filter((k) => newState[k]));
83
+ } else {
84
+ tree.toggleExpanded(node.value);
85
+ }
86
+ };
87
+ const renderIndentGuides = () => {
88
+ if (!showIndentGuides || depth === 0) {
89
+ return null;
90
+ }
91
+ const guides = [];
92
+ for (let i = 0; i < depth; i++) {
93
+ const colorIndex = i % 5;
94
+ guides.push(
95
+ /* @__PURE__ */ React.createElement(
96
+ "div",
97
+ {
98
+ key: i,
99
+ ...getStyles("indentGuide", {
100
+ style: {
101
+ left: `${i * 32 + 8}px`
102
+ }
103
+ }),
104
+ "data-color-index": colorIndex
105
+ }
106
+ )
107
+ );
108
+ }
109
+ return guides;
110
+ };
111
+ const lineNumber = showLineNumbers ? /* @__PURE__ */ React.createElement("span", { ...getStyles("lineNumber") }) : null;
112
+ const wrapWithTooltip = (content) => showPathOnHover ? /* @__PURE__ */ React.createElement(core.Tooltip, { label: path, position: "top-start", withArrow: true, openDelay: 300, ...tooltipProps }, content) : content;
113
+ if (!hasChildren) {
114
+ return wrapWithTooltip(
115
+ /* @__PURE__ */ React.createElement(
116
+ core.Group,
117
+ {
118
+ gap: 4,
119
+ wrap: "nowrap",
120
+ ...elementProps,
121
+ onClick: handleClick,
122
+ style: { cursor: onNodeClick ? "pointer" : "default", position: "relative" }
123
+ },
124
+ lineNumber,
125
+ renderIndentGuides(),
126
+ key !== void 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("key"), "data-key": key }, key), /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("keyValueSeparator") }, ":")),
127
+ (() => {
128
+ const formattedValue = utils.formatValue(value, type);
129
+ return /* @__PURE__ */ React.createElement(core.Code, { ...getStyles("value"), "data-type": type, "data-value": formattedValue }, formattedValue);
130
+ })(),
131
+ withCopyToClipboard && /* @__PURE__ */ React.createElement(
132
+ core.ActionIcon,
133
+ {
134
+ size: "xs",
135
+ variant: "subtle",
136
+ color: "gray",
137
+ onClick: handleCopy,
138
+ ...getStyles("copyButton")
139
+ },
140
+ copyToClipboardIcon
141
+ )
142
+ )
143
+ );
144
+ }
145
+ const openBracket = type === "array" ? "[" : "{";
146
+ const closeBracket = type === "array" ? "]" : "}";
147
+ const expandCollapseIcon = (() => {
148
+ if (!expandControlIcon && !collapseControlIcon) {
149
+ return /* @__PURE__ */ React.createElement(
150
+ iconsReact.IconChevronRight,
151
+ {
152
+ size: 14,
153
+ style: {
154
+ transform: expanded ? "rotate(90deg)" : "rotate(0deg)",
155
+ transition: "transform 0.2s ease"
156
+ }
157
+ }
158
+ );
159
+ }
160
+ if (expandControlIcon && !collapseControlIcon) {
161
+ return React.cloneElement(expandControlIcon, {
162
+ style: {
163
+ ...expandControlIcon.props?.style,
164
+ transform: expanded ? "rotate(90deg)" : "rotate(0deg)",
165
+ transition: "transform 0.2s ease"
166
+ }
167
+ });
168
+ }
169
+ if (!expandControlIcon && collapseControlIcon) {
170
+ return expanded ? collapseControlIcon : /* @__PURE__ */ React.createElement(iconsReact.IconChevronRight, { size: 14 });
171
+ }
172
+ return expanded ? collapseControlIcon : expandControlIcon;
173
+ })();
174
+ return wrapWithTooltip(
175
+ /* @__PURE__ */ React.createElement(
176
+ core.Group,
177
+ {
178
+ gap: 4,
179
+ wrap: "nowrap",
180
+ ...elementProps,
181
+ onClick: handleClick,
182
+ "data-expanded": expanded,
183
+ "data-has-children": hasChildren,
184
+ "data-type": type,
185
+ style: { cursor: onNodeClick ? "pointer" : "default", position: "relative" }
186
+ },
187
+ lineNumber,
188
+ renderIndentGuides(),
189
+ /* @__PURE__ */ React.createElement(
190
+ core.ActionIcon,
191
+ {
192
+ size: "xs",
193
+ variant: "subtle",
194
+ onClick: handleToggleExpanded,
195
+ ...getStyles("expandCollapse")
196
+ },
197
+ expandCollapseIcon
198
+ ),
199
+ key !== void 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("key") }, key), /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("keyValueSeparator") }, ":")),
200
+ /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("bracket") }, openBracket),
201
+ !expanded && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(core.Text, { component: "span", size: "xs", ...getStyles("ellipsis") }, "..."), /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("bracket") }, closeBracket), itemCount !== void 0 && showItemsCount && /* @__PURE__ */ React.createElement(core.Badge, { size: "xs", variant: "light", color: "gray", ...getStyles("itemsCount") }, itemCount)),
202
+ withCopyToClipboard && /* @__PURE__ */ React.createElement(
203
+ core.ActionIcon,
204
+ {
205
+ size: "xs",
206
+ variant: "subtle",
207
+ color: "gray",
208
+ onClick: handleCopy,
209
+ ...getStyles("copyButton")
210
+ },
211
+ copyToClipboardIcon
212
+ )
213
+ )
214
+ );
215
+ }
23
216
  const varsResolver = core.createVarsResolver(
24
- (_, { size, stickyHeader, stickyHeaderOffset }) => {
217
+ (_, { stickyHeader, stickyHeaderOffset }) => {
25
218
  return {
26
219
  root: {
27
220
  "--json-tree-font-family": "var(--mantine-font-family-monospace)",
28
- "--json-tree-font-size": core.getFontSize(size) || "var(--mantine-font-size-xs)"
221
+ "--json-tree-font-size": void 0
29
222
  },
30
223
  header: {
31
224
  "--json-tree-header-background-color": "inherit",
@@ -60,7 +253,8 @@ const varsResolver = core.createVarsResolver(
60
253
  },
61
254
  expandCollapse: {},
62
255
  keyValueSeparator: {},
63
- ellipsis: {},
256
+ ellipsis: { "--json-tree-color-ellipsis": "var(--mantine-color-dark-3)" },
257
+ lineNumber: { "--json-tree-color-line-number": "var(--mantine-color-gray-5)" },
64
258
  itemsCount: {},
65
259
  controls: {},
66
260
  copyButton: {}
@@ -75,12 +269,19 @@ const JsonTree = core.factory((_props, ref) => {
75
269
  maxDepth,
76
270
  onNodeClick,
77
271
  onCopy,
272
+ onExpand,
273
+ onCollapse,
78
274
  withExpandAll,
79
- variant,
80
275
  title,
81
276
  showItemsCount,
82
277
  withCopyToClipboard,
83
278
  showIndentGuides,
279
+ showLineNumbers,
280
+ showPathOnHover,
281
+ tooltipProps,
282
+ maxHeight,
283
+ expanded: controlledExpanded,
284
+ onExpandedChange,
84
285
  stickyHeaderOffset,
85
286
  stickyHeader,
86
287
  displayFunctions,
@@ -89,6 +290,7 @@ const JsonTree = core.factory((_props, ref) => {
89
290
  copyToClipboardIcon,
90
291
  expandControlIcon,
91
292
  collapseControlIcon,
293
+ size,
92
294
  classNames,
93
295
  style,
94
296
  styles,
@@ -109,12 +311,19 @@ const JsonTree = core.factory((_props, ref) => {
109
311
  vars,
110
312
  varsResolver
111
313
  });
112
- const theme = core.useMantineTheme();
314
+ const responsiveClassName = core.useRandomClassName();
113
315
  const treeData = React.useMemo(
114
316
  () => [utils.convertToTreeData(data, void 0, "root", 0, displayFunctions)],
115
317
  [data, displayFunctions]
116
318
  );
117
319
  const initialExpandedState = React.useMemo(() => {
320
+ if (controlledExpanded) {
321
+ const state = {};
322
+ controlledExpanded.forEach((path) => {
323
+ state[path] = true;
324
+ });
325
+ return state;
326
+ }
118
327
  if (defaultExpanded) {
119
328
  if (maxDepth === -1) {
120
329
  return core.getTreeExpandedState(treeData, "*");
@@ -132,190 +341,104 @@ const JsonTree = core.factory((_props, ref) => {
132
341
  return core.getTreeExpandedState(treeData, expandedNodes);
133
342
  }
134
343
  return {};
135
- }, [treeData, defaultExpanded, maxDepth]);
344
+ }, [treeData, defaultExpanded, maxDepth, controlledExpanded]);
136
345
  const tree = core.useTree({
137
346
  initialExpandedState
138
347
  });
139
- function renderJSONNode({ node, expanded, hasChildren, elementProps, tree: tree2 }, _, props2, onNodeClick2) {
140
- const jsonNode = node;
141
- const {
142
- type,
143
- value,
144
- key,
145
- path,
146
- itemCount,
147
- depth = 0
148
- } = jsonNode.nodeData || {
149
- type: "null",
150
- value: null,
151
- path: "unknown",
152
- depth: 0
153
- };
154
- const { showItemsCount: showItemsCount2, withCopyToClipboard: withCopyToClipboard2, onCopy: onCopy2, showIndentGuides: showIndentGuides2 } = props2;
155
- const handleCopy = async (e) => {
156
- e.stopPropagation();
157
- try {
158
- const copy = JSON.stringify(value, null, 2);
159
- await navigator.clipboard.writeText(copy);
160
- onCopy2?.(copy, value);
161
- } catch (error) {
162
- }
163
- };
164
- const handleClick = () => {
165
- if (onNodeClick2) {
166
- onNodeClick2(path, value);
167
- }
168
- };
169
- const renderIndentGuides = () => {
170
- if (!showIndentGuides2 || depth === 0) {
171
- return null;
172
- }
173
- const guides = [];
174
- for (let i = 0; i < depth; i++) {
175
- const colorIndex = i % 5;
176
- guides.push(
177
- /* @__PURE__ */ React.createElement(
178
- "div",
179
- {
180
- key: i,
181
- ...getStyles("indentGuide", {
182
- style: {
183
- left: `${i * 32 + 8}px`
184
- }
185
- }),
186
- "data-color-index": colorIndex
187
- }
188
- )
189
- );
190
- }
191
- return guides;
192
- };
193
- if (!hasChildren) {
194
- return /* @__PURE__ */ React.createElement(
195
- core.Group,
196
- {
197
- gap: 4,
198
- wrap: "nowrap",
199
- ...elementProps,
200
- onClick: handleClick,
201
- style: { cursor: onNodeClick2 ? "pointer" : "default", position: "relative" }
202
- },
203
- renderIndentGuides(),
204
- key !== void 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("key"), "data-key": key }, key), /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("keyValueSeparator") }, ":")),
205
- (() => {
206
- const formattedValue = utils.formatValue(value, type);
207
- return /* @__PURE__ */ React.createElement(core.Code, { ...getStyles("value"), "data-type": type, "data-value": formattedValue }, formattedValue);
208
- })(),
209
- withCopyToClipboard2 && /* @__PURE__ */ React.createElement(
210
- core.ActionIcon,
211
- {
212
- size: "xs",
213
- variant: "subtle",
214
- color: "gray",
215
- onClick: handleCopy,
216
- ...getStyles("copyButton")
217
- },
218
- copyToClipboardIcon
219
- )
220
- );
348
+ React.useEffect(() => {
349
+ if (controlledExpanded) {
350
+ const state = {};
351
+ controlledExpanded.forEach((path) => {
352
+ state[path] = true;
353
+ });
354
+ tree.setExpandedState(state);
221
355
  }
222
- const openBracket = type === "array" ? "[" : "{";
223
- const closeBracket = type === "array" ? "]" : "}";
224
- const expandCollapseIcon = (() => {
225
- if (!expandControlIcon && !collapseControlIcon) {
226
- return /* @__PURE__ */ React.createElement(
227
- iconsReact.IconChevronRight,
228
- {
229
- size: 14,
230
- style: {
231
- transform: expanded ? "rotate(90deg)" : "rotate(0deg)",
232
- transition: "transform 0.2s ease"
233
- }
234
- }
356
+ }, [controlledExpanded, tree.setExpandedState]);
357
+ const handleKeyDown = React.useCallback(
358
+ async (e) => {
359
+ if ((e.metaKey || e.ctrlKey) && e.key === "c" && withCopyToClipboard) {
360
+ e.preventDefault();
361
+ const focused = e.currentTarget.querySelector(
362
+ '[data-value][tabindex="0"], [data-value]:focus'
235
363
  );
236
- }
237
- if (expandControlIcon && !collapseControlIcon) {
238
- return React.cloneElement(expandControlIcon, {
239
- style: {
240
- ...expandControlIcon.props?.style,
241
- transform: expanded ? "rotate(90deg)" : "rotate(0deg)",
242
- transition: "transform 0.2s ease"
364
+ if (focused) {
365
+ const nodePath = focused.getAttribute("data-value");
366
+ if (nodePath) {
367
+ const nodeData = utils.findNodeByPath(treeData, nodePath);
368
+ if (nodeData?.nodeData) {
369
+ try {
370
+ const copy = JSON.stringify(nodeData.nodeData.value, null, 2);
371
+ await navigator.clipboard.writeText(copy);
372
+ onCopy?.(copy, nodeData.nodeData.value);
373
+ } catch {
374
+ }
375
+ }
243
376
  }
244
- });
245
- }
246
- if (!expandControlIcon && collapseControlIcon) {
247
- return expanded ? collapseControlIcon : /* @__PURE__ */ React.createElement(iconsReact.IconChevronRight, { size: 14 });
377
+ }
248
378
  }
249
- return expanded ? collapseControlIcon : expandControlIcon;
250
- })();
251
- return /* @__PURE__ */ React.createElement(
252
- core.Group,
253
- {
254
- gap: 4,
255
- wrap: "nowrap",
256
- ...elementProps,
257
- onClick: handleClick,
258
- "data-expanded": expanded,
259
- "data-has-children": hasChildren,
260
- "data-type": type,
261
- style: { cursor: onNodeClick2 ? "pointer" : "default", position: "relative" }
262
- },
263
- renderIndentGuides(),
264
- /* @__PURE__ */ React.createElement(
265
- core.ActionIcon,
266
- {
267
- size: "xs",
268
- variant: "subtle",
269
- onClick: (e) => {
270
- e.stopPropagation();
271
- tree2.toggleExpanded(node.value);
272
- },
273
- ...getStyles("expandCollapse")
274
- },
275
- expandCollapseIcon
276
- ),
277
- key !== void 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("key") }, key), /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("keyValueSeparator") }, ":")),
278
- /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("bracket") }, openBracket),
279
- !expanded && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(core.Text, { component: "span", size: "xs", ...getStyles("ellipsis") }, "..."), /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("bracket") }, closeBracket), itemCount !== void 0 && showItemsCount2 && /* @__PURE__ */ React.createElement(core.Badge, { size: "xs", variant: "light", color: "gray", ...getStyles("itemsCount") }, itemCount)),
280
- withCopyToClipboard2 && /* @__PURE__ */ React.createElement(
281
- core.ActionIcon,
282
- {
283
- size: "xs",
284
- variant: "subtle",
285
- color: "gray",
286
- onClick: handleCopy,
287
- ...getStyles("copyButton")
288
- },
289
- copyToClipboardIcon
290
- )
291
- );
292
- }
293
- return /* @__PURE__ */ React.createElement(core.Box, { ref, ...getStyles("root"), ...others }, (title || withExpandAll) && /* @__PURE__ */ React.createElement(core.Group, { ...getStyles("header"), justify: "space-between", mod: { sticky: stickyHeader } }, title || /* @__PURE__ */ React.createElement("div", null), withExpandAll && utils.isExpandable(data) && /* @__PURE__ */ React.createElement(core.Group, { gap: "xs", style: { top: 10, zIndex: 1 } }, /* @__PURE__ */ React.createElement(
294
- core.ActionIcon,
295
- {
296
- size: "xs",
297
- variant: "transparent",
298
- onClick: () => tree.expandAllNodes(),
299
- ...getStyles("controls")
300
379
  },
301
- expandAllControlIcon
302
- ), /* @__PURE__ */ React.createElement(
303
- core.ActionIcon,
304
- {
305
- size: "xs",
306
- variant: "transparent",
307
- onClick: () => tree.collapseAllNodes(),
308
- ...getStyles("controls")
309
- },
310
- collapseAllControlIcon
311
- ))), /* @__PURE__ */ React.createElement(
380
+ [withCopyToClipboard, treeData, onCopy]
381
+ );
382
+ const renderCtx = {
383
+ getStyles,
384
+ copyToClipboardIcon,
385
+ expandControlIcon,
386
+ collapseControlIcon,
387
+ onExpand,
388
+ onCollapse,
389
+ onExpandedChange
390
+ };
391
+ const treeComponent = /* @__PURE__ */ React.createElement(
312
392
  core.Tree,
313
393
  {
314
394
  data: treeData,
315
395
  tree,
316
396
  levelOffset: 32,
317
- renderNode: (payload) => renderJSONNode(payload, theme, props, onNodeClick)
397
+ renderNode: (payload) => renderJSONNode(payload, props, renderCtx, onNodeClick)
318
398
  }
399
+ );
400
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(JsonTreeMediaVariables.JsonTreeMediaVariables, { size, selector: `.${responsiveClassName}` }), /* @__PURE__ */ React.createElement(
401
+ core.Box,
402
+ {
403
+ ref,
404
+ ...getStyles("root", { className: responsiveClassName }),
405
+ ...others,
406
+ "data-line-numbers": showLineNumbers || void 0,
407
+ onKeyDown: handleKeyDown
408
+ },
409
+ (title || withExpandAll) && /* @__PURE__ */ React.createElement(core.Group, { ...getStyles("header"), justify: "space-between", mod: { sticky: stickyHeader } }, title || /* @__PURE__ */ React.createElement("div", null), withExpandAll && utils.isExpandable(data) && /* @__PURE__ */ React.createElement(core.Group, { gap: "xs", style: { top: 10, zIndex: 1 } }, /* @__PURE__ */ React.createElement(
410
+ core.ActionIcon,
411
+ {
412
+ size: "xs",
413
+ variant: "transparent",
414
+ onClick: () => {
415
+ const allState = core.getTreeExpandedState(treeData, "*");
416
+ if (onExpandedChange) {
417
+ onExpandedChange(Object.keys(allState).filter((k) => allState[k]));
418
+ } else {
419
+ tree.expandAllNodes();
420
+ }
421
+ },
422
+ ...getStyles("controls")
423
+ },
424
+ expandAllControlIcon
425
+ ), /* @__PURE__ */ React.createElement(
426
+ core.ActionIcon,
427
+ {
428
+ size: "xs",
429
+ variant: "transparent",
430
+ onClick: () => {
431
+ if (onExpandedChange) {
432
+ onExpandedChange([]);
433
+ } else {
434
+ tree.collapseAllNodes();
435
+ }
436
+ },
437
+ ...getStyles("controls")
438
+ },
439
+ collapseAllControlIcon
440
+ ))),
441
+ maxHeight ? /* @__PURE__ */ React.createElement(core.ScrollArea.Autosize, { mah: maxHeight }, treeComponent) : treeComponent
319
442
  ));
320
443
  });
321
444
  JsonTree.classes = JsonTree_module;