Commit e6c59d07 by Dominik Prokop Committed by GitHub

grafana/ui: Add basic horizontal and vertical layout components (#22303)

parent 55277ca7
import React from 'react';
import { withCenteredStory, withHorizontallyCenteredStory } from '../../utils/storybook/withCenteredStory';
import { VerticalGroup, HorizontalGroup, Layout } from './Layout';
import { Button } from '../Forms/Button';
import { withStoryContainer } from '../../utils/storybook/withStoryContainer';
import { select } from '@storybook/addon-knobs';
export default {
title: 'Layout/Groups',
component: Layout,
decorators: [withStoryContainer, withCenteredStory, withHorizontallyCenteredStory],
};
const justifyVariants = ['flex-start', 'flex-end', 'space-between'];
const spacingVariants = ['xs', 'sm', 'md', 'lg'];
export const horizontal = () => {
const justify = select('Justify elements', justifyVariants, 'flex-start');
const spacing = select('Elements spacing', spacingVariants, 'sm');
return (
<HorizontalGroup justify={justify as any} spacing={spacing as any}>
<Button>Save</Button>
<Button>Cancel</Button>
</HorizontalGroup>
);
};
export const vertical = () => {
const justify = select('Justify elements', justifyVariants, 'flex-start');
const spacing = select('Elements spacing', spacingVariants, 'sm');
return (
<VerticalGroup justify={justify as any} spacing={spacing as any}>
<Button>Save</Button>
<Button>Cancel</Button>
</VerticalGroup>
);
};
import React from 'react';
import { css } from 'emotion';
import { stylesFactory, useTheme } from '../../themes';
import { GrafanaTheme } from '@grafana/data';
enum Orientation {
Horizontal,
Vertical,
}
type Spacing = 'xs' | 'sm' | 'md' | 'lg';
type Justify = 'flex-start' | 'flex-end' | 'space-between';
export interface LayoutProps {
children: React.ReactNode[];
orientation?: Orientation;
spacing?: Spacing;
justify?: Justify;
}
export const Layout: React.FC<LayoutProps> = ({
children,
orientation = Orientation.Horizontal,
spacing = 'sm',
justify = 'flex-start',
}) => {
const theme = useTheme();
const styles = getStyles(theme, orientation, spacing, justify);
return (
<div className={styles.layout}>
{React.Children.map(children, (child, index) => {
return <div className={styles.buttonWrapper}>{child}</div>;
})}
</div>
);
};
export const HorizontalGroup: React.FC<Omit<LayoutProps, 'orientation'>> = ({ children, spacing, justify }) => (
<Layout spacing={spacing} justify={justify} orientation={Orientation.Horizontal}>
{children}
</Layout>
);
export const VerticalGroup: React.FC<Omit<LayoutProps, 'orientation'>> = ({ children, spacing, justify }) => (
<Layout spacing={spacing} justify={justify} orientation={Orientation.Vertical}>
{children}
</Layout>
);
const getStyles = stylesFactory((theme: GrafanaTheme, orientation: Orientation, spacing: Spacing, justify: Justify) => {
return {
layout: css`
display: flex;
flex-direction: ${orientation === Orientation.Vertical ? 'column' : 'row'};
justify-content: ${justify};
height: 100%;
`,
buttonWrapper: css`
margin-bottom: ${orientation === Orientation.Horizontal ? 0 : theme.spacing[spacing]};
margin-right: ${orientation === Orientation.Horizontal ? theme.spacing[spacing] : 0};
&:last-child {
margin-bottom: 0;
margin-right: 0;
}
`,
};
});
......@@ -25,7 +25,6 @@ export { SecretFormField } from './SecretFormFied/SecretFormField';
export { LoadingPlaceholder } from './LoadingPlaceholder/LoadingPlaceholder';
export { ColorPicker, SeriesColorPicker } from './ColorPicker/ColorPicker';
export { SeriesColorPickerPopover, SeriesColorPickerPopoverWithTheme } from './ColorPicker/SeriesColorPickerPopover';
export { PanelOptionsGroup } from './PanelOptionsGroup/PanelOptionsGroup';
export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid';
export { ValueMappingsEditor } from './ValueMappingsEditor/ValueMappingsEditor';
......@@ -142,3 +141,4 @@ export { default as Forms } from './Forms';
export { ValuePicker } from './ValuePicker/ValuePicker';
export { fieldMatchersUI } from './MatchersUI/fieldMatchersUI';
export { getStandardFieldConfigs } from './FieldConfigs/standardFieldConfigEditors';
export { HorizontalGroup, VerticalGroup } from './Layout/Layout';
......@@ -3,9 +3,15 @@ import { boolean, number } from '@storybook/addon-knobs';
import { css, cx } from 'emotion';
import { RenderFunction } from '../../types';
const StoryContainer: React.FC<{ width?: number; showBoundaries: boolean }> = ({ children, width, showBoundaries }) => {
const StoryContainer: React.FC<{ width?: number; height?: number; showBoundaries: boolean }> = ({
children,
width,
height,
showBoundaries,
}) => {
const checkColor = '#f0f0f0';
const finalWidth = width ? `${width}px` : '100%';
const finalHeight = height !== 0 ? `${height}px` : 'auto';
const bgStyles =
showBoundaries &&
css`
......@@ -27,6 +33,7 @@ const StoryContainer: React.FC<{ width?: number; showBoundaries: boolean }> = ({
className={cx(
css`
width: ${finalWidth};
height: ${finalHeight};
`,
bgStyles
)}
......@@ -52,8 +59,23 @@ export const withStoryContainer = (story: RenderFunction) => {
},
CONTAINER_GROUP
);
const containerHeight = number(
'Container height',
0,
{
range: true,
min: 100,
max: 500,
step: 10,
},
CONTAINER_GROUP
);
return (
<StoryContainer width={fullWidthContainter ? undefined : containerWidth} showBoundaries={containerBoundary}>
<StoryContainer
width={fullWidthContainter ? undefined : containerWidth}
height={containerHeight}
showBoundaries={containerBoundary}
>
{story()}
</StoryContainer>
);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment