@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
@@ -52051,6 +52051,213 @@ function collectConstrainedVideoMediaValues(options) {
52051
52051
  return values;
52052
52052
  }
52053
52053
  //#endregion
52054
+ //#region ../blocks/src/system/manifest/hydrateLinks.ts
52055
+ /**
52056
+ * Hydrates link objects within block content using the provided route map. Returns
52057
+ * the original content reference when no mutations are required to avoid unnecessary renders.
52058
+ */
52059
+ function hydrateManifestLinks(manifest, content, routes, pagesByIdentifier, entriesByIdentifier) {
52060
+ if (!routes || !manifest?.fields?.length) return content;
52061
+ return hydrateValue(content, {
52062
+ routes,
52063
+ pagesByIdentifier,
52064
+ entriesByIdentifier
52065
+ });
52066
+ }
52067
+ function hydrateValue(value, context) {
52068
+ try {
52069
+ if (Array.isArray(value)) {
52070
+ const resolvedItems = value.map((item) => hydrateValue(item, context));
52071
+ return resolvedItems.every((item, index) => item === value[index]) ? value : resolvedItems;
52072
+ }
52073
+ if (isRecord$27(value)) {
52074
+ if (isInternalLink$1(value)) return hydrateInternalLink(value, context.routes);
52075
+ if (isPageLink$1(value)) return hydratePageLink(value, context);
52076
+ if (isEntryLink$1(value)) return hydrateEntryLink(value, context);
52077
+ const resolvedEntries = Object.entries(value).map(([key, entry]) => [key, hydrateValue(entry, context)]);
52078
+ return resolvedEntries.every(([key, entry]) => entry === value[key]) ? value : Object.fromEntries(resolvedEntries);
52079
+ }
52080
+ return value;
52081
+ } catch (err) {
52082
+ console.error("[hydrateLinks] Error hydrating value:", err, value);
52083
+ return value;
52084
+ }
52085
+ }
52086
+ function hydrateInternalLink(link, routes) {
52087
+ const resolved = resolveRouteTarget(link.routeId, routes);
52088
+ if (!resolved) return link;
52089
+ const nextHref = resolved.href;
52090
+ const currentHref = typeof link.href === "string" && link.href.length > 0 ? link.href : null;
52091
+ const nextUpdatedAt = resolved.updatedAt;
52092
+ const updates = {};
52093
+ if (nextHref && nextHref !== currentHref) updates.href = nextHref;
52094
+ if (nextUpdatedAt && link.updatedAt !== nextUpdatedAt) updates.updatedAt = nextUpdatedAt;
52095
+ return Object.keys(updates).length > 0 ? {
52096
+ ...link,
52097
+ ...updates
52098
+ } : link;
52099
+ }
52100
+ function isInternalLink$1(value) {
52101
+ if (value.kind !== "internal") return false;
52102
+ if (typeof value.routeId !== "string" || value.routeId.length === 0) return false;
52103
+ return true;
52104
+ }
52105
+ function isPageLink$1(value) {
52106
+ if (value.kind !== "page") return false;
52107
+ if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
52108
+ return true;
52109
+ }
52110
+ function hydratePageLink(link, context) {
52111
+ const resolved = resolvePageRouteTarget(link, context);
52112
+ if (!resolved) return link;
52113
+ return {
52114
+ ...link,
52115
+ href: resolved.href,
52116
+ routeId: resolved.routeId
52117
+ };
52118
+ }
52119
+ function isEntryLink$1(value) {
52120
+ if (value.kind !== "entry") return false;
52121
+ if (typeof value.contentType !== "string" || value.contentType.length === 0) return false;
52122
+ if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
52123
+ return true;
52124
+ }
52125
+ function hydrateEntryLink(link, context) {
52126
+ const resolved = resolveEntryRouteTarget(link, context);
52127
+ if (!resolved) return link;
52128
+ return {
52129
+ ...link,
52130
+ href: resolved.href,
52131
+ routeId: resolved.routeId
52132
+ };
52133
+ }
52134
+ //#endregion
52135
+ //#region ../blocks/src/sdkBlockTransform.ts
52136
+ /**
52137
+ * Transforms an SDK custom block into a BlockManifest.
52138
+ *
52139
+ * If the block has a `layout`, it can be rendered declaratively without React code.
52140
+ * If no layout, the block MUST use blockOverrides for rendering.
52141
+ */
52142
+ function transformSdkBlockToManifest(sdkBlock) {
52143
+ const hasLayout = Boolean(sdkBlock.layout) || Boolean(sdkBlock.variants && Object.keys(sdkBlock.variants).length > 0);
52144
+ return augmentManifest({
52145
+ name: sdkBlock.id,
52146
+ version: "1.0.0",
52147
+ title: sdkBlock.title,
52148
+ titleSource: sdkBlock.titleSource,
52149
+ description: sdkBlock.description,
52150
+ component: sdkBlock.id,
52151
+ fields: sdkBlock.fields,
52152
+ slots: [],
52153
+ category: sdkBlock.category,
52154
+ tags: sdkBlock.tags,
52155
+ icon: sdkBlock.icon,
52156
+ layout: sdkBlock.layout,
52157
+ variants: sdkBlock.variants,
52158
+ defaultVariant: sdkBlock.defaultVariant,
52159
+ variantOptions: sdkBlock.variantOptions,
52160
+ previewCustomize: sdkBlock.previewCustomize,
52161
+ behaviours: {
52162
+ supportsThemeSwitching: true,
52163
+ inlineEditing: hasLayout,
52164
+ animation: hasLayout,
52165
+ paletteHidden: false
52166
+ }
52167
+ });
52168
+ }
52169
+ /**
52170
+ * Transforms an SDK custom block into a SystemBlockDefinition.
52171
+ *
52172
+ * This creates a minimal definition with just the manifest - no data loaders
52173
+ * or content normalizers since SDK blocks handle their own rendering.
52174
+ */
52175
+ function transformSdkBlockToDefinition(sdkBlock) {
52176
+ return {
52177
+ manifest: transformSdkBlockToManifest(sdkBlock),
52178
+ dataLoaders: sdkBlock.dataLoaders
52179
+ };
52180
+ }
52181
+ //#endregion
52182
+ //#region ../blocks/src/customBlockRegistry.ts
52183
+ const defaultCustomBlockSourcePolicy = { kind: "canonical-db-fallback-sdk" };
52184
+ function isCustomBlockKind(blockKind) {
52185
+ return blockKind.startsWith("custom.");
52186
+ }
52187
+ function transformToBlockDescriptor(sdkBlock, source = "sdk") {
52188
+ return {
52189
+ name: sdkBlock.id,
52190
+ title: sdkBlock.title,
52191
+ description: sdkBlock.description,
52192
+ category: sdkBlock.category,
52193
+ tags: sdkBlock.tags,
52194
+ icon: sdkBlock.icon,
52195
+ definition: transformSdkBlockToDefinition(sdkBlock),
52196
+ source
52197
+ };
52198
+ }
52199
+ function toResolvedCustomBlock(manifest, source) {
52200
+ return {
52201
+ blockKind: manifest.id,
52202
+ manifest: transformSdkBlockToManifest(manifest),
52203
+ source,
52204
+ descriptor: transformToBlockDescriptor(manifest, source.kind === "managed-database" ? "database" : "sdk")
52205
+ };
52206
+ }
52207
+ function planCustomBlockRegistryResolution({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy }) {
52208
+ switch (policy.kind) {
52209
+ case "canonical-db-fallback-sdk": {
52210
+ const entriesByKind = /* @__PURE__ */ new Map();
52211
+ const conflicts = [];
52212
+ for (const customBlock of customBlocks) entriesByKind.set(customBlock.manifest.id, toResolvedCustomBlock(customBlock.manifest, customBlock.source));
52213
+ for (const sdkBlock of sdkConfig?.customBlocks ?? []) {
52214
+ const existing = entriesByKind.get(sdkBlock.id);
52215
+ if (existing) {
52216
+ conflicts.push({
52217
+ kind: "conflict",
52218
+ blockKind: existing.blockKind,
52219
+ winner: existing.source,
52220
+ loser: { kind: "sdk-config" },
52221
+ reason: "db-canonical-sdk-fallback"
52222
+ });
52223
+ continue;
52224
+ }
52225
+ entriesByKind.set(sdkBlock.id, toResolvedCustomBlock(sdkBlock, { kind: "sdk-config" }));
52226
+ }
52227
+ return {
52228
+ policy,
52229
+ entries: Array.from(entriesByKind.values()),
52230
+ conflicts
52231
+ };
52232
+ }
52233
+ }
52234
+ }
52235
+ function createCustomBlockRegistry({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy, onConflict }) {
52236
+ const plan = planCustomBlockRegistryResolution({
52237
+ sdkConfig,
52238
+ customBlocks,
52239
+ policy
52240
+ });
52241
+ const entriesByKind = new Map(plan.entries.map((entry) => [entry.blockKind, entry]));
52242
+ for (const conflict of plan.conflicts) onConflict?.(`Using ${sourceLabel(conflict.winner)} custom block "${conflict.blockKind}" - ${sourceLabel(conflict.loser)} block is fallback only`);
52243
+ return {
52244
+ entries: plan.entries,
52245
+ conflicts: plan.conflicts,
52246
+ findManifest: (blockKind) => {
52247
+ if (!isCustomBlockKind(blockKind)) return void 0;
52248
+ return entriesByKind.get(blockKind);
52249
+ }
52250
+ };
52251
+ }
52252
+ function sourceLabel(source) {
52253
+ switch (source.kind) {
52254
+ case "managed-database": return "DB";
52255
+ case "sdk-synced": return "SDK-synced DB";
52256
+ case "sdk-config": return "SDK config";
52257
+ default: return assertNever$24(source);
52258
+ }
52259
+ }
52260
+ //#endregion
52054
52261
  //#region ../theme-core/src/runtime/fontFamily.ts
