fix(ui): use expand button in sidebar and tables [EE-6844] (#11608)

pull/11833/head
Chaim Lev-Ari 2024-05-15 08:26:23 +03:00 committed by GitHub
parent 413b9c3b04
commit a808f83e7d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 155 additions and 61 deletions

View File

@ -0,0 +1,68 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { CollapseExpandButton } from './CollapseExpandButton';
it('should render the button with the correct icon and title', () => {
renderCollapseExpandButton();
const button = screen.getByRole('button');
expect(button).toBeInTheDocument();
expect(button).toHaveAttribute('title', 'Expand');
expect(button).toHaveAttribute('aria-label', 'Expand');
expect(button).toHaveAttribute('aria-expanded', 'false');
expect(button.querySelector('svg')).toBeInTheDocument();
});
it('should call the onClick handler when the button is clicked', async () => {
const onClick = vi.fn();
const { user } = renderCollapseExpandButton({ onClick });
const button = screen.getByRole('button');
await user.click(button);
expect(onClick).toHaveBeenCalledTimes(1);
});
it('should prevent default and stop propagation when the button is clicked', async () => {
const user = userEvent.setup();
const onClick = vi.fn();
const onOuterClick = vi.fn();
render(
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
<div onClick={onOuterClick}>
<CollapseExpandButton
onClick={onClick}
isExpanded={false}
data-cy="nothing"
/>
</div>
);
const button = screen.getByLabelText('Expand');
await user.click(button);
expect(onOuterClick).not.toHaveBeenCalled();
expect(onClick).toHaveBeenCalled();
});
function renderCollapseExpandButton({
isExpanded = false,
onClick = vi.fn(),
}: {
isExpanded?: boolean;
onClick?(): void;
} = {}) {
const user = userEvent.setup();
render(
<CollapseExpandButton
isExpanded={isExpanded}
data-cy="random"
onClick={onClick}
/>
);
return { user };
}

View File

@ -0,0 +1,41 @@
import { ChevronDown } from 'lucide-react';
import { ComponentProps } from 'react';
import clsx from 'clsx';
import { Icon } from './Icon';
export function CollapseExpandButton({
onClick,
isExpanded,
...props
}: { isExpanded: boolean } & ComponentProps<'button'>) {
return (
<button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onClick?.(e);
}}
color="none"
title={isExpanded ? 'Collapse' : 'Expand'}
aria-label={isExpanded ? 'Collapse' : 'Expand'}
aria-expanded={isExpanded}
type="button"
className="flex-none border-none bg-transparent flex items-center p-0 px-3 group"
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
>
<div className="flex items-center group-hover:bg-blue-5 be:group-hover:bg-gray-5 group-hover:th-dark:bg-gray-true-7 group-hover:bg-opacity-10 be:group-hover:bg-opacity-10 rounded-full p-[3px] transition ease-in-out">
<Icon
icon={ChevronDown}
size="md"
className={clsx('transition ease-in-out', {
'rotate-180': isExpanded,
'rotate-0': !isExpanded,
})}
/>
</div>
</button>
);
}

View File

@ -1,7 +1,6 @@
import { ChevronDown, ChevronUp } from 'lucide-react';
import { ColumnDef } from '@tanstack/react-table';
import { Button } from '@@/buttons';
import { CollapseExpandButton } from '../CollapseExpandButton';
import { DefaultType } from './types';
@ -13,32 +12,25 @@ export function buildExpandColumn<T extends DefaultType>(): ColumnDef<T> {
return (
hasExpandableItems && (
<Button
<CollapseExpandButton
isExpanded={table.getIsAllRowsExpanded()}
onClick={table.getToggleAllRowsExpandedHandler()}
color="none"
icon={table.getIsAllRowsExpanded() ? ChevronDown : ChevronUp}
title="Expand all"
data-cy="expand-all-rows-button"
aria-label="Expand all rows"
aria-label={
table.getIsAllRowsExpanded()
? 'Collapse all rows'
: 'Expand all rows'
}
/>
)
);
},
cell: ({ row }) =>
row.getCanExpand() && (
<Button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
row.toggleExpanded();
}}
color="none"
icon={row.getIsExpanded() ? ChevronDown : ChevronUp}
title={row.getIsExpanded() ? 'Collapse' : 'Expand'}
<CollapseExpandButton
isExpanded={row.getIsExpanded()}
onClick={row.getToggleExpandedHandler()}
data-cy={`expand-row-button_${row.index}`}
aria-label={row.getIsExpanded() ? 'Collapse row' : 'Expand row'}
aria-expanded={row.getIsExpanded()}
/>
),
enableColumnFilter: false,

