From cb8817a87993a77148426fd682e2087c77218970 Mon Sep 17 00:00:00 2001 From: cchaos Date: Tue, 26 Jan 2021 16:33:29 -0500 Subject: [PATCH 01/27] Added content type props to EuiPageHeader --- src-docs/src/components/guide_components.scss | 4 + src-docs/src/views/page/page_example.js | 85 +++++++ src-docs/src/views/page/page_header.js | 30 +++ src-docs/src/views/page/page_header_custom.js | 18 ++ src-docs/src/views/page/playground.js | 51 ++++ .../__snapshots__/page_header.test.tsx.snap | 8 +- .../page/page_header/_page_header.scss | 42 ++++ .../page/page_header/page_header.tsx | 232 +++++++++++++++++- 8 files changed, 458 insertions(+), 12 deletions(-) create mode 100644 src-docs/src/views/page/page_header.js create mode 100644 src-docs/src/views/page/page_header_custom.js create mode 100644 src-docs/src/views/page/playground.js diff --git a/src-docs/src/components/guide_components.scss b/src-docs/src/components/guide_components.scss index 5047858a5e6f..553623ae7c59 100644 --- a/src-docs/src/components/guide_components.scss +++ b/src-docs/src/components/guide_components.scss @@ -110,6 +110,10 @@ $guideZLevelHighest: $euiZLevel9 + 1000; } } +.guideDemo__highlightLayout--single { + background: transparentize($euiColorPrimary, .9); +} + .guideDemo__highlightSpacer { .euiSpacer { background: transparentize($euiColorPrimary, .9); diff --git a/src-docs/src/views/page/page_example.js b/src-docs/src/views/page/page_example.js index fbb6c94d5ef3..c713c4977cdd 100644 --- a/src-docs/src/views/page/page_example.js +++ b/src-docs/src/views/page/page_example.js @@ -3,6 +3,7 @@ import React from 'react'; import { renderToHtml } from '../../services'; import { GuideSectionTypes } from '../../components'; +import Playground from './playground'; import { EuiCode, @@ -27,6 +28,14 @@ import PageSimple from './page_simple'; const pageSimpleSource = require('!!raw-loader!./page_simple'); const pageSimpleHtml = renderToHtml(PageSimple); +import PageHeader from './page_header'; +const pageHeaderSource = require('!!raw-loader!./page_header'); +const pageHeaderHtml = renderToHtml(PageHeader); + +import PageHeaderCustom from './page_header_custom'; +const pageHeaderCustomSource = require('!!raw-loader!./page_header_custom'); +const pageHeaderCustomHtml = renderToHtml(PageHeaderCustom); + import PageContentOnly from './page_content_only'; const pageContentOnlySource = require('!!raw-loader!./page_content_only'); const pageContentOnlyHtml = renderToHtml(Page); @@ -40,6 +49,7 @@ const PageContentCenterWithSideBarSource = require('!!raw-loader!./page_content_ const PageContentCenterWithSideBarHtml = renderToHtml(Page); export const PageExample = { + playground: Playground, title: 'Page', intro: ( @@ -117,6 +127,81 @@ export const PageExample = { ), }, + { + title: 'Page header', + source: [ + { + type: GuideSectionTypes.JS, + code: pageHeaderSource, + }, + { + type: GuideSectionTypes.HTML, + code: pageHeaderHtml, + }, + ], + text: ( + <> +

+ EuiPageHeader comes with some pre-determined + content that you can apply to the left and right sides of the + component. +

+

+ The left side allows you to pass any combination of{' '} + pageTitle, description,{' '} + tabs, or any leftSideContent. + The order of which are determined by the particular combination. +

+

+ The right side, rightSideContent, allows for just + a simple array of nodes which are placed within a + flexbox row. This is usually in the form of multiple buttons, of + which, at least one is primary (or{' '} + {'fill="true"'}). These items are + also display in reverse order so that the first and + primary action should be first in the list. +

+

+ You can further adjust the display of these content types with an + optional iconType placed to the left of the + title, alignItems for adjusting the vertical + alignment of the two sides, and responsiveOrder + to determine which content to display first on smaller screens. +

+ + ), + demo: ( +
+ +
+ ), + }, + { + source: [ + { + type: GuideSectionTypes.JS, + code: pageHeaderCustomSource, + }, + { + type: GuideSectionTypes.HTML, + code: pageHeaderCustomHtml, + }, + ], + text: ( +

+ Or you can simply pass in your own custom children{' '} + utilizing the EuiPageHeaderSection components. Do + note, that when supplying children,{' '} + EuiPageHeader will completely ignore any other + content props and only render the children. +

+ ), + demo: ( +
+ +
+ ), + }, { title: 'Page with content only', source: [ diff --git a/src-docs/src/views/page/page_header.js b/src-docs/src/views/page/page_header.js new file mode 100644 index 000000000000..51adf5ec40d5 --- /dev/null +++ b/src-docs/src/views/page/page_header.js @@ -0,0 +1,30 @@ +import React from 'react'; + +import { EuiPageHeader, EuiText, EuiButton } from '../../../../src/components'; + +export default () => ( + +

And some custom content

+
+ } + rightSideContent={[ + Add something, + Do something, + ]} + alignItems="top" + /> +); diff --git a/src-docs/src/views/page/page_header_custom.js b/src-docs/src/views/page/page_header_custom.js new file mode 100644 index 000000000000..db26eff29d9d --- /dev/null +++ b/src-docs/src/views/page/page_header_custom.js @@ -0,0 +1,18 @@ +import React from 'react'; + +import { + EuiPageHeader, + EuiPageHeaderSection, + EuiTitle, +} from '../../../../src/components'; + +export default () => ( + + + +

Page title

+
+
+ Page abilities +
+); diff --git a/src-docs/src/views/page/playground.js b/src-docs/src/views/page/playground.js new file mode 100644 index 000000000000..8523f76f6c7f --- /dev/null +++ b/src-docs/src/views/page/playground.js @@ -0,0 +1,51 @@ +import { PropTypes } from 'react-view'; +import { EuiPageHeader } from '../../../../src/components/'; +import { propUtilityForPlayground } from '../../services/playground'; + +export default () => { + const docgenInfo = Array.isArray(EuiPageHeader.__docgenInfo) + ? EuiPageHeader.__docgenInfo[0] + : EuiPageHeader.__docgenInfo; + const propsToUse = propUtilityForPlayground(docgenInfo.props); + + propsToUse.pageTitle = { + ...propsToUse.pageTitle, + type: PropTypes.String, + value: 'Page title', + }; + + propsToUse.leftSideContent = { + ...propsToUse.leftSideContent, + type: PropTypes.Custom, + // value: undefined, + custom: { + use: 'textarea', + label: 'Anything', + }, + }; + + propsToUse.description = { + ...propsToUse.description, + type: PropTypes.String, + }; + + propsToUse.rightSideContent = { + ...propsToUse.rightSideContent, + type: PropTypes.Array, + }; + + return { + config: { + componentName: 'EuiPageHeader', + props: propsToUse, + scope: { + EuiPageHeader, + }, + imports: { + '@elastic/eui': { + named: ['EuiPageHeader'], + }, + }, + }, + }; +}; diff --git a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap index 44bb0884549e..f3e54952574c 100644 --- a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap @@ -3,7 +3,11 @@ exports[`EuiPageHeader is rendered 1`] = `
+> +
+
`; diff --git a/src/components/page/page_header/_page_header.scss b/src/components/page/page_header/_page_header.scss index 1661035bd927..2b3a3f0a4e18 100644 --- a/src/components/page/page_header/_page_header.scss +++ b/src/components/page/page_header/_page_header.scss @@ -4,6 +4,21 @@ flex-direction: row; justify-content: space-between; align-items: center; + // padding-top: $euiSizeL; + // padding-bottom: $euiSizeL; +} + +.euiPageHeader--top { + align-items: flex-start; +} + +.euiPageHeader--bottom { + align-items: flex-end; +} + +.euiPageHeader__titleIcon { + vertical-align: baseline; + margin-right: $euiSize; } @include euiBreakpoint('xs', 's') { @@ -15,4 +30,31 @@ .euiPageHeader--responsive { flex-direction: column; } + + // Match all around padding and spacers + .euiPageHeaderSection + .euiPageHeaderSection { + margin-top: $euiSizeL; + } + + .euiPageHeader--responsiveReverse { + flex-direction: column-reverse; + + .euiPageHeaderSection { + margin-top: $euiSizeL; + } + + .euiPageHeaderSection + .euiPageHeaderSection { + margin-top: 0; + } + } +} + +@include euiBreakpoint('m', 'l', 'xl') { + .euiPageHeader--tabsAtBottom { + padding-bottom: 0; + } + + .euiPageHeader__rightSideContent { + flex-direction: row-reverse; + } } diff --git a/src/components/page/page_header/page_header.tsx b/src/components/page/page_header/page_header.tsx index bf682c0e622e..b6c19d59da4d 100644 --- a/src/components/page/page_header/page_header.tsx +++ b/src/components/page/page_header/page_header.tsx @@ -17,23 +17,117 @@ * under the License. */ -import React, { FunctionComponent, HTMLAttributes } from 'react'; +import React, { FunctionComponent, ReactNode, HTMLAttributes } from 'react'; import classNames from 'classnames'; import { CommonProps } from '../../common'; +import { EuiIcon, IconType } from '../../icon'; +import { EuiTab, EuiTabs, EuiTabsProps } from '../../tabs'; +import { EuiPageHeaderSection } from './page_header_section'; +import { EuiFlexGroup, EuiFlexItem } from '../../flex'; +import { EuiSpacer } from '../../spacer'; +import { EuiTitle } from '../../title'; +import { EuiText } from '../../text'; -export interface EuiPageHeaderProps - extends CommonProps, - HTMLAttributes { +export const ALIGN_ITEMS = ['top', 'bottom', 'middle'] as const; +export const RESPONSIVE_ORDER = ['leftFirst', 'rightFirst'] as const; + +// Gets all the tab props including the button or link props +type EuiTabProps = React.ComponentProps & { + /** + * Visible text of the tab + */ + label: string; +}; + +export type EuiPageHeaderTitle = { + /** + * Wrapped in an `H1` so choose appropriately. + * A simple string is best + */ + pageTitle?: ReactNode; /** - * Set to false if you don't want the children to stack - * at small screen sizes. + * Optional icon to place to the left of the title */ - responsive?: boolean; -} + iconType?: IconType; +}; + +export type EuiPageHeaderTabs = { + /** + * In-app navigation presented as large borderless tabs. + * Accepts an array of `EuiTab` objects + */ + tabs?: EuiTabProps[]; + /** + * Any extras to apply to the outer tabs container. + * Extends `EuiTabs` + */ + tabsProps?: Omit; +}; + +/** + * The left side can either be a title with optional description and/or icon; + * Or a list of tabs, + * Or a custom node + */ +type EuiPageHeaderLeft = EuiPageHeaderTitle & + EuiPageHeaderTabs & { + /** + * Pass custom content to the left side with `leftSideContent` + */ + leftSideContent?: ReactNode; + /** + * Position is dependent on existing with a `pageTitle` or `tabs` + * Automatically get wrapped in a single paragraph tag inside an EuiText block + */ + description?: string | ReactNode; + }; + +export type EuiPageHeaderProps = CommonProps & + HTMLAttributes & + EuiPageHeaderLeft & { + /** + * Set to false if you don't want the children to stack + * at small screen sizes. + */ + responsive?: boolean; + /** + * Pass custom an array of content to this side usually up to 3 buttons. + * The first button should be primary, usually with `fill` and will be visually displayed as the last item + */ + rightSideContent?: ReactNode[]; + /** + * (?) Should we allow custom values too? + */ + restrictWidth?: boolean; + /** + * Vertical alignment of the left and right side content; + * Default is `top` or dependendent on content + */ + alignItems?: typeof ALIGN_ITEMS[number]; + /** + * Which content to display first when on smaller screens + */ + responsiveOrder?: typeof RESPONSIVE_ORDER[number]; + /** + * Whether the array of right side items should all break to their own line on small screens + */ + rightSideResponsive?: boolean; + }; export const EuiPageHeader: FunctionComponent = ({ - children, + pageTitle, + iconType, + description, + tabs, + tabsProps, className, + leftSideContent, + rightSideContent, + restrictWidth = false, + alignItems = 'center', + responsiveOrder = 'leftFirst', + rightSideResponsive = false, + children, responsive = true, ...rest }) => { @@ -41,13 +135,131 @@ export const EuiPageHeader: FunctionComponent = ({ 'euiPageHeader', { 'euiPageHeader--responsive': responsive, + 'euiPageHeader--restrictWidth-default': restrictWidth, + 'euiPageHeader--tabsAtBottom': pageTitle && tabs, + 'euiPageHeader--responsiveReverse': responsiveOrder === 'rightFirst', }, + `euiPageHeader--${alignItems}`, className ); + if (children) { + return ( +
+ {children} +
+ ); + } + + let descriptionNode; + if (description) { + descriptionNode = ( + <> + + +

{description}

+
+ + ); + } + + let pageTitleNode; + if (pageTitle) { + const icon = iconType ? ( + + ) : undefined; + + pageTitleNode = ( + +

+ {icon} + {pageTitle} +

+
+ ); + } + + let tabsNode; + if (tabs) { + const renderTabs = () => { + return tabs.map((tab, index) => { + const { label, ...tabRest } = tab; + return ( + + {label} + + ); + }); + }; + + tabsNode = ( + <> + {pageTitleNode && } + + {renderTabs()} + + + ); + } + + let leftSideContentNode = leftSideContent; + if (leftSideContent && (tabsNode || pageTitleNode)) { + leftSideContentNode = ( + <> + + {leftSideContent} + + ); + } + + let leftSideOrder; + if (tabsNode && !pageTitleNode) { + leftSideOrder = ( + <> + {tabsNode} + {leftSideContentNode} + {descriptionNode} + + ); + } else { + leftSideOrder = ( + <> + {pageTitleNode} + {descriptionNode} + {leftSideContentNode} + {tabsNode} + + ); + } + + let rightSideNode; + if (rightSideContent && rightSideContent.length) { + const wrapWithFlex = () => { + return rightSideContent.map((item, index) => { + return ( + + {item} + + ); + }); + }; + + rightSideNode = ( + + + {wrapWithFlex()} + + + ); + } + return (
- {children} + {leftSideOrder} + {rightSideNode}
); }; From b54aae408426990f331b5cefc72e35bd673e878c Mon Sep 17 00:00:00 2001 From: cchaos Date: Tue, 26 Jan 2021 16:41:01 -0500 Subject: [PATCH 02/27] Replaced example usages with props --- src-docs/src/services/playground/knobs.js | 10 ++++++++++ src-docs/src/views/page/page.js | 10 +--------- .../page/page_content_center_with_side_bar.js | 13 ++++--------- src-docs/src/views/page/page_simple.js | 9 +-------- src-docs/src/views/tour/fullscreen.js | 17 ++++++----------- 5 files changed, 22 insertions(+), 37 deletions(-) diff --git a/src-docs/src/services/playground/knobs.js b/src-docs/src/services/playground/knobs.js index 3094bf950cb3..6221cfdd0c45 100644 --- a/src-docs/src/services/playground/knobs.js +++ b/src-docs/src/services/playground/knobs.js @@ -251,6 +251,16 @@ const Knob = ({ /> ); + case 'textarea': + return ( + { + set(e.target.value); + }} + /> + ); } } diff --git a/src-docs/src/views/page/page.js b/src-docs/src/views/page/page.js index 3fe78d2f491e..a132c42320a7 100644 --- a/src-docs/src/views/page/page.js +++ b/src-docs/src/views/page/page.js @@ -8,7 +8,6 @@ import { EuiPageContentHeader, EuiPageContentHeaderSection, EuiPageHeader, - EuiPageHeaderSection, EuiPageSideBar, EuiTitle, } from '../../../../src/components'; @@ -17,14 +16,7 @@ export default () => ( SideBar nav - - - -

Page title

-
-
- Page abilities -
+ diff --git a/src-docs/src/views/page/page_content_center_with_side_bar.js b/src-docs/src/views/page/page_content_center_with_side_bar.js index 2856fd5b7334..a2a3bc2b7f87 100644 --- a/src-docs/src/views/page/page_content_center_with_side_bar.js +++ b/src-docs/src/views/page/page_content_center_with_side_bar.js @@ -8,7 +8,6 @@ import { EuiPageContentHeader, EuiPageContentHeaderSection, EuiPageHeader, - EuiPageHeaderSection, EuiPageSideBar, EuiTitle, } from '../../../../src/components'; @@ -18,14 +17,10 @@ export default () => ( SideBar nav {/* The EUI docs site already has a wrapping
tag, so we've changed this example to a
for accessibility. You likely don't need to copy the `component` prop for your own usage. */} - - - -

Page title

-
-
- Page abilities -
+ diff --git a/src-docs/src/views/page/page_simple.js b/src-docs/src/views/page/page_simple.js index d473522c6757..f7c7b237d98d 100644 --- a/src-docs/src/views/page/page_simple.js +++ b/src-docs/src/views/page/page_simple.js @@ -8,20 +8,13 @@ import { EuiPageContentHeader, EuiPageContentHeaderSection, EuiPageHeader, - EuiPageHeaderSection, EuiTitle, } from '../../../../src/components'; export default () => ( - - - -

Page title

-
-
-
+ diff --git a/src-docs/src/views/tour/fullscreen.js b/src-docs/src/views/tour/fullscreen.js index b79159e15d46..df718dbee293 100644 --- a/src-docs/src/views/tour/fullscreen.js +++ b/src-docs/src/views/tour/fullscreen.js @@ -10,7 +10,6 @@ import { EuiPage, EuiPageBody, EuiPageHeader, - EuiPageHeaderSection, EuiPageContent, EuiPageContentHeader, EuiPageContentHeaderSection, @@ -178,22 +177,18 @@ export default () => { - - - -

My app

-
-
- + setIsFullScreen(false)} iconType="exit" aria-label="Exit fullscreen demo"> Exit fullscreen demo - - -
+ , + ]} + /> From 06afe852a80eec191c5c32bfffe39724431fbc1e Mon Sep 17 00:00:00 2001 From: cchaos Date: Tue, 26 Jan 2021 17:41:31 -0500 Subject: [PATCH 03/27] Setting up a new $`euiPageDefaultMaxWidth` sass token --- src-docs/src/components/guide_components.scss | 2 +- src/components/page/_page.scss | 2 +- src/components/page/page.tsx | 2 +- src/components/page/page_body/_page_body.scss | 2 +- src/components/page/page_header/_page_header.scss | 10 +++++++++- src/global_styling/mixins/_responsive.scss | 2 -- src/global_styling/variables/_index.scss | 2 ++ src/global_styling/variables/_page.scss | 1 + .../eui-amsterdam/global_styling/variables/_index.scss | 1 + .../eui-amsterdam/global_styling/variables/_page.scss | 1 + 10 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 src/global_styling/variables/_page.scss create mode 100644 src/themes/eui-amsterdam/global_styling/variables/_page.scss diff --git a/src-docs/src/components/guide_components.scss b/src-docs/src/components/guide_components.scss index 553623ae7c59..fe702ab827c0 100644 --- a/src-docs/src/components/guide_components.scss +++ b/src-docs/src/components/guide_components.scss @@ -96,7 +96,7 @@ $guideZLevelHighest: $euiZLevel9 + 1000; min-height: 100vh; background-color: $euiColorEmptyShade; border-left: $euiBorderThin; - max-width: 1000px; + max-width: $euiPageDefaultMaxWidth; margin-left: 240px; } diff --git a/src/components/page/_page.scss b/src/components/page/_page.scss index 973a1ee53b1b..39634976c120 100644 --- a/src/components/page/_page.scss +++ b/src/components/page/_page.scss @@ -9,7 +9,7 @@ } &--restrictWidth-default { - max-width: 1000px; + max-width: $euiPageDefaultMaxWidth; } @include euiBreakpoint('xs', 's') { diff --git a/src/components/page/page.tsx b/src/components/page/page.tsx index 89668dd07e7b..87fd0cd70d9a 100644 --- a/src/components/page/page.tsx +++ b/src/components/page/page.tsx @@ -35,7 +35,7 @@ export interface EuiPageProps HTMLAttributes { /** * Sets the max-width of the page, - * set to `true` to use the default size of `1000px`, + * set to `true` to use the default size of `1000px (1200 for Amsterdam)`, * set to `false` to not restrict the width, * set to a number for a custom width in px, * set to a string for a custom width in custom measurement. diff --git a/src/components/page/page_body/_page_body.scss b/src/components/page/page_body/_page_body.scss index 990f0fcd1ab6..ccc2c84d399b 100644 --- a/src/components/page/page_body/_page_body.scss +++ b/src/components/page/page_body/_page_body.scss @@ -13,7 +13,7 @@ } &--restrictWidth-default { - max-width: 1000px; + max-width: $euiPageDefaultMaxWidth; } } diff --git a/src/components/page/page_header/_page_header.scss b/src/components/page/page_header/_page_header.scss index 2b3a3f0a4e18..71bb11bef1bd 100644 --- a/src/components/page/page_header/_page_header.scss +++ b/src/components/page/page_header/_page_header.scss @@ -8,6 +8,13 @@ // padding-bottom: $euiSizeL; } +.euiPageHeader--restrictWidth-default { + width: 100%; + max-width: $euiPageDefaultMaxWidth; + margin-left: auto; + margin-right: auto; +} + .euiPageHeader--top { align-items: flex-start; } @@ -17,7 +24,8 @@ } .euiPageHeader__titleIcon { - vertical-align: baseline; + top: -$euiSizeXS; + position: relative; margin-right: $euiSize; } diff --git a/src/global_styling/mixins/_responsive.scss b/src/global_styling/mixins/_responsive.scss index 910c26d27a2a..6747bde4c762 100644 --- a/src/global_styling/mixins/_responsive.scss +++ b/src/global_styling/mixins/_responsive.scss @@ -3,8 +3,6 @@ // sass-lint:disable quotes, no-warn, indentation -@import '../variables/responsive'; - // A sem-complicated mixin for breakpoints, that takes any number of // named breakpoints that exists in $euiBreakpoints. diff --git a/src/global_styling/variables/_index.scss b/src/global_styling/variables/_index.scss index 61d74dfcec34..ce7d1d67fccd 100644 --- a/src/global_styling/variables/_index.scss +++ b/src/global_styling/variables/_index.scss @@ -12,6 +12,7 @@ @import 'animations'; @import 'typography'; @import 'borders'; +@import 'responsive'; @import 'shadows'; @import 'states'; @import 'z_index'; @@ -19,5 +20,6 @@ @import 'buttons'; @import 'form'; @import 'header'; +@import 'page'; @import 'panel'; @import 'tool_tip'; diff --git a/src/global_styling/variables/_page.scss b/src/global_styling/variables/_page.scss new file mode 100644 index 000000000000..870b260aa830 --- /dev/null +++ b/src/global_styling/variables/_page.scss @@ -0,0 +1 @@ +$euiPageDefaultMaxWidth: 1000px !default; diff --git a/src/themes/eui-amsterdam/global_styling/variables/_index.scss b/src/themes/eui-amsterdam/global_styling/variables/_index.scss index b3d6b1d5f8cd..2b1628872ce9 100644 --- a/src/themes/eui-amsterdam/global_styling/variables/_index.scss +++ b/src/themes/eui-amsterdam/global_styling/variables/_index.scss @@ -7,6 +7,7 @@ @import 'flyout'; @import 'form'; @import 'header'; +@import 'page'; @import 'panel'; @import 'steps'; @import 'typography'; diff --git a/src/themes/eui-amsterdam/global_styling/variables/_page.scss b/src/themes/eui-amsterdam/global_styling/variables/_page.scss new file mode 100644 index 000000000000..318cae556816 --- /dev/null +++ b/src/themes/eui-amsterdam/global_styling/variables/_page.scss @@ -0,0 +1 @@ +$euiPageDefaultMaxWidth: map-get($euiBreakpoints, 'xl'); From a2b0e6fa4507fd6b1aa5e14dacf03b72c37480fe Mon Sep 17 00:00:00 2001 From: cchaos Date: Tue, 26 Jan 2021 17:57:42 -0500 Subject: [PATCH 04/27] Updating playground & docs --- .../src/services/playground/iconValidator.js | 3 +- src-docs/src/views/icon/logos.js | 2 +- src-docs/src/views/page/page_example.js | 22 +- src-docs/src/views/page/playground.js | 41 +- .../__snapshots__/page_header.test.tsx.snap | 440 ++++++++++++++++++ .../page/page_header/page_header.test.tsx | 164 ++++++- .../page/page_header/page_header.tsx | 13 +- 7 files changed, 662 insertions(+), 23 deletions(-) diff --git a/src-docs/src/services/playground/iconValidator.js b/src-docs/src/services/playground/iconValidator.js index 336f9180dfd3..3bfd7b30d66f 100644 --- a/src-docs/src/services/playground/iconValidator.js +++ b/src-docs/src/services/playground/iconValidator.js @@ -1,8 +1,9 @@ import { iconTypes } from '../../views/icon/icons'; +import { iconTypes as logoTypes } from '../../views/icon/logos'; import { mapOptions } from './mapOptions'; import { PropTypes } from 'react-view'; -const iconOptions = mapOptions(iconTypes); +const iconOptions = mapOptions(iconTypes.concat(logoTypes)); export const iconValidator = (prop = { custom: {} }) => { const newProp = { diff --git a/src-docs/src/views/icon/logos.js b/src-docs/src/views/icon/logos.js index b433169d531d..d0d42f58846a 100644 --- a/src-docs/src/views/icon/logos.js +++ b/src-docs/src/views/icon/logos.js @@ -20,7 +20,7 @@ import { EuiCopy, } from '../../../../src/components'; -const iconTypes = [ +export const iconTypes = [ 'logoAppSearch', 'logoBeats', 'logoBusinessAnalytics', diff --git a/src-docs/src/views/page/page_example.js b/src-docs/src/views/page/page_example.js index c713c4977cdd..8ac88210dad5 100644 --- a/src-docs/src/views/page/page_example.js +++ b/src-docs/src/views/page/page_example.js @@ -175,6 +175,7 @@ export const PageExample = {
), + props: { EuiPageHeader }, }, { source: [ @@ -188,19 +189,26 @@ export const PageExample = { }, ], text: ( -

- Or you can simply pass in your own custom children{' '} - utilizing the EuiPageHeaderSection components. Do - note, that when supplying children,{' '} - EuiPageHeader will completely ignore any other - content props and only render the children. -

+ <> +

+ The page header content props mainly are helpful props to push + content into established Elastic page layout patterns. They are + completely optional and by nature, inflexible. If you need a layout + that does not match these patterns you can simply pass in your own{' '} + children utilizing the{' '} + EuiPageHeaderSection components. Do note, that when + supplying children,{' '} + EuiPageHeader will completely ignore any other + content props and only render the children. +

+ ), demo: (
), + props: { EuiPageHeader }, }, { title: 'Page with content only', diff --git a/src-docs/src/views/page/playground.js b/src-docs/src/views/page/playground.js index 8523f76f6c7f..250ada2cddc5 100644 --- a/src-docs/src/views/page/playground.js +++ b/src-docs/src/views/page/playground.js @@ -1,6 +1,28 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ + +import React from 'react'; import { PropTypes } from 'react-view'; -import { EuiPageHeader } from '../../../../src/components/'; -import { propUtilityForPlayground } from '../../services/playground'; +import { EuiPageHeader, EuiButton } from '../../../../src/components/'; +import { + propUtilityForPlayground, + iconValidator, +} from '../../services/playground'; + +// HELP: Can we get a "simulate" toggle and pass ReactNodes? +const tabs = [ + { + label: 'Tab 1', + isSelected: true, + }, + { + label: 'Tab 2', + }, +]; + +const rightSideContent = [ + Button 1, + Button 2, +]; export default () => { const docgenInfo = Array.isArray(EuiPageHeader.__docgenInfo) @@ -8,6 +30,8 @@ export default () => { : EuiPageHeader.__docgenInfo; const propsToUse = propUtilityForPlayground(docgenInfo.props); + propsToUse.iconType = iconValidator(propsToUse.iconType); + propsToUse.pageTitle = { ...propsToUse.pageTitle, type: PropTypes.String, @@ -16,12 +40,13 @@ export default () => { propsToUse.leftSideContent = { ...propsToUse.leftSideContent, - type: PropTypes.Custom, - // value: undefined, - custom: { - use: 'textarea', - label: 'Anything', - }, + type: PropTypes.String, + }; + + // HELP: NOT WORKING + propsToUse.alignItems = { + ...propsToUse.alignItems, + defaultValue: 'center', }; propsToUse.description = { diff --git a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap index f3e54952574c..c2cf2a5db1aa 100644 --- a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap @@ -11,3 +11,443 @@ exports[`EuiPageHeader is rendered 1`] = ` />
`; + +exports[`EuiPageHeader props alignItems bottom is rendered 1`] = ` +
+
+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+
+`; + +exports[`EuiPageHeader props alignItems middle is rendered 1`] = ` +
+
+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+
+`; + +exports[`EuiPageHeader props alignItems top is rendered 1`] = ` +
+
+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+
+`; + +exports[`EuiPageHeader props children is rendered 1`] = ` +
+ Child +
+`; + +exports[`EuiPageHeader props children is rendered even if content props are passed 1`] = ` +
+ Child +
+`; + +exports[`EuiPageHeader props description is rendered 1`] = ` +
+
+
+

+ Description +

+
+
+
+`; + +exports[`EuiPageHeader props leftSideContent is rendered 1`] = ` +
+
+

+ Anything +

+
+
+`; + +exports[`EuiPageHeader props pageTitle is rendered 1`] = ` +
+
+

+ Page title +

+
+
+`; + +exports[`EuiPageHeader props pageTitle is rendered with icon 1`] = ` +
+
+

+ + Page title +

+
+
+`; + +exports[`EuiPageHeader props responsive is rendered as false 1`] = ` +
+
+
+`; + +exports[`EuiPageHeader props responsiveOrder leftFirst is rendered 1`] = ` +
+
+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+
+`; + +exports[`EuiPageHeader props responsiveOrder rightFirst is rendered 1`] = ` +
+
+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+
+`; + +exports[`EuiPageHeader props restrictWidth is rendered as true 1`] = ` +
+
+
+`; + +exports[`EuiPageHeader props rightSideContent is rendered 1`] = ` +
+
+
+
+
+ +
+
+ +
+
+
+
+`; + +exports[`EuiPageHeader props rightSideContent is rendered with rightSideResponsive as true 1`] = ` +
+
+
+
+
+ +
+
+ +
+
+
+
+`; + +exports[`EuiPageHeader props tabs is rendered 1`] = ` +
+
+
+ + +
+
+
+`; + +exports[`EuiPageHeader props tabs is rendered with tabsProps 1`] = ` +
+
+
+ + +
+
+
+`; diff --git a/src/components/page/page_header/page_header.test.tsx b/src/components/page/page_header/page_header.test.tsx index 2fe9aa62fd70..aecf747398ef 100644 --- a/src/components/page/page_header/page_header.test.tsx +++ b/src/components/page/page_header/page_header.test.tsx @@ -21,7 +21,27 @@ import React from 'react'; import { render } from 'enzyme'; import { requiredProps } from '../../../test/required_props'; -import { EuiPageHeader } from './page_header'; +import { + ALIGN_ITEMS, + EuiPageHeader, + EuiPageHeaderProps, + RESPONSIVE_ORDER, +} from './page_header'; + +const tabs: EuiPageHeaderProps['tabs'] = [ + { + label: 'Tab 1', + isSelected: true, + }, + { + label: 'Tab 2', + }, +]; + +const rightSideContent: EuiPageHeaderProps['rightSideContent'] = [ + , + , +]; describe('EuiPageHeader', () => { test('is rendered', () => { @@ -29,4 +49,146 @@ describe('EuiPageHeader', () => { expect(component).toMatchSnapshot(); }); + + describe('props', () => { + describe('pageTitle', () => { + test('is rendered', () => { + const component = render(); + + expect(component).toMatchSnapshot(); + }); + + test('is rendered with icon', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('tabs', () => { + test('is rendered', () => { + const component = render(); + + expect(component).toMatchSnapshot(); + }); + + test('is rendered with tabsProps', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('leftSideContent', () => { + test('is rendered', () => { + const component = render( + Anything

} /> + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('description', () => { + test('is rendered', () => { + const component = render(); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('rightSideContent', () => { + test('is rendered', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + + test('is rendered with rightSideResponsive as true', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('children', () => { + test('is rendered', () => { + const component = render(Child); + + expect(component).toMatchSnapshot(); + }); + + test('is rendered even if content props are passed', () => { + const component = render( + + Child + + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('alignItems', () => { + ALIGN_ITEMS.forEach((alignment) => { + it(`${alignment} is rendered`, () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + }); + + describe('responsiveOrder', () => { + RESPONSIVE_ORDER.forEach((order) => { + it(`${order} is rendered`, () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + }); + + describe('responsive', () => { + test('is rendered as false', () => { + const component = render(); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('restrictWidth', () => { + test('is rendered as true', () => { + const component = render(); + + expect(component).toMatchSnapshot(); + }); + }); + }); }); diff --git a/src/components/page/page_header/page_header.tsx b/src/components/page/page_header/page_header.tsx index b6c19d59da4d..a306a4a98e78 100644 --- a/src/components/page/page_header/page_header.tsx +++ b/src/components/page/page_header/page_header.tsx @@ -54,7 +54,8 @@ export type EuiPageHeaderTitle = { export type EuiPageHeaderTabs = { /** * In-app navigation presented as large borderless tabs. - * Accepts an array of `EuiTab` objects + * Accepts an array of `EuiTab` objects; + * HELP: This is evaluating to `any[]` in the props table */ tabs?: EuiTabProps[]; /** @@ -105,7 +106,8 @@ export type EuiPageHeaderProps = CommonProps & */ alignItems?: typeof ALIGN_ITEMS[number]; /** - * Which content to display first when on smaller screens + * Which content to display first when on smaller screens. + * Useful when the right side content should actually come beforehand in the hierarchy (like time) */ responsiveOrder?: typeof RESPONSIVE_ORDER[number]; /** @@ -136,8 +138,9 @@ export const EuiPageHeader: FunctionComponent = ({ { 'euiPageHeader--responsive': responsive, 'euiPageHeader--restrictWidth-default': restrictWidth, - 'euiPageHeader--tabsAtBottom': pageTitle && tabs, - 'euiPageHeader--responsiveReverse': responsiveOrder === 'rightFirst', + 'euiPageHeader--tabsAtBottom': !children && pageTitle && tabs, + 'euiPageHeader--responsiveReverse': + !children && responsiveOrder === 'rightFirst', }, `euiPageHeader--${alignItems}`, className @@ -155,7 +158,7 @@ export const EuiPageHeader: FunctionComponent = ({ if (description) { descriptionNode = ( <> - + {(pageTitle || tabs) && }

{description}

From c19d0380e8446667d0b31401a324770a3a252e89 Mon Sep 17 00:00:00 2001 From: cchaos Date: Tue, 26 Jan 2021 18:00:12 -0500 Subject: [PATCH 05/27] Fixin amsterdam small and reverse shadows --- .../eui-amsterdam/global_styling/mixins/_shadow.scss | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/themes/eui-amsterdam/global_styling/mixins/_shadow.scss b/src/themes/eui-amsterdam/global_styling/mixins/_shadow.scss index 49d46e2e0e4c..f50c8a74c28e 100644 --- a/src/themes/eui-amsterdam/global_styling/mixins/_shadow.scss +++ b/src/themes/eui-amsterdam/global_styling/mixins/_shadow.scss @@ -17,8 +17,7 @@ box-shadow: 0 .7px 1.4px rgba($color, shadowOpacity(.07)), 0 1.9px 4px rgba($color, shadowOpacity(.05)), - 0 4.5px 10px rgba($color, shadowOpacity(.05)), - 0 15px 32px rgba($color, shadowOpacity(.04)); + 0 4.5px 10px rgba($color, shadowOpacity(.05)); @if ($opacity > 0) { @warn 'The $opacity variable of euiBottomShadowSmall() will be depricated in a future version of EUI.'; @@ -77,9 +76,9 @@ ) { @if ($reverse) { box-shadow: - 0 2.7px -9px rgba($color, shadowOpacity(.13)), - 0 9.4px -24px rgba($color, shadowOpacity(.09)), - 0 21.8px -43px rgba($color, shadowOpacity(.08)); + 0 -2.7px 9px rgba($color, shadowOpacity(.13)), + 0 -9.4px 24px rgba($color, shadowOpacity(.09)), + 0 -21.8px 43px rgba($color, shadowOpacity(.08)); } @else { box-shadow: 0 2.7px 9px rgba($color, shadowOpacity(.13)), From eff79dc4f7b89abb6eff59920aab8bdc0cc2a298 Mon Sep 17 00:00:00 2001 From: cchaos Date: Tue, 26 Jan 2021 18:02:09 -0500 Subject: [PATCH 06/27] =?UTF-8?q?=E2=80=98Fixing=E2=80=99=20paddingSize=20?= =?UTF-8?q?prop=20on=20EuiPageContent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/page/page_content/page_content.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/page/page_content/page_content.tsx b/src/components/page/page_content/page_content.tsx index c707a6639c45..cefc78a27537 100644 --- a/src/components/page/page_content/page_content.tsx +++ b/src/components/page/page_content/page_content.tsx @@ -48,7 +48,8 @@ export type EuiPageContentProps = CommonProps & export const EuiPageContent: FunctionComponent = ({ verticalPosition, horizontalPosition, - panelPaddingSize = 'l', + panelPaddingSize, + paddingSize = 'l', children, className, ...rest @@ -63,7 +64,10 @@ export const EuiPageContent: FunctionComponent = ({ ); return ( - + {children} ); From 206351c8081ceaeab860433ea3cd4ed5c4fe44e7 Mon Sep 17 00:00:00 2001 From: cchaos Date: Thu, 28 Jan 2021 12:19:53 -0500 Subject: [PATCH 07/27] Adding custom options for `restrictWidth` --- src-docs/src/views/page/page_example.js | 6 ++--- src/components/page/page.tsx | 2 +- .../__snapshots__/page_header.test.tsx.snap | 2 +- .../page/page_header/_page_header.scss | 18 +++++++------ .../page/page_header/page_header.tsx | 25 +++++++++++++++---- 5 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src-docs/src/views/page/page_example.js b/src-docs/src/views/page/page_example.js index 8ac88210dad5..75cd7dfd5297 100644 --- a/src-docs/src/views/page/page_example.js +++ b/src-docs/src/views/page/page_example.js @@ -158,15 +158,15 @@ export const PageExample = { flexbox row. This is usually in the form of multiple buttons, of which, at least one is primary (or{' '} {'fill="true"'}). These items are - also display in reverse order so that the first and - primary action should be first in the list. + also displayed in reverse order so that the first + and primary action should be first in the list.

You can further adjust the display of these content types with an optional iconType placed to the left of the title, alignItems for adjusting the vertical alignment of the two sides, and responsiveOrder - to determine which content to display first on smaller screens. + to determine which content side to display first on smaller screens.

), diff --git a/src/components/page/page.tsx b/src/components/page/page.tsx index 87fd0cd70d9a..33deab797a86 100644 --- a/src/components/page/page.tsx +++ b/src/components/page/page.tsx @@ -43,7 +43,7 @@ export interface EuiPageProps restrictWidth?: boolean | number | string; /** * Adjust the padding. - * When using this setting it's best to be consistent throught all similar usages. + * When using this setting it's best to be consistent throughout all similar usages. */ paddingSize?: typeof SIZES[number]; } diff --git a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap index c2cf2a5db1aa..3f25cab3c07e 100644 --- a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap @@ -298,7 +298,7 @@ exports[`EuiPageHeader props responsiveOrder rightFirst is rendered 1`] = ` exports[`EuiPageHeader props restrictWidth is rendered as true 1`] = `
= ({ rightSideResponsive = false, children, responsive = true, + style, ...rest }) => { + let widthClassname; + let newStyle; + + if (restrictWidth === true) { + widthClassname = 'euiPageHeader--restrictWidth-default'; + } else if (restrictWidth !== false) { + widthClassname = 'euiPageHeader--restrictWidth-custom'; + newStyle = { ...style, maxWidth: restrictWidth }; + } + const classes = classNames( 'euiPageHeader', { 'euiPageHeader--responsive': responsive, - 'euiPageHeader--restrictWidth-default': restrictWidth, 'euiPageHeader--tabsAtBottom': !children && pageTitle && tabs, 'euiPageHeader--responsiveReverse': !children && responsiveOrder === 'rightFirst', }, `euiPageHeader--${alignItems}`, + widthClassname, className ); if (children) { return ( -
+
{children}
); @@ -260,7 +275,7 @@ export const EuiPageHeader: FunctionComponent = ({ } return ( -
+
{leftSideOrder} {rightSideNode}
From 6413fb497af9d8de370f1daed3ed4c1b88b79a8d Mon Sep 17 00:00:00 2001 From: cchaos Date: Thu, 28 Jan 2021 17:34:52 -0500 Subject: [PATCH 08/27] Starting the switch to a new component `EuiPageHeaderContent` --- src-docs/src/views/page/page_example.js | 36 ++ src-docs/src/views/page/page_header.js | 81 ++- src-docs/src/views/page/page_header_tabs.js | 57 ++ src/components/index.js | 1 + src/components/page/index.ts | 2 + .../page_header_content.test.tsx.snap | 525 ++++++++++++++++++ src/components/page/page_header/_index.scss | 1 + .../page_header/_page_header_content.scss | 85 +++ src/components/page/page_header/index.ts | 4 + .../page_header/page_header_content.test.tsx | 200 +++++++ .../page/page_header/page_header_content.tsx | 282 ++++++++++ 11 files changed, 1249 insertions(+), 25 deletions(-) create mode 100644 src-docs/src/views/page/page_header_tabs.js create mode 100644 src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap create mode 100644 src/components/page/page_header/_page_header_content.scss create mode 100644 src/components/page/page_header/page_header_content.test.tsx create mode 100644 src/components/page/page_header/page_header_content.tsx diff --git a/src-docs/src/views/page/page_example.js b/src-docs/src/views/page/page_example.js index 75cd7dfd5297..9e43769a92e5 100644 --- a/src-docs/src/views/page/page_example.js +++ b/src-docs/src/views/page/page_example.js @@ -32,6 +32,10 @@ import PageHeader from './page_header'; const pageHeaderSource = require('!!raw-loader!./page_header'); const pageHeaderHtml = renderToHtml(PageHeader); +import PageHeaderTabs from './page_header_tabs'; +const pageHeaderTabsSource = require('!!raw-loader!./page_header_tabs'); +const pageHeaderTabsHtml = renderToHtml(PageHeaderTabs); + import PageHeaderCustom from './page_header_custom'; const pageHeaderCustomSource = require('!!raw-loader!./page_header_custom'); const pageHeaderCustomHtml = renderToHtml(PageHeaderCustom); @@ -178,6 +182,38 @@ export const PageExample = { props: { EuiPageHeader }, }, { + title: 'Page header tabs', + source: [ + { + type: GuideSectionTypes.JS, + code: pageHeaderTabsSource, + }, + { + type: GuideSectionTypes.HTML, + code: pageHeaderTabsHtml, + }, + ], + text: ( + <> +

+ When using supplying tabs with a{' '} + pageTitle, EuiPageHeader will + promote those tabs as if they are the page title. This means that + any description, or{' '} + leftSideContent will sit below{' '} + the tabs. +

+ + ), + demo: ( +
+ +
+ ), + props: { EuiPageHeader }, + }, + { + title: 'Page header custom', source: [ { type: GuideSectionTypes.JS, diff --git a/src-docs/src/views/page/page_header.js b/src-docs/src/views/page/page_header.js index 51adf5ec40d5..592a3191b42e 100644 --- a/src-docs/src/views/page/page_header.js +++ b/src-docs/src/views/page/page_header.js @@ -1,30 +1,61 @@ import React from 'react'; -import { EuiPageHeader, EuiText, EuiButton } from '../../../../src/components'; +import { + EuiPageHeader, + EuiText, + EuiButton, + EuiPageHeaderContent, +} from '../../../../src/components'; export default () => ( - -

And some custom content

- - } - rightSideContent={[ - Add something, - Do something, - ]} - alignItems="top" - /> + <> + +

And some custom content

+ + } + rightSideContent={[ + Add something, + Do something, + ]} + alignItems="top" + /> + +

And some custom content

+ + } + rightSideContent={[ + Add something, + Do something, + ]} + alignItems="top" + /> + ); diff --git a/src-docs/src/views/page/page_header_tabs.js b/src-docs/src/views/page/page_header_tabs.js new file mode 100644 index 000000000000..cdc7d32650f1 --- /dev/null +++ b/src-docs/src/views/page/page_header_tabs.js @@ -0,0 +1,57 @@ +import React from 'react'; + +import { + EuiPageHeader, + EuiText, + EuiButton, + EuiPageHeaderContent, +} from '../../../../src/components'; + +export default () => ( + <> + +

And some custom content

+ + } + rightSideContent={[ + Add something, + Do something, + ]} + alignItems="top" + /> + +

And some custom content

+ + } + rightSideContent={[ + Add something, + Do something, + ]} + alignItems="top" + /> + +); diff --git a/src/components/index.js b/src/components/index.js index a57b1fe2235d..b2af052ad9f7 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -253,6 +253,7 @@ export { EuiPageContentHeader, EuiPageContentHeaderSection, EuiPageHeader, + EuiPageHeaderContent, EuiPageHeaderSection, EuiPageSideBar, } from './page'; diff --git a/src/components/page/index.ts b/src/components/page/index.ts index 7cfb2d64ef34..942c6887b014 100644 --- a/src/components/page/index.ts +++ b/src/components/page/index.ts @@ -34,6 +34,8 @@ export { export { EuiPageHeader, + EuiPageHeaderContent, + EuiPageHeaderContentProps, EuiPageHeaderProps, EuiPageHeaderSection, EuiPageHeaderSectionProps, diff --git a/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap new file mode 100644 index 000000000000..8ca711f7e807 --- /dev/null +++ b/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap @@ -0,0 +1,525 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EuiPageHeaderContent is rendered 1`] = ` +
+
+
+`; + +exports[`EuiPageHeaderContent props alignItems bottom is rendered 1`] = ` +
+
+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+
+`; + +exports[`EuiPageHeaderContent props alignItems middle is rendered 1`] = ` +
+
+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+
+`; + +exports[`EuiPageHeaderContent props alignItems top is rendered 1`] = ` +
+
+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+
+`; + +exports[`EuiPageHeaderContent props children is rendered 1`] = ` +
+
+ Child +
+`; + +exports[`EuiPageHeaderContent props children is rendered even if content props are passed 1`] = ` +
+
+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+
+
+ Child +
+
+ + +
+
+
+`; + +exports[`EuiPageHeaderContent props description is rendered 1`] = ` +
+
+
+

+ Description +

+
+
+
+`; + +exports[`EuiPageHeaderContent props leftSideContent is rendered 1`] = ` +
+
+

+ Anything +

+
+`; + +exports[`EuiPageHeaderContent props pageTitle is rendered 1`] = ` +
+
+

+ Page title +

+
+
+`; + +exports[`EuiPageHeaderContent props pageTitle is rendered with icon 1`] = ` +
+
+

+ + Page title +

+
+
+`; + +exports[`EuiPageHeaderContent props responsive is rendered as false 1`] = ` +
+
+
+`; + +exports[`EuiPageHeaderContent props responsiveOrder leftFirst is rendered 1`] = ` +
+
+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+
+`; + +exports[`EuiPageHeaderContent props responsiveOrder rightFirst is rendered 1`] = ` +
+
+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+
+`; + +exports[`EuiPageHeaderContent props restrictWidth is rendered as true 1`] = ` +
+
+
+`; + +exports[`EuiPageHeaderContent props rightSideContent is rendered 1`] = ` +
+
+
+
+
+ +
+
+ +
+
+
+
+`; + +exports[`EuiPageHeaderContent props rightSideContent is rendered with rightSideResponsive as true 1`] = ` +
+
+
+
+
+ +
+
+ +
+
+
+
+`; + +exports[`EuiPageHeaderContent props tabs is rendered 1`] = ` +
+
+
+ + +
+
+
+`; + +exports[`EuiPageHeaderContent props tabs is rendered with tabsProps 1`] = ` +
+
+
+ + +
+
+
+`; diff --git a/src/components/page/page_header/_index.scss b/src/components/page/page_header/_index.scss index df5354044ba4..600ba67cd57f 100644 --- a/src/components/page/page_header/_index.scss +++ b/src/components/page/page_header/_index.scss @@ -1,2 +1,3 @@ @import 'page_header'; +@import 'page_header_content'; @import 'page_header_section'; diff --git a/src/components/page/page_header/_page_header_content.scss b/src/components/page/page_header/_page_header_content.scss new file mode 100644 index 000000000000..f4b2d6ed36fe --- /dev/null +++ b/src/components/page/page_header/_page_header_content.scss @@ -0,0 +1,85 @@ +.euiPageHeader { + width: 100%; + margin-bottom: $euiSize; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + + &--restrictWidth-default, + &--restrictWidth-custom { + margin-left: auto; + margin-right: auto; + } + + &--restrictWidth-default { + max-width: $euiPageDefaultMaxWidth; + } +} + +.euiPageHeader__top { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; +} + +.euiPageHeader--column { + flex-direction: column; +} + +.euiPageHeader--top .euiPageHeader__top, +.euiPageHeader--top { + align-items: flex-start; +} + +.euiPageHeader--bottom .euiPageHeader__top, +.euiPageHeader--bottom { + align-items: flex-end; +} + +.euiPageHeader__titleIcon { + top: -$euiSizeXS; + position: relative; + margin-right: $euiSize; +} + +@include euiBreakpoint('xs', 's') { + .euiPageHeader { + padding: $euiSize 0; + margin-bottom: 0; + } + + .euiPageHeader--responsive .euiPageHeader__top, + .euiPageHeader--responsive { + flex-direction: column; + } + + // Match all around padding and spacers + .euiPageHeaderSection + .euiPageHeaderSection { + margin-top: $euiSizeL; + } + + .euiPageHeader--responsiveReverse .euiPageHeader__top, + .euiPageHeader--responsiveReverse { + flex-direction: column-reverse; + + .euiPageHeaderSection { + margin-top: $euiSizeL; + } + + .euiPageHeaderSection + .euiPageHeaderSection { + margin-top: 0; + } + } +} + +@include euiBreakpoint('m', 'l', 'xl') { + .euiPageHeader--tabsAtBottom { + padding-bottom: 0; + } + + .euiPageHeader__rightSideContent { + flex-direction: row-reverse; + } +} diff --git a/src/components/page/page_header/index.ts b/src/components/page/page_header/index.ts index 8a1d06549516..bba450a17330 100644 --- a/src/components/page/page_header/index.ts +++ b/src/components/page/page_header/index.ts @@ -18,6 +18,10 @@ */ export { EuiPageHeader, EuiPageHeaderProps } from './page_header'; +export { + EuiPageHeaderContent, + EuiPageHeaderContentProps, +} from './page_header_content'; export { EuiPageHeaderSection, EuiPageHeaderSectionProps, diff --git a/src/components/page/page_header/page_header_content.test.tsx b/src/components/page/page_header/page_header_content.test.tsx new file mode 100644 index 000000000000..ed5351f53cf5 --- /dev/null +++ b/src/components/page/page_header/page_header_content.test.tsx @@ -0,0 +1,200 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { render } from 'enzyme'; +import { requiredProps } from '../../../test/required_props'; + +import { + ALIGN_ITEMS, + EuiPageHeaderContent, + EuiPageHeaderContentProps, + RESPONSIVE_ORDER, +} from './page_header_content'; + +const tabs: EuiPageHeaderContentProps['tabs'] = [ + { + label: 'Tab 1', + isSelected: true, + }, + { + label: 'Tab 2', + }, +]; + +const rightSideContent: EuiPageHeaderContentProps['rightSideContent'] = [ + , + , +]; + +describe('EuiPageHeaderContent', () => { + test('is rendered', () => { + const component = render(); + + expect(component).toMatchSnapshot(); + }); + + describe('props', () => { + describe('pageTitle', () => { + test('is rendered', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + + test('is rendered with icon', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('tabs', () => { + test('is rendered', () => { + const component = render(); + + expect(component).toMatchSnapshot(); + }); + + test('is rendered with tabsProps', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('leftSideContent', () => { + test('is rendered', () => { + const component = render( + Anything

} /> + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('description', () => { + test('is rendered', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('rightSideContent', () => { + test('is rendered', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + + test('is rendered with rightSideResponsive as true', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('children', () => { + test('is rendered', () => { + const component = render( + Child + ); + + expect(component).toMatchSnapshot(); + }); + + test('is rendered even if content props are passed', () => { + const component = render( + + Child + + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('alignItems', () => { + ALIGN_ITEMS.forEach((alignment) => { + it(`${alignment} is rendered`, () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + }); + + describe('responsiveOrder', () => { + RESPONSIVE_ORDER.forEach((order) => { + it(`${order} is rendered`, () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + }); + + describe('responsive', () => { + test('is rendered as false', () => { + const component = render(); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('restrictWidth', () => { + test('is rendered as true', () => { + const component = render(); + + expect(component).toMatchSnapshot(); + }); + }); + }); +}); diff --git a/src/components/page/page_header/page_header_content.tsx b/src/components/page/page_header/page_header_content.tsx new file mode 100644 index 000000000000..e80f27f02ad4 --- /dev/null +++ b/src/components/page/page_header/page_header_content.tsx @@ -0,0 +1,282 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { FunctionComponent, ReactNode, HTMLAttributes } from 'react'; +import classNames from 'classnames'; +import { CommonProps } from '../../common'; +import { EuiIcon, IconType } from '../../icon'; +import { EuiTab, EuiTabs, EuiTabsProps } from '../../tabs'; +import { EuiPageHeaderSection } from './page_header_section'; +import { EuiFlexGroup, EuiFlexItem } from '../../flex'; +import { EuiSpacer } from '../../spacer'; +import { EuiTitle } from '../../title'; +import { EuiText } from '../../text'; + +export const ALIGN_ITEMS = ['top', 'bottom', 'middle'] as const; +export const RESPONSIVE_ORDER = ['leftFirst', 'rightFirst'] as const; + +// Gets all the tab props including the button or link props +type EuiTabProps = React.ComponentProps & { + /** + * Visible text of the tab + */ + label: string; +}; + +export type EuiPageHeaderContentTitle = { + /** + * Wrapped in an `H1` so choose appropriately. + * A simple string is best + */ + pageTitle?: ReactNode; + /** + * Optional icon to place to the left of the title + */ + iconType?: IconType; +}; + +export type EuiPageHeaderContentTabs = { + /** + * In-app navigation presented as large borderless tabs. + * Accepts an array of `EuiTab` objects; + * HELP: This is evaluating to `any[]` in the props table + */ + tabs?: EuiTabProps[]; + /** + * Any extras to apply to the outer tabs container. + * Extends `EuiTabs` + */ + tabsProps?: Omit; +}; + +/** + * The left side can either be a title with optional description and/or icon; + * Or a list of tabs, + * Or a custom node + */ +type EuiPageHeaderContentLeft = EuiPageHeaderContentTitle & + EuiPageHeaderContentTabs & { + /** + * Position is dependent on existing with a `pageTitle` or `tabs` + * Automatically get wrapped in a single paragraph tag inside an EuiText block + */ + description?: string | ReactNode; + }; + +export type EuiPageHeaderContentProps = CommonProps & + HTMLAttributes & + EuiPageHeaderContentLeft & { + /** + * Set to false if you don't want the children to stack + * at small screen sizes. + */ + responsive?: boolean; + /** + * Pass custom an array of content to this side usually up to 3 buttons. + * The first button should be primary, usually with `fill` and will be visually displayed as the last item, + * but first in the tab order + */ + rightSideContent?: ReactNode[]; + /** + * Sets the max-width of the page, + * set to `true` to use the default size of `1000px (1200 for Amsterdam)`, + * set to `false` to not restrict the width, + * set to a number for a custom width in px, + * set to a string for a custom width in custom measurement. + */ + restrictWidth?: boolean | number | string; + /** + * Vertical alignment of the left and right side content; + * Default is `top` or dependendent on content + */ + alignItems?: typeof ALIGN_ITEMS[number]; + /** + * Which content to display first when on smaller screens. + * Useful when the right side content should actually come beforehand in the hierarchy (like time) + */ + responsiveOrder?: typeof RESPONSIVE_ORDER[number]; + /** + * Whether the array of right side items should all break to their own line on small screens + */ + rightSideResponsive?: boolean; + /** + * Custom children will be rendered before the `tabs` unless no `pageTitle` is present, then it will be the last item + */ + children?: ReactNode; + }; + +export const EuiPageHeaderContent: FunctionComponent = ({ + pageTitle, + iconType, + description, + tabs, + tabsProps, + className, + rightSideContent, + restrictWidth = false, + alignItems = 'center', + responsiveOrder = 'leftFirst', + rightSideResponsive = false, + children, + responsive = true, + style, + ...rest +}) => { + let widthClassname; + let newStyle; + + if (restrictWidth === true) { + widthClassname = 'EuiPageHeaderContent--restrictWidth-default'; + } else if (restrictWidth !== false) { + widthClassname = 'EuiPageHeaderContent--restrictWidth-custom'; + newStyle = { ...style, maxWidth: restrictWidth }; + } + + const classes = classNames( + 'EuiPageHeaderContent', + { + 'EuiPageHeaderContent--responsive': responsive, + 'EuiPageHeaderContent--column': !children, + 'EuiPageHeaderContent--tabsAtBottom': pageTitle && tabs, + 'EuiPageHeaderContent--responsiveReverse': + !children && responsiveOrder === 'rightFirst', + }, + widthClassname, + `EuiPageHeaderContent--${alignItems}` + ); + + let descriptionNode; + if (description) { + descriptionNode = ( + <> + {(pageTitle || tabs) && } + +

{description}

+
+ + ); + } + + let pageTitleNode; + if (pageTitle) { + const icon = iconType ? ( + + ) : undefined; + + pageTitleNode = ( + +

+ {icon} + {pageTitle} +

+
+ ); + } + + let tabsNode; + if (tabs) { + const renderTabs = () => { + return tabs.map((tab, index) => { + const { label, ...tabRest } = tab; + return ( + + {label} + + ); + }); + }; + + tabsNode = ( + <> + {pageTitleNode && } + + {renderTabs()} + + + ); + } + + let leftSideContentNode = children; + if (children && (tabsNode || pageTitleNode)) { + leftSideContentNode = ( +
+ + {children} + {pageTitle && tabsNode} +
+ ); + } + + /** + * The left side order depends on if a `pageTitle` was supplied. + * If not, but there are `tabs`, then the tabs become the page title + */ + let leftSideOrder; + if (tabsNode && !pageTitleNode) { + leftSideOrder = ( + <> + {tabsNode} + {descriptionNode} + + ); + } else { + leftSideOrder = ( + <> + {pageTitleNode} + {descriptionNode} + + ); + } + + let rightSideNode; + if (rightSideContent && rightSideContent.length) { + const wrapWithFlex = () => { + return rightSideContent.map((item, index) => { + return ( + + {item} + + ); + }); + }; + + rightSideNode = ( + + + {wrapWithFlex()} + + + ); + } + + return ( +
+ {leftSideOrder} + {rightSideNode} + {leftSideContentNode} +
+ ); +}; From 59643df1f53510ee41790871f1e38dee2d7ea47c Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Fri, 29 Jan 2021 12:11:37 -0600 Subject: [PATCH 09/27] middle; simulate node --- src-docs/src/services/playground/knobs.js | 4 +-- src-docs/src/views/page/playground.js | 36 ++++++++++++++----- .../page/page_header/page_header.tsx | 2 +- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src-docs/src/services/playground/knobs.js b/src-docs/src/services/playground/knobs.js index 6221cfdd0c45..ea4d695a0153 100644 --- a/src-docs/src/services/playground/knobs.js +++ b/src-docs/src/services/playground/knobs.js @@ -241,11 +241,11 @@ const Knob = ({ { const value = e.target.checked; - set(value ? value : undefined); + set(value ? custom.value ?? e.target.checked : undefined); }} compressed /> diff --git a/src-docs/src/views/page/playground.js b/src-docs/src/views/page/playground.js index 250ada2cddc5..5ab7179b6e99 100644 --- a/src-docs/src/views/page/playground.js +++ b/src-docs/src/views/page/playground.js @@ -2,14 +2,26 @@ import React from 'react'; import { PropTypes } from 'react-view'; +import template from '@babel/template'; import { EuiPageHeader, EuiButton } from '../../../../src/components/'; import { propUtilityForPlayground, iconValidator, + simulateFunction, } from '../../services/playground'; // HELP: Can we get a "simulate" toggle and pass ReactNodes? -const tabs = [ +// const tabs = [ +// { +// label: 'Tab 1', +// isSelected: true, +// }, +// { +// label: 'Tab 2', +// }, +// ]; + +const tabs = `[ { label: 'Tab 1', isSelected: true, @@ -17,7 +29,7 @@ const tabs = [ { label: 'Tab 2', }, -]; +]`; const rightSideContent = [ Button 1, @@ -43,12 +55,6 @@ export default () => { type: PropTypes.String, }; - // HELP: NOT WORKING - propsToUse.alignItems = { - ...propsToUse.alignItems, - defaultValue: 'center', - }; - propsToUse.description = { ...propsToUse.description, type: PropTypes.String, @@ -59,6 +65,13 @@ export default () => { type: PropTypes.Array, }; + propsToUse.tabs = simulateFunction({ + ...propsToUse.tabs, + custom: { + value: tabs, + }, + }); + return { config: { componentName: 'EuiPageHeader', @@ -71,6 +84,13 @@ export default () => { named: ['EuiPageHeader'], }, }, + customProps: { + tabs: { + generate: (value) => { + return template.ast(String(value), { plugins: ['jsx'] }).expression; + }, + }, + }, }, }; }; diff --git a/src/components/page/page_header/page_header.tsx b/src/components/page/page_header/page_header.tsx index 1cfee059dbe0..95bb1c5084c6 100644 --- a/src/components/page/page_header/page_header.tsx +++ b/src/components/page/page_header/page_header.tsx @@ -130,7 +130,7 @@ export const EuiPageHeader: FunctionComponent = ({ leftSideContent, rightSideContent, restrictWidth = false, - alignItems = 'center', + alignItems = 'middle', responsiveOrder = 'leftFirst', rightSideResponsive = false, children, From 517542d215fbf471abd4149e05e3099e7a502ff3 Mon Sep 17 00:00:00 2001 From: cchaos Date: Fri, 29 Jan 2021 16:37:42 -0500 Subject: [PATCH 10/27] Update `useIsWithinBreakpoints` to be conditional --- src/services/hooks/useIsWithinBreakpoints.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/services/hooks/useIsWithinBreakpoints.ts b/src/services/hooks/useIsWithinBreakpoints.ts index 0bdef3562fbd..8e3b263d1599 100644 --- a/src/services/hooks/useIsWithinBreakpoints.ts +++ b/src/services/hooks/useIsWithinBreakpoints.ts @@ -29,7 +29,10 @@ import { isWithinBreakpoints, EuiBreakpointSize } from '../breakpoint'; * @param {EuiBreakpointSize[]} sizes An array of named breakpoints * @returns {boolean} Returns `true` if current breakpoint name is included in `sizes` */ -export function useIsWithinBreakpoints(sizes: EuiBreakpointSize[]) { +export function useIsWithinBreakpoints( + sizes: EuiBreakpointSize[], + isActive: boolean = true +) { const [isWithinBreakpointsValue, setIsWithinBreakpointsValue] = useState< boolean >(false); @@ -41,12 +44,14 @@ export function useIsWithinBreakpoints(sizes: EuiBreakpointSize[]) { ); } - window.addEventListener('resize', handleResize); - - handleResize(); + if (isActive) { + window.removeEventListener('resize', handleResize); + window.addEventListener('resize', handleResize); + handleResize(); + } return () => window.removeEventListener('resize', handleResize); - }, [sizes]); + }, [sizes, isActive]); return isWithinBreakpointsValue; } From ea27ca03bceb3e23acb3a0a79f656cd9bf498e26 Mon Sep 17 00:00:00 2001 From: cchaos Date: Fri, 29 Jan 2021 16:40:53 -0500 Subject: [PATCH 11/27] Moving the content to a new component --- src-docs/src/components/guide_components.scss | 3 +- .../page/page_content_center_with_side_bar.js | 1 + src-docs/src/views/page/page_example.js | 2 +- src-docs/src/views/page/page_header.js | 78 +- src-docs/src/views/page/page_header_custom.js | 2 +- src-docs/src/views/page/page_header_tabs.js | 72 +- src-docs/src/views/page/playground.js | 29 +- .../__snapshots__/page_header.test.tsx.snap | 811 +++++++++++++----- .../page_header_content.test.tsx.snap | 558 ++++++------ .../page/page_header/_page_header.scss | 33 +- .../page_header/_page_header_content.scss | 76 +- .../page_header/_page_header_section.scss | 20 +- .../page/page_header/page_header.test.tsx | 142 +-- .../page/page_header/page_header.tsx | 246 +----- .../page_header/page_header_content.test.tsx | 29 +- .../page/page_header/page_header_content.tsx | 116 ++- 16 files changed, 1075 insertions(+), 1143 deletions(-) diff --git a/src-docs/src/components/guide_components.scss b/src-docs/src/components/guide_components.scss index fe702ab827c0..73cbebe954d9 100644 --- a/src-docs/src/components/guide_components.scss +++ b/src-docs/src/components/guide_components.scss @@ -105,7 +105,8 @@ $guideZLevelHighest: $euiZLevel9 + 1000; min-height: 460px; } - div { + > div, + > div > div { background: transparentize($euiColorPrimary, .9); } } diff --git a/src-docs/src/views/page/page_content_center_with_side_bar.js b/src-docs/src/views/page/page_content_center_with_side_bar.js index a2a3bc2b7f87..5ff4cb412dc0 100644 --- a/src-docs/src/views/page/page_content_center_with_side_bar.js +++ b/src-docs/src/views/page/page_content_center_with_side_bar.js @@ -20,6 +20,7 @@ export default () => ( diff --git a/src-docs/src/views/page/page_example.js b/src-docs/src/views/page/page_example.js index 9e43769a92e5..b4f002a81da7 100644 --- a/src-docs/src/views/page/page_example.js +++ b/src-docs/src/views/page/page_example.js @@ -196,7 +196,7 @@ export const PageExample = { text: ( <>

- When using supplying tabs with a{' '} + When using supplying tabs without a{' '} pageTitle, EuiPageHeader will promote those tabs as if they are the page title. This means that any description, or{' '} diff --git a/src-docs/src/views/page/page_header.js b/src-docs/src/views/page/page_header.js index 592a3191b42e..085149d8c907 100644 --- a/src-docs/src/views/page/page_header.js +++ b/src-docs/src/views/page/page_header.js @@ -2,60 +2,36 @@ import React from 'react'; import { EuiPageHeader, + EuiCode, EuiText, EuiButton, - EuiPageHeaderContent, } from '../../../../src/components'; export default () => ( - <> - -

And some custom content

- - } - rightSideContent={[ - Add something, - Do something, - ]} - alignItems="top" - /> - -

And some custom content

- - } - rightSideContent={[ - Add something, - Do something, - ]} - alignItems="top" - /> - + Add something, + Do something, + ]}> + +

+ This custom content (children), on the other hand, exists below the + content above including below the right side content and therefore will + stretch beneath them. Unless you set the alignItems{' '} + prop to something other than top. +

+
+
); diff --git a/src-docs/src/views/page/page_header_custom.js b/src-docs/src/views/page/page_header_custom.js index db26eff29d9d..f1642afe595e 100644 --- a/src-docs/src/views/page/page_header_custom.js +++ b/src-docs/src/views/page/page_header_custom.js @@ -7,7 +7,7 @@ import { } from '../../../../src/components'; export default () => ( - +

Page title

diff --git a/src-docs/src/views/page/page_header_tabs.js b/src-docs/src/views/page/page_header_tabs.js index cdc7d32650f1..06b19a5461ed 100644 --- a/src-docs/src/views/page/page_header_tabs.js +++ b/src-docs/src/views/page/page_header_tabs.js @@ -4,54 +4,32 @@ import { EuiPageHeader, EuiText, EuiButton, - EuiPageHeaderContent, + EuiCode, } from '../../../../src/components'; export default () => ( - <> - -

And some custom content

- - } - rightSideContent={[ - Add something, - Do something, - ]} - alignItems="top" - /> - -

And some custom content

- - } - rightSideContent={[ - Add something, - Do something, - ]} - alignItems="top" - /> - + Add something, + Do something, + ]}> + +

+ This custom content (children), on the other hand, exists below the + content above including below the right side content and therefore will + stretch beneath them. Unless you set the alignItems{' '} + prop to something other than top. +

+
+
); diff --git a/src-docs/src/views/page/playground.js b/src-docs/src/views/page/playground.js index 250ada2cddc5..2c0c852eb7a2 100644 --- a/src-docs/src/views/page/playground.js +++ b/src-docs/src/views/page/playground.js @@ -2,7 +2,11 @@ import React from 'react'; import { PropTypes } from 'react-view'; -import { EuiPageHeader, EuiButton } from '../../../../src/components/'; +import { + EuiPageHeaderContent, + EuiButton, + EuiText, +} from '../../../../src/components/'; import { propUtilityForPlayground, iconValidator, @@ -25,9 +29,9 @@ const rightSideContent = [ ]; export default () => { - const docgenInfo = Array.isArray(EuiPageHeader.__docgenInfo) - ? EuiPageHeader.__docgenInfo[0] - : EuiPageHeader.__docgenInfo; + const docgenInfo = Array.isArray(EuiPageHeaderContent.__docgenInfo) + ? EuiPageHeaderContent.__docgenInfo[0] + : EuiPageHeaderContent.__docgenInfo; const propsToUse = propUtilityForPlayground(docgenInfo.props); propsToUse.iconType = iconValidator(propsToUse.iconType); @@ -59,16 +63,27 @@ export default () => { type: PropTypes.Array, }; + propsToUse.children = { + value: ` +

+ Any content children of EuiPageHeaderContent will appear here. +

+
`, + type: PropTypes.ReactNode, + hidden: false, + }; + return { config: { - componentName: 'EuiPageHeader', + componentName: 'EuiPageHeaderContent', props: propsToUse, scope: { - EuiPageHeader, + EuiPageHeaderContent, + EuiText, }, imports: { '@elastic/eui': { - named: ['EuiPageHeader'], + named: ['EuiPageHeaderContent', 'EuiText'], }, }, }, diff --git a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap index 3f25cab3c07e..dae3768b5904 100644 --- a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap @@ -6,9 +6,7 @@ exports[`EuiPageHeader is rendered 1`] = ` class="euiPageHeader euiPageHeader--responsive euiPageHeader--center testClass1 testClass2" data-test-subj="test subject string" > -
+ Anything
`; @@ -17,71 +15,89 @@ exports[`EuiPageHeader props alignItems bottom is rendered 1`] = ` class="euiPageHeader euiPageHeader--responsive euiPageHeader--bottom" >
-

- Page title -

-
-
- +

+ Page title +

+
- +
+
+ +
+
+ +
+
`; -exports[`EuiPageHeader props alignItems middle is rendered 1`] = ` +exports[`EuiPageHeader props alignItems center is rendered 1`] = `
-

- Page title -

-
-
- +

+ Page title +

+
- +
+
+ +
+
+ +
+
@@ -93,32 +109,144 @@ exports[`EuiPageHeader props alignItems top is rendered 1`] = ` class="euiPageHeader euiPageHeader--responsive euiPageHeader--top" >
-

- Page title -

+
+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+
+
+`; + +exports[`EuiPageHeader props page content props are passed down is rendered 1`] = ` +
- +

+ + Page title +

+
+
+

+ Description +

+
- +
+
+ +
+
+
+
+
+
+

+ Anything +

+
+
+ +
@@ -126,327 +254,540 @@ exports[`EuiPageHeader props alignItems top is rendered 1`] = `
`; -exports[`EuiPageHeader props children is rendered 1`] = ` +exports[`EuiPageHeader props responsive is rendered as false 1`] = `
- Child -
+ class="euiPageHeader euiPageHeader--center" +/> `; -exports[`EuiPageHeader props children is rendered even if content props are passed 1`] = ` +exports[`EuiPageHeader props responsive is rendered as reverse 1`] = `
- Child -
+ class="euiPageHeader euiPageHeader--responsiveReverse euiPageHeader--center" +/> `; -exports[`EuiPageHeader props description is rendered 1`] = ` +exports[`EuiPageHeader props restrictWidth is rendered as custom 1`] = `
+`; + +exports[`EuiPageHeader props restrictWidth is rendered as true 1`] = ` +
+`; + +exports[`EuiPageHeaderContent is rendered 1`] = ` +
-

- Description -

-
+ class="euiFlexItem" + />
`; -exports[`EuiPageHeader props leftSideContent is rendered 1`] = ` +exports[`EuiPageHeaderContent props alignItems bottom is rendered 1`] = `
-

- Anything -

+
+

+ Page title +

+ +
+
+
+
+ +
+
+ +
+
+
`; -exports[`EuiPageHeader props pageTitle is rendered 1`] = ` +exports[`EuiPageHeaderContent props alignItems center is rendered 1`] = `
-

+

+ Page title +

+ +
+
- Page title - +
+
+ +
+
+ +
+
+
`; -exports[`EuiPageHeader props pageTitle is rendered with icon 1`] = ` +exports[`EuiPageHeaderContent props alignItems top is rendered 1`] = `
-

- - Page title -

+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
`; -exports[`EuiPageHeader props responsive is rendered as false 1`] = ` +exports[`EuiPageHeaderContent props children is rendered 1`] = `
+ class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsFlexStart euiFlexGroup--directionRow euiFlexGroup--responsive euiPageHeaderContent__top" + > +
+
+ Child
`; -exports[`EuiPageHeader props responsiveOrder leftFirst is rendered 1`] = ` +exports[`EuiPageHeaderContent props children is rendered even if content props are passed 1`] = `
-

- Page title -

+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+ Child +
+
- + + Tab 1 + + + +
+
+
+`; + +exports[`EuiPageHeaderContent props description is rendered 1`] = ` +
+
+
- +

+ Description +

`; -exports[`EuiPageHeader props responsiveOrder rightFirst is rendered 1`] = ` +exports[`EuiPageHeaderContent props leftSideContent is rendered 1`] = `
-

- Page title -

+
+

+ Anything +

+
+`; + +exports[`EuiPageHeaderContent props pageTitle is rendered 1`] = ` +
-
- -
-
+
+
+
+`; + +exports[`EuiPageHeaderContent props pageTitle is rendered with icon 1`] = ` +
+
+
+

- -

+ + Page title +
`; -exports[`EuiPageHeader props restrictWidth is rendered as true 1`] = ` +exports[`EuiPageHeaderContent props responsive is rendered as false 1`] = `
+ class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsFlexStart euiFlexGroup--directionRow euiPageHeaderContent__top" + > +
+
`; -exports[`EuiPageHeader props rightSideContent is rendered 1`] = ` +exports[`EuiPageHeaderContent props responsive is rendered as reverse 1`] = `
+ class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsFlexStart euiFlexGroup--directionRow euiFlexGroup--responsive euiPageHeaderContent__top" + > +
+
+
+`; + +exports[`EuiPageHeaderContent props rightSideContent is rendered 1`] = ` +
+
- -
-
- +
+ +
+
+ +
`; -exports[`EuiPageHeader props rightSideContent is rendered with rightSideResponsive as true 1`] = ` +exports[`EuiPageHeaderContent props rightSideContent is rendered with rightSideResponsive as true 1`] = `
-
+
- -
-
- +
+ +
+
+ +
`; -exports[`EuiPageHeader props tabs is rendered 1`] = ` +exports[`EuiPageHeaderContent props tabs is rendered 1`] = `
- - + + + Tab 2 + + +
`; -exports[`EuiPageHeader props tabs is rendered with tabsProps 1`] = ` +exports[`EuiPageHeaderContent props tabs is rendered with tabsProps 1`] = `
- - + + + Tab 2 + + +
diff --git a/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap index 8ca711f7e807..1e6e3801b30f 100644 --- a/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap @@ -3,85 +3,99 @@ exports[`EuiPageHeaderContent is rendered 1`] = `
+ class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsFlexStart euiFlexGroup--directionRow euiFlexGroup--responsive euiPageHeaderContent__top" + > +
+
`; exports[`EuiPageHeaderContent props alignItems bottom is rendered 1`] = `
-

- Page title -

-
-
-
- -
+ Page title + + +
+
- +
+ +
+
+ +
`; -exports[`EuiPageHeaderContent props alignItems middle is rendered 1`] = ` +exports[`EuiPageHeaderContent props alignItems center is rendered 1`] = `
-

- Page title -

-
-
-
- -
+ Page title + + +
+
- +
+ +
+
+ +
@@ -90,36 +104,40 @@ exports[`EuiPageHeaderContent props alignItems middle is rendered 1`] = ` exports[`EuiPageHeaderContent props alignItems top is rendered 1`] = `
-

- Page title -

-
-
-
- -
+ Page title + +
+
- +
+ +
+
+ +
@@ -128,52 +146,60 @@ exports[`EuiPageHeaderContent props alignItems top is rendered 1`] = ` exports[`EuiPageHeaderContent props children is rendered 1`] = `
+ class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsFlexStart euiFlexGroup--directionRow euiFlexGroup--responsive euiPageHeaderContent__top" + > +
+
Child
`; exports[`EuiPageHeaderContent props children is rendered even if content props are passed 1`] = `
-

- Page title -

-
-
-
- -
+ Page title + +
+
- +
+ +
+
+ +
-

- Description -

+
+

+ Description +

+
@@ -235,11 +265,15 @@ exports[`EuiPageHeaderContent props description is rendered 1`] = ` exports[`EuiPageHeaderContent props leftSideContent is rendered 1`] = `
+ class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsFlexStart euiFlexGroup--directionRow euiFlexGroup--responsive euiPageHeaderContent__top" + > +
+

Anything

@@ -248,162 +282,106 @@ exports[`EuiPageHeaderContent props leftSideContent is rendered 1`] = ` exports[`EuiPageHeaderContent props pageTitle is rendered 1`] = `
-

- Page title -

+

+ Page title +

+
`; exports[`EuiPageHeaderContent props pageTitle is rendered with icon 1`] = `
-

- - Page title -

+

+ + Page title +

+
`; exports[`EuiPageHeaderContent props responsive is rendered as false 1`] = `
-
-
-`; - -exports[`EuiPageHeaderContent props responsiveOrder leftFirst is rendered 1`] = ` -
-

- Page title -

-
-
-
- -
-
- -
-
+ class="euiFlexItem" + />
`; -exports[`EuiPageHeaderContent props responsiveOrder rightFirst is rendered 1`] = ` +exports[`EuiPageHeaderContent props responsive is rendered as reverse 1`] = `
-

- Page title -

-
-
-
- -
-
- -
-
+ class="euiFlexItem" + />
`; -exports[`EuiPageHeaderContent props restrictWidth is rendered as true 1`] = ` -
-
-
-`; - exports[`EuiPageHeaderContent props rightSideContent is rendered 1`] = `
-
+
- -
-
- +
+ +
+
+ +
@@ -412,30 +390,34 @@ exports[`EuiPageHeaderContent props rightSideContent is rendered 1`] = ` exports[`EuiPageHeaderContent props rightSideContent is rendered with rightSideResponsive as true 1`] = `
-
+
- -
-
- +
+ +
+
+ +
@@ -444,39 +426,43 @@ exports[`EuiPageHeaderContent props rightSideContent is rendered with rightSideR exports[`EuiPageHeaderContent props tabs is rendered 1`] = `
- - + + + Tab 2 + + +
@@ -484,41 +470,45 @@ exports[`EuiPageHeaderContent props tabs is rendered 1`] = ` exports[`EuiPageHeaderContent props tabs is rendered with tabsProps 1`] = `
- - + + + Tab 2 + + +
diff --git a/src/components/page/page_header/_page_header.scss b/src/components/page/page_header/_page_header.scss index 6812f3ae8c21..9765e33de32e 100644 --- a/src/components/page/page_header/_page_header.scss +++ b/src/components/page/page_header/_page_header.scss @@ -25,10 +25,8 @@ align-items: flex-end; } -.euiPageHeader__titleIcon { - top: -$euiSizeXS; - position: relative; - margin-right: $euiSize; +.euiPageHeader--tabsAtBottom { + padding-bottom: 0; } @include euiBreakpoint('xs', 's') { @@ -37,34 +35,15 @@ margin-bottom: 0; } - .euiPageHeader--responsive { - flex-direction: column; + .euiPageHeader--tabsAtBottom { + padding-bottom: 0; } - // Match all around padding and spacers - .euiPageHeaderSection + .euiPageHeaderSection { - margin-top: $euiSizeL; + .euiPageHeader--responsive { + flex-direction: column; } .euiPageHeader--responsiveReverse { flex-direction: column-reverse; - - .euiPageHeaderSection { - margin-top: $euiSizeL; - } - - .euiPageHeaderSection + .euiPageHeaderSection { - margin-top: 0; - } - } -} - -@include euiBreakpoint('m', 'l', 'xl') { - .euiPageHeader--tabsAtBottom { - padding-bottom: 0; - } - - .euiPageHeader__rightSideContent { - flex-direction: row-reverse; } } diff --git a/src/components/page/page_header/_page_header_content.scss b/src/components/page/page_header/_page_header_content.scss index f4b2d6ed36fe..2589fb2fbff4 100644 --- a/src/components/page/page_header/_page_header_content.scss +++ b/src/components/page/page_header/_page_header_content.scss @@ -1,85 +1,15 @@ -.euiPageHeader { +.euiPageHeader .euiPageHeaderContent { width: 100%; - margin-bottom: $euiSize; - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - - &--restrictWidth-default, - &--restrictWidth-custom { - margin-left: auto; - margin-right: auto; - } - - &--restrictWidth-default { - max-width: $euiPageDefaultMaxWidth; - } } -.euiPageHeader__top { - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; -} - -.euiPageHeader--column { - flex-direction: column; -} - -.euiPageHeader--top .euiPageHeader__top, -.euiPageHeader--top { - align-items: flex-start; -} - -.euiPageHeader--bottom .euiPageHeader__top, -.euiPageHeader--bottom { - align-items: flex-end; -} - -.euiPageHeader__titleIcon { +.euiPageHeaderContent__titleIcon { top: -$euiSizeXS; position: relative; margin-right: $euiSize; } -@include euiBreakpoint('xs', 's') { - .euiPageHeader { - padding: $euiSize 0; - margin-bottom: 0; - } - - .euiPageHeader--responsive .euiPageHeader__top, - .euiPageHeader--responsive { - flex-direction: column; - } - - // Match all around padding and spacers - .euiPageHeaderSection + .euiPageHeaderSection { - margin-top: $euiSizeL; - } - - .euiPageHeader--responsiveReverse .euiPageHeader__top, - .euiPageHeader--responsiveReverse { - flex-direction: column-reverse; - - .euiPageHeaderSection { - margin-top: $euiSizeL; - } - - .euiPageHeaderSection + .euiPageHeaderSection { - margin-top: 0; - } - } -} - @include euiBreakpoint('m', 'l', 'xl') { - .euiPageHeader--tabsAtBottom { - padding-bottom: 0; - } - - .euiPageHeader__rightSideContent { + .euiPageHeaderContent__rightSideContent { flex-direction: row-reverse; } } diff --git a/src/components/page/page_header/_page_header_section.scss b/src/components/page/page_header/_page_header_section.scss index f9df787fad66..dff7fb0a3d29 100644 --- a/src/components/page/page_header/_page_header_section.scss +++ b/src/components/page/page_header/_page_header_section.scss @@ -1,15 +1,25 @@ -.euiPageHeaderSection { - & + & { - margin-left: $euiSizeXL; - } +.euiPageHeaderSection:not(:first-of-type) { + margin-left: $euiSizeXL; } @include euiBreakpoint('xs', 's') { .euiPageHeader--responsive .euiPageHeaderSection { width: 100%; - + .euiPageHeaderSection { + &:not(:first-of-type) { + margin-left: 0; + margin-top: $euiSize; + } + } + + .euiPageHeader--responsiveReverse .euiPageHeaderSection { + width: 100%; + + &:not(:first-of-type) { margin-left: 0; + } + + &:not(:last-of-type) { margin-top: $euiSize; } } diff --git a/src/components/page/page_header/page_header.test.tsx b/src/components/page/page_header/page_header.test.tsx index aecf747398ef..1f64d7945c36 100644 --- a/src/components/page/page_header/page_header.test.tsx +++ b/src/components/page/page_header/page_header.test.tsx @@ -21,121 +21,31 @@ import React from 'react'; import { render } from 'enzyme'; import { requiredProps } from '../../../test/required_props'; -import { - ALIGN_ITEMS, - EuiPageHeader, - EuiPageHeaderProps, - RESPONSIVE_ORDER, -} from './page_header'; - -const tabs: EuiPageHeaderProps['tabs'] = [ - { - label: 'Tab 1', - isSelected: true, - }, - { - label: 'Tab 2', - }, -]; - -const rightSideContent: EuiPageHeaderProps['rightSideContent'] = [ - , - , -]; +import { ALIGN_ITEMS, EuiPageHeader } from './page_header'; +import { rightSideContent, tabs } from './page_header_content.test'; describe('EuiPageHeader', () => { test('is rendered', () => { - const component = render(); + const component = render( + Anything + ); expect(component).toMatchSnapshot(); }); describe('props', () => { - describe('pageTitle', () => { - test('is rendered', () => { - const component = render(); - - expect(component).toMatchSnapshot(); - }); - - test('is rendered with icon', () => { - const component = render( - - ); - - expect(component).toMatchSnapshot(); - }); - }); - - describe('tabs', () => { - test('is rendered', () => { - const component = render(); - - expect(component).toMatchSnapshot(); - }); - - test('is rendered with tabsProps', () => { - const component = render( - - ); - - expect(component).toMatchSnapshot(); - }); - }); - - describe('leftSideContent', () => { - test('is rendered', () => { - const component = render( - Anything

} /> - ); - - expect(component).toMatchSnapshot(); - }); - }); - - describe('description', () => { - test('is rendered', () => { - const component = render(); - - expect(component).toMatchSnapshot(); - }); - }); - - describe('rightSideContent', () => { + describe('page content props are passed down', () => { test('is rendered', () => { - const component = render( - - ); - - expect(component).toMatchSnapshot(); - }); - - test('is rendered with rightSideResponsive as true', () => { - const component = render( - - ); - - expect(component).toMatchSnapshot(); - }); - }); - - describe('children', () => { - test('is rendered', () => { - const component = render(Child); - - expect(component).toMatchSnapshot(); - }); - - test('is rendered even if content props are passed', () => { const component = render( - Child + tabsProps={requiredProps} + description="Description" + rightSideContent={rightSideContent} + rightSideResponsive={true}> +

Anything

); @@ -159,28 +69,18 @@ describe('EuiPageHeader', () => { }); }); - describe('responsiveOrder', () => { - RESPONSIVE_ORDER.forEach((order) => { - it(`${order} is rendered`, () => { - const component = render( - - ); - - expect(component).toMatchSnapshot(); - }); - }); - }); - describe('responsive', () => { test('is rendered as false', () => { const component = render(); expect(component).toMatchSnapshot(); }); + + test('is rendered as reverse', () => { + const component = render(); + + expect(component).toMatchSnapshot(); + }); }); describe('restrictWidth', () => { @@ -189,6 +89,12 @@ describe('EuiPageHeader', () => { expect(component).toMatchSnapshot(); }); + + test('is rendered as custom', () => { + const component = render(); + + expect(component).toMatchSnapshot(); + }); }); }); }); diff --git a/src/components/page/page_header/page_header.tsx b/src/components/page/page_header/page_header.tsx index 1cfee059dbe0..7044187cee8f 100644 --- a/src/components/page/page_header/page_header.tsx +++ b/src/components/page/page_header/page_header.tsx @@ -17,85 +17,19 @@ * under the License. */ -import React, { FunctionComponent, ReactNode, HTMLAttributes } from 'react'; +import React, { FunctionComponent, HTMLAttributes } from 'react'; import classNames from 'classnames'; import { CommonProps } from '../../common'; -import { EuiIcon, IconType } from '../../icon'; -import { EuiTab, EuiTabs, EuiTabsProps } from '../../tabs'; -import { EuiPageHeaderSection } from './page_header_section'; -import { EuiFlexGroup, EuiFlexItem } from '../../flex'; -import { EuiSpacer } from '../../spacer'; -import { EuiTitle } from '../../title'; -import { EuiText } from '../../text'; +import { + EuiPageHeaderContent, + EuiPageHeaderContentProps, +} from './page_header_content'; -export const ALIGN_ITEMS = ['top', 'bottom', 'middle'] as const; -export const RESPONSIVE_ORDER = ['leftFirst', 'rightFirst'] as const; - -// Gets all the tab props including the button or link props -type EuiTabProps = React.ComponentProps & { - /** - * Visible text of the tab - */ - label: string; -}; - -export type EuiPageHeaderTitle = { - /** - * Wrapped in an `H1` so choose appropriately. - * A simple string is best - */ - pageTitle?: ReactNode; - /** - * Optional icon to place to the left of the title - */ - iconType?: IconType; -}; - -export type EuiPageHeaderTabs = { - /** - * In-app navigation presented as large borderless tabs. - * Accepts an array of `EuiTab` objects; - * HELP: This is evaluating to `any[]` in the props table - */ - tabs?: EuiTabProps[]; - /** - * Any extras to apply to the outer tabs container. - * Extends `EuiTabs` - */ - tabsProps?: Omit; -}; - -/** - * The left side can either be a title with optional description and/or icon; - * Or a list of tabs, - * Or a custom node - */ -type EuiPageHeaderLeft = EuiPageHeaderTitle & - EuiPageHeaderTabs & { - /** - * Pass custom content to the left side with `leftSideContent` - */ - leftSideContent?: ReactNode; - /** - * Position is dependent on existing with a `pageTitle` or `tabs` - * Automatically get wrapped in a single paragraph tag inside an EuiText block - */ - description?: string | ReactNode; - }; +export const ALIGN_ITEMS = ['top', 'bottom', 'center'] as const; export type EuiPageHeaderProps = CommonProps & HTMLAttributes & - EuiPageHeaderLeft & { - /** - * Set to false if you don't want the children to stack - * at small screen sizes. - */ - responsive?: boolean; - /** - * Pass custom an array of content to this side usually up to 3 buttons. - * The first button should be primary, usually with `fill` and will be visually displayed as the last item - */ - rightSideContent?: ReactNode[]; + EuiPageHeaderContentProps & { /** * Sets the max-width of the page, * set to `true` to use the default size of `1000px (1200 for Amsterdam)`, @@ -104,38 +38,26 @@ export type EuiPageHeaderProps = CommonProps & * set to a string for a custom width in custom measurement. */ restrictWidth?: boolean | number | string; - /** - * Vertical alignment of the left and right side content; - * Default is `top` or dependendent on content - */ - alignItems?: typeof ALIGN_ITEMS[number]; - /** - * Which content to display first when on smaller screens. - * Useful when the right side content should actually come beforehand in the hierarchy (like time) - */ - responsiveOrder?: typeof RESPONSIVE_ORDER[number]; - /** - * Whether the array of right side items should all break to their own line on small screens - */ - rightSideResponsive?: boolean; }; export const EuiPageHeader: FunctionComponent = ({ + className, + restrictWidth = false, + style, + + // Page header content shared props: + alignItems, + responsive = true, + children, + + // Page header content only props: pageTitle, iconType, - description, tabs, tabsProps, - className, - leftSideContent, + description, rightSideContent, - restrictWidth = false, - alignItems = 'center', - responsiveOrder = 'leftFirst', - rightSideResponsive = false, - children, - responsive = true, - style, + rightSideResponsive, ...rest }) => { let widthClassname; @@ -151,17 +73,16 @@ export const EuiPageHeader: FunctionComponent = ({ const classes = classNames( 'euiPageHeader', { - 'euiPageHeader--responsive': responsive, - 'euiPageHeader--tabsAtBottom': !children && pageTitle && tabs, - 'euiPageHeader--responsiveReverse': - !children && responsiveOrder === 'rightFirst', + 'euiPageHeader--responsive': responsive === true, + 'euiPageHeader--responsiveReverse': responsive === 'reverse', + 'euiPageHeader--tabsAtBottom': pageTitle && tabs, }, - `euiPageHeader--${alignItems}`, + `euiPageHeader--${alignItems ?? 'center'}`, widthClassname, className ); - if (children) { + if (!pageTitle && !tabs && !description && !rightSideContent) { return (
{children} @@ -169,115 +90,20 @@ export const EuiPageHeader: FunctionComponent = ({ ); } - let descriptionNode; - if (description) { - descriptionNode = ( - <> - {(pageTitle || tabs) && } - -

{description}

-
- - ); - } - - let pageTitleNode; - if (pageTitle) { - const icon = iconType ? ( - - ) : undefined; - - pageTitleNode = ( - -

- {icon} - {pageTitle} -

-
- ); - } - - let tabsNode; - if (tabs) { - const renderTabs = () => { - return tabs.map((tab, index) => { - const { label, ...tabRest } = tab; - return ( - - {label} - - ); - }); - }; - - tabsNode = ( - <> - {pageTitleNode && } - - {renderTabs()} - - - ); - } - - let leftSideContentNode = leftSideContent; - if (leftSideContent && (tabsNode || pageTitleNode)) { - leftSideContentNode = ( - <> - - {leftSideContent} - - ); - } - - let leftSideOrder; - if (tabsNode && !pageTitleNode) { - leftSideOrder = ( - <> - {tabsNode} - {leftSideContentNode} - {descriptionNode} - - ); - } else { - leftSideOrder = ( - <> - {pageTitleNode} - {descriptionNode} - {leftSideContentNode} - {tabsNode} - - ); - } - - let rightSideNode; - if (rightSideContent && rightSideContent.length) { - const wrapWithFlex = () => { - return rightSideContent.map((item, index) => { - return ( - - {item} - - ); - }); - }; - - rightSideNode = ( - - - {wrapWithFlex()} - - - ); - } - return (
- {leftSideOrder} - {rightSideNode} + + {children} +
); }; diff --git a/src/components/page/page_header/page_header_content.test.tsx b/src/components/page/page_header/page_header_content.test.tsx index ed5351f53cf5..b8e07890796c 100644 --- a/src/components/page/page_header/page_header_content.test.tsx +++ b/src/components/page/page_header/page_header_content.test.tsx @@ -25,10 +25,9 @@ import { ALIGN_ITEMS, EuiPageHeaderContent, EuiPageHeaderContentProps, - RESPONSIVE_ORDER, } from './page_header_content'; -const tabs: EuiPageHeaderContentProps['tabs'] = [ +export const tabs: EuiPageHeaderContentProps['tabs'] = [ { label: 'Tab 1', isSelected: true, @@ -38,7 +37,7 @@ const tabs: EuiPageHeaderContentProps['tabs'] = [ }, ]; -const rightSideContent: EuiPageHeaderContentProps['rightSideContent'] = [ +export const rightSideContent: EuiPageHeaderContentProps['rightSideContent'] = [ , , ]; @@ -165,33 +164,17 @@ describe('EuiPageHeaderContent', () => { }); }); - describe('responsiveOrder', () => { - RESPONSIVE_ORDER.forEach((order) => { - it(`${order} is rendered`, () => { - const component = render( - - ); - - expect(component).toMatchSnapshot(); - }); - }); - }); - describe('responsive', () => { test('is rendered as false', () => { const component = render(); expect(component).toMatchSnapshot(); }); - }); - describe('restrictWidth', () => { - test('is rendered as true', () => { - const component = render(); + test('is rendered as reverse', () => { + const component = render( + + ); expect(component).toMatchSnapshot(); }); diff --git a/src/components/page/page_header/page_header_content.tsx b/src/components/page/page_header/page_header_content.tsx index e80f27f02ad4..da81c4f90276 100644 --- a/src/components/page/page_header/page_header_content.tsx +++ b/src/components/page/page_header/page_header_content.tsx @@ -22,14 +22,13 @@ import classNames from 'classnames'; import { CommonProps } from '../../common'; import { EuiIcon, IconType } from '../../icon'; import { EuiTab, EuiTabs, EuiTabsProps } from '../../tabs'; -import { EuiPageHeaderSection } from './page_header_section'; import { EuiFlexGroup, EuiFlexItem } from '../../flex'; import { EuiSpacer } from '../../spacer'; import { EuiTitle } from '../../title'; import { EuiText } from '../../text'; +import { useIsWithinBreakpoints } from '../../../services/hooks'; -export const ALIGN_ITEMS = ['top', 'bottom', 'middle'] as const; -export const RESPONSIVE_ORDER = ['leftFirst', 'rightFirst'] as const; +export const ALIGN_ITEMS = ['top', 'bottom', 'center'] as const; // Gets all the tab props including the button or link props type EuiTabProps = React.ComponentProps & { @@ -83,84 +82,53 @@ export type EuiPageHeaderContentProps = CommonProps & HTMLAttributes & EuiPageHeaderContentLeft & { /** - * Set to false if you don't want the children to stack - * at small screen sizes. + * Set to false if you don't want the children to stack at small screen sizes. + * Set to `reverse` to display the right side content first for the sack of hierarchy (like global time) */ - responsive?: boolean; + responsive?: boolean | 'reverse'; /** * Pass custom an array of content to this side usually up to 3 buttons. * The first button should be primary, usually with `fill` and will be visually displayed as the last item, * but first in the tab order */ rightSideContent?: ReactNode[]; - /** - * Sets the max-width of the page, - * set to `true` to use the default size of `1000px (1200 for Amsterdam)`, - * set to `false` to not restrict the width, - * set to a number for a custom width in px, - * set to a string for a custom width in custom measurement. - */ - restrictWidth?: boolean | number | string; /** * Vertical alignment of the left and right side content; - * Default is `top` or dependendent on content + * Default is `middle` for custom content, but `top` for when `pageTitle` or `tabs` are included */ alignItems?: typeof ALIGN_ITEMS[number]; - /** - * Which content to display first when on smaller screens. - * Useful when the right side content should actually come beforehand in the hierarchy (like time) - */ - responsiveOrder?: typeof RESPONSIVE_ORDER[number]; /** * Whether the array of right side items should all break to their own line on small screens */ rightSideResponsive?: boolean; /** - * Custom children will be rendered before the `tabs` unless no `pageTitle` is present, then it will be the last item + * Custom children will be rendered before the `tabs` unless no `pageTitle` is present, + * then it will be the last item */ children?: ReactNode; }; export const EuiPageHeaderContent: FunctionComponent = ({ + className, pageTitle, iconType, - description, tabs, tabsProps, - className, + description, rightSideContent, - restrictWidth = false, - alignItems = 'center', - responsiveOrder = 'leftFirst', + alignItems = 'top', + responsive = true, rightSideResponsive = false, children, - responsive = true, - style, ...rest }) => { - let widthClassname; - let newStyle; - - if (restrictWidth === true) { - widthClassname = 'EuiPageHeaderContent--restrictWidth-default'; - } else if (restrictWidth !== false) { - widthClassname = 'EuiPageHeaderContent--restrictWidth-custom'; - newStyle = { ...style, maxWidth: restrictWidth }; - } - - const classes = classNames( - 'EuiPageHeaderContent', - { - 'EuiPageHeaderContent--responsive': responsive, - 'EuiPageHeaderContent--column': !children, - 'EuiPageHeaderContent--tabsAtBottom': pageTitle && tabs, - 'EuiPageHeaderContent--responsiveReverse': - !children && responsiveOrder === 'rightFirst', - }, - widthClassname, - `EuiPageHeaderContent--${alignItems}` + const isResponsiveBreakpoint = useIsWithinBreakpoints( + ['xs', 's'], + !!responsive ); + const classes = classNames('euiPageHeaderContent'); + let descriptionNode; if (description) { descriptionNode = ( @@ -177,7 +145,7 @@ export const EuiPageHeaderContent: FunctionComponent if (pageTitle) { const icon = iconType ? ( @@ -219,7 +187,7 @@ export const EuiPageHeaderContent: FunctionComponent let leftSideContentNode = children; if (children && (tabsNode || pageTitleNode)) { leftSideContentNode = ( -
+
{children} {pageTitle && tabsNode} @@ -248,7 +216,7 @@ export const EuiPageHeaderContent: FunctionComponent ); } - let rightSideNode; + let rightSideFlexItem; if (rightSideContent && rightSideContent.length) { const wrapWithFlex = () => { return rightSideContent.map((item, index) => { @@ -260,23 +228,51 @@ export const EuiPageHeaderContent: FunctionComponent }); }; - rightSideNode = ( - + rightSideFlexItem = ( + {wrapWithFlex()} - + ); } - return ( -
- {leftSideOrder} - {rightSideNode} + return alignItems === 'top' || isResponsiveBreakpoint ? ( +
+ + {isResponsiveBreakpoint && responsive === 'reverse' ? ( + <> + {rightSideFlexItem} + {leftSideOrder} + + ) : ( + <> + {leftSideOrder} + {rightSideFlexItem} + + )} + {leftSideContentNode}
+ ) : ( +
+ + + {leftSideOrder} {leftSideContentNode} + + {rightSideFlexItem} + +
); }; From 20f3bb9e66079e03e6e1e4d8f40b385ae312c0f9 Mon Sep 17 00:00:00 2001 From: cchaos Date: Fri, 29 Jan 2021 16:54:00 -0500 Subject: [PATCH 12/27] Cleaning up --- .../playground/_playground_compiler.scss | 2 +- src-docs/src/views/page/page_example.js | 14 +++----- src-docs/src/views/page/playground.js | 29 +++++----------- .../__snapshots__/page_header.test.tsx.snap | 34 +++++++++---------- .../page_header_content.test.tsx.snap | 34 +++++++++---------- .../page_header/page_header_content.test.tsx | 6 ++-- .../page/page_header/page_header_content.tsx | 13 +++---- 7 files changed, 59 insertions(+), 73 deletions(-) diff --git a/src-docs/src/services/playground/_playground_compiler.scss b/src-docs/src/services/playground/_playground_compiler.scss index 79c32707828d..0771394014b7 100644 --- a/src-docs/src/services/playground/_playground_compiler.scss +++ b/src-docs/src/services/playground/_playground_compiler.scss @@ -11,4 +11,4 @@ @if (lightness($euiTextColor) < 50) { background: $euiColorDarkestShade; } -} \ No newline at end of file +} diff --git a/src-docs/src/views/page/page_example.js b/src-docs/src/views/page/page_example.js index b4f002a81da7..e4bcb61b842e 100644 --- a/src-docs/src/views/page/page_example.js +++ b/src-docs/src/views/page/page_example.js @@ -153,8 +153,8 @@ export const PageExample = {

The left side allows you to pass any combination of{' '} pageTitle, description,{' '} - tabs, or any leftSideContent. - The order of which are determined by the particular combination. + tabs, or any children. The + order of which are determined by the particular combination.

The right side, rightSideContent, allows for just @@ -199,9 +199,8 @@ export const PageExample = { When using supplying tabs without a{' '} pageTitle, EuiPageHeader will promote those tabs as if they are the page title. This means that - any description, or{' '} - leftSideContent will sit below{' '} - the tabs. + any description, or children{' '} + will sit below the tabs.

), @@ -232,10 +231,7 @@ export const PageExample = { completely optional and by nature, inflexible. If you need a layout that does not match these patterns you can simply pass in your own{' '} children utilizing the{' '} - EuiPageHeaderSection components. Do note, that when - supplying children,{' '} - EuiPageHeader will completely ignore any other - content props and only render the children. + EuiPageHeaderSection components.

), diff --git a/src-docs/src/views/page/playground.js b/src-docs/src/views/page/playground.js index 2c0c852eb7a2..f3cf318fb980 100644 --- a/src-docs/src/views/page/playground.js +++ b/src-docs/src/views/page/playground.js @@ -2,11 +2,7 @@ import React from 'react'; import { PropTypes } from 'react-view'; -import { - EuiPageHeaderContent, - EuiButton, - EuiText, -} from '../../../../src/components/'; +import { EuiPageHeader, EuiButton, EuiText } from '../../../../src/components/'; import { propUtilityForPlayground, iconValidator, @@ -29,9 +25,9 @@ const rightSideContent = [ ]; export default () => { - const docgenInfo = Array.isArray(EuiPageHeaderContent.__docgenInfo) - ? EuiPageHeaderContent.__docgenInfo[0] - : EuiPageHeaderContent.__docgenInfo; + const docgenInfo = Array.isArray(EuiPageHeader.__docgenInfo) + ? EuiPageHeader.__docgenInfo[0] + : EuiPageHeader.__docgenInfo; const propsToUse = propUtilityForPlayground(docgenInfo.props); propsToUse.iconType = iconValidator(propsToUse.iconType); @@ -42,11 +38,6 @@ export default () => { value: 'Page title', }; - propsToUse.leftSideContent = { - ...propsToUse.leftSideContent, - type: PropTypes.String, - }; - // HELP: NOT WORKING propsToUse.alignItems = { ...propsToUse.alignItems, @@ -55,6 +46,7 @@ export default () => { propsToUse.description = { ...propsToUse.description, + value: 'Example of a description.', type: PropTypes.String, }; @@ -64,26 +56,21 @@ export default () => { }; propsToUse.children = { - value: ` -

- Any content children of EuiPageHeaderContent will appear here. -

-
`, type: PropTypes.ReactNode, hidden: false, }; return { config: { - componentName: 'EuiPageHeaderContent', + componentName: 'EuiPageHeader', props: propsToUse, scope: { - EuiPageHeaderContent, + EuiPageHeader, EuiText, }, imports: { '@elastic/eui': { - named: ['EuiPageHeaderContent', 'EuiText'], + named: ['EuiPageHeader', 'EuiText'], }, }, }, diff --git a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap index dae3768b5904..f9ad34086aa7 100644 --- a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap @@ -424,6 +424,23 @@ exports[`EuiPageHeaderContent props alignItems top is rendered 1`] = ` `; exports[`EuiPageHeaderContent props children is rendered 1`] = ` +
+
+
+
+

+ Anything +

+
+`; + +exports[`EuiPageHeaderContent props children is rendered 2`] = `
@@ -542,23 +559,6 @@ exports[`EuiPageHeaderContent props description is rendered 1`] = `
`; -exports[`EuiPageHeaderContent props leftSideContent is rendered 1`] = ` -
-
-
-
-

- Anything -

-
-`; - exports[`EuiPageHeaderContent props pageTitle is rendered 1`] = `
+
+
+
+

+ Anything +

+
+`; + +exports[`EuiPageHeaderContent props children is rendered 2`] = `
@@ -263,23 +280,6 @@ exports[`EuiPageHeaderContent props description is rendered 1`] = `
`; -exports[`EuiPageHeaderContent props leftSideContent is rendered 1`] = ` -
-
-
-
-

- Anything -

-
-`; - exports[`EuiPageHeaderContent props pageTitle is rendered 1`] = `
{ }); }); - describe('leftSideContent', () => { + describe('children', () => { test('is rendered', () => { const component = render( - Anything

} /> + +

Anything

+
); expect(component).toMatchSnapshot(); diff --git a/src/components/page/page_header/page_header_content.tsx b/src/components/page/page_header/page_header_content.tsx index da81c4f90276..655027b209ca 100644 --- a/src/components/page/page_header/page_header_content.tsx +++ b/src/components/page/page_header/page_header_content.tsx @@ -27,11 +27,12 @@ import { EuiSpacer } from '../../spacer'; import { EuiTitle } from '../../title'; import { EuiText } from '../../text'; import { useIsWithinBreakpoints } from '../../../services/hooks'; +import { Props as EuiTabProps } from '../../../components/tabs/tab'; export const ALIGN_ITEMS = ['top', 'bottom', 'center'] as const; // Gets all the tab props including the button or link props -type EuiTabProps = React.ComponentProps & { +type Tab = EuiTabProps & { /** * Visible text of the tab */ @@ -56,7 +57,7 @@ export type EuiPageHeaderContentTabs = { * Accepts an array of `EuiTab` objects; * HELP: This is evaluating to `any[]` in the props table */ - tabs?: EuiTabProps[]; + tabs?: Tab[]; /** * Any extras to apply to the outer tabs container. * Extends `EuiTabs` @@ -184,9 +185,9 @@ export const EuiPageHeaderContent: FunctionComponent ); } - let leftSideContentNode = children; + let bottomContentNode = children; if (children && (tabsNode || pageTitleNode)) { - leftSideContentNode = ( + bottomContentNode = (
{children} @@ -259,7 +260,7 @@ export const EuiPageHeaderContent: FunctionComponent )} - {leftSideContentNode} + {bottomContentNode}
) : (
@@ -269,7 +270,7 @@ export const EuiPageHeaderContent: FunctionComponent alignItems={alignItems === 'bottom' ? 'flexEnd' : 'center'} gutterSize="l"> - {leftSideOrder} {leftSideContentNode} + {leftSideOrder} {bottomContentNode} {rightSideFlexItem} From 09285bfac05baf7d7567fd3721339be5979040f4 Mon Sep 17 00:00:00 2001 From: cchaos Date: Fri, 29 Jan 2021 16:55:02 -0500 Subject: [PATCH 13/27] Playground fix --- src-docs/src/views/page/playground.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src-docs/src/views/page/playground.js b/src-docs/src/views/page/playground.js index f3cf318fb980..3931f9a5ed22 100644 --- a/src-docs/src/views/page/playground.js +++ b/src-docs/src/views/page/playground.js @@ -38,12 +38,6 @@ export default () => { value: 'Page title', }; - // HELP: NOT WORKING - propsToUse.alignItems = { - ...propsToUse.alignItems, - defaultValue: 'center', - }; - propsToUse.description = { ...propsToUse.description, value: 'Example of a description.', From a3051f2f5aac9087d990b05df2d88c939cabb43c Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Mon, 1 Feb 2021 12:08:25 -0600 Subject: [PATCH 14/27] more customProps --- src-docs/src/services/playground/index.js | 1 + src-docs/src/services/playground/utils.js | 16 ++++++++++ src-docs/src/views/page/playground.js | 36 +++++++---------------- 3 files changed, 28 insertions(+), 25 deletions(-) create mode 100644 src-docs/src/services/playground/utils.js diff --git a/src-docs/src/services/playground/index.js b/src-docs/src/services/playground/index.js index a426fce24f6c..72420fda6b01 100644 --- a/src-docs/src/services/playground/index.js +++ b/src-docs/src/services/playground/index.js @@ -6,3 +6,4 @@ export { iconValidator } from './iconValidator'; export { createOptionalEnum } from './createOptionalEnum'; export { dummyFunction } from './dummyFunction'; export { simulateFunction } from './simulateFunction'; +export { generateAst, generateCustomProps } from './utils'; diff --git a/src-docs/src/services/playground/utils.js b/src-docs/src/services/playground/utils.js new file mode 100644 index 000000000000..a0fe26d599e8 --- /dev/null +++ b/src-docs/src/services/playground/utils.js @@ -0,0 +1,16 @@ +import template from '@babel/template'; + +export const generateAst = (value) => { + return template.ast(String(value), { plugins: ['jsx'] }).expression; +}; + +export const generateCustomProps = (props) => { + return props.reduce((obj, item) => { + return { + ...obj, + [item]: { + generate: generateAst, + }, + }; + }, {}); +}; diff --git a/src-docs/src/views/page/playground.js b/src-docs/src/views/page/playground.js index 5ab7179b6e99..7690d7bd91bd 100644 --- a/src-docs/src/views/page/playground.js +++ b/src-docs/src/views/page/playground.js @@ -2,25 +2,14 @@ import React from 'react'; import { PropTypes } from 'react-view'; -import template from '@babel/template'; import { EuiPageHeader, EuiButton } from '../../../../src/components/'; import { propUtilityForPlayground, iconValidator, simulateFunction, + generateCustomProps, } from '../../services/playground'; -// HELP: Can we get a "simulate" toggle and pass ReactNodes? -// const tabs = [ -// { -// label: 'Tab 1', -// isSelected: true, -// }, -// { -// label: 'Tab 2', -// }, -// ]; - const tabs = `[ { label: 'Tab 1', @@ -31,10 +20,10 @@ const tabs = `[ }, ]`; -const rightSideContent = [ +const rightSideContent = `[ Button 1, Button 2, -]; +]`; export default () => { const docgenInfo = Array.isArray(EuiPageHeader.__docgenInfo) @@ -60,10 +49,12 @@ export default () => { type: PropTypes.String, }; - propsToUse.rightSideContent = { + propsToUse.rightSideContent = simulateFunction({ ...propsToUse.rightSideContent, - type: PropTypes.Array, - }; + custom: { + value: rightSideContent, + }, + }); propsToUse.tabs = simulateFunction({ ...propsToUse.tabs, @@ -78,19 +69,14 @@ export default () => { props: propsToUse, scope: { EuiPageHeader, + EuiButton, }, imports: { '@elastic/eui': { - named: ['EuiPageHeader'], - }, - }, - customProps: { - tabs: { - generate: (value) => { - return template.ast(String(value), { plugins: ['jsx'] }).expression; - }, + named: ['EuiPageHeader', 'EuiButton'], }, }, + customProps: generateCustomProps(['rightSideContent', 'tabs']), }, }; }; From a5b6eb53595f12450981bebda9bcddb61a3f48de Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Tue, 2 Feb 2021 18:32:07 -0600 Subject: [PATCH 15/27] prevent format errors --- src-docs/src/services/playground/playground.js | 10 +++++++++- src-docs/src/views/page/playground.js | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src-docs/src/services/playground/playground.js b/src-docs/src/services/playground/playground.js index 503154b23be4..01293d19d82c 100644 --- a/src-docs/src/services/playground/playground.js +++ b/src-docs/src/services/playground/playground.js @@ -26,7 +26,15 @@ export default ({ config, setGhostBackground, playgroundClassName }) => { newCode = newCode.replace(/(\);)$/m, ''); } - return format(newCode.trim(), ' '.repeat(4)); + let formatted; + // TODO: Replace `html-format` with something better. + // Notably, something more jsx-friendly + try { + formatted = format(newCode.trim(), ' '.repeat(4)); + } catch { + formatted = newCode.trim(); + } + return formatted; }; const Playground = () => { diff --git a/src-docs/src/views/page/playground.js b/src-docs/src/views/page/playground.js index 04d34c936488..91ae10611ce1 100644 --- a/src-docs/src/views/page/playground.js +++ b/src-docs/src/views/page/playground.js @@ -65,6 +65,7 @@ export default () => { }); propsToUse.children = { + ...propsToUse.children, type: PropTypes.ReactNode, hidden: false, }; From 373fa5e7ed91790a57886e2a9944678722dd70ad Mon Sep 17 00:00:00 2001 From: cchaos Date: Wed, 3 Feb 2021 10:47:19 -0500 Subject: [PATCH 16/27] Some cleanup and fixing of logic --- .../services/playground/createOptionalEnum.js | 2 +- src-docs/src/services/playground/knobs.js | 11 +---- src-docs/src/views/page/page_example.js | 21 ++++++++- src-docs/src/views/page/playground.js | 44 ++++++++++++++----- .../__snapshots__/page_header.test.tsx.snap | 26 +++++++---- .../page_header_content.test.tsx.snap | 24 +++++++--- .../page/page_header/page_header_content.tsx | 19 +++++--- 7 files changed, 104 insertions(+), 43 deletions(-) diff --git a/src-docs/src/services/playground/createOptionalEnum.js b/src-docs/src/services/playground/createOptionalEnum.js index ab4a9d91032f..64a6db09b565 100644 --- a/src-docs/src/services/playground/createOptionalEnum.js +++ b/src-docs/src/services/playground/createOptionalEnum.js @@ -2,7 +2,7 @@ export const createOptionalEnum = (prop = { options: {} }) => { const newProp = { ...prop, options: { - none: '-- No value selected --', + none: '', ...prop.options, }, defaultValue: 'none', diff --git a/src-docs/src/services/playground/knobs.js b/src-docs/src/services/playground/knobs.js index ea4d695a0153..614a03a386fa 100644 --- a/src-docs/src/services/playground/knobs.js +++ b/src-docs/src/services/playground/knobs.js @@ -214,6 +214,7 @@ const Knob = ({ isInvalid={error && error.length > 0} compressed fullWidth + hasNoInitialSelection={!valueKey && !defaultValue} /> ); @@ -251,16 +252,6 @@ const Knob = ({ /> ); - case 'textarea': - return ( - { - set(e.target.value); - }} - /> - ); } } diff --git a/src-docs/src/views/page/page_example.js b/src-docs/src/views/page/page_example.js index e4bcb61b842e..9d2f83f92604 100644 --- a/src-docs/src/views/page/page_example.js +++ b/src-docs/src/views/page/page_example.js @@ -163,7 +163,7 @@ export const PageExample = { which, at least one is primary (or{' '} {'fill="true"'}). These items are also displayed in reverse order so that the first - and primary action should be first in the list. + and primary action will be displayed far right.

You can further adjust the display of these content types with an @@ -180,6 +180,18 @@ export const PageExample = {

), props: { EuiPageHeader }, + snippet: `Button 1, + Button 2 + ]} +/>`, }, { title: 'Page header tabs', @@ -210,6 +222,13 @@ export const PageExample = {
), props: { EuiPageHeader }, + snippet: ``, }, { title: 'Page header custom', diff --git a/src-docs/src/views/page/playground.js b/src-docs/src/views/page/playground.js index 91ae10611ce1..59625bd72bc3 100644 --- a/src-docs/src/views/page/playground.js +++ b/src-docs/src/views/page/playground.js @@ -2,12 +2,18 @@ import React from 'react'; import { PropTypes } from 'react-view'; -import { EuiPageHeader, EuiButton } from '../../../../src/components/'; +import { + EuiPageHeader, + EuiButton, + EuiTabs, + EuiImage, +} from '../../../../src/components/'; import { propUtilityForPlayground, iconValidator, simulateFunction, generateCustomProps, + createOptionalEnum, } from '../../services/playground'; const tabs = `[ @@ -20,10 +26,12 @@ const tabs = `[ }, ]`; -const rightSideContent = `[ - Button 1, - Button 2, -]`; +// const rightSideContent = `[ +// Button 1, +// Button 2, +// ]`; +const rightSideContent = + '[]'; export default () => { const docgenInfo = Array.isArray(EuiPageHeader.__docgenInfo) @@ -39,11 +47,6 @@ export default () => { value: 'Page title', }; - propsToUse.leftSideContent = { - ...propsToUse.leftSideContent, - type: PropTypes.String, - }; - propsToUse.description = { ...propsToUse.description, value: 'Example of a description.', @@ -70,6 +73,23 @@ export default () => { hidden: false, }; + propsToUse.alignItems = createOptionalEnum(propsToUse.alignItems); + + // propsToUse.alignItems = { + // ...propsToUse.alignItems, + // type: PropTypes.Enum, + // defaultValue: '-- Choose --', + // options: { + // empty: '-- Choose --', + // subdued: 'subdued', + // secondary: 'secondary', + // accent: 'accent', + // danger: 'danger', + // warning: 'warning', + // ghost: 'ghost', + // }, + // }; + return { config: { componentName: 'EuiPageHeader', @@ -77,10 +97,12 @@ export default () => { scope: { EuiPageHeader, EuiButton, + EuiTabs, + EuiImage, }, imports: { '@elastic/eui': { - named: ['EuiPageHeader', 'EuiButton'], + named: ['EuiPageHeader', 'EuiButton', 'EuiTabs', 'EuiImage'], }, }, customProps: generateCustomProps(['rightSideContent', 'tabs']), diff --git a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap index f9ad34086aa7..b4df791e9aa4 100644 --- a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap @@ -28,7 +28,6 @@ exports[`EuiPageHeader props alignItems bottom is rendered 1`] = ` > Page title -
Page title -
Page title -
Page title -
-

- Anything -

+
+
+

+ Anything +

+
`; @@ -451,7 +454,14 @@ exports[`EuiPageHeaderContent props children is rendered 2`] = ` class="euiFlexItem" />
- Child +
+
+ Child +
`; diff --git a/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap index 7fc4a1e7913a..776ce34d6c35 100644 --- a/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap @@ -31,7 +31,6 @@ exports[`EuiPageHeaderContent props alignItems bottom is rendered 1`] = ` > Page title -
Page title -
-

- Anything -

+
+
+

+ Anything +

+
`; @@ -172,7 +177,14 @@ exports[`EuiPageHeaderContent props children is rendered 2`] = ` class="euiFlexItem" />
- Child +
+
+ Child +
`; diff --git a/src/components/page/page_header/page_header_content.tsx b/src/components/page/page_header/page_header_content.tsx index 655027b209ca..24f330d8d1fd 100644 --- a/src/components/page/page_header/page_header_content.tsx +++ b/src/components/page/page_header/page_header_content.tsx @@ -185,13 +185,19 @@ export const EuiPageHeaderContent: FunctionComponent ); } - let bottomContentNode = children; - if (children && (tabsNode || pageTitleNode)) { + const childrenNode = children && ( + <> + + {children} + + ); + + let bottomContentNode; + if (childrenNode || (tabsNode && pageTitleNode)) { bottomContentNode = (
- - {children} - {pageTitle && tabsNode} + {childrenNode} + {pageTitleNode && tabsNode}
); } @@ -270,7 +276,8 @@ export const EuiPageHeaderContent: FunctionComponent alignItems={alignItems === 'bottom' ? 'flexEnd' : 'center'} gutterSize="l"> - {leftSideOrder} {bottomContentNode} + {leftSideOrder} + {bottomContentNode} {rightSideFlexItem} From 2a59f3233841fffde8eceecc581e8b774db16edc Mon Sep 17 00:00:00 2001 From: cchaos Date: Wed, 3 Feb 2021 11:12:58 -0500 Subject: [PATCH 17/27] Added `stretch` to the align prop and fixed tests --- src-docs/src/views/page/playground.js | 29 +- .../__snapshots__/page_header.test.tsx.snap | 572 ++---------------- .../page_header_content.test.tsx.snap | 42 ++ .../page/page_header/_page_header.scss | 4 + .../page/page_header/page_header.test.tsx | 19 +- .../page/page_header/page_header.tsx | 2 - .../page/page_header/page_header_content.tsx | 4 +- 7 files changed, 119 insertions(+), 553 deletions(-) diff --git a/src-docs/src/views/page/playground.js b/src-docs/src/views/page/playground.js index 59625bd72bc3..62734838ae61 100644 --- a/src-docs/src/views/page/playground.js +++ b/src-docs/src/views/page/playground.js @@ -26,12 +26,14 @@ const tabs = `[ }, ]`; -// const rightSideContent = `[ -// Button 1, -// Button 2, -// ]`; -const rightSideContent = - '[]'; +const rightSideContent = `[ + Button 1, + Button 2, +]`; + +// TODO: Try later to find build a toggle that allows switching between different types of content to pass +// const rightSideContent = +// '[]'; export default () => { const docgenInfo = Array.isArray(EuiPageHeader.__docgenInfo) @@ -75,21 +77,6 @@ export default () => { propsToUse.alignItems = createOptionalEnum(propsToUse.alignItems); - // propsToUse.alignItems = { - // ...propsToUse.alignItems, - // type: PropTypes.Enum, - // defaultValue: '-- Choose --', - // options: { - // empty: '-- Choose --', - // subdued: 'subdued', - // secondary: 'secondary', - // accent: 'accent', - // danger: 'danger', - // warning: 'warning', - // ghost: 'ghost', - // }, - // }; - return { config: { componentName: 'EuiPageHeader', diff --git a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap index b4df791e9aa4..2d8b9d53da51 100644 --- a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap @@ -102,6 +102,52 @@ exports[`EuiPageHeader props alignItems center is rendered 1`] = `
`; +exports[`EuiPageHeader props alignItems stretch is rendered 1`] = ` +
+
+
+
+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+
+
+
+`; + exports[`EuiPageHeader props alignItems top is rendered 1`] = `
`; - -exports[`EuiPageHeaderContent is rendered 1`] = ` -
-
-
-
-
-`; - -exports[`EuiPageHeaderContent props alignItems bottom is rendered 1`] = ` -
-
-
-

- Page title -

-
-
-
-
- -
-
- -
-
-
-
-
-`; - -exports[`EuiPageHeaderContent props alignItems center is rendered 1`] = ` -
-
-
-

- Page title -

-
-
-
-
- -
-
- -
-
-
-
-
-`; - -exports[`EuiPageHeaderContent props alignItems top is rendered 1`] = ` -
-
-
-

- Page title -

-
-
-
-
- -
-
- -
-
-
-
-
-`; - -exports[`EuiPageHeaderContent props children is rendered 1`] = ` -
-
-
-
-
-
-

- Anything -

-
-
-`; - -exports[`EuiPageHeaderContent props children is rendered 2`] = ` -
-
-
-
-
-
- Child -
-
-`; - -exports[`EuiPageHeaderContent props children is rendered even if content props are passed 1`] = ` -
-
-
-

- Page title -

-
-
-
-
- -
-
- -
-
-
-
-
-
- Child -
-
- - -
-
-
-`; - -exports[`EuiPageHeaderContent props description is rendered 1`] = ` -
-
-
-
-

- Description -

-
-
-
-
-`; - -exports[`EuiPageHeaderContent props pageTitle is rendered 1`] = ` -
-
-
-

- Page title -

-
-
-
-`; - -exports[`EuiPageHeaderContent props pageTitle is rendered with icon 1`] = ` -
-
-
-

- - Page title -

-
-
-
-`; - -exports[`EuiPageHeaderContent props responsive is rendered as false 1`] = ` -
-
-
-
-
-`; - -exports[`EuiPageHeaderContent props responsive is rendered as reverse 1`] = ` -
-
-
-
-
-`; - -exports[`EuiPageHeaderContent props rightSideContent is rendered 1`] = ` -
-
-
-
-
-
- -
-
- -
-
-
-
-
-`; - -exports[`EuiPageHeaderContent props rightSideContent is rendered with rightSideResponsive as true 1`] = ` -
-
-
-
-
-
- -
-
- -
-
-
-
-
-`; - -exports[`EuiPageHeaderContent props tabs is rendered 1`] = ` -
-
-
-
- - -
-
-
-
-`; - -exports[`EuiPageHeaderContent props tabs is rendered with tabsProps 1`] = ` -
-
-
-
- - -
-
-
-
-`; diff --git a/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap index 776ce34d6c35..b404edb405c7 100644 --- a/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap @@ -100,6 +100,48 @@ exports[`EuiPageHeaderContent props alignItems center is rendered 1`] = `
`; +exports[`EuiPageHeaderContent props alignItems stretch is rendered 1`] = ` +
+
+
+

+ Page title +

+
+
+
+
+ +
+
+ +
+
+
+
+
+`; + exports[`EuiPageHeaderContent props alignItems top is rendered 1`] = `
Button 1, + , +]; describe('EuiPageHeader', () => { test('is rendered', () => { diff --git a/src/components/page/page_header/page_header.tsx b/src/components/page/page_header/page_header.tsx index 7044187cee8f..27e9635eb61c 100644 --- a/src/components/page/page_header/page_header.tsx +++ b/src/components/page/page_header/page_header.tsx @@ -25,8 +25,6 @@ import { EuiPageHeaderContentProps, } from './page_header_content'; -export const ALIGN_ITEMS = ['top', 'bottom', 'center'] as const; - export type EuiPageHeaderProps = CommonProps & HTMLAttributes & EuiPageHeaderContentProps & { diff --git a/src/components/page/page_header/page_header_content.tsx b/src/components/page/page_header/page_header_content.tsx index 24f330d8d1fd..32eb11b251ca 100644 --- a/src/components/page/page_header/page_header_content.tsx +++ b/src/components/page/page_header/page_header_content.tsx @@ -29,7 +29,7 @@ import { EuiText } from '../../text'; import { useIsWithinBreakpoints } from '../../../services/hooks'; import { Props as EuiTabProps } from '../../../components/tabs/tab'; -export const ALIGN_ITEMS = ['top', 'bottom', 'center'] as const; +export const ALIGN_ITEMS = ['top', 'bottom', 'center', 'stretch'] as const; // Gets all the tab props including the button or link props type Tab = EuiTabProps & { @@ -273,7 +273,7 @@ export const EuiPageHeaderContent: FunctionComponent {leftSideOrder} From 27d7815737e71716beb302790148ae4750b7fdf4 Mon Sep 17 00:00:00 2001 From: cchaos Date: Wed, 3 Feb 2021 11:35:02 -0500 Subject: [PATCH 18/27] cl & comments --- CHANGELOG.md | 7 +++++++ .../page/page_header/page_header_content.test.tsx | 4 ++-- src/services/hooks/useIsWithinBreakpoints.ts | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1451858e10d..bdc6cd62a9ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,19 @@ ## [`master`](https://github.com/elastic/eui/tree/master) - Added `isLoading` prop and added `EuiOverlayMask` directly to `EuiConfirmModal` ([#4421](https://github.com/elastic/eui/pull/4421)) +- Added content-specific props (`pageTitle`, `description`, `tabs`, `rightSideContent`) to `EuiPageHeader` by creating a new `EuiPageHeaderContent` component ([#4451](https://github.com/elastic/eui/pull/4451)) +- Added `isActive` parameter to the `useIsWithinBreakpoints` hook ([#4451](https://github.com/elastic/eui/pull/4451)) **Bug fixes** - Fixed `id` usage throughout `EuiTreeView` to respect custom ids and stop conflicts in generated ids ([#4435](https://github.com/elastic/eui/pull/4435)) - Fixed `EuiTabs` `role` if no tabs are passed in ([#4435](https://github.com/elastic/eui/pull/4435)) +**Theme: Amsterdam** + +- Increased `EuiPage`'s default `restrictWidth` size to `1200px` (extra large breakpoint) ([#4451](https://github.com/elastic/eui/pull/4451)) +- Reduced size of `euiBottomShadowSmall` by one layer ([#4451](https://github.com/elastic/eui/pull/4451)) + ## [`31.4.0`](https://github.com/elastic/eui/tree/v31.4.0) - Added `getDefaultEuiMarkdownProcessingPlugins` method for better control over `EuiMarkdownEditor`'s toolbar UI ([#4383](https://github.com/elastic/eui/pull/4383)) diff --git a/src/components/page/page_header/page_header_content.test.tsx b/src/components/page/page_header/page_header_content.test.tsx index df0e3e440011..851244115b3a 100644 --- a/src/components/page/page_header/page_header_content.test.tsx +++ b/src/components/page/page_header/page_header_content.test.tsx @@ -27,7 +27,7 @@ import { EuiPageHeaderContentProps, } from './page_header_content'; -export const tabs: EuiPageHeaderContentProps['tabs'] = [ +const tabs: EuiPageHeaderContentProps['tabs'] = [ { label: 'Tab 1', isSelected: true, @@ -37,7 +37,7 @@ export const tabs: EuiPageHeaderContentProps['tabs'] = [ }, ]; -export const rightSideContent: EuiPageHeaderContentProps['rightSideContent'] = [ +const rightSideContent: EuiPageHeaderContentProps['rightSideContent'] = [ , , ]; diff --git a/src/services/hooks/useIsWithinBreakpoints.ts b/src/services/hooks/useIsWithinBreakpoints.ts index 8e3b263d1599..17ffa46a17de 100644 --- a/src/services/hooks/useIsWithinBreakpoints.ts +++ b/src/services/hooks/useIsWithinBreakpoints.ts @@ -27,6 +27,7 @@ import { isWithinBreakpoints, EuiBreakpointSize } from '../breakpoint'; * falls within any of the named breakpoints. * * @param {EuiBreakpointSize[]} sizes An array of named breakpoints + * @param {boolean} isActive Manages whether the resize handler should be active * @returns {boolean} Returns `true` if current breakpoint name is included in `sizes` */ export function useIsWithinBreakpoints( From 18a429b9d3f3e19985381f7fd1b8a8da7335fa0a Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Wed, 3 Feb 2021 21:22:28 -0800 Subject: [PATCH 19/27] Docs clarity --- src-docs/src/views/page/page.js | 19 ++- src-docs/src/views/page/page_example.js | 191 +++++++++++++----------- 2 files changed, 123 insertions(+), 87 deletions(-) diff --git a/src-docs/src/views/page/page.js b/src-docs/src/views/page/page.js index a132c42320a7..47bb37476ea6 100644 --- a/src-docs/src/views/page/page.js +++ b/src-docs/src/views/page/page.js @@ -10,13 +10,30 @@ import { EuiPageHeader, EuiPageSideBar, EuiTitle, + EuiButton, } from '../../../../src/components'; export default () => ( SideBar nav - + Add something, + Do something, + ]} + /> diff --git a/src-docs/src/views/page/page_example.js b/src-docs/src/views/page/page_example.js index 9d2f83f92604..5def084c3b0c 100644 --- a/src-docs/src/views/page/page_example.js +++ b/src-docs/src/views/page/page_example.js @@ -67,7 +67,7 @@ export const PageExample = { ), sections: [ { - title: 'Page with everything on', + title: 'A full page layout with everything on', source: [ { type: GuideSectionTypes.JS, @@ -80,6 +80,29 @@ export const PageExample = { ], text: (
+

+ EUI provides a family of components using the{' '} + EuiPage prefix that work together to build + consistant page layouts that work responsively. The below example + utilizes the following major components +

+
    +
  • + EuiPage provides the overall wrapper. +
  • +
  • + EuiPageHeader provides a title, description and + section for actions. +
  • +
  • + EuiPageContent and its family of related + components provide the main content container. +
  • +
  • + EuiPageSideBar provides a way to provide a + menu. +
  • +

By default, the entire page will always be 100% of the window's width; to max out the typical width and center the page, set the{' '} @@ -107,7 +130,7 @@ export const PageExample = { ), }, { - title: 'Simple page with title', + title: 'A simple page layout with a title', source: [ { type: GuideSectionTypes.JS, @@ -132,7 +155,75 @@ export const PageExample = { ), }, { - title: 'Page header', + title: 'A simple page layout with content only', + source: [ + { + type: GuideSectionTypes.JS, + code: pageContentOnlySource, + }, + { + type: GuideSectionTypes.HTML, + code: pageContentOnlyHtml, + }, + ], + text:

We can further simplify pages by only showing the content.

, + demo: ( +
+ +
+ ), + }, + { + title: 'A simple page layout with content centered', + source: [ + { + type: GuideSectionTypes.JS, + code: pageContentCenterSource, + }, + { + type: GuideSectionTypes.HTML, + code: pageContentCenterHtml, + }, + ], + text: ( +

+ The page content can be optionally centered either vertically or + horizontally. This is useful for various empty states. +

+ ), + demo: ( +
+ +
+ ), + }, + { + title: 'A simple page layout with content centered in a full layout', + source: [ + { + type: GuideSectionTypes.JS, + code: PageContentCenterWithSideBarSource, + }, + { + type: GuideSectionTypes.HTML, + code: PageContentCenterWithSideBarHtml, + }, + ], + text: ( +

+ Centering the content can happen regardless of layout configuration. + In this example, we’re centering within a complex sidebar + layout. +

+ ), + demo: ( +
+ +
+ ), + }, + { + title: 'The EuiPageHeader component in more detail', source: [ { type: GuideSectionTypes.JS, @@ -146,24 +237,20 @@ export const PageExample = { text: ( <>

- EuiPageHeader comes with some pre-determined - content that you can apply to the left and right sides of the - component. -

-

- The left side allows you to pass any combination of{' '} + EuiPageHeader provides props for opinionated, + consistant formatting of your header. Any combination of pageTitle, description,{' '} - tabs, or any children. The - order of which are determined by the particular combination. + tabs, or any children will + adjust the layout as needed.

- The right side, rightSideContent, allows for just - a simple array of nodes which are placed within a - flexbox row. This is usually in the form of multiple buttons, of - which, at least one is primary (or{' '} + An additional prop rightSideContent allows for a + simple array of nodes which will layout in a + flexbox row. This is commonly used for adding multiple buttons, of + which, at least should be primary (or{' '} {'fill="true"'}). These items are also displayed in reverse order so that the first - and primary action will be displayed far right. + and primary array item will be displayed on the far right.

You can further adjust the display of these content types with an @@ -194,7 +281,7 @@ export const PageExample = { />`, }, { - title: 'Page header tabs', + title: 'Adding tabs to EuiPageHeader', source: [ { type: GuideSectionTypes.JS, @@ -231,7 +318,7 @@ export const PageExample = { />`, }, { - title: 'Page header custom', + title: 'Customizing EuiPageHeader', source: [ { type: GuideSectionTypes.JS, @@ -261,73 +348,5 @@ export const PageExample = { ), props: { EuiPageHeader }, }, - { - title: 'Page with content only', - source: [ - { - type: GuideSectionTypes.JS, - code: pageContentOnlySource, - }, - { - type: GuideSectionTypes.HTML, - code: pageContentOnlyHtml, - }, - ], - text:

We can further simplify pages by only showing the content.

, - demo: ( -
- -
- ), - }, - { - title: 'Page content centered', - source: [ - { - type: GuideSectionTypes.JS, - code: pageContentCenterSource, - }, - { - type: GuideSectionTypes.HTML, - code: pageContentCenterHtml, - }, - ], - text: ( -

- The page content can be optionally centered either vertically or - horizontally. This is useful for various empty states. -

- ), - demo: ( -
- -
- ), - }, - { - title: 'Page content centered in a full layout', - source: [ - { - type: GuideSectionTypes.JS, - code: PageContentCenterWithSideBarSource, - }, - { - type: GuideSectionTypes.HTML, - code: PageContentCenterWithSideBarHtml, - }, - ], - text: ( -

- Centering the content can happen regardless of layout configuration. - In this example, we’re centering within a complex sidebar - layout. -

- ), - demo: ( -
- -
- ), - }, ], }; From 5d1ea8231546fa4eaf08d65ac8b422ad077c37c2 Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Wed, 3 Feb 2021 21:38:42 -0800 Subject: [PATCH 20/27] words --- src-docs/src/views/page/page_example.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src-docs/src/views/page/page_example.js b/src-docs/src/views/page/page_example.js index 5def084c3b0c..990e86d409bf 100644 --- a/src-docs/src/views/page/page_example.js +++ b/src-docs/src/views/page/page_example.js @@ -91,16 +91,15 @@ export const PageExample = { EuiPage provides the overall wrapper.
  • - EuiPageHeader provides a title, description and - section for actions. + EuiPageHeader provides a title, description, + tabs and section for actions.
  • EuiPageContent and its family of related components provide the main content container.
  • - EuiPageSideBar provides a way to provide a - menu. + EuiPageSideBar provides a way to add a menu.
  • From f6108ef554342d859c388f40e3dab5bf381fce58 Mon Sep 17 00:00:00 2001 From: Caroline Horn <549577+cchaos@users.noreply.github.com> Date: Thu, 4 Feb 2021 11:52:04 -0500 Subject: [PATCH 21/27] Apply suggestions from code review --- src-docs/src/views/page/page.js | 9 --------- src-docs/src/views/page/page_example.js | 21 ++++++++++----------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src-docs/src/views/page/page.js b/src-docs/src/views/page/page.js index 47bb37476ea6..2a98e36005c2 100644 --- a/src-docs/src/views/page/page.js +++ b/src-docs/src/views/page/page.js @@ -20,15 +20,6 @@ export default () => ( Add something, Do something, diff --git a/src-docs/src/views/page/page_example.js b/src-docs/src/views/page/page_example.js index 990e86d409bf..39871fd116a9 100644 --- a/src-docs/src/views/page/page_example.js +++ b/src-docs/src/views/page/page_example.js @@ -83,23 +83,22 @@ export const PageExample = {

    EUI provides a family of components using the{' '} EuiPage prefix that work together to build - consistant page layouts that work responsively. The below example - utilizes the following major components + consistent page layouts that work responsively.

    • - EuiPage provides the overall wrapper. + EuiPage provides the overall wrapper.
    • - EuiPageHeader provides a title, description, - tabs and section for actions. + EuiPageHeader provides a title, description, + section for actions and possible tabs.
    • - EuiPageContent and its family of related + EuiPageContent and its family of related components provide the main content container.
    • - EuiPageSideBar provides a way to add a menu. + EuiPageSideBar provides a way to add side navigation.

    @@ -222,7 +221,7 @@ export const PageExample = { ), }, { - title: 'The EuiPageHeader component in more detail', + title: 'The page header in detail', source: [ { type: GuideSectionTypes.JS, @@ -246,7 +245,7 @@ export const PageExample = { An additional prop rightSideContent allows for a simple array of nodes which will layout in a flexbox row. This is commonly used for adding multiple buttons, of - which, at least should be primary (or{' '} + which, at least one should be primary (or{' '} {'fill="true"'}). These items are also displayed in reverse order so that the first and primary array item will be displayed on the far right. @@ -280,7 +279,7 @@ export const PageExample = { />`, }, { - title: 'Adding tabs to EuiPageHeader', + title: 'Tabs in the page header', source: [ { type: GuideSectionTypes.JS, @@ -317,7 +316,7 @@ export const PageExample = { />`, }, { - title: 'Customizing EuiPageHeader', + title: 'Customizing the page header', source: [ { type: GuideSectionTypes.JS, From fb2c6b980f621e230392b2d8354ac07dc6c49ec6 Mon Sep 17 00:00:00 2001 From: cchaos Date: Mon, 8 Feb 2021 12:10:21 -0500 Subject: [PATCH 22/27] Render `

    ` element in EuiPageHeader --- src-docs/src/views/page/page_example.js | 5 +-- .../__snapshots__/page_header.test.tsx.snap | 32 +++++++++---------- .../page/page_header/page_header.tsx | 10 +++--- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src-docs/src/views/page/page_example.js b/src-docs/src/views/page/page_example.js index 39871fd116a9..c1ddbb3b2ea1 100644 --- a/src-docs/src/views/page/page_example.js +++ b/src-docs/src/views/page/page_example.js @@ -83,7 +83,7 @@ export const PageExample = {

    EUI provides a family of components using the{' '} EuiPage prefix that work together to build - consistent page layouts that work responsively. + consistent page layouts that work responsively.

    • @@ -98,7 +98,8 @@ export const PageExample = { components provide the main content container.
    • - EuiPageSideBar provides a way to add side navigation. + EuiPageSideBar provides a way to add side + navigation.

    diff --git a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap index 2d8b9d53da51..b9c6289f6366 100644 --- a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap @@ -1,17 +1,17 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`EuiPageHeader is rendered 1`] = ` -

    Anything -
    +
    `; exports[`EuiPageHeader props alignItems bottom is rendered 1`] = ` -
    -
    + `; exports[`EuiPageHeader props alignItems center is rendered 1`] = ` -
    -
    + `; exports[`EuiPageHeader props alignItems stretch is rendered 1`] = ` -
    -
    + `; exports[`EuiPageHeader props alignItems top is rendered 1`] = ` -
    -
    + `; exports[`EuiPageHeader props page content props are passed down is rendered 1`] = ` -
    -
    + `; exports[`EuiPageHeader props responsive is rendered as false 1`] = ` -
    `; exports[`EuiPageHeader props responsive is rendered as reverse 1`] = ` -
    `; exports[`EuiPageHeader props restrictWidth is rendered as custom 1`] = ` -
    `; exports[`EuiPageHeader props restrictWidth is rendered as true 1`] = ` -
    `; diff --git a/src/components/page/page_header/page_header.tsx b/src/components/page/page_header/page_header.tsx index 27e9635eb61c..06d4c2061040 100644 --- a/src/components/page/page_header/page_header.tsx +++ b/src/components/page/page_header/page_header.tsx @@ -26,7 +26,7 @@ import { } from './page_header_content'; export type EuiPageHeaderProps = CommonProps & - HTMLAttributes & + HTMLAttributes & EuiPageHeaderContentProps & { /** * Sets the max-width of the page, @@ -82,14 +82,14 @@ export const EuiPageHeader: FunctionComponent = ({ if (!pageTitle && !tabs && !description && !rightSideContent) { return ( -
    +
    {children} -
    + ); } return ( -
    +
    = ({ rightSideResponsive={rightSideResponsive}> {children} -
    + ); }; From fc50d9568751763b4c58b8553b2262523b524521 Mon Sep 17 00:00:00 2001 From: cchaos Date: Mon, 8 Feb 2021 12:18:53 -0500 Subject: [PATCH 23/27] Adding `iconProps` to optional icon --- src-docs/src/views/page/page_example.js | 4 +-- .../__snapshots__/page_header.test.tsx.snap | 4 ++- .../page_header_content.test.tsx.snap | 26 +++++++++++++++++++ .../page/page_header/page_header.test.tsx | 1 + .../page/page_header/page_header.tsx | 2 ++ .../page_header/page_header_content.test.tsx | 12 +++++++++ .../page/page_header/page_header_content.tsx | 18 +++++++++---- 7 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src-docs/src/views/page/page_example.js b/src-docs/src/views/page/page_example.js index c1ddbb3b2ea1..e4de08fe34ec 100644 --- a/src-docs/src/views/page/page_example.js +++ b/src-docs/src/views/page/page_example.js @@ -269,7 +269,7 @@ export const PageExample = { snippet: ` Page title diff --git a/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap index b404edb405c7..e1a284f23110 100644 --- a/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header_content.test.tsx.snap @@ -378,6 +378,32 @@ exports[`EuiPageHeaderContent props pageTitle is rendered with icon 1`] = `
    `; +exports[`EuiPageHeaderContent props pageTitle is rendered with icon and iconProps 1`] = ` +
    +
    +
    +

    + + Page title +

    +
    +
    +
    +`; + exports[`EuiPageHeaderContent props responsive is rendered as false 1`] = `
    { = ({ // Page header content only props: pageTitle, iconType, + iconProps, tabs, tabsProps, description, @@ -95,6 +96,7 @@ export const EuiPageHeader: FunctionComponent = ({ responsive={responsive} pageTitle={pageTitle} iconType={iconType} + iconProps={iconProps} tabs={tabs} tabsProps={tabsProps} description={description} diff --git a/src/components/page/page_header/page_header_content.test.tsx b/src/components/page/page_header/page_header_content.test.tsx index 851244115b3a..271b26626c70 100644 --- a/src/components/page/page_header/page_header_content.test.tsx +++ b/src/components/page/page_header/page_header_content.test.tsx @@ -66,6 +66,18 @@ describe('EuiPageHeaderContent', () => { expect(component).toMatchSnapshot(); }); + + test('is rendered with icon and iconProps', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); }); describe('tabs', () => { diff --git a/src/components/page/page_header/page_header_content.tsx b/src/components/page/page_header/page_header_content.tsx index 32eb11b251ca..e8e10137996a 100644 --- a/src/components/page/page_header/page_header_content.tsx +++ b/src/components/page/page_header/page_header_content.tsx @@ -20,7 +20,7 @@ import React, { FunctionComponent, ReactNode, HTMLAttributes } from 'react'; import classNames from 'classnames'; import { CommonProps } from '../../common'; -import { EuiIcon, IconType } from '../../icon'; +import { EuiIcon, EuiIconProps, IconType } from '../../icon'; import { EuiTab, EuiTabs, EuiTabsProps } from '../../tabs'; import { EuiFlexGroup, EuiFlexItem } from '../../flex'; import { EuiSpacer } from '../../spacer'; @@ -49,6 +49,10 @@ export type EuiPageHeaderContentTitle = { * Optional icon to place to the left of the title */ iconType?: IconType; + /** + * Additional EuiIcon props to apply to the optional icon + */ + iconProps?: Partial; }; export type EuiPageHeaderContentTabs = { @@ -103,8 +107,7 @@ export type EuiPageHeaderContentProps = CommonProps & */ rightSideResponsive?: boolean; /** - * Custom children will be rendered before the `tabs` unless no `pageTitle` is present, - * then it will be the last item + * Custom children will be rendered before the `tabs` unless no `pageTitle` is present, then it will be the last item */ children?: ReactNode; }; @@ -113,6 +116,7 @@ export const EuiPageHeaderContent: FunctionComponent className, pageTitle, iconType, + iconProps, tabs, tabsProps, description, @@ -146,9 +150,13 @@ export const EuiPageHeaderContent: FunctionComponent if (pageTitle) { const icon = iconType ? ( ) : undefined; From e3f1ce1cdea837d2e613186979d847d8f8d2779f Mon Sep 17 00:00:00 2001 From: cchaos Date: Mon, 8 Feb 2021 12:28:45 -0500 Subject: [PATCH 24/27] Renaming `rightSideContent` to `rightSideItems` for better clarity of what the prop type is --- CHANGELOG.md | 2 +- src-docs/src/views/page/page.js | 2 +- .../page/page_content_center_with_side_bar.js | 2 +- src-docs/src/views/page/page_example.js | 8 ++++---- src-docs/src/views/page/page_header.js | 2 +- src-docs/src/views/page/page_header_tabs.js | 2 +- src-docs/src/views/page/playground.js | 12 ++++++------ src-docs/src/views/tour/fullscreen.js | 2 +- .../__snapshots__/page_header.test.tsx.snap | 10 +++++----- .../page_header_content.test.tsx.snap | 18 +++++++++--------- .../page/page_header/_page_header_content.scss | 2 +- .../page/page_header/page_header.test.tsx | 6 +++--- .../page/page_header/page_header.tsx | 6 +++--- .../page_header/page_header_content.test.tsx | 12 ++++++------ .../page/page_header/page_header_content.tsx | 10 +++++----- 15 files changed, 48 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bdc6cd62a9ad..5990c228d8ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## [`master`](https://github.com/elastic/eui/tree/master) - Added `isLoading` prop and added `EuiOverlayMask` directly to `EuiConfirmModal` ([#4421](https://github.com/elastic/eui/pull/4421)) -- Added content-specific props (`pageTitle`, `description`, `tabs`, `rightSideContent`) to `EuiPageHeader` by creating a new `EuiPageHeaderContent` component ([#4451](https://github.com/elastic/eui/pull/4451)) +- Added content-specific props (`pageTitle`, `description`, `tabs`, `rightSideItems`) to `EuiPageHeader` by creating a new `EuiPageHeaderContent` component ([#4451](https://github.com/elastic/eui/pull/4451)) - Added `isActive` parameter to the `useIsWithinBreakpoints` hook ([#4451](https://github.com/elastic/eui/pull/4451)) **Bug fixes** diff --git a/src-docs/src/views/page/page.js b/src-docs/src/views/page/page.js index 2a98e36005c2..d6d4eca6e776 100644 --- a/src-docs/src/views/page/page.js +++ b/src-docs/src/views/page/page.js @@ -20,7 +20,7 @@ export default () => ( Add something, Do something, ]} diff --git a/src-docs/src/views/page/page_content_center_with_side_bar.js b/src-docs/src/views/page/page_content_center_with_side_bar.js index 5ff4cb412dc0..27e97f9aa337 100644 --- a/src-docs/src/views/page/page_content_center_with_side_bar.js +++ b/src-docs/src/views/page/page_content_center_with_side_bar.js @@ -19,7 +19,7 @@ export default () => ( diff --git a/src-docs/src/views/page/page_example.js b/src-docs/src/views/page/page_example.js index e4de08fe34ec..a84baa69ba26 100644 --- a/src-docs/src/views/page/page_example.js +++ b/src-docs/src/views/page/page_example.js @@ -237,13 +237,13 @@ export const PageExample = { <>

    EuiPageHeader provides props for opinionated, - consistant formatting of your header. Any combination of + consistent formatting of your header. Any combination of{' '} pageTitle, description,{' '} tabs, or any children will adjust the layout as needed.

    - An additional prop rightSideContent allows for a + An additional prop rightSideItems allows for a simple array of nodes which will layout in a flexbox row. This is commonly used for adding multiple buttons, of which, at least one should be primary (or{' '} @@ -255,7 +255,7 @@ export const PageExample = { You can further adjust the display of these content types with an optional iconType placed to the left of the title, alignItems for adjusting the vertical - alignment of the two sides, and responsiveOrder + alignment of the two sides, and responsiveOrder{' '} to determine which content side to display first on smaller screens.

    @@ -273,7 +273,7 @@ export const PageExample = { { label:"Tab 2" } ]} description="Example of a description." - rightSideContent={[ + rightSideItems={[ Button 1, Button 2 ]} diff --git a/src-docs/src/views/page/page_header.js b/src-docs/src/views/page/page_header.js index 085149d8c907..239c9a704f0b 100644 --- a/src-docs/src/views/page/page_header.js +++ b/src-docs/src/views/page/page_header.js @@ -21,7 +21,7 @@ export default () => ( }, ]} description="This description should be describing the current page as depicted by the page title. It has the grow prop set to false on the EuiText block so that it is the proper line length. And it will also never extend beneath the right side content (buttons)." - rightSideContent={[ + rightSideItems={[ Add something, Do something, ]}> diff --git a/src-docs/src/views/page/page_header_tabs.js b/src-docs/src/views/page/page_header_tabs.js index 06b19a5461ed..6c92df0e8aca 100644 --- a/src-docs/src/views/page/page_header_tabs.js +++ b/src-docs/src/views/page/page_header_tabs.js @@ -19,7 +19,7 @@ export default () => ( }, ]} description="This description should be describing the currently selected tab. It has the grow prop set to false on the EuiText block so that it is the proper line length. And it will also never extend beneath the right side content (buttons)." - rightSideContent={[ + rightSideItems={[ Add something, Do something, ]}> diff --git a/src-docs/src/views/page/playground.js b/src-docs/src/views/page/playground.js index 62734838ae61..6be4412b5f9b 100644 --- a/src-docs/src/views/page/playground.js +++ b/src-docs/src/views/page/playground.js @@ -26,13 +26,13 @@ const tabs = `[ }, ]`; -const rightSideContent = `[ +const rightSideItems = `[ Button 1, Button 2, ]`; // TODO: Try later to find build a toggle that allows switching between different types of content to pass -// const rightSideContent = +// const rightSideItems = // '[]'; export default () => { @@ -55,10 +55,10 @@ export default () => { type: PropTypes.String, }; - propsToUse.rightSideContent = simulateFunction({ - ...propsToUse.rightSideContent, + propsToUse.rightSideItems = simulateFunction({ + ...propsToUse.rightSideItems, custom: { - value: rightSideContent, + value: rightSideItems, }, }); @@ -92,7 +92,7 @@ export default () => { named: ['EuiPageHeader', 'EuiButton', 'EuiTabs', 'EuiImage'], }, }, - customProps: generateCustomProps(['rightSideContent', 'tabs']), + customProps: generateCustomProps(['rightSideItems', 'tabs']), }, }; }; diff --git a/src-docs/src/views/tour/fullscreen.js b/src-docs/src/views/tour/fullscreen.js index df718dbee293..07e46c8083f2 100644 --- a/src-docs/src/views/tour/fullscreen.js +++ b/src-docs/src/views/tour/fullscreen.js @@ -179,7 +179,7 @@ export default () => { setIsFullScreen(false)} diff --git a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap index 23379cc31011..3f11d6db6ca5 100644 --- a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap @@ -33,7 +33,7 @@ exports[`EuiPageHeader props alignItems bottom is rendered 1`] = ` class="euiFlexItem euiFlexItem--flexGrowZero" >
    `; -exports[`EuiPageHeaderContent props rightSideContent is rendered 1`] = ` +exports[`EuiPageHeaderContent props rightSideItems is rendered 1`] = `
    @@ -446,7 +446,7 @@ exports[`EuiPageHeaderContent props rightSideContent is rendered 1`] = ` class="euiFlexItem euiFlexItem--flexGrowZero" >
    `; -exports[`EuiPageHeaderContent props rightSideContent is rendered with rightSideResponsive as true 1`] = ` +exports[`EuiPageHeaderContent props rightSideItems is rendered with rightSideResponsive as true 1`] = `
    @@ -482,7 +482,7 @@ exports[`EuiPageHeaderContent props rightSideContent is rendered with rightSideR class="euiFlexItem euiFlexItem--flexGrowZero" >
    Button 1, , ]; @@ -59,7 +59,7 @@ describe('EuiPageHeader', () => { tabs={tabs} tabsProps={requiredProps} description="Description" - rightSideContent={rightSideContent} + rightSideItems={rightSideItems} rightSideResponsive={true}>

    Anything

    @@ -75,7 +75,7 @@ describe('EuiPageHeader', () => { const component = render( ); diff --git a/src/components/page/page_header/page_header.tsx b/src/components/page/page_header/page_header.tsx index 01f280c57a88..f424ad7f7311 100644 --- a/src/components/page/page_header/page_header.tsx +++ b/src/components/page/page_header/page_header.tsx @@ -55,7 +55,7 @@ export const EuiPageHeader: FunctionComponent = ({ tabs, tabsProps, description, - rightSideContent, + rightSideItems, rightSideResponsive, ...rest }) => { @@ -81,7 +81,7 @@ export const EuiPageHeader: FunctionComponent = ({ className ); - if (!pageTitle && !tabs && !description && !rightSideContent) { + if (!pageTitle && !tabs && !description && !rightSideItems) { return (
    {children} @@ -100,7 +100,7 @@ export const EuiPageHeader: FunctionComponent = ({ tabs={tabs} tabsProps={tabsProps} description={description} - rightSideContent={rightSideContent} + rightSideItems={rightSideItems} rightSideResponsive={rightSideResponsive}> {children} diff --git a/src/components/page/page_header/page_header_content.test.tsx b/src/components/page/page_header/page_header_content.test.tsx index 271b26626c70..92ba2224017b 100644 --- a/src/components/page/page_header/page_header_content.test.tsx +++ b/src/components/page/page_header/page_header_content.test.tsx @@ -37,7 +37,7 @@ const tabs: EuiPageHeaderContentProps['tabs'] = [ }, ]; -const rightSideContent: EuiPageHeaderContentProps['rightSideContent'] = [ +const rightSideItems: EuiPageHeaderContentProps['rightSideItems'] = [ , , ]; @@ -118,10 +118,10 @@ describe('EuiPageHeaderContent', () => { }); }); - describe('rightSideContent', () => { + describe('rightSideItems', () => { test('is rendered', () => { const component = render( - + ); expect(component).toMatchSnapshot(); @@ -130,7 +130,7 @@ describe('EuiPageHeaderContent', () => { test('is rendered with rightSideResponsive as true', () => { const component = render( ); @@ -153,7 +153,7 @@ describe('EuiPageHeaderContent', () => { + rightSideItems={rightSideItems}> Child ); @@ -168,7 +168,7 @@ describe('EuiPageHeaderContent', () => { const component = render( ); diff --git a/src/components/page/page_header/page_header_content.tsx b/src/components/page/page_header/page_header_content.tsx index e8e10137996a..293232130580 100644 --- a/src/components/page/page_header/page_header_content.tsx +++ b/src/components/page/page_header/page_header_content.tsx @@ -96,7 +96,7 @@ export type EuiPageHeaderContentProps = CommonProps & * The first button should be primary, usually with `fill` and will be visually displayed as the last item, * but first in the tab order */ - rightSideContent?: ReactNode[]; + rightSideItems?: ReactNode[]; /** * Vertical alignment of the left and right side content; * Default is `middle` for custom content, but `top` for when `pageTitle` or `tabs` are included @@ -120,7 +120,7 @@ export const EuiPageHeaderContent: FunctionComponent tabs, tabsProps, description, - rightSideContent, + rightSideItems, alignItems = 'top', responsive = true, rightSideResponsive = false, @@ -232,9 +232,9 @@ export const EuiPageHeaderContent: FunctionComponent } let rightSideFlexItem; - if (rightSideContent && rightSideContent.length) { + if (rightSideItems && rightSideItems.length) { const wrapWithFlex = () => { - return rightSideContent.map((item, index) => { + return rightSideItems.map((item, index) => { return ( {item} @@ -246,7 +246,7 @@ export const EuiPageHeaderContent: FunctionComponent rightSideFlexItem = ( {wrapWithFlex()} From f0964c0b7125ef7701e9d8951cc85654157bd024 Mon Sep 17 00:00:00 2001 From: cchaos Date: Mon, 8 Feb 2021 12:52:56 -0500 Subject: [PATCH 25/27] Replacing `rightSideResponsive` with a more generic `rightSideGroupProps` Also had to change the EuiFlexGroupProps to include ALL props (like Common) --- src/components/flex/flex_group.tsx | 8 ++--- src/components/flex/index.ts | 6 +++- .../__snapshots__/page_header.test.tsx.snap | 4 ++- .../page_header_content.test.tsx.snap | 6 ++-- .../page/page_header/page_header.test.tsx | 2 +- .../page/page_header/page_header.tsx | 4 +-- .../page_header/page_header_content.test.tsx | 4 +-- .../page/page_header/page_header_content.tsx | 30 +++++++++++-------- 8 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/components/flex/flex_group.tsx b/src/components/flex/flex_group.tsx index 72c1fa8f5161..e3ae0de1cdde 100644 --- a/src/components/flex/flex_group.tsx +++ b/src/components/flex/flex_group.tsx @@ -27,7 +27,9 @@ export type FlexGroupDirection = keyof typeof directionToClassNameMap; export type FlexGroupGutterSize = keyof typeof gutterSizeToClassNameMap; export type FlexGroupJustifyContent = keyof typeof justifyContentToClassNameMap; -export interface EuiFlexGroupProps { +export interface EuiFlexGroupProps + extends CommonProps, + HTMLAttributes { alignItems?: FlexGroupAlignItems; component?: FlexGroupComponentType; direction?: FlexGroupDirection; @@ -87,9 +89,7 @@ const isValidElement = ( export const EuiFlexGroup = forwardRef< HTMLDivElement | HTMLSpanElement, - CommonProps & - HTMLAttributes & - EuiFlexGroupProps + EuiFlexGroupProps >( ( { diff --git a/src/components/flex/index.ts b/src/components/flex/index.ts index 5ea60b7ceaa8..f9804e43cb5f 100644 --- a/src/components/flex/index.ts +++ b/src/components/flex/index.ts @@ -17,7 +17,11 @@ * under the License. */ -export { EuiFlexGroup, EuiFlexGroupGutterSize } from './flex_group'; +export { + EuiFlexGroup, + EuiFlexGroupProps, + EuiFlexGroupGutterSize, +} from './flex_group'; export { EuiFlexGrid } from './flex_grid'; diff --git a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap index 3f11d6db6ca5..a30fad4cb450 100644 --- a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap @@ -233,7 +233,9 @@ exports[`EuiPageHeader props page content props are passed down is rendered 1`] class="euiFlexItem euiFlexItem--flexGrowZero" >
    `; -exports[`EuiPageHeaderContent props rightSideItems is rendered with rightSideResponsive as true 1`] = ` +exports[`EuiPageHeaderContent props rightSideItems is rendered with rightSideGroupProps 1`] = `
    @@ -482,7 +482,9 @@ exports[`EuiPageHeaderContent props rightSideItems is rendered with rightSideRes class="euiFlexItem euiFlexItem--flexGrowZero" >
    { tabsProps={requiredProps} description="Description" rightSideItems={rightSideItems} - rightSideResponsive={true}> + rightSideGroupProps={{ responsive: true, ...requiredProps }}>

    Anything

    ); diff --git a/src/components/page/page_header/page_header.tsx b/src/components/page/page_header/page_header.tsx index f424ad7f7311..8df58ceff1c2 100644 --- a/src/components/page/page_header/page_header.tsx +++ b/src/components/page/page_header/page_header.tsx @@ -56,7 +56,7 @@ export const EuiPageHeader: FunctionComponent = ({ tabsProps, description, rightSideItems, - rightSideResponsive, + rightSideGroupProps, ...rest }) => { let widthClassname; @@ -101,7 +101,7 @@ export const EuiPageHeader: FunctionComponent = ({ tabsProps={tabsProps} description={description} rightSideItems={rightSideItems} - rightSideResponsive={rightSideResponsive}> + rightSideGroupProps={rightSideGroupProps}> {children}
    diff --git a/src/components/page/page_header/page_header_content.test.tsx b/src/components/page/page_header/page_header_content.test.tsx index 92ba2224017b..d704dd2af063 100644 --- a/src/components/page/page_header/page_header_content.test.tsx +++ b/src/components/page/page_header/page_header_content.test.tsx @@ -127,11 +127,11 @@ describe('EuiPageHeaderContent', () => { expect(component).toMatchSnapshot(); }); - test('is rendered with rightSideResponsive as true', () => { + test('is rendered with rightSideGroupProps', () => { const component = render( ); diff --git a/src/components/page/page_header/page_header_content.tsx b/src/components/page/page_header/page_header_content.tsx index 293232130580..65caa5ab87b6 100644 --- a/src/components/page/page_header/page_header_content.tsx +++ b/src/components/page/page_header/page_header_content.tsx @@ -22,12 +22,12 @@ import classNames from 'classnames'; import { CommonProps } from '../../common'; import { EuiIcon, EuiIconProps, IconType } from '../../icon'; import { EuiTab, EuiTabs, EuiTabsProps } from '../../tabs'; -import { EuiFlexGroup, EuiFlexItem } from '../../flex'; +import { Props as EuiTabProps } from '../../tabs/tab'; +import { EuiFlexGroup, EuiFlexItem, EuiFlexGroupProps } from '../../flex'; import { EuiSpacer } from '../../spacer'; import { EuiTitle } from '../../title'; import { EuiText } from '../../text'; import { useIsWithinBreakpoints } from '../../../services/hooks'; -import { Props as EuiTabProps } from '../../../components/tabs/tab'; export const ALIGN_ITEMS = ['top', 'bottom', 'center', 'stretch'] as const; @@ -91,6 +91,11 @@ export type EuiPageHeaderContentProps = CommonProps & * Set to `reverse` to display the right side content first for the sack of hierarchy (like global time) */ responsive?: boolean | 'reverse'; + /** + * Vertical alignment of the left and right side content; + * Default is `middle` for custom content, but `top` for when `pageTitle` or `tabs` are included + */ + alignItems?: typeof ALIGN_ITEMS[number]; /** * Pass custom an array of content to this side usually up to 3 buttons. * The first button should be primary, usually with `fill` and will be visually displayed as the last item, @@ -98,14 +103,9 @@ export type EuiPageHeaderContentProps = CommonProps & */ rightSideItems?: ReactNode[]; /** - * Vertical alignment of the left and right side content; - * Default is `middle` for custom content, but `top` for when `pageTitle` or `tabs` are included - */ - alignItems?: typeof ALIGN_ITEMS[number]; - /** - * Whether the array of right side items should all break to their own line on small screens + * Additional EuiFlexGroup props to pass to the container of the `rightSideItems` */ - rightSideResponsive?: boolean; + rightSideGroupProps?: Partial; /** * Custom children will be rendered before the `tabs` unless no `pageTitle` is present, then it will be the last item */ @@ -120,10 +120,10 @@ export const EuiPageHeaderContent: FunctionComponent tabs, tabsProps, description, - rightSideItems, alignItems = 'top', responsive = true, - rightSideResponsive = false, + rightSideItems, + rightSideGroupProps, children, ...rest }) => { @@ -246,9 +246,13 @@ export const EuiPageHeaderContent: FunctionComponent rightSideFlexItem = ( + responsive={false} + {...rightSideGroupProps} + className={classNames( + 'euiPageHeaderContent__rightSideItems', + rightSideGroupProps?.className + )}> {wrapWithFlex()} From 7d557fcf5b0d1d6d31f18dbe27b1fb5415ab1a81 Mon Sep 17 00:00:00 2001 From: Caroline Horn <549577+cchaos@users.noreply.github.com> Date: Wed, 10 Feb 2021 13:14:28 -0500 Subject: [PATCH 26/27] Apply suggestions from code review Co-authored-by: Greg Thompson --- src/components/page/page_header/page_header_content.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/page/page_header/page_header_content.tsx b/src/components/page/page_header/page_header_content.tsx index 65caa5ab87b6..a82df74d0bf6 100644 --- a/src/components/page/page_header/page_header_content.tsx +++ b/src/components/page/page_header/page_header_content.tsx @@ -52,7 +52,7 @@ export type EuiPageHeaderContentTitle = { /** * Additional EuiIcon props to apply to the optional icon */ - iconProps?: Partial; + iconProps?: Partial>; }; export type EuiPageHeaderContentTabs = { From e97d3b8318b70558ec8622c34957dde6907626a0 Mon Sep 17 00:00:00 2001 From: cchaos Date: Wed, 10 Feb 2021 13:40:39 -0500 Subject: [PATCH 27/27] Set deprecation notice for `panelPaddingSize` --- src/components/page/page_content/page_content.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/page/page_content/page_content.tsx b/src/components/page/page_content/page_content.tsx index cefc78a27537..9169f6fc65b4 100644 --- a/src/components/page/page_content/page_content.tsx +++ b/src/components/page/page_content/page_content.tsx @@ -40,6 +40,9 @@ const horizontalPositionToClassNameMap: { export type EuiPageContentProps = CommonProps & EuiPanelProps & { + /** + * **DEPRECATED: use `paddingSize` instead.** + */ panelPaddingSize?: PanelPaddingSize; verticalPosition?: EuiPageContentVerticalPositions; horizontalPosition?: EuiPageContentHorizontalPositions;