Add Slot/Fill to discounts area in cart sidebar (https://github.com/woocommerce/woocommerce-blocks/pull/4248)
* Move text-input to checkout package
* Pass validation props directly to ValidatedTextInput
* Import label relatively instead of from package
* Pass validation functions to ValidatedTextInput
This is so it doesn't need to get them from useValidationContext.
* Add InputProps to ValidatedTextInput
This will be used to control additional props on the input element of TextInput
* Spread inputProps onto <input> element of TextInput
* Export TextInput from @woocommerce/blocks-checkout
* Add @woocommerce/blocks-checkout package to tsconfig
* Allow styling to be applied to number inputs and when value is 0
* Make style order consistent
* Remove inputProps to rely on rest in TextInput
* Add specific prop for the inputErrorComponent
* Only disallow active state if value is 0 AND type is number
* Change all uses of ValidatedTextInput to also pass inputErrorComponent
* Revert "Change all uses of ValidatedTextInput to also pass inputErrorComponent"
This reverts commit ec734b99c20c4d29fcf778714246fc406ee37eaf.
* Revert "Remove inputProps to rely on rest in TextInput"
This reverts commit 1fc64cca4002206423d1fa443ff2d60130ba1ea0.
* Revert "Revert "Change all uses of ValidatedTextInput to also pass inputErrorComponent""
This reverts commit 110e3606a996668be5a32698b634b7706d16cddc.
* Revert "Revert "Remove inputProps to rely on rest in TextInput""
This reverts commit aeb03526c44b3fcc97a719a18930d08157a80baf.
* Don't pass errorMessage to ValidatedTextInput
* Add DiscountsMetaSlot
* Add ExperimentalDiscountsMeta.Slot to Cart sidebar
* Add extra styles for Button and Panel components
* Export ExperimentalDiscountsMeta from checkout package
* Add updateCartFromApi util to @woocommerce/blocks-checkout
* Add comment to updateCartFromApi
* Change updateCartFromApi to TypeScript
* Revert "Move `TextInput` to checkout package and allow it to be used for input type=number (https://github.com/woocommerce/woocommerce-blocks/pull/4238)"
This reverts commit ee9b2d20e0
.
* Stop passing contexts through the discounts slot fill
* Allow ValidatedTextInput to be used for type=number
* Remove contexts from Discounts slot fill
* Update snapshots
* Stop `errorMessage` being spread onto input fields in checkout
* Add paths to tsconfig
* Remove contexts from Discounts slot
* Accept step min and max on ValidatedTextInput
* Remove "no-margin" option on buttons
* Remove spinners from input type number
* Remove `no-top-border` style from panel
* Prevent text in buttons from breaking in the middle of words
* Add checkout package to tsconfig file list
* Stop passing components through DiscountsMetaSlot
This commit is contained in:
parent
749406ecb9
commit
ffa77f26f7
|
@ -40,6 +40,7 @@
|
|||
input[type="tel"],
|
||||
input[type="url"],
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="email"] {
|
||||
@include font-size(regular);
|
||||
background-color: #fff;
|
||||
|
@ -72,9 +73,20 @@
|
|||
}
|
||||
}
|
||||
|
||||
input[type="number"] {
|
||||
-moz-appearance: textfield;
|
||||
|
||||
&::-webkit-outer-spin-button,
|
||||
&::-webkit-inner-spin-button {
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active input[type="tel"],
|
||||
&.is-active input[type="url"],
|
||||
&.is-active input[type="text"],
|
||||
&.is-active input[type="number"],
|
||||
&.is-active input[type="email"] {
|
||||
padding: em($gap-large) 0 em($gap-smallest) $gap;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,13 @@ import { Label } from '@woocommerce/blocks-checkout';
|
|||
*/
|
||||
import './style.scss';
|
||||
|
||||
interface TextInputPropsWithNumberType {
|
||||
type: 'number';
|
||||
step?: number;
|
||||
min?: number;
|
||||
max?: number;
|
||||
}
|
||||
|
||||
interface TextInputProps
|
||||
extends Omit<
|
||||
InputHTMLAttributes< HTMLInputElement >,
|
||||
|
@ -28,7 +35,10 @@ interface TextInputProps
|
|||
onBlur?: ( newValue: string ) => void;
|
||||
}
|
||||
|
||||
const TextInput = forwardRef< HTMLInputElement, TextInputProps >(
|
||||
const TextInput = forwardRef<
|
||||
HTMLInputElement,
|
||||
TextInputProps & ( Record< string, never > | TextInputPropsWithNumberType )
|
||||
>(
|
||||
(
|
||||
{
|
||||
className,
|
||||
|
@ -44,6 +54,9 @@ const TextInput = forwardRef< HTMLInputElement, TextInputProps >(
|
|||
autoComplete = 'off',
|
||||
value = '',
|
||||
onChange,
|
||||
min,
|
||||
max,
|
||||
step,
|
||||
required = false,
|
||||
onBlur = () => {
|
||||
/* Do nothing */
|
||||
|
@ -54,6 +67,28 @@ const TextInput = forwardRef< HTMLInputElement, TextInputProps >(
|
|||
) => {
|
||||
const [ isActive, setIsActive ] = useState( false );
|
||||
|
||||
const numberAttributesFromProps: {
|
||||
[ prop: string ]: string | number | undefined;
|
||||
} =
|
||||
type === 'number'
|
||||
? {
|
||||
step,
|
||||
min,
|
||||
max,
|
||||
}
|
||||
: {};
|
||||
|
||||
const numberProps: {
|
||||
[ prop: string ]: string | number | undefined;
|
||||
} = {};
|
||||
|
||||
Object.keys( numberAttributesFromProps ).forEach( ( key ) => {
|
||||
if ( typeof numberAttributesFromProps[ key ] === 'undefined' ) {
|
||||
return;
|
||||
}
|
||||
numberProps[ key ] = numberAttributesFromProps[ key ];
|
||||
} );
|
||||
|
||||
return (
|
||||
<div
|
||||
className={ classnames(
|
||||
|
@ -87,6 +122,7 @@ const TextInput = forwardRef< HTMLInputElement, TextInputProps >(
|
|||
: ariaDescribedBy
|
||||
}
|
||||
required={ required }
|
||||
{ ...numberProps }
|
||||
/>
|
||||
<Label
|
||||
label={ label }
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
useValidationContext,
|
||||
} from '@woocommerce/base-context';
|
||||
import { withInstanceId } from '@woocommerce/base-hocs/with-instance-id';
|
||||
import { isString } from '@woocommerce/types';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -36,6 +37,7 @@ type ValidatedTextInputProps = (
|
|||
validateOnMount?: boolean;
|
||||
focusOnMount?: boolean;
|
||||
showError?: boolean;
|
||||
errorMessage?: string;
|
||||
onChange: ( newValue: string ) => void;
|
||||
};
|
||||
|
||||
|
@ -49,6 +51,7 @@ const ValidatedTextInput = ( {
|
|||
focusOnMount = false,
|
||||
onChange,
|
||||
showError = true,
|
||||
errorMessage: passedErrorMessage = '',
|
||||
...rest
|
||||
}: ValidatedTextInputProps ) => {
|
||||
const [ isPristine, setIsPristine ] = useState( true );
|
||||
|
@ -123,6 +126,9 @@ const ValidatedTextInput = ( {
|
|||
message?: string;
|
||||
hidden?: boolean;
|
||||
};
|
||||
if ( isString( passedErrorMessage ) && passedErrorMessage !== '' ) {
|
||||
errorMessage.message = passedErrorMessage;
|
||||
}
|
||||
const hasError = errorMessage.message && ! errorMessage.hidden;
|
||||
const describedBy =
|
||||
showError && hasError && getValidationErrorId( errorIdString )
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {},
|
||||
"include": [ ".", "../../../../packages/prices", "../context/hooks", "../../type-defs" ],
|
||||
"include": [ ".", "../../../../packages/prices", "../../../../packages/checkout", "../context", "../../type-defs", "../hocs" ],
|
||||
"exclude": [ "**/test/**" ]
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@ import {
|
|||
TotalsFees,
|
||||
TotalsTaxes,
|
||||
ExperimentalOrderMeta,
|
||||
ExperimentalDiscountsMeta,
|
||||
} from '@woocommerce/blocks-checkout';
|
||||
|
||||
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
|
||||
import {
|
||||
useStoreCartCoupons,
|
||||
|
@ -40,7 +40,6 @@ import CheckoutButton from '../checkout-button';
|
|||
import CartLineItemsTitle from './cart-line-items-title';
|
||||
import CartLineItemsTable from './cart-line-items-table';
|
||||
import { CartExpressPayment } from '../../payment-methods';
|
||||
|
||||
import './style.scss';
|
||||
|
||||
interface CartAttributes {
|
||||
|
@ -114,6 +113,11 @@ const Cart = ( { attributes }: CartProps ) => {
|
|||
cart,
|
||||
};
|
||||
|
||||
const discountsSlotFillProps = {
|
||||
extensions,
|
||||
cart,
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<CartLineItemsTitle itemCount={ cartItemsCount } />
|
||||
|
@ -152,6 +156,10 @@ const Cart = ( { attributes }: CartProps ) => {
|
|||
isLoading={ isApplyingCoupon }
|
||||
/>
|
||||
) }
|
||||
<ExperimentalDiscountsMeta.Slot
|
||||
{ ...discountsSlotFillProps }
|
||||
/>
|
||||
|
||||
{ cartNeedsShipping && (
|
||||
<TotalsShipping
|
||||
showCalculator={ isShippingCalculatorEnabled }
|
||||
|
|
|
@ -455,6 +455,9 @@ exports[`Testing cart Contains a Taxes section if Core options are set to show i
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="wc-block-components-discounts-meta"
|
||||
/>
|
||||
<div
|
||||
class="wc-block-components-totals-shipping"
|
||||
>
|
||||
|
@ -1146,6 +1149,9 @@ exports[`Testing cart Shows individual tax lines if the store is set to do so 1`
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="wc-block-components-discounts-meta"
|
||||
/>
|
||||
<div
|
||||
class="wc-block-components-totals-shipping"
|
||||
>
|
||||
|
@ -1842,6 +1848,9 @@ exports[`Testing cart Shows rate percentages after tax lines if the block is set
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="wc-block-components-discounts-meta"
|
||||
/>
|
||||
<div
|
||||
class="wc-block-components-totals-shipping"
|
||||
>
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import classnames from 'classnames';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { createSlotFill } from '../slot';
|
||||
|
||||
const slotName = '__experimentalDiscountsMeta';
|
||||
|
||||
const {
|
||||
Fill: ExperimentalDiscountsMeta,
|
||||
Slot: DiscountsMetaSlot,
|
||||
} = createSlotFill( slotName );
|
||||
|
||||
const Slot = ( { className, extensions, cart } ) => {
|
||||
return (
|
||||
<DiscountsMetaSlot
|
||||
className={ classnames(
|
||||
className,
|
||||
'wc-block-components-discounts-meta'
|
||||
) }
|
||||
fillProps={ { extensions, cart } }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
ExperimentalDiscountsMeta.Slot = Slot;
|
||||
|
||||
export default ExperimentalDiscountsMeta;
|
|
@ -3,6 +3,7 @@ export * from './utils';
|
|||
export * from './slot';
|
||||
export * from './registry';
|
||||
export { default as ExperimentalOrderMeta } from './order-meta';
|
||||
export { default as ExperimentalDiscountsMeta } from './discounts-meta';
|
||||
export { default as ExperimentalOrderShippingPackages } from './order-shipping-packages';
|
||||
export { default as Panel } from './panel';
|
||||
export { SlotFillProvider } from 'wordpress-components';
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
position: relative;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
word-break: break-word;
|
||||
|
||||
&,
|
||||
&:hover,
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
export * from './validation';
|
||||
export { updateCartFromApi } from './update-cart-from-api';
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { CART_STORE_KEY } from '@woocommerce/block-data';
|
||||
import { select, dispatch } from '@wordpress/data';
|
||||
import type { CartResponse } from '@woocommerce/type-defs/cart-response';
|
||||
|
||||
/**
|
||||
* When executed, this will invalidate the getCartData selector, causing a request to be made
|
||||
* to the API. This is in place to allow extensions to signal that they have modified the cart,
|
||||
* and that it needs to be reloaded in the client.
|
||||
*/
|
||||
export const updateCartFromApi = (): void => {
|
||||
const { getCartData } = select( CART_STORE_KEY );
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore - Can't figure out why invalidateResolutionForStoreSelector isn't available
|
||||
// but it's a standard action dispatched by @wordpress/data.
|
||||
const { invalidateResolutionForStoreSelector, receiveCart } = dispatch(
|
||||
CART_STORE_KEY
|
||||
);
|
||||
invalidateResolutionForStoreSelector( 'getCartData' );
|
||||
const cartData = ( getCartData() as unknown ) as CartResponse;
|
||||
receiveCart( cartData );
|
||||
};
|
|
@ -10,7 +10,8 @@
|
|||
"../assets/js/base/hooks",
|
||||
"../settings/shared/index.ts",
|
||||
"../settings/blocks/index.ts",
|
||||
"../type-defs"
|
||||
"../type-defs",
|
||||
"../assets/js/data"
|
||||
],
|
||||
"exclude": [ "**/test/**" ]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue