Refactor/new menu item (#1448)

* wip

* finished

* Added disabled

* Fixed disabled

* Finished cleaning

* Minor fixes from merge

* Added docs

* Added PascalCase

* Fix from review

* Fixes from merge

* Fix lint

* Fixed storybook tests
This commit is contained in:
Lucas Bordeau
2023-09-06 16:41:26 +02:00
committed by GitHub
parent 5c7660f588
commit 28ca9a9e49
96 changed files with 816 additions and 918 deletions

View File

@ -1,3 +1,4 @@
import { MouseEvent } from 'react';
import { useTheme } from '@emotion/react';
import { FloatingIconButton } from '@/ui/button/components/FloatingIconButton';
@ -10,24 +11,26 @@ import { MenuItemAccent } from '../types/MenuItemAccent';
export type MenuItemIconButton = {
Icon: IconComponent;
onClick: () => void;
onClick?: (event: MouseEvent<any>) => void;
};
export type MenuItemProps = {
LeftIcon?: IconComponent;
accent: MenuItemAccent;
LeftIcon?: IconComponent | null;
accent?: MenuItemAccent;
text: string;
iconButtons?: MenuItemIconButton[];
className: string;
className?: string;
testId?: string;
onClick?: () => void;
};
export function MenuItem({
LeftIcon,
accent,
accent = 'default',
text,
iconButtons,
className,
testId,
onClick,
}: MenuItemProps) {
const theme = useTheme();
@ -35,8 +38,13 @@ export function MenuItem({
const showIconButtons = Array.isArray(iconButtons) && iconButtons.length > 0;
return (
<StyledMenuItemBase onClick={onClick} className={className} accent={accent}>
<MenuItemLeftContent LeftIcon={LeftIcon} text={text} />
<StyledMenuItemBase
data-testid={testId ?? undefined}
onClick={onClick}
className={className}
accent={accent}
>
<MenuItemLeftContent LeftIcon={LeftIcon ?? undefined} text={text} />
{showIconButtons && (
<FloatingIconButtonGroup>
{iconButtons?.map(({ Icon, onClick }, index) => (

View File

@ -0,0 +1,51 @@
import { ReactNode } from 'react';
import styled from '@emotion/styled';
import { Checkbox } from '@/ui/input/checkbox/components/Checkbox';
import {
StyledMenuItemBase,
StyledMenuItemLabel,
StyledMenuItemLeftContent,
} from '../internals/components/StyledMenuItemBase';
const StyledLeftContentWithCheckboxContainer = styled.div`
align-items: center;
display: flex;
flex-direction: row;
gap: ${({ theme }) => theme.spacing(2)};
`;
type OwnProps = {
avatar?: ReactNode;
selected: boolean;
text: string;
className?: string;
onSelectChange?: (selected: boolean) => void;
};
export function MenuItemMultiSelectAvatar({
avatar,
text,
selected,
className,
onSelectChange,
}: OwnProps) {
function handleOnClick() {
onSelectChange?.(!selected);
}
return (
<StyledMenuItemBase className={className} onClick={handleOnClick}>
<StyledLeftContentWithCheckboxContainer>
<Checkbox checked={selected} />
<StyledMenuItemLeftContent>
{avatar}
<StyledMenuItemLabel hasLeftIcon={!!avatar}>
{text}
</StyledMenuItemLabel>
</StyledMenuItemLeftContent>
</StyledLeftContentWithCheckboxContainer>
</StyledMenuItemBase>
);
}

View File

@ -10,7 +10,7 @@ export type MenuItemProps = {
LeftIcon?: IconComponent;
text: string;
onClick?: () => void;
className: string;
className?: string;
};
export function MenuItemNavigate({

View File

@ -7,8 +7,12 @@ import { IconComponent } from '@/ui/icon/types/IconComponent';
import { MenuItemLeftContent } from '../internals/components/MenuItemLeftContent';
import { StyledMenuItemBase } from '../internals/components/StyledMenuItemBase';
const StyledMenuItemSelect = styled(StyledMenuItemBase)<{ selected: boolean }>`
${({ theme, selected }) => {
export const StyledMenuItemSelect = styled(StyledMenuItemBase)<{
selected: boolean;
disabled?: boolean;
hovered?: boolean;
}>`
${({ theme, selected, disabled, hovered }) => {
if (selected) {
return css`
background: ${theme.background.transparent.light};
@ -16,16 +20,33 @@ const StyledMenuItemSelect = styled(StyledMenuItemBase)<{ selected: boolean }>`
background: ${theme.background.transparent.medium};
}
`;
} else if (disabled) {
return css`
background: inherit;
&:hover {
background: inherit;
}
color: ${theme.font.color.tertiary};
cursor: default;
`;
} else if (hovered) {
return css`
background: ${theme.background.transparent.light};
`;
}
}}
`;
type OwnProps = {
LeftIcon?: IconComponent;
LeftIcon: IconComponent | null | undefined;
selected: boolean;
text: string;
className: string;
className?: string;
onClick?: () => void;
disabled?: boolean;
hovered?: boolean;
};
export function MenuItemSelect({
@ -34,6 +55,8 @@ export function MenuItemSelect({
selected,
className,
onClick,
disabled,
hovered,
}: OwnProps) {
const theme = useTheme();
@ -42,6 +65,8 @@ export function MenuItemSelect({
onClick={onClick}
className={className}
selected={selected}
disabled={disabled}
hovered={hovered}
>
<MenuItemLeftContent LeftIcon={LeftIcon} text={text} />
{selected && <IconCheck size={theme.icon.size.sm} />}

View File

@ -0,0 +1,55 @@
import { ReactNode } from 'react';
import { useTheme } from '@emotion/react';
import { IconCheck } from '@/ui/icon';
import { OverflowingTextWithTooltip } from '@/ui/tooltip/OverflowingTextWithTooltip';
import {
StyledMenuItemLabel,
StyledMenuItemLeftContent,
} from '../internals/components/StyledMenuItemBase';
import { StyledMenuItemSelect } from './MenuItemSelect';
type OwnProps = {
avatar: ReactNode;
selected: boolean;
text: string;
className?: string;
onClick?: () => void;
disabled?: boolean;
hovered?: boolean;
testId?: string;
};
export function MenuItemSelectAvatar({
avatar,
text,
selected,
className,
onClick,
disabled,
hovered,
testId,
}: OwnProps) {
const theme = useTheme();
return (
<StyledMenuItemSelect
onClick={onClick}
className={className}
selected={selected}
disabled={disabled}
hovered={hovered}
data-testid={testId}
>
<StyledMenuItemLeftContent>
{avatar}
<StyledMenuItemLabel hasLeftIcon={!!avatar}>
<OverflowingTextWithTooltip text={text} />
</StyledMenuItemLabel>
</StyledMenuItemLeftContent>
{selected && <IconCheck size={theme.icon.size.sm} />}
</StyledMenuItemSelect>
);
}

View File

@ -0,0 +1,59 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconCheck } from '@/ui/icon';
import { ThemeColor } from '@/ui/theme/constants/colors';
import {
StyledMenuItemLabel,
StyledMenuItemLeftContent,
} from '../internals/components/StyledMenuItemBase';
import { StyledMenuItemSelect } from './MenuItemSelect';
const StyledColorSample = styled.div<{ colorName: ThemeColor }>`
background-color: ${({ theme, colorName }) =>
theme.tag.background[colorName]};
border: 1px solid ${({ theme, colorName }) => theme.color[colorName]};
border-radius: ${({ theme }) => theme.border.radius.sm};
height: 12px;
width: 12px;
`;
type OwnProps = {
selected: boolean;
text: string;
className?: string;
onClick?: () => void;
disabled?: boolean;
hovered?: boolean;
color: ThemeColor;
};
export function MenuItemSelectColor({
color,
text,
selected,
className,
onClick,
disabled,
hovered,
}: OwnProps) {
const theme = useTheme();
return (
<StyledMenuItemSelect
onClick={onClick}
className={className}
selected={selected}
disabled={disabled}
hovered={hovered}
>
<StyledMenuItemLeftContent>
<StyledColorSample colorName={color} />
<StyledMenuItemLabel hasLeftIcon={true}>{text}</StyledMenuItemLabel>
</StyledMenuItemLeftContent>
{selected && <IconCheck size={theme.icon.size.sm} />}
</StyledMenuItemSelect>
);
}