@riverbankcms/sdk 0.98.0 → 0.99.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/dist/{PreviewEditorSidebar-CG3SSJND.mjs → PreviewEditorSidebar-TPOKCCKY.mjs} +3 -3
  2. package/dist/{PreviewEditorUI-RHNGKAAU.mjs → PreviewEditorUI-Y347GLC2.mjs} +3 -3
  3. package/dist/SdkPreviewModeRuntime-OGTXRQ4M.mjs +8 -0
  4. package/dist/_dts/ai/src/contracts/proposals.d.ts +36 -36
  5. package/dist/_dts/api/src/billing.d.ts +2 -0
  6. package/dist/_dts/api/src/commercePortalEndpoints.d.ts +5 -1
  7. package/dist/_dts/api/src/endpoints.d.ts +8 -0
  8. package/dist/_dts/api/src/index.d.ts +1 -1
  9. package/dist/_dts/api/src/siteOperations.d.ts +65 -1
  10. package/dist/_dts/billing/src/site-arrangements.d.ts +151 -0
  11. package/dist/_dts/billing/src/subscriptions/store.d.ts +2 -0
  12. package/dist/_dts/block-form/src/widgets/RepeaterField/utils/resolveThumbnail.d.ts +2 -1
  13. package/dist/_dts/blocks/src/PageRenderer.d.ts +6 -0
  14. package/dist/_dts/blocks/src/system/runtime/components/booking/DatePicker.d.ts +6 -2
  15. package/dist/_dts/blocks/src/system/runtime/components/booking/SuccessMessage.d.ts +3 -1
  16. package/dist/_dts/blocks/src/system/runtime/components/booking/TimeSlotSelector.d.ts +10 -4
  17. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.state.d.ts +2 -2
  18. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +11 -0
  19. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/StepIndicator.d.ts +3 -1
  20. package/dist/_dts/blocks/src/system/runtime/shared/components/FeedbackMessage.d.ts +2 -1
  21. package/dist/_dts/blocks/src/system/runtime/{nodes/event-registration → shared/components}/SelectableOptionCard.d.ts +11 -2
  22. package/dist/_dts/blocks/src/system/runtime/shared/components/StepIndicator.d.ts +16 -5
  23. package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +2 -0
  24. package/dist/_dts/blocks/src/system/runtime/shared/index.d.ts +2 -2
  25. package/dist/_dts/blocks/src/utils/date-formatting.d.ts +17 -1
  26. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +274 -30
  27. package/dist/_dts/sdk/src/__mocks__/next-cache.d.ts +1 -1
  28. package/dist/_dts/sdk/src/cli/commands/push.d.ts +13 -0
  29. package/dist/_dts/sdk/src/cli/merge-remote/entryMergeReport.d.ts +6 -18
  30. package/dist/_dts/sdk/src/cli/merge-remote/entrySnapshots.d.ts +2 -4
  31. package/dist/_dts/sdk/src/cli/merge-remote/pageMergeReport.d.ts +6 -18
  32. package/dist/_dts/sdk/src/cli/merge-remote/pageSnapshots.d.ts +2 -4
  33. package/dist/_dts/sdk/src/cli/merge-remote/sharedBaseSnapshots.d.ts +32 -0
  34. package/dist/_dts/sdk/src/cli/merge-remote/sharedMergePlan.d.ts +27 -0
  35. package/dist/_dts/sdk/src/cli/merge-remote/sharedMergeReport.d.ts +63 -0
  36. package/dist/_dts/sdk/src/client/index.d.ts +6 -0
  37. package/dist/_dts/sdk/src/data/prefetchBlockData.d.ts +6 -1
  38. package/dist/_dts/sdk/src/next/types.d.ts +19 -0
  39. package/dist/_dts/sdk/src/prebuild/loader.d.ts +8 -1
  40. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +2 -0
  41. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +4 -0
  42. package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +6 -0
  43. package/dist/_dts/sdk/src/rendering/helpers/loadPage.d.ts +8 -0
  44. package/dist/_dts/sdk/src/rendering/index.d.ts +7 -7
  45. package/dist/_dts/sdk/src/rendering/overrides.d.ts +2 -0
  46. package/dist/_dts/sdk/src/routing/resolveRoute.d.ts +18 -0
  47. package/dist/_dts/sdk/src/test/apiClient.d.ts +17 -0
  48. package/dist/_dts/sdk/src/test/bunDom.setup.d.ts +1 -0
  49. package/dist/_dts/sdk/src/test/env.d.ts +4 -0
  50. package/dist/_dts/sdk/src/version.d.ts +1 -1
  51. package/dist/_dts/site-commands/src/commands.d.ts +3 -3
  52. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  53. package/dist/_dts/theme-core/src/interactive/generateBaseCSS.d.ts +6 -0
  54. package/dist/_dts/theme-core/src/status/contextualColors.d.ts +6 -0
  55. package/dist/_dts/theme-core/src/status/index.d.ts +1 -0
  56. package/dist/{chunk-H24OU7WG.mjs → chunk-4HXF2QLH.mjs} +2 -2
  57. package/dist/{chunk-QPXE2OUZ.mjs → chunk-EMJIT3ZJ.mjs} +1 -1
  58. package/dist/{chunk-PKDPQHB5.mjs → chunk-PM7HGDHM.mjs} +2 -2
  59. package/dist/{chunk-DBRI3PQF.mjs → chunk-XO34WBBP.mjs} +1383 -1143
  60. package/dist/{chunk-6WDBXCPX.mjs → chunk-YGTTEVUM.mjs} +7 -7
  61. package/dist/{chunk-V2BYFSPW.mjs → chunk-YWTCCOSF.mjs} +8 -0
  62. package/dist/cli/index.mjs +1010 -921
  63. package/dist/client/{accordion-Q2BDNL53.mjs → accordion-QSUEYL4L.mjs} +2 -2
  64. package/dist/client/{bookingForm-ZMP4P7EK.mjs → bookingForm-QYGAHPDP.mjs} +364 -300
  65. package/dist/client/bookings.mjs +697 -411
  66. package/dist/client/{carousel-LW3UXPWO.mjs → carousel-SM2LEWAU.mjs} +3 -3
  67. package/dist/client/{cart-Z6D3KS6K.mjs → cart-3N3SFKNQ.mjs} +7 -7
  68. package/dist/client/{checkout-YMT2QJQM.mjs → checkout-YFAYPKPZ.mjs} +7 -7
  69. package/dist/client/{chunk-XNTHVZ25.mjs → chunk-5DLGREUB.mjs} +1 -1
  70. package/dist/client/{chunk-SK2BMD22.mjs → chunk-CLZ7NBSP.mjs} +147 -75
  71. package/dist/client/{chunk-R4XK3CKR.mjs → chunk-CYJ3MUFP.mjs} +6 -5
  72. package/dist/client/{chunk-JNE6UI6U.mjs → chunk-H3H3ODO7.mjs} +1 -1
  73. package/dist/client/{chunk-IEOECM7U.mjs → chunk-HPEQ4YWW.mjs} +28 -73
  74. package/dist/client/{chunk-PCHACQEB.mjs → chunk-IIUIKJ4K.mjs} +15 -7
  75. package/dist/client/{chunk-KDP7ZRZV.mjs → chunk-IOAHWAQG.mjs} +2 -0
  76. package/dist/client/{chunk-26ZBRXFR.mjs → chunk-JTKBF3W2.mjs} +3 -3
  77. package/dist/client/{chunk-OLAOAZEO.mjs → chunk-K7KTSACR.mjs} +1 -1
  78. package/dist/client/{chunk-ET2MDQQT.mjs → chunk-R32M5HFS.mjs} +6 -6
  79. package/dist/client/{chunk-DRRQ7QSL.mjs → chunk-WEVT46PX.mjs} +3 -3
  80. package/dist/client/{chunk-HBQEAOG4.mjs → chunk-ZU65LTI3.mjs} +1 -1
  81. package/dist/client/client.mjs +1875 -1581
  82. package/dist/client/{courseRegistration-DGKCMC77.mjs → courseRegistration-LYBE7VVK.mjs} +7 -7
  83. package/dist/client/{eventCalendar-74Z2NNFM.mjs → eventCalendar-FMTB75X6.mjs} +9 -9
  84. package/dist/client/{eventCombined-GK2ODOX2.mjs → eventCombined-E4LUCJXT.mjs} +9 -9
  85. package/dist/client/{eventDetails-MONAGT3N.mjs → eventDetails-GELSRR4Z.mjs} +9 -9
  86. package/dist/client/{eventListing-SKGAO6PS.mjs → eventListing-TB623B6R.mjs} +9 -9
  87. package/dist/client/{eventRegistration-6KISGXRD.mjs → eventRegistration-NRIKHXTI.mjs} +9 -9
  88. package/dist/client/{form-FXPRTXHI.mjs → form-Y4U4IAXE.mjs} +3 -3
  89. package/dist/client/{headerSection-7NAN5WNB.mjs → headerSection-QSOVV5P7.mjs} +3 -3
  90. package/dist/client/hooks.mjs +115 -21
  91. package/dist/client/{locationMap-UERN74U4.mjs → locationMap-QYCAHH7H.mjs} +3 -3
  92. package/dist/client/{newsletterForm-SGWXMJ7U.mjs → newsletterForm-NWHY5TBY.mjs} +3 -3
  93. package/dist/client/{productDetail-HN3HWZQZ.mjs → productDetail-FYDMU2CE.mjs} +7 -7
  94. package/dist/client/{productList-YT22Z5UR.mjs → productList-D76CGACQ.mjs} +7 -7
  95. package/dist/client/rendering/client.mjs +1209 -975
  96. package/dist/client/rendering/islands.mjs +19 -19
  97. package/dist/client/rendering.mjs +1952 -1638
  98. package/dist/client/{shop-TKEDNWUS.mjs → shop-SOUACT5N.mjs} +7 -7
  99. package/dist/preview-next/before-render.mjs +8 -0
  100. package/dist/preview-next/client/runtime.mjs +5 -5
  101. package/dist/preview-next/middleware.mjs +8 -0
  102. package/dist/{sdk-runtime-LWNYCQF2.mjs → sdk-runtime-XPVE3LBA.mjs} +6 -6
  103. package/dist/server/components.mjs +917 -765
  104. package/dist/server/config-validation.mjs +100 -19
  105. package/dist/server/config.mjs +100 -19
  106. package/dist/server/data.mjs +115 -21
  107. package/dist/server/index.mjs +59 -25
  108. package/dist/server/next.mjs +1017 -816
  109. package/dist/server/page-converter.mjs +92 -19
  110. package/dist/server/prebuild-loader.mjs +42 -23
  111. package/dist/server/prebuild.mjs +1 -1
  112. package/dist/server/rendering/server.mjs +932 -767
  113. package/dist/server/rendering.mjs +968 -776
  114. package/dist/server/routing.mjs +162 -36
  115. package/dist/server/server.mjs +156 -32
  116. package/dist/server/theme-bridge.mjs +597 -505
  117. package/dist/server/theme.mjs +5 -4
  118. package/dist/styles/index.css +499 -490
  119. package/package.json +6 -4
  120. package/dist/SdkPreviewModeRuntime-OV5PNJBB.mjs +0 -8
