basic layout edits
Summary: Include toggle button, trees/sidebar not separately interactive Reviewed By: danielbuechele Differential Revision: D8680613 fbshipit-source-id: 3bc52b66881abc56ea5cc0955f8237509d039fc4
This commit is contained in:
committed by
Facebook Github Bot
parent
3833f061e2
commit
917376db6d
25
src/fb-stubs/AXLayoutExtender.js
Normal file
25
src/fb-stubs/AXLayoutExtender.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018-present Facebook.
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Component} from 'react';
|
||||||
|
import type {Element, ElementID, ElementSearchResultSet} from 'sonar';
|
||||||
|
|
||||||
|
export class AXElementsInspector extends Component<{
|
||||||
|
onElementExpanded: (key: ElementID, deep: boolean) => void,
|
||||||
|
onElementSelected: (key: ElementID) => void,
|
||||||
|
onElementHovered: ?(key: ?ElementID) => void,
|
||||||
|
onValueChanged: ?(path: Array<string>, val: any) => void,
|
||||||
|
selected: ?ElementID,
|
||||||
|
searchResults?: ?ElementSearchResultSet,
|
||||||
|
root: ?ElementID,
|
||||||
|
elements: {[key: ElementID]: Element},
|
||||||
|
useAppSidebar?: boolean,
|
||||||
|
}> {
|
||||||
|
render() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,15 +24,20 @@ import {
|
|||||||
SonarSidebar,
|
SonarSidebar,
|
||||||
} from 'sonar';
|
} from 'sonar';
|
||||||
|
|
||||||
|
import {AXElementsInspector} from '../../fb-stubs/AXLayoutExtender.js';
|
||||||
|
import config from '../../fb-stubs/config.js';
|
||||||
|
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
import debounce from 'lodash.debounce';
|
import debounce from 'lodash.debounce';
|
||||||
|
|
||||||
export type InspectorState = {|
|
export type InspectorState = {|
|
||||||
initialised: boolean,
|
initialised: boolean,
|
||||||
selected: ?ElementID,
|
selected: ?ElementID,
|
||||||
|
selectedAX: ?ElementID,
|
||||||
root: ?ElementID,
|
root: ?ElementID,
|
||||||
elements: {[key: ElementID]: Element},
|
elements: {[key: ElementID]: Element},
|
||||||
isSearchActive: boolean,
|
isSearchActive: boolean,
|
||||||
|
inAXMode: boolean,
|
||||||
searchResults: ?ElementSearchResultSet,
|
searchResults: ?ElementSearchResultSet,
|
||||||
outstandingSearchQuery: ?string,
|
outstandingSearchQuery: ?string,
|
||||||
|};
|
|};
|
||||||
@@ -140,8 +145,10 @@ export default class Layout extends SonarPlugin<InspectorState> {
|
|||||||
elements: {},
|
elements: {},
|
||||||
initialised: false,
|
initialised: false,
|
||||||
isSearchActive: false,
|
isSearchActive: false,
|
||||||
|
inAXMode: false,
|
||||||
root: null,
|
root: null,
|
||||||
selected: null,
|
selected: null,
|
||||||
|
selectedAX: null,
|
||||||
searchResults: null,
|
searchResults: null,
|
||||||
outstandingSearchQuery: null,
|
outstandingSearchQuery: null,
|
||||||
};
|
};
|
||||||
@@ -153,6 +160,12 @@ export default class Layout extends SonarPlugin<InspectorState> {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
SelectAXElement(state: InspectorState, {key}: SelectElementArgs) {
|
||||||
|
return {
|
||||||
|
selectedAX: key,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
ExpandElement(state: InspectorState, {expand, key}: ExpandElementArgs) {
|
ExpandElement(state: InspectorState, {expand, key}: ExpandElementArgs) {
|
||||||
return {
|
return {
|
||||||
elements: {
|
elements: {
|
||||||
@@ -206,6 +219,10 @@ export default class Layout extends SonarPlugin<InspectorState> {
|
|||||||
) {
|
) {
|
||||||
return {isSearchActive};
|
return {isSearchActive};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
SetAXMode(state: InspectorState, {inAXMode}: {inAXMode: boolean}) {
|
||||||
|
return {inAXMode};
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
search(query: string) {
|
search(query: string) {
|
||||||
@@ -481,6 +498,16 @@ export default class Layout extends SonarPlugin<InspectorState> {
|
|||||||
this.client.send('setSearchActive', {active: isSearchActive});
|
this.client.send('setSearchActive', {active: isSearchActive});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onTestToggleAccessibility = () => {
|
||||||
|
const inAXMode = !this.state.inAXMode;
|
||||||
|
this.dispatchAction({inAXMode, type: 'SetAXMode'});
|
||||||
|
this.client
|
||||||
|
.call('testAccessibility', {active: inAXMode})
|
||||||
|
.then(({message}: {message: string}) => {
|
||||||
|
console.log(message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
onElementSelected = debounce((key: ElementID) => {
|
onElementSelected = debounce((key: ElementID) => {
|
||||||
this.dispatchAction({key, type: 'SelectElement'});
|
this.dispatchAction({key, type: 'SelectElement'});
|
||||||
this.client.send('setHighlighted', {id: key});
|
this.client.send('setHighlighted', {id: key});
|
||||||
@@ -489,14 +516,25 @@ export default class Layout extends SonarPlugin<InspectorState> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onAXElementSelected = debounce((key: ElementID) => {
|
||||||
|
this.dispatchAction({key, type: 'SelectAXElement'});
|
||||||
|
this.client.send('setHighlighted', {id: key});
|
||||||
|
this.getNodes([key], true).then((elements: Array<Element>) => {
|
||||||
|
this.dispatchAction({elements, type: 'UpdateElements'});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
onElementHovered = debounce((key: ?ElementID) => {
|
onElementHovered = debounce((key: ?ElementID) => {
|
||||||
this.client.send('setHighlighted', {id: key});
|
this.client.send('setHighlighted', {id: key});
|
||||||
});
|
});
|
||||||
|
|
||||||
onDataValueChanged = (path: Array<string>, value: any) => {
|
onDataValueChanged = (path: Array<string>, value: any) => {
|
||||||
this.client.send('setData', {id: this.state.selected, path, value});
|
const selected = this.state.inAXMode
|
||||||
|
? this.state.selectedAX
|
||||||
|
: this.state.selected;
|
||||||
|
this.client.send('setData', {id: selected, path, value});
|
||||||
this.props.logger.track('usage', 'layout:value-changed', {
|
this.props.logger.track('usage', 'layout:value-changed', {
|
||||||
id: this.state.selected,
|
id: selected,
|
||||||
value: value,
|
value: value,
|
||||||
path: path,
|
path: path,
|
||||||
});
|
});
|
||||||
@@ -512,16 +550,42 @@ export default class Layout extends SonarPlugin<InspectorState> {
|
|||||||
) : null;
|
) : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
renderAXSidebar = () => {
|
||||||
|
return this.state.selectedAX != null ? (
|
||||||
|
<InspectorSidebar
|
||||||
|
element={this.state.elements[this.state.selectedAX]}
|
||||||
|
onValueChanged={this.onDataValueChanged}
|
||||||
|
client={this.client}
|
||||||
|
/>
|
||||||
|
) : null;
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
initialised,
|
initialised,
|
||||||
selected,
|
selected,
|
||||||
|
selectedAX,
|
||||||
root,
|
root,
|
||||||
elements,
|
elements,
|
||||||
isSearchActive,
|
isSearchActive,
|
||||||
|
inAXMode,
|
||||||
outstandingSearchQuery,
|
outstandingSearchQuery,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
|
const AXInspector = (
|
||||||
|
<AXElementsInspector
|
||||||
|
onElementSelected={this.onAXElementSelected}
|
||||||
|
onElementHovered={this.onElementHovered}
|
||||||
|
onElementExpanded={this.onElementExpanded}
|
||||||
|
onValueChanged={this.onDataValueChanged}
|
||||||
|
selected={selectedAX}
|
||||||
|
searchResults={this.state.searchResults}
|
||||||
|
root={root}
|
||||||
|
elements={elements}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
const AXButtonVisible = AXInspector !== null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FlexColumn fill={true}>
|
<FlexColumn fill={true}>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
@@ -540,6 +604,23 @@ export default class Layout extends SonarPlugin<InspectorState> {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</SearchIconContainer>
|
</SearchIconContainer>
|
||||||
|
{AXButtonVisible ? (
|
||||||
|
<SearchIconContainer
|
||||||
|
onClick={this.onTestToggleAccessibility}
|
||||||
|
role="button"
|
||||||
|
tabIndex={-1}
|
||||||
|
title="Toggle accessibility mode within the LayoutInspector">
|
||||||
|
<Glyph
|
||||||
|
name="accessibility"
|
||||||
|
size={16}
|
||||||
|
color={
|
||||||
|
inAXMode
|
||||||
|
? colors.macOSTitleBarIconSelected
|
||||||
|
: colors.macOSTitleBarIconActive
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</SearchIconContainer>
|
||||||
|
) : null}
|
||||||
<SearchBox tabIndex={-1}>
|
<SearchBox tabIndex={-1}>
|
||||||
<SearchIcon
|
<SearchIcon
|
||||||
name="magnifying-glass"
|
name="magnifying-glass"
|
||||||
@@ -567,8 +648,11 @@ export default class Layout extends SonarPlugin<InspectorState> {
|
|||||||
<LoadingIndicator />
|
<LoadingIndicator />
|
||||||
</Center>
|
</Center>
|
||||||
)}
|
)}
|
||||||
|
{initialised && inAXMode ? AXInspector : null}
|
||||||
</FlexRow>
|
</FlexRow>
|
||||||
<SonarSidebar>{this.renderSidebar()}</SonarSidebar>
|
<SonarSidebar>
|
||||||
|
{inAXMode ? this.renderAXSidebar() : this.renderSidebar()}
|
||||||
|
</SonarSidebar>
|
||||||
</FlexColumn>
|
</FlexColumn>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user