diff --git a/src-docs/src/routes.js b/src-docs/src/routes.js index 2e97b630318..fae0e6f7833 100644 --- a/src-docs/src/routes.js +++ b/src-docs/src/routes.js @@ -171,6 +171,9 @@ import { ModalExample } import { MutationObserverExample } from './views/mutation_observer/mutation_observer_example'; +import { NavDrawerExample } + from './views/nav_drawer/nav_drawer_example'; + import { OutsideClickDetectorExample } from './views/outside_click_detector/outside_click_detector_example'; @@ -335,6 +338,7 @@ const navigation = [{ HeaderExample, HorizontalRuleExample, ModalExample, + NavDrawerExample, PageExample, PanelExample, PopoverExample, diff --git a/src-docs/src/views/nav_drawer/nav_drawer.js b/src-docs/src/views/nav_drawer/nav_drawer.js new file mode 100644 index 00000000000..bb475b74512 --- /dev/null +++ b/src-docs/src/views/nav_drawer/nav_drawer.js @@ -0,0 +1,669 @@ +import React, { Component, Fragment } from 'react'; + +import { + EuiPage, + EuiPageBody, + EuiPageHeader, + EuiPageHeaderSection, + EuiPageContent, + EuiPageContentHeader, + EuiPageContentHeaderSection, + EuiPageContentBody, + EuiHeader, + EuiHeaderSection, + EuiHeaderSectionItem, + EuiHeaderSectionItemButton, + EuiHeaderBreadcrumbs, + EuiIcon, + EuiTitle, + EuiNavDrawer, + EuiNavDrawerMenu, + EuiNavDrawerFlyout, + EuiListGroup, + EuiHorizontalRule, + EuiShowFor, + EuiHideFor, + EuiOutsideClickDetector, +} from '../../../../src/components'; + +import HeaderUserMenu from '../header/header_user_menu'; +import HeaderSpacesMenu from '../header/header_spaces_menu'; + +export default class extends Component { + constructor(props) { + super(props); + + this.state = { + isCollapsed: true, + flyoutIsCollapsed: true, + flyoutIsAnimating: false, + navFlyoutTitle: undefined, + navFlyoutContent: [], + mobileIsHidden: true, + showScrollbar: false, + outsideClickDisaled: true, + isManagingFocus: false, + }; + + this.topLinks = [ + { + label: 'Recently viewed', + iconType: 'clock', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Recently viewed items', + onClick: () => this.expandFlyout(this.recentLinks, 'Recent items'), + extraAction: { + color: 'subdued', + iconType: 'arrowRight', + iconSize: 's', + 'aria-label': 'Expand to view recent apps and objects', + onClick: () => this.expandFlyout(this.recentLinks, 'Recent items'), + alwaysShow: true, + }, + }, + { + label: 'Favorites', + iconType: 'starEmpty', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Favorited items', + onClick: () => this.expandFlyout(this.favoriteLinks, 'Favorite items'), + extraAction: { + color: 'subdued', + iconType: 'arrowRight', + iconSize: 's', + 'aria-label': 'Expand to view favorited apps and objects', + onClick: () => this.expandFlyout(this.favoriteLinks, 'Favorite items'), + alwaysShow: true, + }, + }, + ]; + + this.exploreLinks = [ + { + label: 'Canvas', + href: '/#/layout/nav-drawer', + iconType: 'canvasApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Canvas', + isActive: true, + extraAction: { + color: 'subdued', + iconType: 'pinFilled', + iconSize: 's', + 'aria-label': 'Pin to top', + alwaysShow: true, + }, + }, + { + label: 'Discover', + href: '/#/layout/nav-drawer', + iconType: 'discoverApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Discover', + extraAction: { + color: 'subdued', + iconType: 'pin', + iconSize: 's', + 'aria-label': 'Pin to top', + }, + }, + { + label: 'Visualize', + href: '/#/layout/nav-drawer', + iconType: 'visualizeApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Visualize', + extraAction: { + color: 'subdued', + iconType: 'pin', + iconSize: 's', + 'aria-label': 'Pin to top', + }, + }, + { + label: 'Dashboard', + href: '/#/layout/nav-drawer', + iconType: 'dashboardApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Dashboard', + extraAction: { + color: 'subdued', + iconType: 'pin', + iconSize: 's', + 'aria-label': 'Pin to top', + }, + }, + { + label: 'Machine learning', + href: '/#/layout/nav-drawer', + iconType: 'machineLearningApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Machine learning', + extraAction: { + color: 'subdued', + iconType: 'pin', + iconSize: 's', + 'aria-label': 'Pin to top', + }, + }, + { + label: 'Graph', + href: '/#/layout/nav-drawer', + iconType: 'graphApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Graph', + extraAction: { + color: 'subdued', + iconType: 'pin', + iconSize: 's', + 'aria-label': 'Pin to top', + }, + } + ]; + + this.solutionsLinks = [ + { + label: 'APM', + href: '/#/layout/nav-drawer', + iconType: 'apmApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'APM', + extraAction: { + color: 'subdued', + iconType: 'pin', + iconSize: 's', + 'aria-label': 'Pin to top', + }, + }, + { + label: 'Infrastructure', + href: '/#/layout/nav-drawer', + iconType: 'infraApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Infra', + extraAction: { + color: 'subdued', + iconType: 'pin', + iconSize: 's', + 'aria-label': 'Pin to top', + }, + }, + { + label: 'Log viewer', + href: '/#/layout/nav-drawer', + iconType: 'loggingApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Logs', + extraAction: { + color: 'subdued', + iconType: 'pin', + iconSize: 's', + 'aria-label': 'Pin to top', + }, + }, + { + label: 'Uptime', + href: '/#/layout/nav-drawer', + iconType: 'upgradeAssistantApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Graph', + extraAction: { + color: 'subdued', + iconType: 'pin', + iconSize: 's', + 'aria-label': 'Pin to top', + }, + }, + { + label: 'Maps', + href: '/#/layout/nav-drawer', + iconType: 'gisApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Maps', + extraAction: { + color: 'subdued', + iconType: 'pin', + iconSize: 's', + 'aria-label': 'Pin to top', + }, + }, + { + label: 'SIEM', + href: '/#/layout/nav-drawer', + iconType: 'securityAnalyticsApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'SIEM', + extraAction: { + color: 'subdued', + iconType: 'pin', + iconSize: 's', + 'aria-label': 'Pin to top', + }, + } + ]; + + this.adminLinks = [ + { + label: 'Admin', + iconType: 'managementApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Admin', + onClick: () => this.expandFlyout(this.adminSubLinks, 'Tools and settings'), + extraAction: { + color: 'subdued', + iconType: 'arrowRight', + iconSize: 's', + 'aria-label': 'Pin to top', + alwaysShow: true, + onClick: () => this.expandFlyout(this.adminSubLinks, 'Tools and settings'), + }, + }, + ]; + + this.adminSubLinks = [ + { + label: 'Dev tools', + href: '/#/layout/nav-drawer', + iconType: 'devToolsApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Dev tools', + extraAction: { + color: 'subdued', + iconType: 'starEmpty', + iconSize: 's', + 'aria-label': 'Add to favorites', + }, + }, + { + label: 'Stack Monitoring', + href: '/#/layout/nav-drawer', + iconType: 'monitoringApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Monitoring', + extraAction: { + color: 'subdued', + iconType: 'starEmpty', + iconSize: 's', + 'aria-label': 'Add to favorites', + }, + }, + { + label: 'Stack Management', + href: '/#/layout/nav-drawer', + iconType: 'managementApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'Management', + extraAction: { + color: 'subdued', + iconType: 'starEmpty', + iconSize: 's', + 'aria-label': 'Add to favorites', + }, + }, + ]; + + this.recentLinks = [ + { + label: 'My dashboard', + href: '/#/layout/nav-drawer', + iconType: 'dashboardApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'My dashboard', + extraAction: { + color: 'subdued', + iconType: 'starEmpty', + iconSize: 's', + 'aria-label': 'Add to favorites', + }, + }, + { + label: 'My workpad', + href: '/#/layout/nav-drawer', + iconType: 'canvasApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'My workpad', + extraAction: { + color: 'subdued', + iconType: 'starEmpty', + iconSize: 's', + 'aria-label': 'Add to favorites', + }, + }, + { + label: 'My logs', + href: '/#/layout/nav-drawer', + iconType: 'loggingApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'My logs', + extraAction: { + color: 'subdued', + iconType: 'starEmpty', + iconSize: 's', + 'aria-label': 'Add to favorites', + }, + }, + ]; + + this.favoriteLinks = [ + { + label: 'My workpad', + href: '/#/layout/nav-drawer', + iconType: 'canvasApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'My workpad', + extraAction: { + color: 'subdued', + iconType: 'starFilled', + iconSize: 's', + 'aria-label': 'Add to favorites', + alwaysShow: true, + }, + }, + { + label: 'My logs', + href: '/#/layout/nav-drawer', + iconType: 'loggingApp', + size: 's', + style: { color: 'inherit' }, + 'aria-label': 'My logs', + extraAction: { + color: 'subdued', + iconType: 'starFilled', + iconSize: 's', + 'aria-label': 'Add to favorites', + alwaysShow: true, + }, + }, + ]; + } + + renderLogo() { + return ( + + + + ); + } + + renderMenuTrigger() { + return ( + + + + ); + } + + renderBreadcrumbs() { + const breadcrumbs = [ + { + text: 'Management', + href: '#', + onClick: e => { + e.preventDefault(); + console.log('You clicked management'); + }, + 'data-test-subj': 'breadcrumbsAnimals', + className: 'customClass' + }, + { + text: 'Truncation test is here for a really long item', + href: '#', + onClick: e => { + e.preventDefault(); + console.log('You clicked truncation test'); + } + }, + { + text: 'hidden', + href: '#', + onClick: e => { + e.preventDefault(); + console.log('You clicked hidden'); + } + }, + { + text: 'Users', + href: '#', + onClick: e => { + e.preventDefault(); + console.log('You clicked users'); + } + }, + { + text: 'Create' + } + ]; + + return ( + + ); + } + + timeoutID; + + toggleOpen = () => { + this.setState({ + mobileIsHidden: !this.state.mobileIsHidden + }); + + setTimeout(() => { + this.setState({ + outsideClickDisaled: this.state.mobileIsHidden ? true : false, + }); + }, 150); + }; + + expandDrawer = () => { + this.setState({ isCollapsed: false }); + + setTimeout(() => { + this.setState({ + showScrollbar: true, + }); + }, 350); + + // This prevents the drawer from collapsing when tabbing through children + // by clearing the timeout thus cancelling the onBlur event (see focusOut). + // This means isManagingFocus remains true as long as a child element + // has focus. This is the case since React bubbles up onFocus and onBlur + // events from the child elements. + clearTimeout(this.timeoutID); + + if (!this.state.isManagingFocus) { + this.setState({ + isManagingFocus: true, + }); + } + }; + + collapseDrawer = () => { + this.setState({ + flyoutIsAnimating: false, + }); + + setTimeout(() => { + this.setState({ + isCollapsed: true, + flyoutIsCollapsed: true, + mobileIsHidden: true, + showScrollbar: false, + outsideClickDisaled: true, + }); + }, 350); + + // Scrolls the menu and flyout back to top when the nav drawer collapses + document.getElementById('navDrawerMenu').scroll(0, 0); + document.getElementById('navDrawerFlyout').scroll(0, 0); + }; + + focusOut = () => { + // This collapses the drawer when no children have focus (i.e. tabbed out). + // In other words, if focus does not bubble up from a child element, then + // the drawer will collapse. See the corresponding block in expandDrawer + // (called by onFocus) which cancels this operation via clearTimeout. + this.timeoutID = setTimeout(() => { + if (this.state.isManagingFocus) { + this.setState({ + isManagingFocus: false, + }); + + this.collapseDrawer(); + } + }, 0); + } + + expandFlyout = (links, title) => { + const content = links; + + this.setState(prevState => ({ + flyoutIsCollapsed: prevState.navFlyoutTitle === title ? !this.state.flyoutIsCollapsed : false, + })); + + this.setState({ + flyoutIsAnimating: true, + navFlyoutTitle: title, + navFlyoutContent: content + }); + }; + + collapseFlyout = () => { + this.setState({ flyoutIsAnimating: true }); + + setTimeout(() => { + this.setState({ + flyoutIsCollapsed: true, + navFlyoutTitle: null, + navFlyoutContent: null + }); + }, 250); + }; + + render() { + const { + isCollapsed, + flyoutIsCollapsed, + flyoutIsAnimating, + navFlyoutTitle, + navFlyoutContent, + mobileIsHidden, + showScrollbar, + outsideClickDisaled, + } = this.state; + + return ( + +
+ + + + + {this.renderMenuTrigger()} + + + {this.renderLogo()} + + + + + + {this.renderBreadcrumbs()} + + + + + + + + this.collapseDrawer()} + isDisabled={outsideClickDisaled} + > + + + + + + + + + + + + + + + + + + + +

Page title

+
+
+
+ + + + +

Content title

+
+
+
+ + Body content + +
+
+
+
+
+
+ ); + } +} diff --git a/src-docs/src/views/nav_drawer/nav_drawer_example.js b/src-docs/src/views/nav_drawer/nav_drawer_example.js new file mode 100644 index 00000000000..a28df3fec52 --- /dev/null +++ b/src-docs/src/views/nav_drawer/nav_drawer_example.js @@ -0,0 +1,41 @@ +import React from 'react'; + +import { renderToHtml } from '../../services'; + +import { + GuideSectionTypes, +} from '../../components'; + +import { + EuiNavDrawer, + EuiCode, +} from '../../../../src/components'; + +import NavDrawer from './nav_drawer'; +const navDrawerSource = require('!!raw-loader!./nav_drawer'); +const navDrawerHtml = renderToHtml(NavDrawer); + +export const NavDrawerExample = { + title: 'Nav Drawer', + sections: [{ + source: [{ + type: GuideSectionTypes.JS, + code: navDrawerSource, + }, { + type: GuideSectionTypes.HTML, + code: navDrawerHtml, + }], + text: ( +

+ EuiNavDrawer provides a side navigation feature that + is complete with interactions and a mobile-frienly design. It can + contain one or more EuiListGroup components and is + designed to be used in conjunction with EuiHeader. +

+ ), + props: { + EuiNavDrawer, + }, + demo: , + }] +}; diff --git a/src/components/header/__snapshots__/header_logo.test.js.snap b/src/components/header/__snapshots__/header_logo.test.js.snap index 960c5da9ae1..32532c920a3 100644 --- a/src/components/header/__snapshots__/header_logo.test.js.snap +++ b/src/components/header/__snapshots__/header_logo.test.js.snap @@ -7,7 +7,7 @@ exports[`EuiHeaderLogo is rendered 1`] = ` data-test-subj="test subject string" > diff --git a/src/components/header/header_section/_header_section_item.scss b/src/components/header/header_section/_header_section_item.scss index 9ec1827752f..8ad4addb559 100644 --- a/src/components/header/header_section/_header_section_item.scss +++ b/src/components/header/header_section/_header_section_item.scss @@ -19,7 +19,7 @@ .euiHeaderSectionItem__button { height: $euiHeaderChildSize; - min-width: $euiHeaderChildSize; + min-width: $euiHeaderChildSize + 1px; text-align: center; font-size: 0; // aligns icons better vertically @@ -45,16 +45,16 @@ .euiHeaderNotification { position: absolute; - top: 18%; - right: 18%; + top: 9%; + right: 9%; box-shadow: 0 0 0 1px $euiHeaderBackgroundColor; } @include euiBreakpoint('xs') { .euiHeaderSectionItem, .euiHeaderSectionItem__button { - height: $euiHeaderChildSize * .75; - min-width: $euiHeaderChildSize * .75; + height: $euiHeaderChildSizeMobile; + min-width: $euiHeaderChildSizeMobile; } .euiHeaderSectionItem--borderLeft, diff --git a/src/components/index.js b/src/components/index.js index 31bc138669d..9d39dd18f68 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -217,6 +217,12 @@ export { EuiMutationObserver, } from './mutation_observer'; +export { + EuiNavDrawer, + EuiNavDrawerMenu, + EuiNavDrawerFlyout, +} from './nav_drawer'; + export { EuiOutsideClickDetector, } from './outside_click_detector'; diff --git a/src/components/index.scss b/src/components/index.scss index 333447b1ca0..dd41057b6d2 100644 --- a/src/components/index.scss +++ b/src/components/index.scss @@ -36,6 +36,7 @@ @import 'list_group/index'; @import 'loading/index'; @import 'modal/index'; +@import 'nav_drawer/index'; @import 'overlay_mask/index'; @import 'page/index'; @import 'pagination/index'; diff --git a/src/components/list_group/_list_group_item.scss b/src/components/list_group/_list_group_item.scss index 1177f140f59..f2cb42ce077 100644 --- a/src/components/list_group/_list_group_item.scss +++ b/src/components/list_group/_list_group_item.scss @@ -6,6 +6,7 @@ display: flex; align-items: center; transition: background-color $euiAnimSpeedFast; + position: relative; &:first-child { margin-top: 0; @@ -40,7 +41,7 @@ padding: $euiSizeM $euiSizeS; display: flex; align-items: center; - flex-grow: 1; + flex: 1 0 auto; // The flex-shrink and flex-basis values are needed for IE11 text-align: left; } diff --git a/src/components/nav_drawer/_index.scss b/src/components/nav_drawer/_index.scss new file mode 100644 index 00000000000..8eeab22cbe3 --- /dev/null +++ b/src/components/nav_drawer/_index.scss @@ -0,0 +1,6 @@ +@import 'variables'; + +// Components +@import 'nav_drawer'; +@import 'nav_drawer_menu'; +@import 'nav_drawer_flyout'; diff --git a/src/components/nav_drawer/_nav_drawer.scss b/src/components/nav_drawer/_nav_drawer.scss new file mode 100644 index 00000000000..bfa23c53f18 --- /dev/null +++ b/src/components/nav_drawer/_nav_drawer.scss @@ -0,0 +1,99 @@ +// Nav drawer. Global application navigation. + +.euiNavDrawer { + width: $euiNavDrawerWidthCollapsed; + height: calc(100% - #{$euiNavDrawerTopPosition}); + position: fixed; + left: 0; + top: $euiNavDrawerTopPosition; + overflow: hidden; + z-index: $euiZHeader; + background: $euiHeaderBackgroundColor; + box-shadow: $euiNavDrawerSideShadow; + transition: width $euiAnimSpeedFast $euiAnimSlightResistance; + transition-delay: $euiNavDrawerContractingDelay; + + &.euiNavDrawer-isExpanded { + width: $euiNavDrawerWidthExpanded; + transition-delay: $euiNavDrawerExpandingDelay; + + .euiNavDrawerMenu .euiListGroupItem__label { + opacity: 1; + transition-delay: ( + $euiNavDrawerExpandingDelay + $euiNavDrawerMenuAddedDelay + ); + } + + &.euiNavDrawer-flyoutIsExpanded { + width: $euiNavDrawerWidthExpanded * 2; + } + + &.euiNavDrawer-flyoutIsAnimating { + transition-delay: 0s; + } + } + + .euiNavDrawerMenu .euiListGroupItem__label { + white-space: nowrap; + opacity: 0; + transition: opacity $euiAnimSpeedNormal; + transition-delay: ( + $euiNavDrawerContractingDelay + $euiNavDrawerMenuAddedDelay + ); + } + + &.euiNavDrawer-showScrollbar .euiNavDrawerMenu, + &.euiNavDrawer-showScrollbar .euiNavDrawerFlyout { + height: 100%; + overflow-y: auto; + // This prevents the scrollbar from overlapping the nav links. Scrollbars still show on hover + // sass-lint:disable no-vendor-prefixes + -ms-overflow-style: -ms-autohiding-scrollbar; + } +} + +@include euiBreakpoint('xs', 's') { + .euiNavDrawer { + width: $euiNavDrawerWidthExpanded; + + &.euiNavDrawer-mobileIsHidden { + width: 0; + } + + &.euiNavDrawer-isExpanded.euiNavDrawer-flyoutIsExpanded { + width: $euiNavDrawerWidthCollapsed + $euiNavDrawerWidthExpanded; + + .euiNavDrawerFlyout { + left: $euiNavDrawerWidthCollapsed; + } + } + + &.euiNavDrawer-flyoutIsExpanded { + .euiNavDrawerMenu { + width: $euiNavDrawerWidthCollapsed; + overflow-y: hidden; + } + + .euiNavDrawerMenu .euiListGroupItem__label { + display: none; + } + } + + &.euiNavDrawer-flyoutIsCollapsed .euiNavDrawerFlyout { + width: 0; + transition-delay: 0s; + transition-duration: 0s; + } + + .euiNavDrawerMenu .euiListGroupItem__label { + opacity: 1; + } + } +} + +@include euiBreakpoint('xs') { + .euiNavDrawer { + height: calc(100% - #{$euiNavDrawerTopPositionMobile}); + top: $euiNavDrawerTopPositionMobile; + } +} \ No newline at end of file diff --git a/src/components/nav_drawer/_nav_drawer_flyout.scss b/src/components/nav_drawer/_nav_drawer_flyout.scss new file mode 100644 index 00000000000..789ecbd3457 --- /dev/null +++ b/src/components/nav_drawer/_nav_drawer_flyout.scss @@ -0,0 +1,27 @@ +.euiNavDrawerFlyout { + @include euiScrollBar; + position: absolute; + left: $euiNavDrawerWidthExpanded; + top: 0; + width: $euiNavDrawerWidthExpanded; + height: 100%; + padding: $euiSize; + background-color: $euiNavDrawerBackgroundColor; + border-left: $euiBorderThin; + box-shadow: $euiNavDrawerSideShadow; + opacity: 0; + + &.euiNavDrawerFlyout-isExpanded { + opacity: 1; + transition: opacity $euiAnimSpeedNormal; + } + + &.euiNavDrawerFlyout-isCollapsed { + transition: opacity $euiAnimSpeedFast $euiNavDrawerContractingDelay; + } + + .euiNavDrawerFlyout__listGroup { + padding-left: 0; + padding-right: 0; + } +} diff --git a/src/components/nav_drawer/_nav_drawer_menu.scss b/src/components/nav_drawer/_nav_drawer_menu.scss new file mode 100644 index 00000000000..2ef3f729783 --- /dev/null +++ b/src/components/nav_drawer/_nav_drawer_menu.scss @@ -0,0 +1,4 @@ +.euiNavDrawerMenu { + @include euiScrollBar; + max-width: $euiNavDrawerWidthExpanded; +} \ No newline at end of file diff --git a/src/components/nav_drawer/_variables.scss b/src/components/nav_drawer/_variables.scss new file mode 100644 index 00000000000..6c146f027ed --- /dev/null +++ b/src/components/nav_drawer/_variables.scss @@ -0,0 +1,17 @@ +// Themable colors +$euiNavDrawerBackgroundColor: $euiHeaderBackgroundColor; + +// Drawer variables +$euiNavDrawerWidthExpanded: 240px; +$euiNavDrawerWidthCollapsed: $euiHeaderChildSize; +$euiNavDrawerSideShadow: 2px 0 2px -1px rgba($euiShadowColor, .3); + +// Layout variables +$euiNavDrawerTopPosition: $euiHeaderChildSize + 1px; +$euiNavDrawerTopPositionMobile: $euiHeaderChildSizeMobile + 1px; + +// Animation variables +$euiNavDrawerExpandingDelay: $euiAnimSpeedNormal; +$euiNavDrawerContractingDelay: $euiAnimSpeedSlow; +$euiNavDrawerExtendedDelay: $euiAnimSpeedExtraSlow * 2; +$euiNavDrawerMenuAddedDelay: $euiAnimSpeedExtraFast; \ No newline at end of file diff --git a/src/components/nav_drawer/index.js b/src/components/nav_drawer/index.js new file mode 100644 index 00000000000..d67776d58f9 --- /dev/null +++ b/src/components/nav_drawer/index.js @@ -0,0 +1,11 @@ +export { + EuiNavDrawer, +} from './nav_drawer'; + +export { + EuiNavDrawerMenu, +} from './nav_drawer_menu'; + +export { + EuiNavDrawerFlyout, +} from './nav_drawer_flyout'; diff --git a/src/components/nav_drawer/nav_drawer.js b/src/components/nav_drawer/nav_drawer.js new file mode 100644 index 00000000000..03991ae15ef --- /dev/null +++ b/src/components/nav_drawer/nav_drawer.js @@ -0,0 +1,63 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; + +export const EuiNavDrawer = ({ + children, + className, + isCollapsed, + flyoutIsCollapsed, + flyoutIsAnimating, + mobileIsHidden, + showScrollbar, + ...rest +}) => { + const classes = classNames( + 'euiNavDrawer', + { + 'euiNavDrawer-isCollapsed': isCollapsed, + 'euiNavDrawer-isExpanded': !isCollapsed, + 'euiNavDrawer-flyoutIsCollapsed': flyoutIsCollapsed, + 'euiNavDrawer-flyoutIsExpanded': !flyoutIsCollapsed, + 'euiNavDrawer-flyoutIsAnimating': flyoutIsAnimating, + 'euiNavDrawer-mobileIsHidden': mobileIsHidden, + 'euiNavDrawer-showScrollbar': showScrollbar, + }, + className + ); + + return ( +
+ {children} +
+ ); +}; + +EuiNavDrawer.propTypes = { + className: PropTypes.string, + + /** + * Toggle the nav drawer between collapsed (docked) and expanded + */ + isCollapsed: PropTypes.bool, + mobileIsHidden: PropTypes.bool, + + /** + * Toggle the flyout menu between collapsed and expanded + */ + flyoutIsCollapsed: PropTypes.bool, + flyoutIsAnimating: PropTypes.bool, + + showScrollbar: PropTypes.bool, +}; + +EuiNavDrawer.defaultProps = { + isCollapsed: true, + mobileIsHidden: true, + flyoutIsCollapsed: true, + flyoutIsAnimating: false, + showScrollbar: false, +}; \ No newline at end of file diff --git a/src/components/nav_drawer/nav_drawer_flyout.js b/src/components/nav_drawer/nav_drawer_flyout.js new file mode 100644 index 00000000000..468ffe5b829 --- /dev/null +++ b/src/components/nav_drawer/nav_drawer_flyout.js @@ -0,0 +1,47 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; + +import { EuiTitle } from '../title'; +import { EuiListGroup } from '../list_group'; + +export const EuiNavDrawerFlyout = ({ className, title, isCollapsed, listItems, ...rest }) => { + const classes = classNames( + 'euiNavDrawerFlyout', + { + 'euiNavDrawerFlyout-isCollapsed': isCollapsed, + 'euiNavDrawerFlyout-isExpanded': !isCollapsed, + }, + className + ); + + return ( +
+ + +
+ ); +}; + +EuiNavDrawerFlyout.propTypes = { + className: PropTypes.string, + listItems: EuiListGroup.propTypes.listItems, + + /** + * Display a title atop the flyout + */ + title: PropTypes.string, + + /** + * Toggle the nav drawer between collapsed and expanded + */ + isCollapsed: PropTypes.bool, +}; + +EuiNavDrawerFlyout.defaultProps = { + isCollapsed: true, +}; \ No newline at end of file diff --git a/src/components/nav_drawer/nav_drawer_menu.js b/src/components/nav_drawer/nav_drawer_menu.js new file mode 100644 index 00000000000..ac75d0388b5 --- /dev/null +++ b/src/components/nav_drawer/nav_drawer_menu.js @@ -0,0 +1,24 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; + +export const EuiNavDrawerMenu = ({ children, className, ...rest }) => { + const classes = classNames( + 'euiNavDrawerMenu', + className + ); + + return ( +
+ {children} +
+ ); +}; + +EuiNavDrawerMenu.propTypes = { + className: PropTypes.string, + children: PropTypes.node, +}; \ No newline at end of file