From 6e3187a467560326ec9c2a22d189cdb76bafe7a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Sch=C3=B6ldstr=C3=B6m?= Date: Wed, 10 Jun 2020 10:23:23 -0300 Subject: [PATCH 1/9] Refactor Media & Text edit method to be a functional component --- packages/block-library/src/media-text/edit.js | 409 ++++++++---------- 1 file changed, 184 insertions(+), 225 deletions(-) diff --git a/packages/block-library/src/media-text/edit.js b/packages/block-library/src/media-text/edit.js index 8a5b6383fee8e..67e037e4f5d24 100644 --- a/packages/block-library/src/media-text/edit.js +++ b/packages/block-library/src/media-text/edit.js @@ -8,8 +8,8 @@ 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 +17,6 @@ import { InspectorControls, __experimentalImageURLInputUI as ImageURLInputUI, } from '@wordpress/block-editor'; -import { Component } from '@wordpress/element'; import { PanelBody, TextareaControl, @@ -56,22 +55,9 @@ 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( { setAttributes, attributes } ) { + return ( media ) => { + const { linkDestination, href } = attributes; let mediaType; let src; @@ -122,228 +108,201 @@ class MediaTextEdit extends Component { href: newHref, focalPoint: undefined, } ); - } + }; +} - onWidthChange( width ) { - this.setState( { - mediaWidth: applyWidthConstraints( width ), - } ); - } +function MediaTextEdit( { + attributes, + className, + isSelected, + setAttributes, + clientId, +} ) { + const { + mediaAlt, + mediaId, + mediaPosition, + mediaType, + mediaUrl, + mediaWidth, + verticalAlignment, + imageFill, + focalPoint, + isStackedOnMobile, + rel, + href, + linkTarget, + linkClass, + linkDestination, + } = attributes; + + const image = useSelect( + ( select ) => { + const { getMedia } = select( 'core' ); + return { + image: mediaId && isSelected ? getMedia( mediaId ) : null, + }; + }, + [ clientId ] + ); + + const [ temporaryMediaWidth, setTemporaryMediaWidth ] = useState( null ); - onSetHref( props ) { - this.props.setAttributes( props ); - } + const onSelectMedia = attributesFromMedia( { setAttributes, attributes } ); - 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; From d8acb0400fc86f4c315a5b09fc6c861825544355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Sch=C3=B6ldstr=C3=B6m?= Date: Wed, 10 Jun 2020 12:02:54 -0300 Subject: [PATCH 2/9] Refactor Media Container to be a functional component --- .../block-library/src/media-text/editor.scss | 1 - .../src/media-text/media-container.js | 232 ++++++++---------- 2 files changed, 108 insertions(+), 125 deletions(-) diff --git a/packages/block-library/src/media-text/editor.scss b/packages/block-library/src/media-text/editor.scss index 2fd4f7c886fbe..273c7f50a56bb 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 0d29cd4b089f8..5fcdc332c8708 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,7 +13,6 @@ 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'; @@ -43,141 +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( { onSelectMedia, mediaUrl, mediaId } ) { + return ( + + + + ); +} + +function PlaceholderContainer( { + onSelectMedia, + className, + noticeUI, + noticeOperations, +} ) { + 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 { + mediaPosition, + mediaUrl, + mediaType, + mediaWidth, + commitWidthChange, + onWidthChange, + toggleSelection, + isSelected, + isStackedOnMobile, + className, + imageFill, + focalPoint, + mediaId, + mediaAlt, + onSelectMedia, + } = props; + + 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: () =>