import React, { useCallback, useState } from 'react'; import JSONArrow from './JSONArrow'; import getCollectionEntries from './getCollectionEntries'; import JSONNode from './JSONNode'; import ItemRange from './ItemRange'; import type { CircularCache, CommonInternalProps } from './types'; /** * Renders nested values (eg. objects, arrays, lists, etc.) */ export interface RenderChildNodesProps extends CommonInternalProps { data: unknown; nodeType: string; circularCache: CircularCache; level: number; } interface Range { from: number; to: number; } interface Entry { key: string | number; value: unknown; } function isRange(rangeOrEntry: Range | Entry): rangeOrEntry is Range { return (rangeOrEntry as Range).to !== undefined; } function renderChildNodes( props: RenderChildNodesProps, from?: number, to?: number, ) { const { nodeType, data, collectionLimit, circularCache, keyPath, postprocessValue, sortObjectKeys, } = props; const childNodes: React.ReactNode[] = []; getCollectionEntries( nodeType, data, sortObjectKeys, collectionLimit, from, to, ).forEach((entry) => { if (isRange(entry)) { childNodes.push( , ); } else { const { key, value } = entry; const isCircular = circularCache.indexOf(value) !== -1; childNodes.push( , ); } }); return childNodes; } interface Props extends CommonInternalProps { data: unknown; nodeType: string; nodeTypeIndicator: string; createItemString: (data: unknown, collectionLimit: number) => string; expandable: boolean; } export default function JSONNestedNode(props: Props) { const { circularCache = [], collectionLimit, createItemString, data, expandable, getItemString, hideRoot, isCircular, keyPath, labelRenderer, level = 0, nodeType, nodeTypeIndicator, shouldExpandNodeInitially, styling, } = props; const [expanded, setExpanded] = useState( // calculate individual node expansion if necessary isCircular ? false : shouldExpandNodeInitially(keyPath, data, level), ); const handleClick = useCallback(() => { if (expandable) setExpanded(!expanded); }, [expandable, expanded]); const renderedChildren = expanded || (hideRoot && level === 0) ? renderChildNodes({ ...props, circularCache, level: level + 1 }) : null; const itemType = ( {nodeTypeIndicator} ); const renderedItemString = getItemString( nodeType, data, itemType, createItemString(data, collectionLimit), keyPath, ); const stylingArgs = [keyPath, nodeType, expanded, expandable] as const; return hideRoot ? (
    • {renderedChildren}
  • ) : (
  • {expandable && ( )} {renderedItemString}
      {renderedChildren}
  • ); }