@riverbankcms/sdk 0.72.0 → 0.75.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 (146) hide show
  1. package/README.md +1 -1
  2. package/dist/{PreviewEditorSidebar-44T64SAR.mjs → PreviewEditorSidebar-U2IHCBYN.mjs} +3 -3
  3. package/dist/{PreviewEditorUI-4WKHZTXW.mjs → PreviewEditorUI-ZGH2RQNP.mjs} +3 -3
  4. package/dist/SdkPreviewModeRuntime-MTUGBTLQ.mjs +8 -0
  5. package/dist/_dts/ai/src/contracts/proposals.d.ts +10 -10
  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/publicExperienceEndpoints.d.ts +2 -1
  10. package/dist/_dts/block-form/src/blockDraftSaveability.d.ts +4 -1
  11. package/dist/_dts/blocks/src/client/booking-form.d.ts +2 -0
  12. package/dist/_dts/blocks/src/client/carousel.d.ts +1 -0
  13. package/dist/_dts/blocks/src/client/course-registration.d.ts +2 -0
  14. package/dist/_dts/blocks/src/client/events.d.ts +4 -0
  15. package/dist/_dts/blocks/src/client/form.d.ts +2 -0
  16. package/dist/_dts/blocks/src/client/header.d.ts +1 -0
  17. package/dist/_dts/blocks/src/client/location-map.d.ts +1 -0
  18. package/dist/_dts/blocks/src/client/newsletter-form.d.ts +2 -0
  19. package/dist/_dts/blocks/src/client/shop.d.ts +6 -0
  20. package/dist/_dts/blocks/src/lib/video.d.ts +2 -0
  21. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +21 -1
  22. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +6 -6
  23. package/dist/_dts/blocks/src/system/node/fragments/backgroundLayer.d.ts +15 -1
  24. package/dist/_dts/blocks/src/system/node/fragments/styledSection.d.ts +11 -0
  25. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +1 -0
  26. package/dist/_dts/blocks/src/system/runtime/header/enhanceHeaderSection.d.ts +13 -0
  27. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +3 -2
  28. package/dist/_dts/blocks/src/system/runtime/nodes/events/index.d.ts +3 -0
  29. package/dist/_dts/blocks/src/system/runtime/nodes/header-section.client.d.ts +1 -0
  30. package/dist/_dts/blocks/src/system/runtime/nodes/header-section.server.d.ts +1 -0
  31. package/dist/_dts/blocks/src/system/runtime/nodes/media.d.ts +6 -0
  32. package/dist/_dts/content-editor/src/hooks/validateBlocksForPublish.d.ts +5 -0
  33. package/dist/_dts/preview-next/src/client/preview/SiteChromeEditableSurface.d.ts +12 -2
  34. package/dist/_dts/sdk/src/public-api/contracts.d.ts +1 -0
  35. package/dist/_dts/sdk/src/rendering/components/Layout.d.ts +2 -2
  36. package/dist/_dts/sdk/src/rendering/islands/deferredVideoEmbeds.d.ts +2 -0
  37. package/dist/_dts/sdk/src/rendering/islands/enhancers/accordion.d.ts +1 -0
  38. package/dist/_dts/sdk/src/rendering/islands/enhancers/bookingForm.d.ts +1 -0
  39. package/dist/_dts/sdk/src/rendering/islands/enhancers/carousel.d.ts +1 -0
  40. package/dist/_dts/sdk/src/rendering/islands/enhancers/cart.d.ts +1 -0
  41. package/dist/_dts/sdk/src/rendering/islands/enhancers/checkout.d.ts +1 -0
  42. package/dist/_dts/sdk/src/rendering/islands/enhancers/courseRegistration.d.ts +1 -0
  43. package/dist/_dts/sdk/src/rendering/islands/enhancers/eventCalendar.d.ts +1 -0
  44. package/dist/_dts/sdk/src/rendering/islands/enhancers/eventCombined.d.ts +1 -0
  45. package/dist/_dts/sdk/src/rendering/islands/enhancers/eventDetails.d.ts +1 -0
  46. package/dist/_dts/sdk/src/rendering/islands/enhancers/eventListing.d.ts +1 -0
  47. package/dist/_dts/sdk/src/rendering/islands/enhancers/eventRegistration.d.ts +1 -0
  48. package/dist/_dts/sdk/src/rendering/islands/enhancers/form.d.ts +1 -0
  49. package/dist/_dts/sdk/src/rendering/islands/enhancers/headerSection.d.ts +1 -0
  50. package/dist/_dts/sdk/src/rendering/islands/enhancers/locationMap.d.ts +1 -0
  51. package/dist/_dts/sdk/src/rendering/islands/enhancers/newsletterForm.d.ts +1 -0
  52. package/dist/_dts/sdk/src/rendering/islands/enhancers/productDetail.d.ts +1 -0
  53. package/dist/_dts/sdk/src/rendering/islands/enhancers/productList.d.ts +1 -0
  54. package/dist/_dts/sdk/src/rendering/islands/enhancers/shop.d.ts +1 -0
  55. package/dist/_dts/sdk/src/rendering/islands/hydrateBlocksIslands.d.ts +2 -2
  56. package/dist/_dts/sdk/src/rendering/islands/propsDecoder.d.ts +7 -0
  57. package/dist/_dts/sdk/src/rendering/islands/types.d.ts +9 -0
  58. package/dist/_dts/sdk/src/rendering/server.d.ts +3 -0
  59. package/dist/_dts/sdk/src/version.d.ts +1 -1
  60. package/dist/_dts/theme-core/src/accordions/types.d.ts +3 -3
  61. package/dist/_dts/theme-core/src/buttons/personalities/types.d.ts +7 -7
  62. package/dist/_dts/theme-core/src/buttons/types.d.ts +20 -20
  63. package/dist/_dts/theme-core/src/cards/types.d.ts +2 -2
  64. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  65. package/dist/_dts/theme-core/src/header/navDropdownSizing.d.ts +7 -0
  66. package/dist/_dts/theme-core/src/inputs/types.d.ts +3 -3
  67. package/dist/_dts/theme-core/src/interactive/baseSchema.d.ts +1 -1
  68. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +156 -156
  69. package/dist/_dts/theme-core/src/navigation/types.d.ts +1 -1
  70. package/dist/_dts/theme-core/src/palette/variants/types.d.ts +4 -4
  71. package/dist/_dts/theme-core/src/schema.d.ts +178 -178
  72. package/dist/_dts/theme-core/src/shared/componentStyles.d.ts +2 -2
  73. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +8 -8
  74. package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +5 -5
  75. package/dist/_dts/theme-core/src/tokens/themeColorTokens.d.ts +2 -2
  76. package/dist/{chunk-G4NLITC2.mjs → chunk-BGMNDF6T.mjs} +7 -7
  77. package/dist/{chunk-3YNCQG5N.mjs → chunk-GFE74WRD.mjs} +457 -98
  78. package/dist/{chunk-HV745JYE.mjs → chunk-RWXQBRQZ.mjs} +1 -1
  79. package/dist/{chunk-7RX72SK2.mjs → chunk-VX7B5VAC.mjs} +36 -25
  80. package/dist/{chunk-YRJKZEQ3.mjs → chunk-Z7JLNTJR.mjs} +1 -1
  81. package/dist/{chunk-KWQPAJYS.mjs → chunk-ZSHFGFUG.mjs} +2 -2
  82. package/dist/cli/index.mjs +3498 -3826
  83. package/dist/client/accordion-T2UD2ZTH.mjs +120 -0
  84. package/dist/client/altcha-LIGLPZS5.mjs +2755 -0
  85. package/dist/client/bookingForm-GUP75FKN.mjs +3022 -0
  86. package/dist/client/bookings.mjs +32 -10
  87. package/dist/client/carousel-2NQA6V57.mjs +47 -0
  88. package/dist/client/cart-5TFIAFDS.mjs +18 -0
  89. package/dist/client/checkout-TP4WAHZE.mjs +18 -0
  90. package/dist/client/chunk-2PHQZ666.mjs +383 -0
  91. package/dist/client/chunk-3DCJ45Z2.mjs +36 -0
  92. package/dist/client/chunk-3PEDD5KJ.mjs +146 -0
  93. package/dist/client/chunk-CY2ZTSE5.mjs +204 -0
  94. package/dist/client/chunk-F7LHOKEH.mjs +146 -0
  95. package/dist/client/chunk-FU2QRZMX.mjs +7617 -0
  96. package/dist/client/chunk-I2MMZO53.mjs +6 -0
  97. package/dist/client/chunk-II7O4XN3.mjs +2206 -0
  98. package/dist/client/chunk-M3L3KYYR.mjs +1181 -0
  99. package/dist/client/chunk-N7PBWBWQ.mjs +26 -0
  100. package/dist/client/chunk-NWOUL6JY.mjs +1378 -0
  101. package/dist/client/chunk-OJPZEZU2.mjs +31 -0
  102. package/dist/client/chunk-PMAIXMAB.mjs +1960 -0
  103. package/dist/client/chunk-RTZ3JKKX.mjs +178 -0
  104. package/dist/client/chunk-TQ5MSPDX.mjs +74 -0
  105. package/dist/client/chunk-VUAOE3AG.mjs +5592 -0
  106. package/dist/client/chunk-WJXXNDSE.mjs +245 -0
  107. package/dist/client/chunk-YLMKMCSJ.mjs +86 -0
  108. package/dist/client/chunk-ZLMS67RR.mjs +106 -0
  109. package/dist/client/client.mjs +51865 -52071
  110. package/dist/client/courseRegistration-5DPU6PDY.mjs +1737 -0
  111. package/dist/client/eventCalendar-F3GZGTEF.mjs +40 -0
  112. package/dist/client/eventCombined-BQOB6QMY.mjs +37 -0
  113. package/dist/client/eventDetails-PEM2EJWE.mjs +25 -0
  114. package/dist/client/eventListing-YMIQPVME.mjs +40 -0
  115. package/dist/client/eventRegistration-4I6ZNDUF.mjs +40 -0
  116. package/dist/client/form-ZJVAYZ6G.mjs +300 -0
  117. package/dist/client/headerSection-TOT5MGTF.mjs +729 -0
  118. package/dist/client/hooks.mjs +91 -42
  119. package/dist/client/locationMap-J66NZREU.mjs +227 -0
  120. package/dist/client/newsletterForm-ET2XUMRO.mjs +208 -0
  121. package/dist/client/productDetail-C2XIH7C5.mjs +18 -0
  122. package/dist/client/productList-T2AZLFTP.mjs +18 -0
  123. package/dist/client/rendering/client.mjs +12796 -18295
  124. package/dist/client/rendering/islands.mjs +108 -44022
  125. package/dist/client/rendering.mjs +45141 -45346
  126. package/dist/client/shop-UZ6IUZXD.mjs +20 -0
  127. package/dist/preview-next/before-render.mjs +37 -25
  128. package/dist/preview-next/client/runtime.mjs +5 -5
  129. package/dist/preview-next/middleware.mjs +37 -25
  130. package/dist/{sdk-runtime-NGDWSWOS.mjs → sdk-runtime-JCUQM63Y.mjs} +6 -6
  131. package/dist/server/components.mjs +472 -276
  132. package/dist/server/config-validation.mjs +91 -42
  133. package/dist/server/config.mjs +91 -42
  134. package/dist/server/data.mjs +91 -42
  135. package/dist/server/index.mjs +45 -33
  136. package/dist/server/next.mjs +468 -272
  137. package/dist/server/page-converter.mjs +41 -17
  138. package/dist/server/prebuild.mjs +1 -1
  139. package/dist/server/rendering/server.mjs +556 -275
  140. package/dist/server/rendering.mjs +474 -278
  141. package/dist/server/routing.mjs +99 -43
  142. package/dist/server/server.mjs +92 -43
  143. package/dist/server/theme-bridge.mjs +29 -0
  144. package/dist/styles/index.css +16 -0
  145. package/package.json +2 -1
  146. package/dist/SdkPreviewModeRuntime-FO6V7YVY.mjs +0 -8
