mirror of
https://github.com/grafana/grafana.git
synced 2025-07-31 23:22:17 +08:00
Grafana UI: Add columnGap
+ rowGap
to Stack
/Grid
(#102883)
add columnGap/rowGap to Stack/Grid
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
import { Meta, StoryFn } from '@storybook/react';
|
import { Meta, StoryFn } from '@storybook/react';
|
||||||
|
|
||||||
import { useTheme2 } from '../../../themes';
|
import { useTheme2 } from '../../../themes';
|
||||||
|
import { SpacingTokenControl } from '../../../utils/storybook/themeStorybookControls';
|
||||||
|
|
||||||
import { Grid } from './Grid';
|
import { Grid } from './Grid';
|
||||||
import mdx from './Grid.mdx';
|
import mdx from './Grid.mdx';
|
||||||
@ -39,6 +40,9 @@ ColumnsNumber.argTypes = {
|
|||||||
control: 'select',
|
control: 'select',
|
||||||
options: ['stretch', 'flex-start', 'flex-end', 'center', 'baseline', 'start', 'end', 'self-start', 'self-end'],
|
options: ['stretch', 'flex-start', 'flex-end', 'center', 'baseline', 'start', 'end', 'self-start', 'self-end'],
|
||||||
},
|
},
|
||||||
|
gap: SpacingTokenControl,
|
||||||
|
rowGap: SpacingTokenControl,
|
||||||
|
columnGap: SpacingTokenControl,
|
||||||
};
|
};
|
||||||
ColumnsNumber.args = {
|
ColumnsNumber.args = {
|
||||||
columns: 3,
|
columns: 3,
|
||||||
@ -52,7 +56,7 @@ ColumnsNumber.parameters = {
|
|||||||
export const ColumnsMinWidth: StoryFn<typeof Grid> = (args) => {
|
export const ColumnsMinWidth: StoryFn<typeof Grid> = (args) => {
|
||||||
const theme = useTheme2();
|
const theme = useTheme2();
|
||||||
return (
|
return (
|
||||||
<Grid gap={args.gap} minColumnWidth={args.minColumnWidth}>
|
<Grid {...args}>
|
||||||
{Array.from({ length: 9 }).map((_, i) => (
|
{Array.from({ length: 9 }).map((_, i) => (
|
||||||
<div key={i} style={{ background: theme.colors.background.secondary, textAlign: 'center' }}>
|
<div key={i} style={{ background: theme.colors.background.secondary, textAlign: 'center' }}>
|
||||||
N# {i}
|
N# {i}
|
||||||
@ -61,6 +65,11 @@ export const ColumnsMinWidth: StoryFn<typeof Grid> = (args) => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
ColumnsMinWidth.argTypes = {
|
||||||
|
gap: SpacingTokenControl,
|
||||||
|
rowGap: SpacingTokenControl,
|
||||||
|
columnGap: SpacingTokenControl,
|
||||||
|
};
|
||||||
ColumnsMinWidth.args = {
|
ColumnsMinWidth.args = {
|
||||||
minColumnWidth: 21,
|
minColumnWidth: 21,
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,8 @@ interface GridPropsBase extends Omit<HTMLAttributes<HTMLDivElement>, 'className'
|
|||||||
children: NonNullable<React.ReactNode>;
|
children: NonNullable<React.ReactNode>;
|
||||||
/** Specifies the gutters between columns and rows. It is overwritten when a column or row gap has a value. */
|
/** Specifies the gutters between columns and rows. It is overwritten when a column or row gap has a value. */
|
||||||
gap?: ResponsiveProp<ThemeSpacingTokens>;
|
gap?: ResponsiveProp<ThemeSpacingTokens>;
|
||||||
|
rowGap?: ResponsiveProp<ThemeSpacingTokens>;
|
||||||
|
columnGap?: ResponsiveProp<ThemeSpacingTokens>;
|
||||||
alignItems?: ResponsiveProp<AlignItems>;
|
alignItems?: ResponsiveProp<AlignItems>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,8 +35,8 @@ interface PropsWithMinColumnWidth extends GridPropsBase {
|
|||||||
type GridProps = PropsWithColumns | PropsWithMinColumnWidth;
|
type GridProps = PropsWithColumns | PropsWithMinColumnWidth;
|
||||||
|
|
||||||
export const Grid = forwardRef<HTMLDivElement, GridProps>((props, ref) => {
|
export const Grid = forwardRef<HTMLDivElement, GridProps>((props, ref) => {
|
||||||
const { alignItems, children, gap, columns, minColumnWidth, ...rest } = props;
|
const { alignItems, children, gap, rowGap, columnGap, columns, minColumnWidth, ...rest } = props;
|
||||||
const styles = useStyles2(getGridStyles, gap, columns, minColumnWidth, alignItems);
|
const styles = useStyles2(getGridStyles, gap, rowGap, columnGap, columns, minColumnWidth, alignItems);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ref} {...rest} className={styles.grid}>
|
<div ref={ref} {...rest} className={styles.grid}>
|
||||||
@ -48,6 +50,8 @@ Grid.displayName = 'Grid';
|
|||||||
const getGridStyles = (
|
const getGridStyles = (
|
||||||
theme: GrafanaTheme2,
|
theme: GrafanaTheme2,
|
||||||
gap: GridProps['gap'],
|
gap: GridProps['gap'],
|
||||||
|
rowGap: GridProps['rowGap'],
|
||||||
|
columnGap: GridProps['columnGap'],
|
||||||
columns: GridProps['columns'],
|
columns: GridProps['columns'],
|
||||||
minColumnWidth: GridProps['minColumnWidth'],
|
minColumnWidth: GridProps['minColumnWidth'],
|
||||||
alignItems: GridProps['alignItems']
|
alignItems: GridProps['alignItems']
|
||||||
@ -58,6 +62,12 @@ const getGridStyles = (
|
|||||||
getResponsiveStyle(theme, gap, (val) => ({
|
getResponsiveStyle(theme, gap, (val) => ({
|
||||||
gap: theme.spacing(val),
|
gap: theme.spacing(val),
|
||||||
})),
|
})),
|
||||||
|
getResponsiveStyle(theme, rowGap, (val) => ({
|
||||||
|
rowGap: theme.spacing(val),
|
||||||
|
})),
|
||||||
|
getResponsiveStyle(theme, columnGap, (val) => ({
|
||||||
|
columnGap: theme.spacing(val),
|
||||||
|
})),
|
||||||
minColumnWidth &&
|
minColumnWidth &&
|
||||||
getResponsiveStyle(theme, minColumnWidth, (val) => ({
|
getResponsiveStyle(theme, minColumnWidth, (val) => ({
|
||||||
gridTemplateColumns: `repeat(auto-fill, minmax(${theme.spacing(val)}, 1fr))`,
|
gridTemplateColumns: `repeat(auto-fill, minmax(${theme.spacing(val)}, 1fr))`,
|
||||||
|
@ -36,11 +36,11 @@ const meta: Meta<typeof Stack> = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Basic: StoryFn<typeof Stack> = ({ direction, wrap, alignItems, justifyContent, gap }) => {
|
export const Basic: StoryFn<typeof Stack> = (args) => {
|
||||||
const theme = useTheme2();
|
const theme = useTheme2();
|
||||||
return (
|
return (
|
||||||
<div style={{ width: '600px', height: '600px', border: '1px solid grey' }}>
|
<div style={{ width: '600px', height: '600px', border: '1px solid grey' }}>
|
||||||
<Stack direction={direction} wrap={wrap} alignItems={alignItems} justifyContent={justifyContent} gap={gap}>
|
<Stack {...args}>
|
||||||
{Array.from({ length: 5 }).map((_, i) => (
|
{Array.from({ length: 5 }).map((_, i) => (
|
||||||
<Item key={i} color={theme.colors.warning.main} text={i + 1} />
|
<Item key={i} color={theme.colors.warning.main} text={i + 1} />
|
||||||
))}
|
))}
|
||||||
@ -51,6 +51,8 @@ export const Basic: StoryFn<typeof Stack> = ({ direction, wrap, alignItems, just
|
|||||||
|
|
||||||
Basic.argTypes = {
|
Basic.argTypes = {
|
||||||
gap: SpacingTokenControl,
|
gap: SpacingTokenControl,
|
||||||
|
rowGap: SpacingTokenControl,
|
||||||
|
columnGap: SpacingTokenControl,
|
||||||
direction: { control: 'select', options: ['row', 'row-reverse', 'column', 'column-reverse'] },
|
direction: { control: 'select', options: ['row', 'row-reverse', 'column', 'column-reverse'] },
|
||||||
wrap: { control: 'select', options: ['nowrap', 'wrap', 'wrap-reverse'] },
|
wrap: { control: 'select', options: ['nowrap', 'wrap', 'wrap-reverse'] },
|
||||||
alignItems: {
|
alignItems: {
|
||||||
|
@ -10,6 +10,8 @@ import { getSizeStyles, SizeProps } from '../utils/styles';
|
|||||||
|
|
||||||
interface StackProps extends FlexProps, SizeProps, Omit<React.HTMLAttributes<HTMLElement>, 'className' | 'style'> {
|
interface StackProps extends FlexProps, SizeProps, Omit<React.HTMLAttributes<HTMLElement>, 'className' | 'style'> {
|
||||||
gap?: ResponsiveProp<ThemeSpacingTokens>;
|
gap?: ResponsiveProp<ThemeSpacingTokens>;
|
||||||
|
rowGap?: ResponsiveProp<ThemeSpacingTokens>;
|
||||||
|
columnGap?: ResponsiveProp<ThemeSpacingTokens>;
|
||||||
alignItems?: ResponsiveProp<AlignItems>;
|
alignItems?: ResponsiveProp<AlignItems>;
|
||||||
justifyContent?: ResponsiveProp<JustifyContent>;
|
justifyContent?: ResponsiveProp<JustifyContent>;
|
||||||
direction?: ResponsiveProp<Direction>;
|
direction?: ResponsiveProp<Direction>;
|
||||||
@ -20,6 +22,8 @@ interface StackProps extends FlexProps, SizeProps, Omit<React.HTMLAttributes<HTM
|
|||||||
export const Stack = React.forwardRef<HTMLDivElement, StackProps>((props, ref) => {
|
export const Stack = React.forwardRef<HTMLDivElement, StackProps>((props, ref) => {
|
||||||
const {
|
const {
|
||||||
gap = 1,
|
gap = 1,
|
||||||
|
rowGap,
|
||||||
|
columnGap,
|
||||||
alignItems,
|
alignItems,
|
||||||
justifyContent,
|
justifyContent,
|
||||||
direction,
|
direction,
|
||||||
@ -37,7 +41,20 @@ export const Stack = React.forwardRef<HTMLDivElement, StackProps>((props, ref) =
|
|||||||
maxHeight,
|
maxHeight,
|
||||||
...rest
|
...rest
|
||||||
} = props;
|
} = props;
|
||||||
const styles = useStyles2(getStyles, gap, alignItems, justifyContent, direction, wrap, grow, shrink, basis, flex);
|
const styles = useStyles2(
|
||||||
|
getStyles,
|
||||||
|
gap,
|
||||||
|
rowGap,
|
||||||
|
columnGap,
|
||||||
|
alignItems,
|
||||||
|
justifyContent,
|
||||||
|
direction,
|
||||||
|
wrap,
|
||||||
|
grow,
|
||||||
|
shrink,
|
||||||
|
basis,
|
||||||
|
flex
|
||||||
|
);
|
||||||
const sizeStyles = useStyles2(getSizeStyles, width, minWidth, maxWidth, height, minHeight, maxHeight);
|
const sizeStyles = useStyles2(getSizeStyles, width, minWidth, maxWidth, height, minHeight, maxHeight);
|
||||||
return (
|
return (
|
||||||
<div ref={ref} className={cx(styles.flex, sizeStyles)} {...rest}>
|
<div ref={ref} className={cx(styles.flex, sizeStyles)} {...rest}>
|
||||||
@ -51,6 +68,8 @@ Stack.displayName = 'Stack';
|
|||||||
const getStyles = (
|
const getStyles = (
|
||||||
theme: GrafanaTheme2,
|
theme: GrafanaTheme2,
|
||||||
gap: StackProps['gap'],
|
gap: StackProps['gap'],
|
||||||
|
rowGap: StackProps['rowGap'],
|
||||||
|
columnGap: StackProps['columnGap'],
|
||||||
alignItems: StackProps['alignItems'],
|
alignItems: StackProps['alignItems'],
|
||||||
justifyContent: StackProps['justifyContent'],
|
justifyContent: StackProps['justifyContent'],
|
||||||
direction: StackProps['direction'],
|
direction: StackProps['direction'],
|
||||||
@ -80,6 +99,12 @@ const getStyles = (
|
|||||||
getResponsiveStyle(theme, gap, (val) => ({
|
getResponsiveStyle(theme, gap, (val) => ({
|
||||||
gap: theme.spacing(val),
|
gap: theme.spacing(val),
|
||||||
})),
|
})),
|
||||||
|
getResponsiveStyle(theme, rowGap, (val) => ({
|
||||||
|
rowGap: theme.spacing(val),
|
||||||
|
})),
|
||||||
|
getResponsiveStyle(theme, columnGap, (val) => ({
|
||||||
|
columnGap: theme.spacing(val),
|
||||||
|
})),
|
||||||
getResponsiveStyle(theme, grow, (val) => ({
|
getResponsiveStyle(theme, grow, (val) => ({
|
||||||
flexGrow: val,
|
flexGrow: val,
|
||||||
})),
|
})),
|
||||||
|
Reference in New Issue
Block a user