mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
grafana/ui: Add basic horizontal and vertical layout components (#22303)
This commit is contained in:
parent
55277ca732
commit
e6c59d0729
38
packages/grafana-ui/src/components/Layout/Layout.story.tsx
Normal file
38
packages/grafana-ui/src/components/Layout/Layout.story.tsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
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>
|
||||||
|
);
|
||||||
|
};
|
66
packages/grafana-ui/src/components/Layout/Layout.tsx
Normal file
66
packages/grafana-ui/src/components/Layout/Layout.tsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
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 { LoadingPlaceholder } from './LoadingPlaceholder/LoadingPlaceholder';
|
||||||
export { ColorPicker, SeriesColorPicker } from './ColorPicker/ColorPicker';
|
export { ColorPicker, SeriesColorPicker } from './ColorPicker/ColorPicker';
|
||||||
export { SeriesColorPickerPopover, SeriesColorPickerPopoverWithTheme } from './ColorPicker/SeriesColorPickerPopover';
|
export { SeriesColorPickerPopover, SeriesColorPickerPopoverWithTheme } from './ColorPicker/SeriesColorPickerPopover';
|
||||||
|
|
||||||
export { PanelOptionsGroup } from './PanelOptionsGroup/PanelOptionsGroup';
|
export { PanelOptionsGroup } from './PanelOptionsGroup/PanelOptionsGroup';
|
||||||
export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid';
|
export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid';
|
||||||
export { ValueMappingsEditor } from './ValueMappingsEditor/ValueMappingsEditor';
|
export { ValueMappingsEditor } from './ValueMappingsEditor/ValueMappingsEditor';
|
||||||
@ -142,3 +141,4 @@ export { default as Forms } from './Forms';
|
|||||||
export { ValuePicker } from './ValuePicker/ValuePicker';
|
export { ValuePicker } from './ValuePicker/ValuePicker';
|
||||||
export { fieldMatchersUI } from './MatchersUI/fieldMatchersUI';
|
export { fieldMatchersUI } from './MatchersUI/fieldMatchersUI';
|
||||||
export { getStandardFieldConfigs } from './FieldConfigs/standardFieldConfigEditors';
|
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 { css, cx } from 'emotion';
|
||||||
import { RenderFunction } from '../../types';
|
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 checkColor = '#f0f0f0';
|
||||||
const finalWidth = width ? `${width}px` : '100%';
|
const finalWidth = width ? `${width}px` : '100%';
|
||||||
|
const finalHeight = height !== 0 ? `${height}px` : 'auto';
|
||||||
const bgStyles =
|
const bgStyles =
|
||||||
showBoundaries &&
|
showBoundaries &&
|
||||||
css`
|
css`
|
||||||
@ -27,6 +33,7 @@ const StoryContainer: React.FC<{ width?: number; showBoundaries: boolean }> = ({
|
|||||||
className={cx(
|
className={cx(
|
||||||
css`
|
css`
|
||||||
width: ${finalWidth};
|
width: ${finalWidth};
|
||||||
|
height: ${finalHeight};
|
||||||
`,
|
`,
|
||||||
bgStyles
|
bgStyles
|
||||||
)}
|
)}
|
||||||
@ -52,8 +59,23 @@ export const withStoryContainer = (story: RenderFunction) => {
|
|||||||
},
|
},
|
||||||
CONTAINER_GROUP
|
CONTAINER_GROUP
|
||||||
);
|
);
|
||||||
|
const containerHeight = number(
|
||||||
|
'Container height',
|
||||||
|
0,
|
||||||
|
{
|
||||||
|
range: true,
|
||||||
|
min: 100,
|
||||||
|
max: 500,
|
||||||
|
step: 10,
|
||||||
|
},
|
||||||
|
CONTAINER_GROUP
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<StoryContainer width={fullWidthContainter ? undefined : containerWidth} showBoundaries={containerBoundary}>
|
<StoryContainer
|
||||||
|
width={fullWidthContainter ? undefined : containerWidth}
|
||||||
|
height={containerHeight}
|
||||||
|
showBoundaries={containerBoundary}
|
||||||
|
>
|
||||||
{story()}
|
{story()}
|
||||||
</StoryContainer>
|
</StoryContainer>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user