@riverbankcms/sdk 0.111.0 → 0.119.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 (196) hide show
  1. package/dist/{PreviewEditorSidebar-CTR6LUhN.mjs → PreviewEditorSidebar-C7TXFitV.mjs} +4 -4
  2. package/dist/{PreviewEditorUI-DZg15Zip.mjs → PreviewEditorUI-_1JIHTXS.mjs} +3 -3
  3. package/dist/{PreviewQueryProvider-kkmjklLG.mjs → PreviewQueryProvider-nKUT4TL-.mjs} +1 -1
  4. package/dist/{SdkPreviewModeRuntime-DeOTAFvR.mjs → SdkPreviewModeRuntime-CvJTVgWa.mjs} +2579 -34325
  5. package/dist/{SiteChromeCustomizeContext-DOSDLCiJ.mjs → SiteChromeCustomizeContext-66QfCbAS.mjs} +64625 -32791
  6. package/dist/_dts/ai/src/contracts/proposals.d.ts +5211 -639
  7. package/dist/_dts/ai/src/designer/themePatch.d.ts +1 -1
  8. package/dist/_dts/api/src/bookingAdjustments.d.ts +30 -36
  9. package/dist/_dts/api/src/bookingConfig.d.ts +26 -1
  10. package/dist/_dts/api/src/bookingRecords.d.ts +6 -74
  11. package/dist/_dts/api/src/bookingRefundOutcomes.d.ts +3 -3
  12. package/dist/_dts/api/src/contentRuntime.d.ts +5 -1
  13. package/dist/_dts/api/src/customerMembershipOutcomes.d.ts +4 -4
  14. package/dist/_dts/api/src/endpoints.d.ts +35 -0
  15. package/dist/_dts/api/src/event-presentation.d.ts +4 -0
  16. package/dist/_dts/api/src/index.d.ts +4 -4
  17. package/dist/_dts/api/src/navigation/dashboardBookingsNav.d.ts +4 -1
  18. package/dist/_dts/api/src/navigation/dashboardSettingsNav.d.ts +2 -2
  19. package/dist/_dts/api/src/sdk-event-upsert.d.ts +2 -2
  20. package/dist/_dts/api/src/sdkContracts.d.ts +85 -7
  21. package/dist/_dts/api/src/siteBanner.d.ts +8 -8
  22. package/dist/_dts/api/src/siteOperations.d.ts +1 -1
  23. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +32 -4
  24. package/dist/_dts/block-form/src/widgets/RichTextField/richTextFieldDefaults.d.ts +3 -12
  25. package/dist/_dts/block-form/src/widgets/RichTextField/richTextFieldSchema.d.ts +1 -5
  26. package/dist/_dts/blocks/src/bindings/index.d.ts +1 -10
  27. package/dist/_dts/blocks/src/index.d.ts +3 -6
  28. package/dist/_dts/blocks/src/primitives/content/primitives.d.ts +2 -2
  29. package/dist/_dts/blocks/src/system/blocks/body-text.d.ts +2 -2
  30. package/dist/_dts/blocks/src/system/blocks/events/recurring-schedule.d.ts +2 -2
  31. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +2 -8
  32. package/dist/_dts/blocks/src/system/blocks/feature-card-icons.d.ts +2 -2
  33. package/dist/_dts/blocks/src/system/blocks/feature-cards.d.ts +3 -3
  34. package/dist/_dts/blocks/src/system/blocks/form.d.ts +2 -15
  35. package/dist/_dts/blocks/src/system/blocks/intro.d.ts +2 -2
  36. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +66 -66
  37. package/dist/_dts/blocks/src/system/blocks/newsletter-signup.d.ts +2 -16
  38. package/dist/_dts/blocks/src/system/blocks/site-footer.d.ts +0 -3
  39. package/dist/_dts/blocks/src/system/fragments/index.d.ts +0 -1
  40. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +19 -2
  41. package/dist/_dts/blocks/src/system/manifest/richTextSchema.d.ts +8 -70
  42. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +1 -0
  43. package/dist/_dts/blocks/src/system/manifest/validation.d.ts +6 -0
  44. package/dist/_dts/blocks/src/system/node/schema.d.ts +4 -4
  45. package/dist/_dts/blocks/src/system/runtime/nodes/basic.d.ts +1 -10
  46. package/dist/_dts/blocks/src/system/runtime/nodes/buttonAffordance.d.ts +5 -21
  47. package/dist/_dts/blocks/src/system/runtime/nodes/richText-coerce.d.ts +14 -2
  48. package/dist/_dts/blocks/src/system/transforms/typed.d.ts +1 -1
  49. package/dist/_dts/content-editor/src/controller/seedDraftBaselinesFromBlocks.d.ts +1 -1
  50. package/dist/_dts/content-editor/src/hooks/useBlockAutosave.d.ts +17 -1
  51. package/dist/_dts/content-editor/src/hooks/useDebouncedLatestSave.d.ts +1 -1
  52. package/dist/_dts/content-editor/src/hooks/useSimpleAutosave.d.ts +1 -1
  53. package/dist/_dts/content-editor/src/ui/editorSnapshot.d.ts +3 -2
  54. package/dist/_dts/content-editor/src/ui/editorUiStore.d.ts +2 -2
  55. package/dist/_dts/content-editor/src/ui/stores/autosaveStore.d.ts +1 -1
  56. package/dist/_dts/content-editor/src/ui/stores/types.d.ts +1 -1
  57. package/dist/_dts/content-model/src/content-types/builtins.d.ts +3 -15
  58. package/dist/_dts/content-model/src/content-types/entryValidation.d.ts +2 -0
  59. package/dist/_dts/content-model/src/content-types/schema.d.ts +1 -1
  60. package/dist/_dts/content-model/src/templates/defaults.d.ts +1 -21
  61. package/dist/_dts/core/src/editor-state.d.ts +14 -1
  62. package/dist/_dts/core/src/footer-composition.d.ts +2 -1
  63. package/dist/_dts/core/src/index.d.ts +1 -0
  64. package/dist/_dts/core/src/rich-text.d.ts +16 -0
  65. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +189 -86
  66. package/dist/_dts/editor/src/index.d.ts +1 -1
  67. package/dist/_dts/editor/src/primitives/rich-text/utils.d.ts +3 -5
  68. package/dist/_dts/editor-blocks/src/BlockEditor.d.ts +1 -1
  69. package/dist/_dts/editor-blocks/src/block-editor/BlockCard.d.ts +2 -1
  70. package/dist/_dts/editor-blocks/src/block-editor/BlockCardHeader.d.ts +2 -1
  71. package/dist/_dts/editor-blocks/src/block-editor/blockDraftBaselineSeed.d.ts +15 -0
  72. package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockBaselineSync.d.ts +3 -7
  73. package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockDuplication.d.ts +12 -0
  74. package/dist/_dts/editor-blocks/src/block-editor/types.d.ts +1 -0
  75. package/dist/_dts/editor-blocks/src/block-editor/utils.d.ts +1 -1
  76. package/dist/_dts/editor-blocks/src/index.d.ts +6 -5
  77. package/dist/_dts/editor-blocks/src/widgets/rich-text/RichTextField.d.ts +2 -2
  78. package/dist/_dts/media-core/src/contentMediaAudit.d.ts +104 -0
  79. package/dist/_dts/media-core/src/contentMediaAuditFieldAdapter.d.ts +8 -0
  80. package/dist/_dts/media-core/src/contentMediaSnapshotAudit.d.ts +22 -0
  81. package/dist/_dts/media-core/src/index.d.ts +3 -1
  82. package/dist/_dts/sdk/src/cli/commands/event.d.ts +18 -1
  83. package/dist/_dts/sdk/src/cli/commands/push/execute/theme.d.ts +2 -16
  84. package/dist/_dts/sdk/src/cli/content/reader.d.ts +8 -5
  85. package/dist/_dts/sdk/src/client/management/events.d.ts +2 -1
  86. package/dist/_dts/sdk/src/client/management/index.d.ts +1 -1
  87. package/dist/_dts/sdk/src/client/management/types.d.ts +36 -9
  88. package/dist/_dts/sdk/src/config/typed-entries.d.ts +7 -7
  89. package/dist/_dts/sdk/src/config/validation.d.ts +7 -7
  90. package/dist/_dts/sdk/src/contracts/content.d.ts +5 -15
  91. package/dist/_dts/sdk/src/contracts/index.d.ts +1 -1
  92. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +12 -25
  93. package/dist/_dts/sdk/src/contracts/theme.d.ts +2 -18
  94. package/dist/_dts/sdk/src/manifest/passes/pass1-fields.d.ts +1 -1
  95. package/dist/_dts/sdk/src/manifest/three-pass-converter.d.ts +4 -4
  96. package/dist/_dts/sdk/src/rendering/helpers/bindings.d.ts +1 -2
  97. package/dist/_dts/sdk/src/rendering/helpers/index.d.ts +1 -1
  98. package/dist/_dts/sdk/src/rendering/islands/types.d.ts +2 -13
  99. package/dist/_dts/sdk/src/theme/index.d.ts +0 -29
  100. package/dist/_dts/sdk/src/version.d.ts +1 -1
  101. package/dist/_dts/site-commands/src/commands.d.ts +31 -18
  102. package/dist/_dts/theme-core/src/buttons/affordanceIcons.d.ts +2 -2
  103. package/dist/_dts/theme-core/src/buttons/core.d.ts +0 -1
  104. package/dist/_dts/theme-core/src/buttons/effectClassification.d.ts +22 -9
  105. package/dist/_dts/theme-core/src/buttons/effects/presets/background.d.ts +1 -2
  106. package/dist/_dts/theme-core/src/buttons/effects/presets/border.d.ts +1 -2
  107. package/dist/_dts/theme-core/src/buttons/effects/presets/overlay.d.ts +3 -1
  108. package/dist/_dts/theme-core/src/buttons/effects/presets/shadow.d.ts +2 -2
  109. package/dist/_dts/theme-core/src/buttons/effects/types.d.ts +8 -18
  110. package/dist/_dts/theme-core/src/buttons/generateButtonCss.d.ts +2 -2
  111. package/dist/_dts/theme-core/src/buttons/generateDefaultButtonSystem.d.ts +5 -5
  112. package/dist/_dts/theme-core/src/buttons/index.d.ts +1 -4
  113. package/dist/_dts/theme-core/src/buttons/parseThemeForPersistence.d.ts +36 -0
  114. package/dist/_dts/theme-core/src/buttons/types.d.ts +1638 -93
  115. package/dist/_dts/theme-core/src/cards/types.d.ts +13 -13
  116. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +969 -69
  117. package/dist/_dts/theme-core/src/navigation/types.d.ts +2 -2
  118. package/dist/_dts/theme-core/src/recommend/generateThemes.d.ts +0 -1
  119. package/dist/_dts/theme-core/src/schema.d.ts +1100 -116
  120. package/dist/_dts/theme-core/src/site-styles/backgroundAppearance.d.ts +2 -2
  121. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +14 -14
  122. package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +2 -2
  123. package/dist/_dts/theme-core/src/site-styles/pageDesignIntent.d.ts +4 -4
  124. package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +6 -0
  125. package/dist/cli/index.mjs +5706 -4852
  126. package/dist/cli/init-docs/content/cli-reference.md +40 -1
  127. package/dist/cli/init-docs/content/content-management.md +6 -0
  128. package/dist/client/{DiscountCodeDisclosure-C4xvTBux.mjs → DiscountCodeDisclosure-DIWj-P9v.mjs} +1 -1
  129. package/dist/client/{EventCombined.client-Cr7G131j.mjs → EventCombined.client-De8YWBSr.mjs} +2 -2
  130. package/dist/client/{EventListing.client-CAjbseNy.mjs → EventListing.client-seHTjimY.mjs} +2 -2
  131. package/dist/client/{LeafletStaticMap-BMlWfwz3.mjs → LeafletStaticMap-BmQxFcJW.mjs} +1 -1
  132. package/dist/client/{MagicLinkForm-ChdFz96y.mjs → MagicLinkForm-OoJAIUIj.mjs} +1 -1
  133. package/dist/client/{StepIndicator-7D3GaBeM.mjs → StepIndicator-CiZ8kdPk.mjs} +2 -2
  134. package/dist/client/{accordion-D8JTs2Si.mjs → accordion-6lnN__XJ.mjs} +1 -1
  135. package/dist/client/{bookingForm-H3DCRBHs.mjs → bookingForm-5uyqhONU.mjs} +6 -6
  136. package/dist/client/bookings.mjs +2219 -527
  137. package/dist/client/{carousel-DMr_QWlz.mjs → carousel-Dtnifil_.mjs} +1 -1
  138. package/dist/client/{cart-DWMbfBdR.mjs → cart-5Tc5S7NV.mjs} +3 -3
  139. package/dist/client/{checkout-zmfdkXLx.mjs → checkout-CYKKN5Hr.mjs} +3 -3
  140. package/dist/client/client.mjs +2498 -2384
  141. package/dist/client/{colorTokenParts-FSS3al6l.mjs → colorStyles-BWpj_h4C.mjs} +88 -1
  142. package/dist/client/{courseRegistration-Z_mn18jy.mjs → courseRegistration-CxCBybB4.mjs} +6 -6
  143. package/dist/client/{eventCalendar-CYp0YJGF.mjs → eventCalendar-Xj2jZS9X.mjs} +4 -4
  144. package/dist/client/{eventCombined-rKyYZUa9.mjs → eventCombined-CgcMoOgM.mjs} +2 -2
  145. package/dist/client/{eventDetails-X0ZaUuMj.mjs → eventDetails-CEAH8Edc.mjs} +3 -3
  146. package/dist/client/{eventListing-W1SuL7EP.mjs → eventListing-qyPVQ0wP.mjs} +2 -2
  147. package/dist/client/{eventRegistration-ClWricui.mjs → eventRegistration-DDu79CtL.mjs} +6 -6
  148. package/dist/client/{form--eKPwAAD.mjs → form-Bc7JKI7I.mjs} +1 -1
  149. package/dist/client/{headerSection-BSeGr-FS.mjs → headerSection-vTku_LEl.mjs} +2 -2
  150. package/dist/client/hooks.mjs +373 -555
  151. package/dist/client/{locationMap-BpOrtNYn.mjs → locationMap-Bg7X4Jna.mjs} +3 -3
  152. package/dist/client/{media-DoF0dcVx.mjs → media-CNE1Z-wb.mjs} +1 -2
  153. package/dist/client/{newsletterForm-Bt7it7Dy.mjs → newsletterForm-lpylVdp5.mjs} +1 -1
  154. package/dist/client/{pricing-BTjSDDr4.mjs → pricing-DE8fjJiT.mjs} +1 -1
  155. package/dist/client/{productDetail-ICnVTcCg.mjs → productDetail-D7Bo2RMH.mjs} +3 -3
  156. package/dist/client/{productList-ZHr6D604.mjs → productList-VjnZqiqN.mjs} +3 -3
  157. package/dist/client/{propsDecoder-wWN0tBDF.mjs → propsDecoder-DreFXjNP.mjs} +2212 -621
  158. package/dist/client/rendering/client.mjs +21612 -21646
  159. package/dist/client/rendering/islands.mjs +20 -20
  160. package/dist/client/rendering.mjs +1571 -1547
  161. package/dist/client/{shop-C1u_BUn0.mjs → shop-IRsHHbf7.mjs} +5 -5
  162. package/dist/client/{shop-commerce-CleZdRha.mjs → shop-commerce-gnI8PieZ.mjs} +27 -10
  163. package/dist/client/{shop-commerce-store-ycnoB2Ce.mjs → shop-commerce-store-BTbrhObn.mjs} +1 -1
  164. package/dist/client/{shopShared-CPhByt2a.mjs → shopShared-D6KS2_qk.mjs} +3 -3
  165. package/dist/client/{useDiscountCodeUi-cStSQI6C.mjs → useDiscountCodeUi-DCccGCxV.mjs} +1 -1
  166. package/dist/client/{useEventFilters-DKPN7hSY.mjs → useEventFilters-eGs3rPZQ.mjs} +3 -104
  167. package/dist/client/{usePolling-BKAd6pkZ.mjs → usePolling-CvSU2sur.mjs} +2 -2
  168. package/dist/preview-next/before-render.mjs +57 -0
  169. package/dist/preview-next/client/runtime.mjs +4 -4
  170. package/dist/preview-next/middleware.mjs +57 -0
  171. package/dist/{previewAuthStore-BkT1D06A.mjs → previewAuthStore-DN7vcRsv.mjs} +57 -0
  172. package/dist/{sdk-runtime-hu3wr3ng.mjs → sdk-runtime-DaOiA7ct.mjs} +2 -2
  173. package/dist/{separator-Bln8izQ9.mjs → separator-CqRhcCxD.mjs} +1 -1
  174. package/dist/server/components.mjs +4092 -4108
  175. package/dist/server/config-template-validation.mjs +4 -23
  176. package/dist/server/config-validation.mjs +373 -555
  177. package/dist/server/config.mjs +410 -558
  178. package/dist/server/data.mjs +373 -555
  179. package/dist/server/index.mjs +58 -1
  180. package/dist/server/next.mjs +32958 -32926
  181. package/dist/server/page-converter.mjs +369 -526
  182. package/dist/server/prebuild.mjs +1 -1
  183. package/dist/server/rendering/server.mjs +5371 -3174
  184. package/dist/server/rendering.mjs +4099 -4124
  185. package/dist/server/routing.mjs +758 -966
  186. package/dist/server/server.mjs +448 -632
  187. package/dist/server/theme-bridge.mjs +472 -525
  188. package/dist/server/theme.mjs +1074 -392
  189. package/package.json +1 -1
  190. package/dist/_dts/blocks/src/primitives/content/components/Button.d.ts +0 -40
  191. package/dist/_dts/blocks/src/system/fragments/library/footerBottomText.d.ts +0 -19
  192. package/dist/_dts/media-core/src/legacyMediaValue.d.ts +0 -11
  193. package/dist/_dts/theme-core/src/styles/buttons.d.ts +0 -27
  194. package/dist/_dts/theme-core/src/styles/buttonsLibrary.d.ts +0 -2
  195. package/dist/_dts/theme-core/src/styles/glow.d.ts +0 -3
  196. package/dist/client/colorStyles-gcTh5yZT.mjs +0 -89
