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"],
};
}