Skip to content

Commit

Permalink
fix(Dropdown): extend Heading component and introduce Dropdown.Button (
Browse files Browse the repository at this point in the history
…#2694)

- Fixes #2439 
- Adds `Dropdown.Button` for more explicit API and alignment with
`Pagination` and `Breadcrumbs`

---------

Co-authored-by: Tobias Barsnes <[email protected]>
  • Loading branch information
eirikbacker and Barsnes authored Oct 28, 2024
1 parent d51732c commit 519fe18
Show file tree
Hide file tree
Showing 14 changed files with 174 additions and 109 deletions.
6 changes: 6 additions & 0 deletions .changeset/five-turkeys-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@digdir/designsystemet-css": patch
"@digdir/designsystemet-react": major
---

Dropdown: Add `Dropdown.Button` for more explicit API
24 changes: 16 additions & 8 deletions apps/storefront/components/Tokens/TokenList/TokenList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -226,17 +226,25 @@ const TokenList = ({
</Dropdown.Trigger>
<Dropdown>
<Dropdown.List>
<Dropdown.Item onClick={() => setBrand('digdir')}>
Digdir
<Dropdown.Item>
<Dropdown.Button onClick={() => setBrand('digdir')}>
Digdir
</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item onClick={() => setBrand('altinn')}>
Altinn
<Dropdown.Item>
<Dropdown.Button onClick={() => setBrand('altinn')}>
Altinn
</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item onClick={() => setBrand('tilsynet')}>
Tilsynet
<Dropdown.Item>
<Dropdown.Button onClick={() => setBrand('tilsynet')}>
Tilsynet
</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item onClick={() => setBrand('portal')}>
Brreg
<Dropdown.Item>
<Dropdown.Button onClick={() => setBrand('portal')}>
Brreg
</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
Expand Down
16 changes: 12 additions & 4 deletions apps/theme/components/Previews/Components/Components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -400,10 +400,18 @@ export const Components = () => {
<Dropdown.Context>
<Dropdown.Trigger data-size='sm'>Velg språk</Dropdown.Trigger>
<Dropdown placement='top' data-size='sm'>
<Dropdown.Item>Norsk</Dropdown.Item>
<Dropdown.Item>Engelsk</Dropdown.Item>
<Dropdown.Item>Spansk</Dropdown.Item>
<Dropdown.Item>Fransk</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Norsk</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Engelsk</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Spansk</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Fransk</Dropdown.Button>
</Dropdown.Item>
</Dropdown>
<HelpText aria-label='Du har ikke valgt språk'>
Velg språk for å endre innholdet på siden
Expand Down
14 changes: 7 additions & 7 deletions packages/css/dropdown.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
display: none;
}

.ds-dropdown__heading {
& > :is(h2, h3, h4, h5, h6) {
align-items: center;
box-sizing: border-box;
color: var(--ds-color-neutral-text-subtle);
Expand All @@ -29,17 +29,17 @@
padding: var(--dsc-dropdown-item-padding);
}

& > ul {
margin: 0;
padding: 0;
list-style: none;
}

& :is(a, button, [role='button']) {
justify-content: start;
padding: var(--dsc-dropdown-item-padding);
min-height: var(--dsc-dropdown-item-size);
width: 100%;
font-weight: var(--ds-font-weight-regular);
}

.ds-dropdown__list {
margin: 0;
padding: 0;
list-style: none;
}
}
24 changes: 14 additions & 10 deletions packages/react/src/components/Avatar/Avatar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,18 +96,22 @@ export const InDropdown: Story = () => (
<Dropdown placement='bottom-end' data-size='md' open>
<Dropdown.List>
<Dropdown.Item>
<Badge overlap='circle' color='danger' data-size='sm'>
<Avatar aria-label='Ola Nordmann' data-size='xs'>
ON
</Avatar>
</Badge>
Ola Nordmann
<Dropdown.Button>
<Badge overlap='circle' color='danger' data-size='sm'>
<Avatar aria-label='Ola Nordmann' data-size='xs'>
ON
</Avatar>
</Badge>
Ola Nordmann
</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item>
<Avatar data-size='xs' color='brand1' aria-label='Sogndal Kommune'>
<BriefcaseIcon fontSize='5em' />
</Avatar>
Sogndal kommune
<Dropdown.Button>
<Avatar data-size='xs' color='brand1' aria-label='Sogndal Kommune'>
<BriefcaseIcon fontSize='5em' />
</Avatar>
Sogndal kommune
</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
Expand Down
8 changes: 6 additions & 2 deletions packages/react/src/components/Dropdown/Dropdown.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ import { Dropdown } from '@digdir/designsystemet-react';
<Dropdown>
<Dropdown.Heading>Heading</Dropdown.Heading>
<Dropdown.List>
<Dropdown.Item>Item</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Item</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
</Dropdown.Context>
Expand All @@ -33,7 +35,9 @@ import { Dropdown } from '@digdir/designsystemet-react';
<Dropdown id="my-dropdown">
<Dropdown.Heading>Heading</Dropdown.Heading>
<Dropdown.List>
<Dropdown.Item>Item</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Item</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
```
Expand Down
104 changes: 61 additions & 43 deletions packages/react/src/components/Dropdown/Dropdown.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,23 @@ export const Preview: StoryFn<typeof Dropdown> = (args) => {
<Dropdown.Context>
<Dropdown.Trigger>Dropdown</Dropdown.Trigger>
<Dropdown {...args}>
<Dropdown.Heading>Heading 1</Dropdown.Heading>
<Dropdown.Heading>First heading</Dropdown.Heading>
<Dropdown.List>
<Dropdown.Item>Button 1.1</Dropdown.Item>
<Dropdown.Item>Button 1.2</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Button 1.1</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Button 1.2</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
<Dropdown.Heading>Heading 2</Dropdown.Heading>
<Dropdown.Heading>Second heading</Dropdown.Heading>
<Dropdown.List>
<Dropdown.Item>Button 2.1</Dropdown.Item>
<Dropdown.Item>Button 2.2</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Button 2.1</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Button 2.2</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
</Dropdown.Context>
Expand All @@ -64,25 +72,29 @@ export const Icons: StoryFn<typeof Dropdown> = (args) => {
<Dropdown.Trigger>Dropdown</Dropdown.Trigger>
<Dropdown {...args}>
<Dropdown.List>
<Dropdown.Item asChild>
<a
href='https://github.com/digdir/designsystemet'
target='_blank'
rel='noreferrer'
>
<LinkIcon aria-hidden fontSize='1.5rem' />
Github
</a>
<Dropdown.Item>
<Dropdown.Button asChild>
<a
href='https://github.com/digdir/designsystemet'
target='_blank'
rel='noreferrer'
>
<LinkIcon aria-hidden fontSize='1.5rem' />
Github
</a>
</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item asChild>
<a
href='https://designsystemet.no'
target='_blank'
rel='noreferrer'
>
<LinkIcon aria-hidden fontSize='1.5rem' />
Designsystemet.no
</a>
<Dropdown.Item>
<Dropdown.Button asChild>
<a
href='https://designsystemet.no'
target='_blank'
rel='noreferrer'
>
<LinkIcon aria-hidden fontSize='1.5rem' />
Designsystemet.no
</a>
</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
Expand All @@ -100,25 +112,29 @@ export const Controlled: StoryFn<typeof Dropdown> = () => {
</Dropdown.Trigger>
<Dropdown open={open} onClose={() => setOpen(false)}>
<Dropdown.List>
<Dropdown.Item asChild>
<a
href='https://github.com/digdir/designsystemet'
target='_blank'
rel='noreferrer'
>
<LinkIcon aria-hidden fontSize='1.5rem' />
Github
</a>
<Dropdown.Item>
<Dropdown.Button asChild>
<a
href='https://github.com/digdir/designsystemet'
target='_blank'
rel='noreferrer'
>
<LinkIcon aria-hidden fontSize='1.5rem' />
Github
</a>
</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item asChild>
<a
href='https://designsystemet.no'
target='_blank'
rel='noreferrer'
>
<LinkIcon aria-hidden fontSize='1.5rem' />
Designsystemet.no
</a>
<Dropdown.Item>
<Dropdown.Button asChild>
<a
href='https://designsystemet.no'
target='_blank'
rel='noreferrer'
>
<LinkIcon aria-hidden fontSize='1.5rem' />
Designsystemet.no
</a>
</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
Expand All @@ -132,7 +148,9 @@ export const WithoutTrigger: StoryFn<typeof Dropdown> = () => {
<Button popovertarget='dropdown'>Dropdown</Button>
<Dropdown id='dropdown'>
<Dropdown.List>
<Dropdown.Item>Item</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Item</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
</>
Expand Down
18 changes: 13 additions & 5 deletions packages/react/src/components/Dropdown/Dropdown.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ const Comp = (args: Partial<DropdownContextProps>) => {
<Dropdown>
<Dropdown.Heading>Links</Dropdown.Heading>
<Dropdown.List>
<Dropdown.Item>Item</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Item</Dropdown.Button>
</Dropdown.Item>
{args.children}
</Dropdown.List>
</Dropdown>
Expand All @@ -36,7 +38,11 @@ describe('Dropdown', () => {
/* We are testing closing and opening in Popover.tests.tsx */
it('should render children', async () => {
const { user } = await render({
children: <Dropdown.Item>Item 2</Dropdown.Item>,
children: (
<Dropdown.Item>
<Dropdown.Button>Item 2</Dropdown.Button>
</Dropdown.Item>
),
});
const dropdownTrigger = screen.getByRole('button');

Expand All @@ -45,11 +51,13 @@ describe('Dropdown', () => {
expect(screen.queryByText('Item 2')).toBeInTheDocument();
});

it('should be able to render `Dropdown.Item` as a anchor element using asChild', async () => {
it('should be able to render `Dropdown.Button` as a anchor element using asChild', async () => {
const { user } = await render({
children: (
<Dropdown.Item asChild>
<a href='/'>Anchor</a>
<Dropdown.Item>
<Dropdown.Button asChild>
<a href='/'>Anchor</a>
</Dropdown.Button>
</Dropdown.Item>
),
});
Expand Down
15 changes: 15 additions & 0 deletions packages/react/src/components/Dropdown/DropdownButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { forwardRef } from 'react';

import { Button, type ButtonProps } from '../Button/Button';

export type DropdownButtonProps = Omit<
ButtonProps,
'variant' | 'size' | 'color'
>;

export const DropdownButton = forwardRef<
HTMLButtonElement,
DropdownButtonProps
>(function DropdownButton({ className, ...rest }, ref) {
return <Button ref={ref} variant='tertiary' {...rest} />;
});
10 changes: 4 additions & 6 deletions packages/react/src/components/Dropdown/DropdownHeading.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import cl from 'clsx/lite';
import { type HTMLAttributes, forwardRef } from 'react';
import { forwardRef } from 'react';
import { Heading, type HeadingProps } from '../Heading';

export type DropdownHeadingProps = HTMLAttributes<HTMLHeadingElement>;
export type DropdownHeadingProps = HeadingProps;

export const DropdownHeading = forwardRef<
HTMLHeadingElement,
DropdownHeadingProps
>(function DropdownHeading({ className, ...rest }, ref) {
return (
<h2 ref={ref} className={cl('ds-dropdown__heading', className)} {...rest} />
);
return <Heading ref={ref} {...rest} />;
});
22 changes: 5 additions & 17 deletions packages/react/src/components/Dropdown/DropdownItem.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
import { forwardRef } from 'react';
import { type HTMLAttributes, forwardRef } from 'react';

import type { ButtonProps } from '../Button';
import { Button } from '../Button/Button';
export type DropdownItemProps = HTMLAttributes<HTMLLIElement>;

export type DropdownItemProps = Omit<ButtonProps, 'variant' | 'size' | 'color'>;

export const DropdownItem = forwardRef<HTMLButtonElement, DropdownItemProps>(
function DropdownItem({ className, style, ...rest }, ref) {
return (
<li className={className} style={style}>
<Button
className='ds-dropdown__item'
ref={ref}
variant='tertiary'
{...rest}
/>
</li>
);
export const DropdownItem = forwardRef<HTMLLIElement, DropdownItemProps>(
function DropdownItem({ className, ...rest }, ref) {
return <li ref={ref} {...rest} />;
},
);
Loading

0 comments on commit 519fe18

Please sign in to comment.