View File

@ -1,7 +1,6 @@
import { PropsWithChildren, ReactNode, useState } from 'react';
import { ChevronUp, ChevronRight } from 'lucide-react';
import { Icon } from '@@/Icon';
import { CollapseExpandButton } from '@@/CollapseExpandButton';
import { FormSectionTitle } from '../FormSectionTitle';
@ -26,30 +25,22 @@ export function FormSection({
htmlFor = '',
}: PropsWithChildren<Props>) {
const [isExpanded, setIsExpanded] = useState(!defaultFolded);
const id = `foldingButton${title}`;
return (
<div className={className}>
<FormSectionTitle
htmlFor={isFoldable ? `foldingButton${title}` : htmlFor}
htmlFor={isFoldable ? id : htmlFor}
titleSize={titleSize}
className={titleClassName}
>
{isFoldable && (
<button
id={`foldingButton${title}`}
type="button"
onClick={(e) => {
setIsExpanded(!isExpanded);
e.stopPropagation();
e.preventDefault();
}}
className="mx-2 !ml-0 inline-flex w-2 items-center justify-center border-0 bg-transparent"
>
<Icon
icon={isExpanded ? ChevronUp : ChevronRight}
className="shrink-0"
/>
</button>
<CollapseExpandButton
isExpanded={isExpanded}
data-cy={id}
id={id}
onClick={() => setIsExpanded((isExpanded) => !isExpanded)}
/>
)}
{title}

View File

@ -1,11 +1,11 @@
import clsx from 'clsx';
import { ChevronDown } from 'lucide-react';
import { PropsWithChildren, useState } from 'react';
import { AutomationTestingProps } from '@/types';
import { Icon } from '@@/Icon';
import { Link } from '@@/Link';
import { CollapseExpandButton } from '@@/CollapseExpandButton';
import { useSidebarState } from '../useSidebarState';
@ -79,29 +79,11 @@ export function SidebarParent({
</Link>
</button>
{isSidebarOpen && (
<button
type="button"
className="flex-none border-none bg-transparent flex items-center group p-0 px-3 h-8"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
setIsExpanded((isExpanded) => !isExpanded);
}}
title={isExpanded ? 'Collapse' : 'Expand'}
aria-expanded={isExpanded}
aria-controls={listId}
>
<div className="flex items-center group-hover:bg-blue-5 be:group-hover:bg-gray-5 group-hover:th-dark:bg-gray-true-7 group-hover:bg-opacity-10 be:group-hover:bg-opacity-10 rounded-full p-[3px] transition ease-in-out">
<Icon
icon={ChevronDown}
size="md"
className={clsx('transition ease-in-out', {
'rotate-180': isExpanded,
'rotate-0': !isExpanded,
})}
/>
</div>
</button>
<SidebarExpandButton
onClick={() => setIsExpanded((isExpanded) => !isExpanded)}
isExpanded={isExpanded}
listId={listId}
/>
)}
</div>
</Wrapper>
@ -145,3 +127,23 @@ export function SidebarParent({
</SidebarTooltip>
);
}
function SidebarExpandButton({
isExpanded,
listId,
onClick,
}: {
onClick(): void;
isExpanded: boolean;
listId: string;
}) {
return (
<CollapseExpandButton
isExpanded={isExpanded}
onClick={onClick}
aria-controls={listId}
data-cy="expand-button"
className="flex-none border-none bg-transparent flex items-center group p-0 px-3 h-8"
/>
);
}