diff --git a/src/layout/Tree/JsonTree/JsonTree.story.tsx b/src/layout/Tree/JsonTree/JsonTree.story.tsx
index 33f5a75a..cc784bb0 100644
--- a/src/layout/Tree/JsonTree/JsonTree.story.tsx
+++ b/src/layout/Tree/JsonTree/JsonTree.story.tsx
@@ -9,6 +9,7 @@ export default {
const data = {
name: 'John Doe',
age: 30,
+ over21: true,
children: [
{ name: 'Jane Doe', age: 25 },
{ name: 'Jim Doe', age: 33 }
@@ -16,3 +17,5 @@ const data = {
};
export const Simple = () => ;
+
+export const Expanded = () => ;
diff --git a/src/layout/Tree/JsonTree/JsonTree.tsx b/src/layout/Tree/JsonTree/JsonTree.tsx
index 7ca62994..032d92a8 100644
--- a/src/layout/Tree/JsonTree/JsonTree.tsx
+++ b/src/layout/Tree/JsonTree/JsonTree.tsx
@@ -1,32 +1,38 @@
import React, { FC } from 'react';
import { Tree } from '../Tree';
import { JsonTreeNode } from './JsonTreeNode';
+import { parseJsonTree } from './utils';
export interface JsonTreeProps {
data: { [key: string]: any };
- root?: boolean;
- allowCopy?: boolean;
showAll?: boolean;
showAllLimit?: number;
showAllThreshold?: number;
- showCount: boolean;
- showEmpty: boolean;
+ showCount?: boolean;
+ showEmpty?: boolean;
ellipsisText?: boolean;
ellipsisTextLength?: number;
- expandDepth: number;
+ expandDepth?: number;
className?: string;
}
export const JsonTree: FC = ({
data,
- root,
className,
+ expandDepth,
...rest
}) => {
+ const tree = parseJsonTree({ data });
+
return (
- {root && }
+
);
@@ -40,6 +46,5 @@ JsonTree.defaultProps = {
showEmpty: true,
ellipsisText: true,
ellipsisTextLength: 150,
- expandDepth: 2,
- root: true
+ expandDepth: 2
};
diff --git a/src/layout/Tree/JsonTree/JsonTreeNode.tsx b/src/layout/Tree/JsonTree/JsonTreeNode.tsx
index 78f6ca33..10d5a19f 100644
--- a/src/layout/Tree/JsonTree/JsonTreeNode.tsx
+++ b/src/layout/Tree/JsonTree/JsonTreeNode.tsx
@@ -1,28 +1,39 @@
-import React, { FC, PropsWithChildren, useCallback } from 'react';
+import React, { FC, useCallback } from 'react';
import { TreeNode } from '../TreeNode';
+import { JsonTreeData } from './utils';
-export interface JsonTreeNodeProps extends PropsWithChildren {
- data?: any;
+export interface JsonTreeNodeProps {
+ data?: JsonTreeData;
className?: string;
- index?: number;
depth?: number;
expandDepth?: number;
- type?: string;
}
export const JsonTreeNode: FC = ({
depth,
- children,
- type,
+ data,
expandDepth
}) => {
+ const type = data.type;
+
const renderExpandableNode = useCallback(() => {
- return hi
;
- }, []);
+ const label = type === 'array' ? 'items' : 'keys';
+ return (
+
+ {data.label}
+ {` (${data.data.length.toLocaleString()} ${label})`}
+
+ );
+ }, [data]);
const renderPrimativeNode = useCallback(() => {
- return hi
;
- }, []);
+ return (
+
+ {data.label}
+ {`: ${data.data}`}
+
+ );
+ }, [data]);
return (
= ({
}
>
- {children}
+ {(data.type === 'array' || data.type === 'object') && (
+ <>
+ {data.data.map(item => (
+
+ ))}
+ >
+ )}
);
};
diff --git a/src/layout/Tree/JsonTree/JsonTreeTheme.ts b/src/layout/Tree/JsonTree/JsonTreeTheme.ts
new file mode 100644
index 00000000..ed72d658
--- /dev/null
+++ b/src/layout/Tree/JsonTree/JsonTreeTheme.ts
@@ -0,0 +1,15 @@
+export interface JsonTreeTheme {
+ node: {
+ label: string;
+ value: string;
+ count: string;
+ };
+}
+
+const baseTheme: JsonTreeTheme = {
+ node: {
+ label: 'font-mono opacity-70',
+ value: '',
+ count: ''
+ }
+};
diff --git a/src/layout/Tree/JsonTree/index.ts b/src/layout/Tree/JsonTree/index.ts
index e69de29b..5540078d 100644
--- a/src/layout/Tree/JsonTree/index.ts
+++ b/src/layout/Tree/JsonTree/index.ts
@@ -0,0 +1,3 @@
+export * from './JsonTree';
+export * from './JsonTreeNode';
+export * from './JsonTreeTheme';
diff --git a/src/layout/Tree/JsonTree/utils.ts b/src/layout/Tree/JsonTree/utils.ts
index e69de29b..81716d04 100644
--- a/src/layout/Tree/JsonTree/utils.ts
+++ b/src/layout/Tree/JsonTree/utils.ts
@@ -0,0 +1,102 @@
+function getDataType(data: any) {
+ if (data === null || data === undefined) {
+ return 'nil';
+ }
+
+ if (data instanceof Date) {
+ return 'date';
+ }
+
+ if (Array.isArray(data)) {
+ return 'array';
+ }
+
+ if (data != null && data.constructor.name === 'Object') {
+ return 'object';
+ }
+
+ if (typeof data === 'string') {
+ return 'string';
+ }
+
+ if (typeof data === 'number') {
+ return 'number';
+ }
+
+ if (typeof data === 'boolean') {
+ return 'boolean';
+ }
+
+ return 'unknown';
+}
+
+export interface ParseJsonInputs {
+ data: any;
+ id?: string;
+ label?: string;
+ index?: number;
+ showEmpty?: boolean;
+}
+
+export interface JsonTreeData {
+ type: string;
+ id: string;
+ data: any;
+ label: string;
+ index?: number;
+}
+
+export function parseJsonTree({
+ id = 'root',
+ data,
+ index,
+ label,
+ showEmpty = true
+}: ParseJsonInputs): JsonTreeData {
+ const type = getDataType(data);
+
+ if (type === 'object') {
+ const keys = Object.keys(data);
+ const result = keys.reduce((parsedItems, key, idx) => {
+ const value = data[key];
+ const childParsed = parseJsonTree({
+ data: value,
+ id: `${id}.${key}`,
+ index: idx,
+ label: key
+ });
+ if (showEmpty || (!showEmpty && childParsed !== null)) {
+ parsedItems.push(childParsed);
+ }
+ return parsedItems;
+ }, []);
+
+ return {
+ type,
+ id,
+ data: result,
+ label: index !== undefined ? `${index}` : 'root',
+ index
+ };
+ } else if (type === 'array') {
+ const result = data.map((item, idx) =>
+ parseJsonTree({ data: item, id: `${id}[${idx}]`, index: idx })
+ );
+
+ return {
+ type,
+ id,
+ data: result,
+ label,
+ index
+ };
+ } else {
+ return {
+ type,
+ id,
+ data,
+ label,
+ index
+ };
+ }
+}
diff --git a/src/layout/Tree/index.tsx b/src/layout/Tree/index.tsx
index c37697f1..7ba552c0 100644
--- a/src/layout/Tree/index.tsx
+++ b/src/layout/Tree/index.tsx
@@ -1,3 +1,4 @@
export * from './Tree';
export * from './TreeNode';
export * from './TreeTheme';
+export * from './JsonTree';