@@ -1,15 +1,15 @@
1
1
  "use client";
2
- import { buildBookingPaymentSelectionViewModel, usePolling } from './chunk-DRRQ7QSL.mjs';
3
- import { SpinnerNode } from './chunk-OLAOAZEO.mjs';
2
+ import { buildBookingPaymentSelectionViewModel, usePolling } from './chunk-WEVT46PX.mjs';
3
+ import { SpinnerNode } from './chunk-K7KTSACR.mjs';
4
4
  import { buildRouteIslandApiConfig } from './chunk-L4J5Y62O.mjs';
5
- import { scrollToBlock, useDiscountCodeUi, buildCheckoutReturnUrls, DiscountCodeDisclosure } from './chunk-SK2BMD22.mjs';
5
+ import { scrollToBlock, useDiscountCodeUi, TerminalPanel, StateIcon, CheckIcon, StepIndicator, buildCheckoutReturnUrls, DiscountCodeDisclosure } from './chunk-CLZ7NBSP.mjs';
6
6
  import { FieldValidationMessage, getFieldValidationControlProps } from './chunk-3DCJ45Z2.mjs';
7
7
  import './chunk-WBQG7VJA.mjs';
8
8
  import { isSpamProtectionEnabled, getChallengeUrl, AltchaWidget } from './chunk-LJCX6V7Q.mjs';
9
- import { BlockApiProvider, useBlockApi, FeedbackMessage } from './chunk-KDP7ZRZV.mjs';
9
+ import { BlockApiProvider, useBlockApi, FeedbackMessage } from './chunk-IOAHWAQG.mjs';
10
10
  import { mountReactIsland } from './chunk-N7PBWBWQ.mjs';
11
- import { defineIslandPropsDecoder, resolveBookingSiteId, resolveDefaultBookingServiceId, getBookingRedirectStateFromLocation, deriveBookingFormViewState, logger, getBookingSuccessMessage, getBookingServiceSlidingScale, formatBookingCentsAsCurrencyInput, parseBookingCurrencyInputToCents, themeButtonClassName, toSelectedCollectionOptionKind, assertNever, prepareBookingSubmission, formatBookingSubmissionPreparationError, resolveBookingPaymentStep, resolveAppointmentCheckoutVerificationState, BOOKING_FORM_DATA_RESERVED_KEYS, isBookingServiceSlidingAmountInRange, clearWorkflowFeedback, reportWorkflowError, reportWorkflowSuccess, okWith, err } from './chunk-R4XK3CKR.mjs';
12
- import { resolveBookingTimeZoneId, DEFAULT_BOOKING_TIME_ZONE, unsafeAsFormId, unsafeAsAppointmentResourceId, unsafeAsCustomerPassId, unsafeAsAppointmentServiceId, formatLocalScheduleDate, addLocalScheduleDays, parseBookingLocalDate, unsafeAsPassId, formatCurrencyAmount, formatBookingInstant } from './chunk-PCHACQEB.mjs';
11
+ import { defineIslandPropsDecoder, resolveBookingSiteId, resolveDefaultBookingServiceId, getBookingRedirectStateFromLocation, deriveBookingFormViewState, logger, getBookingSuccessMessage, getBookingServiceSlidingScale, formatBookingCentsAsCurrencyInput, parseBookingCurrencyInputToCents, themeButtonClassName, toSelectedCollectionOptionKind, assertNever, prepareBookingSubmission, formatBookingSubmissionPreparationError, resolveBookingPaymentStep, resolveAppointmentCheckoutVerificationState, BOOKING_FORM_DATA_RESERVED_KEYS, isBookingServiceSlidingAmountInRange, clearWorkflowFeedback, reportWorkflowError, reportWorkflowSuccess, okWith, err } from './chunk-CYJ3MUFP.mjs';
12
+ import { resolveBookingTimeZoneId, DEFAULT_BOOKING_TIME_ZONE, unsafeAsFormId, unsafeAsAppointmentResourceId, unsafeAsCustomerPassId, unsafeAsAppointmentServiceId, formatLocalScheduleDate, addLocalScheduleDays, parseBookingLocalDate, unsafeAsPassId, formatCurrencyAmount, formatBookingInstant } from './chunk-IIUIKJ4K.mjs';
13
13
  import React2, { useRef, useState, useMemo, useReducer, useEffect, useCallback, useLayoutEffect } from 'react';
14
14
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
15
15
 
@@ -19,19 +19,20 @@ var SuccessMessage = ({
19
19
  className
20
20
  }) => {
21
21
  return /* @__PURE__ */ jsx(
22
- FeedbackMessage,
22
+ TerminalPanel,
23
23
  {
24
24
  tone: "success",
25
- className: `ab-alert ab-alert--success ${className ?? ""}`,
25
+ title: "Booking confirmed",
26
+ icon: /* @__PURE__ */ jsx(StateIcon, { variant: "success", children: /* @__PURE__ */ jsx(CheckIcon, { strokeWidth: 3 }) }),
27
+ body: /* @__PURE__ */ jsx("p", { className: "ab-text", children: message }),
28
+ secondaryBody: resourceName ? /* @__PURE__ */ jsxs("p", { className: "ab-text rb-on-surface--muted", children: [
29
+ "Practitioner: ",
30
+ resourceName
31
+ ] }) : null,
32
+ className: ["ab-center", className ?? ""].join(" ").trim(),
33
+ titleClassName: "ab-terminal-title",
26
34
  role: "alert",
27
- live: "polite",
28
- children: /* @__PURE__ */ jsxs(Fragment, { children: [
29
- /* @__PURE__ */ jsx("p", { className: "ab-text", children: message }),
30
- resourceName ? /* @__PURE__ */ jsxs("p", { className: "ab-text ab-text--muted", children: [
31
- "Practitioner: ",
32
- resourceName
33
- ] }) : null
34
- ] })
35
+ live: "polite"
35
36
  }
36
37
  );
37
38
  };
@@ -72,9 +73,30 @@ function formatDate(dateStr) {
72
73
  }
73
74
  });
74
75
  }
