initial commit

This commit is contained in:
2021-12-10 12:03:04 +00:00
commit c46c7ddbf0
3643 changed files with 582794 additions and 0 deletions

View File

@ -0,0 +1,121 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { useState, useEffect, useRef } from '@wordpress/element';
import Button from '@woocommerce/base-components/button';
import { ValidatedTextInput } from '@woocommerce/base-components/text-input';
import Label from '@woocommerce/base-components/label';
import LoadingMask from '@woocommerce/base-components/loading-mask';
import PropTypes from 'prop-types';
import { withInstanceId } from '@wordpress/compose';
import {
ValidationInputError,
useValidationContext,
} from '@woocommerce/base-context';
import { Panel } from '@woocommerce/blocks-checkout';
/**
* Internal dependencies
*/
import './style.scss';
const TotalsCoupon = ( {
instanceId,
isLoading = false,
initialOpen = false,
onSubmit = () => {},
} ) => {
const [ couponValue, setCouponValue ] = useState( '' );
const currentIsLoading = useRef( false );
const { getValidationError, getValidationErrorId } = useValidationContext();
const validationError = getValidationError( 'coupon' );
useEffect( () => {
if ( currentIsLoading.current !== isLoading ) {
if ( ! isLoading && couponValue && ! validationError ) {
setCouponValue( '' );
}
currentIsLoading.current = isLoading;
}
}, [ isLoading, couponValue, validationError ] );
const textInputId = `wc-block-components-totals-coupon__input-${ instanceId }`;
return (
<Panel
className="wc-block-components-totals-coupon"
hasBorder={ false }
initialOpen={ initialOpen }
title={
<Label
label={ __(
'Coupon code',
'woocommerce'
) }
screenReaderLabel={ __(
'Apply a coupon code',
'woocommerce'
) }
htmlFor={ textInputId }
/>
}
>
<LoadingMask
screenReaderLabel={ __(
'Applying coupon…',
'woocommerce'
) }
isLoading={ isLoading }
showSpinner={ false }
>
<div className="wc-block-components-totals-coupon__content">
<form className="wc-block-components-totals-coupon__form">
<ValidatedTextInput
id={ textInputId }
errorId="coupon"
className="wc-block-components-totals-coupon__input"
label={ __(
'Enter code',
'woocommerce'
) }
value={ couponValue }
ariaDescribedBy={ getValidationErrorId(
textInputId
) }
onChange={ ( newCouponValue ) => {
setCouponValue( newCouponValue );
} }
validateOnMount={ false }
focusOnMount={ true }
showError={ false }
/>
<Button
className="wc-block-components-totals-coupon__button"
disabled={ isLoading || ! couponValue }
showSpinner={ isLoading }
onClick={ ( e ) => {
e.preventDefault();
onSubmit( couponValue );
} }
type="submit"
>
{ __( 'Apply', 'woocommerce' ) }
</Button>
</form>
<ValidationInputError
propertyName="coupon"
elementId={ textInputId }
/>
</div>
</LoadingMask>
</Panel>
);
};
TotalsCoupon.propTypes = {
onSubmit: PropTypes.func,
isLoading: PropTypes.bool,
};
export default withInstanceId( TotalsCoupon );

View File

@ -0,0 +1,47 @@
/**
* External dependencies
*/
import { text, boolean } from '@storybook/addon-knobs';
import {
useValidationContext,
ValidationContextProvider,
} from '@woocommerce/base-context';
/**
* Internal dependencies
*/
import TotalsCoupon from '../';
export default {
title:
'WooCommerce Blocks/@base-components/cart-checkout/totals/TotalsCoupon',
component: TotalsCoupon,
};
const StoryComponent = ( { validCoupon, isLoading, invalidCouponText } ) => {
const { setValidationErrors } = useValidationContext();
const onSubmit = ( coupon ) => {
if ( coupon !== validCoupon ) {
setValidationErrors( { coupon: invalidCouponText } );
}
};
return <TotalsCoupon isLoading={ isLoading } onSubmit={ onSubmit } />;
};
export const Default = () => {
const validCoupon = text( 'A valid coupon code', 'validcoupon' );
const invalidCouponText = text(
'Error message for invalid code',
'Invalid coupon code.'
);
const isLoading = boolean( 'Toggle isLoading state', false );
return (
<ValidationContextProvider>
<StoryComponent
validCoupon={ validCoupon }
isLoading={ isLoading }
invalidCouponText={ invalidCouponText }
/>
</ValidationContextProvider>
);
};