52055
52262
  /**
52056
52263
  * Font Family Formatting Utilities
@@ -55788,215 +55995,115 @@ function mapFontStyle(italic) {
55788
55995
  return italic ? "italic" : "normal";
55789
55996
  }
55790
55997
  //#endregion
55791
- //#region ../blocks/src/system/manifest/hydrateLinks.ts
55792
- /**
55793
- * Hydrates link objects within block content using the provided route map. Returns
55794
- * the original content reference when no mutations are required to avoid unnecessary renders.
55795
- */
55796
- function hydrateManifestLinks(manifest, content, routes, pagesByIdentifier, entriesByIdentifier) {
55797
- if (!routes || !manifest?.fields?.length) return content;
55798
- return hydrateValue(content, {
55799
- routes,
55800
- pagesByIdentifier,
55801
- entriesByIdentifier
55802
- });
55803
- }
55804
- function hydrateValue(value, context) {
55805
- try {
55806
- if (Array.isArray(value)) {
55807
- const resolvedItems = value.map((item) => hydrateValue(item, context));
55808
- return resolvedItems.every((item, index) => item === value[index]) ? value : resolvedItems;
55809
- }
55810
- if (isRecord$27(value)) {
55811
- if (isInternalLink$1(value)) return hydrateInternalLink(value, context.routes);
55812
- if (isPageLink$1(value)) return hydratePageLink(value, context);
55813
- if (isEntryLink$1(value)) return hydrateEntryLink(value, context);
55814
- const resolvedEntries = Object.entries(value).map(([key, entry]) => [key, hydrateValue(entry, context)]);
55815
- return resolvedEntries.every(([key, entry]) => entry === value[key]) ? value : Object.fromEntries(resolvedEntries);
55816
- }
55817
- return value;
55818
- } catch (err) {
55819
- console.error("[hydrateLinks] Error hydrating value:", err, value);
55820
- return value;
55998
+ //#region ../blocks/src/pageRenderingMode.ts
55999
+ var MissingBlockOverrideError$1 = class extends Error {
56000
+ constructor(blockKind) {
56001
+ super(`Override-only rendering requires an override for block kind "${blockKind}".`);
56002
+ this.blockKind = blockKind;
56003
+ this.code = "missing_block_override";
56004
+ this.name = "MissingBlockOverrideError";
55821
56005
  }
56006
+ };
56007
+ function isOverrideOnlyResourceInput(props) {
56008
+ return props.rendering?.kind === "overrides-only";
55822
56009
  }
55823
- function hydrateInternalLink(link, routes) {
55824
- const resolved = resolveRouteTarget(link.routeId, routes);
55825
- if (!resolved) return link;
55826
- const nextHref = resolved.href;
55827
- const currentHref = typeof link.href === "string" && link.href.length > 0 ? link.href : null;
55828
- const nextUpdatedAt = resolved.updatedAt;
55829
- const updates = {};
55830
- if (nextHref && nextHref !== currentHref) updates.href = nextHref;
55831
- if (nextUpdatedAt && link.updatedAt !== nextUpdatedAt) updates.updatedAt = nextUpdatedAt;
55832
- return Object.keys(updates).length > 0 ? {
55833
- ...link,
55834
- ...updates
55835
- } : link;
55836
- }
55837
- function isInternalLink$1(value) {
55838
- if (value.kind !== "internal") return false;
55839
- if (typeof value.routeId !== "string" || value.routeId.length === 0) return false;
55840
- return true;
55841
- }
55842
- function isPageLink$1(value) {
55843
- if (value.kind !== "page") return false;
55844
- if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
55845
- return true;
55846
- }
55847
- function hydratePageLink(link, context) {
55848
- const resolved = resolvePageRouteTarget(link, context);
55849
- if (!resolved) return link;
56010
+ function resolvePageThemeResources(props) {
56011
+ if (isOverrideOnlyResourceInput(props)) return { kind: "unavailable" };
55850
56012
  return {
55851
- ...link,
55852
- href: resolved.href,
55853
- routeId: resolved.routeId
56013
+ kind: "available",
56014
+ tokens: props.themeTokens ?? buildThemeRuntime$1(props.theme).tokens,
56015
+ config: props.theme
55854
56016
  };
55855
56017
  }
55856
- function isEntryLink$1(value) {
55857
- if (value.kind !== "entry") return false;
55858
- if (typeof value.contentType !== "string" || value.contentType.length === 0) return false;
55859
- if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
55860
- return true;
56018
+ function requireBlockOverride(resources, override, blockKind) {
56019
+ if (resources.kind === "unavailable" && !override) throw new MissingBlockOverrideError$1(blockKind);
55861
56020
  }
55862
- function hydrateEntryLink(link, context) {
55863
- const resolved = resolveEntryRouteTarget(link, context);
55864
- if (!resolved) return link;
55865
- return {
55866
- ...link,
55867
- href: resolved.href,
55868
- routeId: resolved.routeId
55869
- };
56021
+ function overrideThemeProps(resources) {
56022
+ return resources.kind === "available" ? {
56023
+ theme: resources.tokens,
56024
+ themeConfig: resources.config
56025
+ } : {};
56026
+ }
56027
+ function requireThemeResources(resources, blockKind) {
56028
+ if (resources.kind === "unavailable") throw new MissingBlockOverrideError$1(blockKind);
56029
+ return resources;
55870
56030
  }
55871
56031
  //#endregion
55872
- //#region ../blocks/src/sdkBlockTransform.ts
55873
- /**
55874
- * Transforms an SDK custom block into a BlockManifest.
55875
- *
55876
- * If the block has a `layout`, it can be rendered declaratively without React code.
55877
- * If no layout, the block MUST use blockOverrides for rendering.
55878
- */
55879
- function transformSdkBlockToManifest(sdkBlock) {
55880
- const hasLayout = Boolean(sdkBlock.layout) || Boolean(sdkBlock.variants && Object.keys(sdkBlock.variants).length > 0);
55881
- return augmentManifest({
55882
- name: sdkBlock.id,
55883
- version: "1.0.0",
55884
- title: sdkBlock.title,
55885
- titleSource: sdkBlock.titleSource,
55886
- description: sdkBlock.description,
55887
- component: sdkBlock.id,
55888
- fields: sdkBlock.fields,
55889
- slots: [],
55890
- category: sdkBlock.category,
55891
- tags: sdkBlock.tags,
55892
- icon: sdkBlock.icon,
55893
- layout: sdkBlock.layout,
55894
- variants: sdkBlock.variants,
55895
- defaultVariant: sdkBlock.defaultVariant,
55896
- variantOptions: sdkBlock.variantOptions,
55897
- previewCustomize: sdkBlock.previewCustomize,
55898
- behaviours: {
55899
- supportsThemeSwitching: true,
55900
- inlineEditing: hasLayout,
55901
- animation: hasLayout,
55902
- paletteHidden: false
55903
- }
55904
- });
56032
+ //#region ../blocks/src/pageRendererBoundaries.tsx
56033
+ const boundaryKey = (previousBlockId, nextBlockId) => `${previousBlockId}\u0000${nextBlockId}`;
56034
+ function isSiteStyleTransitionStyleGroup(value) {
56035
+ return value?.startsWith("site-style-transition-") === true;
56036
+ }
56037
+ function boundaryMapForAdjacentBlockIds(boundaries) {
56038
+ return new Map(boundaries.map((boundary) => [boundaryKey(boundary.previousBlockId, boundary.nextBlockId), boundary]));
56039
+ }
56040
+ function boundaryBetweenBlocks(previousBlock, nextBlock, boundaries) {
56041
+ const previousBlockId = previousBlock?.id ?? null;
56042
+ const nextBlockId = nextBlock?.id ?? null;
56043
+ if (!previousBlockId || !nextBlockId) return null;
56044
+ return boundaries.get(boundaryKey(previousBlockId, nextBlockId)) ?? null;
56045
+ }
56046
+ function renderBoundaryAfterBlock(input) {
56047
+ const previousBlockId = input.block.id;
56048
+ const nextBlockId = input.nextBlock?.id ?? null;
56049
+ if (!previousBlockId || !nextBlockId) return null;
56050
+ const boundary = input.boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId));
56051
+ if (!boundary) return null;
56052
+ const rendered = /* @__PURE__ */ jsx("div", {
56053
+ "aria-hidden": "true",
56054
+ "data-block-boundary": "",
56055
+ "data-boundary-id": boundary.boundaryId,
56056
+ "data-boundary-previous-block-id": boundary.previousBlockId,
56057
+ "data-boundary-next-block-id": boundary.nextBlockId,
56058
+ "data-style-group": boundary.styleGroup,
56059
+ style: boundaryCssVarsStyle(boundary)
56060
+ }, `${input.blockKey}:boundary`);
56061
+ return input.wrapBoundary ? input.wrapBoundary(boundary, rendered) : rendered;
55905
56062
  }
55906
- /**
55907
- * Transforms an SDK custom block into a SystemBlockDefinition.
55908
- *
55909
- * This creates a minimal definition with just the manifest - no data loaders
55910
- * or content normalizers since SDK blocks handle their own rendering.
55911
- */
55912
- function transformSdkBlockToDefinition(sdkBlock) {
56063
+ function boundaryCssVarsStyle(boundary) {
55913
56064
  return {
55914
- manifest: transformSdkBlockToManifest(sdkBlock),
55915
- dataLoaders: sdkBlock.dataLoaders
56065
+ "--site-style-transition-from": boundary.cssVars.from,
56066
+ "--site-style-transition-to": boundary.cssVars.to
55916
56067
  };
55917
56068
  }
55918
- //#endregion
55919
- //#region ../blocks/src/customBlockRegistry.ts
55920
- const defaultCustomBlockSourcePolicy = { kind: "canonical-db-fallback-sdk" };
55921
- function isCustomBlockKind(blockKind) {
55922
- return blockKind.startsWith("custom.");
55923
- }
55924
- function transformToBlockDescriptor(sdkBlock, source = "sdk") {
56069
+ function boundaryReserveCssVarsStyle(input) {
56070
+ const before = input.before?.metrics.reserveCss ?? null;
56071
+ const after = input.after?.metrics.reserveCss ?? null;
56072
+ if (!before && !after) return void 0;
55925
56073
  return {
55926
- name: sdkBlock.id,
55927
- title: sdkBlock.title,
55928
- description: sdkBlock.description,
55929
- category: sdkBlock.category,
55930
- tags: sdkBlock.tags,
55931
- icon: sdkBlock.icon,
55932
- definition: transformSdkBlockToDefinition(sdkBlock),
55933
- source
56074
+ ...before ? { "--site-style-boundary-before-reserve": before } : {},
56075
+ ...after ? { "--site-style-boundary-after-reserve": after } : {}
55934
56076
  };
55935
56077
  }
55936
- function toResolvedCustomBlock(manifest, source) {
56078
+ function transitionCssVarsStyle(content) {
56079
+ const transitionStyles = isObjectRecord$1(content._transitionStyles) ? content._transitionStyles : null;
56080
+ const cssVars = isObjectRecord$1(transitionStyles?.cssVars) ? transitionStyles.cssVars : null;
56081
+ const from = typeof cssVars?.from === "string" ? cssVars.from : null;
56082
+ const to = typeof cssVars?.to === "string" ? cssVars.to : null;
56083
+ if (!from && !to) return void 0;
55937
56084
  return {
55938
- blockKind: manifest.id,
55939
- manifest: transformSdkBlockToManifest(manifest),
55940
- source,
55941
- descriptor: transformToBlockDescriptor(manifest, source.kind === "managed-database" ? "database" : "sdk")
56085
+ ...from ? { "--site-style-transition-from": from } : {},
56086
+ ...to ? { "--site-style-transition-to": to } : {}
55942
56087
  };
55943
56088
  }
55944
- function planCustomBlockRegistryResolution({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy }) {
55945
- switch (policy.kind) {
55946
- case "canonical-db-fallback-sdk": {
55947
- const entriesByKind = /* @__PURE__ */ new Map();
55948
- const conflicts = [];
55949
- for (const customBlock of customBlocks) entriesByKind.set(customBlock.manifest.id, toResolvedCustomBlock(customBlock.manifest, customBlock.source));
55950
- for (const sdkBlock of sdkConfig?.customBlocks ?? []) {
55951
- const existing = entriesByKind.get(sdkBlock.id);
55952
- if (existing) {
55953
- conflicts.push({
55954
- kind: "conflict",
55955
- blockKind: existing.blockKind,
55956
- winner: existing.source,
55957
- loser: { kind: "sdk-config" },
55958
- reason: "db-canonical-sdk-fallback"
55959
- });
55960
- continue;
55961
- }
55962
- entriesByKind.set(sdkBlock.id, toResolvedCustomBlock(sdkBlock, { kind: "sdk-config" }));
55963
- }
55964
- return {
55965
- policy,
55966
- entries: Array.from(entriesByKind.values()),
55967
- conflicts
55968
- };
55969
- }
55970
- }
55971
- }
55972
- function createCustomBlockRegistry({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy, onConflict }) {
55973
- const plan = planCustomBlockRegistryResolution({
55974
- sdkConfig,
55975
- customBlocks,
55976
- policy
55977
- });
55978
- const entriesByKind = new Map(plan.entries.map((entry) => [entry.blockKind, entry]));
55979
- for (const conflict of plan.conflicts) onConflict?.(`Using ${sourceLabel(conflict.winner)} custom block "${conflict.blockKind}" - ${sourceLabel(conflict.loser)} block is fallback only`);
56089
+ function mergeStyleObjects(left, right) {
56090
+ if (!left) return right;
56091
+ if (!right) return left;
55980
56092
  return {
55981
- entries: plan.entries,
55982
- conflicts: plan.conflicts,
55983
- findManifest: (blockKind) => {
55984
- if (!isCustomBlockKind(blockKind)) return void 0;
55985
- return entriesByKind.get(blockKind);
55986
- }
56093
+ ...left,
56094
+ ...right
55987
56095
  };
55988
56096
  }
55989
- function sourceLabel(source) {
55990
- switch (source.kind) {
55991
- case "managed-database": return "DB";
55992
- case "sdk-synced": return "SDK-synced DB";
55993
- case "sdk-config": return "SDK config";
55994
- default: return assertNever$24(source);
55995
- }
56097
+ function pageBlockPosition(index, blockCount) {
56098
+ if (blockCount <= 1) return "only";
56099
+ if (index === 0) return "first";
56100
+ if (index === blockCount - 1) return "last";
56101
+ return "middle";
55996
56102
  }
55997
56103
  //#endregion
55998
56104
  //#region ../blocks/src/PageRenderer.tsx
55999
- function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = false, dataContext, wrapBlock, wrapBoundary, registry, themeTokens: providedThemeTokens, routeMap, blockOverrides, sdkConfig, customBlocks, previewAuthoring }) {
56105
+ function PageRenderer$1(props) {
56106
+ const { page, runtimeBoundaries, usePlaceholders = false, dataContext, wrapBlock, wrapBoundary, registry, routeMap, blockOverrides, sdkConfig, customBlocks, previewAuthoring } = props;
56000
56107
  const imageResolveContext = React$1.useMemo(() => resolvePageRendererImageResolveContext(dataContext), [
56001
56108
  dataContext?.imageResolveContext,
56002
56109
  dataContext?.mediaAssets,
@@ -56005,12 +56112,16 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
56005
56112
  ]);
56006
56113
  const boundaryByAdjacentBlockIds = React$1.useMemo(() => boundaryMapForAdjacentBlockIds(runtimeBoundaries ?? []), [runtimeBoundaries]);
56007
56114
  const usesRuntimeBoundaries = runtimeBoundaries !== void 0;
56115
+ const themeResources = React$1.useMemo(() => resolvePageThemeResources(props), [
56116
+ props.rendering,
56117
+ props.theme,
56118
+ props.themeTokens
56119
+ ]);
56008
56120
  if (!page || page.blocks.length === 0) return /* @__PURE__ */ jsx("div", {
56009
56121
  className: "rb-p-6 rb-caption",
56010
56122
  style: textColorStyle("mutedText"),
56011
56123
  children: "No blocks found."
56012
56124
  });
56013
- const themeTokens = providedThemeTokens ?? buildThemeRuntime$1(theme).tokens;
56014
56125
  const resolvedRegistry = registry ?? getDefaultComponentRegistry();
56015
56126
  setContextResolveImageUrlContext(imageResolveContext);
56016
56127
  return /* @__PURE__ */ jsx("div", { children: page.blocks.map((block, index) => {
@@ -56033,22 +56144,14 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
56033
56144
  const renderableContent = getRenderableContent(block, dataContext?.previewStage);
56034
56145
  const variantKey = definition?.manifest ? resolveVariantKey(definition.manifest, renderableContent) : null;
56035
56146
  const shouldUseWrapper = !managesOwnWrapper || Boolean(wrapBlock);
56036
- const blockSectionProps = {
56037
- themeTokens,
56038
- themeConfig: theme,
56147
+ const blockSectionProps = buildBlockSectionProps({
56148
+ props,
56149
+ themeResources,
56039
56150
  block,
56040
- usePlaceholders,
56041
- dataContext,
56042
56151
  blockKey,
56043
- registry: resolvedRegistry,
56044
- routeMap,
56045
- wrapBlock,
56046
- blockOverrides,
56047
- sdkConfig,
56048
- customBlocks,
56049
56152
  imageResolveContext,
56050
- previewAuthoring
56051
- };
56153
+ registry: resolvedRegistry
56154
+ });
56052
56155
  if (!shouldUseWrapper) {
56053
56156
  const rendered = /* @__PURE__ */ jsx(MemoBlockSection, { ...blockSectionProps }, `${blockKey}:block`);
56054
56157
  return boundaryElement ? /* @__PURE__ */ jsxs(React$1.Fragment, { children: [rendered, boundaryElement] }, blockKey) : rendered;
@@ -56090,81 +56193,6 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
56090
56193
  })] }, blockKey);
56091
56194
  }) });
56092
56195
  }
56093
- function isSiteStyleTransitionStyleGroup(value) {
56094
- return value?.startsWith("site-style-transition-") === true;
56095
- }
56096
- function boundaryMapForAdjacentBlockIds(boundaries) {
56097
- return new Map(boundaries.map((boundary) => [boundaryKey(boundary.previousBlockId, boundary.nextBlockId), boundary]));
56098
- }
56099
- function boundaryKey(previousBlockId, nextBlockId) {
56100
- return `${previousBlockId}\u0000${nextBlockId}`;
56101
- }
56102
- function boundaryBetweenBlocks(previousBlock, nextBlock, boundaryByAdjacentBlockIds) {
56103
- const previousBlockId = previousBlock?.id ?? null;
56104
- const nextBlockId = nextBlock?.id ?? null;
56105
- if (!previousBlockId || !nextBlockId) return null;
56106
- return boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId)) ?? null;
56107
- }
56108
- function renderBoundaryAfterBlock(input) {
56109
- const previousBlockId = input.block.id;
56110
- const nextBlockId = input.nextBlock?.id ?? null;
56111
- if (!previousBlockId || !nextBlockId) return null;
56112
- const boundary = input.boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId));
56113
- if (!boundary) return null;
56114
- const rendered = /* @__PURE__ */ jsx("div", {
56115
- "aria-hidden": "true",
56116
- "data-block-boundary": "",
56117
- "data-boundary-id": boundary.boundaryId,
56118
- "data-boundary-previous-block-id": boundary.previousBlockId,
56119
- "data-boundary-next-block-id": boundary.nextBlockId,
56120
- "data-style-group": boundary.styleGroup,
56121
- style: boundaryCssVarsStyle(boundary)
56122
- }, `${input.blockKey}:boundary`);
56123
- return input.wrapBoundary ? input.wrapBoundary(boundary, rendered) : rendered;
56124
- }
56125
- function boundaryCssVarsStyle(boundary) {
56126
- return {
56127
- "--site-style-transition-from": boundary.cssVars.from,
56128
- "--site-style-transition-to": boundary.cssVars.to
56129
- };
56130
- }
56131
- function boundaryReserveCssVarsStyle(input) {
56132
- const before = input.before ? boundaryReserveValueForTreatment(input.before) : null;
56133
- const after = input.after ? boundaryReserveValueForTreatment(input.after) : null;
56134
- if (!before && !after) return void 0;
56135
- return {
56136
- ...before ? { "--site-style-boundary-before-reserve": before } : {},
56137
- ...after ? { "--site-style-boundary-after-reserve": after } : {}
56138
- };
56139
- }
56140
- function boundaryReserveValueForTreatment(boundary) {
56141
- return boundary.metrics.reserveCss;
56142
- }
56143
- function transitionCssVarsStyle(content) {
56144
- const transitionStyles = isObjectRecord$1(content._transitionStyles) ? content._transitionStyles : null;
56145
- const cssVars = isObjectRecord$1(transitionStyles?.cssVars) ? transitionStyles.cssVars : null;
56146
- const from = typeof cssVars?.from === "string" ? cssVars.from : null;
56147
- const to = typeof cssVars?.to === "string" ? cssVars.to : null;
56148
- if (!from && !to) return void 0;
56149
- return {
56150
- ...from ? { "--site-style-transition-from": from } : {},
56151
- ...to ? { "--site-style-transition-to": to } : {}
56152
- };
56153
- }
56154
- function mergeStyleObjects(left, right) {
56155
- if (!left) return right;
56156
- if (!right) return left;
56157
- return {
56158
- ...left,
56159
- ...right
56160
- };
56161
- }
56162
- function pageBlockPosition(index, blockCount) {
56163
- if (blockCount <= 1) return "only";
56164
- if (index === 0) return "first";
56165
- if (index === blockCount - 1) return "last";
56166
- return "middle";
56167
- }
56168
56196
  function resolvePageRendererImageResolveContext(dataContext) {
56169
56197
  const input = dataContext?.imageResolveContext;
56170
56198
  return buildResolveImageUrlContext({
@@ -56174,6 +56202,23 @@ function resolvePageRendererImageResolveContext(dataContext) {
56174
56202
  mediaAssets: input?.mediaAssets ?? dataContext?.mediaAssets
56175
56203
  });
56176
56204
  }
56205
+ function buildBlockSectionProps(input) {
56206
+ return {
56207
+ themeResources: input.themeResources,
56208
+ block: input.block,
56209
+ usePlaceholders: input.props.usePlaceholders ?? false,
56210
+ dataContext: input.props.dataContext,
56211
+ blockKey: input.blockKey,
56212
+ registry: input.registry,
56213
+ routeMap: input.props.routeMap,
56214
+ wrapBlock: input.props.wrapBlock,
56215
+ blockOverrides: input.props.blockOverrides,
56216
+ sdkConfig: input.props.sdkConfig,
56217
+ customBlocks: input.props.customBlocks,
56218
+ imageResolveContext: input.imageResolveContext,
56219
+ previewAuthoring: input.props.previewAuthoring
56220
+ };
56221
+ }
56177
56222
  /**
56178
56223
  * Look up a block override component by block kind.
56179
56224
  * Supports both full ("block.hero") and short ("hero") keys.
@@ -56240,7 +56285,7 @@ function getCachedValidator(manifest, flavour) {
56240
56285
  * referential equality of all props that affect rendering. Standard React.memo
56241
56286
  * wouldn't catch all the render triggers from the editor store.
56242
56287
  */
56243
- const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, themeConfig, block, usePlaceholders, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
56288
+ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources, block, usePlaceholders, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
56244
56289
  const perfStart = globalThis.process?.env?.DEBUG_PERF === "1" && typeof window === "undefined" ? Date.now() : 0;
56245
56290
  const fallbackImageResolveContext = getCurrentResolveImageUrlContext();
56246
56291
  const resolvedImageResolveContext = imageResolveContext ?? fallbackImageResolveContext;
@@ -56261,6 +56306,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
56261
56306
  return node;
56262
56307
  }
