112 lines
3.3 KiB
TypeScript
112 lines
3.3 KiB
TypeScript
"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 cards with
|
||
* 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>(
|
||
({
|
||
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;
|