Grafana UI: Add `columnGap` + `rowGap` to `Stack`/`Grid` (#102883)

add columnGap/rowGap to Stack/Grid
pull/102890/head
Ashley Harrison 4 months ago committed by GitHub
parent eff2da96d0
commit 0f0519eae5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 11
      packages/grafana-ui/src/components/Layout/Grid/Grid.story.tsx
  2. 14
      packages/grafana-ui/src/components/Layout/Grid/Grid.tsx
  3. 6
      packages/grafana-ui/src/components/Layout/Stack/Stack.story.tsx
  4. 27
      packages/grafana-ui/src/components/Layout/Stack/Stack.tsx

@ -1,6 +1,7 @@
import { Meta, StoryFn } from '@storybook/react';
import { useTheme2 } from '../../../themes';
import { SpacingTokenControl } from '../../../utils/storybook/themeStorybookControls';
import { Grid } from './Grid';
import mdx from './Grid.mdx';
@ -39,6 +40,9 @@ ColumnsNumber.argTypes = {
control: 'select',
options: ['stretch', 'flex-start', 'flex-end', 'center', 'baseline', 'start', 'end', 'self-start', 'self-end'],
},
gap: SpacingTokenControl,
rowGap: SpacingTokenControl,
columnGap: SpacingTokenControl,
};
ColumnsNumber.args = {
columns: 3,
@ -52,7 +56,7 @@ ColumnsNumber.parameters = {
export const ColumnsMinWidth: StoryFn<typeof Grid> = (args) => {
const theme = useTheme2();
return (
<Grid gap={args.gap} minColumnWidth={args.minColumnWidth}>
<Grid {...args}>
{Array.from({ length: 9 }).map((_, i) => (
<div key={i} style={{ background: theme.colors.background.secondary, textAlign: 'center' }}>
N# {i}
@ -61,6 +65,11 @@ export const ColumnsMinWidth: StoryFn<typeof Grid> = (args) => {
</Grid>
);
};
ColumnsMinWidth.argTypes = {
gap: SpacingTokenControl,
rowGap: SpacingTokenControl,
columnGap: SpacingTokenControl,
};
ColumnsMinWidth.args = {
minColumnWidth: 21,
};

@ -12,6 +12,8 @@ interface GridPropsBase extends Omit<HTMLAttributes<HTMLDivElement>, 'className'
children: NonNullable<React.ReactNode>;
/** Specifies the gutters between columns and rows. It is overwritten when a column or row gap has a value. */
gap?: ResponsiveProp<ThemeSpacingTokens>;
rowGap?: ResponsiveProp<ThemeSpacingTokens>;
columnGap?: ResponsiveProp<ThemeSpacingTokens>;
alignItems?: ResponsiveProp<AlignItems>;
}
@ -33,8 +35,8 @@ interface PropsWithMinColumnWidth extends GridPropsBase {
type GridProps = PropsWithColumns | PropsWithMinColumnWidth;
export const Grid = forwardRef<HTMLDivElement, GridProps>((props, ref) => {
const { alignItems, children, gap, columns, minColumnWidth, ...rest } = props;
const styles = useStyles2(getGridStyles, gap, columns, minColumnWidth, alignItems);
const { alignItems, children, gap, rowGap, columnGap, columns, minColumnWidth, ...rest } = props;
const styles = useStyles2(getGridStyles, gap, rowGap, columnGap, columns, minColumnWidth, alignItems);
return (
<div ref={ref} {...rest} className={styles.grid}>
@ -48,6 +50,8 @@ Grid.displayName = 'Grid';
const getGridStyles = (
theme: GrafanaTheme2,
gap: GridProps['gap'],
rowGap: GridProps['rowGap'],
columnGap: GridProps['columnGap'],
columns: GridProps['columns'],
minColumnWidth: GridProps['minColumnWidth'],
alignItems: GridProps['alignItems']
@ -58,6 +62,12 @@ const getGridStyles = (
getResponsiveStyle(theme, gap, (val) => ({
gap: theme.spacing(val),
})),
getResponsiveStyle(theme, rowGap, (val) => ({
rowGap: theme.spacing(val),
})),
getResponsiveStyle(theme, columnGap, (val) => ({
columnGap: theme.spacing(val),
})),
minColumnWidth &&
getResponsiveStyle(theme, minColumnWidth, (val) => ({
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();
return (
<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) => (
<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 = {
gap: SpacingTokenControl,
rowGap: SpacingTokenControl,
columnGap: SpacingTokenControl,
direction: { control: 'select', options: ['row', 'row-reverse', 'column', 'column-reverse'] },
wrap: { control: 'select', options: ['nowrap', 'wrap', 'wrap-reverse'] },
alignItems: {

@ -10,6 +10,8 @@ import { getSizeStyles, SizeProps } from '../utils/styles';
interface StackProps extends FlexProps, SizeProps, Omit<React.HTMLAttributes<HTMLElement>, 'className' | 'style'> {
gap?: ResponsiveProp<ThemeSpacingTokens>;
rowGap?: ResponsiveProp<ThemeSpacingTokens>;
columnGap?: ResponsiveProp<ThemeSpacingTokens>;
alignItems?: ResponsiveProp<AlignItems>;
justifyContent?: ResponsiveProp<JustifyContent>;
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) => {
const {
gap = 1,
rowGap,
columnGap,
alignItems,
justifyContent,
direction,
@ -37,7 +41,20 @@ export const Stack = React.forwardRef<HTMLDivElement, StackProps>((props, ref) =
maxHeight,
...rest
} = 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);
return (
<div ref={ref} className={cx(styles.flex, sizeStyles)} {...rest}>
@ -51,6 +68,8 @@ Stack.displayName = 'Stack';
const getStyles = (
theme: GrafanaTheme2,
gap: StackProps['gap'],
rowGap: StackProps['rowGap'],
columnGap: StackProps['columnGap'],
alignItems: StackProps['alignItems'],
justifyContent: StackProps['justifyContent'],
direction: StackProps['direction'],
@ -80,6 +99,12 @@ const getStyles = (
getResponsiveStyle(theme, gap, (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) => ({
flexGrow: val,
})),

Loading…
Cancel
Save