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 (
- { 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;
+ }
+ }
+}