UNPKG

@wordpress/block-editor

Version:
295 lines (278 loc) 9.99 kB
/** * External dependencies */ import clsx from 'clsx'; /** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; import { useSelect } from '@wordpress/data'; import { useRef } from '@wordpress/element'; import { useViewportMatch } from '@wordpress/compose'; import { getBlockType, hasBlockSupport, isReusableBlock, isTemplatePart, } from '@wordpress/blocks'; import { ToolbarGroup } from '@wordpress/components'; /** * Internal dependencies */ import BlockMover from '../block-mover'; import BlockParentSelector from '../block-parent-selector'; import BlockSwitcher from '../block-switcher'; import BlockControls from '../block-controls'; import __unstableBlockToolbarLastItem from './block-toolbar-last-item'; import BlockSettingsMenu from '../block-settings-menu'; import { BlockLockToolbar } from '../block-lock'; import { BlockGroupToolbar } from '../convert-to-group-buttons'; import BlockEditVisuallyButton from '../block-edit-visually-button'; import { useShowHoveredOrFocusedGestures } from './utils'; import { store as blockEditorStore } from '../../store'; import __unstableBlockNameContext from './block-name-context'; import NavigableToolbar from '../navigable-toolbar'; import { useHasBlockToolbar } from './use-has-block-toolbar'; import ChangeDesign from './change-design'; import SwitchSectionStyle from './switch-section-style'; import { unlock } from '../../lock-unlock'; /** * Renders the block toolbar. * * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/block-toolbar/README.md * * @param {Object} props Components props. * @param {boolean} props.hideDragHandle Show or hide the Drag Handle for drag and drop functionality. * @param {boolean} props.focusOnMount Focus the toolbar when mounted. * @param {number} props.__experimentalInitialIndex The initial index of the toolbar item to focus. * @param {Function} props.__experimentalOnIndexChange Callback function to be called when the index of the focused toolbar item changes. * @param {string} props.variant Style variant of the toolbar, also passed to the Dropdowns rendered from Block Toolbar Buttons. */ export function PrivateBlockToolbar( { hideDragHandle, focusOnMount, __experimentalInitialIndex, __experimentalOnIndexChange, variant = 'unstyled', } ) { const { blockClientId, blockClientIds, isDefaultEditingMode, blockType, toolbarKey, shouldShowVisualToolbar, showParentSelector, isUsingBindings, hasParentPattern, hasContentOnlyLocking, showShuffleButton, showSlots, showGroupButtons, showLockButtons, showSwitchSectionStyleButton, hasFixedToolbar, isNavigationMode, } = useSelect( ( select ) => { const { getBlockName, getBlockMode, getBlockParents, getSelectedBlockClientIds, isBlockValid, getBlockEditingMode, getBlockAttributes, getBlockParentsByBlockName, getTemplateLock, getSettings, getParentSectionBlock, isZoomOut, isNavigationMode: _isNavigationMode, } = unlock( select( blockEditorStore ) ); const selectedBlockClientIds = getSelectedBlockClientIds(); const selectedBlockClientId = selectedBlockClientIds[ 0 ]; const parents = getBlockParents( selectedBlockClientId ); const parentSection = getParentSectionBlock( selectedBlockClientId ); const parentClientId = parentSection ?? parents[ parents.length - 1 ]; const parentBlockName = getBlockName( parentClientId ); const parentBlockType = getBlockType( parentBlockName ); const editingMode = getBlockEditingMode( selectedBlockClientId ); const _isDefaultEditingMode = editingMode === 'default'; const _blockName = getBlockName( selectedBlockClientId ); const isValid = selectedBlockClientIds.every( ( id ) => isBlockValid( id ) ); const isVisual = selectedBlockClientIds.every( ( id ) => getBlockMode( id ) === 'visual' ); const _isUsingBindings = selectedBlockClientIds.every( ( clientId ) => !! getBlockAttributes( clientId )?.metadata?.bindings ); const _hasParentPattern = selectedBlockClientIds.every( ( clientId ) => getBlockParentsByBlockName( clientId, 'core/block', true ) .length > 0 ); // If one or more selected blocks are locked, do not show the BlockGroupToolbar. const _hasTemplateLock = selectedBlockClientIds.some( ( id ) => getTemplateLock( id ) === 'contentOnly' ); const _isZoomOut = isZoomOut(); return { blockClientId: selectedBlockClientId, blockClientIds: selectedBlockClientIds, isDefaultEditingMode: _isDefaultEditingMode, blockType: selectedBlockClientId && getBlockType( _blockName ), shouldShowVisualToolbar: isValid && isVisual, toolbarKey: `${ selectedBlockClientId }${ parentClientId }`, showParentSelector: ! _isZoomOut && parentBlockType && editingMode !== 'contentOnly' && getBlockEditingMode( parentClientId ) !== 'disabled' && hasBlockSupport( parentBlockType, '__experimentalParentSelector', true ) && selectedBlockClientIds.length === 1, isUsingBindings: _isUsingBindings, hasParentPattern: _hasParentPattern, hasContentOnlyLocking: _hasTemplateLock, showShuffleButton: _isZoomOut, showSlots: ! _isZoomOut, showGroupButtons: ! _isZoomOut, showLockButtons: ! _isZoomOut, showSwitchSectionStyleButton: _isZoomOut, hasFixedToolbar: getSettings().hasFixedToolbar, isNavigationMode: _isNavigationMode(), }; }, [] ); const toolbarWrapperRef = useRef( null ); // Handles highlighting the current block outline on hover or focus of the // block type toolbar area. const nodeRef = useRef(); const showHoveredOrFocusedGestures = useShowHoveredOrFocusedGestures( { ref: nodeRef, } ); const isLargeViewport = ! useViewportMatch( 'medium', '<' ); const hasBlockToolbar = useHasBlockToolbar(); if ( ! hasBlockToolbar ) { return null; } const isMultiToolbar = blockClientIds.length > 1; const isSynced = isReusableBlock( blockType ) || isTemplatePart( blockType ); // Shifts the toolbar to make room for the parent block selector. const classes = clsx( 'block-editor-block-contextual-toolbar', { 'has-parent': showParentSelector, 'is-inverted-toolbar': isNavigationMode && ! hasFixedToolbar, } ); const innerClasses = clsx( 'block-editor-block-toolbar', { 'is-synced': isSynced, 'is-connected': isUsingBindings, } ); return ( <NavigableToolbar focusEditorOnEscape className={ classes } /* translators: accessibility text for the block toolbar */ aria-label={ __( 'Block tools' ) } // The variant is applied as "toolbar" when undefined, which is the black border style of the dropdown from the toolbar popover. variant={ variant === 'toolbar' ? undefined : variant } focusOnMount={ focusOnMount } __experimentalInitialIndex={ __experimentalInitialIndex } __experimentalOnIndexChange={ __experimentalOnIndexChange } // Resets the index whenever the active block changes so // this is not persisted. See https://github.com/WordPress/gutenberg/pull/25760#issuecomment-717906169 key={ toolbarKey } > <div ref={ toolbarWrapperRef } className={ innerClasses }> { showParentSelector && ! isMultiToolbar && isLargeViewport && ( <BlockParentSelector /> ) } { ( shouldShowVisualToolbar || isMultiToolbar ) && ! hasParentPattern && ( <div ref={ nodeRef } { ...showHoveredOrFocusedGestures } > <ToolbarGroup className="block-editor-block-toolbar__block-controls"> <BlockSwitcher clientIds={ blockClientIds } /> { ! isMultiToolbar && isDefaultEditingMode && showLockButtons && ( <BlockLockToolbar clientId={ blockClientId } /> ) } <BlockMover clientIds={ blockClientIds } hideDragHandle={ hideDragHandle } /> </ToolbarGroup> </div> ) } { ! hasContentOnlyLocking && shouldShowVisualToolbar && isMultiToolbar && showGroupButtons && <BlockGroupToolbar /> } { showShuffleButton && ( <ChangeDesign clientId={ blockClientIds[ 0 ] } /> ) } { showSwitchSectionStyleButton && ( <SwitchSectionStyle clientId={ blockClientIds[ 0 ] } /> ) } { shouldShowVisualToolbar && showSlots && ( <> <BlockControls.Slot group="parent" className="block-editor-block-toolbar__slot" /> <BlockControls.Slot group="block" className="block-editor-block-toolbar__slot" /> <BlockControls.Slot className="block-editor-block-toolbar__slot" /> <BlockControls.Slot group="inline" className="block-editor-block-toolbar__slot" /> <BlockControls.Slot group="other" className="block-editor-block-toolbar__slot" /> <__unstableBlockNameContext.Provider value={ blockType?.name } > <__unstableBlockToolbarLastItem.Slot /> </__unstableBlockNameContext.Provider> </> ) } <BlockEditVisuallyButton clientIds={ blockClientIds } /> <BlockSettingsMenu clientIds={ blockClientIds } /> </div> </NavigableToolbar> ); } /** * Renders the block toolbar. * * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/block-toolbar/README.md * * @param {Object} props Components props. * @param {boolean} props.hideDragHandle Show or hide the Drag Handle for drag and drop functionality. * @param {string} props.variant Style variant of the toolbar, also passed to the Dropdowns rendered from Block Toolbar Buttons. */ export default function BlockToolbar( { hideDragHandle, variant } ) { return ( <PrivateBlockToolbar hideDragHandle={ hideDragHandle } variant={ variant } focusOnMount={ undefined } __experimentalInitialIndex={ undefined } __experimentalOnIndexChange={ undefined } /> ); }