// @flow import { copy } from 'clipboard-js'; import React, { useCallback, useContext, useState } from 'react'; import { BridgeContext, StoreContext } from '../context'; import Button from '../Button'; import ButtonIcon from '../ButtonIcon'; import EditableValue from './EditableValue'; import ExpandCollapseToggle from './ExpandCollapseToggle'; import KeyValue from './KeyValue'; import { serializeHooksForCopy } from '../utils'; import styles from './HooksTree.css'; import { meta } from '../../../hydration'; import type { HooksNode, HooksTree } from 'src/backend/types'; type HooksTreeViewProps = {| canEditHooks: boolean, hooks: HooksTree | null, id: number, |}; export function HooksTreeView({ canEditHooks, hooks, id }: HooksTreeViewProps) { const handleCopy = useCallback(() => copy(serializeHooksForCopy(hooks)), [ hooks, ]); if (hooks === null) { return null; } else { return (
hooks
); } } type InnerHooksTreeViewProps = {| canEditHooks: boolean, hooks: HooksTree, id: number, |}; export function InnerHooksTreeView({ canEditHooks, hooks, id, }: InnerHooksTreeViewProps) { // $FlowFixMe "Missing type annotation for U" whatever that means return hooks.map((hook, index) => ( )); } type HookViewProps = {| canEditHooks: boolean, hook: HooksNode, id: number, path?: Array, |}; function HookView({ canEditHooks, hook, id, path = [] }: HookViewProps) { const { name, id: hookID, isStateEditable, subHooks, value } = hook; const bridge = useContext(BridgeContext); const store = useContext(StoreContext); const [isOpen, setIsOpen] = useState(false); const toggleIsOpen = useCallback( () => setIsOpen(prevIsOpen => !prevIsOpen), [] ); if (hook.hasOwnProperty(meta.inspected)) { // This Hook is too deep and hasn't been hydrated. // TODO: show UI to load its data. return (
...
); } // TODO Add click and key handlers for toggling element open/close state. const isCustomHook = subHooks.length > 0; const type = typeof value; let displayValue; let isComplexDisplayValue = false; // Format data for display to mimic the props/state/context for now. if (type === 'string') { displayValue = `"${((value: any): string)}"`; } else if (type === 'boolean') { displayValue = value ? 'true' : 'false'; } else if (type === 'number') { displayValue = value; } else if (value === null) { displayValue = 'null'; } else if (value === undefined) { displayValue = null; } else if (Array.isArray(value)) { isComplexDisplayValue = true; displayValue = 'Array'; } else if (type === 'object') { isComplexDisplayValue = true; displayValue = 'Object'; } if (isCustomHook) { if (isComplexDisplayValue) { return (
{name}
{isOpen && (
)}
); } else { return (
{name} {' '} {/* $FlowFixMe */} {displayValue}
{isOpen && (
)}
); } } else { let overrideValueFn = null; // TODO Maybe read editable value from debug hook? if (canEditHooks && isStateEditable) { overrideValueFn = (path: Array, value: any) => { const rendererID = store.getRendererIDForElement(id); bridge.send('overrideHookState', { id, hookID, path, rendererID, value, }); }; } if (isComplexDisplayValue) { return (
); } else { return (
{name} {typeof overrideValueFn === 'function' ? ( ) : ( // $FlowFixMe Cannot create span element because in property children {displayValue} )}
); } } } // $FlowFixMe export default React.memo(HooksTreeView);