@riverbankcms/sdk 0.140.0 → 0.142.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/dist/{PreviewEditorSidebar-CUyTzd5z.mjs → PreviewEditorSidebar-Dk6Dt11f.mjs} +24 -15
  2. package/dist/{PreviewEditorUI-Agkw4v5i.mjs → PreviewEditorUI-D6EQTsCA.mjs} +3 -3
  3. package/dist/{PreviewQueryProvider-CN0ewic5.mjs → PreviewQueryProvider-CC-EPkyQ.mjs} +1 -1
  4. package/dist/{SdkPreviewModeRuntime-DdbeAdS8.mjs → SdkPreviewModeRuntime-DH1n4ytY.mjs} +85 -54
  5. package/dist/{SiteChromeCustomizeContext-CqGOz-Kv.mjs → SiteChromeCustomizeContext-DunIzY0K.mjs} +797 -216
  6. package/dist/_dts/api/src/billing.d.ts +6 -1
  7. package/dist/_dts/api/src/bookingConfig.d.ts +1 -1
  8. package/dist/_dts/api/src/commercePortalEndpoints.d.ts +2 -2
  9. package/dist/_dts/api/src/contentRuntime.d.ts +12 -31
  10. package/dist/_dts/api/src/domainConnection.d.ts +4 -0
  11. package/dist/_dts/api/src/endpoints.d.ts +0 -27
  12. package/dist/_dts/api/src/footerCompositionContracts.d.ts +25 -0
  13. package/dist/_dts/api/src/index.d.ts +2 -2
  14. package/dist/_dts/api/src/launchReadiness.d.ts +1 -0
  15. package/dist/_dts/api/src/navigation/dashboardSiteNav.d.ts +2 -1
  16. package/dist/_dts/api/src/publicBookingService.d.ts +1 -0
  17. package/dist/_dts/api/src/sdkConfig/layout.d.ts +13 -0
  18. package/dist/_dts/api/src/sdkContracts.d.ts +3 -8
  19. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +3 -26
  20. package/dist/_dts/api/src/siteOnboarding.d.ts +7 -0
  21. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +1 -31
  22. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +6 -1
  23. package/dist/_dts/billing/src/site-arrangements.d.ts +18 -5
  24. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +4 -0
  25. package/dist/_dts/blocks/src/pageRendererContracts.d.ts +2 -0
  26. package/dist/_dts/blocks/src/system/blocks/events/event-calendar.d.ts +2 -0
  27. package/dist/_dts/blocks/src/system/blocks/events/eventSelectionFields.d.ts +122 -0
  28. package/dist/_dts/blocks/src/system/blocks/events/shared/calendarWindow.d.ts +2 -1
  29. package/dist/_dts/blocks/src/system/blocks/events/shared/eventSelection.d.ts +11 -0
  30. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +56 -0
  31. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +8 -0
  32. package/dist/_dts/blocks/src/system/blocks/location-map.d.ts +2 -2
  33. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +47 -47
  34. package/dist/_dts/blocks/src/system/data/prefetchBlockData.d.ts +5 -0
  35. package/dist/_dts/blocks/src/system/data/utils.d.ts +1 -1
  36. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +27 -1
  37. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +12 -180
  38. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +6 -90
  39. package/dist/_dts/blocks/src/system/runtime/hooks/useEventFilters.d.ts +2 -1
  40. package/dist/_dts/blocks/src/system/runtime/nodes/appointment-services.d.ts +5 -1
  41. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.d.ts +4 -0
  42. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.state.d.ts +5 -0
  43. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useDiscountCodeUi.d.ts +3 -0
  44. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useDiscountCodeUi.state.d.ts +10 -3
  45. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventCheckoutHandoffRestore.d.ts +9 -0
  46. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +4 -5
  47. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useSettledCommerceView.d.ts +37 -0
  48. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +4 -3
  49. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +3 -0
  50. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventListing.interactive.d.ts +11 -101
  51. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +63 -2
  52. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/listOptions.d.ts +2 -0
  53. package/dist/_dts/blocks/src/system/transforms/registry/eventCalendar.d.ts +12 -0
  54. package/dist/_dts/commerce/src/purchase/bookingInstalmentSchedule.d.ts +4 -0
  55. package/dist/_dts/commerce/src/purchase/stripeCommissionMetadata.d.ts +1 -2
  56. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +3102 -3122
  57. package/dist/_dts/editor-blocks/src/block-editor/ColourFieldOptionsProvider.d.ts +7 -0
  58. package/dist/_dts/editor-blocks/src/block-editor/colourFieldVisibility.d.ts +7 -0
  59. package/dist/_dts/editor-blocks/src/block-editor/preparedManifest.d.ts +2 -0
  60. package/dist/_dts/editor-blocks/src/index.d.ts +1 -0
  61. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/loaders.d.ts +27 -1
  62. package/dist/_dts/preview-next/src/client/preview/PreviewEditorSidebar.d.ts +2 -2
  63. package/dist/_dts/preview-next/src/client/preview/PreviewFooterEditorPanel.d.ts +3 -6
  64. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +2 -2
  65. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +2 -2
  66. package/dist/_dts/preview-next/src/client/preview/footerInspection.d.ts +16 -0
  67. package/dist/_dts/preview-next/src/client/preview/sdkConfig.d.ts +6 -0
  68. package/dist/_dts/sdk/src/config/types.d.ts +2 -18
  69. package/dist/_dts/sdk/src/config/validation.d.ts +6 -0
  70. package/dist/_dts/sdk/src/public-api/contracts.d.ts +4 -1
  71. package/dist/_dts/sdk/src/version.d.ts +1 -1
  72. package/dist/_dts/theme-core/src/ThemeFontLoader.d.ts +17 -1
  73. package/dist/_dts/theme-core/src/buttons/affordanceSuppression.d.ts +17 -0
  74. package/dist/_dts/theme-core/src/buttons/buttonColourContract.d.ts +1 -1
  75. package/dist/_dts/theme-core/src/buttons/classNames.d.ts +16 -0
  76. package/dist/_dts/theme-core/src/buttons/generateButtonCss.d.ts +0 -6
  77. package/dist/_dts/theme-core/src/buttons/resolvedButtonCss.d.ts +4 -4
  78. package/dist/_dts/theme-core/src/footer/mode.d.ts +10 -1
  79. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  80. package/dist/_dts/theme-core/src/hosted-booking-appearance.d.ts +54 -12
  81. package/dist/_dts/theme-core/src/index.d.ts +1 -1
  82. package/dist/_dts/theme-core/src/schema.d.ts +1 -7
  83. package/dist/_dts/theme-core/src/site-styles/effectivePageDesign.d.ts +32 -0
  84. package/dist/_dts/theme-core/src/site-styles/index.d.ts +1 -0
  85. package/dist/client/{BookingConsentAgreement-CuKa82V4.mjs → BookingConsentAgreement-CnJeq3_r.mjs} +2 -2
  86. package/dist/client/{DiscountCodeDisclosure-BbYieKWB.mjs → DiscountCodeDisclosure-BINEO6J9.mjs} +1 -1
  87. package/dist/client/{EventCombined.client-LTfR1Aby.mjs → EventCombined.client-srxNQ6sZ.mjs} +11 -15
  88. package/dist/client/{EventListing.client-DUHpYSuo.mjs → EventListing.client-DbyVyGkX.mjs} +4 -17
  89. package/dist/client/{LeafletStaticMap-CHRupL6m.mjs → LeafletStaticMap-B-wpijzL.mjs} +1 -1
  90. package/dist/client/{accordion-6HiIFxNL.mjs → accordion-B-iUXU7n.mjs} +1 -1
  91. package/dist/client/{bookingForm-Dlmid43H.mjs → bookingForm-BXYPke5q.mjs} +5 -5
  92. package/dist/client/bookings.mjs +194 -102
  93. package/dist/client/{carousel-DmkZRRq_.mjs → carousel-Cr4aj63H.mjs} +1 -1
  94. package/dist/client/{cart-CIC24330.mjs → cart-DibP9WWa.mjs} +3 -3
  95. package/dist/client/{checkout-D1Zw9imo.mjs → checkout-CrSBVnL8.mjs} +3 -3
  96. package/dist/client/client.mjs +643 -192
  97. package/dist/client/{context-Cy1OayHx.mjs → context-Ces-AgdR.mjs} +1 -1
  98. package/dist/client/{dates-aDcfoLHr.mjs → dates-BXyNeNhB.mjs} +2 -2
  99. package/dist/client/{eventCalendar-FQxMPAjf.mjs → eventCalendar-HwpPeqrH.mjs} +11 -7
  100. package/dist/client/{eventCombined-Dr3ac6Hb.mjs → eventCombined-BpFUkuEI.mjs} +3 -3
  101. package/dist/client/{eventDetails-D-AzUHFQ.mjs → eventDetails-DK_agiWy.mjs} +4 -4
  102. package/dist/client/{eventListing-B3XxBf3i.mjs → eventListing-DhzHqP1c.mjs} +3 -3
  103. package/dist/client/{eventRegistration-I6EaokFD.mjs → eventRegistration-BdQ_Dn2d.mjs} +124 -32
  104. package/dist/client/{form-BbWckVWY.mjs → form-B1frcuzy.mjs} +2 -2
  105. package/dist/client/{headerSection-C9qU4Y7x.mjs → headerSection-CT5z460s.mjs} +2 -2
  106. package/dist/client/hooks.mjs +274 -45
  107. package/dist/client/{locationMap-CLCShvlG.mjs → locationMap-CIQXB9i2.mjs} +2 -2
  108. package/dist/client/{newsletterForm-Briukxzi.mjs → newsletterForm-BYNYZSes.mjs} +23 -10
  109. package/dist/client/{pricing-Copadu-2.mjs → pricing-CbTlAsmt.mjs} +1 -1
  110. package/dist/client/{productDetail-oujlRd-r.mjs → productDetail-CR7Z3yjS.mjs} +3 -3
  111. package/dist/client/{productList-BRiIRUcd.mjs → productList-DXj00vzR.mjs} +3 -3
  112. package/dist/client/{propsDecoder-CB2KS_ko.mjs → propsDecoder-DiLiBdek.mjs} +57 -16
  113. package/dist/client/rendering/client.mjs +476 -132
  114. package/dist/client/rendering/islands.mjs +17 -17
  115. package/dist/client/rendering.mjs +686 -195
  116. package/dist/client/{scrollToBlock-B1IS1_ua.mjs → scrollToBlock-CrcbBf0h.mjs} +28 -11
  117. package/dist/client/{shop-Vn6yNFED.mjs → shop-DgqiB_1b.mjs} +6 -6
  118. package/dist/client/{shop-commerce-BVTqipYp.mjs → shop-commerce-D_J781in.mjs} +5 -5
  119. package/dist/client/{shop-commerce-store-BVnJVy7v.mjs → shop-commerce-store-PGUbDwqe.mjs} +1 -1
  120. package/dist/client/{shopShared-COIeK77T.mjs → shopShared-C_Bb2zwG.mjs} +3 -3
  121. package/dist/client/{useEventFilters-DzIUcS9n.mjs → useEventFilters-CM17Xpr1.mjs} +17 -11
  122. package/dist/preview-next/before-render.mjs +0 -37
  123. package/dist/preview-next/client/runtime.mjs +4 -4
  124. package/dist/preview-next/editor-chrome.css +4 -8
  125. package/dist/preview-next/keepAlive.mjs +0 -37
  126. package/dist/preview-next/middleware.mjs +0 -37
  127. package/dist/{previewAuthStore-Gjb6r6vz.mjs → previewAuthStore-oVttoRDO.mjs} +0 -37
  128. package/dist/{sdk-runtime-CnCLvZRv.mjs → sdk-runtime-DhmuRhIX.mjs} +2 -2
  129. package/dist/{separator-DKDRJ1oH.mjs → separator-C3hlg9LH.mjs} +1 -1
  130. package/dist/server/components.mjs +452 -111
  131. package/dist/server/config-validation.mjs +263 -40
  132. package/dist/server/config.mjs +263 -40
  133. package/dist/server/data.mjs +274 -45
  134. package/dist/server/index.mjs +1 -38
  135. package/dist/server/next.mjs +427 -119
  136. package/dist/server/page-converter.mjs +208 -33
  137. package/dist/server/prebuild.mjs +1 -1
  138. package/dist/server/rendering/server.mjs +467 -119
  139. package/dist/server/rendering.mjs +467 -117
  140. package/dist/server/routing.mjs +301 -50
  141. package/dist/server/server.mjs +275 -83
  142. package/dist/server/theme-bridge.mjs +57 -23
  143. package/dist/server/theme.mjs +11 -9
  144. package/dist/styles/index.css +28 -2
  145. package/package.json +1 -1
