diff --git a/packages/block-editor/src/components/media-placeholder/index.js b/packages/block-editor/src/components/media-placeholder/index.js
index d972aeca06bd7..bdfdb7a45dc4d 100644
--- a/packages/block-editor/src/components/media-placeholder/index.js
+++ b/packages/block-editor/src/components/media-placeholder/index.js
@@ -1,7 +1,14 @@
/**
* External dependencies
*/
-import { every, get, noop, startsWith, defaultTo } from 'lodash';
+import {
+ defaultTo,
+ every,
+ get,
+ isArray,
+ noop,
+ startsWith,
+} from 'lodash';
import classnames from 'classnames';
/**
@@ -103,8 +110,28 @@ export class MediaPlaceholder extends Component {
}
onFilesUpload( files ) {
- const { onSelect, multiple, onError, allowedTypes, mediaUpload } = this.props;
- const setMedia = multiple ? onSelect : ( [ media ] ) => onSelect( media );
+ const {
+ addToGallery,
+ allowedTypes,
+ mediaUpload,
+ multiple,
+ onError,
+ onSelect,
+ value = [],
+ } = this.props;
+ let setMedia;
+ if ( multiple ) {
+ if ( addToGallery ) {
+ const currentValue = value;
+ setMedia = ( newMedia ) => {
+ onSelect( currentValue.concat( newMedia ) );
+ };
+ } else {
+ setMedia = onSelect;
+ }
+ } else {
+ setMedia = ( [ media ] ) => onSelect( media );
+ }
mediaUpload( {
allowedTypes,
filesList: files,
@@ -124,18 +151,21 @@ export class MediaPlaceholder extends Component {
render() {
const {
accept,
- icon,
+ addToGallery,
+ allowedTypes = [],
className,
+ dropZoneUIOnly,
+ hasUploadPermissions,
+ icon,
+ isAppender,
labels = {},
- onSelect,
- value = {},
- onSelectURL,
- onHTMLDrop = noop,
+ mediaUpload,
multiple = false,
notices,
- allowedTypes = [],
- hasUploadPermissions,
- mediaUpload,
+ onHTMLDrop = noop,
+ onSelect,
+ onSelectURL,
+ value = {},
} = this.props;
const {
@@ -143,20 +173,20 @@ export class MediaPlaceholder extends Component {
src,
} = this.state;
- let instructions = labels.instructions || '';
- let title = labels.title || '';
+ let instructions = labels.instructions;
+ let title = labels.title;
if ( ! hasUploadPermissions && ! onSelectURL ) {
instructions = __( 'To edit this block, you need permission to upload media.' );
}
- if ( ! instructions || ! title ) {
+ if ( instructions === undefined || title === undefined ) {
const isOneType = 1 === allowedTypes.length;
const isAudio = isOneType && 'audio' === allowedTypes[ 0 ];
const isImage = isOneType && 'image' === allowedTypes[ 0 ];
const isVideo = isOneType && 'video' === allowedTypes[ 0 ];
- if ( ! instructions ) {
+ if ( instructions === undefined ) {
if ( hasUploadPermissions ) {
instructions = __( 'Drag a media file, upload a new one or select a file from your library.' );
@@ -180,7 +210,7 @@ export class MediaPlaceholder extends Component {
}
}
- if ( ! title ) {
+ if ( title === undefined ) {
title = __( 'Media' );
if ( isAudio ) {
@@ -193,24 +223,47 @@ export class MediaPlaceholder extends Component {
}
}
+ const dropZone = (
+
+ );
+
+ if ( dropZoneUIOnly ) {
+ return (
+
+ { dropZone }
+
+ );
+ }
+
return (
{ !! mediaUpload && (
-
+ { dropZone }
) }
(
-
- ) }
+ value={
+ isArray( value ) ?
+ value.map( ( { id } ) => id ) :
+ value.id
+ }
+ render={ ( { open } ) => {
+ return (
+
+ );
+ } }
/>
{ onSelectURL && (
diff --git a/packages/block-editor/src/components/media-placeholder/style.scss b/packages/block-editor/src/components/media-placeholder/style.scss
index 7cc50c523885a..15ee92a684e6d 100644
--- a/packages/block-editor/src/components/media-placeholder/style.scss
+++ b/packages/block-editor/src/components/media-placeholder/style.scss
@@ -45,3 +45,23 @@
.components-form-file-upload .block-editor-media-placeholder__button {
margin-right: $grid-size-small;
}
+
+.block-editor-media-placeholder.is-appender {
+ min-height: 100px;
+ background-color: unset;
+ outline: $border-width dashed $dark-gray-150;
+
+ &:hover {
+ outline: $border-width dashed $dark-gray-500;
+ }
+
+ .block-editor-media-placeholder__upload-button {
+ margin-right: $grid-size-small;
+ &.components-button:hover,
+ &.components-button:focus {
+ box-shadow: none;
+ border: $border-width solid $dark-gray-500;
+ }
+ }
+
+}
diff --git a/packages/block-editor/src/components/media-upload/README.md b/packages/block-editor/src/components/media-upload/README.md
index eb2f75cbdd8af..6e0a67d9f187c 100644
--- a/packages/block-editor/src/components/media-upload/README.md
+++ b/packages/block-editor/src/components/media-upload/README.md
@@ -101,6 +101,25 @@ CSS class added to the media modal frame.
- Type: `String`
- Required: No
+
+### addToGallery
+
+If true, the gallery media modal opens directly in the media library where the user can add additional images.
+If false the gallery media modal opens in the edit mode where the user can edit existing images, by reordering them, remove them, or change their attributes.
+Only applies if `gallery === true`.
+
+- Type: `Boolean`
+- Required: No
+- Default: `false`
+
+### gallery
+
+If true, the component will initiate all the states required to represent a gallery. By default, the media modal opens in the gallery edit frame, but that can be changed using the `addToGallery`flag.
+
+- Type: `Boolean`
+- Required: No
+- Default: `false`
+
## render
A callback invoked to render the Button opening the media library.
diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js
index 868a6a083723d..113fceed04e74 100644
--- a/packages/block-library/src/gallery/edit.js
+++ b/packages/block-library/src/gallery/edit.js
@@ -8,8 +8,6 @@ import { filter, pick, map, get } from 'lodash';
* WordPress dependencies
*/
import {
- DropZone,
- FormFileUpload,
IconButton,
PanelBody,
RangeControl,
@@ -25,7 +23,6 @@ import {
MediaUpload,
InspectorControls,
} from '@wordpress/block-editor';
-import { mediaUpload } from '@wordpress/editor';
import { Component, Fragment } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
@@ -64,8 +61,6 @@ class GalleryEdit extends Component {
this.toggleImageCrop = this.toggleImageCrop.bind( this );
this.onRemoveImage = this.onRemoveImage.bind( this );
this.setImageAttributes = this.setImageAttributes.bind( this );
- this.addFiles = this.addFiles.bind( this );
- this.uploadFromFiles = this.uploadFromFiles.bind( this );
this.setAttributes = this.setAttributes.bind( this );
this.state = {
@@ -152,27 +147,6 @@ class GalleryEdit extends Component {
} );
}
- uploadFromFiles( event ) {
- this.addFiles( event.target.files );
- }
-
- addFiles( files ) {
- const currentImages = this.props.attributes.images || [];
- const { noticeOperations } = this.props;
- const { setAttributes } = this;
- mediaUpload( {
- allowedTypes: ALLOWED_MEDIA_TYPES,
- filesList: files,
- onFileChange: ( images ) => {
- const imagesNormalized = images.map( ( image ) => pickRelevantMediaFiles( image ) );
- setAttributes( {
- images: currentImages.concat( imagesNormalized ),
- } );
- },
- onError: noticeOperations.createErrorNotice,
- } );
- }
-
componentDidUpdate( prevProps ) {
// Deselect images when deselecting the block
if ( ! this.props.isSelected && prevProps.isSelected ) {
@@ -187,15 +161,11 @@ class GalleryEdit extends Component {
const { attributes, isSelected, className, noticeOperations, noticeUI } = this.props;
const { images, columns = defaultColumnsNumber( attributes ), align, imageCrop, linkTo } = attributes;
- const dropZone = (
-
- );
+ const hasImages = !! images.length;
const controls = (
- { !! images.length && (
+ { hasImages && (
);
- if ( images.length === 0 ) {
+ const mediaPlaceholder = (
+ }
+ labels={ {
+ title: ! hasImages && __( 'Gallery' ),
+ instructions: ! hasImages && __( 'Drag images, upload new ones or select files from your library.' ),
+ } }
+ onSelect={ this.onSelectImages }
+ accept="image/*"
+ allowedTypes={ ALLOWED_MEDIA_TYPES }
+ multiple
+ value={ hasImages ? images : undefined }
+ onError={ noticeOperations.createErrorNotice }
+ notices={ hasImages ? undefined : noticeUI }
+ />
+ );
+
+ if ( ! hasImages ) {
return (
{ controls }
- }
- className={ className }
- labels={ {
- title: __( 'Gallery' ),
- instructions: __( 'Drag images, upload new ones or select files from your library.' ),
- } }
- onSelect={ this.onSelectImages }
- accept="image/*"
- allowedTypes={ ALLOWED_MEDIA_TYPES }
- multiple
- notices={ noticeUI }
- onError={ noticeOperations.createErrorNotice }
- />
+ { mediaPlaceholder }
);
}
@@ -276,7 +254,6 @@ class GalleryEdit extends Component {
}
) }
>
- { dropZone }
{ images.map( ( img, index ) => {
/* translators: %1$d is the order number of the image, %2$d is the total number of images. */
const ariaLabel = sprintf( __( 'image %1$d of %2$d in gallery' ), ( index + 1 ), images.length );
@@ -297,21 +274,8 @@ class GalleryEdit extends Component {
);
} ) }
- { isSelected &&
-
-
- { __( 'Upload an image' ) }
-
-
- }
+ { mediaPlaceholder }
);
}
diff --git a/packages/block-library/src/gallery/editor.scss b/packages/block-library/src/gallery/editor.scss
index 0340f66a31e8e..57ed4d07d969e 100644
--- a/packages/block-library/src/gallery/editor.scss
+++ b/packages/block-library/src/gallery/editor.scss
@@ -53,31 +53,6 @@ ul.wp-block-gallery li {
}
}
- .components-form-file-upload,
- .components-button.block-library-gallery-add-item-button {
- width: 100%;
- height: 100%;
- }
-
- .components-button.block-library-gallery-add-item-button {
- display: flex;
- flex-direction: column;
- justify-content: center;
- box-shadow: none;
- border: none;
- border-radius: 0;
- min-height: 100px;
-
- & .dashicon {
- margin-top: 10px;
- }
-
- &:hover,
- &:focus {
- border: $border-width solid $dark-gray-500;
- }
- }
-
.block-editor-rich-text figcaption {
a {
color: $white;
@@ -122,14 +97,3 @@ ul.wp-block-gallery li {
margin-top: -9px;
margin-left: -9px;
}
-
-// Last item always needs margins reset.
-// When block is selected, only reset the right margin of the 2nd to last item.
-.wp-block-gallery {
- .is-selected & .blocks-gallery-image:nth-last-child(2),
- .is-selected & .blocks-gallery-item:nth-last-child(2),
- .is-typing & .blocks-gallery-image:nth-last-child(2),
- .is-typing & .blocks-gallery-item:nth-last-child(2) {
- margin-right: 0;
- }
-}
diff --git a/packages/block-library/src/gallery/style.scss b/packages/block-library/src/gallery/style.scss
index 2557f727c5c0e..df60d6fd1fc9b 100644
--- a/packages/block-library/src/gallery/style.scss
+++ b/packages/block-library/src/gallery/style.scss
@@ -126,14 +126,6 @@
margin-right: 0;
}
- // Make the "Add new Gallery item" button full-width (so it always appears
- // below other items).
- .blocks-gallery-item {
- &.has-add-item-button {
- width: 100%;
- }
- }
-
// Apply max-width to floated items that have no intrinsic width.
&.alignleft,
&.alignright {
diff --git a/packages/edit-post/src/hooks/components/media-upload/index.js b/packages/edit-post/src/hooks/components/media-upload/index.js
index df65411e1c305..eefb3450a6e1c 100644
--- a/packages/edit-post/src/hooks/components/media-upload/index.js
+++ b/packages/edit-post/src/hooks/components/media-upload/index.js
@@ -78,10 +78,10 @@ const getAttachmentsCollection = ( ids ) => {
class MediaUpload extends Component {
constructor( {
allowedTypes,
- multiple = false,
gallery = false,
- title = __( 'Select or Upload Media' ),
modalClass,
+ multiple = false,
+ title = __( 'Select or Upload Media' ),
} ) {
super( ...arguments );
this.openModal = this.openModal.bind( this );
@@ -124,6 +124,7 @@ class MediaUpload extends Component {
buildAndSetGalleryFrame() {
const {
+ addToGallery = false,
allowedTypes,
multiple = false,
value = null,
@@ -140,7 +141,12 @@ class MediaUpload extends Component {
if ( this.frame ) {
this.frame.remove();
}
- const currentState = value ? 'gallery-edit' : 'gallery';
+ let currentState;
+ if ( addToGallery ) {
+ currentState = 'gallery-library';
+ } else {
+ currentState = value ? 'gallery-edit' : 'gallery';
+ }
if ( ! this.GalleryDetailsMediaFrame ) {
this.GalleryDetailsMediaFrame = getGalleryDetailsMediaFrame();
}