Introduce Info / VBox / HBox / Labeled for more consistent layouting

Summary:
This diff introduces a set of components:

VBox: use this to group things vertically, it little more than a container that fills the full width and adds bottom margin (see screenshot: creating distance between the boxes)

HBox: use to divide a space horizontal in two, and distribute it over two children, supports growing the right side, left side or both equally. In the image used to reserve the necessary width for the image, and give the remaining space to the text

Info: A component that shows a message, prestyled with one of the four types: info, error, warning, pending.

{F222993480}

Reviewed By: jknoxville

Differential Revision: D18595291

fbshipit-source-id: 1957db1b606b2e44e3104b10d32ad8ce75af6adc
This commit is contained in:
Michel Weststrate
2019-11-21 06:28:24 -08:00
committed by Facebook Github Bot
parent c976e3ed63
commit 5589a1b77b
7 changed files with 171 additions and 12 deletions

View File

@@ -0,0 +1,78 @@
/**
* 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 'react-emotion';
import FlexRow from './FlexRow';
/**
* Container that applies a standardized right margin for horizontal spacing
* It takes two children, 'left' and 'right'. One is assumed to have a fixed (or minimum) size,
* and the other will grow automatically
*/
const HBoxContainer = styled(FlexRow)({
shrink: 0,
alignItems: 'center',
});
HBoxContainer.displayName = 'HBoxContainer';
const HBox: React.FC<{
children: [] | [React.ReactNode] | [React.ReactNode, React.ReactNode];
grow?: 'left' | 'right' | 'auto';
childWidth?: number;
}> = ({children, grow, childWidth}) => {
if (children.length > 2) {
throw new Error('HBox expects at most 2 children');
}
const left = children[0] || null;
const right = children[1] || null;
const fixedStyle = {
width: childWidth ? `${childWidth}px` : 'auto',
grow: 0,
shrink: 0,
};
const growStyle = {
width: '100%',
shrink: 1,
grow: 1,
};
switch (grow) {
case 'right':
return (
<HBoxContainer>
<div style={{...fixedStyle, marginRight: 8}}>{left}</div>
<div style={growStyle}>{right}</div>
</HBoxContainer>
);
case 'left':
return (
<HBoxContainer>
<div style={growStyle}>{left}</div>
<div style={{...fixedStyle, marginLeft: 8}}>{right}</div>
</HBoxContainer>
);
default:
return (
<HBoxContainer>
<div style={growStyle}>{left}</div>
<div style={{...growStyle, marginLeft: 8}}>{right}</div>
</HBoxContainer>
);
}
};
HBox.defaultProps = {
grow: 'right',
childWidth: 0,
};
HBox.displayName = 'HBox';
export default HBox;

View File

@@ -0,0 +1,81 @@
/**
* 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 styled from 'react-emotion';
import React from 'react';
import {colors} from './colors';
import HBox from './HBox';
import Glyph from './Glyph';
import LoadingIndicator from './LoadingIndicator';
import FlexColumn from './FlexColumn';
export type InfoProps = {
children: React.ReactNode;
type: 'info' | 'spinning' | 'warning' | 'error';
};
const icons = {
info: 'info-circle',
warning: 'caution-triangle',
error: 'cross-circle',
};
const color = {
info: colors.aluminumDark3,
warning: colors.yellow,
error: colors.red,
spinning: colors.light30,
};
const bgColor = {
info: 'transparent',
warning: colors.yellowTint,
error: colors.redTint,
spinning: 'transparent',
};
const InfoWrapper = styled(FlexColumn)(({type}: {type: InfoProps['type']}) => ({
padding: 10,
borderRadius: 4,
color: color[type],
border: `1px solid ${color[type]}`,
background: bgColor[type],
}));
/**
* Shows an info box with some text and a symbol.
* Supported types: info | spinning | warning | error
*/
function Info({type, children}: InfoProps) {
return (
<InfoWrapper type={type}>
<HBox>
{type === 'spinning' ? (
<LoadingIndicator size={24} />
) : (
<Glyph
name={icons[type]}
color={color[type]}
size={24}
variant="filled"
/>
)}
<>{children}</>
</HBox>
</InfoWrapper>
);
}
Info.defaultProps = {
type: 'info',
};
export default Info;

