@wordpress/block-editor
Version:
160 lines (152 loc) • 4.79 kB
JavaScript
/**
* WordPress dependencies
*/
import { createContext, useContext } from '@wordpress/element';
/**
* Internal dependencies
*/
import { orderBy } from '../../utils/sorting';
export const DEFAULT_BLOCK_LIST_CONTEXT = {
scrollRef: null,
blocksLayouts: {
current: {}
},
findBlockLayoutByClientId,
getBlockLayoutsOrderedByYCoord,
findBlockLayoutByPosition,
updateBlocksLayouts
};
const Context = createContext(DEFAULT_BLOCK_LIST_CONTEXT);
const {
Provider,
Consumer
} = Context;
/**
* Finds a block's layout data by position.
*
* @param {Object} data Blocks layouts object.
* @param {Object} position Position to use for finding the block.
* @param {number} position.x X coordinate.
* @param {number} position.y Y coordinate.
*
* @return {Object|undefined} Found block layout data that matches the provided position. If none is found, `undefined` will be returned.
*/
function findBlockLayoutByPosition(data, position) {
// Only enabled for root level blocks
return Object.values(data).find(block => {
return position.x >= block.x && position.x <= block.x + block.width && position.y >= block.y && position.y <= block.y + block.height;
});
}
/**
* Finds a block's layout data by its client Id.
*
* @param {Object} data Blocks layouts object.
* @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];
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 the layout data of a block by its client Id.
*
* @param {Object} data Blocks layouts object.
* @param {string} clientId Block's clientsId.
*
* @return {Object} Updated data object.
*/
export 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;
}, {});
}
/**
* Orders the block's layout data by its Y coordinate.
*
* @param {Object} data Blocks layouts object.
*
* @return {Object} Blocks layouts object ordered by its Y coordinate.
*/
function getBlockLayoutsOrderedByYCoord(data) {
// Only enabled for root level blocks.
return orderBy(Object.values(data), 'y');
}
/**
* 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 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.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).
*/
function updateBlocksLayouts(blocksLayouts, blockData) {
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);
};
//# sourceMappingURL=block-list-context.native.js.map