From 779fd167ffb004c337b5ba3d7923c2f18a96109a Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Tue, 14 May 2019 21:37:53 +0100 Subject: [PATCH] Adds inspectable event components + props [Flare] Adds inspectable event components + props --- src/__tests__/inspectedElementSerializer.js | 1 + src/backend/renderer.js | 23 +++++ src/devtools/views/Components/EventsTree.css | 27 ++++++ src/devtools/views/Components/EventsTree.js | 88 +++++++++++++++++++ .../Components/InspectedElementContext.js | 1 + .../views/Components/SelectedElement.js | 3 + src/devtools/views/Components/types.js | 1 + 7 files changed, 144 insertions(+) create mode 100644 src/devtools/views/Components/EventsTree.css create mode 100644 src/devtools/views/Components/EventsTree.js diff --git a/src/__tests__/inspectedElementSerializer.js b/src/__tests__/inspectedElementSerializer.js index 2423683c24..13e105cf0d 100644 --- a/src/__tests__/inspectedElementSerializer.js +++ b/src/__tests__/inspectedElementSerializer.js @@ -17,6 +17,7 @@ export function print(inspectedElement, serialize, indent) { id: inspectedElement.id, owners: inspectedElement.owners, context: inspectedElement.context, + events: inspectedElement.events, hooks: inspectedElement.hooks, props: inspectedElement.props, state: inspectedElement.state, diff --git a/src/backend/renderer.js b/src/backend/renderer.js index f4e8a6ffe9..6d23df5032 100644 --- a/src/backend/renderer.js +++ b/src/backend/renderer.js @@ -478,6 +478,10 @@ export function attach( case EVENT_TARGET_TOUCH_HIT_STRING: return 'TouchHitTarget'; default: + const displayName = elementType.displayName; + if (displayName !== undefined) { + return displayName; + } return 'EventTarget'; } case ForwardRef: @@ -1833,6 +1837,23 @@ export function attach( const isTimedOutSuspense = tag === SuspenseComponent && memoizedState !== null; + let events = null; + let node = fiber; + while (node !== null) { + if (node.tag === EventComponent) { + if (events === null) { + events = []; + } + const eventComponentInstance = node.stateNode; + const currentFiber = eventComponentInstance.currentFiber; + events.push({ + props: eventComponentInstance.props, + displayName: currentFiber.type.displayName, + }); + } + node = node.return; + } + return { id, @@ -1858,6 +1879,7 @@ export function attach( // Inspectable properties. // TODO Review sanitization approach for the below inspectable values. context, + events, hooks: usesHooks ? inspectHooksOfFiber(fiber, (renderer.currentDispatcherRef: any)) : null, @@ -1879,6 +1901,7 @@ export function attach( } // TODO Review sanitization approach for the below inspectable values. result.context = cleanForBridge(result.context); + result.events = cleanForBridge(result.events); result.hooks = cleanForBridge(result.hooks); result.props = cleanForBridge(result.props); result.state = cleanForBridge(result.state); diff --git a/src/devtools/views/Components/EventsTree.css b/src/devtools/views/Components/EventsTree.css new file mode 100644 index 0000000000..e89246aa1b --- /dev/null +++ b/src/devtools/views/Components/EventsTree.css @@ -0,0 +1,27 @@ +.EventsTree { + padding: 0.25rem; + border-top: 1px solid var(--color-border); +} +.EventsTree:first-of-type { + border-top: none; +} + +.HeaderRow { + display: flex; + align-items: center; +} + +.Header { + flex: 1 1; + font-family: var(--font-family-sans); +} + +.NameValueRow { + display: flex; +} + +.Empty { + color: var(--color-dimmer); + font-style: italic; + padding-left: 0.75rem; +} \ No newline at end of file diff --git a/src/devtools/views/Components/EventsTree.js b/src/devtools/views/Components/EventsTree.js new file mode 100644 index 0000000000..3c8635e627 --- /dev/null +++ b/src/devtools/views/Components/EventsTree.js @@ -0,0 +1,88 @@ +import { copy } from 'clipboard-js'; +import React, { useCallback, useState } from 'react'; +import styles from './EventsTree.css'; +import Button from '../Button'; +import ButtonIcon from '../ButtonIcon'; +import KeyValue from './KeyValue'; +import ExpandCollapseToggle from './ExpandCollapseToggle'; +import { serializeDataForCopy } from '../utils'; + +type Props = {| + events: Object, +|}; + +function EventsTreeView({ events }: Props) { + const handleCopy = useCallback(() => copy(serializeDataForCopy(events)), [ + events, + ]); + + return ( +
+
+
events
+ { + + } +
+ +
+ ); +} + +function InnerEventsTreeView({ events }: Props) { + return events.map((event, index) => ( + + )); +} + +type EventComponentViewProps = {| + displayName: string, + props: null | Object, +|}; + +function EventComponentView({ displayName, props }: EventComponentViewProps) { + const [isOpen, setIsOpen] = useState(false); + let eventComponentProps = null; + // eslint-disable-next-line no-unused-vars + let children; + + if (props !== null) { + // We don't want children, so extract it out + ({ children, ...eventComponentProps } = props); + } + + return ( +
+
+ + {}} className={styles.Name}> + {displayName} + +
+ +
+ ); +} + +// $FlowFixMe +export default React.memo(EventsTreeView); diff --git a/src/devtools/views/Components/InspectedElementContext.js b/src/devtools/views/Components/InspectedElementContext.js index 0a87518f05..e69b9b9a42 100644 --- a/src/devtools/views/Components/InspectedElementContext.js +++ b/src/devtools/views/Components/InspectedElementContext.js @@ -90,6 +90,7 @@ function InspectedElementContextController({ children }: Props) { inspectedElement = (({ ...inspectedElement, context: hydrateHelper(inspectedElement.context), + events: hydrateHelper(inspectedElement.events), hooks: hydrateHelper(inspectedElement.hooks), props: hydrateHelper(inspectedElement.props), state: hydrateHelper(inspectedElement.state), diff --git a/src/devtools/views/Components/SelectedElement.js b/src/devtools/views/Components/SelectedElement.js index 6f474113fe..aa831c11ad 100644 --- a/src/devtools/views/Components/SelectedElement.js +++ b/src/devtools/views/Components/SelectedElement.js @@ -6,6 +6,7 @@ import { BridgeContext, StoreContext } from '../context'; import Button from '../Button'; import ButtonIcon from '../ButtonIcon'; import HooksTree from './HooksTree'; +import EventsTree from './EventsTree'; import { ModalDialogContext } from '../ModalDialog'; import InspectedElementTree from './InspectedElementTree'; import { InspectedElementContext } from './InspectedElementContext'; @@ -221,6 +222,7 @@ function InspectedElementView({ canEditHooks, canToggleSuspense, context, + events, hooks, owners, props, @@ -297,6 +299,7 @@ function InspectedElementView({ data={context} overrideValueFn={overrideContextFn} /> + {events !== null && events.length > 0 && } {ownerID === null && owners !== null && owners.length > 0 && (
diff --git a/src/devtools/views/Components/types.js b/src/devtools/views/Components/types.js index aaae8d378a..5613e9c205 100644 --- a/src/devtools/views/Components/types.js +++ b/src/devtools/views/Components/types.js @@ -59,6 +59,7 @@ export type InspectedElement = {| // Inspectable properties. context: Object | null, + events: Object | null, hooks: Object | null, props: Object | null, state: Object | null,