Update ImageGallery toolbar: changing icon to text and adding ellipsis menu (#39753)

* Update ImageGallery Toolbar by adding an ellipsis options dropdown menu

* Add changelog

* Remove typings

* Fix build issues

* Fix lint errors

* Add comment and remove old comment
This commit is contained in:
louwie17 2023-08-18 16:24:26 -03:00 committed by GitHub
parent 278366def9
commit b3f7be5fdc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 205 additions and 43 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Update ImageGallery block toolbar, moving some options to an ellipsis dropdown menu.

View File

@ -1,6 +1,6 @@
.woocommerce-image-gallery__item {
height: 146px;
width: 146px;
height: 146px;
width: 146px;
position: relative;
&.is-toolbar-visible {
@ -9,40 +9,38 @@
}
}
&:not(.is-toolbar-visible){
&:not(.is-toolbar-visible) {
img:hover {
border: 1.5px solid #007cba;
}
}
img {
img {
border: 1px solid $gray-200;
border-radius: 3px;
box-sizing: border-box;
object-fit: cover;
width: 100%;
height: 146px;
}
}
.woocommerce-pill {
background: var(--wp-admin-theme-color);
border: 0;
color: $white;
padding-top: 2px;
padding-bottom: 2px;
position: absolute;
top: 10px;
left: 10px;
}
.woocommerce-pill {
background: var(--wp-admin-theme-color);
border: 0;
color: $white;
padding-top: 2px;
padding-bottom: 2px;
position: absolute;
top: 10px;
left: 10px;
}
.components-toolbar-group {
flex-wrap: inherit;
border-right: 1px solid #ccc;
svg {
width: 24px;
margin-top: $gap-smallest;
}
}
}

View File

@ -0,0 +1,6 @@
// Hack to hide when the media modal is open
// Otherwise in Firefox the popover remains visible on top of the modal
// Changing the z-index of Popovers have wider implications.
.modal-open .woocommerce-image-gallery__toolbar-dropdown-popover {
display: none;
}

View File

@ -0,0 +1,101 @@
/**
* External dependencies
*/
import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components';
import { moreVertical } from '@wordpress/icons';
import {
Children,
cloneElement,
createElement,
Fragment,
isValidElement,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { MediaItem, MediaUpload } from '@wordpress/media-utils';
/**
* Internal dependencies
*/
import { MediaUploadComponentType } from './types';
const POPOVER_PROPS = {
className: 'woocommerce-image-gallery__toolbar-dropdown-popover',
placement: 'bottom-start',
};
type ImageGalleryToolbarDropdownProps = {
onReplace: ( media: { id: number } & MediaItem ) => void;
onRemove: () => void;
canRemove?: boolean;
removeBlockLabel?: string;
MediaUploadComponent: MediaUploadComponentType;
};
export function ImageGalleryToolbarDropdown( {
children,
onReplace,
onRemove,
canRemove,
removeBlockLabel,
MediaUploadComponent = MediaUpload,
...props
}: React.PropsWithChildren< ImageGalleryToolbarDropdownProps > ) {
return (
<DropdownMenu
icon={ moreVertical }
label={ __( 'Options', 'woocommerce' ) }
className="woocommerce-image-gallery__toolbar-dropdown"
popoverProps={ POPOVER_PROPS }
{ ...props }
>
{ ( { onClose } ) => (
<>
<MenuGroup>
<MediaUploadComponent
onSelect={ ( media ) => {
onReplace( media as MediaItem );
onClose();
} }
allowedTypes={ [ 'image' ] }
render={ ( { open } ) => (
<MenuItem
onClick={ () => {
open();
} }
>
{ __( 'Replace', 'woocommerce' ) }
</MenuItem>
) }
/>
</MenuGroup>
{ typeof children === 'function'
? children( { onClose } )
: Children.map(
children,
( child ) =>
isValidElement< { onClose: () => void } >(
child
) &&
cloneElement< { onClose: () => void } >(
child,
{ onClose }
)
) }
{ canRemove && (
<MenuGroup>
<MenuItem
onClick={ () => {
onClose();
onRemove();
} }
>
{ removeBlockLabel ||
__( 'Remove', 'woocommerce' ) }
</MenuItem>
</MenuGroup>
) }
</>
) }
</DropdownMenu>
);
}

View File

@ -1,4 +1,5 @@
.woocommerce-image-gallery__toolbar {
width: max-content;
position: absolute;
top: -58px;
left: 50%;

View File

@ -2,17 +2,25 @@
* External dependencies
*/
import { createElement } from '@wordpress/element';
import { Toolbar, ToolbarButton, ToolbarGroup } from '@wordpress/components';
import { chevronRight, chevronLeft, trash } from '@wordpress/icons';
import { MediaItem, MediaUpload } from '@wordpress/media-utils';
import { __ } from '@wordpress/i18n';
import {
Toolbar,
ToolbarButton,
ToolbarGroup,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore No types for this exist yet.
// eslint-disable-next-line @woocommerce/dependency-group
ToolbarItem,
} from '@wordpress/components';
/**
* Internal dependencies
*/
import { CoverImageIcon } from './icons';
import { SortableHandle } from '../sortable';
import { MediaUploadComponentType } from './types';
import { ImageGalleryToolbarDropdown } from './image-gallery-toolbar-dropdown';
export type ImageGalleryToolbarProps = {
childIndex: number;
@ -88,31 +96,60 @@ export const ImageGalleryToolbar: React.FC< ImageGalleryToolbarProps > = ( {
<ToolbarGroup>
<ToolbarButton
onClick={ () => setAsCoverImage( childIndex ) }
icon={ CoverImageIcon }
label={ __( 'Set as cover', 'woocommerce' ) }
>
{ __( 'Set as cover', 'woocommerce' ) }
</ToolbarButton>
</ToolbarGroup>
) }
{ isCoverItem && (
<ToolbarGroup className="woocommerce-image-gallery__toolbar-media">
<MediaUploadComponent
onSelect={ ( media ) =>
replaceItem( childIndex, media as MediaItem )
}
allowedTypes={ [ 'image' ] }
render={ ( { open } ) => (
<ToolbarButton onClick={ open }>
{ __( 'Replace', 'woocommerce' ) }
</ToolbarButton>
) }
/>
</ToolbarGroup>
) }
<ToolbarGroup className="woocommerce-image-gallery__toolbar-media">
<MediaUploadComponent
onSelect={ ( media ) =>
replaceItem( childIndex, media as MediaItem )
}
allowedTypes={ [ 'image' ] }
render={ ( { open } ) => (
<ToolbarButton onClick={ open }>
{ __( 'Replace', 'woocommerce' ) }
</ToolbarButton>
) }
/>
</ToolbarGroup>
<ToolbarGroup>
<ToolbarButton
onClick={ () => removeItem( childIndex ) }
icon={ trash }
label={ __( 'Remove', 'woocommerce' ) }
/>
</ToolbarGroup>
{ isCoverItem && (
<ToolbarGroup>
<ToolbarButton
onClick={ () => removeItem( childIndex ) }
icon={ trash }
label={ __( 'Remove', 'woocommerce' ) }
/>
</ToolbarGroup>
) }
{ ! isCoverItem && (
<ToolbarGroup>
<ToolbarItem>
{ ( toggleProps: {
'data-toolbar-item': boolean;
ref: React.ForwardedRef<
typeof ImageGalleryToolbarDropdown
>;
} ) => (
<ImageGalleryToolbarDropdown
canRemove={ true }
onRemove={ () => removeItem( childIndex ) }
onReplace={ ( media ) =>
replaceItem( childIndex, media )
}
MediaUploadComponent={
MediaUploadComponent
}
{ ...toggleProps }
/>
) }
</ToolbarItem>
</ToolbarGroup>
) }
</Toolbar>
</div>
);

View File

@ -129,6 +129,20 @@ export const ImageGallery: React.FC< ImageGalleryProps > = ( {
event.relatedTarget as Element
).closest(
'.media-modal, .components-modal__frame'
) ) ||
( event.relatedTarget &&
// Check if not a button within the toolbar is clicked, to prevent hiding the toolbar.
(
event.relatedTarget as Element
).closest(
'.woocommerce-image-gallery__toolbar'
) ) ||
( event.relatedTarget &&
// Prevent toolbar from hiding if the dropdown is clicked within the toolbar.
(
event.relatedTarget as Element
).closest(
'.woocommerce-image-gallery__toolbar-dropdown-popover'
) )
) {
return;

View File

@ -1,3 +1,4 @@
@import 'image-gallery.scss';
@import 'image-gallery-item.scss';
@import 'image-gallery-toolbar.scss';
@import "image-gallery.scss";
@import "image-gallery-item.scss";
@import "image-gallery-toolbar.scss";
@import "image-gallery-toolbar-dropdown.scss";