From cb6239d913bc4c32668cd5fae607204917a23b4d Mon Sep 17 00:00:00 2001
From: RoxanaAnamariaTurc
<106086831+RoxanaAnamariaTurc@users.noreply.github.com>
Date: Thu, 24 Aug 2023 15:05:43 +0100
Subject: [PATCH] Grafana UI: Create custom Flex Component (#73226)
---
.../components/Flex/Flex.internal.story.tsx | 178 ++++++++++++++++++
.../grafana-ui/src/components/Flex/Flex.mdx | 138 ++++++++++++++
.../grafana-ui/src/components/Flex/Flex.tsx | 75 ++++++++
packages/grafana-ui/src/unstable.ts | 2 +-
4 files changed, 392 insertions(+), 1 deletion(-)
create mode 100644 packages/grafana-ui/src/components/Flex/Flex.internal.story.tsx
create mode 100644 packages/grafana-ui/src/components/Flex/Flex.mdx
create mode 100644 packages/grafana-ui/src/components/Flex/Flex.tsx
diff --git a/packages/grafana-ui/src/components/Flex/Flex.internal.story.tsx b/packages/grafana-ui/src/components/Flex/Flex.internal.story.tsx
new file mode 100644
index 00000000000..2e933ced959
--- /dev/null
+++ b/packages/grafana-ui/src/components/Flex/Flex.internal.story.tsx
@@ -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 (
+
+ {text &&
{text}
}
+
+ );
+};
+
+const meta: Meta = {
+ title: 'General/Layout/Flex',
+ component: Flex,
+ decorators: [withCenteredStory],
+ parameters: {
+ docs: {
+ page: mdx,
+ },
+ },
+};
+
+export const Basic: StoryFn = ({ direction, wrap, alignItems, justifyContent, gap }) => {
+ const theme = useTheme2();
+ return (
+
+
+ {Array.from({ length: 5 }).map((_, i) => (
+
+ ))}
+
+
+ );
+};
+
+export const AlignItemsExamples: StoryFn = () => {
+ const theme = useTheme2();
+
+ return (
+
+
Align items flex-start
+
+ {Array.from({ length: 5 }).map((_, i) => (
+
+ ))}
+
+
Align items flex-end
+
+ {Array.from({ length: 5 }).map((_, i) => (
+
+ ))}
+
+
Align items baseline
+
+ {Array.from({ length: 5 }).map((_, i) => (
+
+ ))}
+
+
Align items center
+
+ {Array.from({ length: 5 }).map((_, i) => (
+
+ ))}
+
+
Align items stretch
+
+
+
+
+
+
+
+
+ );
+};
+
+export const JustifyContentExamples: StoryFn = () => {
+ const theme = useTheme2();
+ const justifyContentOptions: JustifyContent[] = [
+ 'space-between',
+ 'space-around',
+ 'space-evenly',
+ 'flex-start',
+ 'flex-end',
+ 'center',
+ ];
+
+ return (
+
+ {justifyContentOptions.map((justifyContent) => (
+ <>
+
Justify Content {justifyContent}
+
+ {Array.from({ length: 5 }).map((_, i) => (
+
+ ))}
+
+ >
+ ))}
+
+ );
+};
+
+export const GapExamples: StoryFn = () => {
+ const theme = useTheme2();
+ const gapOptions: ThemeSpacingTokens[] = [2, 8, 10];
+ return (
+
+ {gapOptions.map((gap) => (
+ <>
+
Gap with spacingToken set to {gap}
+
+ {Array.from({ length: 5 }).map((_, i) => (
+
+ ))}
+
+ >
+ ))}
+
+ );
+};
+
+export const WrapExamples: StoryFn = () => {
+ const theme = useTheme2();
+ const wrapOptions: Wrap[] = ['nowrap', 'wrap', 'wrap-reverse'];
+ return (
+
+ {wrapOptions.map((wrap) => (
+ <>
+
Wrap examples with {wrap} and gap set to spacingToken 2 (16px)
+
+ {Array.from({ length: 10 }).map((_, i) => (
+
+ ))}
+
+ >
+ ))}
+
+ );
+};
+
+export const DirectionExamples: StoryFn = () => {
+ const theme = useTheme2();
+ const directionOptions: Direction[] = ['row', 'row-reverse', 'column', 'column-reverse'];
+ return (
+
+ {directionOptions.map((direction) => (
+ <>
+
Direction {direction}
+
+ {Array.from({ length: 5 }).map((_, i) => (
+
+ ))}
+
+ >
+ ))}
+
+ );
+};
+
+export default meta;
diff --git a/packages/grafana-ui/src/components/Flex/Flex.mdx b/packages/grafana-ui/src/components/Flex/Flex.mdx
new file mode 100644
index 00000000000..a8dd4a58777
--- /dev/null
+++ b/packages/grafana-ui/src/components/Flex/Flex.mdx
@@ -0,0 +1,138 @@
+import { Meta, ArgTypes } from '@storybook/blocks';
+import { Flex } from './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();
+
+
+ Using Flex component to align-items stretch and justify-content to be center
+
+
+
+
+
+
+
+```
+
+- Wrap items wrap-reverse
+
+```ts
+import { Flex } from '@grafana/ui'
+import { useTheme2 } from '../../themes';
+
+const theme = useTheme2();
+
+
+ Using Flex component to align-items with wrap-reverse property
+
+
+
+
+
+
+
+```
+
+- JustifyContent flex-start
+
+```ts
+import { Flex } from '@grafana/ui'
+import { useTheme2 } from '../../themes';
+
+const theme = useTheme2();
+
+
+ Using Flex component to align-items with justify-content property
+
+
+
+
+
+
+
+```
+
+- Gap of 16px using the ThemeSpacingTokens
+
+```ts
+import { Flex } from '@grafana/ui'
+import { useTheme2 } from '../../themes';
+
+const theme = useTheme2();
+
+
+ Using Flex component to align-items with gap of 16px
+
+
+
+
+
+
+
+```
+
+- Direction column
+
+```ts
+import { Flex } from '@grafana/ui'
+import { useTheme2 } from '../../themes';
+
+const theme = useTheme2();
+
+
+ Using Flex component to align-items with direction column
+
+
+
+
+
+
+
+```
+
+### Props
+
+
diff --git a/packages/grafana-ui/src/components/Flex/Flex.tsx b/packages/grafana-ui/src/components/Flex/Flex.tsx
new file mode 100644
index 00000000000..8fa3175e463
--- /dev/null
+++ b/packages/grafana-ui/src/components/Flex/Flex.tsx
@@ -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 {children}
;
+};
+
+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),
+ }),
+ };
+};
diff --git a/packages/grafana-ui/src/unstable.ts b/packages/grafana-ui/src/unstable.ts
index 4628306ac09..f882d5a8a34 100644
--- a/packages/grafana-ui/src/unstable.ts
+++ b/packages/grafana-ui/src/unstable.ts
@@ -9,4 +9,4 @@
* be subject to the standard policies
*/
-export {};
+export * from './components/Flex/Flex';