@sentry-internal/react-inspector
Version:
Power of Browser DevTools inspectors right inside your React app
1 lines • 79 kB
Source Map (JSON)
{"version":3,"sources":["../node_modules/is-object/index.js","../node_modules/is-window/index.js","../node_modules/is-dom/index.js","../src/styles/themes/index.tsx","../src/styles/themes/chromeDark.tsx","../src/styles/themes/chromeLight.tsx","../src/object-inspector/ObjectInspector.tsx","../src/tree-view/TreeView.tsx","../src/tree-view/ExpandedPathsContext.tsx","../src/tree-view/TreeNode.tsx","../src/styles/styles.tsx","../src/styles/unselectable.tsx","../src/styles/base.tsx","../src/tree-view/pathUtils.ts","../src/object/ObjectValue.tsx","../src/object-inspector/ObjectRootLabel.tsx","../src/object/ObjectName.tsx","../src/object-inspector/ObjectPreview.tsx","../src/utils/objectPrototype.tsx","../src/utils/propertyUtils.tsx","../src/object-inspector/ObjectLabel.tsx","../src/table-inspector/TableInspector.tsx","../src/table-inspector/getHeaders.ts","../src/table-inspector/DataContainer.tsx","../src/table-inspector/HeaderContainer.tsx","../src/table-inspector/TH.tsx","../src/dom-inspector/DOMInspector.tsx","../src/dom-inspector/DOMNodePreview.tsx","../src/dom-inspector/shouldInline.tsx","../src/index.tsx"],"sourcesContent":["'use strict';\n\nmodule.exports = function isObject(x) {\n\treturn typeof x === 'object' && x !== null;\n};\n","'use strict';\n\nmodule.exports = function (obj) {\n\n if (obj == null) {\n return false;\n }\n\n var o = Object(obj);\n\n return o === o.window;\n};\n","var isObject = require('is-object')\nvar isWindow = require('is-window')\n\nfunction isNode (val) {\n if (!isObject(val) || !isWindow(window) || typeof window.Node !== 'function') {\n return false\n }\n\n return typeof val.nodeType === 'number' &&\n typeof val.nodeName === 'string'\n}\n\nmodule.exports = isNode\n","export { theme as chromeDark } from './chromeDark';\nexport { theme as chromeLight } from './chromeLight';\n","export const theme = {\n BASE_FONT_FAMILY: 'Menlo, monospace',\n BASE_FONT_SIZE: '11px',\n BASE_LINE_HEIGHT: 1.2,\n\n BASE_BACKGROUND_COLOR: 'rgb(36, 36, 36)',\n BASE_COLOR: 'rgb(213, 213, 213)',\n\n OBJECT_PREVIEW_ARRAY_MAX_PROPERTIES: 10,\n OBJECT_PREVIEW_OBJECT_MAX_PROPERTIES: 5,\n OBJECT_NAME_COLOR: 'rgb(227, 110, 236)',\n OBJECT_VALUE_NULL_COLOR: 'rgb(127, 127, 127)',\n OBJECT_VALUE_UNDEFINED_COLOR: 'rgb(127, 127, 127)',\n OBJECT_VALUE_REGEXP_COLOR: 'rgb(233, 63, 59)',\n OBJECT_VALUE_STRING_COLOR: 'rgb(233, 63, 59)',\n OBJECT_VALUE_SYMBOL_COLOR: 'rgb(233, 63, 59)',\n OBJECT_VALUE_NUMBER_COLOR: 'hsl(252, 100%, 75%)',\n OBJECT_VALUE_BOOLEAN_COLOR: 'hsl(252, 100%, 75%)',\n OBJECT_VALUE_FUNCTION_PREFIX_COLOR: 'rgb(85, 106, 242)',\n\n ERROR_COLOR: 'rgb(235, 116, 116)',\n\n HTML_TAG_COLOR: 'rgb(93, 176, 215)',\n HTML_TAGNAME_COLOR: 'rgb(93, 176, 215)',\n HTML_TAGNAME_TEXT_TRANSFORM: 'lowercase',\n HTML_ATTRIBUTE_NAME_COLOR: 'rgb(155, 187, 220)',\n HTML_ATTRIBUTE_VALUE_COLOR: 'rgb(242, 151, 102)',\n HTML_COMMENT_COLOR: 'rgb(137, 137, 137)',\n HTML_DOCTYPE_COLOR: 'rgb(192, 192, 192)',\n\n ARROW_COLOR: 'rgb(145, 145, 145)',\n ARROW_MARGIN_RIGHT: 3,\n ARROW_FONT_SIZE: 12,\n ARROW_ANIMATION_DURATION: '0',\n\n TREENODE_FONT_FAMILY: 'Menlo, monospace',\n TREENODE_FONT_SIZE: '11px',\n TREENODE_LINE_HEIGHT: 1.2,\n TREENODE_PADDING_LEFT: 12,\n\n TABLE_BORDER_COLOR: 'rgb(85, 85, 85)',\n TABLE_TH_BACKGROUND_COLOR: 'rgb(44, 44, 44)',\n TABLE_TH_HOVER_COLOR: 'rgb(48, 48, 48)',\n TABLE_SORT_ICON_COLOR: 'black', //'rgb(48, 57, 66)',\n TABLE_DATA_BACKGROUND_IMAGE:\n 'linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0) 50%, rgba(51, 139, 255, 0.0980392) 50%, rgba(51, 139, 255, 0.0980392))',\n TABLE_DATA_BACKGROUND_SIZE: '128px 32px',\n};\n","export const theme = {\n BASE_FONT_FAMILY: 'Menlo, monospace',\n BASE_FONT_SIZE: '11px',\n BASE_LINE_HEIGHT: 1.2,\n\n BASE_BACKGROUND_COLOR: 'white',\n BASE_COLOR: 'black',\n\n OBJECT_PREVIEW_ARRAY_MAX_PROPERTIES: 10,\n OBJECT_PREVIEW_OBJECT_MAX_PROPERTIES: 5,\n OBJECT_NAME_COLOR: 'rgb(136, 19, 145)',\n OBJECT_VALUE_NULL_COLOR: 'rgb(128, 128, 128)',\n OBJECT_VALUE_UNDEFINED_COLOR: 'rgb(128, 128, 128)',\n OBJECT_VALUE_REGEXP_COLOR: 'rgb(196, 26, 22)',\n OBJECT_VALUE_STRING_COLOR: 'rgb(196, 26, 22)',\n OBJECT_VALUE_SYMBOL_COLOR: 'rgb(196, 26, 22)',\n OBJECT_VALUE_NUMBER_COLOR: 'rgb(28, 0, 207)',\n OBJECT_VALUE_BOOLEAN_COLOR: 'rgb(28, 0, 207)',\n OBJECT_VALUE_FUNCTION_PREFIX_COLOR: 'rgb(13, 34, 170)',\n\n ERROR_COLOR: 'rgb(255, 0, 0)',\n\n HTML_TAG_COLOR: 'rgb(168, 148, 166)',\n HTML_TAGNAME_COLOR: 'rgb(136, 18, 128)',\n HTML_TAGNAME_TEXT_TRANSFORM: 'lowercase',\n HTML_ATTRIBUTE_NAME_COLOR: 'rgb(153, 69, 0)',\n HTML_ATTRIBUTE_VALUE_COLOR: 'rgb(26, 26, 166)',\n HTML_COMMENT_COLOR: 'rgb(35, 110, 37)',\n HTML_DOCTYPE_COLOR: 'rgb(192, 192, 192)',\n\n ARROW_COLOR: '#6e6e6e',\n ARROW_MARGIN_RIGHT: 3,\n ARROW_FONT_SIZE: 12,\n ARROW_ANIMATION_DURATION: '0',\n\n TREENODE_FONT_FAMILY: 'Menlo, monospace',\n TREENODE_FONT_SIZE: '11px',\n TREENODE_LINE_HEIGHT: 1.2,\n TREENODE_PADDING_LEFT: 12,\n\n TABLE_BORDER_COLOR: '#aaa',\n TABLE_TH_BACKGROUND_COLOR: '#eee',\n TABLE_TH_HOVER_COLOR: 'hsla(0, 0%, 90%, 1)',\n TABLE_SORT_ICON_COLOR: '#6e6e6e',\n TABLE_DATA_BACKGROUND_IMAGE:\n 'linear-gradient(to bottom, white, white 50%, rgb(234, 243, 255) 50%, rgb(234, 243, 255))',\n TABLE_DATA_BACKGROUND_SIZE: '128px 32px',\n};\n","import React, { FC } from 'react';\nimport { TreeView } from '../tree-view/TreeView';\n\nimport { ObjectRootLabel } from './ObjectRootLabel';\nimport { ObjectLabel } from './ObjectLabel';\n\nimport { propertyIsEnumerable } from '../utils/objectPrototype';\nimport { getPropertyValue } from '../utils/propertyUtils';\n\nimport { themeAcceptor } from '../styles';\n\nconst createIterator = (showNonenumerable: any, sortObjectKeys: any) => {\n const objectIterator = function* (data: any) {\n const shouldIterate = (typeof data === 'object' && data !== null) || typeof data === 'function';\n if (!shouldIterate) return;\n\n const dataIsArray = Array.isArray(data);\n\n // iterable objects (except arrays)\n if (!dataIsArray && data[Symbol.iterator]) {\n let i = 0;\n for (const entry of data) {\n if (Array.isArray(entry) && entry.length === 2) {\n const [k, v] = entry;\n yield {\n name: k,\n data: v,\n };\n } else {\n yield {\n name: i.toString(),\n data: entry,\n };\n }\n i++;\n }\n } else {\n const keys = Object.getOwnPropertyNames(data);\n if (sortObjectKeys === true && !dataIsArray) {\n // Array keys should not be sorted in alphabetical order\n keys.sort();\n } else if (typeof sortObjectKeys === 'function') {\n keys.sort(sortObjectKeys);\n }\n\n for (const propertyName of keys) {\n if (propertyIsEnumerable.call(data, propertyName)) {\n const propertyValue = getPropertyValue(data, propertyName);\n yield {\n name: propertyName || `\"\"`,\n data: propertyValue,\n };\n } else if (showNonenumerable) {\n // To work around the error (happens some time when propertyName === 'caller' || propertyName === 'arguments')\n // 'caller' and 'arguments' are restricted function properties and cannot be accessed in this context\n // http://stackoverflow.com/questions/31921189/caller-and-arguments-are-restricted-function-properties-and-cannot-be-access\n let propertyValue;\n try {\n propertyValue = getPropertyValue(data, propertyName);\n } catch (e) {\n // console.warn(e)\n }\n\n if (propertyValue !== undefined) {\n yield {\n name: propertyName,\n data: propertyValue,\n isNonenumerable: true,\n };\n }\n }\n }\n\n // [[Prototype]] of the object: `Object.getPrototypeOf(data)`\n // the property name is shown as \"__proto__\"\n if (showNonenumerable && data !== Object.prototype /* already added */) {\n yield {\n name: '__proto__',\n data: Object.getPrototypeOf(data),\n isNonenumerable: true,\n };\n }\n }\n };\n\n return objectIterator;\n};\n\nconst defaultNodeRenderer = ({ depth, name, data, isNonenumerable }: any) =>\n depth === 0 ? (\n <ObjectRootLabel name={name} data={data} />\n ) : (\n <ObjectLabel name={name} data={data} isNonenumerable={isNonenumerable} />\n );\n\n/**\n * Tree-view for objects\n */\nconst ObjectInspector: FC<any> = ({ showNonenumerable = false, sortObjectKeys, nodeRenderer, ...treeViewProps }) => {\n const dataIterator = createIterator(showNonenumerable, sortObjectKeys);\n const renderer = nodeRenderer ? nodeRenderer : defaultNodeRenderer;\n\n return <TreeView nodeRenderer={renderer} dataIterator={dataIterator} {...treeViewProps} />;\n};\n\n// ObjectInspector.propTypes = {\n// /** An integer specifying to which level the tree should be initially expanded. */\n// expandLevel: PropTypes.number,\n// /** An array containing all the paths that should be expanded when the component is initialized, or a string of just one path */\n// expandPaths: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),\n\n// name: PropTypes.string,\n// /** Not required prop because we also allow undefined value */\n// data: PropTypes.any,\n\n// /** Show non-enumerable properties */\n// showNonenumerable: PropTypes.bool,\n// /** Sort object keys with optional compare function. */\n// sortObjectKeys: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),\n\n// /** Provide a custom nodeRenderer */\n// nodeRenderer: PropTypes.func,\n//\n// /** Callback when node is clicked */\n// onExpand: PropTypes.func,\n// };\n\nconst themedObjectInspector = themeAcceptor(ObjectInspector);\n\nexport { themedObjectInspector as ObjectInspector };\n","import React, { useContext, useCallback, useLayoutEffect, useState, memo, MouseEvent } from 'react';\nimport { ExpandedPathsContext } from './ExpandedPathsContext';\nimport { TreeNode } from './TreeNode';\nimport { DEFAULT_ROOT_PATH, hasChildNodes, getExpandedPaths } from './pathUtils';\n\nimport { useStyles } from '../styles';\nimport { ObjectValue } from '../object/ObjectValue';\n\nconst ConnectedTreeNode = memo<any>((props) => {\n const { data, dataIterator, path, depth, nodeRenderer, onExpand } = props;\n const [expandedPaths, setExpandedPaths] = useContext(ExpandedPathsContext);\n const nodeHasChildNodes = hasChildNodes(data, dataIterator);\n const expanded = !!expandedPaths[path];\n const isError = data instanceof Error;\n\n const handleClick = useCallback(\n (e: MouseEvent<HTMLDivElement>) => {\n if (!nodeHasChildNodes) {\n return;\n }\n\n setExpandedPaths((prevExpandedPaths) => ({\n ...prevExpandedPaths,\n [path]: !expanded,\n }));\n\n if (typeof onExpand === 'function') {\n onExpand(path, { ...expandedPaths, [path]: !expanded }, e);\n }\n },\n [nodeHasChildNodes, setExpandedPaths, path, expanded, onExpand]\n );\n\n return (\n <TreeNode\n expanded={expanded}\n // show arrow anyway even if not expanded and not rendering children\n shouldShowArrow={nodeHasChildNodes}\n // show placeholder only for non root nodes\n shouldShowPlaceholder={depth > 0}\n // Render a node from name and data (or possibly other props like isNonenumerable)\n nodeRenderer={nodeRenderer}\n {...props}\n // Do not allow override of `onClick`\n onClick={handleClick}>\n {\n // only render if the node is expanded\n expanded ? (\n isError ? (\n <ObjectValue object={data} />\n ) : (\n [...dataIterator(data)].map(({ name, data, ...renderNodeProps }) => {\n return (\n <ConnectedTreeNode\n name={name}\n data={data}\n depth={depth + 1}\n path={`${path}.${name}`}\n key={name}\n dataIterator={dataIterator}\n nodeRenderer={nodeRenderer}\n onExpand={onExpand}\n {...renderNodeProps}\n />\n );\n })\n )\n ) : null\n }\n </TreeNode>\n );\n});\n\n// ConnectedTreeNode.propTypes = {\n// name: PropTypes.string,\n// data: PropTypes.any,\n// dataIterator: PropTypes.func,\n// depth: PropTypes.number,\n// expanded: PropTypes.bool,\n// nodeRenderer: PropTypes.func,\n// onExpand: PropTypes.func,\n// };\n\nexport const TreeView = memo<any>(({ name, data, dataIterator, nodeRenderer, expandPaths, expandLevel, onExpand }) => {\n const styles = useStyles('TreeView');\n const stateAndSetter = useState({});\n const [, setExpandedPaths] = stateAndSetter;\n\n useLayoutEffect(\n () =>\n setExpandedPaths((prevExpandedPaths) =>\n getExpandedPaths(data, dataIterator, expandPaths, expandLevel, prevExpandedPaths)\n ),\n [data, dataIterator, expandPaths, expandLevel]\n );\n\n return (\n <ExpandedPathsContext.Provider value={stateAndSetter}>\n <ol role=\"tree\" style={styles.treeViewOutline}>\n <ConnectedTreeNode\n name={name}\n data={data}\n dataIterator={dataIterator}\n depth={0}\n path={DEFAULT_ROOT_PATH}\n nodeRenderer={nodeRenderer}\n onExpand={onExpand}\n />\n </ol>\n </ExpandedPathsContext.Provider>\n );\n});\n\n// TreeView.propTypes = {\n// name: PropTypes.string,\n// data: PropTypes.any,\n// dataIterator: PropTypes.func,\n// nodeRenderer: PropTypes.func,\n// expandPaths: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),\n// expandLevel: PropTypes.number,\n// };\n","/* eslint-disable @typescript-eslint/no-empty-function */\nimport { createContext } from 'react';\n\nexport const ExpandedPathsContext = createContext<[any, (...args: any[]) => any]>([{}, () => {}]);\n","/* eslint-disable @typescript-eslint/no-empty-function */\nimport React, { Children, FC, memo } from 'react';\nimport { useStyles } from '../styles';\n\nconst Arrow: FC<any> = ({ expanded, styles }) => (\n <span\n style={{\n ...styles.base,\n ...(expanded ? styles.expanded : styles.collapsed),\n }}>\n ▶\n </span>\n);\n\nexport const TreeNode: FC<any> = memo((props) => {\n props = {\n expanded: true,\n nodeRenderer: ({ name }: any) => <span>{name}</span>,\n onClick: () => {},\n shouldShowArrow: false,\n shouldShowPlaceholder: true,\n ...props,\n };\n const { expanded, onClick, children, nodeRenderer, title, shouldShowArrow, shouldShowPlaceholder } = props;\n\n const styles = useStyles('TreeNode');\n const NodeRenderer = nodeRenderer;\n const isArrowVisible = shouldShowArrow || Children.count(children) > 0;\n\n return (\n <li aria-expanded={expanded} role=\"treeitem\" style={styles.treeNodeBase} title={title}>\n <div style={styles.treeNodePreviewContainer} onClick={onClick}>\n {isArrowVisible || shouldShowPlaceholder ? (\n <Arrow expanded={expanded} styles={isArrowVisible ? styles.treeNodeArrow : styles.treeNodePlaceholder} />\n ) : null}\n <NodeRenderer {...props} />\n </div>\n\n <ol role=\"group\" style={styles.treeNodeChildNodesContainer}>\n {expanded ? children : undefined}\n </ol>\n </li>\n );\n});\n\n// TreeNode.propTypes = {\n// name: PropTypes.string,\n// data: PropTypes.any,\n// expanded: PropTypes.bool,\n// shouldShowArrow: PropTypes.bool,\n// shouldShowPlaceholder: PropTypes.bool,\n// nodeRenderer: PropTypes.func,\n// onClick: PropTypes.func,\n// };\n","import React, { createContext, useContext, useMemo } from 'react';\n\nimport * as themes from './themes';\nimport { createTheme } from './base';\n\nconst DEFAULT_THEME_NAME = 'chromeLight';\n\nconst ThemeContext = createContext(createTheme(themes[DEFAULT_THEME_NAME]));\n\n/**\n * Hook to get the component styles for the current theme.\n * @param {string} baseStylesKey - Name of the component to be styled\n */\nexport const useStyles = (baseStylesKey: any) => {\n const themeStyles = useContext(ThemeContext);\n //@ts-ignore\n return themeStyles[baseStylesKey];\n};\n\n/**\n * HOC to create a component that accepts a \"theme\" prop and uses it to set\n * the current theme. This is intended to be used by the top-level inspector\n * components.\n * @param {Object} WrappedComponent - React component to be wrapped\n */\nexport const themeAcceptor = (WrappedComponent: any) => {\n const ThemeAcceptor = ({ theme = DEFAULT_THEME_NAME, ...restProps }) => {\n const themeStyles = useMemo(() => {\n switch (Object.prototype.toString.call(theme)) {\n case '[object String]':\n //@ts-ignore\n return createTheme(themes[theme]);\n case '[object Object]':\n return createTheme(theme);\n default:\n return createTheme(themes[DEFAULT_THEME_NAME]);\n }\n }, [theme]);\n\n return (\n <ThemeContext.Provider value={themeStyles}>\n <WrappedComponent {...restProps} />\n </ThemeContext.Provider>\n );\n };\n\n // ThemeAcceptor.propTypes = {\n // theme: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),\n // };\n\n return ThemeAcceptor;\n};\n","export const unselectable = {\n WebkitTouchCallout: 'none',\n WebkitUserSelect: 'none',\n KhtmlUserSelect: 'none',\n MozUserSelect: 'none',\n msUserSelect: 'none',\n OUserSelect: 'none',\n userSelect: 'none',\n};\n","import { unselectable } from './unselectable';\n\nexport const createTheme = (theme: any) => ({\n DOMNodePreview: {\n htmlOpenTag: {\n base: {\n color: theme.HTML_TAG_COLOR,\n },\n tagName: {\n color: theme.HTML_TAGNAME_COLOR,\n textTransform: theme.HTML_TAGNAME_TEXT_TRANSFORM,\n },\n htmlAttributeName: {\n color: theme.HTML_ATTRIBUTE_NAME_COLOR,\n },\n htmlAttributeValue: {\n color: theme.HTML_ATTRIBUTE_VALUE_COLOR,\n },\n },\n htmlCloseTag: {\n base: {\n color: theme.HTML_TAG_COLOR,\n },\n offsetLeft: {\n /* hack: offset placeholder */\n marginLeft: -theme.TREENODE_PADDING_LEFT,\n },\n tagName: {\n color: theme.HTML_TAGNAME_COLOR,\n textTransform: theme.HTML_TAGNAME_TEXT_TRANSFORM,\n },\n },\n htmlComment: {\n color: theme.HTML_COMMENT_COLOR,\n },\n htmlDoctype: {\n color: theme.HTML_DOCTYPE_COLOR,\n },\n },\n\n ObjectPreview: {\n objectDescription: {\n fontStyle: 'italic',\n },\n preview: {\n fontStyle: 'italic',\n },\n arrayMaxProperties: theme.OBJECT_PREVIEW_ARRAY_MAX_PROPERTIES,\n objectMaxProperties: theme.OBJECT_PREVIEW_OBJECT_MAX_PROPERTIES,\n errorMessage: {\n color: theme.ERROR_COLOR,\n },\n },\n\n ObjectName: {\n base: {\n color: theme.OBJECT_NAME_COLOR,\n },\n dimmed: {\n opacity: 0.6,\n },\n },\n\n ObjectValue: {\n objectValueNull: {\n color: theme.OBJECT_VALUE_NULL_COLOR,\n },\n objectValueUndefined: {\n color: theme.OBJECT_VALUE_UNDEFINED_COLOR,\n },\n objectValueRegExp: {\n color: theme.OBJECT_VALUE_REGEXP_COLOR,\n },\n objectValueString: {\n color: theme.OBJECT_VALUE_STRING_COLOR,\n },\n objectValueSymbol: {\n color: theme.OBJECT_VALUE_SYMBOL_COLOR,\n },\n objectValueNumber: {\n color: theme.OBJECT_VALUE_NUMBER_COLOR,\n },\n objectValueBoolean: {\n color: theme.OBJECT_VALUE_BOOLEAN_COLOR,\n },\n objectValueFunctionPrefix: {\n color: theme.OBJECT_VALUE_FUNCTION_PREFIX_COLOR,\n fontStyle: 'italic',\n },\n objectValueFunctionName: {\n fontStyle: 'italic',\n },\n objectErrorValue: {\n color: theme.ERROR_COLOR,\n whiteSpace: 'pre-wrap',\n },\n },\n\n TreeView: {\n treeViewOutline: {\n padding: 0,\n margin: 0,\n listStyleType: 'none',\n },\n },\n\n TreeNode: {\n treeNodeBase: {\n color: theme.BASE_COLOR,\n backgroundColor: theme.BASE_BACKGROUND_COLOR,\n\n lineHeight: theme.TREENODE_LINE_HEIGHT,\n cursor: 'default',\n\n boxSizing: 'border-box',\n listStyle: 'none',\n\n fontFamily: theme.TREENODE_FONT_FAMILY,\n fontSize: theme.TREENODE_FONT_SIZE,\n },\n treeNodePreviewContainer: {},\n treeNodePlaceholder: {\n base: {\n whiteSpace: 'pre',\n // Width of arrow can differ from nbsp to font customizations,\n // always render arrow so that we can have consistent placeholder widths.\n visibility: 'hidden',\n\n fontSize: theme.ARROW_FONT_SIZE,\n marginRight: theme.ARROW_MARGIN_RIGHT,\n ...unselectable,\n },\n },\n treeNodeArrow: {\n base: {\n color: theme.ARROW_COLOR,\n display: 'inline-block',\n // lineHeight: '14px',\n fontSize: theme.ARROW_FONT_SIZE,\n marginRight: theme.ARROW_MARGIN_RIGHT,\n ...(parseFloat(theme.ARROW_ANIMATION_DURATION) > 0\n ? {\n transition: `transform ${theme.ARROW_ANIMATION_DURATION} ease 0s`,\n }\n : {}),\n ...unselectable,\n },\n expanded: {\n WebkitTransform: 'rotateZ(90deg)',\n MozTransform: 'rotateZ(90deg)',\n transform: 'rotateZ(90deg)',\n },\n collapsed: {\n WebkitTransform: 'rotateZ(0deg)',\n MozTransform: 'rotateZ(0deg)',\n transform: 'rotateZ(0deg)',\n },\n },\n treeNodeChildNodesContainer: {\n margin: 0, // reset user-agent style\n paddingLeft: theme.TREENODE_PADDING_LEFT,\n },\n },\n\n TableInspector: {\n base: {\n color: theme.BASE_COLOR,\n\n position: 'relative',\n border: `1px solid ${theme.TABLE_BORDER_COLOR}`,\n fontFamily: theme.BASE_FONT_FAMILY,\n fontSize: theme.BASE_FONT_SIZE,\n lineHeight: '120%',\n boxSizing: 'border-box',\n cursor: 'default',\n },\n },\n\n TableInspectorHeaderContainer: {\n base: {\n top: 0,\n height: '17px',\n left: 0,\n right: 0,\n overflowX: 'hidden',\n },\n table: {\n tableLayout: 'fixed',\n borderSpacing: 0,\n borderCollapse: 'separate',\n height: '100%',\n width: '100%',\n margin: 0,\n },\n },\n\n TableInspectorDataContainer: {\n tr: {\n display: 'table-row',\n },\n td: {\n boxSizing: 'border-box',\n border: 'none', // prevent overrides\n height: '16px', // /* 0.5 * table.background-size height */\n verticalAlign: 'top',\n padding: '1px 4px',\n WebkitUserSelect: 'text',\n\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n lineHeight: '14px',\n },\n div: {\n position: 'static',\n top: '17px',\n bottom: 0,\n overflowY: 'overlay',\n transform: 'translateZ(0)',\n\n left: 0,\n right: 0,\n overflowX: 'hidden',\n },\n table: {\n positon: 'static',\n left: 0,\n top: 0,\n right: 0,\n bottom: 0,\n borderTop: '0 none transparent',\n margin: 0, // prevent user agent stylesheet overrides\n\n backgroundImage: theme.TABLE_DATA_BACKGROUND_IMAGE,\n backgroundSize: theme.TABLE_DATA_BACKGROUND_SIZE,\n tableLayout: 'fixed',\n\n // table\n borderSpacing: 0,\n borderCollapse: 'separate',\n // height: '100%',\n width: '100%',\n\n fontSize: theme.BASE_FONT_SIZE,\n lineHeight: '120%',\n },\n },\n\n TableInspectorTH: {\n base: {\n position: 'relative', // anchor for sort icon container\n height: 'auto',\n textAlign: 'left',\n backgroundColor: theme.TABLE_TH_BACKGROUND_COLOR,\n borderBottom: `1px solid ${theme.TABLE_BORDER_COLOR}`,\n fontWeight: 'normal',\n verticalAlign: 'middle',\n padding: '0 4px',\n\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n lineHeight: '14px',\n\n ':hover': {\n backgroundColor: theme.TABLE_TH_HOVER_COLOR,\n },\n },\n div: {\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n\n // prevent user agent stylesheet overrides\n fontSize: theme.BASE_FONT_SIZE,\n lineHeight: '120%',\n },\n },\n\n TableInspectorLeftBorder: {\n none: {\n borderLeft: 'none',\n },\n solid: {\n borderLeft: `1px solid ${theme.TABLE_BORDER_COLOR}`,\n },\n },\n\n TableInspectorSortIcon: {\n display: 'block',\n marginRight: 3, // 4,\n width: 8,\n height: 7,\n\n marginTop: -7,\n color: theme.TABLE_SORT_ICON_COLOR,\n fontSize: 12,\n // lineHeight: 14\n ...unselectable,\n },\n});\n","export const DEFAULT_ROOT_PATH = '$';\n\nconst WILDCARD = '*';\n\nexport function hasChildNodes(data, dataIterator) {\n // We pretend that Error objects have a child node so that the stack trace\n // can be expanded/collapsed.\n return !dataIterator(data).next().done || (data instanceof Error && data.stack !== undefined);\n}\n\nexport const wildcardPathsFromLevel = (level) => {\n // i is depth\n return Array.from({ length: level }, (_, i) =>\n [DEFAULT_ROOT_PATH].concat(Array.from({ length: i }, () => '*')).join('.')\n );\n};\n\nexport const getExpandedPaths = (data, dataIterator, expandPaths, expandLevel, prevExpandedPaths) => {\n const wildcardPaths = []\n .concat(wildcardPathsFromLevel(expandLevel))\n .concat(expandPaths)\n .filter((path) => typeof path === 'string'); // could be undefined\n\n const expandedPaths = [];\n wildcardPaths.forEach((wildcardPath) => {\n const keyPaths = wildcardPath.split('.');\n const populatePaths = (curData, curPath, depth) => {\n if (depth === keyPaths.length) {\n expandedPaths.push(curPath);\n return;\n }\n const key = keyPaths[depth];\n if (depth === 0) {\n if (hasChildNodes(curData, dataIterator) && (key === DEFAULT_ROOT_PATH || key === WILDCARD)) {\n populatePaths(curData, DEFAULT_ROOT_PATH, depth + 1);\n }\n } else {\n if (key === WILDCARD) {\n for (const { name, data } of dataIterator(curData)) {\n if (hasChildNodes(data, dataIterator)) {\n populatePaths(data, `${curPath}.${name}`, depth + 1);\n }\n }\n } else {\n const value = curData[key];\n if (hasChildNodes(value, dataIterator)) {\n populatePaths(value, `${curPath}.${key}`, depth + 1);\n }\n }\n }\n };\n\n populatePaths(data, '', 0);\n });\n\n return expandedPaths.reduce(\n (obj, path) => {\n obj[path] = true;\n return obj;\n },\n { ...prevExpandedPaths }\n );\n};\n","import React, { FC } from 'react';\n\nimport { useStyles } from '../styles';\n\n/**\n * A short description of the object values.\n * Can be used to render tree node in ObjectInspector\n * or render objects in TableInspector.\n */\nexport const ObjectValue: FC<any> = ({ object, styles }) => {\n const themeStyles = useStyles('ObjectValue');\n\n const mkStyle = (key: any) => ({ ...themeStyles[key], ...styles });\n\n switch (typeof object) {\n case 'bigint':\n return <span style={mkStyle('objectValueNumber')}>{String(object)}n</span>;\n case 'number':\n return <span style={mkStyle('objectValueNumber')}>{String(object)}</span>;\n case 'string':\n return <span style={mkStyle('objectValueString')}>\"{object}\"</span>;\n case 'boolean':\n return <span style={mkStyle('objectValueBoolean')}>{String(object)}</span>;\n case 'undefined':\n return <span style={mkStyle('objectValueUndefined')}>undefined</span>;\n case 'object':\n if (object === null) {\n return <span style={mkStyle('objectValueNull')}>null</span>;\n }\n if (object instanceof Date) {\n return <span>{object.toString()}</span>;\n }\n if (object instanceof RegExp) {\n return <span style={mkStyle('objectValueRegExp')}>{object.toString()}</span>;\n }\n if (object instanceof Error) {\n const stackArray = typeof object.stack === 'string' && object.stack.split('\\n');\n // Drop the first line if it's the error message (Chrome only)\n const [firstLine, ...stack] = stackArray || [];\n const stackString =\n firstLine === object.toString() && stack ? stack.join('\\n') : stackArray ? stackArray.join('\\n') : '';\n return <span style={mkStyle('objectErrorValue')}>{stackString}</span>;\n }\n if (Array.isArray(object)) {\n return <span>{`Array(${object.length})`}</span>;\n }\n if (!object.constructor) {\n return <span>Object</span>;\n }\n if (typeof object.constructor.isBuffer === 'function' && object.constructor.isBuffer(object)) {\n return <span>{`Buffer[${object.length}]`}</span>;\n }\n\n return <span>{object.constructor.name}</span>;\n case 'function':\n return (\n <span>\n <span style={mkStyle('objectValueFunctionPrefix')}>ƒ </span>\n <span style={mkStyle('objectValueFunctionName')}>{object.name}()</span>\n </span>\n );\n case 'symbol':\n return <span style={mkStyle('objectValueSymbol')}>{object.toString()}</span>;\n default:\n return <span />;\n }\n};\n\n// ObjectValue.propTypes = {\n// // the object to describe\n// object: PropTypes.any,\n// };\n","import React, { FC } from 'react';\nimport { ObjectName } from '../object/ObjectName';\nimport { ObjectPreview } from './ObjectPreview';\n\nexport const ObjectRootLabel: FC<any> = ({ name, data }) => {\n if (typeof name === 'string') {\n return (\n <span>\n <ObjectName name={name} />\n <span>: </span>\n <ObjectPreview data={data} />\n </span>\n );\n } else {\n return <ObjectPreview data={data} />;\n }\n};\n","import React, { FC } from 'react';\nimport { useStyles } from '../styles';\n\n/**\n * A view for object property names.\n *\n * If the property name is enumerable (in Object.keys(object)),\n * the property name will be rendered normally.\n *\n * If the property name is not enumerable (`Object.prototype.propertyIsEnumerable()`),\n * the property name will be dimmed to show the difference.\n */\nexport const ObjectName: FC<any> = ({ name, dimmed = false, styles = {} }) => {\n const themeStyles = useStyles('ObjectName');\n const appliedStyles = {\n ...themeStyles.base,\n ...(dimmed ? themeStyles['dimmed'] : {}),\n ...styles,\n };\n\n return <span style={appliedStyles}>{name}</span>;\n};\n\n// ObjectName.propTypes = {\n// /** Property name */\n// name: PropTypes.string,\n// /** Should property name be dimmed */\n// dimmed: PropTypes.bool,\n// };\n","import React, { FC, ReactChild } from 'react';\n\nimport { ObjectValue } from '../object/ObjectValue';\nimport { ObjectName } from '../object/ObjectName';\n\nimport { useStyles } from '../styles';\n\nimport { hasOwnProperty } from '../utils/objectPrototype';\nimport { getPropertyValue } from '../utils/propertyUtils';\n\n/* intersperse arr with separator */\nfunction intersperse(arr: any[], sep: string) {\n if (arr.length === 0) {\n return [];\n }\n\n return arr.slice(1).reduce((xs, x) => xs.concat([sep, x]), [arr[0]]);\n}\n\n/**\n * A preview of the object\n */\nexport const ObjectPreview: FC<any> = ({ data }) => {\n const styles = useStyles('ObjectPreview');\n const object = data;\n\n if (typeof object !== 'object' || object === null || object instanceof Date || object instanceof RegExp) {\n return <ObjectValue object={object} />;\n }\n\n if (Array.isArray(object)) {\n const maxProperties = styles.arrayMaxProperties;\n const previewArray = object\n .slice(0, maxProperties)\n .map((element, index) => <ObjectValue key={index} object={element} />);\n if (object.length > maxProperties) {\n previewArray.push(<span key=\"ellipsis\">…</span>);\n }\n const arrayLength = object.length;\n return (\n <React.Fragment>\n <span style={styles.objectDescription}>{arrayLength === 0 ? `` : `(${arrayLength})\\xa0`}</span>\n <span style={styles.preview}>[{intersperse(previewArray, ', ')}]</span>\n </React.Fragment>\n );\n } else {\n const maxProperties = styles.objectMaxProperties;\n const propertyNodes: ReactChild[] = [];\n for (const propertyName in object) {\n if (hasOwnProperty.call(object, propertyName)) {\n let ellipsis;\n if (propertyNodes.length === maxProperties - 1 && Object.keys(object).length > maxProperties) {\n ellipsis = <span key={'ellipsis'}>…</span>;\n }\n\n const propertyValue = getPropertyValue(object, propertyName);\n propertyNodes.push(\n <span key={propertyName}>\n <ObjectName name={propertyName || `\"\"`} />\n : \n <ObjectValue object={propertyValue} />\n {ellipsis}\n </span>\n );\n if (ellipsis) break;\n }\n }\n\n if (object instanceof Error) {\n const errorConstructorName = object.constructor ? object.constructor.name : object.name ? object.name : 'Error';\n\n return (\n <React.Fragment>\n <span style={styles.errorMessage}>{errorConstructorName}: </span>\n <span style={styles.errorMessage}>{object.message}</span>\n </React.Fragment>\n );\n }\n\n const objectConstructorName = object.constructor ? object.constructor.name : 'Object';\n\n return (\n <React.Fragment>\n <span style={styles.objectDescription}>\n {objectConstructorName === 'Object' ? '' : `${objectConstructorName} `}\n </span>\n <span style={styles.preview}>\n {'{'}\n {intersperse(propertyNodes, ', ')}\n {'}'}\n </span>\n </React.Fragment>\n );\n }\n};\n","export const hasOwnProperty = Object.prototype.hasOwnProperty;\nexport const propertyIsEnumerable = Object.prototype.propertyIsEnumerable;\n","export function getPropertyValue(object, propertyName) {\n const propertyDescriptor = Object.getOwnPropertyDescriptor(object, propertyName);\n if (propertyDescriptor.get) {\n try {\n return propertyDescriptor.get();\n } catch {\n return propertyDescriptor.get;\n }\n }\n\n return object[propertyName];\n}\n","import React, { FC } from 'react';\nimport { ObjectName } from '../object/ObjectName';\nimport { ObjectValue } from '../object/ObjectValue';\nimport { ObjectPreview } from './ObjectPreview';\n\n/**\n * if isNonenumerable is specified, render the name dimmed\n */\nexport const ObjectLabel: FC<any> = ({ name, data, isNonenumerable = false }) => {\n const object = data;\n\n return (\n <span>\n {typeof name === 'string' ? <ObjectName name={name} dimmed={isNonenumerable} /> : <ObjectPreview data={name} />}\n <span>: </span>\n <ObjectValue object={object} />\n </span>\n );\n};\n\n// ObjectLabel.propTypes = {\n// /** Non enumerable object property will be dimmed */\n// isNonenumerable: PropTypes.bool,\n// };\n","/**\n * Specs:\n * https://developer.chrome.com/devtools/docs/commandline-api#tabledata-columns\n * https://developer.mozilla.org/en-US/docs/Web/API/Console/table\n */\n\nimport React, { FC, useCallback, useState } from 'react';\n\nimport { getHeaders } from './getHeaders';\nimport { DataContainer } from './DataContainer';\nimport { HeaderContainer } from './HeaderContainer';\n\nimport { themeAcceptor, useStyles } from '../styles';\n\nconst TableInspector: FC<any> = ({\n // The JS object you would like to inspect, either an array or an object\n data,\n // An array of the names of the columns you'd like to display in the table\n columns,\n}) => {\n const styles = useStyles('TableInspector');\n\n const [{ sorted, sortIndexColumn, sortColumn, sortAscending }, setState] = useState({\n // has user ever clicked the <th> tag to sort?\n sorted: false,\n // is index column sorted?\n sortIndexColumn: false,\n // which column is sorted?\n sortColumn: undefined,\n // is sorting ascending or descending?\n sortAscending: false,\n });\n\n const handleIndexTHClick = useCallback(() => {\n setState(({ sortIndexColumn, sortAscending }) => ({\n sorted: true,\n sortIndexColumn: true,\n sortColumn: undefined,\n // when changed to a new column, default to asending\n sortAscending: sortIndexColumn ? !sortAscending : true,\n }));\n }, []);\n\n const handleTHClick = useCallback((col) => {\n setState(({ sortColumn, sortAscending }) => ({\n sorted: true,\n sortIndexColumn: false,\n // update sort column\n sortColumn: col,\n // when changed to a new column, default to asending\n sortAscending: col === sortColumn ? !sortAscending : true,\n }));\n }, []);\n\n if (typeof data !== 'object' || data === null) {\n return <div />;\n }\n\n let { rowHeaders, colHeaders } = getHeaders(data);\n\n // columns to be displayed are specified\n // NOTE: there's some space for optimization here\n if (columns !== undefined) {\n colHeaders = columns;\n }\n\n let rowsData = rowHeaders.map((rowHeader) => data[rowHeader]);\n\n let columnDataWithRowIndexes; /* row indexes are [0..nRows-1] */\n // TODO: refactor\n if (sortColumn !== undefined) {\n // the column to be sorted (rowsData, column) => [[columnData, rowIndex]]\n columnDataWithRowIndexes = rowsData.map((rowData, index: number) => {\n // normalize rowData\n if (typeof rowData === 'object' && rowData !== null /*&& rowData.hasOwnProperty(sortColumn)*/) {\n const columnData = rowData[sortColumn];\n return [columnData, index];\n }\n return [undefined, index];\n });\n } else {\n if (sortIndexColumn) {\n columnDataWithRowIndexes = rowHeaders.map((rowData, index: number) => {\n const columnData = rowHeaders[index];\n return [columnData, index];\n });\n }\n }\n if (columnDataWithRowIndexes !== undefined) {\n // apply a mapper before sorting (because we need to access inside a container)\n const comparator = (mapper, ascending) => {\n return (a, b) => {\n const v1 = mapper(a); // the datum\n const v2 = mapper(b);\n const type1 = typeof v1;\n const type2 = typeof v2;\n // use '<' operator to compare same type of values or compare type precedence order #\n const lt = (v1, v2) => {\n if (v1 < v2) {\n return -1;\n } else if (v1 > v2) {\n return 1;\n } else {\n return 0;\n }\n };\n let result;\n if (type1 === type2) {\n result = lt(v1, v2);\n } else {\n // order of different types\n const order = {\n string: 0,\n number: 1,\n object: 2,\n symbol: 3,\n boolean: 4,\n undefined: 5,\n function: 6,\n };\n result = lt(order[type1], order[type2]);\n }\n // reverse result if descending\n if (!ascending) result = -result;\n return result;\n };\n };\n const sortedRowIndexes = columnDataWithRowIndexes\n .sort(comparator((item) => item[0], sortAscending))\n .map((item) => item[1]); // sorted row indexes\n rowHeaders = sortedRowIndexes.map((i) => rowHeaders[i]);\n rowsData = sortedRowIndexes.map((i) => rowsData[i]);\n }\n\n return (\n <div style={styles.base}>\n <HeaderContainer\n columns={colHeaders}\n /* for sorting */\n sorted={sorted}\n sortIndexColumn={sortIndexColumn}\n sortColumn={sortColumn}\n sortAscending={sortAscending}\n onTHClick={handleTHClick}\n onIndexTHClick={handleIndexTHClick}\n />\n <DataContainer rows={rowHeaders} columns={colHeaders} rowsData={rowsData} />\n </div>\n );\n};\n\n// TableInspector.propTypes = {\n// /**\n// * the Javascript object you would like to inspect, either an array or an object\n// */\n// data: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),\n// /**\n// * An array of the names of the columns you'd like to display in the table\n// */\n// columns: PropTypes.array,\n// };\n\nconst themedTableInspector = themeAcceptor(TableInspector);\n\nexport { themedTableInspector as TableInspector };\n","export function getHeaders(data): any {\n if (typeof data === 'object') {\n let rowHeaders: any[] = [];\n // is an array\n if (Array.isArray(data)) {\n const nRows = data.length;\n rowHeaders = [...Array(nRows).keys()];\n } else if (data !== null) {\n // is an object\n // keys are row indexes\n rowHeaders = Object.keys(data);\n }\n\n // Time: O(nRows * nCols)\n const colHeaders = rowHeaders.reduce((colHeaders, rowHeader) => {\n const row = data[rowHeader];\n if (typeof row === 'object' && row !== null) {\n /* O(nCols) Could optimize `includes` here */\n const cols = Object.keys(row);\n cols.reduce((xs, x) => {\n if (!xs.includes(x)) {\n /* xs is the colHeaders to be filled by searching the row's indexes */\n xs.push(x);\n }\n return xs;\n }, colHeaders);\n }\n return colHeaders;\n }, []);\n return {\n rowHeaders: rowHeaders,\n colHeaders: colHeaders,\n };\n }\n return undefined;\n}\n","import React from 'react';\nimport { ObjectValue } from '../object/ObjectValue';\n\nimport { hasOwnProperty } from '../utils/objectPrototype';\n\nimport { useStyles } from '../styles';\n\nexport const DataContainer = ({ rows, columns, rowsData }) => {\n const styles = useStyles('TableInspectorDataContainer');\n const borderStyles = useStyles('TableInspectorLeftBorder');\n\n return (\n <div style={styles.div}>\n <table style={styles.table}>\n <colgroup />\n <tbody>\n {rows.map((row, i) => (\n <tr key={row} style={styles.tr}>\n <td style={{ ...styles.td, ...borderStyles.none }}>{row}</td>\n\n {columns.map((column) => {\n const rowData = rowsData[i];\n // rowData could be\n // object -> index by key\n // array -> index by array index\n // null -> pass\n // boolean -> pass\n // string -> pass (hasOwnProperty returns true for [0..len-1])\n // number -> pass\n // function -> pass\n // symbol\n // undefined -> pass\n if (typeof rowData === 'object' && rowData !== null && hasOwnProperty.call(rowData, column)) {\n return (\n <td key={column} style={{ ...styles.td, ...borderStyles.solid }}>\n <ObjectValue object={rowData[column]} />\n </td>\n );\n } else {\n return <td key={column} style={{ ...styles.td, ...borderStyles.solid }} />;\n }\n })}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n};\n","import React from 'react';\nimport { useStyles } from '../styles';\nimport { TH } from './TH';\n\nexport const HeaderContainer = ({\n indexColumnText = '(index)',\n columns = [],\n sorted,\n sortIndexColumn,\n sortColumn,\n sortAscending,\n onTHClick,\n onIndexTHClick,\n}) => {\n const styles = useStyles('TableInspectorHeaderContainer');\n const borderStyles = useStyles('TableInspectorLeftBorder');\n return (\n <div style={styles.base}>\n <table style={styles.table}>\n <tbody>\n <tr>\n <TH\n borderStyle={borderStyles.none}\n sorted={sorted && sortIndexColumn}\n sortAscending={sortAscending}\n onClick={onIndexTHClick}>\n {indexColumnText}\n </TH>\n {columns.map((column) => (\n <TH\n borderStyle={borderStyles.solid}\n key={column}\n sorted={sorted && sortColumn === column}\n sortAscending={sortAscending}\n onClick={onTHClick.bind(null, column)}>\n {column}\n </TH>\n ))}\n </tr>\n </tbody>\n </table>\n </div>\n );\n};\n","import React, { useCallback, useState } from 'react';\n\nimport { useStyles } from '../styles';\n\nconst SortIconContainer = (props) => (\n <div\n style={{\n position: 'absolute',\n top: 1,\n right: 0,\n bottom: 1,\n display: 'flex',\n alignItems: 'center',\n }}>\n {props.children}\n </div>\n);\n\nconst SortIcon = ({ sortAscending }) => {\n const styles = useStyles('TableInspectorSortIcon');\n const glyph = sortAscending ? '▲' : '▼';\n return <div style={styles}>{glyph}</div>;\n};\n\nexport const TH = ({\n sortAscending = false,\n sorted = false,\n onClick = undefined,\n borderStyle = {},\n children,\n ...thProps\n}) => {\n const styles = useStyles('TableInspectorTH');\n const [hovered, setHovered] = useState(false);\n\n const handleMouseEnter = useCallback(() => setHovered(true), []);\n const handleMouseLeave = useCallback(() => setHovered(false), []);\n\n return (\n <th\n {...thProps}\n style={{\n ...styles.base,\n ...borderStyle,\n ...(hovered ? styles.base[':hover'] : {}),\n }}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onClick={onClick}>\n <div style={styles.div}>{children}</div>\n {sorted && (\n <SortIconContainer>\n <SortIcon sortAscending={sortAscending} />\n </SortIconContainer>\n )}\n </th>\n );\n};\n","import React, { FC } from 'react';\n\nimport { DOMNodePreview } from './DOMNodePreview';\nimport { TreeView } from '../tree-view/TreeView';\n\nimport { shouldInline } from './shouldInline';\nimport { themeAcceptor } from '../styles';\n\nconst domIterator = function* (data: any) {\n if (data && data.childNodes) {\n const textInlined = shouldInline(data);\n\n if (textInlined) {\n return;\n }\n\n for (let i = 0; i < data.childNodes.length; i++) {\n const node = data.childNodes[i];\n\n if (node.nodeType === Node.TEXT_NODE && node.textContent.trim().length === 0) continue;\n\n yield {\n name: `${node.tagName}[${i}]`,\n data: node,\n };\n }\n\n // at least 1 child node\n if (data.tagName) {\n yield {\n name: 'CLOSE_TAG',\n data: {\n tagName: data.tagName,\n },\n isCloseTag: true,\n };\n }\n }\n};\n\nconst DOMInspector: FC<any> = (props) => {\n return <TreeView nodeRenderer={DOMNodePreview} dataIterator={domIterator} {...props} />;\n};\n\n// DOMInspector.propTypes = {\n// // The DOM Node to inspect\n// data: PropTypes.object.isRequired,\n// };\n\nconst themedDOMInspector = themeAcceptor(DOMInspector);\n\nexport { themedDOMInspector as DOMInspector };\n","import React, { FC, ReactChild } from 'react';\n\nimport { useStyles } from '../styles';\nimport { shouldInline } from './shouldInline';\n\nconst OpenTag: FC<any> = ({ tagName, attributes, styles }) => {\n return (\n <span style={styles.base}>\n {'<'}\n <span style={styles.tagName}>{tagName}</span>\n\n {(() => {\n if (attributes) {\n const attributeNodes: ReactChild[] = [];\n for (let i = 0; i < attributes.length; i++) {\n const attribute = attributes[i];\n attributeNodes.push(\n <span key={i}>\n {' '}\n <span style={styles.htmlAttributeName}>{attribute.name}</span>\n {'=\"'}\n <span style={styles.htmlAttributeValue}>{attribute.value}</span>\n {'\"'}\n </span>\n );\n }\n return attributeNodes;\n }\n })()}\n\n {'>'}\n </span>\n );\n};\n\n// isChildNode style={{ marginLeft: -12 /* hack: offset placeholder */ }}\nconst CloseTag = ({ tagName, isChildNode = false, styles }) => (\n <span style={Object.assign({}, styles.base, isChildNode && styles.offsetLeft)}>\n {'</'}\n <span style={styles.tagName}>{tagName}</span>\n {'>'}\n </span>\n);\n\nconst nameByNodeType = {\n 1: 'ELEMENT_NODE',\n 3: 'TEXT_NODE',\n 7: 'PROCESSING_INSTRUCTION_NODE',\n 8: 'COMMENT_NODE',\n 9: 'DOCUMENT_NODE',\n 10: 'DOCUMENT_TYPE_NODE', // http://stackoverflow.com/questions/6088972/get-doctype-of-an-html-as-string-with-javascript\n 11: 'DOCUMENT_FRAGMENT_NODE',\n};\n\nexport const DOMNodePreview: FC<any> = ({ isCloseTag, data, expanded }) => {\n const styles = useStyles('DOMNodePreview');\n\n if (isCloseTag) {\n return <CloseTag styles={styles.htmlCloseTag} isChildNode tagName={data.tagName} />;\n }\n\n switch (data.nodeType) {\n case Node.ELEMENT_NODE:\n return (\n <span>\n <OpenTag tagName={data.tagName} attributes={data.attributes} styles={styles.htmlOpenTag} />\n\n {shouldInline(data) ? data.textContent : !expanded && '…'}\n\n {!expanded && <CloseTag tagName={data.tagName} styles={styles.htmlCloseTag} />}\n </span>\n );\n case Node.TEXT_NODE:\n return <span>{data.textContent}</span>;\n case Node.CDATA_SECTION_NODE:\n return <span>{'<![CDATA[' + data.textContent + ']]>'}</span>;\n case Node.COMMENT_NODE:\n return (\n <span style={styles.htmlComment}>\n {'<!--'}\n {data.tex