Skip to content

Commit

Permalink
feat: support expand at particular depth
Browse files Browse the repository at this point in the history
  • Loading branch information
blucas.wu committed Jun 5, 2023
1 parent fdd6a65 commit b520218
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 79 deletions.
32 changes: 8 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ Engligh | [中文](./README_ZH.md)

`<ReactJsonView />` is a React component for displaying JSON data.

The component accepts source data of _string_ type, which means you need to ensure that the data passed in is valid JSON string and can be parsed without errors using the `JSON.parse()` method. Otherwise, the data will be converted to a _string_ type before being processed.

## Install

```bash
Expand All @@ -30,17 +28,7 @@ import ReactDOM from 'react-dom';
import ReactJsonView from '@huolala-tech/react-json-view';
import '@huolala-tech/react-json-view/dist/style.css';

const data = JSON.stringify([
1,
true,
"Hello world",
["foo", "bar", "baz"],
{
name: "@huolala-tech/react-json-view",
contributor: "wqcstrong",
description: 'The component accepts source data of *string* type, which means you need to ensure that the data passed in is valid JSON string and can be parsed without errors using the `JSON.parse()` method.',
},
]);
const data = [1,2,3,4]

const App = () => {
return (
Expand All @@ -64,10 +52,6 @@ ReactDOM.render(
)
```

Now you should get that after above:

![Main](./screenshots/expand.jpg)

## Config

The default configuration usage:
Expand All @@ -82,13 +66,13 @@ The default configuration usage:
/>
```

| Name | Type | Default value | Description |
| --------------- | ----------------- | ------------- | ------------------------------------------------ |
| `source` | `string` | None | Origin json string. |
| `rootLabel` | `React.ReactNode` | `""` | Root node's label. |
| `defaultExpand` | `boolean` | `false` | Whether expand property panel. |
| `keyCount` | `number / "all"` | `200` | `ReactJsonView` supports lazily loading more properties. The parameter indicates how many properties to show at a time, and you can pass `"all"` to show all properties. |
| `maxTitleSize` | `number` | `100` | The max length of abbreviated title in collapse. |
| Name | Type | Default value | Description |
| --------------- | ------------------ | ------------- | ------------------------------------------------------------ |
| `source` | `object` | None | Origin json data. |
| `rootLabel` | `React.ReactNode` | `""` | Root node's label. |
| `defaultExpand` | `boolean / number` | `false` | Whether expand property panel. Expand at a particular depth if you pass a integer value. |
| `keyCount` | `number / "all"` | `200` | `ReactJsonView` supports lazily loading more properties. The parameter indicates how many properties to show at a time, and you can pass `"all"` to show all properties. |
| `maxTitleSize` | `number` | `100` | The max length of abbreviated title in collapse. |

## License

Expand Down
20 changes: 2 additions & 18 deletions README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

`<ReactJsonView />` 是一个用于展示 JSON 数据的 React 组件。

该组件接受 `string` 类型的源数据,这意味着你需要确保传入的数据是有效的 JSON 字符串,并且可以使用 `JSON.parse()` 方法正确解析。否则,数据将在被处理之前转换为 `string` 类型。

## 安装

```bash
Expand All @@ -30,17 +28,7 @@ import ReactDOM from 'react-dom';
import ReactJsonView from '@huolala-tech/react-json-view';
import '@huolala-tech/react-json-view/dist/style.css';

const data = JSON.stringify([
1,
true,
"Hello world",
["foo", "bar", "baz"],
{
name: "@huolala-tech/react-json-view",
contributor: "wqcstrong",
description: 'The component accepts source data of *string* type, which means you need to ensure that the data passed in is valid JSON string and can be parsed without errors using the `JSON.parse()` method.',
},
]);
const data = [1, 2, 3, 4];

