Skip to content

Commit

Permalink
json tree continued
Browse files Browse the repository at this point in the history
  • Loading branch information
amcdnl committed Apr 16, 2024
1 parent 3d8427d commit 0b045c4
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 21 deletions.
3 changes: 3 additions & 0 deletions src/layout/Tree/JsonTree/JsonTree.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ export default {
const data = {
name: 'John Doe',
age: 30,
over21: true,
children: [
{ name: 'Jane Doe', age: 25 },
{ name: 'Jim Doe', age: 33 }
]
};

export const Simple = () => <JsonTree data={data} />;

export const Expanded = () => <JsonTree data={data} expandDepth={Infinity} />;
23 changes: 14 additions & 9 deletions src/layout/Tree/JsonTree/JsonTree.tsx
Original file line number Diff line number Diff line change
@@ -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<JsonTreeProps> = ({
data,
root,
className,
expandDepth,
...rest
}) => {
const tree = parseJsonTree({ data });

return (
<div tabIndex={-1}>
<Tree className={className} {...rest}>
{root && <JsonTreeNode index={0} depth={1} />}
<JsonTreeNode
key={`node-${tree.id}`}
depth={1}
data={tree}
expandDepth={expandDepth}
/>
</Tree>
</div>
);
Expand All @@ -40,6 +46,5 @@ JsonTree.defaultProps = {
showEmpty: true,
ellipsisText: true,
ellipsisTextLength: 150,
expandDepth: 2,
root: true
expandDepth: 2
};
47 changes: 35 additions & 12 deletions src/layout/Tree/JsonTree/JsonTreeNode.tsx
Original file line number Diff line number Diff line change
@@ -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<JsonTreeNodeProps> = ({
depth,
children,
type,
data,
expandDepth
}) => {
const type = data.type;

const renderExpandableNode = useCallback(() => {
return <div>hi</div>;
}, []);
const label = type === 'array' ? 'items' : 'keys';
return (
<span>
<span className="font-mono opacity-70">{data.label}</span>
<span>{` (${data.data.length.toLocaleString()} ${label})`}</span>
</span>
);
}, [data]);

const renderPrimativeNode = useCallback(() => {
return <div>hi</div>;
}, []);
return (
<span>
<span className="font-mono opacity-70">{data.label}</span>
<span>{`: ${data.data}`}</span>
</span>
);
}, [data]);

return (
<TreeNode
Expand All @@ -35,7 +46,19 @@ export const JsonTreeNode: FC<JsonTreeNodeProps> = ({
</span>
}
>
{children}
{(data.type === 'array' || data.type === 'object') && (
<>
{data.data.map(item => (
<JsonTreeNode
key={item.id}
data={item}
depth={depth + 1}
expandDepth={expandDepth}
type={item.type}
/>
))}
</>
)}
</TreeNode>
);
};
15 changes: 15 additions & 0 deletions src/layout/Tree/JsonTree/JsonTreeTheme.ts
Original file line number Diff line number Diff line change
@@ -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: ''
}
};
3 changes: 3 additions & 0 deletions src/layout/Tree/JsonTree/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './JsonTree';
export * from './JsonTreeNode';
export * from './JsonTreeTheme';
102 changes: 102 additions & 0 deletions src/layout/Tree/JsonTree/utils.ts
Original file line number Diff line number Diff line change
@@ -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
};
}
}
1 change: 1 addition & 0 deletions src/layout/Tree/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './Tree';
export * from './TreeNode';
export * from './TreeTheme';
export * from './JsonTree';

0 comments on commit 0b045c4

Please sign in to comment.