@gfazioli/mantine-json-tree 3.0.0 → 3.2.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
@@ -27,9 +27,13 @@ Wrapped with Mantine layout primitives like Paper, Stack, and SimpleGrid, JsonTr
27
27
  ## Features
28
28
 
29
29
  - Interactive collapsible tree view for any JSON-serializable data
30
+ - **Search** with text highlight, filtered tree view, and auto-expand matching branches
31
+ - **Redesigned toolbar** with key count badge, global copy, search toggle, and modern icons
32
+ - **Paper wrapper** with `withBorder` for bordered container look
33
+ - **Custom root name** via `rootName` prop
30
34
  - Syntax highlighting with customizable colors for 16+ data types (strings, numbers, booleans, null, Date, RegExp, Map, Set, BigInt, Symbol, React elements, etc.)
31
35
  - Dark mode support with automatic color adaptation
32
- - Copy-to-clipboard on individual nodes
36
+ - Copy-to-clipboard on individual nodes + global copy all JSON
33
37
  - Keyboard navigation (arrow keys, Space to expand, Ctrl+C to copy)
34
38
  - Configurable expansion depth with expand/collapse all controls
35
39
  - Controlled expand/collapse state with `expanded` and `onExpandedChange` props
@@ -40,10 +44,10 @@ Wrapped with Mantine layout primitives like Paper, Stack, and SimpleGrid, JsonTr
40
44
  - Sticky header support with configurable offset
41
45
  - Function display modes: as-string, hide, or as-object introspection
42
46
  - Responsive font size via Mantine breakpoint objects (CSS-native, no re-renders)
43
- - Full Mantine Styles API support with 13 style selectors and 25+ CSS variables
47
+ - Full Mantine Styles API support with 21 style selectors and 25+ CSS variables
44
48
  - Custom icons for expand/collapse and copy controls
45
49
  - Item count badges for objects and arrays
46
- - `onExpand`, `onCollapse`, `onNodeClick`, and `onCopy` callbacks
50
+ - `onExpand`, `onCollapse`, `onNodeClick`, `onCopy`, and `onCopyAll` callbacks
47
51
 
48
52
  > [!note]
49
53
  >
@@ -4,11 +4,13 @@
4
4
  var React = require('react');
5
5
  var iconsReact = require('@tabler/icons-react');
6
6
  var core = require('@mantine/core');
7
+ var hooks = require('@mantine/hooks');
7
8
  var JsonTreeMediaVariables = require('./JsonTreeMediaVariables.cjs');
8
9
  var utils = require('./lib/utils.cjs');
9
10
  var JsonTree_module = require('./JsonTree.module.css.cjs');
10
11
 
