Files
web/packages/design-system/lib/components/IconButton/IconButton.stories.tsx
Erik Tiekstra 3f632e6031 Merged in fix/BOOK-293-button-variants (pull request #3371)
fix(BOOK-293): changed variants and props on IconButton component

* fix(BOOK-293): changed variants and props on IconButton component

* fix(BOOK-293): inherit color for icon


Approved-by: Bianca Widstam
Approved-by: Christel Westerberg
2025-12-19 12:32:52 +00:00

438 lines
11 KiB
TypeScript

import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import { expect, fn } from 'storybook/test'
import { IconButton } from './IconButton'
import { iconButtonIconNames, IconButtonProps } from './types'
import { config } from './variants'
const meta: Meta<typeof IconButton> = {
title: 'Core Components/IconButton',
component: IconButton,
argTypes: {
onPress: {
table: {
type: { summary: 'function' },
defaultValue: { summary: 'undefined' },
},
description: 'Callback function to handle button press events.',
},
variant: {
control: 'select',
options: Object.keys(config.variants.variant),
table: {
defaultValue: {
summary: config.defaultVariants.variant,
},
type: {
summary: Object.keys(config.variants.variant).join(' | '),
},
},
},
size: {
control: 'select',
options: Object.keys(config.variants.size),
table: {
defaultValue: {
summary: config.defaultVariants.size,
},
type: {
summary: Object.keys(config.variants.size).join(' | '),
},
},
description:
'The size of the `IconButton`. Please note that you control the size of the icon inside the button separately. Please check the examples below for recommended icon sizes for each button size.',
},
emphasis: {
control: 'boolean',
options: Object.keys(config.variants.emphasis),
table: {
defaultValue: {
summary: config.defaultVariants.emphasis.toString(),
},
type: {
summary: 'boolean',
},
},
},
iconName: {
control: 'select',
options: iconButtonIconNames,
table: {
type: { summary: iconButtonIconNames.join(' | ') },
defaultValue: { summary: 'undefined' },
},
description: 'Name of the Material Icon to use as icon.',
},
isDisabled: {
control: 'boolean',
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' },
},
},
},
}
const globalStoryPropsInverted = {
backgrounds: { value: 'scandicPrimaryDark' },
}
export default meta
type Story = StoryObj<typeof IconButton>
function renderAllSizesFn(
args: Story['args'],
iconName: IconButtonProps['iconName'] = 'search'
) {
return (
<div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
{Object.keys(config.variants.size).map((size) => (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '8px',
}}
key={size}
>
<IconButton
{...args}
iconName={iconName}
size={size as keyof typeof config.variants.size}
key={size}
/>
<span>{size}</span>
</div>
))}
</div>
)
}
export const Default: Story = {
args: {
onPress: fn(),
iconName: 'search',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
export const Examples: Story = {
render: () => {
return (
<div style={{ display: 'grid', gap: '16px', justifyContent: 'center' }}>
<div
style={{
padding: '16px',
borderRadius: '8px',
border: '1px solid #4D001B',
}}
>
<h3 style={{ marginBottom: '8px' }}>Filled</h3>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
{renderAllSizesFn({ ...Default.args, variant: 'Filled' })}
</div>
</div>
<div
style={{
padding: '16px',
borderRadius: '8px',
border: '1px solid #4D001B',
}}
>
<h3 style={{ marginBottom: '8px' }}>Filled with emphasis</h3>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
{renderAllSizesFn(
{
...Default.args,
variant: 'Filled',
emphasis: true,
},
'arrow_forward'
)}
</div>
</div>
<div
style={{
padding: '16px',
borderRadius: '8px',
border: '1px solid #4D001B',
}}
>
<h3 style={{ marginBottom: '8px' }}>Outlined</h3>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
{renderAllSizesFn(
{
...Default.args,
variant: 'Outlined',
},
'arrow_forward'
)}
</div>
</div>
<div
style={{
padding: '16px',
borderRadius: '8px',
border: '1px solid #4D001B',
}}
>
<h3 style={{ marginBottom: '8px' }}>Elevated</h3>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
{renderAllSizesFn(
{
...Default.args,
variant: 'Elevated',
},
'arrow_forward'
)}
</div>
</div>
<div
style={{
backgroundColor: '#4D001B',
color: 'white',
padding: '16px',
borderRadius: '8px',
border: '1px solid #4D001B',
}}
>
<h3 style={{ marginBottom: '8px' }}>Faded</h3>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
{renderAllSizesFn(
{
...Default.args,
variant: 'Faded',
},
'arrow_forward'
)}
</div>
</div>
<div
style={{
backgroundColor: '#4D001B',
color: 'white',
padding: '16px',
borderRadius: '8px',
border: '1px solid #4D001B',
}}
>
<h3 style={{ marginBottom: '8px' }}>Muted</h3>
<div
style={{
display: 'flex',
flexWrap: 'wrap',
gap: '8px',
}}
>
{renderAllSizesFn(
{
...Default.args,
variant: 'Muted',
},
'arrow_forward'
)}
</div>
</div>
<div
style={{
padding: '16px',
borderRadius: '8px',
border: '1px solid #4D001B',
}}
>
<h3 style={{ marginBottom: '8px' }}>Muted with emphasis</h3>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
{renderAllSizesFn(
{
...Default.args,
variant: 'Muted',
emphasis: true,
},
'arrow_forward'
)}
</div>
</div>
</div>
)
},
}
export const Filled: Story = {
args: {
...Default.args,
variant: 'Filled',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
export const FilledDisabled: Story = {
args: {
...Filled.args,
isDisabled: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
export const FilledOnDarkBackground: Story = {
globals: globalStoryPropsInverted,
args: {
...Filled.args,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
export const FilledWithEmphasis: Story = {
args: {
...Filled.args,
iconName: 'arrow_forward',
emphasis: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
export const FilledWithEmphasisDisabled: Story = {
args: {
...FilledWithEmphasis.args,
isDisabled: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
export const Outlined: Story = {
args: {
...Default.args,
iconName: 'arrow_forward',
variant: 'Outlined',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
export const OutlinedDisabled: Story = {
args: {
...Outlined.args,
isDisabled: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
export const Elevated: Story = {
args: {
...Default.args,
iconName: 'arrow_forward',
variant: 'Elevated',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
export const ElevatedDisabled: Story = {
args: {
...Elevated.args,
isDisabled: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
export const Faded: Story = {
globals: globalStoryPropsInverted,
args: {
...Default.args,
iconName: 'arrow_forward',
variant: 'Faded',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
export const FadedDisabled: Story = {
globals: globalStoryPropsInverted,
args: {
...Faded.args,
isDisabled: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
export const Muted: Story = {
globals: globalStoryPropsInverted,
args: {
...Default.args,
iconName: 'arrow_forward',
variant: 'Muted',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
export const MutedDisabled: Story = {
globals: globalStoryPropsInverted,
args: {
...Muted.args,
isDisabled: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
export const MutedWithEmphasis: Story = {
args: {
...Muted.args,
emphasis: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
export const MutedWithEmphasisDisabled: Story = {
args: {
...MutedWithEmphasis.args,
isDisabled: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}