View File

@ -0,0 +1,41 @@
.wc-block-components-totals-coupon {
.wc-block-components-panel__button {
margin-top: 0;
padding-top: 0;
}
.wc-block-components-panel__content {
padding-bottom: 0;
}
}
.wc-block-components-totals-coupon__form {
display: flex;
width: 100%;
margin-bottom: 0;
.wc-block-components-totals-coupon__input {
margin-bottom: 0;
margin-top: 0;
flex-grow: 1;
}
.wc-block-components-totals-coupon__button {
height: em(48px);
flex-shrink: 0;
margin-left: $gap-smaller;
padding-left: $gap-large;
padding-right: $gap-large;
white-space: nowrap;
}
.wc-block-components-totals-coupon__button.no-margin {
margin: 0;
}
}
.wc-block-components-totals-coupon__content {
flex-direction: column;
position: relative;
}

View File

@ -0,0 +1,128 @@
/**
* External dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import LoadingMask from '@woocommerce/base-components/loading-mask';
import { RemovableChip } from '@woocommerce/base-components/chip';
import PropTypes from 'prop-types';
import {
__experimentalApplyCheckoutFilter,
TotalsItem,
} from '@woocommerce/blocks-checkout';
import { getSetting } from '@woocommerce/settings';
/**
* Internal dependencies
*/
import './style.scss';
const filteredCartCouponsFilterArg = {
context: 'summary',
};
const TotalsDiscount = ( {
cartCoupons = [],
currency,
isRemovingCoupon,
removeCoupon,
values,
} ) => {
const {
total_discount: totalDiscount,
total_discount_tax: totalDiscountTax,
} = values;
const discountValue = parseInt( totalDiscount, 10 );
if ( ! discountValue && cartCoupons.length === 0 ) {
return null;
}
const discountTaxValue = parseInt( totalDiscountTax, 10 );
const discountTotalValue = getSetting(
'displayCartPricesIncludingTax',
false
)
? discountValue + discountTaxValue
: discountValue;
const filteredCartCoupons = __experimentalApplyCheckoutFilter( {
arg: filteredCartCouponsFilterArg,
filterName: 'coupons',
defaultValue: cartCoupons,
} );
return (
<TotalsItem
className="wc-block-components-totals-discount"
currency={ currency }
description={
filteredCartCoupons.length !== 0 && (
<LoadingMask
screenReaderLabel={ __(
'Removing coupon…',
'woocommerce'
) }
isLoading={ isRemovingCoupon }
showSpinner={ false }
>
<ul className="wc-block-components-totals-discount__coupon-list">
{ filteredCartCoupons.map( ( cartCoupon ) => {
return (
<RemovableChip
key={ 'coupon-' + cartCoupon.code }
className="wc-block-components-totals-discount__coupon-list-item"
text={ cartCoupon.label }
screenReaderText={ sprintf(
/* translators: %s Coupon code. */
__(
'Coupon: %s',
'woocommerce'
),
cartCoupon.label
) }
disabled={ isRemovingCoupon }
onRemove={ () => {
removeCoupon( cartCoupon.code );
} }
radius="large"
ariaLabel={ sprintf(
/* translators: %s is a coupon code. */
__(
'Remove coupon "%s"',
'woocommerce'
),
cartCoupon.label
) }
/>
);
} ) }
</ul>
</LoadingMask>
)
}
label={
!! discountTotalValue
? __( 'Discount', 'woocommerce' )
: __( 'Coupons', 'woocommerce' )
}
value={ discountTotalValue ? discountTotalValue * -1 : '-' }
/>
);
};
TotalsDiscount.propTypes = {
cartCoupons: PropTypes.arrayOf(
PropTypes.shape( {
code: PropTypes.string.isRequired,
} )
),
currency: PropTypes.object.isRequired,
isRemovingCoupon: PropTypes.bool.isRequired,
removeCoupon: PropTypes.func.isRequired,
values: PropTypes.shape( {
total_discount: PropTypes.string,
total_discount_tax: PropTypes.string,
} ).isRequired,
};
export default TotalsDiscount;

View File

