@wordpress/block-editor
Version:
188 lines (162 loc) • 6.55 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import { createElement, Fragment } from "@wordpress/element";
/**
* WordPress dependencies
*/
import { __experimentalTreeGridRow as TreeGridRow, __experimentalTreeGridCell as TreeGridCell } from '@wordpress/components';
import { memo } from '@wordpress/element';
import { AsyncModeProvider, useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
import { Appender } from './appender';
import ListViewBlock from './block';
import { useListViewContext } from './context';
import { isClientIdSelected } from './utils';
import { store as blockEditorStore } from '../../store';
import useBlockDisplayInformation from '../use-block-display-information';
/**
* Given a block, returns the total number of blocks in that subtree. This is used to help determine
* the list position of a block.
*
* When a block is collapsed, we do not count their children as part of that total. In the current drag
* implementation dragged blocks and their children are not counted.
*
* @param {Object} block block tree
* @param {Object} expandedState state that notes which branches are collapsed
* @param {Array} draggedClientIds a list of dragged client ids
* @param {boolean} isExpandedByDefault flag to determine the default fallback expanded state.
* @return {number} block count
*/
function countBlocks(block, expandedState, draggedClientIds, isExpandedByDefault) {
var _expandedState$block$;
const isDragged = draggedClientIds?.includes(block.clientId);
if (isDragged) {
return 0;
}
const isExpanded = (_expandedState$block$ = expandedState[block.clientId]) !== null && _expandedState$block$ !== void 0 ? _expandedState$block$ : isExpandedByDefault;
if (isExpanded) {
return 1 + block.innerBlocks.reduce(countReducer(expandedState, draggedClientIds, isExpandedByDefault), 0);
}
return 1;
}
const countReducer = (expandedState, draggedClientIds, isExpandedByDefault) => (count, block) => {
var _expandedState$block$2;
const isDragged = draggedClientIds?.includes(block.clientId);
if (isDragged) {
return count;
}
const isExpanded = (_expandedState$block$2 = expandedState[block.clientId]) !== null && _expandedState$block$2 !== void 0 ? _expandedState$block$2 : isExpandedByDefault;
if (isExpanded && block.innerBlocks.length > 0) {
return count + countBlocks(block, expandedState, draggedClientIds, isExpandedByDefault);
}
return count + 1;
};
const noop = () => {};
function ListViewBranch(props) {
const {
blocks,
selectBlock = noop,
showBlockMovers,
selectedClientIds,
level = 1,
path = '',
isBranchSelected = false,
listPosition = 0,
fixedListWindow,
isExpanded,
parentId,
shouldShowInnerBlocks = true,
isSyncedBranch = false,
showAppender: showAppenderProp = true
} = props;
const parentBlockInformation = useBlockDisplayInformation(parentId);
const syncedBranch = isSyncedBranch || !!parentBlockInformation?.isSynced;
const canParentExpand = useSelect(select => {
if (!parentId) {
return true;
}
return select(blockEditorStore).canEditBlock(parentId);
}, [parentId]);
const {
expandedState,
draggedClientIds
} = useListViewContext();
if (!canParentExpand) {
return null;
} // Only show the appender at the first level.
const showAppender = showAppenderProp && level === 1;
const filteredBlocks = blocks.filter(Boolean);
const blockCount = filteredBlocks.length; // The appender means an extra row in List View, so add 1 to the row count.
const rowCount = showAppender ? blockCount + 1 : blockCount;
let nextPosition = listPosition;
return createElement(Fragment, null, filteredBlocks.map((block, index) => {
var _expandedState$client;
const {
clientId,
innerBlocks
} = block;
if (index > 0) {
nextPosition += countBlocks(filteredBlocks[index - 1], expandedState, draggedClientIds, isExpanded);
}
const {
itemInView
} = fixedListWindow;
const blockInView = itemInView(nextPosition);
const position = index + 1;
const updatedPath = path.length > 0 ? `${path}_${position}` : `${position}`;
const hasNestedBlocks = !!innerBlocks?.length;
const shouldExpand = hasNestedBlocks && shouldShowInnerBlocks ? (_expandedState$client = expandedState[clientId]) !== null && _expandedState$client !== void 0 ? _expandedState$client : isExpanded : undefined;
const isDragged = !!draggedClientIds?.includes(clientId); // Make updates to the selected or dragged blocks synchronous,
// but asynchronous for any other block.
const isSelected = isClientIdSelected(clientId, selectedClientIds);
const isSelectedBranch = isBranchSelected || isSelected && hasNestedBlocks;
const showBlock = isDragged || blockInView || isSelected;
return createElement(AsyncModeProvider, {
key: clientId,
value: !isSelected
}, showBlock && createElement(ListViewBlock, {
block: block,
selectBlock: selectBlock,
isSelected: isSelected,
isBranchSelected: isSelectedBranch,
isDragged: isDragged,
level: level,
position: position,
rowCount: rowCount,
siblingBlockCount: blockCount,
showBlockMovers: showBlockMovers,
path: updatedPath,
isExpanded: shouldExpand,
listPosition: nextPosition,
selectedClientIds: selectedClientIds,
isSyncedBranch: syncedBranch
}), !showBlock && createElement("tr", null, createElement("td", {
className: "block-editor-list-view-placeholder"
})), hasNestedBlocks && shouldExpand && !isDragged && createElement(ListViewBranch, {
parentId: clientId,
blocks: innerBlocks,
selectBlock: selectBlock,
showBlockMovers: showBlockMovers,
level: level + 1,
path: updatedPath,
listPosition: nextPosition + 1,
fixedListWindow: fixedListWindow,
isBranchSelected: isSelectedBranch,
selectedClientIds: selectedClientIds,
isExpanded: isExpanded,
isSyncedBranch: syncedBranch
}));
}), showAppender && createElement(TreeGridRow, {
level: level,
setSize: rowCount,
positionInSet: rowCount,
isExpanded: true
}, createElement(TreeGridCell, null, treeGridCellProps => createElement(Appender, _extends({
clientId: parentId,
nestingLevel: level,
blockCount: blockCount
}, treeGridCellProps)))));
}
export default memo(ListViewBranch);
//# sourceMappingURL=branch.js.map