@@ -199,7 +199,7 @@ function isFreePublicEventPriceDisplay(display) {
199
199
  //#endregion
200
200
  //#region ../core/src/event-page-surface-subject.ts
201
201
  function parseEventPageSurfaceSubject(value) {
202
- if (!isRecord$7(value)) return err({ kind: "notObject" });
202
+ if (!isRecord$8(value)) return err({ kind: "notObject" });
203
203
  switch (value.kind) {
204
204
  case "eventSeries": {
205
205
  const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
@@ -242,7 +242,7 @@ function parseEventPageSurfaceSubject(value) {
242
242
  });
243
243
  }
244
244
  }
245
- function isRecord$7(value) {
245
+ function isRecord$8(value) {
246
246
  return typeof value === "object" && value !== null && !Array.isArray(value);
247
247
  }
248
248
  //#endregion
@@ -399,6 +399,38 @@ function toLocationCoordinates(value) {
399
399
  lng: value.lng
400
400
  };
401
401
  }
402
+ //#endregion
403
+ //#region ../core/src/rich-text.ts
404
+ function isRecord$7(value) {
405
+ return typeof value === "object" && value !== null && !Array.isArray(value);
406
+ }
407
+ function hasOnlyKeys(value, allowed) {
408
+ return Object.keys(value).every((key) => allowed.has(key));
409
+ }
410
+ const rootKeys = /* @__PURE__ */ new Set(["type", "content"]);
411
+ const nodeKeys = /* @__PURE__ */ new Set([
412
+ "type",
413
+ "content",
414
+ "text",
415
+ "attrs",
416
+ "marks"
417
+ ]);
418
+ const markKeys = /* @__PURE__ */ new Set(["type", "attrs"]);
419
+ function isDenseArrayOf(value, predicate) {
420
+ for (let index = 0; index < value.length; index += 1) if (!(index in value) || !predicate(value[index])) return false;
421
+ return true;
422
+ }
423
+ function isTipTapMark(value) {
424
+ return isRecord$7(value) && hasOnlyKeys(value, markKeys) && typeof value.type === "string" && value.type.length > 0 && (value.attrs === void 0 || isRecord$7(value.attrs));
425
+ }
426
+ function isTipTapNode(value) {
427
+ if (!isRecord$7(value) || !hasOnlyKeys(value, nodeKeys) || typeof value.type !== "string" || value.type.length === 0 || value.type === "doc" || value.attrs !== void 0 && !isRecord$7(value.attrs) || value.marks !== void 0 && (!Array.isArray(value.marks) || !isDenseArrayOf(value.marks, isTipTapMark)) || value.content !== void 0 && (!Array.isArray(value.content) || !isDenseArrayOf(value.content, isTipTapNode))) return false;
428
+ if (value.type === "text") return typeof value.text === "string" && value.text.length > 0 && value.content === void 0;
429
+ return value.text === void 0;
430
+ }
431
+ function isCanonicalRichTextDoc(value) {
432
+ return isRecord$7(value) && hasOnlyKeys(value, rootKeys) && value.type === "doc" && Array.isArray(value.content) && isDenseArrayOf(value.content, isTipTapNode);
433
+ }
402
434
  z$1.object({
403
435
  formulaVersion: z$1.literal("managed-domain-overage-v1"),
404
436
  conversionRule: z$1.literal("usd-to-gbp-1-to-1-v1"),
@@ -3292,151 +3324,6 @@ z$1.discriminatedUnion("kind", [
3292
3324
  })
3293
3325
  ]);
3294
3326
  //#endregion
3295
- //#region ../theme-core/src/surfaces/foregroundContract.ts
3296
- const SURFACE_FOREGROUND_CSS_VARS = {
3297
- text: "--rb-surface-text-color",
3298
- heading: "--rb-surface-heading-color",
3299
- link: "--rb-surface-link-color",
3300
- supporting: "--rb-surface-supporting-color"
3301
- };
3302
- const DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
3303
- const DEFAULT_ROLE_FALLBACKS = {
3304
- text: DEFAULT_SURFACE_TEXT_COLOR,
3305
- heading: DEFAULT_SURFACE_TEXT_COLOR,
3306
- link: "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))",
3307
- supporting: "rgb(var(--tb-mutedText, 100 116 139))"
3308
- };
3309
- function requireSurfaceColorValue(role, value) {
3310
- const normalized = value.trim();
3311
- if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
3312
- return normalized;
3313
- }
3314
- function completeSurfaceForegrounds(input) {
3315
- const text = requireSurfaceColorValue("text", input.text);
3316
- return {
3317
- text,
3318
- heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
3319
- link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
3320
- supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
3321
- };
3322
- }
3323
- function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
3324
- const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
3325
- const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
3326
- if (role === "text") return `var(${roleVariable}, ${fallback})`;
3327
- return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
3328
- }
3329
- function surfaceForegroundValueWithOpacity(role, opacityPercent) {
3330
- if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
3331
- return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
3332
- }
3333
- function surfaceForegroundStyle(input) {
3334
- const foregrounds = completeSurfaceForegrounds(input);
3335
- return {
3336
- color: foregrounds.text,
3337
- [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
3338
- [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
3339
- [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
3340
- [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
3341
- };
3342
- }
3343
- //#endregion
3344
- //#region ../theme-core/src/utils/colorStyles.ts
3345
- const COLOR_VAR_PREFIX = "--tb-";
3346
- function parseToken(source) {
3347
- const parts = parseColorTokenParts(source);
3348
- if (parts.kind === "raw") return {
3349
- token: source,
3350
- raw: parts.value
3351
- };
3352
- if (parts.kind === "invalid") return { token: source };
3353
- return {
3354
- token: parts.token,
3355
- opacityPercent: parts.opacityPercent === null ? void 0 : parts.opacityPercent
3356
- };
3357
- }
3358
- const SURFACE_TEXT_ROLE_BY_TOKEN = {
3359
- text: "text",
3360
- heading: "heading",
3361
- mutedText: "supporting"
3362
- };
3363
- function surfaceRoleForTextToken(token) {
3364
- return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
3365
- }
3366
- /**
3367
- * Converts a theme color token to a CSS rgb value.
3368
- * This is the primary function for applying theme colors to CSS properties.
3369
- *
3370
- * @param token - Theme color token (semantic, with opacity, or raw)
3371
- * @returns CSS color value (rgb with optional alpha, or raw CSS value)
3372
- *
3373
- * @example
3374
- * rgbColorValue('primary') // => 'rgb(var(--tb-primary))'
3375
- * rgbColorValue('surface/95') // => 'rgb(var(--tb-surface) / 0.95)'
3376
- * rgbColorValue('raw:transparent') // => 'transparent'
3377
- */
3378
- function rgbColorValue(token) {
3379
- const { token: baseToken, opacityPercent, raw } = parseToken(token);
3380
- if (raw) return raw;
3381
- const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
3382
- if (opacityPercent === void 0) return `rgb(var(${cssVar}))`;
3383
- return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
3384
- }
3385
- /**
3386
- * Creates a backgroundColor style object from a theme token.
3387
- *
3388
- * @param token - Theme color token
3389
- * @returns CSSProperties with backgroundColor
3390
- */
3391
- function backgroundColorStyle(token) {
3392
- return { backgroundColor: rgbColorValue(token) };
3393
- }
3394
- /**
3395
- * Creates a text color style object from a theme token.
3396
- *
3397
- * @param token - Theme color token
3398
- * @returns CSSProperties with color
3399
- */
3400
- function textColorStyle(token) {
3401
- const parsed = parseToken(token);
3402
- const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
3403
- if (surfaceRole) return { color: parsed.opacityPercent === void 0 ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent) };
3404
- return { color: rgbColorValue(token) };
3405
- }
3406
- /**
3407
- * Creates a border color style object from a theme token.
3408
- *
3409
- * @param token - Theme color token
3410
- * @returns CSSProperties with borderColor
3411
- */
3412
- function borderColorStyle(token) {
3413
- return { borderColor: rgbColorValue(token) };
3414
- }
3415
- /**
3416
- * Merges multiple CSSProperties objects into a single object.
3417
- * Later styles override earlier ones. Undefined values are filtered out.
3418
- * Returns undefined if the merged result is empty.
3419
- *
3420
- * @param styles - Variable number of CSSProperties objects (can be undefined)
3421
- * @returns Merged CSSProperties object, or undefined if empty
3422
- *
3423
- * @example
3424
- * mergeStyles(
3425
- * backgroundColorStyle('surface'),
3426
- * textColorStyle('text'),
3427
- * borderColorStyle('border')
3428
- * )
3429
- * // => { backgroundColor: '...', color: '...', borderColor: '...' }
3430
- */
3431
- function mergeStyles(...styles) {
3432
- const merged = {};
3433
- for (const style of styles) {
3434
- if (!style) continue;
3435
- Object.assign(merged, style);
3436
- }
3437
- return Object.keys(merged).length ? merged : void 0;
3438
- }
3439
- //#endregion
3440
3327
  //#region ../theme-core/src/lib/media.ts
3441
3328
  const hotspotSchema$1 = z.object({
3442
3329
  x: z.number().min(0).max(1),
@@ -3494,111 +3381,6 @@ const mediaSchema$1 = z.object({
3494
3381
  transform: transformSchema$1.optional()
3495
3382
  });
3496
3383
  //#endregion
3497
- //#region ../theme-core/src/buttons/effectClassification.ts
3498
- /**
3499
- * Exhaustive live policy for every registered effect id.
3500
- *
3501
- * The resolver consumes the transition payload directly, so adding an effect
3502
- * cannot update classification without also defining its runtime behavior.
3503
- */
3504
- const BUTTON_EFFECT_POLICIES = {
3505
- "darken-background": {
3506
- classification: "colour-transition",
3507
- transition: {
3508
- kind: "adjust-shade",
3509
- direction: "darker"
3510
- }
3511
- },
3512
- "lighten-background": {
3513
- classification: "colour-transition",
3514
- transition: {
3515
- kind: "adjust-shade",
3516
- direction: "lighter"
3517
- }
3518
- },
3519
- "background-on-hover": {
3520
- classification: "colour-transition",
3521
- transition: { kind: "replace-background" }
3522
- },
3523
- "background-on-hover-alpha": {
3524
- classification: "unsupported-colour",
3525
- reason: "alpha_requires_surface"
3526
- },
3527
- "fade-background": {
3528
- classification: "unsupported-colour",
3529
- reason: "changes_element_opacity"
3530
- },
3531
- "opacity-reduce": {
3532
- classification: "unsupported-colour",
3533
- reason: "changes_element_opacity"
3534
- },
3535
- "gradient-text": {
3536
- classification: "unsupported-colour",
3537
- reason: "changes_foreground"
3538
- },
3539
- "text-color-change": {
3540
- classification: "unsupported-colour",
3541
- reason: "changes_foreground"
3542
- },
3543
- "border-color-change": {
3544
- classification: "unsupported-colour",
3545
- reason: "changes_border"
3546
- },
3547
- "aurora-glow": {
3548
- classification: "unsupported-background-overlay",
3549
- reason: "unresolved_background_overlay"
3550
- },
3551
- "cosmic-stardust": {
3552
- classification: "unsupported-background-overlay",
3553
- reason: "unresolved_background_overlay"
3554
- },
3555
- "gradient-border-fill": {
3556
- classification: "unsupported-background-overlay",
3557
- reason: "unresolved_background_overlay"
3558
- },
3559
- "animated-gradient-border-fill": {
3560
- classification: "unsupported-background-overlay",
3561
- reason: "unresolved_background_overlay"
3562
- },
3563
- "nav-underline": {
3564
- classification: "not-button",
3565
- reason: "not_button_effect"
3566
- },
3567
- "nav-frosted-base": {
3568
- classification: "not-button",
3569
- reason: "not_button_effect"
3570
- },
3571
- "nav-frosted-hover": {
3572
- classification: "not-button",
3573
- reason: "not_button_effect"
3574
- },
3575
- "nav-frosted-active": {
3576
- classification: "not-button",
3577
- reason: "not_button_effect"
3578
- },
3579
- "animated-gradient": { classification: "non-colour" },
3580
- "border-glow": { classification: "non-colour" },
3581
- "drop-shadow": { classification: "non-colour" },
3582
- "inner-shadow": { classification: "non-colour" },
3583
- "neumorphic-shadow": { classification: "non-colour" },
3584
- "outer-glow": { classification: "non-colour" },
3585
- "retro-3d-shadow": { classification: "non-colour" },
3586
- "scale-up": { classification: "non-colour" },
3587
- "scale-down": { classification: "non-colour" },
3588
- lift: { classification: "non-colour" },
3589
- "press-down": { classification: "non-colour" },
3590
- pop: { classification: "non-colour" },
3591
- "border-bottom-grow": { classification: "non-colour" },
3592
- "sketchy-border": { classification: "non-colour" },
3593
- "pulse-animation": { classification: "non-colour" }
3594
- };
3595
- function getButtonEffectPolicy(effectId) {
3596
- return Object.prototype.hasOwnProperty.call(BUTTON_EFFECT_POLICIES, effectId) ? BUTTON_EFFECT_POLICIES[effectId] : null;
3597
- }
3598
- function classifyButtonEffectId(effectId) {
3599
- return getButtonEffectPolicy(effectId)?.classification ?? "unknown";
3600
- }
3601
- //#endregion
3602
3384
  //#region ../theme-core/src/buttons/types.ts
3603
3385
  /**
3604
3386
  * Standard semantic variant roles a theme exposes.
@@ -3615,6 +3397,13 @@ const VARIANT_ROLES = [
3615
3397
  "tertiary",
3616
3398
  "accent"
3617
3399
  ];
3400
+ /**
3401
+ * Canonical persisted/CSS-safe button variant identifier.
3402
+ *
3403
+ * IDs become class selectors, so keep the contract deliberately narrower than
3404
+ * an arbitrary string and shared with every authoring/runtime boundary.
3405
+ */
3406
+ const buttonVariantIdSchema = z$1.string().min(1).max(50).regex(/^[a-z0-9-]+$/, "Button variant IDs may contain lowercase letters, numbers, and hyphens only");
3618
3407
  function parseOpaqueButtonColourToken(value) {
3619
3408
  const token = parseThemeColorToken(value);
3620
3409
  if (token === null) return null;
@@ -3629,6 +3418,109 @@ const opaqueButtonColourTokenSchema = themeColorTokenSchema.refine((value) => pa
3629
3418
  if (token === null) throw new Error("Invariant: opaque button token passed its schema");
3630
3419
  return token;
3631
3420
  });
3421
+ const buttonShadeAmountSchema = z$1.number().finite().min(0).max(900).multipleOf(100);
3422
+ const buttonShadowIntensitySchema = z$1.enum([
3423
+ "subtle",
3424
+ "medium",
3425
+ "strong"
3426
+ ]);
3427
+ /**
3428
+ * The complete persisted button-effect contract.
3429
+ *
3430
+ * Navigation has its own generic interactive-effect model. Button variants use
3431
+ * this closed union so unsupported effect IDs, unknown option keys, and unsafe
3432
+ * CSS values cannot become representable after the schema boundary.
3433
+ */
3434
+ const buttonEffectApplicationSchema = z$1.discriminatedUnion("effectId", [
3435
+ z$1.strictObject({
3436
+ effectId: z$1.literal("darken-background"),
3437
+ options: z$1.strictObject({ amount: buttonShadeAmountSchema.optional() }).optional()
3438
+ }),
3439
+ z$1.strictObject({
3440
+ effectId: z$1.literal("lighten-background"),
3441
+ options: z$1.strictObject({ amount: buttonShadeAmountSchema.optional() }).optional()
3442
+ }),
3443
+ z$1.strictObject({
3444
+ effectId: z$1.literal("background-on-hover"),
3445
+ options: z$1.strictObject({ colorToken: opaqueButtonColourTokenSchema.optional() }).optional()
3446
+ }),
3447
+ z$1.strictObject({
3448
+ effectId: z$1.literal("animated-gradient"),
3449
+ options: z$1.strictObject({ direction: z$1.enum(["horizontal", "vertical"]).optional() }).optional()
3450
+ }),
3451
+ z$1.strictObject({
3452
+ effectId: z$1.literal("drop-shadow"),
3453
+ options: z$1.strictObject({ intensity: buttonShadowIntensitySchema.optional() }).optional()
3454
+ }),
3455
+ z$1.strictObject({
3456
+ effectId: z$1.literal("inner-shadow"),
3457
+ options: z$1.strictObject({}).optional()
3458
+ }),
3459
+ z$1.strictObject({
3460
+ effectId: z$1.literal("neumorphic-shadow"),
3461
+ options: z$1.strictObject({
3462
+ mode: z$1.enum(["raised", "pressed"]).optional(),
3463
+ intensity: buttonShadowIntensitySchema.optional()
3464
+ }).optional()
3465
+ }),
3466
+ z$1.strictObject({
3467
+ effectId: z$1.literal("retro-3d-shadow"),
3468
+ options: z$1.strictObject({}).optional()
3469
+ }),
3470
+ z$1.strictObject({
3471
+ effectId: z$1.literal("scale-up"),
3472
+ options: z$1.strictObject({ scale: z$1.enum([
3473
+ "1.02",
3474
+ "1.03",
3475
+ "1.05",
3476
+ "1.10"
3477
+ ]).optional() }).optional()
3478
+ }),
3479
+ z$1.strictObject({
3480
+ effectId: z$1.literal("scale-down"),
3481
+ options: z$1.strictObject({ scale: z$1.enum([
3482
+ "0.90",
3483
+ "0.95",
3484
+ "0.97",
3485
+ "0.98"
3486
+ ]).optional() }).optional()
3487
+ }),
3488
+ z$1.strictObject({
3489
+ effectId: z$1.literal("lift"),
3490
+ options: z$1.strictObject({ amount: z$1.enum([
3491
+ "0.25",
3492
+ "0.5",
3493
+ "1"
3494
+ ]).optional() }).optional()
3495
+ }),
3496
+ z$1.strictObject({
3497
+ effectId: z$1.literal("press-down"),
3498
+ options: z$1.strictObject({}).optional()
3499
+ }),
3500
+ z$1.strictObject({
3501
+ effectId: z$1.literal("pop"),
3502
+ options: z$1.strictObject({ intensity: z$1.enum([
3503
+ "subtle",
3504
+ "medium",
3505
+ "dramatic"
3506
+ ]).optional() }).optional()
3507
+ }),
3508
+ z$1.strictObject({
3509
+ effectId: z$1.literal("border-bottom-grow"),
3510
+ options: z$1.strictObject({
3511
+ height: z$1.union([z$1.literal(1), z$1.literal(2)]).optional(),
3512
+ origin: z$1.enum([
3513
+ "left",
3514
+ "center",
3515
+ "right"
3516
+ ]).optional()
3517
+ }).optional()
3518
+ }),
3519
+ z$1.strictObject({
3520
+ effectId: z$1.literal("sketchy-border"),
3521
+ options: z$1.strictObject({ intensity: buttonShadowIntensitySchema.optional() }).optional()
3522
+ })
3523
+ ]);
3632
3524
  const cornerStyleSchema = z$1.enum([
3633
3525
  "square",
3634
3526
  "rounded",
@@ -3663,13 +3555,7 @@ const hoverTransformSchema = z$1.enum([
3663
3555
  "scale",
3664
3556
  "press"
3665
3557
  ]);
3666
- const hoverColorSchema = z$1.enum([
3667
- "none",
3668
- "brighten",
3669
- "darken",
3670
- "saturate",
3671
- "token"
3672
- ]);
3558
+ z$1.enum(["none", "token"]);
3673
3559
  const buttonPaddingPresetSchema = z$1.enum([
3674
3560
  "compact",
3675
3561
  "default",
@@ -3730,7 +3616,7 @@ const buttonSizesSchema = z$1.object({
3730
3616
  lg,
3731
3617
  xl: xl ?? lg
3732
3618
  }));
3733
- const canonicalButtonGlobalSettingsSchema = z$1.object({
3619
+ const buttonGlobalSettingsBaseSchema = z$1.strictObject({
3734
3620
  cornerStyle: cornerStyleSchema,
3735
3621
  cornerRadius: z$1.number().min(0).max(24).optional(),
3736
3622
  /**
@@ -3743,30 +3629,23 @@ const canonicalButtonGlobalSettingsSchema = z$1.object({
3743
3629
  shadow: shadowSizeSchema.optional(),
3744
3630
  textTransform: textTransformSchema,
3745
3631
  fontWeight: fontWeightSchema,
3746
- /**
3747
- * @deprecated Set per-variant via `variant.border.widthClass` instead.
3748
- * Schema field is preserved so existing presets parse; the value is unread
3749
- * by the current generator and will be removed once the legacy
3750
- * `primitives/content/components/Button.tsx` slot exports are deleted.
3751
- */
3752
- borderWidth: z$1.union([
3753
- z$1.literal(1),
3754
- z$1.literal(2),
3755
- z$1.literal(3)
3756
- ]),
3757
3632
  typography: buttonTypographySchema.optional(),
3758
3633
  fontSize: z$1.string().optional(),
3759
3634
  letterSpacing: letterSpacingSchema.optional(),
3760
3635
  italic: z$1.boolean().optional(),
3761
3636
  paddingPreset: buttonPaddingPresetSchema.optional(),
3762
3637
  hoverTransform: hoverTransformSchema,
3763
- hoverColor: hoverColorSchema,
3764
- hoverColorToken: opaqueButtonColourTokenSchema.optional(),
3765
3638
  gradientStyle: gradientStyleSchema.optional(),
3766
3639
  gradientAngle: z$1.number().min(0).max(360).optional(),
3767
3640
  gradientSharpness: gradientSharpnessSchema.optional()
3768
3641
  });
3769
- const buttonGlobalSettingsSchema = z$1.preprocess(normalizeLegacyButtonGlobalInput, canonicalButtonGlobalSettingsSchema);
3642
+ const buttonGlobalSettingsSchema = z$1.discriminatedUnion("hoverColor", [buttonGlobalSettingsBaseSchema.extend({
3643
+ hoverColor: z$1.literal("none"),
3644
+ hoverColorToken: z$1.never().optional()
3645
+ }), buttonGlobalSettingsBaseSchema.extend({
3646
+ hoverColor: z$1.literal("token"),
3647
+ hoverColorToken: opaqueButtonColourTokenSchema
3648
+ })]);
3770
3649
  const gradientDirectionSchema$1 = z$1.enum([
3771
3650
  "to-r",
3772
3651
  "to-l",
@@ -3778,11 +3657,11 @@ const gradientDirectionSchema$1 = z$1.enum([
3778
3657
  "to-bl"
3779
3658
  ]);
3780
3659
  const buttonColourTreatmentSchema = z$1.discriminatedUnion("type", [
3781
- z$1.object({
3660
+ z$1.strictObject({
3782
3661
  type: z$1.literal("solid"),
3783
3662
  colorToken: opaqueButtonColourTokenSchema
3784
3663
  }),
3785
- z$1.object({
3664
+ z$1.strictObject({
3786
3665
  type: z$1.literal("gradient"),
3787
3666
  stops: z$1.array(opaqueButtonColourTokenSchema).min(2).transform((stops) => {
3788
3667
  const [first, second, ...rest] = stops;
@@ -3796,19 +3675,15 @@ const buttonColourTreatmentSchema = z$1.discriminatedUnion("type", [
3796
3675
  direction: gradientDirectionSchema$1,
3797
3676
  foregroundToken: opaqueButtonColourTokenSchema
3798
3677
  }),
3799
- z$1.object({
3678
+ z$1.strictObject({
3800
3679
  type: z$1.literal("surface"),
3801
3680
  role: z$1.literal("link")
3802
3681
  })
3803
3682
  ]);
3804
3683
  const buttonBackgroundSchema = buttonColourTreatmentSchema;
3805
- const effectApplicationSchema$1 = z$1.object({
3806
- effectId: z$1.string(),
3807
- options: z$1.record(z$1.string(), z$1.json()).optional()
3808
- });
3809
- const buttonBorderSchema = z$1.object({ widthClass: z$1.string() });
3810
- const buttonVariantAffordanceSchema = z$1.object({ iconId: z$1.string().min(1) });
3811
- const variantShadowSchema = z$1.object({
3684
+ const buttonBorderSchema = z$1.strictObject({ widthClass: z$1.string() });
3685
+ const buttonVariantAffordanceSchema = z$1.strictObject({ iconId: z$1.string().min(1) });
3686
+ const variantShadowSchema = z$1.strictObject({
3812
3687
  elevation: z$1.enum([
3813
3688
  "none",
3814
3689
  "low",
@@ -3821,13 +3696,13 @@ const variantShadowSchema = z$1.object({
3821
3696
  "hard"
3822
3697
  ]).nullable(),
3823
3698
  position: z$1.enum(["bottom", "bottom-right"]).default("bottom"),
3824
- colorToken: themeColorTokenSchema.optional()
3699
+ colorToken: opaqueButtonColourTokenSchema.optional()
3825
3700
  });
3826
- const variantEffectsSchema = z$1.object({
3827
- base: z$1.array(effectApplicationSchema$1).optional(),
3828
- hover: z$1.array(effectApplicationSchema$1).optional(),
3829
- active: z$1.array(effectApplicationSchema$1).optional(),
3830
- focus: z$1.array(effectApplicationSchema$1).optional()
3701
+ const variantEffectsSchema = z$1.strictObject({
3702
+ base: z$1.array(buttonEffectApplicationSchema).optional(),
3703
+ hover: z$1.array(buttonEffectApplicationSchema).optional(),
3704
+ active: z$1.array(buttonEffectApplicationSchema).optional(),
3705
+ focus: z$1.array(buttonEffectApplicationSchema).optional()
3831
3706
  });
3832
3707
  /**
3833
3708
  * Per-variant size overrides schema — every entry is optional.
@@ -3848,8 +3723,8 @@ const variantSizeOverridesSchema = z$1.object({
3848
3723
  * default (e.g. link-style variants declaring zero horizontal padding at
3849
3724
  * every size).
3850
3725
  */
3851
- const canonicalButtonVariantSchema = z$1.object({
3852
- id: z$1.string(),
3726
+ const buttonVariantSchema = z$1.strictObject({
3727
+ id: buttonVariantIdSchema,
3853
3728
  name: z$1.string().min(1).max(20),
3854
3729
  enabled: z$1.boolean(),
3855
3730
  priority: prioritySchema,
@@ -3863,154 +3738,73 @@ const canonicalButtonVariantSchema = z$1.object({
3863
3738
  sizes: variantSizeOverridesSchema.optional(),
3864
3739
  affordance: buttonVariantAffordanceSchema.optional()
3865
3740
  });
3866
- /**
3867
- * Temporary persisted-theme admission boundary for issue #1206.
3868
- *
3869
- * Production inventory on 2026-07-22 found 22 rows using the old independent
3870
- * `textColorToken`/border colour shape. New source and all downstream code use
3871
- * only the canonical relationship. Delete this preprocessor after the reviewed
3872
- * production rewrite reports zero legacy rows.
3873
- */
3874
- const buttonVariantSchema = z$1.preprocess(normalizeLegacyButtonVariantInput, canonicalButtonVariantSchema);
3875
- const buttonSystemSchema = z$1.object({
3741
+ const buttonSystemSchema = z$1.strictObject({
3876
3742
  global: buttonGlobalSettingsSchema,
3877
3743
  variants: z$1.array(buttonVariantSchema).min(1).max(6),
3878
3744
  sizes: buttonSizesSchema.optional()
3745
+ }).superRefine((system, ctx) => {
3746
+ const seen = /* @__PURE__ */ new Set();
3747
+ system.variants.forEach((variant, index) => {
3748
+ if (seen.has(variant.id)) ctx.addIssue({
3749
+ code: "custom",
3750
+ path: [
3751
+ "variants",
3752
+ index,
3753
+ "id"
3754
+ ],
3755
+ message: `Duplicate button variant ID: ${variant.id}`
3756
+ });
3757
+ seen.add(variant.id);
3758
+ });
3879
3759
  });
3880
- function normalizeLegacyButtonVariantInput(input) {
3881
- if (!isUnknownRecord(input)) return input;
3882
- const background = input.background;
3883
- if (!isUnknownRecord(background)) return input;
3884
- if (!(background.type === "transparent" || Object.prototype.hasOwnProperty.call(input, "textColorToken") || isUnknownRecord(input.border) && Object.prototype.hasOwnProperty.call(input.border, "colorToken") || hasLegacyButtonEffects(input.effects) || hasLegacyAlphaToken(input, background))) return input;
3885
- const { textColorToken, ...withoutLegacyText } = input;
3886
- const normalizedBorder = isUnknownRecord(input.border) && typeof input.border.widthClass === "string" ? { widthClass: input.border.widthClass } : input.border;
3887
- const normalizedAffordance = isUnknownRecord(input.affordance) && typeof input.affordance.iconId === "string" ? { iconId: input.affordance.iconId } : input.affordance;
3888
- const normalizedEffects = normalizeLegacyButtonEffects(input.effects, background.type);
3889
- const hoverBackgroundToken = stripLegacyTokenAlpha(input.hoverBackgroundToken);
3890
- if (background.type === "transparent") return {
3891
- ...withoutLegacyText,
3892
- background: {
3893
- type: "surface",
3894
- role: "link"
3895
- },
3896
- border: normalizedBorder,
3897
- affordance: normalizedAffordance,
3898
- effects: normalizedEffects,
3899
- hoverBackgroundToken
3900
- };
3901
- if (background.type === "gradient") {
3902
- const stops = Array.isArray(background.stops) ? background.stops.map(stripLegacyTokenAlpha) : background.stops;
3903
- return {
3904
- ...withoutLegacyText,
3905
- background: {
3906
- ...background,
3907
- stops,
3908
- foregroundToken: stripLegacyTokenAlpha(background.foregroundToken ?? textColorToken)
3909
- },
3910
- border: normalizedBorder,
3911
- affordance: normalizedAffordance,
3912
- effects: normalizedEffects,
3913
- hoverBackgroundToken
3914
- };
3915
- }
3916
- return {
3917
- ...withoutLegacyText,
3918
- background: background.type === "solid" ? {
3919
- ...background,
3920
- colorToken: stripLegacyTokenAlpha(background.colorToken)
3921
- } : background,
3922
- border: normalizedBorder,
3923
- affordance: normalizedAffordance,
3924
- effects: normalizedEffects,
3925
- hoverBackgroundToken
3926
- };
3760
+ //#endregion
3761
+ //#region ../theme-core/src/surfaces/foregroundContract.ts
3762
+ const SURFACE_FOREGROUND_CSS_VARS = {
3763
+ text: "--rb-surface-text-color",
3764
+ heading: "--rb-surface-heading-color",
3765
+ link: "--rb-surface-link-color",
3766
+ supporting: "--rb-surface-supporting-color"
3767
+ };
3768
+ const DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
3769
+ const DEFAULT_ROLE_FALLBACKS = {
3770
+ text: DEFAULT_SURFACE_TEXT_COLOR,
3771
+ heading: DEFAULT_SURFACE_TEXT_COLOR,
3772
+ link: "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))",
3773
+ supporting: "rgb(var(--tb-mutedText, 100 116 139))"
3774
+ };
3775
+ function requireSurfaceColorValue(role, value) {
3776
+ const normalized = value.trim();
3777
+ if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
3778
+ return normalized;
3927
3779
  }
3928
- function normalizeLegacyButtonGlobalInput(input) {
3929
- if (!isUnknownRecord(input)) return input;
3930
- const hoverColorToken = stripLegacyTokenAlpha(input.hoverColorToken);
3931
- return hoverColorToken === input.hoverColorToken ? input : {
3932
- ...input,
3933
- hoverColorToken
3780
+ function completeSurfaceForegrounds(input) {
3781
+ const text = requireSurfaceColorValue("text", input.text);
3782
+ return {
3783
+ text,
3784
+ heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
3785
+ link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
3786
+ supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
3934
3787
  };
3935
3788
  }
3936
- function hasLegacyAlphaToken(input, background) {
3937
- const stops = isUnknownArray(background.stops) ? background.stops : [];
3938
- return [
3939
- input.hoverBackgroundToken,
3940
- background.colorToken,
3941
- background.foregroundToken,
3942
- ...stops
3943
- ].some((token) => stripLegacyTokenAlpha(token) !== token);
3944
- }
3945
- function stripLegacyTokenAlpha(value) {
3946
- if (typeof value !== "string") return value;
3947
- const slashIndex = value.indexOf("/");
3948
- return slashIndex < 0 ? value : value.slice(0, slashIndex);
3949
- }
3950
- function hasLegacyButtonEffects(input) {
3951
- if (!isUnknownRecord(input)) return false;
3952
- return [
3953
- "base",
3954
- "hover",
3955
- "active",
3956
- "focus"
3957
- ].some((state) => {
3958
- const effects = input[state];
3959
- return Array.isArray(effects) && effects.some((effect) => {
3960
- if (!isUnknownRecord(effect) || typeof effect.effectId !== "string") return true;
3961
- const classification = classifyButtonEffectId(effect.effectId);
3962
- if (classification !== "colour-transition" && classification !== "non-colour") return true;
3963
- return effect.effectId === "background-on-hover" && isUnknownRecord(effect.options) && stripLegacyTokenAlpha(effect.options.colorToken) !== effect.options.colorToken;
3964
- });
3965
- });
3966
- }
3967
- function normalizeLegacyButtonEffects(input, backgroundType) {
3968
- if (!isUnknownRecord(input)) return input;
3969
- const normalized = {};
3970
- for (const state of [
3971
- "base",
3972
- "hover",
3973
- "active",
3974
- "focus"
3975
- ]) {
3976
- const effects = input[state];
3977
- if (!Array.isArray(effects)) continue;
3978
- const safeEffects = effects.flatMap((effect) => {
3979
- if (!isUnknownRecord(effect) || typeof effect.effectId !== "string") return [];
3980
- const classification = classifyButtonEffectId(effect.effectId);
3981
- if (classification === "non-colour") return [effect];
3982
- if (classification !== "colour-transition") return [];
3983
- if (effect.effectId === "background-on-hover") {
3984
- const options = isUnknownRecord(effect.options) ? effect.options : null;
3985
- const colorToken = options === null ? null : parseOpaqueButtonColourToken(stripLegacyTokenAlpha(options.colorToken));
3986
- return colorToken === null ? [] : [{
3987
- ...effect,
3988
- options: {
3989
- ...options,
3990
- colorToken
3991
- }
3992
- }];
3993
- }
3994
- if (backgroundType !== "solid") return [];
3995
- const rawAmount = isUnknownRecord(effect.options) ? effect.options.amount : void 0;
3996
- const amount = typeof rawAmount === "number" && rawAmount > 0 ? Math.max(100, Math.round(rawAmount / 100) * 100) : 100;
3997
- return [{
3998
- ...effect,
3999
- options: {
4000
- ...isUnknownRecord(effect.options) ? effect.options : {},
4001
- amount
4002
- }
4003
- }];
4004
- });
4005
- if (safeEffects.length > 0) normalized[state] = safeEffects;
4006
- }
4007
- return Object.keys(normalized).length === 0 ? void 0 : normalized;
3789
+ function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
3790
+ const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
3791
+ const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
3792
+ if (role === "text") return `var(${roleVariable}, ${fallback})`;
3793
+ return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
4008
3794
  }
4009
- function isUnknownRecord(value) {
4010
- return typeof value === "object" && value !== null && !Array.isArray(value);
3795
+ function surfaceForegroundValueWithOpacity(role, opacityPercent) {
3796
+ if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
3797
+ return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
4011
3798
  }
4012
- function isUnknownArray(value) {
4013
- return Array.isArray(value);
3799
+ function surfaceForegroundStyle(input) {
3800
+ const foregrounds = completeSurfaceForegrounds(input);
3801
+ return {
3802
+ color: foregrounds.text,
3803
+ [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
3804
+ [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
3805
+ [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
3806
+ [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
3807
+ };
4014
3808
  }
4015
3809
  buttonSizeNameSchema.options;
4016
3810
  //#endregion
@@ -4167,7 +3961,6 @@ const quietArrowRecipe = defineButtonStyleRecipe({
4167
3961
  cornerStyle: "rounded",
4168
3962
  textTransform: "uppercase",
4169
3963
  fontWeight: 500,
4170
- borderWidth: 1,
4171
3964
  typography: "body",
4172
3965
  fontSize: "text-sm",
4173
3966
  letterSpacing: "loose",
@@ -4231,7 +4024,7 @@ const quietArrowRecipe = defineButtonStyleRecipe({
4231
4024
  affordance: { iconId: "ArrowRight" },
4232
4025
  effects: { hover: [{
4233
4026
  effectId: "background-on-hover",
4234
- options: { colorToken: "surfaceAlt" }
4027
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
4235
4028
  }] }
4236
4029
  }
4237
4030
  },
@@ -4342,7 +4135,6 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4342
4135
  shadow: "low",
4343
4136
  textTransform: "none",
4344
4137
  fontWeight: 500,
4345
- borderWidth: 2,
4346
4138
  hoverTransform: "lift",
4347
4139
  hoverColor: "none"
4348
4140
  },
@@ -4361,10 +4153,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4361
4153
  position: "bottom"
4362
4154
  },
4363
4155
  effects: {
4364
- hover: [{
4365
- effectId: "lift",
4366
- options: { translateY: "-1px" }
4367
- }],
4156
+ hover: [{ effectId: "lift" }],
4368
4157
  active: [{
4369
4158
  effectId: "scale-down",
4370
4159
  options: { scale: "0.98" }
@@ -4383,7 +4172,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4383
4172
  border: { widthClass: "border-2" },
4384
4173
  effects: { hover: [{
4385
4174
  effectId: "background-on-hover",
4386
- options: { colorToken: "surface" }
4175
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4387
4176
  }] }
4388
4177
  }
4389
4178
  },
@@ -4398,7 +4187,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4398
4187
  border: { widthClass: "border" },
4399
4188
  effects: { hover: [{
4400
4189
  effectId: "background-on-hover",
4401
- options: { colorToken: "surface" }
4190
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4402
4191
  }] }
4403
4192
  }
4404
4193
  },
@@ -4412,7 +4201,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4412
4201
  borderRadius: "rounded-full",
4413
4202
  effects: { hover: [{
4414
4203
  effectId: "background-on-hover",
4415
- options: { colorToken: "surface" }
4204
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4416
4205
  }] }
4417
4206
  }
4418
4207
  },
@@ -4442,7 +4231,6 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
4442
4231
  shadow: "low",
4443
4232
  textTransform: "none",
4444
4233
  fontWeight: 500,
4445
- borderWidth: 1,
4446
4234
  hoverTransform: "lift",
4447
4235
  hoverColor: "none",
4448
4236
  typography: "body",
@@ -4478,12 +4266,9 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
4478
4266
  position: "bottom"
4479
4267
  },
4480
4268
  effects: {
4481
- hover: [{
4482
- effectId: "lift",
4483
- options: { translateY: "-1px" }
4484
- }, {
4269
+ hover: [{ effectId: "lift" }, {
4485
4270
  effectId: "background-on-hover",
4486
- options: { colorToken: "accent" }
4271
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("accent") }
4487
4272
  }],
4488
4273
  active: [{
4489
4274
  effectId: "scale-down",
@@ -4503,7 +4288,7 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
4503
4288
  border: { widthClass: "border" },
4504
4289
  effects: { hover: [{
4505
4290
  effectId: "background-on-hover",
4506
- options: { colorToken: "muted" }
4291
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("muted") }
4507
4292
  }] }
4508
4293
  }
4509
4294
  },
@@ -4518,7 +4303,7 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
4518
4303
  border: { widthClass: "border" },
4519
4304
  effects: { hover: [{
4520
4305
  effectId: "background-on-hover",
4521
- options: { colorToken: "surfaceAlt" }
4306
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
4522
4307
  }] }
4523
4308
  }
4524
4309
  },
@@ -4578,7 +4363,6 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4578
4363
  shadow: "medium",
4579
4364
  textTransform: "none",
4580
4365
  fontWeight: 600,
4581
- borderWidth: 1,
4582
4366
  hoverTransform: "none",
4583
4367
  hoverColor: "none"
4584
4368
  },
@@ -4619,7 +4403,7 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4619
4403
  border: { widthClass: "border" },
4620
4404
  effects: { hover: [{
4621
4405
  effectId: "background-on-hover",
4622
- options: { colorToken: "background" }
4406
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("background") }
4623
4407
  }] }
4624
4408
  }
4625
4409
  },
@@ -4634,7 +4418,7 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4634
4418
  border: { widthClass: "border" },
4635
4419
  effects: { hover: [{
4636
4420
  effectId: "background-on-hover",
4637
- options: { colorToken: "surface" }
4421
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4638
4422
  }] }
4639
4423
  }
4640
4424
  },
@@ -4648,7 +4432,7 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4648
4432
  borderRadius: "rounded-md",
4649
4433
  effects: { hover: [{
4650
4434
  effectId: "background-on-hover",
4651
- options: { colorToken: "surface" }
4435
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4652
4436
  }] }
4653
4437
  }
4654
4438
  },
@@ -4683,7 +4467,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4683
4467
  cornerStyle: "square",
4684
4468
  textTransform: "none",
4685
4469
  fontWeight: 500,
4686
- borderWidth: 1,
4687
4470
  hoverTransform: "none",
4688
4471
  hoverColor: "none"
4689
4472
  },
@@ -4701,7 +4484,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4701
4484
  effectId: "border-bottom-grow",
4702
4485
  options: {
4703
4486
  height: 2,
4704
- colorToken: "text",
4705
4487
  origin: "left"
4706
4488
  }
4707
4489
  }] }
@@ -4720,7 +4502,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4720
4502
  effectId: "border-bottom-grow",
4721
4503
  options: {
4722
4504
  height: 1,
4723
- colorToken: "mutedText",
4724
4505
  origin: "left"
4725
4506
  }
4726
4507
  }] }
@@ -4739,7 +4520,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4739
4520
  effectId: "border-bottom-grow",
4740
4521
  options: {
4741
4522
  height: 1,
4742
- colorToken: "accent",
4743
4523
  origin: "left"
4744
4524
  }
4745
4525
  }] }
@@ -4763,7 +4543,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4763
4543
  effectId: "border-bottom-grow",
4764
4544
  options: {
4765
4545
  height: 2,
4766
- colorToken: "accent",
4767
4546
  origin: "left"
4768
4547
  }
4769
4548
  }] } }
@@ -4785,7 +4564,6 @@ const pebbleRecipe = defineStaticButtonStyleRecipe({
4785
4564
  cornerStyle: "pill",
4786
4565
  textTransform: "none",
4787
4566
  fontWeight: 500,
4788
- borderWidth: 2,
4789
4567
  hoverTransform: "none",
4790
4568
  hoverColor: "none"
4791
4569
  },
@@ -4830,7 +4608,7 @@ const pebbleRecipe = defineStaticButtonStyleRecipe({
4830
4608
  border: { widthClass: "border-2" },
4831
4609
  effects: { hover: [{
4832
4610
  effectId: "background-on-hover",
4833
- options: { colorToken: "accent" }
4611
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("accent") }
4834
4612
  }] }
4835
4613
  }
4836
4614
  },
@@ -4845,7 +4623,7 @@ const pebbleRecipe = defineStaticButtonStyleRecipe({
4845
4623
  border: { widthClass: "border" },
4846
4624
  effects: { hover: [{
4847
4625
  effectId: "background-on-hover",
4848
- options: { colorToken: "surface" }
4626
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4849
4627
  }] }
4850
4628
  }
4851
4629
  },
@@ -4900,7 +4678,6 @@ const brushedWashRecipe = defineStaticButtonStyleRecipe({
4900
4678
  shadow: "low",
4901
4679
  textTransform: "none",
4902
4680
  fontWeight: 500,
4903
- borderWidth: 1,
4904
4681
  hoverTransform: "none",
4905
4682
  hoverColor: "none"
4906
4683
  },
@@ -4965,7 +4742,7 @@ const brushedWashRecipe = defineStaticButtonStyleRecipe({
4965
4742
  border: { widthClass: "border" },
4966
4743
  effects: { hover: [{
4967
4744
  effectId: "background-on-hover",
4968
- options: { colorToken: "surface" }
4745
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4969
4746
  }] }
4970
4747
  }
4971
4748
  },
@@ -4979,7 +4756,7 @@ const brushedWashRecipe = defineStaticButtonStyleRecipe({
4979
4756
  borderRadius: "rounded-lg",
4980
4757
  effects: { hover: [{
4981
4758
  effectId: "background-on-hover",
4982
- options: { colorToken: "surface" }
4759
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4983
4760
  }] }
4984
4761
  }
4985
4762
  },
@@ -5008,7 +4785,6 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
5008
4785
  cornerStyle: "rounded",
5009
4786
  textTransform: "uppercase",
5010
4787
  fontWeight: 600,
5011
- borderWidth: 1,
5012
4788
  hoverTransform: "none",
5013
4789
  hoverColor: "none",
5014
4790
  letterSpacing: "loose"
@@ -5066,7 +4842,7 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
5066
4842
  border: { widthClass: "border-2" },
5067
4843
  effects: { hover: [{
5068
4844
  effectId: "background-on-hover",
5069
- options: { colorToken: "surface" }
4845
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
5070
4846
  }] }
5071
4847
  }
5072
4848
  },
@@ -5081,7 +4857,7 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
5081
4857
  border: { widthClass: "border-2" },
5082
4858
  effects: { hover: [{
5083
4859
  effectId: "background-on-hover",
5084
- options: { colorToken: "surface" }
4860
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
5085
4861
  }] }
5086
4862
  }
5087
4863
  },
@@ -5115,7 +4891,6 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
5115
4891
  effectId: "border-bottom-grow",
5116
4892
  options: {
5117
4893
  height: 1,
5118
- colorToken: "accent",
5119
4894
  origin: "left"
5120
4895
  }
5121
4896
  }] }
@@ -5146,7 +4921,6 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5146
4921
  cornerStyle: "rounded",
5147
4922
  textTransform: "none",
5148
4923
  fontWeight: 600,
5149
- borderWidth: 1,
5150
4924
  typography: "body",
5151
4925
  letterSpacing: "tight",
5152
4926
  paddingPreset: "default",
@@ -5178,12 +4952,9 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5178
4952
  },
5179
4953
  borderRadius: "rounded-lg",
5180
4954
  affordance: { iconId: "ArrowRight" },
5181
- effects: { hover: [{
5182
- effectId: "lift",
5183
- options: { translateY: "-2px" }
5184
- }, {
4955
+ effects: { hover: [{ effectId: "lift" }, {
5185
4956
  effectId: "background-on-hover",
5186
- options: { colorToken: "secondary" }
4957
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("secondary") }
5187
4958
  }] }
5188
4959
  }
5189
4960
  },
@@ -5196,12 +4967,9 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5196
4967
  },
5197
4968
  borderRadius: "rounded-lg",
5198
4969
  border: { widthClass: "border" },
5199
- effects: { hover: [{
5200
- effectId: "lift",
5201
- options: { translateY: "-2px" }
5202
- }, {
4970
+ effects: { hover: [{ effectId: "lift" }, {
5203
4971
  effectId: "background-on-hover",
5204
- options: { colorToken: "surfaceAlt" }
4972
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
5205
4973
  }] }
5206
4974
  }
5207
4975
  },
@@ -5214,12 +4982,9 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5214
4982
  },
5215
4983
  borderRadius: "rounded-lg",
5216
4984
  border: { widthClass: "border" },
5217
- effects: { hover: [{
5218
- effectId: "lift",
5219
- options: { translateY: "-2px" }
5220
- }, {
4985
+ effects: { hover: [{ effectId: "lift" }, {
5221
4986
  effectId: "background-on-hover",
5222
- options: { colorToken: "surfaceAlt" }
4987
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
5223
4988
  }] }
5224
4989
  }
5225
4990
  },
@@ -5231,10 +4996,7 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5231
4996
  role: "link"
5232
4997
  },
5233
4998
  borderRadius: "rounded-lg",
5234
- effects: { hover: [{
5235
- effectId: "lift",
5236
- options: { translateY: "-2px" }
5237
- }] }
4999
+ effects: { hover: [{ effectId: "lift" }] }
5238
5000
  }
5239
5001
  },
5240
5002
  accent: {
@@ -5246,10 +5008,7 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5246
5008
  },
5247
5009
  borderRadius: "rounded-lg",
5248
5010
  affordance: { iconId: "ArrowRight" },
5249
- effects: { hover: [{
5250
- effectId: "lift",
5251
- options: { translateY: "-2px" }
5252
- }] }
5011
+ effects: { hover: [{ effectId: "lift" }] }
5253
5012
  }
5254
5013
  }
5255
5014
  }
@@ -5270,9 +5029,8 @@ const showtimePillRecipe = defineStaticButtonStyleRecipe({
5270
5029
  shadow: "low",
5271
5030
  textTransform: "uppercase",
5272
5031
  fontWeight: 700,
5273
- borderWidth: 2,
5274
5032
  hoverTransform: "lift",
5275
- hoverColor: "darken",
5033
+ hoverColor: "none",
5276
5034
  typography: "body",
5277
5035
  paddingPreset: "spacious",
5278
5036
  italic: false
@@ -5330,7 +5088,7 @@ const showtimePillRecipe = defineStaticButtonStyleRecipe({
5330
5088
  border: { widthClass: "border-2" },
5331
5089
  effects: { hover: [{
5332
5090
  effectId: "background-on-hover",
5333
- options: { colorToken: "background" }
5091
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("background") }
5334
5092
  }] }
5335
5093
  }
5336
5094
  },
@@ -5344,7 +5102,7 @@ const showtimePillRecipe = defineStaticButtonStyleRecipe({
5344
5102
  borderRadius: "rounded-full",
5345
5103
  effects: { hover: [{
5346
5104
  effectId: "background-on-hover",
5347
- options: { colorToken: "surface" }
5105
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
5348
5106
  }] }
5349
5107
  }
5350
5108
  },
@@ -5379,7 +5137,6 @@ const joyStampRecipe = defineStaticButtonStyleRecipe({
5379
5137
  typography: "heading",
5380
5138
  fontWeight: 700,
5381
5139
  fontSize: "text-lg",
5382
- borderWidth: 2,
5383
5140
  hoverTransform: "none",
5384
5141
  hoverColor: "none"
5385
5142
  },
@@ -5414,7 +5171,7 @@ const joyStampRecipe = defineStaticButtonStyleRecipe({
5414
5171
  elevation: "high",
5415
5172
  softness: "hard",
5416
5173
  position: "bottom-right",
5417
- colorToken: "text"
5174
+ colorToken: unsafeAsOpaqueButtonColourToken("text")
5418
5175
  },
5419
5176
  effects: { hover: [{ effectId: "press-down" }] }
5420
5177
  }
@@ -5432,7 +5189,7 @@ const joyStampRecipe = defineStaticButtonStyleRecipe({
5432
5189
  elevation: "high",
5433
5190
  softness: "hard",
5434
5191
  position: "bottom-right",
5435
- colorToken: "secondary"
5192
+ colorToken: unsafeAsOpaqueButtonColourToken("secondary")
5436
5193
  },
5437
5194
  effects: { hover: [{ effectId: "press-down" }] }
5438
5195
  }
@@ -5477,7 +5234,6 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5477
5234
  cornerStyle: "rounded",
5478
5235
  textTransform: "uppercase",
5479
5236
  fontWeight: 600,
5480
- borderWidth: 1,
5481
5237
  hoverTransform: "none",
5482
5238
  hoverColor: "none",
5483
5239
  letterSpacing: "loose"
@@ -5513,7 +5269,7 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5513
5269
  effects: {
5514
5270
  hover: [{
5515
5271
  effectId: "background-on-hover",
5516
- options: { colorToken: "primary-100" }
5272
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("primary-100") }
5517
5273
  }],
5518
5274
  active: [{
5519
5275
  effectId: "scale-down",
@@ -5533,7 +5289,7 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5533
5289
  border: { widthClass: "border" },
5534
5290
  effects: { hover: [{
5535
5291
  effectId: "background-on-hover",
5536
- options: { colorToken: "surface" }
5292
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
5537
5293
  }] }
5538
5294
  }
5539
5295
  },
@@ -5548,7 +5304,7 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5548
5304
  border: { widthClass: "border" },
5549
5305
  effects: { hover: [{
5550
5306
  effectId: "background-on-hover",
5551
- options: { colorToken: "muted" }
5307
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("muted") }
5552
5308
  }] }
5553
5309
  }
5554
5310
  },
@@ -5582,7 +5338,6 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5582
5338
  effectId: "border-bottom-grow",
5583
5339
  options: {
5584
5340
  height: 1,
5585
- colorToken: "accent",
5586
5341
  origin: "left"
5587
5342
  }
5588
5343
  }] }
