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
} ) => (