From 1e2d8b0df1147b144aea91406e3a71740f3785e9 Mon Sep 17 00:00:00 2001 From: Andrei Draganescu Date: Mon, 10 Oct 2022 19:30:53 +0300 Subject: [PATCH] Introduce distraction free mode (#41740) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhances the effect of the reduceUI preference - hide all the chrome of the editor, including the block toolbar, top bar, most top bar buttons, insertion point and closes any sidebars Co-authored-by: Matias Ventura <548849+mtias@users.noreply.github.com> Co-authored-by: James Koster <846565+jameskoster@users.noreply.github.com> * snapshot update * remove useless prop * Adds framer motion animation to header elements in distraction free mode. Co-authored-by: Matias Ventura <548849+mtias@users.noreply.github.com> Co-authored-by: James Koster <846565+jameskoster@users.noreply.github.com> * Adjusts the bottom distance of snackbars for distraction free mode. Co-authored-by: Javier Arce <4933+javierarce@users.noreply.github.com> * Deals with editor notices: - moves them to the header of the interface skeleton - moves them on top of the interface header to make them dismissable Co-authored-by: Javier Arce <4933+javierarce@users.noreply.github.com> Co-authored-by: Joen A. <1204802+jasmussen@users.noreply.github.com> * Limits notices in interface header only when distraction free mode is on. Co-authored-by: Matias Ventura <548849+mtias@users.noreply.github.com> * Handles toolbar focus in distraction free mode: - Shift+Tab shows the top toolbar and allos reverse tabbing - Alt+F10 is disabled like in other situations when focusin the toolbar not possible Co-authored-by: Alex Stine <13755480+alexstine@users.noreply.github.com> * Removes wrong visual margin artefact for notifications in DFM Co-authored-by: Javier Arce <4933+javierarce@users.noreply.github.com> * refactores reducedUI to distractionFree and hasReducedUI to isDistractionFree * Fixes the page jump in distraction free mode. Part of this bug but with a different cause exists in trunk as well. Co-authored-by: Ella van Durpe <4710635+ellatrix@users.noreply.github.com> * Bulk adds the same distraction free mode toggle effects to: - toggle in the writing menu - the keyboard shortcut - the preference toggle Adds a new action to set a feature to a desired value. Some duplication, not sure how to DRY. * Removes "reduce UI" from the prefferences modal. Co-authored-by: Matias Ventura <548849+mtias@users.noreply.github.com> * adds back slash to allowed chars in shortcuts visual expression * fix snapshot and pref modal test * fix pref modal bug introduced by prev commit * use only one useSelect for easier mock implementation * adds correct order of mocked return values for useSelect * fix order of flags in the prefferences modal * Moves focus on distraction free toggle to first block via block selection. Unclear what to do when there is not a post edited by a block editor, but one where the flow of the block list is not linear. Co-authored-by: Alex Stine <13755480+alexstine@users.noreply.github.com> * Remove double border in header and add subtle backdrop transparency. * Let's not use "Toggle interface" as a name. * Removes the inline toolbar in distraction free mode. For those who have tested this PR run this in console to unset the preference, which is not otherwise visible anywhere: ``` wp.data.dispatch( 'core/preferences' ).set('core/edit-post', 'inlineToolbar', false); ``` Co-authored-by: Matias Ventura <548849+mtias@users.noreply.github.com> * Adds the mode selector, undo, redo and doc stats back to the toolbar. Co-authored-by: Matias Ventura <548849+mtias@users.noreply.github.com> * creates the distraction free experiment * Revert "creates the distraction free experiment" This reverts commit 4565b66ea427475a58ec74a98b01fb52c56be47d. * Combines two css rules into one. Co-authored-by: Matias Ventura <548849+mtias@users.noreply.github.com> * Undo a new public API `setFeature` in the prefferences package. Use the store directly instead. Co-authored-by: Daniel Richards <677833+talldan@users.noreply.github.com> * Fixes small nits in code. Co-authored-by: Ben Dwyer <275961+scruffian@users.noreply.github.com> Co-authored-by: Matias Ventura <548849+mtias@users.noreply.github.com> Co-authored-by: James Koster <846565+jameskoster@users.noreply.github.com> Co-authored-by: Javier Arce <4933+javierarce@users.noreply.github.com> Co-authored-by: Joen A. <1204802+jasmussen@users.noreply.github.com> Co-authored-by: Alex Stine <13755480+alexstine@users.noreply.github.com> Co-authored-by: Ella van Durpe <4710635+ellatrix@users.noreply.github.com> Co-authored-by: Matías Ventura Co-authored-by: Daniel Richards <677833+talldan@users.noreply.github.com> Co-authored-by: Ben Dwyer <275961+scruffian@users.noreply.github.com> --- .../block-list/use-in-between-inserter.js | 2 +- .../components/block-parent-selector/index.js | 6 +- .../block-settings-dropdown.js | 6 +- .../src/components/block-toolbar/index.js | 10 ++-- .../components/block-tools/insertion-point.js | 12 ++++ .../block-tools/selected-block-popover.js | 15 ++++- .../edit-post/src/components/header/index.js | 43 +++++++++++---- .../src/components/header/more-menu/index.js | 2 +- .../src/components/header/style.scss | 44 +++++++++++++++ .../components/header/writing-menu/index.js | 55 ++++++++++++++++++- .../components/keyboard-shortcuts/index.js | 52 +++++++++++++++++- .../edit-post/src/components/layout/index.js | 21 +++++-- .../src/components/layout/style.scss | 7 +++ .../src/components/preferences-modal/index.js | 54 +++++++++++------- .../options/enable-feature.js | 7 ++- .../test/__snapshots__/index.js.snap | 16 +++--- .../preferences-modal/test/index.js | 6 +- packages/edit-post/src/editor.js | 8 +-- .../provider/use-block-editor-settings.js | 2 +- .../components/interface-skeleton/index.js | 36 +++++++++++- packages/keycodes/src/index.js | 2 +- .../preference-toggle-menu-item/index.js | 4 ++ 22 files changed, 332 insertions(+), 78 deletions(-) diff --git a/packages/block-editor/src/components/block-list/use-in-between-inserter.js b/packages/block-editor/src/components/block-list/use-in-between-inserter.js index 22ad418d2e7297..2053c8f3eb4fc9 100644 --- a/packages/block-editor/src/components/block-list/use-in-between-inserter.js +++ b/packages/block-editor/src/components/block-list/use-in-between-inserter.js @@ -15,7 +15,7 @@ export function useInBetweenInserter() { const openRef = useContext( InsertionPointOpenRef ); const isInBetweenInserterDisabled = useSelect( ( select ) => - select( blockEditorStore ).getSettings().hasReducedUI || + select( blockEditorStore ).getSettings().isDistractionFree || select( blockEditorStore ).__unstableGetEditorMode() === 'zoom-out', [] ); diff --git a/packages/block-editor/src/components/block-parent-selector/index.js b/packages/block-editor/src/components/block-parent-selector/index.js index caf488ac06ec6f..e338a10f170695 100644 --- a/packages/block-editor/src/components/block-parent-selector/index.js +++ b/packages/block-editor/src/components/block-parent-selector/index.js @@ -24,7 +24,7 @@ import { store as blockEditorStore } from '../../store'; export default function BlockParentSelector() { const { selectBlock, toggleBlockHighlight } = useDispatch( blockEditorStore ); - const { firstParentClientId, shouldHide, hasReducedUI } = useSelect( + const { firstParentClientId, shouldHide, isDistractionFree } = useSelect( ( select ) => { const { getBlockName, @@ -46,7 +46,7 @@ export default function BlockParentSelector() { '__experimentalParentSelector', true ), - hasReducedUI: settings.hasReducedUI, + isDistractionFree: settings.isDistractionFree, }; }, [] @@ -59,7 +59,7 @@ export default function BlockParentSelector() { const { gestures: showMoversGestures } = useShowMoversGestures( { ref: nodeRef, onChange( isFocused ) { - if ( isFocused && hasReducedUI ) { + if ( isFocused && isDistractionFree ) { return; } toggleBlockHighlight( firstParentClientId, isFocused ); diff --git a/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js b/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js index 97ef1c52b6dd97..2076b4bb49091d 100644 --- a/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js +++ b/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js @@ -63,7 +63,7 @@ export function BlockSettingsDropdown( { const firstBlockClientId = blockClientIds[ 0 ]; const { firstParentClientId, - hasReducedUI, + isDistractionFree, onlyBlock, parentBlockType, previousBlockClientId, @@ -90,7 +90,7 @@ export function BlockSettingsDropdown( { return { firstParentClientId: _firstParentClientId, - hasReducedUI: getSettings().hasReducedUI, + isDistractionFree: getSettings().isDistractionFree, onlyBlock: 1 === getBlockCount(), parentBlockType: getActiveBlockVariation( @@ -182,7 +182,7 @@ export function BlockSettingsDropdown( { const { gestures: showParentOutlineGestures } = useShowMoversGestures( { ref: selectParentButtonRef, onChange( isFocused ) { - if ( isFocused && hasReducedUI ) { + if ( isFocused && isDistractionFree ) { return; } toggleBlockHighlight( firstParentClientId, isFocused ); diff --git a/packages/block-editor/src/components/block-toolbar/index.js b/packages/block-editor/src/components/block-toolbar/index.js index 07d4e861f60947..b2160b3db4b6b6 100644 --- a/packages/block-editor/src/components/block-toolbar/index.js +++ b/packages/block-editor/src/components/block-toolbar/index.js @@ -34,7 +34,7 @@ const BlockToolbar = ( { hideDragHandle } ) => { blockClientId, blockType, hasFixedToolbar, - hasReducedUI, + isDistractionFree, isValid, isVisual, isContentLocked, @@ -60,7 +60,7 @@ const BlockToolbar = ( { hideDragHandle } ) => { selectedBlockClientId && getBlockType( getBlockName( selectedBlockClientId ) ), hasFixedToolbar: settings.hasFixedToolbar, - hasReducedUI: settings.hasReducedUI, + isDistractionFree: settings.isDistractionFree, rootClientId: blockRootClientId, isValid: selectedBlockClientIds.every( ( id ) => isBlockValid( id ) @@ -82,7 +82,7 @@ const BlockToolbar = ( { hideDragHandle } ) => { { ref: nodeRef, onChange( isFocused ) { - if ( isFocused && hasReducedUI ) { + if ( isFocused && isDistractionFree ) { return; } toggleBlockHighlight( blockClientId, isFocused ); @@ -132,9 +132,7 @@ const BlockToolbar = ( { hideDragHandle } ) => { ) } ) } diff --git a/packages/block-editor/src/components/block-tools/insertion-point.js b/packages/block-editor/src/components/block-tools/insertion-point.js index 005e372ff2388d..4f98a29a6e0efb 100644 --- a/packages/block-editor/src/components/block-tools/insertion-point.js +++ b/packages/block-editor/src/components/block-tools/insertion-point.js @@ -33,6 +33,8 @@ function InsertionPointPopover( { nextClientId, rootClientId, isInserterShown, + isDistractionFree, + isNavigationMode, } = useSelect( ( select ) => { const { getBlockOrder, @@ -41,6 +43,8 @@ function InsertionPointPopover( { isBlockBeingDragged, getPreviousBlockClientId, getNextBlockClientId, + getSettings, + isNavigationMode: _isNavigationMode, } = select( blockEditorStore ); const insertionPoint = getBlockInsertionPoint(); const order = getBlockOrder( insertionPoint.rootClientId ); @@ -60,6 +64,8 @@ function InsertionPointPopover( { _nextClientId = getNextBlockClientId( _nextClientId ); } + const settings = getSettings(); + return { previousClientId: _previousClientId, nextClientId: _nextClientId, @@ -67,6 +73,8 @@ function InsertionPointPopover( { getBlockListSettings( insertionPoint.rootClientId ) ?.orientation || 'vertical', rootClientId: insertionPoint.rootClientId, + isNavigationMode: _isNavigationMode(), + isDistractionFree: settings.isDistractionFree, isInserterShown: insertionPoint?.__unstableWithInserter, }; }, [] ); @@ -161,6 +169,10 @@ function InsertionPointPopover( { }, }; + if ( isDistractionFree && ! isNavigationMode ) { + return null; + } + const className = classnames( 'block-editor-block-list__insertion-point', 'is-' + orientation diff --git a/packages/block-editor/src/components/block-tools/selected-block-popover.js b/packages/block-editor/src/components/block-tools/selected-block-popover.js index 530a3b7bdc263d..44dd9b04b31359 100644 --- a/packages/block-editor/src/components/block-tools/selected-block-popover.js +++ b/packages/block-editor/src/components/block-tools/selected-block-popover.js @@ -36,6 +36,7 @@ function selector( select ) { isMultiSelecting: isMultiSelecting(), isTyping: isTyping(), hasFixedToolbar: getSettings().hasFixedToolbar, + isDistractionFree: getSettings().isDistractionFree, lastClientId: hasMultiSelection() ? getLastMultiSelectedBlockClientId() : null, @@ -46,6 +47,7 @@ function SelectedBlockPopover( { clientId, rootClientId, isEmptyDefaultBlock, + showContents, // we may need to mount an empty popover because we reuse capturingClientId, __unstablePopoverSlot, __unstableContentRef, @@ -55,6 +57,7 @@ function SelectedBlockPopover( { isMultiSelecting, isTyping, hasFixedToolbar, + isDistractionFree, lastClientId, } = useSelect( selector, [] ); const isInsertionPointVisible = useSelect( @@ -94,6 +97,7 @@ function SelectedBlockPopover( { editorMode === 'edit' && ! shouldShowContextualToolbar && ! hasFixedToolbar && + ! isDistractionFree && ! isEmptyDefaultBlock; useShortcut( @@ -136,7 +140,7 @@ function SelectedBlockPopover( { resize={ false } { ...popoverProps } > - { shouldShowContextualToolbar && ( + { shouldShowContextualToolbar && showContents && ( ( { hasActiveMetaboxes: select( editPostStore ).hasMetaBoxes(), @@ -38,28 +38,47 @@ function Header( { setEntitiesSavedStatesCallback } ) { isSaving: select( editPostStore ).isSavingMetaBoxes(), showIconLabels: select( editPostStore ).isFeatureActive( 'showIconLabels' ), - hasReducedUI: - select( editPostStore ).isFeatureActive( 'reducedUI' ), } ), [] ); const isLargeViewport = useViewportMatch( 'large' ); - const classes = classnames( 'edit-post-header', { - 'has-reduced-ui': hasReducedUI, - } ); + const classes = classnames( 'edit-post-header' ); + + const slideY = { + hidden: isDistractionFree ? { y: '-50' } : { y: 0 }, + hover: { y: 0, transition: { type: 'tween', delay: 0.2 } }, + }; + + const slideX = { + hidden: isDistractionFree ? { x: '-100%' } : { x: 0 }, + hover: { x: 0, transition: { type: 'tween', delay: 0.2 } }, + }; return (
- + + + -
+ -
-
+ + { ! isPublishSidebarOpened && ( // This button isn't completely hidden by the publish sidebar. // We can't hide the whole toolbar when the publish sidebar is open because @@ -93,7 +112,7 @@ function Header( { setEntitiesSavedStatesCallback } ) { { showIconLabels && ! isLargeViewport && ( ) } -
+
); } diff --git a/packages/edit-post/src/components/header/more-menu/index.js b/packages/edit-post/src/components/header/more-menu/index.js index 6085ce65e51e5e..e134c7ac13194d 100644 --- a/packages/edit-post/src/components/header/more-menu/index.js +++ b/packages/edit-post/src/components/header/more-menu/index.js @@ -36,7 +36,7 @@ const MoreMenu = ( { showIconLabels } ) => { scope="core/edit-post" /> ) } - + .edit-post-header__settings > .editor-post-preview { + visibility: hidden; + } + + & > .edit-post-header__toolbar .edit-post-header-toolbar__inserter-toggle, + & > .edit-post-header__toolbar .edit-post-header-toolbar__list-view-toggle, + & > .edit-post-header__settings > .block-editor-post-preview__dropdown, + & > .edit-post-header__settings > .interface-pinned-items { + display: none; + } + + } + + // We need ! important because we override inline styles + // set by the motion component. + .interface-interface-skeleton__header:focus-within { + opacity: 1 !important; + div { + transform: translateX(0) translateZ(0) !important; + } + + } + + .components-editor-notices__dismissible { + position: absolute; + z-index: 35; + } + +} diff --git a/packages/edit-post/src/components/header/writing-menu/index.js b/packages/edit-post/src/components/header/writing-menu/index.js index a6e6052fd29df3..3d6c3e75a16eab 100644 --- a/packages/edit-post/src/components/header/writing-menu/index.js +++ b/packages/edit-post/src/components/header/writing-menu/index.js @@ -1,13 +1,51 @@ /** * WordPress dependencies */ +import { useSelect, useDispatch } from '@wordpress/data'; import { MenuGroup } from '@wordpress/components'; import { __, _x } from '@wordpress/i18n'; import { useViewportMatch } from '@wordpress/compose'; import { displayShortcut } from '@wordpress/keycodes'; -import { PreferenceToggleMenuItem } from '@wordpress/preferences'; +import { + PreferenceToggleMenuItem, + store as preferencesStore, +} from '@wordpress/preferences'; +import { store as blockEditorStore } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import { store as postEditorStore } from '../../../store'; + +function WritingMenu( { onClose } ) { + const isDistractionFree = useSelect( + ( select ) => + select( blockEditorStore ).getSettings().isDistractionFree, + [] + ); + + const blocks = useSelect( + ( select ) => select( blockEditorStore ).getBlocks(), + [] + ); + + const { setIsInserterOpened, setIsListViewOpened, closeGeneralSidebar } = + useDispatch( postEditorStore ); + const { set: setPreference } = useDispatch( preferencesStore ); + + const { selectBlock } = useDispatch( blockEditorStore ); + + const toggleDistractionFree = () => { + setPreference( 'core/edit-post', 'fixedToolbar', false ); + setIsInserterOpened( false ); + setIsListViewOpened( false ); + closeGeneralSidebar(); + onClose(); + if ( ! isDistractionFree ) { + selectBlock( blocks[ 0 ].clientId ); + } + }; -function WritingMenu() { const isLargeViewport = useViewportMatch( 'medium' ); if ( ! isLargeViewport ) { return null; @@ -17,6 +55,7 @@ function WritingMenu() { + ); } diff --git a/packages/edit-post/src/components/keyboard-shortcuts/index.js b/packages/edit-post/src/components/keyboard-shortcuts/index.js index c7d481ee976a4b..19aa1990f8f48a 100644 --- a/packages/edit-post/src/components/keyboard-shortcuts/index.js +++ b/packages/edit-post/src/components/keyboard-shortcuts/index.js @@ -7,9 +7,11 @@ import { useShortcut, store as keyboardShortcutsStore, } from '@wordpress/keyboard-shortcuts'; -import { __ } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; import { store as editorStore } from '@wordpress/editor'; import { store as blockEditorStore } from '@wordpress/block-editor'; +import { store as noticesStore } from '@wordpress/notices'; +import { store as preferencesStore } from '@wordpress/preferences'; /** * Internal dependencies @@ -18,23 +20,39 @@ import { store as editPostStore } from '../../store'; function KeyboardShortcuts() { const { getBlockSelectionStart } = useSelect( blockEditorStore ); - const { getEditorMode, isEditorSidebarOpened, isListViewOpened } = - useSelect( editPostStore ); + const { + getEditorMode, + isEditorSidebarOpened, + isListViewOpened, + isFeatureActive, + } = useSelect( editPostStore ); const isModeToggleDisabled = useSelect( ( select ) => { const { richEditingEnabled, codeEditingEnabled } = select( editorStore ).getEditorSettings(); return ! richEditingEnabled || ! codeEditingEnabled; }, [] ); + const { createInfoNotice } = useDispatch( noticesStore ); + const { switchEditorMode, openGeneralSidebar, closeGeneralSidebar, toggleFeature, setIsListViewOpened, + setIsInserterOpened, } = useDispatch( editPostStore ); const { registerShortcut } = useDispatch( keyboardShortcutsStore ); + const { set: setPreference } = useDispatch( preferencesStore ); + + const toggleDistractionFree = () => { + setPreference( 'core/edit-post', 'fixedToolbar', false ); + setIsInserterOpened( false ); + setIsListViewOpened( false ); + closeGeneralSidebar(); + }; + useEffect( () => { registerShortcut( { name: 'core/edit-post/toggle-mode', @@ -46,6 +64,16 @@ function KeyboardShortcuts() { }, } ); + registerShortcut( { + name: 'core/edit-post/toggle-distraction-free', + category: 'global', + description: __( 'Toggle disrtaction free mode.' ), + keyCombination: { + modifier: 'primaryShift', + character: '\\', + }, + } ); + registerShortcut( { name: 'core/edit-post/toggle-fullscreen', category: 'global', @@ -135,6 +163,24 @@ function KeyboardShortcuts() { toggleFeature( 'fullscreenMode' ); } ); + useShortcut( 'core/edit-post/toggle-distraction-free', () => { + closeGeneralSidebar(); + setIsListViewOpened( false ); + toggleDistractionFree(); + toggleFeature( 'distractionFree' ); + const modeState = isFeatureActive( 'distractionFree' ) + ? __( 'on' ) + : __( 'off' ); + createInfoNotice( + // translators: Mode of distraction free can be 'on' or 'off'; + sprintf( __( 'Distraction free mode turned %s.' ), modeState ), + { + speak: true, + type: 'snackbar', + } + ); + } ); + useShortcut( 'core/edit-post/toggle-sidebar', ( event ) => { // This shortcut has no known clashes, but use preventDefault to prevent any // obscure shortcuts from triggering. diff --git a/packages/edit-post/src/components/layout/index.js b/packages/edit-post/src/components/layout/index.js index d9bf9ba5cbf826..e05ec9062ec5c5 100644 --- a/packages/edit-post/src/components/layout/index.js +++ b/packages/edit-post/src/components/layout/index.js @@ -82,7 +82,7 @@ function Layout( { styles } ) { isInserterOpened, isListViewOpened, showIconLabels, - hasReducedUI, + isDistractionFree, showBlockBreadcrumbs, isTemplateMode, documentLabel, @@ -115,8 +115,8 @@ function Layout( { styles } ) { ).getAllShortcutKeyCombinations( 'core/edit-post/next-region' ), showIconLabels: select( editPostStore ).isFeatureActive( 'showIconLabels' ), - hasReducedUI: - select( editPostStore ).isFeatureActive( 'reducedUI' ), + isDistractionFree: + select( editPostStore ).isFeatureActive( 'distractionFree' ), showBlockBreadcrumbs: select( editPostStore ).isFeatureActive( 'showBlockBreadcrumbs' ), @@ -124,11 +124,19 @@ function Layout( { styles } ) { documentLabel: postTypeLabel || _x( 'Document', 'noun' ), }; }, [] ); + const [ distractionFree, setDistractionFree ] = + useState( isDistractionFree ); + + useEffect( () => { + setDistractionFree( isDistractionFree ); + }, [ isDistractionFree ] ); + const className = classnames( 'edit-post-layout', 'is-mode-' + mode, { 'is-sidebar-opened': sidebarIsOpened, 'has-fixed-toolbar': hasFixedToolbar, 'has-metaboxes': hasActiveMetaboxes, 'show-icon-labels': showIconLabels, + 'is-distraction-free': isDistractionFree, } ); const openSidebarPanel = () => openGeneralSidebar( @@ -199,6 +207,7 @@ function Layout( { styles } ) { } + editorNotices={ } secondarySidebar={ secondarySidebar() } sidebar={ ( ! isMobileViewport || sidebarIsOpened ) && ( @@ -236,7 +247,7 @@ function Layout( { styles } ) { notices={ } content={ <> - + { ! isDistractionFree && } { ( mode === 'text' || ! isRichEditingEnabled ) && ( ) } @@ -256,7 +267,7 @@ function Layout( { styles } ) { } footer={ - ! hasReducedUI && + ! isDistractionFree && showBlockBreadcrumbs && ! isMobileViewport && isRichEditingEnabled && diff --git a/packages/edit-post/src/components/layout/style.scss b/packages/edit-post/src/components/layout/style.scss index f030ce7cdc6b58..f785b695489e31 100644 --- a/packages/edit-post/src/components/layout/style.scss +++ b/packages/edit-post/src/components/layout/style.scss @@ -11,6 +11,13 @@ padding-left: 16px; padding-right: 16px; } + +.is-distraction-free { + .components-editor-notices__snackbar { + bottom: 20px; + } +} + @include editor-left(".edit-post-layout .components-editor-notices__snackbar"); .edit-post-layout .editor-post-publish-panel { diff --git a/packages/edit-post/src/components/preferences-modal/index.js b/packages/edit-post/src/components/preferences-modal/index.js index 9e3e1a53f4a870..8bba0691261a62 100644 --- a/packages/edit-post/src/components/preferences-modal/index.js +++ b/packages/edit-post/src/components/preferences-modal/index.js @@ -24,6 +24,7 @@ import { PreferencesModalTabs, PreferencesModalSection, } from '@wordpress/interface'; +import { store as preferencesStore } from '@wordpress/preferences'; /** * Internal dependencies @@ -44,26 +45,40 @@ const MODAL_NAME = 'edit-post/preferences'; export default function EditPostPreferencesModal() { const isLargeViewport = useViewportMatch( 'medium' ); const { closeModal } = useDispatch( editPostStore ); - const isModalActive = useSelect( - ( select ) => select( editPostStore ).isModalActive( MODAL_NAME ), - [] - ); - const showBlockBreadcrumbsOption = useSelect( + const [ isModalActive, showBlockBreadcrumbsOption ] = useSelect( ( select ) => { const { getEditorSettings } = select( editorStore ); const { getEditorMode, isFeatureActive } = select( editPostStore ); + const modalActive = + select( editPostStore ).isModalActive( MODAL_NAME ); const mode = getEditorMode(); const isRichEditingEnabled = getEditorSettings().richEditingEnabled; - const hasReducedUI = isFeatureActive( 'reducedUI' ); - return ( - ! hasReducedUI && - isLargeViewport && - isRichEditingEnabled && - mode === 'visual' - ); + const isDistractionFreeEnabled = + isFeatureActive( 'distractionFree' ); + return [ + modalActive, + ! isDistractionFreeEnabled && + isLargeViewport && + isRichEditingEnabled && + mode === 'visual', + isDistractionFreeEnabled, + ]; }, [ isLargeViewport ] ); + + const { closeGeneralSidebar, setIsListViewOpened, setIsInserterOpened } = + useDispatch( editPostStore ); + + const { set: setPreference } = useDispatch( preferencesStore ); + + const toggleDistractionFree = () => { + setPreference( 'core/edit-post', 'fixedToolbar', false ); + setIsInserterOpened( false ); + setIsListViewOpened( false ); + closeGeneralSidebar(); + }; + const sections = useMemo( () => [ { @@ -95,6 +110,14 @@ export default function EditPostPreferencesModal() { 'Customize options related to the block editor interface and editing flow.' ) } > + - ( { - onChange: () => dispatch( editPostStore ).toggleFeature( featureName ), + withDispatch( ( dispatch, { featureName, onToggle = () => {} } ) => ( { + onChange: () => { + onToggle(); + dispatch( editPostStore ).toggleFeature( featureName ); + }, } ) ) )( BaseOption ); diff --git a/packages/edit-post/src/components/preferences-modal/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/preferences-modal/test/__snapshots__/index.js.snap index 723d5c071d425a..95812a2828ea91 100644 --- a/packages/edit-post/src/components/preferences-modal/test/__snapshots__/index.js.snap +++ b/packages/edit-post/src/components/preferences-modal/test/__snapshots__/index.js.snap @@ -253,7 +253,7 @@ exports[`EditPostPreferencesModal should match snapshot when the modal is active class="components-toggle-control__label" for="inspector-toggle-control-1" > - Spotlight mode + Distraction Free @@ -261,7 +261,7 @@ exports[`EditPostPreferencesModal should match snapshot when the modal is active class="components-base-control__help emotion-6 emotion-7" id="inspector-toggle-control-1__help" > - Highlights the current block and fades other content. + Reduce visual distractions by hiding the toolbar and other elements to focus on writing.