@@ -3259,6 +3259,14 @@ function adaptFields(rawFields, flattenRepeaterGroups = false, defaultFileKinds
3259
3259
  }];
3260
3260
  }));
3261
3261
  }
3262
+ //#endregion
3263
+ //#region ../theme-core/src/footer/mode.ts
3264
+ const footerModeSchema = z$1.enum([
3265
+ "default",
3266
+ "blocks",
3267
+ "default+blocks",
3268
+ "none"
3269
+ ]);
3262
3270
  const hotspotSchema = z$1.object({
3263
3271
  x: z$1.number().min(0).max(1),
3264
3272
  y: z$1.number().min(0).max(1),
@@ -4760,7 +4768,7 @@ const BUTTON_CONTRAST_POLICY = {
4760
4768
  nonTextMinimumRatio: 3,
4761
4769
  gradientSamplesPerSegment: 20,
4762
4770
  alphaBackgrounds: "reject-without-known-surface",
4763
- disabled: "retain-full-colour-contract"
4771
+ disabled: "validated-colour-pair-with-muted-control-opacity"
4764
4772
  };
4765
4773
  function formatButtonColourContractError(error) {
4766
4774
  switch (error.tag) {
@@ -5348,6 +5356,25 @@ function parseThemeForPersistence(value) {
5348
5356
  };
5349
5357
  }
5350
5358
  //#endregion
5359
+ //#region ../theme-core/src/buttons/affordanceSuppression.ts
5360
+ /**
5361
+ * Internal: the opt-out the generated affordance rule is written against.
5362
+ *
5363
+ * A button style may declare a trailing `affordance`, which the theme renders as
5364
+ * a CSS `::after` on every button of that variant. An authored button that
5365
+ * renders its own trailing icon must not also receive the theme's, or it shows
5366
+ * two.
5367
+ *
5368
+ * Deliberately not exported from `./index`. This used to be public, and two
5369
+ * block components reached past the theme to draw arrows of their own — one of
5370
+ * them doubling up on the styles that declare an affordance, both of them
5371
+ * overriding the twelve styles that deliberately declare none. Whether a button
5372
+ * carries a trailing affordance is the style's decision; the only caller that
5373
+ * legitimately opts out is the authored-button renderer, which reaches it
5374
+ * through `themeButtonClassNameWithTrailingIcon`.
5375
+ */
5376
+ const AFFORDANCE_SUPPRESS_CLASS = "rb-affordance-off";
5377
+ //#endregion
5351
5378
  //#region ../theme-core/src/buttons/classNames.ts
5352
5379
  /**
5353
5380
  * Parse content/runtime variant identifiers into the closed theme-button class
@@ -5380,6 +5407,27 @@ function themeButtonClassName(spec) {
5380
5407
  spec.extraClassName
5381
5408
  ].filter(Boolean).join(" ");
5382
5409
  }
5410
+ /**
5411
+ * Button classes for an authored button that renders its own trailing icon.
5412
+ *
5413
+ * A separate function rather than a flag on `themeButtonClassName`, because
5414
+ * there is exactly one caller and it should stay visible in a diff. The name
5415
+ * states what the caller knows to be true of its own markup — that it renders a
5416
+ * trailing icon — rather than what the theme does about it. The consequence is
5417
+ * the theme's to decide and to change; a caller naming the consequence would be
5418
+ * asserting a policy it does not own, and would quietly become a lie the moment
5419
+ * that policy moved.
5420
+ *
5421
+ * Do not reach for this to remove an arrow you simply do not want. A trailing
5422
+ * affordance is declared by the button style, and a block overriding that is the
5423
+ * defect this replaced.
5424
+ */
5425
+ function themeButtonClassNameWithTrailingIcon(spec) {
5426
+ return themeButtonClassName({
5427
+ ...spec,
5428
+ extraClassName: [spec.extraClassName, AFFORDANCE_SUPPRESS_CLASS].filter(Boolean).join(" ")
5429
+ });
5430
+ }
5383
5431
  const defaultThemeTokens = {
5384
5432
  color: {
5385
5433
  "background/base": "#ffffff",
@@ -7798,26 +7846,19 @@ function resolvedButtonFocusDeclarations(indicator, role) {
7798
7846
  ] : [["outline", value("outline", `3px solid ${indicator.colorCss}`)], ["outline-offset", value("outline-offset", "3px")]];
7799
7847
  }
7800
7848
  /**
7801
- * Disabled buttons retain their validated colour pair and add a non-layout
7802
- * visual affordance. `currentColor` keeps the cue inside the same contrast
7803
- * relationship, while retaining pointer events lets the not-allowed cursor
7804
- * remain observable.
7849
+ * Disabled buttons are deliberately muted as unavailable controls. Native
7850
+ * disabled controls are exempt from active-control contrast requirements;
7851
+ * opacity distinguishes the state without introducing a focus-like outline.
7852
+ * Retaining pointer events lets the not-allowed cursor remain observable.
7805
7853
  */
7806
7854
  const RESOLVED_BUTTON_DISABLED_DECLARATIONS = [
7807
7855
  ["cursor", "not-allowed"],
7808
7856
  ["transform", "none"],
7809
7857
  ["box-shadow", "none"],
7810
- ["outline", "2px dashed currentColor"],
7811
- ["outline-offset", "-4px"]
7858
+ ["opacity", "0.55"]
7812
7859
  ];
7813
7860
  //#endregion
7814
7861
  //#region ../theme-core/src/buttons/generateButtonCss.ts
7815
- /**
7816
- * Class the `button` runtime node adds when it renders its own trailing icon,
7817
- * so a node-level icon suppresses the theme's CSS `::after` affordance.
7818
- * Shared so generator and renderer can't drift.
7819
- */
7820
- const AFFORDANCE_SUPPRESS_CLASS = "rb-affordance-off";
7821
7862
  const BUTTON_SIZE_NAMES = buttonSizeNameSchema.options;
7822
7863
  /**
7823
7864
  * Letter spacing token → CSS value.
@@ -10611,14 +10652,12 @@ function generateVariantCSS(variant, themeId, cardClasses, tokens, theme) {
10611
10652
  const shadowValue = generateShadowValue(shadow);
10612
10653
  rules.push(`box-shadow: ${shadowValue}`);
10613
10654
  }
10614
- rules.push(`display: flex`);
10615
- rules.push(`flex-direction: column`);
10616
- rules.push(`position: relative`);
10617
- rules.push(`overflow: visible`);
10655
+ const structureSelector = cardClasses.map((cardClass) => `:where([data-theme-scope="${themeId}"]) :where(.${cardClass})`).join(",\n");
10618
10656
  const mediaRadius = MEDIA_CORNER_MAP[corners];
10619
10657
  const mediaRules = [`border-top-left-radius: ${mediaRadius}`, `border-top-right-radius: ${mediaRadius}`];
10620
10658
  const contentRules = [`padding: ${resolveContentPadding(variant)}`];
10621
10659
  return [
10660
+ `${structureSelector} {\n display: flex;\n flex-direction: column;\n position: relative;\n overflow: visible;\n}`,
10622
10661
  `${containerSelector} {\n ${rules.join(";\n ")};\n}`,
10623
10662
  ...cardDecorationPseudoRules(containerSelectors, variant.decorations, resolveColor),
10624
10663
  `${fallbackBackgroundSelector} {\n background: transparent;\n}`,
@@ -12580,12 +12619,6 @@ const footerVariant = z$1.enum([
12580
12619
  "split"
12581
12620
  ]);
12582
12621
  const footerMaxWidth = z$1.enum(["container", "full"]);
12583
- const footerMode = z$1.enum([
12584
- "default",
12585
- "blocks",
12586
- "default+blocks",
12587
- "none"
12588
- ]);
12589
12622
  const footerNavLayoutMode = z$1.enum([
12590
12623
  "stack",
12591
12624
  "inline",
@@ -12674,9 +12707,9 @@ const footerSchema = z$1.object({
12674
12707
  /**
12675
12708
  * SDK-only footer rendering mode.
12676
12709
  *
12677
- * Backwards compatible: missing/undefined behaves as 'default'.
12710
+ * Historical persisted field; SDK rendering mode now lives in layout.footerMode.
12678
12711
  */
12679
- mode: footerMode.optional(),
12712
+ mode: footerModeSchema.optional(),
12680
12713
  variant: footerVariant,
12681
12714
  maxWidth: footerMaxWidth,
12682
12715
  showLogoText: z$1.boolean().optional(),
@@ -13299,6 +13332,15 @@ const publicEventBaseSchema = z$1.object({
13299
13332
  timeZone: z$1.string(),
13300
13333
  pricing: publicEventPricingSchema,
13301
13334
  paymentTerms: blockBookingPaymentTermsSchema,
13335
+ cancellationPolicy: z$1.object({ refunds: z$1.object({
13336
+ mode: z$1.enum([
13337
+ "never",
13338
+ "always",
13339
+ "cutoff"
13340
+ ]),
13341
+ cutoffHours: z$1.number(),
13342
+ method: z$1.enum(["original_payment_method", "site_credit"])
13343
+ }) }),
13302
13344
  consent: blockBookingConsentSchema.nullable(),
13303
13345
  accessRestriction: accessRestrictionSchema,
13304
13346
  allowedCategoryIds: z$1.array(z$1.string()),
@@ -13470,6 +13512,7 @@ const calendarWindowQuerySchema = z$1.object({
13470
13512
  eventSurface: z$1.enum(eventSurfaceScopeValues).optional(),
13471
13513
  eventPresets: z$1.string().optional(),
13472
13514
  scheduleScope: z$1.enum(eventScheduleScopeValues).optional(),
13515
+ seriesIds: z$1.string().optional(),
13473
13516
  categoryIds: z$1.string().optional(),
13474
13517
  venueId: z$1.string().transform(normalizeCalendarFilterId).optional(),
13475
13518
  staffMemberId: z$1.string().transform(normalizeCalendarFilterId).optional()
@@ -23298,6 +23341,7 @@ function isDisplayMediaKind$2(kind) {
23298
23341
  }
23299
23342
  const siteOptionSources = [
23300
23343
  "eventCategories",
23344
+ "eventSeries",
23301
23345
  "venues",
23302
23346
  "staffMembers"
23303
23347
  ];
@@ -27666,6 +27710,35 @@ function buildBookingFormInteractiveIslandProps(props) {
27666
27710
  });
27667
27711
  }
27668
27712
  //#endregion
27713
+ //#region ../blocks/src/system/blocks/events/shared/eventSelection.ts
27714
+ /** Invalid saved selections fail closed rather than widening discovery. */
27715
+ function resolveEventSelection(mode, value) {
27716
+ if (mode !== "selected") return { kind: "matching" };
27717
+ const candidates = Array.isArray(value) ? value : typeof value === "string" ? value.split(",").filter(Boolean) : [];
27718
+ const ids = [];
27719
+ for (const candidate of candidates) {
27720
+ if (typeof candidate !== "string") return {
27721
+ kind: "selected",
27722
+ seriesIds: []
27723
+ };
27724
+ const parsed = parseEventSeriesId(candidate.trim());
27725
+ if (!parsed.ok) return {
27726
+ kind: "selected",
27727
+ seriesIds: []
27728
+ };
27729
+ ids.push(parsed.value);
27730
+ }
27731
+ return {
27732
+ kind: "selected",
27733
+ seriesIds: [...new Set(ids)].sort()
27734
+ };
27735
+ }
27736
+ /** Undefined means discovery; an empty string is an explicitly empty selection. */
27737
+ function eventSeriesScopeCsv(value) {
27738
+ if (value == null) return void 0;
27739
+ return typeof value === "string" ? value : value.join(",");
27740
+ }
27741
+ //#endregion
27669
27742
  //#region ../blocks/src/system/runtime/nodes/events/domain/capacity.ts
27670
27743
  /**
27671
27744
  * Compute remaining spots for an event from `availableSpots` with a fallback
@@ -30285,12 +30358,12 @@ const EventCompactRow = ({ event, buttonVariant = "primary", buttonText }) => {
30285
30358
  }), cta.hidden ? /* @__PURE__ */ jsx("span", {
30286
30359
  className: "event-compact-row-status",
30287
30360
  children: cta.label
30288
- }) : /* @__PURE__ */ jsxs("a", {
30361
+ }) : /* @__PURE__ */ jsx("a", {
30289
30362
  href: cta.href,
30290
30363
  target: cta.external ? "_blank" : void 0,
30291
30364
  rel: cta.external ? "noopener noreferrer" : void 0,
30292
30365
  className: `${buttonClass} event-compact-row-cta`,
30293
- children: [/* @__PURE__ */ jsx("span", { children: cta.label }), /* @__PURE__ */ jsx(ArrowRightIcon, { "aria-hidden": "true" })]
30366
+ children: /* @__PURE__ */ jsx("span", { children: cta.label })
30294
30367
  })]
30295
30368
  })]
30296
30369
  })]
