fix(BOOK-711): Added isFloating prop to decide when the booking widget should have a border radius

Approved-by: Bianca Widstam
This commit is contained in:
Erik Tiekstra
2026-01-28 12:02:42 +00:00
parent 70838060e5
commit ead34c07ee
9 changed files with 74 additions and 45 deletions

View File

@@ -1,3 +1,8 @@
.formContent {
display: flex;
flex-direction: column;
}
.vouchersHeader {
display: flex;
gap: var(--Space-x15);
@@ -100,25 +105,25 @@
height: fit-content;
}
.input {
display: flex;
flex-direction: column;
@media screen and (min-width: 768px) and (max-width: 1366px) {
.formContent.floating .voucherContainer {
border-bottom-left-radius: var(--Corner-Radius-lg);
border-bottom-right-radius: var(--Corner-Radius-lg);
}
}
@media screen and (min-width: 768px) {
.input {
.formContent {
display: flex;
align-items: center;
flex-direction: row;
}
.inputContainer {
display: flex;
flex: 2;
gap: var(--Space-x15);
}
.voucherContainer {
border-radius: 0 0 var(--Corner-Radius-md) var(--Corner-Radius-md);
}
.rooms,
.when,
@@ -154,7 +159,7 @@
}
@media screen and (min-width: 768px) and (max-width: 1366px) {
.input {
.formContent {
flex-wrap: wrap;
}
.inputRow {
@@ -197,8 +202,8 @@
.inputContainer {
margin-left: calc(-1 * var(--Space-x15));
}
.input {
gap: var(--Space-x15);
.formContent {
gap: var(--Space-x2);
}
.inputRow {
flex: 1;

View File

@@ -31,11 +31,13 @@ type BookingWidgetFormContentProps = {
formId: string
onSubmit: () => void
isSearching: boolean
isFloating: boolean
}
export default function FormContent({
formId,
onSubmit,
isSearching,
isFloating,
}: BookingWidgetFormContentProps) {
const intl = useIntl()
const {
@@ -61,7 +63,7 @@ export default function FormContent({
const nights = dt(selectedDate.toDate).diff(dt(selectedDate.fromDate), "days")
return (
<div className={styles.input}>
<div className={cx(styles.formContent, { [styles.floating]: isFloating })}>
<div className={styles.inputRow}>
<div className={styles.inputContainer}>
<div className={styles.where}>
@@ -170,7 +172,7 @@ export function BookingWidgetFormContentSkeleton() {
const intl = useIntl()
return (
<div className={styles.input}>
<div className={styles.formContent}>
<div className={styles.inputRow}>
<div className={styles.inputContainer}>
<div className={styles.where}>

View File

@@ -32,9 +32,14 @@ const formId = "booking-widget"
type BookingWidgetFormProps = {
type?: BookingWidgetType
isFloating: boolean
onClose: () => void
}
export default function Form({ type, onClose }: BookingWidgetFormProps) {
export default function Form({
type,
isFloating,
onClose,
}: BookingWidgetFormProps) {
const router = useRouter()
const pathname = usePathname()
const lang = useLang()
@@ -106,6 +111,7 @@ export default function Form({ type, onClose }: BookingWidgetFormProps) {
formId={formId}
onSubmit={handleSubmit(onSubmit)}
isSearching={isPending}
isFloating={isFloating}
/>
</FormRAC>
</section>

View File

@@ -1,6 +1,7 @@
"use client"
import { zodResolver } from "@hookform/resolvers/zod"
import { cx } from "class-variance-authority"
import { useSearchParams } from "next/navigation"
import { use, useEffect, useRef, useState } from "react"
import { FormProvider, useForm } from "react-hook-form"
@@ -43,6 +44,7 @@ export type BookingWidgetClientProps = {
type?: BookingWidgetType
data: BookingWidgetSearchData
pageSettingsBookingCodePromise: Promise<string> | null
isFloating?: boolean
}
export const FOCUS_WIDGET = "focusWidget"
@@ -50,6 +52,7 @@ export default function BookingWidgetClient({
type,
data,
pageSettingsBookingCodePromise,
isFloating = false,
}: BookingWidgetClientProps) {
const searchParams = useSearchParams()
const focusWidget = searchParams.get(FOCUS_WIDGET) === "true"
@@ -245,10 +248,13 @@ export default function BookingWidgetClient({
<FormProvider {...methods}>
<section
ref={bookingWidgetRef}
className={classNames}
className={cx(classNames, { [styles.floating]: isFloating })}
data-booking-widget-open={isOpen}
>
<MobileToggleButton openMobileSearch={openMobileSearch} />
<MobileToggleButton
openMobileSearch={openMobileSearch}
isFloating={isFloating}
/>
<div className={styles.backdrop} onClick={closeMobileSearch} />
<div className={formContainerClassNames}>
<button
@@ -258,7 +264,11 @@ export default function BookingWidgetClient({
>
<MaterialIcon icon="close" />
</button>
<Form type={type} onClose={closeMobileSearch} />
<Form
type={type}
onClose={closeMobileSearch}
isFloating={isFloating}
/>
</div>
</section>
</FormProvider>

View File

@@ -56,7 +56,11 @@ export function FloatingBookingWidgetClient(props: Props) {
ref={containerRef}
>
<div className={styles.floatingBackground}>
<BookingWidgetClient {...props} type="compact" />
<BookingWidgetClient
{...props}
type="compact"
isFloating={!stickyTop}
/>
</div>
</div>
)

View File

@@ -14,7 +14,10 @@
/* To avoid this "flash" the styling is set to transparent) */
/* It is a non-standard css proprty, so shouldn't have too much of an effect on accessibility. */
-webkit-tap-highlight-color: transparent;
&.floating {
border-radius: var(--Corner-Radius-md);
}
}
.complete {

View File

@@ -20,9 +20,11 @@ import type { BookingWidgetSchema } from "../Client"
type BookingWidgetToggleButtonProps = {
openMobileSearch: () => void
isFloating: boolean
}
export default function MobileToggleButton({
openMobileSearch,
isFloating,
}: BookingWidgetToggleButtonProps) {
const intl = useIntl()
const lang = useLang()
@@ -99,7 +101,8 @@ export default function MobileToggleButton({
<Button
className={cx(
styles.mobileToggleButton,
locationAndDateIsSet ? styles.complete : styles.partial
locationAndDateIsSet ? styles.complete : styles.partial,
{ [styles.floating]: isFloating }
)}
onPress={openMobileSearch}
>

View File

@@ -1,4 +1,4 @@
.wrapper {
.bookingWidgetContainer {
position: sticky;
z-index: var(--booking-widget-z-index);
width: 100%;
@@ -14,7 +14,9 @@
z-index: 1;
transform: translateY(0);
visibility: visible;
border-radius: var(--Corner-Radius-lg);
}
@media screen and (max-width: 767px) {
.backdrop {
position: fixed;
@@ -30,13 +32,16 @@
&:has([data-rooms-open="true"]) {
z-index: var(--booking-widget-open-z-index);
}
&.floating .formContainer {
border-radius: var(--Corner-Radius-lg);
}
}
.formContainer {
display: grid;
grid-template-rows: auto 1fr;
background-color: var(--UI-Input-Controls-Surface-Normal);
border-radius: 0;
gap: var(--Space-x3);
height: calc(100dvh - max(var(--sitewide-alert-sticky-height), 20px));
width: 100%;
@@ -53,18 +58,6 @@
}
}
.compact {
.formContainer {
border-radius: var(--Corner-Radius-lg);
}
}
@media screen and (max-width: 767px) {
.formContainer {
border-radius: var(--Corner-Radius-lg) var(--Corner-Radius-lg) 0 0;
}
}
.close {
background: none;
border: none;
@@ -74,7 +67,7 @@
}
@media screen and (min-width: 768px) {
.wrapper {
.bookingWidgetContainer {
top: 0;
}

View File

@@ -2,7 +2,9 @@ import { cva } from "class-variance-authority"
import styles from "./bookingWidget.module.css"
export const bookingWidgetContainerVariants = cva(styles.wrapper, {
export const bookingWidgetContainerVariants = cva(
styles.bookingWidgetContainer,
{
variants: {
type: {
default: "",
@@ -13,7 +15,8 @@ export const bookingWidgetContainerVariants = cva(styles.wrapper, {
defaultVariants: {
type: "full",
},
})
}
)
export const formContainerVariants = cva(styles.formContainer, {
variants: {