Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create Menu component #2990

Open
wants to merge 41 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
6c6ef1d
add basic Menu component
luiqor Dec 12, 2024
3207989
enhance MenuItem
luiqor Dec 12, 2024
3cc4ccb
enhance styles for density 2
luiqor Dec 12, 2024
eb17c67
add nested menu items
luiqor Dec 14, 2024
7dbdaad
add isDropdown item
luiqor Dec 14, 2024
f46a4b7
replace isDropDown with dropDownIconVariant
luiqor Dec 14, 2024
c738a7a
add state logic
luiqor Dec 14, 2024
fde760b
replace Fragment with flatMap to fix MUI error
luiqor Dec 14, 2024
eaa88a2
replace isToggled handled in parent
luiqor Dec 14, 2024
e3d25a1
add onClick to stories
luiqor Dec 14, 2024
82497b8
refactor types for MenuItem
luiqor Dec 14, 2024
86f3f6e
add decorator with anchorEl to storybook
luiqor Dec 15, 2024
d9846f2
add Menu props
luiqor Dec 15, 2024
9e78bab
add defaultOnItemClick
luiqor Dec 15, 2024
b42a3b6
add stories
luiqor Dec 15, 2024
a959490
update stories onClicks
luiqor Dec 15, 2024
3e6988a
enhance style variants for menu item
luiqor Dec 15, 2024
0c3dfa0
remove min width
luiqor Dec 15, 2024
6868eb7
add custom menu positioning stories
luiqor Dec 15, 2024
a3acc96
add ability to remove items
luiqor Dec 15, 2024
836be19
enhance remove items styles and logic
luiqor Dec 15, 2024
bee008f
enhance stories docs to include arguments and description
luiqor Dec 15, 2024
d0d0126
add MenuItem enums
luiqor Dec 15, 2024
b3bdc35
add constants to Menu
luiqor Dec 15, 2024
091d3ba
add MenuItem to storybook
luiqor Dec 15, 2024
bcb6af3
enhance MenuItem documentation
luiqor Dec 15, 2024
b61c666
fix MenuItem checkbox
luiqor Dec 16, 2024
bc6b9b7
add initialy toggled functionallity
luiqor Dec 16, 2024
accdc9a
add toggleAsSingleItem
luiqor Dec 16, 2024
032f604
add menu items removal tests
luiqor Dec 16, 2024
83faba9
add Menu component tests
luiqor Dec 16, 2024
6323fe7
add menu item tests
luiqor Dec 16, 2024
2518256
add missing argTypes to storybook docs
luiqor Dec 16, 2024
45347c2
fix elements with click handlers must have at least one keyboard list…
luiqor Dec 17, 2024
5fb9b14
fix additional info line height
luiqor Dec 17, 2024
f3ff703
fix role button sonar issues
luiqor Dec 17, 2024
5675a26
fix tabIndex on graphics divs sonar issues
luiqor Dec 17, 2024
0782dc2
refactor divs to buttons to fix sonar issues
luiqor Dec 17, 2024
e2cf5e4
refactor defaultNoItemsMessage
luiqor Dec 17, 2024
d54af8e
refactor small code issues
luiqor Dec 18, 2024
7d4eedb
remove redundant usage of useCallbacks
luiqor Dec 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/design-system/components/menu-item/MenuItem.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export enum MenuItemColorVariant {
Default = 'default',
Danger = 'danger',
Secondary = 'secondary'
}

export enum MenuItemVariant {
Default = 'default',
Nested = 'nested'
}
106 changes: 106 additions & 0 deletions src/design-system/components/menu-item/MenuItem.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
@use '~scss/utilities' as *;

.#{$prefix}item {
background-color: $neutral-0;
width: 100%;
padding: 16px 8px;
display: flex;
justify-content: space-between;

&:disabled {
color: $blue-gray-700;
}

&:hover {
background-color: $blue-gray-100;
}

&.selected {
background-color: $blue-gray-50;
}

&--align-center {
justify-content: center;
}

&--align-right {
justify-content: flex-end;
}

&--density-1 {
height: 48px;
}

&--density-2 {
height: 64px;
padding-top: 30px;
}

&--density-2 &-title {
font-weight: $font-weight-medium;
}

&--density-2 &-additional-info {
line-height: $line-height-sm;
}

&--variant-nested {
background-color: $neutral-50;
}

&--toggled {
background-color: $blue-gray-50;
}

&--default {
color: $blue-gray-700;
}

&--color-danger {
color: $red-500;
}

&--color-secondary {
color: $blue-gray-500;
}

&--disabled {
color: $blue-gray-700;
}

&--bottom-border {
border-bottom: 1px solid $blue-gray-100;
}

&__graphics {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: none;
border: none;
}

