diff --git a/packages/block-editor/src/components/block-list/block-mobile-floating-toolbar.native.js b/packages/block-editor/src/components/block-list/block-mobile-floating-toolbar.native.js new file mode 100644 index 00000000000000..cdd54ffdcaca1b --- /dev/null +++ b/packages/block-editor/src/components/block-list/block-mobile-floating-toolbar.native.js @@ -0,0 +1,40 @@ +/** + * External dependencies + */ +import { View, TouchableWithoutFeedback } from 'react-native'; + +/** + * Internal dependencies + */ +import styles from './block-mobile-floating-toolbar.scss'; +/** + * WordPress dependencies + */ +import { createSlotFill } from '@wordpress/components'; + +const { Fill, Slot } = createSlotFill( 'FloatingToolbar' ); + +function FloatingToolbar( { children } ) { + return ( + + { ( { innerFloatingToolbar } ) => { + return ( + + { children } + + + ); + } } + + + ); +} + +FloatingToolbar.Slot = Slot; + +export default FloatingToolbar; diff --git a/packages/block-editor/src/components/block-list/block-mobile-floating-toolbar.native.scss b/packages/block-editor/src/components/block-list/block-mobile-floating-toolbar.native.scss new file mode 100644 index 00000000000000..713633516fca23 --- /dev/null +++ b/packages/block-editor/src/components/block-list/block-mobile-floating-toolbar.native.scss @@ -0,0 +1,15 @@ +.floatingToolbarFill { + background-color: $dark-gray-500; + margin: auto; + min-width: 100; + max-height: $floating-toolbar-height; + border-radius: 22px; + flex-direction: row; + z-index: 100; + top: -$floating-toolbar-height; + height: $floating-toolbar-height; + position: absolute; + align-items: center; + justify-content: center; + align-self: center; +} 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 69503bf7151e24..eac9c7be152062 100644 --- a/packages/block-editor/src/components/block-list/block.native.js +++ b/packages/block-editor/src/components/block-list/block.native.js @@ -23,6 +23,7 @@ import styles from './block.scss'; import BlockEdit from '../block-edit'; import BlockInvalidWarning from './block-invalid-warning'; import BlockMobileToolbar from './block-mobile-toolbar'; +import FloatingToolbar from './block-mobile-floating-toolbar'; class BlockListBlock extends Component { constructor() { @@ -111,6 +112,9 @@ class BlockListBlock extends Component { isValid, showTitle, title, + showFloatingToolbar, + parentId, + isFirstBlock, } = this.props; const borderColor = isSelected ? focusedBorderColor : 'transparent'; @@ -118,25 +122,29 @@ class BlockListBlock extends Component { const accessibilityLabel = this.getAccessibilityLabel(); return ( - - - { showTitle && this.renderBlockTitle() } - - { isValid && this.getBlockForType() } - { ! isValid && + <> + { showFloatingToolbar && ( ! isFirstBlock || parentId === '' ) && } + { showFloatingToolbar && } + + + { showTitle && this.renderBlockTitle() } + + { isValid && this.getBlockForType() } + { ! isValid && - } + } + + { isSelected && } - { isSelected && } - - + + ); } } @@ -148,6 +156,10 @@ export default compose( [ getBlocks, isBlockSelected, __unstableGetBlockWithoutInnerBlocks, + getBlockHierarchyRootClientId, + getBlock, + getBlockRootClientId, + getSelectedBlock, } = select( 'core/block-editor' ); const order = getBlockIndex( clientId, rootClientId ); const isSelected = isBlockSelected( clientId ); @@ -160,6 +172,19 @@ export default compose( [ const icon = blockType.icon; const getAccessibilityLabelExtra = blockType.__experimentalGetAccessibilityLabel; + const selectedBlock = getSelectedBlock(); + const parentId = getBlockRootClientId( clientId ); + const parentBlock = getBlock( parentId ); + + const isMediaText = selectedBlock && selectedBlock.name === 'core/media-text'; + const isMediaTextParent = parentBlock && parentBlock.name === 'core/media-text'; + + const rootBlockId = getBlockHierarchyRootClientId( clientId ); + const rootBlock = getBlock( rootBlockId ); + const hasRootInnerBlocks = rootBlock.innerBlocks.length !== 0; + + const showFloatingToolbar = isSelected && hasRootInnerBlocks && ! isMediaText && ! isMediaTextParent; + return { icon, name: name || 'core/missing', @@ -172,6 +197,8 @@ export default compose( [ isSelected, isValid, getAccessibilityLabelExtra, + showFloatingToolbar, + parentId, }; } ), withDispatch( ( dispatch, ownProps, { select } ) => { 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 0eefa1274378c8..05c2898899ca39 100644 --- a/packages/block-editor/src/components/block-list/index.native.js +++ b/packages/block-editor/src/components/block-list/index.native.js @@ -20,6 +20,7 @@ import { KeyboardAwareFlatList, ReadableContentView } from '@wordpress/component import styles from './style.scss'; import BlockListBlock from './block'; import BlockListAppender from '../block-list-appender'; +import FloatingToolbar from './block-mobile-floating-toolbar'; const innerToolbarHeight = 44; @@ -69,13 +70,15 @@ export class BlockList extends Component { } render() { - const { clearSelectedBlock, blockClientIds, isFullyBordered, title, header, withFooter = true, renderAppender } = this.props; + const { clearSelectedBlock, blockClientIds, isFullyBordered, title, header, withFooter = true, renderAppender, isFirstBlock, selectedBlockParentId } = this.props; + const showFloatingToolbar = isFirstBlock && selectedBlockParentId !== ''; return ( + { showFloatingToolbar && } { + return { length: 0, offset: 0, index }; + } } /> { renderAppender && blockClientIds.length > 0 && @@ -166,6 +172,7 @@ export default compose( [ getBlockInsertionPoint, isBlockInsertionPointVisible, getSelectedBlock, + getBlockRootClientId, } = select( 'core/block-editor' ); const selectedBlockClientId = getSelectedBlockClientId(); @@ -182,7 +189,12 @@ export default compose( [ ); }; - const selectedBlockIndex = getBlockIndex( selectedBlockClientId ); + const selectedBlockIndex = getBlockIndex( selectedBlockClientId, rootClientId ); + + const isFirstBlock = selectedBlockIndex === 0; + + const selectedBlockParentId = getBlockRootClientId( selectedBlockClientId ); + const shouldShowBlockAtIndex = ( index ) => { const shouldHideBlockAtIndex = ( ! isSelectedGroup && blockInsertionPointIsVisible && @@ -201,6 +213,8 @@ export default compose( [ shouldShowBlockAtIndex, shouldShowInsertionPoint, selectedBlockClientId, + isFirstBlock, + selectedBlockParentId, }; } ), withDispatch( ( dispatch ) => { @@ -218,4 +232,3 @@ export default compose( [ } ), withPreferredColorScheme, ] )( BlockList ); - diff --git a/packages/components/src/mobile/keyboard-aware-flat-list/index.ios.js b/packages/components/src/mobile/keyboard-aware-flat-list/index.ios.js index 33c56715268971..52a3b98269e932 100644 --- a/packages/components/src/mobile/keyboard-aware-flat-list/index.ios.js +++ b/packages/components/src/mobile/keyboard-aware-flat-list/index.ios.js @@ -12,7 +12,7 @@ export const KeyboardAwareFlatList = ( { ...listProps } ) => (