@riverbankcms/sdk 0.74.0 → 0.76.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 (145) hide show
  1. package/README.md +2 -0
  2. package/dist/{PreviewEditorSidebar-5XL7M3OM.mjs → PreviewEditorSidebar-X2HWXFOL.mjs} +172 -89
  3. package/dist/{PreviewEditorUI-ZDFRDJID.mjs → PreviewEditorUI-AQXIXPOH.mjs} +3 -3
  4. package/dist/SdkPreviewModeRuntime-ZQNDCASH.mjs +8 -0
  5. package/dist/_dts/api/src/bookingOperations.d.ts +12 -0
  6. package/dist/_dts/api/src/cache-tags.d.ts +22 -0
  7. package/dist/_dts/api/src/contentRuntime.d.ts +1 -0
  8. package/dist/_dts/api/src/endpoints.d.ts +24 -24
  9. package/dist/_dts/api/src/index.d.ts +1 -1
  10. package/dist/_dts/api/src/publicExperienceEndpoints.d.ts +13 -4
  11. package/dist/_dts/block-form/src/blockDraftSaveability.d.ts +4 -2
  12. package/dist/_dts/block-form/src/client/index.d.ts +1 -1
  13. package/dist/_dts/block-form/src/manifest/utils.d.ts +24 -0
  14. package/dist/_dts/blocks/src/client/booking-form.d.ts +2 -0
  15. package/dist/_dts/blocks/src/client/carousel.d.ts +1 -0
  16. package/dist/_dts/blocks/src/client/course-registration.d.ts +2 -0
  17. package/dist/_dts/blocks/src/client/events.d.ts +6 -0
  18. package/dist/_dts/blocks/src/client/form.d.ts +2 -0
  19. package/dist/_dts/blocks/src/client/header.d.ts +1 -0
  20. package/dist/_dts/blocks/src/client/location-map.d.ts +1 -0
  21. package/dist/_dts/blocks/src/client/newsletter-form.d.ts +2 -0
  22. package/dist/_dts/blocks/src/client/shop.d.ts +6 -0
  23. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +4 -4
  24. package/dist/_dts/blocks/src/lib/video.d.ts +2 -0
  25. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +21 -1
  26. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +7 -6
  27. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +3 -3
  28. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +3 -2
  29. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.interactive.d.ts +3 -27
  30. package/dist/_dts/blocks/src/system/runtime/nodes/booking-runtime-sources.d.ts +163 -0
  31. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +5 -5
  32. package/dist/_dts/blocks/src/system/runtime/nodes/events/index.d.ts +3 -0
  33. package/dist/_dts/blocks/src/system/runtime/nodes/header-section.client.d.ts +1 -0
  34. package/dist/_dts/blocks/src/system/runtime/nodes/header-section.server.d.ts +1 -0
  35. package/dist/_dts/blocks/src/system/runtime/shared/components/BookingOptionCompactRow.d.ts +29 -0
  36. package/dist/_dts/blocks/src/system/runtime/shared/components/BookingOptionList.d.ts +13 -0
  37. package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +4 -0
  38. package/dist/_dts/blocks/src/system/runtime/shared/index.d.ts +4 -3
  39. package/dist/_dts/blocks/src/system/runtime/shared/utils/bookingRoute.d.ts +20 -0
  40. package/dist/_dts/blocks/src/system/runtime/shared/utils/index.d.ts +2 -1
  41. package/dist/_dts/blocks/src/system/types/link.d.ts +12 -0
  42. package/dist/_dts/content-editor/src/hooks/validateBlocksForPublish.d.ts +5 -0
  43. package/dist/_dts/editor-blocks/src/BlockEditor.d.ts +2 -0
  44. package/dist/_dts/editor-blocks/src/block-editor/BlockCard.d.ts +3 -1
  45. package/dist/_dts/editor-blocks/src/block-editor/BlockCardHeader.d.ts +3 -1
  46. package/dist/_dts/editor-blocks/src/block-editor/BlockSettingsModal.d.ts +5 -1
  47. package/dist/_dts/editor-blocks/src/block-editor/SortableBlockItem.d.ts +2 -0
  48. package/dist/_dts/editor-blocks/src/block-editor/actionControlMode.d.ts +2 -0
  49. package/dist/_dts/editor-blocks/src/index.d.ts +1 -1
  50. package/dist/_dts/preview-next/src/client/preview/SiteChromeEditableSurface.d.ts +12 -2
  51. package/dist/_dts/preview-next/src/client/preview/themeOverlay.d.ts +21 -3
  52. package/dist/_dts/sdk/src/components.d.ts +2 -2
  53. package/dist/_dts/sdk/src/public-api/contracts.d.ts +1 -0
  54. package/dist/_dts/sdk/src/rendering/index.d.ts +2 -2
  55. package/dist/_dts/sdk/src/rendering/islands/deferredVideoEmbeds.d.ts +2 -0
  56. package/dist/_dts/sdk/src/rendering/overrideResolution.d.ts +6 -0
  57. package/dist/_dts/sdk/src/rendering/overrides.d.ts +21 -1
  58. package/dist/_dts/sdk/src/rendering/server.d.ts +4 -0
  59. package/dist/_dts/sdk/src/version.d.ts +1 -1
  60. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  61. package/dist/{chunk-2MIWNFJM.mjs → chunk-LYI7TEMH.mjs} +494 -171
  62. package/dist/{chunk-YY7K3QD2.mjs → chunk-Q4OLG66B.mjs} +9 -9
  63. package/dist/{chunk-CEQBBLMJ.mjs → chunk-TW2Y4RR5.mjs} +69 -14
  64. package/dist/{chunk-CBD47MTM.mjs → chunk-V5VORNEJ.mjs} +2 -2
  65. package/dist/{chunk-7RX72SK2.mjs → chunk-VX7B5VAC.mjs} +36 -25
  66. package/dist/{chunk-YRJKZEQ3.mjs → chunk-Z7JLNTJR.mjs} +1 -1
  67. package/dist/cli/index.mjs +3395 -3753
  68. package/dist/client/{accordion-ZZVXWV3N.mjs → accordion-2YHIBOZH.mjs} +1 -1
  69. package/dist/client/bookingForm-35IBDWAS.mjs +3012 -0
  70. package/dist/client/bookings.mjs +30 -21
  71. package/dist/client/{carousel-25WK2H7G.mjs → carousel-K6XG7NZQ.mjs} +3 -2
  72. package/dist/client/cart-HCFYUTTU.mjs +18 -0
  73. package/dist/client/checkout-J3U4XR7K.mjs +18 -0
  74. package/dist/client/chunk-3DCJ45Z2.mjs +36 -0
  75. package/dist/client/chunk-3PEDD5KJ.mjs +146 -0
  76. package/dist/client/{chunk-6VGXRE34.mjs → chunk-7UOSCYY4.mjs} +76 -29
  77. package/dist/client/chunk-BOIHIU7E.mjs +106 -0
  78. package/dist/client/chunk-F7LHOKEH.mjs +146 -0
  79. package/dist/client/chunk-FGUIVT2B.mjs +204 -0
  80. package/dist/client/chunk-I2MMZO53.mjs +6 -0
  81. package/dist/client/chunk-II7O4XN3.mjs +2206 -0
  82. package/dist/client/chunk-J227A3CQ.mjs +245 -0
  83. package/dist/client/chunk-JEZECJ3W.mjs +383 -0
  84. package/dist/client/chunk-M3L3KYYR.mjs +1181 -0
  85. package/dist/client/chunk-OJPZEZU2.mjs +31 -0
  86. package/dist/client/chunk-PFBX3IQL.mjs +1378 -0
  87. package/dist/client/chunk-RTZ3JKKX.mjs +178 -0
  88. package/dist/client/chunk-SNSWVZEP.mjs +5592 -0
  89. package/dist/client/chunk-TQ5MSPDX.mjs +74 -0
  90. package/dist/client/chunk-YLMKMCSJ.mjs +86 -0
  91. package/dist/client/client.mjs +54052 -54518
  92. package/dist/client/courseRegistration-ZBXS7VGI.mjs +1737 -0
  93. package/dist/client/{eventCalendar-X6GIPYFM.mjs → eventCalendar-EQQZHJBA.mjs} +13 -2
  94. package/dist/client/{eventCombined-EZUOPM3G.mjs → eventCombined-JCFTGBFQ.mjs} +13 -2
  95. package/dist/client/eventDetails-HLUTQSYY.mjs +25 -0
  96. package/dist/client/{eventListing-HEFGAETC.mjs → eventListing-FG4MICVB.mjs} +13 -2
  97. package/dist/client/{eventRegistration-3LCP2V3P.mjs → eventRegistration-GUEB7LBT.mjs} +13 -2
  98. package/dist/client/form-YQEW4YIT.mjs +300 -0
  99. package/dist/client/headerSection-GTR3TTRM.mjs +729 -0
  100. package/dist/client/hooks.mjs +49 -33
  101. package/dist/client/locationMap-SPC7VGUH.mjs +227 -0
  102. package/dist/client/newsletterForm-4IW5BLID.mjs +208 -0
  103. package/dist/client/productDetail-KP5H2WJO.mjs +18 -0
  104. package/dist/client/productList-3M3M72XZ.mjs +18 -0
  105. package/dist/client/rendering/client.mjs +15580 -16277
  106. package/dist/client/rendering/islands.mjs +98 -21
  107. package/dist/client/rendering.mjs +48730 -49191
  108. package/dist/client/shop-ACQKVGOM.mjs +20 -0
  109. package/dist/preview-next/before-render.mjs +37 -25
  110. package/dist/preview-next/chrome.css +1 -1
  111. package/dist/preview-next/client/runtime.mjs +5 -5
  112. package/dist/preview-next/editor-base.css +2 -148
  113. package/dist/preview-next/editor-chrome.css +179 -0
  114. package/dist/preview-next/middleware.mjs +37 -25
  115. package/dist/{sdk-runtime-OHNONZ5U.mjs → sdk-runtime-K7HNB4U2.mjs} +6 -6
  116. package/dist/server/components.mjs +1294 -1103
  117. package/dist/server/config-validation.mjs +49 -33
  118. package/dist/server/config.mjs +49 -33
  119. package/dist/server/data.mjs +49 -33
  120. package/dist/server/index.mjs +45 -33
  121. package/dist/server/next.mjs +1240 -1050
  122. package/dist/server/page-converter.mjs +12 -8
  123. package/dist/server/prebuild.mjs +1 -1
  124. package/dist/server/rendering/server.mjs +1389 -1104
  125. package/dist/server/rendering.mjs +1300 -1109
  126. package/dist/server/routing.mjs +49 -33
  127. package/dist/server/server.mjs +50 -34
  128. package/dist/server/theme-bridge.mjs +5 -0
  129. package/dist/styles/index.css +5 -0
  130. package/package.json +2 -1
  131. package/dist/SdkPreviewModeRuntime-CRYNDSPL.mjs +0 -8
  132. package/dist/client/bookingForm-4X77HKDS.mjs +0 -34
  133. package/dist/client/cart-JWD2VRFU.mjs +0 -11
  134. package/dist/client/checkout-V7KYGWL7.mjs +0 -11
  135. package/dist/client/chunk-5IYGMTUE.mjs +0 -18614
  136. package/dist/client/chunk-RKCFVIMS.mjs +0 -26
  137. package/dist/client/courseRegistration-O6ZPK4YT.mjs +0 -29
  138. package/dist/client/eventDetails-3WODIXET.mjs +0 -14
  139. package/dist/client/form-AKXQMY6Z.mjs +0 -85
  140. package/dist/client/headerSection-5KHCMU6B.mjs +0 -12
  141. package/dist/client/locationMap-7HIADW76.mjs +0 -14
  142. package/dist/client/newsletterForm-5N4YTMU3.mjs +0 -60
  143. package/dist/client/productDetail-IZUA7ZP3.mjs +0 -11
  144. package/dist/client/productList-KWIIJE6I.mjs +0 -11
  145. package/dist/client/shop-XZQFRQWZ.mjs +0 -13