11
12
  const defaultProps = {
13
+ rootName: "root",
12
14
  defaultExpanded: false,
13
15
  maxDepth: 2,
14
16
  withExpandAll: false,
@@ -19,10 +21,71 @@ const defaultProps = {
19
21
  showPathOnHover: false,
20
22
  stickyHeader: false,
21
23
  displayFunctions: "as-string",
22
- expandAllControlIcon: /* @__PURE__ */ React.createElement(iconsReact.IconLibraryPlus, { size: 16 }),
23
- collapseAllControlIcon: /* @__PURE__ */ React.createElement(iconsReact.IconLibraryMinus, { size: 16 }),
24
- copyToClipboardIcon: /* @__PURE__ */ React.createElement(iconsReact.IconCopy, { size: 12 })
24
+ expandAllControlIcon: /* @__PURE__ */ React.createElement(iconsReact.IconArrowBarToDown, { size: 16 }),
25
+ collapseAllControlIcon: /* @__PURE__ */ React.createElement(iconsReact.IconArrowBarToUp, { size: 16 }),
26
+ copyToClipboardIcon: /* @__PURE__ */ React.createElement(iconsReact.IconCopy, { size: 12 }),
27
+ withBorder: false,
28
+ borderRadius: "sm",
29
+ withKeyCountBadge: false,
30
+ withCopyAll: false,
31
+ withSearch: false,
32
+ copyAllIcon: /* @__PURE__ */ React.createElement(iconsReact.IconCopy, { size: 16 }),
33
+ searchIcon: /* @__PURE__ */ React.createElement(iconsReact.IconSearch, { size: 16 }),
34
+ searchPlaceholder: "Filter keys and values...",
35
+ searchDebounce: 300
25
36
  };
37
+ function highlightText(text, query, getStyles) {
38
+ if (!query) {
39
+ return text;
40
+ }
41
+ const lowerText = text.toLowerCase();
42
+ const lowerQuery = query.toLowerCase();
43
+ const idx = lowerText.indexOf(lowerQuery);
44
+ if (idx === -1) {
45
+ return text;
46
+ }
47
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, text.substring(0, idx), /* @__PURE__ */ React.createElement("span", { ...getStyles("searchHighlight") }, text.substring(idx, idx + query.length)), text.substring(idx + query.length));
48
+ }
49
+ function CopyNodeButton({
50
+ icon,
51
+ getStyles,
52
+ onCopy
53
+ }) {
54
+ const [copied, setCopied] = React.useState(false);
55
+ const timeoutRef = React.useRef(null);
56
+ React.useEffect(() => {
57
+ return () => {
58
+ if (timeoutRef.current) {
59
+ clearTimeout(timeoutRef.current);
60
+ }
61
+ };
62
+ }, []);
63
+ const handleClick = async (e) => {
64
+ const success = await onCopy(e);
65
+ if (!success) {
66
+ return;
67
+ }
68
+ setCopied(true);
69
+ if (timeoutRef.current) {
70
+ clearTimeout(timeoutRef.current);
71
+ }
72
+ timeoutRef.current = setTimeout(() => {
73
+ setCopied(false);
74
+ timeoutRef.current = null;
75
+ }, 1500);
76
+ };
77
+ return /* @__PURE__ */ React.createElement(
78
+ core.ActionIcon,
79
+ {
80
+ size: "xs",
81
+ variant: "subtle",
82
+ color: copied ? "green" : "gray",
83
+ onClick: handleClick,
84
+ ...getStyles("copyButton")
85
+ },
86
+ copied ? /* @__PURE__ */ React.createElement(iconsReact.IconCheck, { size: 12 }) : icon
87
+ );
88
+ }
26
89
  function renderJSONNode({ node, expanded, hasChildren, elementProps, tree }, props, ctx, onNodeClick) {
27
90
  const {
28
91
  getStyles,
@@ -62,7 +125,9 @@ function renderJSONNode({ node, expanded, hasChildren, elementProps, tree }, pro
62
125
  const copy = JSON.stringify(value, null, 2);
63
126
  await navigator.clipboard.writeText(copy);
64
127
  onCopy?.(copy, value);
65
- } catch (error) {
128
+ return true;
129
+ } catch {
130
+ return false;
66
131
  }
67
132
  };
68
133
  const handleClick = () => {
@@ -119,26 +184,21 @@ function renderJSONNode({ node, expanded, hasChildren, elementProps, tree }, pro
119
184
  wrap: "nowrap",
120
185
  ...elementProps,
121
186
  onClick: handleClick,
122
- style: { cursor: onNodeClick ? "pointer" : "default", position: "relative" }
187
+ style: {
188
+ cursor: onNodeClick ? "pointer" : "default",
189
+ position: "relative",
190
+ backgroundColor: ctx.directMatches?.has(node.value) ? "rgba(251, 191, 36, 0.15)" : void 0,
191
+ borderRadius: ctx.directMatches?.has(node.value) ? "4px" : void 0
192
+ }
123
193
  },
124
194
  lineNumber,
125
195
  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") }, ":")),
196
+ key !== void 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("key"), "data-key": key }, ctx.searchQuery ? highlightText(String(key), ctx.searchQuery, getStyles) : key), /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("keyValueSeparator") }, ":")),
127
197
  (() => {
128
198
  const formattedValue = utils.formatValue(value, type);
129
- return /* @__PURE__ */ React.createElement(core.Code, { ...getStyles("value"), "data-type": type, "data-value": formattedValue }, formattedValue);
199
+ return /* @__PURE__ */ React.createElement(core.Code, { ...getStyles("value"), "data-type": type, "data-value": formattedValue }, ctx.searchQuery ? highlightText(formattedValue, ctx.searchQuery, getStyles) : formattedValue);
130
200
  })(),
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
- )
201
+ withCopyToClipboard && /* @__PURE__ */ React.createElement(CopyNodeButton, { icon: copyToClipboardIcon, getStyles, onCopy: handleCopy })
142
202
  )
143
203
  );
144
204
  }
@@ -182,7 +242,12 @@ function renderJSONNode({ node, expanded, hasChildren, elementProps, tree }, pro
182
242
  "data-expanded": expanded,
183
243
  "data-has-children": hasChildren,
184
244
  "data-type": type,
185
- style: { cursor: onNodeClick ? "pointer" : "default", position: "relative" }
245
+ style: {
246
+ cursor: onNodeClick ? "pointer" : "default",
247
+ position: "relative",
248
+ backgroundColor: ctx.directMatches?.has(node.value) ? "rgba(251, 191, 36, 0.15)" : void 0,
249
+ borderRadius: ctx.directMatches?.has(node.value) ? "4px" : void 0
250
+ }
186
251
  },
