diff --git a/packages/block-editor/src/components/block-list/block-list-item-cell.native.js b/packages/block-editor/src/components/block-list/block-list-item-cell.native.js index e32d793af46d6..80aa2589eb64f 100644 --- a/packages/block-editor/src/components/block-list/block-list-item-cell.native.js +++ b/packages/block-editor/src/components/block-list/block-list-item-cell.native.js @@ -7,14 +7,23 @@ import { View } from 'react-native'; * WordPress dependencies */ import { useEffect, useCallback } from '@wordpress/element'; +import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ import { useBlockListContext } from './block-list-context'; +import { store as blockEditorStore } from '../../store'; -function BlockListItemCell( { children, clientId, rootClientId, onLayout } ) { +function BlockListItemCell( { children, item: clientId, onLayout } ) { const { blocksLayouts, updateBlocksLayouts } = useBlockListContext(); + const { rootClientId } = useSelect( + ( select ) => { + const { getBlockRootClientId } = select( blockEditorStore ); + return { rootClientId: getBlockRootClientId( clientId ) }; + }, + [ clientId ] + ); useEffect( () => { return () => { 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 0a1458db02bb9..48f839b156d45 100644 --- a/packages/block-editor/src/components/block-list/index.native.js +++ b/packages/block-editor/src/components/block-list/index.native.js @@ -6,9 +6,8 @@ import { View, Platform, TouchableWithoutFeedback } from 'react-native'; /** * WordPress dependencies */ -import { Component } from '@wordpress/element'; -import { withDispatch, withSelect } from '@wordpress/data'; -import { compose, withPreferredColorScheme } from '@wordpress/compose'; +import { useRef, useState } from '@wordpress/element'; +import { useSelect, useDispatch } from '@wordpress/data'; import { createBlock } from '@wordpress/blocks'; import { KeyboardAwareFlatList, @@ -57,83 +56,117 @@ const getStyles = ( return computedStyles; }; -export class BlockList extends Component { - constructor() { - super( ...arguments ); - this.extraData = { - parentWidth: this.props.parentWidth, - renderFooterAppender: this.props.renderFooterAppender, - renderAppender: this.props.renderAppender, - onDeleteBlock: this.props.onDeleteBlock, - contentStyle: this.props.contentStyle, - }; - this.renderItem = this.renderItem.bind( this ); - this.renderBlockListFooter = this.renderBlockListFooter.bind( this ); - this.scrollViewInnerRef = this.scrollViewInnerRef.bind( this ); - this.addBlockToEndOfPost = this.addBlockToEndOfPost.bind( this ); - this.shouldFlatListPreventAutomaticScroll = - this.shouldFlatListPreventAutomaticScroll.bind( this ); - this.shouldShowInnerBlockAppender = - this.shouldShowInnerBlockAppender.bind( this ); - this.renderEmptyList = this.renderEmptyList.bind( this ); - this.getExtraData = this.getExtraData.bind( this ); - this.getCellRendererComponent = - this.getCellRendererComponent.bind( this ); - - this.onLayout = this.onLayout.bind( this ); - - this.state = { - blockWidth: this.props.blockWidth || 0, - }; - } +export default function BlockList( { + blockWidth: initialBlockWidth, + contentResizeMode, + contentStyle, + filterInnerBlocks, + gridProperties, + header, + horizontal, + horizontalAlignment, + marginHorizontal = styles.defaultBlock.marginLeft, + marginVertical = styles.defaultBlock.marginTop, + onAddBlock, + onDeleteBlock, + orientation, + parentWidth, + renderAppender, + renderFooterAppender, + rootClientId, + title, + withFooter = true, +} ) { + const { + blockClientIds, + blockCount, + blockInsertionPointIsVisible, + isReadOnly, + isRootList, + isFloatingToolbarVisible, + isStackedHorizontally, + maxWidth, + isRTL, + } = useSelect( + ( select ) => { + const { + getBlockCount, + getBlockHierarchyRootClientId, + getBlockOrder, + getSelectedBlockClientId, + isBlockInsertionPointVisible, + getSettings, + } = select( blockEditorStore ); - addBlockToEndOfPost( newBlock ) { - this.props.insertBlock( newBlock, this.props.blockCount ); - } + const selectedBlockClientId = getSelectedBlockClientId(); + const rootBlockId = getBlockHierarchyRootClientId( + selectedBlockClientId + ); - scrollViewInnerRef( ref ) { - this.scrollViewRef = ref; - } + let blockOrder = getBlockOrder( rootClientId ); + // Display only block which fulfill the condition in passed `filterInnerBlocks` function. + if ( filterInnerBlocks ) { + blockOrder = filterInnerBlocks( blockOrder ); + } - shouldFlatListPreventAutomaticScroll() { - return this.props.isBlockInsertionPointVisible; - } + const { + isRTL: isRTLSetting, + maxWidth: maxWidthSetting, + readOnly, + } = getSettings(); - shouldShowInnerBlockAppender() { - const { blockClientIds, renderAppender } = this.props; - return renderAppender && blockClientIds.length > 0; - } + return { + blockClientIds: blockOrder, + blockCount: getBlockCount(), + blockInsertionPointIsVisible: + Platform.OS === 'ios' && isBlockInsertionPointVisible(), + isReadOnly: readOnly, + isRootList: rootClientId === undefined, + isFloatingToolbarVisible: + !! selectedBlockClientId && !! getBlockCount( rootBlockId ), + isStackedHorizontally: orientation === 'horizontal', + maxWidth: maxWidthSetting, + isRTL: isRTLSetting, + }; + }, + [ filterInnerBlocks, orientation, rootClientId ] + ); - renderEmptyList() { - return ( - - ); - } + const { insertBlock, clearSelectedBlock } = useDispatch( blockEditorStore ); - getExtraData() { - const { - parentWidth, - renderFooterAppender, - onDeleteBlock, - contentStyle, - renderAppender, - gridProperties, - } = this.props; - const { blockWidth } = this.state; + const extraData = useRef( { + parentWidth, + renderFooterAppender, + renderAppender, + onDeleteBlock, + contentStyle, + } ); + + const [ blockWidth, setBlockWidth ] = useState( initialBlockWidth || 0 ); + + const addBlockToEndOfPost = ( newBlock ) => { + insertBlock( newBlock, blockCount ); + }; + + const scrollViewRef = useRef( null ); + + const shouldFlatListPreventAutomaticScroll = () => + blockInsertionPointIsVisible; + + const shouldShowInnerBlockAppender = () => + renderAppender && blockClientIds.length > 0; + + const getExtraData = () => { if ( - this.extraData.parentWidth !== parentWidth || - this.extraData.renderFooterAppender !== renderFooterAppender || - this.extraData.onDeleteBlock !== onDeleteBlock || - this.extraData.contentStyle !== contentStyle || - this.extraData.renderAppender !== renderAppender || - this.extraData.blockWidth !== blockWidth || - this.extraData.gridProperties !== gridProperties + extraData.current.parentWidth !== parentWidth || + extraData.current.renderFooterAppender !== renderFooterAppender || + extraData.current.onDeleteBlock !== onDeleteBlock || + extraData.current.contentStyle !== contentStyle || + extraData.current.renderAppender !== renderAppender || + extraData.current.blockWidth !== blockWidth || + extraData.current.gridProperties !== gridProperties ) { - this.extraData = { + extraData.current = { parentWidth, renderFooterAppender, onDeleteBlock, @@ -143,81 +176,21 @@ export class BlockList extends Component { gridProperties, }; } - return this.extraData; - } + return extraData.current; + }; - getCellRendererComponent( { children, item, onLayout } ) { - const { rootClientId } = this.props; - return ( - - ); - } - - onLayout( { nativeEvent } ) { + const onLayout = ( { nativeEvent } ) => { const { layout } = nativeEvent; - const { blockWidth } = this.state; - const { isRootList, maxWidth } = this.props; const layoutWidth = Math.floor( layout.width ); if ( isRootList && blockWidth !== layoutWidth ) { - this.setState( { - blockWidth: Math.min( layoutWidth, maxWidth ), - } ); + setBlockWidth( Math.min( layoutWidth, maxWidth ) ); } else if ( ! isRootList && ! blockWidth ) { - this.setState( { blockWidth: Math.min( layoutWidth, maxWidth ) } ); + setBlockWidth( Math.min( layoutWidth, maxWidth ) ); } - } - - render() { - const { isRootList, isRTL } = this.props; - // Use of Context to propagate the main scroll ref to its children e.g InnerBlocks. - const blockList = isRootList ? ( - - - { ( { onScroll } ) => this.renderList( { onScroll } ) } - - - ) : ( - - { ( { scrollRef } ) => - this.renderList( { - parentScrollRef: scrollRef, - } ) - } - - ); - - return blockList; - } + }; - renderList( extraProps = {} ) { - const { - clearSelectedBlock, - blockClientIds, - rootClientId, - title, - header, - isReadOnly, - isRootList, - horizontal, - marginVertical = styles.defaultBlock.marginTop, - marginHorizontal = styles.defaultBlock.marginLeft, - isFloatingToolbarVisible, - isStackedHorizontally, - horizontalAlignment, - contentResizeMode, - blockWidth, - } = this.props; + const renderList = ( extraProps = {} ) => { const { parentScrollRef, onScroll } = extraProps; const { blockToolbar, headerToolbar, floatingToolbar } = styles; @@ -246,7 +219,7 @@ export class BlockList extends Component { { - this.scrollViewInnerRef( parentScrollRef || ref ); + scrollViewRef.current = parentScrollRef || ref; } } extraScrollHeight={ extraScrollHeight } keyboardShouldPersistTaps="always" scrollViewStyle={ scrollViewStyle } - extraData={ this.getExtraData() } + extraData={ getExtraData() } scrollEnabled={ isRootList } contentContainerStyle={ [ horizontal && styles.horizontalContentContainer, @@ -279,18 +252,34 @@ export class BlockList extends Component { listKey={ rootClientId ? `list-${ rootClientId }` : 'list-root' } - renderItem={ this.renderItem } - CellRendererComponent={ this.getCellRendererComponent } + renderItem={ renderItem } + CellRendererComponent={ BlockListItemCell } shouldPreventAutomaticScroll={ - this.shouldFlatListPreventAutomaticScroll + shouldFlatListPreventAutomaticScroll } title={ title } ListHeaderComponent={ header } - ListEmptyComponent={ ! isReadOnly && this.renderEmptyList } - ListFooterComponent={ this.renderBlockListFooter } + ListEmptyComponent={ + ! isReadOnly && ( + + ) + } + ListFooterComponent={ +