import { forwardRef, useMemo, type ReactNode } from 'react'; import { View, type ViewProps } from 'react-native'; import { Slot, dataAttributes, mergeDataAttributes } from '@cdx-ui/primitives'; import { cn, ParentContext, useParentContext, useStyleContext } from '@cdx-ui/utils'; import { cardContentVariants, cardFooterVariants, cardHeaderVariants, cardRootVariants, cardStripeVariants, type CardContentVariantProps, type CardFooterVariantProps, type CardVariantProps, } from './styles'; // ============================================================================= // STYLED ROOT COMPONENT // ============================================================================= const SCOPE = 'CARD'; const useCardStyleContext = () => useStyleContext(SCOPE) as CardVariantProps; export interface CardProps extends ViewProps, CardVariantProps { asChild?: boolean; className?: string; children?: ReactNode; } const CardRoot = forwardRef( ({ asChild, className, children, style, fullBleed, ...props }, ref) => { const parent = useParentContext(); const ctx = useMemo(() => ({ ...parent, [SCOPE]: { fullBleed } }), [parent, fullBleed]); const computedClassName = cn(cardRootVariants(), className); const Comp = asChild ? Slot : View; return ( {children} ); }, ); CardRoot.displayName = 'Card'; // ============================================================================= // STYLED STRIPE COMPONENT // ============================================================================= export interface CardStripeProps extends ViewProps { asChild?: boolean; className?: string; } const CardStripe = forwardRef( ({ asChild, className, style, ...props }, ref) => { const computedClassName = cn(cardStripeVariants(), className); const Comp = asChild ? Slot : View; return ( ); }, ); CardStripe.displayName = 'Card.Stripe'; // ============================================================================= // STYLED HEADER COMPONENT // ============================================================================= export interface CardHeaderProps extends ViewProps { asChild?: boolean; className?: string; children?: ReactNode; } const CardHeader = forwardRef( ({ asChild, className, children, style, ...props }, ref) => { const computedClassName = cn(cardHeaderVariants(), className); const Comp = asChild ? Slot : View; return ( {children} ); }, ); CardHeader.displayName = 'Card.Header'; // ============================================================================= // STYLED CONTENT COMPONENT // ============================================================================= export interface CardContentProps extends ViewProps, CardContentVariantProps { asChild?: boolean; className?: string; children?: ReactNode; } const CardContent = forwardRef( ({ asChild, className, children, style, fullBleed, ...props }, ref) => { const { fullBleed: fullBleedFromContext } = useCardStyleContext(); const computedClassName = cn( cardContentVariants({ fullBleed: fullBleed ?? fullBleedFromContext }), className, ); const Comp = asChild ? Slot : View; return ( {children} ); }, ); CardContent.displayName = 'Card.Content'; // ============================================================================= // STYLED FOOTER COMPONENT // ============================================================================= export interface CardFooterProps extends ViewProps, CardFooterVariantProps { asChild?: boolean; className?: string; children?: ReactNode; } const CardFooter = forwardRef( ({ asChild, className, children, style, fullBleed, ...props }, ref) => { const { fullBleed: fullBleedFromContext } = useCardStyleContext(); const computedClassName = cn( cardFooterVariants({ fullBleed: fullBleed ?? fullBleedFromContext }), className, ); const Comp = asChild ? Slot : View; return ( {children} ); }, ); CardFooter.displayName = 'Card.Footer'; // ============================================================================= // COMPOUND COMPONENT // ============================================================================= type CardCompoundComponent = typeof CardRoot & { Stripe: typeof CardStripe; Header: typeof CardHeader; Content: typeof CardContent; Footer: typeof CardFooter; }; export const Card = Object.assign(CardRoot, { Stripe: CardStripe, Header: CardHeader, Content: CardContent, Footer: CardFooter, }) as CardCompoundComponent;