Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/editor/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### Enhancements

- Migrate the classic-theme template selector to `@wordpress/ui` `SelectControl` ([#84345](https://github.com/WordPress/gutenberg/pull/84345)).
- Show viewport dimensions and responsive editing status in the editor footer, and clarify when viewport-specific styling is available ([#84146](https://github.com/WordPress/gutenberg/pull/84146)).

### Bug Fixes

Expand Down
8 changes: 4 additions & 4 deletions packages/editor/src/components/commands/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,16 +264,16 @@ const getEditorCommandLoader = () =>
commands.push( {
name: 'core/toggle-breadcrumbs',
label: showBlockBreadcrumbs
? __( 'Hide block breadcrumbs' )
: __( 'Show block breadcrumbs' ),
? __( 'Hide editor footer' )
: __( 'Show editor footer' ),
category: 'command',
callback: ( { close } ) => {
toggle( 'core', 'showBlockBreadcrumbs' );
close();
createInfoNotice(
showBlockBreadcrumbs
? __( 'Breadcrumbs hidden.' )
: __( 'Breadcrumbs visible.' ),
? __( 'Editor footer hidden.' )
: __( 'Editor footer visible.' ),
{
id: 'core/editor/toggle-breadcrumbs/notice',
type: 'snackbar',
Expand Down
29 changes: 21 additions & 8 deletions packages/editor/src/components/editor-interface/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useState, useCallback, useLayoutEffect } from '@wordpress/element';
import { decodeEntities } from '@wordpress/html-entities';
import { InlineNotices } from '@wordpress/notices';
import { ThemeProvider } from '@wordpress/theme';
import { Stack } from '@wordpress/ui';
import { store as editorStore } from '../../store';
import { unlock } from '../../lock-unlock';
import TemplateValidationNotice from '../template-validation-notice';
Expand All @@ -31,6 +32,7 @@ import SavePublishPanels from '../save-publish-panels';
import TextEditor from '../text-editor';
import VisualEditor from '../visual-editor';
import StylesCanvas from '../styles-canvas';
import ViewportStatus from '../viewport-status';

const { blockToolbarShowPlaceholderKey } = unlock( blockEditorPrivateApis );

Expand Down Expand Up @@ -85,6 +87,7 @@ export default function EditorInterface( {
isDistractionFree,
isPreviewMode,
showBlockBreadcrumbs,
hasCanvasWidth,
postTypeLabel,
stylesPath,
showStylebook,
Expand All @@ -103,6 +106,7 @@ export default function EditorInterface( {
getShowStylebook,
isRevisionsMode: _isRevisionsMode,
isShowingRevisionDiff,
getCanvasWidth,
} = unlock( select( editorStore ) );
const editorSettings = getEditorSettings();

Expand All @@ -123,6 +127,7 @@ export default function EditorInterface( {
isDistractionFree: get( 'core', 'distractionFree' ),
isPreviewMode: editorSettings.isPreviewMode,
showBlockBreadcrumbs: get( 'core', 'showBlockBreadcrumbs' ),
hasCanvasWidth: getCanvasWidth() !== undefined,
postTypeLabel: getPostTypeLabel(),
stylesPath: getStylesPath(),
showStylebook: getShowStylebook(),
Expand Down Expand Up @@ -283,15 +288,23 @@ export default function EditorInterface( {
! isDistractionFree &&
isLargeViewport &&
showBlockBreadcrumbs &&
shouldShowBlockEditor &&
Comment thread
talldan marked this conversation as resolved.
mode === 'visual' && (
<BlockBreadcrumb
className="editor-editor-interface__breadcrumbs"
rootLabelText={
postTypeLabel
? decodeEntities( postTypeLabel )
: undefined
}
/>
<Stack
direction="row"
align="center"
className="editor-editor-interface__footer"
>
<BlockBreadcrumb
className="editor-editor-interface__breadcrumbs"
rootLabelText={
postTypeLabel
? decodeEntities( postTypeLabel )
: undefined
}
/>
{ hasCanvasWidth && <ViewportStatus /> }
</Stack>
)
}
actions={
Expand Down
7 changes: 7 additions & 0 deletions packages/editor/src/components/editor-interface/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
flex: 1 1 auto;
height: var(--wpds-dimension-size-md);
padding: 0 ($grid-unit-15 + 6px);
min-width: 0;
}

.editor-editor-interface__footer {
flex: 1;
min-width: 0;
min-height: var(--wpds-dimension-size-md);
}

.editor-editor-interface .entities-saved-states__panel-header {
Expand Down
12 changes: 6 additions & 6 deletions packages/editor/src/components/preferences-modal/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ export default function EditorPreferencesModal( { extraSections = {} } ) {

function PreferencesModalContents( { extraSections = {} } ) {
const isLargeViewport = useViewportMatch( 'medium' );
const { showBlockBreadcrumbsOption, showCollaborationOptions } = useSelect(
const { showFooterOptions, showCollaborationOptions } = useSelect(
( select ) => {
const { getEditorSettings, isCollaborationEnabledForCurrentPost } =
unlock( select( editorStore ) );
const { get } = select( preferencesStore );
const isRichEditingEnabled = getEditorSettings().richEditingEnabled;
const isDistractionFreeEnabled = get( 'core', 'distractionFree' );
return {
showBlockBreadcrumbsOption:
showFooterOptions:
! isDistractionFreeEnabled &&
isLargeViewport &&
isRichEditingEnabled,
Expand Down Expand Up @@ -89,14 +89,14 @@ function PreferencesModalContents( { extraSections = {} } ) {
) }
label={ __( 'Always open List View' ) }
/>
{ showBlockBreadcrumbsOption && (
{ showFooterOptions && (
<PreferenceToggleControl
scope="core"
featureName="showBlockBreadcrumbs"
help={ __(
'Display the block hierarchy trail at the bottom of the editor.'
'Display block breadcrumbs, viewport dimensions, and responsive editing status at the bottom of the editor.'
) }
label={ __( 'Show block breadcrumbs' ) }
label={ __( 'Show editor footer' ) }
/>
) }
<PreferenceToggleControl
Expand Down Expand Up @@ -370,7 +370,7 @@ function PreferencesModalContents( { extraSections = {} } ) {
},
].filter( Boolean ),
[
showBlockBreadcrumbsOption,
showFooterOptions,
showCollaborationOptions,
extraSections,
setIsInserterOpened,
Expand Down
34 changes: 18 additions & 16 deletions packages/editor/src/components/preview-dropdown/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import clsx from 'clsx';
import { useViewportMatch } from '@wordpress/compose';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { desktop, mobile, tablet } from '@wordpress/icons';
import { useSelect, useDispatch } from '@wordpress/data';
import { useEffect, useRef } from '@wordpress/element';
import { store as coreStore } from '@wordpress/core-data';
Expand All @@ -17,7 +16,10 @@ import MoreMenuItem from '../more-menu/more-menu-item';
import { toMenuItems } from '../more-menu/more-menu-submenu';
import { PostPreviewMenuItem } from '../post-preview-button';
import { sidebars } from '../sidebar/constants';
import { VIEWPORT_STATE_BY_DEVICE_TYPE } from '../../utils/device-type';
import {
DEVICE_TYPE_METADATA,
VIEWPORT_STATE_BY_DEVICE_TYPE,
} from '../../utils/device-type';
import { unlock } from '../../lock-unlock';

const { getViewportBreakpoints } = unlock( globalStylesEnginePrivateApis );
Expand Down Expand Up @@ -113,12 +115,6 @@ function PreviewMenu( { forceIsAutosaveable, disabled } ) {
}
};

const deviceIcons = {
desktop,
mobile,
tablet,
};

/**
* The choices for the device type.
* Duplicated in block-editor block-visibility constants, and in the edit-site
Expand All @@ -129,7 +125,7 @@ function PreviewMenu( { forceIsAutosaveable, disabled } ) {
const choices = [
{
value: 'Desktop',
label: __( 'Desktop' ),
label: DEVICE_TYPE_METADATA.Desktop.label,
info: isResponsiveEditing
? __( 'Style all viewports.' )
: __( 'Preview desktop viewport.' ),
Expand All @@ -138,7 +134,7 @@ function PreviewMenu( { forceIsAutosaveable, disabled } ) {
? [
{
value: 'Tablet',
label: __( 'Tablet' ),
label: DEVICE_TYPE_METADATA.Tablet.label,
info: isResponsiveEditing
? __( 'Style tablet only.' )
: __( 'Preview tablet viewport.' ),
Expand All @@ -149,7 +145,7 @@ function PreviewMenu( { forceIsAutosaveable, disabled } ) {
? [
{
value: 'Mobile',
label: __( 'Mobile' ),
label: DEVICE_TYPE_METADATA.Mobile.label,
info: isResponsiveEditing
? __( 'Style mobile only.' )
: __( 'Preview mobile viewport.' ),
Expand All @@ -165,10 +161,11 @@ function PreviewMenu( { forceIsAutosaveable, disabled } ) {
render={
<Button
className={ clsx( 'editor-preview-dropdown__toggle', {
'is-responsive-editing': isResponsiveEditing,
'is-responsive-editing':
isResponsiveEditing && deviceType !== 'Desktop',
} ) }
size="compact"
icon={ deviceIcons[ deviceType.toLowerCase() ] }
icon={ DEVICE_TYPE_METADATA[ deviceType ].icon }
label={ __( 'View' ) }
showTooltip={ ! showIconLabels }
accessibleWhenDisabled={ disabled }
Expand Down Expand Up @@ -202,6 +199,7 @@ function PreviewMenu( { forceIsAutosaveable, disabled } ) {
<Menu.Separator />
<Menu.Group>
<Menu.CheckboxItem
disabled={ deviceType === 'Desktop' }
checked={ isResponsiveEditing }
onCheckedChange={
handleResponsiveEditingChange
Expand All @@ -211,9 +209,13 @@ function PreviewMenu( { forceIsAutosaveable, disabled } ) {
{ __( 'Responsive styles' ) }
</Menu.ItemLabel>
<Menu.ItemDescription>
{ __(
'Style changes apply only to the selected viewport.'
) }
{ deviceType === 'Desktop'
? __(
'Select Tablet or Mobile to style a specific viewport.'
)
: __(
'Style changes apply only to the selected viewport.'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also a good improvement! It was confusing to have 'Style changes apply only to the selected viewport.' on desktop.

) }
</Menu.ItemDescription>
</Menu.CheckboxItem>
</Menu.Group>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { useDispatch, useSelect } from '@wordpress/data';
import { lock } from '../../../lock-unlock';
import PreviewDropdown from '../';

const setResponsiveEditing = vi.fn();

vi.mock( import( '@wordpress/compose' ), async ( importOriginal ) => ( {
...( await importOriginal() ),
useViewportMatch: vi.fn< typeof useViewportMatch >(),
Expand All @@ -27,10 +29,31 @@ beforeEach( () => {
lock( actions, {
setDeviceType: vi.fn(),
resetZoomLevel: vi.fn(),
setResponsiveEditing,
setStyleStateViewport: vi.fn(),
} );
vi.mocked( useDispatch ).mockReturnValue( actions );
} );

it( 'keeps responsive styles discoverable but prevents activation on Desktop', async () => {
await render( <Preview disabled={ false } /> );
await page.getByRole( 'button', { name: 'View', exact: true } ).click();
const option = page.getByRole( 'menuitemcheckbox', {
name: 'Responsive styles',
} );
await expect.element( option ).toHaveAttribute( 'aria-disabled', 'true' );
await expect
.element( option )
.toHaveAccessibleDescription(
'Select Tablet or Mobile to style a specific viewport.'
);
await userEvent.keyboard( '{Home}{ArrowDown}{ArrowDown}{ArrowDown}' );
await expect.element( option ).toHaveFocus();
await userEvent.keyboard( '{Enter} ' );
expect( setResponsiveEditing ).not.toHaveBeenCalled();
await expect.element( option ).toHaveAttribute( 'aria-checked', 'false' );
} );

function Preview( { disabled }: { disabled: boolean } ) {
return (
<SlotFillProvider>
Expand Down Expand Up @@ -58,3 +81,28 @@ it( 'closes the View menu when it becomes unavailable and keeps its trigger focu
await userEvent.keyboard( '{Escape}' );
await expect.element( page.getByRole( 'menu' ) ).not.toBeInTheDocument();
} );

it( 'shows the responsive editing cue only on viewport-specific breakpoints', async () => {
const selection = {
deviceType: 'Tablet',
hasMobileViewport: true,
hasTabletViewport: true,
isResponsiveEditing: true,
isResponsiveEditingEnabled: true,
};
vi.mocked( useSelect ).mockReturnValue( selection );
const screen = await render( <Preview disabled={ false } /> );
const trigger = page.getByRole( 'button', { name: 'View', exact: true } );
await expect.element( trigger ).toHaveClass( 'is-responsive-editing' );

vi.mocked( useSelect ).mockReturnValue( {
...selection,
deviceType: 'Desktop',
} );
await screen.rerender( <Preview disabled={ false } /> );
await expect.element( trigger ).not.toHaveClass( 'is-responsive-editing' );

vi.mocked( useSelect ).mockReturnValue( selection );
await screen.rerender( <Preview disabled={ false } /> );
await expect.element( trigger ).toHaveClass( 'is-responsive-editing' );
} );
16 changes: 13 additions & 3 deletions packages/editor/src/components/resizable-editor/index.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import clsx from 'clsx';
import { useDispatch } from '@wordpress/data';
import { useRef, useCallback, useState } from '@wordpress/element';
import { useRef, useCallback, useState, useEffect } from '@wordpress/element';
import {
ResizableBox,
__unstableMotion as motion,
} from '@wordpress/components';
import { useReducedMotion } from '@wordpress/compose';
import { useReducedMotion, useResizeObserver } from '@wordpress/compose';
import ResizeHandle from './resize-handle';
import { store as editorStore } from '../../store';
import { unlock } from '../../lock-unlock';
Expand Down Expand Up @@ -44,7 +44,16 @@ function ResizableEditor( {
} ) {
const [ isResizing, setIsResizing ] = useState( false );
const disableMotion = useReducedMotion();
const { setCanvasWidth } = unlock( useDispatch( editorStore ) );
const { setCanvasWidth, setPhysicalCanvasWidth } = unlock(
useDispatch( editorStore )
);
const measuredRef = useResizeObserver( ( entries ) => {
setPhysicalCanvasWidth( entries[ 0 ].contentRect.width );
} );
useEffect(
() => () => setPhysicalCanvasWidth( undefined ),
[ setPhysicalCanvasWidth ]
);

const resizableRef = useRef();
const resizeWidthBy = useCallback(
Expand Down Expand Up @@ -94,6 +103,7 @@ function ResizableEditor( {
} ) }
ref={ ( api ) => {
resizableRef.current = api?.resizable;
measuredRef( api?.resizable );
} }
size={ {
width,
Expand Down
Loading
Loading