import React from 'react'; import styled from 'styled-components'; import { SQUARE_CSS } from '../../styles'; import { FilledVariant, Size, ThemeMode } from '../../types'; import { getThemedColor } from '../../utils/colorUtils'; import { AvatarComponent } from '../Avatar'; import Icons, { Icon } from '../Icons'; import { IconComponent } from '../IconText'; import { ICON_TEXT_TYPOGRAPHY_SIZE } from '../IconText/IconText.constants'; import Tooltip, { TooltipContent, TooltipPlacement, TooltipTrigger } from '../Tooltip'; import Typography, { TypographyWeight } from '../Typography'; import { ICON_CONTAINER_SIZE, CHIP_ICON_SIZE, CHIP_END_ICON_DATA_TEST } from './Chip.constants'; import { CHIP_TYPE_CSS } from './Chip.styles'; import { ChipProps } from './Chip.types'; import { getIconTextAndBgColors } from './Chip.utils'; export const ChipContainer = styled.div<{ $clickable: boolean; $destructive: boolean; $variant: FilledVariant; $forceTheme?: ThemeMode; $noBorder?: boolean; }>` border-radius: 32px; box-sizing: border-box; align-items: center; display: flex; flex-direction: row; flex-grow: 0; gap: 0px; padding: 4px; width: fit-content; ${(props) => !props.$noBorder && `border: 1px solid ${getThemedColor('var(--border-secondary)', props.$forceTheme)};`} ${(props) => props.$clickable && ` cursor: pointer; user-select: none; `} ${CHIP_TYPE_CSS} `; const IconContainer = styled.div<{ $size: number; $bgColor: string; $forceTheme?: ThemeMode }>` display: flex; align-items: center; justify-content: center; border-radius: 30px; background: ${(props) => getThemedColor(props.$bgColor, props.$forceTheme)}; ${SQUARE_CSS} `; const PaddedText = styled.div` padding: 0 8px; `; const StartElement = styled.div` display: flex; align-items: center; gap: 8px; `; const Chip: React.FC = (props) => { const { avatar: startAvatar, avatarTooltip, className, color, dataTest, forceTheme, icon: startIcon, label, noBorder, size = Size.MEDIUM, style, tooltip = '', typographyWeight = TypographyWeight.REGULAR, variant = FilledVariant.FILLED, onClick, onDelete } = props; const destructive = color === 'destructive'; // Chips with defined onDelete functions are input chipss const isInputType = !!onDelete; const iconSize = CHIP_ICON_SIZE[size]; const iconContainerSize = ICON_CONTAINER_SIZE[size]; const typographyColor = color ?? 'primary'; const typographySize = ICON_TEXT_TYPOGRAPHY_SIZE[size]; const renderAvatar = (avatar: AvatarComponent) => { return ( {avatarTooltip} {React.cloneElement(avatar, { forceTheme, rounded: true, size: avatar.props.size ?? iconSize })} ); }; const renderStartIcon = (icon: Icon | IconComponent) => { const customColor = typeof icon === 'object' && icon.props.color ? icon.props.color : color; const [iconColor, bgColor] = getIconTextAndBgColors(destructive, customColor); return ( {typeof icon === 'string' && } {/* Prestyled icon object */} {typeof icon === 'object' && React.cloneElement(icon, { color: iconColor, forceTheme, size: icon.props.size ?? iconSize })} ); }; const renderDeleteIcon = (runDelete: (e: React.MouseEvent) => Promise | void) => { const icon = Icon.Close; const customColor = color ?? 'secondary'; const [iconColor, bgColor] = getIconTextAndBgColors(destructive, customColor); return ( { e.stopPropagation(); void runDelete(e); }} forceTheme={forceTheme} size={iconSize} /> ); }; if (!startAvatar && !startIcon && !label && !isInputType) return <>; return ( {tooltip} {(startAvatar || startIcon) && ( {startAvatar && renderAvatar(startAvatar)} {startIcon && renderStartIcon(startIcon)} )} {label && ( {label} )} {/* We render an X icon for input chips to run onDelete */} {isInputType && renderDeleteIcon(onDelete)} ); }; export default Chip;