import React, { useMemo } from "react"; import type { AccessibilityRole } from "react-native"; import { Pressable, View } from "react-native"; import type { IconNames } from "@jobber/design"; import { allColors } from "@jobber/design"; import { useStyles } from "./Chip.style"; import { Icon } from "../Icon"; import { Typography } from "../Typography"; import type { TypographyProps } from "../Typography"; import type { AtlantisThemeContextValue } from "../AtlantisThemeContext"; import { useAtlantisTheme } from "../AtlantisThemeContext"; export type AccentType = "client" | "invoice" | "job" | "request" | "quote"; export interface ChipProps { /** * label of the chip. */ readonly label?: string; /** * chip's active status */ readonly isActive: boolean; /** * Boolean for chip's ability to be dismissed */ readonly isDismissible?: boolean; /** * Background color to be used for inactive chips * * @default "background" */ readonly inactiveBackgroundColor?: "surface" | "background"; /** * Accessibility label for the component. It's also used for testing */ readonly accessibilityLabel?: string; /** * Accessibility role for the component */ readonly accessibilityRole?: AccessibilityRole; /** * Press handler */ onPress?(): void; /** * Optional Icon */ readonly icon?: IconNames; /** * Background color to be used for Active chips */ readonly accent?: AccentType; } export function Chip({ icon, label, onPress, isDismissible, isActive, inactiveBackgroundColor = "background", accessibilityLabel, accessibilityRole = "radio", accent, }: ChipProps) { const styles = useStyles(); const { tokens, effectiveTheme } = useAtlantisTheme(); const { chipStyle, iconCustomColor, labelStyle, dismissColor } = useMemo(() => { const accentColor = accent ? tokens[`color-${accent}`] : tokens["color-surface--reverse"]; let backgroundColor = accentColor; let iconColor = isActive ? tokens["color-surface"] : accentColor; let selectedLabelStyle: TypographyProps<"base">["UNSAFE_style"]; if (isActive && accent) { const selected = getSelectedAccentColors(accent, { tokens, effectiveTheme, }); backgroundColor = selected.background; iconColor = selected.foreground; selectedLabelStyle = { textStyle: { color: selected.foreground }, }; } const chip = [ styles.container, { backgroundColor: inactiveBackgroundColor === "surface" ? tokens["color-surface"] : tokens["color-interactive--background"], }, isActive && { backgroundColor }, getBorderStyle(inactiveBackgroundColor, tokens), ]; const dismiss = (isActive || inactiveBackgroundColor === "surface") && styles.activeDismissIcon; return { chipStyle: chip, iconCustomColor: iconColor, labelStyle: selectedLabelStyle, dismissColor: dismiss, }; }, [ accent, isActive, inactiveBackgroundColor, styles, tokens, effectiveTheme, ]); const accessibilityState = useMemo(() => { const checkableRoles = ["radio", "switch", "togglebutton", "checkbox"]; if (checkableRoles.includes(accessibilityRole)) { return { checked: isActive }; } return {}; }, [accessibilityRole, isActive]); return ( {icon && ( )} {label && ( {label} )} {isDismissible && ( )} ); } // Object labels and leading icons share the selected foreground. function getSelectedAccentColors( accent: AccentType, { tokens, effectiveTheme, }: Pick, ) { const colors = { background: allColors[`color-${accent}`], foreground: allColors["color-text--reverse"], }; if (accent === "client") { colors.background = tokens["color-client"]; if (effectiveTheme === "dark") { colors.foreground = allColors["color-text"]; } } return colors; } function getBorderStyle( inactiveBackgroundColor: "surface" | "background", tokens: AtlantisThemeContextValue["tokens"], ) { let borderColor = "transparent"; if (inactiveBackgroundColor === "surface") { borderColor = tokens["color-border"]; } return { borderColor, borderWidth: tokens["border-base"], }; }