// ES6 + inline style port of JSONViewer https://bitbucket.org/davevedder/react-json-viewer/ // all credits and original code to the author // Dave Vedder http://www.eskimospy.com/ // port by Daniele Zannotti http://www.github.com/dzannotti import React from 'react'; import PropTypes from 'prop-types'; import JSONNode from './JSONNode'; import createStylingFromTheme from './createStylingFromTheme'; import { invertTheme, type StylingConfig, type StylingFunction, type StylingValue, type Theme, } from 'react-base16-styling'; import { CircularPropsPassedThroughJSONTree } from './types'; interface Props extends CircularPropsPassedThroughJSONTree { data: any; theme?: Theme; invertTheme: boolean; } interface State { styling: StylingFunction; } const identity = (value: any) => value; const expandRootNode = ( keyPath: (string | number)[], data: any, level: number ) => level === 0; const defaultItemString = ( type: string, data: any, itemType: React.ReactNode, itemString: string ) => ( {itemType} {itemString} ); const defaultLabelRenderer = ([label]: (string | number)[]) => ( {label}: ); const noCustomNode = () => false; function checkLegacyTheming(theme: Theme | undefined, props: Props) { const deprecatedStylingMethodsMap = { getArrowStyle: 'arrow', getListStyle: 'nestedNodeChildren', getItemStringStyle: 'nestedNodeItemString', getLabelStyle: 'label', getValueStyle: 'valueText', }; const deprecatedStylingMethods = Object.keys( deprecatedStylingMethodsMap ).filter((name) => props[name as keyof Props]); if (deprecatedStylingMethods.length > 0) { if (typeof theme === 'string') { theme = { extend: theme, }; } else { theme = { ...theme }; } deprecatedStylingMethods.forEach((name) => { // eslint-disable-next-line no-console console.error( `Styling method "${name}" is deprecated, use "theme" property instead` ); (theme as StylingConfig)[ deprecatedStylingMethodsMap[ name as keyof typeof deprecatedStylingMethodsMap ] ] = ({ style }, ...args) => ({ style: { ...style, ...props[name as keyof Props](...args), }, }); }); } return theme; } function getStateFromProps(props: Props) { let theme = checkLegacyTheming(props.theme, props); if (props.invertTheme) { theme = invertTheme(theme); } return { styling: createStylingFromTheme(theme), }; } export class JSONTree extends React.Component { static propTypes = { data: PropTypes.any, hideRoot: PropTypes.bool, theme: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), invertTheme: PropTypes.bool, keyPath: PropTypes.arrayOf( PropTypes.oneOfType([PropTypes.string, PropTypes.number]) ), postprocessValue: PropTypes.func, sortObjectKeys: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]), }; static defaultProps = { shouldExpandNode: expandRootNode, hideRoot: false, keyPath: ['root'], getItemString: defaultItemString, labelRenderer: defaultLabelRenderer, valueRenderer: identity, postprocessValue: identity, isCustomNode: noCustomNode, collectionLimit: 50, invertTheme: true, }; constructor(props: Props) { super(props); this.state = getStateFromProps(props); } UNSAFE_componentWillReceiveProps(nextProps: Props) { if ( ['theme', 'invertTheme'].find( (k) => nextProps[k as keyof Props] !== this.props[k as keyof Props] ) ) { this.setState(getStateFromProps(nextProps)); } } shouldComponentUpdate(nextProps: Props) { return !!Object.keys(nextProps).find((k) => k === 'keyPath' ? nextProps[k].join('/') !== this.props[k].join('/') : nextProps[k as keyof Props] !== this.props[k as keyof Props] ); } render() { const { data: value, keyPath, postprocessValue, hideRoot, theme, // eslint-disable-line no-unused-vars invertTheme: _, // eslint-disable-line no-unused-vars ...rest } = this.props; const { styling } = this.state; return (
); } } export { StylingValue };