Skip to content

Commit

Permalink
Hide horizontal overflow in Navigator (#35332)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
stokesman and ciampo authored Oct 11, 2021
1 parent b5a6329 commit ba37ffd
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 26 deletions.
23 changes: 17 additions & 6 deletions packages/components/src/navigator/navigator-provider/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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';
Expand All @@ -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 (
<View ref={ forwardedRef } { ...otherProps }>
<View ref={ forwardedRef } className={ classes } { ...otherProps }>
<NavigatorContext.Provider value={ [ path, setPath ] }>
{ children }
</NavigatorContext.Provider>
Expand Down
16 changes: 13 additions & 3 deletions packages/components/src/navigator/navigator-screen/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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';
Expand All @@ -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'
);
Expand All @@ -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 );
Expand All @@ -61,7 +70,7 @@ function NavigatorScreen( props: Props, forwardedRef: Ref< any > ) {

if ( prefersReducedMotion ) {
return (
<View ref={ forwardedRef } { ...otherProps }>
<View ref={ forwardedRef } className={ classes } { ...otherProps }>
{ children }
</View>
);
Expand Down Expand Up @@ -107,6 +116,7 @@ function NavigatorScreen( props: Props, forwardedRef: Ref< any > ) {
return (
<motion.div
ref={ hasPathChanged ? ref : undefined }
className={ classes }
{ ...otherProps }
{ ...animatedProps }
>
Expand Down
87 changes: 70 additions & 17 deletions packages/components/src/navigator/stories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -19,23 +22,73 @@ function NavigatorButton( { path, isBack = false, ...props } ) {
);
}

const MyNavigation = () => (
<NavigatorProvider initialPath="/">
<NavigatorScreen path="/">
<p>This is the home screen.</p>
<NavigatorButton isPrimary path="/child">
Navigate to child screen.
</NavigatorButton>
</NavigatorScreen>

<NavigatorScreen path="/child">
<p>This is the child screen.</p>
<NavigatorButton isPrimary path="/" isBack>
Go back
</NavigatorButton>
</NavigatorScreen>
</NavigatorProvider>
);
const MyNavigation = () => {
return (
<NavigatorProvider initialPath="/">
<NavigatorScreen path="/">
<Card>
<CardBody>
<p>This is the home screen.</p>

<HStack justify="flex-start" wrap>
<NavigatorButton isPrimary path="/child">
Navigate to child screen.
</NavigatorButton>

<NavigatorButton path="/overflow-child">
Navigate to screen with horizontal overflow.
</NavigatorButton>

<Flyout
trigger={ <Button>Open test dialog</Button> }
placement="bottom-start"
>
<CardHeader>Go</CardHeader>
<CardBody>Stuff</CardBody>
</Flyout>
</HStack>
</CardBody>
</Card>
</NavigatorScreen>

<NavigatorScreen path="/child">
<Card>
<CardBody>
<p>This is the child screen.</p>
<NavigatorButton isPrimary path="/" isBack>
Go back
</NavigatorButton>
</CardBody>
</Card>
</NavigatorScreen>
<NavigatorScreen path="/overflow-child">
<Card>
<CardBody>
<NavigatorButton isPrimary path="/" isBack>
Go back
</NavigatorButton>
<div
style={ {
display: 'inline-block',
background: 'papayawhip',
} }
>
<span
style={ {
color: 'palevioletred',
whiteSpace: 'nowrap',
fontSize: '42vw',
} }
>
¯\_(ツ)_/¯
</span>
</div>
</CardBody>
</Card>
</NavigatorScreen>
</NavigatorProvider>
);
};

export const _default = () => {
return <MyNavigation />;
Expand Down

0 comments on commit ba37ffd

Please sign in to comment.