Render sidebar
Summary: Restore sidebar functionality for Sandy plugins Also needed to fix some circular dependency issues as fallout. Reviewed By: cekkaewnumchai Differential Revision: D24362215 fbshipit-source-id: 0a09ac35ba981322ae0793edc3aa79ffddf2ce73
This commit is contained in:
committed by
Facebook GitHub Bot
parent
ba5f067320
commit
a2fac737f6
@@ -45,7 +45,7 @@ import {activateMenuItems} from './MenuBar';
|
|||||||
import {Message} from './reducers/pluginMessageQueue';
|
import {Message} from './reducers/pluginMessageQueue';
|
||||||
import {Idler} from './utils/Idler';
|
import {Idler} from './utils/Idler';
|
||||||
import {processMessageQueue} from './utils/messageQueue';
|
import {processMessageQueue} from './utils/messageQueue';
|
||||||
import {ToggleButton, SmallText} from './ui';
|
import {ToggleButton, SmallText, Layout} from './ui';
|
||||||
import {SandyPluginRenderer} from 'flipper-plugin';
|
import {SandyPluginRenderer} from 'flipper-plugin';
|
||||||
import {isDevicePluginDefinition} from './utils/pluginUtils';
|
import {isDevicePluginDefinition} from './utils/pluginUtils';
|
||||||
import ArchivedDevice from './devices/ArchivedDevice';
|
import ArchivedDevice from './devices/ArchivedDevice';
|
||||||
@@ -67,7 +67,6 @@ const Waiting = styled(FlexColumn)({
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
background: colors.light02,
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
@@ -95,6 +94,7 @@ const ProgressBarBar = styled.div<{progress: number}>(({progress}) => ({
|
|||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
|
isSandy?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateFromProps = {
|
type StateFromProps = {
|
||||||
@@ -362,6 +362,7 @@ class PluginContainer extends PureComponent<Props, State> {
|
|||||||
isArchivedDevice,
|
isArchivedDevice,
|
||||||
selectedApp,
|
selectedApp,
|
||||||
settingsState,
|
settingsState,
|
||||||
|
isSandy,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
if (!activePlugin || !target || !pluginKey) {
|
if (!activePlugin || !target || !pluginKey) {
|
||||||
console.warn(`No selected plugin. Rendering empty!`);
|
console.warn(`No selected plugin. Rendering empty!`);
|
||||||
@@ -429,7 +430,17 @@ class PluginContainer extends PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
pluginElement = React.createElement(activePlugin, props);
|
pluginElement = React.createElement(activePlugin, props);
|
||||||
}
|
}
|
||||||
return (
|
return isSandy ? (
|
||||||
|
<Layout.Right>
|
||||||
|
<ErrorBoundary
|
||||||
|
heading={`Plugin "${
|
||||||
|
activePlugin.title || 'Unknown'
|
||||||
|
}" encountered an error during render`}>
|
||||||
|
{pluginElement}
|
||||||
|
</ErrorBoundary>
|
||||||
|
<SidebarContainer id="detailsSidebar" />
|
||||||
|
</Layout.Right>
|
||||||
|
) : (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Container key="plugin">
|
<Container key="plugin">
|
||||||
<ErrorBoundary
|
<ErrorBoundary
|
||||||
|
|||||||
@@ -7,12 +7,14 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React, {useEffect, useMemo, useContext} from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
import {ReactReduxContext} from 'react-redux';
|
||||||
import Sidebar from '../ui/components/Sidebar';
|
import Sidebar from '../ui/components/Sidebar';
|
||||||
import {connect} from 'react-redux';
|
|
||||||
import {toggleRightSidebarAvailable} from '../reducers/application';
|
import {toggleRightSidebarAvailable} from '../reducers/application';
|
||||||
import {State as Store} from '../reducers';
|
import {useDispatch, useStore} from '../utils/useStore';
|
||||||
|
import {useIsSandy} from '../sandy-chrome/SandyContext';
|
||||||
|
import {ContentContainer} from '../sandy-chrome/ContentContainer';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
children: any;
|
children: any;
|
||||||
@@ -20,57 +22,47 @@ type OwnProps = {
|
|||||||
minWidth?: number;
|
minWidth?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateFromProps = {
|
/* eslint-disable react-hooks/rules-of-hooks */
|
||||||
rightSidebarVisible: boolean;
|
export default function DetailSidebar({children, width, minWidth}: OwnProps) {
|
||||||
rightSidebarAvailable: boolean;
|
const reduxContext = useContext(ReactReduxContext);
|
||||||
};
|
const domNode = useMemo(() => document.getElementById('detailsSidebar'), []);
|
||||||
|
|
||||||
type DispatchFromProps = {
|
if (!reduxContext || !domNode) {
|
||||||
toggleRightSidebarAvailable: (visible?: boolean) => any;
|
// For unit tests, make sure to render elements inline
|
||||||
};
|
return <div id="detailsSidebar">{children}</div>;
|
||||||
|
|
||||||
type Props = OwnProps & StateFromProps & DispatchFromProps;
|
|
||||||
class DetailSidebar extends React.Component<Props> {
|
|
||||||
componentDidMount() {
|
|
||||||
this.updateSidebarAvailablility();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
const isSandy = useIsSandy();
|
||||||
this.updateSidebarAvailablility();
|
const dispatch = useDispatch();
|
||||||
}
|
const {rightSidebarAvailable, rightSidebarVisible} = useStore((state) => {
|
||||||
|
const {rightSidebarAvailable, rightSidebarVisible} = state.application;
|
||||||
|
return {rightSidebarAvailable, rightSidebarVisible};
|
||||||
|
});
|
||||||
|
|
||||||
updateSidebarAvailablility() {
|
useEffect(
|
||||||
const available = Boolean(this.props.children);
|
function updateSidebarAvailablility() {
|
||||||
if (available !== this.props.rightSidebarAvailable) {
|
const available = Boolean(children);
|
||||||
this.props.toggleRightSidebarAvailable(available);
|
if (available !== rightSidebarAvailable) {
|
||||||
}
|
dispatch(toggleRightSidebarAvailable(available));
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
[children, rightSidebarAvailable, dispatch],
|
||||||
|
);
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
const domNode = document.getElementById('detailsSidebar');
|
(children &&
|
||||||
return (
|
rightSidebarVisible &&
|
||||||
this.props.children &&
|
|
||||||
this.props.rightSidebarVisible &&
|
|
||||||
domNode &&
|
domNode &&
|
||||||
ReactDOM.createPortal(
|
ReactDOM.createPortal(
|
||||||
<Sidebar
|
<Sidebar
|
||||||
minWidth={this.props.minWidth}
|
minWidth={minWidth}
|
||||||
width={this.props.width || 300}
|
width={width || 300}
|
||||||
position="right">
|
position="right"
|
||||||
{this.props.children}
|
gutter={isSandy}>
|
||||||
|
{isSandy ? <ContentContainer>{children}</ContentContainer> : children}
|
||||||
</Sidebar>,
|
</Sidebar>,
|
||||||
domNode,
|
domNode,
|
||||||
)
|
)) ||
|
||||||
);
|
null
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
|
||||||
({application: {rightSidebarVisible, rightSidebarAvailable}}) => ({
|
|
||||||
rightSidebarVisible,
|
|
||||||
rightSidebarAvailable,
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
toggleRightSidebarAvailable,
|
|
||||||
},
|
|
||||||
)(DetailSidebar);
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import {StaticView, setStaticView} from '../../reducers/connections';
|
|||||||
import {setActiveSheet} from '../../reducers/application';
|
import {setActiveSheet} from '../../reducers/application';
|
||||||
import UserAccount from '../UserAccount';
|
import UserAccount from '../UserAccount';
|
||||||
import SupportRequestFormV2 from '../../fb-stubs/SupportRequestFormV2';
|
import SupportRequestFormV2 from '../../fb-stubs/SupportRequestFormV2';
|
||||||
import WatchTools from '../../fb-stubs/WatchTools';
|
|
||||||
import {
|
import {
|
||||||
isStaticViewActive,
|
isStaticViewActive,
|
||||||
PluginIcon,
|
PluginIcon,
|
||||||
@@ -32,6 +31,7 @@ import {ConsoleLogs, errorCounterAtom} from '../ConsoleLogs';
|
|||||||
import {useValue} from 'flipper-plugin';
|
import {useValue} from 'flipper-plugin';
|
||||||
import {colors} from '../../ui';
|
import {colors} from '../../ui';
|
||||||
import GK from '../../fb-stubs/GK';
|
import GK from '../../fb-stubs/GK';
|
||||||
|
import WatchTools from '../../fb-stubs/WatchTools';
|
||||||
|
|
||||||
type OwnProps = {};
|
type OwnProps = {};
|
||||||
|
|
||||||
|
|||||||
19
desktop/app/src/sandy-chrome/ContentContainer.tsx
Normal file
19
desktop/app/src/sandy-chrome/ContentContainer.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* 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 {Layout, styled} from '../ui';
|
||||||
|
import {theme} from './theme';
|
||||||
|
|
||||||
|
export const ContentContainer = styled(Layout.Container)({
|
||||||
|
overflow: 'hidden',
|
||||||
|
background: theme.backgroundDefault,
|
||||||
|
border: `1px solid ${theme.dividerColor}`,
|
||||||
|
borderRadius: theme.containerBorderRadius,
|
||||||
|
boxShadow: `0px 0px 5px rgba(0, 0, 0, 0.05), 0px 0px 1px rgba(0, 0, 0, 0.05)`,
|
||||||
|
});
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {cloneElement, useState, useCallback, useMemo} from 'react';
|
import React, {cloneElement, useState, useCallback, useMemo} from 'react';
|
||||||
import {styled, Layout} from '../ui';
|
|
||||||
import {Button, Divider, Badge, Tooltip, Avatar, Popover} from 'antd';
|
import {Button, Divider, Badge, Tooltip, Avatar, Popover} from 'antd';
|
||||||
import {
|
import {
|
||||||
MobileFilled,
|
MobileFilled,
|
||||||
@@ -23,7 +22,10 @@ import {
|
|||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import {SidebarLeft, SidebarRight} from './SandyIcons';
|
import {SidebarLeft, SidebarRight} from './SandyIcons';
|
||||||
import {useDispatch, useStore} from '../utils/useStore';
|
import {useDispatch, useStore} from '../utils/useStore';
|
||||||
import {toggleLeftSidebarVisible} from '../reducers/application';
|
import {
|
||||||
|
toggleLeftSidebarVisible,
|
||||||
|
toggleRightSidebarVisible,
|
||||||
|
} from '../reducers/application';
|
||||||
import {theme} from './theme';
|
import {theme} from './theme';
|
||||||
import SetupDoctorScreen, {checkHasNewProblem} from './SetupDoctorScreen';
|
import SetupDoctorScreen, {checkHasNewProblem} from './SetupDoctorScreen';
|
||||||
import SettingsSheet from '../chrome/SettingsSheet';
|
import SettingsSheet from '../chrome/SettingsSheet';
|
||||||
@@ -34,6 +36,8 @@ import {ToplevelProps} from './SandyApp';
|
|||||||
import {useValue} from 'flipper-plugin';
|
import {useValue} from 'flipper-plugin';
|
||||||
import {logout} from '../reducers/user';
|
import {logout} from '../reducers/user';
|
||||||
import config from '../fb-stubs/config';
|
import config from '../fb-stubs/config';
|
||||||
|
import Layout from '../ui/components/Layout';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
const LeftRailButtonElem = styled(Button)<{kind?: 'small'}>(({kind}) => ({
|
const LeftRailButtonElem = styled(Button)<{kind?: 'small'}>(({kind}) => ({
|
||||||
width: kind === 'small' ? 32 : 36,
|
width: kind === 'small' ? 32 : 36,
|
||||||
@@ -52,11 +56,13 @@ function LeftRailButton({
|
|||||||
count,
|
count,
|
||||||
title,
|
title,
|
||||||
onClick,
|
onClick,
|
||||||
|
disabled,
|
||||||
}: {
|
}: {
|
||||||
icon?: React.ReactElement;
|
icon?: React.ReactElement;
|
||||||
small?: boolean;
|
small?: boolean;
|
||||||
toggled?: boolean;
|
toggled?: boolean;
|
||||||
selected?: boolean; // TODO: make sure only one element can be selected
|
selected?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
count?: number | true;
|
count?: number | true;
|
||||||
title: string;
|
title: string;
|
||||||
onClick?: React.MouseEventHandler<HTMLElement>;
|
onClick?: React.MouseEventHandler<HTMLElement>;
|
||||||
@@ -78,6 +84,7 @@ function LeftRailButton({
|
|||||||
type={selected ? 'primary' : 'ghost'}
|
type={selected ? 'primary' : 'ghost'}
|
||||||
icon={iconElement}
|
icon={iconElement}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
disabled={disabled}
|
||||||
style={{
|
style={{
|
||||||
color: toggled ? theme.primaryColor : undefined,
|
color: toggled ? theme.primaryColor : undefined,
|
||||||
background: toggled ? theme.backgroundWash : undefined,
|
background: toggled ? theme.backgroundWash : undefined,
|
||||||
@@ -99,9 +106,9 @@ export function LeftRail({
|
|||||||
setToplevelSelection,
|
setToplevelSelection,
|
||||||
}: ToplevelProps) {
|
}: ToplevelProps) {
|
||||||
return (
|
return (
|
||||||
<Layout.Container borderRight padv={12} padh={6} width={48}>
|
<Layout.Container borderRight padv={12} width={48}>
|
||||||
<Layout.Bottom>
|
<Layout.Bottom>
|
||||||
<Layout.Vertical center gap={10}>
|
<Layout.Vertical center gap={10} padh={6}>
|
||||||
<LeftRailButton
|
<LeftRailButton
|
||||||
icon={<MobileFilled />}
|
icon={<MobileFilled />}
|
||||||
title="App Inspect"
|
title="App Inspect"
|
||||||
@@ -118,7 +125,7 @@ export function LeftRail({
|
|||||||
setToplevelSelection={setToplevelSelection}
|
setToplevelSelection={setToplevelSelection}
|
||||||
/>
|
/>
|
||||||
</Layout.Vertical>
|
</Layout.Vertical>
|
||||||
<Layout.Vertical center gap={10}>
|
<Layout.Vertical center gap={10} padh={6}>
|
||||||
<SetupDoctorButton />
|
<SetupDoctorButton />
|
||||||
<WelcomeScreenButton />
|
<WelcomeScreenButton />
|
||||||
<ShowSettingsButton />
|
<ShowSettingsButton />
|
||||||
@@ -127,11 +134,7 @@ export function LeftRail({
|
|||||||
small
|
small
|
||||||
title="Feedback / Bug Reporter"
|
title="Feedback / Bug Reporter"
|
||||||
/>
|
/>
|
||||||
<LeftRailButton
|
<RightSidebarToggleButton />
|
||||||
icon={<SidebarRight />}
|
|
||||||
small
|
|
||||||
title="Right Sidebar Toggle"
|
|
||||||
/>
|
|
||||||
<LeftSidebarToggleButton />
|
<LeftSidebarToggleButton />
|
||||||
{config.showLogin && <LoginButton />}
|
{config.showLogin && <LoginButton />}
|
||||||
</Layout.Vertical>
|
</Layout.Vertical>
|
||||||
@@ -141,12 +144,11 @@ export function LeftRail({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function LeftSidebarToggleButton() {
|
function LeftSidebarToggleButton() {
|
||||||
|
const dispatch = useDispatch();
|
||||||
const mainMenuVisible = useStore(
|
const mainMenuVisible = useStore(
|
||||||
(state) => state.application.leftSidebarVisible,
|
(state) => state.application.leftSidebarVisible,
|
||||||
);
|
);
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LeftRailButton
|
<LeftRailButton
|
||||||
icon={<SidebarLeft />}
|
icon={<SidebarLeft />}
|
||||||
@@ -160,6 +162,29 @@ function LeftSidebarToggleButton() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function RightSidebarToggleButton() {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const rightSidebarAvailable = useStore(
|
||||||
|
(state) => state.application.rightSidebarAvailable,
|
||||||
|
);
|
||||||
|
const rightSidebarVisible = useStore(
|
||||||
|
(state) => state.application.rightSidebarVisible,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LeftRailButton
|
||||||
|
icon={<SidebarRight />}
|
||||||
|
small
|
||||||
|
title="Right Sidebar Toggle"
|
||||||
|
toggled={rightSidebarVisible}
|
||||||
|
disabled={!rightSidebarAvailable}
|
||||||
|
onClick={() => {
|
||||||
|
dispatch(toggleRightSidebarVisible());
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function DebugLogsButton({
|
function DebugLogsButton({
|
||||||
toplevelSelection,
|
toplevelSelection,
|
||||||
setToplevelSelection,
|
setToplevelSelection,
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {setStaticView} from '../reducers/connections';
|
|||||||
import {toggleLeftSidebarVisible} from '../reducers/application';
|
import {toggleLeftSidebarVisible} from '../reducers/application';
|
||||||
import {AppInspect} from './appinspect/AppInspect';
|
import {AppInspect} from './appinspect/AppInspect';
|
||||||
import PluginContainer from '../PluginContainer';
|
import PluginContainer from '../PluginContainer';
|
||||||
|
import {ContentContainer} from './ContentContainer';
|
||||||
|
|
||||||
export type ToplevelNavItem = 'appinspect' | 'flipperlogs' | undefined;
|
export type ToplevelNavItem = 'appinspect' | 'flipperlogs' | undefined;
|
||||||
export type ToplevelProps = {
|
export type ToplevelProps = {
|
||||||
@@ -95,25 +96,15 @@ export function SandyApp({logger}: {logger: Logger}) {
|
|||||||
</Sidebar>
|
</Sidebar>
|
||||||
</Layout.Horizontal>
|
</Layout.Horizontal>
|
||||||
<MainContainer>
|
<MainContainer>
|
||||||
<ContentContainer>
|
{staticView ? (
|
||||||
{staticView ? (
|
<ContentContainer>
|
||||||
React.createElement(staticView, {
|
{React.createElement(staticView, {
|
||||||
logger: logger,
|
logger: logger,
|
||||||
})
|
})}
|
||||||
) : (
|
|
||||||
<PluginContainer logger={logger} />
|
|
||||||
)}
|
|
||||||
</ContentContainer>
|
|
||||||
<Sidebar
|
|
||||||
width={300}
|
|
||||||
minWidth={220}
|
|
||||||
maxWidth={800}
|
|
||||||
gutter
|
|
||||||
position="right">
|
|
||||||
<ContentContainer style={{marginRight: theme.space.large}}>
|
|
||||||
<RightMenu />
|
|
||||||
</ContentContainer>
|
</ContentContainer>
|
||||||
</Sidebar>
|
) : (
|
||||||
|
<PluginContainer logger={logger} isSandy />
|
||||||
|
)}
|
||||||
</MainContainer>
|
</MainContainer>
|
||||||
</Layout.Left>
|
</Layout.Left>
|
||||||
</Layout.Top>
|
</Layout.Top>
|
||||||
@@ -121,19 +112,7 @@ export function SandyApp({logger}: {logger: Logger}) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MainContainer = styled(Layout.Right)({
|
const MainContainer = styled(Layout.Container)({
|
||||||
background: theme.backgroundWash,
|
background: theme.backgroundWash,
|
||||||
|
padding: `${theme.space.large}px ${theme.space.large}px ${theme.space.large}px 0`,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ContentContainer = styled(Layout.Container)({
|
|
||||||
background: theme.backgroundDefault,
|
|
||||||
border: `1px solid ${theme.dividerColor}`,
|
|
||||||
borderRadius: theme.containerBorderRadius,
|
|
||||||
boxShadow: `0px 0px 5px rgba(0, 0, 0, 0.05), 0px 0px 1px rgba(0, 0, 0, 0.05)`,
|
|
||||||
marginTop: theme.space.large,
|
|
||||||
marginBottom: theme.space.large,
|
|
||||||
});
|
|
||||||
|
|
||||||
function RightMenu() {
|
|
||||||
return <div>RightMenu</div>;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ const Container = styled.div<ContainerProps>(
|
|||||||
height,
|
height,
|
||||||
...rest
|
...rest
|
||||||
}) => ({
|
}) => ({
|
||||||
|
boxSizing: 'border-box',
|
||||||
minWidth: `0`, // ensures the Container can shrink smaller than it's largest
|
minWidth: `0`, // ensures the Container can shrink smaller than it's largest
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
@@ -64,6 +65,7 @@ const Container = styled.div<ContainerProps>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const ScrollParent = styled.div({
|
const ScrollParent = styled.div({
|
||||||
|
boxSizing: 'border-box',
|
||||||
flex: 1,
|
flex: 1,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
@@ -141,11 +143,7 @@ const Layout = {
|
|||||||
let [child1, child2] = props.children;
|
let [child1, child2] = props.children;
|
||||||
if (props.scrollable) child2 = <ScrollContainer>{child2}</ScrollContainer>;
|
if (props.scrollable) child2 = <ScrollContainer>{child2}</ScrollContainer>;
|
||||||
return (
|
return (
|
||||||
<SandySplitContainer
|
<SandySplitContainer {...props} flexDirection="column" grow={2}>
|
||||||
{...props}
|
|
||||||
flexDirection="column"
|
|
||||||
flex1={0}
|
|
||||||
flex2={1}>
|
|
||||||
{child1}
|
{child1}
|
||||||
{child2}
|
{child2}
|
||||||
</SandySplitContainer>
|
</SandySplitContainer>
|
||||||
@@ -157,11 +155,7 @@ const Layout = {
|
|||||||
let [child1, child2] = props.children;
|
let [child1, child2] = props.children;
|
||||||
if (props.scrollable) child1 = <ScrollContainer>{child1}</ScrollContainer>;
|
if (props.scrollable) child1 = <ScrollContainer>{child1}</ScrollContainer>;
|
||||||
return (
|
return (
|
||||||
<SandySplitContainer
|
<SandySplitContainer {...props} flexDirection="column" grow={1}>
|
||||||
{...props}
|
|
||||||
flexDirection="column"
|
|
||||||
flex1={1}
|
|
||||||
flex2={0}>
|
|
||||||
{child1}
|
{child1}
|
||||||
{child2}
|
{child2}
|
||||||
</SandySplitContainer>
|
</SandySplitContainer>
|
||||||
@@ -173,7 +167,7 @@ const Layout = {
|
|||||||
let [child1, child2] = props.children;
|
let [child1, child2] = props.children;
|
||||||
if (props.scrollable) child2 = <ScrollContainer>{child2}</ScrollContainer>;
|
if (props.scrollable) child2 = <ScrollContainer>{child2}</ScrollContainer>;
|
||||||
return (
|
return (
|
||||||
<SandySplitContainer {...props} flexDirection="row" flex1={0} flex2={1}>
|
<SandySplitContainer {...props} flexDirection="row" grow={2}>
|
||||||
{child1}
|
{child1}
|
||||||
{child2}
|
{child2}
|
||||||
</SandySplitContainer>
|
</SandySplitContainer>
|
||||||
@@ -185,7 +179,7 @@ const Layout = {
|
|||||||
let [child1, child2] = props.children;
|
let [child1, child2] = props.children;
|
||||||
if (props.scrollable) child1 = <ScrollContainer>{child1}</ScrollContainer>;
|
if (props.scrollable) child1 = <ScrollContainer>{child1}</ScrollContainer>;
|
||||||
return (
|
return (
|
||||||
<SandySplitContainer {...props} flexDirection="row" flex1={1} flex2={0}>
|
<SandySplitContainer {...props} flexDirection="row" grow={1}>
|
||||||
{child1}
|
{child1}
|
||||||
{child2}
|
{child2}
|
||||||
</SandySplitContainer>
|
</SandySplitContainer>
|
||||||
@@ -202,23 +196,25 @@ Object.keys(Layout).forEach((key) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const SandySplitContainer = styled.div<{
|
const SandySplitContainer = styled.div<{
|
||||||
flex1: number;
|
grow: 1 | 2;
|
||||||
flex2: number;
|
|
||||||
center?: boolean;
|
center?: boolean;
|
||||||
flexDirection: CSSProperties['flexDirection'];
|
flexDirection: CSSProperties['flexDirection'];
|
||||||
}>((props) => ({
|
}>((props) => ({
|
||||||
|
boxSizing: 'border-box',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: props.flexDirection,
|
flexDirection: props.flexDirection,
|
||||||
alignItems: props.center ? 'center' : 'stretch',
|
alignItems: props.center ? 'center' : 'stretch',
|
||||||
|
overflow: 'hidden',
|
||||||
'> :first-child': {
|
'> :first-child': {
|
||||||
flexGrow: props.flex1,
|
flex: props.grow === 1 ? growStyle : fixedStyle,
|
||||||
flexShrink: props.flex1,
|
|
||||||
},
|
},
|
||||||
'> :last-child': {
|
'> :last-child': {
|
||||||
flexGrow: props.flex2,
|
flex: props.grow === 2 ? growStyle : fixedStyle,
|
||||||
flexShrink: props.flex2,
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const fixedStyle = `0 0 auto`;
|
||||||
|
const growStyle = `1 0 0`;
|
||||||
|
|
||||||
export default Layout;
|
export default Layout;
|
||||||
|
|||||||
@@ -7,20 +7,12 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from 'react';
|
|
||||||
import * as Flipper from 'flipper';
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
import {act} from '@testing-library/react';
|
import {act} from '@testing-library/react';
|
||||||
|
|
||||||
{
|
{
|
||||||
// These mocks are needed because seammammals still uses Flipper in its UI implementation,
|
// These mocks are needed because seammammals still uses Flipper in its UI implementation,
|
||||||
// so we need to mock some things
|
// so we need to mock some things
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
jest.spyOn(Flipper.DetailSidebar, 'type').mockImplementation((props) => {
|
|
||||||
return <div className="DetailsSidebar">{props.children}</div>;
|
|
||||||
});
|
|
||||||
|
|
||||||
const origRequestIdleCallback = window.requestIdleCallback;
|
const origRequestIdleCallback = window.requestIdleCallback;
|
||||||
const origCancelIdleCallback = window.cancelIdleCallback;
|
const origCancelIdleCallback = window.cancelIdleCallback;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|||||||
Reference in New Issue
Block a user