* feat(BOOK-293): Adjusted padding of the buttons to match Figma design * feat(BOOK-293): Updated variants for IconButton * feat(BOOK-113): Updated focus indicators on buttons and added default focus ring color * feat(BOOK-293): Replaced buttons inside booking widget Approved-by: Christel Westerberg
469 lines
12 KiB
TypeScript
469 lines
12 KiB
TypeScript
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
|
|
|
|
import { expect, fn } from 'storybook/test'
|
|
|
|
import { MaterialIcon, MaterialIconProps } from '../Icons/MaterialIcon'
|
|
import { IconButton } from './IconButton'
|
|
import { config } from './variants'
|
|
|
|
const meta: Meta<typeof IconButton> = {
|
|
title: 'Core Components/IconButton',
|
|
component: IconButton,
|
|
argTypes: {
|
|
onPress: {
|
|
table: {
|
|
disable: true,
|
|
},
|
|
},
|
|
children: {
|
|
table: {
|
|
disable: true,
|
|
},
|
|
},
|
|
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',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
const buttonAndIconSizesMap = Object.keys(config.variants.size).map<{
|
|
size: keyof typeof config.variants.size
|
|
iconSize: number
|
|
}>((key) => {
|
|
const typedKey = key as keyof typeof config.variants.size
|
|
switch (typedKey) {
|
|
case 'sm':
|
|
return {
|
|
size: typedKey,
|
|
iconSize: 16,
|
|
}
|
|
case 'md':
|
|
return {
|
|
size: typedKey,
|
|
iconSize: 20,
|
|
}
|
|
case 'lg':
|
|
return {
|
|
size: typedKey,
|
|
iconSize: 24,
|
|
}
|
|
case 'xl':
|
|
return {
|
|
size: typedKey,
|
|
iconSize: 28,
|
|
}
|
|
default:
|
|
return {
|
|
size: typedKey,
|
|
iconSize: 24,
|
|
}
|
|
}
|
|
})
|
|
|
|
const globalStoryPropsInverted = {
|
|
backgrounds: { value: 'scandicPrimaryDark' },
|
|
}
|
|
export default meta
|
|
|
|
type Story = StoryObj<typeof IconButton>
|
|
|
|
function renderAllSizesFn(
|
|
args: Story['args'],
|
|
iconName: MaterialIconProps['icon'] = 'search'
|
|
) {
|
|
return (
|
|
<div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
|
|
{buttonAndIconSizesMap.map(({ size, iconSize }) => (
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'center',
|
|
gap: '8px',
|
|
}}
|
|
key={size}
|
|
>
|
|
<IconButton {...args} size={size} key={size}>
|
|
<MaterialIcon
|
|
icon={iconName}
|
|
size={iconSize}
|
|
color="CurrentColor"
|
|
/>
|
|
</IconButton>
|
|
<span>{size}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export const Default: Story = {
|
|
args: {
|
|
onPress: fn(),
|
|
children: <MaterialIcon icon="search" size={24} color="CurrentColor" />,
|
|
},
|
|
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,
|
|
children: (
|
|
<MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
|
|
),
|
|
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,
|
|
children: (
|
|
<MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
|
|
),
|
|
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,
|
|
children: (
|
|
<MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
|
|
),
|
|
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,
|
|
children: (
|
|
<MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
|
|
),
|
|
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,
|
|
children: (
|
|
<MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
|
|
),
|
|
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)
|
|
},
|
|
}
|