Commit ac502060dd8 for woocommerce
commit ac502060dd8929452ca34fa5664efa324f62aa67
Author: Karol Manijak <20098064+kmanijak@users.noreply.github.com>
Date: Wed Jul 29 07:54:32 2026 +0200
Fix ESLint warnings in Blocks (#65992)
* Harden Blocks ESLint warning coverage
* Add changelog entry for Blocks ESLint hardening
* Preserve quantity selector prop export
* Remove quantity selector prop barrel export
* Fix Blocks JSDoc alignment
* Revert checkout validation error subscription changes
* Clarify checkout validation lint suppressions
* Restore Blocks ESLint warning severities
* Update changelog for Blocks ESLint warning fixes
* Restore the shared Blocks ESLint configuration
diff --git a/plugins/woocommerce/changelog/57341-blocks-eslint-warnings b/plugins/woocommerce/changelog/57341-blocks-eslint-warnings
new file mode 100644
index 00000000000..a17337f136f
--- /dev/null
+++ b/plugins/woocommerce/changelog/57341-blocks-eslint-warnings
@@ -0,0 +1,3 @@
+Significance: patch
+Type: dev
+Comment: Fix ESLint warnings in Blocks.
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/address-autocomplete/address-autocomplete.tsx b/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/address-autocomplete/address-autocomplete.tsx
index 6227a7a9964..f5b1ac2af89 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/address-autocomplete/address-autocomplete.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/address-autocomplete/address-autocomplete.tsx
@@ -240,7 +240,8 @@ export const AddressAutocomplete = ( {
const parentElement = inputElement.parentElement;
if ( parentElement ) {
// Store current focus state and cursor position
- const hasFocus = document.activeElement === inputElement;
+ const hasFocus =
+ inputElement.ownerDocument.activeElement === inputElement;
const selectionStart = inputElement.selectionStart;
const selectionEnd = inputElement.selectionEnd;
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/address-autocomplete/test/integration.tsx b/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/address-autocomplete/test/integration.tsx
index f9f41ac118d..a734377a888 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/address-autocomplete/test/integration.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/address-autocomplete/test/integration.tsx
@@ -52,7 +52,6 @@ jest.mock( '@woocommerce/settings', () => ( {
// jsdom/userEvent don't fully replicate. The suggestion rendering path
// never fires because the typing guard isn't tripped. These tests should
// be migrated to Playwright E2E where real browser events are available.
-// eslint-disable-next-line jest/no-disabled-tests
describe.skip( 'Suggestions - when rendered in AddressAutocomplete component', () => {
beforeAll( () => {
// Mock use select so we can override it when wc/store/cart or
@@ -611,7 +610,7 @@ describe.skip( 'Suggestions - when rendered in AddressAutocomplete component', (
await act( async () => {
input.focus();
} );
- expect( document.activeElement ).toBe( input );
+ expect( input ).toHaveFocus();
// Type to trigger suggestions
await act( async () => {
@@ -631,21 +630,21 @@ describe.skip( 'Suggestions - when rendered in AddressAutocomplete component', (
} );
// Focus should remain on input
- expect( document.activeElement ).toBe( input );
+ expect( input ).toHaveFocus();
await act( async () => {
await userEvent.type( input, '{arrowdown}' );
} );
// Focus should still be on input
- expect( document.activeElement ).toBe( input );
+ expect( input ).toHaveFocus();
await act( async () => {
await userEvent.type( input, '{arrowup}' );
} );
// Focus should still be on input
- expect( document.activeElement ).toBe( input );
+ expect( input ).toHaveFocus();
} );
it( 'Pressing Escape key hides suggestions and resets all ARIA states', async () => {
@@ -720,7 +719,7 @@ describe.skip( 'Suggestions - when rendered in AddressAutocomplete component', (
expect( input ).not.toHaveAttribute( 'aria-activedescendant' );
// Verify focus remains on input
- expect( document.activeElement ).toBe( input );
+ expect( input ).toHaveFocus();
// Verify input value is preserved
expect( input ).toHaveValue( '1234' );
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/components/index.ts b/plugins/woocommerce/client/blocks/assets/js/base/components/index.ts
index 722a7f190c5..aec5e2ccb25 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/components/index.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/base/components/index.ts
@@ -19,8 +19,8 @@ export * from './price-slider';
export * from './product-list';
export * from './product-name';
export * from './product-price';
-export * from './product-rating';
-export * from './quantity-selector';
+export { default as ProductRating } from './product-rating';
+export { default as QuantitySelector } from './quantity-selector';
export * from './read-more';
export * from './reviews';
export * from './select';
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx b/plugins/woocommerce/client/blocks/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx
index 7e3272d7317..bf9cd430cf1 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx
@@ -133,7 +133,7 @@ export const CheckoutEventsProvider = ( {
void __internalSetRegisteredExpressPaymentMethods(
convertToPlainExpressPaymentMethods( registeredMethods )
);
- }, [ registeredMethods ] );
+ }, [ __internalSetRegisteredExpressPaymentMethods, registeredMethods ] );
// Update the payment method store when paymentMethods or expressPaymentMethods changes.
// Ensure this happens in the editor even if paymentMethods is empty. This won't happen instantly when the objects
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/variation-selector/frontend.ts b/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/variation-selector/frontend.ts
index 8dca45a7d54..cd10cf2a5f2 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/variation-selector/frontend.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/variation-selector/frontend.ts
@@ -510,7 +510,7 @@ const { actions, state } = store< VariableProductAddToCartWithOptionsStore >(
}
// Let's not do anything if the user is typing in the input.
- if ( ref === document.activeElement ) {
+ if ( ref === ref.ownerDocument.activeElement ) {
return;
}
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/customer-address.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/customer-address.tsx
index ddbf4d529fc..3b4797211ef 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/customer-address.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/customer-address.tsx
@@ -63,6 +63,7 @@ const CustomerAddress = () => {
editingBillingAddress,
billingAddress,
isInitialized,
+ setEditingBillingAddress,
validationErrors,
] );
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-address-block/customer-address.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-address-block/customer-address.tsx
index c91235dfbc0..4749d57e2b1 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-address-block/customer-address.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-address-block/customer-address.tsx
@@ -65,6 +65,7 @@ const CustomerAddress = () => {
editingShippingAddress,
shippingAddress,
isInitialized,
+ setEditingShippingAddress,
validationErrors,
] );
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/classic-template/index.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/classic-template/index.tsx
index 1d45cd0dc6c..954979c4d19 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/classic-template/index.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/classic-template/index.tsx
@@ -208,7 +208,7 @@ const Edit = ( {
template: templateSlug ?? attributes.template,
align: attributes.align ?? 'wide',
} ),
- [ attributes.align, attributes.template, setAttributes ]
+ [ attributes.align, attributes.template, setAttributes, templateSlug ]
);
const { getDescription, getSkeleton, blockifyConfig } =
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/use-background-image.ts b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/use-background-image.ts
index b1474edbe61..3e137316698 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/use-background-image.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/featured-items/use-background-image.ts
@@ -130,9 +130,7 @@ export function useBackgroundImage( {
return false;
} )();
- if ( isImageBgTransparent !== hasTransparentPixels ) {
- setIsImageBgTransparent( hasTransparentPixels );
- }
+ setIsImageBgTransparent( hasTransparentPixels );
};
} else {
setIsImageBgTransparent( true );
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/use-carousel-layout-adjustments.ts b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/use-carousel-layout-adjustments.ts
index 2a4a40b6095..478615ff2f3 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/use-carousel-layout-adjustments.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/use-carousel-layout-adjustments.ts
@@ -255,7 +255,7 @@ const useCarouselLayoutAdjustments = (
);
useEffect( () => {
- if ( ! clientId ) {
+ if ( ! clientId || ! productCollectionBlock ) {
return;
}
@@ -280,7 +280,13 @@ const useCarouselLayoutAdjustments = (
}
previousLayoutType.current = displayLayout.type;
- }, [ displayLayout.type, clientId, actions, collection ] );
+ }, [
+ displayLayout.type,
+ clientId,
+ actions,
+ collection,
+ productCollectionBlock,
+ ] );
};
export default useCarouselLayoutAdjustments;
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/utils.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/utils.tsx
index ee48b5339ed..e193990baf6 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/utils.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/utils.tsx
@@ -443,6 +443,7 @@ export const useSetPreviewState = ( {
setAttributes,
usesReferencePreviewMessage,
isUsingReferencePreviewMode,
+ __unstableMarkNextChangeAsNotPersistent,
] );
// Running setPreviewState function provided by Collection, if it exists.
@@ -504,6 +505,7 @@ export const useSetPreviewState = ( {
setAttributes,
setPreviewState,
isUsingReferencePreviewMode,
+ __unstableMarkNextChangeAsNotPersistent,
] );
};
export const getDefaultQueryForSettingsSection = (
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-search/inspector-controls.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/product-search/inspector-controls.tsx
index 3212dd9e76e..d10acefa8e7 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-search/inspector-controls.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-search/inspector-controls.tsx
@@ -44,7 +44,7 @@ const ProductSearchControls = ( props: ProductSearchBlockProps ) => {
) {
setInitialPosition( buttonPosition );
}
- }, [ buttonPosition ] );
+ }, [ buttonPosition, initialPosition ] );
return (
<InspectorControls group="styles">
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/single-product/edit/index.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/single-product/edit/index.tsx
index c8aa327578e..193c7720e34 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/single-product/edit/index.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/single-product/edit/index.tsx
@@ -101,7 +101,7 @@ const Editor = ( {
}, [ attributes, productId, productPreview, setAttributes ] );
useEffect( () => {
- if ( isInvalidProductId && ! isEditing ) {
+ if ( isInvalidProductId ) {
setIsEditing( true );
}
}, [ isInvalidProductId ] );
diff --git a/plugins/woocommerce/client/blocks/assets/js/data/cart/thunks.ts b/plugins/woocommerce/client/blocks/assets/js/data/cart/thunks.ts
index d77056087d3..161cf89cf0e 100644
--- a/plugins/woocommerce/client/blocks/assets/js/data/cart/thunks.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/data/cart/thunks.ts
@@ -133,7 +133,7 @@ export const receiveError =
* Updates the checkout store with the shopper's collection preference based on
* the selected shipping rates in the cart.
*
- * @param {CartResponse} response
+ * @param {CartResponse} response
* @param {CartThunkArgs['registry']} registry
*/
const syncPrefersCollectionFromSelectedShippingRates = (
diff --git a/plugins/woocommerce/client/blocks/assets/js/editor-components/default-notice/index.tsx b/plugins/woocommerce/client/blocks/assets/js/editor-components/default-notice/index.tsx
index 708a4d3f7d8..db78eb095c0 100644
--- a/plugins/woocommerce/client/blocks/assets/js/editor-components/default-notice/index.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/editor-components/default-notice/index.tsx
@@ -32,17 +32,20 @@ export function DefaultNotice( { block }: { block: string } ) {
// Everything below works the same for Cart/Checkout
const { saveEntityRecord } = useDispatch( coreStore );
const { editPost, savePost } = useDispatch( CORE_EDITOR_STORE );
- const { slug, postPublished, currentPostId } = useSelect( ( select ) => {
- const { getEntityRecord } = select( coreStore );
- const editor = select( CORE_EDITOR_STORE );
- return {
- slug:
- getEntityRecord( 'postType', 'page', ORIGINAL_PAGE_ID )?.slug ||
- block,
- postPublished: editor?.isCurrentPostPublished?.() ?? false,
- currentPostId: editor?.getCurrentPostId?.() ?? 0,
- };
- }, [] );
+ const { slug, postPublished, currentPostId } = useSelect(
+ ( select ) => {
+ const { getEntityRecord } = select( coreStore );
+ const editor = select( CORE_EDITOR_STORE );
+ return {
+ slug:
+ getEntityRecord( 'postType', 'page', ORIGINAL_PAGE_ID )
+ ?.slug || block,
+ postPublished: editor?.isCurrentPostPublished?.() ?? false,
+ currentPostId: editor?.getCurrentPostId?.() ?? 0,
+ };
+ },
+ [ ORIGINAL_PAGE_ID, block ]
+ );
const [ settingStatus, setStatus ] = useState( 'pristine' );
const updatePage = useCallback( () => {
setStatus( 'updating' );
diff --git a/plugins/woocommerce/client/blocks/assets/js/types/type-defs/cart.js b/plugins/woocommerce/client/blocks/assets/js/types/type-defs/cart.js
index 67149a1bf0c..fb42fb618b8 100644
--- a/plugins/woocommerce/client/blocks/assets/js/types/type-defs/cart.js
+++ b/plugins/woocommerce/client/blocks/assets/js/types/type-defs/cart.js
@@ -14,15 +14,15 @@
/**
* @typedef {Object} CartItemImage
*
- * @property {number} id Image id.
- * @property {string} src Full size image URL.
- * @property {string} thumbnail Thumbnail URL.
+ * @property {number} id Image id.
+ * @property {string} src Full size image URL.
+ * @property {string} thumbnail Thumbnail URL.
* @property {string} srcset Full size image srcset for responsive images.
* @property {string} sizes Full size image sizes for responsive images.
* @property {string} thumbnail_srcset Thumbnail srcset for responsive images.
* @property {string} thumbnail_sizes Thumbnail sizes for responsive images.
- * @property {string} name Image name.
- * @property {string} alt Image alternative text.
+ * @property {string} name Image name.
+ * @property {string} alt Image alternative text.
*/
/**
diff --git a/plugins/woocommerce/client/blocks/packages/components/text-input/stories/validated-text-input.stories.tsx b/plugins/woocommerce/client/blocks/packages/components/text-input/stories/validated-text-input.stories.tsx
index f58fdcdc603..648b5b74be0 100644
--- a/plugins/woocommerce/client/blocks/packages/components/text-input/stories/validated-text-input.stories.tsx
+++ b/plugins/woocommerce/client/blocks/packages/components/text-input/stories/validated-text-input.stories.tsx
@@ -16,6 +16,14 @@ import '../style.scss';
import '../../validation-input-error/style.scss';
import { ValidatedTextInputProps } from '../types';
+const getFormattedValue = (
+ val: string | number | readonly string[] | undefined,
+ customFormatter?: ValidatedTextInputProps[ 'customFormatter' ]
+) => {
+ const stringVal = typeof val === 'string' ? val : String( val || '' );
+ return customFormatter ? customFormatter( stringVal ) : stringVal;
+};
+
export default {
title: 'External Components/ValidatedTextInput',
component: ValidatedTextInput,
@@ -217,29 +225,20 @@ export default {
const Template: StoryFn< ValidatedTextInputProps > = ( args ) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [ _, updateArgs ] = useArgs();
- const getFormattedValue = (
- val: string | number | readonly string[] | undefined
- ) => {
- const stringVal = typeof val === 'string' ? val : String( val || '' );
- return args.customFormatter
- ? args.customFormatter( stringVal )
- : stringVal;
- };
+ const { customFormatter } = args;
const [ inputValue, setInputValue ] = useState(
- getFormattedValue( args.value )
+ getFormattedValue( args.value, customFormatter )
);
const { setValidationErrors, showValidationError } =
useDispatch( validationStore );
useEffect( () => {
- setInputValue( getFormattedValue( args.value ) );
- }, [ args.value, args.customFormatter ] );
+ setInputValue( getFormattedValue( args.value, customFormatter ) );
+ }, [ args.value, customFormatter ] );
const onChange = ( newValue: string ) => {
- const formattedValue = args.customFormatter
- ? args.customFormatter( newValue )
- : newValue;
+ const formattedValue = getFormattedValue( newValue, customFormatter );
setInputValue( formattedValue );