Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
54 changes: 51 additions & 3 deletions src/Dropdown/Dropdown.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Meta, StoryFn as Story } from '@storybook/react'
import React from 'react'
import { StoryFn as Story, Meta } from '@storybook/react'

import Dropdown, { DropdownProps } from '.'
import Badge from '../Badge'
import Button from '../Button'
import Card from '../Card/'
import Navbar from '../Navbar'
import Button from '../Button'

export default {
title: 'Actions/Dropdown',
Expand Down Expand Up @@ -76,6 +76,54 @@ InNavbar.args = {
end: true,
}

export const ButtonToggle: Story<DropdownProps> = (args) => {
return (
<div className="my-32">
<Dropdown {...args}>
<Dropdown.Toggle size="xl" color="success" variant="dash">
Click
</Dropdown.Toggle>
<Dropdown.Menu className="w-52">
<Dropdown.Item>Item 1</Dropdown.Item>
<Dropdown.Item>Item 2</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</div>
)
}

export const LabelToggle: Story<DropdownProps> = (args) => {
return (
<div className="my-32">
<Dropdown {...args}>
<Dropdown.Toggle button={false}>Click</Dropdown.Toggle>
<Dropdown.Menu className="w-52">
<Dropdown.Item>Item 1</Dropdown.Item>
<Dropdown.Item>Item 2</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</div>
)
}

export const UnstyledCustomToggle: Story<DropdownProps> = (args) => {
return (
<div className="my-32">
<Dropdown {...args}>
<Dropdown.Toggle unstyled>
<Badge color="primary" variant="outline" className="cursor-pointer">
Any component can be a toggle, even a {`<Badge>`}!
</Badge>
</Dropdown.Toggle>
<Dropdown.Menu className="w-52">
<Dropdown.Item>Item 1</Dropdown.Item>
<Dropdown.Item>Item 2</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</div>
)
}

export const Helper: Story<DropdownProps> = (args) => {
return (
<div className="my-32 font-sans">
Expand Down
56 changes: 55 additions & 1 deletion src/Dropdown/Dropdown.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('Dropdown', () => {
)

expect(screen.getByRole('listbox')).toHaveClass('custom-dropdown')
expect(screen.getByText('Toggle').parentElement).toHaveClass(
expect(screen.getByText('Toggle').closest('button')).toHaveClass(
'custom-toggle'
)
expect(screen.getByRole('menu')).toHaveClass('custom-menu')
Expand Down Expand Up @@ -75,4 +75,58 @@ describe('Dropdown', () => {
expect(screen.getByRole('listbox')).toHaveClass('dropdown-hover')
expect(screen.getByRole('listbox')).toHaveClass('dropdown-open')
})

test('Should render a Button when button=true (default)', () => {
render(
<Dropdown>
<Dropdown.Toggle>Toggle</Dropdown.Toggle>
<Dropdown.Menu>{DropdownItems}</Dropdown.Menu>
</Dropdown>
)

const toggle = screen.getByRole('button', { name: 'Toggle' })
expect(toggle).toBeInTheDocument()
expect(toggle.tagName).toBe('BUTTON')
})

test('Should render a Button when button=true (explicit)', () => {
render(
<Dropdown>
<Dropdown.Toggle button={true}>Toggle</Dropdown.Toggle>
<Dropdown.Menu>{DropdownItems}</Dropdown.Menu>
</Dropdown>
)

const toggle = screen.getByRole('button', { name: 'Toggle' })
expect(toggle).toBeInTheDocument()
expect(toggle.tagName).toBe('BUTTON')
})

test('Should render a Label when button=false', () => {
render(
<Dropdown>
<Dropdown.Toggle button={false}>Toggle</Dropdown.Toggle>
<Dropdown.Menu>{DropdownItems}</Dropdown.Menu>
</Dropdown>
)

const toggle = screen.getByRole('button', { name: 'Toggle' })
expect(toggle).toBeInTheDocument()
expect(toggle.tagName).toBe('LABEL')
})

test('Should render a div when unstyled=true', () => {
render(
<Dropdown>
<Dropdown.Toggle unstyled aria-label="Dropdown toggle">
Toggle
</Dropdown.Toggle>
<Dropdown.Menu>{DropdownItems}</Dropdown.Menu>
</Dropdown>
)

const toggle = screen.getByRole('button', { name: 'Dropdown toggle' })
expect(toggle).toBeInTheDocument()
expect(toggle.tagName).toBe('DIV')
})
})
89 changes: 49 additions & 40 deletions src/Dropdown/DropdownToggle.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,58 @@
import React, { forwardRef } from 'react'
import React, { forwardRef, HTMLAttributes } from 'react'
import Button, { ButtonProps } from '../Button'
import Label, { LabelProps } from '../Form/Label'

import { ComponentColor, ComponentSize, IComponentBaseProps } from '../types'
export type ButtonDropdownToggleProps = ButtonProps & {
button?: true
unstyled?: false
}

import Button, { ButtonProps } from '../Button'
export type LabelDropdownToggleProps = Omit<LabelProps, 'color'> & {
button: false
unstyled?: false
}

export type DropdownToggleProps = Omit<
React.LabelHTMLAttributes<HTMLLabelElement>,
export type UnstyledDropdownToggleProps = Omit<
HTMLAttributes<HTMLElement>,
'color'
> &
IComponentBaseProps & {
color?: ComponentColor
size?: ComponentSize
button?: boolean
disabled?: boolean
}

const DropdownToggle = ({
children,
color,
size,
button = true,
dataTheme,
className,
disabled,
...props
}: DropdownToggleProps) => {
return (
<label tabIndex={0} className={className} {...props}>
{button ? (
<Button
type="button"
dataTheme={dataTheme}
color={color}
size={size}
disabled={disabled}
>
{children}
</Button>
) : (
children
)}
</label>
)
> & {
button?: false
unstyled: true
}

export type DropdownToggleProps =
| ButtonDropdownToggleProps
| LabelDropdownToggleProps
| UnstyledDropdownToggleProps

const DropdownToggle = forwardRef<HTMLElement, DropdownToggleProps>(
(props, ref) => {
const { button = true, unstyled = false, ...rest } = props

if (unstyled) {
return (
<div
ref={ref as React.Ref<HTMLDivElement>}
role="button"
tabIndex={0}
{...(rest as React.HTMLAttributes<HTMLElement>)}
/>
)
} else if (button) {
return <Button ref={ref} {...(rest as ButtonDropdownToggleProps)} />
} else {
return (
<Label
ref={ref as React.Ref<HTMLLabelElement>}
role="button"
tabIndex={0}
{...(rest as LabelDropdownToggleProps)}
/>
)
}
}
)

export type SummaryProps = Omit<ButtonProps, 'tag'>
export const Summary = forwardRef<HTMLElement, SummaryProps>(
(props, ref): JSX.Element => {
Expand Down