fix(ui): keep 2 components for chip (#13359)
This commit is contained in:
@ -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>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -6,14 +6,14 @@ import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
|||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
import { MenuItem } from 'twenty-ui/navigation';
|
||||||
import {
|
import {
|
||||||
MultipleAvatarChip,
|
CommandMenuContextChip,
|
||||||
MultipleAvatarChipProps,
|
CommandMenuContextChipProps,
|
||||||
} from 'twenty-ui/components';
|
} from './CommandMenuContextChip';
|
||||||
|
|
||||||
export const CommandMenuContextChipGroups = ({
|
export const CommandMenuContextChipGroups = ({
|
||||||
contextChips,
|
contextChips,
|
||||||
}: {
|
}: {
|
||||||
contextChips: MultipleAvatarChipProps[];
|
contextChips: CommandMenuContextChipProps[];
|
||||||
}) => {
|
}) => {
|
||||||
const { closeDropdown } = useCloseDropdown();
|
const { closeDropdown } = useCloseDropdown();
|
||||||
|
|
||||||
@ -25,9 +25,9 @@ export const CommandMenuContextChipGroups = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{contextChips.map((chip, index) => (
|
{contextChips.map((chip, index) => (
|
||||||
<MultipleAvatarChip
|
<CommandMenuContextChip
|
||||||
key={index}
|
key={index}
|
||||||
maxWidth={180}
|
maxWidth={'180px'}
|
||||||
Icons={chip.Icons}
|
Icons={chip.Icons}
|
||||||
text={chip.text}
|
text={chip.text}
|
||||||
onClick={chip.onClick}
|
onClick={chip.onClick}
|
||||||
@ -46,7 +46,7 @@ export const CommandMenuContextChipGroups = ({
|
|||||||
{firstChips.length > 0 && (
|
{firstChips.length > 0 && (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
clickableComponent={
|
clickableComponent={
|
||||||
<MultipleAvatarChip
|
<CommandMenuContextChip
|
||||||
Icons={firstThreeChips.map((chip) => chip.Icons?.[0])}
|
Icons={firstThreeChips.map((chip) => chip.Icons?.[0])}
|
||||||
onClick={() => {}}
|
onClick={() => {}}
|
||||||
text={`${firstChips.length}`}
|
text={`${firstChips.length}`}
|
||||||
@ -77,11 +77,11 @@ export const CommandMenuContextChipGroups = ({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{isDefined(lastChip) && (
|
{isDefined(lastChip) && (
|
||||||
<MultipleAvatarChip
|
<CommandMenuContextChip
|
||||||
Icons={lastChip.Icons}
|
Icons={lastChip.Icons}
|
||||||
text={lastChip.text}
|
text={lastChip.text}
|
||||||
onClick={lastChip.onClick}
|
onClick={lastChip.onClick}
|
||||||
maxWidth={180}
|
maxWidth={'180px'}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -4,14 +4,14 @@ import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
|||||||
import { getSelectedRecordsContextText } from '@/command-menu/utils/getRecordContextText';
|
import { getSelectedRecordsContextText } from '@/command-menu/utils/getRecordContextText';
|
||||||
import { useFindManyRecordsSelectedInContextStore } from '@/context-store/hooks/useFindManyRecordsSelectedInContextStore';
|
import { useFindManyRecordsSelectedInContextStore } from '@/context-store/hooks/useFindManyRecordsSelectedInContextStore';
|
||||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||||
|
import { CommandMenuContextChipProps } from './CommandMenuContextChip';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { MultipleAvatarChipProps } from 'twenty-ui/components';
|
|
||||||
|
|
||||||
export const CommandMenuContextChipGroupsWithRecordSelection = ({
|
export const CommandMenuContextChipGroupsWithRecordSelection = ({
|
||||||
contextChips,
|
contextChips,
|
||||||
objectMetadataItemId,
|
objectMetadataItemId,
|
||||||
}: {
|
}: {
|
||||||
contextChips: MultipleAvatarChipProps[];
|
contextChips: CommandMenuContextChipProps[];
|
||||||
objectMetadataItemId: string;
|
objectMetadataItemId: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { objectMetadataItem } = useObjectMetadataItemById({
|
const { objectMetadataItem } = useObjectMetadataItemById({
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
|
import { CommandMenuContextChip } from '@/command-menu/components/CommandMenuContextChip';
|
||||||
import { CommandMenuContextRecordChipAvatars } from '@/command-menu/components/CommandMenuContextRecordChipAvatars';
|
import { CommandMenuContextRecordChipAvatars } from '@/command-menu/components/CommandMenuContextRecordChipAvatars';
|
||||||
import { getSelectedRecordsContextText } from '@/command-menu/utils/getRecordContextText';
|
import { getSelectedRecordsContextText } from '@/command-menu/utils/getRecordContextText';
|
||||||
import { useFindManyRecordsSelectedInContextStore } from '@/context-store/hooks/useFindManyRecordsSelectedInContextStore';
|
import { useFindManyRecordsSelectedInContextStore } from '@/context-store/hooks/useFindManyRecordsSelectedInContextStore';
|
||||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||||
import { MultipleAvatarChip } from 'twenty-ui/components';
|
|
||||||
|
|
||||||
export const CommandMenuContextRecordsChip = ({
|
export const CommandMenuContextRecordsChip = ({
|
||||||
objectMetadataItemId,
|
objectMetadataItemId,
|
||||||
@ -34,7 +34,7 @@ export const CommandMenuContextRecordsChip = ({
|
|||||||
));
|
));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MultipleAvatarChip
|
<CommandMenuContextChip
|
||||||
text={getSelectedRecordsContextText(
|
text={getSelectedRecordsContextText(
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
records,
|
records,
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { CommandMenuContextChip } from '@/command-menu/components/CommandMenuContextChip';
|
||||||
import { CommandMenuContextChipGroups } from '@/command-menu/components/CommandMenuContextChipGroups';
|
import { CommandMenuContextChipGroups } from '@/command-menu/components/CommandMenuContextChipGroups';
|
||||||
import { CommandMenuContextChipGroupsWithRecordSelection } from '@/command-menu/components/CommandMenuContextChipGroupsWithRecordSelection';
|
import { CommandMenuContextChipGroupsWithRecordSelection } from '@/command-menu/components/CommandMenuContextChipGroupsWithRecordSelection';
|
||||||
import { CommandMenuTopBarInputFocusEffect } from '@/command-menu/components/CommandMenuTopBarInputFocusEffect';
|
import { CommandMenuTopBarInputFocusEffect } from '@/command-menu/components/CommandMenuTopBarInputFocusEffect';
|
||||||
@ -21,7 +22,6 @@ import { useLocation } from 'react-router-dom';
|
|||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { IconChevronLeft, IconX } from 'twenty-ui/display';
|
import { IconChevronLeft, IconX } from 'twenty-ui/display';
|
||||||
import { MultipleAvatarChip } from 'twenty-ui/components';
|
|
||||||
import { Button } from 'twenty-ui/input';
|
import { Button } from 'twenty-ui/input';
|
||||||
import { getOsControlSymbol, useIsMobile } from 'twenty-ui/utilities';
|
import { getOsControlSymbol, useIsMobile } from 'twenty-ui/utilities';
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ export const CommandMenuTopBar = () => {
|
|||||||
duration: backButtonAnimationDuration,
|
duration: backButtonAnimationDuration,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MultipleAvatarChip
|
<CommandMenuContextChip
|
||||||
Icons={[<IconChevronLeft size={theme.icon.size.sm} />]}
|
Icons={[<IconChevronLeft size={theme.icon.size.sm} />]}
|
||||||
onClick={goBackFromCommandMenu}
|
onClick={goBackFromCommandMenu}
|
||||||
testId="command-menu-go-back-button"
|
testId="command-menu-go-back-button"
|
||||||
|
|||||||
@ -36,14 +36,6 @@ export const MultipleAvatarChip = ({
|
|||||||
variant = ChipVariant.Static,
|
variant = ChipVariant.Static,
|
||||||
forceEmptyText = false,
|
forceEmptyText = false,
|
||||||
}: MultipleAvatarChipProps) => {
|
}: MultipleAvatarChipProps) => {
|
||||||
const leftComponent = (
|
|
||||||
<StyledIconsContainer>
|
|
||||||
{Icons.map((Icon, index) => (
|
|
||||||
<Fragment key={index}>{Icon}</Fragment>
|
|
||||||
))}
|
|
||||||
</StyledIconsContainer>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledChipContainer onClick={onClick} data-testid={testId}>
|
<StyledChipContainer onClick={onClick} data-testid={testId}>
|
||||||
<Chip
|
<Chip
|
||||||
@ -51,7 +43,13 @@ export const MultipleAvatarChip = ({
|
|||||||
forceEmptyText={forceEmptyText}
|
forceEmptyText={forceEmptyText}
|
||||||
isLabelHidden={!isNonEmptyString(text) && forceEmptyText}
|
isLabelHidden={!isNonEmptyString(text) && forceEmptyText}
|
||||||
variant={variant}
|
variant={variant}
|
||||||
leftComponent={leftComponent}
|
leftComponent={
|
||||||
|
<StyledIconsContainer>
|
||||||
|
{Icons.map((Icon, index) => (
|
||||||
|
<Fragment key={index}>{Icon}</Fragment>
|
||||||
|
))}
|
||||||
|
</StyledIconsContainer>
|
||||||
|
}
|
||||||
rightComponent={rightComponent}
|
rightComponent={rightComponent}
|
||||||
clickable={isDefined(onClick)}
|
clickable={isDefined(onClick)}
|
||||||
maxWidth={maxWidth}
|
maxWidth={maxWidth}
|
||||||
|
|||||||
Reference in New Issue
Block a user