diff --git a/packages/block-library/src/cover/edit.js b/packages/block-library/src/cover/edit.js deleted file mode 100644 index a61003e6dc4ff9..00000000000000 --- a/packages/block-library/src/cover/edit.js +++ /dev/null @@ -1,762 +0,0 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; -import { extend } from 'colord'; -import namesPlugin from 'colord/plugins/names'; - -/** - * WordPress dependencies - */ -import { useEntityProp, store as coreStore } from '@wordpress/core-data'; -import { - Fragment, - useEffect, - useRef, - useState, - useMemo, -} from '@wordpress/element'; -import { - BaseControl, - Button, - ExternalLink, - FocalPointPicker, - PanelBody, - PanelRow, - RangeControl, - ResizableBox, - Spinner, - TextareaControl, - ToggleControl, - ToolbarButton, - __experimentalUseCustomUnits as useCustomUnits, - __experimentalToolsPanelItem as ToolsPanelItem, - __experimentalUnitControl as UnitControl, - __experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue, -} from '@wordpress/components'; -import { compose, useInstanceId } from '@wordpress/compose'; -import { - BlockControls, - BlockIcon, - InspectorControls, - MediaPlaceholder, - MediaReplaceFlow, - withColors, - ColorPalette, - useBlockProps, - useSetting, - useInnerBlocksProps, - __experimentalUseGradient, - __experimentalPanelColorGradientSettings as PanelColorGradientSettings, - __experimentalBlockAlignmentMatrixControl as BlockAlignmentMatrixControl, - __experimentalBlockFullHeightAligmentControl as FullHeightAlignmentControl, - store as blockEditorStore, -} from '@wordpress/block-editor'; -import { __ } from '@wordpress/i18n'; -import { useSelect, useDispatch } from '@wordpress/data'; -import { postFeaturedImage, cover as icon } from '@wordpress/icons'; -import { isBlobURL } from '@wordpress/blob'; -import { store as noticesStore } from '@wordpress/notices'; - -/** - * Internal dependencies - */ -import { - ALLOWED_MEDIA_TYPES, - attributesFromMedia, - IMAGE_BACKGROUND_TYPE, - VIDEO_BACKGROUND_TYPE, - COVER_MIN_HEIGHT, - backgroundImageStyles, - dimRatioToClass, - isContentPositionCenter, - getPositionClassName, -} from './shared'; -import useCoverIsDark from './use-cover-is-dark'; - -extend( [ namesPlugin ] ); - -function getInnerBlocksTemplate( attributes ) { - return [ - [ - 'core/paragraph', - { - align: 'center', - placeholder: __( 'Write title…' ), - ...attributes, - }, - ], - ]; -} - -function CoverHeightInput( { - onChange, - onUnitChange, - unit = 'px', - value = '', -} ) { - const instanceId = useInstanceId( UnitControl ); - const inputId = `block-cover-height-input-${ instanceId }`; - const isPx = unit === 'px'; - - const units = useCustomUnits( { - availableUnits: useSetting( 'spacing.units' ) || [ - 'px', - 'em', - 'rem', - 'vw', - 'vh', - ], - defaultValues: { px: 430, '%': 20, em: 20, rem: 20, vw: 20, vh: 50 }, - } ); - - const handleOnChange = ( unprocessedValue ) => { - const inputValue = - unprocessedValue !== '' - ? parseFloat( unprocessedValue ) - : undefined; - - if ( isNaN( inputValue ) && inputValue !== undefined ) { - return; - } - onChange( inputValue ); - }; - - const computedValue = useMemo( () => { - const [ parsedQuantity ] = parseQuantityAndUnitFromRawValue( value ); - return [ parsedQuantity, unit ].join( '' ); - }, [ unit, value ] ); - - const min = isPx ? COVER_MIN_HEIGHT : 0; - - return ( - - - - ); -} - -const RESIZABLE_BOX_ENABLE_OPTION = { - top: false, - right: false, - bottom: true, - left: false, - topRight: false, - bottomRight: false, - bottomLeft: false, - topLeft: false, -}; - -function ResizableCover( { - className, - onResizeStart, - onResize, - onResizeStop, - ...props -} ) { - const [ isResizing, setIsResizing ] = useState( false ); - - return ( - { - onResizeStart( elt.clientHeight ); - onResize( elt.clientHeight ); - } } - onResize={ ( _event, _direction, elt ) => { - onResize( elt.clientHeight ); - if ( ! isResizing ) { - setIsResizing( true ); - } - } } - onResizeStop={ ( _event, _direction, elt ) => { - onResizeStop( elt.clientHeight ); - setIsResizing( false ); - } } - { ...props } - /> - ); -} - -function mediaPosition( { x, y } ) { - return `${ Math.round( x * 100 ) }% ${ Math.round( y * 100 ) }%`; -} - -/** - * Is the URL a temporary blob URL? A blob URL is one that is used temporarily while - * the media (image or video) is being uploaded and will not have an id allocated yet. - * - * @param {number} id The id of the media. - * @param {string} url The url of the media. - * - * @return {boolean} Is the URL a Blob URL. - */ -const isTemporaryMedia = ( id, url ) => ! id && isBlobURL( url ); - -function CoverPlaceholder( { - disableMediaButtons = false, - children, - onSelectMedia, - onError, - style, -} ) { - return ( - } - labels={ { - title: __( 'Cover' ), - instructions: __( - 'Drag and drop onto this block, upload, or select existing media from your library.' - ), - } } - onSelect={ onSelectMedia } - accept="image/*,video/*" - allowedTypes={ ALLOWED_MEDIA_TYPES } - disableMediaButtons={ disableMediaButtons } - onError={ onError } - style={ style } - > - { children } - - ); -} - -function CoverEdit( { - attributes, - clientId, - isSelected, - overlayColor, - setAttributes, - setOverlayColor, - toggleSelection, - context: { postId, postType }, -} ) { - const { - contentPosition, - id, - useFeaturedImage, - dimRatio, - focalPoint, - hasParallax, - isDark, - isRepeated, - minHeight, - minHeightUnit, - alt, - allowedBlocks, - templateLock, - } = attributes; - - const [ featuredImage ] = useEntityProp( - 'postType', - postType, - 'featured_media', - postId - ); - - const media = useSelect( - ( select ) => - featuredImage && - select( coreStore ).getMedia( featuredImage, { context: 'view' } ), - [ featuredImage ] - ); - const mediaUrl = media?.source_url; - - // instead of destructuring the attributes - // we define the url and background type - // depending on the value of the useFeaturedImage flag - // to preview in edit the dynamic featured image - const url = useFeaturedImage ? mediaUrl : attributes.url; - const backgroundType = useFeaturedImage - ? IMAGE_BACKGROUND_TYPE - : attributes.backgroundType; - - const { __unstableMarkNextChangeAsNotPersistent } = useDispatch( - blockEditorStore - ); - const { createErrorNotice } = useDispatch( noticesStore ); - const { - gradientClass, - gradientValue, - setGradient, - } = __experimentalUseGradient(); - const onSelectMedia = attributesFromMedia( setAttributes, dimRatio ); - const isUploadingMedia = isTemporaryMedia( id, url ); - - const [ prevMinHeightValue, setPrevMinHeightValue ] = useState( minHeight ); - const [ prevMinHeightUnit, setPrevMinHeightUnit ] = useState( - minHeightUnit - ); - const isMinFullHeight = minHeightUnit === 'vh' && minHeight === 100; - - const toggleMinFullHeight = () => { - if ( isMinFullHeight ) { - // If there aren't previous values, take the default ones. - if ( prevMinHeightUnit === 'vh' && prevMinHeightValue === 100 ) { - return setAttributes( { - minHeight: undefined, - minHeightUnit: undefined, - } ); - } - - // Set the previous values of height. - return setAttributes( { - minHeight: prevMinHeightValue, - minHeightUnit: prevMinHeightUnit, - } ); - } - - setPrevMinHeightValue( minHeight ); - setPrevMinHeightUnit( minHeightUnit ); - - // Set full height. - return setAttributes( { - minHeight: 100, - minHeightUnit: 'vh', - } ); - }; - - const toggleParallax = () => { - setAttributes( { - hasParallax: ! hasParallax, - ...( ! hasParallax ? { focalPoint: undefined } : {} ), - } ); - }; - - const toggleIsRepeated = () => { - setAttributes( { - isRepeated: ! isRepeated, - } ); - }; - - const toggleUseFeaturedImage = () => { - setAttributes( { - id: undefined, - url: undefined, - useFeaturedImage: ! useFeaturedImage, - dimRatio: dimRatio === 100 ? 50 : dimRatio, - backgroundType: useFeaturedImage - ? IMAGE_BACKGROUND_TYPE - : undefined, - } ); - }; - - const onUploadError = ( message ) => { - createErrorNotice( Array.isArray( message ) ? message[ 2 ] : message, { - type: 'snackbar', - } ); - }; - - const isDarkElement = useRef(); - const isCoverDark = useCoverIsDark( - url, - dimRatio, - overlayColor.color, - isDarkElement - ); - - useEffect( () => { - // This side-effect should not create an undo level. - __unstableMarkNextChangeAsNotPersistent(); - setAttributes( { isDark: isCoverDark } ); - }, [ isCoverDark ] ); - - const isImageBackground = IMAGE_BACKGROUND_TYPE === backgroundType; - const isVideoBackground = VIDEO_BACKGROUND_TYPE === backgroundType; - - const minHeightWithUnit = - minHeight && minHeightUnit - ? `${ minHeight }${ minHeightUnit }` - : minHeight; - - const isImgElement = ! ( hasParallax || isRepeated ); - - const style = { - ...( isImageBackground && ! isImgElement - ? backgroundImageStyles( url ) - : undefined ), - minHeight: minHeightWithUnit || undefined, - }; - - const bgStyle = { backgroundColor: overlayColor.color }; - const mediaStyle = { - objectPosition: - focalPoint && isImgElement - ? mediaPosition( focalPoint ) - : undefined, - }; - - const hasBackground = !! ( url || overlayColor.color || gradientValue ); - const showFocalPointPicker = - isVideoBackground || - ( isImageBackground && ( ! hasParallax || isRepeated ) ); - - const imperativeFocalPointPreview = ( value ) => { - const [ styleOfRef, property ] = isDarkElement.current - ? [ isDarkElement.current.style, 'objectPosition' ] - : [ ref.current.style, 'backgroundPosition' ]; - styleOfRef[ property ] = mediaPosition( value ); - }; - - const hasInnerBlocks = useSelect( - ( select ) => - select( blockEditorStore ).getBlock( clientId ).innerBlocks.length > - 0, - [ clientId ] - ); - - const controls = ( - <> - - - setAttributes( { - contentPosition: nextPosition, - } ) - } - isDisabled={ ! hasInnerBlocks } - /> - - - - - { ! useFeaturedImage && ( - - ) } - - - { !! url && ( - - { isImageBackground && ( - - - - - - ) } - { showFocalPointPicker && ( - - setAttributes( { - focalPoint: newFocalPoint, - } ) - } - /> - ) } - { ! useFeaturedImage && - url && - isImageBackground && - isImgElement && ( - - setAttributes( { alt: newAlt } ) - } - help={ - <> - - { __( - 'Describe the purpose of the image' - ) } - - { __( - 'Leave empty if the image is purely decorative.' - ) } - - } - /> - ) } - - - - - ) } - - - setAttributes( { - dimRatio: newDimRation, - } ) - } - min={ 0 } - max={ 100 } - step={ 10 } - required - /> - - - - !! minHeight } - label={ __( 'Minimum height' ) } - onDeselect={ () => - setAttributes( { - minHeight: undefined, - minHeightUnit: undefined, - } ) - } - resetAllFilter={ () => ( { - minHeight: undefined, - minHeightUnit: undefined, - } ) } - isShownByDefault={ true } - panelId={ clientId } - > - - setAttributes( { minHeight: newMinHeight } ) - } - onUnitChange={ ( nextUnit ) => - setAttributes( { - minHeightUnit: nextUnit, - } ) - } - /> - - - - ); - - const ref = useRef(); - const blockProps = useBlockProps( { ref } ); - - // Check for fontSize support before we pass a fontSize attribute to the innerBlocks. - const hasFontSizes = !! useSetting( 'typography.fontSizes' )?.length; - const innerBlocksTemplate = getInnerBlocksTemplate( { - fontSize: hasFontSizes ? 'large' : undefined, - } ); - - const innerBlocksProps = useInnerBlocksProps( - { - className: 'wp-block-cover__inner-container', - }, - { - template: innerBlocksTemplate, - templateInsertUpdatesSelection: true, - allowedBlocks, - templateLock, - } - ); - - if ( ! hasInnerBlocks && ! hasBackground ) { - return ( - <> - { controls } -
- -
- -
-
- { - setAttributes( { minHeightUnit: 'px' } ); - toggleSelection( false ); - } } - onResize={ ( value ) => { - setAttributes( { minHeight: value } ); - } } - onResizeStop={ ( newMinHeight ) => { - toggleSelection( true ); - setAttributes( { minHeight: newMinHeight } ); - } } - showHandle={ isSelected } - /> -
- - ); - } - - const classes = classnames( - { - 'is-dark-theme': isDark, - 'is-light': ! isDark, - 'is-transient': isUploadingMedia, - 'has-parallax': hasParallax, - 'is-repeated': isRepeated, - 'has-custom-content-position': ! isContentPositionCenter( - contentPosition - ), - }, - getPositionClassName( contentPosition ) - ); - - return ( - <> - { controls } -
- { - setAttributes( { minHeightUnit: 'px' } ); - toggleSelection( false ); - } } - onResize={ ( value ) => { - setAttributes( { minHeight: value } ); - } } - onResizeStop={ ( newMinHeight ) => { - toggleSelection( true ); - setAttributes( { minHeight: newMinHeight } ); - } } - showHandle={ isSelected } - /> - -