Skip to content

Commit 1575d0c

Browse files
authored
add more customization options (#3)
1 parent 695453b commit 1575d0c

File tree

12 files changed

+362
-140
lines changed

12 files changed

+362
-140
lines changed

.changeset/chatty-beers-prove.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'react-json-friendly-viewer': minor
3+
---
4+
5+
Add more customization options
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { format as formatDate } from 'date-fns';
2+
import * as React from 'react';
3+
import {
4+
Formatter,
5+
JsonPrettyViewer,
6+
prettifyLabel,
7+
} from 'react-json-friendly-viewer';
8+
9+
const data = {
10+
name: 'react-json-friendly-viewer',
11+
version: 'unknown',
12+
description:
13+
'This is a beautiful and user-friendly component to display your JSON data that provides sensible default that even your business users can understand it instantly',
14+
private: false,
15+
changes: 1000,
16+
dependencies: {
17+
react: 'latest',
18+
},
19+
createdAt: '1990-10-13T10:51:05.570Z',
20+
keywords: ['react', 'json viewer'],
21+
experiences: [
22+
{
23+
from: '2013',
24+
to: '2015',
25+
job: 'janitor',
26+
projects: [
27+
{
28+
venue: 'National Museum',
29+
},
30+
],
31+
},
32+
],
33+
referrer: null,
34+
};
35+
36+
const datePattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
37+
38+
const formatter: Partial<Formatter> = {
39+
string: (value: string) => {
40+
return datePattern.test(value)
41+
? formatDate(new Date(value), 'd MMM yyyy, h:mm a')
42+
: value;
43+
},
44+
arrayItem: (index, parentName) =>
45+
prettifyLabel(`${parentName || 'Item'} ${index + 1}`),
46+
none: () => `(None)`,
47+
};
48+
49+
export const AllCustomizationExample = () => {
50+
const [fieldLabel, setFieldLabel] = React.useState('Props');
51+
const [valueLabel, setValueLabel] = React.useState('Value');
52+
const [customFormatter, toggleCustomFormatter] = React.useReducer(
53+
(o) => !o,
54+
true
55+
);
56+
const [mergePrimitiveArray, toggleMergePrimitiveArray] = React.useReducer(
57+
(o) => !o,
58+
false
59+
);
60+
const [customRender, toggleCustomRender] = React.useReducer((o) => !o, true);
61+
62+
return (
63+
<div>
64+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 16, padding: 16 }}>
65+
<div>
66+
<label htmlFor="fieldLabel">fieldLabel</label>
67+
<input
68+
id="fieldLabel"
69+
value={fieldLabel}
70+
onChange={(ev) => setFieldLabel(ev.target.value)}
71+
/>
72+
</div>
73+
<div>
74+
<label htmlFor="valueLabel">valueLabel</label>
75+
<input
76+
id="valueLabel"
77+
value={valueLabel}
78+
onChange={(ev) => setValueLabel(ev.target.value)}
79+
/>
80+
</div>
81+
<div>
82+
Custom formatter
83+
<button type="button" onClick={toggleCustomFormatter}>
84+
{customFormatter ? 'True' : 'False'}
85+
</button>
86+
</div>
87+
<div>
88+
mergePrimitiveArray
89+
<button type="button" onClick={toggleMergePrimitiveArray}>
90+
{mergePrimitiveArray ? 'True' : 'False'}
91+
</button>
92+
</div>
93+
<div>
94+
Custom renderValue
95+
<button type="button" onClick={toggleCustomRender}>
96+
{customRender ? 'True' : 'False'}
97+
</button>
98+
</div>
99+
</div>
100+
<JsonPrettyViewer
101+
json={data}
102+
formatter={customFormatter ? formatter : undefined}
103+
fieldLabel={fieldLabel}
104+
valueLabel={valueLabel}
105+
mergePrimitiveArray={mergePrimitiveArray}
106+
renderValue={
107+
customRender
108+
? (value) => (
109+
<span
110+
style={{
111+
display: 'block',
112+
overflow: 'hidden',
113+
whiteSpace: 'nowrap',
114+
textOverflow: 'ellipsis',
115+
width: '100%',
116+
}}
117+
>
118+
{value}
119+
</span>
120+
)
121+
: undefined
122+
}
123+
/>
124+
</div>
125+
);
126+
};

examples/playground/src/main.tsx

+39-46
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,57 @@
1-
import { format as formatDate } from 'date-fns';
21
import { createRoot } from 'react-dom/client';
3-
import {
4-
JsonPrettyViewer,
5-
Formatter,
6-
prettifyLabel,
7-
} from 'react-json-friendly-viewer';
2+
import { JsonPrettyViewer } from 'react-json-friendly-viewer';
83
import 'react-json-friendly-viewer/style.css';
9-
10-
const data = {
11-
name: 'react-json-friendly-viewer',
12-
version: 'unknown',
13-
private: false,
14-
changes: 1000,
15-
dependencies: {
16-
react: 'latest',
17-
},
18-
createdAt: '1990-10-13T10:51:05.570Z',
19-
hobbies: ['reading', 'eating'],
20-
experiences: [
21-
{
22-
from: '2013',
23-
to: '2015',
24-
job: 'janitor',
25-
},
26-
],
27-
};
28-
29-
const datePattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
30-
31-
const formatter: Partial<Formatter> = {
32-
string: (value: string) => {
33-
return datePattern.test(value)
34-
? formatDate(new Date(value), 'd MMM yyyy, h:mm a')
35-
: value;
36-
},
37-
field: (data) =>
38-
data.type === 'arrayItem'
39-
? prettifyLabel(`${data.parentName || 'Item'} ${data.index + 1}`)
40-
: prettifyLabel(data.name),
41-
};
4+
import { AllCustomizationExample } from './all-customization';
425

