@wordpress/block-editor
Version:
200 lines (191 loc) • 6.34 kB
JavaScript
import { createElement, Fragment } from "@wordpress/element";
/**
* External dependencies
*/
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { __experimentalTreeGridCell as TreeGridCell, __experimentalTreeGridItem as TreeGridItem, MenuGroup, MenuItem } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { moreVertical } from '@wordpress/icons';
import { useState, useRef, useEffect } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
import BlockNavigationLeaf from './leaf';
import { BlockMoverUpButton, BlockMoverDownButton } from '../block-mover/button';
import BlockNavigationBlockContents from './block-contents';
import BlockSettingsDropdown from '../block-settings-menu/block-settings-dropdown';
import { useBlockNavigationContext } from './context';
import { store as blockEditorStore } from '../../store';
export default function BlockNavigationBlock({
block,
isSelected,
isBranchSelected,
isLastOfSelectedBranch,
onClick,
position,
level,
rowCount,
siblingBlockCount,
showBlockMovers,
path
}) {
const cellRef = useRef(null);
const [isHovered, setIsHovered] = useState(false);
const {
clientId
} = block;
const {
isDragging,
blockParents
} = useSelect(select => {
const {
isBlockBeingDragged,
isAncestorBeingDragged,
getBlockParents
} = select(blockEditorStore);
return {
isDragging: isBlockBeingDragged(clientId) || isAncestorBeingDragged(clientId),
blockParents: getBlockParents(clientId)
};
}, [clientId]);
const {
selectBlock: selectEditorBlock,
toggleBlockHighlight
} = useDispatch(blockEditorStore);
const hasSiblings = siblingBlockCount > 0;
const hasRenderedMovers = showBlockMovers && hasSiblings;
const moverCellClassName = classnames('block-editor-block-navigation-block__mover-cell', {
'is-visible': isHovered
});
const {
__experimentalFeatures: withExperimentalFeatures,
__experimentalPersistentListViewFeatures: withExperimentalPersistentListViewFeatures,
isTreeGridMounted
} = useBlockNavigationContext();
const blockNavigationBlockSettingsClassName = classnames('block-editor-block-navigation-block__menu-cell', {
'is-visible': isHovered
}); // If BlockNavigation has experimental features related to the Persistent List View,
// only focus the selected list item on mount; otherwise the list would always
// try to steal the focus from the editor canvas.
useEffect(() => {
if (withExperimentalPersistentListViewFeatures && !isTreeGridMounted && isSelected) {
cellRef.current.focus();
}
}, []); // If BlockNavigation has experimental features (such as drag and drop) enabled,
// leave the focus handling as it was before, to avoid accidental regressions.
useEffect(() => {
if (withExperimentalFeatures && isSelected) {
cellRef.current.focus();
}
}, [withExperimentalFeatures, isSelected]);
const highlightBlock = withExperimentalPersistentListViewFeatures ? toggleBlockHighlight : () => {};
const onMouseEnter = () => {
setIsHovered(true);
highlightBlock(clientId, true);
};
const onMouseLeave = () => {
setIsHovered(false);
highlightBlock(clientId, false);
};
const classes = classnames({
'is-selected': isSelected,
'is-branch-selected': withExperimentalPersistentListViewFeatures && isBranchSelected,
'is-last-of-selected-branch': withExperimentalPersistentListViewFeatures && isLastOfSelectedBranch,
'is-dragging': isDragging
});
return createElement(BlockNavigationLeaf, {
className: classes,
onMouseEnter: onMouseEnter,
onMouseLeave: onMouseLeave,
onFocus: onMouseEnter,
onBlur: onMouseLeave,
level: level,
position: position,
rowCount: rowCount,
path: path,
id: `block-navigation-block-${clientId}`,
"data-block": clientId
}, createElement(TreeGridCell, {
className: "block-editor-block-navigation-block__contents-cell",
colSpan: hasRenderedMovers ? undefined : 2,
ref: cellRef
}, ({
ref,
tabIndex,
onFocus
}) => createElement("div", {
className: "block-editor-block-navigation-block__contents-container"
}, createElement(BlockNavigationBlockContents, {
block: block,
onClick: () => onClick(block.clientId),
isSelected: isSelected,
position: position,
siblingBlockCount: siblingBlockCount,
level: level,
ref: ref,
tabIndex: tabIndex,
onFocus: onFocus
}))), hasRenderedMovers && createElement(Fragment, null, createElement(TreeGridCell, {
className: moverCellClassName,
withoutGridItem: true
}, createElement(TreeGridItem, null, ({
ref,
tabIndex,
onFocus
}) => createElement(BlockMoverUpButton, {
orientation: "vertical",
clientIds: [clientId],
ref: ref,
tabIndex: tabIndex,
onFocus: onFocus
})), createElement(TreeGridItem, null, ({
ref,
tabIndex,
onFocus
}) => createElement(BlockMoverDownButton, {
orientation: "vertical",
clientIds: [clientId],
ref: ref,
tabIndex: tabIndex,
onFocus: onFocus
})))), withExperimentalFeatures && createElement(TreeGridCell, {
className: blockNavigationBlockSettingsClassName
}, ({
ref,
tabIndex,
onFocus
}) => createElement(BlockSettingsDropdown, {
clientIds: [clientId],
icon: moreVertical,
toggleProps: {
ref,
tabIndex,
onFocus
},
disableOpenOnArrowDown: true,
__experimentalSelectBlock: onClick
}, ({
onClose
}) => createElement(MenuGroup, null, createElement(MenuItem, {
onClick: async () => {
if (blockParents.length) {
// If the block to select is inside a dropdown, we need to open the dropdown.
// Otherwise focus won't transfer to the block.
for (const parent of blockParents) {
await selectEditorBlock(parent);
}
} else {
// If clientId is already selected, it won't be focused (see block-wrapper.js)
// This removes the selection first to ensure the focus will always switch.
await selectEditorBlock(null);
}
await selectEditorBlock(clientId);
onClose();
}
}, __('Go to block'))))));
}
//# sourceMappingURL=block.js.map