@@ -6691,6 +6446,102 @@ new Set(themeV2NormalEditorRawStyleFieldNames);
6691
6446
  const pageDesignEditorBackgroundOverrideOwner = "page-design-editor";
6692
6447
  const siteChromeBackgroundOverrideOwner = "site-chrome-editor";
6693
6448
  //#endregion
6449
+ //#region ../theme-core/src/utils/colorStyles.ts
6450
+ const COLOR_VAR_PREFIX = "--tb-";
6451
+ function parseToken(source) {
6452
+ const parts = parseColorTokenParts(source);
6453
+ if (parts.kind === "raw") return {
6454
+ token: source,
6455
+ raw: parts.value
6456
+ };
6457
+ if (parts.kind === "invalid") return { token: source };
6458
+ return {
6459
+ token: parts.token,
6460
+ opacityPercent: parts.opacityPercent === null ? void 0 : parts.opacityPercent
6461
+ };
6462
+ }
6463
+ const SURFACE_TEXT_ROLE_BY_TOKEN = {
6464
+ text: "text",
6465
+ heading: "heading",
6466
+ mutedText: "supporting"
6467
+ };
6468
+ function surfaceRoleForTextToken(token) {
6469
+ return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
6470
+ }
6471
+ /**
6472
+ * Converts a theme color token to a CSS rgb value.
6473
+ * This is the primary function for applying theme colors to CSS properties.
6474
+ *
6475
+ * @param token - Theme color token (semantic, with opacity, or raw)
6476
+ * @returns CSS color value (rgb with optional alpha, or raw CSS value)
6477
+ *
6478
+ * @example
6479
+ * rgbColorValue('primary') // => 'rgb(var(--tb-primary))'
6480
+ * rgbColorValue('surface/95') // => 'rgb(var(--tb-surface) / 0.95)'
6481
+ * rgbColorValue('raw:transparent') // => 'transparent'
6482
+ */
6483
+ function rgbColorValue(token) {
6484
+ const { token: baseToken, opacityPercent, raw } = parseToken(token);
6485
+ if (raw) return raw;
6486
+ const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
6487
+ if (opacityPercent === void 0) return `rgb(var(${cssVar}))`;
6488
+ return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
6489
+ }
6490
+ /**
6491
+ * Creates a backgroundColor style object from a theme token.
6492
+ *
6493
+ * @param token - Theme color token
6494
+ * @returns CSSProperties with backgroundColor
6495
+ */
6496
+ function backgroundColorStyle(token) {
6497
+ return { backgroundColor: rgbColorValue(token) };
6498
+ }
6499
+ /**
6500
+ * Creates a text color style object from a theme token.
6501
+ *
6502
+ * @param token - Theme color token
6503
+ * @returns CSSProperties with color
6504
+ */
6505
+ function textColorStyle(token) {
6506
+ const parsed = parseToken(token);
6507
+ const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
6508
+ if (surfaceRole) return { color: parsed.opacityPercent === void 0 ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent) };
6509
+ return { color: rgbColorValue(token) };
6510
+ }
6511
+ /**
6512
+ * Creates a border color style object from a theme token.
6513
+ *
6514
+ * @param token - Theme color token
6515
+ * @returns CSSProperties with borderColor
6516
+ */
6517
+ function borderColorStyle(token) {
6518
+ return { borderColor: rgbColorValue(token) };
6519
+ }
6520
+ /**
6521
+ * Merges multiple CSSProperties objects into a single object.
6522
+ * Later styles override earlier ones. Undefined values are filtered out.
6523
+ * Returns undefined if the merged result is empty.
6524
+ *
6525
+ * @param styles - Variable number of CSSProperties objects (can be undefined)
6526
+ * @returns Merged CSSProperties object, or undefined if empty
6527
+ *
6528
+ * @example
6529
+ * mergeStyles(
6530
+ * backgroundColorStyle('surface'),
6531
+ * textColorStyle('text'),
6532
+ * borderColorStyle('border')
6533
+ * )
6534
+ * // => { backgroundColor: '...', color: '...', borderColor: '...' }
6535
+ */
6536
+ function mergeStyles(...styles) {
6537
+ const merged = {};
6538
+ for (const style of styles) {
6539
+ if (!style) continue;
6540
+ Object.assign(merged, style);
6541
+ }
6542
+ return Object.keys(merged).length ? merged : void 0;
6543
+ }
6544
+ //#endregion
6694
6545
  //#region ../theme-core/src/utils/tokenOrColor.ts