75
- function formatTime(isoString) {
76
- return formatBookingInstant(isoString, {
76
+ function formatDatePillParts(dateStr) {
77
+ const instant = `${dateStr}T00:00:00.000Z`;
78
+ const partFormat = (format) => formatBookingInstant(instant, {
77
79
  timeZone: DEFAULT_BOOKING_TIME_ZONE,
80
+ format
81
+ });
82
+ return {
83
+ weekday: partFormat({ weekday: "short" }),
84
+ day: partFormat({ day: "numeric" }),
85
+ month: partFormat({ month: "short" })
86
+ };
87
+ }
88
+ function formatTimeShort(isoString, timeZone = DEFAULT_BOOKING_TIME_ZONE) {
89
+ return formatBookingInstant(isoString, {
90
+ timeZone,
91
+ format: {
92
+ hour: "numeric",
93
+ minute: "2-digit"
94
+ }
95
+ });
96
+ }
97
+ function formatTime(isoString, timeZone = DEFAULT_BOOKING_TIME_ZONE) {
98
+ return formatBookingInstant(isoString, {
99
+ timeZone,
78
100
  format: {
79
101
  hour: "numeric",
80
102
  minute: "2-digit",
@@ -794,6 +816,24 @@ function toBookingSlotView(slot) {
794
816
  function toBookingSlotViews(slots) {
795
817
  return slots.map(toBookingSlotView);
796
818
  }
819
+ function deriveBookingSlotDisplayOptions(input) {
820
+ const seenStartTimes = /* @__PURE__ */ new Set();
821
+ const options = [];
822
+ for (const slot of input.slots) {
823
+ if (!input.hasSelectedResource) {
824
+ if (seenStartTimes.has(slot.startAt)) continue;
825
+ seenStartTimes.add(slot.startAt);
826
+ }
827
+ options.push({
828
+ key: slot.key,
829
+ startAt: slot.startAt,
830
+ endAt: slot.endAt,
831
+ resourceId: slot.resourceId,
832
+ slot
833
+ });
834
+ }
835
+ return options;
836
+ }
797
837
  function toBookingFormData(state) {
798
838
  return {
799
839
  ...state.fieldValues,
@@ -1909,63 +1949,96 @@ function useAppointmentCheckoutVerificationWithDeps(config, deps) {
1909
1949
  retry: polling.retry
1910
1950
  };
1911
1951
  }
1952
+ function DateFieldLabel({
1953
+ labelId,
1954
+ required
1955
+ }) {
1956
+ return /* @__PURE__ */ jsxs("span", { className: "form-label", id: labelId, children: [
1957
+ "Select Date",
1958
+ required && /* @__PURE__ */ jsx("span", { className: "required-marker", children: "*" })
1959
+ ] });
1960
+ }
1912
1961
  var DatePicker = ({
1913
1962
  value,
1914
1963
  onChange,
1915
1964
  dateOptions,
1916
1965
  required = true,
1966
+ ariaDescribedBy,
1967
+ ariaInvalid,
1917
1968
  isLoading = false,
1918
1969
  isEmpty = false,
1919
1970
  hasMore = false,
1920
1971
  onLoadMore
1921
1972
  }) => {
1973
+ const generatedId = React2.useId();
1974
+ const labelId = `${generatedId}-date-label`;
1975
+ const gridRef = React2.useRef(null);
1976
+ const previousCountRef = React2.useRef(dateOptions.length);
1977
+ React2.useEffect(() => {
1978
+ const previousCount = previousCountRef.current;
1979
+ previousCountRef.current = dateOptions.length;
1980
+ if (previousCount === 0 || dateOptions.length <= previousCount) return;
1981
+ const pills = gridRef.current?.querySelectorAll(
1982
+ "button[aria-pressed]"
1983
+ );
1984
+ pills?.[previousCount]?.focus();
1985
+ }, [dateOptions.length]);
1922
1986
  if (isLoading) {
1923
- return /* @__PURE__ */ jsxs("div", { className: "ab-stack--sm", children: [
1924
- /* @__PURE__ */ jsxs("label", { className: "ab-label", children: [
1925
- "Select Date",
1926
- required && /* @__PURE__ */ jsx("span", { className: "ab-required", children: "*" })
1927
- ] }),
1928
- /* @__PURE__ */ jsx("div", { className: "ab-skeleton" }),
1929
- /* @__PURE__ */ jsx("p", { className: "ab-text ab-text--muted ab-text--sm", children: "Loading available dates..." })
1987
+ return /* @__PURE__ */ jsxs("div", { className: "rb-reg-stack rb-reg-stack--sm", children: [
1988
+ /* @__PURE__ */ jsx(DateFieldLabel, { labelId, required }),
1989
+ /* @__PURE__ */ jsx("div", { className: "rb-shell-block" }),
1990
+ /* @__PURE__ */ jsx("p", { className: "ab-text ab-text--sm rb-on-surface--muted", children: "Loading available dates..." })
1930
1991
  ] });
1931
1992
  }
1932
1993
  if (isEmpty) {
1933
- return /* @__PURE__ */ jsxs("div", { className: "ab-stack--sm", children: [
1934
- /* @__PURE__ */ jsxs("label", { className: "ab-label", children: [
1935
- "Select Date",
1936
- required && /* @__PURE__ */ jsx("span", { className: "ab-required", children: "*" })
1937
- ] }),
1938
- /* @__PURE__ */ jsx(FeedbackMessage, { tone: "warning", className: "ab-alert ab-alert--warning", role: "status", children: /* @__PURE__ */ jsxs("p", { className: "ab-text", children: [
1994
+ return /* @__PURE__ */ jsxs("div", { className: "rb-reg-stack rb-reg-stack--sm", children: [
1995
+ /* @__PURE__ */ jsx(DateFieldLabel, { labelId, required }),
1996
+ /* @__PURE__ */ jsx(FeedbackMessage, { tone: "warning", className: "alert alert-warning", role: "status", children: /* @__PURE__ */ jsxs("p", { className: "ab-text", children: [
1939
1997
  "No available dates in this period.",
1940
1998
  hasMore && onLoadMore && /* @__PURE__ */ jsx(
1941
1999
  "button",
1942
2000
  {
1943
2001
  type: "button",
1944
2002
  onClick: onLoadMore,
1945
- className: "ab-link",
2003
+ className: "ab-link rb-ml-2",
1946
2004
  children: "Check later dates"
1947
2005
  }
1948
2006
  )
1949
2007
  ] }) })
1950
2008
  ] });
1951
2009
  }
1952
- return /* @__PURE__ */ jsxs("div", { className: "ab-stack--sm", children: [
1953
- /* @__PURE__ */ jsxs("label", { htmlFor: "booking-date", className: "ab-label", children: [
1954
- "Select Date",
1955
- required && /* @__PURE__ */ jsx("span", { className: "ab-required", children: "*" })
1956
- ] }),
1957
- /* @__PURE__ */ jsxs(
1958
- "select",
2010
+ return /* @__PURE__ */ jsxs("div", { className: "rb-reg-stack rb-reg-stack--sm", children: [
2011
+ /* @__PURE__ */ jsx(DateFieldLabel, { labelId, required }),
2012
+ /* @__PURE__ */ jsx(
2013
+ "div",
1959
2014
  {
1960
- id: "booking-date",
1961
- value,
1962
- onChange: (e) => onChange(e.target.value),
1963
- required,
1964
- className: "ab-select",
1965
- children: [
1966
- /* @__PURE__ */ jsx("option", { value: "", children: "Choose a date..." }),
1967
- dateOptions.map((date) => /* @__PURE__ */ jsx("option", { value: date, children: formatDate(date) }, date))
1968
- ]
2015
+ ref: gridRef,
2016
+ role: "group",
2017
+ "aria-labelledby": labelId,
2018
+ "aria-describedby": ariaDescribedBy,
2019
+ "aria-invalid": ariaInvalid || void 0,
2020
+ "aria-required": required || void 0,
2021
+ className: "ab-pill-grid",
2022
+ children: dateOptions.map((date) => {
2023
+ const isSelected = value === date;
2024
+ const parts = formatDatePillParts(date);
2025
+ return /* @__PURE__ */ jsxs(
2026
+ "button",
2027
+ {
2028
+ type: "button",
2029
+ onClick: () => onChange(isSelected ? "" : date),
2030
+ "aria-pressed": isSelected,
2031
+ "aria-label": formatDate(date),
2032
+ className: `rb-option-card ab-date-pill${isSelected ? " rb-option-card--selected" : ""}`,
2033
+ children: [
2034
+ /* @__PURE__ */ jsx("span", { className: "ab-pill-caption", "aria-hidden": "true", children: parts.weekday }),
2035
+ /* @__PURE__ */ jsx("span", { className: "ab-pill-value", "aria-hidden": "true", children: parts.day }),
2036
+ /* @__PURE__ */ jsx("span", { className: "ab-pill-caption", "aria-hidden": "true", children: parts.month })
2037
+ ]
2038
+ },
2039
+ date
2040
+ );
2041
+ })
1969
2042
  }
1970
2043
  ),
1971
2044
  hasMore && onLoadMore && /* @__PURE__ */ jsx(
@@ -1974,7 +2047,7 @@ var DatePicker = ({
1974
2047
  type: "button",
1975
2048
  onClick: onLoadMore,
1976
2049
  className: "ab-link",
1977
- children: "Load more dates \u2192"
2050
+ children: "More dates \u2192"
1978
2051
  }
1979
2052
  )
1980
2053
  ] });
@@ -1984,40 +2057,59 @@ var TimeSlotSelector = ({
1984
2057
  onChange,
1985
2058
  slots,
1986
2059
  isLoading,
1987
- required = true
2060
+ timezone,
2061
+ required = true,
2062
+ ariaDescribedBy,
2063
+ ariaInvalid
1988
2064
  }) => {
1989
- return /* @__PURE__ */ jsxs("div", { className: "ab-stack--sm", children: [
1990
- /* @__PURE__ */ jsxs("label", { htmlFor: "booking-slot", className: "ab-label", children: [
2065
+ const generatedId = React2.useId();
2066
+ const labelId = `${generatedId}-time-label`;
2067
+ const groupRef = React2.useRef(null);
2068
+ const hadSlotsRef = React2.useRef(false);
2069
+ React2.useEffect(() => {
2070
+ const hasSlots = !isLoading && slots.length > 0;
2071
+ if (hasSlots && !hadSlotsRef.current) {
2072
+ groupRef.current?.scrollIntoView({ block: "nearest", behavior: "smooth" });
2073
+ }
2074
+ hadSlotsRef.current = hasSlots;
2075
+ }, [isLoading, slots.length]);
2076
+ return /* @__PURE__ */ jsxs("div", { className: "rb-reg-stack rb-reg-stack--sm", children: [
2077
+ /* @__PURE__ */ jsxs("span", { className: "form-label", id: labelId, children: [
1991
2078
  "Select Time",
1992
- required && /* @__PURE__ */ jsx("span", { className: "ab-required", children: "*" })
2079
+ required && /* @__PURE__ */ jsx("span", { className: "required-marker", children: "*" })
1993
2080
  ] }),
1994
- isLoading ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "info", className: "ab-alert ab-alert--info ab-center", role: "status", children: "Loading available times..." }) : slots.length === 0 ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "info", className: "ab-alert ab-alert--info ab-center", role: "status", children: "No available times for this date" }) : /* @__PURE__ */ jsxs(
1995
- "select",
2081
+ isLoading ? /* @__PURE__ */ jsx("div", { className: "rb-shell-block" }) : slots.length === 0 ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "info", className: "alert alert-info", role: "status", children: "No available times for this date" }) : /* @__PURE__ */ jsx(
2082
+ "div",
1996
2083
  {
1997
- id: "booking-slot",
1998
- value,
1999
- onChange: (e) => onChange(e.target.value),
2000
- required,
2001
- className: "ab-select",
2002
- children: [
2003
- /* @__PURE__ */ jsx("option", { value: "", children: "Choose a time..." }),
2004
- slots.map((slot) => /* @__PURE__ */ jsx("option", { value: slot.startAt, children: formatTime(slot.startAt) }, slot.startAt))
2005
- ]
2084
+ ref: groupRef,
2085
+ role: "group",
2086
+ "aria-labelledby": labelId,
2087
+ "aria-describedby": ariaDescribedBy,
2088
+ "aria-invalid": ariaInvalid || void 0,
2089
+ "aria-required": required || void 0,
2090
+ className: "ab-pill-grid",
2091
+ children: slots.map((slot) => {
2092
+ const isSelected = value === slot.key;
2093
+ return /* @__PURE__ */ jsx(
2094
+ "button",
2095
+ {
2096
+ type: "button",
2097
+ onClick: () => onChange(isSelected ? "" : slot.key),
2098
+ "aria-pressed": isSelected,
2099
+ "aria-label": formatTime(slot.startAt, timezone),
2100
+ className: `rb-option-card ab-time-pill${isSelected ? " rb-option-card--selected" : ""}`,
2101
+ children: formatTimeShort(slot.startAt, timezone)
2102
+ },
2103
+ slot.key
2104
+ );
2105
+ })
2006
2106
  }
2007
2107
  )
2008
2108
  ] });
2009
2109
  };
2010
- var paymentOptionLayoutStyle = {
2011
- alignItems: "flex-start",
2012
- display: "flex",
2013
- flexDirection: "column",
2014
- gap: "0.25rem",
2015
- justifyContent: "flex-start",
2016
- width: "100%"
2017
- };
2018
- var summaryStackStyle = {
2019
- gap: "0.125rem"
2020
- };
2110
+ function optionCardClassName(isSelected) {
2111
+ return `rb-option-card${isSelected ? " rb-option-card--selected" : ""}`;
2112
+ }
2021
2113
  function formatBookingAmount(amount, currency) {
2022
2114
  return formatCurrencyAmount(amount, currency, { decimals: "auto" });
2023
2115
  }
@@ -2026,6 +2118,7 @@ function HeadlessBookingDefaultForm({
2026
2118
  onSubmit
2027
2119
  }) {
2028
2120
  const currentStep = booking.currentStep;
2121
+ const errorSummaryId = React2.useId();
2029
2122
  const currentStepIndex = currentStep?.visibleIndex ?? 0;
2030
2123
  const isFirstStep = currentStepIndex === 0;
2031
2124
  const isLastStep = currentStepIndex === booking.steps.length - 1;
@@ -2041,16 +2134,30 @@ function HeadlessBookingDefaultForm({
2041
2134
  return /* @__PURE__ */ jsx("div", { className: "rb-text-center rb-py-12", children: /* @__PURE__ */ jsx("p", { className: "status-muted", children: "No steps available" }) });
2042
2135
  }
2043
2136
  return /* @__PURE__ */ jsxs("div", { className: "multi-step-form", children: [
2044
- /* @__PURE__ */ jsx("div", { className: "rb-mb-8", children: /* @__PURE__ */ jsx(
2045
- DefaultBookingProgress,
2137
+ booking.steps.length > 1 ? /* @__PURE__ */ jsx(
2138
+ StepIndicator,
2139
+ {
2140
+ currentStep: currentStepIndex + 1,
2141
+ totalSteps: booking.steps.length,
2142
+ stepLabels: booking.steps.map((step) => step.label),
2143
+ emitSharedClasses: true
2144
+ }
2145
+ ) : null,
2146
+ /* @__PURE__ */ jsx("div", { className: "step-content", children: /* @__PURE__ */ jsx(
2147
+ DefaultBookingStepContent,
2046
2148
  {
2047
- steps: booking.steps,
2048
- currentIndex: currentStepIndex
2149
+ booking,
2150
+ errorSummaryId
2049
2151
  }
2050
2152
  ) }),
2051
- /* @__PURE__ */ jsx("div", { className: "step-content", children: /* @__PURE__ */ jsx(DefaultBookingStepContent, { booking }) }),
2052
- /* @__PURE__ */ jsx(DefaultBookingErrorSummary, { errors: currentStep.errors }),
2053
- /* @__PURE__ */ jsxs("div", { className: "rb-flex rb-gap-3 rb-mt-8", children: [
2153
+ /* @__PURE__ */ jsx(
2154
+ DefaultBookingErrorSummary,
2155
+ {
2156
+ errors: currentStep.errors,
2157
+ id: errorSummaryId
2158
+ }
2159
+ ),
2160
+ /* @__PURE__ */ jsxs("div", { className: "rb-wizard-actions", children: [
2054
2161
  !isFirstStep ? /* @__PURE__ */ jsx(
2055
2162
  "button",
2056
2163
  {
@@ -2068,11 +2175,7 @@ function HeadlessBookingDefaultForm({
2068
2175
  void handlePrimaryAction();
2069
2176
  },
2070
2177
  disabled: isSubmitting,
2071
- className: themeButtonClassName({
2072
- variant: "primary",
2073
- size: "md",
2074
- extraClassName: "rb-flex-1"
2075
- }),
2178
+ className: themeButtonClassName({ variant: "primary", size: "md" }),
2076
2179
  children: isSubmitting ? /* @__PURE__ */ jsxs(Fragment, { children: [
2077
2180
  /* @__PURE__ */ jsx(
2078
2181
  SpinnerNode,
@@ -2093,44 +2196,9 @@ function HeadlessBookingDefaultForm({
2093
2196
  /* @__PURE__ */ jsx(DefaultBookingAltcha, { booking })
2094
2197
  ] });
2095
2198
  }
2096
- function DefaultBookingProgress({
2097
- steps,
2098
- currentIndex
2099
- }) {
2100
- return /* @__PURE__ */ jsx("div", { className: "rb-flex rb-items-center rb-justify-between", children: steps.map((step, index) => {
2101
- const isActive = index === currentIndex;
2102
- const isCompleted = index < currentIndex;
2103
- const isLast = index === steps.length - 1;
2104
- return /* @__PURE__ */ jsxs("div", { className: "rb-flex rb-items-center rb-flex-1", children: [
2105
- /* @__PURE__ */ jsxs("div", { className: "rb-flex rb-items-center rb-gap-2 rb-cursor-default", children: [
2106
- /* @__PURE__ */ jsx(
2107
- "div",
2108
- {
2109
- className: `
2110
- step-circle transition-theme-standard
2111
- ${isActive ? "step-circle-active" : ""}
2112
- ${isCompleted ? "step-circle-complete" : ""}
2113
- `,
2114
- children: isCompleted ? "\u2713" : index + 1
2115
- }
2116
- ),
2117
- /* @__PURE__ */ jsx(
2118
- "span",
2119
- {
2120
- className: `
2121
- rb-caption rb-hidden rb-sm-inline
2122
- ${isCompleted || !isActive ? "status-muted" : ""}
2123
- `,
2124
- children: step.label
2125
- }
2126
- )
2127
- ] }),
2128
- !isLast ? /* @__PURE__ */ jsx("div", { className: "step-connector rb-ml-2 rb-mr-2 rb-hidden rb-sm-block" }) : null
2129
- ] }, step.id);
2130
- }) });
2131
- }
2132
2199
  function DefaultBookingStepContent({
2133
- booking
2200
+ booking,
2201
+ errorSummaryId
2134
2202
  }) {
2135
2203
  const stepId = booking.currentStep?.id;
2136
2204
  if (!stepId) return null;
@@ -2138,7 +2206,13 @@ function DefaultBookingStepContent({
2138
2206
  case "service-selection":
2139
2207
  return /* @__PURE__ */ jsx(DefaultServiceSelectionStep, { booking });
2140
2208
  case "datetime-selection":
2141
- return /* @__PURE__ */ jsx(DefaultDateTimeSelectionStep, { booking });
2209
+ return /* @__PURE__ */ jsx(
2210
+ DefaultDateTimeSelectionStep,
2211
+ {
2212
+ booking,
2213
+ errorSummaryId
2214
+ }
2215
+ );
2142
2216
  case "payment-selection":
2143
2217
  return /* @__PURE__ */ jsx(HeadlessBookingPaymentSelectionStep, { booking });
2144
2218
  case "custom-fields":
@@ -2157,32 +2231,33 @@ function DefaultServiceSelectionStep({
2157
2231
  const showServiceSelect = booking.services.requiresSelection || services.length > 1;
2158
2232
  const showResourceSelect = booking.resources.requiresSelection || resources.length > 1;
2159
2233
  const allowAnyResource = !booking.resources.requiresSelection;
2160
- return /* @__PURE__ */ jsxs("div", { className: "ab-stack", children: [
2234
+ return /* @__PURE__ */ jsxs("div", { className: "rb-reg-stack", children: [
2161
2235
  /* @__PURE__ */ jsxs("div", { children: [
2162
2236
  /* @__PURE__ */ jsx("h2", { className: "ab-title", children: "Select Service" }),
2163
- /* @__PURE__ */ jsx("p", { className: "ab-text ab-text--muted", children: "Choose the service you'd like to book" })
2237
+ /* @__PURE__ */ jsx("p", { className: "ab-text rb-on-surface--muted", children: "Choose the service you'd like to book" })
2164
2238
  ] }),
2165
- showServiceSelect ? /* @__PURE__ */ jsxs("div", { className: "ab-stack--sm", children: [
2166
- /* @__PURE__ */ jsx("label", { className: "ab-subtitle", children: "Service" }),
2167
- /* @__PURE__ */ jsx("div", { className: "ab-grid", children: services.map((service) => {
2239
+ showServiceSelect ? /* @__PURE__ */ jsxs("div", { className: "rb-reg-stack rb-reg-stack--sm", children: [
2240
+ /* @__PURE__ */ jsx("span", { className: "ab-subtitle", children: "Service" }),
2241
+ /* @__PURE__ */ jsx("div", { className: "rb-reg-grid", children: services.map((service) => {
2168
2242
  const isSelected = selectedServiceId === service.id;
2169
- return /* @__PURE__ */ jsx(
2243
+ return /* @__PURE__ */ jsxs(
2170
2244
  "button",
2171
2245
  {
2172
2246
  type: "button",
2173
2247
  onClick: () => booking.actions.selectService(service.id),
2174
- className: `ab-card ${isSelected ? "ab-card--selected" : ""}`,
2175
- children: /* @__PURE__ */ jsxs("div", { className: "ab-row--between", children: [
2176
- /* @__PURE__ */ jsxs("div", { children: [
2248
+ className: optionCardClassName(isSelected),
2249
+ "aria-pressed": isSelected,
2250
+ children: [
2251
+ /* @__PURE__ */ jsxs("div", { className: "rb-flex-1", children: [
2177
2252
  /* @__PURE__ */ jsx("div", { className: "ab-subtitle", children: service.title }),
2178
- service.description ? /* @__PURE__ */ jsx("div", { className: "ab-text ab-text--muted", children: service.description }) : null,
2179
- service.durationMinutes ? /* @__PURE__ */ jsxs("div", { className: "ab-text ab-text--muted", children: [
2253
+ service.description ? /* @__PURE__ */ jsx("div", { className: "ab-text rb-on-surface--muted", children: service.description }) : null,
2254
+ service.durationMinutes ? /* @__PURE__ */ jsxs("div", { className: "ab-text rb-on-surface--muted", children: [
2180
2255
  service.durationMinutes,
2181
2256
  " minutes"
2182
2257
  ] }) : null
2183
2258
  ] }),
2184
2259
  isSelected ? /* @__PURE__ */ jsx(SelectedCheck, {}) : null
2185
- ] })
2260
+ ]
2186
2261
  },
2187
2262
  service.id
2188
2263
  );
@@ -2190,41 +2265,43 @@ function DefaultServiceSelectionStep({
2190
2265
  ] }) : null,
2191
2266
  booking.resources.state.tag === "loading" ? /* @__PURE__ */ jsxs("div", { className: "ab-center", children: [
2192
2267
  /* @__PURE__ */ jsx(SpinnerNode, { size: "md", srLabel: "Loading practitioners" }),
2193
- /* @__PURE__ */ jsx("p", { className: "ab-text ab-text--muted", children: "Loading practitioners..." })
2268
+ /* @__PURE__ */ jsx("p", { className: "ab-text rb-on-surface--muted", children: "Loading practitioners..." })
2194
2269
  ] }) : null,
2195
- booking.resources.state.tag === "error" ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "error", className: "ab-alert ab-alert--error", role: "alert", children: booking.resources.state.message }) : null,
2196
- showResourceSelect && booking.resources.state.tag === "loaded" && resources.length === 0 ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "error", className: "ab-alert ab-alert--error", role: "alert", children: "No practitioners are available for this service right now." }) : null,
2197
- showResourceSelect && booking.resources.state.tag !== "loading" && (allowAnyResource || resources.length > 0) ? /* @__PURE__ */ jsxs("div", { className: "ab-stack--sm", children: [
2198
- /* @__PURE__ */ jsxs("label", { className: "ab-subtitle", children: [
2270
+ booking.resources.state.tag === "error" ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "error", className: "alert alert-error", role: "alert", children: booking.resources.state.message }) : null,
2271
+ showResourceSelect && booking.resources.state.tag === "loaded" && resources.length === 0 ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "error", className: "alert alert-error", role: "alert", children: "No practitioners are available for this service right now." }) : null,
2272
+ showResourceSelect && booking.resources.state.tag !== "loading" && (allowAnyResource || resources.length > 0) ? /* @__PURE__ */ jsxs("div", { className: "rb-reg-stack rb-reg-stack--sm", children: [
2273
+ /* @__PURE__ */ jsxs("span", { className: "ab-subtitle", children: [
2199
2274
  "Practitioner",
2200
2275
  booking.resources.requiresSelection ? "" : " (Optional)"
2201
2276
  ] }),
2202
- /* @__PURE__ */ jsx("p", { className: "ab-text ab-text--muted", children: allowAnyResource ? 'Choose a specific practitioner or select "Any Available"' : "Choose the practitioner you'd like to book" }),
2203
- /* @__PURE__ */ jsxs("div", { className: "ab-grid", children: [
2204
- allowAnyResource ? /* @__PURE__ */ jsx(
2277
+ /* @__PURE__ */ jsx("p", { className: "ab-text rb-on-surface--muted", children: allowAnyResource ? 'Choose a specific practitioner or select "Any Available"' : "Choose the practitioner you'd like to book" }),
2278
+ /* @__PURE__ */ jsxs("div", { className: "rb-reg-grid", children: [
2279
+ allowAnyResource ? /* @__PURE__ */ jsxs(
2205
2280
  "button",
2206
2281
  {
2207
2282
  type: "button",
2208
2283
  onClick: () => booking.actions.selectResource(null),
2209
- className: `ab-card ${!selectedResourceId ? "ab-card--selected" : ""}`,
2210
- children: /* @__PURE__ */ jsxs("div", { className: "ab-row--between", children: [
2211
- /* @__PURE__ */ jsx("div", { className: "ab-subtitle", children: "Any Available" }),
2284
+ className: optionCardClassName(!selectedResourceId),
2285
+ "aria-pressed": !selectedResourceId,
2286
+ children: [
2287
+ /* @__PURE__ */ jsx("div", { className: "rb-flex-1 ab-subtitle", children: "Any Available" }),
2212
2288
  !selectedResourceId ? /* @__PURE__ */ jsx(SelectedCheck, {}) : null
2213
- ] })
2289
+ ]
2214
2290
  }
2215
2291
  ) : null,
2216
2292
  resources.map((resource) => {
2217
2293
  const isSelected = selectedResourceId === resource.id;
2218
- return /* @__PURE__ */ jsx(
2294
+ return /* @__PURE__ */ jsxs(
2219
2295
  "button",
2220
2296
  {
2221
2297
  type: "button",
2222
2298
  onClick: () => booking.actions.selectResource(resource.id),
2223
- className: `ab-card ${isSelected ? "ab-card--selected" : ""}`,
2224
- children: /* @__PURE__ */ jsxs("div", { className: "ab-row--between", children: [
2225
- /* @__PURE__ */ jsx("div", { className: "ab-subtitle", children: resource.label }),
2299
+ className: optionCardClassName(isSelected),
2300
+ "aria-pressed": isSelected,
2301
+ children: [
2302
+ /* @__PURE__ */ jsx("div", { className: "rb-flex-1 ab-subtitle", children: resource.label }),
2226
2303
  isSelected ? /* @__PURE__ */ jsx(SelectedCheck, {}) : null
2227
- ] })
2304
+ ]
2228
2305
  },
2229
2306
  resource.id
2230
2307
  );
@@ -2234,27 +2311,30 @@ function DefaultServiceSelectionStep({
2234
2311
  ] });
2235
2312
  }
2236
2313
  function DefaultDateTimeSelectionStep({
2237
- booking
2314
+ booking,
2315
+ errorSummaryId
2238
2316
  }) {
2239
2317
  const selectedDate = booking.availability.selectedDate ?? "";
2240
- const selectedSlotStart = booking.availability.selectedSlot?.startAt ?? "";
2318
+ const selectedSlotKey = booking.availability.selectedSlot?.key ?? "";
2241
2319
  const singleService = booking.services.items.length === 1 ? booking.services.items[0] : void 0;
2242
- const slots = collapseHeadlessSlotsForDisplay({
2320
+ const slots = deriveBookingSlotDisplayOptions({
2243
2321
  slots: booking.availability.slots,
2244
2322
  hasSelectedResource: Boolean(booking.resources.selectedResourceId)
2245
2323
  });
2246
2324
  const error = booking.availability.datesState.tag === "error" ? booking.availability.datesState.message : booking.availability.slotsState.tag === "error" ? booking.availability.slotsState.message : null;
2247
- return /* @__PURE__ */ jsxs("div", { className: "ab-stack", children: [
2248
- singleService ? /* @__PURE__ */ jsxs("div", { className: "ab-info-box", children: [
2325
+ const hasValidationError = Boolean(booking.currentStep?.errors.formError);
2326
+ const validationDescribedBy = hasValidationError ? errorSummaryId : void 0;
2327
+ return /* @__PURE__ */ jsxs("div", { className: "rb-reg-stack", children: [
2328
+ singleService ? /* @__PURE__ */ jsxs("div", { className: "rb-reg-summary", children: [
2249
2329
  /* @__PURE__ */ jsx("h3", { className: "ab-subtitle", children: singleService.title }),
2250
- singleService.description ? /* @__PURE__ */ jsx("p", { className: "ab-text ab-text--muted", children: singleService.description }) : null,
2251
- singleService.durationMinutes ? /* @__PURE__ */ jsxs("p", { className: "ab-text ab-text--muted", children: [
2330
+ singleService.description ? /* @__PURE__ */ jsx("p", { className: "ab-text rb-on-surface--muted", children: singleService.description }) : null,
2331
+ singleService.durationMinutes ? /* @__PURE__ */ jsxs("p", { className: "ab-text rb-on-surface--muted", children: [
2252
2332
  "Duration: ",
2253
2333
  singleService.durationMinutes,
2254
2334
  " minutes"
2255
2335
  ] }) : null
2256
2336
  ] }) : null,
2257
- error ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "error", className: "ab-alert ab-alert--error", role: "alert", children: error }) : null,
2337
+ error ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "error", className: "alert alert-error", role: "alert", children: error }) : null,
2258
2338
  /* @__PURE__ */ jsx(
2259
2339
  DatePicker,
2260
2340
  {
@@ -2263,6 +2343,8 @@ function DefaultDateTimeSelectionStep({
2263
2343
  dateOptions: [...booking.availability.availableDates],
2264
2344
  isLoading: booking.availability.datesState.tag === "loading",
2265
2345
  isEmpty: booking.availability.datesState.tag !== "loading" && booking.availability.availableDates.length === 0,
2346
+ ariaDescribedBy: validationDescribedBy,
2347
+ ariaInvalid: hasValidationError,
2266
2348
  hasMore: booking.availability.hasMoreDates,
2267
2349
  onLoadMore: booking.availability.loadMoreDates
2268
2350
  }
@@ -2270,16 +2352,17 @@ function DefaultDateTimeSelectionStep({
2270
2352
  selectedDate ? /* @__PURE__ */ jsx(
2271
2353
  TimeSlotSelector,
2272
2354
  {
2273
- value: selectedSlotStart,
2274
- onChange: (slotStartTime) => {
2355
+ value: selectedSlotKey,
2356
+ onChange: (slotKey) => {
2275
2357
  booking.actions.selectSlot(
2276
- booking.availability.slots.find(
2277
- (slot) => slot.startAt === slotStartTime
2278
- ) ?? null
2358
+ slots.find((slot) => slot.key === slotKey)?.slot ?? null
2279
2359
  );
2280
2360
  },
2281
2361
  slots,
2282
- isLoading: booking.availability.slotsState.tag === "loading"
2362
+ isLoading: booking.availability.slotsState.tag === "loading",
2363
+ timezone: booking.availability.timezone,
2364
+ ariaDescribedBy: validationDescribedBy,
2365
+ ariaInvalid: hasValidationError
2283
2366
  }
2284
2367
  ) : null
2285
2368
  ] });
@@ -2290,21 +2373,21 @@ function HeadlessBookingPaymentSelectionStep({
2290
2373
  const service = booking.services.selected;
2291
2374
  const viewModel = booking.payment.selection;
2292
2375
  if (booking.payment.kind === "unsupported") {
2293
- return /* @__PURE__ */ jsx(FeedbackMessage, { tone: "error", className: "ab-alert ab-alert--error", role: "alert", children: booking.payment.errorMessage });
2376
+ return /* @__PURE__ */ jsx(FeedbackMessage, { tone: "error", className: "alert alert-error", role: "alert", children: booking.payment.errorMessage });
2294
2377
  }
2295
2378
  if (!service || !viewModel) {
2296
- return /* @__PURE__ */ jsx(FeedbackMessage, { tone: "error", className: "ab-alert ab-alert--error", role: "alert", children: "Payment options are unavailable for this service right now." });
2379
+ return /* @__PURE__ */ jsx(FeedbackMessage, { tone: "error", className: "alert alert-error", role: "alert", children: "Payment options are unavailable for this service right now." });
2297
2380
  }
2298
2381
  const packageOptions = booking.payment.appointmentPackages.items;
2299
2382
  const hasPackageOptions = packageOptions.length > 0;
2300
2383
  const slidingScale = booking.payment.slidingScale;
2301
- return /* @__PURE__ */ jsxs("div", { className: "ab-stack", children: [
2302
- /* @__PURE__ */ jsxs("div", { className: "ab-info-box", children: [
2384
+ return /* @__PURE__ */ jsxs("div", { className: "rb-reg-stack", children: [
2385
+ /* @__PURE__ */ jsxs("div", { className: "rb-reg-summary", children: [
2303
2386
  /* @__PURE__ */ jsx("h3", { className: "ab-subtitle", children: viewModel.sectionTitle }),
2304
- /* @__PURE__ */ jsx("p", { className: "ab-text ab-text--muted", children: service.title })
2387
+ /* @__PURE__ */ jsx("p", { className: "ab-text rb-on-surface--muted", children: service.title })
2305
2388
  ] }),
2306
- booking.payment.appointmentPackages.state.tag === "loading" ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "info", className: "ab-alert ab-alert--info", role: "status", children: "Checking package credits..." }) : null,
2307
- booking.payment.appointmentPackages.state.tag === "error" ? /* @__PURE__ */ jsxs(FeedbackMessage, { tone: "info", className: "ab-alert ab-alert--info", role: "status", children: [
2389
+ booking.payment.appointmentPackages.state.tag === "loading" ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "info", className: "alert alert-info", role: "status", children: "Checking package credits..." }) : null,
2390
+ booking.payment.appointmentPackages.state.tag === "error" ? /* @__PURE__ */ jsxs(FeedbackMessage, { tone: "info", className: "alert alert-info", role: "status", children: [
2308
2391
  booking.payment.appointmentPackages.state.message,
2309
2392
  " You can continue with the normal payment option."
2310
2393
  ] }) : null,
@@ -2330,47 +2413,47 @@ function HeadlessBookingPaymentSelectionStep({
2330
2413
  }
2331
2414
  )
2332
2415
  ] }) : null,
2333
- /* @__PURE__ */ jsxs("div", { className: "ab-stack", role: "list", "aria-label": "Payment options", children: [
2334
- packageOptions.map((appointmentPackage) => {
2335
- const isSelected = booking.payment.selectedAppointmentPackageId === appointmentPackage.customerPassId;
2336
- return /* @__PURE__ */ jsx(
2337
- "button",
2338
- {
2339
- type: "button",
2340
- className: themeButtonClassName({
2341
- variant: isSelected ? "primary" : "outline",
2342
- size: "md"
2343
- }),
2344
- style: paymentOptionLayoutStyle,
2345
- onClick: () => booking.actions.selectAppointmentPackage(
2346
- appointmentPackage.customerPassId
2347
- ),
2348
- "aria-pressed": isSelected,
2349
- children: /* @__PURE__ */ jsx(
2350
- PaymentOptionContent,
2416
+ /* @__PURE__ */ jsxs(
2417
+ "div",
2418
+ {
2419
+ className: "rb-reg-stack rb-reg-stack--sm",
2420
+ role: "list",
2421
+ "aria-label": "Payment options",
2422
+ children: [
2423
+ packageOptions.map((appointmentPackage) => {
2424
+ const isSelected = booking.payment.selectedAppointmentPackageId === appointmentPackage.customerPassId;
2425
+ return /* @__PURE__ */ jsxs(
2426
+ "button",
2351
2427
  {
2352
- id: appointmentPackage.customerPassId,
2353
- title: appointmentPackage.passName,
2354
- description: "Use 1 package credit",
2355
- summaryRows: [{
2356
- label: "Balance",
2357
- value: `${appointmentPackage.creditsRemaining} of ${appointmentPackage.creditsTotal} credits remaining`
2358
- }]
2359
- }
2360
- )
2361
- },
2362
- appointmentPackage.customerPassId
2363
- );
2364
- }),
2365
- viewModel.options.map((option) => {
2366
- const isSelected = !booking.payment.selectedAppointmentPackageId && (booking.payment.selectedCollectionOptionKind === option.kind || viewModel.mode === "single_option");
2367
- if (viewModel.mode === "single_option" && !hasPackageOptions) {
2368
- return /* @__PURE__ */ jsx(
2369
- "div",
2370
- {
2371
- className: "ab-card",
2372
- style: paymentOptionLayoutStyle,
2373
- children: /* @__PURE__ */ jsx(
2428
+ type: "button",
2429
+ className: optionCardClassName(isSelected),
2430
+ onClick: () => booking.actions.selectAppointmentPackage(
2431
+ appointmentPackage.customerPassId
2432
+ ),
2433
+ "aria-pressed": isSelected,
2434
+ children: [
2435
+ /* @__PURE__ */ jsx(
2436
+ PaymentOptionContent,
2437
+ {
2438
+ id: appointmentPackage.customerPassId,
2439
+ title: appointmentPackage.passName,
2440
+ description: "Use 1 package credit",
2441
+ summaryRows: [{
2442
+ label: "Balance",
2443
+ value: `${appointmentPackage.creditsRemaining} of ${appointmentPackage.creditsTotal} credits remaining`
2444
+ }]
2445
+ }
2446
+ ),
2447
+ isSelected ? /* @__PURE__ */ jsx(SelectedCheck, {}) : null
2448
+ ]
2449
+ },
2450
+ appointmentPackage.customerPassId
2451
+ );
2452
+ }),
2453
+ viewModel.options.map((option) => {
2454
+ const isSelected = !booking.payment.selectedAppointmentPackageId && (booking.payment.selectedCollectionOptionKind === option.kind || viewModel.mode === "single_option");
2455
+ if (viewModel.mode === "single_option" && !hasPackageOptions) {
2456
+ return /* @__PURE__ */ jsx("div", { className: "rb-reg-summary", children: /* @__PURE__ */ jsx(
2374
2457
  PaymentOptionContent,
2375
2458
  {
2376
2459
  id: option.kind,
@@ -2379,37 +2462,35 @@ function HeadlessBookingPaymentSelectionStep({
2379
2462
  summaryRows: option.summaryRows,
2380
2463
  helperText: option.helperText
2381
2464
  }
2382
- )
2383
- },
2384
- option.kind
2385
- );
2386
- }
2387
- return /* @__PURE__ */ jsx(
2388
- "button",
2389
- {
2390
- type: "button",
2391
- className: themeButtonClassName({
2392
- variant: isSelected ? "primary" : "outline",
2393
- size: "md"
2394
- }),
2395
- style: paymentOptionLayoutStyle,
2396
- onClick: () => booking.actions.selectPaymentOption(option.kind),
2397
- "aria-pressed": isSelected,
2398
- children: /* @__PURE__ */ jsx(
2399
- PaymentOptionContent,
2465
+ ) }, option.kind);
2466
+ }
2467
+ return /* @__PURE__ */ jsxs(
2468
+ "button",
2400
2469
  {
2401
- id: option.kind,
2402
- title: option.title,
2403
- description: option.description,
2404
- summaryRows: option.summaryRows,
2405
- helperText: option.helperText
2406
- }
2407
- )
2408
- },
2409
- option.kind
2410
- );
2411
- })
2412
- ] })
2470
+ type: "button",
2471
+ className: optionCardClassName(isSelected),
2472
+ onClick: () => booking.actions.selectPaymentOption(option.kind),
2473
+ "aria-pressed": isSelected,
2474
+ children: [
2475
+ /* @__PURE__ */ jsx(
2476
+ PaymentOptionContent,
2477
+ {
2478
+ id: option.kind,
2479
+ title: option.title,
2480
+ description: option.description,
2481
+ summaryRows: option.summaryRows,
2482
+ helperText: option.helperText
2483
+ }
2484
+ ),
2485
+ isSelected ? /* @__PURE__ */ jsx(SelectedCheck, {}) : null
2486
+ ]
2487
+ },
2488
+ option.kind
2489
+ );
2490
+ })
2491
+ ]
2492
+ }
2493
+ )
2413
2494
  ] });
2414
2495
  }
2415
2496
  function PaymentOptionContent({
@@ -2419,15 +2500,15 @@ function PaymentOptionContent({
2419
2500
  summaryRows,
2420
2501
  title
2421
2502
  }) {
2422
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2423
- /* @__PURE__ */ jsx("span", { children: title }),
2424
- /* @__PURE__ */ jsx("span", { className: "ab-text ab-text--muted", children: description }),
2425
- /* @__PURE__ */ jsx("div", { className: "ab-stack", style: summaryStackStyle, children: summaryRows.map((row) => /* @__PURE__ */ jsxs("span", { className: "ab-text ab-text--muted", children: [
2503
+ return /* @__PURE__ */ jsxs("div", { className: "rb-flex-1", children: [
2504
+ /* @__PURE__ */ jsx("div", { className: "ab-subtitle", children: title }),
2505
+ /* @__PURE__ */ jsx("div", { className: "ab-text rb-on-surface--muted", children: description }),
2506
+ /* @__PURE__ */ jsx("div", { className: "ab-option-rows", children: summaryRows.map((row) => /* @__PURE__ */ jsxs("span", { className: "ab-text rb-on-surface--muted", children: [
2426
2507
  row.label,
2427
2508
  ": ",
2428
2509
  row.value
2429
2510
  ] }, `${id}-${row.label}`)) }),
2430
- helperText ? /* @__PURE__ */ jsx("span", { className: "ab-text ab-text--muted", children: helperText }) : null
2511
+ helperText ? /* @__PURE__ */ jsx("div", { className: "ab-text rb-on-surface--muted", children: helperText }) : null
2431
2512
  ] });
2432
2513
  }
2433
2514
  function DefaultDynamicFields({
@@ -2699,7 +2780,7 @@ function DefaultBookingDiscount({
2699
2780
  }
2700
2781
  }
2701
2782
  ) : null,
2702
- booking.discount.autoAppliedDiscount && booking.discount.code.trim().length === 0 ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "info", className: "ab-alert ab-alert--info rb-mt-4", role: "status", children: /* @__PURE__ */ jsxs("p", { className: "ab-text", children: [
2783
+ booking.discount.autoAppliedDiscount && booking.discount.code.trim().length === 0 ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "info", className: "alert alert-info rb-mt-4", role: "status", children: /* @__PURE__ */ jsxs("p", { className: "ab-text", children: [
2703
2784
  "Discount available: ",
2704
2785
  booking.discount.autoAppliedDiscount.publicLabel,
2705
2786
  " ",
@@ -2711,7 +2792,7 @@ function DefaultBookingFeedback({
2711
2792
  booking
2712
2793
  }) {
2713
2794
  if (booking.feedback.kind !== "error") return null;
2714
- return /* @__PURE__ */ jsxs(FeedbackMessage, { tone: "error", className: "ab-alert ab-alert--error", role: "alert", children: [
2795
+ return /* @__PURE__ */ jsxs(FeedbackMessage, { tone: "error", className: "alert alert-error rb-mt-4", role: "alert", children: [
2715
2796
  /* @__PURE__ */ jsx("p", { className: "ab-text", children: booking.feedback.message }),
2716
2797
  /* @__PURE__ */ jsx(
2717
2798
  "button",
@@ -2737,43 +2818,26 @@ function DefaultBookingAltcha({
2737
2818
  ) });
2738
2819
  }
2739
2820
  function DefaultBookingErrorSummary({
2740
- errors
2821
+ errors,
2822
+ id
2741
2823
  }) {
2742
2824
  if (!hasBookingValidationErrors(errors)) return null;
2743
- return /* @__PURE__ */ jsxs(FeedbackMessage, { tone: "error", className: "rb-mt-6 alert alert-error", role: "alert", children: [
2744
- errors.formError ? /* @__PURE__ */ jsx("p", { className: "rb-caption", children: /* @__PURE__ */ jsx("strong", { children: errors.formError }) }) : null,
2745
- Object.entries(errors.fieldErrors).map(([key, message]) => /* @__PURE__ */ jsx("p", { className: "rb-caption", children: message }, key))
2746
- ] });
2747
- }
2748
- function SelectedCheck() {
2749
- return /* @__PURE__ */ jsx("div", { className: "ab-check", children: /* @__PURE__ */ jsx(
2750
- "svg",
2825
+ return /* @__PURE__ */ jsxs(
2826
+ FeedbackMessage,
2751
2827
  {
2752
- fill: "none",
2753
- strokeLinecap: "round",
2754
- strokeLinejoin: "round",
2755
- strokeWidth: "2",
2756
- viewBox: "0 0 24 24",
2757
- stroke: "currentColor",
2758
- children: /* @__PURE__ */ jsx("path", { d: "M5 13l4 4L19 7" })
2828
+ tone: "error",
2829
+ className: "rb-mt-6 alert alert-error",
2830
+ id,
2831
+ role: "alert",
2832
+ children: [
2833
+ errors.formError ? /* @__PURE__ */ jsx("p", { className: "rb-caption", children: /* @__PURE__ */ jsx("strong", { children: errors.formError }) }) : null,
2834
+ Object.entries(errors.fieldErrors).map(([key, message]) => /* @__PURE__ */ jsx("p", { className: "rb-caption", children: message }, key))
2835
+ ]
2759
2836
  }
2760
- ) });
2837
+ );
2761
2838
  }
2762
- function collapseHeadlessSlotsForDisplay(input) {
2763
- const seenStartTimes = /* @__PURE__ */ new Set();
2764
- const visibleSlots = [];
2765
- for (const slot of input.slots) {
2766
- if (!input.hasSelectedResource) {
2767
- if (seenStartTimes.has(slot.startAt)) continue;
2768
- seenStartTimes.add(slot.startAt);
2769
- }
2770
- visibleSlots.push({
2771
- startAt: slot.startAt,
2772
- endAt: slot.endAt,
2773
- resourceId: unsafeAsAppointmentResourceId(slot.resourceId)
2774
- });
2775
- }
2776
- return visibleSlots;
2839
+ function SelectedCheck() {
2840
+ return /* @__PURE__ */ jsx("div", { className: "rb-option-check", children: /* @__PURE__ */ jsx(CheckIcon, {}) });
2777
2841
  }
2778
2842
  var PORTAL_REBOOK_QUERY_PARAM = "rebook";
2779
2843
  var PORTAL_REBOOK_QUERY_VALUE = "1";
@@ -2799,6 +2863,14 @@ function appendRebookFlag(url, enabled) {
2799
2863
  );
2800
2864
  return nextUrl.toString();
2801
2865
  }
2866
+ function BookingSurface({
2867
+ id,
2868
+ className,
2869
+ children
2870
+ }) {
2871
+ const classes = ["rb-reg-surface", className ?? ""].join(" ").trim();
2872
+ return /* @__PURE__ */ jsx("div", { id, className: classes, children });
2873
+ }
2802
2874
  var BookingFormClient = ({
2803
2875
  siteId: siteIdProp,
2804
2876
  render
@@ -2896,7 +2968,7 @@ var BookingFormClient = ({
2896
2968
  FeedbackMessage,
2897
2969
  {
2898
2970
  tone: "error",
2899
- className: `ab-alert ab-alert--error ${render.display.className ?? ""}`.trim(),
2971
+ className: `alert alert-error ${render.display.className ?? ""}`.trim(),
2900
2972
  role: "alert",
2901
2973
  children: /* @__PURE__ */ jsx("p", { className: "ab-text", children: render.display.message ?? "Booking form not found. Please check your configuration." })
2902
2974
  }
@@ -2918,28 +2990,20 @@ var BookingFormClient = ({
2918
2990
  }
2919
2991
  };
2920
2992
  if (viewState.kind === "success") {
2921
- return /* @__PURE__ */ jsx(
2993
+ return /* @__PURE__ */ jsx(BookingSurface, { id: bookingAnchorId, className: render.display.className, children: /* @__PURE__ */ jsx(
2922
2994
  SuccessMessage,
2923
2995
  {
2924
2996
  message: getBookingSuccessMessage(render.display.successMessage),
2925
- resourceName: viewState.resourceName,
2926
- className: render.display.className ?? void 0
2997
+ resourceName: viewState.resourceName
2927
2998
  }
2928
- );
2999
+ ) });
2929
3000
  }
2930
3001
  if (viewState.kind === "verifying") {
2931
- return /* @__PURE__ */ jsx(
2932
- "div",
2933
- {
2934
- id: bookingAnchorId,
2935
- className: render.display.className ?? void 0,
2936
- children: /* @__PURE__ */ jsx(FeedbackMessage, { tone: "info", className: "ab-alert ab-alert--info", role: "status", children: /* @__PURE__ */ jsx("p", { className: "ab-text", children: viewState.message }) })
2937
- }
2938
- );
3002
+ return /* @__PURE__ */ jsx(BookingSurface, { id: bookingAnchorId, className: render.display.className, children: /* @__PURE__ */ jsx(FeedbackMessage, { tone: "info", className: "alert alert-info", role: "status", children: /* @__PURE__ */ jsx("p", { className: "ab-text", children: viewState.message }) }) });
2939
3003
  }
2940
- return /* @__PURE__ */ jsxs("div", { id: bookingAnchorId, className: render.display.className ?? void 0, children: [
2941
- render.hydration.noticeMessage ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "info", className: "ab-alert ab-alert--info rb-mb-4", role: "status", children: /* @__PURE__ */ jsx("p", { className: "ab-text", children: render.hydration.noticeMessage }) }) : null,
2942
- viewState.kind === "error" ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "error", className: "ab-alert ab-alert--error", role: "alert", children: /* @__PURE__ */ jsx("p", { className: "ab-text", children: viewState.message }) }) : null,
3004
+ return /* @__PURE__ */ jsxs(BookingSurface, { id: bookingAnchorId, className: render.display.className, children: [
3005
+ render.hydration.noticeMessage ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "info", className: "alert alert-info rb-mb-4", role: "status", children: /* @__PURE__ */ jsx("p", { className: "ab-text", children: render.hydration.noticeMessage }) }) : null,
3006
+ viewState.kind === "error" ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "error", className: "alert alert-error rb-mb-4", role: "alert", children: /* @__PURE__ */ jsx("p", { className: "ab-text", children: viewState.message }) }) : null,
2943
3007
  /* @__PURE__ */ jsx(HeadlessBookingDefaultForm, { booking, onSubmit: handleComplete })
2944
3008
  ] });
2945
3009
  };