179 lines
4.1 KiB
TypeScript
179 lines
4.1 KiB
TypeScript
import { MouseEvent, ReactNode } from 'react';
|
|
import { css } from '@emotion/react';
|
|
import styled from '@emotion/styled';
|
|
|
|
import { OverflowingTextWithTooltip } from '@ui/display/tooltip/OverflowingTextWithTooltip';
|
|
|
|
export enum ChipSize {
|
|
Large = 'large',
|
|
Small = 'small',
|
|
}
|
|
|
|
export enum ChipAccent {
|
|
TextPrimary = 'text-primary',
|
|
TextSecondary = 'text-secondary',
|
|
}
|
|
|
|
export enum ChipVariant {
|
|
Highlighted = 'highlighted',
|
|
Regular = 'regular',
|
|
Transparent = 'transparent',
|
|
Rounded = 'rounded',
|
|
}
|
|
|
|
type ChipProps = {
|
|
size?: ChipSize;
|
|
disabled?: boolean;
|
|
clickable?: boolean;
|
|
label: string;
|
|
maxWidth?: number;
|
|
variant?: ChipVariant;
|
|
accent?: ChipAccent;
|
|
leftComponent?: ReactNode;
|
|
rightComponent?: ReactNode;
|
|
className?: string;
|
|
onClick?: (event: MouseEvent<HTMLDivElement>) => void;
|
|
};
|
|
|
|
const StyledContainer = styled.div<
|
|
Pick<
|
|
ChipProps,
|
|
'accent' | 'clickable' | 'disabled' | 'maxWidth' | 'size' | 'variant'
|
|
>
|
|
>`
|
|
--chip-horizontal-padding: ${({ theme }) => theme.spacing(1)};
|
|
--chip-vertical-padding: ${({ theme }) => theme.spacing(1)};
|
|
|
|
align-items: center;
|
|
border-radius: ${({ theme }) => theme.border.radius.sm};
|
|
color: ${({ theme, disabled }) =>
|
|
disabled ? theme.font.color.light : theme.font.color.secondary};
|
|
cursor: ${({ clickable, disabled }) =>
|
|
clickable ? 'pointer' : disabled ? 'not-allowed' : 'inherit'};
|
|
display: inline-flex;
|
|
gap: ${({ theme }) => theme.spacing(1)};
|
|
height: ${({ theme }) => theme.spacing(3)};
|
|
max-width: ${({ maxWidth }) =>
|
|
maxWidth
|
|
? `calc(${maxWidth}px - 2 * var(--chip-horizontal-padding))`
|
|
: '200px'};
|
|
overflow: hidden;
|
|
padding: var(--chip-vertical-padding) var(--chip-horizontal-padding);
|
|
user-select: none;
|
|
|
|
// Accent style overrides
|
|
${({ accent, disabled, theme }) => {
|
|
if (accent === ChipAccent.TextPrimary) {
|
|
return (
|
|
!disabled &&
|
|
css`
|
|
color: ${theme.font.color.primary};
|
|
`
|
|
);
|
|
}
|
|
|
|
if (accent === ChipAccent.TextSecondary) {
|
|
return css`
|
|
font-weight: ${theme.font.weight.medium};
|
|
`;
|
|
}
|
|
}}
|
|
|
|
// Size style overrides
|
|
${({ theme, size }) =>
|
|
size === ChipSize.Large &&
|
|
css`
|
|
height: ${theme.spacing(4)};
|
|
`}
|
|
|
|
// Variant style overrides
|
|
${({ disabled, theme, variant }) => {
|
|
if (variant === ChipVariant.Regular) {
|
|
return (
|
|
!disabled &&
|
|
css`
|
|
:hover {
|
|
background-color: ${theme.background.transparent.light};
|
|
}
|
|
|
|
:active {
|
|
background-color: ${theme.background.transparent.medium};
|
|
}
|
|
`
|
|
);
|
|
}
|
|
|
|
if (variant === ChipVariant.Highlighted) {
|
|
return css`
|
|
background-color: ${theme.background.transparent.light};
|
|
|
|
${!disabled &&
|
|
css`
|
|
:hover {
|
|
background-color: ${theme.background.transparent.medium};
|
|
}
|
|
|
|
:active {
|
|
background-color: ${theme.background.transparent.strong};
|
|
}
|
|
`}
|
|
`;
|
|
}
|
|
|
|
if (variant === ChipVariant.Rounded) {
|
|
return css`
|
|
--chip-horizontal-padding: ${theme.spacing(2)};
|
|
--chip-vertical-padding: 3px;
|
|
|
|
background-color: ${theme.background.transparent.lighter};
|
|
border: 1px solid ${theme.border.color.medium};
|
|
border-radius: 50px;
|
|
`;
|
|
}
|
|
|
|
if (variant === ChipVariant.Transparent) {
|
|
return css`
|
|
cursor: inherit;
|
|
`;
|
|
}
|
|
}}
|
|
`;
|
|
|
|
const StyledLabel = styled.span`
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
`;
|
|
|
|
export const Chip = ({
|
|
size = ChipSize.Small,
|
|
label,
|
|
disabled = false,
|
|
clickable = true,
|
|
variant = ChipVariant.Regular,
|
|
leftComponent,
|
|
rightComponent,
|
|
accent = ChipAccent.TextPrimary,
|
|
maxWidth,
|
|
className,
|
|
onClick,
|
|
}: ChipProps) => (
|
|
<StyledContainer
|
|
data-testid="chip"
|
|
clickable={clickable}
|
|
variant={variant}
|
|
accent={accent}
|
|
size={size}
|
|
disabled={disabled}
|
|
className={className}
|
|
maxWidth={maxWidth}
|
|
onClick={onClick}
|
|
>
|
|
{leftComponent}
|
|
<StyledLabel>
|
|
<OverflowingTextWithTooltip text={label} />
|
|
</StyledLabel>
|
|
{rightComponent}
|
|
</StyledContainer>
|
|
);
|