6695
6546
  /**
6696
6547
  * Runtime color-reference fields intentionally accept any string, including
@@ -13590,6 +13441,7 @@ const DISPLAY_MEDIA_KINDS = [
13590
13441
  "video",
13591
13442
  "audio"
13592
13443
  ];
13444
+ const DEFAULT_MEDIA_FIELD_KINDS = ["image"];
13593
13445
  const PUBLIC_FILE_FIELD_KINDS = [
13594
13446
  "document",
13595
13447
  "spreadsheet",
@@ -13790,18 +13642,28 @@ const inlineTextFieldSchema = baseFieldSchema.extend({
13790
13642
  maxLength: z$1.number().int().positive().optional(),
13791
13643
  plainTextField: z$1.string().min(1).optional()
13792
13644
  });
13645
+ function hasMediaDefaultIdentifier(value) {
13646
+ return value !== null && typeof value === "object" && !Array.isArray(value) && typeof value.identifier === "string" && value.identifier.trim().length > 0;
13647
+ }
13648
+ function validateMediaFieldDefault(field, ctx) {
13649
+ if (field.defaultValue !== void 0 && field.defaultValue !== null && !hasMediaDefaultIdentifier(field.defaultValue)) ctx.addIssue({
13650
+ code: z$1.ZodIssueCode.custom,
13651
+ path: ["defaultValue"],
13652
+ message: `${field.type} defaultValue must be null or an object with a non-empty identifier`
13653
+ });
13654
+ }
13793
13655
  const mediaFieldSchema = baseFieldSchema.extend({
13794
13656
  type: z$1.literal("media"),
13795
- mediaKinds: z$1.array(z$1.enum(MEDIA_KINDS)).default(["image"]).transform((kinds) => {
13657
+ mediaKinds: z$1.array(z$1.enum(MEDIA_KINDS)).default([...DEFAULT_MEDIA_FIELD_KINDS]).transform((kinds) => {
13796
13658
  const displayKinds = kinds.filter(isDisplayMediaKind);
13797
- return displayKinds.length > 0 ? displayKinds : ["image"];
13659
+ return displayKinds.length > 0 ? displayKinds : [...DEFAULT_MEDIA_FIELD_KINDS];
13798
13660
  }),
13799
13661
  aspectRatio: z$1.string().optional()
13800
- });
13662
+ }).superRefine(validateMediaFieldDefault);
13801
13663
  const fileFieldSchema = baseFieldSchema.extend({
13802
13664
  type: z$1.literal("file"),
13803
13665
  fileKinds: z$1.array(z$1.enum(PUBLIC_FILE_FIELD_KINDS)).default([...PUBLIC_FILE_FIELD_KINDS])
13804
- });
13666
+ }).superRefine(validateMediaFieldDefault);
13805
13667
  const booleanFieldSchema = baseFieldSchema.extend({ type: z$1.literal("boolean") });
13806
13668
  const dateFieldSchema = baseFieldSchema.extend({ type: z$1.literal("date") });
13807
13669
  const timeFieldSchema = baseFieldSchema.extend({ type: z$1.literal("time") });
@@ -22086,20 +21948,10 @@ function visitRichTextNode(node, allowedTokens, tokenValues) {
22086
21948
  }
22087
21949
  function interpolateRichTextTokens(value, options, context) {
22088
21950
  if (!isRecord$6(value)) return value;
22089
- const allowedTokens = new Set(options.tokens);
22090
- const tokenValues = {
21951
+ return visitRichTextNode(value, new Set(options.tokens), {
22091
21952
  year: String((/* @__PURE__ */ new Date()).getFullYear()),
