Feat/performance-refactor-styled-component (#5516)

In this PR I'm optimizing a whole RecordTableCell in real conditions
with a complex RelationFieldDisplay component :
- Broke down getObjectRecordIdentifier into multiple utils
- Precompute memoized function for getting chip data per field with
useRecordChipDataGenerator()
- Refactored RelationFieldDisplay
- Use CSS modules where performance is needed instead of styled
components
- Create a CSS theme with global CSS variables to be used by CSS modules
This commit is contained in:
Lucas Bordeau
2024-05-24 18:53:37 +02:00
committed by GitHub
parent 3680647c9a
commit a0178478d4
39 changed files with 1045 additions and 462 deletions

View File

@ -0,0 +1,20 @@
.main {
font-family: inherit;
font-size: inherit;
font-weight: inherit;
max-width: 100%;
overflow: hidden;
text-decoration: inherit;
text-overflow: ellipsis;
white-space: nowrap;
}
.cursor {
cursor: pointer;
}
.large {
height: calc(var(--twentycrm-spacing-multiplicator) * 4px);
}

View File

@ -1,41 +1,40 @@
import { useState } from 'react';
import { useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import styled from '@emotion/styled';
import clsx from 'clsx';
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;
`;
import styles from './OverflowingTextWithTooltip.module.css';
export const OverflowingTextWithTooltip = ({
size = 'small',
text,
className,
mutliline,
}: {
size?: 'large' | 'small';
text: string | null | undefined;
className?: string;
mutliline?: boolean;
}) => {
const textElementId = `title-id-${uuidV4()}`;
const [textElement, setTextElement] = useState<HTMLDivElement | null>(null);
const isTitleOverflowing =
(text?.length ?? 0) > 0 &&
!!textElement &&
(textElement.scrollHeight > textElement.clientHeight ||
textElement.scrollWidth > textElement.clientWidth);
const textRef = useRef<HTMLDivElement>(null);
const [isTitleOverflowing, setIsTitleOverflowing] = useState(false);
const handleMouseEnter = () => {
const isOverflowing =
(text?.length ?? 0) > 0 && textRef.current
? textRef.current?.scrollHeight > textRef.current?.clientHeight ||
textRef.current.scrollWidth > textRef.current.clientWidth
: false;
setIsTitleOverflowing(isOverflowing);
};
const handleMouseLeave = () => {
setIsTitleOverflowing(false);
};
const handleTooltipClick = (event: React.MouseEvent<HTMLDivElement>) => {
event.stopPropagation();
@ -44,23 +43,29 @@ export const OverflowingTextWithTooltip = ({
return (
<>
<StyledOverflowingText
<div
data-testid="tooltip"
className={className}
ref={setTextElement}
className={clsx({
[styles.main]: true,
[styles.cursor]: isTitleOverflowing,
[styles.large]: size === 'large',
})}
ref={textRef}
id={textElementId}
cursorPointer={isTitleOverflowing}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{text}
</StyledOverflowingText>
</div>
{isTitleOverflowing &&
createPortal(
<div onClick={handleTooltipClick}>
<AppTooltip
anchorSelect={`#${textElementId}`}
content={mutliline ? undefined : text ?? ''}
delayHide={0}
delayHide={1}
offset={5}
isOpen
noArrow
place="bottom"
positionStrategy="absolute"