Skip to content

Commit

Permalink
Refactor Button component to support icon-only buttons
Browse files Browse the repository at this point in the history
  • Loading branch information
dlnr committed Oct 11, 2024
1 parent 479bd06 commit 6eb720a
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 21 deletions.
36 changes: 19 additions & 17 deletions packages/react/src/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,40 @@ import { forwardRef } from 'react'
import type { ButtonHTMLAttributes, ForwardedRef, PropsWithChildren } from 'react'
import { Icon } from '../Icon'

type ButtonIcon = {
icon?: Function
iconStart?: never
iconOnly?: boolean
}

type ButtonIconStart = {
icon?: never
iconStart?: Function
iconOnly?: boolean
}

export type ButtonProps = {
/** The level of prominence. Use a primary button only once per page or section. */
variant?: 'primary' | 'secondary' | 'tertiary'
icon?: Function
iconPosition?: 'none' | 'start' | 'end' | 'only'
} & PropsWithChildren<ButtonHTMLAttributes<HTMLButtonElement>>
} & (ButtonIcon | ButtonIconStart) &
PropsWithChildren<ButtonHTMLAttributes<HTMLButtonElement>>

export const Button = forwardRef(
(
{
children,
className,
type,
disabled,
variant = 'primary',
icon,
iconPosition = 'none',
...restProps
}: ButtonProps,
{ children, className, type, disabled, variant = 'primary', icon, iconStart, iconOnly, ...restProps }: ButtonProps,
ref: ForwardedRef<HTMLButtonElement>,
) => {
return (
<button
{...restProps}
ref={ref}
disabled={disabled}
className={clsx('ams-button', `ams-button--${variant}`, `ams-button--icon-${iconPosition}`, className)}
className={clsx('ams-button', `ams-button--${variant}`, { 'ams-button--icon-only': iconOnly }, className)}
type={type || 'button'}
>
{icon && (iconPosition === 'start' || iconPosition === 'only') && <Icon svg={icon} size="level-5" square />}
{icon && iconPosition === 'only' ? <span className="ams-visually-hidden">{children}</span> : children}
{icon && iconPosition === 'end' && <Icon svg={icon} size="level-5" square />}
{iconStart && <Icon svg={iconStart} size="level-5" square />}
{iconOnly ? <span className="ams-visually-hidden">{children}</span> : children}
{icon && <Icon svg={icon} size="level-5" square />}
</button>
)
},
Expand Down
2 changes: 2 additions & 0 deletions storybook/src/components/Button/Button.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ Use tertiary Buttons for unimportant calls to action – as many as necessary.

### Button with an icon only

To comply with accessibility guidelines, the icon-only button should have a label.

<Canvas of={ButtonStories.OnlyIcon} />

### Text wrapping
Expand Down
9 changes: 5 additions & 4 deletions storybook/src/components/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ const meta = {
icon: {
table: { disable: true },
},
iconStart: {
table: { disable: true },
},
disabled: {
description: 'Prevents interaction. Avoid if possible.',
},
Expand All @@ -45,23 +48,21 @@ export const Tertiary: Story = {

export const StartIcon: Story = {
args: {
icon: ShareIcon,
iconPosition: 'start',
iconStart: ShareIcon,
},
}

export const EndIcon: Story = {
args: {
icon: ShareIcon,
iconPosition: 'end',
},
}

export const OnlyIcon: Story = {
args: {
variant: 'tertiary',
icon: ShareIcon,
iconPosition: 'only',
iconOnly: true,
},
}

Expand Down

0 comments on commit 6eb720a

Please sign in to comment.