187
252
  lineNumber,
188
253
  renderIndentGuides(),
@@ -196,7 +261,7 @@ function renderJSONNode({ node, expanded, hasChildren, elementProps, tree }, pro
196
261
  },
197
262
  expandCollapseIcon
198
263
  ),
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") }, ":")),
264
+ key !== void 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("key") }, ctx.searchQuery ? highlightText(String(key), ctx.searchQuery, getStyles) : key), /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("keyValueSeparator") }, ":")),
200
265
  /* @__PURE__ */ React.createElement(core.Text, { component: "span", ...getStyles("bracket") }, openBracket),
201
266
  !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
267
  withCopyToClipboard && /* @__PURE__ */ React.createElement(
@@ -257,7 +322,17 @@ const varsResolver = core.createVarsResolver(
257
322
  lineNumber: { "--json-tree-color-line-number": "var(--mantine-color-gray-5)" },
258
323
  itemsCount: {},
259
324
  controls: {},
260
- copyButton: {}
325
+ copyButton: {},
326
+ paper: {},
327
+ toolbar: {},
328
+ keyCountBadge: {},
329
+ copyAllButton: {},
330
+ searchToggle: {},
331
+ searchBar: {},
332
+ searchInput: {},
333
+ searchHighlight: {
334
+ "--json-tree-search-highlight-color": "var(--mantine-color-yellow-3)"
335
+ }
261
336
  };
262
337
  }
263
338
  );
