diff --git a/.changeset/chubby-clowns-walk.md b/.changeset/chubby-clowns-walk.md new file mode 100644 index 00000000..8201e17f --- /dev/null +++ b/.changeset/chubby-clowns-walk.md @@ -0,0 +1,5 @@ +--- +'@tanstack/devtools-ui': minor +--- + +Adds collapsible path prop to devtools-ui, allowing an array of object paths to collapse by default. diff --git a/packages/devtools-ui/src/components/tree.tsx b/packages/devtools-ui/src/components/tree.tsx index 546d8842..a1291fd3 100644 --- a/packages/devtools-ui/src/components/tree.tsx +++ b/packages/devtools-ui/src/components/tree.tsx @@ -2,11 +2,13 @@ import { For, Match, Show, Switch, createSignal } from 'solid-js' import clsx from 'clsx' import { css, useStyles } from '../styles/use-styles' import { CopiedCopier, Copier, ErrorCopier } from './icons' +import type { CollapsiblePaths } from '../utils/deep-keys' -export function JsonTree(props: { - value: any +export function JsonTree>(props: { + value: TData copyable?: boolean defaultExpansionDepth?: number + collapsePaths?: Array }) { return ( ) } @@ -25,8 +29,12 @@ function JsonValue(props: { isRoot?: boolean isLastKey?: boolean copyable?: boolean + defaultExpansionDepth: number depth: number + + collapsePaths?: Array + path: string }) { const { value, @@ -36,6 +44,8 @@ function JsonValue(props: { copyable, defaultExpansionDepth, depth, + collapsePaths, + path, } = props const styles = useStyles() @@ -75,6 +85,8 @@ function JsonValue(props: { copyable={copyable} keyName={keyName} value={value} + collapsePaths={collapsePaths} + path={path} /> ) } @@ -86,6 +98,8 @@ function JsonValue(props: { copyable={copyable} keyName={keyName} value={value} + collapsePaths={collapsePaths} + path={path} /> ) } @@ -107,15 +121,22 @@ const ArrayValue = ({ copyable, defaultExpansionDepth, depth, + collapsePaths, + path, }: { value: Array copyable?: boolean keyName?: string defaultExpansionDepth: number depth: number + collapsePaths?: Array + path: string }) => { const styles = useStyles() - const [expanded, setExpanded] = createSignal(depth <= defaultExpansionDepth) + + const [expanded, setExpanded] = createSignal( + depth <= defaultExpansionDepth && !collapsePaths?.includes(path), + ) if (value.length === 0) { return ( @@ -125,6 +146,7 @@ const ArrayValue = ({ "{keyName}":{' '} )} + [] ) @@ -135,6 +157,7 @@ const ArrayValue = ({ onClick={() => setExpanded(!expanded())} expanded={expanded()} /> + {keyName && ( { @@ -148,7 +171,9 @@ const ArrayValue = ({ {value.length} items )} + [ + @@ -161,12 +186,15 @@ const ArrayValue = ({ isLastKey={isLastKey} defaultExpansionDepth={defaultExpansionDepth} depth={depth + 1} + collapsePaths={collapsePaths} + path={path ? `${path}[${i()}]` : `[${i()}]`} /> ) }} + { @@ -190,15 +218,23 @@ const ObjectValue = ({ copyable, defaultExpansionDepth, depth, + collapsePaths, + path, }: { value: Record keyName?: string copyable?: boolean defaultExpansionDepth: number depth: number + collapsePaths?: Array + path: string }) => { const styles = useStyles() - const [expanded, setExpanded] = createSignal(depth <= defaultExpansionDepth) + + const [expanded, setExpanded] = createSignal( + depth <= defaultExpansionDepth && !collapsePaths?.includes(path), + ) + const keys = Object.keys(value) const lastKeyName = keys[keys.length - 1] @@ -210,10 +246,12 @@ const ObjectValue = ({ "{keyName}":{' '} )} + {'{}'} ) } + return ( {keyName && ( @@ -222,6 +260,7 @@ const ObjectValue = ({ expanded={expanded()} /> )} + {keyName && ( { @@ -235,7 +274,9 @@ const ObjectValue = ({ {keys.length} items )} + {'{'} + @@ -248,12 +289,15 @@ const ObjectValue = ({ copyable={copyable} defaultExpansionDepth={defaultExpansionDepth} depth={depth + 1} + collapsePaths={collapsePaths} + path={`${path}${path ? '.' : ''}${k}`} /> )} + { @@ -266,6 +310,7 @@ const ObjectValue = ({ {`...`} + {'}'} ) diff --git a/packages/devtools-ui/src/utils/deep-keys.ts b/packages/devtools-ui/src/utils/deep-keys.ts new file mode 100644 index 00000000..4d76f258 --- /dev/null +++ b/packages/devtools-ui/src/utils/deep-keys.ts @@ -0,0 +1,18 @@ +type CollapsibleKeys = + T extends ReadonlyArray + ? + | (TPrefix extends '' ? '' : TPrefix) + | CollapsibleKeys + : T extends object + ? + | (TPrefix extends '' ? '' : TPrefix) + | { + [K in Extract]: CollapsibleKeys< + T[K], + TPrefix extends '' ? `${K}` : `${TPrefix}.${K}` + > + }[Extract] + : never + +export type CollapsiblePaths = + CollapsibleKeys extends string ? CollapsibleKeys : never