UNPKG

@wordpress/block-editor

Version:
314 lines (275 loc) 11.1 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _element = require("@wordpress/element"); var _classnames = _interopRequireDefault(require("classnames")); var _blocks = require("@wordpress/blocks"); var _components = require("@wordpress/components"); var _compose = require("@wordpress/compose"); var _icons = require("@wordpress/icons"); var _data = require("@wordpress/data"); var _i18n = require("@wordpress/i18n"); var _dom = require("@wordpress/dom"); var _leaf = _interopRequireDefault(require("./leaf")); var _useListViewScrollIntoView = _interopRequireDefault(require("./use-list-view-scroll-into-view")); var _button = require("../block-mover/button"); var _blockContents = _interopRequireDefault(require("./block-contents")); var _context = require("./context"); var _utils = require("./utils"); var _store = require("../../store"); var _useBlockDisplayInformation = _interopRequireDefault(require("../use-block-display-information")); var _blockLock = require("../block-lock"); var _lockUnlock = require("../../lock-unlock"); var _ariaReferencedText = _interopRequireDefault(require("./aria-referenced-text")); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ function ListViewBlock({ block: { clientId }, isDragged, isSelected, isBranchSelected, selectBlock, position, level, rowCount, siblingBlockCount, showBlockMovers, path, isExpanded, selectedClientIds, isSyncedBranch }) { const cellRef = (0, _element.useRef)(null); const rowRef = (0, _element.useRef)(null); const [isHovered, setIsHovered] = (0, _element.useState)(false); const { isLocked, canEdit } = (0, _blockLock.useBlockLock)(clientId); const isFirstSelectedBlock = isSelected && selectedClientIds[0] === clientId; const isLastSelectedBlock = isSelected && selectedClientIds[selectedClientIds.length - 1] === clientId; const { toggleBlockHighlight } = (0, _data.useDispatch)(_store.store); const blockInformation = (0, _useBlockDisplayInformation.default)(clientId); const blockTitle = blockInformation?.title || (0, _i18n.__)('Untitled'); const block = (0, _data.useSelect)(select => select(_store.store).getBlock(clientId), [clientId]); const blockName = (0, _data.useSelect)(select => select(_store.store).getBlockName(clientId), [clientId]); const blockEditingMode = (0, _data.useSelect)(select => (0, _lockUnlock.unlock)(select(_store.store)).getBlockEditingMode(clientId), [clientId]); const showBlockActions = // When a block hides its toolbar it also hides the block settings menu, // since that menu is part of the toolbar in the editor canvas. // List View respects this by also hiding the block settings menu. (0, _blocks.hasBlockSupport)(blockName, '__experimentalToolbar', true) && // Don't show the settings menu if block is disabled or content only. blockEditingMode === 'default'; const instanceId = (0, _compose.useInstanceId)(ListViewBlock); const descriptionId = `list-view-block-select-button__${instanceId}`; const blockPositionDescription = (0, _utils.getBlockPositionDescription)(position, siblingBlockCount, level); const blockAriaLabel = isLocked ? (0, _i18n.sprintf)( // translators: %s: The title of the block. This string indicates a link to select the locked block. (0, _i18n.__)('%s (locked)'), blockTitle) : blockTitle; const settingsAriaLabel = (0, _i18n.sprintf)( // translators: %s: The title of the block. (0, _i18n.__)('Options for %s'), blockTitle); const { isTreeGridMounted, expand, collapse, BlockSettingsMenu, listViewInstanceId, expandedState, setInsertedBlock, treeGridElementRef } = (0, _context.useListViewContext)(); const hasSiblings = siblingBlockCount > 0; const hasRenderedMovers = showBlockMovers && hasSiblings; const moverCellClassName = (0, _classnames.default)('block-editor-list-view-block__mover-cell', { 'is-visible': isHovered || isSelected }); const listViewBlockSettingsClassName = (0, _classnames.default)('block-editor-list-view-block__menu-cell', { 'is-visible': isHovered || isFirstSelectedBlock }); // If ListView 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. (0, _element.useEffect)(() => { if (!isTreeGridMounted && isSelected) { cellRef.current.focus(); } }, []); const onMouseEnter = (0, _element.useCallback)(() => { setIsHovered(true); toggleBlockHighlight(clientId, true); }, [clientId, setIsHovered, toggleBlockHighlight]); const onMouseLeave = (0, _element.useCallback)(() => { setIsHovered(false); toggleBlockHighlight(clientId, false); }, [clientId, setIsHovered, toggleBlockHighlight]); const selectEditorBlock = (0, _element.useCallback)(event => { selectBlock(event, clientId); event.preventDefault(); }, [clientId, selectBlock]); const updateFocusAndSelection = (0, _element.useCallback)((focusClientId, shouldSelectBlock) => { if (shouldSelectBlock) { selectBlock(undefined, focusClientId, null, null); } const getFocusElement = () => { const row = treeGridElementRef.current?.querySelector(`[role=row][data-block="${focusClientId}"]`); if (!row) return null; // Focus the first focusable in the row, which is the ListViewBlockSelectButton. return _dom.focus.focusable.find(row)[0]; }; let focusElement = getFocusElement(); if (focusElement) { focusElement.focus(); } else { // The element hasn't been painted yet. Defer focusing on the next frame. // This could happen when all blocks have been deleted and the default block // hasn't been added to the editor yet. window.requestAnimationFrame(() => { focusElement = getFocusElement(); // Ignore if the element still doesn't exist. if (focusElement) { focusElement.focus(); } }); } }, [selectBlock, treeGridElementRef]); const toggleExpanded = (0, _element.useCallback)(event => { // Prevent shift+click from opening link in a new window when toggling. event.preventDefault(); event.stopPropagation(); if (isExpanded === true) { collapse(clientId); } else if (isExpanded === false) { expand(clientId); } }, [clientId, expand, collapse, isExpanded]); let colSpan; if (hasRenderedMovers) { colSpan = 2; } else if (!showBlockActions) { colSpan = 3; } const classes = (0, _classnames.default)({ 'is-selected': isSelected, 'is-first-selected': isFirstSelectedBlock, 'is-last-selected': isLastSelectedBlock, 'is-branch-selected': isBranchSelected, 'is-synced-branch': isSyncedBranch, 'is-dragging': isDragged, 'has-single-cell': !showBlockActions, 'is-synced': blockInformation?.isSynced }); // Only include all selected blocks if the currently clicked on block // is one of the selected blocks. This ensures that if a user attempts // to alter a block that isn't part of the selection, they're still able // to do so. const dropdownClientIds = selectedClientIds.includes(clientId) ? selectedClientIds : [clientId]; // Pass in a ref to the row, so that it can be scrolled // into view when selected. For long lists, the placeholder for the // selected block is also observed, within ListViewLeafPlaceholder. (0, _useListViewScrollIntoView.default)({ isSelected, rowItemRef: rowRef, selectedClientIds }); // Detect if there is a block in the canvas currently being edited and multi-selection is not happening. const currentlyEditingBlockInCanvas = isSelected && selectedClientIds.length === 1; return (0, _element.createElement)(_leaf.default, { className: classes, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onFocus: onMouseEnter, onBlur: onMouseLeave, level: level, position: position, rowCount: rowCount, path: path, id: `list-view-${listViewInstanceId}-block-${clientId}`, "data-block": clientId, "data-expanded": canEdit ? isExpanded : undefined, ref: rowRef }, (0, _element.createElement)(_components.__experimentalTreeGridCell, { className: "block-editor-list-view-block__contents-cell", colSpan: colSpan, ref: cellRef, "aria-selected": !!isSelected }, ({ ref, tabIndex, onFocus }) => (0, _element.createElement)("div", { className: "block-editor-list-view-block__contents-container" }, (0, _element.createElement)(_blockContents.default, { block: block, onClick: selectEditorBlock, onToggleExpanded: toggleExpanded, isSelected: isSelected, position: position, siblingBlockCount: siblingBlockCount, level: level, ref: ref, tabIndex: currentlyEditingBlockInCanvas ? 0 : tabIndex, onFocus: onFocus, isExpanded: canEdit ? isExpanded : undefined, selectedClientIds: selectedClientIds, ariaLabel: blockAriaLabel, ariaDescribedBy: descriptionId, updateFocusAndSelection: updateFocusAndSelection }), (0, _element.createElement)(_ariaReferencedText.default, { id: descriptionId }, blockPositionDescription))), hasRenderedMovers && (0, _element.createElement)(_element.Fragment, null, (0, _element.createElement)(_components.__experimentalTreeGridCell, { className: moverCellClassName, withoutGridItem: true }, (0, _element.createElement)(_components.__experimentalTreeGridItem, null, ({ ref, tabIndex, onFocus }) => (0, _element.createElement)(_button.BlockMoverUpButton, { orientation: "vertical", clientIds: [clientId], ref: ref, tabIndex: tabIndex, onFocus: onFocus })), (0, _element.createElement)(_components.__experimentalTreeGridItem, null, ({ ref, tabIndex, onFocus }) => (0, _element.createElement)(_button.BlockMoverDownButton, { orientation: "vertical", clientIds: [clientId], ref: ref, tabIndex: tabIndex, onFocus: onFocus })))), showBlockActions && BlockSettingsMenu && (0, _element.createElement)(_components.__experimentalTreeGridCell, { className: listViewBlockSettingsClassName, "aria-selected": !!isSelected }, ({ ref, tabIndex, onFocus }) => (0, _element.createElement)(BlockSettingsMenu, { clientIds: dropdownClientIds, block: block, icon: _icons.moreVertical, label: settingsAriaLabel, toggleProps: { ref, className: 'block-editor-list-view-block__menu', tabIndex, onFocus }, disableOpenOnArrowDown: true, expand: expand, expandedState: expandedState, setInsertedBlock: setInsertedBlock, __experimentalSelectBlock: updateFocusAndSelection }))); } var _default = (0, _element.memo)(ListViewBlock); exports.default = _default; //# sourceMappingURL=block.js.map