Keep See-all method cards at the compact 142px tile height so expanded rows do not stretch with badges and wrapping copy.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
adilallo
2026-08-21 16:14:27 -06:00
co-authored by Cursor
parent 75ba0a214f
commit ef60175805
6 changed files with 75 additions and 32 deletions
@@ -11,6 +11,8 @@ const DEFAULT_TOGGLE_LABEL = "See all communication approaches";
* Figma: "Utility / CardStack"; canonical code under `cards/`. * Figma: "Utility / CardStack"; canonical code under `cards/`.
* Selectable stack of cards with * Selectable stack of cards with
* an optional "see all"/"show less" expand toggle. * an optional "see all"/"show less" expand toggle.
* Expanded default layout matches Flow — Expanded Card Stack (`20768:14820`):
* 281×142 CardSelection tiles in two columns.
*/ */
const CardStackContainer = memo<CardStackProps>( const CardStackContainer = memo<CardStackProps>(
({ ({
@@ -20,7 +20,7 @@ export interface CardStackProps {
showLessLabel?: string; showLessLabel?: string;
title?: string; title?: string;
description?: ReactNode; description?: ReactNode;
/** "default" = compact grid/column + expanded grid; "singleStack" = always one column, expand shows more in same stack */ /** "default" = compact grid/column + expanded 2-col 142px tiles; "singleStack" = always one column, expand shows more in same stack */
layout?: "default" | "singleStack"; layout?: "default" | "singleStack";
/** /**
* Max recommended cards in compact (non-expanded) mode. Default 5; Figma compact stack uses 3. * Max recommended cards in compact (non-expanded) mode. Default 5; Figma compact stack uses 3.
@@ -6,6 +6,10 @@ import type { HeaderLockupSizeValue } from "../../type/HeaderLockup/HeaderLockup
import Selection from "../Selection"; import Selection from "../Selection";
import type { CardStackViewProps } from "./CardStack.types"; import type { CardStackViewProps } from "./CardStack.types";
/** Figma Card / CardSelection on Compact + Expanded Card Stack (`281×142`). */
const FIGMA_CARD_SELECTION_TILE_CLASS =
"h-[142px] min-h-[142px] max-h-[142px] w-[281px] max-w-[281px] shrink-0";
function CardStackHeaderLockup({ function CardStackHeaderLockup({
title, title,
description, description,
@@ -175,24 +179,46 @@ export function CardStackView({
/> />
{expanded ? ( {expanded ? (
<div className="mx-auto grid w-full max-w-[min(100%,860px)] grid-cols-1 gap-x-4 gap-y-6 md:grid-cols-2"> <>
{cards.map((item) => ( <div className="flex w-full flex-col gap-2 md:hidden">
<Selection {cards.map((item) => (
key={item.id} <Selection
id={item.id} key={item.id}
label={item.label} id={item.id}
supportText={item.supportText} label={item.label}
recommended={item.recommended ?? false} supportText={item.supportText}
selected={isSelected(item.id)} recommended={item.recommended ?? false}
orientation="vertical" selected={isSelected(item.id)}
showInfoIcon={true} orientation="horizontal"
onClick={() => onCardSelect(item.id)} showInfoIcon={false}
/> className="min-h-[142px]"
))} onClick={() => onCardSelect(item.id)}
{addTile ? ( />
<div className="min-w-0 md:col-span-2">{addTile}</div> ))}
) : null} {addTile}
</div> </div>
<div className="mx-auto hidden w-full max-w-[min(100%,570px)] flex-wrap justify-center gap-2 md:flex">
{cards.map((item) => (
<Selection
key={item.id}
id={item.id}
label={item.label}
supportText={item.supportText}
recommended={item.recommended ?? false}
selected={isSelected(item.id)}
orientation="horizontal"
showInfoIcon={false}
className={FIGMA_CARD_SELECTION_TILE_CLASS}
onClick={() => onCardSelect(item.id)}
/>
))}
{addTile ? (
<div className="flex w-full min-w-0 shrink-0 justify-center md:flex-[1_1_100%]">
{addTile}
</div>
) : null}
</div>
</>
) : compactDesktopLayout === "pyramidFive" ? ( ) : compactDesktopLayout === "pyramidFive" ? (
<> <>
<div className="flex w-full flex-col gap-2 md:hidden"> <div className="flex w-full flex-col gap-2 md:hidden">
@@ -230,7 +256,7 @@ export function CardStackView({
selected={isSelected(item.id)} selected={isSelected(item.id)}
orientation="horizontal" orientation="horizontal"
showInfoIcon={false} showInfoIcon={false}
className="h-[142px] min-h-[142px] max-h-[142px] w-[281px] max-w-[281px] shrink-0" className={FIGMA_CARD_SELECTION_TILE_CLASS}
onClick={() => onCardSelect(item.id)} onClick={() => onCardSelect(item.id)}
/> />
))} ))}
@@ -249,7 +275,7 @@ export function CardStackView({
selected={isSelected(item.id)} selected={isSelected(item.id)}
orientation="horizontal" orientation="horizontal"
showInfoIcon={false} showInfoIcon={false}
className="h-[142px] min-h-[142px] max-h-[142px] w-[281px] max-w-[281px] shrink-0" className={FIGMA_CARD_SELECTION_TILE_CLASS}
onClick={() => onCardSelect(item.id)} onClick={() => onCardSelect(item.id)}
/> />
))} ))}
@@ -268,7 +294,7 @@ export function CardStackView({
selected={isSelected(item.id)} selected={isSelected(item.id)}
orientation="horizontal" orientation="horizontal"
showInfoIcon={false} showInfoIcon={false}
className="h-[142px] min-h-[142px] max-h-[142px] w-[281px] max-w-[281px] shrink-0" className={FIGMA_CARD_SELECTION_TILE_CLASS}
onClick={() => onCardSelect(item.id)} onClick={() => onCardSelect(item.id)}
/> />
))} ))}
@@ -284,7 +310,7 @@ export function CardStackView({
selected={isSelected(item.id)} selected={isSelected(item.id)}
orientation="horizontal" orientation="horizontal"
showInfoIcon={false} showInfoIcon={false}
className="h-[142px] min-h-[142px] max-h-[142px] w-[281px] max-w-[281px] shrink-0" className={FIGMA_CARD_SELECTION_TILE_CLASS}
onClick={() => onCardSelect(item.id)} onClick={() => onCardSelect(item.id)}
/> />
))} ))}
@@ -299,7 +325,7 @@ export function CardStackView({
selected={isSelected(compactCards[4].id)} selected={isSelected(compactCards[4].id)}
orientation="horizontal" orientation="horizontal"
showInfoIcon={false} showInfoIcon={false}
className="h-[142px] min-h-[142px] max-h-[142px] w-[281px] max-w-[281px] shrink-0" className={FIGMA_CARD_SELECTION_TILE_CLASS}
onClick={() => onCardSelect(compactCards[4].id)} onClick={() => onCardSelect(compactCards[4].id)}
/> />
</div> </div>
@@ -346,7 +372,7 @@ export function CardStackView({
selected={isSelected(item.id)} selected={isSelected(item.id)}
orientation="horizontal" orientation="horizontal"
showInfoIcon={false} showInfoIcon={false}
className="h-[142px] min-h-[142px] max-h-[142px] w-[281px] max-w-[281px] shrink-0" className={FIGMA_CARD_SELECTION_TILE_CLASS}
onClick={() => onCardSelect(item.id)} onClick={() => onCardSelect(item.id)}
/> />
))} ))}
@@ -360,7 +386,7 @@ export function CardStackView({
selected={isSelected(compactCards[2].id)} selected={isSelected(compactCards[2].id)}
orientation="horizontal" orientation="horizontal"
showInfoIcon={false} showInfoIcon={false}
className="h-[142px] min-h-[142px] max-h-[142px] w-[281px] max-w-[281px] shrink-0" className={FIGMA_CARD_SELECTION_TILE_CLASS}
onClick={() => onCardSelect(compactCards[2].id)} onClick={() => onCardSelect(compactCards[2].id)}
/> />
</div> </div>
@@ -379,7 +405,7 @@ export function CardStackView({
selected={isSelected(item.id)} selected={isSelected(item.id)}
orientation="horizontal" orientation="horizontal"
showInfoIcon={false} showInfoIcon={false}
className="h-[142px] min-h-[142px] max-h-[142px] w-[281px] max-w-[281px] shrink-0" className={FIGMA_CARD_SELECTION_TILE_CLASS}
onClick={() => onCardSelect(item.id)} onClick={() => onCardSelect(item.id)}
/> />
))} ))}
@@ -6,7 +6,7 @@ import type { SelectionProps } from "./Selection.types";
/** /**
* Figma: "Card / CardSelection" — stacked tile e.g. `16775:28762` (recommended + label + supportText). * Figma: "Card / CardSelection" — stacked tile e.g. `16775:28762` (recommended + label + supportText).
* `orientation="horizontal"` selects that vertical stack; `"vertical"` is label + optional info icon with tag on the right (CardStack expanded / single-column). * `orientation="horizontal"` selects that vertical stack; `"vertical"` is label + optional info icon with tag on the right (CardStack `singleStack` / right-rail).
*/ */
const SelectionContainer = memo<SelectionProps>( const SelectionContainer = memo<SelectionProps>(
({ ({
+2 -1
View File
@@ -97,7 +97,8 @@ export const Expanded = {
parameters: { parameters: {
docs: { docs: {
description: { description: {
story: "Expanded list layout with vertical cards and Show less toggle.", story:
"Expanded 2-column stack of 142px CardSelection tiles and Show less toggle.",
}, },
}, },
}, },
+17 -3
View File
@@ -60,9 +60,23 @@ describe("CardStack Component", () => {
test("renders all cards in expanded (list) mode", () => { test("renders all cards in expanded (list) mode", () => {
render(<CardStack cards={SAMPLE_CARDS} expanded={true} />); render(<CardStack cards={SAMPLE_CARDS} expanded={true} />);
expect(screen.getByText("Option A")).toBeInTheDocument(); expect(screen.getAllByText("Option A").length).toBeGreaterThanOrEqual(1);
expect(screen.getByText("Option B")).toBeInTheDocument(); expect(screen.getAllByText("Option B").length).toBeGreaterThanOrEqual(1);
expect(screen.getByText("Option C")).toBeInTheDocument(); expect(screen.getAllByText("Option C").length).toBeGreaterThanOrEqual(1);
});
test("expanded tiles use the compact 142px CardSelection height", () => {
render(<CardStack cards={SAMPLE_CARDS} expanded={true} />);
const tiles = screen.getAllByRole("button", {
name: "Option A: Description A",
});
expect(tiles.length).toBeGreaterThan(0);
for (const tile of tiles) {
expect(tile.className).toMatch(/142px/);
expect(tile).toHaveClass("flex-col");
expect(tile).not.toHaveClass("flex-row");
}
}); });
test("shows See all toggle when hasMore is true", () => { test("shows See all toggle when hasMore is true", () => {