From f62723c6e5e4efbca900014c1b6742288d229adc Mon Sep 17 00:00:00 2001 From: Erik Tiekstra Date: Fri, 11 Apr 2025 15:13:37 +0000 Subject: [PATCH] feat(SW-2178): Changed to new buttons for summary inside enter details MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Approved-by: Michael Zetterberg Approved-by: Matilda Landström --- .../EnterDetails/Summary/UI/index.tsx | 22 +- .../HotelReservation/PriceDetailsModal.tsx | 13 +- .../RateSummary/MobileSummary/Summary.tsx | 24 +- packages/design-system/.storybook/preview.tsx | 14 +- .../lib/components/Button/Button.stories.tsx | 242 +++++++++++++++--- .../lib/components/Button/Button.tsx | 2 + .../lib/components/Button/button.module.css | 77 +++++- .../lib/components/Button/variants.ts | 6 +- .../ChipButton/ChipButton.stories.tsx | 6 +- .../Icons/MaterialIcon/MaterialIcon.tsx | 8 +- .../components/RateCard/Campaign/index.tsx | 8 +- .../lib/components/RateCard/Code/index.tsx | 10 +- .../RateCard/NoRateAvailable/index.tsx | 10 +- .../lib/components/RateCard/Points/index.tsx | 12 +- .../lib/components/RateCard/Regular/index.tsx | 10 +- 15 files changed, 363 insertions(+), 101 deletions(-) diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx index 9a53c0059..f6edbc33b 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx @@ -3,6 +3,7 @@ import { Fragment } from "react" import { useIntl } from "react-intl" +import { Button } from "@scandic-hotels/design-system/Button" import DiscountIcon from "@scandic-hotels/design-system/Icons/DiscountIcon" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" import { Typography } from "@scandic-hotels/design-system/Typography" @@ -12,7 +13,6 @@ import { dt } from "@/lib/dt" import PriceDetailsModal from "@/components/HotelReservation/PriceDetailsModal" import SignupPromoDesktop from "@/components/HotelReservation/SignupPromo/Desktop" import Modal from "@/components/Modal" -import Button from "@/components/TempDesignSystem/Button" import Divider from "@/components/TempDesignSystem/Divider" import IconChip from "@/components/TempDesignSystem/IconChip" import Body from "@/components/TempDesignSystem/Text/Body" @@ -109,10 +109,9 @@ export default function SummaryUI({ {dt(booking.toDate).locale(lang).format("ddd, D MMM")} ({nights}) } title={ diff --git a/apps/scandic-web/components/HotelReservation/PriceDetailsModal.tsx b/apps/scandic-web/components/HotelReservation/PriceDetailsModal.tsx index f5181062a..d3fcd79e3 100644 --- a/apps/scandic-web/components/HotelReservation/PriceDetailsModal.tsx +++ b/apps/scandic-web/components/HotelReservation/PriceDetailsModal.tsx @@ -1,11 +1,10 @@ "use client" import { useIntl } from "react-intl" +import { Button } from "@scandic-hotels/design-system/Button" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" import Modal from "@/components/Modal" -import Button from "@/components/TempDesignSystem/Button" -import Caption from "@/components/TempDesignSystem/Text/Caption" export default function PriceDetailsModal({ children, @@ -16,10 +15,12 @@ export default function PriceDetailsModal({ - - {intl.formatMessage({ id: "Price details" })} - + } diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Summary.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Summary.tsx index 03f1b8cb0..d4ba1fcf0 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Summary.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Summary.tsx @@ -2,6 +2,7 @@ import { Fragment } from "react" import { useIntl } from "react-intl" +import { Button } from "@scandic-hotels/design-system/Button" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" import { dt } from "@/lib/dt" @@ -9,7 +10,6 @@ import { dt } from "@/lib/dt" import PriceDetailsModal from "@/components/HotelReservation/PriceDetailsModal" import SignupPromoDesktop from "@/components/HotelReservation/SignupPromo/Desktop" import Modal from "@/components/Modal" -import Button from "@/components/TempDesignSystem/Button" import Divider from "@/components/TempDesignSystem/Divider" import Body from "@/components/TempDesignSystem/Text/Body" import Caption from "@/components/TempDesignSystem/Text/Caption" @@ -79,12 +79,7 @@ export default function Summary({ /> {dt(booking.toDate).locale(lang).format("ddd, D MMM")} ({nights}) - } title={room.cancellationText} diff --git a/packages/design-system/.storybook/preview.tsx b/packages/design-system/.storybook/preview.tsx index 1869fabcb..721f25f13 100644 --- a/packages/design-system/.storybook/preview.tsx +++ b/packages/design-system/.storybook/preview.tsx @@ -2,8 +2,8 @@ import { withThemeByClassName } from '@storybook/addon-themes' import type { Preview, ReactRenderer } from '@storybook/react' -import '../lib/style.css' import '../lib/fonts.css' +import '../lib/style.css' export const themes = { themes: { @@ -30,6 +30,18 @@ const preview: Preview = { order: ['Introduction', 'Global', 'Components', 'Compositions', '*'], }, }, + backgrounds: { + values: [ + // 👇 Scandic + { name: 'Scandic Primary', value: '#FAF6F2' }, + { name: 'Scandic Subtle', value: '#F2ECE6' }, + { name: 'Scandic Primary Dark', value: '#4D001B' }, + // 👇 Default values + { name: 'Storybook Dark', value: '#333' }, + { name: 'Storybook Light', value: '#F7F9F2' }, + ], + default: 'Scandic Primary', + }, }, tags: ['autodocs'], } diff --git a/packages/design-system/lib/components/Button/Button.stories.tsx b/packages/design-system/lib/components/Button/Button.stories.tsx index e0e44e2df..7311bb957 100644 --- a/packages/design-system/lib/components/Button/Button.stories.tsx +++ b/packages/design-system/lib/components/Button/Button.stories.tsx @@ -2,9 +2,10 @@ import type { Meta, StoryObj } from '@storybook/react' import { fn } from '@storybook/test' +import { MaterialIcon } from '../Icons/MaterialIcon' +import { config as typographyConfig } from '../Typography/variants' import { Button } from './Button' import { config as buttonConfig } from './variants' -import { config as typographyConfig } from '../Typography/variants' const meta: Meta = { title: 'Components/Button', @@ -22,6 +23,28 @@ const meta: Meta = { variant: { control: 'select', options: Object.keys(buttonConfig.variants.variant), + default: 'Primary', + }, + color: { + control: 'select', + options: Object.keys(buttonConfig.variants.color), + type: 'string', + description: + 'The color variant, only applies to the variants `Primary`, `Secondary` and `Text`. Defaults to `Primary`.', + }, + size: { + control: 'select', + options: Object.keys(buttonConfig.variants.size), + type: 'string', + description: + 'The size of the button. Defaults to `Large`. This variant does not apply to the `Icon` variant.', + }, + wrapping: { + control: 'radio', + options: Object.keys(buttonConfig.variants.wrapping), + type: 'boolean', + description: + 'Only applies to variant `Text`. If `true`, the button will keep the default padding set on the buttons. Defaults to `true`.', }, }, } @@ -67,6 +90,44 @@ export const PrimarySmall: Story = { }, } +export const PrimaryInvertedDefault: Story = { + args: { + onPress: fn(), + children: 'Primary inverted button', + typography: 'Body/Paragraph/mdBold', + variant: 'Primary', + color: 'Inverted', + }, +} + +export const PrimaryInvertedDisabled: Story = { + args: { + ...PrimaryInvertedDefault.args, + isDisabled: true, + }, +} + +export const PrimaryInvertedLarge: Story = { + args: { + ...PrimaryInvertedDefault.args, + size: 'Large', + }, +} + +export const PrimaryInvertedMedium: Story = { + args: { + ...PrimaryInvertedDefault.args, + size: 'Medium', + }, +} + +export const PrimaryInvertedSmall: Story = { + args: { + ...PrimaryInvertedDefault.args, + size: 'Small', + }, +} + export const SecondaryDefault: Story = { args: { onPress: fn(), @@ -104,6 +165,44 @@ export const SecondarySmall: Story = { }, } +export const SecondaryInvertedDefault: Story = { + args: { + onPress: fn(), + children: 'Secondary inverted button', + typography: 'Body/Paragraph/mdBold', + variant: 'Secondary', + color: 'Inverted', + }, +} + +export const SecondaryInvertedDisabled: Story = { + args: { + ...SecondaryInvertedDefault.args, + isDisabled: true, + }, +} + +export const SecondaryInvertedLarge: Story = { + args: { + ...SecondaryInvertedDefault.args, + size: 'Large', + }, +} + +export const SecondaryInvertedMedium: Story = { + args: { + ...SecondaryInvertedDefault.args, + size: 'Medium', + }, +} + +export const SecondaryInvertedSmall: Story = { + args: { + ...SecondaryInvertedDefault.args, + size: 'Small', + }, +} + export const TertiaryDefault: Story = { args: { onPress: fn(), @@ -141,43 +240,6 @@ export const TertiarySmall: Story = { }, } -export const InvertedDefault: Story = { - args: { - onPress: fn(), - children: 'Inverted button', - typography: 'Body/Paragraph/mdBold', - variant: 'Inverted', - }, -} - -export const InvertedDisabled: Story = { - args: { - ...InvertedDefault.args, - isDisabled: true, - }, -} - -export const InvertedLarge: Story = { - args: { - ...InvertedDefault.args, - size: 'Large', - }, -} - -export const InvertedMedium: Story = { - args: { - ...InvertedDefault.args, - size: 'Medium', - }, -} - -export const InvertedSmall: Story = { - args: { - ...InvertedDefault.args, - size: 'Small', - }, -} - export const TextDefault: Story = { args: { onPress: fn(), @@ -187,6 +249,13 @@ export const TextDefault: Story = { }, } +export const TextDisabled: Story = { + args: { + ...TextDefault.args, + isDisabled: true, + }, +} + export const TextLarge: Story = { args: { ...TextDefault.args, @@ -207,3 +276,100 @@ export const TextSmall: Story = { size: 'Small', }, } + +export const TextNoWrapping: Story = { + args: { + ...TextDefault.args, + children: 'Text button with wrapping false', + wrapping: false, + }, +} + +export const TextInvertedDefault: Story = { + args: { + onPress: fn(), + children: 'Text inverted button', + typography: 'Body/Paragraph/mdBold', + variant: 'Text', + color: 'Inverted', + }, +} + +export const TextInvertedDisabled: Story = { + args: { + ...TextInvertedDefault.args, + isDisabled: true, + }, +} + +export const TextInvertedLarge: Story = { + args: { + ...TextInvertedDefault.args, + size: 'Large', + }, +} + +export const TextInvertedMedium: Story = { + args: { + ...TextInvertedDefault.args, + size: 'Medium', + }, +} + +export const TextInvertedSmall: Story = { + args: { + ...TextInvertedDefault.args, + size: 'Small', + }, +} + +export const TextWithIcon: Story = { + args: { + onPress: fn(), + children: ( + <> + Text with icon + + + ), + typography: 'Body/Paragraph/mdBold', + variant: 'Text', + }, +} + +export const TextWithIconInverted: Story = { + args: { + onPress: fn(), + children: ( + <> + Text with icon + + + ), + typography: 'Body/Paragraph/mdBold', + variant: 'Text', + color: 'Inverted', + }, +} + +export const Icon: Story = { + args: { + onPress: fn(), + children: , + variant: 'Icon', + }, +} + +export const IconWithColor: Story = { + args: { + onPress: fn(), + children: ( + + ), + variant: 'Icon', + }, +} diff --git a/packages/design-system/lib/components/Button/Button.tsx b/packages/design-system/lib/components/Button/Button.tsx index d5c62d420..c5b7268c2 100644 --- a/packages/design-system/lib/components/Button/Button.tsx +++ b/packages/design-system/lib/components/Button/Button.tsx @@ -10,6 +10,7 @@ export function Button({ variant, color, size, + wrapping, typography, className, @@ -20,6 +21,7 @@ export function Button({ variant, color, size, + wrapping, typography, className, diff --git a/packages/design-system/lib/components/Button/button.module.css b/packages/design-system/lib/components/Button/button.module.css index d466eaae3..e6a39a091 100644 --- a/packages/design-system/lib/components/Button/button.module.css +++ b/packages/design-system/lib/components/Button/button.module.css @@ -6,6 +6,10 @@ display: flex; align-items: center; justify-content: center; + + &:disabled { + cursor: unset; + } } .size-large { @@ -38,6 +42,24 @@ color: var(--Component-Button-Brand-Primary-On-fill-Disabled); } +.variant-primary.color-inverted { + background-color: var(--Component-Button-Inverted-Fill-Default); + border-color: var(--Component-Button-Inverted-Border-Default); + color: var(--Component-Button-Inverted-On-fill-Default); +} + +.variant-primary.color-inverted:hover { + background-color: var(--Component-Button-Inverted-Fill-Hover); + border-color: var(--Component-Button-Inverted-Border-Hover); + color: var(--Component-Button-Inverted-On-fill-Hover); +} + +.variant-primary.color-inverted:disabled { + background-color: var(--Component-Button-Inverted-Fill-Disabled); + border-color: var(--Component-Button-Inverted-Border-Disabled); + color: var(--Component-Button-Inverted-On-fill-Disabled); +} + .variant-secondary { background-color: var(--Component-Button-Brand-Secondary-Fill-Default); border-color: var(--Component-Button-Brand-Secondary-Border-Default); @@ -56,6 +78,24 @@ color: var(--Component-Button-Brand-Secondary-On-fill-Disabled); } +.variant-secondary.color-inverted { + background-color: var(--Component-Button-Brand-Secondary-Fill-Default); + border-color: var(--Component-Button-Brand-Secondary-Border-Inverted); + color: var(--Component-Button-Brand-Secondary-On-fill-Inverted); +} + +.variant-secondary.color-inverted:hover { + background-color: var(--Component-Button-Brand-Secondary-Fill-Hover); + border-color: var(--Component-Button-Brand-Secondary-Border-Hover-inverted); + color: var(--Component-Button-Brand-Secondary-On-fill-Hover-inverted); +} + +.variant-secondary.color-inverted:disabled { + background-color: var(--Component-Button-Brand-Secondary-Fill-Disabled); + border-color: var(--Component-Button-Brand-Secondary-Border-Disabled); + color: var(--Component-Button-Brand-Secondary-On-fill-Disabled); +} + .variant-tertiary { background-color: var(--Component-Button-Brand-Tertiary-Fill-Default); border-color: var(--Component-Button-Brand-Tertiary-Border-Default); @@ -95,9 +135,36 @@ .variant-text { background-color: transparent; border-color: transparent; - /* TODO: Missing text variant tokens for button */ - color: var(--Scandic-Red-100); - padding: var(--Space-x15) 0; + color: var(--Component-Button-Brand-Secondary-On-fill-Default); + padding-left: 0; + padding-right: 0; +} + +.variant-text:hover { + color: var(--Component-Button-Brand-Secondary-On-fill-Hover); + text-decoration: underline; +} + +.variant-text:disabled { + color: var(--Component-Button-Brand-Secondary-On-fill-Disabled); + text-decoration: none; +} + +.variant-text.no-wrapping { + padding: var(--Space-x025) 0; + border-width: 0; +} + +.variant-text.color-inverted { + color: var(--Component-Button-Brand-Secondary-On-fill-Inverted); +} + +.variant-text.color-inverted:hover { + color: var(--Component-Button-Brand-Secondary-On-fill-Hover-inverted); +} + +.variant-text.color-inverted:disabled { + color: var(--Component-Button-Brand-Secondary-On-fill-Disabled); } .variant-icon { @@ -107,7 +174,3 @@ padding: 0; margin: 0; } - -.color-icon-default { - color: var(--Icon-Default); -} diff --git a/packages/design-system/lib/components/Button/variants.ts b/packages/design-system/lib/components/Button/variants.ts index 5d9bb0107..18dd4e6a4 100644 --- a/packages/design-system/lib/components/Button/variants.ts +++ b/packages/design-system/lib/components/Button/variants.ts @@ -21,18 +21,22 @@ export const config = { color: { Primary: styles['color-primary'], Inverted: styles['color-inverted'], - IconDefault: styles['color-icon-default'], }, size: { Small: styles['size-small'], Medium: styles['size-medium'], Large: styles['size-large'], }, + wrapping: { + true: undefined, + false: styles['no-wrapping'], + }, }, defaultVariants: { variant: 'Primary', color: 'Primary', size: 'Large', + wrapping: true, }, } as const diff --git a/packages/design-system/lib/components/ChipButton/ChipButton.stories.tsx b/packages/design-system/lib/components/ChipButton/ChipButton.stories.tsx index c83bc43cd..112942e5c 100644 --- a/packages/design-system/lib/components/ChipButton/ChipButton.stories.tsx +++ b/packages/design-system/lib/components/ChipButton/ChipButton.stories.tsx @@ -4,7 +4,7 @@ import type { Meta, StoryObj } from '@storybook/react' import { fn } from '@storybook/test' -import { MaterialSymbol } from 'react-material-symbols' +import { MaterialIcon } from '../Icons/MaterialIcon/MaterialIcon.tsx' import { ChipButton } from './ChipButton.tsx' import { config as chipButtonConfig } from './variants' @@ -35,7 +35,7 @@ export const Default: Story = { children: ( <> Button Chip - + ), }, @@ -48,7 +48,7 @@ export const Outlined: Story = { children: ( <> Button Chip - + ), }, diff --git a/packages/design-system/lib/components/Icons/MaterialIcon/MaterialIcon.tsx b/packages/design-system/lib/components/Icons/MaterialIcon/MaterialIcon.tsx index 838bc3e28..c744cf70d 100644 --- a/packages/design-system/lib/components/Icons/MaterialIcon/MaterialIcon.tsx +++ b/packages/design-system/lib/components/Icons/MaterialIcon/MaterialIcon.tsx @@ -15,6 +15,7 @@ export interface MaterialIconProps export type MaterialIconSetIconProps = Omit export function MaterialIcon({ color, + size = 24, className, isFilled = false, ...props @@ -23,7 +24,12 @@ export function MaterialIcon({ return ( // The span is used to prevent the MaterialSymbol from being underlined when used inside a link or button - + ) } diff --git a/packages/design-system/lib/components/RateCard/Campaign/index.tsx b/packages/design-system/lib/components/RateCard/Campaign/index.tsx index 0ddfb7228..5be4a0112 100644 --- a/packages/design-system/lib/components/RateCard/Campaign/index.tsx +++ b/packages/design-system/lib/components/RateCard/Campaign/index.tsx @@ -1,11 +1,11 @@ import { Typography } from '../../Typography' import { Rate, RateTermDetails } from '../types' -import styles from '../rate-card.module.css' import { Button } from '../../Button' -import { variants } from '../variants' import { MaterialIcon } from '../../Icons/MaterialIcon' import Modal from '../Modal' +import styles from '../rate-card.module.css' +import { variants } from '../variants' interface CampaignRateCardProps { name: string @@ -67,11 +67,11 @@ export default function CampaignRateCard({ title={rateTitle} subtitle={paymentTerm} trigger={ - } diff --git a/packages/design-system/lib/components/RateCard/Code/index.tsx b/packages/design-system/lib/components/RateCard/Code/index.tsx index 12c77885e..2aaa9f75c 100644 --- a/packages/design-system/lib/components/RateCard/Code/index.tsx +++ b/packages/design-system/lib/components/RateCard/Code/index.tsx @@ -1,11 +1,11 @@ import { Rate, RateTermDetails } from '../types' -import styles from '../rate-card.module.css' -import { Typography } from '../../Typography' import { Button } from '../../Button' -import { variants } from '../variants' import { MaterialIcon } from '../../Icons/MaterialIcon' +import { Typography } from '../../Typography' import Modal from '../Modal' +import styles from '../rate-card.module.css' +import { variants } from '../variants' interface CodeRateCardProps { name: string @@ -63,11 +63,11 @@ export default function CodeRateCard({ title={rateTitle} subtitle={paymentTerm} trigger={ - } diff --git a/packages/design-system/lib/components/RateCard/NoRateAvailable/index.tsx b/packages/design-system/lib/components/RateCard/NoRateAvailable/index.tsx index 3dddc5aac..d1822f9fb 100644 --- a/packages/design-system/lib/components/RateCard/NoRateAvailable/index.tsx +++ b/packages/design-system/lib/components/RateCard/NoRateAvailable/index.tsx @@ -1,8 +1,8 @@ -import styles from '../rate-card.module.css' -import { Typography } from '../../Typography' import { Button } from '../../Button' -import { variants } from '../variants' import { MaterialIcon } from '../../Icons/MaterialIcon' +import { Typography } from '../../Typography' +import styles from '../rate-card.module.css' +import { variants } from '../variants' interface NoRateAvailableCardProps { variant: 'Regular' | 'Campaign' | 'Code' | 'Points' @@ -34,8 +34,8 @@ export default function NoRateAvailableCard({

- {`${rateTitle} / ${paymentTerm}`}

diff --git a/packages/design-system/lib/components/RateCard/Points/index.tsx b/packages/design-system/lib/components/RateCard/Points/index.tsx index e7b5f200b..707ddbd1e 100644 --- a/packages/design-system/lib/components/RateCard/Points/index.tsx +++ b/packages/design-system/lib/components/RateCard/Points/index.tsx @@ -1,13 +1,13 @@ import { Typography } from '../../Typography' import { RatePointsOption, RateTermDetails } from '../types' -import styles from '../rate-card.module.css' -import { Button } from '../../Button' -import { Radio } from '../../Radio' import { RadioGroup } from 'react-aria-components' -import { variants } from '../variants' +import { Button } from '../../Button' import { MaterialIcon } from '../../Icons/MaterialIcon' +import { Radio } from '../../Radio' import Modal from '../Modal' +import styles from '../rate-card.module.css' +import { variants } from '../variants' interface PointsRateCardProps { rateTitle: string @@ -49,8 +49,8 @@ export default function PointsRateCard({ title={rateTitle} subtitle={paymentTerm} trigger={ - } > diff --git a/packages/design-system/lib/components/RateCard/Regular/index.tsx b/packages/design-system/lib/components/RateCard/Regular/index.tsx index cc4020a43..180194fb2 100644 --- a/packages/design-system/lib/components/RateCard/Regular/index.tsx +++ b/packages/design-system/lib/components/RateCard/Regular/index.tsx @@ -1,11 +1,11 @@ import { Rate, RateTermDetails } from '../types' -import styles from '../rate-card.module.css' -import { Typography } from '../../Typography' import { Button } from '../../Button' -import { variants } from '../variants' import { MaterialIcon } from '../../Icons/MaterialIcon' +import { Typography } from '../../Typography' import Modal from '../Modal' +import styles from '../rate-card.module.css' +import { variants } from '../variants' interface RegularRateCardProps { name: string @@ -56,11 +56,11 @@ export default function RegularRateCard({ title={rateTitle} subtitle={paymentTerm} trigger={ - }