Merged in feat/sw-3238-move-modal-to-design-system (pull request #2628)

feat(SW-3238): Move modal to design system

* Move Modal to design-system

* Remove temp modal from booking-flow


Approved-by: Joakim Jäderberg
This commit is contained in:
Anton Gunnarsson
2025-08-14 07:14:51 +00:00
parent dc483fe599
commit 04aebb372c
29 changed files with 72 additions and 573 deletions

View File

@@ -8,6 +8,7 @@ import Body from "@scandic-hotels/design-system/Body"
import Caption from "@scandic-hotels/design-system/Caption"
import Checkbox from "@scandic-hotels/design-system/Form/Checkbox"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import Modal from "@scandic-hotels/design-system/Modal"
import {
type ButtonProps,
OldDSButton as Button,
@@ -18,7 +19,6 @@ import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking"
import BookingFlowInput from "../../../../BookingFlowInput"
import { getErrorMessage } from "../../../../BookingFlowInput/errors"
import Modal from "../../../../TEMP/Modal"
import { Input as BookingWidgetInput } from "../Input"
import { isMultiRoomError } from "../utils"

View File

@@ -8,12 +8,12 @@ import { useMediaQuery } from "usehooks-ts"
import Caption from "@scandic-hotels/design-system/Caption"
import Checkbox from "@scandic-hotels/design-system/Form/Checkbox"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import Modal from "@scandic-hotels/design-system/Modal"
import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking"
import { getErrorMessage } from "../../../../BookingFlowInput/errors"
import Modal from "../../../../TEMP/Modal"
import { RemoveExtraRooms } from "../BookingCode"
import { isMultiRoomError } from "../utils"

View File

@@ -1,23 +0,0 @@
export const fade = {
hidden: {
opacity: 0,
transition: { duration: 0.4, ease: "easeInOut" },
},
visible: {
opacity: 1,
transition: { duration: 0.4, ease: "easeInOut" },
},
}
export const slideInOut = {
hidden: {
opacity: 0,
y: 32,
transition: { duration: 0.4, ease: "easeInOut" },
},
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.4, ease: "easeInOut" },
},
}

View File

