Update the frontend to adhere to the custom eslint rule twenty/no-spread-props (#1958)

* Update the frontend to adhere to the custom eslint rule `twenty/no-spread-props`

Co-authored-by: v1b3m <vibenjamin6@gmail.com>

* Update the frontend to adhere to the custom eslint rule `twenty/no-spread-props`

Co-authored-by: v1b3m <vibenjamin6@gmail.com>

* resolve bug with data-testid

---------

Co-authored-by: v1b3m <vibenjamin6@gmail.com>
Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
This commit is contained in:
gitstart-twenty 2023-10-10 16:40:49 +03:00 committed by GitHub
parent 5dddd77eb3
commit bf397bc6ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 276 additions and 169 deletions

View File

@ -7,13 +7,12 @@ type CellCommentChipProps = CommentChipProps;
// TODO: tie those fixed values to the other components in the cell
const StyledCellWrapper = styled.div``;
export const CellCommentChip = (props: CellCommentChipProps) => {
if (props.count === 0) return null;
export const CellCommentChip = ({ count, onClick }: CellCommentChipProps) => {
if (count === 0) return null;
return (
<StyledCellWrapper>
{/* eslint-disable-next-line twenty/no-spread-props */}
<CommentChip {...props} />
<CommentChip count={count} onClick={onClick} />
</StyledCellWrapper>
);
};

View File

@ -2,7 +2,7 @@ import styled from '@emotion/styled';
import { getImageAbsoluteURIOrBase64 } from '@/users/utils/getProfilePictureAbsoluteURI';
type LogoProps = React.ComponentProps<'div'> & {
type LogoProps = {
workspaceLogo?: string | null;
};
@ -47,19 +47,17 @@ const StyledMainLogo = styled.div<StyledMainLogoProps>`
width: 100%;
`;
export const Logo = ({ workspaceLogo, ...props }: LogoProps) => {
export const Logo = ({ workspaceLogo }: LogoProps) => {
if (!workspaceLogo) {
return (
// eslint-disable-next-line twenty/no-spread-props
<StyledContainer {...props}>
<StyledContainer>
<StyledMainLogo logo="/icons/android/android-launchericon-192-192.png" />
</StyledContainer>
);
}
return (
// eslint-disable-next-line twenty/no-spread-props
<StyledContainer {...props}>
<StyledContainer>
<StyledMainLogo logo={getImageAbsoluteURIOrBase64(workspaceLogo)} />
<StyledTwentyLogoContainer>
<StyledTwentyLogo src="/icons/android/android-launchericon-192-192.png" />

View File

@ -8,11 +8,10 @@ const StyledContent = styled(UIModal.Content)`
width: calc(400px - ${({ theme }) => theme.spacing(10 * 2)});
`;
type AuthModalProps = React.ComponentProps<'div'>;
type AuthModalProps = { children: React.ReactNode };
export const AuthModal = ({ children, ...restProps }: AuthModalProps) => (
// eslint-disable-next-line twenty/no-spread-props
<UIModal isOpen={true} {...restProps}>
export const AuthModal = ({ children }: AuthModalProps) => (
<UIModal isOpen={true}>
<StyledContent>{children}</StyledContent>
</UIModal>
);

View File

@ -1,7 +1,7 @@
import React from 'react';
import styled from '@emotion/styled';
type FooterNoteProps = React.ComponentProps<'div'>;
type FooterNoteProps = { children: React.ReactNode };
const StyledContainer = styled.div`
align-items: center;
@ -11,7 +11,6 @@ const StyledContainer = styled.div`
text-align: center;
`;
export const FooterNote = (props: FooterNoteProps) => (
// eslint-disable-next-line twenty/no-spread-props
<StyledContainer {...props} />
export const FooterNote = ({ children }: FooterNoteProps) => (
<StyledContainer>{children}</StyledContainer>
);

View File

@ -99,7 +99,7 @@ export const CompanyProgressPicker = ({
) : (
<>
<DropdownMenuHeader
data-testid="selected-pipeline-stage"
testId="selected-pipeline-stage"
EndIcon={IconChevronDown}
onClick={() => setIsProgressSelectionUnfolded(true)}
>

View File

@ -1,7 +1,7 @@
import React from 'react';
import styled from '@emotion/styled';
export type HeadingProps = React.ComponentProps<'div'> & {
export type HeadingProps = {
title: string;
description?: string;
};
@ -27,9 +27,8 @@ const StyledDescription = styled.span`
text-align: center;
`;
export const Heading = ({ title, description, ...props }: HeadingProps) => (
// eslint-disable-next-line twenty/no-spread-props
<StyledContainer {...props}>
export const Heading = ({ title, description }: HeadingProps) => (
<StyledContainer>
<StyledTitle>{title}</StyledTitle>
{description && <StyledDescription>{description}</StyledDescription>}
</StyledContainer>

View File

@ -111,11 +111,36 @@ type TableProps<Data> = DataGridProps<Data> & {
hiddenHeader?: boolean;
};
export const Table = <Data,>(props: TableProps<Data>) => {
export const Table = <Data,>({
className,
columns,
components,
headerRowHeight,
rowKeyGetter,
rows,
onRowClick,
onRowsChange,
onSelectedRowsChange,
selectedRows,
}: TableProps<Data>) => {
const { rtl } = useSpreadsheetImportInternal();
return (
// eslint-disable-next-line twenty/no-spread-props
<StyledDataGrid direction={rtl ? 'rtl' : 'ltr'} rowHeight={52} {...props} />
<StyledDataGrid
direction={rtl ? 'rtl' : 'ltr'}
rowHeight={52}
{...{
className,
columns,
components,
headerRowHeight,
rowKeyGetter,
rows,
onRowClick,
onRowsChange,
onSelectedRowsChange,
selectedRows,
}}
/>
);
};

View File

@ -103,12 +103,13 @@ export const MainButton = ({
title,
fullWidth = false,
variant = 'primary',
...props
type,
onClick,
disabled,
}: MainButtonProps) => {
const theme = useTheme();
return (
// eslint-disable-next-line twenty/no-spread-props
<StyledButton fullWidth={fullWidth} variant={variant} {...props}>
<StyledButton {...{ disabled, fullWidth, onClick, type, variant }}>
{Icon && <Icon size={theme.icon.size.sm} />}
{title}
</StyledButton>

View File

@ -35,13 +35,13 @@ type RoundedIconButtonProps = {
export const RoundedIconButton = ({
Icon,
...props
onClick,
disabled,
}: RoundedIconButtonProps) => {
const theme = useTheme();
return (
// eslint-disable-next-line twenty/no-spread-props
<StyledIconButton {...props}>
<StyledIconButton {...{ disabled, onClick }}>
{<Icon size={theme.icon.size.md} />}
</StyledIconButton>
);

View File

@ -15,7 +15,6 @@ export const AnimatedCheckmark = ({
color,
duration = 0.5,
size = 28,
...restProps
}: AnimatedCheckmarkProps) => {
const theme = useTheme();
return (
@ -26,8 +25,6 @@ export const AnimatedCheckmark = ({
height={size}
>
<motion.path
// eslint-disable-next-line twenty/no-spread-props
{...restProps}
fill="none"
stroke={color ?? theme.grayScale.gray0}
strokeWidth={4}

View File

@ -16,12 +16,11 @@ const StyledContainer = styled.div`
export type CheckmarkProps = React.ComponentPropsWithoutRef<'div'>;
export const Checkmark = (props: CheckmarkProps) => {
export const Checkmark = (_props: CheckmarkProps) => {
const theme = useTheme();
return (
// eslint-disable-next-line twenty/no-spread-props
<StyledContainer {...props}>
<StyledContainer>
<IconCheck color={theme.grayScale.gray0} size={14} />
</StyledContainer>
);

View File

@ -103,10 +103,14 @@ export type ColorSchemeSegmentProps = {
const ColorSchemeSegment = ({
variant,
controls,
...rest
style,
onClick,
onMouseEnter,
onMouseLeave,
}: ColorSchemeSegmentProps) => (
// eslint-disable-next-line twenty/no-spread-props
<StyledColorSchemeBackground variant={variant} {...rest}>
<StyledColorSchemeBackground
{...{ variant, style, onClick, onMouseEnter, onMouseLeave }}
>
<StyledColorSchemeContent animate={controls} variant={variant}>
Aa
</StyledColorSchemeContent>
@ -148,7 +152,7 @@ const checkmarkAnimationVariants = {
export const ColorSchemeCard = ({
variant,
selected,
...rest
onClick,
}: ColorSchemeCardProps) => {
const controls = useAnimation();
@ -174,8 +178,7 @@ export const ColorSchemeCard = ({
<StyledMixedColorSchemeSegment
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
// eslint-disable-next-line twenty/no-spread-props
{...rest}
onClick={onClick}
>
<ColorSchemeSegment
style={{ borderTopRightRadius: 0, borderBottomRightRadius: 0 }}
@ -213,8 +216,7 @@ export const ColorSchemeCard = ({
onMouseLeave={handleMouseLeave}
controls={controls}
variant={variant}
// eslint-disable-next-line twenty/no-spread-props
{...rest}
onClick={onClick}
/>
<AnimatePresence>
{selected && (

View File

@ -26,7 +26,6 @@ type DataTableHeaderPlusButtonProps = {
export const DataTableHeaderPlusButton = ({
onAddColumn,
onClickOutside = () => undefined,
...props
}: DataTableHeaderPlusButtonProps) => {
const ref = useRef<HTMLDivElement>(null);
@ -51,8 +50,7 @@ export const DataTableHeaderPlusButton = ({
);
return (
// eslint-disable-next-line twenty/no-spread-props
<StyledHeaderPlusButton {...props} ref={ref}>
<StyledHeaderPlusButton ref={ref}>
<DropdownMenuItemsContainer>
{hiddenTableColumns.map((column) => (
<MenuItem

View File

@ -79,7 +79,7 @@ export const Dialog = ({
allowDismiss = true,
children,
onClose,
...rootProps
id,
}: DialogProps) => {
const closeSnackbar = useCallback(() => {
onClose && onClose();
@ -137,23 +137,20 @@ export const Dialog = ({
<StyledDialogContainer
variants={containerVariants}
transition={{ damping: 15, stiffness: 100 }}
// eslint-disable-next-line twenty/no-spread-props
{...rootProps}
id={id}
>
{title && <StyledDialogTitle>{title}</StyledDialogTitle>}
{message && <StyledDialogMessage>{message}</StyledDialogMessage>}
{children}
{buttons.map((button) => (
{buttons.map(({ accent, onClick, role, title: key, variant }) => (
<StyledDialogButton
key={button.title}
onClick={(event) => {
button?.onClick?.(event);
onClick?.(event);
closeSnackbar();
}}
fullWidth={true}
variant={button.variant ?? 'secondary'}
// eslint-disable-next-line twenty/no-spread-props
{...button}
variant={variant ?? 'secondary'}
{...{ accent, key, role }}
/>
))}
</StyledDialogContainer>

View File

@ -37,12 +37,11 @@ export const DialogProvider = ({ children }: React.PropsWithChildren) => {
return (
<>
{children}
{dialogInternal.queue.map((dialog) => (
{dialogInternal.queue.map(({ buttons, children, id, message, title }) => (
<Dialog
key={dialog.id}
// eslint-disable-next-line twenty/no-spread-props
{...dialog}
onClose={() => handleDialogClose(dialog.id)}
key={id}
{...{ title, message, buttons, id, children }}
onClose={() => handleDialogClose(id)}
/>
))}
</>

View File

@ -27,7 +27,6 @@ export const DropdownMenuContainer = ({
children,
onClose,
width,
...props
}: DropdownMenuContainerProps) => {
const dropdownRef = useRef(null);
@ -39,8 +38,7 @@ export const DropdownMenuContainer = ({
});
return (
// eslint-disable-next-line twenty/no-spread-props
<StyledDropdownMenuContainer data-select-disable {...props} anchor={anchor}>
<StyledDropdownMenuContainer data-select-disable anchor={anchor}>
<StyledDropdownMenu ref={dropdownRef} width={width}>
{children}
</StyledDropdownMenu>

View File

@ -30,6 +30,7 @@ type DropdownMenuHeaderProps = ComponentProps<'li'> & {
StartIcon?: IconComponent;
EndIcon?: IconComponent;
onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
testId?: string;
};
export const DropdownMenuHeader = ({
@ -37,14 +38,13 @@ export const DropdownMenuHeader = ({
StartIcon,
EndIcon,
onClick,
...props
testId,
}: DropdownMenuHeaderProps) => {
return (
// eslint-disable-next-line twenty/no-spread-props
<StyledHeader {...props}>
<StyledHeader data-testid={testId}>
{StartIcon && (
<LightIconButton
data-testid="dropdown-menu-header-end-icon"
testId="dropdown-menu-header-end-icon"
Icon={StartIcon}
onClick={onClick}
accent="tertiary"

View File

@ -36,9 +36,12 @@ const StyledInput = styled.input`
export const DropdownMenuSearchInput = forwardRef<
HTMLInputElement,
InputHTMLAttributes<HTMLInputElement>
>((props, ref) => (
>(({ value, onChange, autoFocus, placeholder = 'Search', type }, ref) => (
<StyledDropdownMenuSearchInputContainer>
{/* eslint-disable-next-line twenty/no-spread-props */}
<StyledInput autoComplete="off" placeholder="Search" {...props} ref={ref} />
<StyledInput
autoComplete="off"
{...{ autoFocus, onChange, placeholder, type, value }}
ref={ref}
/>
</StyledDropdownMenuSearchInputContainer>
));

View File

@ -118,7 +118,6 @@ export const Radio = ({
size = RadioSize.Small,
labelPosition = LabelPosition.Right,
disabled = false,
...restProps
}: RadioProps) => {
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
onChange?.(event);
@ -126,8 +125,7 @@ export const Radio = ({
};
return (
// eslint-disable-next-line twenty/no-spread-props
<StyledContainer {...restProps} labelPosition={labelPosition}>
<StyledContainer labelPosition={labelPosition}>
<StyledRadioInput
type="radio"
id="input-radio"

View File

@ -95,7 +95,6 @@ export const ImageInput = ({
isUploading = false,
errorMessage,
disabled = false,
...restProps
}: ImageInputProps) => {
const theme = useTheme();
const hiddenFileInput = React.useRef<HTMLInputElement>(null);
@ -104,8 +103,7 @@ export const ImageInput = ({
};
return (
// eslint-disable-next-line twenty/no-spread-props
<StyledContainer {...restProps}>
<StyledContainer>
<StyledPicture
withPicture={!!picture}
disabled={disabled}

View File

@ -34,11 +34,16 @@ export type SingleEntitySelectProps<
export const SingleEntitySelect = <
CustomEntityForSelect extends EntityForSelect,
>({
EmptyIcon,
disableBackgroundBlur = false,
emptyLabel,
entitiesToSelect,
loading,
onCancel,
onCreate,
onEntitySelected,
selectedEntity,
width,
...props
}: SingleEntitySelectProps<CustomEntityForSelect>) => {
const containerRef = useRef<HTMLDivElement>(null);
@ -69,11 +74,17 @@ export const SingleEntitySelect = <
/>
<StyledDropdownMenuSeparator />
<SingleEntitySelectBase
// eslint-disable-next-line twenty/no-spread-props
{...props}
onCancel={onCancel}
onCreate={onCreate}
showCreateButton={showCreateButton}
{...{
EmptyIcon,
emptyLabel,
entitiesToSelect,
loading,
onCancel,
onCreate,
onEntitySelected,
selectedEntity,
showCreateButton,
}}
/>
</StyledDropdownMenu>
);

View File

@ -34,7 +34,17 @@ const meta: Meta<typeof SingleEntitySelect> = {
),
},
},
render: (args) => {
render: ({
EmptyIcon,
disableBackgroundBlur = false,
emptyLabel,
loading,
onCancel,
onCreate,
onEntitySelected,
selectedEntity,
width,
}) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const relationPickerSearchFilter = useRecoilScopedValue(
relationPickerSearchFilterScopedState,
@ -42,11 +52,20 @@ const meta: Meta<typeof SingleEntitySelect> = {
return (
<SingleEntitySelect
// eslint-disable-next-line twenty/no-spread-props
{...args}
{...{
EmptyIcon,
disableBackgroundBlur,
emptyLabel,
loading,
onCancel,
onCreate,
onEntitySelected,
selectedEntity,
width,
}}
entitiesToSelect={entities.filter(
(entity) =>
entity.id !== args.selectedEntity?.id &&
entity.id !== selectedEntity?.id &&
entity.name.includes(relationPickerSearchFilter),
)}
/>

View File

@ -113,7 +113,10 @@ const TextInputComponent = (
required,
type,
disableHotkeys = false,
...props
autoFocus,
placeholder,
disabled,
tabIndex,
}: TextInputComponentProps,
// eslint-disable-next-line twenty/component-props-naming
ref: ForwardedRef<HTMLInputElement>,
@ -163,19 +166,14 @@ const TextInputComponent = (
<StyledInput
autoComplete="off"
ref={combinedRef}
tabIndex={props.tabIndex ?? 0}
tabIndex={tabIndex ?? 0}
onFocus={handleFocus}
onBlur={handleBlur}
value={value}
required={required}
type={passwordVisible ? 'text' : type}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
if (onChange) {
onChange(event.target.value);
}
onChange?.(event.target.value);
}}
// eslint-disable-next-line twenty/no-spread-props
{...props}
{...{ autoFocus, disabled, placeholder, required, value }}
/>
<StyledTrailingIconContainer>
{error && (

View File

@ -21,15 +21,38 @@ export default meta;
type Story = StoryObj<typeof TextInputSettings>;
const FakeTextInput = ({
autoFocus,
disableHotkeys = false,
disabled,
error,
fullWidth,
label,
onBlur,
onChange,
onFocus,
placeholder,
required,
tabIndex,
type,
value: initialValue,
...props
}: React.ComponentProps<typeof TextInputSettings>) => {
const [value, setValue] = useState(initialValue);
return (
<TextInputSettings
// eslint-disable-next-line twenty/no-spread-props
{...props}
{...{
autoFocus,
disableHotkeys,
disabled,
error,
fullWidth,
label,
onBlur,
onFocus,
placeholder,
required,
tabIndex,
type,
}}
value={value}
onChange={(text) => {
setValue(text);
@ -42,8 +65,41 @@ const FakeTextInput = ({
export const Default: Story = {
argTypes: { value: { control: false } },
args: { value: 'A good value ' },
// eslint-disable-next-line twenty/no-spread-props
render: (args) => <FakeTextInput {...args} />,
render: ({
autoFocus,
disableHotkeys,
disabled,
error,
fullWidth,
label,
onBlur,
onChange,
onFocus,
placeholder,
required,
tabIndex,
type,
value,
}) => (
<FakeTextInput
{...{
autoFocus,
disableHotkeys,
disabled,
error,
fullWidth,
label,
onBlur,
onChange,
onFocus,
placeholder,
required,
tabIndex,
type,
value,
}}
/>
),
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

View File

@ -81,7 +81,6 @@ export const PageHeader = ({
hasBackButton,
Icon,
children,
...props
}: PageHeaderProps) => {
const navigate = useNavigate();
const navigateBack = useCallback(() => navigate(-1), [navigate]);
@ -92,8 +91,7 @@ export const PageHeader = ({
const theme = useTheme();
return (
// eslint-disable-next-line twenty/no-spread-props
<StyledTopBarContainer {...props}>
<StyledTopBarContainer>
<StyledLeftContainer>
{!isNavbarOpened && (
<StyledTopBarButtonContainer>

View File

@ -98,23 +98,20 @@ const StyledBackDrop = styled(motion.div)`
*/
type ModalHeaderProps = React.PropsWithChildren & React.ComponentProps<'div'>;
const ModalHeader = ({ children, ...restProps }: ModalHeaderProps) => (
// eslint-disable-next-line twenty/no-spread-props
<StyledHeader {...restProps}>{children}</StyledHeader>
const ModalHeader = ({ children }: ModalHeaderProps) => (
<StyledHeader>{children}</StyledHeader>
);
type ModalContentProps = React.PropsWithChildren & React.ComponentProps<'div'>;
const ModalContent = ({ children, ...restProps }: ModalContentProps) => (
// eslint-disable-next-line twenty/no-spread-props
<StyledContent {...restProps}>{children}</StyledContent>
const ModalContent = ({ children }: ModalContentProps) => (
<StyledContent>{children}</StyledContent>
);
type ModalFooterProps = React.PropsWithChildren & React.ComponentProps<'div'>;
const ModalFooter = ({ children, ...restProps }: ModalFooterProps) => (
// eslint-disable-next-line twenty/no-spread-props
<StyledFooter {...restProps}>{children}</StyledFooter>
const ModalFooter = ({ children }: ModalFooterProps) => (
<StyledFooter>{children}</StyledFooter>
);
/**
@ -147,7 +144,6 @@ export const Modal = ({
onEnter,
size = 'medium',
padding = 'medium',
...restProps
}: ModalProps) => {
const modalRef = useRef<HTMLDivElement>(null);
@ -206,8 +202,6 @@ export const Modal = ({
exit="exit"
layout
variants={modalVariants}
// eslint-disable-next-line twenty/no-spread-props
{...restProps}
>
{children}
</StyledModalDiv>

View File

@ -111,7 +111,8 @@ export const SnackBar = ({
variant = 'info',
children,
onClose,
...rootProps
id,
title,
}: SnackBarProps) => {
const theme = useTheme();
@ -156,12 +157,7 @@ export const SnackBar = ({
return (
<StyledMotionContainer
aria-live={role === 'alert' ? 'assertive' : 'polite'}
role={role}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
variant={variant}
// eslint-disable-next-line twenty/no-spread-props
{...rootProps}
{...{ id, onMouseEnter, onMouseLeave, role, title, variant }}
>
<StyledProgressBarContainer>
<ProgressBar

View File

@ -69,23 +69,24 @@ export const SnackBarProvider = ({ children }: React.PropsWithChildren) => {
<>
{children}
<StyledSnackBarContainer>
{snackBarInternal.queue.map((snackBar) => (
<StyledSnackBarMotionContainer
key={snackBar.id}
variants={reducedMotion ? reducedVariants : variants}
initial="initial"
animate="animate"
exit="exit"
transition={{ duration: 0.5 }}
layout
>
<SnackBar
// eslint-disable-next-line twenty/no-spread-props
{...snackBar}
onClose={() => handleSnackBarClose(snackBar.id)}
/>
</StyledSnackBarMotionContainer>
))}
{snackBarInternal.queue.map(
({ duration, icon, id, message, title, variant }) => (
<StyledSnackBarMotionContainer
key={id}
variants={reducedMotion ? reducedVariants : variants}
initial="initial"
animate="animate"
exit="exit"
transition={{ duration: 0.5 }}
layout
>
<SnackBar
{...{ duration, icon, message, title, variant }}
onClose={() => handleSnackBarClose(id)}
/>
</StyledSnackBarMotionContainer>
),
)}
</StyledSnackBarContainer>
</>
);

View File

@ -21,16 +21,11 @@ export type StepBarProps = React.PropsWithChildren &
activeStep: number;
};
export const StepBar = ({
children,
activeStep,
...restProps
}: StepBarProps) => {
export const StepBar = ({ activeStep, children }: StepBarProps) => {
const isMobile = useIsMobile();
return (
// eslint-disable-next-line twenty/no-spread-props
<StyledContainer {...restProps}>
<StyledContainer>
{React.Children.map(children, (child, index) => {
if (!React.isValidElement(child)) {
return null;

View File

@ -43,7 +43,28 @@ export type AppTooltipProps = {
positionStrategy?: PositionStrategy;
};
export const AppTooltip = (props: AppTooltipProps) => (
// eslint-disable-next-line twenty/no-spread-props
<StyledAppTooltip {...props} />
export const AppTooltip = ({
anchorSelect,
className,
content,
delayHide,
isOpen,
noArrow,
offset,
place,
positionStrategy,
}: AppTooltipProps) => (
<StyledAppTooltip
{...{
anchorSelect,
className,
content,
delayHide,
isOpen,
noArrow,
offset,
place,
positionStrategy,
}}
/>
);

View File

@ -22,13 +22,34 @@ export const Default: Story = {
anchorSelect: '#hover-text',
},
decorators: [ComponentDecorator],
render: (args) => (
render: ({
anchorSelect,
className,
content,
delayHide,
isOpen,
noArrow,
offset,
place,
positionStrategy,
}) => (
<>
<p id="hover-text" data-testid="tooltip">
Hover me!
</p>
{/* eslint-disable-next-line twenty/no-spread-props */}
<Tooltip {...args} />
<Tooltip
{...{
anchorSelect,
className,
content,
delayHide,
isOpen,
noArrow,
offset,
place,
positionStrategy,
}}
/>
</>
),
};

View File

@ -10,20 +10,13 @@ type AnimatedEaseInProps = Omit<
export const AnimatedEaseIn = ({
children,
duration = 0.3,
...restProps
}: AnimatedEaseInProps) => {
const initial = { opacity: 0 };
const animate = { opacity: 1 };
const transition = { ease: 'linear', duration };
return (
<motion.div
initial={initial}
animate={animate}
transition={transition}
// eslint-disable-next-line twenty/no-spread-props
{...restProps}
>
<motion.div initial={initial} animate={animate} transition={transition}>
{children}
</motion.div>
);

View File

@ -47,10 +47,7 @@ const childAnimation = {
},
};
export const AnimatedTextWord = ({
text = '',
...restProps
}: AnimatedTextWordProps) => {
export const AnimatedTextWord = ({ text = '' }: AnimatedTextWordProps) => {
const words = useMemo(() => {
const words = text.split(' ');
@ -64,8 +61,6 @@ export const AnimatedTextWord = ({
variants={containerAnimation}
initial="hidden"
animate="visible"
// eslint-disable-next-line twenty/no-spread-props
{...restProps}
>
{words.map((word, index) => (
<StyledWord variants={childAnimation} key={index}>