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

@@ -134,13 +134,16 @@ export default function BookingCodeFilter() {
})}
</h3>
</Typography>
<IconButton variant="Muted" emphasis onPress={close}>
<MaterialIcon
icon="close"
size={24}
color="CurrentColor"
/>
</IconButton>
<IconButton
variant="Muted"
emphasis
onPress={close}
iconName="close"
aria-label={intl.formatMessage({
id: "common.close",
defaultMessage: "Close",
})}
/>
</div>
<Typography variant="Body/Paragraph/mdRegular">
<RadioGroup

View File

@@ -8,14 +8,7 @@ export function AddToCalendarButton({ onPress }: { onPress: () => void }) {
const intl = useIntl()
return (
<Button
variant="Text"
size="Small"
color="Primary"
wrapping
typography="Body/Supporting text (caption)/smBold"
onPress={onPress}
>
<Button variant="Text" size="sm" color="Primary" onPress={onPress}>
<MaterialIcon size={20} icon="calendar_add_on" color="CurrentColor" />
{intl.formatMessage({

View File

@@ -39,9 +39,8 @@ export default function ManageBooking({ booking }: ManageBookingProps) {
<ButtonLink
href={myStayURL}
variant="Text"
size="Small"
size="sm"
color="Primary"
typography="Body/Supporting text (caption)/smBold"
wrapping
>
<MaterialIcon size={20} icon="edit_square" color="CurrentColor" />

View File

@@ -26,7 +26,7 @@ export function Promo({ buttonText, href, text, title }: PromoProps) {
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.text}>{text}</p>
</Typography>
<Button size="Small" variant="Secondary" color="Inverted" wrapping>
<Button size="sm" variant="Secondary" color="Inverted" wrapping>
<div>{buttonText}</div>
</Button>
</article>

View File

@@ -137,7 +137,6 @@ export function ReceiptRoom({
<Button
className={styles.termsButton}
variant="Text"
typography="Body/Supporting text (caption)/smBold"
wrapping={false}
>
{intl.formatMessage({

View File

@@ -24,7 +24,7 @@ export default function Retry({ handleRefetch }: RetryProps) {
</p>
</Typography>
<Button size="Small" onPress={handleRefetch}>
<Button size="sm" onPress={handleRefetch}>
{intl.formatMessage({
id: "bookingConfirmation.linkedReservation.tryAgain",
defaultMessage: "Try again",

View File

@@ -90,6 +90,7 @@
@media screen and (min-width: 768px) and (max-width: 1366px) {
.container {
display: flex;
align-items: center;
}
.codePopover {
background: var(--Base-Surface-Primary-light-Normal);

View File

@@ -230,13 +230,7 @@ function CodeRulesModal() {
return (
<Modal
trigger={
<IconButton variant="Muted" size="sm" emphasis>
<MaterialIcon
icon="info"
color="Icon/Interactive/Placeholder"
size={20}
/>
</IconButton>
<IconButton variant="Muted" size="sm" emphasis iconName="info" />
}
title={codeVoucher}
>
@@ -264,7 +258,7 @@ function CodeRemember({ bookingCodeValue, onApplyClick }: CodeRememberProps) {
</Checkbox>
{bookingCodeValue ? (
<Button
size="Small"
size="sm"
className={styles.hideOnMobile}
variant="Tertiary"
type="button"

View File

@@ -24,7 +24,7 @@ export function RemoveExtraRooms({ ...props }: ButtonProps) {
style={{ width: "100%" }}
type="button"
onClick={removeExtraRooms}
size="Small"
size="sm"
variant="Secondary"
{...props}
>

View File

@@ -101,14 +101,7 @@ export default function RewardNight() {
</Typography>
<Modal
trigger={
<IconButton variant="Muted" emphasis size="sm">
<MaterialIcon
icon="info"
size={20}
color="Icon/Interactive/Placeholder"
className={styles.errorIcon}
/>
</IconButton>
<IconButton variant="Muted" emphasis size="sm" iconName="info" />
}
title={reward}
>

View File

@@ -181,7 +181,7 @@ export function Search({
<Typography variant="Body/Supporting text (caption)/smBold">
<Button
variant="Text"
size="Small"
size="sm"
aria-label={intl.formatMessage({
id: "common.clear",
defaultMessage: "Clear",
@@ -197,7 +197,7 @@ export function Search({
<Button
className={styles.searchButton}
variant="Primary"
size="Small"
size="sm"
type="submit"
onPress={() => {
if (!searchTerm) {

View File

@@ -10,7 +10,6 @@ import { hotelreservation } from "@scandic-hotels/common/constants/routes/hotelR
import { dt } from "@scandic-hotels/common/dt"
import { Button } from "@scandic-hotels/design-system/Button"
import { IconButton } from "@scandic-hotels/design-system/IconButton"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking"
@@ -119,9 +118,8 @@ export default function FormContent({
form={formId}
type="submit"
isDisabled={isSearching}
>
<MaterialIcon icon="search" color="CurrentColor" size={28} />
</IconButton>
iconName="search"
/>
</div>
<div
className={cx(
@@ -147,10 +145,9 @@ export default function FormContent({
className={styles.submitButton}
form={formId}
variant="Primary"
size="Medium"
size="md"
type="submit"
isDisabled={isSearching}
typography="Body/Supporting text (caption)/smBold"
>
{isDirty && isBookingFlow
? intl.formatMessage({
@@ -210,9 +207,13 @@ export function BookingWidgetFormContentSkeleton() {
</div>
</div>
<div className={cx(styles.buttonContainer, styles.showOnTablet)}>
<IconButton variant="Filled" size="xl" type="submit" isDisabled>
<MaterialIcon icon="search" color="CurrentColor" size={28} />
</IconButton>
<IconButton
variant="Filled"
size="xl"
type="submit"
isDisabled
iconName="search"
/>
</div>
<div className={cx(styles.voucherContainer, styles.voucherRow)}>
<VoucherSkeleton />
@@ -221,10 +222,9 @@ export function BookingWidgetFormContentSkeleton() {
<Button
className={styles.submitButton}
variant="Primary"
size="Medium"
size="md"
type="submit"
isDisabled
typography="Body/Supporting text (caption)/smBold"
>
{intl.formatMessage({
id: "bookingWidget.button.search",

View File

@@ -131,8 +131,7 @@ export default function GuestsRoomsPickerDialog({
wrapping
onPress={handleAddRoom}
isDisabled
size="Small"
typography="Body/Supporting text (caption)/smBold"
size="sm"
>
<MaterialIcon icon="add" color="CurrentColor" />
{addRoomLabel}
@@ -163,8 +162,7 @@ export default function GuestsRoomsPickerDialog({
wrapping
color="Primary"
onPress={handleAddRoom}
size="Small"
typography="Body/Supporting text (caption)/smBold"
size="sm"
>
<MaterialIcon icon="add" color="CurrentColor" />
{addRoomLabel}
@@ -187,9 +185,8 @@ export default function GuestsRoomsPickerDialog({
wrapping
color="Primary"
isDisabled
size="Small"
size="sm"
onPress={handleAddRoom}
typography="Body/Supporting text (caption)/smBold"
>
<MaterialIcon icon="add_circle" color="CurrentColor" />
{addRoomLabel}
@@ -204,9 +201,8 @@ export default function GuestsRoomsPickerDialog({
variant="Text"
wrapping
color="Primary"
size="Small"
size="sm"
onPress={handleAddRoom}
typography="Body/Supporting text (caption)/smBold"
>
<MaterialIcon icon="add_circle" color="CurrentColor" />
{addRoomLabel}
@@ -220,8 +216,7 @@ export default function GuestsRoomsPickerDialog({
className={styles.hideOnDesktop}
variant="Tertiary"
color="Primary"
size="Small"
typography="Body/Supporting text (caption)/smBold"
size="sm"
>
{doneLabel}
</Button>
@@ -231,8 +226,7 @@ export default function GuestsRoomsPickerDialog({
className={styles.hideOnMobile}
variant="Tertiary"
color="Primary"
size="Small"
typography="Body/Supporting text (caption)/smBold"
size="sm"
>
{doneLabel}
</Button>

View File

@@ -76,7 +76,7 @@ export function JoinScandicFriendsCard({ name = "join" }: Props) {
<LoginButton
color="Primary"
variant="Tertiary"
size="Small"
size="sm"
lang={lang}
className={styles.login}
loginPosition="enter-details"

View File

@@ -23,9 +23,8 @@ export function GuaranteeInfo({ buttonClassName }: GuaranteeInfoProps) {
<Button
variant="Text"
color="Primary"
size="Small"
size="sm"
type="button"
typography="Body/Supporting text (caption)/smBold"
wrapping={false}
className={buttonClassName}
onPress={() => setIsOpen(true)}
@@ -59,8 +58,7 @@ export function GuaranteeInfo({ buttonClassName }: GuaranteeInfoProps) {
className={styles.closeButton}
variant="Secondary"
color="Primary"
size="Medium"
typography="Body/Paragraph/mdBold"
size="md"
onPress={() => setIsOpen(false)}
>
{intl.formatMessage({

View File

@@ -36,7 +36,6 @@ import useLang from "../../../hooks/useLang"
import { useEnterDetailsStore } from "../../../stores/enter-details"
import ConfirmBooking from "../Confirm"
import PriceChangeDialog from "../PriceChangeDialog"
import { writeGlaToSessionStorage } from "./PaymentCallback/helpers"
import BookingAlert from "./BookingAlert"
import { GuaranteeInfo } from "./GuaranteeInfo"
import {
@@ -47,6 +46,7 @@ import {
mustGuaranteeBooking,
writePaymentInfoToSessionStorage,
} from "./helpers"
import { writeGlaToSessionStorage } from "./PaymentCallback/helpers"
import { type PaymentFormData, paymentSchema } from "./schema"
import { getPaymentHeadingConfig } from "./utils"
@@ -497,8 +497,7 @@ export default function PaymentClient({
type="submit"
isDisabled={isSubmitting}
isPending={isSubmitting}
size="Medium"
typography="Body/Paragraph/mdBold"
size="md"
>
{intl.formatMessage({
id: "enterDetails.completeBooking",

View File

@@ -82,11 +82,10 @@ export default function SelectedRoom() {
</Subtitle>
<Button
variant="Text"
size="Small"
size="sm"
onPress={changeRoom}
isDisabled={isPending}
wrapping={false}
typography="Body/Supporting text (caption)/smBold"
>
<MaterialIcon icon="edit_square" size={20} color="CurrentColor" />
{intl.formatMessage({

View File

@@ -131,9 +131,8 @@ export default function SummaryBottomSheet({
<Button
variant="Primary"
color="Primary"
size="Large"
size="lg"
type="submit"
typography="Body/Paragraph/mdBold"
isDisabled={isSubmitting}
isPending={isSubmitting}
form={formId}

View File

@@ -196,7 +196,6 @@ export default function Room({
<Button
className={styles.termsButton}
variant="Text"
typography="Body/Supporting text (caption)/smBold"
wrapping={false}
>
{intl.formatMessage({

View File

@@ -65,12 +65,7 @@ export function HotelSidePeekContent({
<AdditionalAmenities amenities={hotel.detailedFacilities} />
</Accordion>
{hotelUrl ? (
<ButtonLink
href={hotelUrl}
variant="Secondary"
size="Medium"
typography="Body/Paragraph/mdBold"
>
<ButtonLink href={hotelUrl} variant="Secondary" size="md">
{intl.formatMessage({
id: "hotelSidePeek.readMore.buttonText",
defaultMessage: "Read more about the hotel",

View File

@@ -30,22 +30,17 @@ interface HotelDetailsSidePeekProps {
const buttonPropsMap: Record<
HotelDetailsSidePeekProps["buttonVariant"],
Pick<
React.ComponentProps<typeof Button>,
"variant" | "color" | "size" | "typography"
>
Pick<React.ComponentProps<typeof Button>, "variant" | "color" | "size">
> = {
primary: {
variant: "Text",
color: "Primary",
size: "Medium",
typography: "Body/Paragraph/mdBold",
size: "md",
},
secondary: {
variant: "Secondary",
color: "Inverted",
size: "Small",
typography: "Body/Supporting text (caption)/smBold",
size: "sm",
},
}

View File

@@ -10,7 +10,6 @@ import { HotelCardDialogImage } from "@scandic-hotels/design-system/HotelCard/Ho
import { HotelPointsRow } from "@scandic-hotels/design-system/HotelCard/HotelPointsRow"
import { NoPriceAvailableCard } from "@scandic-hotels/design-system/HotelCard/NoPriceAvailableCard"
import { IconButton } from "@scandic-hotels/design-system/IconButton"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton"
import Link from "@scandic-hotels/design-system/OldDSLink"
import Subtitle from "@scandic-hotels/design-system/Subtitle"
@@ -75,9 +74,8 @@ export default function ListingHotelCardDialog({
id: "common.close",
defaultMessage: "Close",
})}
>
<MaterialIcon icon="close" size={22} color="CurrentColor" />
</IconButton>
iconName="close"
/>
<div className={styles.content}>
<div className={styles.header}>
<HotelCardDialogImage

View File

@@ -11,12 +11,7 @@ import PriceDetailsTable, {
function Trigger({ title }: { title: string }) {
return (
<Button
variant="Text"
size="Medium"
typography="Body/Paragraph/mdBold"
wrapping={false}
>
<Button variant="Text" size="md" wrapping={false}>
{title}
<MaterialIcon icon="chevron_right" color="CurrentColor" size={20} />
</Button>

View File

@@ -26,22 +26,17 @@ interface RoomDetailsSidePeekProps {
const buttonPropsMap: Record<
NonNullable<RoomDetailsSidePeekProps["buttonVariant"]>,
Pick<
React.ComponentProps<typeof Button>,
"variant" | "color" | "size" | "typography"
>
Pick<React.ComponentProps<typeof Button>, "variant" | "color" | "size">
> = {
primary: {
variant: "Text",
color: "Primary",
size: "Medium",
typography: "Body/Paragraph/mdBold",
size: "md",
},
secondary: {
variant: "Text",
color: "Inverted",
size: "Small",
typography: "Body/Supporting text (caption)/smBold",
size: "sm",
},
}

View File

@@ -135,7 +135,7 @@ export default function FilterAndSortModal({
return (
<>
<DialogTrigger>
<Button variant="Secondary" size="Small" color="Primary">
<Button variant="Secondary" size="sm" color="Primary">
<MaterialIcon icon="filter_alt" color="CurrentColor" />
<Typography variant="Body/Supporting text (caption)/smBold">
<p>
@@ -176,9 +176,8 @@ export default function FilterAndSortModal({
id: "common.close",
defaultMessage: "Close",
})}
>
<MaterialIcon icon="close" />
</IconButton>
iconName="close"
/>
</header>
<div className={styles.sorter}>
<DeprecatedSelect
@@ -217,8 +216,8 @@ export default function FilterAndSortModal({
<Button
variant="Tertiary"
color="Primary"
size="Large"
onClick={() => handleApplyFiltersAndSorting(close)}
size="lg"
onPress={() => handleApplyFiltersAndSorting(close)}
>
<Typography variant="Body/Paragraph/mdBold">
<p>
@@ -238,13 +237,13 @@ export default function FilterAndSortModal({
</Typography>
</Button>
<Button
onClick={() => {
onPress={() => {
setSelectedFilters([])
setFilteredCount(unfilteredResultCount)
}}
variant="Text"
color="Primary"
size="Medium"
size="md"
>
<Typography variant="Body/Paragraph/mdBold">
<p>

View File

@@ -14,8 +14,7 @@ export function MapWithButtonWrapper({ children }: React.PropsWithChildren) {
<FakeButton
variant="Primary"
color="Inverted"
size="Small"
typography="Body/Supporting text (caption)/smBold"
size="sm"
className={styles.button}
>
<MaterialIcon icon="map" color="CurrentColor" size={20} />

View File

@@ -168,7 +168,7 @@ export function SelectHotelMapContent({
variant="Primary"
color="Inverted"
wrapping
size="Small"
size="sm"
className={styles.closeButton}
>
<Link
@@ -216,7 +216,7 @@ export function SelectHotelMapContent({
<Button
variant="Text"
type="button"
size="Small"
size="sm"
className={styles.filterContainerCloseButton}
>
<Link href={closeMapUrl} keepSearchParams className={styles.link}>

View File

@@ -91,13 +91,12 @@ export default function SummaryContent({
onPress={toggleSummaryOpen}
variant="Muted"
emphasis
>
<MaterialIcon
icon="keyboard_arrow_down"
size={20}
color="CurrentColor"
/>
</IconButton>
aria-label={intl.formatMessage({
id: "common.close",
defaultMessage: "Close",
})}
iconName="keyboard_arrow_down"
/>
</div>
<Typography variant="Body/Paragraph/mdBold">
<p className={styles.dates}>

View File

@@ -159,7 +159,6 @@ export default function Room({
<Button
className={styles.termsButton}
variant="Text"
typography="Body/Supporting text (caption)/smBold"
wrapping={false}
>
{intl.formatMessage({

View File

@@ -137,9 +137,8 @@ export function MobileSummary() {
<Button
variant="Primary"
color="Primary"
size="Large"
size="lg"
type="submit"
typography="Body/Paragraph/mdBold"
isDisabled={selectedRates.state !== "ALL_SELECTED"}
>
{intl.formatMessage({

View File

@@ -56,7 +56,7 @@ export function RoomPackagesForm({
<Divider color="Border/Divider/Subtle" className={styles.divider} />
<div className={styles.buttonContainer}>
<Typography variant="Body/Supporting text (caption)/smBold">
<Button variant="Tertiary" size="Small" type="submit">
<Button variant="Tertiary" size="sm" type="submit">
{intl.formatMessage({
id: "common.apply",
defaultMessage: "Apply",
@@ -64,11 +64,7 @@ export function RoomPackagesForm({
</Button>
</Typography>
<Typography variant="Body/Supporting text (caption)/smBold">
<Button
onPress={clearSelectedPackages}
size="Small"
variant="Text"
>
<Button onPress={clearSelectedPackages} size="sm" variant="Text">
{intl.formatMessage({
id: "common.clear",
defaultMessage: "Clear",

View File

@@ -64,9 +64,12 @@ export function RoomPackageFilterModal({
variant="Muted"
emphasis
onPress={() => setIsOpen(false)}
>
<MaterialIcon icon="close" size={24} color="CurrentColor" />
</IconButton>
aria-label={intl.formatMessage({
id: "common.close",
defaultMessage: "Close",
})}
iconName="close"
/>
</div>
<RoomPackagesForm
close={() => setIsOpen(false)}

View File

@@ -100,6 +100,7 @@ export function RoomPackageFilter({ roomIndex }: { roomIndex: number }) {
{filterLabel}
<IconButton
variant="Muted"
emphasis
onPress={() => deletePackage(pkg.code)}
aria-label={intl.formatMessage(
{
@@ -111,13 +112,9 @@ export function RoomPackageFilter({ roomIndex }: { roomIndex: number }) {
}
)}
className={styles.removeButton}
>
<MaterialIcon
icon="close"
size={16}
color="Icon/Interactive/Default"
/>
</IconButton>
iconName="close"
size="sm"
/>
</span>
</Typography>
)

View File

@@ -55,8 +55,7 @@ export default function ParkingAccordionItem({
href={parkingPageHref}
variant="Secondary"
color="Primary"
size="Medium"
typography="Body/Paragraph/mdBold"
size="md"
>
{intl.formatMessage({
id: "sideepek.parking.aboutParking",

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>
)