Fix menu item overflowing hiding icon buttons (#14847)
FIxes https://github.com/twentyhq/twenty/issues/14764 <img width="3944" height="886" alt="CleanShot 2025-10-02 at 16 01 43@2x" src="https://github.com/user-attachments/assets/9d6cbb73-903d-4fd1-9456-395aa9745c45" /> <img width="525" height="1266" alt="CleanShot 2025-10-02 at 16 06 34@2x" src="https://github.com/user-attachments/assets/cc6d6e89-48f7-48da-abff-b8458c2e7ae3" />
This commit is contained in:
@@ -1,9 +1,5 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import {
|
||||
IconChevronRight,
|
||||
OverflowingTextWithTooltip,
|
||||
type IconComponent,
|
||||
} from '@ui/display';
|
||||
import { IconChevronRight, type IconComponent } from '@ui/display';
|
||||
import { type LightIconButtonProps } from '@ui/input/button/components/LightIconButton';
|
||||
import { LightIconButtonGroup } from '@ui/input/button/components/LightIconButtonGroup';
|
||||
import {
|
||||
@@ -14,16 +10,12 @@ import {
|
||||
} from 'react';
|
||||
|
||||
import styled from '@emotion/styled';
|
||||
import { isString } from '@sniptt/guards';
|
||||
import { MenuItemHotKeys } from '@ui/navigation/menu/menu-item/components/MenuItemHotKeys';
|
||||
import { motion } from 'framer-motion';
|
||||
import { MenuItemLeftContent } from '../internals/components/MenuItemLeftContent';
|
||||
import {
|
||||
StyledHoverableMenuItemBase,
|
||||
StyledMenuItemLabel,
|
||||
StyledMenuItemLeftContent,
|
||||
StyledMenuItemRightContent,
|
||||
StyledRightMenuItemContextualText,
|
||||
} from '../internals/components/StyledMenuItemBase';
|
||||
import { type MenuItemAccent } from '../types/MenuItemAccent';
|
||||
|
||||
@@ -111,30 +103,17 @@ export const MenuItem = ({
|
||||
onMouseLeave={onMouseLeave}
|
||||
focused={focused}
|
||||
>
|
||||
<StyledMenuItemLeftContent>
|
||||
<MenuItemLeftContent
|
||||
LeftIcon={LeftIcon ?? undefined}
|
||||
LeftComponent={LeftComponent}
|
||||
withIconContainer={withIconContainer}
|
||||
text={text}
|
||||
contextualText={
|
||||
contextualTextPosition === 'left' ? contextualText : null
|
||||
}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</StyledMenuItemLeftContent>
|
||||
<MenuItemLeftContent
|
||||
LeftIcon={LeftIcon ?? undefined}
|
||||
LeftComponent={LeftComponent}
|
||||
withIconContainer={withIconContainer}
|
||||
text={text}
|
||||
contextualText={contextualText}
|
||||
contextualTextPosition={contextualTextPosition}
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
||||
<StyledMenuItemRightContent>
|
||||
{contextualTextPosition === 'right' && (
|
||||
<StyledMenuItemLabel>
|
||||
{isString(contextualText) ? (
|
||||
<StyledRightMenuItemContextualText>
|
||||
<OverflowingTextWithTooltip text={contextualText} />
|
||||
</StyledRightMenuItemContextualText>
|
||||
) : (
|
||||
contextualText
|
||||
)}
|
||||
</StyledMenuItemLabel>
|
||||
)}
|
||||
{iconButtons && (
|
||||
<div className="hoverable-buttons">
|
||||
{showIconButtons && (
|
||||
|
||||
+50
@@ -198,6 +198,7 @@ export const ContextualTextCatalog: CatalogStory<Story, typeof MenuItem> = {
|
||||
},
|
||||
decorators: [CatalogDecorator],
|
||||
parameters: {
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
{
|
||||
@@ -227,6 +228,55 @@ export const ContextualTextCatalog: CatalogStory<Story, typeof MenuItem> = {
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'iconButtons',
|
||||
values: ['no icon button', 'one icon button'],
|
||||
props: (choice: string) => {
|
||||
switch (choice) {
|
||||
case 'no icon button': {
|
||||
return {
|
||||
iconButtons: [],
|
||||
};
|
||||
}
|
||||
case 'one icon button': {
|
||||
return {
|
||||
iconButtons: [
|
||||
{
|
||||
Icon: IconBell,
|
||||
onClick: action('Clicked on icon button'),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
},
|
||||
labels: (choice: string) => {
|
||||
switch (choice) {
|
||||
case 'no icon button':
|
||||
return 'No icon button';
|
||||
case 'one icon button':
|
||||
return 'One icon button';
|
||||
default:
|
||||
return choice;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'states',
|
||||
values: ['default', 'hover'],
|
||||
props: (state: string) => {
|
||||
switch (state) {
|
||||
case 'default':
|
||||
return {};
|
||||
case 'hover':
|
||||
return { className: 'hover' };
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
options: {
|
||||
elementContainer: {
|
||||
|
||||
+26
-8
@@ -13,6 +13,7 @@ import {
|
||||
StyledMenuItemContextualText,
|
||||
StyledMenuItemLabel,
|
||||
StyledMenuItemLeftContent,
|
||||
StyledRightMenuItemContextualText,
|
||||
} from './StyledMenuItemBase';
|
||||
|
||||
const StyledMainText = styled.div`
|
||||
@@ -32,6 +33,10 @@ const StyledIconContainer = styled.div`
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledMenuItemLabelRight = styled(StyledMenuItemLabel)`
|
||||
margin-left: auto;
|
||||
`;
|
||||
|
||||
type MenuItemLeftContentProps = {
|
||||
className?: string;
|
||||
LeftComponent?: ReactNode;
|
||||
@@ -41,6 +46,7 @@ type MenuItemLeftContentProps = {
|
||||
disabled?: boolean;
|
||||
text: ReactNode;
|
||||
contextualText?: ReactNode;
|
||||
contextualTextPosition?: 'left' | 'right';
|
||||
};
|
||||
|
||||
export const MenuItemLeftContent = ({
|
||||
@@ -50,6 +56,7 @@ export const MenuItemLeftContent = ({
|
||||
withIconContainer = false,
|
||||
text,
|
||||
contextualText,
|
||||
contextualTextPosition = 'left',
|
||||
showGrip = false,
|
||||
disabled = false,
|
||||
}: MenuItemLeftContentProps) => {
|
||||
@@ -89,18 +96,29 @@ export const MenuItemLeftContent = ({
|
||||
) : (
|
||||
text
|
||||
)}
|
||||
{isString(contextualText) ? (
|
||||
{contextualTextPosition === 'left' && (
|
||||
<>
|
||||
{isNonEmptyString(contextualText) && (
|
||||
<StyledMenuItemContextualText>
|
||||
<OverflowingTextWithTooltip text={`· ${contextualText}`} />
|
||||
</StyledMenuItemContextualText>
|
||||
)}
|
||||
{isString(contextualText)
|
||||
? isNonEmptyString(contextualText) && (
|
||||
<StyledMenuItemContextualText>
|
||||
<OverflowingTextWithTooltip text={`· ${contextualText}`} />
|
||||
</StyledMenuItemContextualText>
|
||||
)
|
||||
: contextualText}
|
||||
</>
|
||||
) : (
|
||||
contextualText
|
||||
)}
|
||||
</StyledMenuItemLabel>
|
||||
{contextualTextPosition === 'right' && (
|
||||
<StyledMenuItemLabelRight>
|
||||
<StyledRightMenuItemContextualText>
|
||||
{isString(contextualText) ? (
|
||||
<OverflowingTextWithTooltip text={contextualText} />
|
||||
) : (
|
||||
contextualText
|
||||
)}
|
||||
</StyledRightMenuItemContextualText>
|
||||
</StyledMenuItemLabelRight>
|
||||
)}
|
||||
</StyledMenuItemLeftContent>
|
||||
);
|
||||
};
|
||||
|
||||
+9
-5
@@ -112,16 +112,22 @@ export const StyledMenuItemLeftContent = styled.div`
|
||||
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
|
||||
flex-shrink: 0;
|
||||
& svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledMenuItemRightContent = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
|
||||
& svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledDraggableItem = styled.div`
|
||||
@@ -187,7 +193,5 @@ export const StyledMenuItemContextualText = styled.div`
|
||||
export const StyledRightMenuItemContextualText = styled(
|
||||
StyledMenuItemContextualText,
|
||||
)`
|
||||
display: flex;
|
||||
text-align: right;
|
||||
padding-right: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user