From dfb6a5375aea1c6d1bdb6177ed8b9a3b8dd3e972 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Sat, 23 Nov 2024 09:37:00 -0800 Subject: [PATCH] Opinionated reorganization/rewriting of our flex docs - it's one of our most used (and sometimes most misused) components, so we might as well spend more time here - flex usage has also changed somewhat since the docs were first written (we use `gap` now instead of negative margins, and flex grid uses CSS grid instead of flexbox), so some of this copy needed updating --- .../eui/src/components/flex/flex_group.tsx | 7 +- .../website/docs/components/layout/flex.mdx | 522 ------------------ .../components/layout/flex/_category_.yml | 2 + .../layout/flex/_flex_preview_note.mdx | 5 + .../docs/components/layout/flex/flex.mdx | 89 +++ .../docs/components/layout/flex/flex_grid.mdx | 147 +++++ .../components/layout/flex/flex_group.mdx | 223 ++++++++ .../docs/components/layout/flex/flex_item.mdx | 173 ++++++ .../{ => flex}/flex_preview_wrapper.tsx | 0 9 files changed, 640 insertions(+), 528 deletions(-) delete mode 100644 packages/website/docs/components/layout/flex.mdx create mode 100644 packages/website/docs/components/layout/flex/_category_.yml create mode 100644 packages/website/docs/components/layout/flex/_flex_preview_note.mdx create mode 100644 packages/website/docs/components/layout/flex/flex.mdx create mode 100644 packages/website/docs/components/layout/flex/flex_grid.mdx create mode 100644 packages/website/docs/components/layout/flex/flex_group.mdx create mode 100644 packages/website/docs/components/layout/flex/flex_item.mdx rename packages/website/docs/components/layout/{ => flex}/flex_preview_wrapper.tsx (100%) diff --git a/packages/eui/src/components/flex/flex_group.tsx b/packages/eui/src/components/flex/flex_group.tsx index 9de2867907e..017ddae0bd3 100644 --- a/packages/eui/src/components/flex/flex_group.tsx +++ b/packages/eui/src/components/flex/flex_group.tsx @@ -64,14 +64,9 @@ export type EuiFlexGroupProps = * such as `'div'` or `'span'`, a React component (a function, a class, * or an exotic component like `memo()`). * - * `` accepts and forwards all extra props to the custom + * `EuiFlexGroup` accepts and forwards all extra props to the custom * component. * - * @example - * // Renders a - ); - ``` - - -## Panels grow to fill flex items - -The [**EuiPanel**](/docs/layout/panel) component will naturally grow to fill the **EuiFlexItem** which contains it. - -```tsx interactive -import React from 'react'; -import { - EuiFlexItem, - EuiFlexGroup, - EuiPanel, - EuiCode, - EuiText, -} from '@elastic/eui'; - -export default () => ( - - - -

- FlexItem -

-

A side nav might be in this one.

-

And you would want the panel on the right to expand with it.

