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