diff --git a/packages/e2e-test-utils-playwright/src/editor/publish-post.ts b/packages/e2e-test-utils-playwright/src/editor/publish-post.ts index bf4b240a3fd619..81451cd516f0ed 100644 --- a/packages/e2e-test-utils-playwright/src/editor/publish-post.ts +++ b/packages/e2e-test-utils-playwright/src/editor/publish-post.ts @@ -16,7 +16,7 @@ export async function publishPost( this: Editor ) { .getByRole( 'button', { name: 'Save', exact: true } ); const publishButton = this.page .getByRole( 'region', { name: 'Editor top bar' } ) - .getByRole( 'button', { name: 'Publish' } ); + .getByRole( 'button', { name: 'Publish', exact: true } ); const buttonToClick = ( await saveButton.isVisible() ) ? saveButton : publishButton; diff --git a/packages/e2e-test-utils/src/ensure-sidebar-opened.js b/packages/e2e-test-utils/src/ensure-sidebar-opened.js index 5ea99c629c15ef..95c674e980643a 100644 --- a/packages/e2e-test-utils/src/ensure-sidebar-opened.js +++ b/packages/e2e-test-utils/src/ensure-sidebar-opened.js @@ -8,7 +8,8 @@ export async function ensureSidebarOpened() { '.edit-post-header__settings [aria-label="Settings"][aria-expanded="false"],' + '.edit-site-header__actions [aria-label="Settings"][aria-expanded="false"],' + '.edit-widgets-header__actions [aria-label="Settings"][aria-expanded="false"],' + - '.edit-site-header-edit-mode__actions [aria-label="Settings"][aria-expanded="false"]' + '.edit-site-header-edit-mode__actions [aria-label="Settings"][aria-expanded="false"],' + + '.editor-header__settings [aria-label="Settings"][aria-expanded="false"]' ); if ( toggleSidebarButton ) { diff --git a/packages/e2e-test-utils/src/inserter.js b/packages/e2e-test-utils/src/inserter.js index cf5d7c48c9dfdd..5beab3c6205b6e 100644 --- a/packages/e2e-test-utils/src/inserter.js +++ b/packages/e2e-test-utils/src/inserter.js @@ -53,7 +53,8 @@ async function isGlobalInserterOpen() { '.edit-site-header [aria-label="Toggle block inserter"].is-pressed,' + '.edit-widgets-header [aria-label="Toggle block inserter"].is-pressed,' + '.edit-widgets-header [aria-label="Add block"].is-pressed,' + - '.edit-site-header-edit-mode__inserter-toggle.is-pressed' + '.edit-site-header-edit-mode__inserter-toggle.is-pressed,' + + '.editor-header [aria-label="Toggle block inserter"].is-pressed' ); } ); } diff --git a/packages/e2e-test-utils/src/site-editor.js b/packages/e2e-test-utils/src/site-editor.js index 4f6cf1773134fb..98ba34f7db4f51 100644 --- a/packages/e2e-test-utils/src/site-editor.js +++ b/packages/e2e-test-utils/src/site-editor.js @@ -97,9 +97,7 @@ export async function visitSiteEditor( query, skipWelcomeGuide = true ) { * Toggles the global styles sidebar (opens it if closed and closes it if open). */ export async function toggleGlobalStyles() { - await page.click( - '.edit-site-header-edit-mode__actions button[aria-label="Styles"]' - ); + await page.click( '.editor-header__settings button[aria-label="Styles"]' ); } /** diff --git a/packages/edit-post/src/components/header/index.js b/packages/edit-post/src/components/header/index.js index 86c928ff157662..311279292d8f6a 100644 --- a/packages/edit-post/src/components/header/index.js +++ b/packages/edit-post/src/components/header/index.js @@ -1,24 +1,9 @@ -/** - * External dependencies - */ -import clsx from 'clsx'; - /** * WordPress dependencies */ -import { - DocumentBar, - PostSavedState, - PostPreviewButton, - store as editorStore, - privateApis as editorPrivateApis, -} from '@wordpress/editor'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; import { useSelect } from '@wordpress/data'; -import { useViewportMatch } from '@wordpress/compose'; import { __unstableMotion as motion } from '@wordpress/components'; -import { store as preferencesStore } from '@wordpress/preferences'; -import { useState } from '@wordpress/element'; -import { store as blockEditorStore } from '@wordpress/block-editor'; /** * Internal dependencies @@ -29,21 +14,7 @@ import MainDashboardButton from './main-dashboard-button'; import { store as editPostStore } from '../../store'; import { unlock } from '../../lock-unlock'; -const { - CollapsableBlockToolbar, - DocumentTools, - PostViewLink, - PreviewDropdown, - PinnedItems, - MoreMenu, - PostPublishButtonOrToggle, -} = unlock( editorPrivateApis ); - -const slideY = { - hidden: { y: '-50px' }, - distractionFreeInactive: { y: 0 }, - hover: { y: 0, transition: { type: 'tween', delay: 0.2 } }, -}; +const { Header: EditorHeader } = unlock( editorPrivateApis ); const slideX = { hidden: { x: '-100%' }, @@ -52,42 +23,17 @@ const slideX = { }; function Header( { setEntitiesSavedStatesCallback, initialPost } ) { - const isWideViewport = useViewportMatch( 'large' ); - const isLargeViewport = useViewportMatch( 'medium' ); - const { - isTextEditor, - hasActiveMetaboxes, - isPublishSidebarOpened, - showIconLabels, - hasHistory, - hasFixedToolbar, - isZoomedOutView, - } = useSelect( ( select ) => { - const { get: getPreference } = select( preferencesStore ); - const { getEditorMode } = select( editorStore ); - const { __unstableGetEditorMode } = select( blockEditorStore ); - + const { hasActiveMetaboxes } = useSelect( ( select ) => { return { - isTextEditor: getEditorMode() === 'text', hasActiveMetaboxes: select( editPostStore ).hasMetaBoxes(), - hasHistory: - !! select( editorStore ).getEditorSettings() - .onNavigateToPreviousEntityRecord, - isPublishSidebarOpened: - select( editorStore ).isPublishSidebarOpened(), - showIconLabels: getPreference( 'core', 'showIconLabels' ), - hasFixedToolbar: getPreference( 'core', 'fixedToolbar' ), - isZoomedOutView: __unstableGetEditorMode() === 'zoom-out', }; }, [] ); - const hasTopToolbar = isLargeViewport && hasFixedToolbar; - - const [ isBlockToolsCollapsed, setIsBlockToolsCollapsed ] = - useState( true ); - return ( -
+ - - - { hasTopToolbar && ( - - ) } -
- { hasHistory && } -
-
- - { ! 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 - // we want to prevent mounting/unmounting the PostPublishButtonOrToggle DOM node. - // We track that DOM node to return focus to the PostPublishButtonOrToggle - // when the publish sidebar has been closed. - - ) } - - - - - { ( isWideViewport || ! showIconLabels ) && ( - - ) } - - - -
+ + ); } diff --git a/packages/edit-post/src/components/header/style.scss b/packages/edit-post/src/components/header/style.scss index 93c1461774cbd0..53672eb09e701f 100644 --- a/packages/edit-post/src/components/header/style.scss +++ b/packages/edit-post/src/components/header/style.scss @@ -1,251 +1,14 @@ -.edit-post-header { - height: $header-height; - background: $white; - display: flex; - flex-wrap: wrap; - align-items: center; - // The header should never be wider than the viewport, or buttons might be hidden. Especially relevant at high zoom levels. Related to https://core.trac.wordpress.org/ticket/47603#ticket. - max-width: 100vw; - justify-content: space-between; - - // Make toolbar sticky on larger breakpoints - @include break-zoomed-in { - flex-wrap: nowrap; - } -} - -.edit-post-header__toolbar { - display: flex; - // Allow this area to shrink to fit the toolbar buttons. - flex-shrink: 8; - // Take up the space of the toolbar so it can be justified to the left side of the toolbar. - flex-grow: 3; - // Hide the overflow so flex will limit its width. Block toolbar will allow scrolling on fixed toolbar. - overflow: hidden; - // Leave enough room for the focus ring to show. - padding: 2px 0; - align-items: center; - // Allow focus ring to be fully visible on furthest right button. - @include break-medium() { - padding-right: var(--wp-admin-border-width-focus); - } - - .table-of-contents { - display: none; - - @include break-small() { - display: block; - } - } -} - -.edit-post-header__center { - flex-grow: 1; - display: flex; - justify-content: center; - - &.is-collapsed { - display: none; - } -} - /** - * Buttons on the right side + * Show icon label overrides. */ - -.edit-post-header__settings { - display: inline-flex; - align-items: center; - flex-wrap: nowrap; - padding-right: $grid-unit-05; - - @include break-small () { - padding-right: $grid-unit-10; - } - - gap: $grid-unit-10; -} - -/** - * Show icon labels. - */ - -.show-icon-labels.interface-pinned-items, -.show-icon-labels .edit-post-header, -.edit-post-header__dropdown { - .components-button.has-icon { - width: auto; - - // Hide the button icons when labels are set to display... - svg { - display: none; - } - // ... and display labels. - &::after { - content: attr(aria-label); - } - &[aria-disabled="true"] { - background-color: transparent; - } - } - .is-tertiary { - &:active { - box-shadow: 0 0 0 1.5px var(--wp-admin-theme-color); - background-color: transparent; - } - } - // Exception for drodpdown toggle buttons. - // Exception for the fullscreen mode button. - .edit-post-fullscreen-mode-close.has-icon, - .components-button.has-icon.button-toggle { - svg { - display: block; - } - &::after { - content: none; - } - } - // Undo the width override for fullscreen mode button. +.show-icon-labels .editor-header { .edit-post-fullscreen-mode-close.has-icon { width: $header-height; - } - // Don't hide MenuItemsChoice check icons - .components-menu-items-choice .components-menu-items__item-icon.components-menu-items__item-icon { - display: block; - } - .editor-document-tools__inserter-toggle.editor-document-tools__inserter-toggle, - .interface-pinned-items .components-button { - padding-left: $grid-unit; - padding-right: $grid-unit; - - @include break-small { - padding-left: $grid-unit-15; - padding-right: $grid-unit-15; + svg { + display: block; } - } - - .editor-post-save-draft.editor-post-save-draft, - .editor-post-saved-state.editor-post-saved-state { &::after { content: none; } } } - -.show-icon-labels { - .edit-post-header__toolbar .block-editor-block-mover { - // Modified group borders. - border-left: none; - - &::before { - content: ""; - width: $border-width; - height: $grid-unit-30; - background-color: $gray-300; - margin-top: $grid-unit-05; - margin-left: $grid-unit; - } - - // Modified block movers horizontal separator. - .block-editor-block-mover__move-button-container { - &::before { - width: calc(100% - #{$grid-unit-30}); - background: $gray-300; - left: calc(50% + 1px); - } - } - } -} - -.edit-post-header__dropdown { - .components-menu-item__button.components-menu-item__button, - .components-button.editor-history__undo, - .components-button.editor-history__redo, - .table-of-contents .components-button, - .components-button.block-editor-list-view { - margin: 0; - padding: 6px 6px 6px $grid-unit-50; - width: 14.625rem; - text-align: left; - justify-content: flex-start; - } -} - -.show-icon-labels.interface-pinned-items { - padding: 6px $grid-unit-15 $grid-unit-15; - margin-top: 0; - margin-bottom: 0; - margin-left: -$grid-unit-15; - margin-right: -$grid-unit-15; - border-bottom: 1px solid $gray-400; - display: block; - - > .components-button.has-icon { - margin: 0; - padding: 6px 6px 6px $grid-unit; - width: 14.625rem; - justify-content: flex-start; - - &[aria-expanded="true"] svg { - display: block; - max-width: $grid-unit-30; - } - &[aria-expanded="false"] { - padding-left: $grid-unit-50; - } - svg { - margin-right: 8px; - } - } -} - -.edit-post-header__post-preview-button { - @include break-small { - display: none; - } -} - -.is-distraction-free { - .interface-interface-skeleton__header { - border-bottom: none; - } - - .edit-post-header { - background-color: $white; - border-bottom: 1px solid #e0e0e0; - position: absolute; - width: 100%; - - - // hide some parts - & > .edit-post-header__settings > .edit-post-header__post-preview-button { - visibility: hidden; - } - - & > .edit-post-header__toolbar .editor-document-tools__document-overview-toggle, - & > .edit-post-header__settings > .editor-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; - } -} - -.components-popover.more-menu-dropdown__content { - z-index: z-index(".components-popover.more-menu__content"); -} diff --git a/packages/edit-post/src/style.scss b/packages/edit-post/src/style.scss index d780f4257f25ab..f477bef7bbffd3 100644 --- a/packages/edit-post/src/style.scss +++ b/packages/edit-post/src/style.scss @@ -39,7 +39,7 @@ body.js.block-editor-page { } // Target the editor UI excluding the visual editor contents, metaboxes and custom fields areas. -.edit-post-header, +.editor-header, .edit-post-text-editor, .editor-sidebar, .editor-post-publish-panel { diff --git a/packages/edit-site/src/components/editor/style.scss b/packages/edit-site/src/components/editor/style.scss index 8803c0c59ff5a6..000c64fd8ae03d 100644 --- a/packages/edit-site/src/components/editor/style.scss +++ b/packages/edit-site/src/components/editor/style.scss @@ -6,10 +6,6 @@ &.is-loading { opacity: 0; } - - .interface-interface-skeleton__header { - border: 0; - } } .edit-site-editor__toggle-save-panel { diff --git a/packages/edit-site/src/components/header-edit-mode/index.js b/packages/edit-site/src/components/header-edit-mode/index.js index 921ff61dd23a1e..fcd4ea1b388028 100644 --- a/packages/edit-site/src/components/header-edit-mode/index.js +++ b/packages/edit-site/src/components/header-edit-mode/index.js @@ -1,188 +1,51 @@ -/** - * External dependencies - */ -import clsx from 'clsx'; - /** * WordPress dependencies */ -import { useViewportMatch, useReducedMotion } from '@wordpress/compose'; -import { store as blockEditorStore } from '@wordpress/block-editor'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; import { useSelect } from '@wordpress/data'; -import { useState } from '@wordpress/element'; -import { __unstableMotion as motion } from '@wordpress/components'; -import { store as preferencesStore } from '@wordpress/preferences'; -import { - DocumentBar, - PostSavedState, - store as editorStore, - privateApis as editorPrivateApis, -} from '@wordpress/editor'; -import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import SiteEditorMoreMenuItems from './more-menu'; +import SiteEditorMoreMenu from './more-menu'; +import { unlock } from '../../lock-unlock'; import SaveButton from '../save-button'; -import { store as editSiteStore } from '../../store'; +import { isPreviewingTheme } from '../../utils/is-previewing-theme'; import { getEditorCanvasContainerTitle, useHasEditorCanvasContainer, } from '../editor-canvas-container'; -import { unlock } from '../../lock-unlock'; -import { FOCUSABLE_ENTITIES } from '../../utils/constants'; -import { isPreviewingTheme } from '../../utils/is-previewing-theme'; - -const { - CollapsableBlockToolbar, - DocumentTools, - MoreMenu, - PostViewLink, - PreviewDropdown, - PinnedItems, - PostPublishButtonOrToggle, -} = unlock( editorPrivateApis ); +import { store as editSiteStore } from '../../store'; -export default function HeaderEditMode( { setEntitiesSavedStatesCallback } ) { - const { - templateType, - isDistractionFree, - blockEditorMode, - showIconLabels, - editorCanvasView, - isFixedToolbar, - isPublishSidebarOpened, - isVisualMode, - } = useSelect( ( select ) => { - const { getEditedPostType } = select( editSiteStore ); - const { __unstableGetEditorMode } = select( blockEditorStore ); - const { get: getPreference } = select( preferencesStore ); - const { getDeviceType, getEditorMode } = select( editorStore ); +const { Header: EditorHeader } = unlock( editorPrivateApis ); +function Header( { setEntitiesSavedStatesCallback } ) { + const _isPreviewingTheme = isPreviewingTheme(); + const hasDefaultEditorCanvasView = ! useHasEditorCanvasContainer(); + const { editorCanvasView } = useSelect( ( select ) => { return { - deviceType: getDeviceType(), - templateType: getEditedPostType(), - blockEditorMode: __unstableGetEditorMode(), - showIconLabels: getPreference( 'core', 'showIconLabels' ), editorCanvasView: unlock( select( editSiteStore ) ).getEditorCanvasContainerView(), - isDistractionFree: getPreference( 'core', 'distractionFree' ), - isFixedToolbar: getPreference( 'core', 'fixedToolbar' ), - isPublishSidebarOpened: - select( editorStore ).isPublishSidebarOpened(), - isVisualMode: getEditorMode() === 'visual', }; }, [] ); - const isLargeViewport = useViewportMatch( 'medium' ); - const showTopToolbar = - isLargeViewport && isFixedToolbar && blockEditorMode !== 'zoom-out'; - const disableMotion = useReducedMotion(); - - const hasDefaultEditorCanvasView = ! useHasEditorCanvasContainer(); - - const isFocusMode = FOCUSABLE_ENTITIES.includes( templateType ); - - const isZoomedOutView = blockEditorMode === 'zoom-out'; - - const [ isBlockToolsCollapsed, setIsBlockToolsCollapsed ] = - useState( true ); - - const toolbarVariants = { - isDistractionFree: { y: '-50px' }, - isDistractionFreeHovering: { y: 0 }, - view: { y: 0 }, - edit: { y: 0 }, - }; - - const toolbarTransition = { - type: 'tween', - duration: disableMotion ? 0 : 0.2, - ease: 'easeOut', - }; - - const _isPreviewingTheme = isPreviewingTheme(); return ( -
+ } + forceDisableBlockTools={ ! hasDefaultEditorCanvasView } + title={ + ! hasDefaultEditorCanvasView + ? getEditorCanvasContainerTitle( editorCanvasView ) + : undefined + } > - { hasDefaultEditorCanvasView && ( - - - { showTopToolbar && ( - - ) } - - ) } - - { ! isDistractionFree && ( -
- { ! hasDefaultEditorCanvasView ? ( - getEditorCanvasContainerTitle( editorCanvasView ) - ) : ( - - ) } -
- ) } - -
- - { isLargeViewport && ( - - ) } - - { - // TODO: For now we conditionally render the Save/Publish buttons based on - // some specific site editor extra handling. Examples are when we're previewing - // a theme, handling of global styles changes or when we're in 'view' mode, - // which opens the save panel in a Modal. - } - { ! _isPreviewingTheme && ! 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 - // we want to prevent mounting/unmounting the PostPublishButtonOrToggle DOM node. - // We track that DOM node to return focus to the PostPublishButtonOrToggle - // when the publish sidebar has been closed. - - ) } - { ! _isPreviewingTheme && ( - - ) } - { _isPreviewingTheme && } - { ! isDistractionFree && } - - - -
-
+ + ); } + +export default Header; diff --git a/packages/edit-site/src/components/header-edit-mode/style.scss b/packages/edit-site/src/components/header-edit-mode/style.scss index 39a1a3418395a3..69b1e9dff38492 100644 --- a/packages/edit-site/src/components/header-edit-mode/style.scss +++ b/packages/edit-site/src/components/header-edit-mode/style.scss @@ -1,192 +1,3 @@ -.edit-site-header-edit-mode { - height: $header-height; - align-items: center; - background-color: $white; - color: $gray-900; - display: flex; - box-sizing: border-box; - width: 100%; - justify-content: space-between; - border-bottom: $border-width solid $gray-200; +.editor-header { padding-left: $header-height; - - // When top toolbar is engaged and should expand fully. - &.show-block-toolbar { - - .edit-site-header-edit-mode__start, - .edit-site-header-edit-mode__end { - flex-basis: auto; - } - - .edit-site-header-edit-mode__center { - display: none; - } - } - - .edit-site-header-edit-mode__start { - display: flex; - border: none; - align-items: center; - flex-grow: 1; - flex-shrink: 2; - // Take up the full height of the header so the border focus - // is visible on toolbar buttons. - height: 100%; - // Allow focus ring to be fully visible on furthest right button. - @include break-medium() { - padding-right: var(--wp-admin-border-width-focus); - // Account for the site hub, which is 60x60px. - flex-basis: calc(37.5% - 60px); - // We need this to be overflow hidden so the block toolbar can - // overflow scroll. If the overflow is visible, flexbox allows - // the toolbar to grow outside of the allowed container space. - overflow: hidden; - } - } - - .edit-site-header-edit-mode__end { - display: flex; - justify-content: flex-end; - height: 100%; - flex-grow: 1; - flex-shrink: 1; - - @include break-medium() { - flex-basis: 37.5%; - } - } - - .edit-site-header-edit-mode__center { - align-items: center; - display: flex; - flex-basis: 100%; - flex-grow: 1; - flex-shrink: 2; - height: 100%; - justify-content: center; - - // Flex items will, by default, refuse to shrink below a minimum - // intrinsic width. In order to shrink this flexbox item, and - // subsequently truncate child text, we set an explicit min-width. - // See https://dev.w3.org/csswg/css-flexbox/#min-size-auto - min-width: 0; - - @include break-medium() { - flex-basis: 25%; - } - } - -} - -.edit-site-header-edit-mode__toolbar { - align-items: center; - display: flex; - gap: $grid-unit-10; - padding-left: $grid-unit-20; - - @include break-medium() { - padding-left: $grid-unit-50 * 0.5; - } - - @include break-wide() { - padding-right: $grid-unit-10; - } - - .edit-site-header-edit-mode__inserter-toggle { - svg { - transition: transform cubic-bezier(0.165, 0.84, 0.44, 1) 0.2s; - @include reduce-motion("transition"); - } - - &.is-pressed { - svg { - transform: rotate(45deg); - } - } - } -} - -/** - * Buttons on the right side - */ - -.edit-site-header-edit-mode__actions { - display: inline-flex; - align-items: center; - flex-wrap: nowrap; - // Ensure actions do not press against .edit-site-header-edit-mode__center. - padding-left: $grid-unit-10; - padding-right: $grid-unit-10; - gap: $grid-unit-10; -} - -// Button text label styles - -.edit-site-header-edit-mode.show-icon-labels { - .components-button.has-icon { - width: auto; - - // Hide the button icons when labels are set to display... - svg { - display: none; - } - // ... and display labels. - &::after { - content: attr(aria-label); - } - &[aria-disabled="true"] { - background-color: transparent; - } - } - .is-tertiary { - &:active { - box-shadow: 0 0 0 1.5px var(--wp-admin-theme-color); - background-color: transparent; - } - } - // Some margins and padding have to be adjusted so the buttons can still fit on smaller screens. - .edit-site-save-button__button { - padding-left: 6px; - padding-right: 6px; - } - - // The template details toggle has a custom label, different from its aria-label, so we don't want to display both. - .edit-site-document-actions__get-info.edit-site-document-actions__get-info.edit-site-document-actions__get-info { - &::after { - content: none; - } - } - - .edit-site-header-edit-mode__inserter-toggle.edit-site-header-edit-mode__inserter-toggle, - .edit-site-document-actions__get-info.edit-site-document-actions__get-info.edit-site-document-actions__get-info { - height: 36px; - padding: 0 $grid-unit-10; - } - - .block-editor-block-mover { - // Modified group borders. - border-left: none; - - &::before { - content: ""; - width: $border-width; - height: $grid-unit-30; - background-color: $gray-300; - margin-top: $grid-unit-05; - margin-left: $grid-unit; - } - - // Modified block movers horizontal separator. - .block-editor-block-mover__move-button-container { - &::before { - width: calc(100% - #{$grid-unit-30}); - background: $gray-300; - left: calc(50% + 1px); - } - } - } -} - -.components-popover.more-menu-dropdown__content { - z-index: z-index(".components-popover.more-menu__content"); } diff --git a/packages/edit-site/src/components/layout/style.scss b/packages/edit-site/src/components/layout/style.scss index 00b67f00f6f23d..55a071caacac41 100644 --- a/packages/edit-site/src/components/layout/style.scss +++ b/packages/edit-site/src/components/layout/style.scss @@ -165,8 +165,9 @@ position: relative; color: $white; border-radius: 0; - height: $header-height; + height: $header-height + $border-width; width: $header-height; + margin-bottom: - $border-width; overflow: hidden; padding: 0; display: flex; diff --git a/packages/editor/src/components/document-tools/index.js b/packages/editor/src/components/document-tools/index.js index c799e9eae30de6..434b55a7e0fe20 100644 --- a/packages/editor/src/components/document-tools/index.js +++ b/packages/editor/src/components/document-tools/index.js @@ -204,6 +204,7 @@ function DocumentTools( { ); } } size="compact" + disabled={ disableBlockTools } /> ) } diff --git a/packages/editor/src/components/header/index.js b/packages/editor/src/components/header/index.js new file mode 100644 index 00000000000000..98501386434b69 --- /dev/null +++ b/packages/editor/src/components/header/index.js @@ -0,0 +1,154 @@ +/** + * External dependencies + */ +import clsx from 'clsx'; + +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { useViewportMatch } from '@wordpress/compose'; +import { __unstableMotion as motion } from '@wordpress/components'; +import { store as preferencesStore } from '@wordpress/preferences'; +import { useState } from '@wordpress/element'; +import { PinnedItems } from '@wordpress/interface'; +import { store as blockEditorStore } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import CollapsableBlockToolbar from '../collapsible-block-toolbar'; +import DocumentBar from '../document-bar'; +import DocumentTools from '../document-tools'; +import MoreMenu from '../more-menu'; +import PostPreviewButton from '../post-preview-button'; +import PostPublishButtonOrToggle from '../post-publish-button/post-publish-button-or-toggle'; +import PostSavedState from '../post-saved-state'; +import PostTypeSupportCheck from '../post-type-support-check'; +import PostViewLink from '../post-view-link'; +import PreviewDropdown from '../preview-dropdown'; +import { store as editorStore } from '../../store'; + +const slideY = { + hidden: { y: '-50px' }, + distractionFreeInactive: { y: 0 }, + hover: { y: 0, transition: { type: 'tween', delay: 0.2 } }, +}; + +function Header( { + customSaveButton, + forceIsDirty, + forceDisableBlockTools, + setEntitiesSavedStatesCallback, + title, + children, +} ) { + const isWideViewport = useViewportMatch( 'large' ); + const isLargeViewport = useViewportMatch( 'medium' ); + const { + isTextEditor, + isPublishSidebarOpened, + showIconLabels, + hasFixedToolbar, + isNestedEntity, + isZoomedOutView, + } = useSelect( ( select ) => { + const { get: getPreference } = select( preferencesStore ); + const { + getEditorMode, + getEditorSettings, + isPublishSidebarOpened: _isPublishSidebarOpened, + } = select( editorStore ); + const { __unstableGetEditorMode } = select( blockEditorStore ); + + return { + isTextEditor: getEditorMode() === 'text', + isPublishSidebarOpened: _isPublishSidebarOpened(), + showIconLabels: getPreference( 'core', 'showIconLabels' ), + hasFixedToolbar: getPreference( 'core', 'fixedToolbar' ), + isNestedEntity: + !! getEditorSettings().onNavigateToPreviousEntityRecord, + isZoomedOutView: __unstableGetEditorMode() === 'zoom-out', + }; + }, [] ); + + const hasTopToolbar = isLargeViewport && hasFixedToolbar; + + const [ isBlockToolsCollapsed, setIsBlockToolsCollapsed ] = + useState( true ); + + // The edit-post-header classname is only kept for backward compatibilty + // as some plugins might be relying on its presence. + return ( +
+ { children } + + + { hasTopToolbar && ( + + ) } +
+ { ! title ? ( + + + + ) : ( + title + ) } +
+
+ + { ! customSaveButton && ! 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 + // we want to prevent mounting/unmounting the PostPublishButtonOrToggle DOM node. + // We track that DOM node to return focus to the PostPublishButtonOrToggle + // when the publish sidebar has been closed. + + ) } + + + + { ! customSaveButton && ( + + ) } + { customSaveButton } + { ( isWideViewport || ! showIconLabels ) && ( + + ) } + + +
+ ); +} + +export default Header; diff --git a/packages/editor/src/components/header/style.scss b/packages/editor/src/components/header/style.scss new file mode 100644 index 00000000000000..3040362a7bd575 --- /dev/null +++ b/packages/editor/src/components/header/style.scss @@ -0,0 +1,231 @@ +.editor-header { + height: $header-height; + background: $white; + display: flex; + flex-wrap: wrap; + align-items: center; + // The header should never be wider than the viewport, or buttons might be hidden. Especially relevant at high zoom levels. Related to https://core.trac.wordpress.org/ticket/47603#ticket. + max-width: 100vw; + justify-content: space-between; + + // Make toolbar sticky on larger breakpoints + @include break-zoomed-in { + flex-wrap: nowrap; + } +} + +.editor-header__toolbar { + display: flex; + // Allow this area to shrink to fit the toolbar buttons. + flex-shrink: 8; + // Take up the space of the toolbar so it can be justified to the left side of the toolbar. + flex-grow: 3; + // Hide the overflow so flex will limit its width. Block toolbar will allow scrolling on fixed toolbar. + overflow: hidden; + // Leave enough room for the focus ring to show. + padding: 2px 0; + align-items: center; + // Allow focus ring to be fully visible on furthest right button. + @include break-medium() { + padding-right: var(--wp-admin-border-width-focus); + } + + .table-of-contents { + display: none; + + @include break-small() { + display: block; + } + } +} + +.editor-header__center { + flex-grow: 1; + display: flex; + justify-content: center; + + &.is-collapsed { + display: none; + } +} + +/** + * Buttons on the right side + */ + +.editor-header__settings { + display: inline-flex; + align-items: center; + flex-wrap: nowrap; + padding-right: $grid-unit-05; + + @include break-small () { + padding-right: $grid-unit-10; + } + + gap: $grid-unit-10; +} + +/** + * Show icon labels. + */ + +.show-icon-labels.interface-pinned-items, +.show-icon-labels .editor-header { + .components-button.has-icon { + width: auto; + + // Hide the button icons when labels are set to display... + svg { + display: none; + } + // ... and display labels. + &::after { + content: attr(aria-label); + } + &[aria-disabled="true"] { + background-color: transparent; + } + } + .is-tertiary { + &:active { + box-shadow: 0 0 0 1.5px var(--wp-admin-theme-color); + background-color: transparent; + } + } + // Exception for drodpdown toggle buttons. + .components-button.has-icon.button-toggle { + svg { + display: block; + } + &::after { + content: none; + } + } + + // Don't hide MenuItemsChoice check icons + .components-menu-items-choice .components-menu-items__item-icon.components-menu-items__item-icon { + display: block; + } + .editor-document-tools__inserter-toggle.editor-document-tools__inserter-toggle, + .interface-pinned-items .components-button { + padding-left: $grid-unit; + padding-right: $grid-unit; + + @include break-small { + padding-left: $grid-unit-15; + padding-right: $grid-unit-15; + } + } + + .editor-post-save-draft.editor-post-save-draft, + .editor-post-saved-state.editor-post-saved-state { + &::after { + content: none; + } + } +} + +.show-icon-labels { + .editor-header__toolbar .block-editor-block-mover { + // Modified group borders. + border-left: none; + + &::before { + content: ""; + width: $border-width; + height: $grid-unit-30; + background-color: $gray-300; + margin-top: $grid-unit-05; + margin-left: $grid-unit; + } + + // Modified block movers horizontal separator. + .block-editor-block-mover__move-button-container { + &::before { + width: calc(100% - #{$grid-unit-30}); + background: $gray-300; + left: calc(50% + 1px); + } + } + } +} + +.show-icon-labels.interface-pinned-items { + padding: 6px $grid-unit-15 $grid-unit-15; + margin-top: 0; + margin-bottom: 0; + margin-left: -$grid-unit-15; + margin-right: -$grid-unit-15; + border-bottom: 1px solid $gray-400; + display: block; + + > .components-button.has-icon { + margin: 0; + padding: 6px 6px 6px $grid-unit; + width: 14.625rem; + justify-content: flex-start; + + &[aria-expanded="true"] svg { + display: block; + max-width: $grid-unit-30; + } + &[aria-expanded="false"] { + padding-left: $grid-unit-50; + } + svg { + margin-right: 8px; + } + } +} + +.editor-header__post-preview-button { + @include break-small { + display: none; + } +} + +.is-distraction-free { + .interface-interface-skeleton__header { + border-bottom: none; + } + + .editor-header { + background-color: $white; + border-bottom: 1px solid #e0e0e0; + position: absolute; + width: 100%; + + + // hide some parts + & > .edit-post-header__settings > .edit-post-header__post-preview-button { + visibility: hidden; + } + + & > .editor-header__toolbar .editor-document-tools__document-overview-toggle, + & > .editor-header__settings > .editor-preview-dropdown, + & > .editor-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; + } +} + +.components-popover.more-menu-dropdown__content { + z-index: z-index(".components-popover.more-menu__content"); +} diff --git a/packages/editor/src/private-apis.js b/packages/editor/src/private-apis.js index 762c6bec89c883..cee1a734ca34c5 100644 --- a/packages/editor/src/private-apis.js +++ b/packages/editor/src/private-apis.js @@ -6,22 +6,18 @@ import * as interfaceApis from '@wordpress/interface'; /** * Internal dependencies */ -import CollapsableBlockToolbar from './components/collapsible-block-toolbar'; import EditorCanvas from './components/editor-canvas'; import { ExperimentalEditorProvider } from './components/provider'; import { lock } from './lock-unlock'; import { EntitiesSavedStatesExtensible } from './components/entities-saved-states'; import useAutoSwitchEditorSidebars from './components/provider/use-auto-switch-editor-sidebars'; import useBlockEditorSettings from './components/provider/use-block-editor-settings'; -import DocumentTools from './components/document-tools'; +import Header from './components/header'; import InserterSidebar from './components/inserter-sidebar'; import ListViewSidebar from './components/list-view-sidebar'; -import MoreMenu from './components/more-menu'; import PatternOverridesPanel from './components/pattern-overrides-panel'; import PluginPostExcerpt from './components/post-excerpt/plugin'; import PostPanelRow from './components/post-panel-row'; -import PostViewLink from './components/post-view-link'; -import PreviewDropdown from './components/preview-dropdown'; import PreferencesModal from './components/preferences-modal'; import PostActions from './components/post-actions'; import { usePostActions } from './components/post-actions/actions'; @@ -30,7 +26,6 @@ import PostStatus from './components/post-status'; import ToolsMoreMenuGroup from './components/more-menu/tools-more-menu-group'; import ViewMoreMenuGroup from './components/more-menu/view-more-menu-group'; import { PrivatePostExcerptPanel } from './components/post-excerpt/panel'; -import PostPublishButtonOrToggle from './components/post-publish-button/post-publish-button-or-toggle'; import SavePublishPanels from './components/save-publish-panels'; import PostContentInformation from './components/post-content-information'; import PostLastEditedPanel from './components/post-last-edited-panel'; @@ -39,20 +34,16 @@ const { store: interfaceStore, ...remainingInterfaceApis } = interfaceApis; export const privateApis = {}; lock( privateApis, { - CollapsableBlockToolbar, - DocumentTools, EditorCanvas, ExperimentalEditorProvider, EntitiesSavedStatesExtensible, + Header, InserterSidebar, ListViewSidebar, - MoreMenu, PatternOverridesPanel, PluginPostExcerpt, PostActions, PostPanelRow, - PostViewLink, - PreviewDropdown, PreferencesModal, usePostActions, PostCardPanel, @@ -60,7 +51,6 @@ lock( privateApis, { ToolsMoreMenuGroup, ViewMoreMenuGroup, PrivatePostExcerptPanel, - PostPublishButtonOrToggle, SavePublishPanels, PostContentInformation, PostLastEditedPanel, diff --git a/packages/editor/src/private-apis.native.js b/packages/editor/src/private-apis.native.js new file mode 100644 index 00000000000000..78ef82c327f8fd --- /dev/null +++ b/packages/editor/src/private-apis.native.js @@ -0,0 +1,61 @@ +/** + * WordPress dependencies + */ +import * as interfaceApis from '@wordpress/interface'; + +/** + * Internal dependencies + */ +import EditorCanvas from './components/editor-canvas'; +import { ExperimentalEditorProvider } from './components/provider'; +import { lock } from './lock-unlock'; +import { EntitiesSavedStatesExtensible } from './components/entities-saved-states'; +import useAutoSwitchEditorSidebars from './components/provider/use-auto-switch-editor-sidebars'; +import useBlockEditorSettings from './components/provider/use-block-editor-settings'; +import InserterSidebar from './components/inserter-sidebar'; +import ListViewSidebar from './components/list-view-sidebar'; +import PatternOverridesPanel from './components/pattern-overrides-panel'; +import PluginPostExcerpt from './components/post-excerpt/plugin'; +import PostPanelRow from './components/post-panel-row'; +import PreferencesModal from './components/preferences-modal'; +import PostActions from './components/post-actions'; +import { usePostActions } from './components/post-actions/actions'; +import PostCardPanel from './components/post-card-panel'; +import PostStatus from './components/post-status'; +import ToolsMoreMenuGroup from './components/more-menu/tools-more-menu-group'; +import ViewMoreMenuGroup from './components/more-menu/view-more-menu-group'; +import { PrivatePostExcerptPanel } from './components/post-excerpt/panel'; +import SavePublishPanels from './components/save-publish-panels'; +import PostContentInformation from './components/post-content-information'; +import PostLastEditedPanel from './components/post-last-edited-panel'; + +const { store: interfaceStore, ...remainingInterfaceApis } = interfaceApis; + +export const privateApis = {}; +lock( privateApis, { + EditorCanvas, + ExperimentalEditorProvider, + EntitiesSavedStatesExtensible, + InserterSidebar, + ListViewSidebar, + PatternOverridesPanel, + PluginPostExcerpt, + PostActions, + PostPanelRow, + PreferencesModal, + usePostActions, + PostCardPanel, + PostStatus, + ToolsMoreMenuGroup, + ViewMoreMenuGroup, + PrivatePostExcerptPanel, + SavePublishPanels, + PostContentInformation, + PostLastEditedPanel, + + // This is a temporary private API while we're updating the site editor to use EditorProvider. + useAutoSwitchEditorSidebars, + useBlockEditorSettings, + interfaceStore, + ...remainingInterfaceApis, +} ); diff --git a/packages/editor/src/style.scss b/packages/editor/src/style.scss index ed61638ffb7ef6..e869bf2d68b363 100644 --- a/packages/editor/src/style.scss +++ b/packages/editor/src/style.scss @@ -9,6 +9,7 @@ @import "./components/editor-notices/style.scss"; @import "./components/entities-saved-states/style.scss"; @import "./components/error-boundary/style.scss"; +@import "./components/header/style.scss"; @import "./components/inserter-sidebar/style.scss"; @import "./components/keyboard-shortcut-help-modal/style.scss"; @import "./components/list-view-sidebar/style.scss"; diff --git a/test/e2e/specs/site-editor/block-removal.spec.js b/test/e2e/specs/site-editor/block-removal.spec.js index 2b149bcc69bf3e..7d656fbd2774ff 100644 --- a/test/e2e/specs/site-editor/block-removal.spec.js +++ b/test/e2e/specs/site-editor/block-removal.spec.js @@ -25,7 +25,9 @@ test.describe( 'Site editor block removal prompt', () => { } ) => { // Open and focus List View const topBar = page.getByRole( 'region', { name: 'Editor top bar' } ); - await topBar.getByRole( 'button', { name: 'List View' } ).click(); + await topBar + .getByRole( 'button', { name: 'Document Overview' } ) + .click(); // Select and try to remove Query Loop block const listView = page.getByRole( 'region', { name: 'List View' } ); @@ -45,7 +47,9 @@ test.describe( 'Site editor block removal prompt', () => { } ) => { // Open and focus List View const topBar = page.getByRole( 'region', { name: 'Editor top bar' } ); - await topBar.getByRole( 'button', { name: 'List View' } ).click(); + await topBar + .getByRole( 'button', { name: 'Document Overview' } ) + .click(); // Select and open child blocks of Query Loop block const listView = page.getByRole( 'region', { name: 'List View' } ); @@ -70,7 +74,9 @@ test.describe( 'Site editor block removal prompt', () => { } ) => { // Open and focus List View const topBar = page.getByRole( 'region', { name: 'Editor top bar' } ); - await topBar.getByRole( 'button', { name: 'List View' } ).click(); + await topBar + .getByRole( 'button', { name: 'Document Overview' } ) + .click(); // Select Query Loop list item const listView = page.getByRole( 'region', { name: 'List View' } ); diff --git a/test/e2e/specs/site-editor/list-view.spec.js b/test/e2e/specs/site-editor/list-view.spec.js index 9b7a1c17a9ce1d..9bccc7c56446a6 100644 --- a/test/e2e/specs/site-editor/list-view.spec.js +++ b/test/e2e/specs/site-editor/list-view.spec.js @@ -106,7 +106,7 @@ test.describe( 'Site Editor List View', () => { // Focus should now be on the list view toggle button. await expect( - page.getByRole( 'button', { name: 'List View' } ) + page.getByRole( 'button', { name: 'Document Overview' } ) ).toBeFocused(); // Open List View. @@ -129,7 +129,7 @@ test.describe( 'Site Editor List View', () => { await pageUtils.pressKeys( 'access+o' ); await expect( listView ).toBeHidden(); await expect( - page.getByRole( 'button', { name: 'List View' } ) + page.getByRole( 'button', { name: 'Document Overview' } ) ).toBeFocused(); } ); } ); diff --git a/test/e2e/specs/site-editor/style-book.spec.js b/test/e2e/specs/site-editor/style-book.spec.js index 4a5864755614b4..087013607be2f2 100644 --- a/test/e2e/specs/site-editor/style-book.spec.js +++ b/test/e2e/specs/site-editor/style-book.spec.js @@ -30,18 +30,12 @@ test.describe( 'Style Book', () => { test( 'should disable toolbar buttons when open', async ( { page } ) => { await expect( page.locator( 'role=button[name="Toggle block inserter"i]' ) - ).toBeHidden(); + ).toBeDisabled(); await expect( page.locator( 'role=button[name="Tools"i]' ) - ).toBeHidden(); - await expect( - page.locator( 'role=button[name="Undo"i]' ) - ).toBeHidden(); - await expect( - page.locator( 'role=button[name="Redo"i]' ) - ).toBeHidden(); + ).toBeDisabled(); await expect( - page.locator( 'role=button[name="View"i]' ) + page.locator( 'role=button[name="Document Overview"i]' ) ).toBeDisabled(); } );