Product Gallery: Polish Gallery in full view mode (https://github.com/woocommerce/woocommerce-blocks/pull/10947)

* Product Gallery: add support for On Sale Badge Block

* add align support

* Add E2E tests

* set margin via Block Styles

* disable experimental flag

* add next previous block

* restore support file

* fix TS error

* fix layout

* change product

* change product

* Product Gallert Block: Add zoom on hover

* set to true by default

* remove block is already registered error

* remove unecessary await

* Improve zoom logic

Co-authored-by: Alexandre Lara <allexandrelara@gmail.com>

* Product Gallery Full view mode: Add the logic to render the dedicated template

* use template-part instead template

* add E2E tests

* update selectors

* add feature flag product gallery template part

* fix E2E tests

* remove not necessary file

* polish the dialog

* fix: dialog show always the selected product

* fix: not open the dialog when the user click on icon

* rename handleClick to handleCloseButtonClick

* improve style

* fix overlay css

* fix registration

* improve logic

* improve default template

---------

Co-authored-by: Alexandre Lara <allexandrelara@gmail.com>
This commit is contained in:
Luigi Teschio 2023-10-02 14:36:48 +02:00 committed by GitHub
parent 60e5943c53
commit 29fe7cdce0
11 changed files with 171 additions and 55 deletions

View File

@ -20,7 +20,8 @@
"productGalleryClientId": "productGalleryClientId",
"nextPreviousButtonsPosition": "nextPreviousButtonsPosition",
"pagerDisplayMode": "pagerDisplayMode",
"hoverZoom": "hoverZoom"
"hoverZoom": "hoverZoom",
"fullScreenOnClick": "fullScreenOnClick"
},
"usesContext": [ "postId" ],
"attributes": {

View File

@ -88,19 +88,14 @@ const TEMPLATE: InnerBlockTemplate[] = [
],
];
const setMode = (
currentTemplateId: string,
templateType: string,
setAttributes: ( attrs: Partial< ProductGalleryAttributes > ) => void
) => {
const getMode = ( currentTemplateId: string, templateType: string ) => {
if (
templateType === 'wp_template_part' &&
currentTemplateId.includes( 'product-gallery' )
) {
setAttributes( {
mode: 'full',
} );
return 'full';
}
return 'standard';
};
export const Edit = ( {
@ -123,17 +118,22 @@ export const Edit = ( {
);
useEffect( () => {
setMode( currentTemplateId, templateType, setAttributes );
}, [ currentTemplateId, setAttributes, templateType ] );
const mode = getMode( currentTemplateId, templateType );
useEffect( () => {
setAttributes( {
...attributes,
mode,
productGalleryClientId: clientId,
} );
// Move the Thumbnails block to the correct above or below the Large Image based on the thumbnailsPosition attribute.
moveInnerBlocksToPosition( attributes, clientId );
}, [ setAttributes, attributes, clientId ] );
}, [
setAttributes,
attributes,
clientId,
currentTemplateId,
templateType,
] );
return (
<div { ...blockProps }>

View File

@ -60,7 +60,7 @@ interactivityApiStore( {
: 0.2;
},
isDialogOpen: ( { context }: Store ) => {
return context?.woocommerce.isDialogOpen;
return context.woocommerce.isDialogOpen;
},
},
},
@ -72,6 +72,11 @@ interactivityApiStore( {
context.woocommerce.imageId;
},
},
dialog: {
handleCloseButtonClick: ( { context }: Store ) => {
context.woocommerce.isDialogOpen = false;
},
},
handleSelectImage: ( { context }: Store ) => {
context.woocommerce.selectedImage = context.woocommerce.imageId;
},

View File

@ -1,8 +1,8 @@
/**
* External dependencies
*/
import { registerBlockSingleProductTemplate } from '@woocommerce/atomic-utils';
import { isExperimentalBuild } from '@woocommerce/block-settings';
import { registerBlockType } from '@wordpress/blocks';
/**
* Internal dependencies
@ -18,16 +18,10 @@ import './inner-blocks/product-gallery-pager';
import './inner-blocks/product-gallery-thumbnails';
if ( isExperimentalBuild() ) {
registerBlockSingleProductTemplate( {
blockName: metadata.name,
// @ts-expect-error: `metadata` currently does not have a type definition in WordPress core
blockMetadata: metadata,
blockSettings: {
icon,
// @ts-expect-error `edit` can be extended to include other attributes
edit: Edit,
save: Save,
},
isAvailableOnPostEditor: true,
// @ts-expect-error: `metadata` currently does not have a type definition in WordPress core.
registerBlockType( metadata, {
icon,
edit: Edit,
save: Save,
} );
}

View File

@ -7,7 +7,7 @@
"description": "Display the Large Image of a product.",
"category": "woocommerce",
"keywords": [ "WooCommerce" ],
"usesContext": [ "nextPreviousButtonsPosition", "postId", "hoverZoom"],
"usesContext": [ "nextPreviousButtonsPosition", "postId", "hoverZoom", "fullScreenOnClick"],
"supports": {
"interactivity": true
},

View File

@ -65,8 +65,16 @@ interactivityStore(
context.woocommerce.styles.transform = `scale(1.0)`;
context.woocommerce.styles[ 'transform-origin' ] = '';
},
handleClick: ( { context }: { context: Context } ) => {
context.woocommerce.isDialogOpen = true;
handleClick: ( {
context,
event,
}: {
context: Context;
event: Event;
} ) => {
if ( ( event.target as HTMLElement ).tagName === 'IMG' ) {
context.woocommerce.isDialogOpen = true;
}
},
},
},

View File

@ -11,13 +11,39 @@ $outside-image-max-width: calc(100% - (2 * $outside-image-offset));
// Product Gallery
#{$gallery} {
.wc-block-product-gallery-dialog__overlay {
height: 100vh;
width: 100vw;
position: fixed;
top: 0;
left: 0;
background-color: #808080;
z-index: 9999;
}
dialog {
position: fixed;
width: 90vw;
width: calc(100vw - 100px);
border: none;
border-radius: 10px;
height: 90vh;
top: 0;
margin: $gap-largest;
margin-top: $gap-largest;
margin-bottom: $gap-largest;
z-index: 9999;
.wc-block-product-galler-dialog__header-right {
display: flex;
justify-content: flex-end;
.wc-block-product-gallery-dialog__close {
border: none;
background-color: transparent;
outline: none;
cursor: pointer;
}
}
}
}
@ -37,9 +63,16 @@ $outside-image-max-width: calc(100% - (2 * $outside-image-offset));
img {
display: block;
position: relative;
margin: 0 auto;
z-index: 1;
transition: all 0.1s linear;
// Keep the order in this way. The hoverZoom class should override the full-screen-on-click class when both are applied.
&.wc-block-woocommerce-product-gallery-large-image__image--full-screen-on-click {
cursor: pointer;
}
&.wc-block-woocommerce-product-gallery-large-image__image--hoverZoom {
cursor: zoom-in;
}
@ -53,8 +86,6 @@ $outside-image-max-width: calc(100% - (2 * $outside-image-offset));
display: flex;
flex-direction: column;
position: absolute;
pointer-events: none;
z-index: 1;
width: 100%;
height: 100%;
top: 0;
@ -76,6 +107,11 @@ $outside-image-max-width: calc(100% - (2 * $outside-image-offset));
width: 100%;
height: 100%;
svg {
z-index: 3;
pointer-events: all;
}
.is-vertically-aligned-top {
align-items: flex-start;
}

View File

@ -9,7 +9,7 @@ export interface ProductGalleryBlockAttributes {
cropImages?: boolean;
hoverZoom?: boolean;
fullScreenOnClick?: boolean;
mode: 'standard' | 'full';
mode?: 'standard' | 'full';
}
export interface ProductGalleryThumbnailsBlockAttributes {

View File

@ -65,7 +65,39 @@ class ProductGallery extends AbstractBlock {
''
);
$gallery_dialog = '<dialog data-wc-bind--open="selectors.woocommerce.isDialogOpen">' . $html . '</dialog>';
$html_processor = new \WP_HTML_Tag_Processor( $html );
$html_processor->next_tag(
array(
'class_name' => 'wp-block-woocommerce-product-gallery',
)
);
$html_processor->remove_attribute( 'data-wc-context' );
$gallery_dialog = strtr(
'
<div class="wc-block-product-gallery-dialog__overlay" hidden data-wc-bind--hidden="!selectors.woocommerce.isDialogOpen">
<dialog data-wc-bind--open="selectors.woocommerce.isDialogOpen">
<div class="wc-block-product-gallery-dialog__header">
<div class="wc-block-product-galler-dialog__header-right">
<button class="wc-block-product-gallery-dialog__close" data-wc-on--click="actions.woocommerce.dialog.handleCloseButtonClick">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="24" height="24" rx="2"/>
<path d="M13 11.8L19.1 5.5L18.1 4.5L12 10.7L5.9 4.5L4.9 5.5L11 11.8L4.5 18.5L5.5 19.5L12 12.9L18.5 19.5L19.5 18.5L13 11.8Z" fill="black"/>
</svg>
</button>
</div>
</div>
<div class="wc-block-product-gallery-dialog__body">
{{html}}
</div>
</dialog>
</div>',
array(
'{{html}}' => $html_processor->get_updated_html(),
)
);
return $gallery_dialog;
}

View File

@ -30,7 +30,7 @@ class ProductGalleryLargeImage extends AbstractBlock {
* @return string[]
*/
protected function get_block_type_uses_context() {
return [ 'postId', 'hoverZoom' ];
return [ 'postId', 'hoverZoom', 'fullScreenOnClick' ];
}
/**
@ -41,7 +41,7 @@ class ProductGalleryLargeImage extends AbstractBlock {
* @param WP_Block $block The block object.
*/
protected function enqueue_assets( array $attributes, $content, $block ) {
if ( $block->context['hoverZoom'] ) {
if ( $block->context['hoverZoom'] || $block->context['fullScreenOnClick'] ) {
parent::enqueue_assets( $attributes, $content, $block );
}
}
@ -124,6 +124,10 @@ class ProductGalleryLargeImage extends AbstractBlock {
);
if ( $context['fullScreenOnClick'] ) {
$attributes['class'] .= ' wc-block-woocommerce-product-gallery-large-image__image--full-screen-on-click';
}
if ( $context['hoverZoom'] ) {
$attributes['class'] .= ' wc-block-woocommerce-product-gallery-large-image__image--hoverZoom';
$attributes['data-wc-bind--style'] = 'selectors.woocommerce.styles';
@ -147,17 +151,30 @@ class ProductGalleryLargeImage extends AbstractBlock {
}
/**
* Get directives for the hover zoom.
* Get directives for the block.
*
* @param array $block_context The block context.
*
* @return array
*/
private function get_directives( $block_context ) {
return array_merge(
$this->get_zoom_directives( $block_context ),
$this->get_open_dialog_directives( $block_context )
);
}
/**
* Get directives for zoom.
*
* @param array $block_context The block context.
*
* @return array
*/
private function get_zoom_directives( $block_context ) {
if ( ! $block_context['hoverZoom'] ) {
return array();
}
$context = array(
'woocommerce' => array(
'styles' => array(
@ -170,8 +187,24 @@ class ProductGalleryLargeImage extends AbstractBlock {
return array(
'data-wc-on--mousemove' => 'actions.woocommerce.handleMouseMove',
'data-wc-on--mouseleave' => 'actions.woocommerce.handleMouseLeave',
'data-wc-on--click' => 'actions.woocommerce.handleClick',
'data-wc-context' => wp_json_encode( $context, JSON_NUMERIC_CHECK ),
);
}
/**
* Get directives for opening the dialog.
*
* @param array $block_context The block context.
*
* @return array
*/
private function get_open_dialog_directives( $block_context ) {
if ( ! $block_context['fullScreenOnClick'] ) {
return array();
}
return array(
'data-wc-on--click' => 'actions.woocommerce.handleClick',
);
}
}

View File

@ -1,20 +1,27 @@
<!-- wp:woocommerce/product-gallery {"mode":"full"} -->
<div class="wp-block-woocommerce-product-gallery"><!-- wp:group {"layout":{"type":"flex","flexWrap":"nowrap"}} -->
<div class="wp-block-group"><!-- wp:woocommerce/product-gallery-thumbnails {"lock":{"move":true,"remove":true}} /-->
<!-- wp:group {"layout":{"type":"constrained"}} -->
<div class="wp-block-group">
<!-- wp:woocommerce/product-gallery {"mode":"full"} -->
<div
class="wp-block-woocommerce-product-gallery wc-block-product-gallery wc-block-product-gallery--has-next-previous-buttons-inside-image">
<!-- wp:group {"layout":{"type":"flex","flexWrap":"nowrap"}} -->
<div class="wp-block-group">
<!-- wp:woocommerce/product-gallery-thumbnails {"lock":{"move":true,"remove":true}} /-->
<!-- wp:woocommerce/product-gallery-large-image {"lock":{"move":true,"remove":true}} -->
<div
class="wp-block-woocommerce-product-gallery-large-image wc-block-product-gallery-large-image__inner-blocks">
<!-- wp:woocommerce/product-sale-badge {"isDescendentOfSingleProductTemplate":true,"align":"right","style":{"spacing":{"margin":{"top":"4px","right":"4px","bottom":"4px","left":"4px"}}}} /-->
<!-- wp:woocommerce/product-gallery-large-image {"lock":{"move":true,"remove":true}} -->
<div
class="wp-block-woocommerce-product-gallery-large-image wc-block-product-gallery-large-image__inner-blocks">
<!-- wp:woocommerce/product-sale-badge {"isDescendentOfSingleProductTemplate":true,"align":"right","style":{"spacing":{"margin":{"top":"4px","right":"4px","bottom":"4px","left":"4px"}}}} /-->
<!-- wp:woocommerce/product-gallery-large-image-next-previous {"layout":{"type":"flex","verticalAlignment":"bottom"}} -->
<div class="wp-block-woocommerce-product-gallery-large-image-next-previous"></div>
<!-- /wp:woocommerce/product-gallery-large-image-next-previous -->
<!-- wp:woocommerce/product-gallery-large-image-next-previous {"layout":{"type":"flex","verticalAlignment":"bottom"}} -->
<div class="wp-block-woocommerce-product-gallery-large-image-next-previous"></div>
<!-- /wp:woocommerce/product-gallery-large-image-next-previous -->
</div>
<!-- /wp:woocommerce/product-gallery-large-image -->
</div>
<!-- /wp:woocommerce/product-gallery-large-image -->
</div>
<!-- /wp:group -->
<!-- /wp:group -->
<!-- wp:woocommerce/product-gallery-pager {"lock":{"move":true,"remove":true}} /-->
<!-- wp:woocommerce/product-gallery-pager {"lock":{"move":true,"remove":true}} /-->
</div>
<!-- /wp:woocommerce/product-gallery -->
</div>
<!-- /wp:woocommerce/product-gallery -->
<!-- /wp:group -->