@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 +7 -3
- package/dist/cjs/JsonTree.cjs +253 -42
- package/dist/cjs/JsonTree.cjs.map +1 -1
- package/dist/cjs/JsonTree.module.css.cjs +1 -1
- package/dist/cjs/lib/utils.cjs +70 -5
- package/dist/cjs/lib/utils.cjs.map +1 -1
- package/dist/esm/JsonTree.mjs +257 -46
- package/dist/esm/JsonTree.mjs.map +1 -1
- package/dist/esm/JsonTree.module.css.mjs +1 -1
- package/dist/esm/lib/utils.mjs +69 -6
- package/dist/esm/lib/utils.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.layer.css +1 -1
- package/dist/types/JsonTree.d.ts +58 -2
- package/dist/types/lib/utils.d.ts +20 -0
- package/package.json +1 -1
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
|
|
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 `
|
|
50
|
+
- `onExpand`, `onCollapse`, `onNodeClick`, `onCopy`, and `onCopyAll` callbacks
|
|
47
51
|
|
|
48
52
|
> [!note]
|
|
49
53
|
>
|
package/dist/cjs/JsonTree.cjs
CHANGED
|
@@ -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.
|
|
23
|
-
collapseAllControlIcon: /* @__PURE__ */ React.createElement(iconsReact.
|
|
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
|
-
|
|
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: {
|
|
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: {
|
|
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,
|
|
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:
|
|
564
|
+
data: filteredTreeData,
|
|
395
565
|
tree,
|
|
396
566
|
levelOffset: 32,
|
|
397
567
|
renderNode: (payload) => renderJSONNode(payload, props, renderCtx, onNodeClick)
|
|
398
568
|
}
|
|
399
569
|
);
|
|
400
|
-
|
|
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
|
-
|
|
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: "
|
|
412
|
-
variant: "
|
|
583
|
+
size: "sm",
|
|
584
|
+
variant: searchOpen ? "light" : "subtle",
|
|
585
|
+
color: "gray",
|
|
413
586
|
onClick: () => {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
onExpandedChange(Object.keys(allState).filter((k) => allState[k]));
|
|
587
|
+
if (searchOpen) {
|
|
588
|
+
handleCloseSearch();
|
|
417
589
|
} else {
|
|
418
|
-
|
|
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: "
|
|
428
|
-
variant: "
|
|
429
|
-
|
|
430
|
-
|
|
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";
|