UNPKG

@wordpress/block-library

Version:
186 lines (167 loc) 4.32 kB
/** * External dependencies */ import classnames from 'classnames'; /** * WordPress dependencies */ import { ResizableBox, Spinner } from '@wordpress/components'; import { BlockControls, BlockIcon, MediaPlaceholder, MediaReplaceFlow, store as blockEditorStore, } from '@wordpress/block-editor'; import { __ } from '@wordpress/i18n'; import { useViewportMatch } from '@wordpress/compose'; import { useDispatch } from '@wordpress/data'; import { forwardRef } from '@wordpress/element'; import { isBlobURL } from '@wordpress/blob'; import { store as noticesStore } from '@wordpress/notices'; /** * Internal dependencies */ import icon from './media-container-icon'; /** * Constants */ const ALLOWED_MEDIA_TYPES = [ 'image', 'video' ]; const noop = () => {}; export function imageFillStyles( url, focalPoint ) { return url ? { backgroundImage: `url(${ url })`, backgroundPosition: focalPoint ? `${ Math.round( focalPoint.x * 100 ) }% ${ Math.round( focalPoint.y * 100 ) }%` : `50% 50%`, } : {}; } const ResizableBoxContainer = forwardRef( ( { isSelected, isStackedOnMobile, ...props }, ref ) => { const isMobile = useViewportMatch( 'small', '<' ); return ( <ResizableBox ref={ ref } showHandle={ isSelected && ( ! isMobile || ! isStackedOnMobile ) } { ...props } /> ); } ); function ToolbarEditButton( { mediaId, mediaUrl, onSelectMedia } ) { return ( <BlockControls group="other"> <MediaReplaceFlow mediaId={ mediaId } mediaURL={ mediaUrl } allowedTypes={ ALLOWED_MEDIA_TYPES } accept="image/*,video/*" onSelect={ onSelectMedia } /> </BlockControls> ); } function PlaceholderContainer( { className, mediaUrl, onSelectMedia } ) { const { createErrorNotice } = useDispatch( noticesStore ); const onUploadError = ( message ) => { createErrorNotice( message, { type: 'snackbar' } ); }; return ( <MediaPlaceholder icon={ <BlockIcon icon={ icon } /> } labels={ { title: __( 'Media area' ), } } className={ className } onSelect={ onSelectMedia } accept="image/*,video/*" allowedTypes={ ALLOWED_MEDIA_TYPES } onError={ onUploadError } disableMediaButtons={ mediaUrl } /> ); } function MediaContainer( props, ref ) { const { className, commitWidthChange, focalPoint, imageFill, isSelected, isStackedOnMobile, mediaAlt, mediaId, mediaPosition, mediaType, mediaUrl, mediaWidth, onSelectMedia, onWidthChange, isContentLocked, } = props; const isTemporaryMedia = ! mediaId && isBlobURL( mediaUrl ); const { toggleSelection } = useDispatch( blockEditorStore ); if ( mediaUrl ) { const onResizeStart = () => { toggleSelection( false ); }; const onResize = ( event, direction, elt ) => { onWidthChange( parseInt( elt.style.width ) ); }; const onResizeStop = ( event, direction, elt ) => { toggleSelection( true ); commitWidthChange( parseInt( elt.style.width ) ); }; const enablePositions = { right: ! isContentLocked && mediaPosition === 'left', left: ! isContentLocked && mediaPosition === 'right', }; const backgroundStyles = mediaType === 'image' && imageFill ? imageFillStyles( mediaUrl, focalPoint ) : {}; const mediaTypeRenderers = { image: () => <img src={ mediaUrl } alt={ mediaAlt } />, video: () => <video controls src={ mediaUrl } />, }; return ( <ResizableBoxContainer as="figure" className={ classnames( className, 'editor-media-container__resizer', { 'is-transient': isTemporaryMedia } ) } style={ backgroundStyles } size={ { width: mediaWidth + '%' } } minWidth="10%" maxWidth="100%" enable={ enablePositions } onResizeStart={ onResizeStart } onResize={ onResize } onResizeStop={ onResizeStop } axis="x" isSelected={ isSelected } isStackedOnMobile={ isStackedOnMobile } ref={ ref } > <ToolbarEditButton onSelectMedia={ onSelectMedia } mediaUrl={ mediaUrl } mediaId={ mediaId } /> { ( mediaTypeRenderers[ mediaType ] || noop )() } { isTemporaryMedia && <Spinner /> } <PlaceholderContainer { ...props } /> </ResizableBoxContainer> ); } return <PlaceholderContainer { ...props } />; } export default forwardRef( MediaContainer );