Commit 9dc5a15500 for woocommerce

commit 9dc5a15500ac3348d707d3d45ee86c02f06b23f9
Author: Abdullah Ayman <63800091+AbdullahAymanMSRE@users.noreply.github.com>
Date:   Mon Feb 9 09:44:53 2026 +0200

    Enhancement/variation selector attribute options (#63038)

    * refactor: migrate Variation Selector Attribute Options to ToolsPanel

    Replace PanelBody with ToolsPanel in inspector controls.

    Part of #62863
    Related to #59464

    * refactor: clean up imports in Variation Selector Attribute Options

    * refactor: clarify auto-select toggle text in Variation Selector Attribute Options

    Update toggle label from "Auto-select when only one attribute is compatible" to "Auto-select when only one option is available" and improve help text for better clarity.

    * refactor: replace SelectControl with ToggleGroupControl in Variation Selector Attribute Options

    Updated the attribute options interface to use ToggleGroupControl for managing invalid options, enhancing user experience and clarity. Adjusted related tests to reflect the new control structure.

    * chore: add changelog for Variation Selector Attribute Options UI enhancements

    * Add onDeselect handlers and separate ToolsPanelItem for invalid options in AttributeOptionsEdit

      Improves the variation selector's settings panel by:
      - Adding onDeselect handlers to reset optionStyle and autoselect attributes to their defaults
      - Separating invalid options control into its own ToolsPanelItem for better organization
      - Updating resetAll handler to reset both autoselect and disabledAttributesAction attributes

diff --git a/plugins/woocommerce/changelog/enhancement-variation-selector-attribute-options b/plugins/woocommerce/changelog/enhancement-variation-selector-attribute-options
new file mode 100644
index 0000000000..4c4aab0a9e
--- /dev/null
+++ b/plugins/woocommerce/changelog/enhancement-variation-selector-attribute-options
@@ -0,0 +1,4 @@
+Significance: patch
+Type: enhancement
+
+Updated Variation Selector Attribute Options block settings UI for improved clarity
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/variation-selector/attribute-options/block.json b/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/variation-selector/attribute-options/block.json
index cc5caee3a8..d745d5632b 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/variation-selector/attribute-options/block.json
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/variation-selector/attribute-options/block.json
@@ -10,7 +10,8 @@
 	"attributes": {
 		"optionStyle": {
 			"type": "string",
-			"enum": [ "pills", "dropdown" ]
+			"enum": [ "pills", "dropdown" ],
+			"default": "pills"
 		},
 		"autoselect": {
 			"type": "boolean",
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/variation-selector/attribute-options/edit.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/variation-selector/attribute-options/edit.tsx
index 966af28c78..3b4f08f70d 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/variation-selector/attribute-options/edit.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/variation-selector/attribute-options/edit.tsx
@@ -1,20 +1,23 @@
 /**
  * External dependencies
  */
+import clsx from 'clsx';
+import { useCustomDataContext } from '@woocommerce/shared-context';
+import type { ProductResponseAttributeItem } from '@woocommerce/types';
 import { __ } from '@wordpress/i18n';
 import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
 import { type BlockEditProps } from '@wordpress/blocks';
 import {
 	Disabled,
-	PanelBody,
 	SelectControl,
 	ToggleControl,
 	__experimentalToggleGroupControl as ToggleGroupControl,
 	__experimentalToggleGroupControlOption as ToggleGroupControlOption,
+	// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
+	__experimentalToolsPanel as ToolsPanel,
+	// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
+	__experimentalToolsPanelItem as ToolsPanelItem,
 } from '@wordpress/components';
-import { useCustomDataContext } from '@woocommerce/shared-context';
-import type { ProductResponseAttributeItem } from '@woocommerce/types';
-import clsx from 'clsx';

 /**
  * Internal dependencies
@@ -23,7 +26,7 @@ import { useThemeColors } from '../../../../shared/hooks/use-theme-colors';

 interface Attributes {
 	className?: string;
-	optionStyle?: 'pills' | 'dropdown';
+	optionStyle: 'pills' | 'dropdown';
 	autoselect: boolean;
 	disabledAttributesAction: 'disable' | 'hide';
 }
@@ -96,83 +99,122 @@ export default function AttributeOptionsEdit(
 	return (
 		<div { ...blockProps }>
 			<InspectorControls>
-				<PanelBody title={ __( 'Style', 'woocommerce' ) }>
-					<ToggleGroupControl
+				<ToolsPanel
+					label={ __( 'Style', 'woocommerce' ) }
+					resetAll={ () => setAttributes( { optionStyle: 'pills' } ) }
+				>
+					<ToolsPanelItem
+						hasValue={ () => optionStyle !== 'pills' }
 						label={ __( 'Style', 'woocommerce' ) }
-						value={ optionStyle ?? 'pills' }
-						onChange={ ( newOptionStyle ) => {
-							if (
-								newOptionStyle === 'pills' ||
-								newOptionStyle === 'dropdown'
-							) {
-								setAttributes( {
-									optionStyle: newOptionStyle,
-								} );
-							}
-						} }
-						isBlock
-						hideLabelFromVision
-						size="__unstable-large"
+						onDeselect={ () =>
+							setAttributes( { optionStyle: 'pills' } )
+						}
+						isShownByDefault
 					>
-						<ToggleGroupControlOption
-							value="pills"
-							label={ __( 'Pills', 'woocommerce' ) }
-						/>
-						<ToggleGroupControlOption
-							value="dropdown"
-							label={ __( 'Dropdown', 'woocommerce' ) }
-						/>
-					</ToggleGroupControl>
-				</PanelBody>
-				<PanelBody title={ __( 'Auto-select', 'woocommerce' ) }>
-					<ToggleControl
+						<ToggleGroupControl
+							label={ __( 'Style', 'woocommerce' ) }
+							value={ optionStyle }
+							onChange={ ( newOptionStyle ) => {
+								if (
+									newOptionStyle === 'pills' ||
+									newOptionStyle === 'dropdown'
+								) {
+									setAttributes( {
+										optionStyle: newOptionStyle,
+									} );
+								}
+							} }
+							isBlock
+							hideLabelFromVision
+							size="__unstable-large"
+						>
+							<ToggleGroupControlOption
+								value="pills"
+								label={ __( 'Pills', 'woocommerce' ) }
+							/>
+							<ToggleGroupControlOption
+								value="dropdown"
+								label={ __( 'Dropdown', 'woocommerce' ) }
+							/>
+						</ToggleGroupControl>
+					</ToolsPanelItem>
+				</ToolsPanel>
+				<ToolsPanel
+					label={ __( 'Auto-select', 'woocommerce' ) }
+					resetAll={ () =>
+						setAttributes( {
+							autoselect: false,
+							disabledAttributesAction: 'disable',
+						} )
+					}
+				>
+					<ToolsPanelItem
 						label={ __(
-							'Auto-select when only one attribute is compatible',
+							'Auto-select when only one option is available',
 							'woocommerce'
 						) }
-						help={ __(
-							'This controls whether attributes will be auto-selected once upon loading the page and when an attribute is changed by the user. Only attributes with a single compatible value will be auto-selected.',
-							'woocommerce'
-						) }
-						checked={ autoselect }
-						onChange={ () =>
-							setAttributes( { autoselect: ! autoselect } )
+						hasValue={ () => autoselect }
+						onDeselect={ () =>
+							setAttributes( { autoselect: false } )
 						}
-						__nextHasNoMarginBottom
-					/>
-					<SelectControl
-						label={ __(
-							'Values in conflict with current selection',
-							'woocommerce'
-						) }
-						help={ __(
-							'This controls what to do with attribute values that conflict with the current selection.',
-							'woocommerce'
-						) }
-						value={ disabledAttributesAction }
-						options={ [
-							{
-								label: __( 'Hidden', 'woocommerce' ),
-								value: 'hide',
-							},
-							{
-								label: __(
-									'Grayed-out/crossed-out and disabled',
-									'woocommerce'
-								),
-								value: 'disable',
-							},
-						] }
-						onChange={ ( value ) =>
+						isShownByDefault
+					>
+						<ToggleControl
+							label={ __(
+								'Auto-select when only one option is available',
+								'woocommerce'
+							) }
+							help={ __(
+								'Automatically select options on page load or after the shopper changes attributes, when only one valid choice is available.',
+								'woocommerce'
+							) }
+							checked={ autoselect }
+							onChange={ () =>
+								setAttributes( { autoselect: ! autoselect } )
+							}
+							__nextHasNoMarginBottom
+						/>
+					</ToolsPanelItem>
+					<ToolsPanelItem
+						label={ __( 'Invalid options', 'woocommerce' ) }
+						hasValue={ () =>
+							disabledAttributesAction !== 'disable'
+						}
+						onDeselect={ () =>
 							setAttributes( {
-								disabledAttributesAction: value as
-									| 'disable'
-									| 'hide',
+								disabledAttributesAction: 'disable',
 							} )
 						}
-						__nextHasNoMarginBottom
-					/>
-				</PanelBody>
+						isShownByDefault
+					>
+						<ToggleGroupControl
+							label={ __( 'Invalid options', 'woocommerce' ) }
+							help={ __(
+								'Control the display of invalid options.',
+								'woocommerce'
+							) }
+							value={ disabledAttributesAction }
+							onChange={ ( value ) => {
+								if ( value === 'hide' || value === 'disable' ) {
+									setAttributes( {
+										disabledAttributesAction: value,
+									} );
+								}
+							} }
+							isBlock
+							size="__unstable-large"
+						>
+							<ToggleGroupControlOption
+								value="disable"
+								label={ __( 'Grayed-out', 'woocommerce' ) }
+							/>
+							<ToggleGroupControlOption
+								value="hide"
+								label={ __( 'Hidden', 'woocommerce' ) }
+							/>
+						</ToggleGroupControl>
+					</ToolsPanelItem>
+				</ToolsPanel>
 			</InspectorControls>

 			<Disabled>
diff --git a/plugins/woocommerce/client/blocks/tests/e2e/tests/add-to-cart-with-options/add-to-cart-with-options.block_theme.spec.ts b/plugins/woocommerce/client/blocks/tests/e2e/tests/add-to-cart-with-options/add-to-cart-with-options.block_theme.spec.ts
index b0cbe70f88..d0a1b3b6a9 100644
--- a/plugins/woocommerce/client/blocks/tests/e2e/tests/add-to-cart-with-options/add-to-cart-with-options.block_theme.spec.ts
+++ b/plugins/woocommerce/client/blocks/tests/e2e/tests/add-to-cart-with-options/add-to-cart-with-options.block_theme.spec.ts
@@ -1166,21 +1166,32 @@ test.describe( 'Add to Cart + Options Block', () => {
 			}

 			const autoselectInput = page.getByRole( 'checkbox', {
-				name: 'Auto-select when only one attribute is compatible',
+				name: 'Auto-select when only one option is available',
 			} );
-			const disabledAttributesActionInput =
-				page.getByLabel( 'Values in conflict' );
+			const invalidOptionsLabel =
+				disabledAttributesAction === 'disable'
+					? 'Grayed-out'
+					: 'Hidden';
+			const invalidOptionsRadio = page
+				.getByLabel( 'Invalid options' )
+				.getByRole( 'radio', { name: invalidOptionsLabel } );
+
+			const isAutoselectChecked = await autoselectInput.isChecked();
+			const isInvalidOptionSelected =
+				( await invalidOptionsRadio.getAttribute( 'aria-checked' ) ) ===
+				'true';
+
 			if (
-				( await autoselectInput.isChecked() ) !== autoselect ||
-				( await disabledAttributesActionInput.inputValue() ) !==
-					disabledAttributesAction
+				isAutoselectChecked !== autoselect ||
+				! isInvalidOptionSelected
 			) {
 				isOnlyCurrentEntityDirty = false;
 			}
+
 			await autoselectInput.setChecked( autoselect );
-			await disabledAttributesActionInput.selectOption( {
-				value: disabledAttributesAction,
-			} );
+			if ( ! isInvalidOptionSelected ) {
+				await invalidOptionsRadio.click();
+			}
 			if (
 				await page
 					.getByRole( 'region', {