56263
56308
  const OverrideComponent = getBlockOverride(block.kind, blockOverrides);
56309
+ requireBlockOverride(themeResources, OverrideComponent, block.kind);
56264
56310
  let definition = getBlockDefinition(block.kind);
56265
56311
  if (!definition && block.kind.startsWith("custom.")) definition = createCustomBlockRegistry({
56266
56312
  sdkConfig,
@@ -56273,8 +56319,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
56273
56319
  if (OverrideComponent) {
56274
56320
  const rendered = /* @__PURE__ */ jsx(OverrideComponent, {
56275
56321
  content: getRenderableContent(block, dataContext?.previewStage),
56276
- theme: themeTokens,
56277
- themeConfig,
56322
+ ...overrideThemeProps(themeResources),
56278
56323
  data: void 0,
56279
56324
  siteId: dataContext?.siteId,
56280
56325
  apiBaseUrl: dataContext?.apiBaseUrl,
@@ -56373,8 +56418,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
56373
56418
  const hasResolvedData = !!resolved && typeof resolved === "object" && Object.keys(resolved).length > 0;
56374
56419
  const baseProps = {
56375
56420
  content: hydratedContent,
56376
- theme: themeTokens,
56377
- themeConfig,
56421
+ ...overrideThemeProps(themeResources),
56378
56422
  data: resolved,
56379
56423
  siteId: dataContext?.siteId,
56380
56424
  apiBaseUrl: dataContext?.apiBaseUrl,
@@ -56394,6 +56438,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
56394
56438
  let rendered;
56395
56439
  if (OverrideComponent) rendered = /* @__PURE__ */ jsx(OverrideComponent, { ...baseProps });
56396
56440
  else {
56441
+ requireThemeResources(themeResources, block.kind);
56397
56442
  const BlockComponent = getCachedBlockComponent(definition.manifest);
56398
56443
  const pathBase = typeof block.id === "string" && block.id.length > 0 ? `blocks.${block.id}.` : void 0;
56399
56444
  const rootContext = { $root: {
@@ -56443,7 +56488,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
56443
56488
  });
56444
56489
  }
56445
56490
  }, (prev, next) => {
56446
- 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;
56491
+ 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;
56447
56492
  });
56448
56493
  function fallback(message) {
56449
56494
  return /* @__PURE__ */ jsx("div", {
@@ -69660,6 +69705,10 @@ function toBlocksImageResolveContextInput(context) {
69660
69705
  }
69661
69706
  //#endregion
69662
69707
  //#region src/rendering/blocks-page-renderer.ts
69708
+ const MissingBlockOverrideError = MissingBlockOverrideError$1;
69709
+ function isOverrideOnlyPageRenderer(props) {
69710
+ return props.rendering?.kind === "overrides-only";
69711
+ }
69663
69712
  function normalizeSdkCustomBlocks(customBlocks) {
69664
69713
  if (!customBlocks) return void 0;
69665
69714
  return customBlocks.map((block) => {
@@ -69690,15 +69739,23 @@ function toBlocksPageRendererDataContext(dataContext) {
69690
69739
  }
69691
69740
  function PageRenderer(props) {
69692
69741
  const blocksSdkConfig = props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig;
69693
- const blocksTheme = parseBlocksTheme(props.theme);
69694
- const blocksProps = {
69695
- ...props,
69696
- theme: blocksTheme,
69742
+ const { rendering: _rendering, theme: _theme, themeTokens: _themeTokens, ...commonProps } = props;
69743
+ const commonBlocksProps = {
69744
+ ...commonProps,
69697
69745
  dataContext: props.dataContext ? toBlocksPageRendererDataContext(props.dataContext) : void 0,
69698
69746
  blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
69699
69747
  sdkConfig: blocksSdkConfig,
69700
69748
  customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
69701
69749
  };
69750
+ const blocksProps = isOverrideOnlyPageRenderer(props) ? {
69751
+ ...commonBlocksProps,
69752
+ rendering: { kind: "overrides-only" },
69753
+ blockOverrides: toBlocksBlockOverrides(props.blockOverrides) ?? {}
69754
+ } : {
69755
+ ...commonBlocksProps,
69756
+ theme: parseBlocksTheme(props.theme),
69757
+ themeTokens: props.themeTokens
69758
+ };
69702
69759
  return React$1.createElement(PageRenderer$1, blocksProps);
69703
69760
  }
69704
69761
  //#endregion
@@ -69740,8 +69797,31 @@ function renderWithSdkThemeRuntime({ themeRuntime, theme, children }) {
69740
69797
  default: return assertNever$24(themeRuntime);
69741
69798
  }
69742
69799
  }
69800
+ function renderWithOverrideOnlyRuntime({ runtime, children }) {
69801
+ switch (runtime.kind) {
69802
+ case "responsive-only": return /* @__PURE__ */ jsx(ResponsiveScope, {
69803
+ responsiveMode: runtime.responsiveMode,
69804
+ children
69805
+ });
69806
+ case "none": return /* @__PURE__ */ jsx(Fragment, { children });
69807
+ default: return assertNever$24(runtime);
69808
+ }
69809
+ }
69743
69810
  //#endregion
69744
69811
  //#region src/rendering/components/pageShared.tsx
69812
+ function isOverrideOnlyPage(props) {
69813
+ return props.rendering?.kind === "overrides-only";
69814
+ }
69815
+ function resolvePageThemeTokens(props) {
69816
+ const baseTokens = props.themeTokens ?? buildThemeRuntime(props.theme).tokens;
69817
+ return props.sdkConfig?.theme?.palette ? {
69818
+ ...baseTokens,
69819
+ palette: {
69820
+ ...baseTokens.palette,
69821
+ ...props.sdkConfig.theme.palette
69822
+ }
69823
+ } : baseTokens;
69824
+ }
69745
69825
  function toPageHydrationBootstrapConfig(props) {
69746
69826
  return {
69747
69827
  siteId: props.siteId,
@@ -69749,55 +69829,60 @@ function toPageHydrationBootstrapConfig(props) {
69749
69829
  mediaAssets: props.mediaAssets
69750
69830
  };
69751
69831
  }
69752
- 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 }) {
69753
- const baseTokens = providedTokens ?? buildThemeRuntime(theme).tokens;
69754
- return renderWithSdkThemeRuntime({
69755
- themeRuntime,
69756
- theme,
69757
- children: /* @__PURE__ */ jsx(PageRenderer, {
69758
- theme,
69759
- page,
69760
- runtimeBoundaries,
69761
- themeTokens: sdkConfig?.theme?.palette ? {
69762
- ...baseTokens,
69763
- palette: {
69764
- ...baseTokens.palette,
69765
- ...sdkConfig.theme.palette
69766
- }
69767
- } : baseTokens,
69768
- usePlaceholders,
69769
- dataContext: {
69832
+ function PageContent(props) {
69833
+ const { page, runtimeBoundaries, siteId, resolvedData, bookingOfferingPresets, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, usePlaceholders = false, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext } = props;
69834
+ const rendererCommonProps = {
69835
+ page,
69836
+ runtimeBoundaries,
69837
+ usePlaceholders,
69838
+ dataContext: {
69839
+ siteId,
69840
+ apiBaseUrl,
69841
+ portalToken,
69842
+ previewToken,
69843
+ resolvedData,
69844
+ bookingOfferingPresets: bookingOfferingPresets ?? [],
69845
+ routes: routeMap,
69846
+ pagesByIdentifier,
69847
+ entriesByIdentifier,
69848
+ occurrenceContext: dataContext?.occurrenceContext ?? null,
69849
+ entrySubrouteContext: dataContext?.entrySubrouteContext ?? null,
69850
+ contentEntry: dataContext?.contentEntry ?? null,
69851
+ pageSurface: dataContext?.pageSurface ?? null,
69852
+ subject: dataContext?.subject ?? null,
69853
+ editableRouteMetadataFieldIds: dataContext?.editableRouteMetadataFieldIds ?? null,
69854
+ previewStage: dataContext?.previewStage,
69855
+ supabaseUrl,
69856
+ mediaAssets,
69857
+ imageResolveContext: {
69770
69858
  siteId,
69771
- apiBaseUrl,
69772
- portalToken,
69773
- previewToken,
69774
- resolvedData,
69775
- bookingOfferingPresets: bookingOfferingPresets ?? [],
69776
- routes: routeMap,
69777
- pagesByIdentifier,
69778
- entriesByIdentifier,
69779
- occurrenceContext: dataContext?.occurrenceContext ?? null,
69780
- entrySubrouteContext: dataContext?.entrySubrouteContext ?? null,
69781
- contentEntry: dataContext?.contentEntry ?? null,
69782
- pageSurface: dataContext?.pageSurface ?? null,
69783
- subject: dataContext?.subject ?? null,
69784
- editableRouteMetadataFieldIds: dataContext?.editableRouteMetadataFieldIds ?? null,
69785
- previewStage: dataContext?.previewStage,
69786
69859
  supabaseUrl,
69787
- mediaAssets,
69788
- imageResolveContext: {
69789
- siteId,
69790
- supabaseUrl,
69791
- mediaAssets
69792
- }
69793
- },
69794
- routeMap,
69795
- wrapBlock,
69796
- registry,
69797
- blockOverrides,
69798
- sdkConfig: sdkConfig ? { customBlocks: sdkConfig.customBlocks } : null,
69799
- customBlocks
69800
- })
69860
+ mediaAssets
69861
+ }
69862
+ },
69863
+ routeMap,
69864
+ wrapBlock,
69865
+ registry,
69866
+ sdkConfig: sdkConfig ? { customBlocks: sdkConfig.customBlocks } : null,
69867
+ customBlocks
69868
+ };
69869
+ const content = isOverrideOnlyPage(props) ? /* @__PURE__ */ jsx(PageRenderer, {
69870
+ ...rendererCommonProps,
69871
+ rendering: { kind: "overrides-only" },
69872
+ blockOverrides: props.blockOverrides
69873
+ }) : /* @__PURE__ */ jsx(PageRenderer, {
69874
+ ...rendererCommonProps,
69875
+ theme: props.theme,
69876
+ themeTokens: resolvePageThemeTokens(props),
69877
+ blockOverrides
69878
+ });
69879
+ return isOverrideOnlyPage(props) ? renderWithOverrideOnlyRuntime({
69880
+ runtime: props.rendering.runtime,
69881
+ children: content
69882
+ }) : renderWithSdkThemeRuntime({
69883
+ themeRuntime: props.themeRuntime ?? defaultPageThemeRuntime,
69884
+ theme: props.theme,
69885
+ children: content
69801
69886
  });
69802
69887
  }
69803
69888
  //#endregion
@@ -70320,12 +70405,48 @@ function buildLogo(logo, fallbackAlt) {
70320
70405
  return result;
70321
70406
  }
70322
70407
  //#endregion
70408
+ //#region src/rendering/renderingMode.ts
70409
+ const defaultOverrideOnlyRuntime = { kind: "responsive-only" };
70410
+ //#endregion
70323
70411
  //#region src/rendering/components/Layout.tsx
70324
70412
  /**
70325
70413
  * Layout component with header and footer
70326
70414
  *
70327
70415
  * Renders site header and footer around content. Fetches site data if not provided.
70328
70416
  */
70417
+ function isOverrideOnlyLayout(props) {
70418
+ return props.rendering?.kind === "overrides-only";
70419
+ }
70420
+ var UnsupportedOverrideOnlyLayoutChromeError = class extends Error {
70421
+ constructor(surface) {
70422
+ super(`Override-only Layout requires a custom or disabled ${surface}; SDK default chrome is unavailable.`);
70423
+ this.surface = surface;
70424
+ this.code = "unsupported_override_only_layout_chrome";
70425
+ this.name = "UnsupportedOverrideOnlyLayoutChromeError";
70426
+ }
70427
+ };
70428
+ async function resolveLayoutSiteData(props) {
70429
+ if (props.siteData) return props.siteData;
70430
+ if (!props.client) throw new Error("Layout: must provide either siteData or client");
70431
+ if (!props.siteId && !props.slug && !props.domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
70432
+ return props.client.getSite({
70433
+ id: props.siteId,
70434
+ slug: props.slug,
70435
+ domain: props.domain
70436
+ });
70437
+ }
70438
+ function renderOverrideOnlyLayout(props, data) {
70439
+ if (data.header === true) throw new UnsupportedOverrideOnlyLayoutChromeError("header");
70440
+ if (data.footer === true) throw new UnsupportedOverrideOnlyLayoutChromeError("footer");
70441
+ return renderWithOverrideOnlyRuntime({
70442
+ runtime: props.rendering.runtime ?? defaultOverrideOnlyRuntime,
70443
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
70444
+ typeof props.header === "function" ? props.header(data.headerData) : null,
70445
+ props.children,
70446
+ typeof props.footer === "function" ? props.footer(data.footerData) : null
70447
+ ] })
70448
+ });
70449
+ }
70329
70450
  /**
70330
70451
  * Layout component that wraps content with site header and footer.
70331
70452
  *
@@ -70361,20 +70482,13 @@ function buildLogo(logo, fallbackAlt) {
70361
70482
  * </Layout>
70362
70483
  * ```
70363
70484
  */
70364
- async function Layout({ siteData: providedSiteData, client, siteId, slug, domain, children, header = true, footer = true, headerVariant, hasPortalSession = false, previewStage = "published", themeRuntime }) {
70365
- let siteData = providedSiteData;
70366
- if (!siteData) {
70367
- if (!client) throw new Error("Layout: must provide either siteData or client");
70368
- if (!siteId && !slug && !domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
70369
- siteData = await client.getSite({
70370
- id: siteId,
70371
- slug,
70372
- domain
70373
- });
70374
- }
70375
- const { site, theme, navigation, layout, routes } = siteData;
70485
+ async function Layout(props) {
70486
+ const { children, hasPortalSession = false, previewStage = "published" } = props;
70487
+ const header = props.header ?? true;
70488
+ const footer = props.footer ?? true;
70489
+ const siteData = await resolveLayoutSiteData(props);
70490
+ const { site, navigation, layout, routes } = siteData;
70376
70491
  const footerBlocks = siteData.footerBlocks ?? [];
70377
- const builtThemeRuntime = buildThemeRuntime(theme);
70378
70492
  const navigationOptions = {
70379
70493
  hasPortalSession,
70380
70494
  previewStage,
@@ -70388,22 +70502,38 @@ async function Layout({ siteData: providedSiteData, client, siteId, slug, domain
70388
70502
  const footerMenuViewModel = buildFooterMenu(navigation, routes, navigationOptions);
70389
70503
  const legalFooterMenuViewModel = buildFooterMenuForRole(navigation, routes, "legal-policy", navigationOptions);
70390
70504
  const logoViewModel = buildLogo(layout.logo ?? null, site.title);
70391
- const headerData = {
70505
+ const customHeaderData = {
70392
70506
  menu: menuViewModel,
70393
70507
  logo: logoViewModel,
70394
70508
  site,
70395
- theme,
70396
70509
  routes
70397
70510
  };
70398
- const footerData = {
70511
+ const customFooterData = {
70399
70512
  menu: menuViewModel,
70400
70513
  footerMenu: footerMenuViewModel,
70401
70514
  legalFooterMenu: legalFooterMenuViewModel,
70402
70515
  logo: logoViewModel,
70403
70516
  site,
70404
- theme,
70405
70517
  routes
70406
70518
  };
70519
+ if (isOverrideOnlyLayout(props)) return renderOverrideOnlyLayout(props, {
70520
+ header: props.header ?? true,
70521
+ footer: props.footer ?? true,
70522
+ headerData: customHeaderData,
70523
+ footerData: customFooterData
70524
+ });
70525
+ const { theme } = siteData;
70526
+ const builtThemeRuntime = buildThemeRuntime(theme);
70527
+ const headerVariant = props.headerVariant;
70528
+ const themeRuntime = props.themeRuntime;
70529
+ const headerData = {
70530
+ ...customHeaderData,
70531
+ theme
70532
+ };
70533
+ const footerData = {
70534
+ ...customFooterData,
70535
+ theme
70536
+ };
70407
70537
  const headerContent = headerVariant ? {
70408
70538
  ...layout.header,
70409
70539
  variant: headerVariant
@@ -73803,6 +73933,17 @@ async function prefetchBlockDataWithDeps(deps, page, context, client, options) {
73803
73933
  * hydration; the strict `@riverbankcms/sdk/rendering/server` surface exports it
73804
73934
  * directly.
73805
73935
  */
73936
+ function isOverrideOnlyBlock(props) {
73937
+ return props.rendering?.kind === "overrides-only";
73938
+ }
73939
+ var MissingStandaloneBlockOverrideError = class extends Error {
73940
+ constructor(blockKind) {
73941
+ super(`Override-only standalone rendering requires an override for block kind "${blockKind}".`);
73942
+ this.blockKind = blockKind;
73943
+ this.code = "missing_standalone_block_override";
73944
+ this.name = "MissingStandaloneBlockOverrideError";
73945
+ }
73946
+ };
73806
73947
  function toBlockHydrationBootstrapConfig(props) {
73807
73948
  return {
73808
73949
  siteId: props.siteId,
@@ -73872,14 +74013,16 @@ function buildStandaloneBlockViewModel({ siteId, pageId, previewStage, apiBaseUr
73872
74013
  function renderBlockOverride({ OverrideComponent, props, runtime, resolvedData }) {
73873
74014
  return /* @__PURE__ */ jsx(OverrideComponent, {
73874
74015
  content: props.content,
73875
- theme: runtime.themeRuntime.tokens,
73876
- themeConfig: props.theme,
74016
+ ...runtime && "theme" in props ? {
74017
+ theme: runtime.themeRuntime.tokens,
74018
+ themeConfig: props.theme
74019
+ } : {},
73877
74020
  data: resolvedData,
73878
74021
  siteId: props.siteId,
73879
74022
  apiBaseUrl: props.apiBaseUrl,
73880
74023
  portalToken: props.portalToken ?? null,
73881
74024
  supabaseUrl: props.supabaseUrl,
73882
- imageResolveContext: runtime.imageResolveContext,
74025
+ imageResolveContext: runtime?.imageResolveContext,
73883
74026
  blockId: props.blockId ?? null,
73884
74027
  blockKind: props.blockKind
73885
74028
  });
@@ -73908,8 +74051,8 @@ function renderManifestBlock({ definition, props, runtime, resolvedData }) {
73908
74051
  async function BlockContent(props) {
73909
74052
  const definition = getBlockDefinition(props.blockKind);
73910
74053
  const OverrideComponent = props.override;
74054
+ if (isOverrideOnlyBlock(props) && !OverrideComponent) throw new MissingStandaloneBlockOverrideError(props.blockKind);
73911
74055
  if (!definition && !OverrideComponent) return renderUnknownBlock(props.blockKind);
73912
- const runtime = buildBlockContentRuntime(props);
73913
74056
  const resolvedData = await loadStandaloneBlockData({
73914
74057
  ...props,
73915
74058
  hasDefinition: Boolean(definition)
@@ -73917,13 +74060,14 @@ async function BlockContent(props) {
73917
74060
  if (OverrideComponent) return renderBlockOverride({
73918
74061
  OverrideComponent,
73919
74062
  props,
73920
- runtime,
74063
+ runtime: isOverrideOnlyBlock(props) ? void 0 : buildBlockContentRuntime(props),
73921
74064
  resolvedData
73922
74065
  });
74066
+ if (isOverrideOnlyBlock(props)) throw new MissingStandaloneBlockOverrideError(props.blockKind);
73923
74067
  return renderManifestBlock({
73924
74068
  definition,
73925
74069
  props,
73926
- runtime,
74070
+ runtime: buildBlockContentRuntime(props),
73927
74071
  resolvedData
73928
74072
  });
73929
74073
  }
@@ -77728,4 +77872,4 @@ function defineBlockOverrideRegistrations(registrations) {
77728
77872
  * ```
77729
77873
  */
77730
77874
  //#endregion
77731
- export { Block, ImagePresets, Layout, Page, PageRenderer, RichText, ThemeScope, buildThemeRuntime, defineBlockOverrideRegistrations, defineBlockOverrides, defineLazyBlockOverride, isEntryContent, isPageContent, isPageSurfaceContent, loadContent, loadPage, resolveImageSourceSetWithContext, resolveImageUrl, resolveImageUrlWithContext, toBlocksImageResolveContextInput, toBlocksMediaAssets, toBlocksPageRendererDataContext };
77875
+ export { Block, ImagePresets, Layout, MissingBlockOverrideError, Page, PageRenderer, RichText, ThemeScope, UnsupportedOverrideOnlyLayoutChromeError, buildThemeRuntime, defineBlockOverrideRegistrations, defineBlockOverrides, defineLazyBlockOverride, isEntryContent, isPageContent, isPageSurfaceContent, loadContent, loadPage, resolveImageSourceSetWithContext, resolveImageUrl, resolveImageUrlWithContext, toBlocksImageResolveContextInput, toBlocksMediaAssets, toBlocksPageRendererDataContext };