@@ -0,0 +1,729 @@
1
+ "use client";
2
+ import { useCommerceCart } from './chunk-ZLMS67RR.mjs';
3
+ import { resolveDedicatedCheckoutPath, ModalShell } from './chunk-3PEDD5KJ.mjs';
4
+ import { defineIslandPropsDecoder, buildCartDisplay, themeButtonClassName } from './chunk-FU2QRZMX.mjs';
5
+ import './chunk-PMAIXMAB.mjs';
6
+ import * as React2 from 'react';
7
+ import { createPortal } from 'react-dom';
8
+ import { createRoot } from 'react-dom/client';
9
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
+
11
+ var NAV_DROPDOWN_VIEWPORT_GUTTER_PX = 16;
12
+ var NAV_DROPDOWN_SHIFT_PROPERTY = "--nav-dropdown-shift-x";
13
+ function normalizeQuantityInput(value) {
14
+ const parsed = Number(value);
15
+ return Number.isFinite(parsed) ? Math.max(1, parsed || 1) : 1;
16
+ }
17
+ function HeaderCartDrawerItems(props) {
18
+ return /* @__PURE__ */ jsx("div", { className: "rb-flex rb-flex-col rb-gap-4", children: props.items.map((item) => /* @__PURE__ */ jsxs(
19
+ "div",
20
+ {
21
+ className: "rb-flex rb-items-start rb-justify-between rb-gap-4 rb-border-b rb-py-4",
22
+ style: { borderColor: "rgba(var(--tb-border, 226 232 240), 0.75)" },
23
+ children: [
24
+ /* @__PURE__ */ jsxs("div", { className: "rb-flex rb-flex-1 rb-flex-col rb-gap-2", children: [
25
+ /* @__PURE__ */ jsxs("div", { children: [
26
+ /* @__PURE__ */ jsx("strong", { children: item.title }),
27
+ /* @__PURE__ */ jsx("p", { className: "rb-caption status-muted", children: item.priceLabel })
28
+ ] }),
29
+ item.quantityEditable ? /* @__PURE__ */ jsxs("label", { className: "rb-flex rb-flex-col rb-gap-1", children: [
30
+ /* @__PURE__ */ jsx("span", { className: "rb-label", children: "Quantity" }),
31
+ /* @__PURE__ */ jsx(
32
+ "input",
33
+ {
34
+ type: "number",
35
+ min: 1,
36
+ className: "form-input rb-w-24",
37
+ value: item.quantity,
38
+ onChange: (event) => props.cart.updateQuantity(item.key, normalizeQuantityInput(event.target.value))
39
+ }
40
+ )
41
+ ] }) : /* @__PURE__ */ jsxs("p", { className: "rb-caption status-muted", children: [
42
+ "Quantity: ",
43
+ item.quantity
44
+ ] })
45
+ ] }),
46
+ /* @__PURE__ */ jsx(
47
+ "button",
48
+ {
49
+ type: "button",
50
+ className: themeButtonClassName({ variant: "secondary", size: "sm" }),
51
+ onClick: () => props.cart.removeItem(item.key),
52
+ children: "Remove"
53
+ }
54
+ )
55
+ ]
56
+ },
57
+ item.key
58
+ )) });
59
+ }
60
+ function HeaderCartDrawer(props) {
61
+ const titleId = React2.useId();
62
+ const display = React2.useMemo(
63
+ () => buildCartDisplay(props.cart.items, {
64
+ heading: "Cart",
65
+ emptyMessage: "Your cart is empty.",
66
+ checkoutButtonText: "Checkout",
67
+ clearButtonText: "Clear cart"
68
+ }),
69
+ [props.cart.items]
70
+ );
71
+ if (!props.open) {
72
+ return null;
73
+ }
74
+ const checkoutUnavailable = props.checkoutHref === null;
75
+ return /* @__PURE__ */ jsxs(
76
+ ModalShell,
77
+ {
78
+ title: "Cart",
79
+ titleId,
80
+ onClose: props.onClose,
81
+ portal: true,
82
+ portalRoot: props.portalRoot,
83
+ overlayClassName: "rb-fixed rb-inset-0 rb-z-50 rb-flex rb-justify-end rb-bg-black-40",
84
+ modalClassName: "rb-flex rb-h-full rb-w-full rb-max-w-xl rb-flex-col",
85
+ renderHeader: ({ title, titleId: resolvedTitleId, onClose, closeButtonRef }) => /* @__PURE__ */ jsxs(
86
+ "div",
87
+ {
88
+ className: "rb-flex rb-items-center rb-justify-between rb-gap-4 rb-border-b rb-px-6 rb-py-5",
89
+ style: {
90
+ background: "rgb(var(--tb-surface, 255 255 255))",
91
+ color: "rgb(var(--tb-foreground, 15 23 42))",
92
+ borderColor: "rgba(var(--tb-border, 226 232 240), 0.9)"
93
+ },
94
+ children: [
95
+ /* @__PURE__ */ jsx("h2", { id: resolvedTitleId, children: title }),
96
+ /* @__PURE__ */ jsx(
97
+ "button",
98
+ {
99
+ ref: closeButtonRef,
100
+ type: "button",
101
+ className: "header-nav-link rb-inline-flex rb-items-center rb-justify-center",
102
+ onClick: onClose,
103
+ "aria-label": "Close cart",
104
+ children: "\xD7"
105
+ }
106
+ )
107
+ ]
108
+ }
109
+ ),
110
+ children: [
111
+ /* @__PURE__ */ jsx(
112
+ "div",
113
+ {
114
+ className: "rb-flex-1 rb-overflow-y-auto rb-px-6 rb-py-6",
115
+ style: {
116
+ background: "rgb(var(--tb-surface, 255 255 255))",
117
+ color: "rgb(var(--tb-foreground, 15 23 42))",
118
+ boxShadow: "0 24px 80px rgba(var(--tb-foreground, 15 23 42), 0.22)"
119
+ },
120
+ children: display.state === "empty" ? /* @__PURE__ */ jsx("p", { className: "rb-caption status-muted", children: display.emptyMessage }) : /* @__PURE__ */ jsx(HeaderCartDrawerItems, { cart: props.cart, items: display.items })
121
+ }
122
+ ),
123
+ /* @__PURE__ */ jsxs(
124
+ "div",
125
+ {
126
+ className: "rb-border-t rb-px-6 rb-py-5",
127
+ style: {
128
+ borderColor: "rgba(var(--tb-border, 226 232 240), 0.9)",
129
+ background: "rgb(var(--tb-surface, 255 255 255))",
130
+ color: "rgb(var(--tb-foreground, 15 23 42))"
131
+ },
132
+ children: [
133
+ /* @__PURE__ */ jsxs("div", { className: "rb-mb-4 rb-flex rb-items-center rb-justify-between", children: [
134
+ /* @__PURE__ */ jsx("span", { className: "rb-label", children: "Subtotal" }),
135
+ /* @__PURE__ */ jsx("strong", { children: display.subtotalLabel ?? "\u2014" })
136
+ ] }),
137
+ checkoutUnavailable ? /* @__PURE__ */ jsx("p", { className: "rb-mb-4 rb-caption status-muted", children: "Checkout preview is not available for this internal published route yet." }) : null,
138
+ /* @__PURE__ */ jsxs("div", { className: "rb-flex rb-flex-wrap rb-gap-3", children: [
139
+ /* @__PURE__ */ jsx(
140
+ "button",
141
+ {
142
+ type: "button",
143
+ className: themeButtonClassName({ variant: "secondary", size: "md" }),
144
+ onClick: () => props.cart.clear(),
145
+ disabled: display.state === "empty",
146
+ children: display.clearButtonText
147
+ }
148
+ ),
149
+ props.checkoutHref && display.state === "ready" ? /* @__PURE__ */ jsx(
150
+ "a",
151
+ {
152
+ className: themeButtonClassName({ variant: "default", size: "md" }),
153
+ href: props.checkoutHref,
154
+ onClick: props.onClose,
155
+ children: display.checkoutButtonText
156
+ }
157
+ ) : /* @__PURE__ */ jsx(
158
+ "button",
159
+ {
160
+ type: "button",
161
+ className: themeButtonClassName({ variant: "default", size: "md" }),
162
+ disabled: true,
163
+ children: display.checkoutButtonText
164
+ }
165
+ )
166
+ ] })
167
+ ]
168
+ }
169
+ )
170
+ ]
171
+ }
172
+ );
173
+ }
174
+
175
+ // ../blocks/src/system/runtime/header/headerCartRuntime.shared.ts
176
+ function getCartItemCount(items) {
177
+ return items.reduce((total, item) => total + item.quantity, 0);
178
+ }
179
+ function getHeaderCartTriggerClassName(context) {
180
+ return context === "mobile" ? "nav-mobile-link rb-flex rb-w-full rb-items-center rb-justify-between rb-py-3 rb-nav-text-mobile transition-theme-standard" : "header-nav-link rb-inline-flex rb-items-center rb-gap-2 rb-px-4 rb-py-2 rb-nav-text transition-theme-standard";
181
+ }
182
+ function resolveHeaderCartCheckoutHref(mounts, pathname) {
183
+ const configuredHrefs = Array.from(new Set(
184
+ mounts.map((mount) => mount.checkoutHref).filter((href) => href !== null)
185
+ )).sort();
186
+ const configuredHref = configuredHrefs[0];
187
+ if (configuredHref) {
188
+ return configuredHref;
189
+ }
190
+ return pathname ? resolveDedicatedCheckoutPath(pathname) : null;
191
+ }
192
+ function snapshotHeaderCartMounts(mounts) {
193
+ return mounts.map((mount) => ({
194
+ mount,
195
+ fallbackNodes: Array.from(mount.element.childNodes)
196
+ }));
197
+ }
198
+ function clearHeaderCartMounts(mounts) {
199
+ mounts.forEach(({ mount }) => {
200
+ mount.element.replaceChildren();
201
+ });
202
+ }
203
+ function restoreHeaderCartMounts(mounts) {
204
+ mounts.forEach(({ mount, fallbackNodes }) => {
205
+ mount.element.replaceChildren(...fallbackNodes);
206
+ });
207
+ }
208
+ function CartIcon() {
209
+ return /* @__PURE__ */ jsxs(
210
+ "svg",
211
+ {
212
+ "aria-hidden": "true",
213
+ viewBox: "0 0 24 24",
214
+ width: "20",
215
+ height: "20",
216
+ fill: "none",
217
+ stroke: "currentColor",
218
+ strokeWidth: "1.8",
219
+ strokeLinecap: "round",
220
+ strokeLinejoin: "round",
221
+ children: [
222
+ /* @__PURE__ */ jsx("path", { d: "M6 7h13l-1.4 7.1a2 2 0 0 1-2 1.6H10a2 2 0 0 1-2-1.6L6 4H3" }),
223
+ /* @__PURE__ */ jsx("circle", { cx: "10", cy: "19", r: "1.25" }),
224
+ /* @__PURE__ */ jsx("circle", { cx: "16", cy: "19", r: "1.25" })
225
+ ]
226
+ }
227
+ );
228
+ }
229
+ function HeaderCartTrigger(props) {
230
+ return /* @__PURE__ */ jsxs(
231
+ "button",
232
+ {
233
+ type: "button",
234
+ className: getHeaderCartTriggerClassName(props.mount.context),
235
+ onClick: props.onOpen,
236
+ "aria-label": props.mount.ariaLabel,
237
+ "data-nav-cart-trigger": "true",
238
+ children: [
239
+ /* @__PURE__ */ jsxs("span", { className: "rb-inline-flex rb-items-center rb-gap-2", children: [
240
+ /* @__PURE__ */ jsx(CartIcon, {}),
241
+ props.mount.visibleLabel ? /* @__PURE__ */ jsx("span", { children: props.mount.visibleLabel }) : null
242
+ ] }),
243
+ props.mount.badge === "show-count" && props.itemCount > 0 ? /* @__PURE__ */ jsx(
244
+ "span",
245
+ {
246
+ className: "rb-inline-flex rb-min-w-0 rb-items-center rb-justify-center rb-rounded-full rb-px-2 rb-py-1 rb-text-xs",
247
+ style: {
248
+ background: "rgba(var(--tb-foreground, 15 23 42), 0.12)"
249
+ },
250
+ children: props.itemCount
251
+ }
252
+ ) : null
253
+ ]
254
+ }
255
+ );
256
+ }
257
+ function HeaderCartRuntime(props) {
258
+ const cart = useCommerceCart(props.siteId);
259
+ const itemCount = React2.useMemo(() => getCartItemCount(cart.items), [cart.items]);
260
+ const [open, setOpen] = React2.useState(false);
261
+ const checkoutHref = React2.useMemo(
262
+ () => resolveHeaderCartCheckoutHref(
263
+ props.mounts,
264
+ typeof window === "undefined" ? null : window.location.pathname
265
+ ),
266
+ [props.mounts]
267
+ );
268
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
269
+ props.mounts.map(
270
+ (mount) => createPortal(
271
+ /* @__PURE__ */ jsx(
272
+ HeaderCartTrigger,
273
+ {
274
+ mount,
275
+ itemCount,
276
+ onOpen: () => setOpen(true)
277
+ }
278
+ ),
279
+ mount.element,
280
+ mount.context === "mobile" ? `mobile:${mount.ariaLabel}` : `desktop:${mount.ariaLabel}`
281
+ )
282
+ ),
283
+ /* @__PURE__ */ jsx(
284
+ HeaderCartDrawer,
285
+ {
286
+ portalRoot: props.portalRoot,
287
+ open,
288
+ checkoutHref,
289
+ onClose: () => setOpen(false),
290
+ cart
291
+ }
292
+ )
293
+ ] });
294
+ }
295
+ function mountHeaderCartRuntime(root, siteId, mounts) {
296
+ if (mounts.length === 0) {
297
+ return;
298
+ }
299
+ const preparedMounts = snapshotHeaderCartMounts(mounts);
300
+ clearHeaderCartMounts(preparedMounts);
301
+ const mountNode = document.createElement("div");
302
+ mountNode.hidden = true;
303
+ root.appendChild(mountNode);
304
+ const reactRoot = createRoot(mountNode);
305
+ try {
306
+ reactRoot.render(
307
+ /* @__PURE__ */ jsx(
308
+ HeaderCartRuntime,
309
+ {
310
+ portalRoot: root,
311
+ siteId,
312
+ mounts: preparedMounts.map(({ mount }) => mount)
313
+ }
314
+ )
315
+ );
316
+ } catch (error) {
317
+ reactRoot.unmount();
318
+ mountNode.remove();
319
+ restoreHeaderCartMounts(preparedMounts);
320
+ throw error;
321
+ }
322
+ return () => {
323
+ reactRoot.unmount();
324
+ mountNode.remove();
325
+ restoreHeaderCartMounts(preparedMounts);
326
+ };
327
+ }
328
+
329
+ // ../blocks/src/system/runtime/header/enhanceHeaderSection.ts
330
+ var SELECTORS = {
331
+ dropdown: ".nav-dropdown",
332
+ dropdownMenu: ".nav-dropdown-menu",
333
+ dropdownTrigger: ".nav-dropdown-trigger",
334
+ mobileOverlay: "[data-nav-mobile-overlay]",
335
+ mobileToggle: "[data-nav-mobile-toggle]",
336
+ mobileBackdrop: "[data-nav-mobile-backdrop]",
337
+ mobileClose: "[data-nav-mobile-close]",
338
+ mobileTrigger: "[data-nav-mobile-trigger]",
339
+ mobileDropdown: "[data-nav-mobile-dropdown]",
340
+ mobileChildren: "[data-nav-mobile-children]",
341
+ cartPlaceholder: "[data-nav-cart-placeholder]"
342
+ };
343
+ var CLASSES = {
344
+ hidden: "rb-hidden",
345
+ headerShrink: "rb-header-shrink",
346
+ headerScrolled: "header-scrolled",
347
+ mobileOpen: "nav-mobile-open"
348
+ };
349
+ var FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])';
350
+ function planDropdownViewportShift(input) {
351
+ const { left, right, viewportWidth, gutter } = input;
352
+ if (!Number.isFinite(left) || !Number.isFinite(right) || !Number.isFinite(viewportWidth) || !Number.isFinite(gutter)) {
353
+ return { kind: "unchanged" };
354
+ }
355
+ const normalizedGutter = Math.max(0, gutter);
356
+ const viewportLeft = normalizedGutter;
357
+ const viewportRight = Math.max(viewportLeft, viewportWidth - normalizedGutter);
358
+ const menuWidth = right - left;
359
+ const availableWidth = viewportRight - viewportLeft;
360
+ if (menuWidth >= availableWidth) {
361
+ const x2 = viewportLeft - left;
362
+ return x2 === 0 ? { kind: "unchanged" } : { kind: "shift", x: x2 };
363
+ }
364
+ let x = 0;
365
+ if (right > viewportRight) x = viewportRight - right;
366
+ if (left + x < viewportLeft) x += viewportLeft - (left + x);
367
+ return x === 0 ? { kind: "unchanged" } : { kind: "shift", x };
368
+ }
369
+ function applyDropdownPlacementPlan(menu, plan) {
370
+ switch (plan.kind) {
371
+ case "unchanged":
372
+ menu.style.removeProperty(NAV_DROPDOWN_SHIFT_PROPERTY);
373
+ return;
374
+ case "shift":
375
+ menu.style.setProperty(NAV_DROPDOWN_SHIFT_PROPERTY, `${plan.x}px`);
376
+ return;
377
+ default: {
378
+ const _exhaustive = plan;
379
+ return _exhaustive;
380
+ }
381
+ }
382
+ }
383
+ function getFirstNonScriptChild(root) {
384
+ const children = Array.from(root.children);
385
+ for (const child of children) {
386
+ if (child.tagName.toLowerCase() === "script") continue;
387
+ return child;
388
+ }
389
+ return null;
390
+ }
391
+ function enhanceDesktopDropdownAria(root) {
392
+ const cleanups = [];
393
+ const dropdowns = Array.from(root.querySelectorAll(SELECTORS.dropdown));
394
+ const setExpanded = (trigger, expanded) => {
395
+ trigger.setAttribute("aria-expanded", expanded ? "true" : "false");
396
+ };
397
+ dropdowns.forEach((dropdown) => {
398
+ const trigger = dropdown.querySelector(SELECTORS.dropdownTrigger);
399
+ if (!trigger) return;
400
+ const menu = dropdown.querySelector(SELECTORS.dropdownMenu);
401
+ let placementRafId = null;
402
+ let placementRafScheduled = false;
403
+ const cancelPlacementFrame = () => {
404
+ if (placementRafId !== null) {
405
+ window.cancelAnimationFrame(placementRafId);
406
+ placementRafId = null;
407
+ }
408
+ placementRafScheduled = false;
409
+ };
410
+ const resetPlacement = () => {
411
+ cancelPlacementFrame();
412
+ menu?.style.removeProperty(NAV_DROPDOWN_SHIFT_PROPERTY);
413
+ };
414
+ const schedulePlacement = () => {
415
+ if (!menu) return;
416
+ resetPlacement();
417
+ placementRafScheduled = true;
418
+ const id = window.requestAnimationFrame(() => {
419
+ placementRafScheduled = false;
420
+ placementRafId = null;
421
+ const rect = menu.getBoundingClientRect();
422
+ const plan = planDropdownViewportShift({
423
+ left: rect.left,
424
+ right: rect.right,
425
+ viewportWidth: document.documentElement.clientWidth,
426
+ gutter: NAV_DROPDOWN_VIEWPORT_GUTTER_PX
427
+ });
428
+ applyDropdownPlacementPlan(menu, plan);
429
+ });
430
+ placementRafId = placementRafScheduled ? id : null;
431
+ };
432
+ setExpanded(trigger, false);
433
+ const handleEnter = () => {
434
+ setExpanded(trigger, true);
435
+ schedulePlacement();
436
+ };
437
+ const handleLeave = () => {
438
+ if (dropdown.contains(document.activeElement)) return;
439
+ setExpanded(trigger, false);
440
+ resetPlacement();
441
+ };
442
+ const handleFocusIn = () => {
443
+ setExpanded(trigger, true);
444
+ schedulePlacement();
445
+ };
446
+ const handleFocusOut = (event) => {
447
+ const next = event.relatedTarget;
448
+ if (!next || !dropdown.contains(next)) {
449
+ setExpanded(trigger, false);
450
+ resetPlacement();
451
+ }
452
+ };
453
+ dropdown.addEventListener("mouseenter", handleEnter);
454
+ dropdown.addEventListener("mouseleave", handleLeave);
455
+ dropdown.addEventListener("focusin", handleFocusIn);
456
+ dropdown.addEventListener("focusout", handleFocusOut);
457
+ cleanups.push(() => {
458
+ dropdown.removeEventListener("mouseenter", handleEnter);
459
+ dropdown.removeEventListener("mouseleave", handleLeave);
460
+ dropdown.removeEventListener("focusin", handleFocusIn);
461
+ dropdown.removeEventListener("focusout", handleFocusOut);
462
+ resetPlacement();
463
+ });
464
+ });
465
+ return cleanups;
466
+ }
467
+ function enhanceMobileDropdowns(root) {
468
+ const cleanups = [];
469
+ const triggers = Array.from(root.querySelectorAll(SELECTORS.mobileTrigger));
470
+ const reset = () => {
471
+ triggers.forEach((trigger) => {
472
+ const dropdown = trigger.closest(SELECTORS.mobileDropdown);
473
+ const children = dropdown?.querySelector(SELECTORS.mobileChildren);
474
+ trigger.setAttribute("aria-expanded", "false");
475
+ children?.classList.add(CLASSES.hidden);
476
+ dropdown?.classList.remove(CLASSES.mobileOpen);
477
+ });
478
+ };
479
+ triggers.forEach((trigger) => {
480
+ const dropdown = trigger.closest(SELECTORS.mobileDropdown);
481
+ const children = dropdown?.querySelector(SELECTORS.mobileChildren);
482
+ if (!children) return;
483
+ trigger.setAttribute("aria-expanded", "false");
484
+ const handleClick = () => {
485
+ const isOpen = trigger.getAttribute("aria-expanded") === "true";
486
+ trigger.setAttribute("aria-expanded", isOpen ? "false" : "true");
487
+ children.classList.toggle(CLASSES.hidden, isOpen);
488
+ dropdown?.classList.toggle(CLASSES.mobileOpen, !isOpen);
489
+ };
490
+ trigger.addEventListener("click", handleClick);
491
+ cleanups.push(() => trigger.removeEventListener("click", handleClick));
492
+ });
493
+ return { cleanups, reset };
494
+ }
495
+ function enhanceMobileOverlay(root, resetMobileDropdowns) {
496
+ const cleanups = [];
497
+ const overlay = root.querySelector(SELECTORS.mobileOverlay);
498
+ const toggles = Array.from(root.querySelectorAll(SELECTORS.mobileToggle));
499
+ const backdrop = root.querySelector(SELECTORS.mobileBackdrop);
500
+ const closeBtn = root.querySelector(SELECTORS.mobileClose);
501
+ if (!overlay || toggles.length === 0) return { cleanups };
502
+ overlay.classList.remove(CLASSES.hidden);
503
+ overlay.setAttribute("aria-hidden", "true");
504
+ overlay.setAttribute("inert", "");
505
+ toggles.forEach((toggle) => toggle.setAttribute("aria-expanded", "false"));
506
+ const state = {
507
+ isOpen: overlay.getAttribute("aria-hidden") === "false",
508
+ previousBodyOverflow: null,
509
+ previousBodyPaddingRight: null,
510
+ lastActiveElement: null
511
+ };
512
+ const setOpen = (open) => {
513
+ state.isOpen = open;
514
+ overlay.setAttribute("aria-hidden", open ? "false" : "true");
515
+ toggles.forEach((toggle) => {
516
+ toggle.setAttribute("aria-expanded", open ? "true" : "false");
517
+ toggle.setAttribute("aria-label", open ? "Close menu" : "Open menu");
518
+ });
519
+ if (open) {
520
+ overlay.removeAttribute("inert");
521
+ state.previousBodyOverflow = document.body.style.overflow;
522
+ state.previousBodyPaddingRight = document.body.style.paddingRight;
523
+ const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
524
+ if (scrollbarWidth > 0) {
525
+ document.body.style.paddingRight = `${scrollbarWidth}px`;
526
+ }
527
+ document.body.style.overflow = "hidden";
528
+ state.lastActiveElement = document.activeElement;
529
+ const overlayToggle = overlay.querySelector(SELECTORS.mobileToggle);
530
+ const focusTarget = overlayToggle ?? overlay.querySelector(FOCUSABLE_SELECTOR);
531
+ if (focusTarget) {
532
+ try {
533
+ focusTarget.focus({ preventScroll: true });
534
+ } catch {
535
+ focusTarget.focus();
536
+ }
537
+ }
538
+ } else {
539
+ overlay.setAttribute("inert", "");
540
+ if (state.previousBodyOverflow !== null) {
541
+ document.body.style.overflow = state.previousBodyOverflow;
542
+ state.previousBodyOverflow = null;
543
+ if (state.previousBodyPaddingRight !== null) {
544
+ document.body.style.paddingRight = state.previousBodyPaddingRight;
545
+ state.previousBodyPaddingRight = null;
546
+ }
547
+ if (state.lastActiveElement) {
548
+ try {
549
+ state.lastActiveElement.focus({ preventScroll: true });
550
+ } catch {
551
+ state.lastActiveElement.focus();
552
+ }
553
+ }
554
+ }
555
+ }
556
+ };
557
+ const handleClose = () => {
558
+ setOpen(false);
559
+ resetMobileDropdowns();
560
+ };
561
+ const handleToggleClick = () => {
562
+ if (state.isOpen) {
563
+ handleClose();
564
+ return;
565
+ }
566
+ setOpen(true);
567
+ };
568
+ const handleKeyDown = (event) => {
569
+ if (!state.isOpen) return;
570
+ if (event.key !== "Escape") return;
571
+ event.preventDefault();
572
+ handleClose();
573
+ };
574
+ const handleOverlayClick = (event) => {
575
+ const targetEl = event.target;
576
+ const link = targetEl?.closest("a[href]");
577
+ if (link) handleClose();
578
+ };
579
+ toggles.forEach((toggle) => toggle.addEventListener("click", handleToggleClick));
580
+ backdrop?.addEventListener("click", handleClose);
581
+ closeBtn?.addEventListener("click", handleClose);
582
+ document.addEventListener("keydown", handleKeyDown);
583
+ overlay.addEventListener("click", handleOverlayClick);
584
+ cleanups.push(() => {
585
+ setOpen(false);
586
+ toggles.forEach((toggle) => toggle.removeEventListener("click", handleToggleClick));
587
+ backdrop?.removeEventListener("click", handleClose);
588
+ closeBtn?.removeEventListener("click", handleClose);
589
+ document.removeEventListener("keydown", handleKeyDown);
590
+ overlay.removeEventListener("click", handleOverlayClick);
591
+ if (state.previousBodyOverflow !== null) document.body.style.overflow = state.previousBodyOverflow;
592
+ if (state.previousBodyPaddingRight !== null) document.body.style.paddingRight = state.previousBodyPaddingRight;
593
+ });
594
+ return { cleanups };
595
+ }
596
+ function getFirstParsedCartMount(mounts) {
597
+ return mounts[0] ?? null;
598
+ }
599
+ function readOptionalDatasetValue(element, key) {
600
+ const value = element.dataset[key];
601
+ if (typeof value !== "string") return null;
602
+ const trimmed = value.trim();
603
+ return trimmed.length > 0 ? trimmed : null;
604
+ }
605
+ function parseCartMount(element) {
606
+ const siteId = readOptionalDatasetValue(element, "navCartSiteId");
607
+ const context = readOptionalDatasetValue(element, "navCartContext");
608
+ if (!siteId || context !== "desktop" && context !== "mobile") {
609
+ return null;
610
+ }
611
+ const badge = readOptionalDatasetValue(element, "navCartBadge") === "hidden" ? "hidden" : "show-count";
612
+ return {
613
+ siteId,
614
+ mount: {
615
+ element,
616
+ context,
617
+ badge,
618
+ ariaLabel: readOptionalDatasetValue(element, "navCartAriaLabel") ?? "Cart",
619
+ visibleLabel: readOptionalDatasetValue(element, "navCartVisibleLabel"),
620
+ checkoutHref: readOptionalDatasetValue(element, "navCartCheckoutHref")
621
+ }
622
+ };
623
+ }
624
+ function enhanceCartMounts(root) {
625
+ const cleanups = [];
626
+ const parsedMounts = Array.from(root.querySelectorAll(SELECTORS.cartPlaceholder)).map((element) => parseCartMount(element)).filter((mount) => mount !== null);
627
+ const firstMount = getFirstParsedCartMount(parsedMounts);
628
+ if (!firstMount) {
629
+ return { cleanups };
630
+ }
631
+ const siteId = firstMount.siteId;
632
+ const mounts = parsedMounts.filter((mount) => mount.siteId === siteId).map((mount) => mount.mount);
633
+ const cleanup = mountHeaderCartRuntime(root, siteId, mounts);
634
+ if (cleanup) {
635
+ cleanups.push(cleanup);
636
+ }
637
+ return { cleanups };
638
+ }
639
+ var SCROLL_THRESHOLD_PX = 8;
640
+ var SCROLL_HYSTERESIS_PX = 4;
641
+ var SCROLL_ON_THRESHOLD_PX = SCROLL_THRESHOLD_PX;
642
+ var SCROLL_OFF_THRESHOLD_PX = Math.max(0, SCROLL_THRESHOLD_PX - SCROLL_HYSTERESIS_PX);
643
+ function getScrollContainer(element) {
644
+ let parent = element.parentElement;
645
+ while (parent && parent !== document.body) {
646
+ const style = getComputedStyle(parent);
647
+ const overflowY = style.overflowY || style.overflow;
648
+ if (/auto|scroll|overlay/.test(overflowY)) {
649
+ if (parent.scrollHeight > parent.clientHeight) {
650
+ return parent;
651
+ }
652
+ }
653
+ parent = parent.parentElement;
654
+ }
655
+ return document.scrollingElement || window;
656
+ }
657
+ function getRootScrollTop() {
658
+ if (typeof window.scrollY === "number" && Number.isFinite(window.scrollY)) return window.scrollY;
659
+ const scrollingElement = document.scrollingElement;
660
+ if (scrollingElement) return scrollingElement.scrollTop;
661
+ return document.documentElement.scrollTop || document.body.scrollTop || 0;
662
+ }
663
+ function enhanceScrollBehavior(target, scrollEnabled) {
664
+ const cleanups = [];
665
+ const enabled = typeof scrollEnabled === "boolean" ? scrollEnabled : target.classList.contains(CLASSES.headerShrink);
666
+ if (!enabled) return cleanups;
667
+ const scrollContainer = getScrollContainer(target);
668
+ const isRootScroll = scrollContainer === window || scrollContainer instanceof HTMLElement && (scrollContainer === document.scrollingElement || scrollContainer === document.documentElement || scrollContainer === document.body);
669
+ const scrollEventTarget = isRootScroll ? window : scrollContainer;
670
+ const getScrollTop = () => isRootScroll ? getRootScrollTop() : scrollContainer.scrollTop;
671
+ const update = () => {
672
+ const scrollTop = Math.max(0, getScrollTop());
673
+ const isScrolled = target.classList.contains(CLASSES.headerScrolled);
674
+ if (isScrolled) {
675
+ if (scrollTop < SCROLL_OFF_THRESHOLD_PX) target.classList.remove(CLASSES.headerScrolled);
676
+ return;
677
+ }
678
+ if (scrollTop > SCROLL_ON_THRESHOLD_PX) target.classList.add(CLASSES.headerScrolled);
679
+ };
680
+ let rafId = null;
681
+ let rafScheduled = false;
682
+ const onScroll = () => {
683
+ if (rafScheduled) return;
684
+ rafScheduled = true;
685
+ const id = window.requestAnimationFrame(() => {
686
+ rafScheduled = false;
687
+ rafId = null;
688
+ update();
689
+ });
690
+ rafId = id;
691
+ if (!rafScheduled) rafId = null;
692
+ };
693
+ update();
694
+ scrollEventTarget.addEventListener("scroll", onScroll, { passive: true });
695
+ cleanups.push(() => {
696
+ scrollEventTarget.removeEventListener("scroll", onScroll);
697
+ if (rafId !== null) window.cancelAnimationFrame(rafId);
698
+ });
699
+ return cleanups;
700
+ }
701
+ function enhanceHeaderSection(root, options = {}) {
702
+ if (root.dataset.rbHeaderEnhanced === "true") return;
703
+ root.dataset.rbHeaderEnhanced = "true";
704
+ const cleanups = [];
705
+ cleanups.push(...enhanceDesktopDropdownAria(root));
706
+ const mobileDropdowns = enhanceMobileDropdowns(root);
707
+ cleanups.push(...mobileDropdowns.cleanups);
708
+ const overlay = enhanceMobileOverlay(root, mobileDropdowns.reset);
709
+ cleanups.push(...overlay.cleanups);
710
+ const cartMounts = enhanceCartMounts(root);
711
+ cleanups.push(...cartMounts.cleanups);
712
+ const target = options.scrollTarget ?? getFirstNonScriptChild(root);
713
+ if (target) {
714
+ cleanups.push(...enhanceScrollBehavior(target, options.scrollEnabled));
715
+ }
716
+ if (cleanups.length === 0) return;
717
+ return () => {
718
+ cleanups.forEach((fn) => fn());
719
+ };
720
+ }
721
+
722
+ // src/rendering/islands/enhancers/headerSection.ts
723
+ var decode = defineIslandPropsDecoder("headerSection");
724
+ var enhance = (root, props) => {
725
+ const scrollEnabled = typeof props?.scrollEnabled === "boolean" ? props.scrollEnabled : typeof props?.enabled === "boolean" ? props.enabled : void 0;
726
+ return enhanceHeaderSection(root, { scrollEnabled });
727
+ };
728
+
729
+ export { decode, enhance };