diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d92c9a760a..05e123f1d20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## [`master`](https://github.com/elastic/eui/tree/master) - Fixed `logoCloudEnterprise`, `logoLogging`, and `logoSecurity` SVGs in `EuiIcon` to be center aligned ([#2246](https://github.com/elastic/eui/pull/2246)) +- Added locking behavior of `EuiNavDrawer` expanded state inluding the following props `isLocked`, `onIsLockedUpdate` ([#2247](https://github.com/elastic/eui/pull/2247)) ## [`13.4.1`](https://github.com/elastic/eui/tree/v13.4.1) diff --git a/src/components/list_group/list_group_item.tsx b/src/components/list_group/list_group_item.tsx index 9600cfeea64..6f17d0cb6a0 100644 --- a/src/components/list_group/list_group_item.tsx +++ b/src/components/list_group/list_group_item.tsx @@ -156,11 +156,15 @@ export const EuiListGroupItem: FunctionComponent = ({ let extraActionNode; if (extraAction) { - const { iconType, alwaysShow, ...rest } = extraAction; - - const extraActionClasses = classNames('euiListGroupItem__extraAction', { - 'euiListGroupItem__extraAction-alwaysShow': alwaysShow, - }); + const { iconType, alwaysShow, className, ...rest } = extraAction; + + const extraActionClasses = classNames( + 'euiListGroupItem__extraAction', + { + 'euiListGroupItem__extraAction-alwaysShow': alwaysShow, + }, + className + ); extraActionNode = ( { + if (this.props.onIsLockedUpdate) { + this.props.onIsLockedUpdate(isLockedState); + } + }; + + functionToCallOnWindowResize = throttle(() => { + if (window.innerWidth < 1200) { + this.collapseDrawer(); + this.collapseFlyout(); + } + // reacts every 50ms to resize changes and always gets the final update + }, 50); + timeoutID; + sideNavLockClicked = () => { + if (this.state.isLocked) { + window.removeEventListener('resize', this.functionToCallOnWindowResize); + } else { + window.addEventListener('resize', this.functionToCallOnWindowResize); + } + + this.returnOnIsLockedUpdate(!this.state.isLocked); + + this.setState({ + isLocked: !this.state.isLocked, + isCollapsed: false, + outsideClickDisabled: true, + }); + }; + toggleOpen = () => { this.setState({ isCollapsed: !this.state.isCollapsed, @@ -36,6 +78,16 @@ export class EuiNavDrawer extends Component { }, 150); }; + collapseButtonClick = () => { + if (this.state.isCollapsed) { + this.expandDrawer(); + } else { + this.collapseDrawer(); + } + + this.collapseFlyout(); + }; + expandDrawer = () => { this.setState({ isCollapsed: false, @@ -54,12 +106,18 @@ export class EuiNavDrawer extends Component { isCollapsed: true, outsideClickDisabled: this.state.flyoutIsCollapsed ? true : false, toolTipsEnabled: true, + isLocked: false, }); + this.returnOnIsLockedUpdate(false); + // Scrolls the menu and flyout back to top when the nav drawer collapses setTimeout(() => { document.getElementById('navDrawerMenu').scrollTop = 0; }, 50); + + // In case it was locked before, remove the window resize listener + window.removeEventListener('resize', this.functionToCallOnWindowResize); }; manageFocus = () => { @@ -103,7 +161,7 @@ export class EuiNavDrawer extends Component { flyoutIsCollapsed: false, navFlyoutTitle: title, navFlyoutContent: content, - isCollapsed: true, + isCollapsed: this.state.isLocked ? false : true, toolTipsEnabled: false, outsideClickDisabled: false, }); @@ -115,12 +173,12 @@ export class EuiNavDrawer extends Component { flyoutIsCollapsed: true, navFlyoutTitle: null, navFlyoutContent: null, - toolTipsEnabled: true, + toolTipsEnabled: this.state.isLocked ? false : true, }); }; closeBoth = () => { - this.collapseDrawer(); + if (!this.state.isLocked) this.collapseDrawer(); this.collapseFlyout(); }; @@ -150,6 +208,9 @@ export class EuiNavDrawer extends Component { className, showExpandButton, showToolTips, + isCollapsed, + isLocked, + onIsLockedUpdate, ...rest } = this.props; @@ -158,6 +219,7 @@ export class EuiNavDrawer extends Component { { 'euiNavDrawer-isCollapsed': this.state.isCollapsed, 'euiNavDrawer-isExpanded': !this.state.isCollapsed, + 'euiNavDrawer-isLocked': this.state.isLocked, 'euiNavDrawer-flyoutIsCollapsed': this.state.flyoutIsCollapsed, 'euiNavDrawer-flyoutIsExpanded': !this.state.flyoutIsCollapsed, }, @@ -172,22 +234,43 @@ export class EuiNavDrawer extends Component { tokens={[ 'euiNavDrawer.sideNavCollapse', 'euiNavDrawer.sideNavExpand', + 'euiNavDrawer.sideNavLockAriaLabel', + 'euiNavDrawer.sideNavLockExpanded', + 'euiNavDrawer.sideNavLockCollapsed', ]} - defaults={['Collapse', 'Expand']}> - {([sideNavCollapse, sideNavExpand]) => ( + defaults={[ + 'Collapse', + 'Expand', + 'Dock navigation', + 'Navigation is docked', + 'Navigation is undocked', + ]}> + {([ + sideNavCollapse, + sideNavExpand, + sideNavLockAriaLabel, + sideNavLockExpanded, + sideNavLockCollapsed, + ]) => ( { - this.expandDrawer(); - this.collapseFlyout(); - } - : () => this.collapseDrawer() - } + extraAction={{ + className: 'euiNavDrawer__expandButtonLockAction', + color: 'text', + onClick: this.sideNavLockClicked, + iconType: this.state.isLocked ? 'lock' : 'lockOpen', + iconSize: 's', + 'aria-label': sideNavLockAriaLabel, + title: this.state.isLocked + ? sideNavLockCollapsed + : sideNavLockExpanded, + 'aria-checked': this.state.isLocked ? true : false, + role: 'switch', + }} + onClick={this.collapseButtonClick} data-test-subj={ this.state.isCollapsed ? 'navDrawerExpandButton-isCollapsed' @@ -273,6 +356,16 @@ EuiNavDrawer.propTypes = { * Display tooltips on side nav items */ showToolTips: PropTypes.bool, + + /** + * Keep drawer locked open by default + */ + isLocked: PropTypes.bool, + + /** + * Returns the current state of isLocked + */ + onIsLockedUpdate: PropTypes.func, }; EuiNavDrawer.defaultProps = {