&__text-box {
margin-left: 12px;
display: flex;
flex-direction: column;
padding-right: 8px;
}

&__additional-info {
font-size: $font-size-xs;
color: $blue-gray-500;
line-height: $line-height-sm;
}

&__main-info-box {
display: flex;
align-items: center;
}

&__close {
font-size: $font-size-sm;
}
}
107 changes: 107 additions & 0 deletions src/design-system/components/menu-item/MenuItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { FC, useRef } from 'react'
import { MenuItem as MuiMenuItem } from '@mui/material'
import { ArrowDropDown, ArrowDropUp, CloseRounded } from '@mui/icons-material'

import { MenuItemProps as CommonMenuItemProps } from './MenuItem.types'
import { MenuItemColorVariant, MenuItemVariant } from './MenuItem.constants'
import { cn } from '~/utils/cn'

import '~scss-components/menu-item/MenuItem.scss'

interface MenuItemProps extends CommonMenuItemProps {
isDropdown?: boolean
density?: 1 | 2
isToggled?: boolean
onRemove?: () => void
variant?: MenuItemVariant
}

const MenuItem: FC<MenuItemProps> = ({
title,
additionalInfo,
alignVariant = 'left',
colorVariant = MenuItemColorVariant.Default,
density = 1,
graphics,
isDropdown = false,
isToggled = false,
isBottomBorder = false,
isDisabled = false,
onClick,
onRemove,
variant = MenuItemVariant.Default
}) => {
const graphicsRef = useRef<HTMLButtonElement | null>(null)

const handleClick = () => {
if (graphicsRef.current) {
const interactiveElement =
graphicsRef.current.querySelector<HTMLInputElement>(
'input[type="radio"], input[type="checkbox"], [role="radio"], [role="checkbox"]'
)

if (interactiveElement) {
interactiveElement.click()
return
}
}
Comment on lines +37 to +47
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get same result with using the element? Its default behaviour that it is clicking on input that currently inside the label.

Copy link
Contributor Author

@luiqor luiqor Dec 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you mean like that:

const handleClick = () => {
    if (graphicsRef.current) {
      graphicsRef.current.click()
      return
    }

    onClick?.()
  }

: unfortunately, checkbox then is not marked as selected on click.
When I am changing the button tag to label here, I can't get rid of onClick triggering two times, even with event.stopPropagation()


onClick?.()
}

const handleGraphicsClick = (event: React.MouseEvent) => {
event.stopPropagation()
onClick?.()
}

const handleRemoveItem = (event: React.MouseEvent) => {
event.stopPropagation()
onRemove?.()
}

return (
<MuiMenuItem
className={cn(
's2s-item',
`s2s-item--density-${density}`,
`s2s-item--variant-${variant}`,
`s2s-item--color-${colorVariant}`,
`s2s-item--align-${alignVariant}`,
isToggled && 's2s-item--toggled',
isBottomBorder && 's2s-item--bottom-border',
isDisabled && 's2s-item--disabled'
)}
disabled={isDisabled}
key={title}
ShadowOfTheSpace marked this conversation as resolved.
Show resolved Hide resolved
onClick={handleClick}
>
<div className='s2s-item__main-info-box'>
{graphics && (
<button
className='s2s-item__graphics'
onClick={handleGraphicsClick}
ref={graphicsRef}
>
{graphics}
</button>
)}
<div className='s2s-item__text-box'>
<span className='s2s-item__additional-info'>{additionalInfo}</span>
<span className='s2s-item__title'>{title}</span>
</div>
</div>
{isDropdown && (
<div className='s2s-item__graphics'>
{isToggled ? <ArrowDropUp /> : <ArrowDropDown />}
</div>
)}
{onRemove && !isDropdown && !isDisabled && (
<button className='s2s-item__graphics' onClick={handleRemoveItem}>
<CloseRounded className='s2s-item__close' />
</button>
)}
</MuiMenuItem>
)
}

export default MenuItem
15 changes: 15 additions & 0 deletions src/design-system/components/menu-item/MenuItem.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { ReactNode } from 'react'
import { MenuItemColorVariant } from './MenuItem.constants'

export type OnItemClickArgs = Record<string, string | Event>

export interface MenuItemProps {
title: string
additionalInfo?: string
alignVariant?: 'left' | 'center' | 'right'
colorVariant?: MenuItemColorVariant
isDisabled?: boolean
graphics?: ReactNode
isBottomBorder?: boolean
onClick?: () => void
}
8 changes: 8 additions & 0 deletions src/design-system/components/menu/Menu.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@use '~scss/utilities' as *;

.#{$prefix}menu {
border-radius: 6px;
box-shadow:
0 0 8px 0 rgba(0, 0, 0, 0.08),
0 10px 12px 0 rgba(0, 0, 0, 0.1);
}
Loading
Loading