diff --git a/CHANGELOG.md b/CHANGELOG.md index f84b20c58bc..46625f61632 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,16 @@ ## [`master`](https://github.com/elastic/eui/tree/master) +- Added `showCloseButton` and `dockedBreakpoint` flexibility to `EuiCollapsibleNav` ([#3330](https://github.com/elastic/eui/pull/3330)) + **Bug Fixes** - Fixed `EuiInMemoryTable` `isClearable` property to initiate reset ([#3328](https://github.com/elastic/eui/pull/3328)) +- Fixed `EuiCollapsibleNav` docked states on mobile ([#3330](https://github.com/elastic/eui/pull/3330)) **Breaking changes** - Upgraded `TypeScript` to 3.7.2 ([#3295](https://github.com/elastic/eui/pull/3295)) +- Changed `EuiCollapsibleNav` prop name from `hideButtonIfDocked` to `showButtonIfDocked` and flipped default ([#3330](https://github.com/elastic/eui/pull/3330)) ## [`22.6.0`](https://github.com/elastic/eui/tree/v22.6.0) diff --git a/src-docs/src/views/collapsible_nav/collapsible_nav.tsx b/src-docs/src/views/collapsible_nav/collapsible_nav.tsx index 1846d214457..cfe4cdc50a8 100644 --- a/src-docs/src/views/collapsible_nav/collapsible_nav.tsx +++ b/src-docs/src/views/collapsible_nav/collapsible_nav.tsx @@ -15,12 +15,12 @@ export default () => { <> setNavIsOpen(!navIsOpen)}> Toggle nav } - isDocked={navIsDocked} onClose={() => setNavIsOpen(false)}>
@@ -40,8 +40,8 @@ export default () => { {navIsDocked && (

- The button gets hidden by default when nav is docked unless you set{' '} - hideButtonIfDocked = false. + The button gets hidden by default when the nav is docked unless you + set showButtonIfDocked = true.

)} diff --git a/src/components/collapsible_nav/__snapshots__/collapsible_nav.test.tsx.snap b/src/components/collapsible_nav/__snapshots__/collapsible_nav.test.tsx.snap index 9c6136cdc25..dc3eae1d21b 100644 --- a/src/components/collapsible_nav/__snapshots__/collapsible_nav.test.tsx.snap +++ b/src/components/collapsible_nav/__snapshots__/collapsible_nav.test.tsx.snap @@ -1,23 +1,178 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`EuiCollapsibleNav is rendered 1`] = `null`; +exports[`EuiCollapsibleNav does not render if isOpen is false 1`] = `null`; + +exports[`EuiCollapsibleNav is rendered 1`] = ` +Array [ +
, +
+
+
+
+ +
+
+
, +] +`; exports[`EuiCollapsibleNav props button 1`] = ` - + +
+
+
, +] `; -exports[`EuiCollapsibleNav props hideButtonIfDocked 1`] = ` - + +
+
+
, +] `; exports[`EuiCollapsibleNav props isDocked 1`] = ` @@ -54,7 +209,11 @@ exports[`EuiCollapsibleNav props isDocked 1`] = ` - close + + close + @@ -68,7 +227,7 @@ exports[`EuiCollapsibleNav props isDocked 1`] = `
`; -exports[`EuiCollapsibleNav props isOpen 1`] = ` +exports[`EuiCollapsibleNav props onClose 1`] = ` Array [
,
@@ -104,7 +263,11 @@ Array [ - close + + close + @@ -119,4 +282,93 @@ Array [ ] `; -exports[`EuiCollapsibleNav props onClose 1`] = `null`; +exports[`EuiCollapsibleNav props showButtonIfDocked 1`] = ` +Array [ + + +
+
+
, +] +`; + +exports[`EuiCollapsibleNav props showCloseButton can be false 1`] = ` +Array [ +
, +
+
+
+
+
+
+
, +] +`; diff --git a/src/components/collapsible_nav/_collapsible_nav.scss b/src/components/collapsible_nav/_collapsible_nav.scss index f15d58a6b49..7276a382f84 100644 --- a/src/components/collapsible_nav/_collapsible_nav.scss +++ b/src/components/collapsible_nav/_collapsible_nav.scss @@ -7,10 +7,7 @@ left: 0; width: $euiCollapsibleNavWidth; max-width: 80vw; - - &:not(.euiCollapsibleNav--isDocked) { - animation: euiCollapsibleNavIn $euiAnimSpeedNormal $euiAnimSlightResistance; - } + animation: euiCollapsibleNavIn $euiAnimSpeedNormal $euiAnimSlightResistance; } .euiCollapsibleNav__closeButton { @@ -20,25 +17,31 @@ margin-right: -25%; } -@include euiBreakpoint('l', 'xl') { - // The addition of this class is handled through JS as well - // but adding under the breakpoint mixin is an additional fail-safe - .euiCollapsibleNav.euiCollapsibleNav--isDocked { - @include euiBottomShadowMedium; +// The addition of this class is handled through JS +// via the `dockingBreakpoint` and `isDocked` combination +.euiCollapsibleNav.euiCollapsibleNav--isDocked { + @include euiBottomShadowMedium; - .euiCollapsibleNav__closeButton { - display: none; - } + .euiCollapsibleNav__closeButton { + display: none; } +} - .euiCollapsibleNav__toggle--navIsDocked { - display: none; +.euiBody--collapsibleNavIsDocked { + // Shrink the content from the left so it's no longer overlapped by the nav drawer (ALWAYS) + padding-left: $euiCollapsibleNavWidth !important; // sass-lint:disable-line no-important + transition: padding $euiAnimSpeedFast $euiAnimSlightResistance; +} + +@include euiBreakpoint('xs') { + // At tiny screens, reduce the close button to a simple `x` + .euiCollapsibleNav__closeButton { + margin-right: -15%; } - .euiBody--collapsibleNavIsDocked { - // Shrink the content from the left so it's no longer overlapped by the nav drawer (ALWAYS) - padding-left: $euiCollapsibleNavWidth !important; // sass-lint:disable-line no-important - transition: padding $euiAnimSpeedFast $euiAnimSlightResistance; + .euiCollapsibleNav__closeButtonLabel { + // But be sure the text can still be read by a screenreader + @include euiScreenReaderOnly; } } diff --git a/src/components/collapsible_nav/collapsible_nav.test.tsx b/src/components/collapsible_nav/collapsible_nav.test.tsx index eb49c5de086..87131064594 100644 --- a/src/components/collapsible_nav/collapsible_nav.test.tsx +++ b/src/components/collapsible_nav/collapsible_nav.test.tsx @@ -27,9 +27,13 @@ jest.mock('../overlay_mask', () => ({ EuiOverlayMask: (props: any) =>
, })); +const propsNeededToRender = { id: 'id', isOpen: true }; + describe('EuiCollapsibleNav', () => { test('is rendered', () => { - const component = render(); + const component = render( + + ); expect(component).toMatchSnapshot(); }); @@ -37,42 +41,61 @@ describe('EuiCollapsibleNav', () => { describe('props', () => { test('onClose', () => { const component = render( - {}} /> + {}} /> ); expect(component).toMatchSnapshot(); }); test('isDocked', () => { - const component = render(); + const component = render( + + ); expect(component).toMatchSnapshot(); }); - test('isOpen', () => { - const component = render(); + test('dockedBreakpoint', () => { + const component = render( + + ); expect(component).toMatchSnapshot(); }); test('button', () => { const component = render( - } /> + } /> ); expect(component).toMatchSnapshot(); }); - test('hideButtonIfDocked', () => { + test('showCloseButton can be false', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + + test('showButtonIfDocked', () => { const component = render( } - hideButtonIfDocked={false} + isDocked={true} + showButtonIfDocked={true} /> ); expect(component).toMatchSnapshot(); }); }); + + test('does not render if isOpen is false', () => { + const component = render(); + + expect(component).toMatchSnapshot(); + }); }); diff --git a/src/components/collapsible_nav/collapsible_nav.tsx b/src/components/collapsible_nav/collapsible_nav.tsx index 9b077131064..9d159f671dd 100644 --- a/src/components/collapsible_nav/collapsible_nav.tsx +++ b/src/components/collapsible_nav/collapsible_nav.tsx @@ -42,6 +42,10 @@ export type EuiCollapsibleNavProps = CommonProps & * Keeps navigation flyout visible and push `` content via padding */ isDocked?: boolean; + /** + * Pixel value for customizing the minimum window width for enabling docking + */ + dockedBreakpoint?: number; /** * Shows the navigation flyout */ @@ -51,9 +55,14 @@ export type EuiCollapsibleNavProps = CommonProps & */ button?: ReactElement; /** - * Removes display of toggle button when in docked state + * Keeps the display of toggle button when in docked state + */ + showButtonIfDocked?: boolean; + /** + * Keeps the display of floating close button. + * If `false`, you must then keep the `button` displayed at all breakpoints. */ - hideButtonIfDocked?: boolean; + showCloseButton?: boolean; onClose?: () => void; }; @@ -62,20 +71,22 @@ export const EuiCollapsibleNav: FunctionComponent = ({ className, isDocked = false, isOpen = false, - onClose, button, - hideButtonIfDocked = true, + showButtonIfDocked = false, + dockedBreakpoint = 992, + showCloseButton = true, + onClose, id, ...rest }) => { const [flyoutID] = useState(id || htmlIdGenerator()('euiCollapsibleNav')); const [windowIsLargeEnoughToDock, setWindowIsLargeEnoughToDock] = useState( - window.innerWidth >= 992 + window.innerWidth >= dockedBreakpoint ); const navIsDocked = isDocked && windowIsLargeEnoughToDock; const functionToCallOnWindowResize = throttle(() => { - if (window.innerWidth < 992) { + if (window.innerWidth < dockedBreakpoint) { setWindowIsLargeEnoughToDock(false); } else { setWindowIsLargeEnoughToDock(true); @@ -85,15 +96,17 @@ export const EuiCollapsibleNav: FunctionComponent = ({ // Watch for docked status and appropriately add/remove body classes and resize handlers useEffect(() => { - if (isDocked) { + window.addEventListener('resize', functionToCallOnWindowResize); + + if (navIsDocked) { document.body.classList.add('euiBody--collapsibleNavIsDocked'); - window.addEventListener('resize', functionToCallOnWindowResize); } + return () => { document.body.classList.remove('euiBody--collapsibleNavIsDocked'); window.removeEventListener('resize', functionToCallOnWindowResize); }; - }, [isDocked, functionToCallOnWindowResize]); + }, [navIsDocked, functionToCallOnWindowResize]); const onKeyDown = (event: KeyboardEvent) => { if (event.keyCode === keyCodes.ESCAPE) { @@ -103,7 +116,10 @@ export const EuiCollapsibleNav: FunctionComponent = ({ }; const collapse = () => { - if (!navIsDocked) { + // Skip collapsing if it is docked + if (navIsDocked) { + return; + } else { onClose && onClose(); } }; @@ -120,19 +136,32 @@ export const EuiCollapsibleNav: FunctionComponent = ({ } // Show a trigger button if one was passed but - // not if hideButtonIfDocked and navIsDocked + // not if navIsDocked and showButtonIfDocked is false const trigger = - button && - !(hideButtonIfDocked && navIsDocked) && - cloneElement(button as ReactElement, { - 'aria-controls': flyoutID, - 'aria-expanded': isOpen, - 'aria-pressed': isOpen, - className: classNames( - button.props.className, - 'euiCollapsibleNav__toggle' - ), - }); + navIsDocked && !showButtonIfDocked + ? undefined + : button && + cloneElement(button as ReactElement, { + 'aria-controls': flyoutID, + 'aria-expanded': isOpen, + 'aria-pressed': isOpen, + className: classNames( + button.props.className, + 'euiCollapsibleNav__toggle' + ), + }); + + const closeButton = showCloseButton && ( + + + + + + ); const flyout = ( <> @@ -142,17 +171,7 @@ export const EuiCollapsibleNav: FunctionComponent = ({