UNPKG

@wordpress/block-editor

Version:
204 lines (194 loc) 6.34 kB
/** * External dependencies */ import clsx from 'clsx'; /** * WordPress dependencies */ import { useContext } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import { __unstableGetBlockProps as getBlockProps } from '@wordpress/blocks'; import { useMergeRefs, useDisabled } from '@wordpress/compose'; import warning from '@wordpress/warning'; /** * Internal dependencies */ import useMovingAnimation from '../../use-moving-animation'; import { PrivateBlockContext } from '../private-block-context'; import { useFocusFirstElement } from './use-focus-first-element'; import { useIsHovered } from './use-is-hovered'; import { blockBindingsKey, useBlockEditContext, } from '../../block-edit/context'; import { useFocusHandler } from './use-focus-handler'; import { useEventHandlers } from './use-selected-block-event-handlers'; import { useBlockRefProvider } from './use-block-refs'; import { useIntersectionObserver } from './use-intersection-observer'; import { useScrollIntoView } from './use-scroll-into-view'; import { useFlashEditableBlocks } from '../../use-flash-editable-blocks'; import { canBindBlock } from '../../../utils/block-bindings'; import { useFirefoxDraggableCompatibility } from './use-firefox-draggable-compatibility'; /** * This hook is used to lightly mark an element as a block element. The element * should be the outermost element of a block. Call this hook and pass the * returned props to the element to mark as a block. If you define a ref for the * element, it is important to pass the ref to this hook, which the hook in turn * will pass to the component through the props it returns. Optionally, you can * also pass any other props through this hook, and they will be merged and * returned. * * Use of this hook on the outermost element of a block is required if using API >= v2. * * @example * ```js * import { useBlockProps } from '@wordpress/block-editor'; * * export default function Edit() { * * const blockProps = useBlockProps( { * className: 'my-custom-class', * style: { * color: '#222222', * backgroundColor: '#eeeeee' * } * } ) * * return ( * <div { ...blockProps }> * * </div> * ) * } * * ``` * * * @param {Object} props Optional. Props to pass to the element. Must contain * the ref if one is defined. * @param {Object} options Options for internal use only. * @param {boolean} options.__unstableIsHtml * * @return {Object} Props to pass to the element to mark as a block. */ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) { const { clientId, className, wrapperProps = {}, isAligned, index, mode, name, blockApiVersion, blockTitle, isSelected, isSubtreeDisabled, hasOverlay, initialPosition, blockEditingMode, isHighlighted, isMultiSelected, isPartiallySelected, isReusable, isDragging, hasChildSelected, isEditingDisabled, hasEditableOutline, isTemporarilyEditingAsBlocks, defaultClassName, isSectionBlock, canMove, } = useContext( PrivateBlockContext ); // translators: %s: Type of block (i.e. Text, Image etc) const blockLabel = sprintf( __( 'Block: %s' ), blockTitle ); const htmlSuffix = mode === 'html' && ! __unstableIsHtml ? '-visual' : ''; const ffDragRef = useFirefoxDraggableCompatibility(); const mergedRefs = useMergeRefs( [ props.ref, useFocusFirstElement( { clientId, initialPosition } ), useBlockRefProvider( clientId ), useFocusHandler( clientId ), useEventHandlers( { clientId, isSelected } ), useIsHovered( { clientId } ), useIntersectionObserver(), useMovingAnimation( { triggerAnimationOnChange: index, clientId } ), useDisabled( { isDisabled: ! hasOverlay } ), useFlashEditableBlocks( { clientId, isEnabled: isSectionBlock, } ), useScrollIntoView( { isSelected } ), canMove ? ffDragRef : undefined, ] ); const blockEditContext = useBlockEditContext(); const hasBlockBindings = !! blockEditContext[ blockBindingsKey ]; const bindingsStyle = hasBlockBindings && canBindBlock( name ) ? { '--wp-admin-theme-color': 'var(--wp-block-synced-color)', '--wp-admin-theme-color--rgb': 'var(--wp-block-synced-color--rgb)', } : {}; // Ensures it warns only inside the `edit` implementation for the block. if ( blockApiVersion < 2 && clientId === blockEditContext.clientId ) { warning( `Block type "${ name }" must support API version 2 or higher to work correctly with "useBlockProps" method.` ); } let hasNegativeMargin = false; if ( wrapperProps?.style?.marginTop?.charAt( 0 ) === '-' || wrapperProps?.style?.marginBottom?.charAt( 0 ) === '-' || wrapperProps?.style?.marginLeft?.charAt( 0 ) === '-' || wrapperProps?.style?.marginRight?.charAt( 0 ) === '-' ) { hasNegativeMargin = true; } return { tabIndex: blockEditingMode === 'disabled' ? -1 : 0, draggable: canMove && ! hasChildSelected ? true : undefined, ...wrapperProps, ...props, ref: mergedRefs, id: `block-${ clientId }${ htmlSuffix }`, role: 'document', 'aria-label': blockLabel, 'data-block': clientId, 'data-type': name, 'data-title': blockTitle, inert: isSubtreeDisabled ? 'true' : undefined, className: clsx( 'block-editor-block-list__block', { // The wp-block className is important for editor styles. 'wp-block': ! isAligned, 'has-block-overlay': hasOverlay, 'is-selected': isSelected, 'is-highlighted': isHighlighted, 'is-multi-selected': isMultiSelected, 'is-partially-selected': isPartiallySelected, 'is-reusable': isReusable, 'is-dragging': isDragging, 'has-child-selected': hasChildSelected, 'is-editing-disabled': isEditingDisabled, 'has-editable-outline': hasEditableOutline, 'has-negative-margin': hasNegativeMargin, 'is-content-locked-temporarily-editing-as-blocks': isTemporarilyEditingAsBlocks, }, className, props.className, wrapperProps.className, defaultClassName ), style: { ...wrapperProps.style, ...props.style, ...bindingsStyle }, }; } /** * Call within a save function to get the props for the block wrapper. * * @param {Object} props Optional. Props to pass to the element. */ useBlockProps.save = getBlockProps;