@ -0,0 +1,37 @@
/**
* External dependencies
*/
import { text, boolean } from '@storybook/addon-knobs';
import { currencyKnob } from '@woocommerce/knobs';
/**
* Internal dependencies
*/
import TotalsDiscount from '../';
export default {
title:
'WooCommerce Blocks/@base-components/cart-checkout/totals/TotalsDiscount',
component: TotalsDiscount,
};
export const Default = () => {
const cartCoupons = [ { code: 'COUPON' } ];
const currency = currencyKnob();
const isRemovingCoupon = boolean( 'Toggle isRemovingCoupon state', false );
const totalDiscount = text( 'Total discount', '1000' );
const totalDiscountTax = text( 'Total discount tax', '200' );
return (
<TotalsDiscount
cartCoupons={ cartCoupons }
currency={ currency }
isRemovingCoupon={ isRemovingCoupon }
removeCoupon={ () => void null }
values={ {
total_discount: totalDiscount,
total_discount_tax: totalDiscountTax,
} }
/>
);
};

View File

@ -0,0 +1,9 @@
.wc-block-components-totals-discount__coupon-list {
list-style: none;
margin: 0;
padding: 0;
}
.wc-block-components-totals-discount .wc-block-components-totals-item__value {
color: $discount-color;
}

View File

@ -0,0 +1,80 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { createInterpolateElement } from '@wordpress/element';
import FormattedMonetaryAmount from '@woocommerce/base-components/formatted-monetary-amount';
import PropTypes from 'prop-types';
import {
__experimentalApplyCheckoutFilter,
TotalsItem,
} from '@woocommerce/blocks-checkout';
import { useStoreCart } from '@woocommerce/base-context/hooks';
import { getSetting } from '@woocommerce/settings';
/**
* Internal dependencies
*/
import './style.scss';
const TotalsFooterItem = ( { currency, values } ) => {
const SHOW_TAXES =
getSetting( 'taxesEnabled', true ) &&
getSetting( 'displayCartPricesIncludingTax', false );
const { total_price: totalPrice, total_tax: totalTax } = values;
// Prepare props to pass to the __experimentalApplyCheckoutFilter filter.
// We need to pluck out receiveCart.
// eslint-disable-next-line no-unused-vars
const { receiveCart, ...cart } = useStoreCart();
const label = __experimentalApplyCheckoutFilter( {
filterName: 'totalLabel',
defaultValue: __( 'Total', 'woocommerce' ),
extensions: cart.extensions,
arg: { cart },
} );
const parsedTaxValue = parseInt( totalTax, 10 );
return (
<TotalsItem
className="wc-block-components-totals-footer-item"
currency={ currency }
label={ label }
value={ parseInt( totalPrice, 10 ) }
description={
SHOW_TAXES &&
parsedTaxValue !== 0 && (
<p className="wc-block-components-totals-footer-item-tax">
{ createInterpolateElement(
__(
'Including <TaxAmount/> in taxes',
'woocommerce'
),
{
TaxAmount: (
<FormattedMonetaryAmount
className="wc-block-components-totals-footer-item-tax-value"
currency={ currency }
value={ parsedTaxValue }
/>
),
}
) }
</p>
)
}
/>
);
};
TotalsFooterItem.propTypes = {
currency: PropTypes.object.isRequired,
values: PropTypes.shape( {
total_price: PropTypes.string,
total_tax: PropTypes.string,
} ).isRequired,
};
export default TotalsFooterItem;

View File

@ -0,0 +1,32 @@
/**
* External dependencies
*/
import { text } from '@storybook/addon-knobs';
import { currencyKnob } from '@woocommerce/knobs';
/**
* Internal dependencies
*/
import TotalsFooterItem from '../';
export default {
title:
'WooCommerce Blocks/@base-components/cart-checkout/totals/TotalsFooterItem',
component: TotalsFooterItem,
};
export const Default = () => {
const currency = currencyKnob();
const totalPrice = text( 'Total price', '1200' );
const totalTax = text( 'Total tax', '200' );
return (
<TotalsFooterItem
currency={ currency }
values={ {
total_price: totalPrice,
total_tax: totalTax,
} }
/>
);
};

View File

@ -0,0 +1,14 @@
.wc-block-components-totals-footer-item {
.wc-block-components-totals-item__value,
.wc-block-components-totals-item__label {
@include font-size(large);
}
.wc-block-components-totals-item__label {
font-weight: 700;
}
.wc-block-components-totals-footer-item-tax {
margin-bottom: 0;
}
}

View File

