Fix Height for Main Layout Inspector

Summary:
in Layout plugin, scrollbars where often not visible, for example to see the vertical scrollbar, one had to scroll to the horizontal end first.

Also introduced the `Scrollable` component to simplify this in the feature and separate the concepts of rendering something large and making it scrollable.

This diff cleans up the layout structure and fixes the problem

changelog: Fixed several minor layout issues in the Layout plugin

Reviewed By: cekkaewnumchai

Differential Revision: D21283157

fbshipit-source-id: 81849151475165796c65001616f038a9d6cbdfb2
This commit is contained in:
Michel Weststrate
2020-05-21 03:34:05 -07:00
committed by Facebook GitHub Bot
parent 22dfc33da0
commit b0ab9b9b98
5 changed files with 138 additions and 116 deletions

View File

@@ -0,0 +1,20 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import React from 'react';
import styled from '@emotion/styled';
const Scrollable: React.FC<{children: React.ReactNode}> = styled('div')({
width: '100%',
height: '100%',
overflow: 'auto',
});
Scrollable.displayName = 'Scrollable';
export default Scrollable;

View File

@@ -13,6 +13,7 @@ const VerticalRule = styled.div({
backgroundColor: '#c9ced4',
width: 3,
margin: '0',
flexShrink: 0,
});
VerticalRule.displayName = 'VerticalRule';

View File

