From 3a5721c0d817ace65857488a03b65b02a299199d Mon Sep 17 00:00:00 2001 From: Sam Seay Date: Fri, 3 May 2024 11:28:39 +0800 Subject: [PATCH] Replace @wordpress/components Button, Radio, RadioGroup with Ariakit Button (#45974) --- .../js/base/components/button/index.tsx | 119 +++++++++++++----- .../totals/coupon/test/index.tsx | 4 + .../js/base/components/drawer/index.tsx | 11 +- .../js/base/components/drawer/style.scss | 18 +-- .../base/components/notice-banner/index.tsx | 9 +- .../cart-checkout/cart-events/test/index.tsx | 3 + .../proceed-to-checkout-block/test/block.tsx | 4 + .../assets/js/blocks/cart/test/block.js | 4 + .../checkout-shipping-method-block/block.tsx | 43 ++++--- .../checkout-shipping-method-block/style.scss | 10 +- .../assets/js/blocks/checkout/test/block.js | 4 + .../woocommerce-blocks/bin/webpack-helpers.js | 2 + plugins/woocommerce-blocks/package.json | 1 + ...k.shopper.block_theme.side_effects.spec.ts | 6 +- .../45974-dev-introduce-ariakit-button | 4 + pnpm-lock.yaml | 31 +++++ 16 files changed, 204 insertions(+), 69 deletions(-) create mode 100644 plugins/woocommerce/changelog/45974-dev-introduce-ariakit-button diff --git a/plugins/woocommerce-blocks/assets/js/base/components/button/index.tsx b/plugins/woocommerce-blocks/assets/js/base/components/button/index.tsx index eda66687925..b0e1412fd9e 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/button/index.tsx +++ b/plugins/woocommerce-blocks/assets/js/base/components/button/index.tsx @@ -1,9 +1,12 @@ /** * External dependencies */ -import { Button as WPButton } from 'wordpress-components'; -import type { Button as WPButtonType } from '@wordpress/components'; +import { Button as AriakitButton } from '@ariakit/react'; +import { forwardRef } from '@wordpress/element'; import classNames from 'classnames'; +import type { ForwardedRef } from 'react'; +import type { ButtonProps as AriakitButtonProps } from '@ariakit/react'; +import deprecated from '@wordpress/deprecated'; /** * Internal dependencies @@ -11,60 +14,114 @@ import classNames from 'classnames'; import './style.scss'; import Spinner from '../../../../../packages/components/spinner'; -export interface ButtonProps - extends Omit< WPButtonType.ButtonProps, 'variant' | 'href' > { +type WCButtonProps = AriakitButtonProps & { children?: React.ReactNode }; + +export interface ButtonProps extends WCButtonProps { /** - * Show spinner + * 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'; /** - * The URL the button should link to. + * 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 */ - href?: string | undefined; + removeTextWrap?: boolean; } -export interface AnchorProps extends Omit< ButtonProps, 'href' > { +interface LinkProps extends ButtonProps { /** * Button href */ - href?: string | undefined; + href: string; } /** * Component that visually renders a button but semantically might be `, closeButtonWrapper ) : null; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/drawer/style.scss b/plugins/woocommerce-blocks/assets/js/base/components/drawer/style.scss index 62ac846c723..36b1c516a0b 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/drawer/style.scss +++ b/plugins/woocommerce-blocks/assets/js/base/components/drawer/style.scss @@ -83,20 +83,25 @@ $drawer-animation-duration: 0.3s; transform: translateX(min(100%, var(--drawer-width))); } -.wc-block-components-drawer__screen-overlay--with-slide-out .wc-block-components-drawer { +.wc-block-components-drawer__screen-overlay--with-slide-out +.wc-block-components-drawer { transition: transform $drawer-animation-duration; } -.wc-block-components-drawer__screen-overlay--with-slide-in .wc-block-components-drawer { +.wc-block-components-drawer__screen-overlay--with-slide-in +.wc-block-components-drawer { animation-duration: $drawer-animation-duration; animation-name: slidein; } -.rtl .wc-block-components-drawer__screen-overlay--with-slide-in .wc-block-components-drawer { +.rtl +.wc-block-components-drawer__screen-overlay--with-slide-in +.wc-block-components-drawer { animation-name: rtlslidein; } -.wc-block-components-drawer__screen-overlay--is-hidden .wc-block-components-drawer { +.wc-block-components-drawer__screen-overlay--is-hidden +.wc-block-components-drawer { transform: translateX(0); } @@ -112,7 +117,7 @@ $drawer-animation-duration: 0.3s; } // Important rules are needed to reset button styles. -.wc-block-components-drawer__close { +.wc-block-components-button.wc-block-components-drawer__close { @include reset-box(); background: transparent !important; color: inherit !important; @@ -140,9 +145,6 @@ $drawer-animation-duration: 0.3s; outline: none; } - > span { - @include visually-hidden(); - } svg { fill: currentColor; display: block; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/notice-banner/index.tsx b/plugins/woocommerce-blocks/assets/js/base/components/notice-banner/index.tsx index 74a3919da57..2a7d631a0ee 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/notice-banner/index.tsx +++ b/plugins/woocommerce-blocks/assets/js/base/components/notice-banner/index.tsx @@ -74,11 +74,12 @@ const NoticeBanner = ( { { !! isDismissible && ( ) } ); diff --git a/plugins/woocommerce-blocks/assets/js/base/context/providers/cart-checkout/cart-events/test/index.tsx b/plugins/woocommerce-blocks/assets/js/base/context/providers/cart-checkout/cart-events/test/index.tsx index 48ab11154a7..38a87236f02 100644 --- a/plugins/woocommerce-blocks/assets/js/base/context/providers/cart-checkout/cart-events/test/index.tsx +++ b/plugins/woocommerce-blocks/assets/js/base/context/providers/cart-checkout/cart-events/test/index.tsx @@ -33,6 +33,9 @@ describe( 'CartEventsProvider', () => { ); + // TODO: Fix a recent deprecation of showSpinner prop of Button called in this component. + expect( console ).toHaveWarned(); + expect( screen.getByText( 'Mock observer' ) ).toBeInTheDocument(); const button = screen.getByText( 'Proceed to Checkout' ); diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart/inner-blocks/proceed-to-checkout-block/test/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/cart/inner-blocks/proceed-to-checkout-block/test/block.tsx index 9f0bcd4505a..821fedf24ce 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/cart/inner-blocks/proceed-to-checkout-block/test/block.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/cart/inner-blocks/proceed-to-checkout-block/test/block.tsx @@ -23,6 +23,10 @@ describe( 'Proceed to checkout block', () => { render( ); + + // TODO: Fix a recent deprecation of showSpinner prop of Button called in this component. + expect( console ).toHaveWarned(); + expect( screen.getByText( 'Proceed to step two' ) ).toBeInTheDocument(); } ); it( 'allows the link to be filtered', () => { diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart/test/block.js b/plugins/woocommerce-blocks/assets/js/blocks/cart/test/block.js index dfca48b4b9b..d7968ac6e7c 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/cart/test/block.js +++ b/plugins/woocommerce-blocks/assets/js/blocks/cart/test/block.js @@ -92,6 +92,10 @@ describe( 'Testing cart', () => { it( 'renders cart if there are items in the cart', async () => { render( ); + + // TODO: Fix a recent deprecation of showSpinner prop of Button called in this component. + expect( console ).toHaveWarned(); + await waitFor( () => expect( fetchMock ).toHaveBeenCalled() ); expect( diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-method-block/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-method-block/block.tsx index 2928c420607..34ee83c72a3 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-method-block/block.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-method-block/block.tsx @@ -3,10 +3,6 @@ */ import { __ } from '@wordpress/i18n'; import { useShippingData } from '@woocommerce/base-context/hooks'; -import { - __experimentalRadio as Radio, - __experimentalRadioGroup as RadioGroup, -} from 'wordpress-components'; import classnames from 'classnames'; import { Icon, store, shipping } from '@wordpress/icons'; import { useEffect } from '@wordpress/element'; @@ -22,6 +18,7 @@ import { RatePrice, getLocalPickupPrices, getShippingPrices } from './shared'; import type { minMaxPrices } from './shared'; import { defaultLocalPickupText, defaultShippingText } from './constants'; import { shippingAddressHasValidationErrors } from '../../../../data/cart/utils'; +import Button from '../../../../base/components/button'; const SHIPPING_RATE_ERROR = { hidden: true, @@ -35,6 +32,7 @@ const LocalPickupSelector = ( { showIcon, toggleText, multiple, + onClick, }: { checked: string; rate: minMaxPrices; @@ -42,10 +40,13 @@ const LocalPickupSelector = ( { showIcon: boolean; toggleText: string; multiple: boolean; + onClick: () => void; } ) => { return ( - ) } - + ); }; @@ -81,6 +82,7 @@ const ShippingSelector = ( { showPrice, showIcon, toggleText, + onClick, shippingCostRequiresAddress = false, }: { checked: string; @@ -88,6 +90,7 @@ const ShippingSelector = ( { showPrice: boolean; showIcon: boolean; shippingCostRequiresAddress: boolean; + onClick: () => void; toggleText: string; } ) => { const hasShippableRates = useSelect( ( select ) => { @@ -128,8 +131,10 @@ const ShippingSelector = ( { ); return ( - { showPrice === true && Price } - + ); }; + const Block = ( { checked, onChange, @@ -178,15 +184,17 @@ const Block = ( { ); return ( - { + onChange( 'shipping' ); + } } rate={ getShippingPrices( shippingRates[ 0 ]?.shipping_rates ) } showPrice={ showPrice } showIcon={ showIcon } @@ -195,6 +203,9 @@ const Block = ( { /> { + onChange( 'pickup' ); + } } rate={ getLocalPickupPrices( shippingRates[ 0 ]?.shipping_rates ) } @@ -203,7 +214,7 @@ const Block = ( { showIcon={ showIcon } toggleText={ localPickupTextFromSettings } /> - + ); }; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-method-block/style.scss b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-method-block/style.scss index b5a30c9bc7a..d9242856932 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-method-block/style.scss +++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-method-block/style.scss @@ -5,8 +5,9 @@ justify-content: space-between; } -.edit-post-visual-editor .wc-block-checkout__shipping-method-option, -.wc-block-checkout__shipping-method-option { +.edit-post-visual-editor +.wc-block-components-button.wc-block-checkout__shipping-method-option, +.wc-block-components-button.wc-block-checkout__shipping-method-option { flex-grow: 1; display: flex; flex-direction: row; @@ -34,6 +35,11 @@ &.wc-block-checkout__shipping-method-option--selected { outline: 1px solid $universal-border-strong; background-color: $universal-background; + + &:focus { + outline: 1px solid $universal-border-strong; + background-color: $universal-background; + } } } diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/test/block.js b/plugins/woocommerce-blocks/assets/js/blocks/checkout/test/block.js index 3e07b587a3f..a3fcec5c95e 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/test/block.js +++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/test/block.js @@ -104,6 +104,10 @@ describe( 'Testing cart', () => { it( 'Renders checkout if there are items in the cart', async () => { render( ); + + // TODO: Fix a recent deprecation of showSpinner prop of Button called in this component. + expect( console ).toHaveWarned(); + await waitFor( () => expect( fetchMock ).toHaveBeenCalled() ); expect( screen.getByText( /Place Order/i ) ).toBeInTheDocument(); diff --git a/plugins/woocommerce-blocks/bin/webpack-helpers.js b/plugins/woocommerce-blocks/bin/webpack-helpers.js index b3f2c158023..b09d2419446 100644 --- a/plugins/woocommerce-blocks/bin/webpack-helpers.js +++ b/plugins/woocommerce-blocks/bin/webpack-helpers.js @@ -99,6 +99,8 @@ const getAlias = ( options = {} ) => { __dirname, `../assets/js/templates/` ), + 'react/jsx-dev-runtime': require.resolve( 'react/jsx-dev-runtime.js' ), + 'react/jsx-runtime': require.resolve( 'react/jsx-runtime.js' ), }; }; diff --git a/plugins/woocommerce-blocks/package.json b/plugins/woocommerce-blocks/package.json index 9895a0ff6e3..7775ceb64ef 100644 --- a/plugins/woocommerce-blocks/package.json +++ b/plugins/woocommerce-blocks/package.json @@ -280,6 +280,7 @@ "pnpm": "^8.12.1" }, "dependencies": { + "@ariakit/react": "^0.4.4", "@dnd-kit/core": "^6.1.0", "@dnd-kit/modifiers": "^6.0.1", "@dnd-kit/sortable": "^7.0.2", diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/cart/cart-block.shopper.block_theme.side_effects.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/cart/cart-block.shopper.block_theme.side_effects.spec.ts index 94c5e06d0f4..5b6e9edd273 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/cart/cart-block.shopper.block_theme.side_effects.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/cart/cart-block.shopper.block_theme.side_effects.spec.ts @@ -173,7 +173,7 @@ test.describe( 'Shopper → Cart block', () => { // Verify the "Proceed to Checkout" button is disabled during network request await expect( - page.getByRole( 'button', { name: 'Proceed to Checkout' } ) + page.getByRole( 'link', { name: 'Proceed to Checkout' } ) ).toBeDisabled(); // Verify the "Proceed to Checkout" button is enabled after network request @@ -195,7 +195,7 @@ test.describe( 'Shopper → Cart block', () => { .click(); // Verify the "Proceed to Checkout" button is disabled during network request await expect( - page.getByRole( 'button', { name: 'Proceed to Checkout' } ) + page.getByRole( 'link', { name: 'Proceed to Checkout' } ) ).toBeDisabled(); // Verify the "Proceed to Checkout" button is enabled after network request @@ -215,7 +215,7 @@ test.describe( 'Shopper → Cart block', () => { .click(); // Verify the "Proceed to Checkout" button is disabled during network request await expect( - page.getByRole( 'button', { name: 'Proceed to Checkout' } ) + page.getByRole( 'link', { name: 'Proceed to Checkout' } ) ).toBeDisabled(); // Verify the "Proceed to Checkout" button is enabled after network request diff --git a/plugins/woocommerce/changelog/45974-dev-introduce-ariakit-button b/plugins/woocommerce/changelog/45974-dev-introduce-ariakit-button new file mode 100644 index 00000000000..d07e43d25d6 --- /dev/null +++ b/plugins/woocommerce/changelog/45974-dev-introduce-ariakit-button @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +In blocks migrate `@wordpress/components` Button to Ariakit, replace `__experimentalRadio/RadioGroup` with Ariakit Button. \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 18e3ca42e68..a8ea372c03d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3857,6 +3857,9 @@ importers: plugins/woocommerce-blocks: dependencies: + '@ariakit/react': + specifier: ^0.4.4 + version: 0.4.5(react-dom@17.0.2)(react@17.0.2) '@dnd-kit/core': specifier: ^6.1.0 version: 6.1.0(react-dom@17.0.2)(react@17.0.2) @@ -5069,6 +5072,10 @@ packages: /@ariakit/core@0.3.8: resolution: {integrity: sha512-LlSCwbyyozMX4ZEobpYGcv1LFqOdBTdTYPZw3lAVgLcFSNivsazi3NkKM9qNWNIu00MS+xTa0+RuIcuWAjlB2Q==} + /@ariakit/core@0.4.5: + resolution: {integrity: sha512-e294+bEcyzt/H/kO4fS5/czLAlkF7PY+Kul3q2z54VY+GGay8NlVs9UezAB7L4jUBlYRAXwp7/1Sq3R7b+MZ7w==} + dev: false + /@ariakit/react-core@0.3.9(react-dom@17.0.2)(react@17.0.2): resolution: {integrity: sha512-K1Rcxr6FpF0n3L7Uvo+e5hm+zqoZmXLRcYF/skI+/j+ole+uNbnsnfGhG1avqJlklqH4bmkFkjZzmMdOnUC0Ig==} peerDependencies: @@ -5081,6 +5088,19 @@ packages: react-dom: 17.0.2(react@17.0.2) use-sync-external-store: 1.2.0(react@17.0.2) + /@ariakit/react-core@0.4.5(react-dom@17.0.2)(react@17.0.2): + resolution: {integrity: sha512-ciTYPwpj/+mdA+EstveEnoygbx5e4PXQJxfkLKy4lkTkDJJUS9GcbYhdnIFJVUta6P1YFvzkIKo+/y9mcbMKJg==} + peerDependencies: + react: ^17.0.2 + react-dom: ^17.0.0 || ^18.0.0 + dependencies: + '@ariakit/core': 0.4.5 + '@floating-ui/dom': 1.5.3 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + use-sync-external-store: 1.2.0(react@17.0.2) + dev: false + /@ariakit/react@0.3.9(react-dom@17.0.2)(react@17.0.2): resolution: {integrity: sha512-gC+gibh2go8wvBqzYXavlHKwAfmee5GUMrPSQ9WBBLIfm9nQElujxcHJydaRx+ULR5FbOnbZVC3vU2ic8hSrNw==} peerDependencies: @@ -5091,6 +5111,17 @@ packages: react: 17.0.2 react-dom: 17.0.2(react@17.0.2) + /@ariakit/react@0.4.5(react-dom@17.0.2)(react@17.0.2): + resolution: {integrity: sha512-GUHxaOY1JZrJUHkuV20IY4NWcgknhqTQM0qCQcVZDCi+pJiWchUjTG+UyIr/Of02hU569qnQ7yovskCf+V3tNg==} + peerDependencies: + react: ^17.0.2 + react-dom: ^17.0.0 || ^18.0.0 + dependencies: + '@ariakit/react-core': 0.4.5(react-dom@17.0.2)(react@17.0.2) + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + dev: false + /@automattic/calypso-color-schemes@2.1.1: resolution: {integrity: sha512-X5gmQEDJVtw8N9NARgZGM/pmalfapV8ZyRzEn2o0sCLmTAXGYg6A28ucLCQdBIn1l9t2rghBDFkY71vyqjyyFQ==} dev: false