-
-
- - - - EuiPanel - - - - - - Another EuiPanel, with{' '} - grow={false}. - - -
-); -``` - -## Turn off item stretching - -Sometimes you do not want a **EuiFlexItem** to grow horizontally. It can be turned off for each item individually. - - - ```tsx - import React from 'react'; - import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - - export default () => ( - - This item won’t grow - But this item will. - - ); - ``` - - -## Proportional widths of items - -You can specify a number between 1 and 10 for each **EuiFlexItem** to take up a proportional percentage of the **EuiFlexGroup** it is in. - - - ```tsx - import React from 'react'; - import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; - - export default () => ( -
- - 1 - - 2
- wraps content if necessary -
- - 3
- expands_to_fit_if_content_cannot_wrap -
- 4 -
- - - - - 6 - 3 - 1 - 3 - 6 - -
- ); - ``` -
- -## Justify and align - -**EuiFlexGroups** have the props `justifyContent` and `alignItems` that accept [normal flexbox parameters](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Aligning_Items_in_a_Flex_Container). Below are some common scenarios, where you need to separate two items, center justify a single one, or center an item vertically. Note the usage of **EuiFlexItems** with `grow=false` so that they do not stretch. - - - ```tsx - import React from 'react'; - import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - - export default () => ( - - I’m a single centered item! - - ); - ``` - - - - ```tsx - import React from 'react'; - import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - - export default () => ( - - One here on the left. - The other over here on the right. - - ); - ``` - - - - ```tsx - import React from 'react'; - import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - - export default () => ( - - Spaced evenly between this one. - And this one here on the right. - - ); - ``` - - - - ```tsx - import React from 'react'; - import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - - export default () => ( - - -

I

-

am

-

a

-

tall

-

item

-
- I am vertically centered! -
- ); - ``` -
- -## Change direction - -You can change direction using the `direction` prop. - - - ```tsx - import React from 'react'; - import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - - export default () => ( - - Content grid item - Another content grid item - Using the column direction - - ); - ``` - - -## Allowing flex items to wrap - -You can set `wrap` on **EuiFlexGroup** if it contains **EuiFlexItems** with minimum widths, which you want to wrap as the container becomes narrower. - - - ```tsx - import React from 'react'; - import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - - export default () => ( - - Min-width 300px - - Min-width 300px - - Min-width 300px - - ); - ``` - - -## Responsive flex groups - -By default **EuiFlexGroup** is responsive by always stacking the items on smaller screens. However, often you only want to use groups for alignment and margins, rather than layouts. Simply apply the `responsive={false}` prop to retain a single row layout for the group. - - - ```tsx - import React from 'react'; - import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiIcon } from '@elastic/eui'; - - export default () => ( - <> - - - - - - On mobile, the icon will show above this text. - - - - - - - - - - - On mobile, the icon will stay to the left of this text. - - - - ); - ``` - - -## Flex grids are for repeatable items - -**EuiFlexGrid** is a more rigid component that sets multiple, wrapping rows of same width items. You can set a `columns` prop to specify anywhere between 1-4 columns. Any more would likely break on laptop screens. - - - ```tsx - import React from 'react'; - import { EuiFlexGrid, EuiFlexItem } from '@elastic/eui'; - - export default () => ( - - One - Two - Three - Four - Five - Six - Seven - - ); - ``` - - -## Flex grids can change direction - -Adding `direction="column"` will re-orient the flex items so they display top-down **then** left to right. - - - ```tsx - import React from 'react'; - import { EuiFlexGrid, EuiFlexItem } from '@elastic/eui'; - - export default () => ( - - One - Two - Three - Four - Five - Six - Seven - - ); - ``` - - -## Responsive flex grids - -**EuiFlexGrid** is also similarly responsive by default, responsive by always stacking the items vertically on smaller screens. However, should you want to customize the number of items on small or large screens, we recommend applying the `responsive={false}` prop and then conditionally pass a column number based on the current breakpoint. - - - ```tsx - import React from 'react'; - import { EuiFlexGrid, EuiFlexItem, useIsWithinBreakpoints } from '@elastic/eui'; - - export default () => { - const isMobile = useIsWithinBreakpoints(['xs', 's']); - - return ( - - One - Two - Three - Four - Five - Six - - ); - }; - ``` - - -## Flex grids and flex groups can nest - -**EuiFlexGroup** and **EuiFlexGrid** can nest within themselves indefinitely. For example, here we turn off the growth on a **EuiFlexGroup**, then nest a grid inside of it. - -:::warning Flex items are also a flexbox - -To support nested stretching of items, **EuiFlexItem** also has `display: flex` on it so if your children are not behaving correctly, you may want to wrap them in a `
`. - -::: - - - ```tsx - import React from 'react'; - import { EuiFlexGrid, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; - - export default () => ( - <> - - -
Flex Group
- - - Nested Grid One - Nested Grid Two - -
- -
Flex Grid
- - - Nested Grid One - Nested Grid Two - Nested Grid Three - Nested Grid Four - -
-
- - ); - ``` -
- -## Gutter sizing - -The `gutterSize` prop can be applied to either a **EuiFlexGroup** or a **EuiFlexGrid** to adjust the spacing between **EuiFlexItems**. - - - ```tsx - import React from 'react'; - import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; - - export default () => ( -
- - None - None - None - None - - - - - - Extra small - Extra small - Extra small - Extra small - - - - - - Small - Small - Small - Small - - - - - - Medium - Medium - Medium - Medium - - - - - - Large (default) - Large (default) - Large (default) - Large (default) - - - - - - Extra Large - Extra Large - Extra Large - Extra Large - -
- ); - ``` -
- -## Props - -import docgen from '@elastic/eui-docgen/dist/components/flex'; - - - - - - diff --git a/packages/website/docs/components/layout/flex/_category_.yml b/packages/website/docs/components/layout/flex/_category_.yml new file mode 100644 index 00000000000..57aeb4667fc --- /dev/null +++ b/packages/website/docs/components/layout/flex/_category_.yml @@ -0,0 +1,2 @@ +label: Flex +collapsed: true diff --git a/packages/website/docs/components/layout/flex/_flex_preview_note.mdx b/packages/website/docs/components/layout/flex/_flex_preview_note.mdx new file mode 100644 index 00000000000..ef7846ecbf2 --- /dev/null +++ b/packages/website/docs/components/layout/flex/_flex_preview_note.mdx @@ -0,0 +1,5 @@ +:::note Coloring and padding exist for examples only + +Padding and background-color are added to all **EuiFlexItems** on this documentation page for illustrative purposes only. If needed, you must add your own padding through additional components or classes. + +::: diff --git a/packages/website/docs/components/layout/flex/flex.mdx b/packages/website/docs/components/layout/flex/flex.mdx new file mode 100644 index 00000000000..4ad6fb36236 --- /dev/null +++ b/packages/website/docs/components/layout/flex/flex.mdx @@ -0,0 +1,89 @@ +--- +slug: /layout/flex +id: layout_flex +--- + +# Flex + +import { createDemo } from '@elastic/eui-docusaurus-theme/lib/components'; +import { FlexPreviewWrapper } from './flex_preview_wrapper'; +import DemoNote from './_flex_preview_note.mdx'; + +## Use cases + +- [**EuiFlexGroup**](./group) is useful for single row layouts and for quick alignment of items. +- [**EuiFlexGrid**](./grid) should be used for repeated wrapping rows of same-width items. +- [**EuiFlexItem**](./item) should be used as a direct child of both groups or grids. It can also, depending on the layout, be omitted if its automatic flex or grow behavior is not desired. + +## Shared behavior + +export const FlexDemo = createDemo({ previewWrapper: FlexPreviewWrapper }); + + + +### Nesting flex layouts + +**EuiFlexGroup** and **EuiFlexGrid** can nest within themselves indefinitely. For example, here we turn off the growth on a **EuiFlexGroup**, then nest a grid inside of it. + +:::warning Flex items are also a flexbox + +To support nested stretching of items, **EuiFlexItem** also has `display: flex` on it. If your children are not behaving correctly, consider using one of these [flex item workarounds](./item#flex-items-are-also-flex). + +::: + + + ```tsx + import React from 'react'; + import { EuiFlexGrid, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; + + export default () => ( + <> + + +
Flex Group
+ + + Nested Group One + Nested Group Two + +
+ +
Flex Grid
+ + + Nested Grid One + Nested Grid Two + Nested Grid Three + Nested Grid Four + +
+
+ + ); + ``` +
+ +### Overriding output component type + +The `component` prop can be passed to either the parent **EuiFlexGroup** or **EuiFlexGrid**, or the child **EuiFlexItem**, to change the rendered component type from the default `div`. It can be any valid React component type like a tag name string such as `div`or `span` or a React component. + +This allows you to use semantic tags such as `
` with flex layouts, or obey rules around nesting block elements within inline elements. + + + ```tsx + import React from 'react'; + import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + + export default () => ( + + + These items are nested within a paragraph tag + + + + So they use inline span tags to avoid HTML validation issues + + + ); + ``` + diff --git a/packages/website/docs/components/layout/flex/flex_grid.mdx b/packages/website/docs/components/layout/flex/flex_grid.mdx new file mode 100644 index 00000000000..36863dcea59 --- /dev/null +++ b/packages/website/docs/components/layout/flex/flex_grid.mdx @@ -0,0 +1,147 @@ +--- +slug: /layout/flex/grid +id: layout_flex_grid +sidebar_position: 3 +--- + +# Flex grids + +import { createDemo } from '@elastic/eui-docusaurus-theme/lib/components'; +import { FlexPreviewWrapper } from './flex_preview_wrapper'; +import DemoNote from './_flex_preview_note.mdx'; + +export const FlexDemo = createDemo({ previewWrapper: FlexPreviewWrapper }); + + + +**EuiFlexGrid** is a more rigid component, used for repeatable rows of same-width items. You can set a `columns` prop to specify anywhere between 1-4 columns. Any more would likely break on laptop screens. + + + ```tsx + import React from 'react'; + import { EuiFlexGrid, EuiFlexItem } from '@elastic/eui'; + + export default () => ( + + One + Two + Three + Four + Five + Six + Seven + + ); + ``` + + +## Responsive flex grids + +**EuiFlexGrid** is responsive by default, stacking items vertically on smaller screens. Should you want to customize the number of items on small or large screens, apply the `responsive={false}` prop and then conditionally pass a column number based on the current breakpoint. + + + ```tsx + import React from 'react'; + import { EuiFlexGrid, EuiFlexItem, useIsWithinBreakpoints } from '@elastic/eui'; + + export default () => { + const isMobile = useIsWithinBreakpoints(['xs', 's']); + + return ( + + One + Two + Three + Four + Five + Six + + ); + }; + ``` + + +## Display customization + +### Align + +Flex grids support vertically aligning children via the `alignItems` prop. Unlike flex groups, they do not support `justifyContent`, as grid columns are always evenly distributed. + + + ```tsx + import React from 'react'; + import { EuiFlexGrid, EuiFlexItem } from '@elastic/eui'; + + export default () => ( + + I
am
a
tall
item
+ I am vertically centered! +
+ ); + ``` +
+ +### Gutter sizing + +The `gutterSize` prop can be applied to a parent **EuiFlexGrid** to adjust the spacing between child **EuiFlexItems**. + + + ```tsx + import React, { Fragment } from 'react'; + import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; + + const gutterSizes = { + 'none': 'None', + 'xs': 'Extra small', + 's': 'Small', + 'm': 'Medium', + 'l': 'Large (default)', + 'xl': 'Extra large', + } as const; + + export default () => ( + <> + {Object.entries(gutterSizes).map(([gutterSize, text]) => ( + + + {text} + {text} + {text} + {text} + + + + ))} + + ); + ``` + + +### Changing direction + +Adding `direction="column"` will re-orient the flex items so they display top-down **then** left to right. + + + ```tsx + import React from 'react'; + import { EuiFlexGrid, EuiFlexItem } from '@elastic/eui'; + + export default () => ( + + One + Two + Three + Four + Five + Six + Seven + + ); + ``` + + +## Props + +import docgen from '@elastic/eui-docgen/dist/components/flex'; + + diff --git a/packages/website/docs/components/layout/flex/flex_group.mdx b/packages/website/docs/components/layout/flex/flex_group.mdx new file mode 100644 index 00000000000..876170a35ff --- /dev/null +++ b/packages/website/docs/components/layout/flex/flex_group.mdx @@ -0,0 +1,223 @@ +--- +slug: /layout/flex/group +id: layout_flex_group +sidebar_position: 1 +--- + +# Flex groups + +import { createDemo } from '@elastic/eui-docusaurus-theme/lib/components'; +import { FlexPreviewWrapper } from './flex_preview_wrapper'; +import DemoNote from './_flex_preview_note.mdx'; + +export const FlexDemo = createDemo({ previewWrapper: FlexPreviewWrapper }); + + + +**EuiFlexGroup** is useful for setting up layouts for a single row of content. By default, any [**EuiFlexItem**](./item) within **EuiFlexGroup** will stretch and grow to match their siblings. + + + ```tsx + import React from 'react'; + import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; + + export default () => ( + + Flex item + +

Another flex item

+ +

+ Note how both of these are the same width and height despite having + different content? +

+
+
+ ); + ``` +
+ +## Responsive flex groups + +**EuiFlexGroup** is responsive by default, stacking items vertically on smaller screens. If you need to disable this behavior (e.g. for groups only used for alignment and margins rather than layouts), apply the `responsive={false}` prop to retain a single row layout at all screen sizes. + + + ```tsx + import React from 'react'; + import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiIcon } from '@elastic/eui'; + + export default () => ( + <> + + + + + + On mobile, the icon will show above this text. + + + + + + + + + + + On mobile, the icon will stay to the left of this text. + + + + ); + ``` + + +## Display customization + +### Justify and align + +**EuiFlexGroups** have the props `justifyContent` and `alignItems` that accept [normal flexbox parameters](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Aligning_Items_in_a_Flex_Container). Below are some common scenarios, where you need to separate two items, center justify a single one, or center an item vertically. Note the usage of **EuiFlexItems** with `grow=false` so that they do not stretch. + + + ```tsx + import React from 'react'; + import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + + export default () => ( + + I’m a single centered item! + + ); + ``` + + + + ```tsx + import React from 'react'; + import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + + export default () => ( + + One here on the left. + The other over here on the right. + + ); + ``` + + + + ```tsx + import React from 'react'; + import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + + export default () => ( + + Spaced evenly between this one. + And this one here on the right. + + ); + ``` + + + + ```tsx + import React from 'react'; + import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + + export default () => ( + + +

I

+

am

+

a

+

tall

+

item

+
+ I am vertically centered! +
+ ); + ``` +
+ +### Gutter sizing + +The `gutterSize` prop can be applied to a parent **EuiFlexGroup** to adjust the spacing between child **EuiFlexItems**. + + + ```tsx + import React, { Fragment } from 'react'; + import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; + + const gutterSizes = { + 'none': 'None', + 'xs': 'Extra small', + 's': 'Small', + 'm': 'Medium', + 'l': 'Large (default)', + 'xl': 'Extra large', + } as const; + + export default () => ( + <> + {Object.entries(gutterSizes).map(([gutterSize, text]) => ( + + + {text} + {text} + {text} + {text} + + + + ))} + + ); + ``` + + +### Allowing flex items to wrap + +You can set `wrap` on **EuiFlexGroup** if it contains **EuiFlexItems** with minimum widths, which you want to wrap as the container becomes narrower. + + + ```tsx + import React from 'react'; + import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + + export default () => ( + + Min-width 300px + + Min-width 300px + + Min-width 300px + + ); + ``` + + +### Changing direction + +You can change direction using the `direction` prop. + + + ```tsx + import React from 'react'; + import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + + export default () => ( + + Flex item + Another flex item + Using the column direction + + ); + ``` + + +## Props + +import docgen from '@elastic/eui-docgen/dist/components/flex'; + + + diff --git a/packages/website/docs/components/layout/flex/flex_item.mdx b/packages/website/docs/components/layout/flex/flex_item.mdx new file mode 100644 index 00000000000..6b897c543d5 --- /dev/null +++ b/packages/website/docs/components/layout/flex/flex_item.mdx @@ -0,0 +1,173 @@ +--- +slug: /layout/flex/item +id: layout_flex_item +sidebar_position: 2 +--- + +# Flex items + +:::warning +To work correctly, **EuiFlexItem** must be a **direct child** of [**EuiFlexGroup**](./group) or [**EuiFlexGrid**](./grid). You cannot have any intermediate HTML wrappers between them. +::: + +import { createDemo } from '@elastic/eui-docusaurus-theme/lib/components'; +import { FlexPreviewWrapper } from './flex_preview_wrapper'; +import DemoNote from './_flex_preview_note.mdx'; + +export const FlexDemo = createDemo({ previewWrapper: FlexPreviewWrapper }); + + + +## Flex items are also flex + +To allow for continued stretching of nested flex groups/grids and their items, each **EuiFlexItem** also has the property of `display: flex`. + +This can sometimes cause unwanted layouts of your content when there are multiple elements, or if the element itself also has some specific `display` property. To alleviate this, the simplest method is to wrap your inner children with a HTML wrapper like a `
` or ``. + + + ```tsx + import React from 'react'; + import { EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui'; + + export default () => ( + + + Buttons will widen + + +
+ Unless you wrap them +
+
+
+ ); + ``` +
+ +Alternatively, you can sometimes opt to omit **EuiFlexItem** completely. + + + ```tsx + import React from 'react'; + import { EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui'; + + export default () => ( + + + Flex group parents will still
align children as usual +
+ Look ma, no EuiFlexItem +
+ ); + ``` +
+ +## Panels grow vertically to fill flex items + +The [**EuiPanel**](/docs/layout/panel) component will naturally grow to fill the **EuiFlexItem** which contains it. + +```tsx interactive +import React from 'react'; +import { + EuiFlexItem, + EuiFlexGroup, + EuiPanel, + EuiCode, + EuiText, +} from '@elastic/eui'; + +export default () => ( + + + +

+ FlexItem +

+

A side nav might be in this one.

+

And you would want the panel on the right to expand with it.

+
+
+ + + + EuiPanel + + + + + + Another EuiPanel, with{' '} + grow={false}. + + +
+); +``` + +## Grow + +:::warning +The `grow` prop of **EuiFlexItem** only applies when used within [**EuiFlexGroup**](./group). It is ignored by [**EuiFlexGrid**](./grid), which enforces the same width for each item. +::: + +### Turning off item stretching + +By default, all **EuiFlexItems** will grow horizontally within their flex group if the `grow` prop is not specified. This can be turned off for each item individually via `grow={false}`. + + + ```tsx + import React from 'react'; + import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + + export default () => ( + + This item won’t grow + But this item will. + + ); + ``` + + +### Proportional widths of items + +Alternatively, you can specify a `grow` number between 1 and 10 for each **EuiFlexItem** to take up a proportional percentage of the **EuiFlexGroup** it is in. + + + ```tsx + import React from 'react'; + import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; + + export default () => ( +
+ + 1 + + 2
+ wraps content if necessary +
+ + 3
+ expands_to_fit_if_content_cannot_wrap +
+ 4 +
+ + + + + 6 + 3 + 1 + 3 + 6 + +
+ ); + ``` +
+ +## Props + +import docgen from '@elastic/eui-docgen/dist/components/flex'; + + diff --git a/packages/website/docs/components/layout/flex_preview_wrapper.tsx b/packages/website/docs/components/layout/flex/flex_preview_wrapper.tsx similarity index 100% rename from packages/website/docs/components/layout/flex_preview_wrapper.tsx rename to packages/website/docs/components/layout/flex/flex_preview_wrapper.tsx