Add global style support to Mini Cart (button) (https://github.com/woocommerce/woocommerce-blocks/pull/5100)
This commit is contained in:
parent
af8f5e857c
commit
2b7d906133
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import classNames from 'classnames';
|
||||
import classnames from 'classnames';
|
||||
import { __, _n, sprintf } from '@wordpress/i18n';
|
||||
import { useState, useEffect, useRef } from '@wordpress/element';
|
||||
import {
|
||||
|
@ -31,10 +31,6 @@ import CartLineItemsTable from '../cart/cart-line-items-table';
|
|||
import QuantityBadge from './quantity-badge';
|
||||
import './style.scss';
|
||||
|
||||
interface MiniCartBlockProps {
|
||||
isInitiallyOpen?: boolean;
|
||||
}
|
||||
|
||||
const PaymentMethodIconsElement = (): JSX.Element => {
|
||||
const { paymentMethods } = usePaymentMethods();
|
||||
return (
|
||||
|
@ -44,9 +40,18 @@ const PaymentMethodIconsElement = (): JSX.Element => {
|
|||
);
|
||||
};
|
||||
|
||||
interface Props {
|
||||
isInitiallyOpen?: boolean;
|
||||
transparentButton: boolean;
|
||||
colorClassNames?: string;
|
||||
style?: Record< string, Record< string, string > >;
|
||||
}
|
||||
|
||||
const MiniCartBlock = ( {
|
||||
isInitiallyOpen = false,
|
||||
}: MiniCartBlockProps ): JSX.Element => {
|
||||
colorClassNames,
|
||||
style,
|
||||
}: Props ): JSX.Element => {
|
||||
const {
|
||||
cartItems,
|
||||
cartItemsCount,
|
||||
|
@ -115,6 +120,11 @@ const MiniCartBlock = ( {
|
|||
formatPrice( subTotal, getCurrencyFromPriceResponse( cartTotals ) )
|
||||
);
|
||||
|
||||
const colorStyle = {
|
||||
backgroundColor: style?.color?.background,
|
||||
color: style?.color?.text,
|
||||
};
|
||||
|
||||
const contents =
|
||||
! cartIsLoading && cartItems.length === 0 ? (
|
||||
<div
|
||||
|
@ -176,7 +186,8 @@ const MiniCartBlock = ( {
|
|||
return (
|
||||
<>
|
||||
<button
|
||||
className="wc-block-mini-cart__button"
|
||||
className={ `wc-block-mini-cart__button ${ colorClassNames }` }
|
||||
style={ colorStyle }
|
||||
onClick={ () => {
|
||||
if ( ! isOpen ) {
|
||||
setIsOpen( true );
|
||||
|
@ -191,10 +202,14 @@ const MiniCartBlock = ( {
|
|||
getCurrencyFromPriceResponse( cartTotals )
|
||||
) }
|
||||
</span>
|
||||
<QuantityBadge count={ cartItemsCount } />
|
||||
<QuantityBadge
|
||||
count={ cartItemsCount }
|
||||
colorClassNames={ colorClassNames }
|
||||
style={ colorStyle }
|
||||
/>
|
||||
</button>
|
||||
<Drawer
|
||||
className={ classNames(
|
||||
className={ classnames(
|
||||
'wc-block-mini-cart__drawer',
|
||||
'is-mobile',
|
||||
{
|
||||
|
|
|
@ -28,10 +28,21 @@ const renderMiniCartFrontend = () => {
|
|||
renderFrontend( {
|
||||
selector: '.wc-block-mini-cart',
|
||||
Block: MiniCartBlock,
|
||||
getProps: ( el: HTMLElement ) => ( {
|
||||
isDataOutdated: el.dataset.isDataOutdated,
|
||||
isInitiallyOpen: el.dataset.isInitiallyOpen === 'true',
|
||||
} ),
|
||||
getProps: ( el: HTMLElement ) => {
|
||||
let colorClassNames = '';
|
||||
const button = el.querySelector( '.wc-block-mini-cart__button' );
|
||||
if ( button !== null ) {
|
||||
colorClassNames = button.classList
|
||||
.toString()
|
||||
.replace( 'wc-block-mini-cart__button', '' );
|
||||
}
|
||||
return {
|
||||
isDataOutdated: el.dataset.isDataOutdated,
|
||||
isInitiallyOpen: el.dataset.isInitiallyOpen === 'true',
|
||||
colorClassNames,
|
||||
style: el.dataset.style ? JSON.parse( el.dataset.style ) : {},
|
||||
};
|
||||
},
|
||||
} );
|
||||
|
||||
// Refocus previously focused button if drawer is not open.
|
||||
|
|
|
@ -1,19 +1,65 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
import {
|
||||
InspectorControls,
|
||||
useBlockProps,
|
||||
getColorClassName,
|
||||
} from '@wordpress/block-editor';
|
||||
import type { ReactElement } from 'react';
|
||||
import { formatPrice } from '@woocommerce/price-format';
|
||||
import { CartCheckoutCompatibilityNotice } from '@woocommerce/editor-components/compatibility-notices';
|
||||
import { PanelBody, ToggleControl } from '@wordpress/components';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import classnames from 'classnames';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import QuantityBadge from './quantity-badge';
|
||||
|
||||
const MiniCartBlock = (): ReactElement => {
|
||||
interface Attributes {
|
||||
isInitiallyOpen?: boolean;
|
||||
transparentButton: boolean;
|
||||
backgroundColor?: string;
|
||||
textColor?: string;
|
||||
style?: Record< string, Record< string, string > >;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
attributes: Attributes;
|
||||
setAttributes: ( attributes: Record< string, unknown > ) => void;
|
||||
}
|
||||
|
||||
const MiniCartBlock = ( {
|
||||
attributes,
|
||||
setAttributes,
|
||||
}: Props ): ReactElement => {
|
||||
const { transparentButton, backgroundColor, textColor, style } = attributes;
|
||||
const blockProps = useBlockProps( {
|
||||
className: 'wc-block-mini-cart',
|
||||
className: classnames( 'wc-block-mini-cart', {
|
||||
'is-transparent': transparentButton,
|
||||
} ),
|
||||
} );
|
||||
|
||||
/**
|
||||
* @todo Replace `getColorClassName` and manual style manipulation with
|
||||
* `useColorProps` once the hook is no longer experimental.
|
||||
*/
|
||||
const backgroundClass = getColorClassName(
|
||||
'background-color',
|
||||
backgroundColor
|
||||
);
|
||||
const textColorClass = getColorClassName( 'color', textColor );
|
||||
|
||||
const colorStyle = {
|
||||
backgroundColor: style?.color?.background,
|
||||
color: style?.color?.text,
|
||||
};
|
||||
|
||||
const colorClassNames = classnames( backgroundClass, textColorClass, {
|
||||
'has-background': backgroundClass || style?.color?.background,
|
||||
'has-text-color': textColorClass || style?.color?.text,
|
||||
} );
|
||||
|
||||
const productCount = 0;
|
||||
|
@ -21,11 +67,42 @@ const MiniCartBlock = (): ReactElement => {
|
|||
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<button className="wc-block-mini-cart__button">
|
||||
<InspectorControls>
|
||||
<PanelBody
|
||||
title={ __(
|
||||
'Button style',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
>
|
||||
<ToggleControl
|
||||
label={ __(
|
||||
'Use transparent button',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
checked={ transparentButton }
|
||||
onChange={ () =>
|
||||
setAttributes( {
|
||||
transparentButton: ! transparentButton,
|
||||
} )
|
||||
}
|
||||
/>
|
||||
</PanelBody>
|
||||
</InspectorControls>
|
||||
<button
|
||||
className={ classnames(
|
||||
'wc-block-mini-cart__button',
|
||||
colorClassNames
|
||||
) }
|
||||
style={ colorStyle }
|
||||
>
|
||||
<span className="wc-block-mini-cart__amount">
|
||||
{ formatPrice( productTotal ) }
|
||||
</span>
|
||||
<QuantityBadge count={ productCount } />
|
||||
<QuantityBadge
|
||||
count={ productCount }
|
||||
colorClassNames={ colorClassNames }
|
||||
style={ colorStyle }
|
||||
/>
|
||||
</button>
|
||||
<CartCheckoutCompatibilityNotice blockName="mini-cart" />
|
||||
</div>
|
||||
|
|
|
@ -26,6 +26,19 @@ const settings = {
|
|||
supports: {
|
||||
html: false,
|
||||
multiple: false,
|
||||
color: {
|
||||
/**
|
||||
* Because we don't target the wrapper element, we don't need
|
||||
* to add color classes and style to the wrapper.
|
||||
*/
|
||||
__experimentalSkipSerialization: true,
|
||||
},
|
||||
/**
|
||||
* We need this experimental flag because we don't want to style the
|
||||
* wrapper but inner elements.
|
||||
*/
|
||||
__experimentalSelector:
|
||||
'.wc-block-mini-cart__button, .wc-block-mini-cart__badge',
|
||||
},
|
||||
example: {
|
||||
attributes: {
|
||||
|
@ -38,6 +51,10 @@ const settings = {
|
|||
default: false,
|
||||
save: false,
|
||||
},
|
||||
transparentButton: {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
|
||||
edit,
|
||||
|
|
|
@ -8,15 +8,32 @@ import { Icon, miniCart } from '@woocommerce/icons';
|
|||
*/
|
||||
import './style.scss';
|
||||
|
||||
const QuantityBadge = ( { count }: { count: number } ): JSX.Element => (
|
||||
<span className="wc-block-mini-cart__quantity-badge">
|
||||
<Icon
|
||||
className="wc-block-mini-cart__icon"
|
||||
size={ 20 }
|
||||
srcElement={ miniCart }
|
||||
/>
|
||||
<span className="wc-block-mini-cart__badge">{ count }</span>
|
||||
</span>
|
||||
);
|
||||
interface Props {
|
||||
count: number;
|
||||
colorClassNames?: string;
|
||||
style?: Record< string, string | undefined >;
|
||||
}
|
||||
|
||||
const QuantityBadge = ( {
|
||||
count,
|
||||
colorClassNames,
|
||||
style,
|
||||
}: Props ): JSX.Element => {
|
||||
return (
|
||||
<span className="wc-block-mini-cart__quantity-badge">
|
||||
<Icon
|
||||
className="wc-block-mini-cart__icon"
|
||||
size={ 20 }
|
||||
srcElement={ miniCart }
|
||||
/>
|
||||
<span
|
||||
className={ `wc-block-mini-cart__badge ${ colorClassNames }` }
|
||||
style={ style }
|
||||
>
|
||||
{ count }
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export default QuantityBadge;
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
.wc-block-mini-cart__badge {
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
border: 2px solid;
|
||||
border: 0.15em solid;
|
||||
border-radius: 1em;
|
||||
box-shadow: 0 0 0 2px #fff;
|
||||
box-sizing: border-box;
|
||||
color: #000;
|
||||
display: flex;
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
.wc-block-mini-cart {
|
||||
.wc-block-mini-cart.wp-block-woocommerce-mini-cart {
|
||||
background-color: transparent !important;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
&.is-transparent .wc-block-mini-cart__button {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
}
|
||||
|
||||
.wc-block-mini-cart__button {
|
||||
align-items: center;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: inherit;
|
||||
display: flex;
|
||||
font-weight: 400;
|
||||
padding: em($gap-small) em($gap-smaller);
|
||||
|
||||
&:hover {
|
||||
background: transparent;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +42,7 @@
|
|||
font-size: 1rem;
|
||||
|
||||
.components-modal__content {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
|
|
@ -198,15 +198,17 @@ class MiniCart extends AbstractBlock {
|
|||
* @return string Rendered block type output.
|
||||
*/
|
||||
protected function render( $attributes, $content ) {
|
||||
return $content . $this->get_markup();
|
||||
return $content . $this->get_markup( $attributes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the markup for the Mini Cart block.
|
||||
*
|
||||
* @param array $attributes Block attributes.
|
||||
*
|
||||
* @return string The HTML markup.
|
||||
*/
|
||||
protected function get_markup() {
|
||||
protected function get_markup( $attributes ) {
|
||||
if ( is_admin() || WC()->is_rest_api_request() ) {
|
||||
// In the editor we will display the placeholder, so no need to load
|
||||
// real cart data and to print the markup.
|
||||
|
@ -222,6 +224,39 @@ class MiniCart extends AbstractBlock {
|
|||
$cart_contents_total += $cart->get_subtotal_tax();
|
||||
}
|
||||
|
||||
$wrapper_classes = 'wc-block-mini-cart';
|
||||
$classes = '';
|
||||
$style = '';
|
||||
|
||||
if ( ! isset( $attributes['transparentButton'] ) || $attributes['transparentButton'] ) {
|
||||
$wrapper_classes .= ' is-transparent';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the color class and inline style.
|
||||
*
|
||||
* @todo refactor the logic of color class and style using StyleAttributesUtils.
|
||||
*/
|
||||
if ( ! empty( $attributes['textColor'] ) ) {
|
||||
$classes .= sprintf(
|
||||
' has-%s-color has-text-color',
|
||||
esc_attr( $attributes['textColor'] )
|
||||
);
|
||||
} elseif ( ! empty( $attributes['style']['color']['text'] ) ) {
|
||||
$style .= 'color: ' . esc_attr( $attributes['style']['color']['text'] ) . ';';
|
||||
$classes .= ' has-text-color';
|
||||
}
|
||||
|
||||
if ( ! empty( $attributes['backgroundColor'] ) ) {
|
||||
$classes .= sprintf(
|
||||
' has-%s-background-color has-background',
|
||||
esc_attr( $attributes['backgroundColor'] )
|
||||
);
|
||||
} elseif ( ! empty( $attributes['style']['color']['background'] ) ) {
|
||||
$style .= 'background-color: ' . esc_attr( $attributes['style']['color']['background'] ) . ';';
|
||||
$classes .= ' has-background';
|
||||
}
|
||||
|
||||
$aria_label = sprintf(
|
||||
/* translators: %1$d is the number of products in the cart. %2$s is the cart total */
|
||||
_n(
|
||||
|
@ -258,17 +293,17 @@ class MiniCart extends AbstractBlock {
|
|||
$button_html = '<span class="wc-block-mini-cart__amount">' . esc_html( wp_strip_all_tags( wc_price( $cart_contents_total ) ) ) . '</span>
|
||||
<span class="wc-block-mini-cart__quantity-badge">
|
||||
' . $icon . '
|
||||
<span class="wc-block-mini-cart__badge">' . $cart_contents_count . '</span>
|
||||
<span class="wc-block-mini-cart__badge ' . $classes . '" style="' . $style . '">' . $cart_contents_count . '</span>
|
||||
</span>';
|
||||
|
||||
if ( is_cart() || is_checkout() ) {
|
||||
return '<div class="wc-block-mini-cart">
|
||||
<button class="wc-block-mini-cart__button" aria-label="' . esc_attr( $aria_label ) . '" disabled>' . $button_html . '</button>
|
||||
return '<div class="' . $wrapper_classes . '">
|
||||
<button class="wc-block-mini-cart__button ' . $classes . '" aria-label="' . esc_attr( $aria_label ) . '" style="' . $style . '" disabled>' . $button_html . '</button>
|
||||
</div>';
|
||||
}
|
||||
|
||||
return '<div class="wc-block-mini-cart">
|
||||
<button class="wc-block-mini-cart__button" aria-label="' . esc_attr( $aria_label ) . '">' . $button_html . '</button>
|
||||
return '<div class="' . $wrapper_classes . '">
|
||||
<button class="wc-block-mini-cart__button ' . $classes . '" aria-label="' . esc_attr( $aria_label ) . '" style="' . $style . '">' . $button_html . '</button>
|
||||
<div class="wc-block-mini-cart__drawer is-loading is-mobile wc-block-components-drawer__screen-overlay wc-block-components-drawer__screen-overlay--is-hidden" aria-hidden="true">
|
||||
<div class="components-modal__frame wc-block-components-drawer">
|
||||
<div class="components-modal__content">
|
||||
|
@ -335,4 +370,22 @@ class MiniCart extends AbstractBlock {
|
|||
</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the supports array for this block type.
|
||||
*
|
||||
* @see $this->register_block_type()
|
||||
* @return string;
|
||||
*/
|
||||
protected function get_block_type_supports() {
|
||||
return array_merge(
|
||||
parent::get_block_type_supports(),
|
||||
array(
|
||||
'html' => false,
|
||||
'multiple' => false,
|
||||
'color' => true,
|
||||
'__experimentalSelector' => '.wc-block-mini-cart__button, .wc-block-mini-cart__badge',
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue