Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EuiCollapsibleNavBeta] Final collapsed/docked icon & popover behavior #7034

Merged
merged 14 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ exports[`EuiCollapsibleNavBeta renders 1`] = `
aria-expanded="true"
aria-label="Toggle navigation closed"
aria-pressed="true"
class="euiButtonIcon euiCollapsibleNavButton emotion-euiButtonIcon-s-empty-text"
class="euiButtonIcon euiCollapsibleNavButton emotion-euiButtonIcon-s-empty-text-euiCollapsibleNavButton"
data-test-subj="euiCollapsibleNavButton"
type="button"
>
Expand All @@ -36,7 +36,7 @@ exports[`EuiCollapsibleNavBeta renders 1`] = `
>
<nav
aria-label="aria-label"
class="euiFlyout euiCollapsibleNav euiCollapsibleNavBeta testClass1 testClass2 emotion-euiFlyout-none-noMaxWidth-push-left-left-euiCollapsibleNavBeta-left-euiTestCss"
class="euiFlyout euiCollapsibleNav euiCollapsibleNavBeta testClass1 testClass2 emotion-euiFlyout-none-noMaxWidth-push-left-left-euiCollapsibleNavBeta-left-isPush-euiTestCss"
data-autofocus="true"
data-test-subj="nav"
id="generated-id_euiCollapsibleNav"
Expand Down Expand Up @@ -70,7 +70,7 @@ exports[`EuiCollapsibleNavBeta renders initialIsCollapsed 1`] = `
aria-expanded="false"
aria-label="Toggle navigation open"
aria-pressed="false"
class="euiButtonIcon euiCollapsibleNavButton emotion-euiButtonIcon-s-empty-text"
class="euiButtonIcon euiCollapsibleNavButton emotion-euiButtonIcon-s-empty-text-euiCollapsibleNavButton"
data-test-subj="euiCollapsibleNavButton"
type="button"
>
Expand All @@ -91,7 +91,7 @@ exports[`EuiCollapsibleNavBeta renders initialIsCollapsed 1`] = `
data-focus-lock-disabled="disabled"
>
<nav
class="euiFlyout euiCollapsibleNav euiCollapsibleNavBeta emotion-euiFlyout-none-noMaxWidth-push-left-left-euiCollapsibleNavBeta-left"
class="euiFlyout euiCollapsibleNav euiCollapsibleNavBeta emotion-euiFlyout-none-noMaxWidth-push-left-left-euiCollapsibleNavBeta-left-isPush-isPushCollapsed"
data-autofocus="true"
data-test-subj="nav"
id="generated-id_euiCollapsibleNav"
Expand Down Expand Up @@ -125,7 +125,7 @@ exports[`EuiCollapsibleNavBeta responsive behavior collapses from a push flyout
aria-expanded="false"
aria-label="Toggle navigation open"
aria-pressed="false"
class="euiButtonIcon euiCollapsibleNavButton emotion-euiButtonIcon-s-empty-text"
class="euiButtonIcon euiCollapsibleNavButton emotion-euiButtonIcon-s-empty-text-euiCollapsibleNavButton"
data-test-subj="euiCollapsibleNavButton"
type="button"
>
Expand Down Expand Up @@ -155,7 +155,7 @@ exports[`EuiCollapsibleNavBeta responsive behavior makes the overlay flyout full
aria-expanded="true"
aria-label="Toggle navigation closed"
aria-pressed="true"
class="euiButtonIcon euiCollapsibleNavButton emotion-euiButtonIcon-s-empty-text"
class="euiButtonIcon euiCollapsibleNavButton emotion-euiButtonIcon-s-empty-text-euiCollapsibleNavButton"
data-test-subj="euiCollapsibleNavButton"
type="button"
>
Expand Down Expand Up @@ -183,7 +183,7 @@ exports[`EuiCollapsibleNavBeta responsive behavior makes the overlay flyout full
>
<nav
aria-describedby="generated-id"
class="euiFlyout euiCollapsibleNav euiCollapsibleNavBeta emotion-euiFlyout-none-noMaxWidth-overlay-left-euiCollapsibleNavBeta-left-isSmallestScreen"
class="euiFlyout euiCollapsibleNav euiCollapsibleNavBeta emotion-euiFlyout-none-noMaxWidth-overlay-left-euiCollapsibleNavBeta-left-isOverlayFullWidth"
data-autofocus="true"
id="generated-id_euiCollapsibleNav"
role="dialog"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,26 @@

import { css } from '@emotion/react';
import { UseEuiTheme } from '../../services';
import { logicalCSS } from '../../global_styling';
import { logicalCSS, euiYScroll } from '../../global_styling';
import { euiShadowFlat } from '../../themes';

export const euiCollapsibleNavBetaStyles = (euiThemeContext: UseEuiTheme) => {
const { euiTheme } = euiThemeContext;

return {
euiCollapsibleNavBeta: css`
/* This extra padding is needed for EuiPopovers to have enough
space to render with the right anchorPosition */
${logicalCSS('padding-bottom', euiTheme.size.xs)}
Comment on lines +19 to +21
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise we get this:

When we want this:


/* Allow the nav to scroll, in case consumers don't use EuiFlyoutBody/EuiFyoutFooter */
${euiYScroll(euiThemeContext)}

/* In case things get really dire responsively, ensure the footer doesn't overtake the body */
.euiFlyoutBody {
${logicalCSS('min-height', '50%')}
}

Comment on lines +27 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call on this. I toyed around by opening all of the toggles between the flyout body and footer. Hopefully no one would do this, but this is nice just in case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, I remembered that one issue/bug report we got previously and tried to get ahead of it! :)

.euiFlyoutFooter {
background-color: ${euiTheme.colors.emptyShade};
${logicalCSS('border-top', euiTheme.border.thin)}
Expand All @@ -26,7 +39,22 @@ export const euiCollapsibleNavBetaStyles = (euiThemeContext: UseEuiTheme) => {
right: css`
${logicalCSS('border-left', euiTheme.border.thin)}
`,
isSmallestScreen: css`
isPush: css`
${euiShadowFlat(euiThemeContext)}
`,
isPushCollapsed: css`
/* Hide the scrollbar for docked mode (while still keeping the nav scrollable)
Otherwise if scrollbars are visible, button icon visibility suffers */
&,
.euiFlyoutBody__overflow {
scrollbar-width: none; /* Firefox */

&::-webkit-scrollbar {
display: none; /* Chrome, Edge, & Safari */
}
}
`,
isOverlayFullWidth: css`
/* Override EuiFlyout's max-width */
&.euiFlyout {
${logicalCSS('max-width', '100% !important')}
Expand Down
53 changes: 27 additions & 26 deletions src/components/collapsible_nav_beta/collapsible_nav_beta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { CommonProps } from '../common';
import { EuiFlyout, EuiFlyoutProps } from '../flyout';
import { euiHeaderVariables } from '../header/header.styles';

import { EuiCollapsibleNavContext } from './context';
import { EuiCollapsibleNavButton } from './collapsible_nav_button';
import { euiCollapsibleNavBetaStyles } from './collapsible_nav_beta.styles';

Expand Down Expand Up @@ -87,16 +88,21 @@ export const EuiCollapsibleNavBeta: FunctionComponent<
const onClose = useCallback(() => setIsCollapsed(true), []);

/**
* Mobile behavior
* Responsive behavior
* By default on large enough screens, the nav is always a push flyout,
* but on smaller/mobile screens, the nav overlays the page instead
*/
const [isSmallScreen, setIsSmallScreen] = useState(false);
const [isSmallestScreen, setIsSmallestScreen] = useState(false);
const [isOverlay, setIsOverlay] = useState(false);
const [isOverlayFullWidth, setIsOverlayFullWidth] = useState(false);
Comment on lines +95 to +96
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this change! It's very intuitive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Music to my ears!! 😁


// Add a window resize listener that determines breakpoint behavior
const flyoutType = isOverlay ? 'overlay' : 'push';
const isPush = !isOverlay;

// Set up a window resize listener that determines breakpoint behavior
useEffect(() => {
const getBreakpoints = () => {
setIsSmallScreen(window.innerWidth < _width * 3);
setIsSmallestScreen(window.innerWidth < _width * 1.5);
setIsOverlay(window.innerWidth < _width * 3);
setIsOverlayFullWidth(window.innerWidth < _width * 1.5);
};
getBreakpoints();

Expand All @@ -105,22 +111,17 @@ export const EuiCollapsibleNavBeta: FunctionComponent<
return () => window.removeEventListener('resize', onWindowResize);
}, [_width]);

// If the screen was previously uncollapsed and shrinks down to
// a smaller mobile view, default that view to a collapsed state
// If the nav was previously uncollapsed and shrinks down to the
// overlay flyout, default to its hidden/collapsed state
useEffect(() => {
if (isSmallScreen) setIsCollapsed(true);
}, [isSmallScreen]);

// On small screens, the flyout becomes an overlay rather than a push
const flyoutType = isSmallScreen ? 'overlay' : 'push';
const isMobileCollapsed = isSmallScreen && isCollapsed;
if (isOverlay) setIsCollapsed(true);
}, [isOverlay]);

const width = useMemo(() => {
if (isSmallestScreen) return '100%';
if (isSmallScreen) return _width;
if (isCollapsed) return headerHeight;
if (isOverlayFullWidth) return '100%';
if (isPush && isCollapsed) return headerHeight;
return _width;
}, [_width, isSmallScreen, isSmallestScreen, isCollapsed, headerHeight]);
}, [_width, isOverlayFullWidth, isPush, isCollapsed, headerHeight]);

/**
* Header affordance
Expand Down Expand Up @@ -174,7 +175,9 @@ export const EuiCollapsibleNavBeta: FunctionComponent<
const cssStyles = [
styles.euiCollapsibleNavBeta,
styles[side],
isSmallestScreen && styles.isSmallestScreen,
isPush && styles.isPush,
isPush && isCollapsed && styles.isPushCollapsed,
isOverlayFullWidth && styles.isOverlayFullWidth,
];

// Wait for any fixed headers to be queried before rendering (prevents position jumping)
Expand All @@ -199,18 +202,16 @@ export const EuiCollapsibleNavBeta: FunctionComponent<
</EuiFlyout>
);

const hideFlyout = isOverlay && isCollapsed;

return (
// TODO: Context for sharing state to all children
<>
<EuiCollapsibleNavContext.Provider value={{ isPush, isCollapsed, side }}>
<EuiCollapsibleNavButton
ref={buttonRef}
onClick={toggleCollapsed}
isCollapsed={isCollapsed}
isSmallScreen={isSmallScreen}
side={side}
aria-controls={flyoutID}
/>
{!isMobileCollapsed && flyout}
</>
{!hideFlyout && flyout}
</EuiCollapsibleNavContext.Provider>
);
};
Loading