Files
twenty/packages/twenty-ui/src/display/chip/components/Chip.tsx
T
Paul Rastoin 89e11b4626 [BUGFIX] Account owner should not be clickable & [Refactor] Chip.tsx links (#10359)
# Introduction

closes #10196 
Initially fixing the `Account Owner` record field value should not be
clickable and redirects on current page bug.
This has been fixed computing whereas the current filed is a workspace
member dynamically rendering a stale Chip components instead of an
interactive one

## Refactor
Refactored the `AvatarChip` `to` props logic to be scoped to lower level
scope `Chip`.
Now we have `LinkChip` `Chip`, `LinkAvatarChip` and `AvatarChip` all
exported from twenty-ui.

The caller has to determine which one to call from the design system

## New rule regarding chip links
As discussed with @charlesBochet and @FelixMalfait 
A chip link will now ***always*** have `to` defined. ( and optionally an
`onClick` ).
`ChipLinks` cannot be used as buttons anymore

## Factorization
Deleted the `RecordIndexRecordChip.tsx` file ( aka
`RecordIdentifierChip` component ) that was duplicating some logic,
refactored the `RecordChip` in order to handle what was covered by
`RecordIdentifierChip`

## Conclusion
As always any suggestions are more than welcomed ! Took few opinionated
decision/refactor regarding nested long ternaries rendering `ReactNode`
elements

## Misc


https://github.com/user-attachments/assets/8ef11fb2-7ba6-4e96-bd59-b0be5a425156

---------

Co-authored-by: Mohammed Razak <mohammedrazak2001@gmail.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2025-02-25 14:36:17 +00:00

153 lines
4.0 KiB
TypeScript

import { Theme, withTheme } from '@emotion/react';
import { styled } from '@linaria/react';
import { ReactNode } from 'react';
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',
}
export type ChipProps = {
size?: ChipSize;
disabled?: boolean;
clickable?: boolean;
label: string;
maxWidth?: number;
variant?: ChipVariant;
accent?: ChipAccent;
leftComponent?: (() => ReactNode) | null;
rightComponent?: (() => ReactNode) | null;
className?: string;
};
const StyledContainer = withTheme(styled.div<
Pick<
ChipProps,
'accent' | 'clickable' | 'disabled' | 'maxWidth' | 'size' | 'variant'
> & { theme: Theme }
>`
--chip-horizontal-padding: ${({ theme }) => theme.spacing(1)};
--chip-vertical-padding: ${({ theme }) => theme.spacing(1)};
text-decoration: none;
align-items: center;
color: ${({ theme, accent, disabled }) =>
disabled
? theme.font.color.light
: accent === ChipAccent.TextPrimary
? theme.font.color.primary
: theme.font.color.secondary};
cursor: ${({ clickable, disabled, variant }) =>
variant === ChipVariant.Transparent
? 'inherit'
: clickable
? 'pointer'
: disabled
? 'not-allowed'
: 'inherit'};
display: inline-flex;
justify-content: flex-start;
gap: ${({ theme }) => theme.spacing(1)};
height: ${({ theme, size }) =>
size === ChipSize.Large ? theme.spacing(4) : 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;
font-weight: ${({ theme, accent }) =>
accent === ChipAccent.TextSecondary ? theme.font.weight.medium : 'inherit'};
&:hover {
background-color: ${({ theme, variant, disabled }) =>
variant === ChipVariant.Regular && !disabled
? theme.background.transparent.light
: variant === ChipVariant.Highlighted
? theme.background.transparent.medium
: 'inherit'};
}
&:active {
background-color: ${({ theme, disabled, variant }) =>
variant === ChipVariant.Regular && !disabled
? theme.background.transparent.medium
: variant === ChipVariant.Highlighted
? theme.background.transparent.strong
: 'inherit'};
}
background-color: ${({ theme, variant }) =>
variant === ChipVariant.Highlighted
? theme.background.transparent.light
: variant === ChipVariant.Rounded
? theme.background.transparent.lighter
: 'inherit'};
border: ${({ theme, variant }) =>
variant === ChipVariant.Rounded
? `1px solid ${theme.border.color.medium}`
: 'none'};
border-radius: ${({ theme, variant }) =>
variant === ChipVariant.Rounded ? '50px' : theme.border.radius.sm};
& > svg {
flex-shrink: 0;
}
padding-left: ${({ theme, variant }) =>
variant === ChipVariant.Transparent
? theme.spacing(0)
: 'var(--chip-horizontal-padding)'};
`);
export const Chip = ({
size = ChipSize.Small,
label,
disabled = false,
clickable = true,
variant = ChipVariant.Regular,
leftComponent = null,
rightComponent = null,
accent = ChipAccent.TextPrimary,
className,
maxWidth,
}: ChipProps) => {
return (
<StyledContainer
data-testid="chip"
accent={accent}
clickable={clickable}
disabled={disabled}
size={size}
variant={variant}
className={className}
maxWidth={maxWidth}
>
{leftComponent?.()}
<OverflowingTextWithTooltip size={size} text={label} />
{rightComponent?.()}
</StyledContainer>
);
};