& {
focalPoint?: FocalPoint
dimensions?: { width: number; height: number }
+ src: NextImageProps['src'] | undefined
}
// Next/Image adds & instead of ? before the params
diff --git a/packages/design-system/lib/components/Radio/Radio.tsx b/packages/design-system/lib/components/Radio/Radio.tsx
index f3907f581..4483769b0 100644
--- a/packages/design-system/lib/components/Radio/Radio.tsx
+++ b/packages/design-system/lib/components/Radio/Radio.tsx
@@ -9,9 +9,17 @@ interface RadioProps extends PropsWithChildren {
id?: string
isDisabled?: boolean
color?: 'Burgundy'
+ wrapping?: boolean
}
-export function Radio({ id, value, children, color, isDisabled }: RadioProps) {
+export function Radio({
+ id,
+ value,
+ children,
+ color,
+ isDisabled,
+ wrapping = true,
+}: RadioProps) {
const inputId = id || `radio-${value}`
const classNames = variants({
@@ -23,10 +31,13 @@ export function Radio({ id, value, children, color, isDisabled }: RadioProps) {
id={inputId}
value={value}
isDisabled={isDisabled}
- className={cx(styles.container, { [styles.disabled]: isDisabled })}
+ className={cx(styles.container, {
+ [styles.disabled]: isDisabled,
+ [styles.wrapping]: wrapping,
+ })}
>
- {children}
+ {children && {children}
}
)
}
diff --git a/packages/design-system/lib/components/Radio/radio.module.css b/packages/design-system/lib/components/Radio/radio.module.css
index dcf5e4627..f77ef329d 100644
--- a/packages/design-system/lib/components/Radio/radio.module.css
+++ b/packages/design-system/lib/components/Radio/radio.module.css
@@ -2,10 +2,14 @@
display: flex;
align-items: center;
gap: var(--Space-x15);
- padding: var(--Space-x1) 0;
+
cursor: pointer;
}
+.wrapping {
+ padding: var(--Space-x1) 0;
+}
+
.radio {
position: relative;
width: 24px;
diff --git a/packages/design-system/lib/components/Stepper/index.tsx b/packages/design-system/lib/components/Stepper/index.tsx
new file mode 100644
index 000000000..72972df18
--- /dev/null
+++ b/packages/design-system/lib/components/Stepper/index.tsx
@@ -0,0 +1,58 @@
+import { IconButton } from '../IconButton'
+import { MaterialIcon } from '../Icons/MaterialIcon'
+import { Tooltip } from '../Tooltip'
+import { Typography } from '../Typography'
+
+import styles from './stepper.module.css'
+
+type StepperProps = {
+ count: number
+ handleOnIncrease: () => void
+ handleOnDecrease: () => void
+ disableIncrease: boolean
+ disableDecrease: boolean
+ disabledMessage?: string
+}
+
+export default function Stepper({
+ count,
+ handleOnIncrease,
+ handleOnDecrease,
+ disableIncrease,
+ disableDecrease,
+ disabledMessage,
+}: StepperProps) {
+ return (
+
+ )
+}
diff --git a/packages/booking-flow/lib/components/BookingWidget/GuestsRoomsPicker/Counter/counter.module.css b/packages/design-system/lib/components/Stepper/stepper.module.css
similarity index 76%
rename from packages/booking-flow/lib/components/BookingWidget/GuestsRoomsPicker/Counter/counter.module.css
rename to packages/design-system/lib/components/Stepper/stepper.module.css
index 61ebe9241..a7cfce34d 100644
--- a/packages/booking-flow/lib/components/BookingWidget/GuestsRoomsPicker/Counter/counter.module.css
+++ b/packages/design-system/lib/components/Stepper/stepper.module.css
@@ -2,7 +2,7 @@
display: flex;
justify-content: flex-end;
align-items: center;
- gap: 20px;
+ gap: var(--Space-x1);
color: var(--Text-Interactive-Default);
}
.counterBtn {
@@ -12,3 +12,8 @@
.counterBtn:not([disabled]) {
box-shadow: 0px 0px 8px 1px rgba(0, 0, 0, 0.1);
}
+
+.countDisplay {
+ width: 20px;
+ text-align: center;
+}
diff --git a/packages/design-system/lib/components/Tooltip/index.tsx b/packages/design-system/lib/components/Tooltip/index.tsx
index 5c355bbd8..e4590ddf8 100644
--- a/packages/design-system/lib/components/Tooltip/index.tsx
+++ b/packages/design-system/lib/components/Tooltip/index.tsx
@@ -43,6 +43,9 @@ export function Tooltip({
function handleToggle() {
setIsActive((prevState) => !prevState)
+ setTimeout(() => {
+ setIsActive(false)
+ }, 3000)
}
function handleKeyDown(event: React.KeyboardEvent) {
diff --git a/packages/design-system/lib/components/Tooltip/tooltip.module.css b/packages/design-system/lib/components/Tooltip/tooltip.module.css
index 0b9944697..28add9c62 100644
--- a/packages/design-system/lib/components/Tooltip/tooltip.module.css
+++ b/packages/design-system/lib/components/Tooltip/tooltip.module.css
@@ -44,6 +44,10 @@
right: 0;
}
+.top.arrowRight {
+ right: 0;
+}
+
.tooltip::before {
content: '';
position: absolute;
diff --git a/packages/design-system/lib/fonts.css b/packages/design-system/lib/fonts.css
index 7fe73148e..eeb8db8c1 100644
--- a/packages/design-system/lib/fonts.css
+++ b/packages/design-system/lib/fonts.css
@@ -276,7 +276,7 @@
font-style: normal;
font-weight: 400;
font-display: block;
- src: url(/_static/shared/fonts/material-symbols/rounded-b1df8938.woff2)
+ src: url(/_static/shared/fonts/material-symbols/rounded-3e10d67b.woff2)
format('woff2');
}
diff --git a/packages/design-system/package.json b/packages/design-system/package.json
index 4519e16ad..7c1afc4f5 100644
--- a/packages/design-system/package.json
+++ b/packages/design-system/package.json
@@ -165,6 +165,7 @@
"./Payment/PaymentMethodIcon": "./lib/components/Payment/PaymentMethodIcon.tsx",
"./PointsRateCard": "./lib/components/RateCard/Points/index.tsx",
"./Progress": "./lib/components/Progress/index.tsx",
+ "./Radio": "./lib/components/Radio/index.tsx",
"./RegularRateCard": "./lib/components/RateCard/Regular/index.tsx",
"./Select": "./lib/components/Select/index.tsx",
"./SidePeek": "./lib/components/SidePeek/index.tsx",
@@ -172,6 +173,7 @@
"./SidePeekSelfControlled": "./lib/components/SidePeek/SelfControlled.tsx",
"./SkeletonShimmer": "./lib/components/SkeletonShimmer/index.tsx",
"./StaticMap": "./lib/components/StaticMap/index.tsx",
+ "./Stepper": "./lib/components/Stepper/index.tsx",
"./Subtitle": "./lib/components/Subtitle/index.tsx",
"./Switch": "./lib/components/Switch/index.tsx",
"./Table": "./lib/components/Table/index.tsx",
diff --git a/packages/trpc/lib/routers/hotels/output.ts b/packages/trpc/lib/routers/hotels/output.ts
index 11e0a5f70..533f61e67 100644
--- a/packages/trpc/lib/routers/hotels/output.ts
+++ b/packages/trpc/lib/routers/hotels/output.ts
@@ -496,6 +496,7 @@ export const ancillaryPackagesSchema = z
translatedCategoryName: ancillary.categoryName,
internalCategoryName: ancillary.internalCategoryName,
requiresQuantity: getRequiresQuantity(item.id),
+ unitName: item.unitName,
})),
}))
.filter((ancillary) => ancillary.ancillaryContent.length > 0)
diff --git a/scripts/material-symbols-update.mts b/scripts/material-symbols-update.mts
index 01e0cb45f..db2d7c586 100644
--- a/scripts/material-symbols-update.mts
+++ b/scripts/material-symbols-update.mts
@@ -1,26 +1,27 @@
-import crypto from "node:crypto";
-import { createWriteStream } from "node:fs";
-import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
-import { join, resolve } from "node:path";
-import { Readable } from "node:stream";
-import { pipeline } from "node:stream/promises";
+import crypto from "node:crypto"
+import { createWriteStream } from "node:fs"
+import { mkdir, readFile, rm, writeFile } from "node:fs/promises"
+import { join, resolve } from "node:path"
+import { Readable } from "node:stream"
+import { pipeline } from "node:stream/promises"
-import stringify from "json-stable-stringify-without-jsonify";
-import { fileURLToPath } from "node:url";
+import stringify from "json-stable-stringify-without-jsonify"
+import { fileURLToPath } from "node:url"
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = resolve(__filename, "..");
+const __filename = fileURLToPath(import.meta.url)
+const __dirname = resolve(__filename, "..")
// Defines where the font lives
-const FONT_DIR = resolve(__dirname, "../shared/fonts/material-symbols");
+const FONT_DIR = resolve(__dirname, "../shared/fonts/material-symbols")
// Defines the settings for the font
-const FONT_BASE_URL = `https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0..1,0`;
+const FONT_BASE_URL = `https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0..1,0`
// Defines the subset of icons for the font
const icons = [
"accessibility",
"accessible",
+ "acute",
"add_circle",
"add",
"air_purifier_gen",
@@ -231,16 +232,16 @@ const icons = [
"water_full",
"wifi",
"yard",
-].sort();
+].sort()
function createHash(value: unknown) {
- const stringified = stringify(value);
- const hash = crypto.createHash("sha256");
- hash.update(stringified);
- return hash.digest("hex");
+ const stringified = stringify(value)
+ const hash = crypto.createHash("sha256")
+ hash.update(stringified)
+ return hash.digest("hex")
}
-const hash = createHash(icons).substring(0, 8);
+const hash = createHash(icons).substring(0, 8)
async function fetchIconUrl(url: string) {
const response = await fetch(url, {
@@ -250,105 +251,105 @@ async function fetchIconUrl(url: string) {
"User-Agent":
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
},
- });
+ })
if (!response.ok) {
- console.error(`Unable to fetch woff2 for ${url}`);
- process.exit(1);
+ console.error(`Unable to fetch woff2 for ${url}`)
+ process.exit(1)
}
- const text = await response.text();
+ const text = await response.text()
- const isWoff2 = /format\('woff2'\)/.test(text);
+ const isWoff2 = /format\('woff2'\)/.test(text)
if (!isWoff2) {
- console.error(`Unable to identify woff2 font in response`);
- process.exit(1);
+ console.error(`Unable to identify woff2 font in response`)
+ process.exit(1)
}
- const srcUrl = text.match(/src: url\(([^)]+)\)/);
+ const srcUrl = text.match(/src: url\(([^)]+)\)/)
if (srcUrl && srcUrl[1]) {
- return srcUrl[1];
+ return srcUrl[1]
}
- return null;
+ return null
}
async function download(url: string, destFolder: string) {
- const dest = resolve(join(destFolder, `/rounded-${hash}.woff2`));
+ const dest = resolve(join(destFolder, `/rounded-${hash}.woff2`))
try {
- const response = await fetch(url);
+ const response = await fetch(url)
if (!response.ok) {
- console.error(`Unable to fetch ${url}`);
- process.exit(1);
+ console.error(`Unable to fetch ${url}`)
+ process.exit(1)
}
if (!response.body) {
- console.error(`Bad response from ${url}`);
- process.exit(1);
+ console.error(`Bad response from ${url}`)
+ process.exit(1)
}
- const fileStream = createWriteStream(dest);
+ const fileStream = createWriteStream(dest)
// @ts-expect-error: type mismatch
- const readableNodeStream = Readable.fromWeb(response.body);
+ const readableNodeStream = Readable.fromWeb(response.body)
- await pipeline(readableNodeStream, fileStream);
+ await pipeline(readableNodeStream, fileStream)
} catch (error) {
- console.error(`Error downloading file from ${url}:`, error);
- process.exit(1);
+ console.error(`Error downloading file from ${url}:`, error)
+ process.exit(1)
}
}
async function cleanFontDirs() {
- await rm(FONT_DIR, { recursive: true, force: true });
- await mkdir(FONT_DIR, { recursive: true });
+ await rm(FONT_DIR, { recursive: true, force: true })
+ await mkdir(FONT_DIR, { recursive: true })
await writeFile(
join(FONT_DIR, ".auto-generated"),
`Auto-generated, do not edit. Use scripts/material-symbols-update.mts to update.\nhash=${hash}\ncreated=${new Date().toISOString()}\n`,
- { encoding: "utf-8" },
- );
+ { encoding: "utf-8" }
+ )
}
async function updateFontCSS() {
- const file = resolve(__dirname, "../packages/design-system/lib/fonts.css");
+ const file = resolve(__dirname, "../packages/design-system/lib/fonts.css")
const css = await readFile(file, {
encoding: "utf-8",
- });
+ })
await writeFile(
file,
css.replace(
/url\(\/_static\/shared\/fonts\/material-symbols\/rounded[^)]+\)/,
- `url(/_static/shared/fonts/material-symbols/rounded-${hash}.woff2)`,
+ `url(/_static/shared/fonts/material-symbols/rounded-${hash}.woff2)`
),
{
encoding: "utf-8",
- },
- );
+ }
+ )
}
async function main() {
- const fontUrl = `${FONT_BASE_URL}&icon_names=${icons.join(",")}&display=block`;
+ const fontUrl = `${FONT_BASE_URL}&icon_names=${icons.join(",")}&display=block`
- const iconUrl = await fetchIconUrl(fontUrl);
+ const iconUrl = await fetchIconUrl(fontUrl)
if (iconUrl) {
- await cleanFontDirs();
+ await cleanFontDirs()
- await download(iconUrl, FONT_DIR);
+ await download(iconUrl, FONT_DIR)
- await updateFontCSS();
+ await updateFontCSS()
- console.log("Successfully updated icons!");
- process.exit(0);
+ console.log("Successfully updated icons!")
+ process.exit(0)
} else {
console.error(
- `Unable to find the icon font src URL in CSS response from Google Fonts at ${fontUrl}`,
- );
+ `Unable to find the icon font src URL in CSS response from Google Fonts at ${fontUrl}`
+ )
}
}
-main();
+main()
diff --git a/shared/fonts/material-symbols/.auto-generated b/shared/fonts/material-symbols/.auto-generated
index ecfd3a2fb..5e758b76d 100644
--- a/shared/fonts/material-symbols/.auto-generated
+++ b/shared/fonts/material-symbols/.auto-generated
@@ -1,3 +1,3 @@
Auto-generated, do not edit. Use scripts/material-symbols-update.mts to update.
-hash=b1df8938
-created=2025-12-04T09:28:50.275Z
+hash=3e10d67b
+created=2025-12-09T12:38:38.912Z
diff --git a/shared/fonts/material-symbols/rounded-3e10d67b.woff2 b/shared/fonts/material-symbols/rounded-3e10d67b.woff2
new file mode 100644
index 000000000..02b51a694
Binary files /dev/null and b/shared/fonts/material-symbols/rounded-3e10d67b.woff2 differ
diff --git a/shared/fonts/material-symbols/rounded-b1df8938.woff2 b/shared/fonts/material-symbols/rounded-b1df8938.woff2
deleted file mode 100644
index c1ae861e2..000000000
Binary files a/shared/fonts/material-symbols/rounded-b1df8938.woff2 and /dev/null differ