22092
21953
  site_name: getSiteName(context)
22093
- };
22094
- if (isRecord$6(value.doc)) {
22095
- const nextDoc = visitRichTextNode(value.doc, allowedTokens, tokenValues);
22096
- if (nextDoc === value.doc) return value;
22097
- return {
22098
- ...value,
22099
- doc: nextDoc
22100
- };
22101
- }
22102
- return visitRichTextNode(value, allowedTokens, tokenValues);
21954
+ });
22103
21955
  }
22104
21956
  const contentTransforms = [{
22105
21957
  id: "content.interpolateRichTextTokens",
@@ -24482,11 +24334,8 @@ const mediaSchema = z.discriminatedUnion("type", [
24482
24334
  * This module provides a single source of truth for TipTap rich text validation
24483
24335
  * across both the block-form editor and the block rendering system.
24484
24336
  *
24485
- * Format compatibility:
24486
- * - Unwrapped format (new): { type: 'doc', content: [...] }
24487
- * - Wrapped format (legacy): { doc: { type: 'doc', content: [...] } }
24488
- *
24489
- * Both formats are supported for backward compatibility during migration.
24337
+ * Rich-text fields use one canonical root shape:
24338
+ * `{ type: 'doc', content: [...] }`.
24490
24339
  */
24491
24340
  /**
24492
24341
  * TipTap document node schema (recursive structure)
@@ -24499,17 +24348,40 @@ const mediaSchema = z.discriminatedUnion("type", [
24499
24348
  * - marks: Text formatting marks (e.g., bold, italic)
24500
24349
  */
24501
24350
  const TipTapMarkSchema = z$1.object({
24502
- type: z$1.string(),
24351
+ type: z$1.string().min(1),
24503
24352
  attrs: z$1.record(z$1.string(), z$1.unknown()).optional()
24504
- });
24353
+ }).strict();
24505
24354
  const TipTapNodeSchema = z$1.lazy(() => z$1.object({
24506
- type: z$1.string(),
24355
+ type: z$1.string().min(1),
24507
24356
  content: z$1.array(TipTapNodeSchema).optional(),
24508
24357
  text: z$1.string().optional(),
24509
24358
  attrs: z$1.record(z$1.string(), z$1.unknown()).optional(),
24510
24359
  marks: z$1.array(TipTapMarkSchema).optional()
24360
+ }).strict().superRefine((node, ctx) => {
24361
+ if (node.type === "doc") ctx.addIssue({
24362
+ code: "custom",
24363
+ path: ["type"],
24364
+ message: "Document nodes are only valid at the rich-text root"
24365
+ });
24366
+ if (node.type === "text") {
24367
+ if (node.text === void 0 || node.text.length === 0) ctx.addIssue({
24368
+ code: "custom",
24369
+ path: ["text"],
24370
+ message: "Text nodes require a non-empty text value"
24371
+ });
24372
+ if (node.content !== void 0) ctx.addIssue({
24373
+ code: "custom",
24374
+ path: ["content"],
24375
+ message: "Text nodes cannot contain child nodes"
24376
+ });
24377
+ return;
24378
+ }
24379
+ if (node.text !== void 0) ctx.addIssue({
24380
+ code: "custom",
24381
+ path: ["text"],
24382
+ message: "Only text nodes can contain a text value"
24383
+ });
24511
24384
  }));
24512
- z$1.union([TipTapNodeSchema, z$1.object({ doc: TipTapNodeSchema })]);
24513
24385
  /**
24514
24386
  * Canonical schema for a TipTap rich-text document root.
24515
24387
  *
@@ -24518,13 +24390,11 @@ z$1.union([TipTapNodeSchema, z$1.object({ doc: TipTapNodeSchema })]);
24518
24390
  * (dummy content, editor output, migrations) must emit, and the shape every
24519
24391
  * non-legacy consumer can rely on.
24520
24392
  *
24521
- * Legacy envelopes are read-tolerated by {@link RichTextValueSchema} but
24522
- * normalised before reaching anywhere typed as `RichTextDoc`.
24523
24393
  */
24524
24394
  const RichTextDocSchema = z$1.object({
24525
24395
  type: z$1.literal("doc"),
24526
24396
  content: z$1.array(TipTapNodeSchema)
24527
- });
24397
+ }).strict();
24528
24398
  //#endregion
