mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Grafana UI: Create custom Flex Component (#73226)
This commit is contained in:
parent
e3c65d355f
commit
cb6239d913
178
packages/grafana-ui/src/components/Flex/Flex.internal.story.tsx
Normal file
178
packages/grafana-ui/src/components/Flex/Flex.internal.story.tsx
Normal file
@ -0,0 +1,178 @@
|
||||
import { Meta, StoryFn } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { ThemeSpacingTokens } from '@grafana/data';
|
||||
|
||||
import { useTheme2 } from '../../themes';
|
||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
|
||||
import { Flex, JustifyContent, Wrap, Direction } from './Flex';
|
||||
import mdx from './Flex.mdx';
|
||||
|
||||
const Item = ({ color, text, height }: { color: string; text?: string | number; height?: string }) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: '5em',
|
||||
height: height,
|
||||
backgroundColor: color,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
{text && <h3 style={{ color: 'black' }}>{text}</h3>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const meta: Meta<typeof Flex> = {
|
||||
title: 'General/Layout/Flex',
|
||||
component: Flex,
|
||||
decorators: [withCenteredStory],
|
||||
parameters: {
|
||||
docs: {
|
||||
page: mdx,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Basic: StoryFn<typeof Flex> = ({ direction, wrap, alignItems, justifyContent, gap }) => {
|
||||
const theme = useTheme2();
|
||||
return (
|
||||
<div style={{ width: '600px', height: '600px', border: '1px solid grey' }}>
|
||||
<Flex direction={direction} wrap={wrap} alignItems={alignItems} justifyContent={justifyContent} gap={gap}>
|
||||
{Array.from({ length: 5 }).map((_, i) => (
|
||||
<Item key={i} color={theme.colors.warning.main} text={i + 1} />
|
||||
))}
|
||||
</Flex>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const AlignItemsExamples: StoryFn<typeof Flex> = () => {
|
||||
const theme = useTheme2();
|
||||
|
||||
return (
|
||||
<div style={{ width: '600px' }}>
|
||||
<p>Align items flex-start</p>
|
||||
<Flex direction="row" wrap="wrap" alignItems="flex-start" justifyContent="start" gap={2}>
|
||||
{Array.from({ length: 5 }).map((_, i) => (
|
||||
<Item key={i} color={theme.colors.error.main} text={i + 1} />
|
||||
))}
|
||||
</Flex>
|
||||
<p>Align items flex-end</p>
|
||||
<Flex direction="row" wrap="wrap" alignItems="flex-end" justifyContent="end" gap={2}>
|
||||
{Array.from({ length: 5 }).map((_, i) => (
|
||||
<Item key={i} color={theme.colors.error.main} text={i + 1} />
|
||||
))}
|
||||
</Flex>
|
||||
<p>Align items baseline</p>
|
||||
<Flex direction="row" wrap="nowrap" alignItems="baseline" justifyContent="center" gap={2}>
|
||||
{Array.from({ length: 5 }).map((_, i) => (
|
||||
<Item key={i} color={theme.colors.error.main} text={i + 1} />
|
||||
))}
|
||||
</Flex>
|
||||
<p>Align items center</p>
|
||||
<Flex direction="row" wrap="wrap" alignItems="center" justifyContent="center" gap={2}>
|
||||
{Array.from({ length: 5 }).map((_, i) => (
|
||||
<Item key={i} color={theme.colors.error.main} text={i + 1} />
|
||||
))}
|
||||
</Flex>
|
||||
<p>Align items stretch</p>
|
||||
<Flex direction="row" wrap="wrap" alignItems="stretch" justifyContent="center" gap={2}>
|
||||
<Item color={theme.colors.error.main} height="10em" />
|
||||
<Item color={theme.colors.error.main} />
|
||||
<Item color={theme.colors.error.main} height="3em" />
|
||||
<Item color={theme.colors.error.main} />
|
||||
<Item color={theme.colors.error.main} />
|
||||
</Flex>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const JustifyContentExamples: StoryFn<typeof Flex> = () => {
|
||||
const theme = useTheme2();
|
||||
const justifyContentOptions: JustifyContent[] = [
|
||||
'space-between',
|
||||
'space-around',
|
||||
'space-evenly',
|
||||
'flex-start',
|
||||
'flex-end',
|
||||
'center',
|
||||
];
|
||||
|
||||
return (
|
||||
<div style={{ width: '600px' }}>
|
||||
{justifyContentOptions.map((justifyContent) => (
|
||||
<>
|
||||
<p>Justify Content {justifyContent}</p>
|
||||
<Flex direction="row" wrap="wrap" alignItems="center" justifyContent={justifyContent} gap={2}>
|
||||
{Array.from({ length: 5 }).map((_, i) => (
|
||||
<Item key={i} color={theme.colors.warning.main} text={i + 1} />
|
||||
))}
|
||||
</Flex>
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const GapExamples: StoryFn<typeof Flex> = () => {
|
||||
const theme = useTheme2();
|
||||
const gapOptions: ThemeSpacingTokens[] = [2, 8, 10];
|
||||
return (
|
||||
<div style={{ width: '800px' }}>
|
||||
{gapOptions.map((gap) => (
|
||||
<>
|
||||
<p>Gap with spacingToken set to {gap}</p>
|
||||
<Flex direction="row" wrap="wrap" alignItems="flex-start" justifyContent="flex-start" gap={gap}>
|
||||
{Array.from({ length: 5 }).map((_, i) => (
|
||||
<Item key={i} color={theme.colors.error.main} text={i + 1} />
|
||||
))}
|
||||
</Flex>
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const WrapExamples: StoryFn<typeof Flex> = () => {
|
||||
const theme = useTheme2();
|
||||
const wrapOptions: Wrap[] = ['nowrap', 'wrap', 'wrap-reverse'];
|
||||
return (
|
||||
<div style={{ width: '600px' }}>
|
||||
{wrapOptions.map((wrap) => (
|
||||
<>
|
||||
<p>Wrap examples with {wrap} and gap set to spacingToken 2 (16px)</p>
|
||||
<Flex direction="row" wrap={wrap} alignItems="center" justifyContent="center" gap={2}>
|
||||
{Array.from({ length: 10 }).map((_, i) => (
|
||||
<Item key={i} color={theme.colors.warning.main} text={i + 1} />
|
||||
))}
|
||||
</Flex>
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const DirectionExamples: StoryFn<typeof Flex> = () => {
|
||||
const theme = useTheme2();
|
||||
const directionOptions: Direction[] = ['row', 'row-reverse', 'column', 'column-reverse'];
|
||||
return (
|
||||
<div style={{ width: '600px' }}>
|
||||
{directionOptions.map((direction) => (
|
||||
<>
|
||||
<p>Direction {direction}</p>
|
||||
<Flex direction={direction} wrap="wrap" alignItems="center" justifyContent="center" gap={2}>
|
||||
{Array.from({ length: 5 }).map((_, i) => (
|
||||
<Item key={i} color={theme.colors.warning.main} text={i + 1} />
|
||||
))}
|
||||
</Flex>
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default meta;
|
138
packages/grafana-ui/src/components/Flex/Flex.mdx
Normal file
138
packages/grafana-ui/src/components/Flex/Flex.mdx
Normal file
@ -0,0 +1,138 @@
|
||||
import { Meta, ArgTypes } from '@storybook/blocks';
|
||||
import { Flex } from './Flex';
|
||||
|
||||
<Meta title="MDX|Flex" component={Flex} />
|
||||
|
||||
# Flex
|
||||
|
||||
The Flex Component aims at providing a more efficient way to lay out, align and distribute space among items in a container and
|
||||
the decision to create it is to ensure consistency in design across Grafana.
|
||||
|
||||
### Usage
|
||||
|
||||
#### When to use
|
||||
|
||||
Use when in need to align components and small parts of the application. Use as parent container to wrap elements that you wish to align in a certain way.
|
||||
|
||||
Also:
|
||||
|
||||
* when working with one dimension layout
|
||||
* to display the direction of the elements
|
||||
* to set the elements to wrap
|
||||
* to align items (vertically or horizontally)
|
||||
|
||||
#### When not to use
|
||||
|
||||
When you need to lay out bigger parts of the application or when you want to create page lay out.
|
||||
|
||||
Also:
|
||||
|
||||
* for complex grid layouts with various rows and columns
|
||||
* bidirectional layouts
|
||||
* complex nesting
|
||||
* equal height columns
|
||||
|
||||
### Variants
|
||||
|
||||
Flex component has few variants that can be used based on the desired alignment you need for your case.
|
||||
|
||||
Some examples of how to use the Flex component can be seen below:
|
||||
|
||||
- AlignItems stretch
|
||||
|
||||
```ts
|
||||
import { Flex } from '@grafana/ui'
|
||||
import { useTheme2 } from '../../themes';
|
||||
|
||||
const theme = useTheme2();
|
||||
|
||||
<header>
|
||||
<h1>Using Flex component to align-items stretch and justify-content to be center</h1>
|
||||
</header>
|
||||
<Flex direction="row" wrap="wrap" alignItems="stretch" justifyContent="center" gap={2}>
|
||||
<Item color={theme.colors.warning.main} height="10em" />
|
||||
<Item color={theme.colors.warning.main} />
|
||||
<Item color={theme.colors.warning.main} height="3em" />
|
||||
<Item color={theme.colors.warning.main} />
|
||||
</Flex>
|
||||
```
|
||||
|
||||
- Wrap items wrap-reverse
|
||||
|
||||
```ts
|
||||
import { Flex } from '@grafana/ui'
|
||||
import { useTheme2 } from '../../themes';
|
||||
|
||||
const theme = useTheme2();
|
||||
|
||||
<header>
|
||||
<h1>Using Flex component to align-items with wrap-reverse property</h1>
|
||||
</header>
|
||||
<Flex direction="row" wrap="wrap-reverse" alignItems="center" justifyContent="center" gap={4}>
|
||||
<Item color={theme.colors.warning.main} />
|
||||
<Item color={theme.colors.warning.main} />
|
||||
<Item color={theme.colors.warning.main} />
|
||||
<Item color={theme.colors.warning.main} />
|
||||
</Flex>
|
||||
```
|
||||
|
||||
- JustifyContent flex-start
|
||||
|
||||
```ts
|
||||
import { Flex } from '@grafana/ui'
|
||||
import { useTheme2 } from '../../themes';
|
||||
|
||||
const theme = useTheme2();
|
||||
|
||||
<header>
|
||||
<h1>Using Flex component to align-items with justify-content property</h1>
|
||||
</header>
|
||||
<Flex direction="row" wrap="wrap" alignItems="center" justifyContent="flex-start" gap={2}>
|
||||
<Item color={theme.colors.warning.main} />
|
||||
<Item color={theme.colors.warning.main} />
|
||||
<Item color={theme.colors.warning.main} />
|
||||
<Item color={theme.colors.warning.main} />
|
||||
</Flex>
|
||||
```
|
||||
|
||||
- Gap of 16px using the ThemeSpacingTokens
|
||||
|
||||
```ts
|
||||
import { Flex } from '@grafana/ui'
|
||||
import { useTheme2 } from '../../themes';
|
||||
|
||||
const theme = useTheme2();
|
||||
|
||||
<header>
|
||||
<h1>Using Flex component to align-items with gap of 16px</h1>
|
||||
</header>
|
||||
<Flex direction="row" wrap="wrap" alignItems="center" justifyContent="center" gap={2}>
|
||||
<Item color={theme.colors.warning.main} />
|
||||
<Item color={theme.colors.warning.main} />
|
||||
<Item color={theme.colors.warning.main} />
|
||||
<Item color={theme.colors.warning.main} />
|
||||
</Flex>
|
||||
```
|
||||
|
||||
- Direction column
|
||||
|
||||
```ts
|
||||
import { Flex } from '@grafana/ui'
|
||||
import { useTheme2 } from '../../themes';
|
||||
|
||||
const theme = useTheme2();
|
||||
|
||||
<header>
|
||||
<h1>Using Flex component to align-items with direction column</h1>
|
||||
</header>
|
||||
<Flex direction="column" wrap="wrap" alignItems="center" justifyContent="center" gap={2}>
|
||||
<Item color={theme.colors.warning.main} />
|
||||
<Item color={theme.colors.warning.main} />
|
||||
<Item color={theme.colors.warning.main} />
|
||||
<Item color={theme.colors.warning.main} />
|
||||
</Flex>
|
||||
```
|
||||
|
||||
### Props
|
||||
|
||||
<ArgTypes of={Flex} />
|
75
packages/grafana-ui/src/components/Flex/Flex.tsx
Normal file
75
packages/grafana-ui/src/components/Flex/Flex.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import { GrafanaTheme2, ThemeSpacingTokens } from '@grafana/data';
|
||||
|
||||
import { useStyles2 } from '../../themes';
|
||||
|
||||
export type AlignItems =
|
||||
| 'stretch'
|
||||
| 'flex-start'
|
||||
| 'flex-end'
|
||||
| 'center'
|
||||
| 'baseline'
|
||||
| 'start'
|
||||
| 'end'
|
||||
| 'self-start'
|
||||
| 'self-end';
|
||||
|
||||
export type JustifyContent =
|
||||
| 'flex-start'
|
||||
| 'flex-end'
|
||||
| 'center'
|
||||
| 'space-between'
|
||||
| 'space-around'
|
||||
| 'space-evenly'
|
||||
| 'start'
|
||||
| 'end'
|
||||
| 'left'
|
||||
| 'right';
|
||||
|
||||
export type Direction = 'row' | 'row-reverse' | 'column' | 'column-reverse';
|
||||
|
||||
export type Wrap = 'nowrap' | 'wrap' | 'wrap-reverse';
|
||||
|
||||
interface FlexProps {
|
||||
gap?: ThemeSpacingTokens;
|
||||
alignItems?: AlignItems;
|
||||
justifyContent?: JustifyContent;
|
||||
direction?: Direction;
|
||||
wrap?: Wrap;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const Flex = ({ gap = 1, alignItems, justifyContent, direction, wrap, children }: FlexProps) => {
|
||||
const styles = useStyles2(
|
||||
useCallback(
|
||||
(theme) => getStyles(theme, gap, alignItems, justifyContent, direction, wrap),
|
||||
[gap, alignItems, justifyContent, direction, wrap]
|
||||
)
|
||||
);
|
||||
|
||||
return <div className={styles.flex}>{children}</div>;
|
||||
};
|
||||
|
||||
Flex.displayName = 'Flex';
|
||||
|
||||
const getStyles = (
|
||||
theme: GrafanaTheme2,
|
||||
gap: ThemeSpacingTokens,
|
||||
alignItems: FlexProps['alignItems'],
|
||||
justifyContent: FlexProps['justifyContent'],
|
||||
direction: FlexProps['direction'],
|
||||
wrap: FlexProps['wrap']
|
||||
) => {
|
||||
return {
|
||||
flex: css({
|
||||
display: 'flex',
|
||||
flexDirection: direction,
|
||||
flexWrap: wrap,
|
||||
alignItems: alignItems,
|
||||
justifyContent: justifyContent,
|
||||
gap: theme.spacing(gap),
|
||||
}),
|
||||
};
|
||||
};
|
@ -9,4 +9,4 @@
|
||||
* be subject to the standard policies
|
||||
*/
|
||||
|
||||
export {};
|
||||
export * from './components/Flex/Flex';
|
||||
|
Loading…
Reference in New Issue
Block a user