From ba37ffda9e55832be42f340d865f974be98625bb Mon Sep 17 00:00:00 2001 From: Mitchell Austin Date: Sun, 10 Oct 2021 17:36:51 -0700 Subject: [PATCH] Hide horizontal overflow in `Navigator` (#35332) * Hide horizontal overflow in `Navigator` * Let `NavigatorScreen` show/scroll horizontal overflow * Fix missing classname in reduced motion context, and memoise classname. * Memoise classname and comment * Added dialog to storybook * Add a screen with horizontal overflow to Navigator story * Edit style prop to silence console * Cosmetic touch-ups for Navigator story Co-authored-by: Marco Ciampini --- .../navigator-provider/component.tsx | 23 +++-- .../navigator/navigator-screen/component.tsx | 16 +++- .../components/src/navigator/stories/index.js | 87 +++++++++++++++---- 3 files changed, 100 insertions(+), 26 deletions(-) diff --git a/packages/components/src/navigator/navigator-provider/component.tsx b/packages/components/src/navigator/navigator-provider/component.tsx index 5f8e82e6137213..df17ba55b05591 100644 --- a/packages/components/src/navigator/navigator-provider/component.tsx +++ b/packages/components/src/navigator/navigator-provider/component.tsx @@ -3,11 +3,12 @@ */ // eslint-disable-next-line no-restricted-imports import type { Ref } from 'react'; +import { css } from '@emotion/react'; /** * WordPress dependencies */ -import { useState } from '@wordpress/element'; +import { useMemo, useState } from '@wordpress/element'; /** * Internal dependencies @@ -17,6 +18,7 @@ import { useContextSystem, WordPressComponentProps, } from '../../ui/context'; +import { useCx } from '../../utils/hooks/use-cx'; import { View } from '../../view'; import { NavigatorContext } from '../context'; import type { NavigatorProviderProps, NavigatorPath } from '../types'; @@ -25,17 +27,26 @@ function NavigatorProvider( props: WordPressComponentProps< NavigatorProviderProps, 'div' >, forwardedRef: Ref< any > ) { - const { initialPath, children, ...otherProps } = useContextSystem( - props, - 'NavigatorProvider' - ); + const { + initialPath, + children, + className, + ...otherProps + } = useContextSystem( props, 'NavigatorProvider' ); const [ path, setPath ] = useState< NavigatorPath >( { path: initialPath, } ); + const cx = useCx(); + const classes = useMemo( + // Prevents horizontal overflow while animating screen transitions + () => cx( css( { overflowX: 'hidden' } ), className ), + [ className ] + ); + return ( - + { children } diff --git a/packages/components/src/navigator/navigator-screen/component.tsx b/packages/components/src/navigator/navigator-screen/component.tsx index 95d7fec931dbbe..178fa71965a357 100644 --- a/packages/components/src/navigator/navigator-screen/component.tsx +++ b/packages/components/src/navigator/navigator-screen/component.tsx @@ -5,11 +5,12 @@ import type { Ref } from 'react'; // eslint-disable-next-line no-restricted-imports import { motion, MotionProps } from 'framer-motion'; +import { css } from '@emotion/react'; /** * WordPress dependencies */ -import { useContext, useEffect, useState } from '@wordpress/element'; +import { useContext, useEffect, useState, useMemo } from '@wordpress/element'; import { useReducedMotion, useFocusOnMount } from '@wordpress/compose'; import { isRTL } from '@wordpress/i18n'; @@ -21,6 +22,7 @@ import { useContextSystem, WordPressComponentProps, } from '../../ui/context'; +import { useCx } from '../../utils/hooks/use-cx'; import { View } from '../../view'; import { NavigatorContext } from '../context'; import type { NavigatorScreenProps } from '../types'; @@ -38,7 +40,7 @@ type Props = Omit< >; function NavigatorScreen( props: Props, forwardedRef: Ref< any > ) { - const { children, path, ...otherProps } = useContextSystem( + const { children, className, path, ...otherProps } = useContextSystem( props, 'NavigatorScreen' ); @@ -48,6 +50,13 @@ function NavigatorScreen( props: Props, forwardedRef: Ref< any > ) { const isMatch = currentPath.path === path; const ref = useFocusOnMount(); + const cx = useCx(); + const classes = useMemo( + // Ensures horizontal overflow is visually accessible + () => cx( css( { overflowX: 'auto' } ), className ), + [ className ] + ); + // This flag is used to only apply the focus on mount when the actual path changes. // It avoids the focus to happen on the first render. const [ hasPathChanged, setHasPathChanged ] = useState( false ); @@ -61,7 +70,7 @@ function NavigatorScreen( props: Props, forwardedRef: Ref< any > ) { if ( prefersReducedMotion ) { return ( - + { children } ); @@ -107,6 +116,7 @@ function NavigatorScreen( props: Props, forwardedRef: Ref< any > ) { return ( diff --git a/packages/components/src/navigator/stories/index.js b/packages/components/src/navigator/stories/index.js index 42a5a639e6e671..172c0f5f6f6b91 100644 --- a/packages/components/src/navigator/stories/index.js +++ b/packages/components/src/navigator/stories/index.js @@ -2,6 +2,9 @@ * Internal dependencies */ import Button from '../../button'; +import { Card, CardBody, CardHeader } from '../../card'; +import { HStack } from '../../h-stack'; +import { Flyout } from '../../flyout'; import { NavigatorProvider, NavigatorScreen, useNavigator } from '../'; export default { @@ -19,23 +22,73 @@ function NavigatorButton( { path, isBack = false, ...props } ) { ); } -const MyNavigation = () => ( - - -

This is the home screen.

- - Navigate to child screen. - -
- - -

This is the child screen.

- - Go back - -
-
-); +const MyNavigation = () => { + return ( + + + + +

This is the home screen.

+ + + + Navigate to child screen. + + + + Navigate to screen with horizontal overflow. + + + Open test dialog } + placement="bottom-start" + > + Go + Stuff + + +
+
+
+ + + + +

This is the child screen.

+ + Go back + +
+
+
+ + + + + Go back + +
+ + ¯\_(ツ)_/¯ + +
+
+
+
+
+ ); +}; export const _default = () => { return ;