@@ -265,6 +340,7 @@ const JsonTree = core.factory((_props) => {
265
340
  const props = core.useProps("JsonTree", defaultProps, _props);
266
341
  const {
267
342
  data,
343
+ rootName,
268
344
  defaultExpanded,
269
345
  maxDepth,
270
346
  onNodeClick,
@@ -291,6 +367,20 @@ const JsonTree = core.factory((_props) => {
291
367
  expandControlIcon,
292
368
  collapseControlIcon,
293
369
  size,
370
+ withBorder,
371
+ borderRadius,
372
+ withKeyCountBadge,
373
+ keyCountBadgeLabel,
374
+ withCopyAll,
375
+ copyAllIcon,
376
+ onCopyAll,
377
+ withSearch,
378
+ searchIcon,
379
+ searchPlaceholder,
380
+ searchQuery: controlledSearchQuery,
381
+ onSearchChange,
382
+ searchDebounce,
383
+ searchInputProps,
294
384
  classNames,
295
385
  style,
296
386
  styles,
@@ -313,8 +403,8 @@ const JsonTree = core.factory((_props) => {
313
403
  });
314
404
  const responsiveClassName = core.useRandomClassName();
315
405
  const treeData = React.useMemo(
316
- () => [utils.convertToTreeData(data, void 0, "root", 0, displayFunctions)],
317
- [data, displayFunctions]
406
+ () => [utils.convertToTreeData(data, rootName ?? "root", rootName ?? "root", 0, displayFunctions)],
407
+ [data, rootName, displayFunctions]
318
408
  );
319
409
  const initialExpandedState = React.useMemo(() => {
320
410
  if (controlledExpanded) {
@@ -379,6 +469,83 @@ const JsonTree = core.factory((_props) => {
379
469
  },
380
470
  [withCopyToClipboard, treeData, onCopy]
381
471
  );
472
+ const totalKeyCount = React.useMemo(() => utils.getItemCount(data), [data]);
473
+ const [searchOpen, setSearchOpen] = React.useState(false);
474
+ const [searchQueryInternal, setSearchQueryInternal] = React.useState("");
475
+ const activeSearchQuery = controlledSearchQuery ?? searchQueryInternal ?? "";
476
+ const [debouncedQuery] = hooks.useDebouncedValue(activeSearchQuery, searchDebounce ?? 300);
477
+ const preSearchExpandedRef = React.useRef(null);
478
+ const searchResults = React.useMemo(
479
+ () => utils.searchTree(treeData, debouncedQuery),
480
+ [treeData, debouncedQuery]
481
+ );
482
+ const filteredTreeData = React.useMemo(() => {
483
+ if (!debouncedQuery || searchResults.matchedPaths.size === 0) {
484
+ return treeData;
485
+ }
486
+ return utils.filterTreeBySearch(treeData, searchResults.matchedPaths);
487
+ }, [treeData, debouncedQuery, searchResults]);
488
+ React.useEffect(() => {
489
+ if (debouncedQuery && searchResults.expandedPaths.length > 0) {
490
+ if (!preSearchExpandedRef.current) {
491
+ preSearchExpandedRef.current = { ...tree.expandedState };
492
+ }
493
+ const newState = {};
494
+ searchResults.expandedPaths.forEach((p) => {
495
+ newState[p] = true;
496
+ });
497
+ if (onExpandedChange) {
498
+ onExpandedChange(Object.keys(newState).filter((k) => newState[k]));
499
+ } else {
500
+ tree.setExpandedState(newState);
501
+ }
502
+ }
503
+ }, [debouncedQuery, searchResults]);
504
+ const handleClearSearch = React.useCallback(() => {
505
+ setSearchQueryInternal("");
506
+ onSearchChange?.("");
507
+ if (preSearchExpandedRef.current) {
508
+ if (onExpandedChange) {
509
+ onExpandedChange(
510
+ Object.keys(preSearchExpandedRef.current).filter((k) => preSearchExpandedRef.current[k])
511
+ );
512
+ } else {
513
+ tree.setExpandedState(preSearchExpandedRef.current);
514
+ }
515
+ preSearchExpandedRef.current = null;
516
+ }
517
+ }, [onExpandedChange, onSearchChange, tree]);
518
+ const handleCloseSearch = React.useCallback(() => {
519
+ setSearchOpen(false);
520
+ handleClearSearch();
521
+ }, [handleClearSearch]);
522
+ const handleExpandAll = React.useCallback(() => {
523
+ const allState = core.getTreeExpandedState(treeData, "*");
524
+ if (onExpandedChange) {
525
+ onExpandedChange(Object.keys(allState).filter((k) => allState[k]));
526
+ } else {
527
+ tree.expandAllNodes();
528
+ }
529
+ }, [treeData, onExpandedChange, tree]);
530
+ const handleCollapseAll = React.useCallback(() => {
531
+ if (onExpandedChange) {
532
+ onExpandedChange([]);
533
+ } else {
534
+ tree.collapseAllNodes();
535
+ }
536
+ }, [onExpandedChange, tree]);
537
+ const [copiedAll, setCopiedAll] = React.useState(false);
538
+ const handleCopyAll = React.useCallback(async () => {
539
+ try {
540
+ const json = JSON.stringify(data, null, 2);
541
+ await navigator.clipboard.writeText(json);
542
+ onCopyAll?.(json);
543
+ onCopy?.(json, data);
544
+ setCopiedAll(true);
545
+ setTimeout(() => setCopiedAll(false), 1500);
546
+ } catch {
547
+ }
548
+ }, [data, onCopyAll, onCopy]);
382
549
  const renderCtx = {
383
550
  getStyles,
384
551
  copyToClipboardIcon,
@@ -386,59 +553,103 @@ const JsonTree = core.factory((_props) => {
386
553
  collapseControlIcon,
387
554
  onExpand,
388
555
  onCollapse,
389
- onExpandedChange
556
+ onExpandedChange,
557
+ searchQuery: debouncedQuery || void 0,
558
+ matchedPaths: debouncedQuery ? searchResults.matchedPaths : void 0,
559
+ directMatches: debouncedQuery ? searchResults.directMatches : void 0
390
560
  };
391
561
  const treeComponent = /* @__PURE__ */ React.createElement(
392
562
  core.Tree,
393
563
  {
394
- data: treeData,
564
+ data: filteredTreeData,
395
565
  tree,
396
566
  levelOffset: 32,
397
567
  renderNode: (payload) => renderJSONNode(payload, props, renderCtx, onNodeClick)
398
568
  }
399
569
  );
400
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(JsonTreeMediaVariables.JsonTreeMediaVariables, { size, selector: `.${responsiveClassName}` }), /* @__PURE__ */ React.createElement(
570
+ const showHeader = title || withExpandAll || withKeyCountBadge || withCopyAll || withSearch;
571
+ const content = /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(JsonTreeMediaVariables.JsonTreeMediaVariables, { size, selector: `.${responsiveClassName}` }), /* @__PURE__ */ React.createElement(
401
572
  core.Box,
402
573
  {
403
574
  ...getStyles("root", { className: responsiveClassName }),
404
575
  ...others,
405
576
  "data-line-numbers": showLineNumbers || void 0,
577
+ "data-searching": debouncedQuery ? true : void 0,
406
578
  onKeyDown: handleKeyDown
407
579
  },
408
- (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(
580
+ showHeader && /* @__PURE__ */ React.createElement(core.Group, { ...getStyles("header"), justify: "space-between", mod: { sticky: stickyHeader } }, /* @__PURE__ */ React.createElement(core.Group, { gap: "xs" }, title || /* @__PURE__ */ React.createElement("div", null), withKeyCountBadge && utils.isExpandable(data) && /* @__PURE__ */ React.createElement(core.Badge, { size: "sm", variant: "light", color: "gray", ...getStyles("keyCountBadge") }, keyCountBadgeLabel ? keyCountBadgeLabel(totalKeyCount) : `${totalKeyCount} ${Array.isArray(data) ? "items" : "keys"}`)), /* @__PURE__ */ React.createElement(core.Group, { gap: 4, ...getStyles("toolbar") }, withSearch && /* @__PURE__ */ React.createElement(
409
581
  core.ActionIcon,
410
582
  {
411
- size: "xs",
412
- variant: "transparent",
583
+ size: "sm",
584
+ variant: searchOpen ? "light" : "subtle",
585
+ color: "gray",
413
586
  onClick: () => {
414
- const allState = core.getTreeExpandedState(treeData, "*");
415
- if (onExpandedChange) {
416
- onExpandedChange(Object.keys(allState).filter((k) => allState[k]));
587
+ if (searchOpen) {
588
+ handleCloseSearch();
417
589
  } else {
418
- tree.expandAllNodes();
590
+ setSearchOpen(true);
419
591
  }
420
592
  },
593
+ ...getStyles("searchToggle")
594
+ },
595
+ searchIcon
596
+ ), withExpandAll && utils.isExpandable(data) && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
597
+ core.ActionIcon,
598
+ {
599
+ size: "sm",
600
+ variant: "subtle",
601
+ color: "gray",
602
+ onClick: handleExpandAll,
421
603
  ...getStyles("controls")
422
604
  },
423
605
  expandAllControlIcon
424
606
  ), /* @__PURE__ */ React.createElement(
425
607
  core.ActionIcon,
426
608
  {
427
- size: "xs",
428
- variant: "transparent",
429
- onClick: () => {
430
- if (onExpandedChange) {
431
- onExpandedChange([]);
432
- } else {
433
- tree.collapseAllNodes();
434
- }
435
- },
609
+ size: "sm",
610
+ variant: "subtle",
611
+ color: "gray",
612
+ onClick: handleCollapseAll,
436
613
  ...getStyles("controls")
437
614
  },
438
615
  collapseAllControlIcon
616
+ )), withCopyAll && /* @__PURE__ */ React.createElement(
617
+ core.ActionIcon,
618
+ {
619
+ size: "sm",
620
+ variant: "subtle",
621
+ color: copiedAll ? "green" : "gray",
622
+ onClick: handleCopyAll,
623
+ ...getStyles("copyAllButton")
624
+ },
625
+ copiedAll ? /* @__PURE__ */ React.createElement(iconsReact.IconCheck, { size: 16 }) : copyAllIcon
626
+ ))),
627
+ searchOpen && withSearch && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(core.Divider, null), /* @__PURE__ */ React.createElement(core.Box, { ...getStyles("searchBar"), p: "xs" }, /* @__PURE__ */ React.createElement(
628
+ core.TextInput,
629
+ {
630
+ placeholder: searchPlaceholder,
631
+ size: "sm",
632
+ leftSection: /* @__PURE__ */ React.createElement(iconsReact.IconSearch, { size: 14 }),
633
+ rightSection: activeSearchQuery ? /* @__PURE__ */ React.createElement(core.CloseButton, { size: "sm", onClick: handleClearSearch }) : null,
634
+ ...searchInputProps,
635
+ ...getStyles("searchInput", {
636
+ className: searchInputProps?.className,
637
+ style: searchInputProps?.style
638
+ }),
639
+ value: activeSearchQuery,
640
+ onChange: (e) => {
641
+ const val = e.currentTarget.value;
642
+ setSearchQueryInternal(val);
643
+ onSearchChange?.(val);
644
+ }
645
+ }
439
646
  ))),
440
647
  maxHeight ? /* @__PURE__ */ React.createElement(core.ScrollArea.Autosize, { mah: maxHeight }, treeComponent) : treeComponent
441
648
  ));
649
+ if (withBorder) {
650
+ return /* @__PURE__ */ React.createElement(core.Paper, { withBorder: true, radius: borderRadius, ...getStyles("paper") }, content);
651
+ }
652
+ return content;
442
653
  });
443
654
  JsonTree.classes = JsonTree_module;
444
655
  JsonTree.displayName = "JsonTree";