@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
@@ -132101,6 +132101,216 @@ init_node();
132101
132101
  init_fragments();
132102
132102
  init_defineBlock();
132103
132103
  //#endregion
132104
+ //#region ../blocks/src/system/manifest/hydrateLinks.ts
132105
+ init_typeGuards();
132106
+ /**
132107
+ * Hydrates link objects within block content using the provided route map. Returns
132108
+ * the original content reference when no mutations are required to avoid unnecessary renders.
132109
+ */
132110
+ function hydrateManifestLinks(manifest, content, routes, pagesByIdentifier, entriesByIdentifier) {
132111
+ if (!routes || !manifest?.fields?.length) return content;
132112
+ return hydrateValue(content, {
132113
+ routes,
132114
+ pagesByIdentifier,
132115
+ entriesByIdentifier
132116
+ });
132117
+ }
132118
+ function hydrateValue(value, context) {
132119
+ try {
132120
+ if (Array.isArray(value)) {
132121
+ const resolvedItems = value.map((item) => hydrateValue(item, context));
132122
+ return resolvedItems.every((item, index) => item === value[index]) ? value : resolvedItems;
132123
+ }
132124
+ if (isRecord$32(value)) {
132125
+ if (isInternalLink$1(value)) return hydrateInternalLink(value, context.routes);
132126
+ if (isPageLink$1(value)) return hydratePageLink(value, context);
132127
+ if (isEntryLink$1(value)) return hydrateEntryLink(value, context);
132128
+ const resolvedEntries = Object.entries(value).map(([key, entry]) => [key, hydrateValue(entry, context)]);
132129
+ return resolvedEntries.every(([key, entry]) => entry === value[key]) ? value : Object.fromEntries(resolvedEntries);
132130
+ }
132131
+ return value;
132132
+ } catch (err) {
132133
+ console.error("[hydrateLinks] Error hydrating value:", err, value);
132134
+ return value;
132135
+ }
132136
+ }
132137
+ function hydrateInternalLink(link, routes) {
132138
+ const resolved = resolveRouteTarget(link.routeId, routes);
132139
+ if (!resolved) return link;
132140
+ const nextHref = resolved.href;
132141
+ const currentHref = typeof link.href === "string" && link.href.length > 0 ? link.href : null;
132142
+ const nextUpdatedAt = resolved.updatedAt;
132143
+ const updates = {};
132144
+ if (nextHref && nextHref !== currentHref) updates.href = nextHref;
132145
+ if (nextUpdatedAt && link.updatedAt !== nextUpdatedAt) updates.updatedAt = nextUpdatedAt;
132146
+ return Object.keys(updates).length > 0 ? {
132147
+ ...link,
132148
+ ...updates
132149
+ } : link;
132150
+ }
132151
+ function isInternalLink$1(value) {
132152
+ if (value.kind !== "internal") return false;
132153
+ if (typeof value.routeId !== "string" || value.routeId.length === 0) return false;
132154
+ return true;
132155
+ }
132156
+ function isPageLink$1(value) {
132157
+ if (value.kind !== "page") return false;
132158
+ if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
132159
+ return true;
132160
+ }
132161
+ function hydratePageLink(link, context) {
132162
+ const resolved = resolvePageRouteTarget(link, context);
132163
+ if (!resolved) return link;
132164
+ return {
132165
+ ...link,
132166
+ href: resolved.href,
132167
+ routeId: resolved.routeId
132168
+ };
132169
+ }
132170
+ function isEntryLink$1(value) {
132171
+ if (value.kind !== "entry") return false;
132172
+ if (typeof value.contentType !== "string" || value.contentType.length === 0) return false;
132173
+ if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
132174
+ return true;
132175
+ }
132176
+ function hydrateEntryLink(link, context) {
132177
+ const resolved = resolveEntryRouteTarget(link, context);
132178
+ if (!resolved) return link;
132179
+ return {
132180
+ ...link,
132181
+ href: resolved.href,
132182
+ routeId: resolved.routeId
132183
+ };
132184
+ }
132185
+ //#endregion
132186
+ //#region ../blocks/src/sdkBlockTransform.ts
132187
+ init_augmentManifest();
132188
+ /**
132189
+ * Transforms an SDK custom block into a BlockManifest.
132190
+ *
132191
+ * If the block has a `layout`, it can be rendered declaratively without React code.
132192
+ * If no layout, the block MUST use blockOverrides for rendering.
132193
+ */
132194
+ function transformSdkBlockToManifest(sdkBlock) {
132195
+ const hasLayout = Boolean(sdkBlock.layout) || Boolean(sdkBlock.variants && Object.keys(sdkBlock.variants).length > 0);
132196
+ return augmentManifest({
132197
+ name: sdkBlock.id,
132198
+ version: "1.0.0",
132199
+ title: sdkBlock.title,
132200
+ titleSource: sdkBlock.titleSource,
132201
+ description: sdkBlock.description,
132202
+ component: sdkBlock.id,
132203
+ fields: sdkBlock.fields,
132204
+ slots: [],
132205
+ category: sdkBlock.category,
132206
+ tags: sdkBlock.tags,
132207
+ icon: sdkBlock.icon,
132208
+ layout: sdkBlock.layout,
132209
+ variants: sdkBlock.variants,
132210
+ defaultVariant: sdkBlock.defaultVariant,
132211
+ variantOptions: sdkBlock.variantOptions,
132212
+ previewCustomize: sdkBlock.previewCustomize,
132213
+ behaviours: {
132214
+ supportsThemeSwitching: true,
132215
+ inlineEditing: hasLayout,
132216
+ animation: hasLayout,
132217
+ paletteHidden: false
132218
+ }
132219
+ });
132220
+ }
132221
+ /**
132222
+ * Transforms an SDK custom block into a SystemBlockDefinition.
132223
+ *
132224
+ * This creates a minimal definition with just the manifest - no data loaders
132225
+ * or content normalizers since SDK blocks handle their own rendering.
132226
+ */
132227
+ function transformSdkBlockToDefinition(sdkBlock) {
132228
+ return {
132229
+ manifest: transformSdkBlockToManifest(sdkBlock),
132230
+ dataLoaders: sdkBlock.dataLoaders
132231
+ };
132232
+ }
132233
+ //#endregion
132234
+ //#region ../blocks/src/customBlockRegistry.ts
132235
+ init_src$3();
132236
+ const defaultCustomBlockSourcePolicy = { kind: "canonical-db-fallback-sdk" };
132237
+ function isCustomBlockKind(blockKind) {
132238
+ return blockKind.startsWith("custom.");
132239
+ }
132240
+ function transformToBlockDescriptor(sdkBlock, source = "sdk") {
132241
+ return {
132242
+ name: sdkBlock.id,
132243
+ title: sdkBlock.title,
132244
+ description: sdkBlock.description,
132245
+ category: sdkBlock.category,
132246
+ tags: sdkBlock.tags,
132247
+ icon: sdkBlock.icon,
132248
+ definition: transformSdkBlockToDefinition(sdkBlock),
132249
+ source
132250
+ };
132251
+ }
132252
+ function toResolvedCustomBlock(manifest, source) {
132253
+ return {
132254
+ blockKind: manifest.id,
132255
+ manifest: transformSdkBlockToManifest(manifest),
132256
+ source,
132257
+ descriptor: transformToBlockDescriptor(manifest, source.kind === "managed-database" ? "database" : "sdk")
132258
+ };
132259
+ }
132260
+ function planCustomBlockRegistryResolution({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy }) {
132261
+ switch (policy.kind) {
132262
+ case "canonical-db-fallback-sdk": {
132263
+ const entriesByKind = /* @__PURE__ */ new Map();
132264
+ const conflicts = [];
132265
+ for (const customBlock of customBlocks) entriesByKind.set(customBlock.manifest.id, toResolvedCustomBlock(customBlock.manifest, customBlock.source));
132266
+ for (const sdkBlock of sdkConfig?.customBlocks ?? []) {
132267
+ const existing = entriesByKind.get(sdkBlock.id);
132268
+ if (existing) {
132269
+ conflicts.push({
132270
+ kind: "conflict",
132271
+ blockKind: existing.blockKind,
132272
+ winner: existing.source,
132273
+ loser: { kind: "sdk-config" },
132274
+ reason: "db-canonical-sdk-fallback"
132275
+ });
132276
+ continue;
132277
+ }
132278
+ entriesByKind.set(sdkBlock.id, toResolvedCustomBlock(sdkBlock, { kind: "sdk-config" }));
132279
+ }
132280
+ return {
132281
+ policy,
132282
+ entries: Array.from(entriesByKind.values()),
132283
+ conflicts
132284
+ };
132285
+ }
132286
+ }
132287
+ }
132288
+ function createCustomBlockRegistry({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy, onConflict }) {
132289
+ const plan = planCustomBlockRegistryResolution({
132290
+ sdkConfig,
132291
+ customBlocks,
132292
+ policy
132293
+ });
132294
+ const entriesByKind = new Map(plan.entries.map((entry) => [entry.blockKind, entry]));
132295
+ for (const conflict of plan.conflicts) onConflict?.(`Using ${sourceLabel(conflict.winner)} custom block "${conflict.blockKind}" - ${sourceLabel(conflict.loser)} block is fallback only`);
132296
+ return {
132297
+ entries: plan.entries,
132298
+ conflicts: plan.conflicts,
132299
+ findManifest: (blockKind) => {
132300
+ if (!isCustomBlockKind(blockKind)) return void 0;
132301
+ return entriesByKind.get(blockKind);
132302
+ }
132303
+ };
132304
+ }
132305
+ function sourceLabel(source) {
132306
+ switch (source.kind) {
132307
+ case "managed-database": return "DB";
132308
+ case "sdk-synced": return "SDK-synced DB";
132309
+ case "sdk-config": return "SDK config";
132310
+ default: return assertNever$20(source);
132311
+ }
132312
+ }
132313
+ //#endregion
132104
132314
  //#region ../theme-core/src/runtime/fontFamily.ts
