From c134b585e3998050c595a76911c174e73a02cd58 Mon Sep 17 00:00:00 2001 From: Caroline Horn <549577+cchaos@users.noreply.github.com> Date: Thu, 4 Jun 2020 10:42:23 -0400 Subject: [PATCH] [EuiHeader] Stacked example (#3538) * Added stacked header example **Break**: EuiHeader now requires consumer to use mixin to apply padding to account for fixed position * Adding header updates to test flyouts * Fix styles for dark theme - Darker in actual dark theme * Fix addition/removal of body classes when there are mulitple fixed headers * Fixing shadows on flyouts. * Change Fixed Header example and fixed separation of flyout and header --- CHANGELOG.md | 8 +- src-docs/src/components/guide_components.scss | 44 ++++++--- src-docs/src/views/header/header_example.js | 56 ++++++++++-- src-docs/src/views/header/header_position.js | 35 +++----- src-docs/src/views/header/header_sections.js | 3 + src-docs/src/views/header/header_stacked.tsx | 90 +++++++++++++++++++ src-docs/src/views/header/header_updates.js | 7 +- src/components/flyout/_mixins.scss | 6 -- src/components/header/_header.scss | 16 ++-- src/components/header/_mixins.scss | 14 +-- src/components/header/_variables.scss | 1 + src/components/header/header.tsx | 16 +++- .../_header_breadcrumbs.scss | 13 +-- src/global_styling/mixins/_header.scss | 14 +++ src/global_styling/mixins/_index.scss | 1 + src/global_styling/variables/_index.scss | 2 +- .../global_styling/variables/_header.scss | 6 ++ .../eui-amsterdam/overrides/_flyout.scss | 5 ++ .../eui-amsterdam/overrides/_header.scss | 9 +- .../eui-amsterdam/overrides/_index.scss | 1 + 20 files changed, 262 insertions(+), 85 deletions(-) create mode 100644 src-docs/src/views/header/header_stacked.tsx create mode 100644 src/global_styling/mixins/_header.scss create mode 100644 src/themes/eui-amsterdam/overrides/_flyout.scss diff --git a/CHANGELOG.md b/CHANGELOG.md index a4e1d288e28..e3d7e33c073 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,14 @@ ## [`master`](https://github.com/elastic/eui/tree/master) +**Bug fixes** + +- Fixed `EuiKeyPadMenu` and `EuiKeyPadMenuItem` aria roles ([#3502](https://github.com/elastic/eui/pull/3502)) + **Breaking changes** + +- A fixed `EuiHeader` no longer automatically padding directly to the `` element ([#3538](https://github.com/elastic/eui/pull/3538)) - Improved `EuiPagination`, `EuiDataGrid`, `EuiBasicTable` and `EuiInMemoryTable` accessibility, causing `EuiPaginationButton` to require a new prop `pageIndex` ([#3294](https://github.com/elastic/eui/pull/3294)) -**Bug fixes** -- Fixed `EuiKeyPadMenu` and `EuiKeyPadMenuItem` aria roles ([#3502](https://github.com/elastic/eui/pull/3502)) ## [`24.1.0`](https://github.com/elastic/eui/tree/v24.1.0) diff --git a/src-docs/src/components/guide_components.scss b/src-docs/src/components/guide_components.scss index 7dd4e1973be..ddcd3add658 100644 --- a/src-docs/src/components/guide_components.scss +++ b/src-docs/src/components/guide_components.scss @@ -11,6 +11,22 @@ $guideZLevelHighest: $euiZLevel9 + 1000; } } +@include euiHeaderAffordForFixed; + +.euiBody--headerIsFixed { + .guideSideNav { + top: $euiHeaderHeightCompensation; + } +} + +.euiBody--headerIsFixed--double { + @include euiHeaderAffordForFixed($euiHeaderHeightCompensation * 2); + + .guideSideNav { + top: $euiHeaderHeightCompensation * 2; + } +} + .guidePage { padding: 0; } @@ -215,6 +231,19 @@ $guideZLevelHighest: $euiZLevel9 + 1000; top: 0; } +.euiDataGridRowCell--favoriteFranchise { + background: transparentize($color: #800080, $amount: .95) !important; +} + +.euiDataGridHeaderCell--favoriteFranchise { + background: transparentize($color: #800080, $amount: .9) !important; +} + +.euiTreeView__nodeInnerExample { + color: $euiColorDanger; + font-weight: $euiFontWeightBold; +} + @import '../views/guidelines/index'; @import 'guide_section/index'; @import 'guide_rule/index'; @@ -229,7 +258,7 @@ $guideZLevelHighest: $euiZLevel9 + 1000; } .guideSideNav { - position: relative; + position: static; width: auto; // This is a temporary hack till we fix how classes pass into form controls @@ -263,16 +292,3 @@ $guideZLevelHighest: $euiZLevel9 + 1000; width: 100%; } } - -.euiDataGridRowCell--favoriteFranchise { - background: transparentize($color: #800080, $amount: .95) !important; -} - -.euiDataGridHeaderCell--favoriteFranchise { - background: transparentize($color: #800080, $amount: .9) !important; -} - -.euiTreeView__nodeInnerExample { - color: $euiColorDanger; - font-weight: $euiFontWeightBold; -} diff --git a/src-docs/src/views/header/header_example.js b/src-docs/src/views/header/header_example.js index bee59ed714e..271c8e04c5b 100644 --- a/src-docs/src/views/header/header_example.js +++ b/src-docs/src/views/header/header_example.js @@ -45,6 +45,10 @@ import HeaderDark from './header_dark'; const headerDarkSource = require('!!raw-loader!./header_dark'); const headerDarkHtml = renderToHtml(HeaderDark); +import HeaderStacked from './header_stacked'; +const headerStackedSource = require('!!raw-loader!./header_stacked'); +const headerStackedHtml = renderToHtml(HeaderStacked); + const headerSnippet = ` @@ -184,15 +188,26 @@ export const HeaderExample = { text: ( <>

- Most consumer need a header that does not scroll way with the page - contents. You can apply this display by changing{' '} - position to fixed. It will - also add the appropriate padding to the window body by applying a - class. + Most consumers need a header that does not scroll away with the page + contents. You can apply this display by applying the property{' '} + {'position="fixed"'}. This will + also add a class of .euiBody--headerIsFixed to + the window body. +

+

+ You will then need to apply your own padding to this body class to + afford for the header height. EUI supplies a helper mixin that also + accounts for this height in flyouts and the collapsible nav. Simply + add{' '} + @mixin euiHeaderAffordForFixed;{' '} + anywhere in your SASS.

), - snippet: '', + snippet: [ + '', + '@mixin euiHeaderAffordForFixed;', + ], demo: , }, { @@ -282,5 +297,34 @@ export const HeaderExample = { snippet: headerLinksSnippet, demo: , }, + { + title: 'Stacked headers', + source: [ + { + type: GuideSectionTypes.JS, + code: headerStackedSource, + }, + { + type: GuideSectionTypes.HTML, + code: headerStackedHtml, + }, + ], + text: ( +

+ Stacking multiple headers provide a great way to separate global + navigation concerns. However, the{' '} + {'position="fixed"'} option will not + be aware of the number of headers. Therefore, if you do need fixed and + stacked headers, you will need to apply the helper mixin and pass in + the correct height to afford for. +

+ ), + snippet: [ + ` +`, + '@include euiHeaderAffordForFixed($euiHeaderHeightCompensation * 2);', + ], + demo: , + }, ], }; diff --git a/src-docs/src/views/header/header_position.js b/src-docs/src/views/header/header_position.js index 591658d7058..12ae9828b6d 100644 --- a/src-docs/src/views/header/header_position.js +++ b/src-docs/src/views/header/header_position.js @@ -4,6 +4,7 @@ import { EuiHeader, EuiHeaderLogo, EuiSwitch, + EuiSpacer, } from '../../../../src/components'; export default () => { @@ -11,28 +12,20 @@ export default () => { const sections = [ { - items: [ - , - ], - borders: 'none', - }, - { - items: [ -
- setPosition(e.target.checked ? 'fixed' : 'static')} - /> -
, - ], - borders: 'none', + items: [Kibana], + borders: 'right', }, ]; - return ; + return ( + <> + setPosition(e.target.checked ? 'fixed' : 'static')} + /> + + + + ); }; diff --git a/src-docs/src/views/header/header_sections.js b/src-docs/src/views/header/header_sections.js index 63a048d1dd3..caba40b6fb2 100644 --- a/src-docs/src/views/header/header_sections.js +++ b/src-docs/src/views/header/header_sections.js @@ -72,6 +72,9 @@ export default () => { items: [renderLogo, ], borders: 'right', breadcrumbs: breadcrumbs, + breadcrumbProps: { + 'aria-label': 'Header sections breadcrumbs', + }, }, { items: [renderSearch,
], diff --git a/src-docs/src/views/header/header_stacked.tsx b/src-docs/src/views/header/header_stacked.tsx new file mode 100644 index 00000000000..468352e8c1c --- /dev/null +++ b/src-docs/src/views/header/header_stacked.tsx @@ -0,0 +1,90 @@ +import React, { useState, useEffect } from 'react'; + +import { + EuiHeader, + EuiHeaderLogo, + EuiHeaderSectionItemButton, +} from '../../../../src/components/header'; +import { EuiSwitch } from '../../../../src/components/form'; +import { EuiSpacer } from '../../../../src/components/spacer'; +import { EuiAvatar } from '../../../../src/components/avatar'; +// @ts-ignore +import HeaderUpdates from './header_updates'; + +export default () => { + const [isFixed, setIsFixed] = useState(false); + + const breadcrumbs = [ + { + text: 'Management', + href: '#', + }, + { + text: 'Users', + }, + ]; + + /** + * Docs Note: This additional class is needed only for docs to override the usually single header + */ + useEffect(() => { + if (isFixed) document.body.classList.add('euiBody--headerIsFixed--double'); + + return () => { + document.body.classList.remove('euiBody--headerIsFixed--double'); + }; + }, [isFixed]); + + const headers = ( + <> + Elastic, + ], + borders: 'right', + }, + { + items: [ + + + , + ], + }, + ]} + /> + + + , + ], + breadcrumbs: breadcrumbs, + borders: 'none', + }, + { + items: isFixed ? [] : undefined, + }, + ]} + /> + + ); + + return ( + <> + setIsFixed(e.target.checked)} + /> + + {headers} + + ); +}; diff --git a/src-docs/src/views/header/header_updates.js b/src-docs/src/views/header/header_updates.js index 2becb81e0cc..474a1efa69d 100644 --- a/src-docs/src/views/header/header_updates.js +++ b/src-docs/src/views/header/header_updates.js @@ -121,18 +121,13 @@ export default () => { ); let flyout; - const flyoutStyle = { - top: '49px', - height: 'calc(100vh - 49px)', - }; if (isFlyoutVisible) { flyout = ( closeFlyout()} size="s" id="headerNewsFeed" - aria-labelledby="flyoutSmallTitle" - style={flyoutStyle}> + aria-labelledby="flyoutSmallTitle">

What's new

diff --git a/src/components/flyout/_mixins.scss b/src/components/flyout/_mixins.scss index bd6133ea5c0..cc482a47ae4 100644 --- a/src/components/flyout/_mixins.scss +++ b/src/components/flyout/_mixins.scss @@ -15,10 +15,4 @@ display: flex; flex-direction: column; align-items: stretch; - - // When the EuiHeader is fixed, we need to account for it in the position of the flyout - .euiBody--headerIsFixed & { - top: $euiHeaderHeightCompensation; - height: calc(100% - #{$euiHeaderHeightCompensation}); - } } diff --git a/src/components/header/_header.scss b/src/components/header/_header.scss index c10f16bd14f..948e76fe187 100644 --- a/src/components/header/_header.scss +++ b/src/components/header/_header.scss @@ -9,7 +9,7 @@ display: flex; justify-content: space-between; background: $euiHeaderBackgroundColor; - border-bottom: $euiBorderThin; + border-bottom: 1px solid $euiHeaderBorderColor; &--fixed { position: fixed; @@ -19,10 +19,6 @@ } } -.euiBody--headerIsFixed { - padding-top: $euiHeaderHeightCompensation; -} - .euiBody--collapsibleNavIsOpen, .euiBody--hasFlyout { .euiHeader--fixed { @@ -30,9 +26,15 @@ } } +.euiHeader--fixed + .euiHeader--fixed { + top: $euiHeaderHeightCompensation; +} + .euiHeader--dark { - // Only force reverse theme if the theme is light @if (lightness($euiTextColor) < 50) { - @include euiHeaderDarkTheme; + @include euiHeaderDarkTheme($backgroundColor: shade($euiColorDarkestShade, 28%)); + } @else { + // Makes forced "dark" theme darker than the typical dark them to separate them visually + @include euiHeaderDarkTheme($backgroundColor: shade($euiColorLightestShade, 50%)); } } diff --git a/src/components/header/_mixins.scss b/src/components/header/_mixins.scss index f22c6ffad73..54ee4c66a09 100644 --- a/src/components/header/_mixins.scss +++ b/src/components/header/_mixins.scss @@ -1,6 +1,6 @@ -@mixin euiHeaderDarkTheme { - $headerBackgroundColor: shade($euiColorDarkestShade, 28%); - background-color: $headerBackgroundColor; +@mixin euiHeaderDarkTheme($backgroundColor) { + background-color: $backgroundColor; + border-bottom-color: lightOrDarkTheme($backgroundColor, $euiHeaderBorderColor); .euiHeaderLogo__text, .euiHeaderLink, @@ -9,12 +9,12 @@ } .euiHeaderLink-isActive { - color: makeHighContrastColor($euiColorPrimary, $headerBackgroundColor); + color: makeHighContrastColor($euiColorPrimary, $backgroundColor); } .euiHeaderSectionItem { &:after { - background: $euiColorDarkShade; + background: lightOrDarkTheme($euiColorDarkShade, $euiColorLightestShade); } } @@ -22,7 +22,7 @@ .euiHeaderLink, .euiHeaderSectionItem__button { &:hover { - background: transparentize($euiColorDarkShade, .5); + background: transparentize(lightOrDarkTheme($euiColorDarkShade, $euiColorLightestShade), .5); } &:focus { @@ -32,6 +32,6 @@ .euiHeaderNotification, .euiHeaderSectionItemButton__notification { - box-shadow: 0 0 0 1px $headerBackgroundColor; + box-shadow: 0 0 0 1px $backgroundColor; } } diff --git a/src/components/header/_variables.scss b/src/components/header/_variables.scss index 9d86cc31981..1e9c763d3ad 100644 --- a/src/components/header/_variables.scss +++ b/src/components/header/_variables.scss @@ -1,6 +1,7 @@ // Note - these are also used by the EuiNavDrawer (/nav_drawer) component // Themable colors $euiHeaderBackgroundColor: $euiColorEmptyShade !default; +$euiHeaderBorderColor: $euiBorderColor !default; $euiHeaderBreadcrumbColor: $euiColorDarkestShade !default; // Layout vars diff --git a/src/components/header/header.tsx b/src/components/header/header.tsx index 5ea43095bbc..9835250ef25 100644 --- a/src/components/header/header.tsx +++ b/src/components/header/header.tsx @@ -86,6 +86,9 @@ export type EuiHeaderProps = CommonProps & theme?: 'default' | 'dark'; }; +// Start a counter to manage the total number of fixed headers that need the body class +let euiHeaderFixedCounter = 0; + export const EuiHeader: FunctionComponent = ({ children, className, @@ -103,11 +106,18 @@ export const EuiHeader: FunctionComponent = ({ useEffect(() => { if (position === 'fixed') { + // Increment fixed header counter for each fixed header + euiHeaderFixedCounter++; document.body.classList.add('euiBody--headerIsFixed'); + + return () => { + // Both decrement the fixed counter AND then check if there are none + if (--euiHeaderFixedCounter === 0) { + // If there are none, THEN remove class + document.body.classList.remove('euiBody--headerIsFixed'); + } + }; } - return () => { - document.body.classList.remove('euiBody--headerIsFixed'); - }; }, [position]); let contents; diff --git a/src/components/header/header_breadcrumbs/_header_breadcrumbs.scss b/src/components/header/header_breadcrumbs/_header_breadcrumbs.scss index ba74f7475ed..bc953be7168 100644 --- a/src/components/header/header_breadcrumbs/_header_breadcrumbs.scss +++ b/src/components/header/header_breadcrumbs/_header_breadcrumbs.scss @@ -1,18 +1,9 @@ // Breadcrumb navigation included in the header. -@import '../../link/mixins'; - .euiHeaderBreadcrumbs { - margin-left: $euiSize; - margin-right: $euiSize; + margin-left: $euiSizeS; + margin-right: $euiSizeS; display: flex; align-items: center; flex-grow: 1; } - -@include euiBreakpoint('xs') { - .euiHeaderBreadcrumbs { - margin-left: $euiSizeS; - margin-right: $euiSizeS; - } -} diff --git a/src/global_styling/mixins/_header.scss b/src/global_styling/mixins/_header.scss new file mode 100644 index 00000000000..d0cf770ad3a --- /dev/null +++ b/src/global_styling/mixins/_header.scss @@ -0,0 +1,14 @@ +@mixin euiHeaderAffordForFixed($headerHeight: $euiHeaderHeightCompensation) { + // The `&` allows for grouping inside another specific body class. + // When not applied inside of another selector, it simply renders with the single class + &.euiBody--headerIsFixed { + padding-top: $headerHeight; + + // When the EuiHeader is fixed, we need to account for it in the position of the flyout + .euiFlyout, + .euiCollapsibleNav { + top: $headerHeight; + height: calc(100% - #{$headerHeight}); + } + } +} diff --git a/src/global_styling/mixins/_index.scss b/src/global_styling/mixins/_index.scss index 9e464623b06..bec84abc99f 100644 --- a/src/global_styling/mixins/_index.scss +++ b/src/global_styling/mixins/_index.scss @@ -9,6 +9,7 @@ @import 'beta_badge'; @import 'button'; @import 'form'; +@import 'header'; @import 'loading'; @import 'panel'; @import 'popover'; diff --git a/src/global_styling/variables/_index.scss b/src/global_styling/variables/_index.scss index 2e3a6a64fdc..46c7f8407af 100644 --- a/src/global_styling/variables/_index.scss +++ b/src/global_styling/variables/_index.scss @@ -6,7 +6,7 @@ // coming from when looking inside the individual component files. Any component local // variables should be declared at the top of those documents prefixed with $componentName. -// Import order is important. Size and color..etc are used in other variables. +// Import order is important. Size, color, ...etc are used in other variables. @import 'size'; @import 'colors'; @import 'animations'; diff --git a/src/themes/eui-amsterdam/global_styling/variables/_header.scss b/src/themes/eui-amsterdam/global_styling/variables/_header.scss index 98cbd7f19ac..c823edcea56 100644 --- a/src/themes/eui-amsterdam/global_styling/variables/_header.scss +++ b/src/themes/eui-amsterdam/global_styling/variables/_header.scss @@ -1 +1,7 @@ +// Curated border color to fade into the shadow without looking too much like a border +// It adds separation between the header and flyout +$euiHeaderBorderColor: lightOrDarkTheme(shade($euiBorderColor, 3%), shade($euiColorEmptyShade, 35%)); + +$euiHeaderHeight: $euiSizeXXL + $euiSizeS; $euiHeaderChildSize: $euiSizeXXL; +$euiHeaderHeightCompensation: $euiHeaderHeight; diff --git a/src/themes/eui-amsterdam/overrides/_flyout.scss b/src/themes/eui-amsterdam/overrides/_flyout.scss new file mode 100644 index 00000000000..6e78d2fe0ce --- /dev/null +++ b/src/themes/eui-amsterdam/overrides/_flyout.scss @@ -0,0 +1,5 @@ +// Amsterdam shadows extend upwards as well, but this means flyouts shadows can overlap fixed headers. +// The clip path ensures only the left side of the shadow is exposed. +.euiFlyout { + clip-path: polygon(-10% 0, 100% 0, 100% 100%, -10% 100%); +} diff --git a/src/themes/eui-amsterdam/overrides/_header.scss b/src/themes/eui-amsterdam/overrides/_header.scss index e42ef6b9a44..de2bc6c2b4a 100644 --- a/src/themes/eui-amsterdam/overrides/_header.scss +++ b/src/themes/eui-amsterdam/overrides/_header.scss @@ -1,6 +1,5 @@ .euiHeader { height: $euiHeaderHeight; - border-bottom: none; padding-left: $euiSizeS; padding-right: $euiSizeS; } @@ -11,6 +10,10 @@ } .euiHeaderLogo { + @include euiBreakpoint('xs') { + padding: 0 $euiSizeXS; + } + padding-left: $euiSizeS; padding-right: $euiSizeS; min-width: $euiHeaderChildSize; @@ -23,3 +26,7 @@ .euiHeaderBreadcrumbs { margin-left: $euiSizeS; } + +.euiHeader--default + .euiHeader--default { + border-top: $euiBorderThin; +} diff --git a/src/themes/eui-amsterdam/overrides/_index.scss b/src/themes/eui-amsterdam/overrides/_index.scss index fed4c2dba43..3b7b0823c90 100644 --- a/src/themes/eui-amsterdam/overrides/_index.scss +++ b/src/themes/eui-amsterdam/overrides/_index.scss @@ -1,6 +1,7 @@ @import 'button'; @import 'button_empty'; @import 'button_group'; +@import 'flyout'; @import 'header'; @import 'image'; @import 'modal';