From fab075ecdbabb852e1db4f325d39834a95d74dad Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 21 Oct 2019 16:45:04 +1100 Subject: [PATCH 01/22] Implement welcome guide modal --- .../components/editor-initialization/index.js | 15 --- .../components/header/header-toolbar/index.js | 8 +- .../edit-post/src/components/header/index.js | 22 ++-- .../edit-post/src/components/layout/index.js | 2 + .../src/components/options-modal/index.js | 2 - .../options-modal/options/deferred.js | 36 ------ .../options-modal/options/enable-tips.js | 27 ----- .../components/options-modal/options/index.js | 1 - .../components/welcome-guide-modal/images.js | 36 ++++++ .../components/welcome-guide-modal/index.js | 71 ++++++++++++ .../components/welcome-guide-modal/style.scss | 49 ++++++++ packages/edit-post/src/plugins/index.js | 2 + .../plugins/welcome-guide-menu-item/index.js | 16 +++ packages/edit-post/src/style.scss | 1 + .../components/post-preview-button/index.js | 4 - .../components/post-publish-button/index.js | 21 ++-- packages/nux/package.json | 1 + .../nux/src/components/guide/finish-button.js | 29 +++++ packages/nux/src/components/guide/icons.js | 24 ++++ packages/nux/src/components/guide/index.js | 107 ++++++++++++++++++ .../nux/src/components/guide/page-control.js | 28 +++++ packages/nux/src/components/guide/style.scss | 93 +++++++++++++++ packages/nux/src/index.js | 1 + packages/nux/src/style.scss | 1 + 24 files changed, 477 insertions(+), 120 deletions(-) delete mode 100644 packages/edit-post/src/components/options-modal/options/deferred.js delete mode 100644 packages/edit-post/src/components/options-modal/options/enable-tips.js create mode 100644 packages/edit-post/src/components/welcome-guide-modal/images.js create mode 100644 packages/edit-post/src/components/welcome-guide-modal/index.js create mode 100644 packages/edit-post/src/components/welcome-guide-modal/style.scss create mode 100644 packages/edit-post/src/plugins/welcome-guide-menu-item/index.js create mode 100644 packages/nux/src/components/guide/finish-button.js create mode 100644 packages/nux/src/components/guide/icons.js create mode 100644 packages/nux/src/components/guide/index.js create mode 100644 packages/nux/src/components/guide/page-control.js create mode 100644 packages/nux/src/components/guide/style.scss diff --git a/packages/edit-post/src/components/editor-initialization/index.js b/packages/edit-post/src/components/editor-initialization/index.js index a1327684f06b36..a4695fa01aa3b4 100644 --- a/packages/edit-post/src/components/editor-initialization/index.js +++ b/packages/edit-post/src/components/editor-initialization/index.js @@ -1,9 +1,3 @@ -/** - * WordPress dependencies - */ -import { useEffect } from '@wordpress/element'; -import { useDispatch } from '@wordpress/data'; - /** * Internal dependencies */ @@ -24,14 +18,5 @@ export default function( { postId } ) { useBlockSelectionListener( postId ); useAdjustSidebarListener( postId ); useUpdatePostLinkListener( postId ); - const { triggerGuide } = useDispatch( 'core/nux' ); - useEffect( () => { - triggerGuide( [ - 'core/editor.inserter', - 'core/editor.settings', - 'core/editor.preview', - 'core/editor.publish', - ] ); - }, [ triggerGuide ] ); return null; } diff --git a/packages/edit-post/src/components/header/header-toolbar/index.js b/packages/edit-post/src/components/header/header-toolbar/index.js index 92b877e7626cfc..ad6612d7a54195 100644 --- a/packages/edit-post/src/components/header/header-toolbar/index.js +++ b/packages/edit-post/src/components/header/header-toolbar/index.js @@ -4,7 +4,6 @@ import { compose } from '@wordpress/compose'; import { withSelect } from '@wordpress/data'; import { withViewportMatch } from '@wordpress/viewport'; -import { DotTip } from '@wordpress/nux'; import { __ } from '@wordpress/i18n'; import { Inserter, @@ -31,12 +30,7 @@ function HeaderToolbar( { hasFixedToolbar, isLargeViewport, showInserter, isText className="edit-post-header-toolbar" aria-label={ toolbarAriaLabel } > -
- - - { __( '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/index.js b/packages/edit-post/src/components/header/index.js index 8515b6ba372a00..52d9245be0a157 100644 --- a/packages/edit-post/src/components/header/index.js +++ b/packages/edit-post/src/components/header/index.js @@ -9,7 +9,6 @@ import { } from '@wordpress/editor'; import { withDispatch, withSelect } from '@wordpress/data'; import { compose } from '@wordpress/compose'; -import { DotTip } from '@wordpress/nux'; /** * Internal dependencies @@ -57,19 +56,14 @@ function Header( { forceIsDirty={ hasActiveMetaboxes } forceIsSaving={ isSaving } /> -
- - - { __( 'You’ll find more settings for your page and blocks in the sidebar. Click the cog icon to toggle the sidebar open and closed.' ) } - -
+ diff --git a/packages/edit-post/src/components/layout/index.js b/packages/edit-post/src/components/layout/index.js index a8596ca2ce7dd3..141af0f7b63fe3 100644 --- a/packages/edit-post/src/components/layout/index.js +++ b/packages/edit-post/src/components/layout/index.js @@ -47,6 +47,7 @@ import Sidebar from '../sidebar'; import MetaBoxes from '../meta-boxes'; import PluginPostPublishPanel from '../sidebar/plugin-post-publish-panel'; import PluginPrePublishPanel from '../sidebar/plugin-pre-publish-panel'; +import WelcomeGuideModal from '../welcome-guide-modal'; function Layout( { isMobileViewport } ) { const { closePublishSidebar, togglePublishSidebar } = useDispatch( 'core/edit-post' ); @@ -141,6 +142,7 @@ function Layout( { isMobileViewport } ) { + { showPageTemplatePicker && <__experimentalPageTemplatePicker /> } diff --git a/packages/edit-post/src/components/options-modal/index.js b/packages/edit-post/src/components/options-modal/index.js index 792cc348ae1110..58600900bc1d0a 100644 --- a/packages/edit-post/src/components/options-modal/index.js +++ b/packages/edit-post/src/components/options-modal/index.js @@ -25,7 +25,6 @@ import Section from './section'; import { EnablePluginDocumentSettingPanelOption, EnablePublishSidebarOption, - EnableTipsOption, EnablePanelOption, EnableFeature, } from './options'; @@ -47,7 +46,6 @@ export function OptionsModal( { isModalActive, isViewable, closeModal } ) { >
-
diff --git a/packages/edit-post/src/components/options-modal/options/deferred.js b/packages/edit-post/src/components/options-modal/options/deferred.js deleted file mode 100644 index 2a0f84348d23bb..00000000000000 --- a/packages/edit-post/src/components/options-modal/options/deferred.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * WordPress dependencies - */ -import { Component } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import BaseOption from './base'; - -class DeferredOption extends Component { - constructor( { isChecked } ) { - super( ...arguments ); - this.state = { - isChecked, - }; - } - - componentWillUnmount() { - if ( this.state.isChecked !== this.props.isChecked ) { - this.props.onChange( this.state.isChecked ); - } - } - - render() { - return ( - this.setState( { isChecked } ) } - /> - ); - } -} - -export default DeferredOption; diff --git a/packages/edit-post/src/components/options-modal/options/enable-tips.js b/packages/edit-post/src/components/options-modal/options/enable-tips.js deleted file mode 100644 index 8771f8437ba53a..00000000000000 --- a/packages/edit-post/src/components/options-modal/options/enable-tips.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * WordPress dependencies - */ -import { compose } from '@wordpress/compose'; -import { withSelect, withDispatch } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import DeferredOption from './deferred'; - -export default compose( - withSelect( ( select ) => ( { - isChecked: select( 'core/nux' ).areTipsEnabled(), - } ) ), - withDispatch( ( dispatch ) => { - const { enableTips, disableTips } = dispatch( 'core/nux' ); - return { - onChange: ( isEnabled ) => ( isEnabled ? enableTips() : disableTips() ), - }; - } ) -)( - // Using DeferredOption here means enableTips() is called when the Options - // modal is dismissed. This stops the NUX guide from appearing above the - // Options modal, which looks totally weird. - DeferredOption -); diff --git a/packages/edit-post/src/components/options-modal/options/index.js b/packages/edit-post/src/components/options-modal/options/index.js index 8684b680377054..b5cb1c6c4fe1b7 100644 --- a/packages/edit-post/src/components/options-modal/options/index.js +++ b/packages/edit-post/src/components/options-modal/options/index.js @@ -2,5 +2,4 @@ export { default as EnableCustomFieldsOption } from './enable-custom-fields'; export { default as EnablePanelOption } from './enable-panel'; export { default as EnablePluginDocumentSettingPanelOption } from './enable-plugin-document-setting-panel'; export { default as EnablePublishSidebarOption } from './enable-publish-sidebar'; -export { default as EnableTipsOption } from './enable-tips'; export { default as EnableFeature } from './enable-feature'; diff --git a/packages/edit-post/src/components/welcome-guide-modal/images.js b/packages/edit-post/src/components/welcome-guide-modal/images.js new file mode 100644 index 00000000000000..e71a59020665c2 --- /dev/null +++ b/packages/edit-post/src/components/welcome-guide-modal/images.js @@ -0,0 +1,36 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; + +export const CanvasImage = ( props ) => ( + +); + +export const EditorImage = ( props ) => ( + +); + +export const BlockLibraryImage = ( props ) => ( + +); + +export const InserterIconImage = ( props ) => ( + { +); diff --git a/packages/edit-post/src/components/welcome-guide-modal/index.js b/packages/edit-post/src/components/welcome-guide-modal/index.js new file mode 100644 index 00000000000000..9bda3026d4a4c8 --- /dev/null +++ b/packages/edit-post/src/components/welcome-guide-modal/index.js @@ -0,0 +1,71 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { Guide } from '@wordpress/nux'; +import { __ } from '@wordpress/i18n'; +import { __experimentalCreateInterpolateElement } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { CanvasImage, EditorImage, BlockLibraryImage, InserterIconImage } from './images'; + +export default function WelcomeGuideModal() { + const areTipsEnabled = useSelect( ( select ) => select( 'core/nux' ).areTipsEnabled() ); + + const { disableTips } = useDispatch( 'core/nux' ); + + if ( ! areTipsEnabled ) { + return null; + } + + return ( + + + +

+ { __( 'Welcome to the block editor' ) } +

+ +

+ { __( 'In the WordPress editor, each paragraph, image, or video is presented as a distinct “block” of content.' ) } +

+
+ + +

+ { __( 'Make each block your own' ) } +

+ +

+ { __( 'Each block comes with its own set of controls for changing things like color, width, and alignment. These will show and hide automatically when you have a block selected.' ) } +

+
+ + +

+ { __( 'Get to know the block library' ) } +

+ +

+ { __experimentalCreateInterpolateElement( + __( 'All of the blocks available to you live in the Block Library. You’ll find it wherever you see the icon.' ), + { + InserterIconImage: ( + + ), + } + ) } +

+
+ +
+ ); +} diff --git a/packages/edit-post/src/components/welcome-guide-modal/style.scss b/packages/edit-post/src/components/welcome-guide-modal/style.scss new file mode 100644 index 00000000000000..687ca0e85a94f7 --- /dev/null +++ b/packages/edit-post/src/components/welcome-guide-modal/style.scss @@ -0,0 +1,49 @@ +.edit-post-welcome-guide-modal { + $image-height: 300px; + $image-width: 320px; + + &__page { + display: flex; + flex-direction: column; + justify-content: center; + position: relative; + + @include break-small() { + min-height: $image-height; + padding-left: $image-width + $grid-size-xlarge; + } + } + + &__heading { + font-family: $editor-font; + font-size: 32px; + line-height: 44px; + margin: $grid-size 0; + } + + &__image { + background: #66c6e4; + border-radius: $radius-round-rectangle; + height: 200px; + margin: $grid-size 0; + + @include break-small() { + height: $image-height; + left: 0; + position: absolute; + width: $image-width; + } + } + + &__text { + font-size: $editor-font-size; + line-height: 1.5; + margin: $grid-size 0; + } + + &__inserter-icon { + margin: 0 4px; + position: relative; + top: 4px; + } +} diff --git a/packages/edit-post/src/plugins/index.js b/packages/edit-post/src/plugins/index.js index bae6f081189ee6..7a8280a43c0bd1 100644 --- a/packages/edit-post/src/plugins/index.js +++ b/packages/edit-post/src/plugins/index.js @@ -13,6 +13,7 @@ import CopyContentMenuItem from './copy-content-menu-item'; import ManageBlocksMenuItem from './manage-blocks-menu-item'; import KeyboardShortcutsHelpMenuItem from './keyboard-shortcuts-help-menu-item'; import ToolsMoreMenuGroup from '../components/header/tools-more-menu-group'; +import WelcomeGuideMenuItem from './welcome-guide-menu-item'; registerPlugin( 'edit-post', { render() { @@ -29,6 +30,7 @@ registerPlugin( 'edit-post', { { __( 'Manage All Reusable Blocks' ) } + ) } diff --git a/packages/edit-post/src/plugins/welcome-guide-menu-item/index.js b/packages/edit-post/src/plugins/welcome-guide-menu-item/index.js new file mode 100644 index 00000000000000..5c4c877c796905 --- /dev/null +++ b/packages/edit-post/src/plugins/welcome-guide-menu-item/index.js @@ -0,0 +1,16 @@ +/** + * WordPress dependencies + */ +import { useDispatch } from '@wordpress/data'; +import { MenuItem } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +export default function WelcomeGuideMenuItem() { + const { enableTips } = useDispatch( 'core/nux' ); + + return ( + + { __( 'Welcome Guide' ) } + + ); +} diff --git a/packages/edit-post/src/style.scss b/packages/edit-post/src/style.scss index 2bd70b382796ac..556082be5bcf26 100644 --- a/packages/edit-post/src/style.scss +++ b/packages/edit-post/src/style.scss @@ -24,6 +24,7 @@ $footer-height: $icon-button-size-small; @import "./components/text-editor/style.scss"; @import "./components/visual-editor/style.scss"; @import "./components/options-modal/style.scss"; +@import "./components/welcome-guide-modal/style.scss"; /** diff --git a/packages/editor/src/components/post-preview-button/index.js b/packages/editor/src/components/post-preview-button/index.js index a715c0fd3da5aa..415d9da9ba070d 100644 --- a/packages/editor/src/components/post-preview-button/index.js +++ b/packages/editor/src/components/post-preview-button/index.js @@ -10,7 +10,6 @@ import { Component, renderToString } from '@wordpress/element'; import { Button, Path, SVG } from '@wordpress/components'; import { __, _x } from '@wordpress/i18n'; import { withSelect, withDispatch } from '@wordpress/data'; -import { DotTip } from '@wordpress/nux'; import { ifCondition, compose } from '@wordpress/compose'; import { applyFilters } from '@wordpress/hooks'; @@ -191,9 +190,6 @@ 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-publish-button/index.js b/packages/editor/src/components/post-publish-button/index.js index ac195d4de86ce6..c564cccfd6cbef 100644 --- a/packages/editor/src/components/post-publish-button/index.js +++ b/packages/editor/src/components/post-publish-button/index.js @@ -11,7 +11,6 @@ import { Component, createRef } from '@wordpress/element'; import { withSelect, withDispatch } from '@wordpress/data'; import { compose } from '@wordpress/compose'; import { __ } from '@wordpress/i18n'; -import { DotTip } from '@wordpress/nux'; /** * Internal dependencies @@ -111,19 +110,13 @@ export class PostPublishButton extends Component { const componentProps = isToggle ? toggleProps : buttonProps; const componentChildren = isToggle ? toggleChildren : buttonChildren; return ( -
- - { /* Todo: Remove the wrapping div when DotTips are removed. */ } - - { __( '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/nux/package.json b/packages/nux/package.json index f358034d79dfff..ab6471b73c9ec6 100644 --- a/packages/nux/package.json +++ b/packages/nux/package.json @@ -27,6 +27,7 @@ "@wordpress/data": "file:../data", "@wordpress/element": "file:../element", "@wordpress/i18n": "file:../i18n", + "classnames": "^2.2.5", "lodash": "^4.17.15", "rememo": "^3.0.0" }, diff --git a/packages/nux/src/components/guide/finish-button.js b/packages/nux/src/components/guide/finish-button.js new file mode 100644 index 00000000000000..6b90d77cb20f6e --- /dev/null +++ b/packages/nux/src/components/guide/finish-button.js @@ -0,0 +1,29 @@ +/** + * WordPress dependencies + */ +import { useRef, useLayoutEffect } from '@wordpress/element'; +import { Button } from '@wordpress/components'; + +export default function FinishButton( { className, onClick, children } ) { + const button = useRef( null ); + + // Focus the button on mount if nothing else is focused. This prevents a + // focus loss when the 'Next' button is swapped out. + useLayoutEffect( () => { + if ( document.activeElement === document.body ) { + button.current.focus(); + } + }, [ button ] ); + + return ( + + ); +} diff --git a/packages/nux/src/components/guide/icons.js b/packages/nux/src/components/guide/icons.js new file mode 100644 index 00000000000000..b7519b3a8052ae --- /dev/null +++ b/packages/nux/src/components/guide/icons.js @@ -0,0 +1,24 @@ +/** + * WordPress dependencies + */ +import { SVG, Path, Circle } from '@wordpress/components'; + +export const BackButtonIcon = () => ( + + + + +); + +export const ForwardButtonIcon = () => ( + + + + +); + +export const PageControlIcon = ( { isSelected } ) => ( + + + +); diff --git a/packages/nux/src/components/guide/index.js b/packages/nux/src/components/guide/index.js new file mode 100644 index 00000000000000..5cd3c358b8d824 --- /dev/null +++ b/packages/nux/src/components/guide/index.js @@ -0,0 +1,107 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { useState, Children } from '@wordpress/element'; +import { Modal, KeyboardShortcuts, IconButton } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import PageControl from './page-control'; +import { BackButtonIcon, ForwardButtonIcon } from './icons'; +import FinishButton from './finish-button'; + +function Guide( { className, onFinish, finishButtonText, children } ) { + const isMobile = useSelect( ( select ) => + select( 'core/viewport' ).isViewportMatch( '< small' ) ); + + const [ currentPage, setCurrentPage ] = useState( 0 ); + + const numberOfPages = Children.count( children ); + const canGoBack = currentPage > 0; + const canGoForward = currentPage < numberOfPages - 1; + + const goBack = () => { + if ( canGoBack ) { + setCurrentPage( currentPage - 1 ); + } + }; + + const goForward = () => { + if ( canGoForward ) { + setCurrentPage( currentPage + 1 ); + } + }; + + return ( + + + + +
+ + { children[ currentPage ] } + + { isMobile && ! canGoForward && ( + + { finishButtonText || __( 'Finish' ) } + + ) } + +
+ { canGoBack && ( + } + onClick={ goBack } + > + { __( 'Previous' ) } + + ) } + + { canGoForward && ( + } + onClick={ goForward } + > + { __( 'Next' ) } + + ) } + { ! isMobile && ! canGoForward && ( + + { finishButtonText || __( 'Finish' ) } + + ) } +
+ +
+ +
+ ); +} + +function Page( props ) { + return
; +} + +Guide.Page = Page; + +export default Guide; diff --git a/packages/nux/src/components/guide/page-control.js b/packages/nux/src/components/guide/page-control.js new file mode 100644 index 00000000000000..cea80a09a5a3bf --- /dev/null +++ b/packages/nux/src/components/guide/page-control.js @@ -0,0 +1,28 @@ +/** + * External dependencies + */ +import { times } from 'lodash'; + +/** + * WordPress dependencies + */ +import { IconButton } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { PageControlIcon } from './icons'; + +export default function PageControl( { currentPage, numberOfPages, setCurrentPage } ) { + return ( +
+ { times( numberOfPages, ( page ) => ( + } + onClick={ () => setCurrentPage( page ) } + /> + ) ) } +
+ ); +} diff --git a/packages/nux/src/components/guide/style.scss b/packages/nux/src/components/guide/style.scss new file mode 100644 index 00000000000000..1dd1861f2a8d6d --- /dev/null +++ b/packages/nux/src/components/guide/style.scss @@ -0,0 +1,93 @@ +.nux-guide { + @media (max-width: $break-small) { + bottom: 15%; + left: $grid-size-xlarge; + right: $grid-size-xlarge; + top: 15%; + } + + .components-modal__header { + background: none; + border-bottom: none; + } + + &__container { + align-items: center; + display: flex; + flex-direction: column; + margin-top: -$header-height; + min-height: 100%; + } + + &__footer { + align-content: center; + display: flex; + height: 30px; + justify-content: center; + margin: auto 0 $grid-size-xlarge 0; + position: relative; + width: 100%; + + @include break-small() { + margin: $grid-size-xlarge 0 0; + } + } + + &__page-control { + display: flex; + + .components-button { + margin: 0 2px; + } + } + + &__back-button, + &__forward-button, + &__finish-button { + height: 30px; + position: absolute; + } + + &__back-button, + &__forward-button { + font-size: 0; + padding: 4px 2px; + + &.has-text svg { + margin: 0; + } + + @include break-small() { + font-size: $default-font-size; + } + } + + &__back-button { + left: 0; + + @include break-small() { + padding: 4px 8px 4px 2px; + + &.has-text svg { + margin-right: 4px; + } + } + } + + &__forward-button { + right: 0; + + @include break-small() { + padding: 4px 2px 4px 8px; + + &.has-text svg { + margin-left: 4px; + order: 1; + } + } + } + + &__finish-button { + right: 0; + } +} diff --git a/packages/nux/src/index.js b/packages/nux/src/index.js index a11d17bc96961a..ed6d38620bb8bb 100644 --- a/packages/nux/src/index.js +++ b/packages/nux/src/index.js @@ -4,3 +4,4 @@ import './store'; export { default as DotTip } from './components/dot-tip'; +export { default as Guide } from './components/guide'; diff --git a/packages/nux/src/style.scss b/packages/nux/src/style.scss index 0df73ff851e9f9..7f9613efb11a38 100644 --- a/packages/nux/src/style.scss +++ b/packages/nux/src/style.scss @@ -1 +1,2 @@ @import "./components/dot-tip/style.scss"; +@import "./components/guide/style.scss"; From 5d35bf0088e5d49c593d991bdb3c6c8f877432e0 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 22 Nov 2019 11:27:03 +0100 Subject: [PATCH 02/22] Welcome guide: Update images --- .../edit-post/src/components/welcome-guide-modal/images.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/edit-post/src/components/welcome-guide-modal/images.js b/packages/edit-post/src/components/welcome-guide-modal/images.js index e71a59020665c2..9b44eb9709f7d2 100644 --- a/packages/edit-post/src/components/welcome-guide-modal/images.js +++ b/packages/edit-post/src/components/welcome-guide-modal/images.js @@ -6,7 +6,7 @@ import { __ } from '@wordpress/i18n'; export const CanvasImage = ( props ) => ( ); @@ -14,7 +14,7 @@ export const CanvasImage = ( props ) => ( export const EditorImage = ( props ) => ( ); @@ -22,7 +22,7 @@ export const EditorImage = ( props ) => ( export const BlockLibraryImage = ( props ) => ( ); From 8d7332328ea3d2fdff0390f32f9d4f8b5f564cf0 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 22 Nov 2019 11:27:29 +0100 Subject: [PATCH 03/22] Welcome guide: Capitalise 'Block Editor' and 'Block Library' --- .../edit-post/src/components/welcome-guide-modal/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/edit-post/src/components/welcome-guide-modal/index.js b/packages/edit-post/src/components/welcome-guide-modal/index.js index 9bda3026d4a4c8..8674af6b1db625 100644 --- a/packages/edit-post/src/components/welcome-guide-modal/index.js +++ b/packages/edit-post/src/components/welcome-guide-modal/index.js @@ -29,7 +29,7 @@ export default function WelcomeGuideModal() {

- { __( 'Welcome to the block editor' ) } + { __( 'Welcome to the Block Editor' ) }

@@ -49,7 +49,7 @@ export default function WelcomeGuideModal() {

- { __( 'Get to know the block library' ) } + { __( 'Get to know the Block Library' ) }

From d596283fc9250b8c1758308727bf914a4cccdf36 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 22 Nov 2019 11:44:51 +0100 Subject: [PATCH 04/22] Welcome guide: Position close button 24px from edge --- packages/nux/src/components/guide/style.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/nux/src/components/guide/style.scss b/packages/nux/src/components/guide/style.scss index 1dd1861f2a8d6d..1a7f7dc41f915e 100644 --- a/packages/nux/src/components/guide/style.scss +++ b/packages/nux/src/components/guide/style.scss @@ -9,6 +9,12 @@ .components-modal__header { background: none; border-bottom: none; + + .components-icon-button { + align-self: flex-start; + margin-top: $grid-size-xlarge; + position: static; + } } &__container { From eae9ce0eaa1d733e40bac60dd69890c17855dc91 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 22 Nov 2019 12:10:13 +0100 Subject: [PATCH 05/22] Welcome guide: Improve a11y of page controls --- .../nux/src/components/guide/page-control.js | 19 ++++++++++++------- packages/nux/src/components/guide/style.scss | 9 +++++++-- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/nux/src/components/guide/page-control.js b/packages/nux/src/components/guide/page-control.js index cea80a09a5a3bf..1e3d8ceb2ef671 100644 --- a/packages/nux/src/components/guide/page-control.js +++ b/packages/nux/src/components/guide/page-control.js @@ -6,6 +6,7 @@ import { times } from 'lodash'; /** * WordPress dependencies */ +import { __, sprintf } from '@wordpress/i18n'; import { IconButton } from '@wordpress/components'; /** @@ -15,14 +16,18 @@ import { PageControlIcon } from './icons'; export default function PageControl( { currentPage, numberOfPages, setCurrentPage } ) { return ( -

+
    { times( numberOfPages, ( page ) => ( - } - onClick={ () => setCurrentPage( page ) } - /> +
  • + } + /* translators: %1$d: current page number %2$d: total number of pages */ + aria-label={ sprintf( __( 'Page %1$d of %2$d' ), page + 1, numberOfPages ) } + onClick={ () => setCurrentPage( page ) } + /> +
  • ) ) } -
+ ); } diff --git a/packages/nux/src/components/guide/style.scss b/packages/nux/src/components/guide/style.scss index 1a7f7dc41f915e..b720881bfcac05 100644 --- a/packages/nux/src/components/guide/style.scss +++ b/packages/nux/src/components/guide/style.scss @@ -40,11 +40,16 @@ } &__page-control { - display: flex; + margin: 0; - .components-button { + li { + display: inline-block; margin: 0 2px; } + + .components-icon-button { + height: 30px; + } } &__back-button, From a10e7124ba66e8ebc89b629985f36e00043f92d5 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 22 Nov 2019 15:10:45 +0100 Subject: [PATCH 06/22] Welcome guide: Add unit tests --- packages/nux/src/components/guide/index.js | 21 +++-- .../guide/test/__snapshots__/index.js.snap | 40 ++++++++ .../components/guide/test/finish-button.js | 49 ++++++++++ .../nux/src/components/guide/test/index.js | 91 +++++++++++++++++++ .../src/components/guide/test/page-control.js | 39 ++++++++ 5 files changed, 232 insertions(+), 8 deletions(-) create mode 100644 packages/nux/src/components/guide/test/__snapshots__/index.js.snap create mode 100644 packages/nux/src/components/guide/test/finish-button.js create mode 100644 packages/nux/src/components/guide/test/index.js create mode 100644 packages/nux/src/components/guide/test/page-control.js diff --git a/packages/nux/src/components/guide/index.js b/packages/nux/src/components/guide/index.js index 5cd3c358b8d824..ab7b280f070a1c 100644 --- a/packages/nux/src/components/guide/index.js +++ b/packages/nux/src/components/guide/index.js @@ -6,10 +6,10 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useSelect } from '@wordpress/data'; import { useState, Children } from '@wordpress/element'; import { Modal, KeyboardShortcuts, IconButton } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; +import { withSelect } from '@wordpress/data'; /** * Internal dependencies @@ -18,10 +18,7 @@ import PageControl from './page-control'; import { BackButtonIcon, ForwardButtonIcon } from './icons'; import FinishButton from './finish-button'; -function Guide( { className, onFinish, finishButtonText, children } ) { - const isMobile = useSelect( ( select ) => - select( 'core/viewport' ).isViewportMatch( '< small' ) ); - +export function Guide( { children, className, finishButtonText, isMobile, onFinish } ) { const [ currentPage, setCurrentPage ] = useState( 0 ); const numberOfPages = Children.count( children ); @@ -40,6 +37,10 @@ function Guide( { className, onFinish, finishButtonText, children } ) { } }; + if ( numberOfPages === 0 ) { + return null; + } + return ( @@ -98,10 +99,14 @@ function Guide( { className, onFinish, finishButtonText, children } ) { ); } -function Page( props ) { +export function Page( props ) { return
; } -Guide.Page = Page; +const EnhancedGuide = withSelect( ( select ) => ( { + isMobile: select( 'core/viewport' ).isViewportMatch( '< small' ), +} ) )( Guide ); + +EnhancedGuide.Page = Page; -export default Guide; +export default EnhancedGuide; diff --git a/packages/nux/src/components/guide/test/__snapshots__/index.js.snap b/packages/nux/src/components/guide/test/__snapshots__/index.js.snap new file mode 100644 index 00000000000000..df62eea1a049c5 --- /dev/null +++ b/packages/nux/src/components/guide/test/__snapshots__/index.js.snap @@ -0,0 +1,40 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Guide renders when there are pages 1`] = ` + + +
+ + Page 1 + +
+ + } + onClick={[Function]} + > + Next + +
+
+
+`; diff --git a/packages/nux/src/components/guide/test/finish-button.js b/packages/nux/src/components/guide/test/finish-button.js new file mode 100644 index 00000000000000..86e2d659f21b10 --- /dev/null +++ b/packages/nux/src/components/guide/test/finish-button.js @@ -0,0 +1,49 @@ +/** + * External dependencies + */ +import { shallow } from 'enzyme'; +import { create } from 'react-test-renderer'; + +/** + * WordPress dependencies + */ +import { Button } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import FinishButton from '../finish-button'; + +describe( 'FinishButton', () => { + it( 'renders a button', () => { + const wrapper = shallow( ); + expect( wrapper.find( Button ) ).toHaveLength( 1 ); + } ); + + it( 'calls onClick when the button is clicked', () => { + const onClick = jest.fn(); + const wrapper = shallow( ); + wrapper.find( Button ).prop( 'onClick' )(); + expect( onClick ).toHaveBeenCalled(); + } ); + + it( 'receives focus on mount when nothing is focused', () => { + const focus = jest.fn(); + create( , { + createNodeMock: () => ( { focus } ), + } ); + expect( focus ).toHaveBeenCalled(); + } ); + + it( 'does not receive focus on mount when something is already focused', () => { + const button = document.createElement( 'button' ); + document.body.append( button ); + button.focus(); + + const focus = jest.fn(); + create( , { + createNodeMock: () => ( { focus } ), + } ); + expect( focus ).not.toHaveBeenCalled(); + } ); +} ); diff --git a/packages/nux/src/components/guide/test/index.js b/packages/nux/src/components/guide/test/index.js new file mode 100644 index 00000000000000..779a73c2c41393 --- /dev/null +++ b/packages/nux/src/components/guide/test/index.js @@ -0,0 +1,91 @@ +/** + * External dependencies + */ +import { shallow } from 'enzyme'; + +/** + * WordPress dependencies + */ +import { Modal } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { Guide, Page } from '../'; +import PageControl from '../page-control'; + +describe( 'Guide', () => { + it( 'renders nothing when there are no pages', () => { + const wrapper = shallow( ); + expect( wrapper.isEmptyRender() ).toBe( true ); + } ); + + it( 'renders when there are pages', () => { + const wrapper = shallow( + + Page 1 + Page 2 + + ); + expect( wrapper ).toMatchSnapshot(); + } ); + + it( 'hides back button and shows forward button on the first page', () => { + const wrapper = shallow( + + Page 1 + Page 2 + + ); + expect( wrapper.find( PageControl ).prop( 'currentPage' ) ).toBe( 0 ); + expect( wrapper.find( '.nux-guide__back-button' ) ).toHaveLength( 0 ); + expect( wrapper.find( '.nux-guide__forward-button' ) ).toHaveLength( 1 ); + expect( wrapper.find( '.nux-guide__finish-button' ) ).toHaveLength( 0 ); + } ); + + it( 'shows back button and shows finish button on the last page', () => { + const wrapper = shallow( + + Page 1 + Page 2 + + ); + wrapper.find( '.nux-guide__forward-button' ).simulate( 'click' ); + expect( wrapper.find( PageControl ).prop( 'currentPage' ) ).toBe( 1 ); + expect( wrapper.find( '.nux-guide__back-button' ) ).toHaveLength( 1 ); + expect( wrapper.find( '.nux-guide__forward-button' ) ).toHaveLength( 0 ); + expect( wrapper.find( '.nux-guide__finish-button' ) ).toHaveLength( 1 ); + } ); + + it( 'shows the finish button inline with the content on mobile', () => { + const wrapper = shallow( + + Page 1 + + ); + expect( wrapper.find( '.nux-guide__finish-button' ) ).toHaveLength( 0 ); + expect( wrapper.findWhere( ( node ) => node.text() === 'Finish' ) ).toHaveLength( 1 ); + } ); + + it( 'calls onFinish when the finish button is clicked', () => { + const onFinish = jest.fn(); + const wrapper = shallow( + + Page 1 + + ); + wrapper.find( '.nux-guide__finish-button' ).simulate( 'click' ); + expect( onFinish ).toHaveBeenCalled(); + } ); + + it( 'calls onFinish when the modal is closed', () => { + const onFinish = jest.fn(); + const wrapper = shallow( + + Page 1 + + ); + wrapper.find( Modal ).prop( 'onRequestClose' )(); + expect( onFinish ).toHaveBeenCalled(); + } ); +} ); diff --git a/packages/nux/src/components/guide/test/page-control.js b/packages/nux/src/components/guide/test/page-control.js new file mode 100644 index 00000000000000..6490dc1cfaa021 --- /dev/null +++ b/packages/nux/src/components/guide/test/page-control.js @@ -0,0 +1,39 @@ +/** + * External dependencies + */ +import { shallow } from 'enzyme'; + +/** + * WordPress dependencies + */ +import { IconButton } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import PageControl from '../page-control'; + +describe( 'PageControl', () => { + it( 'renders an empty list when there are no pages', () => { + const wrapper = shallow( ); + expect( wrapper.find( IconButton ) ).toHaveLength( 0 ); + } ); + + it( 'renders a button for each page', () => { + const wrapper = shallow( ); + expect( wrapper.find( IconButton ) ).toHaveLength( 5 ); + } ); + + it( 'sets the current page when a button is clicked', () => { + const setCurrentPage = jest.fn(); + const wrapper = shallow( + + ); + wrapper.find( IconButton ).at( 1 ).simulate( 'click' ); + expect( setCurrentPage ).toHaveBeenCalledWith( 1 ); + } ); +} ); From 3fdce05ecc0f7eb2a2d49a13a6653a3b9d0641d9 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 25 Nov 2019 16:18:37 +0100 Subject: [PATCH 07/22] Welcome guide: Add E2E tests --- .../specs/editor/various/nux.test.js | 149 ++++++++---------- packages/nux/src/components/guide/index.js | 6 +- 2 files changed, 73 insertions(+), 82 deletions(-) diff --git a/packages/e2e-tests/specs/editor/various/nux.test.js b/packages/e2e-tests/specs/editor/various/nux.test.js index d3ca54af511763..4cd83af01b49b2 100644 --- a/packages/e2e-tests/specs/editor/various/nux.test.js +++ b/packages/e2e-tests/specs/editor/various/nux.test.js @@ -1,110 +1,97 @@ /** * WordPress dependencies */ -import { - createNewPost, - toggleScreenOption, -} from '@wordpress/e2e-test-utils'; +import { createNewPost, clickOnMoreMenuItem } from '@wordpress/e2e-test-utils'; describe( 'New User Experience (NUX)', () => { - async function clickAllTips( page ) { - // Click through all available tips. - const tips = await getTips( page ); - const numberOfTips = tips.tipIds.length; - - for ( let i = 1; i < numberOfTips; i++ ) { - await page.click( '.nux-dot-tip .components-button.is-link' ); - } - - return { numberOfTips, tips }; - } - - async function getTips( page ) { - return await page.evaluate( () => { - return wp.data.select( 'core/nux' ).getAssociatedGuide( 'core/editor.inserter' ); - } ); - } - - async function getTipsEnabled( page ) { - return await page.evaluate( () => { - return wp.data.select( 'core/nux' ).areTipsEnabled(); - } ); - } - - beforeEach( async () => { + it( 'should show the guide to first-time users', async () => { + let welcomeGuideText, welcomeGuide; + + // Create a new post as a first-time user await createNewPost( { enableTips: true } ); - } ); - it( 'should show tips to a first-time user', async () => { - const firstTipText = await page.$eval( '.nux-dot-tip', ( element ) => element.innerText ); - expect( firstTipText ).toContain( 'Welcome to the wonderful world of blocks!' ); + // Guide should be on page 1 of 3 + welcomeGuideText = await page.$eval( '.edit-post-welcome-guide', ( element ) => element.innerText ); + expect( welcomeGuideText ).toContain( 'Welcome to the Block Editor' ); - const [ nextTipButton ] = await page.$x( "//button[contains(text(), 'See next tip')]" ); - await nextTipButton.click(); + // Click on the 'Next' button + const [ nextButton ] = await page.$x( '//button[contains(text(), "Next")]' ); + await nextButton.click(); - const secondTipText = await page.$eval( '.nux-dot-tip', ( element ) => element.innerText ); - expect( secondTipText ).toContain( 'You’ll find more settings for your page and blocks in the sidebar.' ); - } ); + // Guide should be on page 2 of 3 + welcomeGuideText = await page.$eval( '.edit-post-welcome-guide', ( element ) => element.innerText ); + expect( welcomeGuideText ).toContain( 'Make each block your own' ); + + // Click on the 'Previous' button + const [ previousButton ] = await page.$x( '//button[contains(text(), "Previous")]' ); + await previousButton.click(); + + // Guide should be on page 1 of 3 + welcomeGuideText = await page.$eval( '.edit-post-welcome-guide', ( element ) => element.innerText ); + expect( welcomeGuideText ).toContain( 'Welcome to the Block Editor' ); + + // Press the button for Page 2 + await page.click( 'button[aria-label="Page 2 of 3"]' ); - it( 'should show "Got it" once all tips have been displayed', async () => { - await clickAllTips( page ); + // Press the right arrow key + await page.keyboard.press( 'ArrowRight' ); - // Make sure "Got it" button appears on the last tip. - const gotItButton = await page.$x( "//button[contains(text(), 'Got it')]" ); - expect( gotItButton ).toHaveLength( 1 ); + // Guide should be on page 3 of 3 + welcomeGuideText = await page.$eval( '.edit-post-welcome-guide', ( element ) => element.innerText ); + expect( welcomeGuideText ).toContain( 'Get to know the Block Library' ); - // Click the "Got it button". - await page.click( '.nux-dot-tip .components-button.is-link' ); + // Click on the 'Get started' button + const [ getStartedButton ] = await page.$x( '//button[contains(text(), "Get started")]' ); + await getStartedButton.click(); - // Verify no more tips are visible on the page. - const nuxTipElements = await page.$$( '.nux-dot-tip' ); - expect( nuxTipElements ).toHaveLength( 0 ); + // Guide should be closed + welcomeGuide = await page.$( '.edit-post-welcome-guide' ); + expect( welcomeGuide ).toBeNull(); - // Tips should not be marked as disabled, but when the user has seen all - // of the available tips, they will not appear. - const areTipsEnabled = await getTipsEnabled( page ); - expect( areTipsEnabled ).toEqual( true ); + // Reload the editor + await page.reload(); + + // Guide should be closed + welcomeGuide = await page.$( '.edit-post-welcome-guide' ); + expect( welcomeGuide ).toBeNull(); } ); - it( 'should hide and disable tips if "disable tips" button is clicked', async () => { - await page.click( '.nux-dot-tip__disable' ); + it( 'should not show the welcome guide again if it is dismissed', async () => { + let welcomeGuide; - // Verify no more tips are visible on the page. - let nuxTipElements = await page.$$( '.nux-dot-tip' ); - expect( nuxTipElements ).toHaveLength( 0 ); + // Create a new post as a first-time user + await createNewPost( { enableTips: true } ); - // We should be disabling the tips so they don't appear again. - const areTipsEnabled = await getTipsEnabled( page ); - expect( areTipsEnabled ).toEqual( false ); + // Guide should be open + welcomeGuide = await page.$( '.edit-post-welcome-guide' ); + expect( welcomeGuide ).not.toBeNull(); - // Refresh the page; tips should not show because they were disabled. + // Close the guide + await page.click( 'button[aria-label="Close dialog"]' ); + + // Reload the editor await page.reload(); - nuxTipElements = await page.$$( '.nux-dot-tip' ); - expect( nuxTipElements ).toHaveLength( 0 ); + // Guide should be closed + welcomeGuide = await page.$( '.edit-post-welcome-guide' ); + expect( welcomeGuide ).toBeNull(); } ); - it( 'should enable tips when the "Tips" option is toggled on', async () => { - // Start by disabling tips. - await page.click( '.nux-dot-tip__disable' ); - - // Verify no more tips are visible on the page. - let nuxTipElements = await page.$$( '.nux-dot-tip' ); - expect( nuxTipElements ).toHaveLength( 0 ); + it( 'should show the welcome guide if it is manually opened', async () => { + let welcomeGuide; - // Tips should be disabled in localStorage as well. - let areTipsEnabled = await getTipsEnabled( page ); - expect( areTipsEnabled ).toEqual( false ); + // Create a new post as a returning user + await createNewPost(); - // Toggle the 'Tips' option to enable. - await toggleScreenOption( 'Tips' ); + // Guide should be closed + welcomeGuide = await page.$( '.edit-post-welcome-guide' ); + expect( welcomeGuide ).toBeNull(); - // Tips should once again appear. - nuxTipElements = await page.$$( '.nux-dot-tip' ); - expect( nuxTipElements ).toHaveLength( 1 ); + // Manually open the guide + await clickOnMoreMenuItem( 'Welcome Guide' ); - // Tips should be enabled in localStorage as well. - areTipsEnabled = await getTipsEnabled( page ); - expect( areTipsEnabled ).toEqual( true ); + // Guide should be open + welcomeGuide = await page.$( '.edit-post-welcome-guide' ); + expect( welcomeGuide ).not.toBeNull(); } ); } ); diff --git a/packages/nux/src/components/guide/index.js b/packages/nux/src/components/guide/index.js index ab7b280f070a1c..3377462e42b783 100644 --- a/packages/nux/src/components/guide/index.js +++ b/packages/nux/src/components/guide/index.js @@ -42,7 +42,11 @@ export function Guide( { children, className, finishButtonText, isMobile, onFini } return ( - + Date: Mon, 25 Nov 2019 16:44:08 +0100 Subject: [PATCH 08/22] Welcome guide: Mark Guide as __experimental, as we may want to move it to @wordpress/components --- packages/edit-post/src/components/welcome-guide-modal/index.js | 2 +- packages/nux/src/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/edit-post/src/components/welcome-guide-modal/index.js b/packages/edit-post/src/components/welcome-guide-modal/index.js index 8674af6b1db625..4f85326f7bc6b7 100644 --- a/packages/edit-post/src/components/welcome-guide-modal/index.js +++ b/packages/edit-post/src/components/welcome-guide-modal/index.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { useSelect, useDispatch } from '@wordpress/data'; -import { Guide } from '@wordpress/nux'; +import { __experimentalGuide as Guide } from '@wordpress/nux'; import { __ } from '@wordpress/i18n'; import { __experimentalCreateInterpolateElement } from '@wordpress/element'; diff --git a/packages/nux/src/index.js b/packages/nux/src/index.js index ed6d38620bb8bb..cd3ab4954364b6 100644 --- a/packages/nux/src/index.js +++ b/packages/nux/src/index.js @@ -4,4 +4,4 @@ import './store'; export { default as DotTip } from './components/dot-tip'; -export { default as Guide } from './components/guide'; +export { default as __experimentalGuide } from './components/guide'; From 1905df472f2e05edd8b3e02e6b996a8c2240ee39 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 25 Nov 2019 16:44:33 +0100 Subject: [PATCH 09/22] Welcome guide: Add README.md --- packages/nux/src/components/guide/README.md | 56 +++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 packages/nux/src/components/guide/README.md diff --git a/packages/nux/src/components/guide/README.md b/packages/nux/src/components/guide/README.md new file mode 100644 index 00000000000000..6d457c14b78bf5 --- /dev/null +++ b/packages/nux/src/components/guide/README.md @@ -0,0 +1,56 @@ +Guide +======== + +`Guide` is a React component that renders a _user guide_ in a modal. The guide consists of several `Guide.Page` components which the user can step through one by one. The guide is finished when the modal is closed or when the user clicks _Finish_ on the last page of the guide. + +## Usage + +```jsx +function MyTutorial() { + const [ isOpen, setIsOpen ] = useState( true ); + + if ( ! isOpen ) { + return null; + } + + setIsOpen( false ) }> + +

Welcome to the ACME Store! Select a category to begin browsing our wares.

+
+ +

When you find something you love, click Add to Cart to add the product to your shopping cart.

+
+
+} +``` + +## Props + +The component accepts the following props: + +### onFinish + +A function which is called when the guide is finished. The guide is finished when the modal is closed or when the user clicks _Finish_ on the last page of the guide. + +- Type: `function` +- Required: Yes + +### children + +A list of `Guide.Page` components. One page is shown at a time. + +- Required: Yes + +### className + +A custom class to add to the modal. + +- Type: `string` +- Required: No + +### finishButtonText + +Use this to customize the label of the _Finish_ button shown at the end of the guide. + +- Type: `string` +- Required: No From 4c3682f624c06d6d619a2681519bc0824b7dc7c1 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 25 Nov 2019 16:57:25 +0100 Subject: [PATCH 10/22] Welcome guide: Rename WelcomeGuideModal to WelcomeGuide --- .../edit-post/src/components/layout/index.js | 4 +-- .../images.js | 0 .../index.js | 28 +++++++++---------- .../style.scss | 2 +- packages/edit-post/src/style.scss | 2 +- .../guide/test/__snapshots__/index.js.snap | 1 + 6 files changed, 19 insertions(+), 18 deletions(-) rename packages/edit-post/src/components/{welcome-guide-modal => welcome-guide}/images.js (100%) rename packages/edit-post/src/components/{welcome-guide-modal => welcome-guide}/index.js (64%) rename packages/edit-post/src/components/{welcome-guide-modal => welcome-guide}/style.scss (95%) diff --git a/packages/edit-post/src/components/layout/index.js b/packages/edit-post/src/components/layout/index.js index 141af0f7b63fe3..db618a86d16d9e 100644 --- a/packages/edit-post/src/components/layout/index.js +++ b/packages/edit-post/src/components/layout/index.js @@ -47,7 +47,7 @@ import Sidebar from '../sidebar'; import MetaBoxes from '../meta-boxes'; import PluginPostPublishPanel from '../sidebar/plugin-post-publish-panel'; import PluginPrePublishPanel from '../sidebar/plugin-pre-publish-panel'; -import WelcomeGuideModal from '../welcome-guide-modal'; +import WelcomeGuide from '../welcome-guide'; function Layout( { isMobileViewport } ) { const { closePublishSidebar, togglePublishSidebar } = useDispatch( 'core/edit-post' ); @@ -142,7 +142,7 @@ function Layout( { isMobileViewport } ) { - + { showPageTemplatePicker && <__experimentalPageTemplatePicker /> } diff --git a/packages/edit-post/src/components/welcome-guide-modal/images.js b/packages/edit-post/src/components/welcome-guide/images.js similarity index 100% rename from packages/edit-post/src/components/welcome-guide-modal/images.js rename to packages/edit-post/src/components/welcome-guide/images.js diff --git a/packages/edit-post/src/components/welcome-guide-modal/index.js b/packages/edit-post/src/components/welcome-guide/index.js similarity index 64% rename from packages/edit-post/src/components/welcome-guide-modal/index.js rename to packages/edit-post/src/components/welcome-guide/index.js index 4f85326f7bc6b7..27cda2b7dd5137 100644 --- a/packages/edit-post/src/components/welcome-guide-modal/index.js +++ b/packages/edit-post/src/components/welcome-guide/index.js @@ -11,7 +11,7 @@ import { __experimentalCreateInterpolateElement } from '@wordpress/element'; */ import { CanvasImage, EditorImage, BlockLibraryImage, InserterIconImage } from './images'; -export default function WelcomeGuideModal() { +export default function WelcomeGuide() { const areTipsEnabled = useSelect( ( select ) => select( 'core/nux' ).areTipsEnabled() ); const { disableTips } = useDispatch( 'core/nux' ); @@ -27,38 +27,38 @@ export default function WelcomeGuideModal() { onFinish={ disableTips } > - -

+ +

{ __( 'Welcome to the Block Editor' ) }

- -

+ +

{ __( 'In the WordPress editor, each paragraph, image, or video is presented as a distinct “block” of content.' ) }

- -

+ +

{ __( 'Make each block your own' ) }

- -

+ +

{ __( 'Each block comes with its own set of controls for changing things like color, width, and alignment. These will show and hide automatically when you have a block selected.' ) }

- -

+ +

{ __( 'Get to know the Block Library' ) }

- -

+ +

{ __experimentalCreateInterpolateElement( __( 'All of the blocks available to you live in the Block Library. You’ll find it wherever you see the icon.' ), { InserterIconImage: ( ), } diff --git a/packages/edit-post/src/components/welcome-guide-modal/style.scss b/packages/edit-post/src/components/welcome-guide/style.scss similarity index 95% rename from packages/edit-post/src/components/welcome-guide-modal/style.scss rename to packages/edit-post/src/components/welcome-guide/style.scss index 687ca0e85a94f7..e73c1dce01ea8b 100644 --- a/packages/edit-post/src/components/welcome-guide-modal/style.scss +++ b/packages/edit-post/src/components/welcome-guide/style.scss @@ -1,4 +1,4 @@ -.edit-post-welcome-guide-modal { +.edit-post-welcome-guide { $image-height: 300px; $image-width: 320px; diff --git a/packages/edit-post/src/style.scss b/packages/edit-post/src/style.scss index 556082be5bcf26..43b69c59da22cc 100644 --- a/packages/edit-post/src/style.scss +++ b/packages/edit-post/src/style.scss @@ -24,7 +24,7 @@ $footer-height: $icon-button-size-small; @import "./components/text-editor/style.scss"; @import "./components/visual-editor/style.scss"; @import "./components/options-modal/style.scss"; -@import "./components/welcome-guide-modal/style.scss"; +@import "./components/welcome-guide/style.scss"; /** diff --git a/packages/nux/src/components/guide/test/__snapshots__/index.js.snap b/packages/nux/src/components/guide/test/__snapshots__/index.js.snap index df62eea1a049c5..f476989e53ac17 100644 --- a/packages/nux/src/components/guide/test/__snapshots__/index.js.snap +++ b/packages/nux/src/components/guide/test/__snapshots__/index.js.snap @@ -3,6 +3,7 @@ exports[`Guide renders when there are pages 1`] = ` Date: Mon, 25 Nov 2019 17:15:03 +0100 Subject: [PATCH 11/22] Welcome guide: Update fixtures --- package-lock.json | 1 + .../options-modal/test/__snapshots__/index.js.snap | 3 --- .../test/__snapshots__/index.js.snap | 10 ---------- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 50451a27eb7aed..7e5b76569b2896 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8125,6 +8125,7 @@ "@wordpress/data": "file:packages/data", "@wordpress/element": "file:packages/element", "@wordpress/i18n": "file:packages/i18n", + "classnames": "^2.2.5", "lodash": "^4.17.15", "rememo": "^3.0.0" } diff --git a/packages/edit-post/src/components/options-modal/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/options-modal/test/__snapshots__/index.js.snap index 401d2d952dbab3..f418cd5a335268 100644 --- a/packages/edit-post/src/components/options-modal/test/__snapshots__/index.js.snap +++ b/packages/edit-post/src/components/options-modal/test/__snapshots__/index.js.snap @@ -12,9 +12,6 @@ exports[`OptionsModal should match snapshot when the modal is active 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 +33,5 @@ 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. - `; From ed026a1362f8e0109b60360775675a3a258add25 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 28 Nov 2019 11:41:10 +0100 Subject: [PATCH 12/22] Welcome guide: Rename Guide.Page to GuidePage --- .../src/components/welcome-guide/index.js | 14 ++++++------- packages/nux/src/components/guide/README.md | 12 +++++------ packages/nux/src/components/guide/index.js | 10 +-------- packages/nux/src/components/guide/page.js | 3 +++ .../guide/test/__snapshots__/index.js.snap | 4 ++-- .../nux/src/components/guide/test/index.js | 21 ++++++++++--------- packages/nux/src/index.js | 1 + 7 files changed, 31 insertions(+), 34 deletions(-) create mode 100644 packages/nux/src/components/guide/page.js diff --git a/packages/edit-post/src/components/welcome-guide/index.js b/packages/edit-post/src/components/welcome-guide/index.js index 27cda2b7dd5137..0ec9f4dbd63f59 100644 --- a/packages/edit-post/src/components/welcome-guide/index.js +++ b/packages/edit-post/src/components/welcome-guide/index.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { useSelect, useDispatch } from '@wordpress/data'; -import { __experimentalGuide as Guide } from '@wordpress/nux'; +import { __experimentalGuide as Guide, __experimentalGuidePage as GuidePage } from '@wordpress/nux'; import { __ } from '@wordpress/i18n'; import { __experimentalCreateInterpolateElement } from '@wordpress/element'; @@ -27,7 +27,7 @@ export default function WelcomeGuide() { onFinish={ disableTips } > - +

{ __( 'Welcome to the Block Editor' ) }

@@ -35,9 +35,9 @@ export default function WelcomeGuide() {

{ __( 'In the WordPress editor, each paragraph, image, or video is presented as a distinct “block” of content.' ) }

-
+ - +

{ __( 'Make each block your own' ) }

@@ -45,9 +45,9 @@ export default function WelcomeGuide() {

{ __( 'Each block comes with its own set of controls for changing things like color, width, and alignment. These will show and hide automatically when you have a block selected.' ) }

-
+ - +

{ __( 'Get to know the Block Library' ) }

@@ -64,7 +64,7 @@ export default function WelcomeGuide() { } ) }

-
+ ); diff --git a/packages/nux/src/components/guide/README.md b/packages/nux/src/components/guide/README.md index 6d457c14b78bf5..0c9fdacaf784d4 100644 --- a/packages/nux/src/components/guide/README.md +++ b/packages/nux/src/components/guide/README.md @@ -1,7 +1,7 @@ Guide ======== -`Guide` is a React component that renders a _user guide_ in a modal. The guide consists of several `Guide.Page` components which the user can step through one by one. The guide is finished when the modal is closed or when the user clicks _Finish_ on the last page of the guide. +`Guide` is a React component that renders a _user guide_ in a modal. The guide consists of several `GuidePage` components which the user can step through one by one. The guide is finished when the modal is closed or when the user clicks _Finish_ on the last page of the guide. ## Usage @@ -14,12 +14,12 @@ function MyTutorial() { } setIsOpen( false ) }> - +

Welcome to the ACME Store! Select a category to begin browsing our wares.

-
- + +

When you find something you love, click Add to Cart to add the product to your shopping cart.

-
+
} ``` @@ -37,7 +37,7 @@ A function which is called when the guide is finished. The guide is finished whe ### children -A list of `Guide.Page` components. One page is shown at a time. +A list of `GuidePage` components. One page is shown at a time. - Required: Yes diff --git a/packages/nux/src/components/guide/index.js b/packages/nux/src/components/guide/index.js index 3377462e42b783..4474d120d24cc8 100644 --- a/packages/nux/src/components/guide/index.js +++ b/packages/nux/src/components/guide/index.js @@ -103,14 +103,6 @@ export function Guide( { children, className, finishButtonText, isMobile, onFini ); } -export function Page( props ) { - return
; -} - -const EnhancedGuide = withSelect( ( select ) => ( { +export default withSelect( ( select ) => ( { isMobile: select( 'core/viewport' ).isViewportMatch( '< small' ), } ) )( Guide ); - -EnhancedGuide.Page = Page; - -export default EnhancedGuide; diff --git a/packages/nux/src/components/guide/page.js b/packages/nux/src/components/guide/page.js new file mode 100644 index 00000000000000..d8f0b582e8f9b7 --- /dev/null +++ b/packages/nux/src/components/guide/page.js @@ -0,0 +1,3 @@ +export default function GuidePage( props ) { + return
; +} diff --git a/packages/nux/src/components/guide/test/__snapshots__/index.js.snap b/packages/nux/src/components/guide/test/__snapshots__/index.js.snap index f476989e53ac17..a961ce75c06179 100644 --- a/packages/nux/src/components/guide/test/__snapshots__/index.js.snap +++ b/packages/nux/src/components/guide/test/__snapshots__/index.js.snap @@ -17,9 +17,9 @@ exports[`Guide renders when there are pages 1`] = `
- + Page 1 - +
diff --git a/packages/nux/src/components/guide/test/index.js b/packages/nux/src/components/guide/test/index.js index 779a73c2c41393..52d2bef3d96aee 100644 --- a/packages/nux/src/components/guide/test/index.js +++ b/packages/nux/src/components/guide/test/index.js @@ -11,7 +11,8 @@ import { Modal } from '@wordpress/components'; /** * Internal dependencies */ -import { Guide, Page } from '../'; +import { Guide } from '../'; +import GuidePage from '../page'; import PageControl from '../page-control'; describe( 'Guide', () => { @@ -23,8 +24,8 @@ describe( 'Guide', () => { it( 'renders when there are pages', () => { const wrapper = shallow( - Page 1 - Page 2 + Page 1 + Page 2 ); expect( wrapper ).toMatchSnapshot(); @@ -33,8 +34,8 @@ describe( 'Guide', () => { it( 'hides back button and shows forward button on the first page', () => { const wrapper = shallow( - Page 1 - Page 2 + Page 1 + Page 2 ); expect( wrapper.find( PageControl ).prop( 'currentPage' ) ).toBe( 0 ); @@ -46,8 +47,8 @@ describe( 'Guide', () => { it( 'shows back button and shows finish button on the last page', () => { const wrapper = shallow( - Page 1 - Page 2 + Page 1 + Page 2 ); wrapper.find( '.nux-guide__forward-button' ).simulate( 'click' ); @@ -60,7 +61,7 @@ describe( 'Guide', () => { it( 'shows the finish button inline with the content on mobile', () => { const wrapper = shallow( - Page 1 + Page 1 ); expect( wrapper.find( '.nux-guide__finish-button' ) ).toHaveLength( 0 ); @@ -71,7 +72,7 @@ describe( 'Guide', () => { const onFinish = jest.fn(); const wrapper = shallow( - Page 1 + Page 1 ); wrapper.find( '.nux-guide__finish-button' ).simulate( 'click' ); @@ -82,7 +83,7 @@ describe( 'Guide', () => { const onFinish = jest.fn(); const wrapper = shallow( - Page 1 + Page 1 ); wrapper.find( Modal ).prop( 'onRequestClose' )(); diff --git a/packages/nux/src/index.js b/packages/nux/src/index.js index cd3ab4954364b6..57d48439191ee3 100644 --- a/packages/nux/src/index.js +++ b/packages/nux/src/index.js @@ -5,3 +5,4 @@ import './store'; export { default as DotTip } from './components/dot-tip'; export { default as __experimentalGuide } from './components/guide'; +export { default as __experimentalGuidePage } from './components/guide/page'; From 6614977e7e64e9b271832bfda897b49e80ea0f54 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 28 Nov 2019 11:53:43 +0100 Subject: [PATCH 13/22] Welcome guide: Remove unnecessary onSelect prop --- packages/edit-post/src/plugins/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-post/src/plugins/index.js b/packages/edit-post/src/plugins/index.js index 7a8280a43c0bd1..669a870a8e53c6 100644 --- a/packages/edit-post/src/plugins/index.js +++ b/packages/edit-post/src/plugins/index.js @@ -30,7 +30,7 @@ registerPlugin( 'edit-post', { { __( 'Manage All Reusable Blocks' ) } - + ) } From cf6dbeed6faf7c2c28727b74ee3cd6982e566637 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 28 Nov 2019 13:29:54 +0100 Subject: [PATCH 14/22] Welcome guide: Move Guide to @wordpress/components --- docs/manifest-devhub.json | 6 ++++ package-lock.json | 1 - .../src}/guide/README.md | 0 .../src}/guide/finish-button.js | 6 +++- .../src}/guide/icons.js | 4 +-- .../src}/guide/index.js | 26 +++++++------- .../src}/guide/page-control.js | 4 +-- .../src}/guide/page.js | 0 .../src}/guide/style.scss | 36 ++++++++++--------- .../guide/test/__snapshots__/index.js.snap | 8 ++--- .../src}/guide/test/finish-button.js | 0 .../src}/guide/test/index.js | 35 +++++++++++------- .../src}/guide/test/page-control.js | 0 packages/components/src/index.js | 2 ++ packages/components/src/style.scss | 1 + .../src/components/welcome-guide/index.js | 2 +- packages/nux/package.json | 1 - packages/nux/src/index.js | 2 -- packages/nux/src/style.scss | 1 - 19 files changed, 79 insertions(+), 56 deletions(-) rename packages/{nux/src/components => components/src}/guide/README.md (100%) rename packages/{nux/src/components => components/src}/guide/finish-button.js (90%) rename packages/{nux/src/components => components/src}/guide/icons.js (88%) rename packages/{nux/src/components => components/src}/guide/index.js (75%) rename packages/{nux/src/components => components/src}/guide/page-control.js (84%) rename packages/{nux/src/components => components/src}/guide/page.js (100%) rename packages/{nux/src/components => components/src}/guide/style.scss (77%) rename packages/{nux/src/components => components/src}/guide/test/__snapshots__/index.js.snap (79%) rename packages/{nux/src/components => components/src}/guide/test/finish-button.js (100%) rename packages/{nux/src/components => components/src}/guide/test/index.js (64%) rename packages/{nux/src/components => components/src}/guide/test/page-control.js (100%) diff --git a/docs/manifest-devhub.json b/docs/manifest-devhub.json index 75573dd5ea1337..e36e868ac92e99 100644 --- a/docs/manifest-devhub.json +++ b/docs/manifest-devhub.json @@ -731,6 +731,12 @@ "markdown_source": "../packages/components/src/form-token-field/README.md", "parent": "components" }, + { + "title": "Guide", + "slug": "guide", + "markdown_source": "../packages/components/src/guide/README.md", + "parent": "components" + }, { "title": "NavigateRegions", "slug": "navigate-regions", diff --git a/package-lock.json b/package-lock.json index 7e5b76569b2896..50451a27eb7aed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8125,7 +8125,6 @@ "@wordpress/data": "file:packages/data", "@wordpress/element": "file:packages/element", "@wordpress/i18n": "file:packages/i18n", - "classnames": "^2.2.5", "lodash": "^4.17.15", "rememo": "^3.0.0" } diff --git a/packages/nux/src/components/guide/README.md b/packages/components/src/guide/README.md similarity index 100% rename from packages/nux/src/components/guide/README.md rename to packages/components/src/guide/README.md diff --git a/packages/nux/src/components/guide/finish-button.js b/packages/components/src/guide/finish-button.js similarity index 90% rename from packages/nux/src/components/guide/finish-button.js rename to packages/components/src/guide/finish-button.js index 6b90d77cb20f6e..baf1fccaff480a 100644 --- a/packages/nux/src/components/guide/finish-button.js +++ b/packages/components/src/guide/finish-button.js @@ -2,7 +2,11 @@ * WordPress dependencies */ import { useRef, useLayoutEffect } from '@wordpress/element'; -import { Button } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import Button from '../button'; export default function FinishButton( { className, onClick, children } ) { const button = useRef( null ); diff --git a/packages/nux/src/components/guide/icons.js b/packages/components/src/guide/icons.js similarity index 88% rename from packages/nux/src/components/guide/icons.js rename to packages/components/src/guide/icons.js index b7519b3a8052ae..02638ff58ec331 100644 --- a/packages/nux/src/components/guide/icons.js +++ b/packages/components/src/guide/icons.js @@ -1,7 +1,7 @@ /** - * WordPress dependencies + * Internal dependencies */ -import { SVG, Path, Circle } from '@wordpress/components'; +import { SVG, Path, Circle } from '../primitives/svg'; export const BackButtonIcon = () => ( diff --git a/packages/nux/src/components/guide/index.js b/packages/components/src/guide/index.js similarity index 75% rename from packages/nux/src/components/guide/index.js rename to packages/components/src/guide/index.js index 4474d120d24cc8..e70bb65fb84cd7 100644 --- a/packages/nux/src/components/guide/index.js +++ b/packages/components/src/guide/index.js @@ -6,19 +6,23 @@ import classnames from 'classnames'; /** * WordPress dependencies */ +import { useMediaQuery } from '@wordpress/compose'; import { useState, Children } from '@wordpress/element'; -import { Modal, KeyboardShortcuts, IconButton } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { withSelect } from '@wordpress/data'; /** * Internal dependencies */ +import Modal from '../modal'; +import KeyboardShortcuts from '../keyboard-shortcuts'; +import IconButton from '../icon-button'; import PageControl from './page-control'; import { BackButtonIcon, ForwardButtonIcon } from './icons'; import FinishButton from './finish-button'; -export function Guide( { children, className, finishButtonText, isMobile, onFinish } ) { +export default function Guide( { children, className, finishButtonText, onFinish } ) { + const isMobile = useMediaQuery( '(max-width: 600px)' ); + const [ currentPage, setCurrentPage ] = useState( 0 ); const numberOfPages = Children.count( children ); @@ -43,7 +47,7 @@ export function Guide( { children, className, finishButtonText, isMobile, onFini return ( @@ -53,7 +57,7 @@ export function Guide( { children, className, finishButtonText, isMobile, onFini right: goForward, } } /> -
+
{ children[ currentPage ] } @@ -63,10 +67,10 @@ export function Guide( { children, className, finishButtonText, isMobile, onFini ) } -
+
{ canGoBack && ( } onClick={ goBack } > @@ -80,7 +84,7 @@ export function Guide( { children, className, finishButtonText, isMobile, onFini /> { canGoForward && ( } onClick={ goForward } > @@ -89,7 +93,7 @@ export function Guide( { children, className, finishButtonText, isMobile, onFini ) } { ! isMobile && ! canGoForward && ( { finishButtonText || __( 'Finish' ) } @@ -102,7 +106,3 @@ export function Guide( { children, className, finishButtonText, isMobile, onFini ); } - -export default withSelect( ( select ) => ( { - isMobile: select( 'core/viewport' ).isViewportMatch( '< small' ), -} ) )( Guide ); diff --git a/packages/nux/src/components/guide/page-control.js b/packages/components/src/guide/page-control.js similarity index 84% rename from packages/nux/src/components/guide/page-control.js rename to packages/components/src/guide/page-control.js index 1e3d8ceb2ef671..6a5a451efd6b1d 100644 --- a/packages/nux/src/components/guide/page-control.js +++ b/packages/components/src/guide/page-control.js @@ -7,16 +7,16 @@ import { times } from 'lodash'; * WordPress dependencies */ import { __, sprintf } from '@wordpress/i18n'; -import { IconButton } from '@wordpress/components'; /** * Internal dependencies */ +import IconButton from '../icon-button'; import { PageControlIcon } from './icons'; export default function PageControl( { currentPage, numberOfPages, setCurrentPage } ) { return ( -
    +
      { times( numberOfPages, ( page ) => (
    • Page 1
      } onClick={[Function]} > diff --git a/packages/nux/src/components/guide/test/finish-button.js b/packages/components/src/guide/test/finish-button.js similarity index 100% rename from packages/nux/src/components/guide/test/finish-button.js rename to packages/components/src/guide/test/finish-button.js diff --git a/packages/nux/src/components/guide/test/index.js b/packages/components/src/guide/test/index.js similarity index 64% rename from packages/nux/src/components/guide/test/index.js rename to packages/components/src/guide/test/index.js index 52d2bef3d96aee..446186403e704c 100644 --- a/packages/nux/src/components/guide/test/index.js +++ b/packages/components/src/guide/test/index.js @@ -6,16 +6,26 @@ import { shallow } from 'enzyme'; /** * WordPress dependencies */ -import { Modal } from '@wordpress/components'; +import { useMediaQuery } from '@wordpress/compose'; /** * Internal dependencies */ -import { Guide } from '../'; +import Guide from '../'; import GuidePage from '../page'; import PageControl from '../page-control'; +import Modal from '../../modal'; + +jest.mock( '@wordpress/compose', () => ( { + ...jest.requireActual( '@wordpress/compose' ), + useMediaQuery: jest.fn(), +} ) ); describe( 'Guide', () => { + beforeEach( () => { + useMediaQuery.mockImplementation( () => false ); + } ); + it( 'renders nothing when there are no pages', () => { const wrapper = shallow( ); expect( wrapper.isEmptyRender() ).toBe( true ); @@ -39,9 +49,9 @@ describe( 'Guide', () => { ); expect( wrapper.find( PageControl ).prop( 'currentPage' ) ).toBe( 0 ); - expect( wrapper.find( '.nux-guide__back-button' ) ).toHaveLength( 0 ); - expect( wrapper.find( '.nux-guide__forward-button' ) ).toHaveLength( 1 ); - expect( wrapper.find( '.nux-guide__finish-button' ) ).toHaveLength( 0 ); + expect( wrapper.find( '.components-guide__back-button' ) ).toHaveLength( 0 ); + expect( wrapper.find( '.components-guide__forward-button' ) ).toHaveLength( 1 ); + expect( wrapper.find( '.components-guide__finish-button' ) ).toHaveLength( 0 ); } ); it( 'shows back button and shows finish button on the last page', () => { @@ -51,20 +61,21 @@ describe( 'Guide', () => { Page 2 ); - wrapper.find( '.nux-guide__forward-button' ).simulate( 'click' ); + wrapper.find( '.components-guide__forward-button' ).simulate( 'click' ); expect( wrapper.find( PageControl ).prop( 'currentPage' ) ).toBe( 1 ); - expect( wrapper.find( '.nux-guide__back-button' ) ).toHaveLength( 1 ); - expect( wrapper.find( '.nux-guide__forward-button' ) ).toHaveLength( 0 ); - expect( wrapper.find( '.nux-guide__finish-button' ) ).toHaveLength( 1 ); + expect( wrapper.find( '.components-guide__back-button' ) ).toHaveLength( 1 ); + expect( wrapper.find( '.components-guide__forward-button' ) ).toHaveLength( 0 ); + expect( wrapper.find( '.components-guide__finish-button' ) ).toHaveLength( 1 ); } ); it( 'shows the finish button inline with the content on mobile', () => { + useMediaQuery.mockImplementation( () => true ); const wrapper = shallow( - + Page 1 ); - expect( wrapper.find( '.nux-guide__finish-button' ) ).toHaveLength( 0 ); + expect( wrapper.find( '.components-guide__finish-button' ) ).toHaveLength( 0 ); expect( wrapper.findWhere( ( node ) => node.text() === 'Finish' ) ).toHaveLength( 1 ); } ); @@ -75,7 +86,7 @@ describe( 'Guide', () => { Page 1 ); - wrapper.find( '.nux-guide__finish-button' ).simulate( 'click' ); + wrapper.find( '.components-guide__finish-button' ).simulate( 'click' ); expect( onFinish ).toHaveBeenCalled(); } ); diff --git a/packages/nux/src/components/guide/test/page-control.js b/packages/components/src/guide/test/page-control.js similarity index 100% rename from packages/nux/src/components/guide/test/page-control.js rename to packages/components/src/guide/test/page-control.js diff --git a/packages/components/src/index.js b/packages/components/src/index.js index ff4e4f65b85dc5..eef936406b81b9 100644 --- a/packages/components/src/index.js +++ b/packages/components/src/index.js @@ -34,6 +34,8 @@ export { default as FormFileUpload } from './form-file-upload'; export { default as FormToggle } from './form-toggle'; export { default as FormTokenField } from './form-token-field'; export { default as __experimentalGradientPicker } from './gradient-picker'; +export { default as Guide } from './guide'; +export { default as GuidePage } from './guide/page'; export { default as Icon } from './icon'; export { default as IconButton } from './icon-button'; export { default as KeyboardShortcuts } from './keyboard-shortcuts'; diff --git a/packages/components/src/style.scss b/packages/components/src/style.scss index a21839bd27b3fb..27f6bf2b47a0dc 100644 --- a/packages/components/src/style.scss +++ b/packages/components/src/style.scss @@ -22,6 +22,7 @@ @import "./form-file-upload/style.scss"; @import "./form-toggle/style.scss"; @import "./form-token-field/style.scss"; +@import "./guide/style.scss"; @import "./higher-order/navigate-regions/style.scss"; @import "./icon-button/style.scss"; @import "./menu-group/style.scss"; diff --git a/packages/edit-post/src/components/welcome-guide/index.js b/packages/edit-post/src/components/welcome-guide/index.js index 0ec9f4dbd63f59..756098cfe476c7 100644 --- a/packages/edit-post/src/components/welcome-guide/index.js +++ b/packages/edit-post/src/components/welcome-guide/index.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { useSelect, useDispatch } from '@wordpress/data'; -import { __experimentalGuide as Guide, __experimentalGuidePage as GuidePage } from '@wordpress/nux'; +import { Guide, GuidePage } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { __experimentalCreateInterpolateElement } from '@wordpress/element'; diff --git a/packages/nux/package.json b/packages/nux/package.json index ab6471b73c9ec6..f358034d79dfff 100644 --- a/packages/nux/package.json +++ b/packages/nux/package.json @@ -27,7 +27,6 @@ "@wordpress/data": "file:../data", "@wordpress/element": "file:../element", "@wordpress/i18n": "file:../i18n", - "classnames": "^2.2.5", "lodash": "^4.17.15", "rememo": "^3.0.0" }, diff --git a/packages/nux/src/index.js b/packages/nux/src/index.js index 57d48439191ee3..a11d17bc96961a 100644 --- a/packages/nux/src/index.js +++ b/packages/nux/src/index.js @@ -4,5 +4,3 @@ import './store'; export { default as DotTip } from './components/dot-tip'; -export { default as __experimentalGuide } from './components/guide'; -export { default as __experimentalGuidePage } from './components/guide/page'; diff --git a/packages/nux/src/style.scss b/packages/nux/src/style.scss index 7f9613efb11a38..0df73ff851e9f9 100644 --- a/packages/nux/src/style.scss +++ b/packages/nux/src/style.scss @@ -1,2 +1 @@ @import "./components/dot-tip/style.scss"; -@import "./components/guide/style.scss"; From 0c1594a8c12d3eb072853d0905394de904faebc6 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 28 Nov 2019 13:36:54 +0100 Subject: [PATCH 15/22] Welcome guide: Remove snapshot test --- .../guide/test/__snapshots__/index.js.snap | 41 ------------------- packages/components/src/guide/test/index.js | 4 +- 2 files changed, 2 insertions(+), 43 deletions(-) delete mode 100644 packages/components/src/guide/test/__snapshots__/index.js.snap diff --git a/packages/components/src/guide/test/__snapshots__/index.js.snap b/packages/components/src/guide/test/__snapshots__/index.js.snap deleted file mode 100644 index 6f3d8ab2c754a1..00000000000000 --- a/packages/components/src/guide/test/__snapshots__/index.js.snap +++ /dev/null @@ -1,41 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Guide renders when there are pages 1`] = ` - - -
      - - Page 1 - -
      - - } - onClick={[Function]} - > - Next - -
      -
      -
      -`; diff --git a/packages/components/src/guide/test/index.js b/packages/components/src/guide/test/index.js index 446186403e704c..61b0ddae55f8fe 100644 --- a/packages/components/src/guide/test/index.js +++ b/packages/components/src/guide/test/index.js @@ -31,14 +31,14 @@ describe( 'Guide', () => { expect( wrapper.isEmptyRender() ).toBe( true ); } ); - it( 'renders when there are pages', () => { + it( 'renders one page at a time', () => { const wrapper = shallow( Page 1 Page 2 ); - expect( wrapper ).toMatchSnapshot(); + expect( wrapper.find( GuidePage ) ).toHaveLength( 1 ); } ); it( 'hides back button and shows forward button on the first page', () => { From c207456f57d8995dec72a5241f4c1c0b2ceac4bc Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 28 Nov 2019 14:20:42 +0100 Subject: [PATCH 16/22] Welcome guide: Use CSS to hide and show finish buton --- packages/components/src/guide/index.js | 12 ++++----- packages/components/src/guide/style.scss | 10 ++++++++ packages/components/src/guide/test/index.js | 25 ------------------- .../specs/editor/various/nux.test.js | 12 +++++++-- 4 files changed, 26 insertions(+), 33 deletions(-) diff --git a/packages/components/src/guide/index.js b/packages/components/src/guide/index.js index e70bb65fb84cd7..1ecd619d007662 100644 --- a/packages/components/src/guide/index.js +++ b/packages/components/src/guide/index.js @@ -6,7 +6,6 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useMediaQuery } from '@wordpress/compose'; import { useState, Children } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; @@ -21,8 +20,6 @@ import { BackButtonIcon, ForwardButtonIcon } from './icons'; import FinishButton from './finish-button'; export default function Guide( { children, className, finishButtonText, onFinish } ) { - const isMobile = useMediaQuery( '(max-width: 600px)' ); - const [ currentPage, setCurrentPage ] = useState( 0 ); const numberOfPages = Children.count( children ); @@ -61,8 +58,11 @@ export default function Guide( { children, className, finishButtonText, onFinish { children[ currentPage ] } - { isMobile && ! canGoForward && ( - + { ! canGoForward && ( + { finishButtonText || __( 'Finish' ) } ) } @@ -91,7 +91,7 @@ export default function Guide( { children, className, finishButtonText, onFinish { __( 'Next' ) } ) } - { ! isMobile && ! canGoForward && ( + { ! canGoForward && ( ( { - ...jest.requireActual( '@wordpress/compose' ), - useMediaQuery: jest.fn(), -} ) ); - describe( 'Guide', () => { - beforeEach( () => { - useMediaQuery.mockImplementation( () => false ); - } ); - it( 'renders nothing when there are no pages', () => { const wrapper = shallow( ); expect( wrapper.isEmptyRender() ).toBe( true ); @@ -68,17 +54,6 @@ describe( 'Guide', () => { expect( wrapper.find( '.components-guide__finish-button' ) ).toHaveLength( 1 ); } ); - it( 'shows the finish button inline with the content on mobile', () => { - useMediaQuery.mockImplementation( () => true ); - const wrapper = shallow( - - Page 1 - - ); - expect( wrapper.find( '.components-guide__finish-button' ) ).toHaveLength( 0 ); - expect( wrapper.findWhere( ( node ) => node.text() === 'Finish' ) ).toHaveLength( 1 ); - } ); - it( 'calls onFinish when the finish button is clicked', () => { const onFinish = jest.fn(); const wrapper = shallow( diff --git a/packages/e2e-tests/specs/editor/various/nux.test.js b/packages/e2e-tests/specs/editor/various/nux.test.js index 4cd83af01b49b2..d172f138cb50f2 100644 --- a/packages/e2e-tests/specs/editor/various/nux.test.js +++ b/packages/e2e-tests/specs/editor/various/nux.test.js @@ -40,8 +40,16 @@ describe( 'New User Experience (NUX)', () => { welcomeGuideText = await page.$eval( '.edit-post-welcome-guide', ( element ) => element.innerText ); expect( welcomeGuideText ).toContain( 'Get to know the Block Library' ); - // Click on the 'Get started' button - const [ getStartedButton ] = await page.$x( '//button[contains(text(), "Get started")]' ); + // Click on the *visible* 'Get started' button. There are two in the DOM + // but only one is shown depending on viewport size + let getStartedButton; + for ( const buttonHandle of await page.$x( '//button[contains(text(), "Get started")]' ) ) { + if ( + await page.evaluate( ( button ) => button.style.display !== 'none', buttonHandle ) + ) { + getStartedButton = buttonHandle; + } + } await getStartedButton.click(); // Guide should be closed From b2de4dff67457d8e41fabff4fa2032229f2e6ad4 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 28 Nov 2019 14:40:36 +0100 Subject: [PATCH 17/22] Welcome guide: Add a storybook --- .../components/src/guide/stories/index.js | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 packages/components/src/guide/stories/index.js diff --git a/packages/components/src/guide/stories/index.js b/packages/components/src/guide/stories/index.js new file mode 100644 index 00000000000000..3a96e1031e3968 --- /dev/null +++ b/packages/components/src/guide/stories/index.js @@ -0,0 +1,56 @@ +/** + * External dependencies + */ +import { times } from 'lodash'; +import { text, number } from '@storybook/addon-knobs'; + +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import Button from '../../button'; +import Guide from '../'; +import GuidePage from '../page'; + +export default { title: 'Components|Guide', component: Guide }; + +const ModalExample = ( { numberOfPages, ...props } ) => { + const [ isOpen, setOpen ] = useState( false ); + + const openGuide = () => setOpen( true ); + const closeGuide = () => setOpen( false ); + + const loremIpsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'; + + return ( + <> + + { isOpen && ( + + { times( numberOfPages, ( page ) => ( + +

      Page { page + 1 } of { numberOfPages }

      +

      { loremIpsum }

      +
      + ) ) } +
      + ) } + + ); +}; + +export const _default = () => { + const finishButtonText = text( 'finishButtonText', 'Finish' ); + const numberOfPages = number( 'numberOfPages', 3, { range: true, min: 1, max: 10, step: 1 } ); + + const modalProps = { + finishButtonText, + numberOfPages, + }; + + return ; +}; From 5f1f9dbcd8d3fcbe92899d44ca4fe255e26a10e0 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 28 Nov 2019 14:49:54 +0100 Subject: [PATCH 18/22] Welcome guide: Use break-small() mixin --- packages/components/src/guide/style.scss | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/components/src/guide/style.scss b/packages/components/src/guide/style.scss index c116da37fe462c..92044211ce3cd4 100644 --- a/packages/components/src/guide/style.scss +++ b/packages/components/src/guide/style.scss @@ -103,10 +103,11 @@ } &.components-guide__finish-button { + display: none; right: 0; - @media (max-width: $break-small) { - display: none; + @include break-small() { + display: unset; } } From 113c7aa01a02beacac7fc6074fac116cb5db4054 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 28 Nov 2019 15:55:28 +0100 Subject: [PATCH 19/22] Welcome guide: Generate storybook snapshot --- storybook/test/__snapshots__/index.js.snap | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/storybook/test/__snapshots__/index.js.snap b/storybook/test/__snapshots__/index.js.snap index 1c0741a0c3f8b7..b8a1abeec7cfd4 100644 --- a/storybook/test/__snapshots__/index.js.snap +++ b/storybook/test/__snapshots__/index.js.snap @@ -1826,6 +1826,16 @@ exports[`Storyshots Components|FontSizePicker Without Custom Sizes 1`] = ` `; +exports[`Storyshots Components|Guide Default 1`] = ` + +`; + exports[`Storyshots Components|Icon Colors 1`] = ` Array [
      Date: Fri, 29 Nov 2019 10:01:34 +0100 Subject: [PATCH 20/22] Welcome guide: Update @wordpress/components changelog --- packages/components/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 00cd959951484e..28dd4971244937 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -1,3 +1,9 @@ +# 8.3.0 (Unreleased) + +### New Features + +- Added a new `Guide` component which allows developers to easily present a user guide. + ## 8.2.0 (2019-08-29) ### New Features From 2352da6bb01ba9e27a11c29dfaf5016a0aee3183 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 29 Nov 2019 15:29:26 +0100 Subject: [PATCH 21/22] E2E tests: Reload page after disabling welcome guide / tips --- packages/e2e-test-utils/README.md | 14 ++++--- .../e2e-test-utils/src/create-new-post.js | 13 ++++--- packages/e2e-test-utils/src/index.js | 2 +- .../e2e-test-utils/src/observe-focus-loss.js | 37 +++++++++++++------ .../specs/editor/various/sidebar.test.js | 13 +++++-- 5 files changed, 54 insertions(+), 25 deletions(-) diff --git a/packages/e2e-test-utils/README.md b/packages/e2e-test-utils/README.md index 37d5f86d06cb95..6b2af5c5c6e1ed 100644 --- a/packages/e2e-test-utils/README.md +++ b/packages/e2e-test-utils/README.md @@ -137,6 +137,10 @@ _Parameters_ - _slug_ `string`: Plugin slug. +# **disableFocusLossObservation** + +Removes the focus loss listener that `enableFocusLossObservation()` adds. + # **disablePrePublishChecks** Disables Pre-publish checks. @@ -156,6 +160,11 @@ _Returns_ - `Promise`: Promise resolving when drag completes. +# **enableFocusLossObservation** + +Adds an event listener to the document which throws an error if there is a +loss of focus. + # **enablePageDialogAccept** Enables even listener which accepts a page dialog which @@ -319,11 +328,6 @@ _Returns_ - `Promise`: Promise that uses `mockCheck` to see if a request should be mocked with `mock`, and optionally transforms the response with `responseObjectTransform`. -# **observeFocusLoss** - -Binds to the document on page load which throws an error if a `focusout` -event occurs without a related target (i.e. focus loss). - # **openAllBlockInserterCategories** Opens all block inserter categories. diff --git a/packages/e2e-test-utils/src/create-new-post.js b/packages/e2e-test-utils/src/create-new-post.js index 91a95bf5216a45..3abf89d0e8e63b 100644 --- a/packages/e2e-test-utils/src/create-new-post.js +++ b/packages/e2e-test-utils/src/create-new-post.js @@ -26,14 +26,17 @@ export async function createNewPost( { content, excerpt, } ).slice( 1 ); + await visitAdminPage( 'post-new.php', query ); - await page.evaluate( ( _enableTips ) => { - const action = _enableTips ? 'enableTips' : 'disableTips'; - wp.data.dispatch( 'core/nux' )[ action ](); - }, enableTips ); + const areTipsEnabled = await page.evaluate( () => wp.data.select( 'core/nux' ).areTipsEnabled() ); + + if ( enableTips !== areTipsEnabled ) { + await page.evaluate( ( _enableTips ) => { + const action = _enableTips ? 'enableTips' : 'disableTips'; + wp.data.dispatch( 'core/nux' )[ action ](); + }, enableTips ); - if ( enableTips ) { await page.reload(); } } diff --git a/packages/e2e-test-utils/src/index.js b/packages/e2e-test-utils/src/index.js index 4d78447dec0872..adb2b2867f737d 100644 --- a/packages/e2e-test-utils/src/index.js +++ b/packages/e2e-test-utils/src/index.js @@ -27,7 +27,7 @@ export { installPlugin } from './install-plugin'; export { isCurrentURL } from './is-current-url'; export { isInDefaultBlock } from './is-in-default-block'; export { loginUser } from './login-user'; -export { observeFocusLoss } from './observe-focus-loss'; +export { enableFocusLossObservation, disableFocusLossObservation } from './observe-focus-loss'; export { openAllBlockInserterCategories } from './open-all-block-inserter-categories'; export { openDocumentSettingsSidebar } from './open-document-settings-sidebar'; export { openGlobalBlockInserter } from './open-global-block-inserter'; diff --git a/packages/e2e-test-utils/src/observe-focus-loss.js b/packages/e2e-test-utils/src/observe-focus-loss.js index 13e541de27a8fe..1266d0997c1f29 100644 --- a/packages/e2e-test-utils/src/observe-focus-loss.js +++ b/packages/e2e-test-utils/src/observe-focus-loss.js @@ -1,15 +1,30 @@ /** - * Binds to the document on page load which throws an error if a `focusout` - * event occurs without a related target (i.e. focus loss). + * Adds an event listener to the document which throws an error if there is a + * loss of focus. */ -export function observeFocusLoss() { - page.on( 'load', () => { - page.evaluate( () => { - document.body.addEventListener( 'focusout', ( event ) => { - if ( ! event.relatedTarget ) { - throw new Error( 'Unexpected focus loss' ); - } - } ); - } ); +export async function enableFocusLossObservation() { + await page.evaluate( () => { + if ( window._detectFocusLoss ) { + document.body.removeEventListener( 'focusout', window._detectFocusLoss ); + } + + window._detectFocusLoss = ( event ) => { + if ( ! event.relatedTarget ) { + throw new Error( 'Unexpected focus loss' ); + } + }; + + document.body.addEventListener( 'focusout', window._detectFocusLoss ); + } ); +} + +/** + * Removes the focus loss listener that `enableFocusLossObservation()` adds. + */ +export async function disableFocusLossObservation() { + await page.evaluate( () => { + if ( window._detectFocusLoss ) { + document.body.removeEventListener( 'focusout', window._detectFocusLoss ); + } } ); } diff --git a/packages/e2e-tests/specs/editor/various/sidebar.test.js b/packages/e2e-tests/specs/editor/various/sidebar.test.js index d0768f916f0f63..90dc69789de644 100644 --- a/packages/e2e-tests/specs/editor/various/sidebar.test.js +++ b/packages/e2e-tests/specs/editor/various/sidebar.test.js @@ -5,7 +5,8 @@ import { clearLocalStorage, createNewPost, findSidebarPanelWithTitle, - observeFocusLoss, + enableFocusLossObservation, + disableFocusLossObservation, openDocumentSettingsSidebar, pressKeyWithModifier, setBrowserViewport, @@ -16,14 +17,15 @@ const ACTIVE_SIDEBAR_TAB_SELECTOR = '.edit-post-sidebar__panel-tab.is-active'; const ACTIVE_SIDEBAR_BUTTON_TEXT = 'Document'; describe( 'Sidebar', () => { - beforeAll( () => { - observeFocusLoss(); + afterEach( () => { + disableFocusLossObservation(); } ); it( 'should have sidebar visible at the start with document sidebar active on desktop', async () => { await setBrowserViewport( 'large' ); await clearLocalStorage(); await createNewPost(); + await enableFocusLossObservation(); const { nodesCount, content, height, width } = await page.$$eval( ACTIVE_SIDEBAR_TAB_SELECTOR, ( nodes ) => { const firstNode = nodes[ 0 ]; return { @@ -49,6 +51,7 @@ describe( 'Sidebar', () => { await setBrowserViewport( 'small' ); await clearLocalStorage(); await createNewPost(); + await enableFocusLossObservation(); const sidebar = await page.$( SIDEBAR_SELECTOR ); expect( sidebar ).toBeNull(); } ); @@ -57,6 +60,7 @@ describe( 'Sidebar', () => { await setBrowserViewport( 'large' ); await clearLocalStorage(); await createNewPost(); + await enableFocusLossObservation(); const sidebars = await page.$$( SIDEBAR_SELECTOR ); expect( sidebars ).toHaveLength( 1 ); @@ -72,6 +76,7 @@ describe( 'Sidebar', () => { await setBrowserViewport( 'large' ); await clearLocalStorage(); await createNewPost(); + await enableFocusLossObservation(); await setBrowserViewport( 'small' ); const sidebarsMobile = await page.$$( SIDEBAR_SELECTOR ); @@ -85,6 +90,7 @@ describe( 'Sidebar', () => { it( 'should preserve tab order while changing active tab', async () => { await createNewPost(); + await enableFocusLossObservation(); // Region navigate to Sidebar. await pressKeyWithModifier( 'ctrl', '`' ); @@ -112,6 +118,7 @@ describe( 'Sidebar', () => { it( 'should be possible to programmatically remove Document Settings panels', async () => { await createNewPost(); + await enableFocusLossObservation(); await openDocumentSettingsSidebar(); From 7b8773dc7a22408e13f984fa39604a2d3e303f90 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 2 Dec 2019 14:11:53 +0100 Subject: [PATCH 22/22] Welcome guide: Close guide when user clicks on overlay --- packages/components/src/guide/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/components/src/guide/index.js b/packages/components/src/guide/index.js index 1ecd619d007662..3d0a905741e14b 100644 --- a/packages/components/src/guide/index.js +++ b/packages/components/src/guide/index.js @@ -45,7 +45,6 @@ export default function Guide( { children, className, finishButtonText, onFinish return (