[Mini cart] Make the title customizable (https://github.com/woocommerce/woocommerce-blocks/pull/8905)
* Create the counter block and the header pattern * Change the pattern to an inner block * Allow customizing item counter block * Rename block * Allow removing the items counter block * Add padding controls * Preload new blocks * Add title block back from the inserter * Move h2 tag to the parent title * Align items at the bottom * Unify styles * Add title class in the editor * Prevent removing title blocks * Disallow unlocking and inserter * Disallowing moving blocks
This commit is contained in:
parent
ad2003117e
commit
709a7a9add
|
@ -42,7 +42,11 @@
|
|||
|
||||
h2.wc-block-mini-cart__title {
|
||||
@include font-size(larger);
|
||||
margin: $gap-largest $gap 0;
|
||||
|
||||
.block-editor-block-list__layout {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
}
|
||||
|
||||
table.wc-block-cart-items {
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
import './empty-mini-cart-contents-block';
|
||||
import './filled-mini-cart-contents-block';
|
||||
import './mini-cart-title-block';
|
||||
import './mini-cart-title-items-counter-block';
|
||||
import './mini-cart-title-label-block';
|
||||
import './mini-cart-items-block';
|
||||
import './mini-cart-products-table-block';
|
||||
import './mini-cart-footer-block';
|
||||
|
|
|
@ -13,13 +13,13 @@ import { getIconsFromPaymentMethods } from '@woocommerce/base-utils';
|
|||
import { getSetting } from '@woocommerce/settings';
|
||||
import { PaymentEventsProvider } from '@woocommerce/base-context';
|
||||
import classNames from 'classnames';
|
||||
import { isObject } from '@woocommerce/types';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import CartButton from '../mini-cart-cart-button-block/block';
|
||||
import CheckoutButton from '../mini-cart-checkout-button-block/block';
|
||||
import { hasChildren } from '../utils';
|
||||
|
||||
const PaymentMethodIconsElement = (): JSX.Element => {
|
||||
const { paymentMethods } = usePaymentMethods();
|
||||
|
@ -37,18 +37,6 @@ interface Props {
|
|||
checkoutButtonLabel: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there are any children that are blocks.
|
||||
*/
|
||||
const hasChildren = ( children ): boolean => {
|
||||
return children.some( ( child ) => {
|
||||
if ( Array.isArray( child ) ) {
|
||||
return hasChildren( child );
|
||||
}
|
||||
return isObject( child ) && child.key !== null;
|
||||
} );
|
||||
};
|
||||
|
||||
const Block = ( {
|
||||
children,
|
||||
className,
|
||||
|
|
|
@ -1,34 +1,45 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { sprintf, _n, __ } from '@wordpress/i18n';
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
import classNames from 'classnames';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import TitleItemsCounter from '../mini-cart-title-items-counter-block/block';
|
||||
import TitleYourCart from '../mini-cart-title-label-block/block';
|
||||
import { hasChildren } from '../utils';
|
||||
|
||||
type MiniCartTitleBlockProps = {
|
||||
className: string;
|
||||
children: JSX.Element;
|
||||
};
|
||||
|
||||
const Block = ( { className }: MiniCartTitleBlockProps ): JSX.Element => {
|
||||
const { cartItemsCount, cartIsLoading } = useStoreCart();
|
||||
const Block = ( {
|
||||
children,
|
||||
className,
|
||||
}: MiniCartTitleBlockProps ): JSX.Element | null => {
|
||||
const { cartIsLoading } = useStoreCart();
|
||||
if ( cartIsLoading ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The `Mini Cart Title` was converted to two inner blocks, but we still need to render the old title for
|
||||
// themes that have the old `mini-cart.html` template. So we check if there are any inner blocks and if
|
||||
// not, render the title blocks.
|
||||
const hasTitleInnerBlocks = hasChildren( children );
|
||||
|
||||
return (
|
||||
<h2 className={ classNames( className, 'wc-block-mini-cart__title' ) }>
|
||||
{ cartIsLoading
|
||||
? __( 'Your cart', 'woo-gutenberg-products-block' )
|
||||
: sprintf(
|
||||
/* translators: %d is the count of items in the cart. */
|
||||
_n(
|
||||
'Your cart (%d item)',
|
||||
'Your cart (%d items)',
|
||||
cartItemsCount,
|
||||
'woo-gutenberg-products-block'
|
||||
),
|
||||
cartItemsCount
|
||||
) }
|
||||
{ hasTitleInnerBlocks ? (
|
||||
children
|
||||
) : (
|
||||
<>
|
||||
<TitleYourCart />
|
||||
<TitleItemsCounter />
|
||||
</>
|
||||
) }
|
||||
</h2>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,23 +1,36 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
|
||||
|
||||
export const Edit = (): JSX.Element => {
|
||||
const blockProps = useBlockProps();
|
||||
const blockProps = useBlockProps( {
|
||||
className: 'wc-block-mini-cart__title',
|
||||
} );
|
||||
|
||||
const TEMPLATE = [
|
||||
[ 'woocommerce/mini-cart-title-label-block', {} ],
|
||||
[ 'woocommerce/mini-cart-title-items-counter-block', {} ],
|
||||
];
|
||||
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<Block />
|
||||
</div>
|
||||
<h2 { ...blockProps }>
|
||||
<InnerBlocks
|
||||
allowedBlocks={ [
|
||||
'woocommerce/mini-cart-title-label-block',
|
||||
'woocommerce/mini-cart-title-items-counter-block',
|
||||
] }
|
||||
template={ TEMPLATE }
|
||||
templateLock="all"
|
||||
/>
|
||||
</h2>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() }></div>;
|
||||
return (
|
||||
<div { ...useBlockProps.save() }>
|
||||
<InnerBlocks.Content />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "woocommerce/mini-cart-title-items-counter-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Mini Cart Title Items Counter",
|
||||
"description": "Block that displays the items counter part of the Mini Cart Title block.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"inserter": false,
|
||||
"lock": false,
|
||||
"color": {
|
||||
"text": true,
|
||||
"background": true
|
||||
},
|
||||
"typography": {
|
||||
"fontSize": true
|
||||
},
|
||||
"spacing": {
|
||||
"padding": true
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/mini-cart-title-block" ],
|
||||
"textdomain": "woo-gutenberg-products-block",
|
||||
"apiVersion": 2,
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json"
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useStoreCart } from '@woocommerce/base-context';
|
||||
import classNames from 'classnames';
|
||||
import { _n, sprintf } from '@wordpress/i18n';
|
||||
import {
|
||||
useColorProps,
|
||||
useSpacingProps,
|
||||
useTypographyProps,
|
||||
} from '@woocommerce/base-hooks';
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const Block = ( props: Props ): JSX.Element => {
|
||||
const { cartItemsCount } = useStoreCart();
|
||||
const colorProps = useColorProps( props );
|
||||
const typographyProps = useTypographyProps( props );
|
||||
const spacingProps = useSpacingProps( props );
|
||||
|
||||
return (
|
||||
<span
|
||||
className={ classNames(
|
||||
props.className,
|
||||
colorProps.className,
|
||||
typographyProps.className
|
||||
) }
|
||||
style={ {
|
||||
...colorProps.style,
|
||||
...typographyProps.style,
|
||||
...spacingProps.style,
|
||||
} }
|
||||
>
|
||||
{ sprintf(
|
||||
/* translators: %d is the count of items in the cart. */
|
||||
_n(
|
||||
'(%d item)',
|
||||
'(%d items)',
|
||||
cartItemsCount,
|
||||
'woo-gutenberg-products-block'
|
||||
),
|
||||
cartItemsCount
|
||||
) }
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
import { _n, sprintf } from '@wordpress/i18n';
|
||||
import { useStoreCart } from '@woocommerce/base-context';
|
||||
|
||||
export const Edit = (): JSX.Element => {
|
||||
const blockProps = useBlockProps();
|
||||
const { cartItemsCount } = useStoreCart();
|
||||
|
||||
return (
|
||||
<span { ...blockProps }>
|
||||
{ sprintf(
|
||||
/* translators: %d is the count of items in the cart. */
|
||||
_n(
|
||||
'(%d item)',
|
||||
'(%d items)',
|
||||
cartItemsCount,
|
||||
'woo-gutenberg-products-block'
|
||||
),
|
||||
cartItemsCount
|
||||
) }
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() }></div>;
|
||||
};
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Icon, heading } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore -- TypeScript expects some required properties which we already
|
||||
// registered in PHP.
|
||||
registerBlockType( 'woocommerce/mini-cart-title-items-counter-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ heading }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { defaultYourCartLabel } from './constants';
|
||||
|
||||
export default {
|
||||
label: {
|
||||
type: 'string',
|
||||
default: defaultYourCartLabel,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"name": "woocommerce/mini-cart-title-label-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Mini Cart Title Label",
|
||||
"description": "Block that displays the 'Your cart' part of the Mini Cart Title block.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"inserter": false,
|
||||
"lock": false,
|
||||
"color": {
|
||||
"text": true,
|
||||
"background": true
|
||||
},
|
||||
"typography": {
|
||||
"fontSize": true
|
||||
},
|
||||
"spacing": {
|
||||
"padding": true
|
||||
}
|
||||
},
|
||||
"attributes": {
|
||||
"label": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/mini-cart-title-block" ],
|
||||
"textdomain": "woo-gutenberg-products-block",
|
||||
"apiVersion": 2,
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json"
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import {
|
||||
useColorProps,
|
||||
useSpacingProps,
|
||||
useTypographyProps,
|
||||
} from '@woocommerce/base-hooks';
|
||||
import classNames from 'classnames';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { defaultYourCartLabel } from './constants';
|
||||
|
||||
type Props = {
|
||||
label?: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const Block = ( props: Props ): JSX.Element => {
|
||||
const colorProps = useColorProps( props );
|
||||
const typographyProps = useTypographyProps( props );
|
||||
const spacingProps = useSpacingProps( props );
|
||||
|
||||
return (
|
||||
<span
|
||||
className={ classNames(
|
||||
props.className,
|
||||
colorProps.className,
|
||||
typographyProps.className
|
||||
) }
|
||||
style={ {
|
||||
...colorProps.style,
|
||||
...typographyProps.style,
|
||||
...spacingProps.style,
|
||||
} }
|
||||
>
|
||||
{ props.label || defaultYourCartLabel }
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
export const defaultYourCartLabel = __(
|
||||
'Your cart',
|
||||
'woo-gutenberg-products-block'
|
||||
);
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { RichText, useBlockProps } from '@wordpress/block-editor';
|
||||
|
||||
interface Attributes {
|
||||
attributes: {
|
||||
label: string;
|
||||
};
|
||||
setAttributes: ( attributes: Record< string, unknown > ) => void;
|
||||
}
|
||||
|
||||
export const Edit = ( {
|
||||
attributes: { label },
|
||||
setAttributes,
|
||||
}: Attributes ): JSX.Element => {
|
||||
const blockProps = useBlockProps();
|
||||
|
||||
return (
|
||||
<span { ...blockProps }>
|
||||
<RichText
|
||||
allowedFormats={ [] }
|
||||
value={ label }
|
||||
onChange={ ( newLabel ) =>
|
||||
setAttributes( { label: newLabel } )
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() }></div>;
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Icon, heading } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
import attributes from './attributes';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore -- TypeScript expects some required properties which we already
|
||||
// registered in PHP.
|
||||
registerBlockType( 'woocommerce/mini-cart-title-label-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ heading }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
attributes,
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
|
@ -10,6 +10,8 @@ import { lazy } from '@wordpress/element';
|
|||
import emptyMiniCartContentsMetadata from './empty-mini-cart-contents-block/block.json';
|
||||
import filledMiniCartMetadata from './filled-mini-cart-contents-block/block.json';
|
||||
import miniCartTitleMetadata from './mini-cart-title-block/block.json';
|
||||
import miniCartTitleItemsCounterMetadata from './mini-cart-title-items-counter-block/block.json';
|
||||
import miniCartTitleLabelBlockMetadata from './mini-cart-title-label-block/block.json';
|
||||
import miniCartProductsTableMetadata from './mini-cart-products-table-block/block.json';
|
||||
import miniCartFooterMetadata from './mini-cart-footer-block/block.json';
|
||||
import miniCartItemsMetadata from './mini-cart-items-block/block.json';
|
||||
|
@ -52,6 +54,28 @@ registerCheckoutBlock( {
|
|||
),
|
||||
} );
|
||||
|
||||
registerCheckoutBlock( {
|
||||
metadata: miniCartTitleItemsCounterMetadata,
|
||||
force: false,
|
||||
component: lazy(
|
||||
() =>
|
||||
import(
|
||||
/* webpackChunkName: "mini-cart-contents-block/title-items-counter" */ './mini-cart-title-items-counter-block/block'
|
||||
)
|
||||
),
|
||||
} );
|
||||
|
||||
registerCheckoutBlock( {
|
||||
metadata: miniCartTitleLabelBlockMetadata,
|
||||
force: false,
|
||||
component: lazy(
|
||||
() =>
|
||||
import(
|
||||
/* webpackChunkName: "mini-cart-contents-block/title-label" */ './mini-cart-title-label-block/block'
|
||||
)
|
||||
),
|
||||
} );
|
||||
|
||||
registerCheckoutBlock( {
|
||||
metadata: miniCartItemsMetadata,
|
||||
component: lazy(
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { isObject } from 'lodash';
|
||||
|
||||
type Variant = 'text' | 'contained' | 'outlined';
|
||||
|
||||
export const getVariant = (
|
||||
|
@ -14,3 +19,15 @@ export const getVariant = (
|
|||
|
||||
return defaultVariant;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if there are any children that are blocks.
|
||||
*/
|
||||
export const hasChildren = ( children ): boolean => {
|
||||
return children.some( ( child ) => {
|
||||
if ( Array.isArray( child ) ) {
|
||||
return hasChildren( child );
|
||||
}
|
||||
return isObject( child ) && child.key !== null;
|
||||
} );
|
||||
};
|
||||
|
|
|
@ -121,12 +121,18 @@
|
|||
}
|
||||
|
||||
h2.wc-block-mini-cart__title {
|
||||
@include font-size(larger);
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
background: inherit;
|
||||
margin: $gap $gap $gap * -2;
|
||||
padding-bottom: $gap * 2;
|
||||
mask-image: linear-gradient(#000 calc(100% - #{$gap * 1.5}), transparent);
|
||||
z-index: 1;
|
||||
margin: $gap $gap $gap * -2;
|
||||
@include font-size(larger);
|
||||
|
||||
span:first-child {
|
||||
margin-right: $gap-smaller;
|
||||
}
|
||||
}
|
||||
|
||||
.wc-block-mini-cart__items {
|
||||
|
|
|
@ -25,6 +25,7 @@ export enum innerBlockAreas {
|
|||
MINI_CART = 'woocommerce/mini-cart-contents',
|
||||
EMPTY_MINI_CART = 'woocommerce/empty-mini-cart-contents-block',
|
||||
FILLED_MINI_CART = 'woocommerce/filled-mini-cart-contents-block',
|
||||
MINI_CART_TITLE = 'woocommerce/mini-cart-title-block',
|
||||
MINI_CART_ITEMS = 'woocommerce/mini-cart-items-block',
|
||||
MINI_CART_FOOTER = 'woocommerce/mini-cart-footer-block',
|
||||
CART_ORDER_SUMMARY = 'woocommerce/cart-order-summary-block',
|
||||
|
|
|
@ -282,6 +282,8 @@ class MiniCart extends AbstractBlock {
|
|||
'products-table-frontend',
|
||||
'cart-button-frontend',
|
||||
'checkout-button-frontend',
|
||||
'title-label-frontend',
|
||||
'title-items-counter-frontend',
|
||||
);
|
||||
}
|
||||
foreach ( $inner_blocks_frontend_scripts as $inner_block_frontend_script ) {
|
||||
|
|
|
@ -155,6 +155,8 @@ class MiniCartContents extends AbstractBlock {
|
|||
$block_types[] = 'MiniCartCartButtonBlock';
|
||||
$block_types[] = 'MiniCartCheckoutButtonBlock';
|
||||
$block_types[] = 'MiniCartTitleBlock';
|
||||
$block_types[] = 'MiniCartTitleItemsCounterBlock';
|
||||
$block_types[] = 'MiniCartTitleLabelBlock';
|
||||
|
||||
return $block_types;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
namespace Automattic\WooCommerce\Blocks\BlockTypes;
|
||||
|
||||
/**
|
||||
* MiniCartTitleItemsCounterBlock class.
|
||||
*/
|
||||
class MiniCartTitleItemsCounterBlock extends AbstractInnerBlock {
|
||||
/**
|
||||
* Block name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $block_name = 'mini-cart-title-items-counter-block';
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
namespace Automattic\WooCommerce\Blocks\BlockTypes;
|
||||
|
||||
/**
|
||||
* MiniCartTitleLabelBlock class.
|
||||
*/
|
||||
class MiniCartTitleLabelBlock extends AbstractInnerBlock {
|
||||
/**
|
||||
* Block name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $block_name = 'mini-cart-title-label-block';
|
||||
}
|
|
@ -4,6 +4,15 @@
|
|||
<div class="wp-block-woocommerce-filled-mini-cart-contents-block">
|
||||
<!-- wp:woocommerce/mini-cart-title-block -->
|
||||
<div class="wp-block-woocommerce-mini-cart-title-block">
|
||||
<!-- wp:woocommerce/mini-cart-title-label-block -->
|
||||
<div class="wp-block-woocommerce-mini-cart-title-label-block">
|
||||
</div>
|
||||
<!-- /wp:woocommerce/mini-cart-title-label-block -->
|
||||
|
||||
<!-- wp:woocommerce/mini-cart-title-items-counter-block -->
|
||||
<div class="wp-block-woocommerce-mini-cart-title-items-counter-block">
|
||||
</div>
|
||||
<!-- /wp:woocommerce/mini-cart-title-items-counter-block -->
|
||||
</div>
|
||||
<!-- /wp:woocommerce/mini-cart-title-block -->
|
||||
<!-- wp:woocommerce/mini-cart-items-block -->
|
||||
|
|
Loading…
Reference in New Issue