Product Collection: Add loading indicator for client-side pagination (#44571)
* Add animation for client-side pagination This includes: - Addition of animation state management in the frontend file to control the visual transition between pagination states. - Introduction of new SCSS rules for the start and finish animations, ensuring a seamless and visually appealing pagination experience. - Modification of the PHP logic to inject necessary HTML for the animation to be applied. These updates aim to provide a more engaging and responsive interface for users navigating through product collection. * Add changefile(s) from automation for the following project(s): woocommerce-blocks, woocommerce * Allow user clicks under product collection's loading animation This commit enhances the user experience of the loading animation for the product collection block. Changes include: - Specifying `transform-origin: 0% 0%;` directly within the block's initial style to indicate the animation should start from the left - Adding `pointer-events: none;` to allow user interactions with elements underneath the loading animation, thus improving usability by not blocking clicks. Additionally, redundant `transform-origin` properties were removed from the `@keyframes` declaration to clean up the code and avoid unnecessary repetition. This simplification contributes to both the maintainability and readability of the stylesheet. * Fix linting errors in SCSS file --------- Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
parent
eb2b1fef1d
commit
e210302e8a
|
@ -9,8 +9,14 @@ import {
|
|||
getContext,
|
||||
} from '@woocommerce/interactivity';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
export type ProductCollectionStoreContext = {
|
||||
isPrefetchNextOrPreviousLink: boolean;
|
||||
animation: 'start' | 'finish';
|
||||
};
|
||||
|
||||
const isValidLink = ( ref: HTMLAnchorElement ) =>
|
||||
|
@ -63,6 +69,20 @@ function scrollToFirstProductIfNotVisible( wcNavigationId?: string ) {
|
|||
}
|
||||
|
||||
const productCollectionStore = {
|
||||
state: {
|
||||
get startAnimation() {
|
||||
return (
|
||||
getContext< ProductCollectionStoreContext >().animation ===
|
||||
'start'
|
||||
);
|
||||
},
|
||||
get finishAnimation() {
|
||||
return (
|
||||
getContext< ProductCollectionStoreContext >().animation ===
|
||||
'finish'
|
||||
);
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
*navigate( event: MouseEvent ) {
|
||||
const ctx = getContext< ProductCollectionStoreContext >();
|
||||
|
@ -73,8 +93,18 @@ const productCollectionStore = {
|
|||
|
||||
if ( isValidLink( ref ) && isValidEvent( event ) ) {
|
||||
event.preventDefault();
|
||||
|
||||
// Don't start animation if it doesn't take long to navigate.
|
||||
const timeout = setTimeout( () => {
|
||||
ctx.animation = 'start';
|
||||
}, 400 );
|
||||
|
||||
yield navigate( ref.href );
|
||||
|
||||
// Clear the timeout if the navigation is fast.
|
||||
clearTimeout( timeout );
|
||||
|
||||
ctx.animation = 'finish';
|
||||
ctx.isPrefetchNextOrPreviousLink = !! ref.href;
|
||||
|
||||
scrollToFirstProductIfNotVisible( wcNavigationId );
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
// This animation will be shown when user change the pages in the product collection block
|
||||
.wc-block-product-collection__pagination-animation {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
height: 4px;
|
||||
background-color: var(--wp--preset--color--primary, #000);
|
||||
opacity: 0; // Hide the animation by default.
|
||||
transform-origin: 0% 0%; // Start the animation from the left.
|
||||
pointer-events: none; // Allows click events to pass through to elements underneath.
|
||||
|
||||
&.start-animation {
|
||||
animation: wc-block-product-collection__pagination-start-animation 30s cubic-bezier(0.03, 0.5, 0, 1) forwards;
|
||||
}
|
||||
|
||||
&.finish-animation {
|
||||
animation: wc-block-product-collection__pagination-finish-animation 300ms ease-in;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes wc-block-product-collection__pagination-start-animation {
|
||||
0% {
|
||||
transform: scaleX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: scaleX(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes wc-block-product-collection__pagination-finish-animation {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Product Collection: Add loading indicator for client-side pagination
|
|
@ -45,14 +45,6 @@ class ProductCollection extends AbstractBlock {
|
|||
*/
|
||||
protected $custom_order_opts = array( 'popularity', 'rating' );
|
||||
|
||||
/**
|
||||
* Get the frontend style handle for this block type.
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function get_block_type_style() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this block type.
|
||||
|
@ -85,21 +77,24 @@ class ProductCollection extends AbstractBlock {
|
|||
add_filter( 'rest_product_collection_params', array( $this, 'extend_rest_query_allowed_params' ), 10, 1 );
|
||||
|
||||
// Interactivity API: Add navigation directives to the product collection block.
|
||||
add_filter( 'render_block_woocommerce/product-collection', array( $this, 'add_navigation_id_directive' ), 10, 3 );
|
||||
add_filter( 'render_block_woocommerce/product-collection', array( $this, 'enhance_product_collection_with_interactivity' ), 10, 2 );
|
||||
add_filter( 'render_block_core/query-pagination', array( $this, 'add_navigation_link_directives' ), 10, 3 );
|
||||
|
||||
add_filter( 'posts_clauses', array( $this, 'add_price_range_filter_posts_clauses' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the Product Collection as an interactive region so it can be updated
|
||||
* during client-side navigation.
|
||||
* Enhances the Product Collection block with client-side pagination.
|
||||
*
|
||||
* @param string $block_content The block content.
|
||||
* @param array $block The full block, including name and attributes.
|
||||
* @param \WP_Block $instance The block instance.
|
||||
* This function identifies Product Collection blocks and adds necessary data attributes
|
||||
* to enable client-side navigation and animation effects. It also enqueues the Interactivity API runtime.
|
||||
*
|
||||
* @param string $block_content The HTML content of the block.
|
||||
* @param array $block Block details, including its attributes.
|
||||
*
|
||||
* @return string Updated block content with added interactivity attributes.
|
||||
*/
|
||||
public function add_navigation_id_directive( $block_content, $block, $instance ) {
|
||||
public function enhance_product_collection_with_interactivity( $block_content, $block ) {
|
||||
$is_product_collection_block = $block['attrs']['query']['isProductCollectionBlock'] ?? false;
|
||||
if ( $is_product_collection_block ) {
|
||||
// Enqueue the Interactivity API runtime.
|
||||
|
@ -107,7 +102,7 @@ class ProductCollection extends AbstractBlock {
|
|||
|
||||
$p = new \WP_HTML_Tag_Processor( $block_content );
|
||||
|
||||
// Add `data-wc-navigation-id to the query block.
|
||||
// Add `data-wc-navigation-id to the product collection block.
|
||||
if ( $p->next_tag( array( 'class_name' => 'wp-block-woocommerce-product-collection' ) ) ) {
|
||||
$p->set_attribute(
|
||||
'data-wc-navigation-id',
|
||||
|
@ -125,6 +120,20 @@ class ProductCollection extends AbstractBlock {
|
|||
);
|
||||
$block_content = $p->get_updated_html();
|
||||
}
|
||||
|
||||
// Add animation div to the block content.
|
||||
$last_tag_position = strripos( $block_content, '</div>' );
|
||||
$block_content = substr_replace(
|
||||
$block_content,
|
||||
'<div
|
||||
data-wc-interactive="{"namespace":"woocommerce/product-collection"}"
|
||||
class="wc-block-product-collection__pagination-animation"
|
||||
data-wc-class--start-animation="state.startAnimation"
|
||||
data-wc-class--finish-animation="state.finishAnimation">
|
||||
</div>',
|
||||
$last_tag_position,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
return $block_content;
|
||||
|
|
Loading…
Reference in New Issue