24529
24399
  //#region ../blocks/src/system/blocks/shared/bookingPaymentTerms.ts
24530
24400
  const bookingDepositRefundPolicySchema = z$1.enum(["refundable", "non_refundable"]);
@@ -35202,6 +35072,7 @@ const CANONICAL_REFUND_PLANNER_ERROR_CODES = [
35202
35072
  "idempotency_amount_mismatch",
35203
35073
  "idempotency_method_mismatch",
35204
35074
  "idempotency_receipt_mismatch",
35075
+ "idempotency_scope_mismatch",
35205
35076
  "refund_in_progress"
35206
35077
  ],
35207
35078
  "invalid_amount",
@@ -35588,7 +35459,7 @@ const SITE_BANNER_TONE_VALUES = [
35588
35459
  ];
35589
35460
  const siteBannerScopeSchema = z$1.enum(SITE_BANNER_SCOPE_VALUES);
35590
35461
  const siteBannerToneSchema = z$1.enum(SITE_BANNER_TONE_VALUES);
35591
- const siteBannerBodySchema = z$1.unknown().transform(unwrapRichTextValue);
35462
+ const siteBannerBodySchema = RichTextDocSchema;
35592
35463
  const siteBannerCtaSchema = z$1.object({
35593
35464
  label: z$1.string().trim().min(1),
35594
35465
  link: linkPayloadSchema
@@ -35616,7 +35487,8 @@ const EMPTY_SITE_BANNER_BODY = {
35616
35487
  }]
35617
35488
  };
