From 758a22b5228adaff01febddf3c22d3038dafe924 Mon Sep 17 00:00:00 2001 From: Andrei Draganescu Date: Tue, 3 Dec 2019 17:00:49 +0200 Subject: [PATCH 1/3] adds a media replace flow component to the image block --- packages/block-editor/README.md | 4 + packages/block-editor/src/components/index.js | 1 + .../components/media-replace-flow/index.js | 199 ++++++++++++++++++ .../components/media-replace-flow/style.scss | 72 +++++++ packages/block-editor/src/style.scss | 1 + packages/block-library/src/image/edit.js | 118 ++++------- 6 files changed, 320 insertions(+), 75 deletions(-) create mode 100644 packages/block-editor/src/components/media-replace-flow/index.js create mode 100644 packages/block-editor/src/components/media-replace-flow/style.scss diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 213e7d318cc09..3acda4b4b5273 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -320,6 +320,10 @@ _Related_ - +# **MediaReplaceFlow** + +Undocumented declaration. + # **MediaUpload** _Related_ diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index 1fd101c30082d..1fb22e4200805 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -28,6 +28,7 @@ export { default as InnerBlocks } from './inner-blocks'; export { default as InspectorAdvancedControls } from './inspector-advanced-controls'; export { default as InspectorControls } from './inspector-controls'; export { default as __experimentalLinkControl } from './link-control'; +export { default as MediaReplaceFlow } from './media-replace-flow'; export { default as MediaPlaceholder } from './media-placeholder'; export { default as MediaUpload } from './media-upload'; export { default as MediaUploadCheck } from './media-upload/check'; diff --git a/packages/block-editor/src/components/media-replace-flow/index.js b/packages/block-editor/src/components/media-replace-flow/index.js new file mode 100644 index 0000000000000..466dcce5aa913 --- /dev/null +++ b/packages/block-editor/src/components/media-replace-flow/index.js @@ -0,0 +1,199 @@ +/** + * WordPress dependencies + */ +import { useState, createRef } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { speak } from '@wordpress/a11y'; +import { + FormFileUpload, + NavigableMenu, + MenuItem, + Toolbar, + Button, + Popover, + withNotices, +} from '@wordpress/components'; +import { + LEFT, + RIGHT, + UP, + DOWN, + BACKSPACE, + ENTER, +} from '@wordpress/keycodes'; +import { useSelect } from '@wordpress/data'; +import { compose } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import MediaUpload from '../media-upload'; +import MediaUploadCheck from '../media-upload/check'; +import LinkEditor from '../url-popover/link-editor'; +import LinkViewer from '../url-popover/link-viewer'; + +const MediaReplaceFlow = ( + { + mediaURL, + allowedTypes, + accept, + onSelect, + onSelectURL, + onError, + name = __( 'Replace' ), + } +) => { + const [ showURLInput, setShowURLInput ] = useState( false ); + const [ showEditURLInput, setShowEditURLInput ] = useState( false ); + const [ mediaURLValue, setMediaURLValue ] = useState( mediaURL ); + const [ showMediaReplaceOptions, setShowMediaReplaceOptions ] = useState( false ); + const mediaUpload = useSelect( ( select ) => { + return select( 'core/block-editor' ).getSettings().mediaUpload; + } ); + const editMediaButtonRef = createRef(); + + const stopPropagation = ( event ) => { + event.stopPropagation(); + }; + + const stopPropagationRelevantKeys = ( event ) => { + if ( [ LEFT, DOWN, RIGHT, UP, BACKSPACE, ENTER ].indexOf( event.keyCode ) > -1 ) { + // Stop the key event from propagating up to ObserveTyping.startTypingInTextField. + event.stopPropagation(); + } + }; + + const selectMedia = ( media ) => { + onSelect( media ); + setMediaURLValue( media.url ); + speak( __( 'The media file has been replaced' ) ); + }; + + const uploadFiles = ( event ) => { + const files = event.target.files; + const setMedia = ( [ media ] ) => { + setShowMediaReplaceOptions( false ); + selectMedia( media ); + }; + mediaUpload( { + allowedTypes, + filesList: files, + onFileChange: setMedia, + onError, + } ); + }; + + const onClose = () => { + editMediaButtonRef.current.focus(); + }; + + const onClickOutside = () => ( setShowMediaReplaceOptions( false ) ); + + const openOnArrowDown = ( event ) => { + if ( event.keyCode === DOWN ) { + event.preventDefault(); + event.stopPropagation(); + event.target.click(); + } + }; + + let urlInputUIContent; + if ( showEditURLInput ) { + urlInputUIContent = ( + ( setMediaURLValue( url ) ) } + onSubmit={ ( event ) => { + event.preventDefault(); + onSelectURL( mediaURLValue ); + setShowEditURLInput( ! showEditURLInput ); + editMediaButtonRef.current.focus(); + } } + /> + ); + } else { + urlInputUIContent = ( + ( setShowEditURLInput( ! showEditURLInput ) ) } + /> + ); + } + + return ( + selectMedia( media ) } + onClose={ () => setShowMediaReplaceOptions( true ) } + allowedTypes={ allowedTypes } + render={ ( { open } ) => ( + + + { showMediaReplaceOptions && + + + + { __( 'Open Media Library' ) } + + + { + return ( + { + openFileDialog(); + } } + > + { __( 'Upload' ) } + + ); + } } + /> + + ( setShowURLInput( ! showURLInput ) ) } + aria-expanded={ showURLInput } + > +
{ __( 'Insert from URL' ) }
+
+
+ { showURLInput &&
+ { urlInputUIContent } +
} +
+ } +
+ ) } + /> + ); +}; + +export default compose( + withNotices, +)( MediaReplaceFlow ); diff --git a/packages/block-editor/src/components/media-replace-flow/style.scss b/packages/block-editor/src/components/media-replace-flow/style.scss new file mode 100644 index 0000000000000..63ca56cb1cf6d --- /dev/null +++ b/packages/block-editor/src/components/media-replace-flow/style.scss @@ -0,0 +1,72 @@ +.media-replace-flow .components-dropdown-menu__indicator { + margin-left: 4px; + + .components-dropdown-menu.media-flow_toolbar { + .components-dropdown-menu__label { + margin-right: 6px; + margin-left: 2px; + } + } +} + +.media-replace-flow__options.components-popover:not(.is-mobile) { + + .components-popover__content { + // this is a safari problem that shows scrollbars + // when display:flex and max-width are used together + overflow-x: hidden; + } + + .block-editor-media-flow__url-input { + + padding: 0 15px 10px 25px; + + .components-external-link__icon { + position: absolute; + right: 50px; + bottom: 22px; + } + + input { + max-width: 169px; + border: 1px solid $dark-gray-500; + border-radius: 4px; + } + + .block-editor-url-popover__link-viewer-url { + padding-right: 10px; + padding-top: 3px; + max-width: 169px; + } + + // Mimic toolbar component styles for the icons in this popover. + .components-icon-button { + padding: 5px; + width: 40px; + height: 40px; + + > svg { + padding: 5px; + border-radius: $radius-round-rectangle; + height: 30px; + width: 30px; + } + + &:not(:disabled):not([aria-disabled="true"]):not(.is-default):hover { + box-shadow: none; + + > svg { + @include formatting-button-style__hover; + } + } + + &:not(:disabled):focus { + box-shadow: none; + + > svg { + @include formatting-button-style__focus; + } + } + } + } +} diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss index 1b0cd5f73c38e..417b11c66105b 100644 --- a/packages/block-editor/src/style.scss +++ b/packages/block-editor/src/style.scss @@ -25,6 +25,7 @@ @import "./components/inserter-with-shortcuts/style.scss"; @import "./components/inserter/style.scss"; @import "./components/inserter-list-item/style.scss"; +@import "./components/media-replace-flow/style.scss"; @import "./components/media-placeholder/style.scss"; @import "./components/multi-selection-inspector/style.scss"; @import "./components/panel-color-settings/style.scss"; diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index f8b964e18e617..fc5286295dcab 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -52,6 +52,7 @@ import { InspectorControls, InspectorAdvancedControls, MediaPlaceholder, + MediaReplaceFlow, URLPopover, RichText, } from '@wordpress/block-editor'; @@ -64,13 +65,12 @@ import { import { __, sprintf } from '@wordpress/i18n'; import { getPath } from '@wordpress/url'; import { withViewportMatch } from '@wordpress/viewport'; -import { speak } from '@wordpress/a11y'; /** * Internal dependencies */ import { createUpgradedEmbedBlock } from '../embed/util'; -import icon, { editImageIcon } from './icon'; +import icon from './icon'; import ImageSize from './image-size'; import { getUpdatedLinkTargetSettings, removeNewTabRel } from './utils'; @@ -265,7 +265,7 @@ const ImageURLInputUI = ( { }; export class ImageEdit extends Component { - constructor( { attributes } ) { + constructor() { super( ...arguments ); this.updateAlt = this.updateAlt.bind( this ); this.updateAlignment = this.updateAlignment.bind( this ); @@ -283,14 +283,12 @@ export class ImageEdit extends Component { this.onSetNewTab = this.onSetNewTab.bind( this ); this.onSetTitle = this.onSetTitle.bind( this ); this.getFilename = this.getFilename.bind( this ); - this.toggleIsEditing = this.toggleIsEditing.bind( this ); this.onUploadError = this.onUploadError.bind( this ); this.onImageError = this.onImageError.bind( this ); this.getLinkDestinations = this.getLinkDestinations.bind( this ); this.state = { captionFocused: false, - isEditing: ! attributes.url, }; } @@ -314,7 +312,6 @@ export class ImageEdit extends Component { allowedTypes: ALLOWED_MEDIA_TYPES, onError: ( message ) => { noticeOperations.createErrorNotice( message ); - this.setState( { isEditing: true } ); }, } ); } @@ -340,9 +337,6 @@ export class ImageEdit extends Component { const { noticeOperations } = this.props; noticeOperations.removeAllNotices(); noticeOperations.createErrorNotice( message ); - this.setState( { - isEditing: true, - } ); } onSelectImage( media ) { @@ -357,10 +351,6 @@ export class ImageEdit extends Component { return; } - this.setState( { - isEditing: false, - } ); - const { id, url, alt, caption, linkDestination } = this.props.attributes; let mediaAttributes = pickRelevantMediaFiles( media ); @@ -411,10 +401,6 @@ export class ImageEdit extends Component { sizeSlug: DEFAULT_SIZE_SLUG, } ); } - - this.setState( { - isEditing: false, - } ); } onImageError( url ) { @@ -552,24 +538,12 @@ export class ImageEdit extends Component { ]; } - toggleIsEditing() { - this.setState( { - isEditing: ! this.state.isEditing, - } ); - if ( this.state.isEditing ) { - speak( __( 'You are now viewing the image in the image block.' ) ); - } else { - speak( __( 'You are now editing the image in the image block.' ) ); - } - } - getImageSizeOptions() { const { imageSizes } = this.props; return map( imageSizes, ( { name, slug } ) => ( { value: slug, label: name } ) ); } render() { - const { isEditing } = this.state; const { attributes, setAttributes, @@ -607,48 +581,45 @@ export class ImageEdit extends Component { value={ align } onChange={ this.updateAlignment } /> + { url && } { url && ( - <> - - - - - - - - - - } - /> - - + + + + + + + } + /> + ) } ); @@ -670,18 +641,16 @@ export class ImageEdit extends Component { labels={ labels } onSelect={ this.onSelectImage } onSelectURL={ this.onSelectURL } - onDoubleClick={ this.toggleIsEditing } - onCancel={ !! url && this.toggleIsEditing } notices={ noticeUI } onError={ this.onUploadError } accept="image/*" allowedTypes={ ALLOWED_MEDIA_TYPES } value={ { id, src } } mediaPreview={ mediaPreview } - disableMediaButtons={ ! isEditing && url } + disableMediaButtons={ url } /> ); - if ( isEditing || ! url ) { + if ( ! url ) { return ( <> { controls } @@ -832,7 +801,6 @@ export class ImageEdit extends Component { { this.onImageError( url ) } /> From 6994c1d7982d083099672ba0ae30f9fe93cf955a Mon Sep 17 00:00:00 2001 From: Andrei Draganescu Date: Wed, 4 Dec 2019 12:34:20 +0200 Subject: [PATCH 2/3] fixes bug in chrome where options would be scrolled out of view --- .../src/components/media-replace-flow/index.js | 11 +++++++++-- .../src/components/media-replace-flow/style.scss | 12 ++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/components/media-replace-flow/index.js b/packages/block-editor/src/components/media-replace-flow/index.js index 466dcce5aa913..72a03b843f78f 100644 --- a/packages/block-editor/src/components/media-replace-flow/index.js +++ b/packages/block-editor/src/components/media-replace-flow/index.js @@ -69,6 +69,12 @@ const MediaReplaceFlow = ( speak( __( 'The media file has been replaced' ) ); }; + const selectURL = ( newURL ) => { + onSelectURL( newURL ); + setShowEditURLInput( false ); + setShowURLInput( false ); + }; + const uploadFiles = ( event ) => { const files = event.target.files; const setMedia = ( [ media ] ) => { @@ -84,6 +90,8 @@ const MediaReplaceFlow = ( }; const onClose = () => { + setShowEditURLInput( false ); + setShowURLInput( false ); editMediaButtonRef.current.focus(); }; @@ -109,8 +117,7 @@ const MediaReplaceFlow = ( onChangeInputValue={ ( url ) => ( setMediaURLValue( url ) ) } onSubmit={ ( event ) => { event.preventDefault(); - onSelectURL( mediaURLValue ); - setShowEditURLInput( ! showEditURLInput ); + selectURL( mediaURLValue ); editMediaButtonRef.current.focus(); } } /> diff --git a/packages/block-editor/src/components/media-replace-flow/style.scss b/packages/block-editor/src/components/media-replace-flow/style.scss index 63ca56cb1cf6d..e5f8a559860d2 100644 --- a/packages/block-editor/src/components/media-replace-flow/style.scss +++ b/packages/block-editor/src/components/media-replace-flow/style.scss @@ -23,8 +23,9 @@ .components-external-link__icon { position: absolute; - right: 50px; - bottom: 22px; + right: -4px; + bottom: 5px; + margin-right: 2px; } input { @@ -34,9 +35,11 @@ } .block-editor-url-popover__link-viewer-url { - padding-right: 10px; + padding-right: 15px; padding-top: 3px; - max-width: 169px; + max-width: 179px; + position: relative; + margin-right: 0; } // Mimic toolbar component styles for the icons in this popover. @@ -44,6 +47,7 @@ padding: 5px; width: 40px; height: 40px; + padding-left: 0; > svg { padding: 5px; From 8cdbe0f8b91145e5aa0170b9865a13ea25d0089e Mon Sep 17 00:00:00 2001 From: Andrei Draganescu Date: Sat, 7 Dec 2019 13:58:20 +0200 Subject: [PATCH 3/3] removed hiding the URL viewer on popover close --- .../block-editor/src/components/media-replace-flow/index.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/block-editor/src/components/media-replace-flow/index.js b/packages/block-editor/src/components/media-replace-flow/index.js index 72a03b843f78f..77949fec4ff2e 100644 --- a/packages/block-editor/src/components/media-replace-flow/index.js +++ b/packages/block-editor/src/components/media-replace-flow/index.js @@ -72,7 +72,6 @@ const MediaReplaceFlow = ( const selectURL = ( newURL ) => { onSelectURL( newURL ); setShowEditURLInput( false ); - setShowURLInput( false ); }; const uploadFiles = ( event ) => { @@ -90,8 +89,6 @@ const MediaReplaceFlow = ( }; const onClose = () => { - setShowEditURLInput( false ); - setShowURLInput( false ); editMediaButtonRef.current.focus(); };