refactor: move Checkmark, Avatar, Chip and Tooltip to twenty-ui (#4946)

Split from https://github.com/twentyhq/twenty/pull/4518

Part of #4766
This commit is contained in:
Thaïs
2024-04-15 12:05:06 +02:00
committed by GitHub
parent acc2092b95
commit b6d0b8a895
93 changed files with 225 additions and 189 deletions

View File

@ -1,40 +0,0 @@
import { useTheme } from '@emotion/react';
import { motion } from 'framer-motion';
export type AnimatedCheckmarkProps = React.ComponentProps<
typeof motion.path
> & {
isAnimating?: boolean;
color?: string;
duration?: number;
size?: number;
};
export const AnimatedCheckmark = ({
isAnimating = false,
color,
duration = 0.5,
size = 28,
}: AnimatedCheckmarkProps) => {
const theme = useTheme();
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 52 52"
width={size}
height={size}
>
<motion.path
fill="none"
stroke={color ?? theme.grayScale.gray0}
strokeWidth={4}
d="M14 27l7.8 7.8L38 14"
pathLength="1"
strokeDasharray="1"
strokeDashoffset={isAnimating ? '1' : '0'}
animate={{ strokeDashoffset: isAnimating ? '0' : '1' }}
transition={{ duration }}
/>
</svg>
);
};

View File

@ -1,28 +0,0 @@
import React from 'react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconCheck } from 'twenty-ui';
const StyledContainer = styled.div`
align-items: center;
background-color: ${({ theme }) => theme.color.blue};
border-radius: 50%;
display: flex;
height: 20px;
justify-content: center;
width: 20px;
`;
export type CheckmarkProps = React.ComponentPropsWithoutRef<'div'> & {
className?: string;
};
export const Checkmark = ({ className }: CheckmarkProps) => {
const theme = useTheme();
return (
<StyledContainer className={className}>
<IconCheck color={theme.grayScale.gray0} size={14} />
</StyledContainer>
);
};

View File

@ -1,20 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { Checkmark } from '../Checkmark';
const meta: Meta<typeof Checkmark> = {
title: 'UI/Display/Checkmark/Checkmark',
component: Checkmark,
decorators: [ComponentDecorator],
};
export default meta;
type Story = StoryObj<typeof Checkmark>;
export const Default: Story = { args: {} };
export const WithCustomStyles: Story = {
args: { style: { backgroundColor: 'red', height: 40, width: 40 } },
};

View File

@ -1,178 +0,0 @@
import { MouseEvent, ReactNode } from 'react';
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import { OverflowingTextWithTooltip } from '../../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>
);

View File

@ -1,81 +0,0 @@
import * as React from 'react';
import { useNavigate } from 'react-router-dom';
import { useTheme } from '@emotion/react';
import { isNonEmptyString } from '@sniptt/guards';
import { IconComponent } from 'twenty-ui';
import { Avatar, AvatarType } from '@/users/components/Avatar';
import { Nullable } from '~/types/Nullable';
import { Chip, ChipVariant } from './Chip';
export type EntityChipProps = {
linkToEntity?: string;
entityId: string;
name: string;
avatarUrl?: string;
avatarType?: Nullable<AvatarType>;
variant?: EntityChipVariant;
LeftIcon?: IconComponent;
className?: string;
maxWidth?: number;
};
export enum EntityChipVariant {
Regular = 'regular',
Transparent = 'transparent',
}
export const EntityChip = ({
linkToEntity,
entityId,
name,
avatarUrl,
avatarType = 'rounded',
variant = EntityChipVariant.Regular,
LeftIcon,
className,
maxWidth,
}: EntityChipProps) => {
const navigate = useNavigate();
const theme = useTheme();
const handleLinkClick = (event: React.MouseEvent<HTMLDivElement>) => {
if (isNonEmptyString(linkToEntity)) {
event.preventDefault();
event.stopPropagation();
navigate(linkToEntity);
}
};
return (
<Chip
label={name}
variant={
linkToEntity
? variant === EntityChipVariant.Regular
? ChipVariant.Highlighted
: ChipVariant.Regular
: ChipVariant.Transparent
}
leftComponent={
LeftIcon ? (
<LeftIcon size={theme.icon.size.md} stroke={theme.icon.stroke.sm} />
) : (
<Avatar
avatarUrl={avatarUrl}
entityId={entityId}
placeholder={name}
size="sm"
type={avatarType}
/>
)
}
clickable={!!linkToEntity}
onClick={handleLinkClick}
className={className}
maxWidth={maxWidth}
/>
);
};