@@ -30582,6 +30655,7 @@ const eventCollectionFilterSourceSchemaShape = {
30582
30655
  eventSurface: eventSurfaceScopeSchema$1.nullable().optional(),
30583
30656
  filterEventPresets: z$1.union([z$1.string(), z$1.array(z$1.string())]).nullable().optional(),
30584
30657
  scheduleScope: eventScheduleScopeSchema$1.nullable().optional(),
30658
+ seriesIds: z$1.union([z$1.string(), z$1.array(z$1.string())]).nullable().optional(),
30585
30659
  filterCategoryIds: z$1.union([z$1.string(), z$1.array(z$1.string())]).nullable().optional(),
30586
30660
  filterStaffMemberId: z$1.string().nullable().optional(),
30587
30661
  filterVenueId: z$1.string().nullable().optional()
@@ -30628,6 +30702,7 @@ const eventCollectionDisplaySchemaShape = {
30628
30702
  eventSurface: eventSurfaceScopeSchema$1,
30629
30703
  filterEventPresets: z$1.string().nullable(),
30630
30704
  scheduleScope: eventScheduleScopeSchema$1,
30705
+ seriesIds: z$1.string().nullable().optional(),
30631
30706
  filterCategoryIds: z$1.string().nullable(),
30632
30707
  filterStaffMemberId: z$1.string().nullable(),
30633
30708
  filterVenueId: z$1.string().nullable(),
@@ -30675,11 +30750,15 @@ function buildEventCollectionDisplay(source) {
30675
30750
  };
30676
30751
  }
30677
30752
  function buildEventCollectionFilterDisplay(source) {
30678
- return {
30679
- showFilters: source.showFilters ?? true,
30680
- showCategoryFilter: source.showCategoryFilter ?? "auto",
30681
- showVenueFilter: source.showVenueFilter ?? false,
30682
- showStaffFilter: source.showStaffFilter ?? true,
30753
+ const selected = source.seriesIds != null;
30754
+ const matchingFilters = selected ? {
30755
+ eventSurface: "all",
30756
+ filterEventPresets: null,
30757
+ scheduleScope: "any",
30758
+ filterCategoryIds: null,
30759
+ filterStaffMemberId: null,
30760
+ filterVenueId: null
30761
+ } : {
30683
30762
  eventSurface: normalizeEventSurfaceScope(source.eventSurface),
30684
30763
  filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
30685
30764
  scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
@@ -30687,6 +30766,14 @@ function buildEventCollectionFilterDisplay(source) {
30687
30766
  filterStaffMemberId: normalizeEventStaffMemberId(source.filterStaffMemberId),
30688
30767
  filterVenueId: normalizeEventVenueId(source.filterVenueId)
30689
30768
  };
30769
+ return {
30770
+ seriesIds: eventSeriesScopeCsv(source.seriesIds),
30771
+ showFilters: selected ? false : source.showFilters ?? true,
30772
+ showCategoryFilter: source.showCategoryFilter ?? "auto",
30773
+ showVenueFilter: source.showVenueFilter ?? false,
30774
+ showStaffFilter: source.showStaffFilter ?? true,
30775
+ ...matchingFilters
30776
+ };
30690
30777
  }
30691
30778
  function buildEventCollectionPresentationDisplay(source) {
30692
30779
  return {
@@ -30701,14 +30788,15 @@ function buildEventCollectionPresentationDisplay(source) {
30701
30788
  }
30702
30789
  function buildEventCollectionHydration(source, now = /* @__PURE__ */ new Date()) {
30703
30790
  const timeZone = source.calendarWindow?.scope.timeZone ?? toBookingTimeZone(source.bookingTimeZone);
30791
+ const selected = source.seriesIds != null;
30704
30792
  return {
30705
30793
  calendarWindow: source.calendarWindow ?? void 0,
30706
30794
  siteId: source.siteId,
30707
30795
  stage: source.stage,
30708
30796
  prefetchedEvents: source.events != null,
30709
- eventSurface: normalizeEventSurfaceScope(source.eventSurface),
30710
- filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
30711
- scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
30797
+ eventSurface: selected ? "all" : normalizeEventSurfaceScope(source.eventSurface),
30798
+ filterEventPresets: selected ? null : normalizeEventSurfacePresetsCsv(source.filterEventPresets),
30799
+ scheduleScope: selected ? "any" : normalizeEventScheduleScope(source.scheduleScope),
30712
30800
  calendarContext: {
30713
30801
  timeZone,
30714
30802
  initialToday: source.calendarWindow?.initialToday ?? getLocalScheduleDate(now, timeZone)
@@ -30794,6 +30882,7 @@ const eventListingHydrationSchema = z$1.object({
30794
30882
  eventSurface: eventSurfaceScopeSchema,
30795
30883
  filterEventPresets: z$1.string().nullable(),
30796
30884
  scheduleScope: eventScheduleScopeSchema,
30885
+ seriesIds: z$1.string().nullable().optional(),
30797
30886
  filterCategoryIds: z$1.string().nullable().optional(),
30798
30887
  filterStaffMemberId: z$1.string().nullable().optional(),
30799
30888
  filterVenueId: z$1.string().nullable().optional(),
@@ -30854,6 +30943,7 @@ const eventListingBlockRuntime = defineProgressiveBlockRuntime({
30854
30943
  eventSurface: normalizeEventSurfaceScope(source.eventSurface),
30855
30944
  filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
30856
30945
  scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
30946
+ seriesIds: eventSeriesScopeCsv(source.seriesIds),
30857
30947
  filterCategoryIds: normalizeEventCategoryIdsCsv(source.filterCategoryIds),
30858
30948
  filterStaffMemberId: normalizeEventStaffMemberId(source.filterStaffMemberId),
30859
30949
  filterVenueId: normalizeEventVenueId(source.filterVenueId),
@@ -39472,13 +39562,6 @@ const API_ENDPOINTS$1 = {
39472
39562
  auth: "service",
39473
39563
  responseKind: "json"
39474
39564
  },
39475
- sdkCatalogTheme: {
39476
- path: "/sdk/{siteId}/catalog/theme",
39477
- method: "GET",
39478
- errors: ["server:internal_error"],
39479
- auth: "service",
39480
- responseKind: "json"
39481
- },
39482
39565
  sdkCatalogBlocks: {
39483
39566
  path: "/sdk/{siteId}/catalog/blocks",
39484
39567
  method: "GET",
@@ -39539,12 +39622,6 @@ const API_ENDPOINTS$1 = {
39539
39622
  auth: "service",
39540
39623
  responseKind: "json"
39541
39624
  },
39542
- sdkPullTheme: {
39543
- path: "/sdk/{siteId}/pull/theme",
39544
- method: "GET",
39545
- auth: "service",
39546
- responseKind: "json"
39547
- },
39548
39625
  sdkPullFooter: {
39549
39626
  path: "/sdk/{siteId}/pull/footer",
39550
39627
  method: "GET",
@@ -39651,30 +39728,6 @@ const API_ENDPOINTS$1 = {
39651
39728
  auth: "service",
39652
39729
  responseKind: "json"
39653
39730
  },
39654
- sdkUpsertTheme: {
39655
- path: "/sdk/{siteId}/theme",
39656
- method: "POST",
39657
- auth: "service",
39658
- responseKind: "json",
39659
- errors: [
39660
- "validation:invalid_input",
39661
- "resource:not_found",
39662
- "resource:conflict",
39663
- "server:internal_error"
39664
- ]
39665
- },
39666
- sdkApplySiteStyleSelection: {
39667
- path: "/sdk/{siteId}/theme/style-selection/apply",
39668
- method: "POST",
39669
- auth: "service",
39670
- responseKind: "json",
39671
- errors: [
39672
- "validation:invalid_input",
39673
- "resource:not_found",
39674
- "resource:conflict",
39675
- "server:internal_error"
39676
- ]
39677
- },
39678
39731
  sdkUpsertFooter: {
39679
39732
  path: "/sdk/{siteId}/footer",
39680
39733
  method: "POST",
@@ -42715,6 +42768,26 @@ const headerRuntimeTransforms = [{
42715
42768
  run: resolveHeaderChromeRuntimeContract
42716
42769
  }];
42717
42770
  const defaultTransforms = createTransformRegistry([
42771
+ {
42772
+ id: "events.calendarSelectionParam",
42773
+ kind: "formatter",
42774
+ summary: "Resolve selected events instead of discovery filters",
42775
+ schema: z$1.object({ key: z$1.enum([
42776
+ "seriesIds",
42777
+ "eventSurface",
42778
+ "filterEventPresets",
42779
+ "scheduleScope",
42780
+ "filterCategoryIds",
42781
+ "filterStaffMemberId",
42782
+ "filterVenueId"
42783
+ ]) }),
42784
+ run(value, { key }) {
42785
+ const content = asPartialObject(value) ?? {};
42786
+ const selection = resolveEventSelection(content.eventSelection, content.selectedEventSeriesIds);
42787
+ if (selection.kind === "selected") return key === "seriesIds" ? selection.seriesIds : void 0;
42788
+ return key === "seriesIds" ? void 0 : content[key];
42789
+ }
42790
+ },
42718
42791
  {
42719
42792
  id: "events.calendarReadEnabled",
42720
42793
  kind: "formatter",
@@ -43892,17 +43965,16 @@ const ButtonNode = ({ value, children, href, variantId = "primary", size = "md",
43892
43965
  if (process.env.NODE_ENV === "development") console.warn("[ButtonNode] Missing href for link-required button");
43893
43966
  return null;
43894
43967
  }
43895
- const extraClassName = affordanceIcon ? [className, AFFORDANCE_SUPPRESS_CLASS].filter(Boolean).join(" ") : className;
43896
43968
  const resolvedVariantId = parseThemeButtonVariantId(variantId);
43897
43969
  if (variantId && !resolvedVariantId) {
43898
43970
  console.error("[ButtonNode] Invalid button variant", { variantId });
43899
43971
  return null;
43900
43972
  }
43901
- const combinedClassName = resolvedVariantId ? themeButtonClassName({
43973
+ const combinedClassName = resolvedVariantId ? (affordanceIcon ? themeButtonClassNameWithTrailingIcon : themeButtonClassName)({
43902
43974
  variant: resolvedVariantId,
43903
43975
  size,
43904
- extraClassName
43905
- }) : extraClassName;
43976
+ extraClassName: className
43977
+ }) : className;
43906
43978
  if (resolvedHref) return /* @__PURE__ */ jsxs("a", {
43907
43979
  href: resolvedHref,
43908
43980
  target,
@@ -45089,6 +45161,7 @@ const publicPricingSchema = z$1.object({
45089
45161
  });
45090
45162
  const publicAppointmentServiceSchema = z$1.object({
45091
45163
  id: z$1.string().min(1),
45164
+ slug: z$1.string().min(1).optional(),
45092
45165
  title: z$1.string(),
45093
45166
  description: z$1.string().nullable().optional(),
45094
45167
  durationMinutes: z$1.number().int().positive(),
@@ -45165,7 +45238,7 @@ function formatAmountOrFree(amount, currency) {
45165
45238
  currency
45166
45239
  }, { decimals: "auto" });
45167
45240
  }
45168
- function buildRows(services, pathname) {
45241
+ function buildRows(services, pathname, servicePathPrefix) {
45169
45242
  return services.map((service) => ({
45170
45243
  id: service.id,
45171
45244
  title: service.title,
@@ -45176,7 +45249,8 @@ function buildRows(services, pathname) {
45176
45249
  href: resolveDedicatedBookingHref(pathname, {
45177
45250
  kind: "appointment_service",
45178
45251
  serviceId: service.id
45179
- })
45252
+ }),
45253
+ detailsHref: servicePathPrefix && service.slug ? `${servicePathPrefix.replace(/\/$/, "")}/${encodeURIComponent(service.slug)}` : null
45180
45254
  }));
45181
45255
  }
45182
45256
  function buildAppointmentServicesView(input) {
@@ -45195,13 +45269,14 @@ function buildAppointmentServicesView(input) {
45195
45269
  };
45196
45270
  return {
45197
45271
  kind: "items",
45198
- rows: buildRows(parsed.services, input.pathname)
45272
+ rows: buildRows(parsed.services, input.pathname, input.servicePathPrefix ?? null)
45199
45273
  };
45200
45274
  }
45201
- function AppointmentServicesNode({ sectionHeading, services, pathname, className }) {
45275
+ function AppointmentServicesNode({ sectionHeading, services, pathname, servicePathPrefix, className }) {
45202
45276
  const view = buildAppointmentServicesView({
45203
45277
  services,
45204
- pathname: typeof pathname === "string" ? pathname : void 0
45278
+ pathname: typeof pathname === "string" ? pathname : void 0,
45279
+ servicePathPrefix: typeof servicePathPrefix === "string" ? servicePathPrefix : null
45205
45280
  });
45206
45281
  const rootClassName = `appointment-services ${className ?? ""}`.trim();
45207
45282
  const RowTitle = sectionHeading ? "h3" : "h2";
@@ -45232,7 +45307,10 @@ function AppointmentServicesNode({ sectionHeading, services, pathname, className
45232
45307
  children: [
45233
45308
  /* @__PURE__ */ jsx(RowTitle, {
45234
45309
  className: "appointment-services-row-title rb-text-lg rb-font-medium rb-leading-tight",
45235
- children: row.title
45310
+ children: row.detailsHref ? /* @__PURE__ */ jsx("a", {
45311
+ href: row.detailsHref,
45312
+ children: row.title
45313
+ }) : row.title
45236
45314
  }),
45237
45315
  row.description ? /* @__PURE__ */ jsx("p", {
45238
45316
  className: "appointment-services-row-description rb-text-sm rb-leading-6 status-muted",
@@ -46762,13 +46840,10 @@ function OfferingsPreviewContent(props) {
46762
46840
  }),
46763
46841
  groupCta ? /* @__PURE__ */ jsx("footer", {
46764
46842
  className: "offerings-preview-card-footer rb-mt-auto rb-flex",
46765
- children: /* @__PURE__ */ jsxs("a", {
46843
+ children: /* @__PURE__ */ jsx("a", {
46766
46844
  className: groupLinkClass,
46767
46845
  href: groupCta.href,
46768
- children: [/* @__PURE__ */ jsx("span", { children: groupCta.label }), /* @__PURE__ */ jsx(ArrowRightIcon, {
46769
- "aria-hidden": "true",
46770
- className: "offerings-preview-link-icon rb-h-4 rb-w-4"
46771
- })]
46846
+ children: /* @__PURE__ */ jsx("span", { children: groupCta.label })
46772
46847
  })
46773
46848
  }) : null
46774
46849
  ]
@@ -48130,22 +48205,121 @@ const formBlockDefinition = {
48130
48205
  runtime: formBlockRuntime
48131
48206
  };
48132
48207
  //#endregion
48208
+ //#region ../blocks/src/system/blocks/events/eventSelectionFields.ts
48209
+ const eventSelectionFields = [{
48210
+ id: "eventSelection",
48211
+ type: "select",
48212
+ label: "Events to show",
48213
+ required: false,
48214
+ multiple: false,
48215
+ defaultValue: "matching",
48216
+ options: [{
48217
+ value: "matching",
48218
+ label: "All matching events"
48219
+ }, {
48220
+ value: "selected",
48221
+ label: "Selected events"
48222
+ }],
48223
+ ui: { intent: "behavior" }
48224
+ }, createSiteOptionSelectField({
48225
+ id: "selectedEventSeriesIds",
48226
+ label: "Selected events",
48227
+ description: "Show upcoming dates for these events. Other event filters do not apply.",
48228
+ required: false,
48229
+ multiple: true,
48230
+ defaultValue: [],
48231
+ optionSource: "eventSeries",
48232
+ ui: {
48233
+ intent: "behavior",
48234
+ searchThreshold: 1,
48235
+ visibleWhen: {
48236
+ field: "eventSelection",
48237
+ equals: "selected"
48238
+ }
48239
+ }
48240
+ })];
48241
+ function withEventSelectionVisibility(field) {
48242
+ if (![
48243
+ "eventSurface",
48244
+ "filterEventPresets",
48245
+ "scheduleScope",
48246
+ "filterCategoryIds",
48247
+ "filterStaffMemberId",
48248
+ "filterVenueId",
48249
+ "showFilters",
48250
+ "showCategoryFilter",
48251
+ "showVenueFilter",
48252
+ "showStaffFilter"
48253
+ ].includes(field.id)) return field;
48254
+ const visibleWhen = field.ui?.visibleWhen;
48255
+ return {
48256
+ ...field,
48257
+ ui: {
48258
+ ...field.ui,
48259
+ visibleWhen: { allOf: [{
48260
+ field: "eventSelection",
48261
+ notEquals: "selected"
48262
+ }, ...visibleWhen ? [visibleWhen] : []] }
48263
+ }
48264
+ };
48265
+ }
48266
+ //#endregion
48133
48267
  //#region ../blocks/src/system/blocks/events/eventCalendarDataLoaders.ts
48134
48268
  const scopeParams = {
48135
48269
  siteId: { $bind: { from: "$root.siteId" } },
48270
+ seriesIds: { $bind: {
48271
+ from: "content",
48272
+ transforms: [{
48273
+ id: "events.calendarSelectionParam",
48274
+ options: { key: "seriesIds" }
48275
+ }]
48276
+ } },
48136
48277
  stage: { $bind: {
48137
48278
  from: "$root.previewStage",
48138
48279
  fallback: "published"
48139
48280
  } },
48140
- eventSurface: { $bind: { from: "content.eventSurface" } },
48281
+ eventSurface: { $bind: {
48282
+ from: "content",
48283
+ transforms: [{
48284
+ id: "events.calendarSelectionParam",
48285
+ options: { key: "eventSurface" }
48286
+ }, { id: "value.csv" }]
48287
+ } },
48141
48288
  eventPresets: { $bind: {
48142
- from: "content.filterEventPresets",
48143
- transforms: [{ id: "value.csv" }]
48289
+ from: "content",
48290
+ transforms: [{
48291
+ id: "events.calendarSelectionParam",
48292
+ options: { key: "filterEventPresets" }
48293
+ }, { id: "value.csv" }]
48294
+ } },
48295
+ scheduleScope: { $bind: {
48296
+ from: "content",
48297
+ transforms: [{
48298
+ id: "events.calendarSelectionParam",
48299
+ options: { key: "scheduleScope" }
48300
+ }, { id: "value.csv" }]
48301
+ } },
48302
+ categoryIds: { $bind: {
48303
+ from: "content",
48304
+ transforms: [{
48305
+ id: "events.calendarSelectionParam",
48306
+ options: { key: "filterCategoryIds" }
48307
+ }, { id: "value.csv" }]
48308
+ } },
48309
+ staffMemberId: { $bind: {
48310
+ from: "content",
48311
+ transforms: [{
48312
+ id: "events.calendarSelectionParam",
48313
+ options: { key: "filterStaffMemberId" }
48314
+ }, { id: "value.csv" }]
48144
48315
  } },
48145
- scheduleScope: { $bind: { from: "content.scheduleScope" } },
48146
- categoryIds: { $bind: { from: "content.filterCategoryIds" } },
48147
- staffMemberId: { $bind: { from: "content.filterStaffMemberId" } },
48148
- venueId: { $bind: { from: "content.filterVenueId" } }
48316
+ venueId: { $bind: {
48317
+ from: "content",
48318
+ transforms: [{
48319
+ id: "events.calendarSelectionParam",
48320
+ options: { key: "filterVenueId" }
48321
+ }, { id: "value.csv" }]
48322
+ } }
48149
48323
  };
48150
48324
  /** Combined renders two jobs; calendar-only variants never pay for the list seed. */
48151
48325
  const eventCalendarDataLoaders = {
@@ -48275,6 +48449,13 @@ const eventCalendarLayout = [styledSection({
48275
48449
  from: "content.defaultCalendarView",
48276
48450
  fallback: "month"
48277
48451
  } },
48452
+ seriesIds: { $bind: {
48453
+ from: "content",
48454
+ transforms: [{
48455
+ id: "events.calendarSelectionParam",
48456
+ options: { key: "seriesIds" }
48457
+ }]
48458
+ } },
48278
48459
  showFilters: { $bind: {
48279
48460
  from: "content.showFilters",
48280
48461
  fallback: true
@@ -48296,17 +48477,47 @@ const eventCalendarLayout = [styledSection({
48296
48477
  fallback: true
48297
48478
  } },
48298
48479
  eventSurface: { $bind: {
48299
- from: "content.eventSurface",
48300
- fallback: "all"
48480
+ from: "content",
48481
+ transforms: [{
48482
+ id: "events.calendarSelectionParam",
48483
+ options: { key: "eventSurface" }
48484
+ }]
48485
+ } },
48486
+ filterEventPresets: { $bind: {
48487
+ from: "content",
48488
+ transforms: [{
48489
+ id: "events.calendarSelectionParam",
48490
+ options: { key: "filterEventPresets" }
48491
+ }]
48301
48492
  } },
48302
- filterEventPresets: { $bind: { from: "content.filterEventPresets" } },
48303
48493
  scheduleScope: { $bind: {
48304
- from: "content.scheduleScope",
48305
- fallback: "any"
48494
+ from: "content",
48495
+ transforms: [{
48496
+ id: "events.calendarSelectionParam",
48497
+ options: { key: "scheduleScope" }
48498
+ }]
48499
+ } },
48500
+ filterCategoryIds: { $bind: {
48501
+ from: "content",
48502
+ transforms: [{
48503
+ id: "events.calendarSelectionParam",
48504
+ options: { key: "filterCategoryIds" }
48505
+ }]
48506
+ } },
48507
+ filterStaffMemberId: { $bind: {
48508
+ from: "content",
48509
+ transforms: [{
48510
+ id: "events.calendarSelectionParam",
48511
+ options: { key: "filterStaffMemberId" }
48512
+ }]
48513
+ } },
48514
+ filterVenueId: { $bind: {
48515
+ from: "content",
48516
+ transforms: [{
48517
+ id: "events.calendarSelectionParam",
48518
+ options: { key: "filterVenueId" }
48519
+ }]
48306
48520
  } },
48307
- filterCategoryIds: { $bind: { from: "content.filterCategoryIds" } },
48308
- filterStaffMemberId: { $bind: { from: "content.filterStaffMemberId" } },
48309
- filterVenueId: { $bind: { from: "content.filterVenueId" } },
48310
48521
  cardRole: { $bind: {
48311
48522
  from: "content._cardStyles.role",
48312
48523
  fallback: "default"
@@ -48810,6 +49021,7 @@ const eventCalendarAdditionalFields = [
48810
49021
  }
48811
49022
  }
48812
49023
  },
49024
+ ...eventSelectionFields,
48813
49025
  {
48814
49026
  id: "eventSurface",
48815
49027
  type: "select",
@@ -49019,7 +49231,7 @@ const eventCalendarBlockDefinition = {
49019
49231
  titleSource: "heading",
49020
49232
  description: "Display events with calendar, list, or combined views with filtering",
49021
49233
  skipSectionStyles: true,
49022
- additionalFields: eventCalendarAdditionalFields,
49234
+ additionalFields: eventCalendarAdditionalFields.map(withEventSelectionVisibility),
49023
49235
  styleTokens: {
49024
49236
  background: "surface",
49025
49237
  typography: "body",
@@ -54051,9 +54263,56 @@ function generateNavLinkCSS(options) {
54051
54263
  if (baseRules.length > 0) cssChunks.unshift(`\n${selector} {\n ${baseRules.join("\n ")}\n}\n`);
54052
54264
  if (hoverRules.length > 0) cssChunks.push(`\n${hoverSelector} {\n ${hoverRules.join("\n ")}\n}\n`);
54053
54265
  if (activeRules.length > 0) cssChunks.push(`\n${activeSelector} {\n ${activeRules.join("\n ")}\n}\n`);
54266
+ cssChunks.push(navLinkFocusVisibleCss(selector, style, theme, tokens));
54054
54267
  cssChunks.push(generateInteractiveChildInheritanceCSS(selector));
54055
54268
  return cssChunks.join("");
54056
54269
  }
54270
+ /**
54271
+ * Keyboard focus indicator for nav links, in the header, the footer and header
54272
+ * dropdown menus — the three surfaces `generateNavLinkCSS` serves.
54273
+ *
54274
+ * Emitted unconditionally rather than as an effect, because focus visibility is
54275
+ * a floor rather than a style choice. Only the interaction-palette pill ever
54276
+ * wrote an `effects.focus` group, so every other nav — every `quiet` palette,
54277
+ * every footer, every dropdown — previously fell back to whatever outline the
54278
+ * browser drew.
54279
+ *
54280
+ * The outline takes the link's own resolved colour, so on a header that adapts
54281
+ * to the section it floats over it moves with the adaptation instead of
54282
+ * asserting a brand colour against an unknown backdrop.
54283
+ *
54284
+ * Where the style asks for `soft-glow`, the same halo goes on the outline. That
54285
+ * treatment exists because the theme has already conceded the resolved colour
54286
+ * alone is not reliable over an unpredictable backdrop — a hero photograph with
54287
+ * mixed luminance. Without it the text would stay legible by its halo while the
54288
+ * focus ring, which is the part with a contrast requirement of its own, would
54289
+ * not.
54290
+ *
54291
+ * A style that also paints a focus pill keeps it: this adds an outline around
54292
+ * that pill rather than replacing it.
54293
+ */
54294
+ function navLinkFocusVisibleCss(selector, style, theme, tokens) {
54295
+ const color = tokens.getColor(style.colorToken);
54296
+ const halo = buildTextContrastShadow({
54297
+ theme,
54298
+ colorToken: style.colorToken,
54299
+ treatment: style.contrastTreatment
54300
+ });
54301
+ return `
54302
+ ${selector}:focus-visible {
54303
+ outline: 2px solid ${color};
54304
+ outline-offset: ${focusOutlineOffset(selector)};${halo ? `\n box-shadow: ${halo};` : ""}
54305
+ }
54306
+ `;
54307
+ }
54308
+ /**
54309
+ * Dropdown items are full-width inside a panel with no horizontal padding, so
54310
+ * an outset outline would paint over and past the panel's own border. Keeping
54311
+ * it flush is the only way it reads as belonging to the item.
54312
+ */
54313
+ function focusOutlineOffset(selector) {
54314
+ return selector.includes("nav-dropdown-link") ? "-2px" : "3px";
54315
+ }
54057
54316
  function buildTextContrastShadow(input) {
54058
54317
  if (input.treatment !== "soft-glow") return null;
54059
54318
  return isLikelyLightColorToken(input.theme, input.colorToken) ? "0 1px 3px rgb(0 0 0 / 0.55), 0 0 18px rgb(0 0 0 / 0.38)" : "0 1px 3px rgb(255 255 255 / 0.72), 0 0 18px rgb(255 255 255 / 0.5)";
@@ -57186,7 +57445,7 @@ function pageBlockPosition(index, blockCount) {
57186
57445
  //#endregion
57187
57446
  //#region ../blocks/src/pageRendererContracts.ts
57188
57447
  function buildPageRendererRootRuntime(dataContext) {
57189
- const { siteId = null, pageId = null, pathname = null, bookingTimeZone, previewStage = "published", apiBaseUrl = null, portalToken = null, bookingOfferingPresets = [], mailingList = { tag: "not_configured" }, eventRegistrationOverlayEnabled = false, loaderFailures = {} } = dataContext ?? {};
57448
+ const { siteId = null, pageId = null, pathname = null, bookingTimeZone, previewStage = "published", apiBaseUrl = null, portalToken = null, bookingOfferingPresets = [], appointmentServicePathPrefix = null, mailingList = { tag: "not_configured" }, eventRegistrationOverlayEnabled = false, loaderFailures = {} } = dataContext ?? {};
57190
57449
  return {
57191
57450
  siteId,
57192
57451
  pageId,
@@ -57196,6 +57455,7 @@ function buildPageRendererRootRuntime(dataContext) {
57196
57455
  apiBaseUrl,
57197
57456
  portalToken,
57198
57457
  bookingOfferingPresets,
57458
+ appointmentServicePathPrefix,
57199
57459
  mailingList,
57200
57460
  eventRegistrationOverlayEnabled,
57201
57461
  loaderFailures
@@ -61874,7 +62134,8 @@ const appointmentServicesBlockDefinition = {
61874
62134
  el("appointment-services", {
61875
62135
  sectionHeading: { $bind: { from: "content.heading" } },
61876
62136
  services: { $bind: { from: "data.services" } },
61877
- pathname: { $bind: { from: "$root.pathname" } }
62137
+ pathname: { $bind: { from: "$root.pathname" } },
62138
+ servicePathPrefix: { $bind: { from: "$root.appointmentServicePathPrefix" } }
61878
62139
  })
61879
62140
  ], { gap: "lg" })
61880
62141
  })]
@@ -69312,10 +69573,19 @@ const containerResponsiveThemeCss = `/*
69312
69573
  padding-top: 2.5rem;
69313
69574
  padding-bottom: 2.5rem;
69314
69575
  }
69576
+ /* Clearance for a surface that is not an authored block page.
69577
+ An authored page gets this through its opening block's container (see the
69578
+ overlay-clearance rule in styles.css). A reserved surface or a system
69579
+ destination page has no such block, so it consumes the same variable here.
69580
+ Marked with one class rather than per-surface selectors, because the last
69581
+ two additions to this family were both missed and shipped overlapping. */
69315
69582
  :where(.theme-scope)
69316
69583
  [data-site-document-layout-mode="header-overlay"]
69317
- [data-rb-reserved-surface].rb-reserved-surface-main {
69318
- padding-top: calc(var(--rb-reserved-surface-header-offset, 5.5rem) + 2.5rem);
69584
+ .rb-overlay-clearance-surface {
69585
+ padding-top: calc(
69586
+ var(--site-overlay-header-clearance, 5.5rem) +
69587
+ var(--site-overlay-opening-content-extra-pad, clamp(1rem, 2vw, 1.75rem))
69588
+ );
69319
69589
  }
69320
69590
  .rb-preview-editor-offset {
69321
69591
  padding-bottom: calc(
@@ -79672,6 +79942,23 @@ const containerResponsiveThemeCss = `/*
79672
79942
  gap: 0.5rem;
79673
79943
  }
79674
79944
 
79945
+ /* Error panel and field notes. The form block scopes these to its own
79946
+ data-block, so the newsletter form (which also renders in the footer)
79947
+ needs its own copy of the treatment. */
79948
+ :where(.theme-scope) .newsletter-form .fb-error:not([data-field-validation-message]) {
79949
+ background-color: var(--fb-error-bg);
79950
+ color: var(--fb-error-text);
79951
+ border: 1px solid var(--fb-error-border);
79952
+ border-radius: var(--rb-block-radius);
79953
+ padding: 1rem;
79954
+ font-size: 0.875rem;
79955
+ }
79956
+
79957
+ :where(.theme-scope) .newsletter-form [data-field-validation-message] {
79958
+ font-size: 0.875rem;
79959
+ color: var(--fb-error-text);
79960
+ }
79961
+
79675
79962
  /* Required indicator */
79676
79963
  :where(.theme-scope) .newsletter-required {
79677
79964
  color: rgb(var(--tb-primary));
@@ -82143,12 +82430,12 @@ function normalizeContent(block) {
82143
82430
  }
82144
82431
  /**
82145
82432
  * Normalize params for API calls.
82146
- * Converts all values to strings.
82433
+ * Converts supplied values to strings, preserving absent versus explicitly empty params.
82147
82434
  */
82148
82435
  function normalizeParams(input) {
82149
82436
  if (!input || typeof input !== "object") return {};
82150
82437
  const output = {};
82151
- for (const [key, value] of Object.entries(input)) output[key] = coerceToString(value);
82438
+ for (const [key, value] of Object.entries(input)) if (value !== void 0 && value !== null) output[key] = coerceToString(value);
82152
82439
  return output;
82153
82440
  }
82154
82441
  function isNonArrayObject(value) {
@@ -82212,6 +82499,14 @@ function coercePayload(payload) {
82212
82499
  * - Frontend: provide internal API client
82213
82500
  * - SDK: provide SDK client with endpoint mapping
82214
82501
  */
82502
+ function projectDataLoaders(loaders, shouldLoad, blockId, blockKind) {
82503
+ if (!shouldLoad) return [...loaders];
82504
+ return loaders.filter(({ key }) => shouldLoad({
82505
+ blockId,
82506
+ blockKind,
82507
+ loaderKey: key
82508
+ }));
82509
+ }
82215
82510
  function shouldSkipResolvedLoader(input) {
82216
82511
  if (input.loader.requiredParams?.some((param) => !input.params[param]?.trim())) return true;
82217
82512
  return Boolean(input.isValidEndpoint && !input.isValidEndpoint(input.endpoint));
@@ -82240,7 +82535,7 @@ async function prefetchBlockData$1(page, context, options) {
82240
82535
  return (await prefetchBlockDataWithFailures(page, context, options)).resolvedData;
82241
82536
  }
82242
82537
  async function prefetchBlockDataWithFailures(page, context, options) {
82243
- const { apiClient, isValidEndpoint, onError, getCustomBlockLoaders, getBlockDefinition: getBlockDefinition$1 = getBlockDefinition, resolveParamsBindings: resolveParamsBindings$1 = resolveParamsBindings } = options;
82538
+ const { apiClient, isValidEndpoint, onError, getCustomBlockLoaders, getBlockDefinition: getBlockDefinition$1 = getBlockDefinition, resolveParamsBindings: resolveParamsBindings$1 = resolveParamsBindings, shouldLoad } = options;
82244
82539
  const results = {};
82245
82540
  const loaderFailures = {};
82246
82541
  const tasks = [];
@@ -82257,6 +82552,7 @@ async function prefetchBlockDataWithFailures(page, context, options) {
82257
82552
  loader
82258
82553
  })) : [];
82259
82554
  } else loaders = [];
82555
+ loaders = projectDataLoaders(loaders, shouldLoad, blockId, block.kind);
82260
82556
  if (loaders.length === 0) continue;
82261
82557
  const root = {
82262
82558
  ...context.root ?? {},
@@ -82357,8 +82653,8 @@ function toStringParams(value) {
82357
82653
  for (const [k, v] of Object.entries(value)) if (typeof v === "string") out[k] = v;
82358
82654
  return out;
82359
82655
  }
82360
- function stripEmptyStringValues(params) {
82361
- for (const [key, value] of Object.entries(params)) if (value === "") delete params[key];
82656
+ function stripEmptyStringValues(params, endpoint) {
82657
+ for (const [key, value] of Object.entries(params)) if (value === "" && !(key === "seriesIds" && (endpoint === "listPublicEvents" || endpoint === "listPublicEventCalendarWindow"))) delete params[key];
82362
82658
  }
82363
82659
  function ensureSiteId(params, context) {
82364
82660
  if (!params.siteId && typeof context.siteId === "string" && context.siteId) params.siteId = context.siteId;
@@ -82371,7 +82667,7 @@ function ensureSiteId(params, context) {
82371
82667
  */
82372
82668
  function normalizeLoaderParams(endpoint, params, context) {
82373
82669
  const out = toStringParams(params);
82374
- stripEmptyStringValues(out);
82670
+ stripEmptyStringValues(out, endpoint);
82375
82671
  if (endpoint === "getPublicFormById") {
82376
82672
  ensureSiteId(out, context);
82377
82673
  if (!out.formId && out.formSlug) {
@@ -82627,11 +82923,14 @@ const sdkSiteStyleConfigSchema = z$1.object({
82627
82923
  sectionOptions: sdkSectionOptionsConfigSchema.optional(),
82628
82924
  containerOptions: sdkContainerOptionsConfigSchema.optional()
82629
82925
  });
82630
- const sdkSiteLayoutConfigSchema = z$1.object({ footerBlocks: z$1.array(z$1.object({
82631
- id: z$1.string().min(1).optional(),
82632
- kind: z$1.string().min(1),
82633
- content: z$1.record(z$1.string(), z$1.unknown()).optional()
82634
- })).optional() });
82926
+ const sdkSiteLayoutConfigSchema = z$1.object({
82927
+ footerMode: footerModeSchema.optional(),
82928
+ footerBlocks: z$1.array(z$1.object({
82929
+ id: z$1.string().min(1).optional(),
82930
+ kind: z$1.string().min(1),
82931
+ content: z$1.record(z$1.string(), z$1.unknown()).optional()
82932
+ })).optional()
82933
+ });
82635
82934
  const sdkFieldSelectOptionSchema = z$1.object({
82636
82935
  value: z$1.string(),
82637
82936
  label: z$1.string()
@@ -87533,6 +87832,15 @@ function isEntryResponse(response) {
87533
87832
  function isPageSurfaceResponse(response) {
87534
87833
  return response.type === "pageSurface";
87535
87834
  }
87835
+ z$1.object({
87836
+ palette: paletteColorsSchema,
87837
+ paletteMode: paletteModeSchema,
87838
+ typography: z$1.object({
87839
+ headingFamily: z$1.string().trim().min(1),
87840
+ bodyFamily: z$1.string().trim().min(1)
87841
+ }).strict(),
87842
+ corners
87843
+ }).strict();
87536
87844
  //#endregion
87537
87845
  //#region src/rendering/blocks-theme-runtime.ts
87538
87846
  function parseBlocksTheme(theme) {
@@ -88909,7 +89217,7 @@ var CircuitOpenError = class extends Error {
88909
89217
  * 1. This constant
88910
89218
  * 2. The "version" field in package.json
88911
89219
  */
88912
- const SDK_VERSION = "0.140.0";
89220
+ const SDK_VERSION = "0.142.0";
88913
89221
  //#endregion
88914
89222
  //#region src/next/content-load-failure.ts
88915
89223
  const SdkContentLoadError = RiverbankContentLoadError;