Files
community-rule/app/components/cards/CardStack/CardStack.container.tsx
T
adilalloandCursor 24a9615c0c Standardize create-flow option steps on one question-and-options layout and Selection sizes.
Method cards, chips, and the right rail now share the two-column shell; last options clear the footer fade, See all stays under the stack, and the left heading no longer jumps when the list expands.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-01 17:18:04 -06:00

113 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { memo, useCallback, useState } from "react";
import { useTranslation } from "../../../contexts/MessagesContext";
import { CardStackView } from "./CardStack.view";
import type { CardStackProps } from "./CardStack.types";
const DEFAULT_TOGGLE_LABEL = "See all communication approaches";
/**
* Figma: "Utility / CardStack"; canonical code under `cards/`.
* Selectable stack of {@link Selection} options (`size` `m` tiles or `l` rows) with
* an optional "see all"/"show less" expand toggle.
* Create-flow method steps use `layout="singleStack"` (size `l`) in the shared
* question-and-options shell. Expanded default layout still matches Flow —
* Expanded Card Stack (`20768:14820`): 281×142 size-`m` tiles in two columns.
*/
const CardStackContainer = memo<CardStackProps>(
({
cards,
selectedId: controlledSelectedId,
selectedIds: controlledSelectedIds,
onCardSelect: controlledOnCardSelect,
expanded: controlledExpanded,
onToggleExpand: controlledOnToggleExpand,
hasMore = true,
toggleLabel = DEFAULT_TOGGLE_LABEL,
showLessLabel,
title = "",
description = "",
layout = "default",
compactRecommendedLimit = 5,
compactCardIds,
compactDesktopLayout: compactDesktopLayoutProp = "grid",
headerLockupSize,
toggleAlignment = "center",
className = "",
showAddCard = false,
addCardLabel = "",
addCardAriaLabel = "",
onAddCard,
}) => {
const t = useTranslation("controlsChrome");
const [internalExpanded, setInternalExpanded] = useState(false);
const [internalSelectedIds, setInternalSelectedIds] = useState<string[]>(
[],
);
const expanded =
controlledExpanded !== undefined ? controlledExpanded : internalExpanded;
const handleToggleExpand = useCallback(() => {
if (controlledOnToggleExpand) {
controlledOnToggleExpand();
} else {
setInternalExpanded((prev) => !prev);
}
}, [controlledOnToggleExpand]);
const selectedIds =
controlledSelectedIds !== undefined
? controlledSelectedIds
: controlledSelectedId !== undefined
? controlledSelectedId
? [controlledSelectedId]
: []
: internalSelectedIds;
const handleCardSelect = useCallback(
(id: string) => {
if (controlledOnCardSelect) {
controlledOnCardSelect(id);
} else {
setInternalSelectedIds((prev) =>
prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id],
);
}
},
[controlledOnCardSelect],
);
return (
<CardStackView
cards={cards}
selectedIds={selectedIds}
onCardSelect={handleCardSelect}
expanded={expanded}
onToggleExpand={handleToggleExpand}
hasMore={hasMore}
toggleLabel={toggleLabel}
showLessLabel={showLessLabel ?? t("cardStackShowLess")}
title={title}
description={description}
layout={layout}
compactRecommendedLimit={compactRecommendedLimit}
compactCardIds={compactCardIds}
compactDesktopLayout={compactDesktopLayoutProp}
headerLockupSize={headerLockupSize}
toggleAlignment={toggleAlignment}
className={className}
showAddCard={showAddCard}
addCardLabel={addCardLabel}
addCardAriaLabel={addCardAriaLabel}
onAddCard={onAddCard}
/>
);
},
);
CardStackContainer.displayName = "CardStack";
export default CardStackContainer;