Skip to content

Commit

Permalink
Add an edit button to the gallery images (WordPress#23554)
Browse files Browse the repository at this point in the history
  • Loading branch information
youknowriad authored Jun 30, 2020
1 parent 8a07cdb commit 01cd739
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 76 deletions.
11 changes: 1 addition & 10 deletions packages/block-editor/src/components/tool-selector/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,8 @@ import {
import { __ } from '@wordpress/i18n';
import { useSelect, useDispatch } from '@wordpress/data';
import { forwardRef } from '@wordpress/element';
import { edit as editIcon } from '@wordpress/icons';

const editIcon = (
<SVG
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<Path d="M20.1 5.1L16.9 2 6.2 12.7l-1.3 4.4 4.5-1.3L20.1 5.1zM4 20.8h8v-1.5H4v1.5z" />
</SVG>
);
const selectIcon = (
<SVG
xmlns="http://www.w3.org/2000/svg"
Expand Down
87 changes: 37 additions & 50 deletions packages/block-library/src/gallery/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -56,48 +56,34 @@ figure.wp-block-gallery {
opacity: 0.3;
}

.is-selected .block-library-gallery-item__move-menu,
.is-selected .block-library-gallery-item__inline-menu {
background: $white;
border: 1px solid $dark-gray-primary;
border-radius: $radius-block-ui;
transition: box-shadow 0.2s ease-out;
@include reduce-motion("transition");

&:hover {
box-shadow: $shadow-popover;
}
display: inline-flex;
}

.components-button {
color: $dark-gray-primary;
min-width: $grid-unit-30;
height: $grid-unit-30;

@include break-small() {
// Use smaller buttons to fit when there are many columns.
.columns-7 &,
.columns-8 & {
padding: 0;
width: inherit;
height: inherit;
}
}
}
.block-editor-media-placeholder {
margin: 0;
height: 100%;

.components-button:focus {
color: inherit;
.components-placeholder__label {
display: flex;
}
}
}

.block-library-gallery-item__move-menu,
.block-library-gallery-item__inline-menu {
display: none;
position: absolute;
top: -2px;
margin: $grid-unit-10;
display: inline-flex;
z-index: z-index(".block-library-gallery-item__inline-menu");

.components-button {
color: transparent;
transition: box-shadow 0.2s ease-out;
@include reduce-motion("transition");
border-radius: $radius-block-ui;
background: $white;
border: $border-width solid $dark-gray-primary;

&:hover {
box-shadow: $shadow-popover;
}

@include break-small() {
Expand All @@ -107,27 +93,28 @@ figure.wp-block-gallery {
padding: $grid-unit-05 / 2;
}
}
}

.block-library-gallery-item__inline-menu {
position: absolute;
top: -2px;
right: -2px;
}
.components-button.has-icon {
border: none;
box-shadow: none;

@include break-small() {
// Use smaller buttons to fit when there are many columns.
.columns-7 &,
.columns-8 & {
padding: 0;
width: inherit;
height: inherit;
}
}
}

.block-library-gallery-item__move-menu {
position: absolute;
top: -2px;
left: -2px;
}
&.is-left {
left: -2px;
}

// Increases specificity
// Resolves: https://github.com/WordPress/gutenberg/issues/23469
.wp-block-gallery {
.blocks-gallery-item__move-backward.components-button,
.blocks-gallery-item__move-forward.components-button,
.blocks-gallery-item__remove.components-button {
padding: 0;
&.is-right {
right: -2px;
}
}

Expand Down
114 changes: 100 additions & 14 deletions packages/block-library/src/gallery/gallery-image.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,33 @@
* External dependencies
*/
import classnames from 'classnames';
import { debounce } from 'lodash';
import { debounce, get, omit } from 'lodash';

/**
* WordPress dependencies
*/
import { Component } from '@wordpress/element';
import { Button, Spinner } from '@wordpress/components';
import { Button, Spinner, ButtonGroup } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { BACKSPACE, DELETE } from '@wordpress/keycodes';
import { withSelect, withDispatch } from '@wordpress/data';
import { RichText } from '@wordpress/block-editor';
import { RichText, MediaPlaceholder } from '@wordpress/block-editor';
import { isBlobURL } from '@wordpress/blob';
import { compose } from '@wordpress/compose';
import { closeSmall, chevronLeft, chevronRight } from '@wordpress/icons';
import {
closeSmall,
chevronLeft,
chevronRight,
edit,
image as imageIcon,
} from '@wordpress/icons';

/**
* Internal dependencies
*/
import { pickRelevantMediaFiles } from './shared';

const isTemporaryImage = ( id, url ) => ! id && isBlobURL( url );

class GalleryImage extends Component {
constructor() {
Expand All @@ -27,6 +40,11 @@ class GalleryImage extends Component {
this.onSelectCaption = this.onSelectCaption.bind( this );
this.onRemoveImage = this.onRemoveImage.bind( this );
this.bindContainer = this.bindContainer.bind( this );
this.onEdit = this.onEdit.bind( this );
this.onSelectImageFromLibrary = this.onSelectImageFromLibrary.bind(
this
);
this.onSelectCustomURL = this.onSelectCustomURL.bind( this );

// The onDeselect prop is used to signal that the GalleryImage component
// has lost focus. We want to call it when focus has been lost
Expand All @@ -39,10 +57,11 @@ class GalleryImage extends Component {
//
// onBlur / onFocus events are quick operations (<5ms apart in my testing),
// so 50ms accounts for 10x lagging while feels responsive to the user.
this.debouncedOnDeselect = debounce( this.props.onDeselect, 50 );
this.debouncedOnDeselect = debounce( this.onDeselect.bind( this ), 50 );

this.state = {
captionSelected: false,
isEditing: false,
};
}

Expand Down Expand Up @@ -86,6 +105,12 @@ class GalleryImage extends Component {
}
}

onEdit() {
this.setState( {
isEditing: true,
} );
}

componentDidUpdate( prevProps ) {
const {
isSelected,
Expand Down Expand Up @@ -114,6 +139,11 @@ class GalleryImage extends Component {
}
}

onDeselect() {
this.setState( { isEditing: false } );
this.props.onDeselect();
}

/**
* Note that, unlike the DOM, all React events bubble,
* so this will be called after the onBlur event of any figure's children.
Expand All @@ -130,6 +160,47 @@ class GalleryImage extends Component {
this.debouncedOnDeselect.cancel();
}

onSelectImageFromLibrary( media ) {
const { setAttributes, id, url, alt, caption, sizeSlug } = this.props;
if ( ! media || ! media.url ) {
return;
}

let mediaAttributes = pickRelevantMediaFiles( media, sizeSlug );

// If the current image is temporary but an alt text was meanwhile
// written by the user, make sure the text is not overwritten.
if ( isTemporaryImage( id, url ) ) {
if ( alt ) {
mediaAttributes = omit( mediaAttributes, [ 'alt' ] );
}
}

// If a caption text was meanwhile written by the user,
// make sure the text is not overwritten by empty captions.
if ( caption && ! get( mediaAttributes, [ 'caption' ] ) ) {
mediaAttributes = omit( mediaAttributes, [ 'caption' ] );
}

setAttributes( mediaAttributes );
this.setState( {
isEditing: false,
} );
}

onSelectCustomURL( newURL ) {
const { setAttributes, url } = this.props;
if ( newURL !== url ) {
setAttributes( {
url: newURL,
id: undefined,
} );
this.setState( {
isEditing: false,
} );
}
}

render() {
const {
url,
Expand All @@ -147,6 +218,7 @@ class GalleryImage extends Component {
setAttributes,
'aria-label': ariaLabel,
} = this.props;
const { isEditing } = this.state;

let href;

Expand Down Expand Up @@ -191,35 +263,49 @@ class GalleryImage extends Component {
onBlur={ this.onBlur }
onFocus={ this.onFocus }
>
{ href ? <a href={ href }>{ img }</a> : img }
<div className="block-library-gallery-item__move-menu">
{ ! isEditing && ( href ? <a href={ href }>{ img }</a> : img ) }
{ isEditing && (
<MediaPlaceholder
labels={ { title: __( 'Edit gallery image' ) } }
icon={ imageIcon }
onSelect={ this.onSelectImageFromLibrary }
onSelectURL={ this.onSelectCustomURL }
accept="image/*"
allowedTypes={ [ 'image' ] }
value={ { id, src: url } }
/>
) }
<ButtonGroup className="block-library-gallery-item__inline-menu is-left">
<Button
icon={ chevronLeft }
onClick={ isFirstItem ? undefined : onMoveBackward }
className="blocks-gallery-item__move-backward"
label={ __( 'Move image backward' ) }
aria-disabled={ isFirstItem }
disabled={ ! isSelected }
/>
<Button
icon={ chevronRight }
onClick={ isLastItem ? undefined : onMoveForward }
className="blocks-gallery-item__move-forward"
label={ __( 'Move image forward' ) }
aria-disabled={ isLastItem }
disabled={ ! isSelected }
/>
</div>
<div className="block-library-gallery-item__inline-menu">
</ButtonGroup>
<ButtonGroup className="block-library-gallery-item__inline-menu is-right">
<Button
icon={ edit }
onClick={ this.onEdit }
label={ __( 'Replace image' ) }
disabled={ ! isSelected }
/>
<Button
icon={ closeSmall }
onClick={ onRemove }
className="blocks-gallery-item__remove"
label={ __( 'Remove image' ) }
disabled={ ! isSelected }
/>
</div>
{ ( isSelected || caption ) && (
</ButtonGroup>
{ ! isEditing && ( isSelected || caption ) && (
<RichText
tagName="figcaption"
placeholder={
Expand Down
1 change: 1 addition & 0 deletions packages/block-library/src/gallery/gallery.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export const Gallery = ( props ) => {
}
caption={ img.caption }
aria-label={ ariaLabel }
sizeSlug={ attributes.sizeSlug }
/>
</li>
);
Expand Down
3 changes: 2 additions & 1 deletion packages/edit-post/src/components/visual-editor/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
font-size: $default-font-size;
padding: 6px 12px;

&.is-tertiary {
&.is-tertiary,
&.has-icon {
padding: 6px;
}
}
Expand Down
3 changes: 2 additions & 1 deletion packages/edit-site/src/components/block-editor/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
font-size: $default-font-size;
padding: 6px 12px;

&.is-tertiary {
&.is-tertiary,
&.has-icon {
padding: 6px;
}
}
1 change: 1 addition & 0 deletions packages/icons/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export { default as currencyDollar } from './library/currency-dollar';
export { default as currencyEuro } from './library/currency-euro';
export { default as currencyPound } from './library/currency-pound';
export { default as desktop } from './library/desktop';
export { default as edit } from './library/edit';
export { default as external } from './library/external';
export { default as file } from './library/file';
export { default as flipHorizontal } from './library/flip-horizontal';
Expand Down
12 changes: 12 additions & 0 deletions packages/icons/src/library/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* WordPress dependencies
*/
import { SVG, Path } from '@wordpress/primitives';

const edit = (
<SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<Path d="M20.1 5.1L16.9 2 6.2 12.7l-1.3 4.4 4.5-1.3L20.1 5.1zM4 20.8h8v-1.5H4v1.5z" />
</SVG>
);

export default edit;

0 comments on commit 01cd739

Please sign in to comment.