Skip to content

Commit 7f06d00

Browse files
committed
always collapse arrays
1 parent 48e6307 commit 7f06d00

File tree

3 files changed

+69
-6
lines changed

3 files changed

+69
-6
lines changed

src/components/Json/Json.module.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,6 @@
5252
.string {
5353
color: #eaa;
5454
}
55+
.comment {
56+
color: #ccd8;
57+
}

src/components/Json/Json.stories.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,15 @@ export const Default: Story = {
3232
export const Arrays: Story = {
3333
args: {
3434
json: {
35-
a: Array.from({ length: 100 }, (_, i) => i),
36-
b: Array.from({ length: 100 }, (_, i) => `hello ${i}`),
37-
c: Array.from({ length: 100 }, (_, i) => [i, i + 1, i + 2]),
35+
empty: [],
36+
numbers1: Array.from({ length: 1 }, (_, i) => i),
37+
numbers8: Array.from({ length: 8 }, (_, i) => i),
38+
numbers100: Array.from({ length: 100 }, (_, i) => i),
39+
strings8: Array.from({ length: 8 }, (_, i) => `hello ${i}`),
40+
strings100: Array.from({ length: 100 }, (_, i) => `hello ${i}`),
41+
misc: Array.from({ length: 8 }, (_, i) => i % 2 ? `hello ${i}` : i),
42+
misc2: Array.from({ length: 8 }, (_, i) => i % 3 === 0 ? i : i % 3 === 1 ? `hello ${i}` : [i, i + 1, i + 2]),
43+
arrays100: Array.from({ length: 100 }, (_, i) => [i, i + 1, i + 2]),
3844
},
3945
label: 'json',
4046
},

src/components/Json/Json.tsx

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ interface JsonProps {
1010
* JSON viewer component with collapsible objects and arrays.
1111
*/
1212
export default function Json({ json, label }: JsonProps): ReactNode {
13+
return <div className={styles.json}><JsonContent json={json} label={label} /></div>
14+
}
15+
16+
function JsonContent({ json, label }: JsonProps): ReactNode {
1317
let div
1418
if (Array.isArray(json)) {
1519
div = <JsonArray array={json} label={label} />
@@ -29,17 +33,67 @@ export default function Json({ json, label }: JsonProps): ReactNode {
2933
div = <>{key}<span>{JSON.stringify(json)}</span></>
3034
}
3135
}
32-
return <div className={styles.json}>{div}</div>
36+
return div
37+
}
38+
39+
function isPrimitive(value: unknown): boolean {
40+
return (
41+
value !== undefined &&
42+
!Array.isArray(value) &&
43+
typeof value !== 'object' &&
44+
typeof value !== 'function'
45+
)
46+
}
47+
48+
function InlineArray({ suffix, children }: {suffix?: string, children?: ReactNode}): ReactNode {
49+
return (
50+
<>
51+
<span className={styles.array}>{'['}</span>
52+
<span className={styles.array}>{children}</span>
53+
<span className={styles.array}>{']'}</span>
54+
{suffix && <span className={styles.comment}>{suffix}</span>}
55+
</>
56+
)
57+
}
58+
59+
function CollapsedArray({ array }: {array: unknown[]}): ReactNode {
60+
const maxCharacterCount = 40
61+
const separator = ', '
62+
63+
const children: ReactNode[] = []
64+
let suffix: string | undefined = undefined
65+
66+
let characterCount = 0
67+
for (const [index, item] of array.entries()) {
68+
if (index > 0) {
69+
characterCount += separator.length
70+
children.push(<span key={`separator-${index - 1}`}>, </span>)
71+
}
72+
// should we continue?
73+
if (isPrimitive(item)) {
74+
const asString = typeof item === 'bigint' ? item.toString() : JSON.stringify(item)
75+
characterCount += asString.length
76+
if (characterCount < maxCharacterCount) {
77+
children.push(<JsonContent json={item} key={`item-${index}`} />)
78+
continue
79+
}
80+
}
81+
// no: it was the last entry
82+
children.push(<span key="rest">...</span>)
83+
suffix = ` length: ${array.length}`
84+
break
85+
}
86+
return <InlineArray suffix={suffix}>{children}</InlineArray>
3387
}
3488

3589
function JsonArray({ array, label }: { array: unknown[], label?: string }): ReactNode {
36-
const [collapsed, setCollapsed] = useState(false)
90+
const [collapsed, setCollapsed] = useState(true)
3791
const key = label ? <span className={styles.key}>{label}: </span> : ''
3892
if (collapsed) {
3993
return <div className={styles.clickable} onClick={() => { setCollapsed(false) }}>
4094
<span className={styles.drill}>{'\u25B6'}</span>
4195
{key}
42-
<span className={styles.array}>{'[...]'}</span>
96+
<CollapsedArray array={array}></CollapsedArray>
4397
</div>
4498
}
4599
return <>

0 commit comments

Comments
 (0)