From 7ecf3094594283dfb1ae5f5a138f21a1d9c61aca Mon Sep 17 00:00:00 2001 From: Richie Date: Thu, 23 Apr 2026 11:02:30 +1000 Subject: [PATCH] PackageDetail: toggle pattern for Compare button inCart state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the earlier inert selected-state treatment. Now: - Button keeps its default soft/secondary chrome in both states — no separate brand-tinted visual. - When `inCart=true`, a leading CheckRoundedIcon is added and the label swaps from "Compare" to "Added". - Button remains clickable; `onCompare` is invoked in both states. Caller treats it as a toggle — add when absent, remove when present. - aria-pressed reflects the state for SR users; aria-label spells "Add to comparison" / "Remove from comparison" explicitly. Demo route swaps `basket.add()` for `basket.toggle()` on the handler so a second click removes the package from the comparison basket. Simpler visual (less space, one chrome to maintain) and a clearer interaction — the user can undo directly from the detail panel rather than hunting for CompareBar. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../organisms/PackageDetail/PackageDetail.tsx | 61 +++++++------------ src/demo/apps/arrangement/routes/Packages.tsx | 10 +-- 2 files changed, 28 insertions(+), 43 deletions(-) diff --git a/src/components/organisms/PackageDetail/PackageDetail.tsx b/src/components/organisms/PackageDetail/PackageDetail.tsx index 834af93..f52d61c 100644 --- a/src/components/organisms/PackageDetail/PackageDetail.tsx +++ b/src/components/organisms/PackageDetail/PackageDetail.tsx @@ -55,9 +55,9 @@ export interface PackageDetailProps { /** Whether the compare button is in loading state */ compareLoading?: boolean; /** Whether this package is already in the comparison basket. When true, - * the Compare button swaps to an "In comparison" selected-state (soft - * brand tint + check icon) and is inert — removal happens via the - * CompareBar, not this button. */ + * the Compare button swaps its label to "Added" and adds a leading check + * icon. The button remains clickable — the caller is expected to treat + * `onCompare` as a toggle (add when not in cart, remove when in cart). */ inCart?: boolean; /** Custom label for the arrange CTA button (default: "Make Arrangement") */ arrangeLabel?: string; @@ -219,42 +219,25 @@ export const PackageDetail = React.forwardRef {arrangeLabel} - {onCompare && - (inCart ? ( - // Selected-state: soft brand tint + check icon. Inert - // (disabled + aria-disabled) — removal happens via the - // CompareBar, not this button. sx override keeps the - // brand tint instead of the default greyed-disabled look. - - ) : ( - - ))} + {onCompare && ( + // Same soft/secondary chrome in both states; when the package + // is in the basket a leading check icon appears and the label + // changes to "Added". Click is a toggle — caller decides to + // add or remove based on the `inCart` it's passing in. + + )} diff --git a/src/demo/apps/arrangement/routes/Packages.tsx b/src/demo/apps/arrangement/routes/Packages.tsx index 69d45c3..a659e34 100644 --- a/src/demo/apps/arrangement/routes/Packages.tsx +++ b/src/demo/apps/arrangement/routes/Packages.tsx @@ -21,11 +21,13 @@ export function PackagesRoute() { if (!provider || !bundle) return ; - // Compare CTA on the PackageDetail panel just adds the selection to the - // basket. The floating CompareBar (mounted in App.tsx) handles navigation - // and removal once the user has 2+ packages selected. + // Compare CTA on the PackageDetail panel toggles the selection in the + // basket — adds when absent, removes when present. The button's visible + // state (Compare / Added + ✓) reflects `isSelectedInCart` below. The + // floating CompareBar (mounted in App.tsx) handles navigation once the + // user has 2+ packages selected. const handleCompare = () => { - if (selectedId) basket.add(makeBasketKey(provider.id, selectedId)); + if (selectedId) basket.toggle(makeBasketKey(provider.id, selectedId)); }; // When the selected package is already in the basket, PackageDetail swaps