436
interface CustomData {
447
firstName: string;
458
lastName: string;
9+
age?: number | null;
10+
hobbies: Array<string>;
11+
friends: Array<CustomData>;
4612
}
4713

4814
const customer: CustomData = {
4915
firstName: 'Malcolm',
5016
lastName: 'Kee',
17+
age: null,
18+
hobbies: ['reading', 'eating'],
19+
friends: [
20+
{
21+
firstName: 'Pika',
22+
lastName: 'Chu',
23+
age: 30,
24+
hobbies: ['jumping'],
25+
friends: [],
26+
},
27+
],
5128
};
5229

5330
createRoot(document.getElementById('root') as HTMLElement).render(
54-
<div
31+
<main
5532
style={{
56-
display: 'flex',
57-
flexDirection: 'column',
58-
gap: 8,
33+
maxWidth: '1280px',
34+
margin: `0 auto`,
5935
}}
6036
>
61-
<JsonPrettyViewer json={data} formatter={formatter} />
62-
<JsonPrettyViewer json={customer} />
63-
</div>
37+
<div
38+
style={{
39+
display: 'flex',
40+
flexDirection: 'column',
41+
gap: 8,
42+
}}
43+
>
44+
<h1>
45+
Demo of <code>react-json-friendly-viewer</code>
46+
</h1>
47+
<section>
48+
<h2>Minimal customization</h2>
49+
<JsonPrettyViewer json={customer} />
50+
</section>
51+
<section>
52+
<h2>All customization</h2>
53+
<AllCustomizationExample />
54+
</section>
55+
</div>
56+
</main>
6457
);

packages/react-json-friendly-viewer/README.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
Beautifully display your JSON data for everyone.
44

5+
[Demo](https://react-json-friendly-viewer.netlify.app/)
6+
57
```bash
68
npm install react-json-friendly-viewer
79
```
@@ -17,7 +19,6 @@ import 'react-json-friendly-viewer/style.css';
1719
<JsonPrettyViewer
1820
json={{
1921
name: 'react-json-friendly-viewer',
20-
version: 'unknown',
2122
private: false,
2223
changes: 1000,
2324
dependencies: {
@@ -27,11 +28,15 @@ import 'react-json-friendly-viewer/style.css';
2728
hobbies: ['reading', 'eating'],
2829
experiences: [
2930
{
30-
from: '2013',
31-
to: '2015',
3231
job: 'janitor',
32+
projects: [
33+
{
34+
venue: 'National Museum',
35+
},
36+
],
3337
},
3438
],
39+
referrer: null,
3540
}}
3641
/>;
3742
```
Loading

packages/react-json-friendly-viewer/package.json

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
"name": "react-json-friendly-viewer",
33
"version": "0.3.0",
44
"license": "MIT",
5+
"keywords": [
6+
"react",
7+
"json viewer"
8+
],
59
"peerDependencies": {
610
"react": "^16.8.0 || 17.x || 18.x"
711
},
@@ -55,6 +59,7 @@
5559
"docs"
5660
],
5761
"dependencies": {
62+
"@radix-ui/react-id": "^1.0.0",
5863
"clsx": "^1.2.1",
5964
"title-case": "^3.0.3"
6065
}

packages/react-json-friendly-viewer/src/json-pretty-viewer/json-pretty-viewer.css.ts

+16-11
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,6 @@ export const flex = style({
88
display: 'flex',
99
});
1010

11-
export const flexCenter = style([
12-
flex,
13-
{
14-
alignItems: 'center',
15-
},
16-
]);
17-
1811
export const tableHeading = style({
1912
paddingLeft: vars.spacing[7],
2013
});
@@ -35,9 +28,20 @@ export const stripeRow = styleVariants({
3528
},
3629
});
3730

38-
export const toggleBtn = style({
39-
cursor: 'pointer',
40-
});
31+
export const toggleBtn = style([
32+
flex,
33+
{
34+
fontFamily: 'inherit',
35+
fontSize: 'inherit',
36+
color: 'inherit',
37+
cursor: 'pointer',
38+
alignItems: 'center',
39+
backgroundColor: 'inherit',
40+
width: '100%',
41+
paddingBlock: '8px',
42+
marginBlock: `-8px`,
43+
},
44+
]);
4145

4246
export const toggleIconWrapper = styleVariants({
4347
default: {
@@ -110,6 +114,7 @@ export const prettyCellByType = styleVariants({
110114
label: {
111115
width: spacing[36],
112116
paddingRight: spacing[4],
117+
flexShrink: 0,
113118
'@media': {
114119
[media.md]: {
115120
width: spacing[72],
@@ -139,9 +144,9 @@ export const prettyCellByType = styleVariants({
139144
},
140145
nonHeading: {
141146
paddingBlock: spacing[4],
142-
whiteSpace: 'nowrap',
143147
fontSize: vars.fontSize.sm,
144148
lineHeight: '1.375',
149+
minWidth: 0,
145150
},
146151
});
147152

0 commit comments

Comments
 (0)