View File

@@ -17,8 +17,6 @@ export const inputStyle = (compact: boolean) => ({
fontSize: '1em', fontSize: '1em',
height: compact ? '17px' : '28px', height: compact ? '17px' : '28px',
lineHeight: compact ? '17px' : '28px', lineHeight: compact ? '17px' : '28px',
marginRight: 5,
'&:disabled': { '&:disabled': {
backgroundColor: '#ddd', backgroundColor: '#ddd',
borderColor: '#ccc', borderColor: '#ccc',

View File

@@ -10,7 +10,7 @@
import React from 'react'; import React from 'react';
import FlexColumn from './FlexColumn'; import FlexColumn from './FlexColumn';
import Label from './Label'; import Label from './Label';
import BottomSpaced from './BottomSpaced'; import VBox from './VBox';
/** /**
* Vertically arranged section that starts with a label and includes standard margins * Vertically arranged section that starts with a label and includes standard margins
@@ -18,7 +18,7 @@ import BottomSpaced from './BottomSpaced';
const Labeled: React.FC<{title: string}> = ({title, children}) => ( const Labeled: React.FC<{title: string}> = ({title, children}) => (
<FlexColumn> <FlexColumn>
<Label style={{marginBottom: 6}}>{title}</Label> <Label style={{marginBottom: 6}}>{title}</Label>
<BottomSpaced>{children}</BottomSpaced> <VBox>{children}</VBox>
</FlexColumn> </FlexColumn>
); );

View File

@@ -13,9 +13,9 @@ import FlexColumn from './FlexColumn';
/** /**
* Container that applies a standardized bottom margin for vertical spacing * Container that applies a standardized bottom margin for vertical spacing
*/ */
const BottomSpaced = styled(FlexColumn)({ const VBox = styled(FlexColumn)({
marginBottom: 10, marginBottom: 10,
}); });
BottomSpaced.displayName = 'BottomSpaced'; VBox.displayName = 'VBox';
export default BottomSpaced; export default VBox;

View File

@@ -161,8 +161,10 @@ export {default as Sheet} from './components/Sheet';
export {StarButton} from './components/StarButton'; export {StarButton} from './components/StarButton';
export {Markdown} from './components/Markdown'; export {Markdown} from './components/Markdown';
export {default as BottomSpaced} from './components/BottomSpaced'; export {default as VBox} from './components/VBox';
export {default as HBox} from './components/HBox';
export {default as SmallText} from './components/SmallText'; export {default as SmallText} from './components/SmallText';
export {default as Labeled} from './components/Labeled'; export {default as Labeled} from './components/Labeled';
export {default as RoundedSection} from './components/RoundedSection'; export {default as RoundedSection} from './components/RoundedSection';
export {default as CenteredView} from './components/CenteredView'; export {default as CenteredView} from './components/CenteredView';
export {default as Info} from './components/Info';

View File

@@ -22,15 +22,15 @@ const ICONS = {
'bell-null-outline': [12, 24], 'bell-null-outline': [12, 24],
'bell-null': [12], 'bell-null': [12],
'caution-octagon': [16], 'caution-octagon': [16],
'caution-triangle': [16], 'caution-triangle': [16, 24],
'chevron-down-outline': [10], 'chevron-down-outline': [10],
'chevron-down': [8, 12], 'chevron-down': [8, 12],
'chevron-up': [8, 12], 'chevron-up': [8, 12],
'chevron-right': [8, 16], 'chevron-right': [8, 12, 16],
'cross-circle': [16], 'cross-circle': [16, 24],
'dots-3-circle-outline': [16], 'dots-3-circle-outline': [16],
'flash-default': [12], 'flash-default': [12],
'info-circle': [16], 'info-circle': [16, 24],
'magic-wand': [20], 'magic-wand': [20],
'magnifying-glass': [16, 20], 'magnifying-glass': [16, 20],
'minus-circle': [12], 'minus-circle': [12],