@@ -0,0 +1,245 @@
1
+ "use client";
2
+ import { assertNever } from './chunk-7UOSCYY4.mjs';
3
+ import { useState, useEffect, useReducer, useRef, useCallback } from 'react';
4
+
5
+ function useDiscountCodeUi(options) {
6
+ const [discountUiOpen, setDiscountUiOpen] = useState(false);
7
+ const [discountCode, setDiscountCode] = useState("");
8
+ const [discountsAvailable, setDiscountsAvailable] = useState(false);
9
+ const [manualCodeEntryAllowed, setManualCodeEntryAllowed] = useState(false);
10
+ const [autoAppliedDiscount, setAutoAppliedDiscount] = useState(null);
11
+ const [discountsAvailableLoading, setDiscountsAvailableLoading] = useState(false);
12
+ useEffect(() => {
13
+ let cancelled = false;
14
+ async function checkDiscountAvailability() {
15
+ if (!options.discountContext) {
16
+ setDiscountsAvailable(false);
17
+ setManualCodeEntryAllowed(false);
18
+ setAutoAppliedDiscount(null);
19
+ setDiscountsAvailableLoading(false);
20
+ setDiscountUiOpen(false);
21
+ setDiscountCode("");
22
+ return;
23
+ }
24
+ setDiscountsAvailableLoading(true);
25
+ try {
26
+ const res = await options.api.getDiscountsAvailable({
27
+ context: options.discountContext,
28
+ subtotalCents: options.subtotalCents
29
+ });
30
+ if (cancelled) return;
31
+ setDiscountsAvailable(res.hasDiscounts);
32
+ setManualCodeEntryAllowed(res.manualCodeEntryAllowed);
33
+ setAutoAppliedDiscount(res.autoAppliedDiscount);
34
+ if (!res.hasDiscounts || !res.manualCodeEntryAllowed) {
35
+ setDiscountUiOpen(false);
36
+ setDiscountCode("");
37
+ }
38
+ } catch {
39
+ if (cancelled) return;
40
+ setDiscountsAvailable(false);
41
+ setManualCodeEntryAllowed(false);
42
+ setAutoAppliedDiscount(null);
43
+ setDiscountUiOpen(false);
44
+ setDiscountCode("");
45
+ } finally {
46
+ if (!cancelled) setDiscountsAvailableLoading(false);
47
+ }
48
+ }
49
+ checkDiscountAvailability();
50
+ return () => {
51
+ cancelled = true;
52
+ };
53
+ }, [options.api, options.discountContext, options.subtotalCents]);
54
+ return {
55
+ discountUiOpen,
56
+ setDiscountUiOpen,
57
+ discountCode,
58
+ setDiscountCode,
59
+ discountsAvailable,
60
+ manualCodeEntryAllowed,
61
+ autoAppliedDiscount,
62
+ discountsAvailableLoading
63
+ };
64
+ }
65
+
66
+ // ../blocks/src/system/runtime/hooks/usePolling.state.ts
67
+ function createInitialPollingState() {
68
+ return {
69
+ tag: "idle",
70
+ result: null,
71
+ error: null
72
+ };
73
+ }
74
+ function pollingReducer(state, action) {
75
+ switch (action.type) {
76
+ case "polling-went-idle":
77
+ return createInitialPollingState();
78
+ case "polling-reset":
79
+ return {
80
+ tag: "polling",
81
+ result: null,
82
+ error: null
83
+ };
84
+ case "polling-progressed":
85
+ return {
86
+ tag: "polling",
87
+ result: action.result,
88
+ error: null
89
+ };
90
+ case "polling-completed":
91
+ return {
92
+ tag: "completed",
93
+ result: action.result,
94
+ error: null
95
+ };
96
+ case "polling-failed":
97
+ return {
98
+ tag: "failed",
99
+ result: action.result,
100
+ error: null
101
+ };
102
+ case "polling-request-failed":
103
+ switch (state.tag) {
104
+ case "idle":
105
+ return {
106
+ tag: "polling",
107
+ result: null,
108
+ error: action.error
109
+ };
110
+ case "polling":
111
+ return {
112
+ tag: "polling",
113
+ result: state.result,
114
+ error: action.error
115
+ };
116
+ case "completed":
117
+ case "failed":
118
+ case "timeout":
119
+ return state;
120
+ default:
121
+ return assertNever(state);
122
+ }
123
+ case "polling-timed-out":
124
+ return {
125
+ tag: "timeout",
126
+ result: state.result,
127
+ error: new Error("Polling timed out")
128
+ };
129
+ default:
130
+ return assertNever(action);
131
+ }
132
+ }
133
+
134
+ // ../blocks/src/system/runtime/hooks/usePolling.ts
135
+ var DEFAULT_MAX_ATTEMPTS = 10;
136
+ var DEFAULT_POLL_INTERVAL = 1e3;
137
+ function usePolling(config) {
138
+ const [state, dispatch] = useReducer(
139
+ pollingReducer,
140
+ void 0,
141
+ createInitialPollingState
142
+ );
143
+ const attemptsRef = useRef(0);
144
+ const timeoutRef = useRef(null);
145
+ const isPollingRef = useRef(false);
146
+ const isActiveRef = useRef(false);
147
+ const generationRef = useRef(0);
148
+ const configRef = useRef(config);
149
+ configRef.current = config;
150
+ const cleanup = useCallback(() => {
151
+ isActiveRef.current = false;
152
+ generationRef.current += 1;
153
+ if (timeoutRef.current) {
154
+ clearTimeout(timeoutRef.current);
155
+ timeoutRef.current = null;
156
+ }
157
+ isPollingRef.current = false;
158
+ }, []);
159
+ const resetState = useCallback(() => {
160
+ dispatch({ type: "polling-reset" });
161
+ attemptsRef.current = 0;
162
+ }, []);
163
+ const poll = useCallback(async () => {
164
+ const cfg = configRef.current;
165
+ if (!cfg) return true;
166
+ if (isPollingRef.current) return false;
167
+ const maxAttempts = cfg.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
168
+ if (attemptsRef.current >= maxAttempts) {
169
+ dispatch({ type: "polling-timed-out" });
170
+ cleanup();
171
+ return true;
172
+ }
173
+ isPollingRef.current = true;
174
+ attemptsRef.current += 1;
175
+ const generation = generationRef.current;
176
+ try {
177
+ const data = await cfg.pollFn();
178
+ if (generation !== generationRef.current || !isActiveRef.current) {
179
+ isPollingRef.current = false;
180
+ return true;
181
+ }
182
+ if (cfg.isFailed?.(data)) {
183
+ dispatch({ type: "polling-failed", result: data });
184
+ cleanup();
185
+ return true;
186
+ }
187
+ if (cfg.isComplete(data)) {
188
+ dispatch({ type: "polling-completed", result: data });
189
+ cleanup();
190
+ return true;
191
+ }
192
+ dispatch({ type: "polling-progressed", result: data });
193
+ isPollingRef.current = false;
194
+ return false;
195
+ } catch (err) {
196
+ if (generation !== generationRef.current || !isActiveRef.current) {
197
+ isPollingRef.current = false;
198
+ return true;
199
+ }
200
+ if (err instanceof Error) {
201
+ dispatch({ type: "polling-request-failed", error: err });
202
+ }
203
+ isPollingRef.current = false;
204
+ return false;
205
+ }
206
+ }, [cleanup]);
207
+ const schedulePoll = useCallback(() => {
208
+ if (!isActiveRef.current) return;
209
+ const cfg = configRef.current;
210
+ const pollInterval = cfg?.interval ?? DEFAULT_POLL_INTERVAL;
211
+ const doPoll = async () => {
212
+ const shouldStop = await poll();
213
+ if (!shouldStop && isActiveRef.current) {
214
+ timeoutRef.current = setTimeout(doPoll, pollInterval);
215
+ }
216
+ };
217
+ doPoll();
218
+ }, [poll]);
219
+ useEffect(() => {
220
+ if (!config) {
221
+ cleanup();
222
+ dispatch({ type: "polling-went-idle" });
223
+ return;
224
+ }
225
+ resetState();
226
+ isActiveRef.current = true;
227
+ schedulePoll();
228
+ return cleanup;
229
+ }, [config, cleanup, resetState, schedulePoll]);
230
+ const retry = useCallback(() => {
231
+ if (!configRef.current) return;
232
+ cleanup();
233
+ resetState();
234
+ isActiveRef.current = true;
235
+ schedulePoll();
236
+ }, [cleanup, resetState, schedulePoll]);
237
+ return {
238
+ status: config ? state.tag : "idle",
239
+ result: config ? state.result : null,
240
+ error: config ? state.error : null,
241
+ retry
242
+ };
243
+ }
244
+
245
+ export { useDiscountCodeUi, usePolling };
@@ -0,0 +1,383 @@
1
+ import { FeedbackMessage } from './chunk-M3L3KYYR.mjs';
2
+ import { clsx_default } from './chunk-PMAIXMAB.mjs';
3
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
+
5
+ // ../blocks/src/system/runtime/shared/utils/checkoutUrls.ts
6
+ function buildCheckoutReturnUrls(paramName, anchorId) {
7
+ const currentUrl = new URL(window.location.href);
8
+ const hash = `#${anchorId}`;
9
+ const successParams = new URLSearchParams(currentUrl.search);
10
+ successParams.set(paramName, "success");
11
+ const successUrl = `${currentUrl.origin}${currentUrl.pathname}?${successParams.toString()}${hash}`;
12
+ const cancelParams = new URLSearchParams(currentUrl.search);
13
+ cancelParams.set(paramName, "cancelled");
14
+ const cancelUrl = `${currentUrl.origin}${currentUrl.pathname}?${cancelParams.toString()}${hash}`;
15
+ return { successUrl, cancelUrl };
16
+ }
17
+
18
+ // ../blocks/src/system/runtime/shared/utils/scrollToBlock.ts
19
+ function scrollToBlock(anchorId) {
20
+ requestAnimationFrame(() => {
21
+ document.getElementById(anchorId)?.scrollIntoView({ behavior: "smooth", block: "start" });
22
+ });
23
+ }
24
+
25
+ // ../blocks/src/system/runtime/shared/utils/themePortalRoot.ts
26
+ function copyDataAttributes(from, to) {
27
+ for (const name of from.getAttributeNames()) {
28
+ if (!name.startsWith("data-")) continue;
29
+ const value = from.getAttribute(name);
30
+ if (value === null) continue;
31
+ to.setAttribute(name, value);
32
+ }
33
+ }
34
+ function createBodyThemePortalRoot(sourceEl) {
35
+ if (typeof document === "undefined") return null;
36
+ const scope = sourceEl.closest(".theme-scope");
37
+ if (!scope) return null;
38
+ const root = document.createElement("div");
39
+ root.className = "theme-scope rb-theme-portal-root";
40
+ root.style.cssText = scope.style.cssText;
41
+ copyDataAttributes(scope, root);
42
+ const responsiveMode = scope.getAttribute("data-rb-responsive-mode");
43
+ if (responsiveMode) {
44
+ root.setAttribute("data-rb-responsive-mode", responsiveMode);
45
+ }
46
+ document.body.appendChild(root);
47
+ return {
48
+ root,
49
+ cleanup: () => {
50
+ root.remove();
51
+ }
52
+ };
53
+ }
54
+
55
+ // ../blocks/src/system/runtime/shared/utils/urlParams.ts
56
+ function consumeSearchParam(paramName) {
57
+ const url = new URL(window.location.href);
58
+ const value = url.searchParams.get(paramName);
59
+ if (value === null) return null;
60
+ url.searchParams.delete(paramName);
61
+ const newUrl = url.pathname + (url.search ? url.search : "") + url.hash;
62
+ window.history.replaceState({}, "", newUrl);
63
+ return value;
64
+ }
65
+ function consumeSearchParams(paramNames) {
66
+ const url = new URL(window.location.href);
67
+ const values = Object.fromEntries(
68
+ paramNames.map((name) => [name, url.searchParams.get(name)])
69
+ );
70
+ let changed = false;
71
+ for (const name of paramNames) {
72
+ if (url.searchParams.has(name)) {
73
+ url.searchParams.delete(name);
74
+ changed = true;
75
+ }
76
+ }
77
+ if (changed) {
78
+ const newUrl = url.pathname + (url.search ? url.search : "") + url.hash;
79
+ window.history.replaceState({}, "", newUrl);
80
+ }
81
+ return values;
82
+ }
83
+
84
+ // ../blocks/src/system/runtime/shared/types.ts
85
+ var DEFAULT_CURRENCY = "GBP";
86
+
87
+ // ../blocks/src/system/runtime/shared/utils/formatting.ts
88
+ function formatPrice(cents, currency = DEFAULT_CURRENCY, locale) {
89
+ return new Intl.NumberFormat(locale, {
90
+ style: "currency",
91
+ currency: currency.toUpperCase()
92
+ }).format(cents / 100);
93
+ }
94
+
95
+ // ../blocks/src/system/runtime/shared/utils/portalLogout.ts
96
+ function logoutPortal(anchorId) {
97
+ const form = document.createElement("form");
98
+ form.method = "POST";
99
+ form.action = "/api/portal/logout";
100
+ const redirectInput = document.createElement("input");
101
+ redirectInput.type = "hidden";
102
+ redirectInput.name = "redirect_to";
103
+ redirectInput.value = `${window.location.pathname}#${anchorId}`;
104
+ form.appendChild(redirectInput);
105
+ document.body.appendChild(form);
106
+ form.submit();
107
+ }
108
+
109
+ // ../blocks/src/system/runtime/shared/utils/validation.ts
110
+ var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
111
+ function validateFormData(data) {
112
+ const errors = {};
113
+ if (!data.name.trim()) {
114
+ errors.name = "Name is required";
115
+ }
116
+ if (!data.email.trim()) {
117
+ errors.email = "Email is required";
118
+ } else if (!EMAIL_REGEX.test(data.email.trim())) {
119
+ errors.email = "Please enter a valid email";
120
+ }
121
+ return errors;
122
+ }
123
+
124
+ // ../blocks/src/system/runtime/shared/utils/wizardSteps.ts
125
+ function getStepNumber(step, wizardSteps) {
126
+ const index = wizardSteps.indexOf(step);
127
+ return index >= 0 ? index + 1 : 1;
128
+ }
129
+ function CheckIcon({ className, strokeWidth = 2 }) {
130
+ return /* @__PURE__ */ jsx(
131
+ "svg",
132
+ {
133
+ fill: "none",
134
+ strokeLinecap: "round",
135
+ strokeLinejoin: "round",
136
+ strokeWidth,
137
+ viewBox: "0 0 24 24",
138
+ stroke: "currentColor",
139
+ className,
140
+ width: "1em",
141
+ height: "1em",
142
+ "aria-hidden": "true",
143
+ children: /* @__PURE__ */ jsx("path", { d: "M5 13l4 4L19 7" })
144
+ }
145
+ );
146
+ }
147
+ function CrossIcon({ className, strokeWidth = 2 }) {
148
+ return /* @__PURE__ */ jsx(
149
+ "svg",
150
+ {
151
+ fill: "none",
152
+ strokeLinecap: "round",
153
+ strokeLinejoin: "round",
154
+ strokeWidth,
155
+ viewBox: "0 0 24 24",
156
+ stroke: "currentColor",
157
+ className,
158
+ width: "1em",
159
+ height: "1em",
160
+ "aria-hidden": "true",
161
+ children: /* @__PURE__ */ jsx("path", { d: "M6 18L18 6M6 6l12 12" })
162
+ }
163
+ );
164
+ }
165
+ var alignmentClasses = {
166
+ start: "rb-justify-start",
167
+ end: "rb-justify-end",
168
+ between: "rb-justify-between"
169
+ };
170
+ function joinClasses(...parts) {
171
+ return parts.filter((part) => typeof part === "string" && part.length > 0).join(" ");
172
+ }
173
+ function ActionRow({
174
+ children,
175
+ className,
176
+ align = "start"
177
+ }) {
178
+ return /* @__PURE__ */ jsx(
179
+ "div",
180
+ {
181
+ className: joinClasses("rb-flex rb-flex-wrap rb-items-center rb-gap-2", alignmentClasses[align], className),
182
+ "data-action-row": true,
183
+ children
184
+ }
185
+ );
186
+ }
187
+ function StateIcon({ variant, children }) {
188
+ return /* @__PURE__ */ jsx("div", { className: `rb-state-icon rb-state-icon--${variant}`, "aria-hidden": "true", children });
189
+ }
190
+ function joinClasses2(...parts) {
191
+ return parts.filter((part) => typeof part === "string" && part.length > 0).join(" ");
192
+ }
193
+ function TerminalPanel({
194
+ tone,
195
+ title,
196
+ titleAs: Title = "h3",
197
+ body,
198
+ secondaryBody,
199
+ icon,
200
+ actions,
201
+ className,
202
+ titleClassName,
203
+ bodyClassName,
204
+ secondaryBodyClassName,
205
+ iconClassName,
206
+ actionsClassName,
207
+ role,
208
+ live
209
+ }) {
210
+ const resolvedRole = role ?? (tone === "error" ? "alert" : "status");
211
+ const resolvedLive = live ?? (resolvedRole === "alert" ? "assertive" : "polite");
212
+ return /* @__PURE__ */ jsxs(
213
+ "div",
214
+ {
215
+ className,
216
+ "data-terminal-panel": true,
217
+ "data-terminal-tone": tone,
218
+ role: resolvedRole,
219
+ "aria-live": resolvedLive === "off" ? void 0 : resolvedLive,
220
+ children: [
221
+ icon ? /* @__PURE__ */ jsx("div", { className: joinClasses2(iconClassName), "data-terminal-icon": true, children: icon }) : null,
222
+ /* @__PURE__ */ jsx(Title, { className: joinClasses2(titleClassName), "data-terminal-title": true, children: title }),
223
+ body ? /* @__PURE__ */ jsx("div", { className: joinClasses2(bodyClassName), "data-terminal-body": true, children: body }) : null,
224
+ actions ? /* @__PURE__ */ jsx("div", { className: joinClasses2(actionsClassName), "data-terminal-actions": true, children: actions }) : null,
225
+ secondaryBody ? /* @__PURE__ */ jsx("div", { className: joinClasses2(secondaryBodyClassName), "data-terminal-secondary-body": true, children: secondaryBody }) : null
226
+ ]
227
+ }
228
+ );
229
+ }
230
+ function ClockIcon({ className, strokeWidth = 2 }) {
231
+ return /* @__PURE__ */ jsx(
232
+ "svg",
233
+ {
234
+ fill: "none",
235
+ strokeLinecap: "round",
236
+ strokeLinejoin: "round",
237
+ strokeWidth,
238
+ viewBox: "0 0 24 24",
239
+ stroke: "currentColor",
240
+ className,
241
+ width: "1em",
242
+ height: "1em",
243
+ "aria-hidden": "true",
244
+ children: /* @__PURE__ */ jsx("path", { d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" })
245
+ }
246
+ );
247
+ }
248
+ function LoggedInAsUser({ email, onLogout, classPrefix }) {
249
+ return /* @__PURE__ */ jsxs("p", { className: `${classPrefix}-logged-in-hint`, children: [
250
+ "Logged in as ",
251
+ email,
252
+ onLogout && /* @__PURE__ */ jsxs(Fragment, { children: [
253
+ " \u2014 ",
254
+ /* @__PURE__ */ jsx("button", { type: "button", className: `${classPrefix}-link`, onClick: onLogout, children: "Not you? Log out" })
255
+ ] })
256
+ ] });
257
+ }
258
+ function MembershipHero({
259
+ membershipName,
260
+ classPrefix,
261
+ onBookForSomeoneElse
262
+ }) {
263
+ return /* @__PURE__ */ jsxs(FeedbackMessage, { tone: "success", className: `${classPrefix}-membership-hero`, role: "status", children: [
264
+ /* @__PURE__ */ jsx("div", { className: `${classPrefix}-membership-hero__icon`, "aria-hidden": "true", children: "\u2728" }),
265
+ /* @__PURE__ */ jsxs("h3", { className: `${classPrefix}-membership-hero__title`, children: [
266
+ "Included with your ",
267
+ membershipName
268
+ ] }),
269
+ /* @__PURE__ */ jsx("p", { className: `${classPrefix}-membership-hero__subtitle`, children: "No payment required" }),
270
+ onBookForSomeoneElse && /* @__PURE__ */ jsx(
271
+ "button",
272
+ {
273
+ type: "button",
274
+ className: `${classPrefix}-membership-hero__link`,
275
+ onClick: onBookForSomeoneElse,
276
+ children: "Booking for someone else?"
277
+ }
278
+ )
279
+ ] });
280
+ }
281
+ function clampIndex(idx, len) {
282
+ if (len <= 0) return 0;
283
+ const mod = idx % len;
284
+ return mod < 0 ? mod + len : mod;
285
+ }
286
+ function TabBarFragment({
287
+ tabs,
288
+ activeTab,
289
+ onTabChange,
290
+ ariaLabel,
291
+ className,
292
+ tabClassName,
293
+ activeTabClassName
294
+ }) {
295
+ return /* @__PURE__ */ jsx(
296
+ "div",
297
+ {
298
+ className,
299
+ role: "tablist",
300
+ "aria-label": ariaLabel,
301
+ children: tabs.map((tab, idx) => {
302
+ const isActive = tab.id === activeTab;
303
+ return /* @__PURE__ */ jsx(
304
+ "button",
305
+ {
306
+ type: "button",
307
+ role: "tab",
308
+ "aria-selected": isActive,
309
+ tabIndex: isActive ? 0 : -1,
310
+ className: clsx_default(tabClassName, isActive && activeTabClassName),
311
+ onClick: () => onTabChange(tab.id),
312
+ onKeyDown: (e) => {
313
+ if (tabs.length === 0) return;
314
+ if (!(e.currentTarget instanceof HTMLButtonElement)) return;
315
+ let nextIdx = null;
316
+ if (e.key === "ArrowRight") nextIdx = clampIndex(idx + 1, tabs.length);
317
+ else if (e.key === "ArrowLeft") nextIdx = clampIndex(idx - 1, tabs.length);
318
+ else if (e.key === "Home") nextIdx = 0;
319
+ else if (e.key === "End") nextIdx = tabs.length - 1;
320
+ if (nextIdx === null) return;
321
+ e.preventDefault();
322
+ const nextId = tabs[nextIdx]?.id;
323
+ if (!nextId) return;
324
+ onTabChange(nextId);
325
+ requestAnimationFrame(() => {
326
+ const root = e.currentTarget.closest('[role="tablist"]') ?? null;
327
+ const btns = root?.querySelectorAll('[role="tab"]') ?? null;
328
+ btns?.[nextIdx]?.focus();
329
+ });
330
+ },
331
+ children: tab.label
332
+ },
333
+ tab.id
334
+ );
335
+ })
336
+ }
337
+ );
338
+ }
339
+ function StepIndicator({
340
+ currentStep,
341
+ totalSteps,
342
+ stepLabels,
343
+ classPrefix
344
+ }) {
345
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "Registration progress", className: `${classPrefix}-steps-nav`, children: /* @__PURE__ */ jsx("ol", { className: `${classPrefix}-steps`, children: Array.from({ length: totalSteps }, (_, i) => {
346
+ const stepNum = i + 1;
347
+ const isActive = stepNum === currentStep;
348
+ const isComplete = stepNum < currentStep;
349
+ return /* @__PURE__ */ jsxs(
350
+ "li",
351
+ {
352
+ className: `${classPrefix}-step`,
353
+ "aria-current": isActive ? "step" : void 0,
354
+ children: [
355
+ /* @__PURE__ */ jsx(
356
+ "div",
357
+ {
358
+ className: `${classPrefix}-step-circle${isActive ? ` ${classPrefix}-step-circle--active` : ""}${isComplete ? ` ${classPrefix}-step-circle--completed` : ""}`,
359
+ children: isComplete ? /* @__PURE__ */ jsx(CheckIcon, { className: `${classPrefix}-step-check`, strokeWidth: 3 }) : stepNum
360
+ }
361
+ ),
362
+ stepLabels?.[i] && /* @__PURE__ */ jsx(
363
+ "span",
364
+ {
365
+ className: `${classPrefix}-step-label${isActive ? ` ${classPrefix}-step-label--active` : ""}`,
366
+ children: stepLabels[i]
367
+ }
368
+ ),
369
+ stepNum < totalSteps && /* @__PURE__ */ jsx(
370
+ "div",
371
+ {
372
+ className: `${classPrefix}-step-connector${isComplete ? ` ${classPrefix}-step-connector--completed` : ""}`,
373
+ "aria-hidden": "true"
374
+ }
375
+ )
376
+ ]
377
+ },
378
+ i
379
+ );
380
+ }) }) });
381
+ }
382
+
383
+ export { ActionRow, CheckIcon, ClockIcon, CrossIcon, LoggedInAsUser, MembershipHero, StateIcon, StepIndicator, TabBarFragment, TerminalPanel, buildCheckoutReturnUrls, consumeSearchParam, consumeSearchParams, createBodyThemePortalRoot, formatPrice, getStepNumber, logoutPortal, scrollToBlock, validateFormData };