View File

@ -1,69 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { CatalogStory } from '~/testing/types';
import { Chip, ChipAccent, ChipSize, ChipVariant } from '../Chip';
const meta: Meta<typeof Chip> = {
title: 'UI/Display/Chip/Chip',
component: Chip,
};
export default meta;
type Story = StoryObj<typeof Chip>;
export const Default: Story = {
args: {
label: 'Chip test',
size: ChipSize.Small,
variant: ChipVariant.Highlighted,
accent: ChipAccent.TextPrimary,
disabled: false,
clickable: true,
maxWidth: 200,
},
decorators: [ComponentDecorator],
};
export const Catalog: CatalogStory<Story, typeof Chip> = {
args: { clickable: true, label: 'Hello' },
argTypes: {
size: { control: false },
variant: { control: false },
disabled: { control: false },
className: { control: false },
rightComponent: { control: false },
leftComponent: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.active'] },
catalog: {
dimensions: [
{
name: 'states',
values: ['default', 'hover', 'active', 'disabled'],
props: (state: string) =>
state === 'default' ? {} : { className: state },
},
{
name: 'variants',
values: Object.values(ChipVariant),
props: (variant: ChipVariant) => ({ variant }),
},
{
name: 'sizes',
values: Object.values(ChipSize),
props: (size: ChipSize) => ({ size }),
},
{
name: 'accents',
values: Object.values(ChipAccent),
props: (accent: ChipAccent) => ({ accent }),
},
],
},
},
decorators: [CatalogDecorator],
};

View File

@ -1,21 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
import { EntityChip } from '../EntityChip';
const meta: Meta<typeof EntityChip> = {
title: 'UI/Display/Chip/EntityChip',
component: EntityChip,
decorators: [ComponentWithRouterDecorator],
args: {
name: 'Entity name',
linkToEntity: '/entity-link',
avatarType: 'squared',
},
};
export default meta;
type Story = StoryObj<typeof EntityChip>;
export const Default: Story = {};

View File