35618
35489
  function analyzeSiteBannerBody(body) {
35619
- const sanitizedBody = sanitizeSiteBannerBodyInternal(body, { limitParagraphs: false });
35490
+ const parsed = RichTextDocSchema.safeParse(body);
35491
+ const sanitizedBody = parsed.success ? sanitizeSiteBannerBodyInternal(parsed.data, { limitParagraphs: false }) : EMPTY_SITE_BANNER_BODY;
35620
35492
  const paragraphs = collectParagraphs(sanitizedBody);
35621
35493
  const textLength = paragraphs.reduce((total, paragraph) => total + paragraphTextLength(paragraph), 0);
35622
35494
  const issues = [];
@@ -35638,7 +35510,7 @@ function siteBannerBodyIssueMessage(issue) {
35638
35510
  }
35639
35511
  }
35640
35512
  function sanitizeSiteBannerBodyInternal(input, options) {
35641
- const content = normalizeTopLevelNodes(unwrapRichTextValue(input).content ?? [], options);
35513
+ const content = normalizeTopLevelNodes(input.content, options);
35642
35514
  return {
35643
35515
  type: "doc",
35644
35516
  content: content.length > 0 ? content : EMPTY_SITE_BANNER_BODY.content
@@ -35719,28 +35591,6 @@ function sanitizeMarks(marks) {
35719
35591
  });
35720
35592
  return sanitized.length > 0 ? sanitized : void 0;
35721
35593
  }
