Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/wicked-cobras-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/devtools-ui': patch
---

fix responsiveness in jsontree
169 changes: 78 additions & 91 deletions packages/devtools-ui/src/components/tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,94 +36,87 @@ function JsonValue(props: {
collapsePaths?: Array<string>
path: string
}) {
const {
value,
keyName,
isRoot = false,
isLastKey,
copyable,
defaultExpansionDepth,
depth,
collapsePaths,
path,
} = props
const styles = useStyles()

return (
<span class={styles().tree.valueContainer(isRoot)}>
{keyName && typeof value !== 'object' && !Array.isArray(value) && (
<span class={styles().tree.valueKey}>&quot;{keyName}&quot;: </span>
)}
<span class={styles().tree.valueContainer(props.isRoot ?? false)}>
{props.keyName &&
typeof props.value !== 'object' &&
!Array.isArray(props.value) && (
<span class={styles().tree.valueKey}>
&quot;{props.keyName}&quot;:{' '}
</span>
)}
{(() => {
if (typeof value === 'string') {
if (typeof props.value === 'string') {
return (
<span class={styles().tree.valueString}>&quot;{value}&quot;</span>
<span class={styles().tree.valueString}>
&quot;{props.value}&quot;
</span>
)
}
if (typeof value === 'number') {
return <span class={styles().tree.valueNumber}>{value}</span>
if (typeof props.value === 'number') {
return <span class={styles().tree.valueNumber}>{props.value}</span>
}
if (typeof value === 'boolean') {
return <span class={styles().tree.valueBoolean}>{String(value)}</span>
if (typeof props.value === 'boolean') {
return (
<span class={styles().tree.valueBoolean}>
{String(props.value)}
</span>
)
}
if (value === null) {
if (props.value === null) {
return <span class={styles().tree.valueNull}>null</span>
}
if (value === undefined) {
if (props.value === undefined) {
return <span class={styles().tree.valueNull}>undefined</span>
}
if (typeof value === 'function') {
if (typeof props.value === 'function') {
return (
<span class={styles().tree.valueFunction}>{String(value)}</span>
<span class={styles().tree.valueFunction}>
{String(props.value)}
</span>
)
}
if (Array.isArray(value)) {
if (Array.isArray(props.value)) {
return (
<ArrayValue
defaultExpansionDepth={defaultExpansionDepth}
depth={depth}
copyable={copyable}
keyName={keyName}
value={value}
collapsePaths={collapsePaths}
path={path}
defaultExpansionDepth={props.defaultExpansionDepth}
depth={props.depth}
copyable={props.copyable}
keyName={props.keyName}
value={props.value}
collapsePaths={props.collapsePaths}
path={props.path}
/>
)
}
if (typeof value === 'object') {
if (typeof props.value === 'object') {
return (
<ObjectValue
defaultExpansionDepth={defaultExpansionDepth}
depth={depth}
copyable={copyable}
keyName={keyName}
value={value}
collapsePaths={collapsePaths}
path={path}
defaultExpansionDepth={props.defaultExpansionDepth}
depth={props.depth}
copyable={props.copyable}
keyName={props.keyName}
value={props.value}
collapsePaths={props.collapsePaths}
path={props.path}
/>
)
}
return <span />
})()}
{copyable && (
{props.copyable && (
<div class={clsx(styles().tree.actions, 'actions')}>
<CopyButton value={value} />
<CopyButton value={props.value} />
</div>
)}
{isLastKey || isRoot ? '' : <span>,</span>}
{props.isLastKey || props.isRoot ? '' : <span>,</span>}
</span>
)
}

const ArrayValue = ({
value,
keyName,
copyable,
defaultExpansionDepth,
depth,
collapsePaths,
path,
}: {
const ArrayValue = (props: {
value: Array<any>
copyable?: boolean
keyName?: string
Expand All @@ -135,15 +128,16 @@ const ArrayValue = ({
const styles = useStyles()

const [expanded, setExpanded] = createSignal(
depth <= defaultExpansionDepth && !collapsePaths?.includes(path),
props.depth <= props.defaultExpansionDepth &&
!props.collapsePaths?.includes(props.path),
)

if (value.length === 0) {
if (props.value.length === 0) {
return (
<span class={styles().tree.expanderContainer}>
{keyName && (
{props.keyName && (
<span class={clsx(styles().tree.valueKey, styles().tree.collapsible)}>
&quot;{keyName}&quot;:{' '}
&quot;{props.keyName}&quot;:{' '}
</span>
)}

Expand All @@ -158,7 +152,7 @@ const ArrayValue = ({
expanded={expanded()}
/>

{keyName && (
{props.keyName && (
<span
onclick={(e) => {
e.stopPropagation()
Expand All @@ -167,27 +161,27 @@ const ArrayValue = ({
}}
class={clsx(styles().tree.valueKey, styles().tree.collapsible)}
>
&quot;{keyName}&quot;:{' '}
<span class={styles().tree.info}>{value.length} items</span>
&quot;{props.keyName}&quot;:{' '}
<span class={styles().tree.info}>{props.value.length} items</span>
</span>
)}

<span class={styles().tree.valueBraces}>[</span>

<Show when={expanded()}>
<span class={styles().tree.expandedLine(Boolean(keyName))}>
<For each={value}>
<span class={styles().tree.expandedLine(Boolean(props.keyName))}>
<For each={props.value}>
{(item, i) => {
const isLastKey = i() === value.length - 1
const isLastKey = i() === props.value.length - 1
return (
<JsonValue
copyable={copyable}
copyable={props.copyable}
value={item}
isLastKey={isLastKey}
defaultExpansionDepth={defaultExpansionDepth}
depth={depth + 1}
collapsePaths={collapsePaths}
path={path ? `${path}[${i()}]` : `[${i()}]`}
defaultExpansionDepth={props.defaultExpansionDepth}
depth={props.depth + 1}
collapsePaths={props.collapsePaths}
path={props.path ? `${props.path}[${i()}]` : `[${i()}]`}
/>
)
}}
Expand All @@ -212,15 +206,7 @@ const ArrayValue = ({
)
}

const ObjectValue = ({
value,
keyName,
copyable,
defaultExpansionDepth,
depth,
collapsePaths,
path,
}: {
const ObjectValue = (props: {
value: Record<string, any>
keyName?: string
copyable?: boolean
Expand All @@ -232,18 +218,19 @@ const ObjectValue = ({
const styles = useStyles()

const [expanded, setExpanded] = createSignal(
depth <= defaultExpansionDepth && !collapsePaths?.includes(path),
props.depth <= props.defaultExpansionDepth &&
!props.collapsePaths?.includes(props.path),
)

const keys = Object.keys(value)
const keys = Object.keys(props.value)
const lastKeyName = keys[keys.length - 1]

if (keys.length === 0) {
return (
<span class={styles().tree.expanderContainer}>
{keyName && (
{props.keyName && (
<span class={clsx(styles().tree.valueKey, styles().tree.collapsible)}>
&quot;{keyName}&quot;:{' '}
&quot;{props.keyName}&quot;:{' '}
</span>
)}

Expand All @@ -254,14 +241,14 @@ const ObjectValue = ({

return (
<span class={styles().tree.expanderContainer}>
{keyName && (
{props.keyName && (
<Expander
onClick={() => setExpanded(!expanded())}
expanded={expanded()}
/>
)}

{keyName && (
{props.keyName && (
<span
onClick={(e) => {
e.stopPropagation()
Expand All @@ -270,27 +257,27 @@ const ObjectValue = ({
}}
class={clsx(styles().tree.valueKey, styles().tree.collapsible)}
>
&quot;{keyName}&quot;:{' '}
&quot;{props.keyName}&quot;:{' '}
<span class={styles().tree.info}>{keys.length} items</span>
</span>
)}

<span class={styles().tree.valueBraces}>{'{'}</span>

<Show when={expanded()}>
<span class={styles().tree.expandedLine(Boolean(keyName))}>
<span class={styles().tree.expandedLine(Boolean(props.keyName))}>
<For each={keys}>
{(k) => (
<>
<JsonValue
value={value[k]}
value={props.value[k]}
keyName={k}
isLastKey={lastKeyName === k}
copyable={copyable}
defaultExpansionDepth={defaultExpansionDepth}
depth={depth + 1}
collapsePaths={collapsePaths}
path={`${path}${path ? '.' : ''}${k}`}
copyable={props.copyable}
defaultExpansionDepth={props.defaultExpansionDepth}
depth={props.depth + 1}
collapsePaths={props.collapsePaths}
path={`${props.path}${props.path ? '.' : ''}${k}`}
/>
</>
)}
Expand Down
Loading