@ -0,0 +1,79 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TotalsFooterItem Does not show the "including %s of tax" line if tax is 0 1`] = `
<div>
<div
class="wc-block-components-totals-item wc-block-components-totals-footer-item"
>
<span
class="wc-block-components-totals-item__label"
>
Total
</span>
<span
class="wc-block-formatted-money-amount wc-block-components-formatted-money-amount wc-block-components-totals-item__value"
>
£85.00
</span>
<div
class="wc-block-components-totals-item__description"
/>
</div>
</div>
`;
exports[`TotalsFooterItem Does not show the "including %s of tax" line if tax is disabled 1`] = `
<div>
<div
class="wc-block-components-totals-item wc-block-components-totals-footer-item"
>
<span
class="wc-block-components-totals-item__label"
>
Total
</span>
<span
class="wc-block-formatted-money-amount wc-block-components-formatted-money-amount wc-block-components-totals-item__value"
>
£85.00
</span>
<div
class="wc-block-components-totals-item__description"
/>
</div>
</div>
`;
exports[`TotalsFooterItem Shows the "including %s of tax" line if tax is greater than 0 1`] = `
<div>
<div
class="wc-block-components-totals-item wc-block-components-totals-footer-item"
>
<span
class="wc-block-components-totals-item__label"
>
Total
</span>
<span
class="wc-block-formatted-money-amount wc-block-components-formatted-money-amount wc-block-components-totals-item__value"
>
£85.00
</span>
<div
class="wc-block-components-totals-item__description"
>
<p
class="wc-block-components-totals-footer-item-tax"
>
Including
<span
class="wc-block-formatted-money-amount wc-block-components-formatted-money-amount wc-block-components-totals-footer-item-tax-value"
>
£1.00
</span>
in taxes
</p>
</div>
</div>
</div>
`;

View File

@ -0,0 +1,81 @@
/**
* External dependencies
*/
import { render } from '@testing-library/react';
/**
* Internal dependencies
*/
import TotalsFooterItem from '../index';
import { allSettings } from '../../../../../../settings/shared/settings-init';
describe( 'TotalsFooterItem', () => {
beforeEach( () => {
allSettings.taxesEnabled = true;
allSettings.displayCartPricesIncludingTax = true;
} );
const currency = {
code: 'GBP',
decimalSeparator: '.',
minorUnit: 2,
prefix: '£',
suffix: '',
symbol: '£',
thousandSeparator: ',',
};
const values = {
currency_code: 'GBP',
currency_decimal_separator: '.',
currency_minor_unit: 2,
currency_prefix: '£',
currency_suffix: '',
currency_symbol: '£',
currency_thousand_separator: ',',
tax_lines: [],
length: 2,
total_discount: '0',
total_discount_tax: '0',
total_fees: '0',
total_fees_tax: '0',
total_items: '7100',
total_items_tax: '0',
total_price: '8500',
total_shipping: '0',
total_shipping_tax: '0',
total_tax: '0',
};
it( 'Does not show the "including %s of tax" line if tax is 0', () => {
const { container } = render(
<TotalsFooterItem currency={ currency } values={ values } />
);
expect( container ).toMatchSnapshot();
} );
it( 'Does not show the "including %s of tax" line if tax is disabled', () => {
allSettings.taxesEnabled = false;
/* This shouldn't ever happen if taxes are disabled, but this is to test whether the taxesEnabled setting works */
const valuesWithTax = {
...values,
total_tax: '100',
total_items_tax: '100',
};
const { container } = render(
<TotalsFooterItem currency={ currency } values={ valuesWithTax } />
);
expect( container ).toMatchSnapshot();
} );
it( 'Shows the "including %s of tax" line if tax is greater than 0', () => {
const valuesWithTax = {
...values,
total_tax: '100',
total_items_tax: '100',
};
const { container } = render(
<TotalsFooterItem currency={ currency } values={ valuesWithTax } />
);
expect( container ).toMatchSnapshot();
} );
} );

View File

@ -0,0 +1,4 @@
export { default as TotalsCoupon } from './coupon';
export { default as TotalsDiscount } from './discount';
export { default as TotalsFooterItem } from './footer-item';
export { default as TotalsShipping } from './shipping';

View File

@ -0,0 +1,14 @@
/**
* Searches an array of packages/rates to see if there are actually any rates
* available.
*
* @param {Array} shippingRatePackages An array of packages and rates.
* @return {boolean} True if a rate exists.
*/
const hasShippingRate = ( shippingRatePackages ) => {
return shippingRatePackages.some(
( shippingRatePackage ) => shippingRatePackage.shipping_rates.length
);
};
export default hasShippingRate;

View File

@ -0,0 +1,213 @@
/**
* External dependencies
*/
import classnames from 'classnames';
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import { useStoreCart } from '@woocommerce/base-context/hooks';
import { TotalsItem } from '@woocommerce/blocks-checkout';
import type { Currency } from '@woocommerce/price-format';
import type { ReactElement } from 'react';
import { getSetting, EnteredAddress } from '@woocommerce/settings';
import { ShippingVia } from '@woocommerce/base-components/cart-checkout/totals/shipping/shipping-via';
/**
* Internal dependencies
*/
import ShippingRateSelector from './shipping-rate-selector';
import hasShippingRate from './has-shipping-rate';
import ShippingCalculator from '../../shipping-calculator';
import ShippingLocation from '../../shipping-location';
import './style.scss';
interface CalculatorButtonProps {
label?: string;
isShippingCalculatorOpen: boolean;
setIsShippingCalculatorOpen: ( isShippingCalculatorOpen: boolean ) => void;
}
const CalculatorButton = ( {
label = __( 'Calculate', 'woo-gutenberg-products-block' ),
isShippingCalculatorOpen,
setIsShippingCalculatorOpen,
}: CalculatorButtonProps ): ReactElement => {
return (
<button
className="wc-block-components-totals-shipping__change-address-button"
onClick={ () => {
setIsShippingCalculatorOpen( ! isShippingCalculatorOpen );
} }
aria-expanded={ isShippingCalculatorOpen }
>
{ label }
</button>
);
};
interface ShippingAddressProps {
showCalculator: boolean;
isShippingCalculatorOpen: boolean;
setIsShippingCalculatorOpen: CalculatorButtonProps[ 'setIsShippingCalculatorOpen' ];
shippingAddress: EnteredAddress;
}
const ShippingAddress = ( {
showCalculator,
isShippingCalculatorOpen,
setIsShippingCalculatorOpen,
shippingAddress,
}: ShippingAddressProps ): ReactElement | null => {
return (
<>
<ShippingLocation address={ shippingAddress } />
{ showCalculator && (
<CalculatorButton
label={ __(
'(change address)',
'woo-gutenberg-products-block'
) }
isShippingCalculatorOpen={ isShippingCalculatorOpen }
setIsShippingCalculatorOpen={ setIsShippingCalculatorOpen }
/>
) }
</>
);
};
interface NoShippingPlaceholderProps {
showCalculator: boolean;
isShippingCalculatorOpen: boolean;
setIsShippingCalculatorOpen: CalculatorButtonProps[ 'setIsShippingCalculatorOpen' ];
}
const NoShippingPlaceholder = ( {
showCalculator,
isShippingCalculatorOpen,
setIsShippingCalculatorOpen,
}: NoShippingPlaceholderProps ): ReactElement => {
if ( ! showCalculator ) {
return (
<em>
{ __(
'Calculated during checkout',
'woo-gutenberg-products-block'
) }
</em>
);
}
return (
<CalculatorButton
isShippingCalculatorOpen={ isShippingCalculatorOpen }
setIsShippingCalculatorOpen={ setIsShippingCalculatorOpen }
/>
);
};
interface TotalShippingProps {
currency: Currency;
values: {
total_shipping: string;
total_shipping_tax: string;
}; // Values in use
showCalculator?: boolean; //Whether to display the rate selector below the shipping total.
showRateSelector?: boolean; // Whether to show shipping calculator or not.
className?: string;
}
const TotalsShipping = ( {
currency,
values,
showCalculator = true,
showRateSelector = true,
className,
}: TotalShippingProps ): ReactElement => {
const [ isShippingCalculatorOpen, setIsShippingCalculatorOpen ] = useState(
false
);
const {
shippingAddress,
cartHasCalculatedShipping,
shippingRates,
shippingRatesLoading,
} = useStoreCart();
const totalShippingValue = getSetting(
'displayCartPricesIncludingTax',
false
)
? parseInt( values.total_shipping, 10 ) +
parseInt( values.total_shipping_tax, 10 )
: parseInt( values.total_shipping, 10 );
const hasRates = hasShippingRate( shippingRates ) || totalShippingValue;
const calculatorButtonProps = {
isShippingCalculatorOpen,
setIsShippingCalculatorOpen,
};
const selectedShippingRates = shippingRates.flatMap(
( shippingPackage ) => {
return shippingPackage.shipping_rates
.filter( ( rate ) => rate.selected )
.flatMap( ( rate ) => rate.name );
}
);
return (
<div
className={ classnames(
'wc-block-components-totals-shipping',
className
) }
>
<TotalsItem
label={ __( 'Shipping', 'woo-gutenberg-products-block' ) }
value={
cartHasCalculatedShipping ? (
totalShippingValue
) : (
<NoShippingPlaceholder
showCalculator={ showCalculator }
{ ...calculatorButtonProps }
/>
)
}
description={
<>
{ cartHasCalculatedShipping && (
<>
<ShippingVia
selectedShippingRates={
selectedShippingRates
}
/>
<ShippingAddress
shippingAddress={ shippingAddress }
showCalculator={ showCalculator }
{ ...calculatorButtonProps }
/>
</>
) }
</>
}
currency={ currency }
/>
{ showCalculator && isShippingCalculatorOpen && (
<ShippingCalculator
onUpdate={ () => {
setIsShippingCalculatorOpen( false );
} }
/>
) }
{ showRateSelector && cartHasCalculatedShipping && (
<ShippingRateSelector
hasRates={ hasRates }
shippingRates={ shippingRates }
shippingRatesLoading={ shippingRatesLoading }
/>
) }
</div>
);
};
export default TotalsShipping;

View File

@ -0,0 +1,48 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Notice } from 'wordpress-components';
import classnames from 'classnames';
/**
* Internal dependencies
*/
import ShippingRatesControl from '../../shipping-rates-control';
const ShippingRateSelector = ( {
hasRates,
shippingRates,
shippingRatesLoading,
} ) => {
const legend = hasRates
? __( 'Shipping options', 'woocommerce' )
: __( 'Choose a shipping option', 'woocommerce' );
return (
<fieldset className="wc-block-components-totals-shipping__fieldset">
<legend className="screen-reader-text">{ legend }</legend>
<ShippingRatesControl
className="wc-block-components-totals-shipping__options"
collapsible={ true }
noResultsMessage={
<Notice
isDismissible={ false }
className={ classnames(
'wc-block-components-shipping-rates-control__no-results-notice',
'woocommerce-error'
) }
>
{ __(
'No shipping options were found.',
'woocommerce'
) }
</Notice>
}
shippingRates={ shippingRates }
shippingRatesLoading={ shippingRatesLoading }
/>
</fieldset>
);
};
export default ShippingRateSelector;

View File

@ -0,0 +1,17 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
export const ShippingVia = ( {
selectedShippingRates,
}: {
selectedShippingRates: string[];
} ): JSX.Element => {
return (
<div className="wc-block-components-totals-item__description wc-block-components-totals-shipping__via">
{ __( 'via', 'woo-gutenberg-products-block' ) }{ ' ' }
{ selectedShippingRates.join( ', ' ) }
</div>
);
};

View File

@ -0,0 +1,35 @@
/**
* External dependencies
*/
import { boolean, text } from '@storybook/addon-knobs';
import { currencyKnob } from '@woocommerce/knobs';
/**
* Internal dependencies
*/
import TotalsShipping from '../';
export default {
title: 'WooCommerce Blocks/@blocks-checkout/TotalsShipping',
component: TotalsShipping,
};
export const Default = () => {
const currency = currencyKnob();
const showCalculator = boolean( 'Show calculator', true );
const showRateSelector = boolean( 'Show rate selector', true );
const totalShipping = text( 'Total shipping', '1000' );
const totalShippingTax = text( 'Total shipping tax', '200' );
return (
<TotalsShipping
currency={ currency }
showCalculator={ showCalculator }
showRateSelector={ showRateSelector }
values={ {
total_shipping: totalShipping,
total_shipping_tax: totalShippingTax,
} }
/>
);
};

View File

@ -0,0 +1,42 @@
.wc-block-components-totals-shipping {
// Added extra label for specificity.
fieldset.wc-block-components-totals-shipping__fieldset {
background-color: transparent;
margin: 0;
padding: 0;
border: 0;
}
.wc-block-components-totals-shipping__via {
margin-bottom: $gap;
}
.wc-block-components-totals-shipping__options {
.wc-block-components-radio-control__label,
.wc-block-components-radio-control__description,
.wc-block-components-radio-control__secondary-label,
.wc-block-components-radio-control__secondary-description {
flex-basis: 100%;
text-align: left;
}
}
.wc-block-components-shipping-rates-control__no-results-notice {
margin: 0 0 em($gap-small);
}
.wc-block-components-totals-shipping__change-address-button {
@include link-button();
&:hover,
&:focus,
&:active {
opacity: 0.8;
}
}
}
// Extra classes for specificity.
.theme-twentytwentyone.theme-twentytwentyone.theme-twentytwentyone .wc-block-components-totals-shipping__change-address-button {
@include link-button();
}