35722
- function unwrapRichTextValue(value) {
35723
- if (isRecord(value) && isRecord(value.doc)) return unwrapRichTextValue(value.doc);
35724
- if (isRecord(value) && value.type === "doc") return {
35725
- type: "doc",
35726
- content: Array.isArray(value.content) ? value.content.filter(isTipTapNodeLike).map(coerceTipTapNode) : []
35727
- };
35728
- return EMPTY_SITE_BANNER_BODY;
35729
- }
35730
- function isTipTapNodeLike(value) {
35731
- return isRecord(value) && typeof value.type === "string";
35732
- }
35733
- function coerceTipTapNode(value) {
35734
- return {
35735
- type: value.type,
35736
- ...Array.isArray(value.content) ? { content: value.content.filter(isTipTapNodeLike).map(coerceTipTapNode) } : {},
35737
- ...typeof value.text === "string" ? { text: value.text } : {},
35738
- ...Array.isArray(value.marks) ? { marks: value.marks.filter((mark) => isRecord(mark) && typeof mark.type === "string").map((mark) => ({
35739
- type: mark.type,
35740
- ...isRecord(mark.attrs) ? { attrs: mark.attrs } : {}
35741
- })) } : {}
35742
- };
35743
- }
35744
35594
  function paragraphTextLength(paragraph) {
35745
35595
  return collectText(paragraph).length;
35746
35596
  }
@@ -36972,10 +36822,12 @@ const tiptap = {
36972
36822
  * @returns A TipTap document wrapping the content
36973
36823
  */
36974
36824
  doc(content) {
36975
- return {
36825
+ const doc = {
36976
36826
  type: "doc",
36977
36827
  content
36978
36828
  };
36829
+ if (!isCanonicalRichTextDoc(doc)) throw new TypeError("tiptap.doc() requires canonical TipTap nodes");
36830
+ return doc;
36979
36831
  },
36980
36832
  /**
36981
36833
  * Create a heading node.