Skip to content

Commit

Permalink
Fix menu (#282)
Browse files Browse the repository at this point in the history
* make MenuItem not depend on Button

* fix arrow selection of menu items

* show only one story of MenuItem and let the user pick the tone

* make MenuItem button of type 'button'
  • Loading branch information
devgioele authored Sep 14, 2023
1 parent 7b467a0 commit 5d1c6d3
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 43 deletions.
2 changes: 1 addition & 1 deletion src/components/menu/Menu.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const meta = {

return (
<div className="h-96 overflow-y-scroll border-2" tabIndex={-1}>
<div className="flex h-[1100px] items-center justify-center">
<div className="flex h-[70rem] items-center justify-center">
<div ref={elementRef}>
<Story />
</div>
Expand Down
7 changes: 2 additions & 5 deletions src/components/menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,7 @@ export function Menu({ className, children, button, placement }: MenuProps) {
})

return (
<HeadlessMenu
as="div"
className={classNames(menu.menuContainer, className)}
>
<HeadlessMenu as="div" className={classNames(menu.container, className)}>
{({ open }) => (
<>
<HeadlessMenu.Button as={Fragment} ref={refs.setReference}>
Expand All @@ -79,7 +76,7 @@ export function Menu({ className, children, button, placement }: MenuProps) {
</HeadlessMenu.Button>
<HeadlessMenu.Items
ref={refs.setFloating}
className={menu.menuList.base}
className={menu.list.base}
style={floatingStyles}
>
{children}
Expand Down
17 changes: 14 additions & 3 deletions src/components/menu/MenuItem.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import { useEffect, useRef } from 'react'
import { Theme } from '../../../.storybook/components'
import { Button } from '../button'
import { Tone } from '../types'
import { Menu, MenuPlacement } from './Menu'
import { MenuItem } from './MenuItem'

Expand All @@ -19,6 +20,16 @@ const meta = {
args: {
children: 'Menu item',
onClick: action(`onClick()`),
tone: Tone.Neutral,
},
argTypes: {
disabled: { type: 'boolean' },
tone: {
options: Object.values(Tone).filter(
(t) => t === Tone.Neutral || t === Tone.Critical,
),
control: { type: 'select' },
},
},
parameters: {
docs: {
Expand All @@ -44,8 +55,8 @@ const meta = {
}, [])

return (
<div className="h-96 overflow-y-scroll border-2" tabIndex={-1}>
<div className="flex h-[1100px] items-center justify-center">
<div className="h-60 overflow-y-scroll border-2" tabIndex={-1}>
<div className="flex h-[42rem] items-center justify-center">
<div ref={elementRef}>
<Menu
placement={MenuPlacement.Bottom}
Expand All @@ -65,5 +76,5 @@ export default meta
type Story = StoryObj<typeof meta>

export const Default: Story = {
args: {} as never,
args: {},
}
67 changes: 37 additions & 30 deletions src/components/menu/MenuItem.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,71 @@
import { Menu as HeadlessMenu } from '@headlessui/react'
import { Fragment, ReactNode } from 'react'
import { ClassNameProps, Size, Tone } from '../types'
import { Button, ButtonLink, ButtonVariant } from '../button'
import classNames from 'classnames'
import { ClassNameProps, Tone } from '../types'
import { useLinkComponent, useTheme } from '../../framework'

export type MenuItemProps = ClassNameProps & {
children: ReactNode
disabled?: boolean
} & (
| {
onClick: () => void
href?: never
}
| {
onClick?: never
href: string
}
)

const sharedProps = {
variant: ButtonVariant.Transparent,
size: Size.Sm,
tone: Tone.Neutral,
role: 'menuitem',
tone?: Tone.Neutral | Tone.Critical
onClick?: () => void
href?: string
}

const ROLE = 'menuitem'

/**
* This component is used to add an item to the [Menu](/docs/components-menu-menu--docs).
*
* It leverages on the `Menu` component of [HeadlessUI](https://headlessui.com/react/menu).
*/
export function MenuItem({
className,
disabled,
onClick,
href,
children,
disabled,
tone = Tone.Neutral,
}: MenuItemProps) {
const LinkComponent = useLinkComponent()
const {
menu: { item: theme },
} = useTheme()

return (
<HeadlessMenu.Item as={Fragment}>
{() => {
return href === undefined ? (
<Button
className={className}
{({ active }) =>
href === undefined ? (
<button
type="button"
className={classNames(
theme.base,
active && theme.active.tone[tone],
disabled ? theme.tone.disabled : theme.tone[tone],
className,
)}
disabled={disabled}
{...sharedProps}
onClick={onClick}
role={ROLE}
>
{children}
</Button>
</button>
) : (
<ButtonLink
className={className}
<LinkComponent
className={classNames(
theme.base,
active && theme.active.tone[tone],
disabled ? theme.tone.disabled : theme.tone[tone],
className,
)}
disabled={disabled}
{...sharedProps}
role={ROLE}
href={href}
>
{children}
</ButtonLink>
</LinkComponent>
)
}}
}
</HeadlessMenu.Item>
)
}
22 changes: 19 additions & 3 deletions src/components/menu/theme.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
import { Tone } from '../types'

const className = {
menuContainer: 'relative',
menuList: {
base: 'py-2 flex flex-col items-center gap-1 whitespace-nowrap min-w-32 rounded border border-primary-500/10 shadow focus:outline-none bg-white absolute',
container: 'relative',
list: {
base: 'py-2 flex flex-col items-stretch gap-1 whitespace-nowrap min-w-[6rem] rounded border border-primary-500/10 shadow bg-white absolute',
},
item: {
base: 'inline-flex items-start font-medium text-sm leading-5 px-4 py-1.5',
active: {
tone: {
[Tone.Neutral]: 'bg-neutral-500/10',
[Tone.Critical]: 'bg-critical-500/10',
},
},
tone: {
[Tone.Neutral]: 'text-neutral-700',
[Tone.Critical]: 'text-critical-500',
disabled: 'text-neutral-800/[0.36]',
},
},
}

Expand Down
2 changes: 1 addition & 1 deletion src/examples/Menu.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const meta = {

return (
<div className="h-96 overflow-y-scroll border-2" tabIndex={-1}>
<div className="flex h-[1100px] items-center justify-center">
<div className="flex h-[70rem] items-center justify-center">
<div ref={elementRef}>
<Story />
</div>
Expand Down

0 comments on commit 5d1c6d3

Please sign in to comment.