@gfazioli/mantine-json-tree 3.0.0 → 3.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 +7 -3
- package/dist/cjs/JsonTree.cjs +248 -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 +252 -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 +38 -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,19 @@ 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,
|
|
294
383
|
classNames,
|
|
295
384
|
style,
|
|
296
385
|
styles,
|
|
@@ -313,8 +402,8 @@ const JsonTree = core.factory((_props) => {
|
|
|
313
402
|
});
|
|
314
403
|
const responsiveClassName = core.useRandomClassName();
|
|
315
404
|
const treeData = React.useMemo(
|
|
316
|
-
() => [utils.convertToTreeData(data,
|
|
317
|
-
[data, displayFunctions]
|
|
405
|
+
() => [utils.convertToTreeData(data, rootName ?? "root", rootName ?? "root", 0, displayFunctions)],
|
|
406
|
+
[data, rootName, displayFunctions]
|
|
318
407
|
);
|
|
319
408
|
const initialExpandedState = React.useMemo(() => {
|
|
320
409
|
if (controlledExpanded) {
|
|
@@ -379,6 +468,83 @@ const JsonTree = core.factory((_props) => {
|
|
|
379
468
|
},
|
|
380
469
|
[withCopyToClipboard, treeData, onCopy]
|
|
381
470
|
);
|
|
471
|
+
const totalKeyCount = React.useMemo(() => utils.getItemCount(data), [data]);
|
|
472
|
+
const [searchOpen, setSearchOpen] = React.useState(false);
|
|
473
|
+
const [searchQueryInternal, setSearchQueryInternal] = React.useState("");
|
|
474
|
+
const activeSearchQuery = controlledSearchQuery ?? searchQueryInternal ?? "";
|
|
475
|
+
const [debouncedQuery] = hooks.useDebouncedValue(activeSearchQuery, searchDebounce ?? 300);
|
|
476
|
+
const preSearchExpandedRef = React.useRef(null);
|
|
477
|
+
const searchResults = React.useMemo(
|
|
478
|
+
() => utils.searchTree(treeData, debouncedQuery),
|
|
479
|
+
[treeData, debouncedQuery]
|
|
480
|
+
);
|
|
481
|
+
const filteredTreeData = React.useMemo(() => {
|
|
482
|
+
if (!debouncedQuery || searchResults.matchedPaths.size === 0) {
|
|
483
|
+
return treeData;
|
|
484
|
+
}
|
|
485
|
+
return utils.filterTreeBySearch(treeData, searchResults.matchedPaths);
|
|
486
|
+
}, [treeData, debouncedQuery, searchResults]);
|
|
487
|
+
React.useEffect(() => {
|
|
488
|
+
if (debouncedQuery && searchResults.expandedPaths.length > 0) {
|
|
489
|
+
if (!preSearchExpandedRef.current) {
|
|
490
|
+
preSearchExpandedRef.current = { ...tree.expandedState };
|
|
491
|
+
}
|
|
492
|
+
const newState = {};
|
|
493
|
+
searchResults.expandedPaths.forEach((p) => {
|
|
494
|
+
newState[p] = true;
|
|
495
|
+
});
|
|
496
|
+
if (onExpandedChange) {
|
|
497
|
+
onExpandedChange(Object.keys(newState).filter((k) => newState[k]));
|
|
498
|
+
} else {
|
|
499
|
+
tree.setExpandedState(newState);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}, [debouncedQuery, searchResults]);
|
|
503
|
+
const handleClearSearch = React.useCallback(() => {
|
|
504
|
+
setSearchQueryInternal("");
|
|
505
|
+
onSearchChange?.("");
|
|
506
|
+
if (preSearchExpandedRef.current) {
|
|
507
|
+
if (onExpandedChange) {
|
|
508
|
+
onExpandedChange(
|
|
509
|
+
Object.keys(preSearchExpandedRef.current).filter((k) => preSearchExpandedRef.current[k])
|
|
510
|
+
);
|
|
511
|
+
} else {
|
|
512
|
+
tree.setExpandedState(preSearchExpandedRef.current);
|
|
513
|
+
}
|
|
514
|
+
preSearchExpandedRef.current = null;
|
|
515
|
+
}
|
|
516
|
+
}, [onExpandedChange, onSearchChange, tree]);
|
|
517
|
+
const handleCloseSearch = React.useCallback(() => {
|
|
518
|
+
setSearchOpen(false);
|
|
519
|
+
handleClearSearch();
|
|
520
|
+
}, [handleClearSearch]);
|
|
521
|
+
const handleExpandAll = React.useCallback(() => {
|
|
522
|
+
const allState = core.getTreeExpandedState(treeData, "*");
|
|
523
|
+
if (onExpandedChange) {
|
|
524
|
+
onExpandedChange(Object.keys(allState).filter((k) => allState[k]));
|
|
525
|
+
} else {
|
|
526
|
+
tree.expandAllNodes();
|
|
527
|
+
}
|
|
528
|
+
}, [treeData, onExpandedChange, tree]);
|
|
529
|
+
const handleCollapseAll = React.useCallback(() => {
|
|
530
|
+
if (onExpandedChange) {
|
|
531
|
+
onExpandedChange([]);
|
|
532
|
+
} else {
|
|
533
|
+
tree.collapseAllNodes();
|
|
534
|
+
}
|
|
535
|
+
}, [onExpandedChange, tree]);
|
|
536
|
+
const [copiedAll, setCopiedAll] = React.useState(false);
|
|
537
|
+
const handleCopyAll = React.useCallback(async () => {
|
|
538
|
+
try {
|
|
539
|
+
const json = JSON.stringify(data, null, 2);
|
|
540
|
+
await navigator.clipboard.writeText(json);
|
|
541
|
+
onCopyAll?.(json);
|
|
542
|
+
onCopy?.(json, data);
|
|
543
|
+
setCopiedAll(true);
|
|
544
|
+
setTimeout(() => setCopiedAll(false), 1500);
|
|
545
|
+
} catch {
|
|
546
|
+
}
|
|
547
|
+
}, [data, onCopyAll, onCopy]);
|
|
382
548
|
const renderCtx = {
|
|
383
549
|
getStyles,
|
|
384
550
|
copyToClipboardIcon,
|
|
@@ -386,59 +552,99 @@ const JsonTree = core.factory((_props) => {
|
|
|
386
552
|
collapseControlIcon,
|
|
387
553
|
onExpand,
|
|
388
554
|
onCollapse,
|
|
389
|
-
onExpandedChange
|
|
555
|
+
onExpandedChange,
|
|
556
|
+
searchQuery: debouncedQuery || void 0,
|
|
557
|
+
matchedPaths: debouncedQuery ? searchResults.matchedPaths : void 0,
|
|
558
|
+
directMatches: debouncedQuery ? searchResults.directMatches : void 0
|
|
390
559
|
};
|
|
391
560
|
const treeComponent = /* @__PURE__ */ React.createElement(
|
|
392
561
|
core.Tree,
|
|
393
562
|
{
|
|
394
|
-
data:
|
|
563
|
+
data: filteredTreeData,
|
|
395
564
|
tree,
|
|
396
565
|
levelOffset: 32,
|
|
397
566
|
renderNode: (payload) => renderJSONNode(payload, props, renderCtx, onNodeClick)
|
|
398
567
|
}
|
|
399
568
|
);
|
|
400
|
-
|
|
569
|
+
const showHeader = title || withExpandAll || withKeyCountBadge || withCopyAll || withSearch;
|
|
570
|
+
const content = /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(JsonTreeMediaVariables.JsonTreeMediaVariables, { size, selector: `.${responsiveClassName}` }), /* @__PURE__ */ React.createElement(
|
|
401
571
|
core.Box,
|
|
402
572
|
{
|
|
403
573
|
...getStyles("root", { className: responsiveClassName }),
|
|
404
574
|
...others,
|
|
405
575
|
"data-line-numbers": showLineNumbers || void 0,
|
|
576
|
+
"data-searching": debouncedQuery ? true : void 0,
|
|
406
577
|
onKeyDown: handleKeyDown
|
|
407
578
|
},
|
|
408
|
-
|
|
579
|
+
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
580
|
core.ActionIcon,
|
|
410
581
|
{
|
|
411
|
-
size: "
|
|
412
|
-
variant: "
|
|
582
|
+
size: "sm",
|
|
583
|
+
variant: searchOpen ? "light" : "subtle",
|
|
584
|
+
color: "gray",
|
|
413
585
|
onClick: () => {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
onExpandedChange(Object.keys(allState).filter((k) => allState[k]));
|
|
586
|
+
if (searchOpen) {
|
|
587
|
+
handleCloseSearch();
|
|
417
588
|
} else {
|
|
418
|
-
|
|
589
|
+
setSearchOpen(true);
|
|
419
590
|
}
|
|
420
591
|
},
|
|
592
|
+
...getStyles("searchToggle")
|
|
593
|
+
},
|
|
594
|
+
searchIcon
|
|
595
|
+
), withExpandAll && utils.isExpandable(data) && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
596
|
+
core.ActionIcon,
|
|
597
|
+
{
|
|
598
|
+
size: "sm",
|
|
599
|
+
variant: "subtle",
|
|
600
|
+
color: "gray",
|
|
601
|
+
onClick: handleExpandAll,
|
|
421
602
|
...getStyles("controls")
|
|
422
603
|
},
|
|
423
604
|
expandAllControlIcon
|
|
424
605
|
), /* @__PURE__ */ React.createElement(
|
|
425
606
|
core.ActionIcon,
|
|
426
607
|
{
|
|
427
|
-
size: "
|
|
428
|
-
variant: "
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
onExpandedChange([]);
|
|
432
|
-
} else {
|
|
433
|
-
tree.collapseAllNodes();
|
|
434
|
-
}
|
|
435
|
-
},
|
|
608
|
+
size: "sm",
|
|
609
|
+
variant: "subtle",
|
|
610
|
+
color: "gray",
|
|
611
|
+
onClick: handleCollapseAll,
|
|
436
612
|
...getStyles("controls")
|
|
437
613
|
},
|
|
438
614
|
collapseAllControlIcon
|
|
615
|
+
)), withCopyAll && /* @__PURE__ */ React.createElement(
|
|
616
|
+
core.ActionIcon,
|
|
617
|
+
{
|
|
618
|
+
size: "sm",
|
|
619
|
+
variant: "subtle",
|
|
620
|
+
color: copiedAll ? "green" : "gray",
|
|
621
|
+
onClick: handleCopyAll,
|
|
622
|
+
...getStyles("copyAllButton")
|
|
623
|
+
},
|
|
624
|
+
copiedAll ? /* @__PURE__ */ React.createElement(iconsReact.IconCheck, { size: 16 }) : copyAllIcon
|
|
625
|
+
))),
|
|
626
|
+
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(
|
|
627
|
+
core.TextInput,
|
|
628
|
+
{
|
|
629
|
+
placeholder: searchPlaceholder,
|
|
630
|
+
value: activeSearchQuery,
|
|
631
|
+
onChange: (e) => {
|
|
632
|
+
const val = e.currentTarget.value;
|
|
633
|
+
setSearchQueryInternal(val);
|
|
634
|
+
onSearchChange?.(val);
|
|
635
|
+
},
|
|
636
|
+
leftSection: /* @__PURE__ */ React.createElement(iconsReact.IconSearch, { size: 14 }),
|
|
637
|
+
rightSection: activeSearchQuery ? /* @__PURE__ */ React.createElement(core.CloseButton, { size: "sm", onClick: handleClearSearch }) : null,
|
|
638
|
+
size: "sm",
|
|
639
|
+
...getStyles("searchInput")
|
|
640
|
+
}
|
|
439
641
|
))),
|
|
440
642
|
maxHeight ? /* @__PURE__ */ React.createElement(core.ScrollArea.Autosize, { mah: maxHeight }, treeComponent) : treeComponent
|
|
441
643
|
));
|
|
644
|
+
if (withBorder) {
|
|
645
|
+
return /* @__PURE__ */ React.createElement(core.Paper, { withBorder: true, radius: borderRadius, ...getStyles("paper") }, content);
|
|
646
|
+
}
|
|
647
|
+
return content;
|
|
442
648
|
});
|
|
443
649
|
JsonTree.classes = JsonTree_module;
|
|
444
650
|
JsonTree.displayName = "JsonTree";
|