@gechiui/block-editor
Version:
244 lines (216 loc) • 8.15 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import { createElement } from "@gechiui/element";
/**
* External dependencies
*/
import classnames from 'classnames';
/**
* GeChiUI dependencies
*/
import { dragHandle } from '@gechiui/icons';
import { Button, Flex, FlexItem } from '@gechiui/components';
import { useSelect, useDispatch } from '@gechiui/data';
import { useEffect, useRef } from '@gechiui/element';
import { BACKSPACE, DELETE, UP, DOWN, LEFT, RIGHT, TAB, ESCAPE, ENTER, SPACE } from '@gechiui/keycodes';
import { getBlockType, __experimentalGetAccessibleBlockLabel as getAccessibleBlockLabel } from '@gechiui/blocks';
import { speak } from '@gechiui/a11y';
import { focus } from '@gechiui/dom';
import { __ } from '@gechiui/i18n';
/**
* Internal dependencies
*/
import BlockTitle from '../block-title';
import BlockIcon from '../block-icon';
import { store as blockEditorStore } from '../../store';
import BlockDraggable from '../block-draggable';
import useBlockDisplayInformation from '../use-block-display-information';
/**
* Block selection button component, displaying the label of the block. If the block
* descends from a root block, a button is displayed enabling the user to select
* the root block.
*
* @param {string} props Component props.
* @param {string} props.clientId Client ID of block.
*
* @return {GCComponent} The component to be rendered.
*/
function BlockSelectionButton(_ref) {
let {
clientId,
rootClientId,
blockElement
} = _ref;
const blockInformation = useBlockDisplayInformation(clientId);
const selected = useSelect(select => {
var _getBlockListSettings;
const {
getBlock,
getBlockIndex,
hasBlockMovingClientId,
getBlockListSettings
} = select(blockEditorStore);
const index = getBlockIndex(clientId);
const {
name,
attributes
} = getBlock(clientId);
const blockMovingMode = hasBlockMovingClientId();
return {
index,
name,
attributes,
blockMovingMode,
orientation: (_getBlockListSettings = getBlockListSettings(rootClientId)) === null || _getBlockListSettings === void 0 ? void 0 : _getBlockListSettings.orientation
};
}, [clientId, rootClientId]);
const {
index,
name,
attributes,
blockMovingMode,
orientation
} = selected;
const {
setNavigationMode,
removeBlock
} = useDispatch(blockEditorStore);
const ref = useRef();
const blockType = getBlockType(name);
const label = getAccessibleBlockLabel(blockType, attributes, index + 1, orientation); // Focus the breadcrumb in navigation mode.
useEffect(() => {
ref.current.focus();
speak(label);
}, [label]);
const {
hasBlockMovingClientId,
getBlockIndex,
getBlockRootClientId,
getClientIdsOfDescendants,
getSelectedBlockClientId,
getMultiSelectedBlocksEndClientId,
getPreviousBlockClientId,
getNextBlockClientId,
isNavigationMode
} = useSelect(blockEditorStore);
const {
selectBlock,
clearSelectedBlock,
setBlockMovingClientId,
moveBlockToPosition
} = useDispatch(blockEditorStore);
function onKeyDown(event) {
const {
keyCode
} = event;
const isUp = keyCode === UP;
const isDown = keyCode === DOWN;
const isLeft = keyCode === LEFT;
const isRight = keyCode === RIGHT;
const isTab = keyCode === TAB;
const isEscape = keyCode === ESCAPE;
const isEnter = keyCode === ENTER;
const isSpace = keyCode === SPACE;
const isShift = event.shiftKey;
if (keyCode === BACKSPACE || keyCode === DELETE) {
removeBlock(clientId);
event.preventDefault();
return;
}
const selectedBlockClientId = getSelectedBlockClientId();
const selectionEndClientId = getMultiSelectedBlocksEndClientId();
const selectionBeforeEndClientId = getPreviousBlockClientId(selectionEndClientId || selectedBlockClientId);
const selectionAfterEndClientId = getNextBlockClientId(selectionEndClientId || selectedBlockClientId);
const navigateUp = isTab && isShift || isUp;
const navigateDown = isTab && !isShift || isDown; // Move out of current nesting level (no effect if at root level).
const navigateOut = isLeft; // Move into next nesting level (no effect if the current block has no innerBlocks).
const navigateIn = isRight;
let focusedBlockUid;
if (navigateUp) {
focusedBlockUid = selectionBeforeEndClientId;
} else if (navigateDown) {
focusedBlockUid = selectionAfterEndClientId;
} else if (navigateOut) {
var _getBlockRootClientId;
focusedBlockUid = (_getBlockRootClientId = getBlockRootClientId(selectedBlockClientId)) !== null && _getBlockRootClientId !== void 0 ? _getBlockRootClientId : selectedBlockClientId;
} else if (navigateIn) {
var _getClientIdsOfDescen;
focusedBlockUid = (_getClientIdsOfDescen = getClientIdsOfDescendants([selectedBlockClientId])[0]) !== null && _getClientIdsOfDescen !== void 0 ? _getClientIdsOfDescen : selectedBlockClientId;
}
const startingBlockClientId = hasBlockMovingClientId();
if (isEscape && isNavigationMode()) {
clearSelectedBlock();
event.preventDefault();
}
if (isEscape && startingBlockClientId && !event.defaultPrevented) {
setBlockMovingClientId(null);
event.preventDefault();
}
if ((isEnter || isSpace) && startingBlockClientId) {
const sourceRoot = getBlockRootClientId(startingBlockClientId);
const destRoot = getBlockRootClientId(selectedBlockClientId);
const sourceBlockIndex = getBlockIndex(startingBlockClientId);
let destinationBlockIndex = getBlockIndex(selectedBlockClientId);
if (sourceBlockIndex < destinationBlockIndex && sourceRoot === destRoot) {
destinationBlockIndex -= 1;
}
moveBlockToPosition(startingBlockClientId, sourceRoot, destRoot, destinationBlockIndex);
selectBlock(startingBlockClientId);
setBlockMovingClientId(null);
}
if (navigateDown || navigateUp || navigateOut || navigateIn) {
if (focusedBlockUid) {
event.preventDefault();
selectBlock(focusedBlockUid);
} else if (isTab && selectedBlockClientId) {
let nextTabbable;
if (navigateDown) {
nextTabbable = focus.tabbable.findNext(blockElement);
if (!nextTabbable) {
nextTabbable = blockElement.ownerDocument.defaultView.frameElement;
nextTabbable = focus.tabbable.findNext(nextTabbable);
}
} else {
nextTabbable = focus.tabbable.findPrevious(blockElement);
}
if (nextTabbable) {
event.preventDefault();
nextTabbable.focus();
clearSelectedBlock();
}
}
}
}
const classNames = classnames('block-editor-block-list__block-selection-button', {
'is-block-moving-mode': !!blockMovingMode
});
const dragHandleLabel = __('拖动');
return createElement("div", {
className: classNames
}, createElement(Flex, {
justify: "center",
className: "block-editor-block-list__block-selection-button__content"
}, createElement(FlexItem, null, createElement(BlockIcon, {
icon: blockInformation === null || blockInformation === void 0 ? void 0 : blockInformation.icon,
showColors: true
})), createElement(FlexItem, null, createElement(BlockDraggable, {
clientIds: [clientId]
}, draggableProps => createElement(Button, _extends({
icon: dragHandle,
className: "block-selection-button_drag-handle",
"aria-hidden": "true",
label: dragHandleLabel // Should not be able to tab to drag handle as this
// button can only be used with a pointer device.
,
tabIndex: "-1"
}, draggableProps)))), createElement(FlexItem, null, createElement(Button, {
ref: ref,
onClick: () => setNavigationMode(false),
onKeyDown: onKeyDown,
label: label,
className: "block-selection-button_select-button"
}, createElement(BlockTitle, {
clientId: clientId
})))));
}
export default BlockSelectionButton;
//# sourceMappingURL=block-selection-button.js.map