@@ -19,6 +19,7 @@ import Text from '../Text';
import styled from '@emotion/styled';
import {clipboard, MenuItemConstructorOptions} from 'electron';
import React, {MouseEvent, KeyboardEvent} from 'react';
import {Scrollable} from '../..';
export const ROW_HEIGHT = 23;
@@ -424,17 +425,9 @@ const ElementsContainer = styled(FlexColumn)({
backgroundColor: colors.white,
minHeight: '100%',
minWidth: '100%',
overflow: 'auto',
});
ElementsContainer.displayName = 'Elements:ElementsContainer';
const ElementsBox = styled(FlexColumn)({
alignItems: 'flex-start',
flex: 1,
overflow: 'auto',
});
ElementsBox.displayName = 'Elements:ElementsBox';
export type DecorateRow = (e: Element) => ReactElement<any> | undefined | null;
type ElementsProps = {
@@ -710,14 +703,14 @@ export class Elements extends PureComponent<ElementsProps, ElementsState> {
render() {
return (
<ElementsBox>
<Scrollable>
<ElementsContainer
onKeyDown={this.onKeyDown}
tabIndex={0}
ref={this._outerRef}>
{this.state.flatElements.map(this.buildRow)}
</ElementsContainer>
</ElementsBox>
</Scrollable>
);
}
}

View File

@@ -176,4 +176,5 @@ export {default as Info} from './components/Info';
export {default as Bordered} from './components/Bordered';
export {default as AlternatingRows} from './components/AlternatingRows';
export {default as Layout} from './components/Layout';
export {default as Scrollable} from './components/Scrollable';
export * from './components/Highlight';

View File

@@ -12,7 +12,6 @@ import {
Element,
ElementSearchResultSet,
PluginClient,
FlexColumn,
FlexRow,
FlipperPlugin,
Toolbar,
@@ -29,6 +28,7 @@ import {
ReduxState,
ArchivedDevice,
ToolbarIcon,
Layout,
} from 'flipper';
import Inspector from './Inspector';
import InspectorSidebar from './InspectorSidebar';
@@ -80,7 +80,11 @@ const FlipperADButton = styled(Button)({
type ClientGetNodesCalls = 'getNodes' | 'getAXNodes';
type ClientMethodCalls = 'getRoot' | 'getAXRoot' | ClientGetNodesCalls;
export default class Layout extends FlipperPlugin<State, any, PersistedState> {
export default class LayoutPlugin extends FlipperPlugin<
State,
any,
PersistedState
> {
FlipperADBar() {
return (
<FlipperADBarContainer>
@@ -122,7 +126,7 @@ export default class Layout extends FlipperPlugin<State, any, PersistedState> {
if (rootElement) {
statusUpdate && statusUpdate('Fetching Child Nodes...');
await Layout.getAllNodes(
await LayoutPlugin.getAllNodes(
rootElement,
elements,
callClient,
@@ -133,7 +137,7 @@ export default class Layout extends FlipperPlugin<State, any, PersistedState> {
const AXelements: ElementMap = {};
if (rootAXElement) {
statusUpdate && statusUpdate('Fetching Child AX Nodes...');
await Layout.getAllNodes(
await LayoutPlugin.getAllNodes(
rootAXElement,
AXelements,
callClient,
@@ -167,7 +171,7 @@ export default class Layout extends FlipperPlugin<State, any, PersistedState> {
async ({elements}: {elements: Array<Element>}) => {
await Promise.all(
elements.map(async (elem) => {
await Layout.getAllNodes(
await LayoutPlugin.getAllNodes(
elem,
nodeMap,
callClient,
@@ -333,7 +337,7 @@ export default class Layout extends FlipperPlugin<State, any, PersistedState> {
ax: this.state.inAXMode,
});
};
showFlipperADBar: boolean = false;
showFlipperADBar: boolean = true;
getScreenDimensions(): {width: number; height: number} | null {
if (this.state.screenDimensions) {
@@ -405,115 +409,118 @@ export default class Layout extends FlipperPlugin<State, any, PersistedState> {
/>
);
const axInspector = this.state.inAXMode && (
<Inspector
{...inspectorProps}
onSelect={(selectedAXElement) => this.setState({selectedAXElement})}
showsSidebar={true}
ax
/>
);
const divider = this.state.inAXMode && <VerticalRule />;
const axInspector = this.state.inAXMode ? (
<FlexRow>
<VerticalRule />
<Inspector
{...inspectorProps}
onSelect={(selectedAXElement) => this.setState({selectedAXElement})}
showsSidebar={true}
ax
/>
</FlexRow>
) : null;
const showAnalyzeYogaPerformanceButton = GK.get('flipper_yogaperformance');
const screenDimensions = this.getScreenDimensions();
if (!this.state.init) {
return null;
}
return (
<FlexColumn grow={true}>
{this.state.init && (
<>
<Toolbar>
{!this.props.isArchivedDevice && (
<ToolbarIcon
onClick={this.onToggleTargetMode}
title="Toggle target mode"
icon="target"
active={this.state.inTargetMode}
/>
)}
{this.realClient.query.os === 'Android' && (
<ToolbarIcon
onClick={this.onToggleAXMode}
title="Toggle to see the accessibility hierarchy"
icon="accessibility"
active={this.state.inAXMode}
/>
)}
{!this.props.isArchivedDevice && (
<ToolbarIcon
onClick={this.onToggleAlignmentMode}
title="Toggle AlignmentMode to show alignment lines"
icon="borders"
active={this.state.inAlignmentMode}
/>
)}
{this.props.isArchivedDevice &&
this.state.visualizerScreenshot && (
<ToolbarIcon
onClick={this.onToggleVisualizer}
title="Toggle visual recreation of layout"
icon="mobile"
active={!!this.state.visualizerWindow}
/>
)}
<>
<Layout.Top>
<Toolbar>
{!this.props.isArchivedDevice && (
<ToolbarIcon
onClick={this.onToggleTargetMode}
title="Toggle target mode"
icon="target"
active={this.state.inTargetMode}
/>
)}
{this.realClient.query.os === 'Android' && (
<ToolbarIcon
onClick={this.onToggleAXMode}
title="Toggle to see the accessibility hierarchy"
icon="accessibility"
active={this.state.inAXMode}
/>
)}
{!this.props.isArchivedDevice && (
<ToolbarIcon
onClick={this.onToggleAlignmentMode}
title="Toggle AlignmentMode to show alignment lines"
icon="borders"
active={this.state.inAlignmentMode}
/>
)}
{this.props.isArchivedDevice && this.state.visualizerScreenshot && (
<ToolbarIcon
onClick={this.onToggleVisualizer}
title="Toggle visual recreation of layout"
icon="mobile"
active={!!this.state.visualizerWindow}
/>
)}
<Search
client={this.getClient()}
setPersistedState={this.props.setPersistedState}
persistedState={this.props.persistedState}
onSearchResults={(searchResults) =>
this.setState({searchResults})
}
inAXMode={this.state.inAXMode}
initialQuery={this.props.deepLinkPayload}
/>
</Toolbar>
<FlexRow grow={true}>
<Search
client={this.getClient()}
setPersistedState={this.props.setPersistedState}
persistedState={this.props.persistedState}
onSearchResults={(searchResults) =>
this.setState({searchResults})
}
inAXMode={this.state.inAXMode}
initialQuery={this.props.deepLinkPayload}
/>
</Toolbar>
<Layout.Bottom>
<Layout.Right>
{inspector}
{divider}
{axInspector}
</FlexRow>
{this.showFlipperADBar && this.FlipperADBar()}
<DetailSidebar>
<InspectorSidebar
client={this.getClient()}
realClient={this.realClient}
element={element}
onValueChanged={this.onDataValueChanged}
logger={this.props.logger}
/>
{showAnalyzeYogaPerformanceButton &&
element &&
element.decoration === 'litho' ? (
<Button
icon={'share-external'}
compact={true}
style={{marginTop: 8, marginRight: 12}}
onClick={() => {
this.props.selectPlugin('YogaPerformance', element!.id);
}}>
Analyze Yoga Performance
</Button>
) : null}
</DetailSidebar>
{this.state.visualizerWindow &&
screenDimensions &&
(this.state.visualizerScreenshot ? (
<VisualizerPortal
container={this.state.visualizerWindow.document.body}
elements={this.props.persistedState.elements}
highlightedElement={this.state.highlightedElement}
screenshotURL={this.state.visualizerScreenshot}
screenDimensions={screenDimensions}
/>
) : (
'Loading...'
))}
</>
)}
</FlexColumn>
</Layout.Right>
{this.showFlipperADBar ? this.FlipperADBar() : null}
</Layout.Bottom>
</Layout.Top>
<DetailSidebar>
<InspectorSidebar
client={this.getClient()}
realClient={this.realClient}
element={element}
onValueChanged={this.onDataValueChanged}
logger={this.props.logger}
/>
{showAnalyzeYogaPerformanceButton &&
element &&
element.decoration === 'litho' ? (
<Button
icon={'share-external'}
compact={true}
style={{marginTop: 8, marginRight: 12}}
onClick={() => {
this.props.selectPlugin('YogaPerformance', element!.id);
}}>
Analyze Yoga Performance
</Button>
) : null}
</DetailSidebar>
{this.state.visualizerWindow &&
screenDimensions &&
(this.state.visualizerScreenshot ? (
<VisualizerPortal
container={this.state.visualizerWindow.document.body}
elements={this.props.persistedState.elements}
highlightedElement={this.state.highlightedElement}
screenshotURL={this.state.visualizerScreenshot}
screenDimensions={screenDimensions}
/>
) : (
'Loading...'
))}
</>
);
}
}