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

NUX: Avoid popover refresh on tip mount #7748

Merged
merged 2 commits into from
Jul 9, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
30 changes: 30 additions & 0 deletions editor/components/post-type-support-check/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
PostTypeSupportCheck
====================

A component which renders its own children only if the current editor post type supports one of the given `supportKeys`.

## Usage

Render PostTypeSupportCheck with children and one or more `supportKeys`. The children will be displayed if the post type supports at least one of the keys.

```jsx
<PostTypeSupportCheck supportKeys="title">
Supported
</PostTypeSupportCheck>
```

If the post type is not yet known, it will be assumed to be supported.

## Props

### `children`

*Type:* `WPElement`

Children to be rendered if post type supports.

### `supportKeys`

*Type:* `string|string[]`

String or string array of keys to test.
26 changes: 21 additions & 5 deletions editor/components/post-type-support-check/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
/**
* External dependencies
*/
import { get, some, castArray } from 'lodash';
import { some, castArray } from 'lodash';

/**
* WordPress dependencies
*/
import { withSelect } from '@wordpress/data';

function PostTypeSupportCheck( { postType, children, supportKeys } ) {
const isSupported = some(
castArray( supportKeys ), ( key ) => get( postType, [ 'supports', key ], false )
);
/**
* A component which renders its own children only if the current editor post
* type supports one of the given `supportKeys` prop.
*
* @param {?Object} props.postType Current post type.
* @param {WPElement} props.children Children to be rendered if post
* type supports.
* @param {(string|string[])} props.supportKeys String or string array of keys
* to test.
*
* @return {WPElement} Rendered element.
*/
export function PostTypeSupportCheck( { postType, children, supportKeys } ) {
let isSupported = true;
if ( postType ) {
isSupported = some(
castArray( supportKeys ),
( key ) => !! postType.supports[ key ]
);
}

if ( ! isSupported ) {
return null;
Expand Down
88 changes: 88 additions & 0 deletions editor/components/post-type-support-check/test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* External dependencies
*/
import { create } from 'react-test-renderer';

/**
* Internal dependencies
*/
import { PostTypeSupportCheck } from '../';

describe( 'PostTypeSupportCheck', () => {
it( 'renders its children when post type is not known', () => {
let postType;
const tree = create(
<PostTypeSupportCheck
postType={ postType }
supportKeys="title">
Supported
</PostTypeSupportCheck>
);

expect( tree.toJSON() ).toBe( 'Supported' );
} );

it( 'does not render its children when post type is known and not supports', () => {
const postType = {
supports: {},
};
const tree = create(
<PostTypeSupportCheck
postType={ postType }
supportKeys="title">
Supported
</PostTypeSupportCheck>
);

expect( tree.toJSON() ).toBe( null );
} );

it( 'renders its children when post type is known and supports', () => {
const postType = {
supports: {
title: true,
},
};
const tree = create(
<PostTypeSupportCheck
postType={ postType }
supportKeys="title">
Supported
</PostTypeSupportCheck>
);

expect( tree.toJSON() ).toBe( 'Supported' );
} );

it( 'renders its children if some of keys supported', () => {
const postType = {
supports: {
title: true,
},
};
const tree = create(
<PostTypeSupportCheck
postType={ postType }
supportKeys={ [ 'title', 'thumbnail' ] }>
Supported
</PostTypeSupportCheck>
);

expect( tree.toJSON() ).toBe( 'Supported' );
} );

it( 'does not render its children if none of keys supported', () => {
const postType = {
supports: {},
};
const tree = create(
<PostTypeSupportCheck
postType={ postType }
supportKeys={ [ 'title', 'thumbnail' ] }>
Supported
</PostTypeSupportCheck>
);

expect( tree.toJSON() ).toBe( null );
} );
} );
89 changes: 34 additions & 55 deletions nux/components/dot-tip/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* WordPress dependencies
*/
import { Component, createRef, compose } from '@wordpress/element';
import { compose } from '@wordpress/element';
import { Popover, Button, IconButton, withSafeTimeout } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { withSelect, withDispatch } from '@wordpress/data';
Expand All @@ -11,62 +11,41 @@ import { withSelect, withDispatch } from '@wordpress/data';
*/
import './style.scss';

export class DotTip extends Component {
constructor() {
super( ...arguments );

this.popoverRef = createRef();
}

componentDidMount() {
const { isVisible, setTimeout } = this.props;

if ( isVisible ) {
// Force the popover to recalculate its position on the next frame. This
// fixes the tip not appearing next to the inserter toggle on page load. This
// happens because the popover calculates its position before <PostTitle> is
// made visible, resulting in the position being too high on the page.
setTimeout( () => {
const popover = this.popoverRef.current;
popover.refresh();
popover.focus();
}, 0 );
}
export function DotTip( {
children,
isVisible,
hasNextTip,
onDismiss,
onDisable,
} ) {
if ( ! isVisible ) {
return null;
}

render() {
const { children, isVisible, hasNextTip, onDismiss, onDisable } = this.props;

if ( ! isVisible ) {
return null;
}

return (
<Popover
ref={ this.popoverRef }
className="nux-dot-tip"
position="middle right"
noArrow
focusOnMount="container"
role="dialog"
aria-label={ __( 'Gutenberg tips' ) }
onClick={ ( event ) => event.stopPropagation() }
>
<p>{ children }</p>
<p>
<Button isLink onClick={ onDismiss }>
{ hasNextTip ? __( 'See next tip' ) : __( 'Got it' ) }
</Button>
</p>
<IconButton
className="nux-dot-tip__disable"
icon="no-alt"
label={ __( 'Disable tips' ) }
onClick={ onDisable }
/>
</Popover>
);
}
return (
<Popover
className="nux-dot-tip"
position="middle right"
noArrow
focusOnMount="container"
role="dialog"
aria-label={ __( 'Gutenberg tips' ) }
onClick={ ( event ) => event.stopPropagation() }
>
<p>{ children }</p>
<p>
<Button isLink onClick={ onDismiss }>
{ hasNextTip ? __( 'See next tip' ) : __( 'Got it' ) }
</Button>
</p>
<IconButton
className="nux-dot-tip__disable"
icon="no-alt"
label={ __( 'Disable tips' ) }
onClick={ onDisable }
/>
</Popover>
);
}

export default compose(
Expand Down