fix(ui): keep 2 components for chip (#13359)

This commit is contained in:
Antoine Moreaux
2025-07-22 18:51:34 +02:00
committed by GitHub
parent 01805cc71c
commit 5cb163daa1
6 changed files with 110 additions and 24 deletions

View File

@ -0,0 +1,88 @@
import styled from '@emotion/styled';
import { isNonEmptyString } from '@sniptt/guards';
import { Fragment } from 'react/jsx-runtime';
import { isDefined } from 'twenty-shared/utils';
import { OverflowingTextWithTooltip } from 'twenty-ui/display';
const StyledChip = styled.button<{
withText: boolean;
maxWidth?: string;
onClick?: () => void;
}>`
all: unset;
align-items: center;
justify-content: center;
background: ${({ theme }) => theme.background.transparent.light};
border: 1px solid ${({ theme }) => theme.border.color.medium};
border-radius: ${({ theme }) => theme.border.radius.md};
box-sizing: border-box;
display: flex;
gap: ${({ theme }) => theme.spacing(1)};
height: ${({ theme }) => theme.spacing(6)};
/* If the chip has text, we add extra padding to have a more balanced design */
padding: 0
${({ theme, withText }) => (withText ? theme.spacing(2) : theme.spacing(1))};
font-family: inherit;
font-size: ${({ theme }) => theme.font.size.sm};
font-weight: ${({ theme }) => theme.font.weight.medium};
line-height: ${({ theme }) => theme.text.lineHeight.lg};
color: ${({ theme }) => theme.font.color.primary};
cursor: ${({ onClick }) => (isDefined(onClick) ? 'pointer' : 'default')};
&:hover {
background: ${({ onClick, theme }) =>
isDefined(onClick)
? theme.background.transparent.medium
: theme.background.transparent.light};
}
max-width: ${({ maxWidth }) => maxWidth};
`;
const StyledIconsContainer = styled.div`
align-items: center;
display: flex;
`;
const StyledEmptyText = styled.div`
color: ${({ theme }) => theme.font.color.tertiary};
`;
export type CommandMenuContextChipProps = {
Icons: React.ReactNode[];
text?: string;
onClick?: () => void;
testId?: string;
maxWidth?: string;
forceEmptyText?: boolean;
};
export const CommandMenuContextChip = ({
Icons,
text,
onClick,
testId,
maxWidth,
forceEmptyText = false,
}: CommandMenuContextChipProps) => {
return (
<StyledChip
withText={isNonEmptyString(text)}
onClick={onClick}
data-testid={testId}
maxWidth={maxWidth}
>
<StyledIconsContainer>
{Icons.map((Icon, index) => (
<Fragment key={index}>{Icon}</Fragment>
))}
</StyledIconsContainer>
{text?.trim?.() ? (
<OverflowingTextWithTooltip text={text} />
) : !forceEmptyText ? (
<StyledEmptyText>Untitled</StyledEmptyText>
) : (
''
)}
</StyledChip>
);
};

View File

@ -6,14 +6,14 @@ import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { isDefined } from 'twenty-shared/utils';
import { MenuItem } from 'twenty-ui/navigation';
import {
MultipleAvatarChip,
MultipleAvatarChipProps,
} from 'twenty-ui/components';
CommandMenuContextChip,
CommandMenuContextChipProps,
} from './CommandMenuContextChip';
export const CommandMenuContextChipGroups = ({
contextChips,
}: {
contextChips: MultipleAvatarChipProps[];
contextChips: CommandMenuContextChipProps[];
}) => {
const { closeDropdown } = useCloseDropdown();
@ -25,9 +25,9 @@ export const CommandMenuContextChipGroups = ({
return (
<>
{contextChips.map((chip, index) => (
<MultipleAvatarChip
<CommandMenuContextChip
key={index}
maxWidth={180}
maxWidth={'180px'}
Icons={chip.Icons}
text={chip.text}
onClick={chip.onClick}
@ -46,7 +46,7 @@ export const CommandMenuContextChipGroups = ({
{firstChips.length > 0 && (
<Dropdown
clickableComponent={
<MultipleAvatarChip
<CommandMenuContextChip
Icons={firstThreeChips.map((chip) => chip.Icons?.[0])}
onClick={() => {}}
text={`${firstChips.length}`}
@ -77,11 +77,11 @@ export const CommandMenuContextChipGroups = ({
)}
{isDefined(lastChip) && (
<MultipleAvatarChip
<CommandMenuContextChip
Icons={lastChip.Icons}
text={lastChip.text}
onClick={lastChip.onClick}
maxWidth={180}
maxWidth={'180px'}
/>
)}
</>

View File

@ -4,14 +4,14 @@ import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { getSelectedRecordsContextText } from '@/command-menu/utils/getRecordContextText';
import { useFindManyRecordsSelectedInContextStore } from '@/context-store/hooks/useFindManyRecordsSelectedInContextStore';
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
import { CommandMenuContextChipProps } from './CommandMenuContextChip';
import { isDefined } from 'twenty-shared/utils';
import { MultipleAvatarChipProps } from 'twenty-ui/components';
export const CommandMenuContextChipGroupsWithRecordSelection = ({
contextChips,
objectMetadataItemId,
}: {
contextChips: MultipleAvatarChipProps[];
contextChips: CommandMenuContextChipProps[];
objectMetadataItemId: string;
}) => {
const { objectMetadataItem } = useObjectMetadataItemById({

View File

@ -1,8 +1,8 @@
import { CommandMenuContextChip } from '@/command-menu/components/CommandMenuContextChip';
import { CommandMenuContextRecordChipAvatars } from '@/command-menu/components/CommandMenuContextRecordChipAvatars';
import { getSelectedRecordsContextText } from '@/command-menu/utils/getRecordContextText';
import { useFindManyRecordsSelectedInContextStore } from '@/context-store/hooks/useFindManyRecordsSelectedInContextStore';
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
import { MultipleAvatarChip } from 'twenty-ui/components';
export const CommandMenuContextRecordsChip = ({
objectMetadataItemId,
@ -34,7 +34,7 @@ export const CommandMenuContextRecordsChip = ({
));
return (
<MultipleAvatarChip
<CommandMenuContextChip
text={getSelectedRecordsContextText(
objectMetadataItem,
records,

View File

@ -1,3 +1,4 @@
import { CommandMenuContextChip } from '@/command-menu/components/CommandMenuContextChip';
import { CommandMenuContextChipGroups } from '@/command-menu/components/CommandMenuContextChipGroups';
import { CommandMenuContextChipGroupsWithRecordSelection } from '@/command-menu/components/CommandMenuContextChipGroupsWithRecordSelection';
import { CommandMenuTopBarInputFocusEffect } from '@/command-menu/components/CommandMenuTopBarInputFocusEffect';
@ -21,7 +22,6 @@ import { useLocation } from 'react-router-dom';
import { useRecoilState, useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { IconChevronLeft, IconX } from 'twenty-ui/display';
import { MultipleAvatarChip } from 'twenty-ui/components';
import { Button } from 'twenty-ui/input';
import { getOsControlSymbol, useIsMobile } from 'twenty-ui/utilities';
@ -122,7 +122,7 @@ export const CommandMenuTopBar = () => {
duration: backButtonAnimationDuration,
}}
>
<MultipleAvatarChip
<CommandMenuContextChip
Icons={[<IconChevronLeft size={theme.icon.size.sm} />]}
onClick={goBackFromCommandMenu}
testId="command-menu-go-back-button"

View File

@ -36,14 +36,6 @@ export const MultipleAvatarChip = ({
variant = ChipVariant.Static,
forceEmptyText = false,
}: MultipleAvatarChipProps) => {
const leftComponent = (
<StyledIconsContainer>
{Icons.map((Icon, index) => (
<Fragment key={index}>{Icon}</Fragment>
))}
</StyledIconsContainer>
);
return (
<StyledChipContainer onClick={onClick} data-testid={testId}>
<Chip
@ -51,7 +43,13 @@ export const MultipleAvatarChip = ({
forceEmptyText={forceEmptyText}
isLabelHidden={!isNonEmptyString(text) && forceEmptyText}
variant={variant}
leftComponent={leftComponent}
leftComponent={
<StyledIconsContainer>
{Icons.map((Icon, index) => (
<Fragment key={index}>{Icon}</Fragment>
))}
</StyledIconsContainer>
}
rightComponent={rightComponent}
clickable={isDefined(onClick)}
maxWidth={maxWidth}