@ -1,8 +1,8 @@
import React, { ReactElement, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import styled from '@emotion/styled';
import { Chip, ChipVariant } from 'twenty-ui';
import { Chip, ChipVariant } from '@/ui/display/chip/components/Chip';
import { IntersectionObserverWrapper } from '@/ui/display/expandable-list/IntersectionObserverWrapper';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';

View File

@ -1,12 +1,10 @@
import { Meta, StoryObj } from '@storybook/react';
import { CatalogDecorator, CatalogStory, ComponentDecorator } from 'twenty-ui';
import { Info, InfoAccent } from '@/ui/display/info/components/Info.tsx';
import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator.tsx';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator.tsx';
import { CatalogStory } from '~/testing/types.ts';
import { Info, InfoAccent } from '@/ui/display/info/components/Info';
const meta: Meta<typeof Info> = {
title: 'UI/Display/Info/Info',
title: 'UI/Display/Info',
component: Info,
};

View File

@ -1,73 +0,0 @@
import { PlacesType, PositionStrategy, Tooltip } from 'react-tooltip';
import styled from '@emotion/styled';
import { RGBA } from '@/ui/theme/constants/Rgba';
export enum TooltipPosition {
Top = 'top',
Left = 'left',
Right = 'right',
Bottom = 'bottom',
}
const StyledAppTooltip = styled(Tooltip)`
backdrop-filter: ${({ theme }) => theme.blur.strong};
background-color: ${({ theme }) => RGBA(theme.color.gray80, 0.8)};
border-radius: ${({ theme }) => theme.border.radius.sm};
box-shadow: ${({ theme }) => theme.boxShadow.light};
color: ${({ theme }) => theme.grayScale.gray0};
font-size: ${({ theme }) => theme.font.size.sm};
font-weight: ${({ theme }) => theme.font.weight.regular};
max-width: 40%;
overflow: visible;
padding: ${({ theme }) => theme.spacing(2)};
word-break: break-word;
z-index: ${({ theme }) => theme.lastLayerZIndex};
`;
export type AppTooltipProps = {
className?: string;
anchorSelect?: string;
content?: string;
children?: React.ReactNode;
delayHide?: number;
offset?: number;
noArrow?: boolean;
isOpen?: boolean;
place?: PlacesType;
positionStrategy?: PositionStrategy;
};
export const AppTooltip = ({
anchorSelect,
className,
content,
delayHide,
isOpen,
noArrow,
offset,
place,
positionStrategy,
children,
}: AppTooltipProps) => (
<StyledAppTooltip
{...{
anchorSelect,
className,
content,
delayHide,
isOpen,
noArrow,
offset,
place,
positionStrategy,
children,
}}
/>
);

View File

@ -1,84 +0,0 @@
import { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import styled from '@emotion/styled';
import { v4 as uuidV4 } from 'uuid';
import { AppTooltip } from './AppTooltip';
const StyledOverflowingText = styled.div<{ cursorPointer: boolean }>`
cursor: ${({ cursorPointer }) => (cursorPointer ? 'pointer' : 'inherit')};
font-family: inherit;
font-size: inherit;
font-weight: inherit;
max-width: 100%;
overflow: hidden;
text-decoration: inherit;
text-overflow: ellipsis;
white-space: nowrap;
`;
export const OverflowingTextWithTooltip = ({
text,
className,
mutliline,
}: {
text: string | null | undefined;
className?: string;
mutliline?: boolean;
}) => {
const textElementId = `title-id-${uuidV4()}`;
const textRef = useRef<HTMLDivElement>(null);
const [isTitleOverflowing, setIsTitleOverflowing] = useState(false);
useEffect(() => {
const isOverflowing =
(text?.length ?? 0) > 0 && textRef.current
? textRef.current?.scrollHeight > textRef.current?.clientHeight ||
textRef.current.scrollWidth > textRef.current.clientWidth
: false;
if (isTitleOverflowing !== isOverflowing) {
setIsTitleOverflowing(isOverflowing);
}
}, [isTitleOverflowing, text]);
const handleTooltipClick = (event: React.MouseEvent<HTMLDivElement>) => {
event.stopPropagation();
event.preventDefault();
};
return (
<>
<StyledOverflowingText
data-testid="tooltip"
className={className}
ref={textRef}
id={textElementId}
cursorPointer={isTitleOverflowing}
>
{text}
</StyledOverflowingText>
{isTitleOverflowing &&
createPortal(
<div onClick={handleTooltipClick}>
<AppTooltip
anchorSelect={`#${textElementId}`}
content={mutliline ? undefined : text ?? ''}
delayHide={0}
offset={5}
noArrow
place="bottom"
positionStrategy="absolute"
>
{mutliline ? <pre>{text}</pre> : ''}
</AppTooltip>
</div>,
document.body,
)}
</>
);
};

View File

@ -1,29 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/test';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { OverflowingTextWithTooltip } from '../OverflowingTextWithTooltip';
const placeholderText =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi tellus diam, rhoncus nec consequat quis, dapibus quis massa. Praesent tincidunt augue at ex bibendum, non finibus augue faucibus. In at gravida orci. Nulla facilisi. Proin ut augue ut nisi pellentesque tristique. Proin sodales libero id turpis tincidunt posuere.';
const meta: Meta<typeof OverflowingTextWithTooltip> = {
title: 'UI/Display/Tooltip/OverflowingTextWithTooltip',
component: OverflowingTextWithTooltip,
};
export default meta;
type Story = StoryObj<typeof OverflowingTextWithTooltip>;
export const Default: Story = {
args: {
text: placeholderText,
},
decorators: [ComponentDecorator],
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const tooltip = await canvas.findByTestId('tooltip');
userEvent.hover(tooltip);
},
};

View File

@ -1,82 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { CatalogStory } from '~/testing/types';
import { AppTooltip as Tooltip, TooltipPosition } from '../AppTooltip';
const meta: Meta<typeof Tooltip> = {
title: 'UI/Display/Tooltip/Tooltip',
component: Tooltip,
};
export default meta;
type Story = StoryObj<typeof Tooltip>;
export const Default: Story = {
args: {
place: TooltipPosition.Bottom,
content: 'Tooltip Test',
isOpen: true,
anchorSelect: '#hover-text',
},
decorators: [ComponentDecorator],
render: ({
anchorSelect,
className,
content,
delayHide,
isOpen,
noArrow,
offset,
place,
positionStrategy,
}) => (
<>
<p id="hover-text" data-testid="tooltip">
Hover me!
</p>
<Tooltip
{...{
anchorSelect,
className,
content,
delayHide,
isOpen,
noArrow,
offset,
place,
positionStrategy,
}}
/>
</>
),
};
export const Catalog: CatalogStory<Story, typeof Tooltip> = {
args: { isOpen: true, content: 'Tooltip Test' },
play: async ({ canvasElement }) => {
Object.values(TooltipPosition).forEach((position) => {
const element = canvasElement.querySelector(
`#${position}`,
) as HTMLElement;
element.style.margin = '75px';
});
},
parameters: {
catalog: {
dimensions: [
{
name: 'anchorSelect',
values: Object.values(TooltipPosition),
props: (anchorSelect: TooltipPosition) => ({
anchorSelect: `#${anchorSelect}`,
place: anchorSelect,
}),
},
],
},
},
decorators: [CatalogDecorator],
};

View File

@ -1,4 +1,4 @@
import { OverflowingTextWithTooltip } from '../../../display/tooltip/OverflowingTextWithTooltip';
import { OverflowingTextWithTooltip } from 'twenty-ui';
import { EllipsisDisplay } from './EllipsisDisplay';

View File

@ -2,11 +2,11 @@ import { useRef, useState } from 'react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { flip, offset, useFloating } from '@floating-ui/react';
import { Nullable } from 'twenty-ui';
import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents';
import { DateDisplay } from '@/ui/field/display/components/DateDisplay';
import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker';
import { Nullable } from '~/types/Nullable';
const StyledCalendarContainer = styled.div`
background: ${({ theme }) => theme.background.secondary};

View File

@ -6,8 +6,8 @@ import {
motion,
useAnimation,
} from 'framer-motion';
import { Checkmark } from 'twenty-ui';
import { Checkmark } from '@/ui/display/checkmark/components/Checkmark';
import { ColorScheme } from '@/workspace-member/types/WorkspaceMember';
const StyledColorSchemeBackground = styled.div<

View File

@ -3,14 +3,13 @@ import styled from '@emotion/styled';
import { Decorator, Meta, StoryObj } from '@storybook/react';
import { expect, userEvent, waitFor, within } from '@storybook/test';
import { PlayFunction } from '@storybook/types';
import { Avatar, ComponentDecorator } from 'twenty-ui';
import { Button } from '@/ui/input/button/components/Button';
import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { MenuItemMultiSelectAvatar } from '@/ui/navigation/menu-item/components/MenuItemMultiSelectAvatar';
import { MenuItemSelectAvatar } from '@/ui/navigation/menu-item/components/MenuItemSelectAvatar';
import { Avatar } from '@/users/components/Avatar';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { Dropdown } from '../Dropdown';
import { DropdownMenuHeader } from '../DropdownMenuHeader';

View File

@ -4,9 +4,12 @@ import { useNavigate } from 'react-router-dom';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
import { IconChevronLeft, IconComponent } from 'twenty-ui';
import {
IconChevronLeft,
IconComponent,
OverflowingTextWithTooltip,
} from 'twenty-ui';
import { OverflowingTextWithTooltip } from '@/ui/display/tooltip/OverflowingTextWithTooltip';
import { IconButton } from '@/ui/input/button/components/IconButton';
import { NavigationDrawerCollapseButton } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton';
import { isNavigationDrawerOpenState } from '@/ui/navigation/states/isNavigationDrawerOpenState';

View File

@ -1,9 +1,9 @@
import { ChangeEvent, ReactNode, useRef } from 'react';
import { Tooltip } from 'react-tooltip';
import styled from '@emotion/styled';
import { Avatar, AvatarType } from 'twenty-ui';
import { v4 as uuidV4 } from 'uuid';
import { Avatar, AvatarType } from '@/users/components/Avatar';
import {
beautifyExactDateTime,
beautifyPastDateRelativeToNow,

View File

@ -1,8 +1,7 @@
import * as React from 'react';
import { Link as ReactLink } from 'react-router-dom';
import styled from '@emotion/styled';
import { Chip, ChipSize, ChipVariant } from '@/ui/display/chip/components/Chip';
import { Chip, ChipSize, ChipVariant } from 'twenty-ui';
type RoundedLinkProps = {
href: string;

View File

@ -1,7 +1,7 @@
import { ReactNode } from 'react';
import styled from '@emotion/styled';
import { OverflowingTextWithTooltip } from 'twenty-ui';
import { OverflowingTextWithTooltip } from '@/ui/display/tooltip/OverflowingTextWithTooltip';
import { Checkbox } from '@/ui/input/components/Checkbox';
import {

View File

@ -1,8 +1,6 @@
import { ReactNode } from 'react';
import { useTheme } from '@emotion/react';
import { IconCheck } from 'twenty-ui';
import { OverflowingTextWithTooltip } from '@/ui/display/tooltip/OverflowingTextWithTooltip';
import { IconCheck, OverflowingTextWithTooltip } from 'twenty-ui';
import {
StyledMenuItemLabel,

View File

@ -1,14 +1,14 @@
import { Meta, StoryObj } from '@storybook/react';
import { Avatar } from '@/users/components/Avatar';
import {
Avatar,
CatalogDecorator,
CatalogDimension,
CatalogOptions,
} from '~/testing/decorators/CatalogDecorator';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
CatalogStory,
ComponentDecorator,
} from 'twenty-ui';
import { avatarUrl } from '~/testing/mock-data/users';
import { CatalogStory } from '~/testing/types';
import { MenuItemMultiSelectAvatar } from '../MenuItemMultiSelectAvatar';

View File

@ -1,14 +1,14 @@
import { Meta, StoryObj } from '@storybook/react';
import { Avatar } from '@/users/components/Avatar';
import {
Avatar,
CatalogDecorator,
CatalogDimension,
CatalogOptions,
} from '~/testing/decorators/CatalogDecorator';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
CatalogStory,
ComponentDecorator,
} from 'twenty-ui';
import { avatarUrl } from '~/testing/mock-data/users';
import { CatalogStory } from '~/testing/types';
import { MenuItemSelectAvatar } from '../MenuItemSelectAvatar';

View File

@ -1,7 +1,9 @@
import { useTheme } from '@emotion/react';
import { IconComponent, IconGripVertical } from 'twenty-ui';
import { OverflowingTextWithTooltip } from '@/ui/display/tooltip/OverflowingTextWithTooltip';
import {
IconComponent,
IconGripVertical,
OverflowingTextWithTooltip,
} from 'twenty-ui';
import {
StyledMenuItemLabel,

View File

@ -1,8 +1,8 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
import { AnimatedCheckmark } from 'twenty-ui';
import { AnimatedCheckmark } from '@/ui/display/checkmark/components/AnimatedCheckmark';
import { MOBILE_VIEWPORT } from '@/ui/theme/constants/MobileViewport';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';