From ebd6e1dc2c3cd92c662f5e8d7e3f1baa21da1f75 Mon Sep 17 00:00:00 2001 From: Bianca Widstam Date: Thu, 20 Nov 2025 13:28:21 +0000 Subject: [PATCH] Merged in fix/BOOK-119-accessibility-redemption-radiogroup (pull request #3172) fix(BOOK-119): reward nights accessible radiogroup * fix(BOOK-119): reward nights accessible radiogroup * fix(BOOK-119): pr comment focus * fix(BOOK-119): added roomtype name to the radiogroup for accessibility improvment Approved-by: Matilda Haneling Approved-by: Erik Tiekstra --- .../RoomsList/RoomListItem/Details/index.tsx | 5 ++-- .../RoomsList/RoomListItem/Rates/Campaign.tsx | 1 + .../RoomsList/RoomListItem/Rates/Code.tsx | 3 +++ .../RoomListItem/Rates/Redemptions.tsx | 3 +++ .../RoomsList/RoomListItem/Rates/Regular.tsx | 1 + .../Rooms/RoomsList/RoomListItem/index.tsx | 2 +- .../lib/components/Radio/Radio.tsx | 3 ++- .../lib/components/Radio/radio.module.css | 5 ++++ .../components/RateCard/Campaign/index.tsx | 6 +++-- .../lib/components/RateCard/Code/index.tsx | 6 +++-- .../lib/components/RateCard/Points/index.tsx | 23 ++++++++++++++++--- .../lib/components/RateCard/Regular/index.tsx | 6 +++-- 12 files changed, 51 insertions(+), 13 deletions(-) diff --git a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Details/index.tsx b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Details/index.tsx index 4909236f2..fb0c1a186 100644 --- a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Details/index.tsx +++ b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Details/index.tsx @@ -11,9 +11,10 @@ import type { RoomInfo } from "../../../../../../../contexts/SelectRate/types" type Props = { roomInfo: RoomInfo + roomTypeCode: string } -export default function Details({ roomInfo }: Props) { +export default function Details({ roomInfo, roomTypeCode }: Props) { const intl = useIntl() const { name, occupancy, roomSize } = roomInfo || {} @@ -50,7 +51,7 @@ export default function Details({ roomInfo }: Props) {
-

{name}

+

{name}

diff --git a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Campaign.tsx b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Campaign.tsx index a8390ea69..b644439de 100644 --- a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Campaign.tsx +++ b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Campaign.tsx @@ -227,6 +227,7 @@ function Inner({ key={product.rate} approximateRate={approximateRate} bannerText={bannerText} + roomTypeCode={roomTypeCode} handleChange={() => selectRate({ roomIndex, diff --git a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Code.tsx b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Code.tsx index 14fc85bb3..262410ba7 100644 --- a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Code.tsx +++ b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Code.tsx @@ -221,6 +221,7 @@ function CorporateChequeCode({ handleChange={() => handleSelectRate(codeProduct.corporateCheque.rateCode) } + roomTypeCode={roomTypeCode} isSelected={isSelected} id={`${roomNr}-${roomTypeCode}-${rateCode}`.replace(/\s+/g, "-")} paymentTerm={rateTitles[codeProduct.rate].paymentTerm} @@ -314,6 +315,7 @@ function PublicCode({ approximateRate={approximateRate} bannerText={bannerText} comparisonRate={comparisonRate} + roomTypeCode={roomTypeCode} handleChange={() => handleSelectRate(codeProduct.public!.rateCode)} isSelected={isSelected} id={`${roomNr}-${roomTypeCode}-${rateCode}`.replace(/\s+/g, "-")} @@ -379,6 +381,7 @@ function VoucherCode({ bannerText={bannerText} handleChange={() => handleSelectRate(codeProduct.voucher.rateCode)} isSelected={isSelected} + roomTypeCode={roomTypeCode} id={`${roomNr}-${roomTypeCode}-${rateCode}`.replace(/\s+/g, "-")} paymentTerm={rateTitles[codeProduct.rate].paymentTerm} rate={{ diff --git a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Redemptions.tsx b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Redemptions.tsx index 447e0c31c..6770a0207 100644 --- a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Redemptions.tsx +++ b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Redemptions.tsx @@ -34,6 +34,7 @@ export default function Redemptions({ actions: { selectRate }, selectedRates, } = useSelectRateContext() + const roomNr = roomIndex + 1 const pointsCurrency = useGetPointsCurrency() // TODO: Replace with context value when we have support for dropdown "Show all rates" @@ -125,10 +126,12 @@ export default function Redemptions({ }} paymentTerm={rateTitles[firstRedemption.rate].paymentTerm} rates={rates} + id={`${roomNr}-${roomTypeCode}`.replace(/\s+/g, "-")} rateTitle={rateTitles[firstRedemption.rate].title} rateTermDetails={rateTermDetails} selectedRate={selectedRateCode} isNotEnoughPoints={notEnoughPoints} + roomTypeCode={roomTypeCode} notEnoughPointsText={intl.formatMessage({ id: "booking.notEnoughPoints", defaultMessage: "Not enough points", diff --git a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Regular.tsx b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Regular.tsx index 18fd169fd..f42b9ad46 100644 --- a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Regular.tsx +++ b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Regular.tsx @@ -250,6 +250,7 @@ function Inner({ }} isMemberRateActive={isMemberRateActive} isSelected={isSelected} + roomTypeCode={roomTypeCode} id={`${roomNr}-${roomTypeCode}-${rateCode}`.replace(/\s+/g, "-")} paymentTerm={rateTitles[product.rate].paymentTerm} rateTitle={rateTitles[product.rate].title} diff --git a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/index.tsx b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/index.tsx index 617664be9..8ac7d8e29 100644 --- a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/index.tsx +++ b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/index.tsx @@ -47,7 +47,7 @@ export function RoomListItem({ images={room.roomInfo.images ?? []} hotelId={hotelId} /> -
+
{room.status === AvailabilityEnum.NotAvailable ? ( diff --git a/packages/design-system/lib/components/Radio/Radio.tsx b/packages/design-system/lib/components/Radio/Radio.tsx index b22e481b9..f3907f581 100644 --- a/packages/design-system/lib/components/Radio/Radio.tsx +++ b/packages/design-system/lib/components/Radio/Radio.tsx @@ -2,6 +2,7 @@ import { PropsWithChildren } from 'react' import { Radio as AriaRadio } from 'react-aria-components' import styles from './radio.module.css' import { variants } from './variants' +import { cx } from 'class-variance-authority' interface RadioProps extends PropsWithChildren { value: string @@ -22,7 +23,7 @@ export function Radio({ id, value, children, color, isDisabled }: RadioProps) { id={inputId} value={value} isDisabled={isDisabled} - className={`${styles.container} ${isDisabled ? styles.disabled : ''}`} + className={cx(styles.container, { [styles.disabled]: isDisabled })} >
{children}
diff --git a/packages/design-system/lib/components/Radio/radio.module.css b/packages/design-system/lib/components/Radio/radio.module.css index 310a5c68e..dcf5e4627 100644 --- a/packages/design-system/lib/components/Radio/radio.module.css +++ b/packages/design-system/lib/components/Radio/radio.module.css @@ -22,6 +22,11 @@ border-width: 8px; } +.container[data-focus-visible] .radio { + outline: 2px solid var(--UI-Input-Controls-Border-Focus); + outline-offset: 2px; +} + .disabled { opacity: 0.5; cursor: not-allowed; diff --git a/packages/design-system/lib/components/RateCard/Campaign/index.tsx b/packages/design-system/lib/components/RateCard/Campaign/index.tsx index bf4d3d5a1..de7b47426 100644 --- a/packages/design-system/lib/components/RateCard/Campaign/index.tsx +++ b/packages/design-system/lib/components/RateCard/Campaign/index.tsx @@ -24,6 +24,7 @@ interface CampaignRateCardProps { isHighlightedRate?: boolean isHighlightedRateLabel?: boolean approximateRate?: Rate + roomTypeCode: string handleChange: () => void handleTermsClick?: () => void rateTermDetails: RateTermDetails[] @@ -35,6 +36,7 @@ export default function CampaignRateCard({ rateTitle, paymentTerm, rate, + roomTypeCode, memberRate, approximateRate, comparisonRate, @@ -60,8 +62,8 @@ export default function CampaignRateCard({ onPress={handleChange} className={styles.buttonOverlay} aria-pressed={isSelected} - aria-labelledby={`${id}-title`} - aria-describedby={`${id}-details`} + aria-describedby={`${roomTypeCode} ${id}-title`} + aria-labelledby={`${id}-details`} />
diff --git a/packages/design-system/lib/components/RateCard/Code/index.tsx b/packages/design-system/lib/components/RateCard/Code/index.tsx index 4cb8f1799..6ed9dce04 100644 --- a/packages/design-system/lib/components/RateCard/Code/index.tsx +++ b/packages/design-system/lib/components/RateCard/Code/index.tsx @@ -19,6 +19,7 @@ interface CodeRateCardProps { bannerText: string comparisonRate?: Omit approximateRate?: Rate + roomTypeCode: string isHighlightedRate?: boolean handleChange: () => void handleTermsClick?: () => void @@ -31,6 +32,7 @@ export default function CodeRateCard({ rateTitle, paymentTerm, rate, + roomTypeCode, approximateRate, comparisonRate, bannerText, @@ -53,8 +55,8 @@ export default function CodeRateCard({ onPress={handleChange} className={styles.buttonOverlay} aria-pressed={isSelected} - aria-labelledby={`${id}-title`} - aria-describedby={`${id}-details`} + aria-describedby={`${roomTypeCode} ${id}-title`} + aria-labelledby={`${id}-details`} />

{bannerText}

diff --git a/packages/design-system/lib/components/RateCard/Points/index.tsx b/packages/design-system/lib/components/RateCard/Points/index.tsx index 3837a370f..33d06ded1 100644 --- a/packages/design-system/lib/components/RateCard/Points/index.tsx +++ b/packages/design-system/lib/components/RateCard/Points/index.tsx @@ -8,6 +8,7 @@ import { Radio } from '../../Radio' import Modal from '../Modal' import styles from '../rate-card.module.css' import { variants } from '../variants' +import { useIntl } from 'react-intl' interface PointsRateCardProps { rateTitle: string @@ -19,22 +20,27 @@ interface PointsRateCardProps { isNotEnoughPoints?: boolean notEnoughPointsText?: string rateTermDetails: RateTermDetails[] + id: string + roomTypeCode: string } export default function PointsRateCard({ rateTitle, paymentTerm, bannerText, + id, rates, selectedRate, isNotEnoughPoints, notEnoughPointsText, onRateSelect, + roomTypeCode, rateTermDetails, }: PointsRateCardProps) { const classNames = variants({ variant: 'Points', }) + const intl = useIntl() return (
@@ -49,7 +55,15 @@ export default function PointsRateCard({ title={rateTitle} subtitle={paymentTerm} trigger={ - + } @@ -85,8 +99,10 @@ export default function PointsRateCard({
{rates.map((rate, index) => ( @@ -94,6 +110,7 @@ export default function PointsRateCard({
diff --git a/packages/design-system/lib/components/RateCard/Regular/index.tsx b/packages/design-system/lib/components/RateCard/Regular/index.tsx index ac2749942..e1ab78eb4 100644 --- a/packages/design-system/lib/components/RateCard/Regular/index.tsx +++ b/packages/design-system/lib/components/RateCard/Regular/index.tsx @@ -21,6 +21,7 @@ interface RegularRateCardProps { approximateRate?: Rate isMemberRateActive?: boolean handleChange: () => void + roomTypeCode: string rateTermDetails: RateTermDetails[] } @@ -32,6 +33,7 @@ export default function RegularRateCard({ approximateRate, omnibusRate, rate, + roomTypeCode, memberRate, isMemberRateActive, handleChange, @@ -51,8 +53,8 @@ export default function RegularRateCard({ onPress={handleChange} className={styles.buttonOverlay} aria-pressed={isSelected} - aria-labelledby={`${id}-title`} - aria-describedby={`${id}-details`} + aria-describedby={`${roomTypeCode} ${id}-title`} + aria-labelledby={`${id}-details`} />