132105
132315
  /**
132106
132316
  * Font Family Formatting Utilities
@@ -135870,214 +136080,111 @@ function mapFontStyle(italic) {
135870
136080
  return italic ? "italic" : "normal";
135871
136081
  }
135872
136082
  //#endregion
135873
- //#region ../blocks/src/system/manifest/hydrateLinks.ts
135874
- init_typeGuards();
135875
- /**
135876
- * Hydrates link objects within block content using the provided route map. Returns
135877
- * the original content reference when no mutations are required to avoid unnecessary renders.
135878
- */
135879
- function hydrateManifestLinks(manifest, content, routes, pagesByIdentifier, entriesByIdentifier) {
135880
- if (!routes || !manifest?.fields?.length) return content;
135881
- return hydrateValue(content, {
135882
- routes,
135883
- pagesByIdentifier,
135884
- entriesByIdentifier
135885
- });
135886
- }
135887
- function hydrateValue(value, context) {
135888
- try {
135889
- if (Array.isArray(value)) {
135890
- const resolvedItems = value.map((item) => hydrateValue(item, context));
135891
- return resolvedItems.every((item, index) => item === value[index]) ? value : resolvedItems;
135892
- }
135893
- if (isRecord$32(value)) {
135894
- if (isInternalLink$1(value)) return hydrateInternalLink(value, context.routes);
135895
- if (isPageLink$1(value)) return hydratePageLink(value, context);
135896
- if (isEntryLink$1(value)) return hydrateEntryLink(value, context);
135897
- const resolvedEntries = Object.entries(value).map(([key, entry]) => [key, hydrateValue(entry, context)]);
135898
- return resolvedEntries.every(([key, entry]) => entry === value[key]) ? value : Object.fromEntries(resolvedEntries);
135899
- }
135900
- return value;
135901
- } catch (err) {
135902
- console.error("[hydrateLinks] Error hydrating value:", err, value);
135903
- return value;
136083
+ //#region ../blocks/src/pageRenderingMode.ts
136084
+ var MissingBlockOverrideError$1 = class extends Error {
136085
+ constructor(blockKind) {
136086
+ super(`Override-only rendering requires an override for block kind "${blockKind}".`);
136087
+ this.blockKind = blockKind;
136088
+ this.code = "missing_block_override";
136089
+ this.name = "MissingBlockOverrideError";
135904
136090
  }
136091
+ };
136092
+ function isOverrideOnlyResourceInput(props) {
136093
+ return props.rendering?.kind === "overrides-only";
135905
136094
  }
135906
- function hydrateInternalLink(link, routes) {
135907
- const resolved = resolveRouteTarget(link.routeId, routes);
135908
- if (!resolved) return link;
135909
- const nextHref = resolved.href;
135910
- const currentHref = typeof link.href === "string" && link.href.length > 0 ? link.href : null;
135911
- const nextUpdatedAt = resolved.updatedAt;
135912
- const updates = {};
135913
- if (nextHref && nextHref !== currentHref) updates.href = nextHref;
135914
- if (nextUpdatedAt && link.updatedAt !== nextUpdatedAt) updates.updatedAt = nextUpdatedAt;
135915
- return Object.keys(updates).length > 0 ? {
135916
- ...link,
135917
- ...updates
135918
- } : link;
135919
- }
135920
- function isInternalLink$1(value) {
135921
- if (value.kind !== "internal") return false;
135922
- if (typeof value.routeId !== "string" || value.routeId.length === 0) return false;
135923
- return true;
135924
- }
135925
- function isPageLink$1(value) {
135926
- if (value.kind !== "page") return false;
135927
- if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
135928
- return true;
135929
- }
135930
- function hydratePageLink(link, context) {
135931
- const resolved = resolvePageRouteTarget(link, context);
135932
- if (!resolved) return link;
136095
+ function resolvePageThemeResources(props) {
136096
+ if (isOverrideOnlyResourceInput(props)) return { kind: "unavailable" };
135933
136097
  return {
135934
- ...link,
135935
- href: resolved.href,
135936
- routeId: resolved.routeId
136098
+ kind: "available",
136099
+ tokens: props.themeTokens ?? buildThemeRuntime$1(props.theme).tokens,
136100
+ config: props.theme
135937
136101
  };
135938
136102
  }
135939
- function isEntryLink$1(value) {
135940
- if (value.kind !== "entry") return false;
135941
- if (typeof value.contentType !== "string" || value.contentType.length === 0) return false;
135942
- if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
135943
- return true;
136103
+ function requireBlockOverride(resources, override, blockKind) {
136104
+ if (resources.kind === "unavailable" && !override) throw new MissingBlockOverrideError$1(blockKind);
135944
136105
  }
135945
- function hydrateEntryLink(link, context) {
135946
- const resolved = resolveEntryRouteTarget(link, context);
135947
- if (!resolved) return link;
135948
- return {
135949
- ...link,
135950
- href: resolved.href,
135951
- routeId: resolved.routeId
135952
- };
136106
+ function overrideThemeProps(resources) {
136107
+ return resources.kind === "available" ? {
136108
+ theme: resources.tokens,
136109
+ themeConfig: resources.config
136110
+ } : {};
136111
+ }
136112
+ function requireThemeResources(resources, blockKind) {
136113
+ if (resources.kind === "unavailable") throw new MissingBlockOverrideError$1(blockKind);
136114
+ return resources;
135953
136115
  }
135954
136116
  //#endregion
135955
- //#region ../blocks/src/sdkBlockTransform.ts
135956
- init_augmentManifest();
135957
- /**
135958
- * Transforms an SDK custom block into a BlockManifest.
135959
- *
135960
- * If the block has a `layout`, it can be rendered declaratively without React code.
135961
- * If no layout, the block MUST use blockOverrides for rendering.
135962
- */
135963
- function transformSdkBlockToManifest(sdkBlock) {
135964
- const hasLayout = Boolean(sdkBlock.layout) || Boolean(sdkBlock.variants && Object.keys(sdkBlock.variants).length > 0);
135965
- return augmentManifest({
135966
- name: sdkBlock.id,
135967
- version: "1.0.0",
135968
- title: sdkBlock.title,
135969
- titleSource: sdkBlock.titleSource,
135970
- description: sdkBlock.description,
135971
- component: sdkBlock.id,
135972
- fields: sdkBlock.fields,
135973
- slots: [],
135974
- category: sdkBlock.category,
135975
- tags: sdkBlock.tags,
135976
- icon: sdkBlock.icon,
135977
- layout: sdkBlock.layout,
135978
- variants: sdkBlock.variants,
135979
- defaultVariant: sdkBlock.defaultVariant,
135980
- variantOptions: sdkBlock.variantOptions,
135981
- previewCustomize: sdkBlock.previewCustomize,
135982
- behaviours: {
135983
- supportsThemeSwitching: true,
135984
- inlineEditing: hasLayout,
135985
- animation: hasLayout,
135986
- paletteHidden: false
135987
- }
135988
- });
136117
+ //#region ../blocks/src/pageRendererBoundaries.tsx
136118
+ init_typeGuards();
136119
+ const boundaryKey = (previousBlockId, nextBlockId) => `${previousBlockId}\u0000${nextBlockId}`;
136120
+ function isSiteStyleTransitionStyleGroup(value) {
136121
+ return value?.startsWith("site-style-transition-") === true;
136122
+ }
136123
+ function boundaryMapForAdjacentBlockIds(boundaries) {
136124
+ return new Map(boundaries.map((boundary) => [boundaryKey(boundary.previousBlockId, boundary.nextBlockId), boundary]));
136125
+ }
136126
+ function boundaryBetweenBlocks(previousBlock, nextBlock, boundaries) {
136127
+ const previousBlockId = previousBlock?.id ?? null;
136128
+ const nextBlockId = nextBlock?.id ?? null;
136129
+ if (!previousBlockId || !nextBlockId) return null;
136130
+ return boundaries.get(boundaryKey(previousBlockId, nextBlockId)) ?? null;
136131
+ }
136132
+ function renderBoundaryAfterBlock(input) {
136133
+ const previousBlockId = input.block.id;
136134
+ const nextBlockId = input.nextBlock?.id ?? null;
136135
+ if (!previousBlockId || !nextBlockId) return null;
136136
+ const boundary = input.boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId));
136137
+ if (!boundary) return null;
136138
+ const rendered = /* @__PURE__ */ jsx("div", {
136139
+ "aria-hidden": "true",
136140
+ "data-block-boundary": "",
136141
+ "data-boundary-id": boundary.boundaryId,
136142
+ "data-boundary-previous-block-id": boundary.previousBlockId,
136143
+ "data-boundary-next-block-id": boundary.nextBlockId,
136144
+ "data-style-group": boundary.styleGroup,
136145
+ style: boundaryCssVarsStyle(boundary)
136146
+ }, `${input.blockKey}:boundary`);
136147
+ return input.wrapBoundary ? input.wrapBoundary(boundary, rendered) : rendered;
135989
136148
  }
135990
- /**
135991
- * Transforms an SDK custom block into a SystemBlockDefinition.
135992
- *
135993
- * This creates a minimal definition with just the manifest - no data loaders
135994
- * or content normalizers since SDK blocks handle their own rendering.
135995
- */
135996
- function transformSdkBlockToDefinition(sdkBlock) {
136149
+ function boundaryCssVarsStyle(boundary) {
135997
136150
  return {
135998
- manifest: transformSdkBlockToManifest(sdkBlock),
135999
- dataLoaders: sdkBlock.dataLoaders
136151
+ "--site-style-transition-from": boundary.cssVars.from,
136152
+ "--site-style-transition-to": boundary.cssVars.to
136000
136153
  };
136001
136154
  }
136002
- //#endregion
136003
- //#region ../blocks/src/customBlockRegistry.ts
136004
- init_src$3();
136005
- const defaultCustomBlockSourcePolicy = { kind: "canonical-db-fallback-sdk" };
136006
- function isCustomBlockKind(blockKind) {
136007
- return blockKind.startsWith("custom.");
136008
- }
136009
- function transformToBlockDescriptor(sdkBlock, source = "sdk") {
136155
+ function boundaryReserveCssVarsStyle(input) {
136156
+ const before = input.before?.metrics.reserveCss ?? null;
136157
+ const after = input.after?.metrics.reserveCss ?? null;
136158
+ if (!before && !after) return void 0;
136010
136159
  return {
136011
- name: sdkBlock.id,
136012
- title: sdkBlock.title,
136013
- description: sdkBlock.description,
136014
- category: sdkBlock.category,
136015
- tags: sdkBlock.tags,
136016
- icon: sdkBlock.icon,
136017
- definition: transformSdkBlockToDefinition(sdkBlock),
136018
- source
136160
+ ...before ? { "--site-style-boundary-before-reserve": before } : {},
136161
+ ...after ? { "--site-style-boundary-after-reserve": after } : {}
136019
136162
  };
136020
136163
  }
136021
- function toResolvedCustomBlock(manifest, source) {
136164
+ function transitionCssVarsStyle(content) {
136165
+ const transitionStyles = isObjectRecord$1(content._transitionStyles) ? content._transitionStyles : null;
136166
+ const cssVars = isObjectRecord$1(transitionStyles?.cssVars) ? transitionStyles.cssVars : null;
136167
+ const from = typeof cssVars?.from === "string" ? cssVars.from : null;
136168
+ const to = typeof cssVars?.to === "string" ? cssVars.to : null;
136169
+ if (!from && !to) return void 0;
136022
136170
  return {
136023
- blockKind: manifest.id,
136024
- manifest: transformSdkBlockToManifest(manifest),
136025
- source,
136026
- descriptor: transformToBlockDescriptor(manifest, source.kind === "managed-database" ? "database" : "sdk")
136171
+ ...from ? { "--site-style-transition-from": from } : {},
136172
+ ...to ? { "--site-style-transition-to": to } : {}
136027
136173
  };
136028
136174
  }
136029
- function planCustomBlockRegistryResolution({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy }) {
136030
- switch (policy.kind) {
136031
- case "canonical-db-fallback-sdk": {
136032
- const entriesByKind = /* @__PURE__ */ new Map();
136033
- const conflicts = [];
136034
- for (const customBlock of customBlocks) entriesByKind.set(customBlock.manifest.id, toResolvedCustomBlock(customBlock.manifest, customBlock.source));
136035
- for (const sdkBlock of sdkConfig?.customBlocks ?? []) {
136036
- const existing = entriesByKind.get(sdkBlock.id);
136037
- if (existing) {
136038
- conflicts.push({
136039
- kind: "conflict",
136040
- blockKind: existing.blockKind,
136041
- winner: existing.source,
136042
- loser: { kind: "sdk-config" },
136043
- reason: "db-canonical-sdk-fallback"
136044
- });
136045
- continue;
136046
- }
136047
- entriesByKind.set(sdkBlock.id, toResolvedCustomBlock(sdkBlock, { kind: "sdk-config" }));
136048
- }
136049
- return {
136050
- policy,
136051
- entries: Array.from(entriesByKind.values()),
136052
- conflicts
136053
- };
136054
- }
136055
- }
136056
- }
136057
- function createCustomBlockRegistry({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy, onConflict }) {
136058
- const plan = planCustomBlockRegistryResolution({
136059
- sdkConfig,
136060
- customBlocks,
136061
- policy
136062
- });
136063
- const entriesByKind = new Map(plan.entries.map((entry) => [entry.blockKind, entry]));
136064
- for (const conflict of plan.conflicts) onConflict?.(`Using ${sourceLabel(conflict.winner)} custom block "${conflict.blockKind}" - ${sourceLabel(conflict.loser)} block is fallback only`);
136175
+ function mergeStyleObjects(left, right) {
136176
+ if (!left) return right;
136177
+ if (!right) return left;
136065
136178
  return {
136066
- entries: plan.entries,
136067
- conflicts: plan.conflicts,
136068
- findManifest: (blockKind) => {
136069
- if (!isCustomBlockKind(blockKind)) return void 0;
136070
- return entriesByKind.get(blockKind);
136071
- }
136179
+ ...left,
136180
+ ...right
136072
136181
  };
136073
136182
  }
136074
- function sourceLabel(source) {
136075
- switch (source.kind) {
136076
- case "managed-database": return "DB";
136077
- case "sdk-synced": return "SDK-synced DB";
136078
- case "sdk-config": return "SDK config";
136079
- default: return assertNever$20(source);
136080
- }
136183
+ function pageBlockPosition(index, blockCount) {
136184
+ if (blockCount <= 1) return "only";
136185
+ if (index === 0) return "first";
136186
+ if (index === blockCount - 1) return "last";
136187
+ return "middle";
136081
136188
  }
136082
136189
  //#endregion
136083
136190
  //#region ../blocks/src/PageRenderer.tsx
@@ -136085,7 +136192,8 @@ init_fragments();
136085
136192
  init_colorStyles();
136086
136193
  init_typeGuards();
136087
136194
  init_media();
136088
- function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = false, dataContext, wrapBlock, wrapBoundary, registry, themeTokens: providedThemeTokens, routeMap, blockOverrides, sdkConfig, customBlocks, previewAuthoring }) {
136195
+ function PageRenderer$1(props) {
136196
+ const { page, runtimeBoundaries, usePlaceholders = false, dataContext, wrapBlock, wrapBoundary, registry, routeMap, blockOverrides, sdkConfig, customBlocks, previewAuthoring } = props;
136089
136197
  const imageResolveContext = React$1.useMemo(() => resolvePageRendererImageResolveContext(dataContext), [
136090
136198
  dataContext?.imageResolveContext,
136091
136199
  dataContext?.mediaAssets,
@@ -136094,12 +136202,16 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
136094
136202
  ]);
136095
136203
  const boundaryByAdjacentBlockIds = React$1.useMemo(() => boundaryMapForAdjacentBlockIds(runtimeBoundaries ?? []), [runtimeBoundaries]);
136096
136204
  const usesRuntimeBoundaries = runtimeBoundaries !== void 0;
136205
+ const themeResources = React$1.useMemo(() => resolvePageThemeResources(props), [
136206
+ props.rendering,
136207
+ props.theme,
136208
+ props.themeTokens
136209
+ ]);
136097
136210
  if (!page || page.blocks.length === 0) return /* @__PURE__ */ jsx("div", {
136098
136211
  className: "rb-p-6 rb-caption",
136099
136212
  style: textColorStyle("mutedText"),
136100
136213
  children: "No blocks found."
136101
136214
  });
136102
- const themeTokens = providedThemeTokens ?? buildThemeRuntime$1(theme).tokens;
136103
136215
  const resolvedRegistry = registry ?? getDefaultComponentRegistry();
136104
136216
  setContextResolveImageUrlContext(imageResolveContext);
136105
136217
  return /* @__PURE__ */ jsx("div", { children: page.blocks.map((block, index) => {
@@ -136122,22 +136234,14 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
136122
136234
  const renderableContent = getRenderableContent(block, dataContext?.previewStage);
136123
136235
  const variantKey = definition?.manifest ? resolveVariantKey(definition.manifest, renderableContent) : null;
136124
136236
  const shouldUseWrapper = !managesOwnWrapper || Boolean(wrapBlock);
136125
- const blockSectionProps = {
136126
- themeTokens,
136127
- themeConfig: theme,
136237
+ const blockSectionProps = buildBlockSectionProps({
136238
+ props,
136239
+ themeResources,
136128
136240
  block,
136129
- usePlaceholders,
136130
- dataContext,
136131
136241
  blockKey,
136132
- registry: resolvedRegistry,
136133
- routeMap,
136134
- wrapBlock,
136135
- blockOverrides,
136136
- sdkConfig,
136137
- customBlocks,
136138
136242
  imageResolveContext,
136139
- previewAuthoring
136140
- };
136243
+ registry: resolvedRegistry
136244
+ });
136141
136245
  if (!shouldUseWrapper) {
136142
136246
  const rendered = /* @__PURE__ */ jsx(MemoBlockSection, { ...blockSectionProps }, `${blockKey}:block`);
136143
136247
  return boundaryElement ? /* @__PURE__ */ jsxs(React$1.Fragment, { children: [rendered, boundaryElement] }, blockKey) : rendered;
@@ -136179,81 +136283,6 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
136179
136283
  })] }, blockKey);
136180
136284
  }) });
136181
136285
  }
136182
- function isSiteStyleTransitionStyleGroup(value) {
136183
- return value?.startsWith("site-style-transition-") === true;
136184
- }
136185
- function boundaryMapForAdjacentBlockIds(boundaries) {
136186
- return new Map(boundaries.map((boundary) => [boundaryKey(boundary.previousBlockId, boundary.nextBlockId), boundary]));
136187
- }
136188
- function boundaryKey(previousBlockId, nextBlockId) {
136189
- return `${previousBlockId}\u0000${nextBlockId}`;
136190
- }
136191
- function boundaryBetweenBlocks(previousBlock, nextBlock, boundaryByAdjacentBlockIds) {
136192
- const previousBlockId = previousBlock?.id ?? null;
136193
- const nextBlockId = nextBlock?.id ?? null;
136194
- if (!previousBlockId || !nextBlockId) return null;
136195
- return boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId)) ?? null;
136196
- }
136197
- function renderBoundaryAfterBlock(input) {
136198
- const previousBlockId = input.block.id;
136199
- const nextBlockId = input.nextBlock?.id ?? null;
136200
- if (!previousBlockId || !nextBlockId) return null;
136201
- const boundary = input.boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId));
136202
- if (!boundary) return null;
136203
- const rendered = /* @__PURE__ */ jsx("div", {
136204
- "aria-hidden": "true",
136205
- "data-block-boundary": "",
136206
- "data-boundary-id": boundary.boundaryId,
136207
- "data-boundary-previous-block-id": boundary.previousBlockId,
136208
- "data-boundary-next-block-id": boundary.nextBlockId,
136209
- "data-style-group": boundary.styleGroup,
136210
- style: boundaryCssVarsStyle(boundary)
136211
- }, `${input.blockKey}:boundary`);
136212
- return input.wrapBoundary ? input.wrapBoundary(boundary, rendered) : rendered;
136213
- }
136214
- function boundaryCssVarsStyle(boundary) {
136215
- return {
136216
- "--site-style-transition-from": boundary.cssVars.from,
136217
- "--site-style-transition-to": boundary.cssVars.to
136218
- };
136219
- }
136220
- function boundaryReserveCssVarsStyle(input) {
136221
- const before = input.before ? boundaryReserveValueForTreatment(input.before) : null;
136222
- const after = input.after ? boundaryReserveValueForTreatment(input.after) : null;
136223
- if (!before && !after) return void 0;
136224
- return {
136225
- ...before ? { "--site-style-boundary-before-reserve": before } : {},
136226
- ...after ? { "--site-style-boundary-after-reserve": after } : {}
136227
- };
136228
- }
136229
- function boundaryReserveValueForTreatment(boundary) {
136230
- return boundary.metrics.reserveCss;
136231
- }
136232
- function transitionCssVarsStyle(content) {
136233
- const transitionStyles = isObjectRecord$1(content._transitionStyles) ? content._transitionStyles : null;
136234
- const cssVars = isObjectRecord$1(transitionStyles?.cssVars) ? transitionStyles.cssVars : null;
136235
- const from = typeof cssVars?.from === "string" ? cssVars.from : null;
136236
- const to = typeof cssVars?.to === "string" ? cssVars.to : null;
136237
- if (!from && !to) return void 0;
136238
- return {
136239
- ...from ? { "--site-style-transition-from": from } : {},
136240
- ...to ? { "--site-style-transition-to": to } : {}
136241
- };
136242
- }
136243
- function mergeStyleObjects(left, right) {
136244
- if (!left) return right;
136245
- if (!right) return left;
136246
- return {
136247
- ...left,
136248
- ...right
136249
- };
136250
- }
136251
- function pageBlockPosition(index, blockCount) {
136252
- if (blockCount <= 1) return "only";
136253
- if (index === 0) return "first";
136254
- if (index === blockCount - 1) return "last";
136255
- return "middle";
136256
- }
136257
136286
  function resolvePageRendererImageResolveContext(dataContext) {
136258
136287
  const input = dataContext?.imageResolveContext;
136259
136288
  return buildResolveImageUrlContext({
@@ -136263,6 +136292,23 @@ function resolvePageRendererImageResolveContext(dataContext) {
136263
136292
  mediaAssets: input?.mediaAssets ?? dataContext?.mediaAssets
136264
136293
  });
136265
136294
  }
136295
+ function buildBlockSectionProps(input) {
136296
+ return {
136297
+ themeResources: input.themeResources,
136298
+ block: input.block,
136299
+ usePlaceholders: input.props.usePlaceholders ?? false,
136300
+ dataContext: input.props.dataContext,
136301
+ blockKey: input.blockKey,
136302
+ registry: input.registry,
136303
+ routeMap: input.props.routeMap,
136304
+ wrapBlock: input.props.wrapBlock,
136305
+ blockOverrides: input.props.blockOverrides,
136306
+ sdkConfig: input.props.sdkConfig,
136307
+ customBlocks: input.props.customBlocks,
136308
+ imageResolveContext: input.imageResolveContext,
136309
+ previewAuthoring: input.props.previewAuthoring
136310
+ };
136311
+ }
136266
136312
  /**
136267
136313
  * Look up a block override component by block kind.
136268
136314
  * Supports both full ("block.hero") and short ("hero") keys.
@@ -136329,7 +136375,7 @@ function getCachedValidator(manifest, flavour) {
136329
136375
  * referential equality of all props that affect rendering. Standard React.memo
136330
136376
  * wouldn't catch all the render triggers from the editor store.
136331
136377
  */
136332
- const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, themeConfig, block, usePlaceholders, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
136378
+ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources, block, usePlaceholders, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
136333
136379
  const perfStart = globalThis.process?.env?.DEBUG_PERF === "1" && typeof window === "undefined" ? Date.now() : 0;
136334
136380
  const fallbackImageResolveContext = getCurrentResolveImageUrlContext();
136335
136381
  const resolvedImageResolveContext = imageResolveContext ?? fallbackImageResolveContext;
@@ -136350,6 +136396,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
136350
136396
  return node;
136351
136397
  }
