-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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: Make tips appear inline #16582
NUX: Make tips appear inline #16582
Changes from 1 commit
18ab2e9
f45b046
51baead
bdd6473
609a09c
b1270ca
7333838
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,80 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import classnames from 'classnames'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { Notice } from '@wordpress/components'; | ||
import { useState } from '@wordpress/element'; | ||
import { Notice, Modal, Button } from '@wordpress/components'; | ||
import { compose } from '@wordpress/compose'; | ||
import { withSelect, withDispatch } from '@wordpress/data'; | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
export function InlineTip( { isVisible, className, onRemove, children } ) { | ||
if ( ! isVisible ) { | ||
return null; | ||
} | ||
export function InlineTip( { | ||
children, | ||
className, | ||
isTipVisible, | ||
onDisableTips, | ||
onDismissTip, | ||
} ) { | ||
const [ isConfirmationVisible, setIsConfirmationVisible ] = useState( false ); | ||
|
||
const openConfirmation = () => setIsConfirmationVisible( true ); | ||
const closeConfirmation = () => setIsConfirmationVisible( false ); | ||
|
||
const dismissTip = () => { | ||
onDismissTip(); | ||
closeConfirmation(); | ||
}; | ||
|
||
const disableTips = () => { | ||
onDisableTips(); | ||
closeConfirmation(); | ||
}; | ||
|
||
return ( | ||
<Notice className={ className } onRemove={ onRemove }> | ||
{ children } | ||
</Notice> | ||
<> | ||
{ isTipVisible && ( | ||
<Notice | ||
className={ classnames( 'nux-inline-tip', className ) } | ||
onRemove={ openConfirmation } | ||
> | ||
{ children } | ||
</Notice> | ||
) } | ||
|
||
{ isConfirmationVisible && ( | ||
<Modal | ||
className="nux-hide-tips-confirmation" | ||
title={ __( 'Hide Tips' ) } | ||
onRequestClose={ closeConfirmation } | ||
> | ||
{ __( 'Would you like to disable tips like these in the future?' ) } | ||
<div className="nux-hide-tips-confirmation__buttons"> | ||
<Button isDefault isLarge onClick={ dismissTip }> | ||
{ __( 'No' ) } | ||
</Button> | ||
<Button isPrimary isLarge onClick={ disableTips }> | ||
{ __( 'Disable Tips' ) } | ||
</Button> | ||
</div> | ||
</Modal> | ||
) } | ||
</> | ||
); | ||
} | ||
|
||
export default compose( | ||
withSelect( ( select, { tipId } ) => ( { | ||
isVisible: select( 'core/nux' ).isTipVisible( tipId ), | ||
isTipVisible: select( 'core/nux' ).isTipVisible( tipId ), | ||
} ) ), | ||
withDispatch( ( dispatch, { tipId } ) => { | ||
const { disableTips, dismissTip } = dispatch( 'core/nux' ); | ||
|
||
return { | ||
onRemove() { | ||
// Disable reason: We don't yet have a <Confirm> component. One day! | ||
// eslint-disable-next-line no-alert | ||
if ( window.confirm( __( 'Would you like to disable tips like these in the future? ' ) ) ) { | ||
disableTips(); | ||
} else { | ||
dismissTip( tipId ); | ||
} | ||
}, | ||
onDismissTip: () => dismissTip( tipId ), | ||
onDisableTips: disableTips, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick - The prefix 'on' seems like it could be changed. Usually I'd expect something prefixed with 'on' to be an event handler prop on a component, but this is an action dispatch and most of those just start with a verb. I found the usage in some of the functions above looked a bit unusual. |
||
}; | ||
} ) | ||
)( InlineTip ); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
.nux-hide-tips-confirmation .components-modal__header { | ||
border-bottom: none; | ||
margin-bottom: 0; | ||
} | ||
|
||
.nux-hide-tips-confirmation__buttons { | ||
margin-top: 2rem; | ||
text-align: right; | ||
|
||
.components-button { | ||
margin-left: 10px; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,12 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`InlineTip should render correctly 1`] = ` | ||
<div | ||
className="components-notice is-undefined is-dismissible" | ||
> | ||
<div | ||
className="components-notice__content" | ||
<Fragment> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This snapshot now seems a bit pointless! |
||
<Notice | ||
className="nux-inline-tip" | ||
onRemove={[Function]} | ||
> | ||
It looks like you’re writing a letter. Would you like help? | ||
</div> | ||
<button | ||
aria-label="Dismiss this notice" | ||
className="components-button components-icon-button components-notice__dismiss" | ||
onClick={[Function]} | ||
type="button" | ||
> | ||
<svg | ||
aria-hidden="true" | ||
className="dashicon dashicons-no" | ||
focusable="false" | ||
height={20} | ||
role="img" | ||
viewBox="0 0 20 20" | ||
width={20} | ||
xmlns="http://www.w3.org/2000/svg" | ||
> | ||
<path | ||
d="M12.12 10l3.53 3.53-2.12 2.12L10 12.12l-3.54 3.54-2.12-2.12L7.88 10 4.34 6.46l2.12-2.12L10 7.88l3.54-3.53 2.12 2.12z" | ||
/> | ||
</svg> | ||
</button> | ||
</div> | ||
</Notice> | ||
</Fragment> | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,7 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import TestRenderer from 'react-test-renderer'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { Notice } from '@wordpress/components'; | ||
import { shallow, mount } from 'enzyme'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm wondering if it is actually worth nuking these tests. E2E tests seem to cover the same ground. |
||
|
||
/** | ||
* Internal dependencies | ||
|
@@ -15,31 +10,44 @@ import { InlineTip } from '../'; | |
|
||
describe( 'InlineTip', () => { | ||
it( 'should not render anything if invisible', () => { | ||
const renderer = TestRenderer.create( | ||
<InlineTip isVisible={ false }> | ||
const wrapper = shallow( | ||
<InlineTip isTipVisible={ false }> | ||
It looks like you’re writing a letter. Would you like help? | ||
</InlineTip> | ||
); | ||
expect( renderer.root.children ).toHaveLength( 0 ); | ||
expect( wrapper.children() ).toHaveLength( 0 ); | ||
} ); | ||
|
||
it( 'should render correctly', () => { | ||
const renderer = TestRenderer.create( | ||
<InlineTip isVisible> | ||
const wrapper = shallow( | ||
<InlineTip isTipVisible> | ||
It looks like you’re writing a letter. Would you like help? | ||
</InlineTip> | ||
); | ||
expect( wrapper ).toMatchSnapshot(); | ||
} ); | ||
|
||
it( 'calls `onDismissTip` when the tip and confirmation are dismissed', () => { | ||
const onDismissTip = jest.fn(); | ||
const wrapper = mount( | ||
<InlineTip isTipVisible onDismissTip={ onDismissTip }> | ||
It looks like you’re writing a letter. Would you like help? | ||
</InlineTip> | ||
); | ||
expect( renderer ).toMatchSnapshot(); | ||
wrapper.find( 'button[aria-label="Dismiss this notice"]' ).simulate( 'click' ); | ||
wrapper.find( 'button' ).find( { children: 'No' } ).simulate( 'click' ); | ||
expect( onDismissTip ).toHaveBeenCalled(); | ||
} ); | ||
|
||
it( 'calls `onRemove` when the rendered notice is dismissed', () => { | ||
const onRemove = jest.fn(); | ||
const renderer = TestRenderer.create( | ||
<InlineTip isVisible onRemove={ onRemove }> | ||
it( 'calls `onDisableTips` when the tip is dismissed and the confirmation is accepted', () => { | ||
const onDisableTips = jest.fn(); | ||
const wrapper = mount( | ||
<InlineTip isTipVisible onDisableTips={ onDisableTips }> | ||
It looks like you’re writing a letter. Would you like help? | ||
</InlineTip> | ||
); | ||
renderer.root.findByType( Notice ).props.onRemove(); | ||
expect( onRemove ).toHaveBeenCalled(); | ||
wrapper.find( 'button[aria-label="Dismiss this notice"]' ).simulate( 'click' ); | ||
wrapper.find( 'button' ).find( { children: 'Disable Tips' } ).simulate( 'click' ); | ||
expect( onDisableTips ).toHaveBeenCalled(); | ||
} ); | ||
} ); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
@import "./components/dot-tip/style.scss"; | ||
@import "./components/inline-tip/style.scss"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's really minor, and I don't care so much if it gets merged without it, but I notice this has changed and I think it could go in the object below.
Also wondering if status should be kebabbed for ultra safety: