Commit c0f025744b for woocommerce

commit c0f025744b778ca725f380fd8a729483af7c7e87
Author: Amit Raj <77401999+amitraj2203@users.noreply.github.com>
Date:   Fri May 30 17:49:58 2025 +0530

    Fix: WooCommerce Blocks Storybook bugs (#58053)

diff --git a/plugins/woocommerce/changelog/58053-fix-woocommerce-blocks-storybook-bugs b/plugins/woocommerce/changelog/58053-fix-woocommerce-blocks-storybook-bugs
new file mode 100644
index 0000000000..b7ab967114
--- /dev/null
+++ b/plugins/woocommerce/changelog/58053-fix-woocommerce-blocks-storybook-bugs
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix various component functionality and styling issues in Storybook implementation.
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/components/country-input/stories/index.stories.tsx b/plugins/woocommerce/client/blocks/assets/js/base/components/country-input/stories/index.stories.tsx
index 7ab78ae523..0276b5311b 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/components/country-input/stories/index.stories.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/base/components/country-input/stories/index.stories.tsx
@@ -21,7 +21,7 @@ export default {
 		countries,
 		autoComplete: 'off',
 		id: 'country',
-		label: 'Countries: ',
+		label: 'Country: ',
 		required: false,
 	},
 	argTypes: {
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/components/quantity-selector/index.tsx b/plugins/woocommerce/client/blocks/assets/js/base/components/quantity-selector/index.tsx
index ee83e68874..6b8d8ec2a2 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/components/quantity-selector/index.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/base/components/quantity-selector/index.tsx
@@ -52,8 +52,10 @@ export interface QuantitySelectorProps {
 	disabled: boolean;
 	/**
 	 * Whether the component should be editable
+	 *
+	 * @default true
 	 */
-	editable: boolean;
+	editable?: boolean;
 }

 const QuantitySelector = ( {
@@ -65,7 +67,7 @@ const QuantitySelector = ( {
 	step = 1,
 	itemName = '',
 	disabled,
-	editable,
+	editable = true,
 }: QuantitySelectorProps ): JSX.Element => {
 	const classes = clsx( 'wc-block-components-quantity-selector', className );

diff --git a/plugins/woocommerce/client/blocks/assets/js/base/components/quantity-selector/stories/index.stories.tsx b/plugins/woocommerce/client/blocks/assets/js/base/components/quantity-selector/stories/index.stories.tsx
index 321c8404ae..2b7daad2ea 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/components/quantity-selector/stories/index.stories.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/base/components/quantity-selector/stories/index.stories.tsx
@@ -32,7 +32,24 @@ const Template: Story< QuantitySelectorProps > = ( args ) => {
 export const Default = Template.bind( {} );
 Default.args = {};

+export const NonEditable = Template.bind( {} );
+NonEditable.args = {
+	editable: false,
+};
+
 export const Disabled = Template.bind( {} );
 Disabled.args = {
 	disabled: true,
 };
+
+export const WithMinimum = Template.bind( {} );
+WithMinimum.args = {
+	minimum: 2,
+	quantity: 2,
+};
+
+export const WithMaximum = Template.bind( {} );
+WithMaximum.args = {
+	maximum: 5,
+	quantity: 3,
+};
diff --git a/plugins/woocommerce/client/blocks/packages/components/chip/stories/removable-chip.stories.tsx b/plugins/woocommerce/client/blocks/packages/components/chip/stories/removable-chip.stories.tsx
index 211c48f80f..e3b0ce79bf 100644
--- a/plugins/woocommerce/client/blocks/packages/components/chip/stories/removable-chip.stories.tsx
+++ b/plugins/woocommerce/client/blocks/packages/components/chip/stories/removable-chip.stories.tsx
@@ -2,6 +2,7 @@
  * External dependencies
  */
 import type { Meta, StoryFn } from '@storybook/react';
+import { useState } from '@wordpress/element';

 /**
  * Internal dependencies
@@ -21,9 +22,22 @@ export default {
 	},
 } as Meta< RemovableChipProps >;

-const Template: StoryFn< RemovableChipProps > = ( args ) => (
-	<RemovableChip { ...args } />
-);
+const Template: StoryFn< RemovableChipProps > = ( args ) => {
+	const [ isVisible, setIsVisible ] = useState( true );
+	const handleRemove = () => {
+		setIsVisible( false );
+	};
+
+	if ( ! isVisible ) {
+		return (
+			<button onClick={ () => setIsVisible( true ) }>
+				<em>Chip was removed, click to reset</em>
+			</button>
+		);
+	}
+
+	return <RemovableChip { ...args } onRemove={ handleRemove } />;
+};

 export const Default: StoryFn< RemovableChipProps > = Template.bind( {} );
 Default.args = {
@@ -31,3 +45,19 @@ Default.args = {
 	text: 'Take me to the casino',
 	screenReaderText: "I'm a removable chip, me",
 };
+
+export const Disabled: StoryFn< RemovableChipProps > = Template.bind( {} );
+Disabled.args = {
+	element: 'li',
+	text: 'Disabled chip',
+	disabled: true,
+};
+
+export const RemoveOnAnyClick: StoryFn< RemovableChipProps > = Template.bind(
+	{}
+);
+RemoveOnAnyClick.args = {
+	element: 'li',
+	text: 'Click anywhere to remove',
+	removeOnAnyClick: true,
+};
diff --git a/plugins/woocommerce/client/blocks/packages/components/radio-control-accordion/stories/index.stories.tsx b/plugins/woocommerce/client/blocks/packages/components/radio-control-accordion/stories/index.stories.tsx
index db29cf22e3..5014bea20f 100644
--- a/plugins/woocommerce/client/blocks/packages/components/radio-control-accordion/stories/index.stories.tsx
+++ b/plugins/woocommerce/client/blocks/packages/components/radio-control-accordion/stories/index.stories.tsx
@@ -8,6 +8,7 @@ import { useArgs } from '@storybook/preview-api';
  * Internal dependencies
  */
 import { RadioControlAccordion, RadioControlAccordionProps } from '..';
+import './style.stories.scss';

 export default {
 	title: 'External Components/RadioControlAccordion',
diff --git a/plugins/woocommerce/client/blocks/packages/components/radio-control-accordion/stories/style.stories.scss b/plugins/woocommerce/client/blocks/packages/components/radio-control-accordion/stories/style.stories.scss
new file mode 100644
index 0000000000..a09819e08f
--- /dev/null
+++ b/plugins/woocommerce/client/blocks/packages/components/radio-control-accordion/stories/style.stories.scss
@@ -0,0 +1,8 @@
+.wc-block-components-radio-control-accordion-option {
+	margin: em($gap) 0;
+	margin-top: 0;
+
+	&:last-child {
+		margin-bottom: 0;
+	}
+}
diff --git a/plugins/woocommerce/client/blocks/packages/components/text-input/stories/text-input.stories.tsx b/plugins/woocommerce/client/blocks/packages/components/text-input/stories/text-input.stories.tsx
index 73e77d6f6d..276ce9cb31 100644
--- a/plugins/woocommerce/client/blocks/packages/components/text-input/stories/text-input.stories.tsx
+++ b/plugins/woocommerce/client/blocks/packages/components/text-input/stories/text-input.stories.tsx
@@ -168,12 +168,24 @@ Default.args = {
 	id: 'unique-id',
 	label: 'Enter your value',
 	value: 'Lorem ipsum',
+};
+
+export const WithError: StoryFn< TextInputProps > = Template.bind( {} );
+WithError.args = {
+	id: 'unique-id',
+	label: 'Enter your value',
+	value: 'Lorem ipsum',
 	feedback: (
 		<div className="wc-block-components-validation-error">
-			<p>
-				This is a feedback element, usually it would be used as an error
-				message.
-			</p>
+			<p>This is an error message.</p>
 		</div>
 	),
 };
+
+export const WithHelp: StoryFn< TextInputProps > = Template.bind( {} );
+WithHelp.args = {
+	id: 'unique-id',
+	label: 'Enter your value',
+	value: 'Lorem ipsum',
+	help: 'This is help text for the input.',
+};
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 a0e7cd72b0..f58fdcdc60 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
@@ -4,6 +4,9 @@
 import type { StoryFn, Meta } from '@storybook/react';
 import { action } from '@storybook/addon-actions';
 import { useArgs } from '@storybook/client-api';
+import { useDispatch } from '@wordpress/data';
+import { validationStore } from '@woocommerce/block-data';
+import { useState, useEffect } from '@wordpress/element';

 /**
  * Internal dependencies
@@ -214,12 +217,70 @@ export default {
 const Template: StoryFn< ValidatedTextInputProps > = ( args ) => {
 	// eslint-disable-next-line @typescript-eslint/no-unused-vars
 	const [ _, updateArgs ] = useArgs();
-	const onChange = ( value: string ) => {
-		action( 'change' )( value || '' );
-		updateArgs( { value } );
+	const getFormattedValue = (
+		val: string | number | readonly string[] | undefined
+	) => {
+		const stringVal = typeof val === 'string' ? val : String( val || '' );
+		return args.customFormatter
+			? args.customFormatter( stringVal )
+			: stringVal;
 	};

-	return <ValidatedTextInput { ...args } onChange={ onChange } />;
+	const [ inputValue, setInputValue ] = useState(
+		getFormattedValue( args.value )
+	);
+	const { setValidationErrors, showValidationError } =
+		useDispatch( validationStore );
+
+	useEffect( () => {
+		setInputValue( getFormattedValue( args.value ) );
+	}, [ args.value, args.customFormatter ] );
+
+	const onChange = ( newValue: string ) => {
+		const formattedValue = args.customFormatter
+			? args.customFormatter( newValue )
+			: newValue;
+
+		setInputValue( formattedValue );
+
+		action( 'change' )( newValue || '' );
+		updateArgs( { value: newValue } );
+
+		// Always show error for WithError story.
+		if ( args.id === 'with-error-id' ) {
+			setValidationErrors( {
+				[ args.id ]: {
+					message: 'This field cannot be empty',
+					hidden: true,
+				},
+			} );
+			showValidationError( args.id );
+			return;
+		}
+
+		// Default: only show error if input is empty and showError is true.
+		if (
+			args.showError &&
+			! newValue.trim() &&
+			args.id !== 'with-error-id'
+		) {
+			setValidationErrors( {
+				[ args.id || 'unique-id' ]: {
+					message: 'This field cannot be empty',
+					hidden: true,
+				},
+			} );
+			showValidationError( args.id || 'unique-id' );
+		}
+	};
+
+	return (
+		<ValidatedTextInput
+			{ ...args }
+			value={ inputValue }
+			onChange={ onChange }
+		/>
+	);
 };

 export const Default: StoryFn< ValidatedTextInputProps > = Template.bind( {} );
@@ -233,11 +294,11 @@ export const WithError: StoryFn< ValidatedTextInputProps > = Template.bind(
 	{}
 );
 WithError.args = {
-	id: 'unique-id',
-	showError: true,
-	errorMessage: 'This is an error message',
+	id: 'with-error-id',
 	label: 'Enter your value',
-	value: 'Lorem ipsum',
+	value: '',
+	errorMessage: 'This is an error message',
+	showError: true,
 };

 export const WithCustomFormatter: StoryFn< ValidatedTextInputProps > =
diff --git a/plugins/woocommerce/client/blocks/packages/components/title/stories/index.stories.tsx b/plugins/woocommerce/client/blocks/packages/components/title/stories/index.stories.tsx
index 42da665b0f..2fbc587afd 100644
--- a/plugins/woocommerce/client/blocks/packages/components/title/stories/index.stories.tsx
+++ b/plugins/woocommerce/client/blocks/packages/components/title/stories/index.stories.tsx
@@ -8,6 +8,7 @@ import type { StoryFn, Meta } from '@storybook/react';
  */
 import Title, { type TitleProps } from '..';
 import '../style.scss';
+import './style.stories.scss';

 export default {
 	title: 'External Components/Title',
@@ -47,8 +48,16 @@ export default {
 } as Meta< TitleProps >;

 const Template: StoryFn< TitleProps > = ( args ) => {
-	const { children, ...rest } = args;
-	return <Title { ...rest }>{ children }</Title>;
+	const { children, headingLevel, ...rest } = args;
+	return (
+		<Title
+			{ ...rest }
+			headingLevel={ headingLevel }
+			className={ `h${ headingLevel }` }
+		>
+			{ children }
+		</Title>
+	);
 };

 export const Default: StoryFn< TitleProps > = Template.bind( {} );
diff --git a/plugins/woocommerce/client/blocks/packages/components/title/stories/style.stories.scss b/plugins/woocommerce/client/blocks/packages/components/title/stories/style.stories.scss
new file mode 100644
index 0000000000..064dd9495c
--- /dev/null
+++ b/plugins/woocommerce/client/blocks/packages/components/title/stories/style.stories.scss
@@ -0,0 +1,20 @@
+.wc-block-components-title {
+	&[class*="h1"] {
+		font-size: 2em;
+	}
+	&[class*="h2"] {
+		font-size: 1.5em;
+	}
+	&[class*="h3"] {
+		font-size: 1.17em;
+	}
+	&[class*="h4"] {
+		font-size: 1em;
+	}
+	&[class*="h5"] {
+		font-size: 0.83em;
+	}
+	&[class*="h6"] {
+		font-size: 0.67em;
+	}
+}