From ff78d859458d12e475e8a61b3e6da8937d87a74c Mon Sep 17 00:00:00 2001 From: andrei draganescu Date: Tue, 29 Oct 2019 02:24:16 +0200 Subject: [PATCH] Add horizontal option for the block movers (#16615) * horizontal option for the mover, missing icons, broken hover * we now have icons * positioned the mover to the middle left * horizontal mover on mobile * vertical layout for horizontal movers * drop block movers into block edit to enable inline movers * implemented so as to not be a concern for the block implementer * removes useless scss variable * hiding the drag handle at block level * renamed horizontalMover to moverOptions to incorporate separation of properties * rafactores the mover options * Initial CSS work to make the menu more manageable. This moves to flex instead of grid, neutralizes margins, simplifies a few things. * Make movers inline again. * Further improve margins for child blocks. * adds proper aliases in BlockEdit * previxed options as experimental * RTL movers * removed the position option, marked option experimental * labeled as experimental new mober and block list props * refactored direction detection code for better readability, fixed some code alignment issues --- .../block-list/block-mobile-toolbar.js | 4 +- .../src/components/block-list/block.js | 42 +++++++----- .../src/components/block-list/index.js | 2 + .../components/block-list/multi-controls.js | 2 + .../src/components/block-list/style.scss | 3 + .../src/components/block-mover/icons.js | 12 ++++ .../src/components/block-mover/index.js | 57 +++++++++++++--- .../block-mover/mover-description.js | 51 ++++++++++---- .../src/components/block-mover/style.scss | 32 +++++++-- .../src/components/inner-blocks/index.js | 2 + .../src/navigation-menu-item/editor.scss | 50 +++++++++++++- .../block-library/src/navigation-menu/edit.js | 3 +- .../src/navigation-menu/editor.scss | 66 +++++++++++++++++++ 13 files changed, 284 insertions(+), 42 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block-mobile-toolbar.js b/packages/block-editor/src/components/block-list/block-mobile-toolbar.js index f35a7add73641..8af64ec12c021 100644 --- a/packages/block-editor/src/components/block-list/block-mobile-toolbar.js +++ b/packages/block-editor/src/components/block-list/block-mobile-toolbar.js @@ -9,11 +9,11 @@ import { ifViewportMatches } from '@wordpress/viewport'; import BlockMover from '../block-mover'; import VisualEditorInserter from '../inserter'; -function BlockMobileToolbar( { clientId } ) { +function BlockMobileToolbar( { clientId, moverDirection } ) { return (
- +
); } diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 777cb54933a80..48b5506e452f2 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -67,6 +67,7 @@ function BlockListBlock( { mode, isFocusMode, hasFixedToolbar, + moverDirection, isLocked, clientId, rootClientId, @@ -450,6 +451,20 @@ function BlockListBlock( { }; } const blockElementId = `block-${ clientId }`; + const blockMover = ( + + ); // We wrap the BlockEdit component in a div that hides it when editing in // HTML mode. This allows us to render all of the ancillary pieces @@ -511,22 +526,18 @@ function BlockListBlock( { rootClientId={ rootClientId } /> { isFirstMultiSelected && ( - + ) } -
- { shouldRenderMovers && ( - +
+ { shouldRenderMovers && ( moverDirection === 'vertical' ) && blockMover } { shouldShowBreadcrumb && ( ) } + { shouldRenderMovers && ( moverDirection === 'horizontal' ) && blockMover } { ! isValid && [ { !! hasError && } { shouldShowMobileToolbar && ( - + ) }
diff --git a/packages/block-editor/src/components/block-list/index.js b/packages/block-editor/src/components/block-list/index.js index 25386d5039c12..b6af745716b28 100644 --- a/packages/block-editor/src/components/block-list/index.js +++ b/packages/block-editor/src/components/block-list/index.js @@ -195,6 +195,7 @@ class BlockList extends Component { className, blockClientIds, rootClientId, + __experimentalMoverDirection: moverDirection = 'vertical', isDraggable, selectedBlockClientId, multiSelectedBlockClientIds, @@ -227,6 +228,7 @@ class BlockList extends Component { blockRef={ this.setBlockRef } onSelectionStart={ this.onSelectionStart } isDraggable={ isDraggable } + moverDirection={ moverDirection } // This prop is explicitely computed and passed down // to avoid being impacted by the async mode diff --git a/packages/block-editor/src/components/block-list/multi-controls.js b/packages/block-editor/src/components/block-list/multi-controls.js index e4dd88aeda030..2f49ca2ca0a3b 100644 --- a/packages/block-editor/src/components/block-list/multi-controls.js +++ b/packages/block-editor/src/components/block-list/multi-controls.js @@ -11,6 +11,7 @@ import BlockMover from '../block-mover'; function BlockListMultiControls( { multiSelectedBlockClientIds, isSelecting, + moverDirection, } ) { if ( isSelecting ) { return null; @@ -19,6 +20,7 @@ function BlockListMultiControls( { return ( ); } diff --git a/packages/block-editor/src/components/block-list/style.scss b/packages/block-editor/src/components/block-list/style.scss index 761632c49d7c7..e06667a0f914e 100644 --- a/packages/block-editor/src/components/block-list/style.scss +++ b/packages/block-editor/src/components/block-list/style.scss @@ -101,6 +101,9 @@ .block-editor-block-list__block-edit { position: relative; + &.has-mover-inside > [data-block] { + display: flex; + } &::before { z-index: z-index(".block-editor-block-list__block-edit::before"); diff --git a/packages/block-editor/src/components/block-mover/icons.js b/packages/block-editor/src/components/block-mover/icons.js index 06bf5601f439d..2a15b8a6159d5 100644 --- a/packages/block-editor/src/components/block-mover/icons.js +++ b/packages/block-editor/src/components/block-mover/icons.js @@ -9,12 +9,24 @@ export const upArrow = ( ); +export const leftArrow = ( + + + +); + export const downArrow = ( ); +export const rightArrow = ( + + + +); + export const dragHandle = ( @@ -107,6 +141,8 @@ export class BlockMover extends Component { isFirst, isLast, 1, + orientation, + isRTL, ) } @@ -125,12 +161,17 @@ export default compose( const blockOrder = getBlockOrder( rootClientId ); const firstIndex = getBlockIndex( firstClientId, rootClientId ); const lastIndex = getBlockIndex( last( normalizedClientIds ), rootClientId ); + const { getSettings } = select( 'core/block-editor' ); + const { + isRTL, + } = getSettings(); return { blockType: block ? getBlockType( block.name ) : null, isLocked: getTemplateLock( rootClientId ) === 'all', rootClientId, firstIndex, + isRTL, isFirst: firstIndex === 0, isLast: lastIndex === blockOrder.length - 1, }; diff --git a/packages/block-editor/src/components/block-mover/mover-description.js b/packages/block-editor/src/components/block-mover/mover-description.js index 44174ce85534c..d9a62de176d82 100644 --- a/packages/block-editor/src/components/block-mover/mover-description.js +++ b/packages/block-editor/src/components/block-mover/mover-description.js @@ -14,12 +14,30 @@ import { __, _n, sprintf } from '@wordpress/i18n'; * @param {boolean} isLast This is the last block. * @param {number} dir Direction of movement (> 0 is considered to be going * down, < 0 is up). + * @param {string} orientation The orientation of the block movers, vertical or + * horizontal. + * @param {boolean} isRTL True if current writing system is right to left. * * @return {string} Label for the block movement controls. */ -export function getBlockMoverDescription( selectedCount, type, firstIndex, isFirst, isLast, dir ) { +export function getBlockMoverDescription( selectedCount, type, firstIndex, isFirst, isLast, dir, orientation, isRTL ) { const position = ( firstIndex + 1 ); + const getMovementDirection = ( moveDirection ) => { + if ( moveDirection === 'up' ) { + if ( orientation === 'horizontal' ) { + return isRTL ? 'right' : 'left'; + } + return 'up'; + } else if ( moveDirection === 'down' ) { + if ( orientation === 'horizontal' ) { + return isRTL ? 'left' : 'right'; + } + return 'down'; + } + return null; + }; + if ( selectedCount > 1 ) { return getMultiBlockMoverDescription( selectedCount, firstIndex, isFirst, isLast, dir ); } @@ -32,35 +50,46 @@ export function getBlockMoverDescription( selectedCount, type, firstIndex, isFir if ( dir > 0 && ! isLast ) { // moving down return sprintf( - // translators: 1: Type of block (i.e. Text, Image etc), 2: Position of selected block, 3: New position - __( 'Move %1$s block from position %2$d down to position %3$d' ), + // translators: 1: Type of block (i.e. Text, Image etc), 2: Position of selected block, 3: Direction of movement ( up, down, left, right ), 4: New position + __( 'Move %1$s block from position %2$d %3$s to position %4$d' ), type, position, - ( position + 1 ) + getMovementDirection( 'down' ), + ( position + 1 ), ); } if ( dir > 0 && isLast ) { // moving down, and is the last item - // translators: %s: Type of block (i.e. Text, Image etc) - return sprintf( __( 'Block %s is at the end of the content and can’t be moved down' ), type ); + // translators: 1: Type of block (i.e. Text, Image etc), 2: Direction of movement ( up, down, left, right ) + return sprintf( + __( 'Block %1$s is at the end of the content and can’t be moved %2$s' ), + type, + getMovementDirection( 'down' ), + + ); } if ( dir < 0 && ! isFirst ) { // moving up return sprintf( - // translators: 1: Type of block (i.e. Text, Image etc), 2: Position of selected block, 3: New position - __( 'Move %1$s block from position %2$d up to position %3$d' ), + // translators: 1: Type of block (i.e. Text, Image etc), 2: Position of selected block, 3: Direction of movement ( up, down, left, right ), 4: New position + __( 'Move %1$s block from position %2$d %3$s to position %4$d' ), type, position, - ( position - 1 ) + getMovementDirection( 'up' ), + ( position - 1 ), ); } if ( dir < 0 && isFirst ) { // moving up, and is the first item - // translators: %s: Type of block (i.e. Text, Image etc) - return sprintf( __( 'Block %s is at the beginning of the content and can’t be moved up' ), type ); + // translators: 1: Type of block (i.e. Text, Image etc), 2: Direction of movement ( up, down, left, right ) + return sprintf( + __( 'Block %1$s is at the beginning of the content and can’t be moved %2$s' ), + type, + getMovementDirection( 'up' ), + ); } } diff --git a/packages/block-editor/src/components/block-mover/style.scss b/packages/block-editor/src/components/block-mover/style.scss index a506b3282fad4..260d456c73d3c 100644 --- a/packages/block-editor/src/components/block-mover/style.scss +++ b/packages/block-editor/src/components/block-mover/style.scss @@ -1,5 +1,4 @@ .block-editor-block-mover { - @include break-small() { min-height: $empty-paragraph-height; opacity: 0; @@ -20,13 +19,38 @@ // 24px is the smallest size of a good pressable button. // With 3 pieces of side UI, that comes to a total of 72px. // To vertically center against a 56px paragraph, move upwards 72px - 56px / 2. - // Don't do this for wide, fullwide, or mobile. - .block-editor-block-list__block:not([data-align="wide"]):not([data-align="full"]) & { - margin-top: -$grid-size; + margin-top: -$grid-size; + } + + &.is-horizontal { + margin-top: 5px; // The height of the appender is 36px. This pushes down the mover to be centered according to that. + margin-right: $grid-size; + padding-right: 0; + min-height: auto; + width: ($icon-button-size-small * 2) + ($border-width * 2); + height: $icon-button-size-small + ($border-width * 2); + display: flex; + + .block-editor-block-mover__control { + width: $icon-button-size-small; + height: $icon-button-size-small; + + svg { + width: $icon-button-size-small; + padding: 3px; + } } } } +// Don't add negative vertical margin for wide, fullwide, or mobile. +// @todo: simplify this selector. +@include break-small() { + .block-editor-block-list__block:not([data-align="wide"]):not([data-align="full"]) .editor-block-mover:not(.is-horizontal) { + margin-top: 0; + } +} + // Mover icon buttons. .block-editor-block-mover__control { display: flex; diff --git a/packages/block-editor/src/components/inner-blocks/index.js b/packages/block-editor/src/components/inner-blocks/index.js index 35e1bf10b47ca..ed147bfe736ad 100644 --- a/packages/block-editor/src/components/inner-blocks/index.js +++ b/packages/block-editor/src/components/inner-blocks/index.js @@ -107,6 +107,7 @@ class InnerBlocks extends Component { hasOverlay, renderAppender, template, + __experimentalMoverDirection: moverDirection, __experimentalTemplateOptions: templateOptions, __experimentalOnSelectTemplateOption: onSelectTemplateOption, __experimentalAllowTemplateOptionSkip: allowTemplateOptionSkip, @@ -131,6 +132,7 @@ class InnerBlocks extends Component { ) }
diff --git a/packages/block-library/src/navigation-menu-item/editor.scss b/packages/block-library/src/navigation-menu-item/editor.scss index fcebe469a04e9..8e6c06274129b 100644 --- a/packages/block-library/src/navigation-menu-item/editor.scss +++ b/packages/block-library/src/navigation-menu-item/editor.scss @@ -1,7 +1,55 @@ + +// Normalize menu items and edit containers, to look mostly the same. .wp-block-navigation-menu-item__field .components-text-control__input.components-text-control__input, .wp-block-navigation-menu-item__container { border-radius: 0; - padding: $block-padding; + // Make it the same height as the appender to prevent a jump. Maybe revisit this. + line-height: $icon-button-size; + min-height: $icon-button-size; +} + +.wp-block-navigation-menu-item { + margin-right: $grid-size; + + // Provide a base menu item margin. + // This should be the same inside the field, + // and the edit container should compensate. + // This is to make sure the edit and view are the same. + padding: 0 $grid-size; +} + +.wp-block-navigation-menu-item__edit-container { + display: flex; + white-space: nowrap; + + // Compensate for menu item base padding. + margin-left: -$grid-size; + + .wp-block-navigation-menu-item__field { + margin-right: $grid-size; + + // This should match the padding of the menu item. + padding: 0 $grid-size; + + // This make it look like an input field. + // We may want to not style this at all, but let's try this. + // We don't use the mixins because they increase the size of the input, which doesn't work with PlainText. + box-shadow: inset 0 0 0 1px $dark-gray-200; + transition: box-shadow 0.1s linear; + border-radius: $radius-round-rectangle; + @include reduce-motion("transition"); + + &:focus { + color: $dark-gray-900; + box-shadow: inset 0 0 0 2px $blue-medium-focus; + + // Windows High Contrast mode will show this outline, but not the box-shadow. + outline: 2px solid transparent; + } + } +} + +.wp-block-navigation-menu-item { font-family: $editor-font; font-weight: bold; font-size: $text-editor-font-size; diff --git a/packages/block-library/src/navigation-menu/edit.js b/packages/block-library/src/navigation-menu/edit.js index 074d683933302..b89afeff3863c 100644 --- a/packages/block-library/src/navigation-menu/edit.js +++ b/packages/block-library/src/navigation-menu/edit.js @@ -35,7 +35,6 @@ import BlockColorsStyleSelector from './block-colors-selector'; function NavigationMenu( { attributes, - setAttributes, clientId, pages, isRequesting, @@ -43,6 +42,7 @@ function NavigationMenu( { textColor, setBackgroundColor, setTextColor, + setAttributes, } ) { const { navigatorToolbarButton, navigatorModal } = useBlockNavigator( clientId ); const defaultMenuItems = useMemo( @@ -140,6 +140,7 @@ function NavigationMenu( { template={ defaultMenuItems ? defaultMenuItems : null } allowedBlocks={ [ 'core/navigation-menu-item' ] } templateInsertUpdatesSelection={ false } + __experimentalMoverDirection={ 'horizontal' } /> } diff --git a/packages/block-library/src/navigation-menu/editor.scss b/packages/block-library/src/navigation-menu/editor.scss index 5133b3261fb24..cc663e7787a99 100644 --- a/packages/block-library/src/navigation-menu/editor.scss +++ b/packages/block-library/src/navigation-menu/editor.scss @@ -1,3 +1,60 @@ +// Reduce the paddings, margins, and UI of inner-blocks. +// @todo: eventually we may add a feature that lets a parent container absorb the block UI of a child block. +// When that happens, leverage that instead of the following overrides. +[data-type="core/navigation-menu"] { + // 1. Reset margins on immediate innerblocks container. + .wp-block-navigation-menu .block-editor-inner-blocks > .block-editor-block-list__layout { + margin-left: 0; + margin-right: 0; + } + + // 2. Remove paddings on subsequent immediate children. + .wp-block-navigation-menu .block-editor-inner-blocks > .block-editor-block-list__layout > .wp-block { + width: auto; + padding-left: 0; + padding-right: 0; + margin-left: 0; // something + } + + // 3. Remove margins on subsequent Edit container. + .wp-block-navigation-menu .block-editor-inner-blocks > .block-editor-block-list__layout > .wp-block > .block-editor-block-list__block-edit { + margin-left: 0; + margin-right: 0; + } + + // 4. Remove vertical margins on subsequent block container. + .wp-block-navigation-menu .block-editor-inner-blocks > .block-editor-block-list__layout .wp-block > .block-editor-block-list__block-edit > [data-block] { + margin-top: 0; + margin-bottom: 0; + } + + // Remove the dashed outlines for child blocks. + &.is-hovered .wp-block-navigation-menu .block-editor-block-list__block-edit::before, + &.is-selected .wp-block-navigation-menu .block-editor-block-list__block-edit::before, + &.has-child-selected .wp-block-navigation-menu .block-editor-block-list__block-edit::before { + border-color: transparent !important; // !important used to keep the selector from growing any more complex. + } + + // Hide the breadcrumb. + // Hide the sibling inserter. + .wp-block-navigation-menu .block-editor-block-list__insertion-point, + .wp-block-navigation-menu .block-editor-block-list__breadcrumb { + display: none; + } + + // Polish the Appender. + .wp-block-navigation-menu .block-list-appender { + margin: 0; + + .block-editor-button-block-appender { + padding: $grid-size; + outline: none; + background: none; + } + } +} + + .wp-block-navigation-menu .block-editor-block-list__layout, .wp-block-navigation-menu { display: flex; @@ -9,6 +66,7 @@ } .wp-block-navigation-menu-item { + margin-left: $grid-size; .wp-block-navigation-menu-item__link { margin-left: $grid-size-large; } @@ -96,3 +154,11 @@ $color-control-label-height: 20px; margin-top: 2px; } } + +.block-editor-block-mover { + &.is-horizontal { + .block-editor-block-mover__control-drag-handle { + display: none; + } + } +}