diff --git a/packages/block-library/src/classic/editor.scss b/packages/block-library/src/classic/editor.scss index bc4e371702a875..0720c22d4a2c3d 100644 --- a/packages/block-library/src/classic/editor.scss +++ b/packages/block-library/src/classic/editor.scss @@ -216,9 +216,12 @@ div[data-type="core/freeform"] .editor-block-contextual-toolbar + div { // So we move it to the right, and make room for it. @include break-small() { .editor-block-list__block[data-type="core/freeform"] { + .editor-block-switcher__no-switcher-icon { + display: none; + } .editor-block-contextual-toolbar { float: right; - margin-right: -$block-side-ui-clearance - $border-width; + margin-right: $icon-button-size - $block-padding + $border-width; transform: translateY(-#{ $block-padding - $border-width }); top: $block-padding; diff --git a/packages/block-library/src/columns/editor.scss b/packages/block-library/src/columns/editor.scss index a96a6dcf8c1ea3..234fd4783f4b24 100644 --- a/packages/block-library/src/columns/editor.scss +++ b/packages/block-library/src/columns/editor.scss @@ -69,10 +69,10 @@ } @include break-small() { - > .editor-block-contextual-toolbar { + > .editor-block-list__block-edit > .editor-block-contextual-toolbar { top: $block-toolbar-height - $border-width; transform: translateY(-$block-toolbar-height - $border-width); - margin-left: -$block-padding - $block-padding - $border-width; + margin-left: -$grid-size-large - $border-width; } > .editor-block-list__block-edit::before { @@ -82,8 +82,9 @@ left: 0; } - > .editor-block-list__breadcrumb { - margin-right: -$block-padding - $border-width; + > .editor-block-list__block-edit > .editor-block-list__breadcrumb { + top: 0; + right: 0; } } @@ -133,6 +134,6 @@ pointer-events: none; } -:not(.components-disabled) > .wp-block-columns > .editor-inner-blocks > .editor-block-list__layout > [data-type="core/column"] > .editor-block-list__block-edit > .editor-inner-blocks { +:not(.components-disabled) > .wp-block-columns > .editor-inner-blocks > .editor-block-list__layout > [data-type="core/column"] > .editor-block-list__block-edit .editor-inner-blocks { pointer-events: all; } diff --git a/packages/edit-post/src/components/visual-editor/style.scss b/packages/edit-post/src/components/visual-editor/style.scss index 2795f5330ba361..0463c005479ef4 100644 --- a/packages/edit-post/src/components/visual-editor/style.scss +++ b/packages/edit-post/src/components/visual-editor/style.scss @@ -29,9 +29,9 @@ // Center the block toolbar on wide and full-wide blocks. // Use specific selector to not affect nested block toolbars. - &[data-align="wide"] > .editor-block-contextual-toolbar, - &[data-align="full"] > .editor-block-contextual-toolbar { - width: calc(100% + #{ $block-side-ui-width * 2 + $block-padding * 2 + $border-width * 2 }); // Matches the negative margins applied to parent blocks. + &[data-align="wide"] > .editor-block-list__block-edit > .editor-block-contextual-toolbar, + &[data-align="full"] > .editor-block-list__block-edit > .editor-block-contextual-toolbar { + width: calc(100% + #{ $block-padding * 2 + $border-width * 2 }); // Matches the negative margins applied to parent blocks. height: 0; // This collapses the container to an invisible element without margin. text-align: center; @@ -42,9 +42,11 @@ } } - // The centering math changes when a fullwide image doesn't have block padding. - &[data-align="full"] > .editor-block-contextual-toolbar { - width: calc(100% + #{ $block-side-ui-width * 2 + $block-padding * 2 }); // Matches the negative margins applied to non-parent blocks, except for borders which are gone in fullwide. + // The centering math is simpler for a fullwide block, which doesn't have any block padding. + &[data-align="full"] > .editor-block-list__block-edit > .editor-block-contextual-toolbar { + width: 100%; + margin-left: 0; + margin-right: 0; .editor-block-toolbar { max-width: $content-width - $border-width - $border-width; @@ -84,6 +86,12 @@ } .edit-post-visual-editor { + // If the first block is floated, it needs top margin, unlike the rule in line 69. + .editor-block-list__layout > .editor-block-list__block[data-align="left"]:first-child, + .editor-block-list__layout > .editor-block-list__block[data-align="right"]:first-child { + margin-top: $block-padding + $block-spacing + $border-width + $border-width + $block-padding; + } + .editor-default-block-appender { // Default to centered and content-width, like blocks margin-left: auto; diff --git a/packages/editor/src/components/block-list/block.js b/packages/editor/src/components/block-list/block.js index 8b656f0616944e..bd156cb3f79ecd 100644 --- a/packages/editor/src/components/block-list/block.js +++ b/packages/editor/src/components/block-list/block.js @@ -515,45 +515,46 @@ export class BlockListBlock extends Component { onDragEnd={ this.onDragEnd } /> ) } - { shouldShowBreadcrumb && ( - - ) } - { shouldShowContextualToolbar && } { isFirstMultiSelected && ( ) } - - - { isValid && blockEdit } - { isValid && mode === 'html' && ( - - ) } - { ! isValid && [ - , -
- { getSaveElement( blockType, block.attributes ) } -
, - ] } -
- { shouldShowMobileToolbar && ( - + { shouldShowBreadcrumb && ( + ) } - { !! error && } -
+ { shouldShowContextualToolbar && } + + + { isValid && blockEdit } + { isValid && mode === 'html' && ( + + ) } + { ! isValid && [ + , +
+ { getSaveElement( blockType, block.attributes ) } +
, + ] } +
+ { shouldShowMobileToolbar && ( + + ) } + { !! error && } +
+ { showEmptyBlockSideInserter && (
diff --git a/packages/editor/src/components/block-list/style.scss b/packages/editor/src/components/block-list/style.scss index 28632c0eda60af..203f5dec761190 100644 --- a/packages/editor/src/components/block-list/style.scss +++ b/packages/editor/src/components/block-list/style.scss @@ -295,13 +295,23 @@ // Position toolbar better on mobile. .editor-block-contextual-toolbar { - border-bottom: 1px solid $light-gray-500; - bottom: $block-padding; - left: auto; - right: auto; + width: auto; + border-bottom: $border-width solid $light-gray-500; + bottom: auto; } } + // Unlike most explicit left/right alignments, this one should be flipped by the auto-RTL system. + &[data-align="left"] .editor-block-contextual-toolbar { + left: 0; + right: auto; + } + + &[data-align="right"] .editor-block-contextual-toolbar { + left: auto; + right: 0; + } + // Left &[data-align="left"] { // This is in the editor only; the image should be floated on the frontend. @@ -407,8 +417,8 @@ // Full-wide &[data-align="full"] { // Position hover label on the right - > .editor-block-list__breadcrumb { - right: -$border-width; + > .editor-block-list__block-edit .editor-block-list__breadcrumb { + right: 0; } // Compensate for main container padding and subtract border. @@ -485,7 +495,8 @@ > .editor-block-mover { position: absolute; width: $block-side-ui-width + $block-side-ui-clearance; - // stretch to fill half of the available space to increase hoverable area + + // Stretch to fill half of the available space to increase hoverable area. height: 100%; max-height: $block-side-ui-width * 4; } @@ -506,7 +517,7 @@ } } - // Left side UI + // Left side UI. > .editor-block-mover { padding-right: $block-side-ui-clearance; @@ -532,15 +543,15 @@ .editor-block-list__block-mobile-toolbar { display: flex; flex-direction: row; + // Make room for the height of the block toolbar above. - margin-top: $grid-size + $block-toolbar-height - $block-padding; + transform: translateY($block-padding + $border-width); + margin-top: $block-toolbar-height; margin-right: -$block-padding; margin-left: -$block-padding; border-top: $border-width solid $light-gray-500; height: $block-toolbar-height; - transform: translateY(#{ $block-padding + $border-width }); - @include break-small() { display: none; } @@ -724,58 +735,72 @@ * Block Toolbar when contextual. */ -.editor-block-list__block .editor-block-contextual-toolbar { - position: sticky; - z-index: z-index(".editor-block-contextual-toolbar"); - white-space: nowrap; - text-align: left; - pointer-events: none; - - // Position toolbar below the block on mobile. - position: absolute; - bottom: $block-toolbar-height - $block-padding - 1px; - left: 0; - right: 0; +.editor-block-list__block { + .editor-block-contextual-toolbar { + position: sticky; + z-index: z-index(".editor-block-contextual-toolbar"); + white-space: nowrap; + text-align: left; + pointer-events: none; - // Paint the borders on the toolbar itself on mobile. - border-top: $border-width solid $light-gray-500; - .components-toolbar { - border-top: none; - border-bottom: none; - } + // Position toolbar below the block on mobile. + position: absolute; + bottom: $block-toolbar-height - $block-padding; + left: -$block-padding; + right: -$block-padding; - @include break-small() { - border-top: none; + // Paint the borders on the toolbar itself on mobile. + border-top: $border-width solid $light-gray-500; .components-toolbar { - border-top: $border-width solid $light-gray-500; - border-bottom: $border-width solid $light-gray-500; + border-top: none; + border-bottom: none; + } + + @include break-small() { + border-top: none; + .components-toolbar { + border-top: $border-width solid $light-gray-500; + border-bottom: $border-width solid $light-gray-500; + } } } // Floated items have special needs for the contextual toolbar position. - .editor-block-list__block[data-align="left"] &, - .editor-block-list__block[data-align="right"] & { + &[data-align="left"] .editor-block-contextual-toolbar, + &[data-align="right"] .editor-block-contextual-toolbar { margin-bottom: $border-width; - margin-top: -$block-toolbar-height - $border-width; + margin-top: -$block-toolbar-height; } // Make block toolbar full width on mobile. - margin-left: 0; - margin-right: 0; + .editor-block-contextual-toolbar { + margin-left: 0; + margin-right: 0; + @include break-small() { + margin-left: -$block-padding - $border-width; + margin-right: -$block-padding - $border-width; + } + } - @include break-small() { - margin-left: -$block-side-ui-width - $block-padding - $border-width; - margin-right: -$block-side-ui-width - $block-padding - $border-width; + // For floats, compensate for this so content doesn't grow smaller. + &[data-align="left"] .editor-block-contextual-toolbar { + /*rtl:ignore*/ + margin-right: $block-padding + $border-width; + } - // Except for wide elements, this causes a horizontal scrollbar. - [data-align="full"] & { - margin-left: -$block-padding - $block-side-ui-width; - margin-right: -$block-padding - $block-side-ui-width; - } + &[data-align="right"] .editor-block-contextual-toolbar { + /*rtl:ignore*/ + margin-left: $block-padding + $border-width; + } + + // Don't do it for wide elements, this causes a horizontal scrollbar. + &[data-align="full"] .editor-block-contextual-toolbar { + margin-left: -$block-padding - $block-side-ui-width; + margin-right: -$block-padding - $block-side-ui-width; } // Reset pointer-events on children. - & > * { + .editor-block-contextual-toolbar > * { pointer-events: auto; } } @@ -804,30 +829,25 @@ // Compensate for translate, so the sticky sticks to the top. top: $block-toolbar-height + $block-padding; } - - // This is an important one. Because the toolbar is sticky, it's part of the flow. - // It behaves as relative, in other words, until it reaches an edge and then behaves as fixed. - // But by applying a float, we take it out of this flow. The benefit is that we don't need to compensate for margins. - // In turn, this allows margins on sibling elements to collapse to parent elements. - // RTL note: this rule does need to be auto-flipped based on direction. - float: left; } } .editor-block-list__block[data-align="left"] & { - @include break-small() { - // RTL note: this rule should not be auto-flipped based on direction. - /*rtl:ignore*/ - float: left; - } + // RTL note: this rule should not be auto-flipped based on direction. + /*rtl:ignore*/ + float: left; } .editor-block-list__block[data-align="right"] & { - @include break-small() { - // RTL note: this rule should not be auto-flipped based on direction. - /*rtl:ignore*/ - float: right; - } + // RTL note: this rule should not be auto-flipped based on direction. + /*rtl:ignore*/ + float: right; + } + + .editor-block-list__block[data-align="left"] &, + .editor-block-list__block[data-align="right"] & { + // Move the block toolbar out of the flow using translate, but less for floats. + transform: translateY(-$block-padding -$border-width); } } @@ -835,20 +855,16 @@ .editor-block-contextual-toolbar .editor-block-toolbar { width: 100%; - // Hide right border on desktop, where the .components-toolbar instead has a right border. @include break-small() { + width: auto; + + // Hide right border on desktop, where the .components-toolbar instead has a right border. border-right: none; - } - // This prevents floats from messing up the position. - @include break-small() { + // This prevents floats from messing up the position. position: absolute; left: 0; } - - @include break-small() { - width: auto; - } } @@ -862,7 +878,7 @@ z-index: z-index(".editor-block-list__breadcrumb"); // Position in the top right of the border. - right: 0; + right: -$block-padding; top: -$block-padding - $border-width; .components-toolbar { @@ -887,6 +903,13 @@ background: rgba($white, 0.5); color: $dark-gray-700; } + + // Position the breadcrumb closer on mobile. + [data-align="left"] &, + [data-align="right"] & { + right: 0; + top: 0; + } } .editor-block-list__descendant-arrow::before { diff --git a/test/e2e/specs/block-icons.test.js b/test/e2e/specs/block-icons.test.js index a02c497bbcd1bc..0e44cddb124f44 100644 --- a/test/e2e/specs/block-icons.test.js +++ b/test/e2e/specs/block-icons.test.js @@ -2,10 +2,11 @@ * Internal dependencies */ import { + ACCESS_MODIFIER_KEYS, + pressWithModifier, newPost, insertBlock, searchForBlock, - selectBlockByClientId, } from '../support/utils'; import { activatePlugin, deactivatePlugin } from '../support/plugins'; @@ -34,18 +35,17 @@ async function getFirstInserterIcon() { return await getInnerHTML( INSERTER_ICON_SELECTOR ); } +async function selectFirstBlock() { + await pressWithModifier( ACCESS_MODIFIER_KEYS, 'o' ); + const navButtons = await page.$$( '.editor-block-navigation__item-button' ); + await navButtons[ 0 ].click(); +} + describe( 'Correctly Renders Block Icons on Inserter and Inspector', () => { const dashIconRegex = /.*?<\/svg>/; const circleString = ''; const svgIcon = new RegExp( `${ circleString }` ); - const getBlockIdFromBlockName = async ( blockName ) => { - return await page.$eval( - `[data-type="${ blockName }"] > .editor-block-list__block-edit`, - ( el ) => el.getAttribute( 'data-block' ) - ); - }; - const validateSvgIcon = ( iconHtml ) => { expect( iconHtml ).toMatch( svgIcon ); }; @@ -81,7 +81,7 @@ describe( 'Correctly Renders Block Icons on Inserter and Inspector', () => { it( 'Renders correctly the icon on the inspector', async () => { await insertBlock( blockTitle ); - await selectBlockByClientId( await getBlockIdFromBlockName( blockName ) ); + await selectFirstBlock(); validateIcon( await getInnerHTML( INSPECTOR_ICON_SELECTOR ) ); } ); } @@ -105,7 +105,6 @@ describe( 'Correctly Renders Block Icons on Inserter and Inspector', () => { } ); describe( 'Block with dash icon and background and foreground colors', () => { - const blockName = 'test/test-dash-icon-colors'; const blockTitle = 'TestDashIconColors'; it( 'Renders the icon in the inserter with the correct colors', async () => { await searchForBlock( blockTitle ); @@ -116,7 +115,7 @@ describe( 'Correctly Renders Block Icons on Inserter and Inspector', () => { it( 'Renders the icon in the inspector with the correct colors', async () => { await insertBlock( blockTitle ); - await selectBlockByClientId( await getBlockIdFromBlockName( blockName ) ); + await selectFirstBlock(); validateDashIcon( await getInnerHTML( INSPECTOR_ICON_SELECTOR ) ); @@ -126,7 +125,6 @@ describe( 'Correctly Renders Block Icons on Inserter and Inspector', () => { } ); describe( 'Block with svg icon and background color', () => { - const blockName = 'test/test-svg-icon-background'; const blockTitle = 'TestSvgIconBackground'; it( 'Renders the icon in the inserter with the correct background color and an automatically compute readable foreground color', async () => { await searchForBlock( blockTitle ); @@ -137,7 +135,7 @@ describe( 'Correctly Renders Block Icons on Inserter and Inspector', () => { it( 'Renders correctly the icon on the inspector', async () => { await insertBlock( blockTitle ); - await selectBlockByClientId( await getBlockIdFromBlockName( blockName ) ); + await selectFirstBlock(); validateSvgIcon( await getInnerHTML( INSPECTOR_ICON_SELECTOR ) );