Left menu and chip links (#12294)

Small optimization for faster loading (gaining ~80ms - average time of a
click)

It might seem a little over-engineered but there are a lot of edge cases
and I couldn't find a simpler solution

I also tried to tackle Link Chips but it's more complex so this will be
for another PR
This commit is contained in:
Félix Malfait
2025-05-28 12:32:49 +02:00
committed by GitHub
parent 97d4ec96af
commit d4fac6793a
29 changed files with 203 additions and 60 deletions

View File

@ -6,6 +6,7 @@ import { ReactElement } from 'react';
import { Link } from 'react-router-dom';
import { Pill } from 'twenty-ui/components';
import { Avatar, IconComponent } from 'twenty-ui/display';
import { useMouseDownNavigation } from 'twenty-ui/utilities';
type TabProps = {
id: string;
@ -87,6 +88,13 @@ export const Tab = ({
logo,
}: TabProps) => {
const theme = useTheme();
const { onClick: handleClick, onMouseDown: handleMouseDown } =
useMouseDownNavigation({
to,
onClick,
disabled,
});
const iconColor = active
? theme.font.color.primary
: disabled
@ -95,7 +103,8 @@ export const Tab = ({
return (
<StyledTab
onClick={onClick}
onClick={handleClick}
onMouseDown={handleMouseDown}
active={active}
className={className}
disabled={disabled}

View File

@ -93,11 +93,13 @@ export const TabList = ({
disabled={tab.disabled ?? loading}
pill={tab.pill}
to={behaveAsLinks ? `#${tab.id}` : undefined}
onClick={() => {
if (!behaveAsLinks) {
setActiveTabId(tab.id);
}
}}
onClick={
behaveAsLinks
? undefined
: () => {
setActiveTabId(tab.id);
}
}
/>
))}
</StyledContainer>

View File

@ -1,16 +1,17 @@
import { Meta, StoryObj } from '@storybook/react';
import { Tab } from '../Tab';
import { IconCheckbox } from 'twenty-ui/display';
import {
CatalogDecorator,
CatalogStory,
ComponentDecorator,
ComponentWithRouterDecorator,
} from 'twenty-ui/testing';
import { IconCheckbox } from 'twenty-ui/display';
import { Tab } from '../Tab';
const meta: Meta<typeof Tab> = {
title: 'UI/Layout/Tab/Tab',
component: Tab,
decorators: [ComponentWithRouterDecorator],
};
export default meta;
@ -23,8 +24,7 @@ export const Default: Story = {
Icon: IconCheckbox,
disabled: false,
},
decorators: [ComponentDecorator],
decorators: [ComponentWithRouterDecorator],
};
export const Catalog: CatalogStory<Story, typeof Tab> = {

View File

@ -11,10 +11,11 @@ import styled from '@emotion/styled';
import { ReactNode } from 'react';
import { Link } from 'react-router-dom';
import { useRecoilState } from 'recoil';
import { capitalize, isDefined } from 'twenty-shared/utils';
import { capitalize } from 'twenty-shared/utils';
import { Pill } from 'twenty-ui/components';
import { IconComponent, Label, TablerIconsProps } from 'twenty-ui/display';
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
import { Pill } from 'twenty-ui/components';
import { TriggerEventType, useMouseDownNavigation } from 'twenty-ui/utilities';
const DEFAULT_INDENTATION_LEVEL = 1;
@ -37,6 +38,7 @@ export type NavigationDrawerItemProps = {
rightOptions?: ReactNode;
isDragging?: boolean;
isRightOptionsDropdownOpen?: boolean;
triggerEvent?: TriggerEventType;
};
type StyledItemProps = Pick<
@ -250,6 +252,7 @@ export const NavigationDrawerItem = ({
rightOptions,
isDragging,
isRightOptionsDropdownOpen,
triggerEvent,
}: NavigationDrawerItemProps) => {
const theme = useTheme();
const isMobile = useIsMobile();
@ -259,22 +262,26 @@ export const NavigationDrawerItem = ({
const showBreadcrumb = indentationLevel === 2;
const showStyledSpacer = !!soon || !!count || !!keyboard || !!rightOptions;
const handleItemClick = () => {
const handleMobileNavigation = () => {
if (isMobile) {
setIsNavigationDrawerExpanded(false);
}
if (isDefined(onClick)) {
onClick();
return;
}
};
const { onClick: handleClick, onMouseDown: handleMouseDown } =
useMouseDownNavigation({
to,
onClick,
onBeforeNavigation: handleMobileNavigation,
triggerEvent,
});
return (
<StyledNavigationDrawerItemContainer>
<StyledItem
className={`navigation-drawer-item ${className || ''}`}
onClick={handleItemClick}
onClick={handleClick}
onMouseDown={handleMouseDown}
active={active}
aria-selected={active}
danger={danger}

View File

@ -20,6 +20,7 @@ export const NavigationDrawerSubItem = ({
subItemState,
rightOptions,
isDragging,
triggerEvent,
}: NavigationDrawerSubItemProps) => {
return (
<NavigationDrawerItem
@ -38,6 +39,7 @@ export const NavigationDrawerSubItem = ({
keyboard={keyboard}
rightOptions={rightOptions}
isDragging={isDragging}
triggerEvent={triggerEvent}
/>
);
};