@@ -299,7 +299,7 @@ exports[`EditPostPreferencesModal should match snapshot when the modal is active class="components-toggle-control__label" for="inspector-toggle-control-2" > - Show button text labels + Spotlight mode @@ -307,7 +307,7 @@ exports[`EditPostPreferencesModal should match snapshot when the modal is active class="components-base-control__help emotion-6 emotion-7" id="inspector-toggle-control-2__help" > - Show text instead of icons on buttons. + Highlights the current block and fades other content.

@@ -345,7 +345,7 @@ exports[`EditPostPreferencesModal should match snapshot when the modal is active class="components-toggle-control__label" for="inspector-toggle-control-3" > - Always open list view + Show button text labels @@ -353,7 +353,7 @@ exports[`EditPostPreferencesModal should match snapshot when the modal is active class="components-base-control__help emotion-6 emotion-7" id="inspector-toggle-control-3__help" > - Opens the block list view sidebar by default. + Show text instead of icons on buttons.

@@ -391,7 +391,7 @@ exports[`EditPostPreferencesModal should match snapshot when the modal is active class="components-toggle-control__label" for="inspector-toggle-control-4" > - Reduce the interface + Always open list view @@ -399,7 +399,7 @@ exports[`EditPostPreferencesModal should match snapshot when the modal is active class="components-base-control__help emotion-6 emotion-7" id="inspector-toggle-control-4__help" > - Compacts options and outlines in the toolbar. + Opens the block list view sidebar by default.

diff --git a/packages/edit-post/src/components/preferences-modal/test/index.js b/packages/edit-post/src/components/preferences-modal/test/index.js index b2ab5ae2465cf2..d1ff306488cb9d 100644 --- a/packages/edit-post/src/components/preferences-modal/test/index.js +++ b/packages/edit-post/src/components/preferences-modal/test/index.js @@ -21,7 +21,7 @@ jest.mock( '@wordpress/compose/src/hooks/use-viewport-match', () => jest.fn() ); describe( 'EditPostPreferencesModal', () => { describe( 'should match snapshot when the modal is active', () => { it( 'large viewports', () => { - useSelect.mockImplementation( () => true ); + useSelect.mockImplementation( () => [ true, true, false ] ); useViewportMatch.mockImplementation( () => true ); render( ); expect( @@ -29,7 +29,7 @@ describe( 'EditPostPreferencesModal', () => { ).toMatchSnapshot(); } ); it( 'small viewports', () => { - useSelect.mockImplementation( () => true ); + useSelect.mockImplementation( () => [ true, true, false ] ); useViewportMatch.mockImplementation( () => false ); render( ); expect( @@ -39,7 +39,7 @@ describe( 'EditPostPreferencesModal', () => { } ); it( 'should not render when the modal is not active', () => { - useSelect.mockImplementation( () => false ); + useSelect.mockImplementation( () => [ false, false, false ] ); render( ); expect( screen.queryByRole( 'dialog', { name: 'Preferences' } ) diff --git a/packages/edit-post/src/editor.js b/packages/edit-post/src/editor.js index c7e5bbaa30d61d..06c3191ceb9f8d 100644 --- a/packages/edit-post/src/editor.js +++ b/packages/edit-post/src/editor.js @@ -38,7 +38,7 @@ function Editor( { const { hasFixedToolbar, focusMode, - hasReducedUI, + isDistractionFree, hasInlineToolbar, hasThemeStyles, post, @@ -85,7 +85,7 @@ function Editor( { isFeatureActive( 'fixedToolbar' ) || __experimentalGetPreviewDeviceType() !== 'Desktop', focusMode: isFeatureActive( 'focusMode' ), - hasReducedUI: isFeatureActive( 'reducedUI' ), + isDistractionFree: isFeatureActive( 'distractionFree' ), hasInlineToolbar: isFeatureActive( 'inlineToolbar' ), hasThemeStyles: isFeatureActive( 'themeStyles' ), preferredStyleVariations: select( preferencesStore ).get( @@ -118,7 +118,7 @@ function Editor( { }, hasFixedToolbar, focusMode, - hasReducedUI, + isDistractionFree, hasInlineToolbar, // This is marked as experimental to give time for the quick inserter to mature. @@ -150,7 +150,7 @@ function Editor( { settings, hasFixedToolbar, focusMode, - hasReducedUI, + isDistractionFree, hiddenBlockTypes, blockTypes, preferredStyleVariations, diff --git a/packages/editor/src/components/provider/use-block-editor-settings.js b/packages/editor/src/components/provider/use-block-editor-settings.js index 95b236e85c5063..51d16ef1b6a7d6 100644 --- a/packages/editor/src/components/provider/use-block-editor-settings.js +++ b/packages/editor/src/components/provider/use-block-editor-settings.js @@ -159,7 +159,7 @@ function useBlockEditorSettings( settings, hasTemplate ) { 'gradients', 'generateAnchors', 'hasFixedToolbar', - 'hasReducedUI', + 'isDistractionFree', 'hasInlineToolbar', 'imageDefaultSize', 'imageDimensions', diff --git a/packages/interface/src/components/interface-skeleton/index.js b/packages/interface/src/components/interface-skeleton/index.js index dc7b672f75325e..766ef73a2fcf56 100644 --- a/packages/interface/src/components/interface-skeleton/index.js +++ b/packages/interface/src/components/interface-skeleton/index.js @@ -7,7 +7,10 @@ import classnames from 'classnames'; * WordPress dependencies */ import { forwardRef, useEffect } from '@wordpress/element'; -import { __unstableUseNavigateRegions as useNavigateRegions } from '@wordpress/components'; +import { + __unstableUseNavigateRegions as useNavigateRegions, + __unstableMotion as motion, +} from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { useMergeRefs } from '@wordpress/compose'; @@ -27,8 +30,10 @@ function useHTMLClass( className ) { function InterfaceSkeleton( { + isDistractionFree, footer, header, + editorNotices, sidebar, secondarySidebar, notices, @@ -64,6 +69,14 @@ function InterfaceSkeleton( const mergedLabels = { ...defaultLabels, ...labels }; + const headerVariants = { + hidden: isDistractionFree ? { opacity: 0 } : { opacity: 1 }, + hover: { + opacity: 1, + transition: { type: 'tween', delay: 0.2, delayChildren: 0.2 }, + }, + }; + return (
) }
- { !! header && ( + { !! header && isDistractionFree && ( + + { header } + + ) } + { !! header && ! isDistractionFree && (
) } + { isDistractionFree && ( +
+ { editorNotices } +
+ ) }
{ !! secondarySidebar && (
{ // so override the rule to allow symbols used for shortcuts. // see: https://github.com/blakeembrey/change-case#options const capitalizedCharacter = capitalCase( character, { - stripRegexp: /[^A-Z0-9`,\.]/gi, + stripRegexp: /[^A-Z0-9`,\.\\]/gi, } ); return [ ...modifierKeys, capitalizedCharacter ]; diff --git a/packages/preferences/src/components/preference-toggle-menu-item/index.js b/packages/preferences/src/components/preference-toggle-menu-item/index.js index 5bd6da3441a9cf..322dd236718c07 100644 --- a/packages/preferences/src/components/preference-toggle-menu-item/index.js +++ b/packages/preferences/src/components/preference-toggle-menu-item/index.js @@ -20,6 +20,8 @@ export default function PreferenceToggleMenuItem( { messageActivated, messageDeactivated, shortcut, + toggleHandler = () => null, + disabled = false, } ) { const isActive = useSelect( ( select ) => !! select( preferencesStore ).get( scope, name ), @@ -53,12 +55,14 @@ export default function PreferenceToggleMenuItem( { icon={ isActive && check } isSelected={ isActive } onClick={ () => { + toggleHandler(); toggle( scope, name ); speakMessage(); } } role="menuitemcheckbox" info={ info } shortcut={ shortcut } + disabled={ disabled } > { label }