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
This commit is contained in:
Erik Tiekstra
2025-12-19 12:32:52 +00:00
committed by Bianca Widstam
parent 2197ab2137
commit 3f632e6031
169 changed files with 665 additions and 944 deletions

View File

@@ -3,9 +3,9 @@
import { useState } from 'react'
import { useIntl } from 'react-intl'
import { Button } from '../../Button'
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { JsonToHtml } from '../../JsonToHtml/JsonToHtml'
import { Button } from '../../Button'
import SidePeek from '../../SidePeek'
import styles from './sidepeek.module.css'
@@ -26,9 +26,7 @@ export default function AlertSidepeek({
onPress={() => setSidePeekIsOpen(true)}
variant="Text"
color="Primary"
size="Small"
wrapping
typography="Body/Supporting text (caption)/smBold"
size="sm"
>
{ctaText}
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />

View File

@@ -110,9 +110,8 @@ export function BookingCodeChip({
id: 'booking.removeBookingCode',
defaultMessage: 'Remove booking code',
})}
>
<MaterialIcon icon="close" size={16} color={iconColor} />
</IconButton>
iconName="close"
/>
)}
</IconChip>
)

View File

@@ -2,9 +2,8 @@ import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import { expect, fn } from 'storybook/test'
import { MaterialIcon } from '../Icons/MaterialIcon'
import { config as typographyConfig } from '../Typography/variants'
import { Button } from './Button'
import { buttonIconNames } from './types'
import { config as buttonConfig } from './variants'
const meta: Meta<typeof Button> = {
@@ -13,12 +12,10 @@ const meta: Meta<typeof Button> = {
argTypes: {
onPress: {
table: {
disable: true,
type: { summary: 'function' },
defaultValue: { summary: 'undefined' },
},
},
typography: {
control: 'select',
options: Object.keys(typographyConfig.variants.variant),
description: 'Callback function to handle button press events.',
},
variant: {
control: 'select',
@@ -58,7 +55,7 @@ const meta: Meta<typeof Button> = {
},
},
wrapping: {
control: 'radio',
control: 'boolean',
options: Object.keys(buttonConfig.variants.wrapping),
type: 'boolean',
table: {
@@ -69,6 +66,47 @@ const meta: Meta<typeof Button> = {
description:
'Only applies to variant `Text`. If `false`, the button will use smaller padding.',
},
leadingIconName: {
control: 'select',
options: buttonIconNames,
table: {
type: { summary: buttonIconNames.join(' | ') },
defaultValue: { summary: 'undefined' },
},
description: 'Name of the Material Icon to use as leading icon.',
},
trailingIconName: {
control: 'select',
options: buttonIconNames,
table: {
type: { summary: buttonIconNames.join(' | ') },
defaultValue: { summary: 'undefined' },
},
description: 'Name of the Material Icon to use as trailing icon.',
},
isDisabled: {
control: 'boolean',
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' },
},
},
isPending: {
control: 'boolean',
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' },
},
},
fullWidth: {
control: 'boolean',
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' },
},
description:
'By default, the button width adjusts to its content. Set to true to make the button take the full width of its container.',
},
},
}
@@ -83,7 +121,6 @@ export const Default: Story = {
args: {
onPress: fn(),
children: 'Button',
typography: 'Body/Paragraph/mdBold',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -95,7 +132,7 @@ export const PrimaryLarge: Story = {
args: {
...Default.args,
variant: 'Primary',
size: 'Large',
size: 'lg',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -106,7 +143,7 @@ export const PrimaryLarge: Story = {
export const PrimaryMedium: Story = {
args: {
...PrimaryLarge.args,
size: 'Medium',
size: 'md',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -117,8 +154,7 @@ export const PrimaryMedium: Story = {
export const PrimarySmall: Story = {
args: {
...PrimaryLarge.args,
typography: 'Body/Supporting text (caption)/smBold',
size: 'Small',
size: 'sm',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -154,7 +190,6 @@ export const PrimaryOnDarkBackground: Story = {
globals: globalStoryPropsInverted,
args: {
...PrimaryLarge.args,
onPress: fn(), // Fresh spy instance
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -166,7 +201,7 @@ export const PrimaryInvertedLarge: Story = {
globals: globalStoryPropsInverted,
args: {
...Default.args,
size: 'Large',
size: 'lg',
color: 'Inverted',
},
play: async ({ canvas, userEvent, args }) => {
@@ -179,7 +214,7 @@ export const PrimaryInvertedMedium: Story = {
globals: globalStoryPropsInverted,
args: {
...PrimaryInvertedLarge.args,
size: 'Medium',
size: 'md',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -191,8 +226,7 @@ export const PrimaryInvertedSmall: Story = {
globals: globalStoryPropsInverted,
args: {
...PrimaryInvertedLarge.args,
typography: 'Body/Supporting text (caption)/smBold',
size: 'Small',
size: 'sm',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -230,7 +264,7 @@ export const SecondaryLarge: Story = {
args: {
...Default.args,
variant: 'Secondary',
size: 'Large',
size: 'lg',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -241,7 +275,7 @@ export const SecondaryLarge: Story = {
export const SecondaryMedium: Story = {
args: {
...SecondaryLarge.args,
size: 'Medium',
size: 'md',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -252,8 +286,7 @@ export const SecondaryMedium: Story = {
export const SecondarySmall: Story = {
args: {
...SecondaryLarge.args,
typography: 'Body/Supporting text (caption)/smBold',
size: 'Small',
size: 'sm',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -291,7 +324,7 @@ export const SecondaryInvertedLarge: Story = {
...Default.args,
variant: 'Secondary',
color: 'Inverted',
size: 'Large',
size: 'lg',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -303,7 +336,7 @@ export const SecondaryInvertedMedium: Story = {
globals: globalStoryPropsInverted,
args: {
...SecondaryInvertedLarge.args,
size: 'Medium',
size: 'md',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -315,8 +348,7 @@ export const SecondaryInvertedSmall: Story = {
globals: globalStoryPropsInverted,
args: {
...SecondaryInvertedLarge.args,
typography: 'Body/Supporting text (caption)/smBold',
size: 'Small',
size: 'sm',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -354,7 +386,7 @@ export const TertiaryLarge: Story = {
args: {
...Default.args,
variant: 'Tertiary',
size: 'Large',
size: 'lg',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -365,7 +397,7 @@ export const TertiaryLarge: Story = {
export const TertiaryMedium: Story = {
args: {
...TertiaryLarge.args,
size: 'Medium',
size: 'md',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -376,8 +408,7 @@ export const TertiaryMedium: Story = {
export const TertiarySmall: Story = {
args: {
...TertiaryLarge.args,
typography: 'Body/Supporting text (caption)/smBold',
size: 'Small',
size: 'sm',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -413,7 +444,7 @@ export const TextLarge: Story = {
args: {
...Default.args,
variant: 'Text',
size: 'Large',
size: 'lg',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -424,7 +455,7 @@ export const TextLarge: Story = {
export const TextMedium: Story = {
args: {
...TextLarge.args,
size: 'Medium',
size: 'md',
},
play: async ({ canvas, userEvent, args }) => {
@@ -436,8 +467,7 @@ export const TextMedium: Story = {
export const TextSmall: Story = {
args: {
...TextLarge.args,
typography: 'Body/Supporting text (caption)/smBold',
size: 'Small',
size: 'sm',
},
play: async ({ canvas, userEvent, args }) => {
@@ -475,7 +505,7 @@ export const TextInvertedLarge: Story = {
...Default.args,
variant: 'Text',
color: 'Inverted',
size: 'Large',
size: 'lg',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -487,7 +517,7 @@ export const TextInvertedMedium: Story = {
globals: globalStoryPropsInverted,
args: {
...TextInvertedLarge.args,
size: 'Medium',
size: 'md',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -499,8 +529,7 @@ export const TextInvertedSmall: Story = {
globals: globalStoryPropsInverted,
args: {
...TextInvertedLarge.args,
typography: 'Body/Supporting text (caption)/smBold',
size: 'Small',
size: 'sm',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
@@ -524,12 +553,8 @@ export const TextInvertedDisabled: Story = {
export const TextWithIcon: Story = {
args: {
...TextLarge.args,
children: (
<>
Text with icon
<MaterialIcon icon="chevron_right" size={24} color="CurrentColor" />
</>
),
children: 'Text with icon',
trailingIconName: 'chevron_right',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))

View File

@@ -1,6 +1,8 @@
import { Button as ButtonRAC } from 'react-aria-components'
import { Loading, type LoadingProps } from '../Loading/Loading'
import { Loading } from '../Loading/Loading'
import { MaterialIcon } from '../Icons/MaterialIcon'
import { Typography } from '../Typography'
import type { ButtonProps } from './types'
import { variants } from './variants'
@@ -10,7 +12,8 @@ export function Button({
size,
wrapping,
fullWidth,
typography,
leadingIconName,
trailingIconName,
className,
children,
...props
@@ -20,32 +23,44 @@ export function Button({
color,
size,
wrapping,
typography,
fullWidth,
className,
})
return (
<ButtonRAC {...props} className={classNames}>
{({ isPending, isHovered }) => {
let loadingType: LoadingProps['type'] = 'White'
if (variant === 'Secondary') {
if (isHovered || color !== 'Inverted') {
loadingType = 'Dark'
}
} else {
if (color === 'Inverted') {
loadingType = 'Dark'
}
}
return (
<>
{children}
{isPending && <Loading size={20} type={loadingType} />}
</>
)
}}
</ButtonRAC>
<Typography
variant={
size === 'sm'
? 'Body/Supporting text (caption)/smBold'
: 'Body/Paragraph/mdBold'
}
>
<ButtonRAC {...props} className={classNames}>
{({ isPending }) => {
return (
<>
{leadingIconName && !isPending ? (
<MaterialIcon
icon={leadingIconName}
color="CurrentColor"
size={size === 'sm' ? 20 : 24}
/>
) : null}
{children}
{trailingIconName && !isPending ? (
<MaterialIcon
icon={trailingIconName}
color="CurrentColor"
size={size === 'sm' ? 20 : 24}
/>
) : null}
{isPending ? (
<Loading size={size === 'sm' ? 18 : 20} type="CurrentColor" />
) : null}
</>
)
}}
</ButtonRAC>
</Typography>
)
}

View File

@@ -37,15 +37,15 @@
}
}
.size-large {
.size-lg {
padding: calc(var(--Space-x2) - 2px) var(--Space-x3); /* Adjust for 2px border */
}
.size-medium {
.size-md {
padding: calc(var(--Space-x15) - 2px) var(--Space-x2); /* Adjust for 2px border */
}
.size-small {
.size-sm {
padding: var(--Space-x1) var(--Space-x2); /* Adjust for 2px border */
}

View File

@@ -3,8 +3,35 @@ import { Button } from 'react-aria-components'
import type { VariantProps } from 'class-variance-authority'
import type { ComponentProps } from 'react'
import type { SymbolCodepoints } from '../Icons/MaterialIcon/MaterialSymbol/types'
import type { variants } from './variants'
export const buttonIconNames = [
'add_circle',
'open_in_new',
'keyboard_arrow_down',
'keyboard_arrow_up',
'edit_square',
'location_on',
'link',
'mail',
'cancel',
'calendar_month',
'calendar_clock',
'edit_calendar',
'calendar_add_on',
'delete',
'chevron_right',
'chevron_left',
] as const
export type ButtonIconName = Extract<
SymbolCodepoints,
(typeof buttonIconNames)[number]
>
export interface ButtonProps
extends ComponentProps<typeof Button>,
VariantProps<typeof variants> {}
extends ComponentProps<typeof Button>, VariantProps<typeof variants> {
leadingIconName?: ButtonIconName | null
trailingIconName?: ButtonIconName | null
}

View File

@@ -1,9 +1,5 @@
import { cva } from 'class-variance-authority'
import {
config as typographyConfig,
withTypography,
} from '../Typography/variants'
import { deepmerge } from 'deepmerge-ts'
import styles from './button.module.css'
@@ -14,7 +10,6 @@ export const config = {
Primary: styles['variant-primary'],
Secondary: styles['variant-secondary'],
Tertiary: styles['variant-tertiary'],
Inverted: styles['variant-inverted'],
Text: styles['variant-text'],
},
color: {
@@ -22,9 +17,9 @@ export const config = {
Inverted: styles['color-inverted'],
},
size: {
Small: styles['size-small'],
Medium: styles['size-medium'],
Large: styles['size-large'],
sm: styles['size-sm'],
md: styles['size-md'],
lg: styles['size-lg'],
},
wrapping: {
true: undefined,
@@ -38,24 +33,21 @@ export const config = {
defaultVariants: {
variant: 'Primary',
color: 'Primary',
size: 'Large',
size: 'lg',
wrapping: true,
fullWidth: false,
},
} as const
const buttonConfig = {
variants: {
...config.variants,
typography: typographyConfig.variants.variant,
},
defaultVariants: {
...config.defaultVariants,
typography: 'Body/Paragraph/mdBold',
},
} as const
export const variants = cva(styles.button, withTypography(buttonConfig))
export const variants = cva(styles.button, buttonConfig)
export function withButton<T>(config: T) {
return deepmerge(buttonConfig, config)

View File

@@ -1,11 +1,9 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import { expect } from 'storybook/test'
import { expect, fn } from 'storybook/test'
import ButtonLink from '.'
import { config as buttonConfig } from '../Button/variants'
import { MaterialIcon } from '../Icons/MaterialIcon'
import { config as typographyConfig } from '../Typography/variants'
import buttonMeta from '../Button/Button.stories'
const meta: Meta<typeof ButtonLink> = {
title: 'Core Components/ButtonLink',
@@ -13,64 +11,24 @@ const meta: Meta<typeof ButtonLink> = {
argTypes: {
onClick: {
table: {
disable: true,
type: { summary: 'function' },
defaultValue: { summary: 'undefined' },
},
description: 'Callback function to handle link click events.',
},
typography: {
control: 'select',
options: Object.keys(typographyConfig.variants.variant),
},
variant: {
control: 'select',
options: Object.keys(buttonConfig.variants.variant),
default: 'Primary',
variant: buttonMeta.argTypes?.variant,
color: buttonMeta.argTypes?.color,
size: buttonMeta.argTypes?.size,
wrapping: buttonMeta.argTypes?.wrapping,
leadingIconName: buttonMeta.argTypes?.leadingIconName,
trailingIconName: buttonMeta.argTypes?.trailingIconName,
fullWidth: buttonMeta.argTypes?.fullWidth,
href: {
table: {
defaultValue: {
summary: buttonConfig.defaultVariants.variant,
},
type: {
summary: 'string',
detail: Object.keys(buttonConfig.variants.variant).join(' | '),
},
type: { summary: 'string' },
defaultValue: { summary: 'undefined' },
},
},
color: {
control: 'select',
options: Object.keys(buttonConfig.variants.color),
table: {
type: {
summary: 'string',
detail: Object.keys(buttonConfig.variants.color).join(' | '),
},
defaultValue: {
summary: buttonConfig.defaultVariants.color,
},
},
},
size: {
control: 'select',
options: Object.keys(buttonConfig.variants.size),
table: {
type: {
summary: 'string',
detail: Object.keys(buttonConfig.variants.size).join(' | '),
},
defaultValue: {
summary: buttonConfig.defaultVariants.size,
},
},
},
wrapping: {
control: 'radio',
options: Object.keys(buttonConfig.variants.wrapping),
type: 'boolean',
table: {
defaultValue: {
summary: buttonConfig.defaultVariants.wrapping.toString(),
},
},
description:
'Only applies to variant `Text`. If `false`, the button will use smaller padding.',
description: 'The URL that the link points to.',
},
},
}
@@ -84,13 +42,9 @@ type Story = StoryObj<typeof ButtonLink>
export const Default: Story = {
args: {
onClick: (event) => {
event.preventDefault()
alert('Button link clicked!')
},
onClick: fn(),
href: '#',
children: 'Button link',
typography: 'Body/Paragraph/mdBold',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
@@ -103,7 +57,7 @@ export const PrimaryLarge: Story = {
args: {
...Default.args,
variant: 'Primary',
size: 'Large',
size: 'lg',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
@@ -115,7 +69,7 @@ export const PrimaryLarge: Story = {
export const PrimaryMedium: Story = {
args: {
...PrimaryLarge.args,
size: 'Medium',
size: 'md',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
@@ -127,8 +81,7 @@ export const PrimaryMedium: Story = {
export const PrimarySmall: Story = {
args: {
...PrimaryLarge.args,
typography: 'Body/Supporting text (caption)/smBold',
size: 'Small',
size: 'sm',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
@@ -142,7 +95,7 @@ export const PrimaryOnDarkBackground: Story = {
args: {
...Default.args,
variant: 'Primary',
size: 'Large',
size: 'lg',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
@@ -157,7 +110,7 @@ export const PrimaryInvertedLarge: Story = {
...Default.args,
variant: 'Primary',
color: 'Inverted',
size: 'Large',
size: 'lg',
},
play: async ({ canvasElement }) => {
@@ -171,9 +124,8 @@ export const PrimaryInvertedMedium: Story = {
globals: globalStoryPropsInverted,
args: {
...PrimaryInvertedLarge.args,
size: 'Medium',
size: 'md',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -185,10 +137,8 @@ export const PrimaryInvertedSmall: Story = {
globals: globalStoryPropsInverted,
args: {
...PrimaryInvertedLarge.args,
typography: 'Body/Supporting text (caption)/smBold',
size: 'Small',
size: 'sm',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -200,9 +150,8 @@ export const SecondaryLarge: Story = {
args: {
...Default.args,
variant: 'Secondary',
size: 'Large',
size: 'lg',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -213,9 +162,8 @@ export const SecondaryLarge: Story = {
export const SecondaryMedium: Story = {
args: {
...SecondaryLarge.args,
size: 'Medium',
size: 'md',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -226,10 +174,8 @@ export const SecondaryMedium: Story = {
export const SecondarySmall: Story = {
args: {
...SecondaryLarge.args,
typography: 'Body/Supporting text (caption)/smBold',
size: 'Small',
size: 'sm',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -243,9 +189,8 @@ export const SecondaryInvertedLarge: Story = {
...Default.args,
variant: 'Secondary',
color: 'Inverted',
size: 'Large',
size: 'lg',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -257,9 +202,8 @@ export const SecondaryInvertedMedium: Story = {
globals: globalStoryPropsInverted,
args: {
...SecondaryInvertedLarge.args,
size: 'Medium',
size: 'md',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -271,10 +215,8 @@ export const SecondaryInvertedSmall: Story = {
globals: globalStoryPropsInverted,
args: {
...SecondaryInvertedLarge.args,
typography: 'Body/Supporting text (caption)/smBold',
size: 'Small',
size: 'sm',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -286,9 +228,8 @@ export const TertiaryLarge: Story = {
args: {
...Default.args,
variant: 'Tertiary',
size: 'Large',
size: 'lg',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -299,9 +240,8 @@ export const TertiaryLarge: Story = {
export const TertiaryMedium: Story = {
args: {
...TertiaryLarge.args,
size: 'Medium',
size: 'md',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -312,10 +252,8 @@ export const TertiaryMedium: Story = {
export const TertiarySmall: Story = {
args: {
...TertiaryLarge.args,
typography: 'Body/Supporting text (caption)/smBold',
size: 'Small',
size: 'sm',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -327,9 +265,8 @@ export const TextLarge: Story = {
args: {
...Default.args,
variant: 'Text',
size: 'Large',
size: 'lg',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -340,9 +277,8 @@ export const TextLarge: Story = {
export const TextMedium: Story = {
args: {
...TextLarge.args,
size: 'Medium',
size: 'md',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -353,10 +289,8 @@ export const TextMedium: Story = {
export const TextSmall: Story = {
args: {
...TextLarge.args,
typography: 'Body/Supporting text (caption)/smBold',
size: 'Small',
size: 'sm',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -383,9 +317,8 @@ export const TextInvertedLarge: Story = {
...Default.args,
variant: 'Text',
color: 'Inverted',
size: 'Large',
size: 'lg',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -397,9 +330,8 @@ export const TextInvertedMedium: Story = {
globals: globalStoryPropsInverted,
args: {
...TextInvertedLarge.args,
size: 'Medium',
size: 'md',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -411,10 +343,8 @@ export const TextInvertedSmall: Story = {
globals: globalStoryPropsInverted,
args: {
...TextInvertedLarge.args,
typography: 'Body/Supporting text (caption)/smBold',
size: 'Small',
size: 'sm',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
@@ -426,12 +356,8 @@ export const TextWithIcon: Story = {
args: {
...Default.args,
variant: 'Text',
children: (
<>
Text with icon
<MaterialIcon icon="chevron_right" size={24} color="CurrentColor" />
</>
),
children: 'Text with icon',
trailingIconName: 'chevron_right',
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
@@ -445,12 +371,6 @@ export const TextWithIconInverted: Story = {
args: {
...TextWithIcon.args,
color: 'Inverted',
children: (
<>
Text with icon
<MaterialIcon icon="chevron_right" size={24} color="CurrentColor" />
</>
),
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')

View File

@@ -7,22 +7,30 @@ import { variants } from './variants'
import type { VariantProps } from 'class-variance-authority'
import Link from 'next/link'
import { useIntl } from 'react-intl'
import { ButtonIconName } from '../Button/types'
import { MaterialIcon } from '../Icons/MaterialIcon'
import { Typography } from '../Typography'
export interface ButtonLinkProps
extends
Omit<ComponentProps<typeof Link>, 'color'>,
VariantProps<typeof variants> {}
VariantProps<typeof variants> {
leadingIconName?: ButtonIconName | null
trailingIconName?: ButtonIconName | null
}
export default function ButtonLink({
variant,
color,
size,
typography,
wrapping,
fullWidth,
className,
href,
target,
leadingIconName,
trailingIconName,
children,
...props
}: ButtonLinkProps) {
const classNames = variants({
@@ -30,7 +38,6 @@ export default function ButtonLink({
color,
size,
wrapping,
typography,
fullWidth,
className,
})
@@ -42,12 +49,36 @@ export default function ButtonLink({
})
return (
<Link
className={classNames}
href={href}
target={target}
title={target === '_blank' ? newTabText : ''}
{...props}
/>
<Typography
variant={
size === 'sm'
? 'Body/Supporting text (caption)/smBold'
: 'Body/Paragraph/mdBold'
}
>
<Link
className={classNames}
href={href}
target={target}
title={target === '_blank' ? newTabText : ''}
{...props}
>
{leadingIconName ? (
<MaterialIcon
icon={leadingIconName}
color="CurrentColor"
size={size === 'sm' ? 20 : 24}
/>
) : null}
{children}
{trailingIconName ? (
<MaterialIcon
icon={trailingIconName}
color="CurrentColor"
size={size === 'sm' ? 20 : 24}
/>
) : null}
</Link>
</Typography>
)
}

View File

@@ -4,8 +4,8 @@ import { fn } from 'storybook/test'
import { themes } from '../../../../.storybook/preview'
import { Card } from '../'
import { Typography } from '../../Typography'
import { Button } from '../../Button'
import { Typography } from '../../Typography'
type CompositionProps = React.ComponentPropsWithoutRef<typeof Card> & {
_onPrimaryPress?: () => void
@@ -97,33 +97,22 @@ const meta: Meta<CompositionProps> = {
)}
{showPrimaryButton && inMainArea && (
<Button
size="Large"
variant="Primary"
typography="Body/Paragraph/mdBold"
onPress={args._onPrimaryPress}
>
<Button size="lg" variant="Primary" onPress={args._onPrimaryPress}>
Primary action
</Button>
)}
{showPrimaryButton && !inMainArea && (
<Button
size="Small"
variant="Tertiary"
typography="Body/Paragraph/mdBold"
onPress={args._onPrimaryPress}
>
<Button size="sm" variant="Tertiary" onPress={args._onPrimaryPress}>
Primary action
</Button>
)}
{showSecondaryButton && (
<Button
size={inMainArea ? 'Large' : 'Small'}
size={inMainArea ? 'lg' : 'sm'}
variant="Secondary"
onPress={args._onSecondaryPress}
typography="Body/Paragraph/mdBold"
>
Secondary action
</Button>

View File

@@ -4,6 +4,7 @@ import { variants } from './variants'
import { cx, type VariantProps } from 'class-variance-authority'
import type { HTMLAttributes } from 'react'
import { Typography } from '../Typography'
interface FakeButtonProps
extends
@@ -16,7 +17,6 @@ export function FakeButton({
variant,
color,
size,
typography,
fullWidth,
children,
className,
@@ -28,19 +28,26 @@ export function FakeButton({
color,
size,
variant,
typography,
fullWidth,
isHovered,
className,
})
return (
<span
className={cx(classNames)}
data-disabled={isDisabled || undefined}
{...props}
<Typography
variant={
size === 'sm'
? 'Body/Supporting text (caption)/smBold'
: 'Body/Paragraph/mdBold'
}
>
{children}
</span>
<span
className={cx(classNames)}
data-disabled={isDisabled || undefined}
{...props}
>
{children}
</span>
</Typography>
)
}

View File

@@ -1,14 +1,14 @@
import { zodResolver } from '@hookform/resolvers/zod'
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import { fn } from 'storybook/test'
import { useEffect } from 'react'
import { FormProvider, useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { fn } from 'storybook/test'
import { z } from 'zod'
import { FormInput } from '../FormInput'
import { Button } from '../../Button'
import { Typography } from '../../Typography'
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { Typography } from '../../Typography'
import { FormInput } from '../FormInput'
const createExampleFormSchema = (prefix?: string) => {
const getKey = (key: string) => (prefix ? `${prefix}_${key}` : key)
@@ -127,7 +127,7 @@ function ExampleFormComponent({
registerOptions={{ required: true }}
/>
<Button type="submit" variant="Primary" size="Large">
<Button type="submit" variant="Primary" size="lg">
Send message
</Button>
</form>
@@ -292,7 +292,7 @@ function SignupFormComponent({
registerOptions={{ required: true }}
/>
<Button type="submit" variant="Primary" size="Large">
<Button type="submit" variant="Primary" size="lg">
Create account
</Button>
</form>

View File

@@ -76,11 +76,7 @@ export const Default: Story = {
],
belowInfoSlot: (
<Button
onPress={() => fn()}
variant="Text"
typography="Body/Paragraph/mdBold"
>
<Button onPress={() => fn()} variant="Text">
Read more
<MaterialIcon icon="chevron_right" size={24} color="CurrentColor" />
</Button>

View File

@@ -4,7 +4,6 @@ import { useState } from 'react'
import { useIntl } from 'react-intl'
import { IconButton } from '../../../IconButton'
import { MaterialIcon } from '../../../Icons/MaterialIcon'
import { Typography } from '../../../Typography'
import { HotelCardDialogImage } from '../../HotelCardDialogImage'
@@ -84,9 +83,8 @@ export function StandaloneHotelCardDialog({
id: 'common.close',
defaultMessage: 'Close',
})}
>
<MaterialIcon icon="close" size={22} color="CurrentColor" />
</IconButton>
iconName="close"
/>
<HotelCardDialogImage
imageSrc={image?.url}
altText={image?.alt}
@@ -187,7 +185,7 @@ export function StandaloneHotelCardDialog({
href={selectRateUrl}
variant="Primary"
color="Primary"
size="Small"
size="sm"
onClick={onClick}
>
{intl.formatMessage({

View File

@@ -364,9 +364,8 @@ export const HotelCardComponent = memo(
) : null}
<FakeButton
variant="Primary"
size="Medium"
size="md"
isDisabled={!!isDisabled}
typography="Body/Paragraph/mdBold"
isHovered={isPricesHovered}
>
{isDisabled

View File

@@ -69,11 +69,7 @@ export const Default: Story = {
mapping: {
none: null,
button: (
<Button
variant="Text"
typography="Body/Supporting text (caption)/smBold"
onPress={() => fn()}
>
<Button variant="Text" onPress={() => fn()}>
Read more <MaterialIcon icon="chevron_right" />
</Button>
),

View File

@@ -2,8 +2,8 @@ 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 { iconButtonIconNames, IconButtonProps } from './types'
import { config } from './variants'
const meta: Meta<typeof IconButton> = {
@@ -12,13 +12,10 @@ const meta: Meta<typeof IconButton> = {
argTypes: {
onPress: {
table: {
disable: true,
},
},
children: {
table: {
disable: true,
type: { summary: 'function' },
defaultValue: { summary: 'undefined' },
},
description: 'Callback function to handle button press events.',
},
variant: {
control: 'select',
@@ -58,43 +55,25 @@ const meta: Meta<typeof IconButton> = {
},
},
},
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 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' },
}
@@ -104,11 +83,11 @@ type Story = StoryObj<typeof IconButton>
function renderAllSizesFn(
args: Story['args'],
iconName: MaterialIconProps['icon'] = 'search'
iconName: IconButtonProps['iconName'] = 'search'
) {
return (
<div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
{buttonAndIconSizesMap.map(({ size, iconSize }) => (
{Object.keys(config.variants.size).map((size) => (
<div
style={{
display: 'flex',
@@ -118,13 +97,12 @@ function renderAllSizesFn(
}}
key={size}
>
<IconButton {...args} size={size} key={size}>
<MaterialIcon
icon={iconName}
size={iconSize}
color="CurrentColor"
/>
</IconButton>
<IconButton
{...args}
iconName={iconName}
size={size as keyof typeof config.variants.size}
key={size}
/>
<span>{size}</span>
</div>
))}
@@ -135,7 +113,7 @@ function renderAllSizesFn(
export const Default: Story = {
args: {
onPress: fn(),
children: <MaterialIcon icon="search" size={24} color="CurrentColor" />,
iconName: 'search',
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole('button'))
@@ -283,6 +261,7 @@ export const Examples: Story = {
)
},
}
export const Filled: Story = {
args: {
...Default.args,
@@ -319,9 +298,7 @@ export const FilledOnDarkBackground: Story = {
export const FilledWithEmphasis: Story = {
args: {
...Filled.args,
children: (
<MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
),
iconName: 'arrow_forward',
emphasis: true,
},
play: async ({ canvas, userEvent, args }) => {
@@ -344,9 +321,7 @@ export const FilledWithEmphasisDisabled: Story = {
export const Outlined: Story = {
args: {
...Default.args,
children: (
<MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
),
iconName: 'arrow_forward',
variant: 'Outlined',
},
play: async ({ canvas, userEvent, args }) => {
@@ -369,9 +344,7 @@ export const OutlinedDisabled: Story = {
export const Elevated: Story = {
args: {
...Default.args,
children: (
<MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
),
iconName: 'arrow_forward',
variant: 'Elevated',
},
play: async ({ canvas, userEvent, args }) => {
@@ -395,9 +368,7 @@ export const Faded: Story = {
globals: globalStoryPropsInverted,
args: {
...Default.args,
children: (
<MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
),
iconName: 'arrow_forward',
variant: 'Faded',
},
play: async ({ canvas, userEvent, args }) => {
@@ -422,9 +393,7 @@ export const Muted: Story = {
globals: globalStoryPropsInverted,
args: {
...Default.args,
children: (
<MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
),
iconName: 'arrow_forward',
variant: 'Muted',
},
play: async ({ canvas, userEvent, args }) => {

View File

@@ -1,16 +1,14 @@
import { Button as ButtonRAC } from 'react-aria-components'
import { VariantProps } from 'class-variance-authority'
import { ComponentProps } from 'react'
import { MaterialIcon } from '../Icons/MaterialIcon'
import { IconButtonProps } from './types'
import { variants } from './variants'
interface IconButtonProps
extends ComponentProps<typeof ButtonRAC>, VariantProps<typeof variants> {}
export function IconButton({
variant,
emphasis,
size,
iconName,
className,
...props
}: IconButtonProps) {
@@ -21,5 +19,27 @@ export function IconButton({
className,
})
return <ButtonRAC {...props} className={classNames} />
return (
<ButtonRAC {...props} className={classNames}>
<MaterialIcon
icon={iconName}
size={getIconSize(size)}
color="CurrentColor"
/>
</ButtonRAC>
)
}
function getIconSize(size: IconButtonProps['size']) {
switch (size) {
case 'sm':
return 16
case 'md':
return 20
case 'xl':
return 28
case 'lg':
default:
return 24
}
}

View File

@@ -73,7 +73,7 @@
&.emphasis {
background-color: var(--Component-Button-Brand-Tertiary-Fill-Default);
color: var(--Component-Button-Brand-Tertiary-On-fill-Default);
color: inherit;
&[data-disabled] {
background-color: var(--Component-Button-Brand-Tertiary-Fill-Disabled);
@@ -231,7 +231,7 @@
}
&.emphasis {
color: var(--Component-Button-Muted-On-fill-Default);
color: inherit;
&[data-disabled] {
background-color: var(--Component-Button-Muted-Fill-Disabled-inverted);

View File

@@ -0,0 +1,39 @@
import { Button as ButtonRAC } from 'react-aria-components'
import type { VariantProps } from 'class-variance-authority'
import type { ComponentProps } from 'react'
import type { SymbolCodepoints } from '../Icons/MaterialIcon/MaterialSymbol/types'
import type { variants } from './variants'
export const iconButtonIconNames = [
'arrow_forward',
'arrow_back',
'remove',
'close',
'add',
'search',
'info_circle',
'help_circle',
'info',
'delete',
'visibility',
'visibility_off',
'keyboard_arrow_down',
'keyboard_arrow_up',
'cancel',
'chevron_left',
'chevron_right',
] as const
export type IconButtonIconName = Extract<
SymbolCodepoints,
(typeof iconButtonIconNames)[number]
>
export interface IconButtonProps
extends
Omit<ComponentProps<typeof ButtonRAC>, 'children'>,
VariantProps<typeof variants> {
iconName: IconButtonIconName
}

View File

@@ -71,9 +71,8 @@ export function InfoCard({
<div className={styles.buttonContainer}>
{primaryButton ? (
<ButtonLink
size="Small"
size="sm"
href={primaryButton.href}
typography="Body/Supporting text (caption)/smBold"
onClick={primaryButton.onClick}
scroll={primaryButton.scrollOnClick ?? false}
{...buttonProps.primaryButton}
@@ -83,9 +82,8 @@ export function InfoCard({
) : null}
{secondaryButton ? (
<ButtonLink
size="Small"
size="sm"
href={secondaryButton.href}
typography="Body/Supporting text (caption)/smBold"
onClick={secondaryButton.onClick}
scroll={secondaryButton.scrollOnClick ?? false}
{...buttonProps.secondaryButton}

View File

@@ -130,6 +130,7 @@ const meta: Meta<typeof Input> = {
defaultValue: { summary: 'false' },
},
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any,
}
@@ -147,6 +148,7 @@ export const Default: Story = {
leftIconName: 'person',
rightIconName: 'lock',
showWarning: false,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any,
render: (args) => {
// Extract custom Storybook args

View File

@@ -13,7 +13,6 @@ import { InputLabel } from '../InputLabel'
import styles from './input.module.css'
import { IconButton } from '../IconButton'
import { MaterialIcon } from '../Icons/MaterialIcon'
import { Typography } from '../Typography'
import type { InputProps } from './types'
import { clearInput, useInputHasValue } from './utils'
@@ -113,9 +112,8 @@ const InputComponent = forwardRef(function AriaInputWithLabelComponent(
onPress={onClearContent}
// eslint-disable-next-line formatjs/no-literal-string-in-jsx
aria-label="Clear content"
>
<MaterialIcon icon="cancel" />
</IconButton>
iconName="cancel"
/>
</div>
)}
{rightIcon && !(showClearContentIcon && hasValue) && (
@@ -162,9 +160,8 @@ const InputComponent = forwardRef(function AriaInputWithLabelComponent(
onPress={onClearContent}
// eslint-disable-next-line formatjs/no-literal-string-in-jsx
aria-label="Clear content"
>
<MaterialIcon icon="cancel" />
</IconButton>
iconName="cancel"
/>
</div>
)}
{rightIcon && !(showClearContentIcon && hasValue) && (

View File

@@ -22,6 +22,7 @@ export function InputLabel({
return (
<span className={classNames} {...rest}>
{children}
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
{required && <span aria-hidden="true">{' *'}</span>}
</span>
)

View File

@@ -7,7 +7,6 @@ import { useIntl } from 'react-intl'
import Image from '../../Image'
import { IconButton } from '../../IconButton'
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { Typography } from '../../Typography'
import { LightboxImage } from '../index'
@@ -94,9 +93,8 @@ export default function FullView({
id: 'common.close',
defaultMessage: 'Close',
})}
>
<MaterialIcon icon="close" color="CurrentColor" size={24} />
</IconButton>
iconName="close"
/>
<div className={styles.header}>
<Typography variant="Tag/sm">
<span className={styles.imageCount}>
@@ -141,16 +139,14 @@ export default function FullView({
variant="Muted"
className={`${styles.navigationButton} ${styles.prev}`}
onPress={handlePrev}
>
<MaterialIcon icon="arrow_back" color="CurrentColor" />
</IconButton>
iconName="arrow_back"
/>
<IconButton
variant="Muted"
className={`${styles.navigationButton} ${styles.next}`}
onPress={handleNext}
>
<MaterialIcon icon="arrow_forward" color="CurrentColor" />
</IconButton>
iconName="arrow_forward"
/>
</div>
)
}

View File

@@ -5,12 +5,12 @@ import { Button as ButtonRAC } from 'react-aria-components'
import { useIntl } from 'react-intl'
import { IconButton } from '../../IconButton'
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { Typography } from '../../Typography'
import Image from '../../Image'
import { cx } from 'class-variance-authority'
import { useMediaQuery } from 'usehooks-ts'
import { LightboxImage } from '..'
import styles from './gallery.module.css'
@@ -35,6 +35,7 @@ export default function Gallery({
const [animateLeft, setAnimateLeft] = useState(true)
const mainImage = selectedImage || images[0]
const mainImageIndex = images.findIndex((img) => img === mainImage)
const isMobile = useMediaQuery('(max-width: 767px)')
function getThumbImages() {
const thumbs = []
@@ -96,20 +97,8 @@ export default function Gallery({
id: 'common.close',
defaultMessage: 'Close',
})}
>
<MaterialIcon
icon="chevron_left"
color="CurrentColor"
size={24}
className={styles.mobileCloseIcon}
/>
<MaterialIcon
icon="close"
color="CurrentColor"
size={24}
className={styles.desktopCloseIcon}
/>
</IconButton>
iconName={isMobile ? 'chevron_left' : 'close'}
/>
{/* Desktop Gallery */}
<div className={styles.desktopGallery}>
@@ -156,9 +145,8 @@ export default function Gallery({
id: 'lightbox.previousImage',
defaultMessage: 'Previous image',
})}
>
<MaterialIcon icon="arrow_back" color="CurrentColor" />
</IconButton>
iconName="arrow_back"
/>
<IconButton
variant="Elevated"
className={cx(styles.navigationButton, styles.next)}
@@ -167,9 +155,8 @@ export default function Gallery({
id: 'lightbox.nextImage',
defaultMessage: 'Next image',
})}
>
<MaterialIcon icon="arrow_forward" color="CurrentColor" />
</IconButton>
iconName="arrow_forward"
/>
</div>
<div className={styles.desktopThumbnailGrid}>
<AnimatePresence initial={false}>

View File

@@ -45,6 +45,10 @@
&.white circle {
fill: var(--Icon-Inverted);
}
&.currentColor circle {
fill: currentColor;
}
}
@keyframes pulse {

View File

@@ -7,6 +7,7 @@ export const config = {
type: {
Dark: styles.dark,
White: styles.white,
CurrentColor: styles.currentColor,
},
},
defaultVariants: {

View File

@@ -5,7 +5,6 @@ import { useEffect, useState } from 'react'
import { useIntl } from 'react-intl'
import { IconButton } from '../../IconButton'
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { HOTEL_PAGE, MAP_RESTRICTIONS } from '../mapConstants'
@@ -150,9 +149,8 @@ export function InteractiveMap({
defaultMessage: 'Zoom out',
})}
isDisabled={isMinZoom}
>
<MaterialIcon icon="remove" color="CurrentColor" />
</IconButton>
iconName="remove"
/>
<IconButton
variant="Elevated"
@@ -163,9 +161,8 @@ export function InteractiveMap({
defaultMessage: 'Zoom in',
})}
isDisabled={isMaxZoom}
>
<MaterialIcon icon="add" color="CurrentColor" />
</IconButton>
iconName="add"
/>
</div>
</div>
</div>

View File

@@ -11,7 +11,6 @@ import {
} from 'react-aria-components'
import { useIntl } from 'react-intl'
import { MaterialIcon } from '../Icons/MaterialIcon'
import {
type AnimationState,
@@ -126,13 +125,8 @@ function InnerModal({
})}
variant="Muted"
emphasis
>
<MaterialIcon
icon="close"
color="Icon/Feedback/Neutral"
size={24}
/>
</IconButton>
iconName="close"
/>
</header>
)}

View File

@@ -86,12 +86,7 @@ export default function ParkingInformation({
</div>
</div>
{parking.externalParkingUrl && showExternalParkingButton && (
<ButtonLink
typography="Body/Paragraph/mdBold"
size="Medium"
href={parking.externalParkingUrl}
target="_blank"
>
<ButtonLink size="md" href={parking.externalParkingUrl} target="_blank">
{intl.formatMessage({
id: 'parkingInformation.bookParking',
defaultMessage: 'Book parking',

View File

@@ -87,9 +87,8 @@ export default function CampaignRateCard({
id: 'selectRate.rateCard.openReservationPolicy',
defaultMessage: 'Open reservation policy',
})}
>
<MaterialIcon icon="info" size={20} color="Icon/Default" />
</IconButton>
iconName="info"
/>
}
>
{rateTermDetails.map((termGroup) => (

View File

@@ -77,9 +77,8 @@ export default function CodeRateCard({
id: 'selectRate.rateCard.openReservationPolicy',
defaultMessage: 'Open reservation policy',
})}
>
<MaterialIcon icon="info" size={20} color="Icon/Default" />
</IconButton>
iconName="info"
/>
}
>
{rateTermDetails.map((termGroup) => (

View File

@@ -19,7 +19,6 @@ import { fade, slideInOut } from './motionVariants'
import { useIntl } from 'react-intl'
import { IconButton } from '../../IconButton'
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { Typography } from '../../Typography'
import styles from './modal.module.css'
@@ -98,9 +97,8 @@ function InnerModal({
id: 'common.close',
defaultMessage: 'Close',
})}
>
<MaterialIcon icon="close" size={24} color="CurrentColor" />
</IconButton>
iconName="close"
/>
</header>
)}

View File

@@ -1,5 +1,4 @@
import { IconButton } from '../../IconButton'
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { Typography } from '../../Typography'
import styles from '../rate-card.module.css'
import { variants } from '../variants'
@@ -34,9 +33,7 @@ export default function NoRateAvailableCard({
<header>
<Typography variant="Tag/sm">
<h3 className={`${styles.title} ${styles.textDisabled}`}>
<IconButton variant="Muted" emphasis size="sm">
<MaterialIcon icon="info" size={20} color="Icon/Default" />
</IconButton>
<IconButton variant="Muted" emphasis size="sm" iconName="info" />
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
{`${rateTitle} / ${paymentTerm}`}
</h3>

View File

@@ -63,9 +63,8 @@ export default function PointsRateCard({
id: 'selectRate.rateCard.openReservationPolicy',
defaultMessage: 'Open reservation policy',
})}
>
<MaterialIcon icon="info" size={20} color="Icon/Default" />
</IconButton>
iconName="info"
/>
}
>
{rateTermDetails.map((termGroup) => (

View File

@@ -72,9 +72,8 @@ export default function RegularRateCard({
id: 'selectRate.rateCard.openReservationPolicy',
defaultMessage: 'Open reservation policy',
})}
>
<MaterialIcon icon="info" size={20} color="Icon/Default" />
</IconButton>
iconName="info"
/>
}
>
{rateTermDetails.map((termGroup) => (

View File

@@ -7,7 +7,6 @@ import { useIntl } from 'react-intl'
import usePopStateHandler from '@scandic-hotels/common/hooks/usePopStateHandler'
import { IconButton } from '../IconButton'
import { MaterialIcon } from '../Icons/MaterialIcon'
import { Typography } from '../Typography'
import SidePeekSEO from './SidePeekSEO'
@@ -72,13 +71,8 @@ export default function SidePeekSelfControlled({
id: 'common.close',
defaultMessage: 'Close',
})}
>
<MaterialIcon
icon="close"
size={24}
color="Icon/Interactive/Default"
/>
</IconButton>
iconName="close"
/>
</div>
</header>
<div className={styles.sidePeekContent}>{children}</div>

View File

@@ -3,7 +3,6 @@
import { useCallback, useContext, useRef } from 'react'
import { Dialog, Modal, ModalOverlay } from 'react-aria-components'
import { IconButton } from '../IconButton'
import { MaterialIcon } from '../Icons/MaterialIcon'
import { Typography } from '../Typography'
import { SidePeekContext } from './SidePeekContext'
@@ -104,12 +103,8 @@ export default function SidePeek({
emphasis
aria-label={closeLabel}
onPress={onClose}
>
<MaterialIcon
icon="close"
color="Icon/Interactive/Default"
/>
</IconButton>
iconName="close"
/>
</div>
</header>
<div className={styles.sidePeekContent}>{children}</div>

View File

@@ -1,5 +1,4 @@
import { IconButton } from '../IconButton'
import { MaterialIcon } from '../Icons/MaterialIcon'
import { Tooltip } from '../Tooltip'
import { Typography } from '../Typography'
@@ -29,9 +28,8 @@ export default function Stepper({
onPress={handleOnDecrease}
variant="Elevated"
isDisabled={disableDecrease}
>
<MaterialIcon icon="remove" color="CurrentColor" />
</IconButton>
iconName="remove"
/>
<div className={styles.countDisplay}>
<Typography variant="Body/Paragraph/mdRegular">
<p>{count}</p>
@@ -49,9 +47,8 @@ export default function Stepper({
onPress={handleOnIncrease}
variant="Elevated"
isDisabled={disableIncrease}
>
<MaterialIcon icon="add" color="CurrentColor" />
</IconButton>
iconName="add"
/>
</Tooltip>
</div>
)

View File

@@ -46,9 +46,8 @@ export function Toast({ children, message, onClose, variant }: ToastsProps) {
})}
variant="Muted"
emphasis
>
<MaterialIcon icon="close" />
</IconButton>
iconName="close"
/>
) : null}
</div>
)