const App = () => {
return (
Expand All @@ -64,10 +52,6 @@ ReactDOM.render(
)
```

此时你应该可以看到如下界面:

![Main](/screenshots/expand.jpg)

## 配置

默认配置下的使用方式:
Expand All @@ -86,7 +70,7 @@ ReactDOM.render(
| --------------- | ----------------- | ------------- | ---------------------- |
| `source` | `string` | 无默认值 | JSON 数据。 |
| `rootLabel` | `React.ReactNode` | `""` | 根节点的标题名称 |
| `defaultExpand` | `boolean` | `false` | 是否展开面板 |
| `defaultExpand` | `boolean / number` | `false` | 是否展开面板。传入整数时是指定展开的层级。 |
| `keyCount` | `number / "all"` | `200` | `ReactJsonView` 支持延迟加载更多属性。 该参数表示一次显示多少个属性,您可以传递 `"all"` 以显示所有属性。 |
| `maxTitleSize` | `number` | `100` | 折叠时缩写标题的最大长度。 |

Expand Down
67 changes: 49 additions & 18 deletions examples/App.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,61 @@
import ReactJsonView from '../dist/index';
import '../dist/style.css';
import json from './assets/data.json?raw';
import json from './assets/data.json';

const data = JSON.stringify([
1,
true,
'Hello world',
['foo', 'bar', 'baz'],
const data = [
{
name: '@huolala-tech/react-json-view',
contributor: 'wqcstrong',
description:
'The component accepts source data of string type, which means you need to ensure that the data passed in is valid JSON string and can be parsed without errors using the JSON.parse() method.',
type: 'Primitive',
data: 'Hello, @huolala-tech/react-json-view',
},
]);
{
type: 'Normal',
data: {
name: '@huolala-tech/react-json-view',
contributor: 'wqcstrong',
description:
'<ReactJsonView /> is a react component for display json tree, it accepts the valid json object as the source and show them',
},
},
{
type: 'Indicate expand depth (3)',
data: {
foo: {
name: 'foo',
child: {
bar: {
name: 'bar',
child: {
name: 'baz',
},
},
},
},
},
},
{
type: 'Self-Reference (window)',
data: window,
},
{ type: 'Big Size', data: json },
];

const App = () => {
return (
<div id="app">
<ReactJsonView
source={data || json}
rootLabel="Response data"
keyCount={200}
defaultExpand={false}
maxTitleSize={100}
/>
{data.map((item) => {
return (
<>
<h2>{item.type}</h2>
<ReactJsonView
key={item.type}
source={item.data}
keyCount={200}
defaultExpand={2}
maxTitleSize={100}
/>
</>
);
})}
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/ReactJsonView/components/ConfigContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { PropsWithChildren, createContext, useContext } from 'react';
import { Options } from '../../../types';

const ConfigContext = createContext<Options>({
source: '',
source: {},
defaultExpand: false,
rootLabel: '',
keyCount: 200,
Expand Down
45 changes: 30 additions & 15 deletions src/ReactJsonView/components/JsonNode.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,42 @@
import { useState, useMemo, ReactNode } from 'react';
import { clsx, isListOrMap, shortTitle } from '../../utils';
import {
clsx,
isBoolean,
isListOrMap,
isNumber,
shortTitle,
} from '../../utils';
import { ArrowRight } from './SvgIcon';
import { useConfigInfo } from './ConfigContext';
import CopyContent from './CopyContent';
import LazyLoadMore from './LazyLoadMore';

const JsonNode = ({
source = '',
source = {},
depth = 1,
label = '',
}: {
source: string;
source: object;
depth?: number;
label?: ReactNode;
}) => {
const { defaultExpand, maxTitleSize } = useConfigInfo();
const [collapsed, setCollapsed] = useState(!defaultExpand);
const [expanded, setExpanded] = useState(() => {
if (isBoolean(defaultExpand)) {
return defaultExpand;
}
if (isNumber(defaultExpand)) {
return defaultExpand + 1 >= depth;
}
return false;
});

let data: unknown;
try {
data = JSON.parse(source);
data = JSON.parse(JSON.stringify(source));
} catch (e) {
data = `${source}`;
label = 'Error';
data = 'The source value must be a valid json object';
}

const labelContent = useMemo(() => {
Expand Down Expand Up @@ -60,28 +77,26 @@ const JsonNode = ({

return (
<div className="rjv-node">
<div
className="rjv-node__title"
onClick={() => setCollapsed(!collapsed)}
>
<div className="rjv-node__title" onClick={() => setExpanded(!expanded)}>
<ArrowRight
width={10}
height={10}
className={clsx('rjv-node__spread-controller', {
spread: !collapsed,
spread: expanded,
})}
/>
{labelContent}
{(!label || collapsed) && <code>{title}</code>}
{(!label || !expanded) && <code>{title}</code>}
</div>
{!collapsed && (
<div className="rjv-node__property">
{expanded && (
<div className="rjv-node__property" data-depth={depth}>
<LazyLoadMore
list={Object.keys(data)}
render={(key) => (
<JsonNode
label={key}
source={JSON.stringify((data as any)[key])}
source={(data as any)[key]}
depth={depth + 1}
/>
)}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/ReactJsonView/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
font-size: @fontSize;
font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, Courier,
monospace;
line-height: 1.3;
line-height: 1.4;
&__title {
cursor: default;
}
Expand Down
7 changes: 7 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ export function toStringTag(data: unknown) {
return Object.prototype.toString.call(data);
}

export function isBoolean(data: unknown): data is boolean {
return typeof data === 'boolean';
}
export function isNumber(data: unknown): data is number {
return typeof data === 'number';
}

export function isArray<T = unknown>(data: unknown): data is T[] {
return Array.isArray(data);
}
Expand Down
4 changes: 2 additions & 2 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export interface Options {
/**
* origin json data.
*/
source: string;
source: object;
/**
* root label.
* @default ""
Expand All @@ -14,7 +14,7 @@ export interface Options {
* Whether expand property panel.
* @default false
*/
defaultExpand?: boolean;
defaultExpand?: boolean | number;
/**
* `ReactJsonView` support load more property lazily.
* The option indicated how many properties to show once, you
Expand Down

0 comments on commit b520218

Please sign in to comment.