Skip to content

Instantly share code, notes, and snippets.

@JTBrinkmann
Last active October 20, 2021 13:58
Show Gist options
  • Save JTBrinkmann/4aabb4e9049f893cc1ff7dab15992536 to your computer and use it in GitHub Desktop.
Save JTBrinkmann/4aabb4e9049f893cc1ff7dab15992536 to your computer and use it in GitHub Desktop.
Chakra UI component to render a javascript object, similar to console.log in browsers' devtools
import { ChevronDownIcon, ChevronRightIcon } from "@chakra-ui/icons"
import { Box, chakra, Icon, useDisclosure } from "@chakra-ui/react"
import { useMemo } from "react"
export const json = (obj: any) =>
obj === undefined ? "undefined" : JSON.stringify(obj, null, 2)
export const closeBrackets = (str: string) =>
str.replace(
/[\(\[\{]+$/,
(brackets) =>
brackets +
"…" +
brackets
.split("")
.reverse()
.map((b) => (b === "{" ? "}" : b === "[" ? "]" : ")"))
.join("")
)
export const Tree = ({ value }: { value: any }) => {
return (
<chakra.pre>
<TreeValue value={value} />
</chakra.pre>
)
}
const TreeObject = ({ isOpen, value }: { isOpen?: boolean; value: object }) => {
const isArray = Array.isArray(value)
const isClassInstance = !isArray && value.constructor !== Object
const names = Object.getOwnPropertyNames(value)
if (isClassInstance) {
names.push("__proto__")
}
return (
<>
{isArray ? "[" : "{"}
{!isOpen
? "…"
: names.map((key) => {
let val
try {
val = (value as Record<string, unknown>)[key]
} catch (err) {
val = err
}
return (
<Box marginStart={6}>
<TreeValue keyName={isArray ? undefined : key} value={val} />,
</Box>
)
})}
{isArray ? "]" : "}"}
</>
)
}
const TreeFunction = ({
isOpen,
value,
}: {
isOpen?: boolean
value: Function
}) => (
<>
<chakra.span color="gray.500">
{isOpen ? `${value}` : closeBrackets(`${value}`.split("\n")[0])}
</chakra.span>
</>
)
const TreeClassInstance = ({
isOpen,
value,
}: {
isOpen?: boolean
value: object
}) => {
const string = useMemo(() => {
try {
return value.toString === Object.prototype.toString
? null
: value.toString()
} catch (err) {
return null
}
}, [value])
return (
<>
<chakra.span color="blue.500">{value.constructor.name} </chakra.span>
{string && <chakra.span color="pink.500">{string} </chakra.span>}
<TreeObject isOpen={isOpen} value={value} />
</>
)
}
const TreeValue = ({
keyName,
value,
}: {
keyName?: string
value: unknown
}) => {
const isFunction = typeof value === "function"
const isObject = typeof value === "object" && !!value
const isArray = isObject && Array.isArray(value)
const isClassInstance = isObject && !isArray && value.constructor !== Object
const isEmptyObject =
isObject && Object.getOwnPropertyNames(value).length === 0
const isCollasible =
isFunction || isClassInstance || (isObject && !isEmptyObject)
const { isOpen, onToggle } = useDisclosure({
defaultIsOpen: !isFunction && !isClassInstance,
})
return isCollasible ? (
<>
<chakra.span aria-role="button" onClick={onToggle} cursor="pointer">
<Icon
as={isOpen ? ChevronDownIcon : ChevronRightIcon}
marginStart={-4}
/>
{keyName && `${keyName}: `}
</chakra.span>
{isClassInstance ? (
<TreeClassInstance value={value} isOpen={isOpen} />
) : isObject ? (
<TreeObject value={value} isOpen={isOpen} />
) : (
<TreeFunction value={value} isOpen={isOpen} />
)}
</>
) : (
<>
{keyName && `${keyName}: `}
{isObject ? (
<TreeClassInstance value={value} isOpen={true} />
) : typeof value === "number" || typeof value === "boolean" ? (
<chakra.span
color={typeof value === "number" ? "orange.500" : "blue.500"}
>
{`${value}`}
</chakra.span>
) : (
<chakra.span
color={typeof value === "string" ? "green.500" : "red.500"}
>
{json(value)}
</chakra.span>
)}
</>
)
}
@JTBrinkmann
Copy link
Author

<Tree
  value={{
    null: null,
    undefined: undefined,
    date: new Date(0),
    true: true,
    false: false,
    Infinity: Number.NEGATIVE_INFINITY,
    minusZero: -0,
    oneThird: 1 / 3,
    multiLineString: "line 1\nline2\nfinal line",
    function: () => "test!",
    numbers: [1, 2, 3],
    strings: ["foo", "baz", "bar"],
    console: typeof window === "undefined" ? {} : window.console,
  }}
/>

firefox_Avz3RpRZDh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment