import React, { useId, ComponentType } from "react"; import classNames from "classnames"; import { ArcSizeBreakpointsL, ArcSizeBreakpointsM } from "@arc-ui/tokens-arc"; import { Carousel } from "@arc-ui/components/Carousel"; import { Heading, type HeadingLevel } from "@arc-ui/components/Heading"; import { useMediaQuery } from "@arc-ui/components/use-media-query"; import { SectionHeading, type SectionHeadingProps } from "../SectionHeading"; import { MediaCard, type MediaCardProps } from "@arc-ui/components/MediaCard"; import { filterAttrs } from "@arc-ui/community-utils/filter-attrs"; import { ImpactCard, type ImpactCardProps, } from "@arc-ui/components/ImpactCard"; import { InformationCard, type InformationCardProps, } from "@arc-ui/components/InformationCard"; import { TypographyCard, type TypographyCardProps, } from "@arc-ui/components/TypographyCard"; import { ButtonV2, type ButtonV2Props } from "@arc-ui/components/ButtonV2"; import { VerticalSpace } from "@arc-ui/components/VerticalSpace"; import styles from "./PromoListing.module.css"; import { BtIconArrowRightFill } from "@arc-ui/icons"; /** * Use `PromoListing` to give supporting information about a page or proposition in the form of the card components (`ImpactCard`, `InformationCard`, `MediaCard` and `TypographyCard`). */ export const PromoListing: React.FC = ({ heading, content, id, isCarousel = false, cards, headingLevel, isHeadingWordWrap, columns = "2", button = { buttonStyle: "secondary" }, overlineHeadingLevel, overlineLabel, ...props }) => { const componentId = useId(); const isMinWidthArcBreakpointL = useMediaQuery( `(min-width: ${ArcSizeBreakpointsL})`, ); const isMinWidthArcBreakpointM = useMediaQuery( `(min-width: ${ArcSizeBreakpointsM})`, ); const cardAspectRatios = columns === "3" ? "10-16" : "3-4"; const getCardAspectRatios = { xs: !isCarousel ? "3-4" : undefined, s: !isCarousel ? "10-16" : undefined, m: !isCarousel ? "3-4" : undefined, l: cardAspectRatios, xl: cardAspectRatios, xxl: cardAspectRatios, xxxl: cardAspectRatios, } as MediaCardProps["preserveAspectRatios"]; const commonProps = { preserveAspectRatios: getCardAspectRatios, minHeight: isCarousel && !isMinWidthArcBreakpointL ? isMinWidthArcBreakpointM ? 557 : 461 : undefined, }; const CARD_COMPONENTS = { "media-card": MediaCard, "impact-card": ImpactCard, "information-card": InformationCard, "typography-card": TypographyCard, } as const; const getCard = (card: PromoListCard) => { const CardComponent = CARD_COMPONENTS[card.type] as ComponentType< typeof card >; return ; }; return (
{overlineLabel && ( <> {overlineLabel} )} {button.label && ( <> )} {isCarousel && !isMinWidthArcBreakpointL ? (
{cards?.map((card: PromoListCard, i) => (
{getCard(card)}
))}
) : (
    {cards?.map((card: PromoListCard, index) => (
  • {getCard(card)}
  • ))}
)}
); }; interface PromoListMediaCard extends MediaCardProps { type: "media-card"; } interface PromoListImpactCard extends ImpactCardProps { type: "impact-card"; } interface PromoListInformationCard extends InformationCardProps { type: "information-card"; } interface PromoListTypographyCard extends TypographyCardProps { type: "typography-card"; } type PromoListCard = | PromoListMediaCard | PromoListInformationCard | PromoListTypographyCard | PromoListImpactCard; export interface PromoListingProps extends Omit { /** * Cards for the PromoListing. */ cards: PromoListCard[]; /** * Shows cards in a carousel on devices below 1024px (m breakpoint) if true. */ isCarousel?: boolean; /** * Number of columns for desktop breakpoints. "2" and "3" column options available. */ columns?: "2" | "3"; /** * Optional button configuration displayed above the cards. */ button?: PromoListingButton; /** * Text label displayed above the main heading in overline style */ overlineLabel?: string; /** * Heading level for the overline label */ overlineHeadingLevel?: HeadingLevel; } /** * Button configuration for PromoListing component. */ interface PromoListingButton extends Omit { /** * Style variant for the button. Defaults to "secondary". */ buttonStyle?: "secondary" | "compact"; }