diff --git a/packages/block-editor/src/components/block-list/block.native.js b/packages/block-editor/src/components/block-list/block.native.js index db30304cfeee3..918c414ba833c 100644 --- a/packages/block-editor/src/components/block-list/block.native.js +++ b/packages/block-editor/src/components/block-list/block.native.js @@ -66,6 +66,7 @@ class BlockListBlock extends Component { this.props.onCaretVerticalPositionChange } clientId={ this.props.clientId } + contentStyle={ this.props.contentStyle } /> ); } @@ -91,6 +92,8 @@ class BlockListBlock extends Component { parentId, isDimmed, isTouchable, + onDeleteBlock, + horizontalDirection, hasParent, isParentSelected, onSelect, @@ -98,6 +101,7 @@ class BlockListBlock extends Component { getStylesFromColorScheme, marginVertical, marginHorizontal, + isInnerBlockSelected, } = this.props; const accessibilityLabel = getAccessibleBlockLabel( @@ -106,13 +110,18 @@ class BlockListBlock extends Component { order + 1 ); + const accessible = ! ( isSelected || isInnerBlockSelected ); + return ( - + { showFloatingToolbar && ( { hasParent && ( @@ -168,7 +177,11 @@ class BlockListBlock extends Component { ) } { isSelected && ( - + ) } @@ -190,10 +203,12 @@ export default compose( [ getBlockRootClientId, getLowestCommonAncestorWithSelectedBlock, getBlockParents, + hasSelectedInnerBlock, } = select( 'core/block-editor' ); const order = getBlockIndex( clientId, rootClientId ); const isSelected = isBlockSelected( clientId ); + const isInnerBlockSelected = hasSelectedInnerBlock( clientId ); const block = __unstableGetBlockWithoutInnerBlocks( clientId ); const { name, attributes, isValid } = block || {}; @@ -256,6 +271,7 @@ export default compose( [ attributes, blockType, isSelected, + isInnerBlockSelected, isValid, parentId, isParentSelected, diff --git a/packages/block-editor/src/components/block-list/index.native.js b/packages/block-editor/src/components/block-list/index.native.js index 53d696e5d00e6..830f92559b5ce 100644 --- a/packages/block-editor/src/components/block-list/index.native.js +++ b/packages/block-editor/src/components/block-list/index.native.js @@ -98,6 +98,8 @@ export class BlockList extends Component { withFooter = true, isReadOnly, isRootList, + horizontal, + scrollEnabled, shouldShowInsertionPointBefore, shouldShowInsertionPointAfter, marginVertical = styles.defaultBlock.marginTop, @@ -133,9 +135,16 @@ export class BlockList extends Component { } inputAccessoryViewHeight={ headerToolbar.height } keyboardShouldPersistTaps="always" - scrollViewStyle={ { - flex: isRootList ? 1 : 0, - } } + scrollViewStyle={ [ + { flex: isRootList ? 1 : 0 }, + ! isRootList && styles.overflowVisible, + ] } + horizontal={ horizontal } + scrollEnabled={ scrollEnabled } + contentContainerStyle={ + horizontal && styles.horizontalContentContainer + } + style={ ! isRootList && styles.overflowVisible } data={ blockClientIds } keyExtractor={ identity } extraData={ forceRefresh } @@ -179,11 +188,23 @@ export class BlockList extends Component { shouldShowInsertionPointAfter, marginVertical = styles.defaultBlock.marginTop, marginHorizontal = styles.defaultBlock.marginLeft, + horizontalDirection, + contentResizeMode, + contentStyle, + onAddBlock, + onDeleteBlock, } = this.props; + const readableContentViewStyle = contentResizeMode === 'stretch' && { + flex: 1, + }; + return ( - - + + { shouldShowInsertionPointBefore( clientId ) && ( ) } @@ -197,6 +218,10 @@ export class BlockList extends Component { onCaretVerticalPositionChange={ this.onCaretVerticalPositionChange } + horizontalDirection={ horizontalDirection } + contentStyle={ contentStyle } + onAddBlock={ onAddBlock } + onDeleteBlock={ onDeleteBlock } /> { ! this.shouldShowInnerBlockAppender() && shouldShowInsertionPointAfter( clientId ) && ( @@ -225,7 +250,7 @@ export class BlockList extends Component { } export default compose( [ - withSelect( ( select, { rootClientId } ) => { + withSelect( ( select, { rootClientId, __experimentalMoverDirection } ) => { const { getBlockCount, getBlockOrder, @@ -235,12 +260,16 @@ export default compose( [ getSettings, } = select( 'core/block-editor' ); + const horizontalDirection = + __experimentalMoverDirection === 'horizontal'; + const selectedBlockClientId = getSelectedBlockClientId(); const blockClientIds = getBlockOrder( rootClientId ); const insertionPoint = getBlockInsertionPoint(); const blockInsertionPointIsVisible = isBlockInsertionPointVisible(); const shouldShowInsertionPointBefore = ( clientId ) => { return ( + ! horizontalDirection && blockInsertionPointIsVisible && insertionPoint.rootClientId === rootClientId && // if list is empty, show the insertion point (via the default appender) @@ -251,6 +280,7 @@ export default compose( [ }; const shouldShowInsertionPointAfter = ( clientId ) => { return ( + ! horizontalDirection && blockInsertionPointIsVisible && insertionPoint.rootClientId === rootClientId && // if the insertion point is at the end of the list @@ -271,6 +301,7 @@ export default compose( [ selectedBlockClientId, isReadOnly, isRootList: rootClientId === undefined, + horizontalDirection, }; } ), withDispatch( ( dispatch ) => { diff --git a/packages/block-editor/src/components/block-list/style.native.scss b/packages/block-editor/src/components/block-list/style.native.scss index 903401f3bedf3..78994455ca0f3 100644 --- a/packages/block-editor/src/components/block-list/style.native.scss +++ b/packages/block-editor/src/components/block-list/style.native.scss @@ -4,6 +4,16 @@ background-color: #fff; } +.horizontalContentContainer { + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + align-items: stretch; + max-width: $content-width; + overflow: visible; + width: 100%; +} + .switch { flex-direction: row; justify-content: flex-start; @@ -70,3 +80,7 @@ .blockToolbar { height: $mobile-block-toolbar-height; } + +.overflowVisible { + overflow: visible; +} diff --git a/packages/block-editor/src/components/block-mobile-toolbar/index.native.js b/packages/block-editor/src/components/block-mobile-toolbar/index.native.js index 43a34c0466b54..b4a56abc4df1b 100644 --- a/packages/block-editor/src/components/block-mobile-toolbar/index.native.js +++ b/packages/block-editor/src/components/block-mobile-toolbar/index.native.js @@ -19,9 +19,17 @@ import styles from './style.scss'; import BlockMover from '../block-mover'; import { BlockSettingsButton } from '../block-settings'; -const BlockMobileToolbar = ( { clientId, onDelete, order } ) => ( +const BlockMobileToolbar = ( { + clientId, + onDelete, + order, + horizontalDirection, +} ) => ( - + @@ -48,13 +56,15 @@ export default compose( order: getBlockIndex( clientId ), }; } ), - withDispatch( ( dispatch, { clientId, rootClientId } ) => { + withDispatch( ( dispatch, { clientId, rootClientId, onDelete } ) => { const { removeBlock } = dispatch( 'core/block-editor' ); return { - onDelete: () => { - Keyboard.dismiss(); - removeBlock( clientId, rootClientId ); - }, + onDelete: + onDelete || + ( () => { + Keyboard.dismiss(); + removeBlock( clientId, rootClientId ); + } ), }; } ) )( BlockMobileToolbar ); diff --git a/packages/block-editor/src/components/block-mover/index.native.js b/packages/block-editor/src/components/block-mover/index.native.js index b572e21ee79dd..5ca80153bee05 100644 --- a/packages/block-editor/src/components/block-mover/index.native.js +++ b/packages/block-editor/src/components/block-mover/index.native.js @@ -1,6 +1,7 @@ /** * External dependencies */ +import { I18nManager } from 'react-native'; import { first, last, partial, castArray } from 'lodash'; /** @@ -10,58 +11,123 @@ import { ToolbarButton } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; import { withSelect, withDispatch } from '@wordpress/data'; import { withInstanceId, compose } from '@wordpress/compose'; -import { arrowUp, arrowDown } from '@wordpress/icons'; +import { arrowUp, arrowDown, arrowLeft, arrowRight } from '@wordpress/icons'; + +const horizontalMover = { + backwardButtonIcon: arrowLeft, + forwardButtonIcon: arrowRight, + backwardButtonHint: __( 'Double tap to move the block to the left' ), + forwardButtonHint: __( 'Double tap to move the block to the right' ), + firstBlockTitle: __( 'Move block left' ), + lastBlockTitle: __( 'Move block right' ), + /* translators: accessibility text. %1: current block position (number). %2: next block position (number) */ + backwardButtonTitle: __( + 'Move block left from position %1$s to position %2$s' + ), + /* translators: accessibility text. %1: current block position (number). %2: next block position (number) */ + forwardButtonTitle: __( + 'Move block right from position %1$s to position %2$s' + ), +}; + +const verticalMover = { + backwardButtonIcon: arrowUp, + forwardButtonIcon: arrowDown, + backwardButtonHint: __( 'Double tap to move the block up' ), + forwardButtonHint: __( 'Double tap to move the block down' ), + firstBlockTitle: __( 'Move block up' ), + lastBlockTitle: __( 'Move block down' ), + /* translators: accessibility text. %1: current block position (number). %2: next block position (number) */ + backwardButtonTitle: __( 'Move block up from row %1$s to row %2$s' ), + /* translators: accessibility text. %1: current block position (number). %2: next block position (number) */ + forwardButtonTitle: __( 'Move block down from row %1$s to row %2$s' ), +}; const BlockMover = ( { isFirst, isLast, + isRTL, isLocked, onMoveDown, onMoveUp, firstIndex, rootClientId, + horizontalDirection, } ) => { + const { + backwardButtonIcon, + forwardButtonIcon, + backwardButtonHint, + forwardButtonHint, + firstBlockTitle, + lastBlockTitle, + } = horizontalDirection ? horizontalMover : verticalMover; + if ( isLocked || ( isFirst && isLast && ! rootClientId ) ) { return null; } + const switchButtonPropIfRTL = ( + isBackwardButton, + forwardButtonProp, + backwardButtonProp + ) => { + if ( isRTL && horizontalDirection ) { + // for RTL and horizontal direction switch prop between forward and backward button + if ( isBackwardButton ) { + return forwardButtonProp; // set forwardButtonProp for backward button + } + return backwardButtonProp; // set backwardButtonProp for forward button + } + + return isBackwardButton ? backwardButtonProp : forwardButtonProp; + }; + + const getMoverButtonTitle = ( isBackwardButton ) => { + const fromIndex = firstIndex + 1; // current position based on index + // for backwardButton decrease index (move left/up) for forwardButton increase index (move right/down) + const direction = isBackwardButton ? -1 : 1; + const toIndex = fromIndex + direction; // position after move + + const { backwardButtonTitle, forwardButtonTitle } = horizontalDirection + ? horizontalMover + : verticalMover; + + const buttonTitle = switchButtonPropIfRTL( + isBackwardButton, + forwardButtonTitle, + backwardButtonTitle + ); + + return sprintf( buttonTitle, fromIndex, toIndex ); + }; + + const getArrowIcon = ( isBackwardButton ) => + switchButtonPropIfRTL( + isBackwardButton, + forwardButtonIcon, + backwardButtonIcon + ); + return ( <> @@ -90,6 +156,7 @@ export default compose( firstIndex, isFirst: firstIndex === 0, isLast: lastIndex === blockOrder.length - 1, + isRTL: I18nManager.isRTL, isLocked: getTemplateLock( rootClientId ) === 'all', rootClientId, }; diff --git a/packages/block-editor/src/components/button-block-appender/index.native.js b/packages/block-editor/src/components/button-block-appender/index.native.js index 692c013a69f72..4a3be1a5b5ac0 100644 --- a/packages/block-editor/src/components/button-block-appender/index.native.js +++ b/packages/block-editor/src/components/button-block-appender/index.native.js @@ -20,6 +20,7 @@ function ButtonBlockAppender( { rootClientId, getStylesFromColorScheme, showSeparator, + onAddBlock, } ) { const appenderStyle = { ...styles.appender, @@ -39,7 +40,7 @@ function ButtonBlockAppender( { rootClientId={ rootClientId } renderToggle={ ( { onToggle, disabled, isOpen } ) => (