From 7315fb77e4facc04223f167040823df9cbb4a87f Mon Sep 17 00:00:00 2001 From: Gerardo Date: Tue, 22 Feb 2022 13:15:18 +0100 Subject: [PATCH 01/12] Mobile - Block list - Extract block list context into a separate file and add support to store the blocks layouts data and coordinates. --- .../block-list/block-list-context.native.js | 47 +++++++++++++++++++ .../src/components/block-list/index.native.js | 26 ++++++---- 2 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 packages/block-editor/src/components/block-list/block-list-context.native.js diff --git a/packages/block-editor/src/components/block-list/block-list-context.native.js b/packages/block-editor/src/components/block-list/block-list-context.native.js new file mode 100644 index 0000000000000..ad25c1ee659cc --- /dev/null +++ b/packages/block-editor/src/components/block-list/block-list-context.native.js @@ -0,0 +1,47 @@ +/** + * WordPress dependencies + */ +import { createContext, useContext } from '@wordpress/element'; + +const BLOCKS_LAYOUTS = {}; + +const Context = createContext( { + scrollRef: null, + blocksLayouts: {}, + updateBlocksLayouts: () => {}, +} ); +const { Provider, Consumer } = Context; + +function updateBlocksLayouts( blockData ) { + const { clientId, shouldRemove } = blockData; + + if ( clientId && shouldRemove ) { + delete BLOCKS_LAYOUTS[ clientId ]; + return; + } + + if ( clientId ) { + const { rootClientId, width, height, x, y } = blockData; + + BLOCKS_LAYOUTS[ clientId ] = { + clientId, + rootClientId, + width, + height, + x, + y, + }; + } +} + +export { + Provider as BlockListProvider, + Consumer as BlockListConsumer, + updateBlocksLayouts, + BLOCKS_LAYOUTS as blocksLayouts, +}; + +export const useBlockListContext = () => { + const blockListContext = useContext( Context ); + return blockListContext; +}; 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 bdea027b116f1..af6cca928534d 100644 --- a/packages/block-editor/src/components/block-list/index.native.js +++ b/packages/block-editor/src/components/block-list/index.native.js @@ -25,10 +25,14 @@ import { __ } from '@wordpress/i18n'; import styles from './style.scss'; import BlockListAppender from '../block-list-appender'; import BlockListItem from './block-list-item'; +import { + BlockListProvider, + BlockListConsumer, + updateBlocksLayouts, + blocksLayouts, +} from './block-list-context'; import { store as blockEditorStore } from '../../store'; -const BlockListContext = createContext(); - export const OnCaretVerticalPositionChange = createContext(); const stylesMemo = {}; @@ -173,17 +177,23 @@ export class BlockList extends Component { const { isRootList } = this.props; // Use of Context to propagate the main scroll ref to its children e.g InnerBlocks const blockList = isRootList ? ( - + { this.renderList() } - + ) : ( - - { ( ref ) => + + { ( { scrollRef } ) => this.renderList( { - parentScrollRef: ref, + parentScrollRef: scrollRef, } ) } - + ); return ( From 0880031be09128adb447ec2a83c1ffb7869ed3e1 Mon Sep 17 00:00:00 2001 From: Gerardo Date: Tue, 22 Feb 2022 16:26:14 +0100 Subject: [PATCH 02/12] Mobile - Block list - Adds block list item cell to get the onLayout data and use updateBlocksLayouts to store it. It is needed to use CellRendererComponent to be able to get the right position coordinates --- .../block-list/block-list-item-cell.native.js | 36 +++++++++++++++++++ .../src/components/block-list/index.native.js | 16 +++++++++ 2 files changed, 52 insertions(+) create mode 100644 packages/block-editor/src/components/block-list/block-list-item-cell.native.js 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 new file mode 100644 index 0000000000000..01238319830b5 --- /dev/null +++ b/packages/block-editor/src/components/block-list/block-list-item-cell.native.js @@ -0,0 +1,36 @@ +/** + * External dependencies + */ +import { View } from 'react-native'; + +/** + * WordPress dependencies + */ +import { useEffect, useCallback } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { useBlockListContext } from './block-list-context'; + +function BlockListItemCell( props ) { + const { clientId, rootClientId } = props; + const { updateBlocksLayouts } = useBlockListContext(); + + useEffect( () => { + return () => { + updateBlocksLayouts( { clientId, shouldRemove: true } ); + }; + }, [] ); + + const onLayout = useCallback( + ( { nativeEvent: { layout } } ) => { + updateBlocksLayouts( { clientId, rootClientId, ...layout } ); + }, + [ clientId, rootClientId, updateBlocksLayouts ] + ); + + return { props.children }; +} + +export default BlockListItemCell; 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 af6cca928534d..e1ae17922deba 100644 --- a/packages/block-editor/src/components/block-list/index.native.js +++ b/packages/block-editor/src/components/block-list/index.native.js @@ -25,6 +25,7 @@ import { __ } from '@wordpress/i18n'; import styles from './style.scss'; import BlockListAppender from '../block-list-appender'; import BlockListItem from './block-list-item'; +import BlockListItemCell from './block-list-item-cell'; import { BlockListProvider, BlockListConsumer, @@ -82,6 +83,9 @@ export class BlockList extends Component { ); this.renderEmptyList = this.renderEmptyList.bind( this ); this.getExtraData = this.getExtraData.bind( this ); + this.getCellRendererComponent = this.getCellRendererComponent.bind( + this + ); this.onLayout = this.onLayout.bind( this ); @@ -158,6 +162,17 @@ export class BlockList extends Component { return this.extraData; } + getCellRendererComponent( { children, item } ) { + const { rootClientId } = this.props; + return ( + + ); + } + onLayout( { nativeEvent } ) { const { layout } = nativeEvent; const { blockWidth } = this.state; @@ -289,6 +304,7 @@ export class BlockList extends Component { data={ blockClientIds } keyExtractor={ identity } renderItem={ this.renderItem } + CellRendererComponent={ this.getCellRendererComponent } shouldPreventAutomaticScroll={ this.shouldFlatListPreventAutomaticScroll } From 50689480f3dbba32dc450176251cdaf5ae63d4ff Mon Sep 17 00:00:00 2001 From: Gerardo Date: Thu, 24 Feb 2022 17:20:50 +0100 Subject: [PATCH 03/12] Mobile - Block list - Store block layouts data for inner blocks in a deep level --- .../block-list/block-list-context.native.js | 74 ++++++++++++++++--- .../src/components/block-list/index.native.js | 2 +- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block-list-context.native.js b/packages/block-editor/src/components/block-list/block-list-context.native.js index ad25c1ee659cc..dc160a814c188 100644 --- a/packages/block-editor/src/components/block-list/block-list-context.native.js +++ b/packages/block-editor/src/components/block-list/block-list-context.native.js @@ -3,7 +3,7 @@ */ import { createContext, useContext } from '@wordpress/element'; -const BLOCKS_LAYOUTS = {}; +const blocksLayouts = { current: {} }; const Context = createContext( { scrollRef: null, @@ -12,25 +12,75 @@ const Context = createContext( { } ); const { Provider, Consumer } = Context; +function findByRootId( data, rootClientId ) { + return Object.entries( data ).reduce( ( acc, entry ) => { + const item = entry[ 1 ]; + if ( acc ) { + return acc; + } + if ( item?.clientId === rootClientId ) { + return item; + } + if ( item?.innerBlocks && Object.keys( item.innerBlocks ).length > 0 ) { + return findByRootId( item.innerBlocks, rootClientId ); + } + return null; + }, null ); +} + +function deleteByClientId( data, clientId ) { + return Object.keys( data ).reduce( ( acc, key ) => { + if ( key !== clientId ) { + acc[ key ] = data[ key ]; + } + if ( + data[ key ]?.innerBlocks && + Object.keys( data[ key ].innerBlocks ).length > 0 + ) { + if ( acc[ key ] ) { + acc[ key ].innerBlocks = deleteByClientId( + data[ key ].innerBlocks, + clientId + ); + } + } + return acc; + }, {} ); +} + function updateBlocksLayouts( blockData ) { - const { clientId, shouldRemove } = blockData; + const { clientId, rootClientId, shouldRemove, ...layoutProps } = blockData; if ( clientId && shouldRemove ) { - delete BLOCKS_LAYOUTS[ clientId ]; + blocksLayouts.current = deleteByClientId( + blocksLayouts.current, + clientId + ); return; } - if ( clientId ) { - const { rootClientId, width, height, x, y } = blockData; - - BLOCKS_LAYOUTS[ clientId ] = { + if ( clientId && ! rootClientId ) { + blocksLayouts.current[ clientId ] = { clientId, rootClientId, - width, - height, - x, - y, + ...layoutProps, + innerBlocks: { + ...blocksLayouts.current[ clientId ]?.innerBlocks, + }, }; + } else if ( clientId && rootClientId ) { + const block = findByRootId( blocksLayouts.current, rootClientId ); + + if ( block ) { + block.innerBlocks[ clientId ] = { + clientId, + rootClientId, + ...layoutProps, + innerBlocks: { + ...block.innerBlocks[ clientId ]?.innerBlocks, + }, + }; + } } } @@ -38,7 +88,7 @@ export { Provider as BlockListProvider, Consumer as BlockListConsumer, updateBlocksLayouts, - BLOCKS_LAYOUTS as blocksLayouts, + blocksLayouts, }; export const useBlockListContext = () => { 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 e1ae17922deba..20cd899b04895 100644 --- a/packages/block-editor/src/components/block-list/index.native.js +++ b/packages/block-editor/src/components/block-list/index.native.js @@ -196,7 +196,7 @@ export class BlockList extends Component { value={ { scrollRef: this.scrollViewRef, updateBlocksLayouts, - blocksLayouts, + blocksLayouts: blocksLayouts.current, } } > { this.renderList() } From a09bceec5589b52627d640acc8f56488e3f30890 Mon Sep 17 00:00:00 2001 From: Gerardo Date: Wed, 2 Mar 2022 16:46:06 +0100 Subject: [PATCH 04/12] Mobile - BlockList ItemCell - Destructuring props --- .../src/components/block-list/block-list-item-cell.native.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 01238319830b5..d175c12e2120b 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 @@ -13,8 +13,7 @@ import { useEffect, useCallback } from '@wordpress/element'; */ import { useBlockListContext } from './block-list-context'; -function BlockListItemCell( props ) { - const { clientId, rootClientId } = props; +function BlockListItemCell( { children, clientId, rootClientId } ) { const { updateBlocksLayouts } = useBlockListContext(); useEffect( () => { @@ -30,7 +29,7 @@ function BlockListItemCell( props ) { [ clientId, rootClientId, updateBlocksLayouts ] ); - return { props.children }; + return { children }; } export default BlockListItemCell; From 6bfc5cb2ae673ec059dfec01c9dc9fcf0b128154 Mon Sep 17 00:00:00 2001 From: Gerardo Date: Thu, 3 Mar 2022 11:46:03 +0100 Subject: [PATCH 05/12] Mobile - BlockListContext - Rename findByRootId to findBlockLayoutByClientId --- .../block-list/block-list-context.native.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block-list-context.native.js b/packages/block-editor/src/components/block-list/block-list-context.native.js index dc160a814c188..f043ccc3b21ce 100644 --- a/packages/block-editor/src/components/block-list/block-list-context.native.js +++ b/packages/block-editor/src/components/block-list/block-list-context.native.js @@ -12,17 +12,17 @@ const Context = createContext( { } ); const { Provider, Consumer } = Context; -function findByRootId( data, rootClientId ) { +function findBlockLayoutByClientId( data, clientId ) { return Object.entries( data ).reduce( ( acc, entry ) => { const item = entry[ 1 ]; if ( acc ) { return acc; } - if ( item?.clientId === rootClientId ) { + if ( item?.clientId === clientId ) { return item; } if ( item?.innerBlocks && Object.keys( item.innerBlocks ).length > 0 ) { - return findByRootId( item.innerBlocks, rootClientId ); + return findBlockLayoutByClientId( item.innerBlocks, clientId ); } return null; }, null ); @@ -69,7 +69,10 @@ function updateBlocksLayouts( blockData ) { }, }; } else if ( clientId && rootClientId ) { - const block = findByRootId( blocksLayouts.current, rootClientId ); + const block = findBlockLayoutByClientId( + blocksLayouts.current, + rootClientId + ); if ( block ) { block.innerBlocks[ clientId ] = { From b1b3107a8356fd8b716ef1d2a54ccc1c12e1f85e Mon Sep 17 00:00:00 2001 From: Gerardo Date: Thu, 3 Mar 2022 12:02:59 +0100 Subject: [PATCH 06/12] Mobile - BlockListContext - Rename deleteByClientId to deleteBlockLayoutByClientId --- .../src/components/block-list/block-list-context.native.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block-list-context.native.js b/packages/block-editor/src/components/block-list/block-list-context.native.js index f043ccc3b21ce..553c39ffc1711 100644 --- a/packages/block-editor/src/components/block-list/block-list-context.native.js +++ b/packages/block-editor/src/components/block-list/block-list-context.native.js @@ -28,7 +28,7 @@ function findBlockLayoutByClientId( data, clientId ) { }, null ); } -function deleteByClientId( data, clientId ) { +function deleteBlockLayoutByClientId( data, clientId ) { return Object.keys( data ).reduce( ( acc, key ) => { if ( key !== clientId ) { acc[ key ] = data[ key ]; @@ -38,7 +38,7 @@ function deleteByClientId( data, clientId ) { Object.keys( data[ key ].innerBlocks ).length > 0 ) { if ( acc[ key ] ) { - acc[ key ].innerBlocks = deleteByClientId( + acc[ key ].innerBlocks = deleteBlockLayoutByClientId( data[ key ].innerBlocks, clientId ); @@ -52,7 +52,7 @@ function updateBlocksLayouts( blockData ) { const { clientId, rootClientId, shouldRemove, ...layoutProps } = blockData; if ( clientId && shouldRemove ) { - blocksLayouts.current = deleteByClientId( + blocksLayouts.current = deleteBlockLayoutByClientId( blocksLayouts.current, clientId ); From 7ce1aae7ae8f03fe0d7e4b53189601a35e8f28ef Mon Sep 17 00:00:00 2001 From: Gerardo Date: Thu, 3 Mar 2022 14:40:29 +0100 Subject: [PATCH 07/12] Mobile - BlockListContext - Store default context and use it for initialization --- .../block-list/block-list-context.native.js | 24 +++++++------------ .../block-list/block-list-item-cell.native.js | 13 +++++++--- .../src/components/block-list/index.native.js | 6 ++--- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block-list-context.native.js b/packages/block-editor/src/components/block-list/block-list-context.native.js index 553c39ffc1711..61c71f4546dc1 100644 --- a/packages/block-editor/src/components/block-list/block-list-context.native.js +++ b/packages/block-editor/src/components/block-list/block-list-context.native.js @@ -3,13 +3,13 @@ */ import { createContext, useContext } from '@wordpress/element'; -const blocksLayouts = { current: {} }; - -const Context = createContext( { +export const DEFAULT_BLOCK_LIST_CONTEXT = { scrollRef: null, - blocksLayouts: {}, - updateBlocksLayouts: () => {}, -} ); + blocksLayouts: { current: {} }, + updateBlocksLayouts, +}; + +const Context = createContext( DEFAULT_BLOCK_LIST_CONTEXT ); const { Provider, Consumer } = Context; function findBlockLayoutByClientId( data, clientId ) { @@ -48,7 +48,7 @@ function deleteBlockLayoutByClientId( data, clientId ) { }, {} ); } -function updateBlocksLayouts( blockData ) { +function updateBlocksLayouts( blocksLayouts, blockData ) { const { clientId, rootClientId, shouldRemove, ...layoutProps } = blockData; if ( clientId && shouldRemove ) { @@ -87,14 +87,8 @@ function updateBlocksLayouts( blockData ) { } } -export { - Provider as BlockListProvider, - Consumer as BlockListConsumer, - updateBlocksLayouts, - blocksLayouts, -}; +export { Provider as BlockListProvider, Consumer as BlockListConsumer }; export const useBlockListContext = () => { - const blockListContext = useContext( Context ); - return blockListContext; + return useContext( Context ); }; 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 d175c12e2120b..c399643a63399 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 @@ -14,17 +14,24 @@ import { useEffect, useCallback } from '@wordpress/element'; import { useBlockListContext } from './block-list-context'; function BlockListItemCell( { children, clientId, rootClientId } ) { - const { updateBlocksLayouts } = useBlockListContext(); + const { blocksLayouts, updateBlocksLayouts } = useBlockListContext(); useEffect( () => { return () => { - updateBlocksLayouts( { clientId, shouldRemove: true } ); + updateBlocksLayouts( blocksLayouts, { + clientId, + shouldRemove: true, + } ); }; }, [] ); const onLayout = useCallback( ( { nativeEvent: { layout } } ) => { - updateBlocksLayouts( { clientId, rootClientId, ...layout } ); + updateBlocksLayouts( blocksLayouts, { + clientId, + rootClientId, + ...layout, + } ); }, [ clientId, rootClientId, updateBlocksLayouts ] ); 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 20cd899b04895..a2d1cdac6e570 100644 --- a/packages/block-editor/src/components/block-list/index.native.js +++ b/packages/block-editor/src/components/block-list/index.native.js @@ -29,8 +29,7 @@ import BlockListItemCell from './block-list-item-cell'; import { BlockListProvider, BlockListConsumer, - updateBlocksLayouts, - blocksLayouts, + DEFAULT_BLOCK_LIST_CONTEXT, } from './block-list-context'; import { store as blockEditorStore } from '../../store'; @@ -194,9 +193,8 @@ export class BlockList extends Component { const blockList = isRootList ? ( { this.renderList() } From daf5b141bd5df3a7422876be708769fd801494a6 Mon Sep 17 00:00:00 2001 From: Gerardo Date: Thu, 3 Mar 2022 15:08:42 +0100 Subject: [PATCH 08/12] Mobile - BlockListContext - Add param's docs --- .../block-list/block-list-context.native.js | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/block-editor/src/components/block-list/block-list-context.native.js b/packages/block-editor/src/components/block-list/block-list-context.native.js index 61c71f4546dc1..4eb533b16f97b 100644 --- a/packages/block-editor/src/components/block-list/block-list-context.native.js +++ b/packages/block-editor/src/components/block-list/block-list-context.native.js @@ -12,6 +12,14 @@ export const DEFAULT_BLOCK_LIST_CONTEXT = { const Context = createContext( DEFAULT_BLOCK_LIST_CONTEXT ); const { Provider, Consumer } = Context; +/** + * Finds a block's layout data within the provided data object. + * + * @param {Object} data Blocks layouts list. + * @param {string} clientId Block's clientId. + * + * @return {Object} Found block layout data. + */ function findBlockLayoutByClientId( data, clientId ) { return Object.entries( data ).reduce( ( acc, entry ) => { const item = entry[ 1 ]; @@ -28,6 +36,14 @@ function findBlockLayoutByClientId( data, clientId ) { }, null ); } +/** + * Deletes a block's layout data from the provided data object. + * + * @param {Object} data Blocks layouts list. + * @param {string} clientId Block's clientsId. + * + * @return {Object} Updated data object. + */ function deleteBlockLayoutByClientId( data, clientId ) { return Object.keys( data ).reduce( ( acc, key ) => { if ( key !== clientId ) { @@ -48,6 +64,20 @@ function deleteBlockLayoutByClientId( data, clientId ) { }, {} ); } +/** + * Updates the blocksLayouts object with the block's layout data. + * + * @param {Object} blocksLayouts Blocks layouts list. + * @param {Object} blockData Block's layout data. + * @param {string} blockData.clientId Block's clientId. + * @param {?string} blockData.rootClientId Optional. Block's rootClientId. + * @param {?boolean} blockData.shouldRemove Optional. Flag to remove it from the blocksLayout list. + * @param {number} blockData.width Block's width. + * @param {number} blockData.heigth Block's heigth. + * @param {number} blockData.x Block's x coordinate (relative to the parent). + * @param {number} blockData.y Block's y coordinate (relative to the parent). + */ + function updateBlocksLayouts( blocksLayouts, blockData ) { const { clientId, rootClientId, shouldRemove, ...layoutProps } = blockData; @@ -89,6 +119,11 @@ function updateBlocksLayouts( blocksLayouts, blockData ) { export { Provider as BlockListProvider, Consumer as BlockListConsumer }; +/** + * Hook that returns the block list context. + * + * @return {Object} Block list context + */ export const useBlockListContext = () => { return useContext( Context ); }; From 23f2c39ffb61d4d20ecda44402807e4b7a63c6d8 Mon Sep 17 00:00:00 2001 From: Gerardo Date: Tue, 15 Mar 2022 15:46:11 +0100 Subject: [PATCH 09/12] Mobile - Block list context - Export findBlockLayoutByClientId --- .../src/components/block-list/block-list-context.native.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-editor/src/components/block-list/block-list-context.native.js b/packages/block-editor/src/components/block-list/block-list-context.native.js index 4eb533b16f97b..127cac1cde784 100644 --- a/packages/block-editor/src/components/block-list/block-list-context.native.js +++ b/packages/block-editor/src/components/block-list/block-list-context.native.js @@ -6,6 +6,7 @@ import { createContext, useContext } from '@wordpress/element'; export const DEFAULT_BLOCK_LIST_CONTEXT = { scrollRef: null, blocksLayouts: { current: {} }, + findBlockLayoutByClientId, updateBlocksLayouts, }; From b1ee8f60d54f96f3c5e723b1de903928357122da Mon Sep 17 00:00:00 2001 From: Gerardo Date: Tue, 15 Mar 2022 16:00:27 +0100 Subject: [PATCH 10/12] Mobile - Block list context - Update comments --- .../block-list/block-list-context.native.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block-list-context.native.js b/packages/block-editor/src/components/block-list/block-list-context.native.js index 127cac1cde784..cedd3683d043a 100644 --- a/packages/block-editor/src/components/block-list/block-list-context.native.js +++ b/packages/block-editor/src/components/block-list/block-list-context.native.js @@ -14,9 +14,9 @@ const Context = createContext( DEFAULT_BLOCK_LIST_CONTEXT ); const { Provider, Consumer } = Context; /** - * Finds a block's layout data within the provided data object. + * Finds a block's layout data by its client Id. * - * @param {Object} data Blocks layouts list. + * @param {Object} data Blocks layouts object. * @param {string} clientId Block's clientId. * * @return {Object} Found block layout data. @@ -38,9 +38,9 @@ function findBlockLayoutByClientId( data, clientId ) { } /** - * Deletes a block's layout data from the provided data object. + * Deletes the layout data of a block by its client Id. * - * @param {Object} data Blocks layouts list. + * @param {Object} data Blocks layouts object. * @param {string} clientId Block's clientsId. * * @return {Object} Updated data object. @@ -66,15 +66,16 @@ function deleteBlockLayoutByClientId( data, clientId ) { } /** - * Updates the blocksLayouts object with the block's layout data. + * Updates or deletes a block's layout data in the blocksLayouts object, + * in case of deletion, the layout data is not required. * - * @param {Object} blocksLayouts Blocks layouts list. - * @param {Object} blockData Block's layout data. + * @param {Object} blocksLayouts Blocks layouts object. + * @param {Object} blockData Block's layout data to add or remove to/from the blockLayouts object. * @param {string} blockData.clientId Block's clientId. * @param {?string} blockData.rootClientId Optional. Block's rootClientId. * @param {?boolean} blockData.shouldRemove Optional. Flag to remove it from the blocksLayout list. * @param {number} blockData.width Block's width. - * @param {number} blockData.heigth Block's heigth. + * @param {number} blockData.height Block's height. * @param {number} blockData.x Block's x coordinate (relative to the parent). * @param {number} blockData.y Block's y coordinate (relative to the parent). */ From b5906a260702d33043ed2c5588668897dfa0c3d3 Mon Sep 17 00:00:00 2001 From: Gerardo Date: Wed, 16 Mar 2022 14:43:19 +0100 Subject: [PATCH 11/12] Mobile - Block list context - Unit tests --- .../block-list/block-list-context.native.js | 2 +- .../test/block-list-context.native.js | 266 ++++++++++++++++++ .../fixtures/block-list-context.native.js | 79 ++++++ 3 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 packages/block-editor/src/components/block-list/test/block-list-context.native.js create mode 100644 packages/block-editor/src/components/block-list/test/fixtures/block-list-context.native.js diff --git a/packages/block-editor/src/components/block-list/block-list-context.native.js b/packages/block-editor/src/components/block-list/block-list-context.native.js index cedd3683d043a..95385b480b3d1 100644 --- a/packages/block-editor/src/components/block-list/block-list-context.native.js +++ b/packages/block-editor/src/components/block-list/block-list-context.native.js @@ -45,7 +45,7 @@ function findBlockLayoutByClientId( data, clientId ) { * * @return {Object} Updated data object. */ -function deleteBlockLayoutByClientId( data, clientId ) { +export function deleteBlockLayoutByClientId( data, clientId ) { return Object.keys( data ).reduce( ( acc, key ) => { if ( key !== clientId ) { acc[ key ] = data[ key ]; diff --git a/packages/block-editor/src/components/block-list/test/block-list-context.native.js b/packages/block-editor/src/components/block-list/test/block-list-context.native.js new file mode 100644 index 0000000000000..07a45577bb99d --- /dev/null +++ b/packages/block-editor/src/components/block-list/test/block-list-context.native.js @@ -0,0 +1,266 @@ +/** + * External dependencies + */ +import { cloneDeep } from 'lodash'; + +/** + * Internal dependencies + */ +import { + DEFAULT_BLOCK_LIST_CONTEXT, + deleteBlockLayoutByClientId, +} from '../block-list-context.native'; +import { + BLOCKS_LAYOUTS_DATA, + DEEP_NESTED_ID, + GROUP_BLOCK_LAYOUT_DATA, + NESTED_WITH_INNER_BLOCKS_ID, + PARAGRAPH_BLOCK_LAYOUT_DATA, + ROOT_LEVEL_ID, +} from './fixtures/block-list-context.native'; + +describe( 'findBlockLayoutByClientId', () => { + it( "finds a block's layout data at root level", () => { + const { findBlockLayoutByClientId } = DEFAULT_BLOCK_LIST_CONTEXT; + const currentBlockLayouts = BLOCKS_LAYOUTS_DATA; + + const blockRootLevel = findBlockLayoutByClientId( + currentBlockLayouts, + ROOT_LEVEL_ID + ); + + expect( blockRootLevel ).toEqual( + expect.objectContaining( { clientId: ROOT_LEVEL_ID } ) + ); + } ); + + it( "finds a nested block's layout data with inner blocks", () => { + const { findBlockLayoutByClientId } = DEFAULT_BLOCK_LIST_CONTEXT; + const currentBlockLayouts = BLOCKS_LAYOUTS_DATA; + + const nestedBlock = findBlockLayoutByClientId( + currentBlockLayouts, + NESTED_WITH_INNER_BLOCKS_ID + ); + + expect( nestedBlock ).toEqual( + expect.objectContaining( { clientId: NESTED_WITH_INNER_BLOCKS_ID } ) + ); + } ); + + it( "finds a deep nested block's layout data", () => { + const { findBlockLayoutByClientId } = DEFAULT_BLOCK_LIST_CONTEXT; + const currentBlockLayouts = BLOCKS_LAYOUTS_DATA; + + const deepNestedBlock = findBlockLayoutByClientId( + currentBlockLayouts, + DEEP_NESTED_ID + ); + + expect( deepNestedBlock ).toEqual( + expect.objectContaining( { clientId: DEEP_NESTED_ID } ) + ); + } ); +} ); + +describe( 'deleteBlockLayoutByClientId', () => { + it( "deletes a block's layout data at root level", () => { + const { findBlockLayoutByClientId } = DEFAULT_BLOCK_LIST_CONTEXT; + const defaultBlockLayouts = cloneDeep( BLOCKS_LAYOUTS_DATA ); + const currentBlockLayouts = deleteBlockLayoutByClientId( + defaultBlockLayouts, + ROOT_LEVEL_ID + ); + + const findDeletedBlock = findBlockLayoutByClientId( + currentBlockLayouts, + ROOT_LEVEL_ID + ); + + expect( findDeletedBlock ).toEqual( + expect.not.objectContaining( { clientId: ROOT_LEVEL_ID } ) + ); + } ); + + it( "deletes a nested block's layout data with inner blocks", () => { + const { findBlockLayoutByClientId } = DEFAULT_BLOCK_LIST_CONTEXT; + const defaultBlockLayouts = cloneDeep( BLOCKS_LAYOUTS_DATA ); + const currentBlockLayouts = deleteBlockLayoutByClientId( + defaultBlockLayouts, + NESTED_WITH_INNER_BLOCKS_ID + ); + + const findDeletedBlock = findBlockLayoutByClientId( + currentBlockLayouts, + NESTED_WITH_INNER_BLOCKS_ID + ); + + expect( findDeletedBlock ).toEqual( + expect.not.objectContaining( { + clientId: NESTED_WITH_INNER_BLOCKS_ID, + } ) + ); + } ); + + it( "deletes a deep nested block's layout data", () => { + const { findBlockLayoutByClientId } = DEFAULT_BLOCK_LIST_CONTEXT; + const defaultBlockLayouts = cloneDeep( BLOCKS_LAYOUTS_DATA ); + const currentBlockLayouts = deleteBlockLayoutByClientId( + defaultBlockLayouts, + DEEP_NESTED_ID + ); + + const findDeletedBlock = findBlockLayoutByClientId( + currentBlockLayouts, + DEEP_NESTED_ID + ); + + expect( findDeletedBlock ).toEqual( + expect.not.objectContaining( { + clientId: DEEP_NESTED_ID, + } ) + ); + } ); +} ); + +describe( 'updateBlocksLayouts', () => { + it( "adds a new block's layout data at root level im an empty object", () => { + const { + blocksLayouts, + findBlockLayoutByClientId, + updateBlocksLayouts, + } = DEFAULT_BLOCK_LIST_CONTEXT; + const currentBlockLayouts = cloneDeep( blocksLayouts ); + const BLOCK_CLIENT_ID = PARAGRAPH_BLOCK_LAYOUT_DATA.clientId; + + updateBlocksLayouts( currentBlockLayouts, PARAGRAPH_BLOCK_LAYOUT_DATA ); + + const findAddedBlock = findBlockLayoutByClientId( + currentBlockLayouts.current, + BLOCK_CLIENT_ID + ); + + expect( findAddedBlock ).toEqual( + expect.objectContaining( { clientId: BLOCK_CLIENT_ID } ) + ); + } ); + + it( "adds a new block's layout data at root level with inner blocks", () => { + const { + findBlockLayoutByClientId, + updateBlocksLayouts, + } = DEFAULT_BLOCK_LIST_CONTEXT; + const currentBlockLayouts = { + current: cloneDeep( BLOCKS_LAYOUTS_DATA ), + }; + const PARENT_BLOCK_CLIENT_ID = GROUP_BLOCK_LAYOUT_DATA.clientId; + + // Add parent block + updateBlocksLayouts( currentBlockLayouts, GROUP_BLOCK_LAYOUT_DATA ); + + const findAddedParentBlock = findBlockLayoutByClientId( + currentBlockLayouts.current, + PARENT_BLOCK_CLIENT_ID + ); + + expect( findAddedParentBlock ).toEqual( + expect.objectContaining( { clientId: PARENT_BLOCK_CLIENT_ID } ) + ); + + // Add inner block to it's parent + updateBlocksLayouts( currentBlockLayouts, { + ...PARAGRAPH_BLOCK_LAYOUT_DATA, + rootClientId: PARENT_BLOCK_CLIENT_ID, + } ); + + const findAddedInnerBlock = findBlockLayoutByClientId( + currentBlockLayouts.current, + PARAGRAPH_BLOCK_LAYOUT_DATA.clientId + ); + + expect( findAddedInnerBlock ).toEqual( + expect.objectContaining( { + clientId: PARAGRAPH_BLOCK_LAYOUT_DATA.clientId, + } ) + ); + } ); + + it( "adds a new block's layout data at a deep level", () => { + const { + findBlockLayoutByClientId, + updateBlocksLayouts, + } = DEFAULT_BLOCK_LIST_CONTEXT; + const currentBlockLayouts = { + current: cloneDeep( BLOCKS_LAYOUTS_DATA ), + }; + + // Add block layout data to it's parents inner blocks + updateBlocksLayouts( currentBlockLayouts, { + ...PARAGRAPH_BLOCK_LAYOUT_DATA, + rootClientId: NESTED_WITH_INNER_BLOCKS_ID, + } ); + + const findAddedInnerBlock = findBlockLayoutByClientId( + currentBlockLayouts.current, + PARAGRAPH_BLOCK_LAYOUT_DATA.clientId + ); + + expect( findAddedInnerBlock ).toEqual( + expect.objectContaining( { + clientId: PARAGRAPH_BLOCK_LAYOUT_DATA.clientId, + } ) + ); + } ); + + it( "deletes a block's layout data at a root level", () => { + const { + findBlockLayoutByClientId, + updateBlocksLayouts, + } = DEFAULT_BLOCK_LIST_CONTEXT; + const currentBlockLayouts = { + current: cloneDeep( BLOCKS_LAYOUTS_DATA ), + }; + + updateBlocksLayouts( currentBlockLayouts, { + shouldRemove: true, + clientId: ROOT_LEVEL_ID, + } ); + + const findDeletedBlock = findBlockLayoutByClientId( + currentBlockLayouts.current, + ROOT_LEVEL_ID + ); + + expect( findDeletedBlock ).toEqual( + expect.not.objectContaining( { + clientId: ROOT_LEVEL_ID, + } ) + ); + } ); + + it( "deletes a block's layout data at a deep level", () => { + const { + findBlockLayoutByClientId, + updateBlocksLayouts, + } = DEFAULT_BLOCK_LIST_CONTEXT; + const currentBlockLayouts = { + current: cloneDeep( BLOCKS_LAYOUTS_DATA ), + }; + + updateBlocksLayouts( currentBlockLayouts, { + shouldRemove: true, + clientId: DEEP_NESTED_ID, + } ); + + const findDeletedBlock = findBlockLayoutByClientId( + currentBlockLayouts.current, + DEEP_NESTED_ID + ); + + expect( findDeletedBlock ).toEqual( + expect.not.objectContaining( { + clientId: DEEP_NESTED_ID, + } ) + ); + } ); +} ); diff --git a/packages/block-editor/src/components/block-list/test/fixtures/block-list-context.native.js b/packages/block-editor/src/components/block-list/test/fixtures/block-list-context.native.js new file mode 100644 index 0000000000000..af74c07ec8e0a --- /dev/null +++ b/packages/block-editor/src/components/block-list/test/fixtures/block-list-context.native.js @@ -0,0 +1,79 @@ +export const ROOT_LEVEL_ID = 'e59528f8-fb35-4ec1-aec6-5a065c236fa1'; +export const ROOT_LEVEL_WITH_INNER_BLOCKS_ID = + '72a9220f-4c3d-4b00-bae1-4506513f63d8'; +export const NESTED_WITH_INNER_BLOCKS_ID = + '9f3d1f1e-df85-485d-af63-dc8cb1b93cbc'; +export const DEEP_NESTED_ID = 'abec845a-e4de-43fb-96f7-80dc3d51ad7a'; + +export const BLOCKS_LAYOUTS_DATA = { + [ ROOT_LEVEL_ID ]: { + clientId: ROOT_LEVEL_ID, + width: 390, + height: 54, + x: 0, + y: 83, + innerBlocks: {}, + }, + [ ROOT_LEVEL_WITH_INNER_BLOCKS_ID ]: { + clientId: ROOT_LEVEL_WITH_INNER_BLOCKS_ID, + width: 390, + height: 386, + x: 0, + y: 137, + innerBlocks: { + '62839858-48b0-44ed-b834-1343a1357e54': { + clientId: '62839858-48b0-44ed-b834-1343a1357e54', + rootClientId: ROOT_LEVEL_WITH_INNER_BLOCKS_ID, + width: 390, + height: 54, + x: 0, + y: 0, + innerBlocks: {}, + }, + [ NESTED_WITH_INNER_BLOCKS_ID ]: { + clientId: NESTED_WITH_INNER_BLOCKS_ID, + rootClientId: ROOT_LEVEL_WITH_INNER_BLOCKS_ID, + width: 390, + height: 332, + x: 0, + y: 54, + innerBlocks: { + '435d62a4-afa7-457c-a894-b04390d7b447': { + clientId: '435d62a4-afa7-457c-a894-b04390d7b447', + rootClientId: NESTED_WITH_INNER_BLOCKS_ID, + width: 358, + height: 54, + x: 0, + y: 0, + innerBlocks: {}, + }, + [ DEEP_NESTED_ID ]: { + clientId: DEEP_NESTED_ID, + rootClientId: NESTED_WITH_INNER_BLOCKS_ID, + width: 358, + height: 98, + x: 0, + y: 54, + innerBlocks: {}, + }, + }, + }, + }, + }, +}; + +export const PARAGRAPH_BLOCK_LAYOUT_DATA = { + clientId: '22dda04f-4718-45b2-8cd2-36cedb9eae4d', + width: 390, + height: 98, + x: 0, + y: 83, +}; + +export const GROUP_BLOCK_LAYOUT_DATA = { + clientId: 'e18249d9-ec06-4f54-b71e-6ec59be5213e', + width: 390, + height: 164, + x: 0, + y: 83, +}; From d8f7cf8ada2d91f1233388fbd9f9953791331e37 Mon Sep 17 00:00:00 2001 From: Gerardo Date: Thu, 17 Mar 2022 13:27:01 +0100 Subject: [PATCH 12/12] Mobile - Block list context - update unit tests --- .../test/block-list-context.native.js | 41 +++++++------------ 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/packages/block-editor/src/components/block-list/test/block-list-context.native.js b/packages/block-editor/src/components/block-list/test/block-list-context.native.js index 07a45577bb99d..13fd0b1e42cb6 100644 --- a/packages/block-editor/src/components/block-list/test/block-list-context.native.js +++ b/packages/block-editor/src/components/block-list/test/block-list-context.native.js @@ -77,9 +77,7 @@ describe( 'deleteBlockLayoutByClientId', () => { ROOT_LEVEL_ID ); - expect( findDeletedBlock ).toEqual( - expect.not.objectContaining( { clientId: ROOT_LEVEL_ID } ) - ); + expect( findDeletedBlock ).toBeNull(); } ); it( "deletes a nested block's layout data with inner blocks", () => { @@ -95,11 +93,7 @@ describe( 'deleteBlockLayoutByClientId', () => { NESTED_WITH_INNER_BLOCKS_ID ); - expect( findDeletedBlock ).toEqual( - expect.not.objectContaining( { - clientId: NESTED_WITH_INNER_BLOCKS_ID, - } ) - ); + expect( findDeletedBlock ).toBeNull(); } ); it( "deletes a deep nested block's layout data", () => { @@ -115,16 +109,12 @@ describe( 'deleteBlockLayoutByClientId', () => { DEEP_NESTED_ID ); - expect( findDeletedBlock ).toEqual( - expect.not.objectContaining( { - clientId: DEEP_NESTED_ID, - } ) - ); + expect( findDeletedBlock ).toBeNull(); } ); } ); describe( 'updateBlocksLayouts', () => { - it( "adds a new block's layout data at root level im an empty object", () => { + it( "adds a new block's layout data at root level with an empty object", () => { const { blocksLayouts, findBlockLayoutByClientId, @@ -141,7 +131,10 @@ describe( 'updateBlocksLayouts', () => { ); expect( findAddedBlock ).toEqual( - expect.objectContaining( { clientId: BLOCK_CLIENT_ID } ) + expect.objectContaining( { + clientId: BLOCK_CLIENT_ID, + rootClientId: undefined, + } ) ); } ); @@ -181,11 +174,12 @@ describe( 'updateBlocksLayouts', () => { expect( findAddedInnerBlock ).toEqual( expect.objectContaining( { clientId: PARAGRAPH_BLOCK_LAYOUT_DATA.clientId, + rootClientId: PARENT_BLOCK_CLIENT_ID, } ) ); } ); - it( "adds a new block's layout data at a deep level", () => { + it( "adds a new block's layout data at deep level", () => { const { findBlockLayoutByClientId, updateBlocksLayouts, @@ -208,11 +202,12 @@ describe( 'updateBlocksLayouts', () => { expect( findAddedInnerBlock ).toEqual( expect.objectContaining( { clientId: PARAGRAPH_BLOCK_LAYOUT_DATA.clientId, + rootClientId: NESTED_WITH_INNER_BLOCKS_ID, } ) ); } ); - it( "deletes a block's layout data at a root level", () => { + it( "deletes a block's layout data at root level", () => { const { findBlockLayoutByClientId, updateBlocksLayouts, @@ -231,11 +226,7 @@ describe( 'updateBlocksLayouts', () => { ROOT_LEVEL_ID ); - expect( findDeletedBlock ).toEqual( - expect.not.objectContaining( { - clientId: ROOT_LEVEL_ID, - } ) - ); + expect( findDeletedBlock ).toBeNull(); } ); it( "deletes a block's layout data at a deep level", () => { @@ -257,10 +248,6 @@ describe( 'updateBlocksLayouts', () => { DEEP_NESTED_ID ); - expect( findDeletedBlock ).toEqual( - expect.not.objectContaining( { - clientId: DEEP_NESTED_ID, - } ) - ); + expect( findDeletedBlock ).toBeNull(); } ); } );