Commit 96c13fb76cc for woocommerce

commit 96c13fb76cc2b8a6654c7cb11c14369e78d64ca6
Author: verofasulo <98944206+verofasulo@users.noreply.github.com>
Date:   Thu May 14 09:59:57 2026 +0200

    Animate the quick edit drawer close transition and close on save (#64858)

    * Animate the quick edit drawer close and close on successful save

    * Use stable boolean dep so close animation isn't undone by re-render

    * improve logic

    ---------

    Co-authored-by: Luigi Teschio <gigitux@gmail.com>

diff --git a/packages/js/experimental-products-app/changelog/fix-products-app-drawer-animated-close b/packages/js/experimental-products-app/changelog/fix-products-app-drawer-animated-close
new file mode 100644
index 00000000000..8e5f4bd6779
--- /dev/null
+++ b/packages/js/experimental-products-app/changelog/fix-products-app-drawer-animated-close
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Animate the quick/bulk edit drawer's close transition in the experimental products app so it mirrors the open animation, and close the drawer after a fully successful save. The drawer stays open on any save failure so the user can correct and retry.
diff --git a/packages/js/experimental-products-app/src/product-edit/index.tsx b/packages/js/experimental-products-app/src/product-edit/index.tsx
index 09ba72447fd..1af74d40718 100644
--- a/packages/js/experimental-products-app/src/product-edit/index.tsx
+++ b/packages/js/experimental-products-app/src/product-edit/index.tsx
@@ -5,7 +5,7 @@ import { Button, Spinner } from '@wordpress/components';
 import { store as coreStore } from '@wordpress/core-data';
 import { select as wpSelect, useDispatch, useSelect } from '@wordpress/data';
 import { DataForm } from '@wordpress/dataviews';
-import { useCallback, useEffect, useState } from '@wordpress/element';
+import { useCallback, useState } from '@wordpress/element';
 import { __, sprintf } from '@wordpress/i18n';
 import { store as noticesStore } from '@wordpress/notices';
 import { privateApis as routerPrivateApis } from '@wordpress/router';
@@ -42,6 +42,7 @@ type ProductEditFormProps = {

 type ProductEditProps = {
 	products: ProductEntityRecord[];
+	isOpen: boolean;
 };

 function getSaveNoticeMessage( successCount: number, failedCount: number ) {
@@ -109,7 +110,7 @@ function ProductEditForm( {
 	);
 }

-export default function ProductEdit( { products }: ProductEditProps ) {
+export default function ProductEdit( { products, isOpen }: ProductEditProps ) {
 	const { navigate } = useHistory();
 	const { path, query = {} } = useLocation();
 	const requestedProductIdsFromRoute = getSelectionFromPostId( query.postId )
@@ -120,7 +121,7 @@ export default function ProductEdit( { products }: ProductEditProps ) {
 	);

 	const [ isSaving, setIsSaving ] = useState( false );
-	const [ isDrawerOpen, setIsDrawerOpen ] = useState( false );
+
 	const editableFields = getProductEditFields( productFields );
 	const {
 		selectedProducts,
@@ -371,10 +372,13 @@ export default function ProductEdit( { products }: ProductEditProps ) {
 					type: 'snackbar',
 				} );
 			}
+
+			closeDrawer();
 		} finally {
 			setIsSaving( false );
 		}
 	}, [
+		closeDrawer,
 		createErrorNotice,
 		createSuccessNotice,
 		editEntityRecord,
@@ -383,22 +387,8 @@ export default function ProductEdit( { products }: ProductEditProps ) {
 		selectedProducts,
 	] );

-	useEffect( () => {
-		if ( requestedProductIds.length > 0 && ! isDrawerOpen ) {
-			setIsDrawerOpen( true );
-		}
-	}, [ requestedProductIds, isDrawerOpen ] );
-
 	return (
-		<Drawer.Root
-			open={ isDrawerOpen }
-			onOpenChangeComplete={ ( isOpen ) => {
-				if ( ! isOpen ) {
-					closeDrawer();
-				}
-			} }
-			swipeDirection="right"
-		>
+		<Drawer.Root open={ isOpen } swipeDirection="right">
 			<Drawer.Popup
 				className="woocommerce-product-edit__drawer"
 				portal={
diff --git a/packages/js/experimental-products-app/src/router.tsx b/packages/js/experimental-products-app/src/router.tsx
index c4d472dcc51..297d69ea1d0 100644
--- a/packages/js/experimental-products-app/src/router.tsx
+++ b/packages/js/experimental-products-app/src/router.tsx
@@ -124,16 +124,19 @@ export default function useLayoutAreas() {
 		key: 'products-list',
 		areas: {
 			content: <ProductList { ...productListProps } />,
-			edit: showQuickEdit ? (
-				<ProductEdit products={ records ?? [] } />
-			) : undefined,
+			edit: (
+				<ProductEdit
+					products={ records ?? [] }
+					isOpen={ showQuickEdit }
+				/>
+			),
 			preview: false,
 			mobile: (
 				<ProductList postType={ postType } { ...productListProps } />
 			),
 		},
 		widths: {
-			edit: showQuickEdit ? 380 : undefined,
+			edit: 380,
 		},
 	};
 }
diff --git a/packages/js/experimental-products-app/src/variation-view/index.tsx b/packages/js/experimental-products-app/src/variation-view/index.tsx
index 193dd7a6fe6..f98a48785cd 100644
--- a/packages/js/experimental-products-app/src/variation-view/index.tsx
+++ b/packages/js/experimental-products-app/src/variation-view/index.tsx
@@ -280,8 +280,11 @@ export function VariationView( { productId }: VariationViewProps ) {
 				<DataViews.Layout />
 				<DataViews.Footer />
 			</DataViews>
-			{ showQuickEdit && productWithVariations && (
-				<ProductEdit products={ [ productWithVariations ] } />
+			{ productWithVariations && (
+				<ProductEdit
+					products={ [ productWithVariations ] }
+					isOpen={ showQuickEdit }
+				/>
 			) }
 		</div>
 	);