diff --git a/packages/block-library/src/media-text/edit.js b/packages/block-library/src/media-text/edit.js index 8a5b6383fee8eb..e37fc5a67fa1c4 100644 --- a/packages/block-library/src/media-text/edit.js +++ b/packages/block-library/src/media-text/edit.js @@ -2,14 +2,13 @@ * External dependencies */ import classnames from 'classnames'; -import { get } from 'lodash'; /** * WordPress dependencies */ import { __, _x } from '@wordpress/i18n'; -import { compose } from '@wordpress/compose'; -import { withSelect } from '@wordpress/data'; +import { useSelect } from '@wordpress/data'; +import { useState } from '@wordpress/element'; import { BlockControls, BlockVerticalAlignmentToolbar, @@ -17,7 +16,6 @@ import { InspectorControls, __experimentalImageURLInputUI as ImageURLInputUI, } from '@wordpress/block-editor'; -import { Component } from '@wordpress/element'; import { PanelBody, TextareaControl, @@ -56,23 +54,11 @@ const applyWidthConstraints = ( width ) => const LINK_DESTINATION_MEDIA = 'media'; const LINK_DESTINATION_ATTACHMENT = 'attachment'; -class MediaTextEdit extends Component { - constructor() { - super( ...arguments ); - - this.onSelectMedia = this.onSelectMedia.bind( this ); - this.onWidthChange = this.onWidthChange.bind( this ); - this.commitWidthChange = this.commitWidthChange.bind( this ); - this.state = { - mediaWidth: null, - }; - this.onSetHref = this.onSetHref.bind( this ); - } - - onSelectMedia( media ) { - const { setAttributes } = this.props; - const { linkDestination, href } = this.props.attributes; - +function attributesFromMedia( { + attributes: { linkDestination, href }, + setAttributes, +} ) { + return ( media ) => { let mediaType; let src; // for media selections originated from a file upload. @@ -92,13 +78,9 @@ class MediaTextEdit extends Component { if ( mediaType === 'image' ) { // Try the "large" size URL, falling back to the "full" size URL below. src = - get( media, [ 'sizes', 'large', 'url' ] ) || - get( media, [ - 'media_details', - 'sizes', - 'large', - 'source_url', - ] ); + media.sizes?.large?.url || + // eslint-disable-next-line camelcase + media.media_details?.sizes?.large?.source_url; } let newHref = href; @@ -122,228 +104,191 @@ class MediaTextEdit extends Component { href: newHref, focalPoint: undefined, } ); - } + }; +} - onWidthChange( width ) { - this.setState( { - mediaWidth: applyWidthConstraints( width ), - } ); - } +function MediaTextEdit( { attributes, className, isSelected, setAttributes } ) { + const { + focalPoint, + href, + imageFill, + isStackedOnMobile, + linkClass, + linkDestination, + linkTarget, + mediaAlt, + mediaId, + mediaPosition, + mediaType, + mediaUrl, + mediaWidth, + rel, + verticalAlignment, + } = attributes; + + const image = useSelect( + ( select ) => + mediaId && isSelected ? select( 'core' ).getMedia( mediaId ) : null, + [ isSelected, mediaId ] + ); + + const [ temporaryMediaWidth, setTemporaryMediaWidth ] = useState( null ); - onSetHref( props ) { - this.props.setAttributes( props ); - } + const onSelectMedia = attributesFromMedia( { attributes, setAttributes } ); - commitWidthChange( width ) { - const { setAttributes } = this.props; + const onSetHref = ( props ) => { + setAttributes( props ); + }; + const onWidthChange = ( width ) => { + setTemporaryMediaWidth( applyWidthConstraints( width ) ); + }; + const commitWidthChange = ( width ) => { setAttributes( { mediaWidth: applyWidthConstraints( width ), } ); - this.setState( { - mediaWidth: null, - } ); - } + setTemporaryMediaWidth( applyWidthConstraints( width ) ); + }; - renderMediaArea() { - const { attributes, isSelected } = this.props; - const { - mediaAlt, - mediaId, - mediaPosition, - mediaType, - mediaUrl, - mediaWidth, - imageFill, - focalPoint, - isStackedOnMobile, - } = attributes; - return ( - setAttributes( { mediaPosition: 'left' } ), + }, + { + icon: pullRight, + title: __( 'Show media on right' ), + isActive: mediaPosition === 'right', + onClick: () => setAttributes( { mediaPosition: 'right' } ), + }, + ]; + const onMediaAltChange = ( newMediaAlt ) => { + setAttributes( { mediaAlt: newMediaAlt } ); + }; + const onVerticalAlignmentChange = ( alignment ) => { + setAttributes( { verticalAlignment: alignment } ); + }; + const mediaTextGeneralSettings = ( + + + setAttributes( { + isStackedOnMobile: ! isStackedOnMobile, + } ) + } /> - ); - } - - render() { - const { - attributes, - className, - isSelected, - setAttributes, - image, - } = this.props; - const { - isStackedOnMobile, - mediaAlt, - mediaPosition, - mediaType, - mediaWidth, - verticalAlignment, - mediaUrl, - imageFill, - focalPoint, - rel, - href, - linkTarget, - linkClass, - linkDestination, - } = attributes; - - const temporaryMediaWidth = this.state.mediaWidth; - const classNames = classnames( className, { - 'has-media-on-the-right': 'right' === mediaPosition, - 'is-selected': isSelected, - 'is-stacked-on-mobile': isStackedOnMobile, - [ `is-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment, - 'is-image-fill': imageFill, - } ); - const widthString = `${ temporaryMediaWidth || mediaWidth }%`; - const gridTemplateColumns = - 'right' === mediaPosition - ? `1fr ${ widthString }` - : `${ widthString } 1fr`; - const style = { - gridTemplateColumns, - msGridColumns: gridTemplateColumns, - }; - const toolbarControls = [ - { - icon: pullLeft, - title: __( 'Show media on left' ), - isActive: mediaPosition === 'left', - onClick: () => setAttributes( { mediaPosition: 'left' } ), - }, - { - icon: pullRight, - title: __( 'Show media on right' ), - isActive: mediaPosition === 'right', - onClick: () => setAttributes( { mediaPosition: 'right' } ), - }, - ]; - const onMediaAltChange = ( newMediaAlt ) => { - setAttributes( { mediaAlt: newMediaAlt } ); - }; - const onVerticalAlignmentChange = ( alignment ) => { - setAttributes( { verticalAlignment: alignment } ); - }; - const mediaTextGeneralSettings = ( - + { mediaType === 'image' && ( setAttributes( { - isStackedOnMobile: ! isStackedOnMobile, + imageFill: ! imageFill, } ) } /> + ) } + { imageFill && ( + + setAttributes( { focalPoint: value } ) + } + /> + ) } + { mediaType === 'image' && ( + + + { __( 'Describe the purpose of the image' ) } + + { __( + 'Leave empty if the image is purely decorative.' + ) } + + } + /> + ) } + + ); + + return ( + <> + { mediaTextGeneralSettings } + + + { mediaType === 'image' && ( - - setAttributes( { - imageFill: ! imageFill, - } ) - } - /> - ) } - { imageFill && ( - - setAttributes( { focalPoint: value } ) - } - /> - ) } - { mediaType === 'image' && ( - - - { __( - 'Describe the purpose of the image' - ) } - - { __( - 'Leave empty if the image is purely decorative.' - ) } - - } - /> + + + ) } - - ); - - return ( - <> - - { mediaTextGeneralSettings } - - - - - { mediaType === 'image' && ( - - - - ) } - -
- { this.renderMediaArea() } - -
- - ); - } + +
+ + +
+ + ); } -export default compose( [ - withSelect( ( select, props ) => { - const { getMedia } = select( 'core' ); - const { - attributes: { mediaId }, - isSelected, - } = props; - return { - image: mediaId && isSelected ? getMedia( mediaId ) : null, - }; - } ), -] )( MediaTextEdit ); +export default MediaTextEdit; diff --git a/packages/block-library/src/media-text/editor.scss b/packages/block-library/src/media-text/editor.scss index 2fd4f7c886fbef..273c7f50a56bb9 100644 --- a/packages/block-library/src/media-text/editor.scss +++ b/packages/block-library/src/media-text/editor.scss @@ -81,4 +81,3 @@ } } } - diff --git a/packages/block-library/src/media-text/media-container.js b/packages/block-library/src/media-text/media-container.js index 0d29cd4b089f84..363f4f9b43f2e6 100644 --- a/packages/block-library/src/media-text/media-container.js +++ b/packages/block-library/src/media-text/media-container.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import { noop } from 'lodash'; + /** * WordPress dependencies */ @@ -8,10 +13,9 @@ import { MediaPlaceholder, MediaReplaceFlow, } from '@wordpress/block-editor'; -import { Component } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; -import { compose, useViewportMatch } from '@wordpress/compose'; -import { withDispatch } from '@wordpress/data'; +import { useViewportMatch } from '@wordpress/compose'; +import { useDispatch } from '@wordpress/data'; /** * Internal dependencies @@ -43,150 +47,121 @@ function ResizableBoxContainer( { isSelected, isStackedOnMobile, ...props } ) { /> ); } -class MediaContainer extends Component { - constructor() { - super( ...arguments ); - this.onUploadError = this.onUploadError.bind( this ); - } - onUploadError( message ) { - const { noticeOperations } = this.props; +function ToolbarEditButton( { mediaId, mediaUrl, onSelectMedia } ) { + return ( + + + + ); +} + +function PlaceholderContainer( { + className, + noticeOperations, + noticeUI, + onSelectMedia, +} ) { + const onUploadError = ( message ) => { noticeOperations.removeAllNotices(); noticeOperations.createErrorNotice( message ); - } + }; + + return ( + } + labels={ { + title: __( 'Media area' ), + } } + className={ className } + onSelect={ onSelectMedia } + accept="image/*,video/*" + allowedTypes={ ALLOWED_MEDIA_TYPES } + notices={ noticeUI } + onError={ onUploadError } + /> + ); +} + +function MediaContainer( props ) { + const { + className, + commitWidthChange, + focalPoint, + imageFill, + isSelected, + isStackedOnMobile, + mediaAlt, + mediaId, + mediaPosition, + mediaType, + mediaUrl, + mediaWidth, + onSelectMedia, + onWidthChange, + } = props; + + const { toggleSelection } = useDispatch( 'core/block-editor' ); + + if ( mediaType && 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: mediaPosition === 'left', + left: mediaPosition === 'right', + }; + + const backgroundStyles = + mediaType === 'image' && imageFill + ? imageFillStyles( mediaUrl, focalPoint ) + : {}; + + const mediaTypeRenderers = { + image: () => {, + video: () =>