@riverbankcms/sdk 0.136.0 → 0.137.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 (160) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/dist/{PreviewEditorSidebar-BU5ZlhQR.mjs → PreviewEditorSidebar-Bn6cONPa.mjs} +8 -8
  3. package/dist/{PreviewEditorUI-9XkHL-bC.mjs → PreviewEditorUI-LAwXZPSx.mjs} +3 -3
  4. package/dist/{PreviewQueryProvider-wbEpXryy.mjs → PreviewQueryProvider-ztQUdsNo.mjs} +1 -1
  5. package/dist/{SdkPreviewModeRuntime-CnWmj-2B.mjs → SdkPreviewModeRuntime-BbbGsI_v.mjs} +596 -164
  6. package/dist/{SiteChromeCustomizeContext-B6d5zkog.mjs → SiteChromeCustomizeContext-BbkNSt5a.mjs} +2888 -1404
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +12 -298
  8. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +21 -14
  9. package/dist/_dts/ai/src/designer/themePatch.d.ts +5 -10
  10. package/dist/_dts/api/src/accessAdmin.d.ts +1 -9
  11. package/dist/_dts/api/src/accountApi.d.ts +49 -2
  12. package/dist/_dts/api/src/contentRuntime.d.ts +1 -4
  13. package/dist/_dts/api/src/domainConnection.d.ts +41 -0
  14. package/dist/_dts/api/src/endpoints.d.ts +194 -181
  15. package/dist/_dts/api/src/index.d.ts +4 -3
  16. package/dist/_dts/api/src/media.d.ts +19 -2
  17. package/dist/_dts/api/src/sdkContracts.d.ts +2 -15
  18. package/dist/_dts/api/src/sdkMediaContracts.d.ts +40 -0
  19. package/dist/_dts/api/src/sdkMediaEndpointDefinitions.d.ts +61 -0
  20. package/dist/_dts/api/src/sdkThemeWire.d.ts +15 -4
  21. package/dist/_dts/api/src/siteInfrastructure.d.ts +17 -23
  22. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +7 -21
  23. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +27 -3
  24. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +37 -17
  25. package/dist/_dts/api/src/types.d.ts +1 -1
  26. package/dist/_dts/blocks/src/PageRenderer.d.ts +2 -2
  27. package/dist/_dts/blocks/src/index.d.ts +1 -1
  28. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +9 -0
  29. package/dist/_dts/blocks/src/pageRendererBlockSupport.d.ts +75 -0
  30. package/dist/_dts/blocks/src/pageRendererBoundaries.d.ts +2 -0
  31. package/dist/_dts/blocks/src/server.d.ts +1 -1
  32. package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +1 -1
  33. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +2 -1
  34. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.d.ts +3 -3
  35. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +34 -22
  36. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/ErrorStep.d.ts +3 -5
  37. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +2 -0
  38. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.d.ts +1 -1
  39. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.d.ts +2 -0
  40. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorPresentation.d.ts +5 -0
  41. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.d.ts +25 -0
  42. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationWizardContext.d.ts +4 -0
  43. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.d.ts +7 -3
  44. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +2 -0
  45. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +5 -2
  46. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useWaitlistClaimRestoration.d.ts +2 -0
  47. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/capacity.d.ts +164 -0
  48. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/cta.d.ts +29 -0
  49. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/dates.d.ts +47 -0
  50. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/index.d.ts +14 -0
  51. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/people.d.ts +6 -0
  52. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/pricing.d.ts +31 -0
  53. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/OfferingTitle.d.ts +11 -0
  54. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekAgendaView.d.ts +1 -1
  55. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekBoardView.d.ts +1 -1
  56. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/index.d.ts +3 -1
  57. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/listingLayout.d.ts +23 -0
  58. package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +57 -0
  59. package/dist/_dts/commerce/src/purchase/index.d.ts +1 -0
  60. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +8 -40
  61. package/dist/_dts/db/src/index.d.ts +1 -0
  62. package/dist/_dts/db/src/utils/postgrestFilter.d.ts +2 -0
  63. package/dist/_dts/media-core/src/bulkDeletePlanning.d.ts +4 -0
  64. package/dist/_dts/media-core/src/fileDomain.d.ts +3 -0
  65. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +1 -0
  66. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +1 -0
  67. package/dist/_dts/preview-next/src/client/preview/SiteChromeCustomizeContext.d.ts +3 -2
  68. package/dist/_dts/preview-next/src/client/preview/siteChromeBrandPreferences.d.ts +1 -1
  69. package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlHistoryState.d.ts +2 -0
  70. package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlSaveRequest.d.ts +51 -0
  71. package/dist/_dts/preview-next/src/client/preview/siteChromeSavePlan.d.ts +24 -2
  72. package/dist/_dts/preview-next/src/client/preview/siteStylePreviewPlanner.d.ts +23 -1
  73. package/dist/_dts/preview-next/src/client/preview/usePersistedHeaderPreferences.d.ts +8 -0
  74. package/dist/_dts/sdk/src/public-api/contracts.d.ts +2 -1
  75. package/dist/_dts/sdk/src/version.d.ts +1 -1
  76. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  77. package/dist/_dts/theme-core/src/gradients/types.d.ts +5 -0
  78. package/dist/_dts/theme-core/src/header/interactionPalette.d.ts +25 -2
  79. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +3 -3
  80. package/dist/_dts/theme-core/src/schema.d.ts +12 -11
  81. package/dist/_dts/theme-core/src/site-styles/compilationPlan.d.ts +43 -3
  82. package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +10 -0
  83. package/dist/_dts/theme-core/src/site-styles/headerBrandPresentation.d.ts +63 -0
  84. package/dist/_dts/theme-core/src/site-styles/headerBytesComparison.d.ts +30 -0
  85. package/dist/_dts/theme-core/src/site-styles/headerInteractionPalette.d.ts +50 -1
  86. package/dist/_dts/theme-core/src/site-styles/headerLayoutCatalog.d.ts +48 -9
  87. package/dist/_dts/theme-core/src/site-styles/headerPreferences.d.ts +162 -0
  88. package/dist/_dts/theme-core/src/site-styles/headerPreferencesPersistence.d.ts +73 -0
  89. package/dist/_dts/theme-core/src/site-styles/headerRecompile.d.ts +118 -0
  90. package/dist/_dts/theme-core/src/site-styles/headerStyleCompiler.d.ts +10 -1
  91. package/dist/_dts/theme-core/src/site-styles/headerStyleDefaults.d.ts +1 -1
  92. package/dist/_dts/theme-core/src/site-styles/headerStyleRecipe.d.ts +7 -0
  93. package/dist/_dts/theme-core/src/site-styles/index.d.ts +5 -0
  94. package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +1 -1
  95. package/dist/_dts/theme-core/src/site-styles/siteChromeBackgrounds.d.ts +20 -1
  96. package/dist/_dts/theme-core/src/site-styles/siteChromeNavPreferences.d.ts +43 -2
  97. package/dist/client/{BookingConsentAgreement-DCch21a6.mjs → BookingConsentAgreement--_fUCZe-.mjs} +2 -2
  98. package/dist/client/{DiscountCodeDisclosure-DIj1T59K.mjs → DiscountCodeDisclosure-BMipSoDJ.mjs} +1 -1
  99. package/dist/client/{EventCombined.client-BWVNlXTx.mjs → EventCombined.client-CwJOxn7A.mjs} +154 -178
  100. package/dist/client/{EventListing.client-DVFCDe3i.mjs → EventListing.client-eVwiylPW.mjs} +2 -2
  101. package/dist/client/{LeafletStaticMap-BY5mIHw9.mjs → LeafletStaticMap-IKenna5u.mjs} +1 -1
  102. package/dist/client/{accordion-CK29E8rG.mjs → accordion-MGAO3PuE.mjs} +1 -1
  103. package/dist/client/{bookingForm-DFvnet-N.mjs → bookingForm-CudlQPUu.mjs} +5 -5
  104. package/dist/client/bookings.mjs +418 -79
  105. package/dist/client/capacity-BW00PO7s.mjs +271 -0
  106. package/dist/client/{carousel-BVU5NQlb.mjs → carousel-BrbGJ2Jl.mjs} +1 -1
  107. package/dist/client/{cart-BNItcZVa.mjs → cart-Bq5eU0xZ.mjs} +3 -3
  108. package/dist/client/{checkout-Bu6iCdkP.mjs → checkout-BAFVRdrK.mjs} +3 -3
  109. package/dist/client/client.mjs +2919 -1918
  110. package/dist/client/{context-BImarOAq.mjs → context-DCkiHVdD.mjs} +8 -5
  111. package/dist/client/dates-2RPXHQy4.mjs +264 -0
  112. package/dist/client/{eventCalendar-DS2h-UXD.mjs → eventCalendar-B0O-hPF7.mjs} +10 -17
  113. package/dist/client/{eventCombined-Drt4Oq9p.mjs → eventCombined-DCkDaoDI.mjs} +3 -3
  114. package/dist/client/{eventDetails-Bl2vWgTX.mjs → eventDetails-D8GG2dnD.mjs} +5 -3
  115. package/dist/client/{eventListing-CS7PHY7v.mjs → eventListing-3ssV_bxz.mjs} +3 -3
  116. package/dist/client/{eventRegistration-D-j8eNy2.mjs → eventRegistration-bPQo3kVw.mjs} +562 -309
  117. package/dist/client/{form-RMpoLTyr.mjs → form-qMv8RDkk.mjs} +2 -2
  118. package/dist/client/{headerSection-BYE3Lb3k.mjs → headerSection-CH0Sc5hX.mjs} +2 -2
  119. package/dist/client/hooks.mjs +289 -32
  120. package/dist/client/{locationMap-BxSr7Kkh.mjs → locationMap-0_xlBnNI.mjs} +2 -2
  121. package/dist/client/{newsletterForm-DerbXwFC.mjs → newsletterForm-NUW7m9RI.mjs} +2 -2
  122. package/dist/client/{productDetail-4SZCLhAf.mjs → productDetail-FBEOM7jW.mjs} +3 -3
  123. package/dist/client/{productList-D7AP4GNq.mjs → productList-R0OSGhnn.mjs} +3 -3
  124. package/dist/client/{propsDecoder-pzBeCh14.mjs → propsDecoder-pYvx_Srl.mjs} +88 -380
  125. package/dist/client/rendering/client.mjs +2616 -1637
  126. package/dist/client/rendering/islands.mjs +17 -17
  127. package/dist/client/rendering.mjs +2710 -1702
  128. package/dist/client/{scrollToBlock-CduAKf8T.mjs → scrollToBlock-ByQv96M2.mjs} +1 -1
  129. package/dist/client/{shop-Cp5p_kGe.mjs → shop-RUG9DmRE.mjs} +6 -6
  130. package/dist/client/{shop-commerce-DicXYaYX.mjs → shop-commerce-B76Jz23B.mjs} +5 -5
  131. package/dist/client/{shop-commerce-store-CGWnpY4K.mjs → shop-commerce-store-QuQNdDsD.mjs} +1 -1
  132. package/dist/client/{shopShared-BDf9ljkm.mjs → shopShared-vXU1omwJ.mjs} +3 -3
  133. package/dist/client/{useEventFilters-DeeyGYuk.mjs → useEventFilters-ByuU6HLA.mjs} +33 -18
  134. package/dist/preview-next/before-render.mjs +79 -51
  135. package/dist/preview-next/client/runtime.mjs +4 -4
  136. package/dist/preview-next/keepAlive.mjs +79 -51
  137. package/dist/preview-next/middleware.mjs +79 -51
  138. package/dist/{previewAuthStore-DbqBol0V.mjs → previewAuthStore-L_cKW8Sb.mjs} +79 -51
  139. package/dist/{sdk-runtime-19MO27F0.mjs → sdk-runtime-sUMr5d70.mjs} +2 -2
  140. package/dist/{separator-DaPLtJ1f.mjs → separator-BIHkie5i.mjs} +1 -1
  141. package/dist/server/components.mjs +2077 -1274
  142. package/dist/server/config-validation.mjs +289 -32
  143. package/dist/server/config.mjs +289 -32
  144. package/dist/server/data.mjs +289 -32
  145. package/dist/server/index.mjs +80 -52
  146. package/dist/server/next.mjs +1822 -1111
  147. package/dist/server/page-converter.mjs +167 -31
  148. package/dist/server/prebuild.mjs +1 -1
  149. package/dist/server/rendering/server.mjs +1988 -1286
  150. package/dist/server/rendering.mjs +1943 -1182
  151. package/dist/server/routing.mjs +351 -86
  152. package/dist/server/server.mjs +293 -128
  153. package/dist/server/theme-bridge.mjs +52 -8
  154. package/dist/server/theme.mjs +27 -8
  155. package/dist/styles/index.css +15 -0
  156. package/package.json +1 -1
  157. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCapacity.d.ts +0 -48
  158. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/pricing.d.ts +0 -17
  159. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/utils.d.ts +0 -100
  160. /package/dist/_dts/blocks/src/system/runtime/nodes/events/{shared → domain}/destination.d.ts +0 -0
