Last active
October 20, 2021 13:58
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | |
)} | |
</> | |
) | |
} |
Author
JTBrinkmann
commented
Oct 20, 2021
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment