@riverbankcms/sdk 0.128.0 → 0.129.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 (51) hide show
  1. package/README.md +33 -0
  2. package/dist/{PreviewEditorSidebar-Dbvb7GIr.mjs → PreviewEditorSidebar-B43CJ0g_.mjs} +3 -3
  3. package/dist/{PreviewEditorUI-e9O9l20X.mjs → PreviewEditorUI-DHirVkeM.mjs} +2 -2
  4. package/dist/{SdkPreviewModeRuntime-BZHt6e9w.mjs → SdkPreviewModeRuntime-BJumZy1B.mjs} +495 -292
  5. package/dist/{SiteChromeCustomizeContext-CvuGbHJX.mjs → SiteChromeCustomizeContext-D9SlpwEj.mjs} +140 -140
  6. package/dist/_dts/blocks/src/PageRenderer.d.ts +20 -10
  7. package/dist/_dts/blocks/src/index.d.ts +2 -1
  8. package/dist/_dts/blocks/src/pageRendererBoundaries.d.ts +30 -0
  9. package/dist/_dts/blocks/src/pageRenderingMode.d.ts +37 -0
  10. package/dist/_dts/blocks/src/server.d.ts +1 -1
  11. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +14 -0
  12. package/dist/_dts/preview-next/src/client/blocks/pageDesignRuntimePreview.d.ts +2 -0
  13. package/dist/_dts/preview-next/src/client/index.d.ts +47 -47
  14. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +18 -6
  15. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +30 -21
  16. package/dist/_dts/preview-next/src/client/preview/PreviewThemedSiteDocument.d.ts +18 -5
  17. package/dist/_dts/preview-next/src/client/preview/themeRuntime.d.ts +9 -0
  18. package/dist/_dts/preview-next/src/client/sdk/SdkPreviewMode.d.ts +21 -6
  19. package/dist/_dts/preview-next/src/client/sdk-runtime.d.ts +8 -8
  20. package/dist/_dts/sdk/src/next/catch-all.d.ts +6 -0
  21. package/dist/_dts/sdk/src/next/index.d.ts +2 -1
  22. package/dist/_dts/sdk/src/next/renderSdkContent.d.ts +33 -0
  23. package/dist/_dts/sdk/src/next/types.d.ts +23 -9
  24. package/dist/_dts/sdk/src/preview-next/before-render.d.ts +4 -6
  25. package/dist/_dts/sdk/src/preview-next/client/index.d.ts +3 -3
  26. package/dist/_dts/sdk/src/preview-next/client/runtime.d.ts +1 -1
  27. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +25 -3
  28. package/dist/_dts/sdk/src/rendering/components/Block.shared.d.ts +13 -2
  29. package/dist/_dts/sdk/src/rendering/components/Layout.d.ts +31 -18
  30. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +20 -9
  31. package/dist/_dts/sdk/src/rendering/index.d.ts +4 -2
  32. package/dist/_dts/sdk/src/rendering/renderingMode.d.ts +23 -0
  33. package/dist/_dts/sdk/src/rendering/server.d.ts +5 -3
  34. package/dist/_dts/sdk/src/rendering/themeRuntime.d.ts +6 -0
  35. package/dist/_dts/sdk/src/version.d.ts +1 -1
  36. package/dist/cli/index.mjs +237 -211
  37. package/dist/cli/init-docs/content/workflow-preview-mode.md +24 -11
  38. package/dist/client/client.mjs +420 -337
  39. package/dist/client/rendering.mjs +503 -358
  40. package/dist/preview-next/before-render.mjs +10 -3
  41. package/dist/preview-next/client/runtime.mjs +3 -3
  42. package/dist/{sdk-runtime-Cn_QSCOg.mjs → sdk-runtime-CfZd5pAm.mjs} +1 -1
  43. package/dist/{separator-CEoGABRc.mjs → separator-DkTe68HE.mjs} +1 -1
  44. package/dist/server/components.mjs +478 -351
  45. package/dist/server/index.mjs +1 -1
  46. package/dist/server/next.mjs +640 -500
  47. package/dist/server/prebuild.mjs +1 -1
  48. package/dist/server/rendering/server.mjs +499 -355
  49. package/dist/server/rendering.mjs +499 -355
  50. package/dist/server/server.mjs +1 -1
  51. package/package.json +1 -1
@@ -50985,6 +50985,213 @@ function renderBlock(manifest, content, options = {}) {
50985
50985
  }, componentElement);
50986
50986
  }
50987
50987
  //#endregion
50988
+ //#region ../blocks/src/system/manifest/hydrateLinks.ts
50989
+ /**
50990
+ * Hydrates link objects within block content using the provided route map. Returns
50991
+ * the original content reference when no mutations are required to avoid unnecessary renders.
50992
+ */
50993
+ function hydrateManifestLinks(manifest, content, routes, pagesByIdentifier, entriesByIdentifier) {
50994
+ if (!routes || !manifest?.fields?.length) return content;
50995
+ return hydrateValue(content, {
50996
+ routes,
50997
+ pagesByIdentifier,
50998
+ entriesByIdentifier
50999
+ });
51000
+ }
51001
+ function hydrateValue(value, context) {
51002
+ try {
51003
+ if (Array.isArray(value)) {
51004
+ const resolvedItems = value.map((item) => hydrateValue(item, context));
51005
+ return resolvedItems.every((item, index) => item === value[index]) ? value : resolvedItems;
51006
+ }
51007
+ if (isRecord$13(value)) {
51008
+ if (isInternalLink(value)) return hydrateInternalLink(value, context.routes);
51009
+ if (isPageLink(value)) return hydratePageLink(value, context);
51010
+ if (isEntryLink(value)) return hydrateEntryLink(value, context);
51011
+ const resolvedEntries = Object.entries(value).map(([key, entry]) => [key, hydrateValue(entry, context)]);
51012
+ return resolvedEntries.every(([key, entry]) => entry === value[key]) ? value : Object.fromEntries(resolvedEntries);
51013
+ }
51014
+ return value;
51015
+ } catch (err) {
51016
+ console.error("[hydrateLinks] Error hydrating value:", err, value);
51017
+ return value;
51018
+ }
51019
+ }
51020
+ function hydrateInternalLink(link, routes) {
51021
+ const resolved = resolveRouteTarget(link.routeId, routes);
51022
+ if (!resolved) return link;
51023
+ const nextHref = resolved.href;
51024
+ const currentHref = typeof link.href === "string" && link.href.length > 0 ? link.href : null;
51025
+ const nextUpdatedAt = resolved.updatedAt;
51026
+ const updates = {};
51027
+ if (nextHref && nextHref !== currentHref) updates.href = nextHref;
51028
+ if (nextUpdatedAt && link.updatedAt !== nextUpdatedAt) updates.updatedAt = nextUpdatedAt;
51029
+ return Object.keys(updates).length > 0 ? {
51030
+ ...link,
51031
+ ...updates
51032
+ } : link;
51033
+ }
51034
+ function isInternalLink(value) {
51035
+ if (value.kind !== "internal") return false;
51036
+ if (typeof value.routeId !== "string" || value.routeId.length === 0) return false;
51037
+ return true;
51038
+ }
51039
+ function isPageLink(value) {
51040
+ if (value.kind !== "page") return false;
51041
+ if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
51042
+ return true;
51043
+ }
51044
+ function hydratePageLink(link, context) {
51045
+ const resolved = resolvePageRouteTarget(link, context);
51046
+ if (!resolved) return link;
51047
+ return {
51048
+ ...link,
51049
+ href: resolved.href,
51050
+ routeId: resolved.routeId
51051
+ };
51052
+ }
51053
+ function isEntryLink(value) {
51054
+ if (value.kind !== "entry") return false;
51055
+ if (typeof value.contentType !== "string" || value.contentType.length === 0) return false;
51056
+ if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
51057
+ return true;
51058
+ }
51059
+ function hydrateEntryLink(link, context) {
51060
+ const resolved = resolveEntryRouteTarget(link, context);
51061
+ if (!resolved) return link;
51062
+ return {
51063
+ ...link,
51064
+ href: resolved.href,
51065
+ routeId: resolved.routeId
51066
+ };
51067
+ }
51068
+ //#endregion
51069
+ //#region ../blocks/src/sdkBlockTransform.ts
51070
+ /**
51071
+ * Transforms an SDK custom block into a BlockManifest.
51072
+ *
51073
+ * If the block has a `layout`, it can be rendered declaratively without React code.
51074
+ * If no layout, the block MUST use blockOverrides for rendering.
51075
+ */
51076
+ function transformSdkBlockToManifest(sdkBlock) {
51077
+ const hasLayout = Boolean(sdkBlock.layout) || Boolean(sdkBlock.variants && Object.keys(sdkBlock.variants).length > 0);
51078
+ return augmentManifest({
51079
+ name: sdkBlock.id,
51080
+ version: "1.0.0",
51081
+ title: sdkBlock.title,
51082
+ titleSource: sdkBlock.titleSource,
51083
+ description: sdkBlock.description,
51084
+ component: sdkBlock.id,
51085
+ fields: sdkBlock.fields,
51086
+ slots: [],
51087
+ category: sdkBlock.category,
51088
+ tags: sdkBlock.tags,
51089
+ icon: sdkBlock.icon,
51090
+ layout: sdkBlock.layout,
51091
+ variants: sdkBlock.variants,
51092
+ defaultVariant: sdkBlock.defaultVariant,
51093
+ variantOptions: sdkBlock.variantOptions,
51094
+ previewCustomize: sdkBlock.previewCustomize,
51095
+ behaviours: {
51096
+ supportsThemeSwitching: true,
51097
+ inlineEditing: hasLayout,
51098
+ animation: hasLayout,
51099
+ paletteHidden: false
51100
+ }
51101
+ });
51102
+ }
51103
+ /**
51104
+ * Transforms an SDK custom block into a SystemBlockDefinition.
51105
+ *
51106
+ * This creates a minimal definition with just the manifest - no data loaders
51107
+ * or content normalizers since SDK blocks handle their own rendering.
51108
+ */
51109
+ function transformSdkBlockToDefinition(sdkBlock) {
51110
+ return {
51111
+ manifest: transformSdkBlockToManifest(sdkBlock),
51112
+ dataLoaders: sdkBlock.dataLoaders
51113
+ };
51114
+ }
51115
+ //#endregion
51116
+ //#region ../blocks/src/customBlockRegistry.ts
51117
+ const defaultCustomBlockSourcePolicy = { kind: "canonical-db-fallback-sdk" };
51118
+ function isCustomBlockKind(blockKind) {
51119
+ return blockKind.startsWith("custom.");
51120
+ }
51121
+ function transformToBlockDescriptor(sdkBlock, source = "sdk") {
51122
+ return {
51123
+ name: sdkBlock.id,
51124
+ title: sdkBlock.title,
51125
+ description: sdkBlock.description,
51126
+ category: sdkBlock.category,
51127
+ tags: sdkBlock.tags,
51128
+ icon: sdkBlock.icon,
51129
+ definition: transformSdkBlockToDefinition(sdkBlock),
51130
+ source
51131
+ };
51132
+ }
51133
+ function toResolvedCustomBlock(manifest, source) {
51134
+ return {
51135
+ blockKind: manifest.id,
51136
+ manifest: transformSdkBlockToManifest(manifest),
51137
+ source,
51138
+ descriptor: transformToBlockDescriptor(manifest, source.kind === "managed-database" ? "database" : "sdk")
51139
+ };
51140
+ }
51141
+ function planCustomBlockRegistryResolution({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy }) {
51142
+ switch (policy.kind) {
51143
+ case "canonical-db-fallback-sdk": {
51144
+ const entriesByKind = /* @__PURE__ */ new Map();
51145
+ const conflicts = [];
51146
+ for (const customBlock of customBlocks) entriesByKind.set(customBlock.manifest.id, toResolvedCustomBlock(customBlock.manifest, customBlock.source));
51147
+ for (const sdkBlock of sdkConfig?.customBlocks ?? []) {
51148
+ const existing = entriesByKind.get(sdkBlock.id);
51149
+ if (existing) {
51150
+ conflicts.push({
51151
+ kind: "conflict",
51152
+ blockKind: existing.blockKind,
51153
+ winner: existing.source,
51154
+ loser: { kind: "sdk-config" },
51155
+ reason: "db-canonical-sdk-fallback"
51156
+ });
51157
+ continue;
51158
+ }
51159
+ entriesByKind.set(sdkBlock.id, toResolvedCustomBlock(sdkBlock, { kind: "sdk-config" }));
51160
+ }
51161
+ return {
51162
+ policy,
51163
+ entries: Array.from(entriesByKind.values()),
51164
+ conflicts
51165
+ };
51166
+ }
51167
+ }
51168
+ }
51169
+ function createCustomBlockRegistry({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy, onConflict }) {
51170
+ const plan = planCustomBlockRegistryResolution({
51171
+ sdkConfig,
51172
+ customBlocks,
51173
+ policy
51174
+ });
51175
+ const entriesByKind = new Map(plan.entries.map((entry) => [entry.blockKind, entry]));
51176
+ for (const conflict of plan.conflicts) onConflict?.(`Using ${sourceLabel(conflict.winner)} custom block "${conflict.blockKind}" - ${sourceLabel(conflict.loser)} block is fallback only`);
51177
+ return {
51178
+ entries: plan.entries,
51179
+ conflicts: plan.conflicts,
51180
+ findManifest: (blockKind) => {
51181
+ if (!isCustomBlockKind(blockKind)) return void 0;
51182
+ return entriesByKind.get(blockKind);
51183
+ }
51184
+ };
51185
+ }
51186
+ function sourceLabel(source) {
51187
+ switch (source.kind) {
51188
+ case "managed-database": return "DB";
51189
+ case "sdk-synced": return "SDK-synced DB";
51190
+ case "sdk-config": return "SDK config";
51191
+ default: return assertNever$4(source);
51192
+ }
51193
+ }
51194
+ //#endregion
50988
51195
  //#region ../theme-core/src/runtime/fontFamily.ts
50989
51196
  /**
50990
51197
  * Font Family Formatting Utilities
@@ -54722,215 +54929,115 @@ function mapFontStyle(italic) {
54722
54929
  return italic ? "italic" : "normal";
54723
54930
  }
54724
54931
  //#endregion
54725
- //#region ../blocks/src/system/manifest/hydrateLinks.ts
54726
- /**
54727
- * Hydrates link objects within block content using the provided route map. Returns
54728
- * the original content reference when no mutations are required to avoid unnecessary renders.
54729
- */
54730
- function hydrateManifestLinks(manifest, content, routes, pagesByIdentifier, entriesByIdentifier) {
54731
- if (!routes || !manifest?.fields?.length) return content;
54732
- return hydrateValue(content, {
54733
- routes,
54734
- pagesByIdentifier,
54735
- entriesByIdentifier
54736
- });
54737
- }
54738
- function hydrateValue(value, context) {
54739
- try {
54740
- if (Array.isArray(value)) {
54741
- const resolvedItems = value.map((item) => hydrateValue(item, context));
54742
- return resolvedItems.every((item, index) => item === value[index]) ? value : resolvedItems;
54743
- }
54744
- if (isRecord$13(value)) {
54745
- if (isInternalLink(value)) return hydrateInternalLink(value, context.routes);
54746
- if (isPageLink(value)) return hydratePageLink(value, context);
54747
- if (isEntryLink(value)) return hydrateEntryLink(value, context);
54748
- const resolvedEntries = Object.entries(value).map(([key, entry]) => [key, hydrateValue(entry, context)]);
54749
- return resolvedEntries.every(([key, entry]) => entry === value[key]) ? value : Object.fromEntries(resolvedEntries);
54750
- }
54751
- return value;
54752
- } catch (err) {
54753
- console.error("[hydrateLinks] Error hydrating value:", err, value);
54754
- return value;
54932
+ //#region ../blocks/src/pageRenderingMode.ts
54933
+ var MissingBlockOverrideError$1 = class extends Error {
54934
+ constructor(blockKind) {
54935
+ super(`Override-only rendering requires an override for block kind "${blockKind}".`);
54936
+ this.blockKind = blockKind;
54937
+ this.code = "missing_block_override";
54938
+ this.name = "MissingBlockOverrideError";
54755
54939
  }
54940
+ };
54941
+ function isOverrideOnlyResourceInput(props) {
54942
+ return props.rendering?.kind === "overrides-only";
54756
54943
  }
54757
- function hydrateInternalLink(link, routes) {
54758
- const resolved = resolveRouteTarget(link.routeId, routes);
54759
- if (!resolved) return link;
54760
- const nextHref = resolved.href;
54761
- const currentHref = typeof link.href === "string" && link.href.length > 0 ? link.href : null;
54762
- const nextUpdatedAt = resolved.updatedAt;
54763
- const updates = {};
54764
- if (nextHref && nextHref !== currentHref) updates.href = nextHref;
54765
- if (nextUpdatedAt && link.updatedAt !== nextUpdatedAt) updates.updatedAt = nextUpdatedAt;
54766
- return Object.keys(updates).length > 0 ? {
54767
- ...link,
54768
- ...updates
54769
- } : link;
54770
- }
54771
- function isInternalLink(value) {
54772
- if (value.kind !== "internal") return false;
54773
- if (typeof value.routeId !== "string" || value.routeId.length === 0) return false;
54774
- return true;
54775
- }
54776
- function isPageLink(value) {
54777
- if (value.kind !== "page") return false;
54778
- if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
54779
- return true;
54780
- }
54781
- function hydratePageLink(link, context) {
54782
- const resolved = resolvePageRouteTarget(link, context);
54783
- if (!resolved) return link;
54944
+ function resolvePageThemeResources(props) {
54945
+ if (isOverrideOnlyResourceInput(props)) return { kind: "unavailable" };
54784
54946
  return {
54785
- ...link,
54786
- href: resolved.href,
54787
- routeId: resolved.routeId
54947
+ kind: "available",
54948
+ tokens: props.themeTokens ?? buildThemeRuntime$1(props.theme).tokens,
54949
+ config: props.theme
54788
54950
  };
54789
54951
  }
54790
- function isEntryLink(value) {
54791
- if (value.kind !== "entry") return false;
54792
- if (typeof value.contentType !== "string" || value.contentType.length === 0) return false;
54793
- if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
54794
- return true;
54952
+ function requireBlockOverride(resources, override, blockKind) {
54953
+ if (resources.kind === "unavailable" && !override) throw new MissingBlockOverrideError$1(blockKind);
54795
54954
  }
54796
- function hydrateEntryLink(link, context) {
54797
- const resolved = resolveEntryRouteTarget(link, context);
54798
- if (!resolved) return link;
54799
- return {
54800
- ...link,
54801
- href: resolved.href,
54802
- routeId: resolved.routeId
54803
- };
54955
+ function overrideThemeProps(resources) {
54956
+ return resources.kind === "available" ? {
54957
+ theme: resources.tokens,
54958
+ themeConfig: resources.config
54959
+ } : {};
54960
+ }
54961
+ function requireThemeResources(resources, blockKind) {
54962
+ if (resources.kind === "unavailable") throw new MissingBlockOverrideError$1(blockKind);
54963
+ return resources;
54804
54964
  }
54805
54965
  //#endregion
54806
- //#region ../blocks/src/sdkBlockTransform.ts
54807
- /**
54808
- * Transforms an SDK custom block into a BlockManifest.
54809
- *
54810
- * If the block has a `layout`, it can be rendered declaratively without React code.
54811
- * If no layout, the block MUST use blockOverrides for rendering.
54812
- */
54813
- function transformSdkBlockToManifest(sdkBlock) {
54814
- const hasLayout = Boolean(sdkBlock.layout) || Boolean(sdkBlock.variants && Object.keys(sdkBlock.variants).length > 0);
54815
- return augmentManifest({
54816
- name: sdkBlock.id,
54817
- version: "1.0.0",
54818
- title: sdkBlock.title,
54819
- titleSource: sdkBlock.titleSource,
54820
- description: sdkBlock.description,
54821
- component: sdkBlock.id,
54822
- fields: sdkBlock.fields,
54823
- slots: [],
54824
- category: sdkBlock.category,
54825
- tags: sdkBlock.tags,
54826
- icon: sdkBlock.icon,
54827
- layout: sdkBlock.layout,
54828
- variants: sdkBlock.variants,
54829
- defaultVariant: sdkBlock.defaultVariant,
54830
- variantOptions: sdkBlock.variantOptions,
54831
- previewCustomize: sdkBlock.previewCustomize,
54832
- behaviours: {
54833
- supportsThemeSwitching: true,
54834
- inlineEditing: hasLayout,
54835
- animation: hasLayout,
54836
- paletteHidden: false
54837
- }
54838
- });
54966
+ //#region ../blocks/src/pageRendererBoundaries.tsx
54967
+ const boundaryKey = (previousBlockId, nextBlockId) => `${previousBlockId}\u0000${nextBlockId}`;
54968
+ function isSiteStyleTransitionStyleGroup(value) {
54969
+ return value?.startsWith("site-style-transition-") === true;
54970
+ }
54971
+ function boundaryMapForAdjacentBlockIds(boundaries) {
54972
+ return new Map(boundaries.map((boundary) => [boundaryKey(boundary.previousBlockId, boundary.nextBlockId), boundary]));
54973
+ }
54974
+ function boundaryBetweenBlocks(previousBlock, nextBlock, boundaries) {
54975
+ const previousBlockId = previousBlock?.id ?? null;
54976
+ const nextBlockId = nextBlock?.id ?? null;
54977
+ if (!previousBlockId || !nextBlockId) return null;
54978
+ return boundaries.get(boundaryKey(previousBlockId, nextBlockId)) ?? null;
54979
+ }
54980
+ function renderBoundaryAfterBlock(input) {
54981
+ const previousBlockId = input.block.id;
54982
+ const nextBlockId = input.nextBlock?.id ?? null;
54983
+ if (!previousBlockId || !nextBlockId) return null;
54984
+ const boundary = input.boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId));
54985
+ if (!boundary) return null;
54986
+ const rendered = /* @__PURE__ */ jsx("div", {
54987
+ "aria-hidden": "true",
54988
+ "data-block-boundary": "",
54989
+ "data-boundary-id": boundary.boundaryId,
54990
+ "data-boundary-previous-block-id": boundary.previousBlockId,
54991
+ "data-boundary-next-block-id": boundary.nextBlockId,
54992
+ "data-style-group": boundary.styleGroup,
54993
+ style: boundaryCssVarsStyle(boundary)
54994
+ }, `${input.blockKey}:boundary`);
54995
+ return input.wrapBoundary ? input.wrapBoundary(boundary, rendered) : rendered;
54839
54996
  }
54840
- /**
54841
- * Transforms an SDK custom block into a SystemBlockDefinition.
54842
- *
54843
- * This creates a minimal definition with just the manifest - no data loaders
54844
- * or content normalizers since SDK blocks handle their own rendering.
54845
- */
54846
- function transformSdkBlockToDefinition(sdkBlock) {
54997
+ function boundaryCssVarsStyle(boundary) {
54847
54998
  return {
54848
- manifest: transformSdkBlockToManifest(sdkBlock),
54849
- dataLoaders: sdkBlock.dataLoaders
54999
+ "--site-style-transition-from": boundary.cssVars.from,
55000
+ "--site-style-transition-to": boundary.cssVars.to
54850
55001
  };
54851
55002
  }
54852
- //#endregion
54853
- //#region ../blocks/src/customBlockRegistry.ts
54854
- const defaultCustomBlockSourcePolicy = { kind: "canonical-db-fallback-sdk" };
54855
- function isCustomBlockKind(blockKind) {
54856
- return blockKind.startsWith("custom.");
54857
- }
54858
- function transformToBlockDescriptor(sdkBlock, source = "sdk") {
55003
+ function boundaryReserveCssVarsStyle(input) {
55004
+ const before = input.before?.metrics.reserveCss ?? null;
55005
+ const after = input.after?.metrics.reserveCss ?? null;
55006
+ if (!before && !after) return void 0;
54859
55007
  return {
54860
- name: sdkBlock.id,
54861
- title: sdkBlock.title,
54862
- description: sdkBlock.description,
54863
- category: sdkBlock.category,
54864
- tags: sdkBlock.tags,
54865
- icon: sdkBlock.icon,
54866
- definition: transformSdkBlockToDefinition(sdkBlock),
54867
- source
55008
+ ...before ? { "--site-style-boundary-before-reserve": before } : {},
55009
+ ...after ? { "--site-style-boundary-after-reserve": after } : {}
54868
55010
  };
54869
55011
  }
54870
- function toResolvedCustomBlock(manifest, source) {
55012
+ function transitionCssVarsStyle(content) {
55013
+ const transitionStyles = isObjectRecord$1(content._transitionStyles) ? content._transitionStyles : null;
55014
+ const cssVars = isObjectRecord$1(transitionStyles?.cssVars) ? transitionStyles.cssVars : null;
55015
+ const from = typeof cssVars?.from === "string" ? cssVars.from : null;
55016
+ const to = typeof cssVars?.to === "string" ? cssVars.to : null;
55017
+ if (!from && !to) return void 0;
54871
55018
  return {
54872
- blockKind: manifest.id,
54873
- manifest: transformSdkBlockToManifest(manifest),
54874
- source,
54875
- descriptor: transformToBlockDescriptor(manifest, source.kind === "managed-database" ? "database" : "sdk")
55019
+ ...from ? { "--site-style-transition-from": from } : {},
55020
+ ...to ? { "--site-style-transition-to": to } : {}
54876
55021
  };
54877
55022
  }
54878
- function planCustomBlockRegistryResolution({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy }) {
54879
- switch (policy.kind) {
54880
- case "canonical-db-fallback-sdk": {
54881
- const entriesByKind = /* @__PURE__ */ new Map();
54882
- const conflicts = [];
54883
- for (const customBlock of customBlocks) entriesByKind.set(customBlock.manifest.id, toResolvedCustomBlock(customBlock.manifest, customBlock.source));
54884
- for (const sdkBlock of sdkConfig?.customBlocks ?? []) {
54885
- const existing = entriesByKind.get(sdkBlock.id);
54886
- if (existing) {
54887
- conflicts.push({
54888
- kind: "conflict",
54889
- blockKind: existing.blockKind,
54890
- winner: existing.source,
54891
- loser: { kind: "sdk-config" },
54892
- reason: "db-canonical-sdk-fallback"
54893
- });
54894
- continue;
54895
- }
54896
- entriesByKind.set(sdkBlock.id, toResolvedCustomBlock(sdkBlock, { kind: "sdk-config" }));
54897
- }
54898
- return {
54899
- policy,
54900
- entries: Array.from(entriesByKind.values()),
54901
- conflicts
54902
- };
54903
- }
54904
- }
54905
- }
54906
- function createCustomBlockRegistry({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy, onConflict }) {
54907
- const plan = planCustomBlockRegistryResolution({
54908
- sdkConfig,
54909
- customBlocks,
54910
- policy
54911
- });
54912
- const entriesByKind = new Map(plan.entries.map((entry) => [entry.blockKind, entry]));
54913
- for (const conflict of plan.conflicts) onConflict?.(`Using ${sourceLabel(conflict.winner)} custom block "${conflict.blockKind}" - ${sourceLabel(conflict.loser)} block is fallback only`);
55023
+ function mergeStyleObjects(left, right) {
55024
+ if (!left) return right;
55025
+ if (!right) return left;
54914
55026
  return {
54915
- entries: plan.entries,
54916
- conflicts: plan.conflicts,
54917
- findManifest: (blockKind) => {
54918
- if (!isCustomBlockKind(blockKind)) return void 0;
54919
- return entriesByKind.get(blockKind);
54920
- }
55027
+ ...left,
55028
+ ...right
54921
55029
  };
54922
55030
  }
54923
- function sourceLabel(source) {
54924
- switch (source.kind) {
54925
- case "managed-database": return "DB";
54926
- case "sdk-synced": return "SDK-synced DB";
54927
- case "sdk-config": return "SDK config";
54928
- default: return assertNever$4(source);
54929
- }
55031
+ function pageBlockPosition(index, blockCount) {
55032
+ if (blockCount <= 1) return "only";
55033
+ if (index === 0) return "first";
55034
+ if (index === blockCount - 1) return "last";
55035
+ return "middle";
54930
55036
  }
54931
55037
  //#endregion
54932
55038
  //#region ../blocks/src/PageRenderer.tsx
54933
- function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = false, dataContext, wrapBlock, wrapBoundary, registry, themeTokens: providedThemeTokens, routeMap, blockOverrides, sdkConfig, customBlocks, previewAuthoring }) {
55039
+ function PageRenderer$1(props) {
55040
+ const { page, runtimeBoundaries, usePlaceholders = false, dataContext, wrapBlock, wrapBoundary, registry, routeMap, blockOverrides, sdkConfig, customBlocks, previewAuthoring } = props;
54934
55041
  const imageResolveContext = React$1.useMemo(() => resolvePageRendererImageResolveContext(dataContext), [
54935
55042
  dataContext?.imageResolveContext,
54936
55043
  dataContext?.mediaAssets,
@@ -54939,12 +55046,16 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
54939
55046
  ]);
54940
55047
  const boundaryByAdjacentBlockIds = React$1.useMemo(() => boundaryMapForAdjacentBlockIds(runtimeBoundaries ?? []), [runtimeBoundaries]);
54941
55048
  const usesRuntimeBoundaries = runtimeBoundaries !== void 0;
55049
+ const themeResources = React$1.useMemo(() => resolvePageThemeResources(props), [
55050
+ props.rendering,
55051
+ props.theme,
55052
+ props.themeTokens
55053
+ ]);
54942
55054
  if (!page || page.blocks.length === 0) return /* @__PURE__ */ jsx("div", {
54943
55055
  className: "rb-p-6 rb-caption",
54944
55056
  style: textColorStyle("mutedText"),
54945
55057
  children: "No blocks found."
54946
55058
  });
54947
- const themeTokens = providedThemeTokens ?? buildThemeRuntime$1(theme).tokens;
54948
55059
  const resolvedRegistry = registry ?? getDefaultComponentRegistry();
54949
55060
  setContextResolveImageUrlContext(imageResolveContext);
54950
55061
  return /* @__PURE__ */ jsx("div", { children: page.blocks.map((block, index) => {
@@ -54967,22 +55078,14 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
54967
55078
  const renderableContent = getRenderableContent(block, dataContext?.previewStage);
54968
55079
  const variantKey = definition?.manifest ? resolveVariantKey(definition.manifest, renderableContent) : null;
54969
55080
  const shouldUseWrapper = !managesOwnWrapper || Boolean(wrapBlock);
54970
- const blockSectionProps = {
54971
- themeTokens,
54972
- themeConfig: theme,
55081
+ const blockSectionProps = buildBlockSectionProps({
55082
+ props,
55083
+ themeResources,
54973
55084
  block,
54974
- usePlaceholders,
54975
- dataContext,
54976
55085
  blockKey,
54977
- registry: resolvedRegistry,
54978
- routeMap,
54979
- wrapBlock,
54980
- blockOverrides,
54981
- sdkConfig,
54982
- customBlocks,
54983
55086
  imageResolveContext,
54984
- previewAuthoring
54985
- };
55087
+ registry: resolvedRegistry
55088
+ });
54986
55089
  if (!shouldUseWrapper) {
54987
55090
  const rendered = /* @__PURE__ */ jsx(MemoBlockSection, { ...blockSectionProps }, `${blockKey}:block`);
54988
55091
  return boundaryElement ? /* @__PURE__ */ jsxs(React$1.Fragment, { children: [rendered, boundaryElement] }, blockKey) : rendered;
@@ -55024,81 +55127,6 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
55024
55127
  })] }, blockKey);
55025
55128
  }) });
55026
55129
  }
55027
- function isSiteStyleTransitionStyleGroup(value) {
55028
- return value?.startsWith("site-style-transition-") === true;
55029
- }
55030
- function boundaryMapForAdjacentBlockIds(boundaries) {
55031
- return new Map(boundaries.map((boundary) => [boundaryKey(boundary.previousBlockId, boundary.nextBlockId), boundary]));
55032
- }
55033
- function boundaryKey(previousBlockId, nextBlockId) {
55034
- return `${previousBlockId}\u0000${nextBlockId}`;
55035
- }
55036
- function boundaryBetweenBlocks(previousBlock, nextBlock, boundaryByAdjacentBlockIds) {
55037
- const previousBlockId = previousBlock?.id ?? null;
55038
- const nextBlockId = nextBlock?.id ?? null;
55039
- if (!previousBlockId || !nextBlockId) return null;
55040
- return boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId)) ?? null;
55041
- }
55042
- function renderBoundaryAfterBlock(input) {
55043
- const previousBlockId = input.block.id;
55044
- const nextBlockId = input.nextBlock?.id ?? null;
55045
- if (!previousBlockId || !nextBlockId) return null;
55046
- const boundary = input.boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId));
55047
- if (!boundary) return null;
55048
- const rendered = /* @__PURE__ */ jsx("div", {
55049
- "aria-hidden": "true",
55050
- "data-block-boundary": "",
55051
- "data-boundary-id": boundary.boundaryId,
55052
- "data-boundary-previous-block-id": boundary.previousBlockId,
55053
- "data-boundary-next-block-id": boundary.nextBlockId,
55054
- "data-style-group": boundary.styleGroup,
55055
- style: boundaryCssVarsStyle(boundary)
55056
- }, `${input.blockKey}:boundary`);
55057
- return input.wrapBoundary ? input.wrapBoundary(boundary, rendered) : rendered;
55058
- }
55059
- function boundaryCssVarsStyle(boundary) {
55060
- return {
55061
- "--site-style-transition-from": boundary.cssVars.from,
55062
- "--site-style-transition-to": boundary.cssVars.to
55063
- };
55064
- }
55065
- function boundaryReserveCssVarsStyle(input) {
55066
- const before = input.before ? boundaryReserveValueForTreatment(input.before) : null;
55067
- const after = input.after ? boundaryReserveValueForTreatment(input.after) : null;
55068
- if (!before && !after) return void 0;
55069
- return {
55070
- ...before ? { "--site-style-boundary-before-reserve": before } : {},
55071
- ...after ? { "--site-style-boundary-after-reserve": after } : {}
55072
- };
55073
- }
55074
- function boundaryReserveValueForTreatment(boundary) {
55075
- return boundary.metrics.reserveCss;
55076
- }
55077
- function transitionCssVarsStyle(content) {
55078
- const transitionStyles = isObjectRecord$1(content._transitionStyles) ? content._transitionStyles : null;
55079
- const cssVars = isObjectRecord$1(transitionStyles?.cssVars) ? transitionStyles.cssVars : null;
55080
- const from = typeof cssVars?.from === "string" ? cssVars.from : null;
55081
- const to = typeof cssVars?.to === "string" ? cssVars.to : null;
55082
- if (!from && !to) return void 0;
55083
- return {
55084
- ...from ? { "--site-style-transition-from": from } : {},
55085
- ...to ? { "--site-style-transition-to": to } : {}
55086
- };
55087
- }
55088
- function mergeStyleObjects(left, right) {
55089
- if (!left) return right;
55090
- if (!right) return left;
55091
- return {
55092
- ...left,
55093
- ...right
55094
- };
55095
- }
55096
- function pageBlockPosition(index, blockCount) {
55097
- if (blockCount <= 1) return "only";
55098
- if (index === 0) return "first";
55099
- if (index === blockCount - 1) return "last";
55100
- return "middle";
55101
- }
55102
55130
  function resolvePageRendererImageResolveContext(dataContext) {
55103
55131
  const input = dataContext?.imageResolveContext;
55104
55132
  return buildResolveImageUrlContext({
@@ -55108,6 +55136,23 @@ function resolvePageRendererImageResolveContext(dataContext) {
55108
55136
  mediaAssets: input?.mediaAssets ?? dataContext?.mediaAssets
55109
55137
  });
55110
55138
  }
55139
+ function buildBlockSectionProps(input) {
55140
+ return {
55141
+ themeResources: input.themeResources,
55142
+ block: input.block,
55143
+ usePlaceholders: input.props.usePlaceholders ?? false,
55144
+ dataContext: input.props.dataContext,
55145
+ blockKey: input.blockKey,
55146
+ registry: input.registry,
55147
+ routeMap: input.props.routeMap,
55148
+ wrapBlock: input.props.wrapBlock,
55149
+ blockOverrides: input.props.blockOverrides,
55150
+ sdkConfig: input.props.sdkConfig,
55151
+ customBlocks: input.props.customBlocks,
55152
+ imageResolveContext: input.imageResolveContext,
55153
+ previewAuthoring: input.props.previewAuthoring
55154
+ };
55155
+ }
55111
55156
  /**
55112
55157
  * Look up a block override component by block kind.
55113
55158
  * Supports both full ("block.hero") and short ("hero") keys.
@@ -55174,7 +55219,7 @@ function getCachedValidator(manifest, flavour) {
55174
55219
  * referential equality of all props that affect rendering. Standard React.memo
55175
55220
  * wouldn't catch all the render triggers from the editor store.
55176
55221
  */
55177
- const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, themeConfig, block, usePlaceholders, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
55222
+ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources, block, usePlaceholders, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
55178
55223
  const perfStart = globalThis.process?.env?.DEBUG_PERF === "1" && typeof window === "undefined" ? Date.now() : 0;
55179
55224
  const fallbackImageResolveContext = getCurrentResolveImageUrlContext();
55180
55225
  const resolvedImageResolveContext = imageResolveContext ?? fallbackImageResolveContext;
@@ -55195,6 +55240,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
55195
55240
  return node;
55196
55241
  }