@@ -1,10 +1,10 @@
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton"
import Subtitle from "@scandic-hotels/design-system/Subtitle"
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { OldDSButton as Button } from '../../OldDSButton'
import Subtitle from '../../Subtitle'
import styles from "./modalContent.module.css"
import styles from './modalContent.module.css'
import type { ReactNode } from "react"
import type { ReactNode } from 'react'
interface ModalContentProps {
title?: string
@@ -12,14 +12,14 @@ interface ModalContentProps {
primaryAction: {
label: string
onClick: () => void
intent?: "primary" | "secondary" | "text"
intent?: 'primary' | 'secondary' | 'text'
isLoading?: boolean
disabled?: boolean
} | null
secondaryAction: {
label: string
onClick: () => void
intent?: "primary" | "secondary" | "text"
intent?: 'primary' | 'secondary' | 'text'
} | null
onClose?: () => void
}
@@ -46,7 +46,7 @@ export function ModalContentWithActions({
{secondaryAction && (
<Button
theme="base"
intent={secondaryAction.intent ?? "text"}
intent={secondaryAction.intent ?? 'text'}
color="burgundy"
onClick={secondaryAction.onClick}
>
@@ -56,7 +56,7 @@ export function ModalContentWithActions({
{primaryAction && (
<Button
theme="base"
intent={primaryAction.intent ?? "secondary"}
intent={primaryAction.intent ?? 'secondary'}
onClick={primaryAction.onClick}
disabled={primaryAction.isLoading || primaryAction.disabled}
>

View File

@@ -1,32 +1,30 @@
"use client"
'use client'
// TODO this is duplicated from scandic-web
import { cx } from "class-variance-authority"
import { AnimatePresence, motion } from "motion/react"
import { type PropsWithChildren, useEffect, useState } from "react"
import { cx } from 'class-variance-authority'
import { AnimatePresence, motion } from 'motion/react'
import { type PropsWithChildren, useEffect, useState } from 'react'
import {
Dialog,
DialogTrigger,
Modal as AriaModal,
ModalOverlay,
} from "react-aria-components"
import { useIntl } from "react-intl"
} from 'react-aria-components'
import { useIntl } from 'react-intl'
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import Preamble from "@scandic-hotels/design-system/Preamble"
import Subtitle from "@scandic-hotels/design-system/Subtitle"
import { MaterialIcon } from '../Icons/MaterialIcon'
import Preamble from '../Preamble'
import Subtitle from '../Subtitle'
import {
type AnimationState,
AnimationStateEnum,
type InnerModalProps,
type ModalProps,
} from "./modal"
import { fade, slideInOut } from "./motionVariants"
import { modalContentVariants } from "./variants"
} from './modal'
import { fade, slideInOut } from './motionVariants'
import { modalContentVariants } from './variants'
import styles from "./modal.module.css"
import styles from './modal.module.css'
const MotionOverlay = motion.create(ModalOverlay)
const MotionModal = motion.create(AriaModal)
@@ -91,14 +89,14 @@ function InnerModal({
<Dialog
className={styles.dialog}
aria-label={intl.formatMessage({
defaultMessage: "Dialog",
defaultMessage: 'Dialog',
})}
>
{({ close }) => (
<>
{!hideHeader && (
<header
className={`${styles.header} ${!subtitle ? styles.verticalCenter : ""}`}
className={`${styles.header} ${!subtitle ? styles.verticalCenter : ''}`}
>
<div>
{title && (
@@ -143,14 +141,14 @@ export default function Modal({
children,
withActions = false,
hideHeader = false,
className = "",
className = '',
}: PropsWithChildren<ModalProps>) {
const [animation, setAnimation] = useState<AnimationState>(
AnimationStateEnum.visible
)
useEffect(() => {
if (typeof isOpen === "boolean") {
if (typeof isOpen === 'boolean') {
setAnimation(
isOpen ? AnimationStateEnum.visible : AnimationStateEnum.hidden
)

View File

@@ -1,9 +1,9 @@
import type { Dispatch, JSX, SetStateAction } from "react"
import type { Dispatch, JSX, SetStateAction } from 'react'
export enum AnimationStateEnum {
unmounted = "unmounted",
hidden = "hidden",
visible = "visible",
unmounted = 'unmounted',
hidden = 'hidden',
visible = 'visible',
}
export type AnimationState = keyof typeof AnimationStateEnum
@@ -30,7 +30,7 @@ export type ModalProps = {
}
)
export type InnerModalProps = Omit<ModalProps, "trigger"> & {
export type InnerModalProps = Omit<ModalProps, 'trigger'> & {
animation: AnimationState
setAnimation: Dispatch<SetStateAction<AnimationState>>
}

View File

@@ -0,0 +1,23 @@
export const fade = {
hidden: {
opacity: 0,
transition: { duration: 0.4, ease: 'easeInOut' },
},
visible: {
opacity: 1,
transition: { duration: 0.4, ease: 'easeInOut' },
},
}
export const slideInOut = {
hidden: {
opacity: 0,
y: 32,
transition: { duration: 0.4, ease: 'easeInOut' },
},
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.4, ease: 'easeInOut' },
},
}

View File

@@ -1,6 +1,6 @@
import { cva } from "class-variance-authority"
import { cva } from 'class-variance-authority'
import styles from "./modal.module.css"
import styles from './modal.module.css'
const config = {
variants: {

View File

@@ -33,6 +33,8 @@
"./Label": "./lib/components/Label/index.tsx",
"./Lightbox": "./lib/components/Lightbox/index.tsx",
"./Link": "./lib/components/Link/index.tsx",
"./Modal": "./lib/components/Modal/index.tsx",
"./Modal/ModalContentWithActions": "./lib/components/Modal/ModalContentWithActions/index.tsx",
"./OldDSButton": "./lib/components/OldDSButton/index.tsx",
"./OpeningHours": "./lib/components/OpeningHours/index.tsx",
"./Select": "./lib/components/Select/index.tsx",