136352
136398
  const OverrideComponent = getBlockOverride(block.kind, blockOverrides);
136399
+ requireBlockOverride(themeResources, OverrideComponent, block.kind);
136353
136400
  let definition = getBlockDefinition(block.kind);
136354
136401
  if (!definition && block.kind.startsWith("custom.")) definition = createCustomBlockRegistry({
136355
136402
  sdkConfig,
@@ -136362,8 +136409,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
136362
136409
  if (OverrideComponent) {
136363
136410
  const rendered = /* @__PURE__ */ jsx(OverrideComponent, {
136364
136411
  content: getRenderableContent(block, dataContext?.previewStage),
136365
- theme: themeTokens,
136366
- themeConfig,
136412
+ ...overrideThemeProps(themeResources),
136367
136413
  data: void 0,
136368
136414
  siteId: dataContext?.siteId,
136369
136415
  apiBaseUrl: dataContext?.apiBaseUrl,
@@ -136462,8 +136508,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
136462
136508
  const hasResolvedData = !!resolved && typeof resolved === "object" && Object.keys(resolved).length > 0;
136463
136509
  const baseProps = {
136464
136510
  content: hydratedContent,
136465
- theme: themeTokens,
136466
- themeConfig,
136511
+ ...overrideThemeProps(themeResources),
136467
136512
  data: resolved,
136468
136513
  siteId: dataContext?.siteId,
136469
136514
  apiBaseUrl: dataContext?.apiBaseUrl,
@@ -136483,6 +136528,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
136483
136528
  let rendered;
136484
136529
  if (OverrideComponent) rendered = /* @__PURE__ */ jsx(OverrideComponent, { ...baseProps });
136485
136530
  else {
136531
+ requireThemeResources(themeResources, block.kind);
136486
136532
  const BlockComponent = getCachedBlockComponent(definition.manifest);
136487
136533
  const pathBase = typeof block.id === "string" && block.id.length > 0 ? `blocks.${block.id}.` : void 0;
136488
136534
  const rootContext = { $root: {
@@ -136532,7 +136578,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
136532
136578
  });
136533
136579
  }
136534
136580
  }, (prev, next) => {
136535
- 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;
136581
+ 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;
136536
136582
  });
136537
136583
  function fallback(message) {
136538
136584
  return /* @__PURE__ */ jsx("div", {
@@ -149769,6 +149815,10 @@ function buildThemeRuntime(theme) {
149769
149815
  }
149770
149816
  //#endregion
149771
149817
  //#region src/rendering/blocks-page-renderer.ts
149818
+ const MissingBlockOverrideError = MissingBlockOverrideError$1;
149819
+ function isOverrideOnlyPageRenderer(props) {
149820
+ return props.rendering?.kind === "overrides-only";
149821
+ }
149772
149822
  function normalizeSdkCustomBlocks(customBlocks) {
149773
149823
  if (!customBlocks) return void 0;
149774
149824
  return customBlocks.map((block) => {
@@ -149799,15 +149849,23 @@ function toBlocksPageRendererDataContext(dataContext) {
149799
149849
  }
149800
149850
  function PageRenderer(props) {
149801
149851
  const blocksSdkConfig = props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig;
149802
- const blocksTheme = parseBlocksTheme(props.theme);
149803
- const blocksProps = {
149804
- ...props,
149805
- theme: blocksTheme,
149852
+ const { rendering: _rendering, theme: _theme, themeTokens: _themeTokens, ...commonProps } = props;
149853
+ const commonBlocksProps = {
149854
+ ...commonProps,
149806
149855
  dataContext: props.dataContext ? toBlocksPageRendererDataContext(props.dataContext) : void 0,
149807
149856
  blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
149808
149857
  sdkConfig: blocksSdkConfig,
149809
149858
  customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
149810
149859
  };
149860
+ const blocksProps = isOverrideOnlyPageRenderer(props) ? {
149861
+ ...commonBlocksProps,
149862
+ rendering: { kind: "overrides-only" },
149863
+ blockOverrides: toBlocksBlockOverrides(props.blockOverrides) ?? {}
149864
+ } : {
149865
+ ...commonBlocksProps,
149866
+ theme: parseBlocksTheme(props.theme),
149867
+ themeTokens: props.themeTokens
149868
+ };
149811
149869
  return React$1.createElement(PageRenderer$1, blocksProps);
149812
149870
  }
149813
149871
  //#endregion
@@ -149850,8 +149908,31 @@ function renderWithSdkThemeRuntime({ themeRuntime, theme, children }) {
149850
149908
  default: return assertNever$20(themeRuntime);
149851
149909
  }
149852
149910
  }
149911
+ function renderWithOverrideOnlyRuntime({ runtime, children }) {
149912
+ switch (runtime.kind) {
149913
+ case "responsive-only": return /* @__PURE__ */ jsx(ResponsiveScope, {
149914
+ responsiveMode: runtime.responsiveMode,
149915
+ children
149916
+ });
149917
+ case "none": return /* @__PURE__ */ jsx(Fragment, { children });
149918
+ default: return assertNever$20(runtime);
149919
+ }
149920
+ }
149853
149921
  //#endregion
149854
149922
  //#region src/rendering/components/pageShared.tsx
149923
+ function isOverrideOnlyPage(props) {
149924
+ return props.rendering?.kind === "overrides-only";
149925
+ }
149926
+ function resolvePageThemeTokens(props) {
149927
+ const baseTokens = props.themeTokens ?? buildThemeRuntime(props.theme).tokens;
149928
+ return props.sdkConfig?.theme?.palette ? {
149929
+ ...baseTokens,
149930
+ palette: {
149931
+ ...baseTokens.palette,
149932
+ ...props.sdkConfig.theme.palette
149933
+ }
149934
+ } : baseTokens;
149935
+ }
149855
149936
  function toPageHydrationBootstrapConfig(props) {
149856
149937
  return {
149857
149938
  siteId: props.siteId,
@@ -149859,55 +149940,60 @@ function toPageHydrationBootstrapConfig(props) {
149859
149940
  mediaAssets: props.mediaAssets
149860
149941
  };
149861
149942
  }
149862
- 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 }) {
149863
- const baseTokens = providedTokens ?? buildThemeRuntime(theme).tokens;
149864
- return renderWithSdkThemeRuntime({
149865
- themeRuntime,
149866
- theme,
149867
- children: /* @__PURE__ */ jsx(PageRenderer, {
149868
- theme,
149869
- page,
149870
- runtimeBoundaries,
149871
- themeTokens: sdkConfig?.theme?.palette ? {
149872
- ...baseTokens,
149873
- palette: {
149874
- ...baseTokens.palette,
149875
- ...sdkConfig.theme.palette
149876
- }
149877
- } : baseTokens,
149878
- usePlaceholders,
149879
- dataContext: {
149943
+ function PageContent(props) {
149944
+ const { page, runtimeBoundaries, siteId, resolvedData, bookingOfferingPresets, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, usePlaceholders = false, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext } = props;
149945
+ const rendererCommonProps = {
149946
+ page,
149947
+ runtimeBoundaries,
149948
+ usePlaceholders,
149949
+ dataContext: {
149950
+ siteId,
149951
+ apiBaseUrl,
149952
+ portalToken,
149953
+ previewToken,
149954
+ resolvedData,
149955
+ bookingOfferingPresets: bookingOfferingPresets ?? [],
149956
+ routes: routeMap,
149957
+ pagesByIdentifier,
149958
+ entriesByIdentifier,
149959
+ occurrenceContext: dataContext?.occurrenceContext ?? null,
149960
+ entrySubrouteContext: dataContext?.entrySubrouteContext ?? null,
149961
+ contentEntry: dataContext?.contentEntry ?? null,
149962
+ pageSurface: dataContext?.pageSurface ?? null,
149963
+ subject: dataContext?.subject ?? null,
149964
+ editableRouteMetadataFieldIds: dataContext?.editableRouteMetadataFieldIds ?? null,
149965
+ previewStage: dataContext?.previewStage,
149966
+ supabaseUrl,
149967
+ mediaAssets,
149968
+ imageResolveContext: {
149880
149969
  siteId,
149881
- apiBaseUrl,
149882
- portalToken,
149883
- previewToken,
149884
- resolvedData,
149885
- bookingOfferingPresets: bookingOfferingPresets ?? [],
149886
- routes: routeMap,
149887
- pagesByIdentifier,
149888
- entriesByIdentifier,
149889
- occurrenceContext: dataContext?.occurrenceContext ?? null,
149890
- entrySubrouteContext: dataContext?.entrySubrouteContext ?? null,
149891
- contentEntry: dataContext?.contentEntry ?? null,
149892
- pageSurface: dataContext?.pageSurface ?? null,
149893
- subject: dataContext?.subject ?? null,
149894
- editableRouteMetadataFieldIds: dataContext?.editableRouteMetadataFieldIds ?? null,
149895
- previewStage: dataContext?.previewStage,
149896
149970
  supabaseUrl,
149897
- mediaAssets,
149898
- imageResolveContext: {
149899
- siteId,
149900
- supabaseUrl,
149901
- mediaAssets
149902
- }
149903
- },
149904
- routeMap,
149905
- wrapBlock,
149906
- registry,
149907
- blockOverrides,
149908
- sdkConfig: sdkConfig ? { customBlocks: sdkConfig.customBlocks } : null,
149909
- customBlocks
149910
- })
149971
+ mediaAssets
149972
+ }
149973
+ },
149974
+ routeMap,
149975
+ wrapBlock,
149976
+ registry,
149977
+ sdkConfig: sdkConfig ? { customBlocks: sdkConfig.customBlocks } : null,
149978
+ customBlocks
149979
+ };
149980
+ const content = isOverrideOnlyPage(props) ? /* @__PURE__ */ jsx(PageRenderer, {
149981
+ ...rendererCommonProps,
149982
+ rendering: { kind: "overrides-only" },
149983
+ blockOverrides: props.blockOverrides
149984
+ }) : /* @__PURE__ */ jsx(PageRenderer, {
149985
+ ...rendererCommonProps,
149986
+ theme: props.theme,
149987
+ themeTokens: resolvePageThemeTokens(props),
149988
+ blockOverrides
149989
+ });
149990
+ return isOverrideOnlyPage(props) ? renderWithOverrideOnlyRuntime({
149991
+ runtime: props.rendering.runtime,
149992
+ children: content
149993
+ }) : renderWithSdkThemeRuntime({
149994
+ themeRuntime: props.themeRuntime ?? defaultPageThemeRuntime,
149995
+ theme: props.theme,
149996
+ children: content
149911
149997
  });
149912
149998
  }
149913
149999
  //#endregion
@@ -150430,12 +150516,48 @@ function buildLogo(logo, fallbackAlt) {
150430
150516
  return result;
150431
150517
  }
150432
150518
  //#endregion
150519
+ //#region src/rendering/renderingMode.ts
150520
+ const defaultOverrideOnlyRuntime = { kind: "responsive-only" };
150521
+ //#endregion
150433
150522
  //#region src/rendering/components/Layout.tsx
150434
150523
  /**
150435
150524
  * Layout component with header and footer
150436
150525
  *
150437
150526
  * Renders site header and footer around content. Fetches site data if not provided.
150438
150527
  */
150528
+ function isOverrideOnlyLayout(props) {
150529
+ return props.rendering?.kind === "overrides-only";
150530
+ }
150531
+ var UnsupportedOverrideOnlyLayoutChromeError = class extends Error {
150532
+ constructor(surface) {
150533
+ super(`Override-only Layout requires a custom or disabled ${surface}; SDK default chrome is unavailable.`);
150534
+ this.surface = surface;
150535
+ this.code = "unsupported_override_only_layout_chrome";
150536
+ this.name = "UnsupportedOverrideOnlyLayoutChromeError";
150537
+ }
150538
+ };
150539
+ async function resolveLayoutSiteData(props) {
150540
+ if (props.siteData) return props.siteData;
150541
+ if (!props.client) throw new Error("Layout: must provide either siteData or client");
150542
+ if (!props.siteId && !props.slug && !props.domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
150543
+ return props.client.getSite({
150544
+ id: props.siteId,
150545
+ slug: props.slug,
150546
+ domain: props.domain
150547
+ });
150548
+ }
150549
+ function renderOverrideOnlyLayout(props, data) {
150550
+ if (data.header === true) throw new UnsupportedOverrideOnlyLayoutChromeError("header");
150551
+ if (data.footer === true) throw new UnsupportedOverrideOnlyLayoutChromeError("footer");
150552
+ return renderWithOverrideOnlyRuntime({
150553
+ runtime: props.rendering.runtime ?? defaultOverrideOnlyRuntime,
150554
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
150555
+ typeof props.header === "function" ? props.header(data.headerData) : null,
150556
+ props.children,
150557
+ typeof props.footer === "function" ? props.footer(data.footerData) : null
150558
+ ] })
150559
+ });
150560
+ }
150439
150561
  /**
150440
150562
  * Layout component that wraps content with site header and footer.
150441
150563
  *
@@ -150471,20 +150593,13 @@ function buildLogo(logo, fallbackAlt) {
150471
150593
  * </Layout>
150472
150594
  * ```
150473
150595
  */
150474
- async function Layout({ siteData: providedSiteData, client, siteId, slug, domain, children, header = true, footer = true, headerVariant, hasPortalSession = false, previewStage = "published", themeRuntime }) {
150475
- let siteData = providedSiteData;
150476
- if (!siteData) {
150477
- if (!client) throw new Error("Layout: must provide either siteData or client");
150478
- if (!siteId && !slug && !domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
150479
- siteData = await client.getSite({
150480
- id: siteId,
150481
- slug,
150482
- domain
150483
- });
150484
- }
150485
- const { site, theme, navigation, layout, routes } = siteData;
150596
+ async function Layout(props) {
150597
+ const { children, hasPortalSession = false, previewStage = "published" } = props;
150598
+ const header = props.header ?? true;
150599
+ const footer = props.footer ?? true;
150600
+ const siteData = await resolveLayoutSiteData(props);
150601
+ const { site, navigation, layout, routes } = siteData;
150486
150602
  const footerBlocks = siteData.footerBlocks ?? [];
150487
- const builtThemeRuntime = buildThemeRuntime(theme);
150488
150603
  const navigationOptions = {
150489
150604
  hasPortalSession,
150490
150605
  previewStage,
@@ -150498,22 +150613,38 @@ async function Layout({ siteData: providedSiteData, client, siteId, slug, domain
150498
150613
  const footerMenuViewModel = buildFooterMenu(navigation, routes, navigationOptions);
150499
150614
  const legalFooterMenuViewModel = buildFooterMenuForRole(navigation, routes, "legal-policy", navigationOptions);
150500
150615
  const logoViewModel = buildLogo(layout.logo ?? null, site.title);
150501
- const headerData = {
150616
+ const customHeaderData = {
150502
150617
  menu: menuViewModel,
150503
150618
  logo: logoViewModel,
150504
150619
  site,
150505
- theme,
150506
150620
  routes
150507
150621
  };
150508
- const footerData = {
150622
+ const customFooterData = {
150509
150623
  menu: menuViewModel,
150510
150624
  footerMenu: footerMenuViewModel,
150511
150625
  legalFooterMenu: legalFooterMenuViewModel,
150512
150626
  logo: logoViewModel,
150513
150627
  site,
150514
- theme,
150515
150628
  routes
150516
150629
  };
150630
+ if (isOverrideOnlyLayout(props)) return renderOverrideOnlyLayout(props, {
150631
+ header: props.header ?? true,
150632
+ footer: props.footer ?? true,
150633
+ headerData: customHeaderData,
150634
+ footerData: customFooterData
150635
+ });
150636
+ const { theme } = siteData;
150637
+ const builtThemeRuntime = buildThemeRuntime(theme);
150638
+ const headerVariant = props.headerVariant;
150639
+ const themeRuntime = props.themeRuntime;
150640
+ const headerData = {
150641
+ ...customHeaderData,
150642
+ theme
150643
+ };
150644
+ const footerData = {
150645
+ ...customFooterData,
150646
+ theme
150647
+ };
150517
150648
  const headerContent = headerVariant ? {
150518
150649
  ...layout.header,
150519
150650
  variant: headerVariant
@@ -153991,6 +154122,17 @@ async function prefetchBlockDataWithDeps(deps, page, context, client, options) {
153991
154122
  * hydration; the strict `@riverbankcms/sdk/rendering/server` surface exports it
153992
154123
  * directly.
153993
154124
  */
154125
+ function isOverrideOnlyBlock(props) {
154126
+ return props.rendering?.kind === "overrides-only";
154127
+ }
154128
+ var MissingStandaloneBlockOverrideError = class extends Error {
154129
+ constructor(blockKind) {
154130
+ super(`Override-only standalone rendering requires an override for block kind "${blockKind}".`);
154131
+ this.blockKind = blockKind;
154132
+ this.code = "missing_standalone_block_override";
154133
+ this.name = "MissingStandaloneBlockOverrideError";
154134
+ }
154135
+ };
153994
154136
  function toBlockHydrationBootstrapConfig(props) {
153995
154137
  return {
153996
154138
  siteId: props.siteId,
@@ -154060,14 +154202,16 @@ function buildStandaloneBlockViewModel({ siteId, pageId, previewStage, apiBaseUr
154060
154202
  function renderBlockOverride({ OverrideComponent, props, runtime, resolvedData }) {
154061
154203
  return /* @__PURE__ */ jsx(OverrideComponent, {
154062
154204
  content: props.content,
154063
- theme: runtime.themeRuntime.tokens,
154064
- themeConfig: props.theme,
154205
+ ...runtime && "theme" in props ? {
154206
+ theme: runtime.themeRuntime.tokens,
154207
+ themeConfig: props.theme
154208
+ } : {},
154065
154209
  data: resolvedData,
154066
154210
  siteId: props.siteId,
154067
154211
  apiBaseUrl: props.apiBaseUrl,
154068
154212
  portalToken: props.portalToken ?? null,
154069
154213
  supabaseUrl: props.supabaseUrl,
154070
- imageResolveContext: runtime.imageResolveContext,
154214
+ imageResolveContext: runtime?.imageResolveContext,
154071
154215
  blockId: props.blockId ?? null,
154072
154216
  blockKind: props.blockKind
154073
154217
  });
@@ -154096,8 +154240,8 @@ function renderManifestBlock({ definition, props, runtime, resolvedData }) {
154096
154240
  async function BlockContent(props) {
154097
154241
  const definition = getBlockDefinition(props.blockKind);
154098
154242
  const OverrideComponent = props.override;
154243
+ if (isOverrideOnlyBlock(props) && !OverrideComponent) throw new MissingStandaloneBlockOverrideError(props.blockKind);
154099
154244
  if (!definition && !OverrideComponent) return renderUnknownBlock(props.blockKind);
154100
- const runtime = buildBlockContentRuntime(props);
154101
154245
  const resolvedData = await loadStandaloneBlockData({
154102
154246
  ...props,
154103
154247
  hasDefinition: Boolean(definition)
@@ -154105,13 +154249,14 @@ async function BlockContent(props) {
154105
154249
  if (OverrideComponent) return renderBlockOverride({
154106
154250
  OverrideComponent,
154107
154251
  props,
154108
- runtime,
154252
+ runtime: isOverrideOnlyBlock(props) ? void 0 : buildBlockContentRuntime(props),
154109
154253
  resolvedData
154110
154254
  });
154255
+ if (isOverrideOnlyBlock(props)) throw new MissingStandaloneBlockOverrideError(props.blockKind);
154111
154256
  return renderManifestBlock({
154112
154257
  definition,
154113
154258
  props,
154114
- runtime,
154259
+ runtime: buildBlockContentRuntime(props),
154115
154260
  resolvedData
154116
154261
  });
154117
154262
  }
@@ -157923,4 +158068,4 @@ function defineBlockOverrideRegistrations(registrations) {
157923
158068
  * ```
157924
158069
  */
157925
158070
  //#endregion
157926
- export { Block, ImagePresets, Layout, Page, PageRenderer, RichText, ThemeScope, buildThemeRuntime, defineBlockOverrideRegistrations, defineBlockOverrides, defineLazyBlockOverride, isEntryContent, isPageContent, isPageSurfaceContent, loadContent, loadPage, resolveImageSourceSetWithContext, resolveImageUrl, resolveImageUrlWithContext, toBlocksImageResolveContextInput, toBlocksMediaAssets, toBlocksPageRendererDataContext };
158071
+ 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 };