55197
55242
  const OverrideComponent = getBlockOverride(block.kind, blockOverrides);
55243
+ requireBlockOverride(themeResources, OverrideComponent, block.kind);
55198
55244
  let definition = getBlockDefinition(block.kind);
55199
55245
  if (!definition && block.kind.startsWith("custom.")) definition = createCustomBlockRegistry({
55200
55246
  sdkConfig,
@@ -55207,8 +55253,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
55207
55253
  if (OverrideComponent) {
55208
55254
  const rendered = /* @__PURE__ */ jsx(OverrideComponent, {
55209
55255
  content: getRenderableContent(block, dataContext?.previewStage),
55210
- theme: themeTokens,
55211
- themeConfig,
55256
+ ...overrideThemeProps(themeResources),
55212
55257
  data: void 0,
55213
55258
  siteId: dataContext?.siteId,
55214
55259
  apiBaseUrl: dataContext?.apiBaseUrl,
@@ -55307,8 +55352,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
55307
55352
  const hasResolvedData = !!resolved && typeof resolved === "object" && Object.keys(resolved).length > 0;
55308
55353
  const baseProps = {
55309
55354
  content: hydratedContent,
55310
- theme: themeTokens,
55311
- themeConfig,
55355
+ ...overrideThemeProps(themeResources),
55312
55356
  data: resolved,
55313
55357
  siteId: dataContext?.siteId,
55314
55358
  apiBaseUrl: dataContext?.apiBaseUrl,
@@ -55328,6 +55372,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
55328
55372
  let rendered;
55329
55373
  if (OverrideComponent) rendered = /* @__PURE__ */ jsx(OverrideComponent, { ...baseProps });
55330
55374
  else {
55375
+ requireThemeResources(themeResources, block.kind);
55331
55376
  const BlockComponent = getCachedBlockComponent(definition.manifest);
55332
55377
  const pathBase = typeof block.id === "string" && block.id.length > 0 ? `blocks.${block.id}.` : void 0;
55333
55378
  const rootContext = { $root: {
@@ -55377,7 +55422,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
55377
55422
  });
55378
55423
  }
55379
55424
  }, (prev, next) => {
55380
- return prev.block === next.block && prev.registry === next.registry && prev.dataContext === next.dataContext && prev.themeTokens === next.themeTokens && prev.themeConfig === next.themeConfig && prev.routeMap === next.routeMap && prev.usePlaceholders === next.usePlaceholders && prev.wrapBlock === next.wrapBlock && prev.blockOverrides === next.blockOverrides && prev.sdkConfig === next.sdkConfig && prev.customBlocks === next.customBlocks && prev.imageResolveContext === next.imageResolveContext && prev.previewAuthoring === next.previewAuthoring;
55425
+ return prev.block === next.block && prev.registry === next.registry && prev.dataContext === next.dataContext && prev.themeResources === next.themeResources && prev.routeMap === next.routeMap && prev.usePlaceholders === next.usePlaceholders && prev.wrapBlock === next.wrapBlock && prev.blockOverrides === next.blockOverrides && prev.sdkConfig === next.sdkConfig && prev.customBlocks === next.customBlocks && prev.imageResolveContext === next.imageResolveContext && prev.previewAuthoring === next.previewAuthoring;
55381
55426
  });
55382
55427
  function fallback(message) {
55383
55428
  return /* @__PURE__ */ jsx("div", {
@@ -68596,6 +68641,10 @@ function toBlocksImageResolveContextInput(context) {
68596
68641
  }
68597
68642
  //#endregion
68598
68643
  //#region src/rendering/blocks-page-renderer.ts
68644
+ const MissingBlockOverrideError = MissingBlockOverrideError$1;
68645
+ function isOverrideOnlyPageRenderer(props) {
68646
+ return props.rendering?.kind === "overrides-only";
68647
+ }
68599
68648
  function normalizeSdkCustomBlocks(customBlocks) {
68600
68649
  if (!customBlocks) return void 0;
68601
68650
  return customBlocks.map((block) => {
@@ -68626,15 +68675,23 @@ function toBlocksPageRendererDataContext(dataContext) {
68626
68675
  }
68627
68676
  function PageRenderer(props) {
68628
68677
  const blocksSdkConfig = props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig;
68629
- const blocksTheme = parseBlocksTheme(props.theme);
68630
- const blocksProps = {
68631
- ...props,
68632
- theme: blocksTheme,
68678
+ const { rendering: _rendering, theme: _theme, themeTokens: _themeTokens, ...commonProps } = props;
68679
+ const commonBlocksProps = {
68680
+ ...commonProps,
68633
68681
  dataContext: props.dataContext ? toBlocksPageRendererDataContext(props.dataContext) : void 0,
68634
68682
  blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
68635
68683
  sdkConfig: blocksSdkConfig,
68636
68684
  customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
68637
68685
  };
68686
+ const blocksProps = isOverrideOnlyPageRenderer(props) ? {
68687
+ ...commonBlocksProps,
68688
+ rendering: { kind: "overrides-only" },
68689
+ blockOverrides: toBlocksBlockOverrides(props.blockOverrides) ?? {}
68690
+ } : {
68691
+ ...commonBlocksProps,
68692
+ theme: parseBlocksTheme(props.theme),
68693
+ themeTokens: props.themeTokens
68694
+ };
68638
68695
  return React$1.createElement(PageRenderer$1, blocksProps);
68639
68696
  }
68640
68697
  //#endregion
@@ -68676,57 +68733,85 @@ function renderWithSdkThemeRuntime({ themeRuntime, theme, children }) {
68676
68733
  default: return assertNever$4(themeRuntime);
68677
68734
  }
68678
68735
  }
68736
+ function renderWithOverrideOnlyRuntime({ runtime, children }) {
68737
+ switch (runtime.kind) {
68738
+ case "responsive-only": return /* @__PURE__ */ jsx(ResponsiveScope, {
68739
+ responsiveMode: runtime.responsiveMode,
68740
+ children
68741
+ });
68742
+ case "none": return /* @__PURE__ */ jsx(Fragment, { children });
68743
+ default: return assertNever$4(runtime);
68744
+ }
68745
+ }
68679
68746
  //#endregion
68680
68747
  //#region src/rendering/components/pageShared.tsx
68681
- function PageContent({ page, runtimeBoundaries, theme, themeTokens: providedTokens, siteId, resolvedData, bookingOfferingPresets, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, usePlaceholders = false, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext, themeRuntime = defaultPageThemeRuntime }) {
68682
- const baseTokens = providedTokens ?? buildThemeRuntime(theme).tokens;
68683
- return renderWithSdkThemeRuntime({
68684
- themeRuntime,
68685
- theme,
68686
- children: /* @__PURE__ */ jsx(PageRenderer, {
68687
- theme,
68688
- page,
68689
- runtimeBoundaries,
68690
- themeTokens: sdkConfig?.theme?.palette ? {
68691
- ...baseTokens,
68692
- palette: {
68693
- ...baseTokens.palette,
68694
- ...sdkConfig.theme.palette
68695
- }
68696
- } : baseTokens,
68697
- usePlaceholders,
68698
- dataContext: {
68748
+ function isOverrideOnlyPage(props) {
68749
+ return props.rendering?.kind === "overrides-only";
68750
+ }
68751
+ function resolvePageThemeTokens(props) {
68752
+ const baseTokens = props.themeTokens ?? buildThemeRuntime(props.theme).tokens;
68753
+ return props.sdkConfig?.theme?.palette ? {
68754
+ ...baseTokens,
68755
+ palette: {
68756
+ ...baseTokens.palette,
68757
+ ...props.sdkConfig.theme.palette
68758
+ }
68759
+ } : baseTokens;
68760
+ }
68761
+ function PageContent(props) {
68762
+ const { page, runtimeBoundaries, siteId, resolvedData, bookingOfferingPresets, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, usePlaceholders = false, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext } = props;
68763
+ const rendererCommonProps = {
68764
+ page,
68765
+ runtimeBoundaries,
68766
+ usePlaceholders,
68767
+ dataContext: {
68768
+ siteId,
68769
+ apiBaseUrl,
68770
+ portalToken,
68771
+ previewToken,
68772
+ resolvedData,
68773
+ bookingOfferingPresets: bookingOfferingPresets ?? [],
68774
+ routes: routeMap,
68775
+ pagesByIdentifier,
68776
+ entriesByIdentifier,
68777
+ occurrenceContext: dataContext?.occurrenceContext ?? null,
68778
+ entrySubrouteContext: dataContext?.entrySubrouteContext ?? null,
68779
+ contentEntry: dataContext?.contentEntry ?? null,
68780
+ pageSurface: dataContext?.pageSurface ?? null,
68781
+ subject: dataContext?.subject ?? null,
68782
+ editableRouteMetadataFieldIds: dataContext?.editableRouteMetadataFieldIds ?? null,
68783
+ previewStage: dataContext?.previewStage,
68784
+ supabaseUrl,
68785
+ mediaAssets,
68786
+ imageResolveContext: {
68699
68787
  siteId,
68700
- apiBaseUrl,
68701
- portalToken,
68702
- previewToken,
68703
- resolvedData,
68704
- bookingOfferingPresets: bookingOfferingPresets ?? [],
68705
- routes: routeMap,
68706
- pagesByIdentifier,
68707
- entriesByIdentifier,
68708
- occurrenceContext: dataContext?.occurrenceContext ?? null,
68709
- entrySubrouteContext: dataContext?.entrySubrouteContext ?? null,
68710
- contentEntry: dataContext?.contentEntry ?? null,
68711
- pageSurface: dataContext?.pageSurface ?? null,
68712
- subject: dataContext?.subject ?? null,
68713
- editableRouteMetadataFieldIds: dataContext?.editableRouteMetadataFieldIds ?? null,
68714
- previewStage: dataContext?.previewStage,
68715
68788
  supabaseUrl,
68716
- mediaAssets,
68717
- imageResolveContext: {
68718
- siteId,
68719
- supabaseUrl,
68720
- mediaAssets
68721
- }
68722
- },
68723
- routeMap,
68724
- wrapBlock,
68725
- registry,
68726
- blockOverrides,
68727
- sdkConfig: sdkConfig ? { customBlocks: sdkConfig.customBlocks } : null,
68728
- customBlocks
68729
- })
68789
+ mediaAssets
68790
+ }
68791
+ },
68792
+ routeMap,
68793
+ wrapBlock,
68794
+ registry,
68795
+ sdkConfig: sdkConfig ? { customBlocks: sdkConfig.customBlocks } : null,
68796
+ customBlocks
68797
+ };
68798
+ const content = isOverrideOnlyPage(props) ? /* @__PURE__ */ jsx(PageRenderer, {
68799
+ ...rendererCommonProps,
68800
+ rendering: { kind: "overrides-only" },
68801
+ blockOverrides: props.blockOverrides
68802
+ }) : /* @__PURE__ */ jsx(PageRenderer, {
68803
+ ...rendererCommonProps,
68804
+ theme: props.theme,
68805
+ themeTokens: resolvePageThemeTokens(props),
68806
+ blockOverrides
68807
+ });
68808
+ return isOverrideOnlyPage(props) ? renderWithOverrideOnlyRuntime({
68809
+ runtime: props.rendering.runtime,
68810
+ children: content
68811
+ }) : renderWithSdkThemeRuntime({
68812
+ themeRuntime: props.themeRuntime ?? defaultPageThemeRuntime,
68813
+ theme: props.theme,
68814
+ children: content
68730
68815
  });
68731
68816
  }
68732
68817
  //#endregion
@@ -69205,12 +69290,48 @@ function buildLogo(logo, fallbackAlt) {
69205
69290
  return result;
69206
69291
  }
69207
69292
  //#endregion
69293
+ //#region src/rendering/renderingMode.ts
69294
+ const defaultOverrideOnlyRuntime = { kind: "responsive-only" };
69295
+ //#endregion
69208
69296
  //#region src/rendering/components/Layout.tsx
69209
69297
  /**
69210
69298
  * Layout component with header and footer
69211
69299
  *
69212
69300
  * Renders site header and footer around content. Fetches site data if not provided.
69213
69301
  */
69302
+ function isOverrideOnlyLayout(props) {
69303
+ return props.rendering?.kind === "overrides-only";
69304
+ }
69305
+ var UnsupportedOverrideOnlyLayoutChromeError = class extends Error {
69306
+ constructor(surface) {
69307
+ super(`Override-only Layout requires a custom or disabled ${surface}; SDK default chrome is unavailable.`);
69308
+ this.surface = surface;
69309
+ this.code = "unsupported_override_only_layout_chrome";
69310
+ this.name = "UnsupportedOverrideOnlyLayoutChromeError";
69311
+ }
69312
+ };
69313
+ async function resolveLayoutSiteData(props) {
69314
+ if (props.siteData) return props.siteData;
69315
+ if (!props.client) throw new Error("Layout: must provide either siteData or client");
69316
+ if (!props.siteId && !props.slug && !props.domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
69317
+ return props.client.getSite({
69318
+ id: props.siteId,
69319
+ slug: props.slug,
69320
+ domain: props.domain
69321
+ });
69322
+ }
69323
+ function renderOverrideOnlyLayout(props, data) {
69324
+ if (data.header === true) throw new UnsupportedOverrideOnlyLayoutChromeError("header");
69325
+ if (data.footer === true) throw new UnsupportedOverrideOnlyLayoutChromeError("footer");
69326
+ return renderWithOverrideOnlyRuntime({
69327
+ runtime: props.rendering.runtime ?? defaultOverrideOnlyRuntime,
69328
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
69329
+ typeof props.header === "function" ? props.header(data.headerData) : null,
69330
+ props.children,
69331
+ typeof props.footer === "function" ? props.footer(data.footerData) : null
69332
+ ] })
69333
+ });
69334
+ }
69214
69335
  /**
69215
69336
  * Layout component that wraps content with site header and footer.
69216
69337
  *
@@ -69246,20 +69367,13 @@ function buildLogo(logo, fallbackAlt) {
69246
69367
  * </Layout>
69247
69368
  * ```
69248
69369
  */
69249
- async function Layout({ siteData: providedSiteData, client, siteId, slug, domain, children, header = true, footer = true, headerVariant, hasPortalSession = false, previewStage = "published", themeRuntime }) {
69250
- let siteData = providedSiteData;
69251
- if (!siteData) {
69252
- if (!client) throw new Error("Layout: must provide either siteData or client");
69253
- if (!siteId && !slug && !domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
69254
- siteData = await client.getSite({
69255
- id: siteId,
69256
- slug,
69257
- domain
69258
- });
69259
- }
69260
- const { site, theme, navigation, layout, routes } = siteData;
69370
+ async function Layout(props) {
69371
+ const { children, hasPortalSession = false, previewStage = "published" } = props;
69372
+ const header = props.header ?? true;
69373
+ const footer = props.footer ?? true;
69374
+ const siteData = await resolveLayoutSiteData(props);
69375
+ const { site, navigation, layout, routes } = siteData;
69261
69376
  const footerBlocks = siteData.footerBlocks ?? [];
69262
- const builtThemeRuntime = buildThemeRuntime(theme);
69263
69377
  const navigationOptions = {
69264
69378
  hasPortalSession,
69265
69379
  previewStage,
@@ -69273,22 +69387,38 @@ async function Layout({ siteData: providedSiteData, client, siteId, slug, domain
69273
69387
  const footerMenuViewModel = buildFooterMenu(navigation, routes, navigationOptions);
69274
69388
  const legalFooterMenuViewModel = buildFooterMenuForRole(navigation, routes, "legal-policy", navigationOptions);
69275
69389
  const logoViewModel = buildLogo(layout.logo ?? null, site.title);
69276
- const headerData = {
69390
+ const customHeaderData = {
69277
69391
  menu: menuViewModel,
69278
69392
  logo: logoViewModel,
69279
69393
  site,
69280
- theme,
69281
69394
  routes
69282
69395
  };
69283
- const footerData = {
69396
+ const customFooterData = {
69284
69397
  menu: menuViewModel,
69285
69398
  footerMenu: footerMenuViewModel,
69286
69399
  legalFooterMenu: legalFooterMenuViewModel,
69287
69400
  logo: logoViewModel,
69288
69401
  site,
69289
- theme,
69290
69402
  routes
69291
69403
  };
69404
+ if (isOverrideOnlyLayout(props)) return renderOverrideOnlyLayout(props, {
69405
+ header: props.header ?? true,
69406
+ footer: props.footer ?? true,
69407
+ headerData: customHeaderData,
69408
+ footerData: customFooterData
69409
+ });
69410
+ const { theme } = siteData;
69411
+ const builtThemeRuntime = buildThemeRuntime(theme);
69412
+ const headerVariant = props.headerVariant;
69413
+ const themeRuntime = props.themeRuntime;
69414
+ const headerData = {
69415
+ ...customHeaderData,
69416
+ theme
69417
+ };
69418
+ const footerData = {
69419
+ ...customFooterData,
69420
+ theme
69421
+ };
69292
69422
  const headerContent = headerVariant ? {
69293
69423
  ...layout.header,
69294
69424
  variant: headerVariant
@@ -72353,6 +72483,17 @@ async function prefetchBlockDataWithDeps(deps, page, context, client, options) {
72353
72483
  }
72354
72484
  //#endregion
72355
72485
  //#region src/rendering/components/Block.shared.tsx
72486
+ function isOverrideOnlyBlock(props) {
72487
+ return props.rendering?.kind === "overrides-only";
72488
+ }
72489
+ var MissingStandaloneBlockOverrideError = class extends Error {
72490
+ constructor(blockKind) {
72491
+ super(`Override-only standalone rendering requires an override for block kind "${blockKind}".`);
72492
+ this.blockKind = blockKind;
72493
+ this.code = "missing_standalone_block_override";
72494
+ this.name = "MissingStandaloneBlockOverrideError";
72495
+ }
72496
+ };
72356
72497
  function renderUnknownBlock(blockKind) {
72357
72498
  return /* @__PURE__ */ jsx("div", {
72358
72499
  className: "p-4 border border-red-300 bg-red-50 rounded",
@@ -72415,14 +72556,16 @@ function buildStandaloneBlockViewModel({ siteId, pageId, previewStage, apiBaseUr
72415
72556
  function renderBlockOverride({ OverrideComponent, props, runtime, resolvedData }) {
72416
72557
  return /* @__PURE__ */ jsx(OverrideComponent, {
72417
72558
  content: props.content,
72418
- theme: runtime.themeRuntime.tokens,
72419
- themeConfig: props.theme,
72559
+ ...runtime && "theme" in props ? {
72560
+ theme: runtime.themeRuntime.tokens,
72561
+ themeConfig: props.theme
72562
+ } : {},
72420
72563
  data: resolvedData,
72421
72564
  siteId: props.siteId,
72422
72565
  apiBaseUrl: props.apiBaseUrl,
72423
72566
  portalToken: props.portalToken ?? null,
72424
72567
  supabaseUrl: props.supabaseUrl,
72425
- imageResolveContext: runtime.imageResolveContext,
72568
+ imageResolveContext: runtime?.imageResolveContext,
72426
72569
  blockId: props.blockId ?? null,
72427
72570
  blockKind: props.blockKind
72428
72571
  });
@@ -72451,8 +72594,8 @@ function renderManifestBlock({ definition, props, runtime, resolvedData }) {
72451
72594
  async function BlockContent(props) {
72452
72595
  const definition = getBlockDefinition(props.blockKind);
72453
72596
  const OverrideComponent = props.override;
72597
+ if (isOverrideOnlyBlock(props) && !OverrideComponent) throw new MissingStandaloneBlockOverrideError(props.blockKind);
72454
72598
  if (!definition && !OverrideComponent) return renderUnknownBlock(props.blockKind);
72455
- const runtime = buildBlockContentRuntime(props);
72456
72599
  const resolvedData = await loadStandaloneBlockData({
72457
72600
  ...props,
72458
72601
  hasDefinition: Boolean(definition)
@@ -72460,13 +72603,14 @@ async function BlockContent(props) {
72460
72603
  if (OverrideComponent) return renderBlockOverride({
72461
72604
  OverrideComponent,
72462
72605
  props,
72463
- runtime,
72606
+ runtime: isOverrideOnlyBlock(props) ? void 0 : buildBlockContentRuntime(props),
72464
72607
  resolvedData
72465
72608
  });
72609
+ if (isOverrideOnlyBlock(props)) throw new MissingStandaloneBlockOverrideError(props.blockKind);
72466
72610
  return renderManifestBlock({
72467
72611
  definition,
72468
72612
  props,
72469
- runtime,
72613
+ runtime: buildBlockContentRuntime(props),
72470
72614
  resolvedData
72471
72615
  });
72472
72616
  }
@@ -72583,4 +72727,4 @@ async function resolveBlockOverridesForPage(registrations, page) {
72583
72727
  return resolved;
72584
72728
  }
72585
72729
  //#endregion
72586
- export { Block, Layout, Page, buildPageBlockKindIndex, collectUsedBlockKindsFromPageOutline, defineBlockOverrideRegistrations, defineBlockOverrides, defineLazyBlockOverride, resolveBlockOverridesForPage };
72730
+ export { Block, Layout, MissingBlockOverrideError, Page, UnsupportedOverrideOnlyLayoutChromeError, buildPageBlockKindIndex, collectUsedBlockKindsFromPageOutline, defineBlockOverrideRegistrations, defineBlockOverrides, defineLazyBlockOverride, resolveBlockOverridesForPage };