@@ -456,10 +456,11 @@ function encodePublicProductCategorySelector(selector) {
456
456
  * Error thrown when an API request fails
457
457
  */
458
458
  var BlockApiError = class extends Error {
459
- constructor(message, status, code) {
459
+ constructor(message, status, code, tag) {
460
460
  super(message);
461
461
  this.status = status;
462
462
  this.code = code;
463
+ this.tag = tag;
463
464
  this.name = "BlockApiError";
464
465
  }
465
466
  };
@@ -491,7 +492,8 @@ function getBlockApiErrorDetails(data) {
491
492
  const nestedError = isRecord(data.error) ? data.error : void 0;
492
493
  return {
493
494
  message: typeof nestedError?.message === "string" ? nestedError.message : typeof data.message === "string" ? data.message : void 0,
494
- code: typeof nestedError?.code === "string" ? nestedError.code : typeof data.code === "string" ? data.code : void 0
495
+ code: typeof nestedError?.code === "string" ? nestedError.code : typeof data.code === "string" ? data.code : void 0,
496
+ tag: typeof nestedError?.tag === "string" ? nestedError.tag : void 0
495
497
  };
496
498
  }
497
499
  function buildUnexpectedJsonResponseMessage(parseResult) {
@@ -510,7 +512,8 @@ async function extractErrorDetails(response) {
510
512
  const details = getBlockApiErrorDetails(parseResult.value);
511
513
  return {
512
514
  message: details.message ?? fallbackMessage,
513
- code: details.code
515
+ code: details.code,
516
+ tag: details.tag
514
517
  };
515
518
  }
516
519
  case "invalid-json": return { message: `${fallbackMessage} (received invalid JSON)` };
@@ -607,7 +610,7 @@ function createBlockApi(config) {
607
610
  const response = await fetch(url, fetchOptions);
608
611
  if (!response.ok) {
609
612
  const details = await extractErrorDetails(response);
610
- throw new BlockApiError(details.message, response.status, details.code);
613
+ throw new BlockApiError(details.message, response.status, details.code, details.tag);
611
614
  }
612
615
  const json = await parseJsonApiResponse(response);
613
616
  if (isApiSuccessResponse(json)) return json.data;
@@ -1114,4 +1117,4 @@ function useBlockApi() {
1114
1117
  return client;
1115
1118
  }
1116
1119
  //#endregion
1117
- export { useBlockApi as n, BlockApiProvider as t };
1120
+ export { useBlockApi as n, BlockApiError as r, BlockApiProvider as t };
@@ -0,0 +1,264 @@
1
+ import { Bt as toScheduledBookingDateTime, H as resolveRuntimeEventDestination, Mt as formatBookingTime, Ot as formatBookingDate, Rt as toBookingTimeZone, kt as formatBookingDateParts, qt as assertNever, zt as toScheduledBookingDateRange } from "./propsDecoder-pYvx_Srl.mjs";
2
+ import { n as canJoinEventWaitlistOnAnyMode, u as isEventFull } from "./capacity-BW00PO7s.mjs";
3
+ //#region ../blocks/src/system/runtime/nodes/events/domain/cta.ts
4
+ /**
5
+ * Booking call-to-action resolution for events: where an event links to and
6
+ * what the button says. Sold-out and waitlist decisions come from capacity.ts
7
+ * so cards, rows and the wizard never disagree.
8
+ */
9
+ function closedEventBookingLabel(reason) {
10
+ switch (reason) {
11
+ case "occurrence_cancelled":
12
+ case "series_cancelled": return "Cancelled";
13
+ case "occurrence_completed":
14
+ case "series_completed": return "Completed";
15
+ case "series_draft":
16
+ case "series_archived":
17
+ case "parent_archived":
18
+ case "parent_inconsistent":
19
+ case "not_public":
20
+ case "already_started":
21
+ case "enrollment_closed": return "Registration closed";
22
+ default: return assertNever(reason);
23
+ }
24
+ }
25
+ function resolveEventHref(event) {
26
+ const destination = resolveRuntimeEventDestination(event);
27
+ return destination.kind === "external" ? destination.url : destination.path;
28
+ }
29
+ function resolveEventLinkProps(event) {
30
+ const href = resolveEventHref(event);
31
+ return resolveRuntimeEventDestination(event).kind === "external" ? {
32
+ href,
33
+ target: "_blank",
34
+ rel: "noopener noreferrer"
35
+ } : { href };
36
+ }
37
+ /**
38
+ * Resolve the CTA state for an event.
39
+ * Shared by EventCard and EventCompactRow to keep sold-out, registration-closed,
40
+ * and course-specific defaults consistent.
41
+ */
42
+ function resolveEventCta(event, buttonText) {
43
+ const isSoldOut = isEventFull(event);
44
+ const destination = resolveRuntimeEventDestination(event);
45
+ const isExternal = destination.kind === "external";
46
+ const defaultButtonText = isExternal ? destination.label : event.bookingScope === "whole_series" ? "Book course" : "Book";
47
+ const effectiveButtonText = buttonText ?? defaultButtonText;
48
+ const href = resolveEventHref(event);
49
+ if (event.bookingAvailability.kind === "closed") {
50
+ const linksToClosedWholeSeriesDetails = event.bookingAvailability.reason === "enrollment_closed" && !isExternal;
51
+ return {
52
+ label: closedEventBookingLabel(event.bookingAvailability.reason),
53
+ href,
54
+ external: isExternal,
55
+ hidden: !linksToClosedWholeSeriesDetails
56
+ };
57
+ }
58
+ if (!isExternal && isSoldOut) {
59
+ if (canJoinEventWaitlistOnAnyMode(event)) return {
60
+ label: "Join waitlist",
61
+ href,
62
+ external: false,
63
+ hidden: false
64
+ };
65
+ return {
66
+ label: "Sold out",
67
+ href,
68
+ external: false,
69
+ hidden: true
70
+ };
71
+ }
72
+ return {
73
+ label: effectiveButtonText,
74
+ href,
75
+ external: isExternal,
76
+ hidden: false
77
+ };
78
+ }
79
+ //#endregion
80
+ //#region ../calendar/src/timezone.ts
81
+ /**
82
+ * Timezone boundary helpers — internal.
83
+ *
84
+ * Both functions read an ISO instant in a given IANA timezone and project it
85
+ * onto the wall clock of that zone. They use Intl.DateTimeFormat with
86
+ * hourCycle: 'h23' to avoid 12/24-hour ambiguity. Used internally by the
87
+ * timetable model and `groupItemsByDate`; not exported from the package's
88
+ * public surface.
89
+ */
90
+ const MINUTES_PER_HOUR = 60;
91
+ /**
92
+ * Local minute-of-day [0, 24*60) for an ISO instant in the given zone.
93
+ * Returns NaN if the inputs cannot be parsed (caller should drop the item).
94
+ */
95
+ function getLocalMinuteOfDay(isoTimestamp, timeZone) {
96
+ const date = new Date(isoTimestamp);
97
+ if (Number.isNaN(date.getTime())) return NaN;
98
+ if (!isValidTimeZone(timeZone)) return NaN;
99
+ const parts = new Intl.DateTimeFormat("en-GB", {
100
+ timeZone,
101
+ hour: "2-digit",
102
+ minute: "2-digit",
103
+ hourCycle: "h23"
104
+ }).formatToParts(date);
105
+ const hourPart = Number(parts.find((part) => part.type === "hour")?.value);
106
+ const minute = Number(parts.find((part) => part.type === "minute")?.value);
107
+ const hour = hourPart === 24 ? 0 : hourPart;
108
+ if (Number.isNaN(hour) || Number.isNaN(minute)) return NaN;
109
+ return hour * MINUTES_PER_HOUR + minute;
110
+ }
111
+ /**
112
+ * Local YYYY-MM-DD for an ISO instant in the given zone.
113
+ * Returns null if the inputs cannot be parsed.
114
+ */
115
+ function getLocalDateKey(isoTimestamp, timeZone) {
116
+ const date = new Date(isoTimestamp);
117
+ if (Number.isNaN(date.getTime())) return null;
118
+ if (!isValidTimeZone(timeZone)) return null;
119
+ const parts = new Intl.DateTimeFormat("en-CA", {
120
+ timeZone,
121
+ year: "numeric",
122
+ month: "2-digit",
123
+ day: "2-digit"
124
+ }).formatToParts(date);
125
+ const year = parts.find((part) => part.type === "year")?.value;
126
+ const month = parts.find((part) => part.type === "month")?.value;
127
+ const day = parts.find((part) => part.type === "day")?.value;
128
+ if (year === void 0 || year.length === 0) return null;
129
+ if (month === void 0 || month.length === 0) return null;
130
+ if (day === void 0 || day.length === 0) return null;
131
+ return `${year}-${month}-${day}`;
132
+ }
133
+ const validTimeZoneCache = /* @__PURE__ */ new Map();
134
+ function isValidTimeZone(timeZone) {
135
+ if (typeof timeZone !== "string" || timeZone.length === 0) return false;
136
+ const cached = validTimeZoneCache.get(timeZone);
137
+ if (cached !== void 0) return cached;
138
+ try {
139
+ new Intl.DateTimeFormat("en-US", { timeZone });
140
+ validTimeZoneCache.set(timeZone, true);
141
+ return true;
142
+ } catch {
143
+ validTimeZoneCache.set(timeZone, false);
144
+ return false;
145
+ }
146
+ }
147
+ //#endregion
148
+ //#region ../calendar/src/group.ts
149
+ /**
150
+ * Group items by their local date (YYYY-MM-DD in the item's own timezone).
151
+ *
152
+ * Generic over `T`. Items with un-parseable startsAt or invalid timezone are
153
+ * silently dropped — call sites that need diagnostics should validate upstream.
154
+ *
155
+ * The output map preserves insertion order of dates (ES2015 spec) and the
156
+ * relative order of items within each date matches input order.
157
+ */
158
+ function groupItemsByDate(items, accessors) {
159
+ const grouped = /* @__PURE__ */ new Map();
160
+ for (const item of items) {
161
+ const dateKey = getLocalDateKey(accessors.getStartsAt(item), accessors.getTimeZone(item));
162
+ if (dateKey == null) continue;
163
+ const existing = grouped.get(dateKey);
164
+ if (existing !== void 0) existing.push(item);
165
+ else grouped.set(dateKey, [item]);
166
+ }
167
+ return grouped;
168
+ }
169
+ //#endregion
170
+ //#region ../blocks/src/system/runtime/nodes/events/domain/dates.ts
171
+ /**
172
+ * Date and time presentation for events: the single place an event's
173
+ * timestamps become strings or date buckets. Calendar-grid primitives are
174
+ * re-exported from @riverbankcms/calendar so block code has one import.
175
+ */
176
+ /**
177
+ * Format date for display.
178
+ * Returns: "Monday, January 15, 2025"
179
+ */
180
+ function formatDate(isoTimestamp, options) {
181
+ return formatBookingDate(toScheduledBookingDateTime({
182
+ startsAt: isoTimestamp,
183
+ timeZone: toBookingTimeZone(options?.timeZone ?? "UTC"),
184
+ locale: options?.locale ?? "en-US"
185
+ }), {
186
+ weekday: "long",
187
+ year: "numeric",
188
+ month: "long",
189
+ day: "numeric"
190
+ });
191
+ }
192
+ /**
193
+ * Format time for display.
194
+ * Returns: "10:00 AM"
195
+ */
196
+ function formatTime(isoTimestamp, options) {
197
+ return formatBookingTime(toScheduledBookingDateTime({
198
+ startsAt: isoTimestamp,
199
+ timeZone: toBookingTimeZone(options?.timeZone ?? "UTC"),
200
+ locale: options?.locale ?? "en-US"
201
+ }), {
202
+ hour: "numeric",
203
+ minute: "2-digit",
204
+ hour12: true
205
+ });
206
+ }
207
+ function formatEventDateParts(args) {
208
+ const scheduledRange = toScheduledBookingDateRange({
209
+ startsAt: args.startsAt,
210
+ endsAt: args.endsAt,
211
+ timeZone: toBookingTimeZone(args.timeZone ?? "UTC"),
212
+ locale: args.locale ?? "en-US"
213
+ });
214
+ const { date, time: start } = formatBookingDateParts(scheduledRange, { dateFormat: {
215
+ weekday: "long",
216
+ year: "numeric",
217
+ month: "long",
218
+ day: "numeric"
219
+ } });
220
+ return {
221
+ date,
222
+ timeRange: `${start} – ${formatBookingTime(toScheduledBookingDateTime({
223
+ startsAt: args.endsAt,
224
+ timeZone: scheduledRange.timeZone,
225
+ locale: args.locale ?? "en-US"
226
+ }))}`
227
+ };
228
+ }
229
+ function formatEventCompactDateRail(isoTimestamp, options) {
230
+ const dateTime = toScheduledBookingDateTime({
231
+ startsAt: isoTimestamp,
232
+ timeZone: toBookingTimeZone(options?.timeZone ?? "UTC"),
233
+ locale: options?.locale ?? "en-US"
234
+ });
235
+ const weekday = formatBookingDate(dateTime, { weekday: "short" }).toLocaleUpperCase(options?.locale ?? "en-US");
236
+ const month = formatBookingDate(dateTime, { month: "short" }).toLocaleUpperCase(options?.locale ?? "en-US");
237
+ return {
238
+ weekday,
239
+ day: formatBookingDate(dateTime, { day: "numeric" }),
240
+ month,
241
+ label: formatBookingDate(dateTime, {
242
+ weekday: "long",
243
+ year: "numeric",
244
+ month: "long",
245
+ day: "numeric"
246
+ })
247
+ };
248
+ }
249
+ /**
250
+ * Group events by their local date (YYYY-MM-DD key in each event's own
251
+ * timezone). Thin domain wrapper over `groupItemsByDate` from the calendar
252
+ * package; preserves the historical `Map<string, PublicEvent[]>` shape.
253
+ */
254
+ function groupEventsByDate(events, calendarTimeZone) {
255
+ const grouped = groupItemsByDate(events, {
256
+ getStartsAt: (event) => event.startsAt,
257
+ getTimeZone: () => calendarTimeZone
258
+ });
259
+ const map = /* @__PURE__ */ new Map();
260
+ for (const [dateKey, bucket] of grouped) map.set(dateKey, [...bucket]);
261
+ return map;
262
+ }
263
+ //#endregion
264
+ export { groupEventsByDate as a, resolveEventCta as c, formatTime as i, resolveEventLinkProps as l, formatEventCompactDateRail as n, getLocalDateKey as o, formatEventDateParts as r, getLocalMinuteOfDay as s, formatDate as t };
@@ -1,12 +1,14 @@
1
1
  "use client";
2
2
  import { D as clsx } from "./colorStyles-CrxJrPjJ.mjs";
3
- import { $ as getLocalMinuteOfDay, E as buildEventCalendarListingRender, H as formatEventTeacherLine, J as resolveEventLinkProps, K as groupEventsByDate, M as buildEventRuntimeFilters, N as getEventRuntimeFiltersKey, Q as getLocalDateKey, U as formatTime, X as getEventAvailability, Z as getEventAvailabilityStatus, st as themeButtonClassName, t as defineIslandPropsDecoder } from "./propsDecoder-pzBeCh14.mjs";
4
- import { o as EventFilters, t as useEventFilters } from "./useEventFilters-DeeyGYuk.mjs";
5
- import { a as CalendarDayCell, c as useCalendarEvents, d as formatDateKey, f as getDayOfWeek, g as isToday, h as isSameCalendarDay, i as WeekAgendaView, l as MONTH_NAMES, m as getWeekCalendarDays, o as EventModalProvider, p as getOrderedDayNames, r as EventModals, s as useEventModal, t as EventCombinedClient, u as addDays } from "./EventCombined.client-BWVNlXTx.mjs";
6
- import { t as BlockApiProvider } from "./context-BImarOAq.mjs";
3
+ import { E as buildEventCalendarListingRender, M as buildEventRuntimeFilters, N as getEventRuntimeFiltersKey, X as themeButtonClassName, t as defineIslandPropsDecoder } from "./propsDecoder-pYvx_Srl.mjs";
4
+ import { o as EventFilters, s as formatEventTeacherLine, t as useEventFilters } from "./useEventFilters-ByuU6HLA.mjs";
5
+ import { c as getEventAvailabilityStatus, r as formatEventRemainingPlaces, u as isEventFull } from "./capacity-BW00PO7s.mjs";
6
+ import { a as groupEventsByDate, i as formatTime, l as resolveEventLinkProps, o as getLocalDateKey, s as getLocalMinuteOfDay } from "./dates-2RPXHQy4.mjs";
7
+ import { a as CalendarDayCell, c as useCalendarEvents, d as formatDateKey, f as getDayOfWeek, g as isToday, h as isSameCalendarDay, i as WeekAgendaView, l as MONTH_NAMES, m as getWeekCalendarDays, o as EventModalProvider, p as getOrderedDayNames, r as EventModals, s as useEventModal, t as EventCombinedClient, u as addDays } from "./EventCombined.client-CwJOxn7A.mjs";
8
+ import { t as BlockApiProvider } from "./context-DCkiHVdD.mjs";
7
9
  import { t as mountReactIsland } from "./reactMount-SY8AVRof.mjs";
8
10
  import { t as buildRouteIslandApiConfig } from "./routeIslandApiConfig-UNsfPcYq.mjs";
9
- import { n as EventListingController } from "./EventListing.client-DVFCDe3i.mjs";
11
+ import { n as EventListingController } from "./EventListing.client-eVwiylPW.mjs";
10
12
  import { useEffect, useId, useMemo, useState } from "react";
11
13
  import { jsx, jsxs } from "react/jsx-runtime";
12
14
  //#region ../calendar/src/lane-packing.ts
@@ -630,7 +632,7 @@ function buildTimetableModel(input) {
630
632
  getEndsAt: (event) => event.endsAt,
631
633
  getTimeZone: (event) => event.timeZone ?? "UTC",
632
634
  getColor: (event) => event.eventCategory?.color ?? null,
633
- getOrderKey: (event) => `${event.title}${event.id}`
635
+ getOrderKey: (event) => `${event.title}\u0000${event.id}`
634
636
  });
635
637
  return {
636
638
  hourTicks: [...generic.hourTicks],
@@ -667,18 +669,9 @@ function toEventCell(cell) {
667
669
  };
668
670
  }
669
671
  function formatTimetableCapacity(event) {
670
- const { available, isFull } = getEventAvailability(event);
671
- if (available == null) return {
672
- label: null,
673
- isFull: false
674
- };
675
- if (isFull) return {
676
- label: "Full",
677
- isFull: true
678
- };
679
672
  return {
680
- label: `${available} spots left`,
681
- isFull: false
673
+ label: formatEventRemainingPlaces(event, { compact: true }),
674
+ isFull: isEventFull(event)
682
675
  };
683
676
  }
684
677
  function formatEventTimeRange(event) {
@@ -1,6 +1,6 @@
1
- import { t as defineIslandPropsDecoder } from "./propsDecoder-pzBeCh14.mjs";
2
- import { n as EventCombinedIslandClient } from "./EventCombined.client-BWVNlXTx.mjs";
3
- import { t as BlockApiProvider } from "./context-BImarOAq.mjs";
1
+ import { t as defineIslandPropsDecoder } from "./propsDecoder-pYvx_Srl.mjs";
2
+ import { n as EventCombinedIslandClient } from "./EventCombined.client-CwJOxn7A.mjs";
3
+ import { t as BlockApiProvider } from "./context-DCkiHVdD.mjs";
4
4
  import { t as mountReactIsland } from "./reactMount-SY8AVRof.mjs";
5
5
  import { t as buildRouteIslandApiConfig } from "./routeIslandApiConfig-UNsfPcYq.mjs";
6
6
  import "react";
@@ -1,6 +1,8 @@
1
- import { B as formatEventPrice, J as resolveEventLinkProps, Jt as toBookingTimeZone, O as resolveEventRegistrationScopedEvents, Qt as publicEventPricingType, Wt as getBookingLocalDateKey, Xt as publicEventPricingCurrency, Y as resolveRuntimeEventPricing, Yt as toScheduledBookingDateTime, et as formatWholeSeriesPriceAmount, nt as resolveWholeSeriesPricingState, t as defineIslandPropsDecoder, tn as formatCurrencyAmount, tt as formatWholeSeriesPriceDisplay, z as formatEventDateParts } from "./propsDecoder-pzBeCh14.mjs";
1
+ import { Bt as toScheduledBookingDateTime, G as resolveWholeSeriesPricingState, Kt as formatCurrencyAmount, O as resolveEventRegistrationScopedEvents, Pt as getBookingLocalDateKey, Rt as toBookingTimeZone, U as formatWholeSeriesPriceAmount, Ut as publicEventPricingType, V as resolveRuntimeEventPricing, Vt as publicEventPricingCurrency, W as formatWholeSeriesPriceDisplay, t as defineIslandPropsDecoder, z as formatEventPrice } from "./propsDecoder-pYvx_Srl.mjs";
2
+ import { o as formatTotalCapacity } from "./capacity-BW00PO7s.mjs";
3
+ import { l as resolveEventLinkProps, r as formatEventDateParts } from "./dates-2RPXHQy4.mjs";
2
4
  import { t as mountReactIsland } from "./reactMount-SY8AVRof.mjs";
3
- import { t as LeafletStaticMap } from "./LeafletStaticMap-BY5mIHw9.mjs";
5
+ import { t as LeafletStaticMap } from "./LeafletStaticMap-IKenna5u.mjs";
4
6
  import "react";
5
7
  import { jsx, jsxs } from "react/jsx-runtime";
6
8
  //#region ../blocks/src/system/runtime/nodes/events/shared/eventProductEligibility.ts
@@ -406,7 +408,7 @@ function EventFacts({ selection, selected, venue, teamMembers, pricing, showCapa
406
408
  children: [/* @__PURE__ */ jsx("div", {
407
409
  className: "rb-label rb-mb-2",
408
410
  children: "Places"
409
- }), /* @__PURE__ */ jsxs("p", { children: [selected.capacity, " places"] })]
411
+ }), /* @__PURE__ */ jsx("p", { children: formatTotalCapacity(selected.capacity) })]
410
412
  }) : null,
411
413
  pricing,
412
414
  selected.bookingScope === "whole_series" ? /* @__PURE__ */ jsxs("div", {
@@ -1,8 +1,8 @@
1
- import { t as defineIslandPropsDecoder } from "./propsDecoder-pzBeCh14.mjs";
2
- import { t as BlockApiProvider } from "./context-BImarOAq.mjs";
1
+ import { t as defineIslandPropsDecoder } from "./propsDecoder-pYvx_Srl.mjs";
2
+ import { t as BlockApiProvider } from "./context-DCkiHVdD.mjs";
3
3
  import { t as mountReactIsland } from "./reactMount-SY8AVRof.mjs";
4
4
  import { t as buildRouteIslandApiConfig } from "./routeIslandApiConfig-UNsfPcYq.mjs";
5
- import { t as EventListingClient } from "./EventListing.client-DVFCDe3i.mjs";
5
+ import { t as EventListingClient } from "./EventListing.client-eVwiylPW.mjs";
6
6
  import "react";
7
7
  import { jsx } from "react/jsx-runtime";
8
8
  //#region src/rendering/islands/enhancers/eventListing.tsx