woocommerce/plugins/woocommerce-blocks/assets/js/base/components/button/index.tsx

128 lines
2.8 KiB
TypeScript
Raw Normal View History

/**
* External dependencies
*/
import { Button as AriakitButton } from '@ariakit/react';
import { forwardRef } from '@wordpress/element';
import clsx from 'clsx';
import type { ForwardedRef } from 'react';
import type { ButtonProps as AriakitButtonProps } from '@ariakit/react';
import deprecated from '@wordpress/deprecated';
Update Express Payments Loading UI (https://github.com/woocommerce/woocommerce-blocks/pull/4228) * Separate button spinner to separate component for reuse * Use block checkout spinner in loading mask * Block pointer events within loading mask * Give the useRef within useShallowEqual a default value This prevents the potential of having an undefined value returned. * State setter and dispatch are stable These do not need to be used as dependencies. * Prevent re-renders of children when using loading mask. This prevents children being rerendered and losing state. Loading styles are applied instead using a classname, but leaving the divs in place. * Use memoization to to prevent excessive express payment rerenders * Wrap express payment in loading mask * Show loading state after submission * remove eslint exclusion * Move spinner to base components so it's available outside of the checkout package * Avoid extra is-loading classname * Update snaps/fix tests * Remove memorization of payment method content due to stale data * Express payment error handling * Split up payment method context to make it more manageable * Add blocking logic to cart * Update snap * Restore useRef * Fix missing function removed by accident * Fix setActivePaymentMethod and started status (so saved methods still allow express to be initialized) * Loading Mask Todo * Remove boolean shallow equals * Missing dep * Memoize typo * Document changes in useStoreEvents * Replace expressPaymentMethodActive * setExpressPaymentError deprecation * Only change status if an error is passed * Track disabled state via useCheckoutSubmit * useCallback on error message functions * Fix mocks in test
2021-06-16 12:44:40 +00:00
/**
* Internal dependencies
*/
import './style.scss';
import Spinner from '../../../../../packages/components/spinner';
type WCButtonProps = AriakitButtonProps & { children?: React.ReactNode };
export interface ButtonProps extends WCButtonProps {
/**
* Deprecated: Show a spinner. Preferably,
* render a spinner in the button children
* instead.
*
* @default false
*/
showSpinner?: boolean | undefined;
/**
* Button variant
*
* @default 'contained'
*/
variant?: 'text' | 'contained' | 'outlined';
/**
* By default we render a wrapper around the button children,
* but you can opt in to removing it by setting removeTextWrap
* to true.
*
* @default false
*/
removeTextWrap?: boolean;
}
interface LinkProps extends ButtonProps {
/**
* Button href
*/
href: string;
}
/**
* Component that visually renders a button but semantically might be `<button>` or `<a>` depending
* on the props.
*/
const Button = forwardRef< HTMLButtonElement, ButtonProps | LinkProps >(
( props, ref ) => {
if ( 'showSpinner' in props ) {
deprecated( 'showSpinner prop', {
version: '8.9.0',
alternative: 'Render a spinner in the button children instead.',
plugin: 'WooCommerce',
} );
}
const {
className,
showSpinner = false,
children,
variant = 'contained',
// To maintain backward compat we render a wrapper for button text by default,
// but you can opt in to removing it by setting removeTextWrap to true.
removeTextWrap = false,
...rest
} = props;
const buttonClassName = clsx(
'wc-block-components-button',
'wp-element-button',
className,
variant,
{
'wc-block-components-button--loading': showSpinner,
}
);
if ( 'href' in props ) {
return (
<AriakitButton
render={
<a
ref={ ref as ForwardedRef< HTMLAnchorElement > }
href={ props.href }
>
{ showSpinner && <Spinner /> }
<span className="wc-block-components-button__text">
{ children }
</span>
</a>
}
className={ buttonClassName }
{ ...rest }
/>
);
}
const buttonChildren = removeTextWrap ? (
props.children
) : (
<span className="wc-block-components-button__text">
{ props.children }
</span>
);
return (
<AriakitButton
ref={ ref }
className={ buttonClassName }
{ ...rest }
>
{ showSpinner && <Spinner /> }
{ buttonChildren }
</AriakitButton>
);
}
);
export default Button;