-
+
{ __( 'Welcome to the wonderful world of blocks! Click the “+” (“Add block”) button to add a new block. There are blocks available for all kinds of content: you can insert text, headings, images, lists, and lots more!' ) }
diff --git a/packages/edit-post/src/components/header/header-toolbar/style.scss b/packages/edit-post/src/components/header/header-toolbar/style.scss
index 02410b24407a54..791cc9a61429f3 100644
--- a/packages/edit-post/src/components/header/header-toolbar/style.scss
+++ b/packages/edit-post/src/components/header/header-toolbar/style.scss
@@ -22,6 +22,17 @@
}
}
+.edit-post-header-toolbar__inserter-button-wrapper {
+ align-items: center;
+ display: flex;
+ position: relative;
+}
+
+.edit-post-header-toolbar__inserter-button-tip {
+ position: absolute;
+ right: -17px;
+}
+
// Block toolbar when fixed to the top of the screen.
.edit-post-header-toolbar__block-toolbar {
// Stack toolbar below Editor Bar.
diff --git a/packages/edit-post/src/components/header/index.js b/packages/edit-post/src/components/header/index.js
index 0663fcd5f98b36..1ca35c04d1eb98 100644
--- a/packages/edit-post/src/components/header/index.js
+++ b/packages/edit-post/src/components/header/index.js
@@ -59,7 +59,7 @@ function Header( {
forceIsDirty={ hasActiveMetaboxes }
forceIsSaving={ isSaving }
/>
-
+
-
+
{ __( 'You’ll find more settings for your page and blocks in the sidebar. Click “Settings” to open it.' ) }
diff --git a/packages/edit-post/src/components/header/style.scss b/packages/edit-post/src/components/header/style.scss
index 987dcbfd5e14cd..36f52ea85d5dce 100644
--- a/packages/edit-post/src/components/header/style.scss
+++ b/packages/edit-post/src/components/header/style.scss
@@ -63,11 +63,21 @@
@include editor-left(".edit-post-header");
-.edit-post-header__settings {
+.edit-post-header__settings,
+.edit-post-header__settings-button-wrapper {
display: inline-flex;
align-items: center;
}
+.edit-post-header__settings-button-wrapper {
+ position: relative;
+}
+
+.edit-post-header__settings-button-tip {
+ left: -17px;
+ position: absolute;
+}
+
.edit-post-header .components-button {
// Header toggle buttons.
&.is-toggled {
diff --git a/packages/editor/src/components/post-preview-button/index.js b/packages/editor/src/components/post-preview-button/index.js
index 5c31e9e271de8f..2295c957b8da46 100644
--- a/packages/editor/src/components/post-preview-button/index.js
+++ b/packages/editor/src/components/post-preview-button/index.js
@@ -182,7 +182,7 @@ export class PostPreviewButton extends Component {
__( '(opens in a new tab)' )
}
-
+
{ __( 'Click “Preview” to load a preview of this page, so you can make sure you’re happy with your blocks.' ) }
diff --git a/packages/editor/src/components/post-preview-button/style.scss b/packages/editor/src/components/post-preview-button/style.scss
new file mode 100644
index 00000000000000..809cbe235b8ac8
--- /dev/null
+++ b/packages/editor/src/components/post-preview-button/style.scss
@@ -0,0 +1,10 @@
+.editor-post-preview {
+ align-items: center;
+ display: flex;
+ position: relative;
+}
+
+.editor-post-preview__tip {
+ left: -17px;
+ position: absolute;
+}
diff --git a/packages/editor/src/components/post-preview-button/test/__snapshots__/index.js.snap b/packages/editor/src/components/post-preview-button/test/__snapshots__/index.js.snap
index cfbde2342e780d..6766ebb3f51268 100644
--- a/packages/editor/src/components/post-preview-button/test/__snapshots__/index.js.snap
+++ b/packages/editor/src/components/post-preview-button/test/__snapshots__/index.js.snap
@@ -15,11 +15,12 @@ exports[`PostPreviewButton render() should render currentPostLink otherwise 1`]
>
(opens in a new tab)
-
Click “Preview” to load a preview of this page, so you can make sure you’re happy with your blocks.
-
+
`;
@@ -38,10 +39,11 @@ exports[`PostPreviewButton render() should render previewLink if provided 1`] =
>
(opens in a new tab)
-
Click “Preview” to load a preview of this page, so you can make sure you’re happy with your blocks.
-
+
`;
diff --git a/packages/editor/src/components/post-publish-button/index.js b/packages/editor/src/components/post-publish-button/index.js
index cfed6dbd112f53..888ece7d7b7dcf 100644
--- a/packages/editor/src/components/post-publish-button/index.js
+++ b/packages/editor/src/components/post-publish-button/index.js
@@ -107,7 +107,7 @@ export class PostPublishButton extends Component {
{ ...componentProps }
>
{ componentChildren }
-
+
{ __( 'Finished writing? That’s great, let’s get this published right now. Just click “Publish” and you’re good to go.' ) }
diff --git a/packages/editor/src/components/post-publish-panel/style.scss b/packages/editor/src/components/post-publish-panel/style.scss
index 0faa264e871ad7..7b8e0ef79d7113 100644
--- a/packages/editor/src/components/post-publish-panel/style.scss
+++ b/packages/editor/src/components/post-publish-panel/style.scss
@@ -40,6 +40,15 @@
padding: 16px;
}
+.editor-post-publish-panel__toggle {
+ position: relative;
+}
+
+.editor-post-publish-panel__toggle-tip {
+ left: -17px;
+ position: absolute;
+}
+
.components-button.editor-post-publish-panel__toggle.is-primary {
display: inline-flex;
align-items: center;
diff --git a/packages/editor/src/style.scss b/packages/editor/src/style.scss
index 5b79e1b52407ac..93ad9ec18990f1 100644
--- a/packages/editor/src/style.scss
+++ b/packages/editor/src/style.scss
@@ -33,6 +33,7 @@
@import "./components/post-last-revision/style.scss";
@import "./components/post-locked-modal/style.scss";
@import "./components/post-permalink/style.scss";
+@import "./components/post-preview-button/style.scss";
@import "./components/post-publish-panel/style.scss";
@import "./components/post-saved-state/style.scss";
@import "./components/post-taxonomies/style.scss";
diff --git a/packages/nux/CHANGELOG.md b/packages/nux/CHANGELOG.md
index ffe9ba7ca937ec..5cd8a88c3cb7c4 100644
--- a/packages/nux/CHANGELOG.md
+++ b/packages/nux/CHANGELOG.md
@@ -1,3 +1,13 @@
+## 4.0.0 (Unreleased)
+
+### New Features
+
+- `DotTip`s can now be made collapsible using the `isCollapsible` prop.
+
+### Breaking Changes
+
+- `DotTip` will no longer automatically position its indicator next to the parent component. Instead, users of `DotTip` should manually position the indicator by applying a `className` or styling `.nux-dot-tip`.
+
## 3.0.4 (2018-11-30)
## 3.0.3 (2018-11-22)
@@ -28,7 +38,7 @@
### Deprecations
-- The id prop of DotTip has been deprecated. Please use the tipId prop instead.
+- The `id` prop of `DotTip` has been deprecated. Please use the `tipId` prop instead.
## 2.0.6 (2018-10-22)
@@ -38,6 +48,6 @@
## 2.0.0 (2018-09-05)
-### Breaking Change
+### Breaking Changes
- Change how required built-ins are polyfilled with Babel 7 ([#9171](https://github.com/WordPress/gutenberg/pull/9171)). If you're using an environment that has limited or no support for ES2015+ such as lower versions of IE then using [core-js](https://github.com/zloirock/core-js) or [@babel/polyfill](https://babeljs.io/docs/en/next/babel-polyfill) will add support for these methods.
diff --git a/packages/nux/src/components/dot-tip/README.md b/packages/nux/src/components/dot-tip/README.md
index 5cde47c52293d8..ee44a000f85398 100644
--- a/packages/nux/src/components/dot-tip/README.md
+++ b/packages/nux/src/components/dot-tip/README.md
@@ -29,3 +29,44 @@ A string that uniquely identifies the tip. Identifiers should be prefixed with t
### children
Any React element or elements can be passed as children. They will be rendered within the tip bubble.
+
+### isCollapsible
+
+Marks a tip as being collapsible. Collapsible tips show a pulsating indicator and nothing else. Clicking on the indicator will expand or collapse the tip.
+
+Defaults to `false`.
+
+- Type: `boolean`
+- Required: No
+
+### title
+
+A short string which describes the tip. This is used to label the button which expands or collapses the tip if it is collapsible.
+
+```jsx
+
+ Click here to add the product to your shopping cart.
+
+```
+
+- Type: `string`
+- Required: No
+
+### shortcut
+
+An object which, if specified, configures a keyboard shortcut which will expand or collapse the tip if it is collapsible.
+
+The object must contain a `raw` property which is the keyboard shortcut to bind to.
+
+Optionally, the object can contain a `display` property which is a textual description of the shortcut used for the button tooltip.
+
+Optionally, the object can contain an `ariaLabel` property which is a textual description of the shortcut used for screen readers.
+
+```jsx
+
+ Click here to add the product to your shopping cart.
+
+```
+
+- Type: `Object`
+- Required: No
diff --git a/packages/nux/src/components/dot-tip/index.js b/packages/nux/src/components/dot-tip/index.js
index cd2356f8026690..7e2501b8cd916d 100644
--- a/packages/nux/src/components/dot-tip/index.js
+++ b/packages/nux/src/components/dot-tip/index.js
@@ -1,60 +1,131 @@
/**
* WordPress dependencies
*/
+import { Component } from '@wordpress/element';
import { compose } from '@wordpress/compose';
-import { Popover, Button, IconButton } from '@wordpress/components';
-import { __ } from '@wordpress/i18n';
+import {
+ Button,
+ IconButton,
+ KeyboardShortcuts,
+ Popover,
+ Tooltip,
+ withSpokenMessages,
+} from '@wordpress/components';
+import { __, sprintf } from '@wordpress/i18n';
import { withSelect, withDispatch } from '@wordpress/data';
-function getAnchorRect( anchor ) {
- // The default getAnchorRect() excludes an element's top and bottom padding
- // from its calculation. We want tips to point to the outer margin of an
- // element, so we override getAnchorRect() to include all padding.
- return anchor.parentNode.getBoundingClientRect();
-}
-
-function onClick( event ) {
+function stopEventPropagation( event ) {
// Tips are often nested within buttons. We stop propagation so that clicking
// on a tip doesn't result in the button being clicked.
event.stopPropagation();
}
-export function DotTip( {
- children,
- isVisible,
- hasNextTip,
- onDismiss,
- onDisable,
-} ) {
- if ( ! isVisible ) {
- return null;
+export class DotTip extends Component {
+ constructor( { isCollapsible } ) {
+ super( ...arguments );
+
+ this.toggleIsOpen = this.toggleIsOpen.bind( this );
+
+ this.state = {
+ isOpen: ! isCollapsible,
+ };
}
- return (
-
-
{ children }
-
-
-
-
-
- );
+ componentDidMount() {
+ const { isCollapsible, shortcut, title, debouncedSpeak } = this.props;
+
+ if ( isCollapsible && shortcut && shortcut.raw && shortcut.ariaLabel && title ) {
+ debouncedSpeak(
+ sprintf( __( 'Press “%s” to open the tip for “%s”.' ), shortcut.ariaLabel, title )
+ );
+ }
+ }
+
+ toggleIsOpen( event ) {
+ stopEventPropagation( event );
+
+ if ( this.props.isCollapsible ) {
+ this.setState( { isOpen: ! this.state.isOpen } );
+ }
+ }
+
+ render() {
+ const {
+ children,
+ className,
+ hasNextTip,
+ isCollapsible,
+ isVisible,
+ title,
+ onDisable,
+ onDismiss,
+ shortcut,
+ } = this.props;
+ const { isOpen } = this.state;
+
+ if ( ! isVisible ) {
+ return null;
+ }
+
+ let classes = 'nux-dot-tip';
+ if ( className ) {
+ classes += ` ${ className }`;
+ }
+
+ let label;
+ if ( title ) {
+ label = isOpen ?
+ sprintf( __( 'Close tip for “%s”' ), title ) :
+ sprintf( __( 'Open tip for “%s”' ), title );
+ } else {
+ label = isOpen ? __( 'Close tip' ) : __( 'Open tip' );
+ }
+
+ let popover = null;
+ if ( isOpen ) {
+ popover = (
+
+
- It looks like you’re writing a letter. Would you like help?
-
-
-
-
-
-
+
+`;
+
+exports[`DotTip should render a custom label when collapsible 1`] = `
+
+
+
+`;
+
+exports[`DotTip should render the tip after being clicked when collapsible 1`] = `
+
+
+
+`;
+
+exports[`DotTip should render the tip when non-collapsible 1`] = `
+
+
+
+ It looks like you’re writing a letter. Would you like help?
+
+
+
+ Got it
+
+
+
+
+
`;
diff --git a/packages/nux/src/components/dot-tip/test/index.js b/packages/nux/src/components/dot-tip/test/index.js
index aa69872d5e6e80..f9070aecf01148 100644
--- a/packages/nux/src/components/dot-tip/test/index.js
+++ b/packages/nux/src/components/dot-tip/test/index.js
@@ -2,7 +2,6 @@
* External dependencies
*/
import { shallow } from 'enzyme';
-import { noop } from 'lodash';
/**
* Internal dependencies
@@ -21,19 +20,52 @@ describe( 'DotTip', () => {
expect( wrapper.isEmptyRender() ).toBe( true );
} );
- it( 'should render correctly', () => {
+ it( 'should render the tip when non-collapsible', () => {
const wrapper = shallow(
-
+
It looks like you’re writing a letter. Would you like help?
);
expect( wrapper ).toMatchSnapshot();
} );
+ it( 'should render a button when collapsible', () => {
+ const wrapper = shallow(
+
+ It looks like you’re writing a letter. Would you like help?
+
+ );
+ expect( wrapper ).toMatchSnapshot();
+ } );
+
+ it( 'should render a custom label when collapsible', () => {
+ const wrapper = shallow(
+
+ It looks like you’re writing a letter. Would you like help?
+
+ );
+ expect( wrapper ).toMatchSnapshot();
+ } );
+
+ it( 'should render the tip after being clicked when collapsible', () => {
+ const wrapper = shallow(
+
+ It looks like you’re writing a letter. Would you like help?
+
+ );
+
+ const stopPropagation = jest.fn();
+ wrapper.find( 'button' ).simulate( 'click', { stopPropagation } );
+ wrapper.update();
+
+ expect( wrapper ).toMatchSnapshot();
+ expect( stopPropagation ).toHaveBeenCalled();
+ } );
+
it( 'should call onDismiss when the dismiss button is clicked', () => {
const onDismiss = jest.fn();
const wrapper = shallow(
-
+
It looks like you’re writing a letter. Would you like help?
);
@@ -44,7 +76,7 @@ describe( 'DotTip', () => {
it( 'should call onDisable when the X button is clicked', () => {
const onDisable = jest.fn();
const wrapper = shallow(
-
+
It looks like you’re writing a letter. Would you like help?
);
diff --git a/test/e2e/specs/nux.test.js b/test/e2e/specs/nux.test.js
index 8702587f6b55b7..225c1bd7baee2b 100644
--- a/test/e2e/specs/nux.test.js
+++ b/test/e2e/specs/nux.test.js
@@ -11,12 +11,15 @@ import {
describe( 'New User Experience (NUX)', () => {
async function clickAllTips( page ) {
- // Click through all available tips.
const tips = await getTips( page );
const numberOfTips = tips.tipIds.length;
+ // Open up the first tip.
+ await page.click( '.nux-dot-tip' );
+
+ // Click through all of the tips.
for ( let i = 1; i < numberOfTips; i++ ) {
- await page.click( '.nux-dot-tip .components-button.is-link' );
+ await page.click( '.nux-dot-tip__popover .components-button.is-link' );
}
return { numberOfTips, tips };
@@ -39,13 +42,19 @@ describe( 'New User Experience (NUX)', () => {
} );
it( 'should show tips to a first-time user', async () => {
- const firstTipText = await page.$eval( '.nux-dot-tip', ( element ) => element.innerText );
+ // Click on the tip indicator to open the first tip.
+ await page.click( '.nux-dot-tip' );
+
+ // Check that we see the first tip.
+ const firstTipText = await page.$eval( '.nux-dot-tip__popover', ( element ) => element.innerText );
expect( firstTipText ).toContain( 'Welcome to the wonderful world of blocks!' );
+ // Go to the next tip.
const [ nextTipButton ] = await page.$x( "//button[contains(text(), 'See next tip')]" );
await nextTipButton.click();
- const secondTipText = await page.$eval( '.nux-dot-tip', ( element ) => element.innerText );
+ // Check that we see the second tip.
+ const secondTipText = await page.$eval( '.nux-dot-tip__popover', ( element ) => element.innerText );
expect( secondTipText ).toContain( 'You’ll find more settings for your page and blocks in the sidebar.' );
} );
@@ -57,7 +66,7 @@ describe( 'New User Experience (NUX)', () => {
expect( gotItButton ).toHaveLength( 1 );
// Click the "Got it button".
- await page.click( '.nux-dot-tip .components-button.is-link' );
+ await page.click( '.nux-dot-tip__popover .components-button.is-link' );
// Verify no more tips are visible on the page.
const nuxTipElements = await page.$$( '.nux-dot-tip' );
@@ -70,6 +79,10 @@ describe( 'New User Experience (NUX)', () => {
} );
it( 'should hide and disable tips if "disable tips" button is clicked', async () => {
+ // Click on the tip indicator to open the first tip.
+ await page.click( '.nux-dot-tip' );
+
+ // Click the X.
await page.click( '.nux-dot-tip__disable' );
// Verify no more tips are visible on the page.
@@ -88,7 +101,10 @@ describe( 'New User Experience (NUX)', () => {
} );
it( 'should enable tips when the "Enable tips" option is toggled on', async () => {
- // Start by disabling tips.
+ // Click on the tip indicator to open the first tip.
+ await page.click( '.nux-dot-tip' );
+
+ // Click the X to disable tips.
await page.click( '.nux-dot-tip__disable' );
// Verify no more tips are visible on the page.