Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Mobile] - Drag & drop blocks - Fetch and share blocks layout size and position coordinates #39089

Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/**
* WordPress dependencies
*/
import { createContext, useContext } from '@wordpress/element';

export const DEFAULT_BLOCK_LIST_CONTEXT = {
scrollRef: null,
blocksLayouts: { current: {} },
updateBlocksLayouts,
};

const Context = createContext( DEFAULT_BLOCK_LIST_CONTEXT );
const { Provider, Consumer } = Context;

/**
* Finds a block's layout data within the provided data object.
fluiddot marked this conversation as resolved.
Show resolved Hide resolved
*
* @param {Object} data Blocks layouts list.
fluiddot marked this conversation as resolved.
Show resolved Hide resolved
* @param {string} clientId Block's clientId.
*
* @return {Object} Found block layout data.
*/
function findBlockLayoutByClientId( data, clientId ) {
fluiddot marked this conversation as resolved.
Show resolved Hide resolved
return Object.entries( data ).reduce( ( acc, entry ) => {
const item = entry[ 1 ];
if ( acc ) {
return acc;
}
if ( item?.clientId === clientId ) {
return item;
}
if ( item?.innerBlocks && Object.keys( item.innerBlocks ).length > 0 ) {
return findBlockLayoutByClientId( item.innerBlocks, clientId );
}
return null;
}, null );
}

/**
* Deletes a block's layout data from the provided data object.
fluiddot marked this conversation as resolved.
Show resolved Hide resolved
*
* @param {Object} data Blocks layouts list.
fluiddot marked this conversation as resolved.
Show resolved Hide resolved
* @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 ) {
acc[ key ] = data[ key ];
}
if (
data[ key ]?.innerBlocks &&
Object.keys( data[ key ].innerBlocks ).length > 0
) {
if ( acc[ key ] ) {
acc[ key ].innerBlocks = deleteBlockLayoutByClientId(
data[ key ].innerBlocks,
clientId
);
}
}
return acc;
}, {} );
}

/**
* Updates the blocksLayouts object with the block's layout data.
fluiddot marked this conversation as resolved.
Show resolved Hide resolved
*
* @param {Object} blocksLayouts Blocks layouts list.
fluiddot marked this conversation as resolved.
Show resolved Hide resolved
* @param {Object} blockData Block's layout data.
fluiddot marked this conversation as resolved.
Show resolved Hide resolved
* @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.
fluiddot marked this conversation as resolved.
Show resolved Hide resolved
* @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 ) {
fluiddot marked this conversation as resolved.
Show resolved Hide resolved
const { clientId, rootClientId, shouldRemove, ...layoutProps } = blockData;

if ( clientId && shouldRemove ) {
blocksLayouts.current = deleteBlockLayoutByClientId(
blocksLayouts.current,
clientId
);
return;
}

if ( clientId && ! rootClientId ) {
blocksLayouts.current[ clientId ] = {
clientId,
rootClientId,
...layoutProps,
innerBlocks: {
...blocksLayouts.current[ clientId ]?.innerBlocks,
},
};
} else if ( clientId && rootClientId ) {
const block = findBlockLayoutByClientId(
blocksLayouts.current,
rootClientId
);

if ( block ) {
block.innerBlocks[ clientId ] = {
clientId,
rootClientId,
...layoutProps,
innerBlocks: {
...block.innerBlocks[ clientId ]?.innerBlocks,
},
};
}
}
}

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 );
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* 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( { children, clientId, rootClientId } ) {
const { blocksLayouts, updateBlocksLayouts } = useBlockListContext();

useEffect( () => {
return () => {
updateBlocksLayouts( blocksLayouts, {
clientId,
shouldRemove: true,
} );
};
}, [] );

const onLayout = useCallback(
( { nativeEvent: { layout } } ) => {
updateBlocksLayouts( blocksLayouts, {
clientId,
rootClientId,
...layout,
} );
},
[ clientId, rootClientId, updateBlocksLayouts ]
);

return <View onLayout={ onLayout }>{ children }</View>;
}

export default BlockListItemCell;
40 changes: 32 additions & 8 deletions packages/block-editor/src/components/block-list/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 BlockListItemCell from './block-list-item-cell';
import {
BlockListProvider,
BlockListConsumer,
DEFAULT_BLOCK_LIST_CONTEXT,
} from './block-list-context';
import { store as blockEditorStore } from '../../store';

const BlockListContext = createContext();

export const OnCaretVerticalPositionChange = createContext();

const stylesMemo = {};
Expand Down Expand Up @@ -78,6 +82,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 );

Expand Down Expand Up @@ -154,6 +161,17 @@ export class BlockList extends Component {
return this.extraData;
}

getCellRendererComponent( { children, item } ) {
const { rootClientId } = this.props;
return (
<BlockListItemCell
children={ children }
clientId={ item }
rootClientId={ rootClientId }
/>
);
}

onLayout( { nativeEvent } ) {
const { layout } = nativeEvent;
const { blockWidth } = this.state;
Expand All @@ -173,17 +191,22 @@ 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 ? (
<BlockListContext.Provider value={ this.scrollViewRef }>
<BlockListProvider
value={ {
...DEFAULT_BLOCK_LIST_CONTEXT,
scrollRef: this.scrollViewRef,
} }
>
{ this.renderList() }
</BlockListContext.Provider>
</BlockListProvider>
) : (
<BlockListContext.Consumer>
{ ( ref ) =>
<BlockListConsumer>
{ ( { scrollRef } ) =>
this.renderList( {
parentScrollRef: ref,
parentScrollRef: scrollRef,
} )
}
</BlockListContext.Consumer>
</BlockListConsumer>
);

return (
Expand Down Expand Up @@ -279,6 +302,7 @@ export class BlockList extends Component {
data={ blockClientIds }
keyExtractor={ identity }
renderItem={ this.renderItem }
CellRendererComponent={ this.getCellRendererComponent }
shouldPreventAutomaticScroll={
this.shouldFlatListPreventAutomaticScroll
}
Expand Down