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:
parent
278366def9
commit
b3f7be5fdc
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: update
|
||||||
|
|
||||||
|
Update ImageGallery block toolbar, moving some options to an ellipsis dropdown menu.
|
|
@ -1,6 +1,6 @@
|
||||||
.woocommerce-image-gallery__item {
|
.woocommerce-image-gallery__item {
|
||||||
height: 146px;
|
height: 146px;
|
||||||
width: 146px;
|
width: 146px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&.is-toolbar-visible {
|
&.is-toolbar-visible {
|
||||||
|
@ -9,40 +9,38 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.is-toolbar-visible){
|
&:not(.is-toolbar-visible) {
|
||||||
img:hover {
|
img:hover {
|
||||||
border: 1.5px solid #007cba;
|
border: 1.5px solid #007cba;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
border: 1px solid $gray-200;
|
border: 1px solid $gray-200;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 146px;
|
height: 146px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.woocommerce-pill {
|
.woocommerce-pill {
|
||||||
background: var(--wp-admin-theme-color);
|
background: var(--wp-admin-theme-color);
|
||||||
border: 0;
|
border: 0;
|
||||||
color: $white;
|
color: $white;
|
||||||
padding-top: 2px;
|
padding-top: 2px;
|
||||||
padding-bottom: 2px;
|
padding-bottom: 2px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
left: 10px;
|
left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.components-toolbar-group {
|
.components-toolbar-group {
|
||||||
flex-wrap: inherit;
|
flex-wrap: inherit;
|
||||||
border-right: 1px solid #ccc;
|
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
margin-top: $gap-smallest;
|
margin-top: $gap-smallest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
.woocommerce-image-gallery__toolbar {
|
.woocommerce-image-gallery__toolbar {
|
||||||
|
width: max-content;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -58px;
|
top: -58px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
|
|
@ -2,17 +2,25 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { createElement } from '@wordpress/element';
|
import { createElement } from '@wordpress/element';
|
||||||
import { Toolbar, ToolbarButton, ToolbarGroup } from '@wordpress/components';
|
|
||||||
import { chevronRight, chevronLeft, trash } from '@wordpress/icons';
|
import { chevronRight, chevronLeft, trash } from '@wordpress/icons';
|
||||||
import { MediaItem, MediaUpload } from '@wordpress/media-utils';
|
import { MediaItem, MediaUpload } from '@wordpress/media-utils';
|
||||||
import { __ } from '@wordpress/i18n';
|
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
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { CoverImageIcon } from './icons';
|
|
||||||
import { SortableHandle } from '../sortable';
|
import { SortableHandle } from '../sortable';
|
||||||
import { MediaUploadComponentType } from './types';
|
import { MediaUploadComponentType } from './types';
|
||||||
|
import { ImageGalleryToolbarDropdown } from './image-gallery-toolbar-dropdown';
|
||||||
|
|
||||||
export type ImageGalleryToolbarProps = {
|
export type ImageGalleryToolbarProps = {
|
||||||
childIndex: number;
|
childIndex: number;
|
||||||
|
@ -88,31 +96,60 @@ export const ImageGalleryToolbar: React.FC< ImageGalleryToolbarProps > = ( {
|
||||||
<ToolbarGroup>
|
<ToolbarGroup>
|
||||||
<ToolbarButton
|
<ToolbarButton
|
||||||
onClick={ () => setAsCoverImage( childIndex ) }
|
onClick={ () => setAsCoverImage( childIndex ) }
|
||||||
icon={ CoverImageIcon }
|
|
||||||
label={ __( 'Set as cover', 'woocommerce' ) }
|
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>
|
||||||
) }
|
) }
|
||||||
<ToolbarGroup className="woocommerce-image-gallery__toolbar-media">
|
{ isCoverItem && (
|
||||||
<MediaUploadComponent
|
<ToolbarGroup>
|
||||||
onSelect={ ( media ) =>
|
<ToolbarButton
|
||||||
replaceItem( childIndex, media as MediaItem )
|
onClick={ () => removeItem( childIndex ) }
|
||||||
}
|
icon={ trash }
|
||||||
allowedTypes={ [ 'image' ] }
|
label={ __( 'Remove', 'woocommerce' ) }
|
||||||
render={ ( { open } ) => (
|
/>
|
||||||
<ToolbarButton onClick={ open }>
|
</ToolbarGroup>
|
||||||
{ __( 'Replace', 'woocommerce' ) }
|
) }
|
||||||
</ToolbarButton>
|
{ ! isCoverItem && (
|
||||||
) }
|
<ToolbarGroup>
|
||||||
/>
|
<ToolbarItem>
|
||||||
</ToolbarGroup>
|
{ ( toggleProps: {
|
||||||
<ToolbarGroup>
|
'data-toolbar-item': boolean;
|
||||||
<ToolbarButton
|
ref: React.ForwardedRef<
|
||||||
onClick={ () => removeItem( childIndex ) }
|
typeof ImageGalleryToolbarDropdown
|
||||||
icon={ trash }
|
>;
|
||||||
label={ __( 'Remove', 'woocommerce' ) }
|
} ) => (
|
||||||
/>
|
<ImageGalleryToolbarDropdown
|
||||||
</ToolbarGroup>
|
canRemove={ true }
|
||||||
|
onRemove={ () => removeItem( childIndex ) }
|
||||||
|
onReplace={ ( media ) =>
|
||||||
|
replaceItem( childIndex, media )
|
||||||
|
}
|
||||||
|
MediaUploadComponent={
|
||||||
|
MediaUploadComponent
|
||||||
|
}
|
||||||
|
{ ...toggleProps }
|
||||||
|
/>
|
||||||
|
) }
|
||||||
|
</ToolbarItem>
|
||||||
|
</ToolbarGroup>
|
||||||
|
) }
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -129,6 +129,20 @@ export const ImageGallery: React.FC< ImageGalleryProps > = ( {
|
||||||
event.relatedTarget as Element
|
event.relatedTarget as Element
|
||||||
).closest(
|
).closest(
|
||||||
'.media-modal, .components-modal__frame'
|
'.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;
|
return;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
@import 'image-gallery.scss';
|
@import "image-gallery.scss";
|
||||||
@import 'image-gallery-item.scss';
|
@import "image-gallery-item.scss";
|
||||||
@import 'image-gallery-toolbar.scss';
|
@import "image-gallery-toolbar.scss";
|
||||||
|
@import "image-gallery-toolbar-dropdown.scss";
|
||||||
|
|
Loading…
Reference in New Issue