@amplifyup/sdk 0.1.78 → 0.1.79

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 (48) hide show
  1. package/README.md +91 -28
  2. package/dist/AmplifyRenderer-BNWBrFQN.d.ts +47 -0
  3. package/dist/AmplifyRenderer-CPUr9Bkc.d.mts +47 -0
  4. package/dist/AmplifyRenderer.d.mts +4 -40
  5. package/dist/AmplifyRenderer.d.ts +4 -40
  6. package/dist/AmplifyRenderer.js +106 -14
  7. package/dist/AmplifyRenderer.js.map +1 -1
  8. package/dist/AmplifyRenderer.mjs +106 -14
  9. package/dist/AmplifyRenderer.mjs.map +1 -1
  10. package/dist/cli.d.mts +1 -0
  11. package/dist/cli.d.ts +1 -0
  12. package/dist/cli.js +266 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/cli.mjs +260 -0
  15. package/dist/cli.mjs.map +1 -0
  16. package/dist/config.d.mts +18 -0
  17. package/dist/config.d.ts +18 -0
  18. package/dist/config.js +10 -0
  19. package/dist/config.js.map +1 -0
  20. package/dist/config.mjs +8 -0
  21. package/dist/config.mjs.map +1 -0
  22. package/dist/index.d.mts +3 -3
  23. package/dist/index.d.ts +3 -3
  24. package/dist/index.js +2 -2
  25. package/dist/index.js.map +1 -1
  26. package/dist/index.mjs +2 -2
  27. package/dist/index.mjs.map +1 -1
  28. package/dist/next.d.mts +9 -0
  29. package/dist/next.d.ts +9 -0
  30. package/dist/next.js +259 -0
  31. package/dist/next.js.map +1 -0
  32. package/dist/next.mjs +253 -0
  33. package/dist/next.mjs.map +1 -0
  34. package/dist/query-DYjs4LQQ.d.mts +262 -0
  35. package/dist/query-Xo9cy-2F.d.ts +262 -0
  36. package/dist/react.d.mts +19 -21
  37. package/dist/react.d.ts +19 -21
  38. package/dist/react.js +1141 -1035
  39. package/dist/react.js.map +1 -1
  40. package/dist/react.mjs +1140 -1035
  41. package/dist/react.mjs.map +1 -1
  42. package/dist/server.d.mts +3 -3
  43. package/dist/server.d.ts +3 -3
  44. package/dist/{types-D4TSd2Yt.d.mts → types-ffQNIQCK.d.mts} +1 -102
  45. package/dist/{types-D4TSd2Yt.d.ts → types-ffQNIQCK.d.ts} +1 -102
  46. package/package.json +17 -2
  47. package/dist/query-B23UsNIv.d.ts +0 -161
  48. package/dist/query-CV8x3oQT.d.mts +0 -161
package/dist/react.js CHANGED
@@ -4120,711 +4120,159 @@ function MaybeComposerProvider({
4120
4120
  }) {
4121
4121
  return /* @__PURE__ */ jsxRuntime.jsx(ComposerProvider, { enabled, children: /* @__PURE__ */ jsxRuntime.jsx(ComposerNodeContext.Provider, { value: enabled ? layoutNodeId : void 0, children }) });
4122
4122
  }
4123
- function nodeRenderProps(node) {
4124
- const settings = node.settings || {};
4125
- const hydrated = hydratePageResourceProps(
4126
- node.props || {},
4127
- getPageResourceFields()
4128
- );
4129
- const fields = hydrated.fields;
4130
- const branded = isBrandedFields(fields) ? fields : brandFields(
4131
- fields && typeof fields === "object" ? fields : {}
4123
+ function AddComponentIcon({ size = 28 }) {
4124
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4125
+ "svg",
4126
+ {
4127
+ width: size,
4128
+ height: size,
4129
+ viewBox: "0 0 24 24",
4130
+ fill: "none",
4131
+ xmlns: "http://www.w3.org/2000/svg",
4132
+ "aria-hidden": "true",
4133
+ focusable: "false",
4134
+ children: [
4135
+ /* @__PURE__ */ jsxRuntime.jsx(
4136
+ "rect",
4137
+ {
4138
+ x: "3",
4139
+ y: "3",
4140
+ width: "18",
4141
+ height: "18",
4142
+ rx: "4",
4143
+ stroke: "currentColor",
4144
+ strokeWidth: "1.75"
4145
+ }
4146
+ ),
4147
+ /* @__PURE__ */ jsxRuntime.jsx(
4148
+ "path",
4149
+ {
4150
+ d: "M12 8v8M8 12h8",
4151
+ stroke: "currentColor",
4152
+ strokeWidth: "1.75",
4153
+ strokeLinecap: "round"
4154
+ }
4155
+ )
4156
+ ]
4157
+ }
4132
4158
  );
4133
- return {
4134
- ...settings,
4135
- ...hydrated,
4136
- fields: branded
4137
- };
4138
4159
  }
4139
- var ComponentRenderBoundary = class extends React3.Component {
4140
- constructor() {
4141
- super(...arguments);
4142
- this.state = { error: null };
4143
- }
4144
- static getDerivedStateFromError(error) {
4145
- return { error };
4146
- }
4147
- componentDidCatch(error) {
4148
- console.error(
4149
- `[AmplifyRenderer] "${this.props.componentId}" (${this.props.nodeId}) threw while rendering:`,
4150
- error
4151
- );
4152
- }
4153
- render() {
4154
- if (this.state.error) {
4155
- if (process.env.NODE_ENV !== "production") {
4156
- return /* @__PURE__ */ jsxRuntime.jsxs(
4157
- "div",
4160
+ function EmptySlotHint({
4161
+ label = "Click here to Add Component",
4162
+ compact = false
4163
+ }) {
4164
+ const iconSize = compact ? 20 : 28;
4165
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4166
+ "div",
4167
+ {
4168
+ className: "amplifyup-slot-placeholder",
4169
+ style: {
4170
+ display: "flex",
4171
+ flexDirection: "column",
4172
+ alignItems: "center",
4173
+ justifyContent: "center",
4174
+ gap: compact ? 8 : 12,
4175
+ minHeight: compact ? 60 : void 0,
4176
+ width: "100%",
4177
+ pointerEvents: "none",
4178
+ textAlign: "center",
4179
+ boxSizing: "border-box",
4180
+ padding: compact ? "12px 8px" : "24px 16px"
4181
+ },
4182
+ children: [
4183
+ /* @__PURE__ */ jsxRuntime.jsx(
4184
+ "span",
4158
4185
  {
4159
- "data-amplifyup-render-error": "",
4160
- "data-component-id": this.props.componentId,
4161
- "data-node-id": this.props.nodeId,
4186
+ className: "amplifyup-slot-placeholder-icon",
4162
4187
  style: {
4163
- margin: "1rem 0",
4164
- padding: "0.75rem 1rem",
4165
- border: "1px solid #fca5a5",
4166
- borderRadius: "0.5rem",
4167
- background: "#fef2f2",
4168
- color: "#991b1b",
4169
- fontSize: "0.875rem"
4188
+ display: "inline-flex",
4189
+ alignItems: "center",
4190
+ justifyContent: "center",
4191
+ width: compact ? 36 : 48,
4192
+ height: compact ? 36 : 48,
4193
+ borderRadius: 12,
4194
+ border: "1.5px dashed currentColor",
4195
+ opacity: 0.9
4170
4196
  },
4171
- children: [
4172
- 'Component "',
4173
- this.props.componentId,
4174
- '" failed to render:',
4175
- " ",
4176
- this.state.error.message
4177
- ]
4197
+ children: /* @__PURE__ */ jsxRuntime.jsx(AddComponentIcon, { size: iconSize })
4178
4198
  }
4179
- );
4180
- }
4181
- return null;
4199
+ ),
4200
+ /* @__PURE__ */ jsxRuntime.jsx(
4201
+ "span",
4202
+ {
4203
+ className: "amplifyup-slot-placeholder-label",
4204
+ style: {
4205
+ fontSize: compact ? 13 : 15,
4206
+ fontWeight: 600,
4207
+ lineHeight: 1.3,
4208
+ letterSpacing: "0.01em"
4209
+ },
4210
+ children: label
4211
+ }
4212
+ )
4213
+ ]
4182
4214
  }
4183
- return this.props.children;
4215
+ );
4216
+ }
4217
+ var ComposerLayoutStatusContext = React3.createContext({
4218
+ ready: true
4219
+ });
4220
+ function ComposerLayoutStatusProvider({
4221
+ ready,
4222
+ children
4223
+ }) {
4224
+ return /* @__PURE__ */ jsxRuntime.jsx(ComposerLayoutStatusContext.Provider, { value: { ready }, children });
4225
+ }
4226
+ function useComposerLayoutStatus() {
4227
+ return React3.useContext(ComposerLayoutStatusContext);
4228
+ }
4229
+
4230
+ // src/slot-state.ts
4231
+ function resolveSlotState(opts) {
4232
+ if (!opts.layoutReady) return "loading";
4233
+ return opts.hasContent ? "filled" : "empty";
4234
+ }
4235
+ function slotShowsAddComponent(state) {
4236
+ return state === "empty";
4237
+ }
4238
+ function slotStateFromEl(el) {
4239
+ if (!el) return null;
4240
+ const explicit = el.getAttribute("data-slot-state");
4241
+ if (explicit === "loading" || explicit === "empty" || explicit === "filled") {
4242
+ return explicit;
4184
4243
  }
4185
- };
4186
- function NodeWithFields({
4187
- nodeId,
4188
- componentId,
4189
- props,
4244
+ if (el.getAttribute("data-slot-empty") === "true") return "empty";
4245
+ return null;
4246
+ }
4247
+
4248
+ // src/composer-edit-mode.ts
4249
+ function isComposerEditMode() {
4250
+ if (typeof window === "undefined") return false;
4251
+ return isComposerPreview() && window.__AMPLIFYUP_EVENT_SELECTION__ !== true;
4252
+ }
4253
+ function subscribeComposerEdit(onStoreChange) {
4254
+ if (typeof window === "undefined") return () => {
4255
+ };
4256
+ window.addEventListener("amplifyup:composer-edit", onStoreChange);
4257
+ return () => window.removeEventListener("amplifyup:composer-edit", onStoreChange);
4258
+ }
4259
+ function getComposerEditModeServer() {
4260
+ return false;
4261
+ }
4262
+ var ComponentContext = React3.createContext(null);
4263
+ function ComponentContextProvider({
4264
+ children,
4190
4265
  slots,
4191
- renderComponent,
4192
- composerPreview
4193
- }) {
4194
- return /* @__PURE__ */ jsxRuntime.jsx(MaybeComposerProvider, { enabled: !!composerPreview, layoutNodeId: nodeId, children: renderComponent(componentId, props, slots, {
4195
- layoutNodeId: nodeId
4196
- }) });
4197
- }
4198
- function AmplifyRendererInner({
4199
- renderComponent,
4200
- pageConfig: serverPageConfig,
4201
- loadingComponent,
4202
- errorComponent,
4203
- emptyComponent,
4204
- composerPreview
4266
+ props,
4267
+ layoutNodeId,
4268
+ componentId
4205
4269
  }) {
4206
- const clientHook = useAmplifyUp();
4207
- useRegisterPageContent(!serverPageConfig);
4208
- const composerPreviewFlag = useComposerPreviewFlag(!!composerPreview);
4209
- const pageConfig = serverPageConfig || clientHook.pageConfig || null;
4210
- const loading = serverPageConfig ? false : clientHook.loading;
4211
- const error = serverPageConfig ? null : clientHook.error;
4212
- const contentSource = clientHook.source;
4213
- const [variantCache, setVariantCache] = React3.useState({});
4214
- React3.useEffect(() => {
4215
- if (typeof window !== "undefined") {
4216
- if (window.__AMPLIFYUP_PREVIEW_MODE__ === true) {
4217
- return;
4218
- }
4219
- if (window.location.pathname.includes("/api/pages/proxy")) {
4220
- return;
4221
- }
4222
- if (window.self !== window.top) {
4223
- return;
4224
- }
4225
- const urlParams = new URLSearchParams(window.location.search);
4226
- if (urlParams.get("preview") === "true" || urlParams.get("visualEditor") === "true") {
4227
- return;
4228
- }
4229
- if (window.location.href.includes("preview=true") || window.location.href.includes("visualEditor=true")) {
4230
- return;
4231
- }
4232
- }
4233
- if (pageConfig && pageConfig.id !== "default") {
4234
- trackContentView(pageConfig.id, "page", {
4235
- route: pageConfig.route,
4236
- title: pageConfig.title
4237
- });
4238
- }
4239
- }, [pageConfig]);
4240
- React3.useEffect(() => {
4241
- if (!pageConfig?.eventTracking?.length) return;
4242
- const sdk = getSDK();
4243
- if (!sdk.isInitialized()) return;
4244
- sdk.setupEventTracking(pageConfig.eventTracking);
4245
- const t1 = window.setTimeout(() => {
4246
- sdk.setupComponentViewTracking();
4247
- refreshEventTracking();
4248
- }, 200);
4249
- const t2 = window.setTimeout(() => {
4250
- sdk.setupComponentViewTracking();
4251
- refreshEventTracking();
4252
- }, 1e3);
4253
- return () => {
4254
- window.clearTimeout(t1);
4255
- window.clearTimeout(t2);
4256
- };
4257
- }, [pageConfig?.id, pageConfig?.eventTracking]);
4258
- React3.useEffect(() => {
4259
- if (!pageConfig) return;
4260
- const t = window.setTimeout(() => {
4261
- getSDK().setupComponentViewTracking();
4262
- refreshEventTracking();
4263
- }, 100);
4264
- return () => window.clearTimeout(t);
4265
- }, [variantCache, pageConfig?.id]);
4266
- React3.useEffect(() => {
4267
- if (!isComposerPreview()) {
4268
- return;
4269
- }
4270
- if (!pageConfig) {
4271
- return;
4272
- }
4273
- const rawTree2 = pageConfig.layoutTree;
4274
- const normalizedTree = Array.isArray(rawTree2) ? rawTree2 : rawTree2 && typeof rawTree2 === "object" && rawTree2.componentId ? [rawTree2] : [];
4275
- if (normalizedTree.length === 0) {
4276
- if (typeof window !== "undefined" && window.parent && window.parent !== window) {
4277
- window.parent.postMessage({
4278
- type: "COMPONENT_TREE",
4279
- tree: []
4280
- }, "*");
4281
- }
4282
- return;
4283
- }
4284
- const convertLayoutTreeToComponentTree = (nodes, parentId = null) => {
4285
- const result = [];
4286
- nodes.forEach((node) => {
4287
- if (!node) return;
4288
- const treeNode = {
4289
- id: node.id,
4290
- componentId: node.componentId,
4291
- componentName: node.componentId,
4292
- // Will be enhanced with actual name if available
4293
- parentId,
4294
- children: []
4295
- };
4296
- if (node.slots && node.slots.length > 0) {
4297
- node.slots.forEach((slot) => {
4298
- const kids = Array.isArray(slot?.children) ? slot.children : [];
4299
- if (kids.length > 0) {
4300
- const slotChildren = convertLayoutTreeToComponentTree(kids, node.id);
4301
- treeNode.children.push(...slotChildren);
4302
- }
4303
- });
4304
- }
4305
- result.push(treeNode);
4306
- });
4307
- return result;
4308
- };
4309
- const layoutTree2 = normalizedTree;
4310
- const componentTree = convertLayoutTreeToComponentTree(layoutTree2);
4311
- const describeLayoutTree = (nodes, depth = 0) => {
4312
- if (!nodes?.length) return "";
4313
- const indent = " ".repeat(depth);
4314
- return nodes.map((n) => {
4315
- const slotsDesc = (n.slots || []).map((s) => {
4316
- const childCount = Array.isArray(s.children) ? s.children.length : 0;
4317
- const childrenDesc = childCount > 0 ? describeLayoutTree(s.children || [], depth + 1) : "";
4318
- return `${indent} slot "${s.slotId || s.slotName || "?"}" (${childCount} children)${childrenDesc ? "\n" + childrenDesc : ""}`;
4319
- }).join("\n");
4320
- return `${indent}- ${n.id} (${n.componentId || "?"})${slotsDesc ? "\n" + slotsDesc : ""}`;
4321
- }).join("\n");
4322
- };
4323
- sdkDebugOnce(
4324
- `layoutTree:${pageConfig?.id || ""}:${pageConfig?.route || ""}`,
4325
- "[AmplifyRenderer] layoutTree received:\n%s",
4326
- describeLayoutTree(layoutTree2)
4327
- );
4328
- if (typeof window !== "undefined" && window.parent && window.parent !== window) {
4329
- const message = {
4330
- type: "COMPONENT_TREE",
4331
- tree: componentTree
4332
- };
4333
- window.parent.postMessage(message, "*");
4334
- sdkDebug(
4335
- "[AmplifyRenderer] Sent component tree from layoutTree:",
4336
- componentTree.length,
4337
- "root components"
4338
- );
4339
- }
4340
- }, [pageConfig]);
4341
- React3.useEffect(() => {
4342
- if (!pageConfig?.layoutTree || !pageConfig.layoutId) return;
4343
- const roots = pageConfig.layoutTree;
4344
- const fromEdge = contentSource === "edge" || roots.some((n) => n._contentSource === "edge");
4345
- if (fromEdge) return;
4346
- const sdk = getSDK();
4347
- const instanceId = sdk.getInstanceId();
4348
- const decisionApiUrl = sdk.getDecisionApiUrl();
4349
- const orchestratorUrl = sdk.getOrchestratorUrl();
4350
- if (!decisionApiUrl && !orchestratorUrl || !instanceId) return;
4351
- const fetchVariants = async () => {
4352
- const nodes = pageConfig.layoutTree;
4353
- const newCache = {};
4354
- const findZonedSlots = (nodeList) => {
4355
- const results = [];
4356
- for (const node of nodeList) {
4357
- if (node.slots) {
4358
- for (const slot of node.slots) {
4359
- if (slot.zoneId && slot.variants) {
4360
- const key = `${node.id}-${slot.slotId}`;
4361
- results.push({ node, slot, key });
4362
- }
4363
- }
4364
- }
4365
- }
4366
- return results;
4367
- };
4368
- const zonedSlots = findZonedSlots(nodes);
4369
- await Promise.all(
4370
- zonedSlots.map(async ({ node, slot, key }) => {
4371
- try {
4372
- let personalizationUrl;
4373
- if (decisionApiUrl) {
4374
- const url = new URL(decisionApiUrl);
4375
- url.searchParams.set("instanceId", instanceId);
4376
- const zoneId = slot.zoneId;
4377
- if (zoneId) {
4378
- url.searchParams.set("zoneId", zoneId);
4379
- }
4380
- const campaignId = slot.campaignId;
4381
- if (campaignId) {
4382
- url.searchParams.set("campaignId", campaignId);
4383
- }
4384
- personalizationUrl = url.toString();
4385
- } else if (orchestratorUrl) {
4386
- personalizationUrl = `${orchestratorUrl}/api/personalization/variant?instanceId=${encodeURIComponent(instanceId)}&layoutId=${encodeURIComponent(pageConfig.layoutId)}&slotId=${encodeURIComponent(slot.slotId)}&nodeId=${encodeURIComponent(node.id)}`;
4387
- } else {
4388
- return;
4389
- }
4390
- const response = await fetch(personalizationUrl);
4391
- if (response.ok) {
4392
- const data = await response.json();
4393
- if (data.variantId && data.componentTree) {
4394
- newCache[key] = {
4395
- variantId: data.variantId,
4396
- children: data.componentTree
4397
- };
4398
- if (typeof window !== "undefined") {
4399
- if (window.__AMPLIFYUP_PREVIEW_MODE__ === true) {
4400
- return;
4401
- }
4402
- if (window.location.pathname.includes("/api/pages/proxy")) {
4403
- return;
4404
- }
4405
- if (window.self !== window.top) {
4406
- return;
4407
- }
4408
- }
4409
- sdk.track("Zone Impression", {
4410
- zoneId: slot.zoneId,
4411
- variantId: data.variantId,
4412
- layoutId: pageConfig.layoutId,
4413
- route: pageConfig.route
4414
- });
4415
- } else {
4416
- const defaultVariant = slot.variants?.find((v) => v.isDefault);
4417
- if (defaultVariant) {
4418
- newCache[key] = {
4419
- variantId: defaultVariant.variantId,
4420
- children: defaultVariant.children
4421
- };
4422
- }
4423
- }
4424
- }
4425
- } catch (err) {
4426
- console.error(`Error fetching variant for slot ${key}:`, err);
4427
- const defaultVariant = slot.variants?.find((v) => v.isDefault);
4428
- if (defaultVariant) {
4429
- newCache[key] = {
4430
- variantId: defaultVariant.variantId,
4431
- children: defaultVariant.children
4432
- };
4433
- }
4434
- }
4435
- })
4436
- );
4437
- setVariantCache(newCache);
4438
- };
4439
- fetchVariants();
4440
- }, [pageConfig?.layoutTree, pageConfig?.layoutId, pageConfig?.route, contentSource]);
4441
- if (loading) {
4442
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loadingComponent || /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen bg-gray-50", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container mx-auto px-4 py-16", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse", children: [
4443
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-8 bg-gray-200 rounded w-1/4 mb-4" }),
4444
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-gray-200 rounded w-1/2 mb-8" }),
4445
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
4446
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-64 bg-gray-200 rounded" }),
4447
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-32 bg-gray-200 rounded" })
4448
- ] })
4449
- ] }) }) }) });
4450
- }
4451
- if (error) {
4452
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: errorComponent ? errorComponent(error) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen bg-gray-50", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container mx-auto px-4 py-16", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-red-50 border border-red-200 rounded-lg p-6", children: [
4453
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-bold text-red-900 mb-2", children: "Error Loading Page" }),
4454
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-red-700", children: error })
4455
- ] }) }) }) });
4456
- }
4457
- if (!pageConfig) {
4458
- return null;
4459
- }
4460
- pageConfig.layout?.header !== false;
4461
- pageConfig.layout?.footer !== false;
4462
- const renderNode = (node) => {
4463
- const zoneIdFromProps = node.componentId === "AmplifyZone" ? String(node.props?.zoneId || "") : "";
4464
- if (node.componentId === "AmplifyZone") {
4465
- const contentSlot = node.slots?.find((s) => s.slotId === "content") || node.slots?.[0];
4466
- const children = Array.isArray(contentSlot?.children) ? contentSlot.children : [];
4467
- return /* @__PURE__ */ jsxRuntime.jsx(
4468
- "div",
4469
- {
4470
- "data-node-id": node.id,
4471
- "data-amplifyup-node": "",
4472
- "data-amplifyup-component": "AmplifyZone",
4473
- "data-amplifyup-zone": zoneIdFromProps || void 0,
4474
- "data-zone-id": zoneIdFromProps || void 0,
4475
- children: /* @__PURE__ */ jsxRuntime.jsx(
4476
- "div",
4477
- {
4478
- "data-slot-id": "content",
4479
- "data-amplifyup-slot": "content",
4480
- "data-parent-node-id": node.id,
4481
- "data-parent-component-id": "AmplifyZone",
4482
- children: children.filter(Boolean).map((child) => /* @__PURE__ */ jsxRuntime.jsx(React3.Fragment, { children: renderNode(child) }, child.id))
4483
- }
4484
- )
4485
- }
4486
- );
4487
- }
4488
- let slotChildren = {};
4489
- sdkDebugOnce(`node:${node.id}`, `[AmplifyRenderer] Rendering node ${node.id} (${node.componentId})`, {
4490
- hasSlots: !!(node.slots && node.slots.length > 0),
4491
- slotCount: node.slots?.length || 0,
4492
- slots: node.slots?.map((s) => ({ slotId: s.slotId, zoneId: s.zoneId, childrenCount: s.children?.length || 0 }))
4493
- });
4494
- if (node.slots && node.slots.length > 0) {
4495
- for (const slot of node.slots) {
4496
- const slotKey = `${node.id}-${slot.slotId}`;
4497
- let childrenToRender = [];
4498
- if (slot.zoneId && slot.variants && variantCache[slotKey]) {
4499
- childrenToRender = variantCache[slotKey].children;
4500
- } else if (slot.zoneId && slot.variants) {
4501
- const defaultVariant = slot.variants.find((v) => v.isDefault);
4502
- childrenToRender = defaultVariant?.children || [];
4503
- } else {
4504
- childrenToRender = Array.isArray(slot.children) ? slot.children : [];
4505
- }
4506
- const safeChildren = Array.isArray(childrenToRender) ? childrenToRender : [];
4507
- slotChildren[slot.slotId] = /* @__PURE__ */ jsxRuntime.jsx(
4508
- "div",
4509
- {
4510
- "data-slot-id": slot.slotId,
4511
- "data-amplifyup-slot": slot.slotId,
4512
- "data-zone-id": slot.zoneId || void 0,
4513
- "data-parent-node-id": node.id,
4514
- "data-parent-component-id": node.componentId,
4515
- children: safeChildren.filter(Boolean).map((child) => /* @__PURE__ */ jsxRuntime.jsx(React3.Fragment, { children: renderNode(child) }, child.id))
4516
- },
4517
- slot.slotId
4518
- );
4519
- }
4520
- }
4521
- const slotsToPass = Object.keys(slotChildren).length > 0 ? slotChildren : void 0;
4522
- return /* @__PURE__ */ jsxRuntime.jsx(
4523
- "div",
4524
- {
4525
- "data-node-id": node.id,
4526
- "data-amplifyup-node": "",
4527
- "data-component-id": node.componentId,
4528
- "data-amplifyup-component": node.componentId,
4529
- children: /* @__PURE__ */ jsxRuntime.jsx(
4530
- ComponentRenderBoundary,
4531
- {
4532
- componentId: node.componentId,
4533
- nodeId: node.id,
4534
- children: /* @__PURE__ */ jsxRuntime.jsx(
4535
- NodeWithFields,
4536
- {
4537
- nodeId: node.id,
4538
- componentId: node.componentId,
4539
- props: nodeRenderProps(node),
4540
- slots: slotsToPass,
4541
- renderComponent,
4542
- composerPreview: composerPreviewFlag
4543
- }
4544
- )
4545
- }
4546
- )
4547
- }
4548
- );
4549
- };
4550
- const rawTree = pageConfig.layoutTree;
4551
- const layoutTree = Array.isArray(rawTree) ? rawTree : rawTree && typeof rawTree === "object" && rawTree.componentId ? [rawTree] : [];
4552
- if (layoutTree.length === 0) {
4553
- return /* @__PURE__ */ jsxRuntime.jsx("main", { children: emptyComponent || /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container mx-auto px-4 py-16", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: "No content configured for this page." }) }) });
4554
- }
4555
- return /* @__PURE__ */ jsxRuntime.jsx(ComposerProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
4556
- "main",
4557
- {
4558
- "data-slot-id": composerPreviewFlag ? "main" : void 0,
4559
- "data-amplifyup-slot": composerPreviewFlag ? "main" : void 0,
4560
- "data-slot-source": composerPreviewFlag ? "page" : void 0,
4561
- "data-slot-state": composerPreviewFlag ? "filled" : void 0,
4562
- children: layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx(React3.Fragment, { children: renderNode(node) }, node.id))
4563
- }
4564
- ) });
4565
- }
4566
- var AmplifyRenderer = React3.memo(AmplifyRendererInner);
4567
- function AddComponentIcon({ size = 28 }) {
4568
- return /* @__PURE__ */ jsxRuntime.jsxs(
4569
- "svg",
4570
- {
4571
- width: size,
4572
- height: size,
4573
- viewBox: "0 0 24 24",
4574
- fill: "none",
4575
- xmlns: "http://www.w3.org/2000/svg",
4576
- "aria-hidden": "true",
4577
- focusable: "false",
4578
- children: [
4579
- /* @__PURE__ */ jsxRuntime.jsx(
4580
- "rect",
4581
- {
4582
- x: "3",
4583
- y: "3",
4584
- width: "18",
4585
- height: "18",
4586
- rx: "4",
4587
- stroke: "currentColor",
4588
- strokeWidth: "1.75"
4589
- }
4590
- ),
4591
- /* @__PURE__ */ jsxRuntime.jsx(
4592
- "path",
4593
- {
4594
- d: "M12 8v8M8 12h8",
4595
- stroke: "currentColor",
4596
- strokeWidth: "1.75",
4597
- strokeLinecap: "round"
4598
- }
4599
- )
4600
- ]
4601
- }
4602
- );
4603
- }
4604
- function EmptySlotHint({
4605
- label = "Click here to Add Component",
4606
- compact = false
4607
- }) {
4608
- const iconSize = compact ? 20 : 28;
4609
- return /* @__PURE__ */ jsxRuntime.jsxs(
4610
- "div",
4611
- {
4612
- className: "amplifyup-slot-placeholder",
4613
- style: {
4614
- display: "flex",
4615
- flexDirection: "column",
4616
- alignItems: "center",
4617
- justifyContent: "center",
4618
- gap: compact ? 8 : 12,
4619
- minHeight: compact ? 60 : void 0,
4620
- width: "100%",
4621
- pointerEvents: "none",
4622
- textAlign: "center",
4623
- boxSizing: "border-box",
4624
- padding: compact ? "12px 8px" : "24px 16px"
4625
- },
4626
- children: [
4627
- /* @__PURE__ */ jsxRuntime.jsx(
4628
- "span",
4629
- {
4630
- className: "amplifyup-slot-placeholder-icon",
4631
- style: {
4632
- display: "inline-flex",
4633
- alignItems: "center",
4634
- justifyContent: "center",
4635
- width: compact ? 36 : 48,
4636
- height: compact ? 36 : 48,
4637
- borderRadius: 12,
4638
- border: "1.5px dashed currentColor",
4639
- opacity: 0.9
4640
- },
4641
- children: /* @__PURE__ */ jsxRuntime.jsx(AddComponentIcon, { size: iconSize })
4642
- }
4643
- ),
4644
- /* @__PURE__ */ jsxRuntime.jsx(
4645
- "span",
4646
- {
4647
- className: "amplifyup-slot-placeholder-label",
4648
- style: {
4649
- fontSize: compact ? 13 : 15,
4650
- fontWeight: 600,
4651
- lineHeight: 1.3,
4652
- letterSpacing: "0.01em"
4653
- },
4654
- children: label
4655
- }
4656
- )
4657
- ]
4658
- }
4659
- );
4660
- }
4661
- var ComposerLayoutStatusContext = React3.createContext({
4662
- ready: true
4663
- });
4664
- function ComposerLayoutStatusProvider({
4665
- ready,
4666
- children
4667
- }) {
4668
- return /* @__PURE__ */ jsxRuntime.jsx(ComposerLayoutStatusContext.Provider, { value: { ready }, children });
4669
- }
4670
- function useComposerLayoutStatus() {
4671
- return React3.useContext(ComposerLayoutStatusContext);
4672
- }
4673
- function previewPageSlot(state) {
4674
- return /* @__PURE__ */ jsxRuntime.jsx(
4675
- "div",
4676
- {
4677
- "data-slot-id": "main",
4678
- "data-amplifyup-slot": "main",
4679
- "data-slot-source": "page",
4680
- "data-slot-state": state,
4681
- "data-slot-empty": state === "empty" ? "true" : void 0,
4682
- style: {
4683
- minHeight: state === "empty" ? "50vh" : void 0,
4684
- width: "100%",
4685
- display: "block",
4686
- position: "relative"
4687
- },
4688
- children: state === "empty" ? /* @__PURE__ */ jsxRuntime.jsx(EmptySlotHint, {}) : null
4689
- }
4690
- );
4691
- }
4692
- function hasAmplifyLayout(pageConfig) {
4693
- return !!(pageConfig && pageConfig.id !== "default" && Array.isArray(pageConfig.layoutTree) && pageConfig.layoutTree.length > 0);
4694
- }
4695
- function normalizeRoutePath(route) {
4696
- if (!route) return "";
4697
- const path = route.split("?")[0] || "/";
4698
- if (path.length > 1 && path.endsWith("/")) return path.replace(/\/+$/, "");
4699
- return path || "/";
4700
- }
4701
- function samePageRoute(a, b) {
4702
- const ar = normalizeRoutePath(a?.route);
4703
- const br = normalizeRoutePath(b?.route);
4704
- return !!ar && !!br && ar === br;
4705
- }
4706
- function layoutTreesEqual(a, b) {
4707
- if (!a || !b) return a === b;
4708
- return JSON.stringify(a.layoutTree) === JSON.stringify(b.layoutTree);
4709
- }
4710
- function AmplifyPageContent({
4711
- fallback,
4712
- renderComponent,
4713
- pageConfig: pageConfigProp,
4714
- forceComposerPreview = false,
4715
- previewLoadingComponent,
4716
- previewEmptyComponent,
4717
- loadingComponent,
4718
- emptyComponent,
4719
- errorComponent
4720
- }) {
4721
- const client = useAmplifyUp();
4722
- useRegisterPageContent();
4723
- const preview = useComposerPreviewFlag(forceComposerPreview);
4724
- const clientLayout = hasAmplifyLayout(client.pageConfig) ? client.pageConfig : null;
4725
- const serverLayout = hasAmplifyLayout(pageConfigProp) ? pageConfigProp : null;
4726
- let pageConfig = serverLayout ?? clientLayout;
4727
- if (preview && clientLayout) {
4728
- pageConfig = clientLayout;
4729
- } else if (clientLayout && serverLayout && samePageRoute(clientLayout, serverLayout) && !layoutTreesEqual(clientLayout, serverLayout)) {
4730
- pageConfig = clientLayout;
4731
- } else if (clientLayout && !serverLayout) {
4732
- pageConfig = clientLayout;
4733
- }
4734
- const loading = !hasAmplifyLayout(pageConfig) && client.loading;
4735
- const error = hasAmplifyLayout(pageConfig) ? null : pageConfigProp ? null : client.error;
4736
- const previewEmpty = previewEmptyComponent ?? previewPageSlot("empty");
4737
- const previewLoading = previewLoadingComponent ?? previewPageSlot("loading");
4738
- if (preview) {
4739
- const ready = previewLayoutReady({
4740
- clientLoading: client.loading,
4741
- hasClientLayout: !!clientLayout,
4742
- hasServerLayout: !!serverLayout
4743
- });
4744
- if (!ready) {
4745
- return /* @__PURE__ */ jsxRuntime.jsx(ComposerLayoutStatusProvider, { ready: false, children: previewLoading });
4746
- }
4747
- const layoutSettled = !client.loading || !!clientLayout;
4748
- return /* @__PURE__ */ jsxRuntime.jsx(ComposerLayoutStatusProvider, { ready: layoutSettled, children: /* @__PURE__ */ jsxRuntime.jsx(
4749
- AmplifyRenderer,
4750
- {
4751
- pageConfig: pageConfig ?? void 0,
4752
- renderComponent,
4753
- composerPreview: true,
4754
- loadingComponent: loadingComponent ?? previewLoading,
4755
- emptyComponent: emptyComponent ?? previewEmpty,
4756
- errorComponent: errorComponent ?? (() => previewEmpty)
4757
- }
4758
- ) });
4759
- }
4760
- if (loading) {
4761
- return loadingComponent ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loadingComponent }) : null;
4762
- }
4763
- if (error) {
4764
- if (errorComponent) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: errorComponent(error) });
4765
- return fallback ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback }) : null;
4766
- }
4767
- if (!hasAmplifyLayout(pageConfig)) {
4768
- return fallback ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback }) : null;
4769
- }
4770
- return /* @__PURE__ */ jsxRuntime.jsx(ComposerLayoutStatusProvider, { ready: true, children: /* @__PURE__ */ jsxRuntime.jsx(
4771
- AmplifyRenderer,
4772
- {
4773
- pageConfig: pageConfig ?? void 0,
4774
- renderComponent,
4775
- loadingComponent,
4776
- emptyComponent,
4777
- errorComponent
4778
- }
4779
- ) });
4780
- }
4781
-
4782
- // src/slot-state.ts
4783
- function resolveSlotState(opts) {
4784
- if (!opts.layoutReady) return "loading";
4785
- return opts.hasContent ? "filled" : "empty";
4786
- }
4787
- function slotShowsAddComponent(state) {
4788
- return state === "empty";
4789
- }
4790
- function slotStateFromEl(el) {
4791
- if (!el) return null;
4792
- const explicit = el.getAttribute("data-slot-state");
4793
- if (explicit === "loading" || explicit === "empty" || explicit === "filled") {
4794
- return explicit;
4795
- }
4796
- if (el.getAttribute("data-slot-empty") === "true") return "empty";
4797
- return null;
4798
- }
4799
-
4800
- // src/composer-edit-mode.ts
4801
- function isComposerEditMode() {
4802
- if (typeof window === "undefined") return false;
4803
- return isComposerPreview() && window.__AMPLIFYUP_EVENT_SELECTION__ !== true;
4804
- }
4805
- function subscribeComposerEdit(onStoreChange) {
4806
- if (typeof window === "undefined") return () => {
4807
- };
4808
- window.addEventListener("amplifyup:composer-edit", onStoreChange);
4809
- return () => window.removeEventListener("amplifyup:composer-edit", onStoreChange);
4810
- }
4811
- function getComposerEditModeServer() {
4812
- return false;
4813
- }
4814
- var ComponentContext = React3.createContext(null);
4815
- function ComponentContextProvider({
4816
- children,
4817
- slots,
4818
- props,
4819
- layoutNodeId,
4820
- componentId
4821
- }) {
4822
- const next = hydratePageResourceProps(props || {}, getPageResourceFields());
4823
- return /* @__PURE__ */ jsxRuntime.jsx(
4824
- ComponentContext.Provider,
4825
- {
4826
- value: { slots, props: next, layoutNodeId, componentId },
4827
- children
4270
+ const next = hydratePageResourceProps(props || {}, getPageResourceFields());
4271
+ return /* @__PURE__ */ jsxRuntime.jsx(
4272
+ ComponentContext.Provider,
4273
+ {
4274
+ value: { slots, props: next, layoutNodeId, componentId },
4275
+ children
4828
4276
  }
4829
4277
  );
4830
4278
  }
@@ -4834,7 +4282,9 @@ function Slot({
4834
4282
  }) {
4835
4283
  const context = React3.useContext(ComponentContext);
4836
4284
  if (!context) {
4837
- console.warn(`[AmplifyUp SDK] Slot "${name}" used outside ComponentContextProvider`);
4285
+ console.warn(
4286
+ `[AmplifyUp SDK] Slot "${name}" only works inside a component rendered from your component registry`
4287
+ );
4838
4288
  return null;
4839
4289
  }
4840
4290
  const slotContent = context.slots?.[name];
@@ -5148,391 +4598,1046 @@ function ComposerInlineField({
5148
4598
  opacity: showHint ? 0.5 : void 0
5149
4599
  }
5150
4600
  }
5151
- );
5152
- }
5153
- function ComposerInlineHtml({
5154
- name,
5155
- html,
5156
- sourceValue,
5157
- className,
5158
- Tag = "div",
5159
- layoutNodeId,
5160
- componentId,
5161
- fieldRef
5162
- }) {
5163
- const elRef = React3.useRef(null);
5164
- React3.useEffect(() => {
5165
- const el = elRef.current;
5166
- if (!el) return;
5167
- if (el.innerHTML !== html) el.innerHTML = html;
5168
- }, [html]);
5169
- const openRichEditor = (event) => {
5170
- if (!elRef.current) return;
5171
- event.preventDefault();
5172
- event.stopPropagation();
5173
- requestCanvasRichTextEdit({
5174
- el: elRef.current,
5175
- layoutNodeId,
5176
- componentId,
5177
- name,
5178
- value: sourceValue,
5179
- fieldRef
5180
- });
5181
- };
5182
- return React3__default.default.createElement(Tag, {
5183
- ref: elRef,
5184
- className,
5185
- "data-amplifyup-field": name,
5186
- "data-amplifyup-field-type": "richtext",
5187
- "data-amplifyup-source": sourceValue,
5188
- "data-amplifyup-node-id": layoutNodeId || void 0,
5189
- "data-amplifyup-ref-provider": fieldRef?.providerId || void 0,
5190
- "data-amplifyup-ref-entity": fieldRef?.entity || void 0,
5191
- "data-amplifyup-ref-id": fieldRef?.id || void 0,
5192
- dangerouslySetInnerHTML: { __html: html },
5193
- onMouseDown: (event) => {
5194
- event.stopPropagation();
5195
- },
5196
- onClick: openRichEditor,
5197
- style: {
5198
- cursor: "text",
5199
- outline: "1px dashed color-mix(in srgb, currentColor 40%, transparent)",
5200
- outlineOffset: "6px"
4601
+ );
4602
+ }
4603
+ function ComposerInlineHtml({
4604
+ name,
4605
+ html,
4606
+ sourceValue,
4607
+ className,
4608
+ Tag = "div",
4609
+ layoutNodeId,
4610
+ componentId,
4611
+ fieldRef
4612
+ }) {
4613
+ const elRef = React3.useRef(null);
4614
+ React3.useEffect(() => {
4615
+ const el = elRef.current;
4616
+ if (!el) return;
4617
+ if (el.innerHTML !== html) el.innerHTML = html;
4618
+ }, [html]);
4619
+ const openRichEditor = (event) => {
4620
+ if (!elRef.current) return;
4621
+ event.preventDefault();
4622
+ event.stopPropagation();
4623
+ requestCanvasRichTextEdit({
4624
+ el: elRef.current,
4625
+ layoutNodeId,
4626
+ componentId,
4627
+ name,
4628
+ value: sourceValue,
4629
+ fieldRef
4630
+ });
4631
+ };
4632
+ return React3__default.default.createElement(Tag, {
4633
+ ref: elRef,
4634
+ className,
4635
+ "data-amplifyup-field": name,
4636
+ "data-amplifyup-field-type": "richtext",
4637
+ "data-amplifyup-source": sourceValue,
4638
+ "data-amplifyup-node-id": layoutNodeId || void 0,
4639
+ "data-amplifyup-ref-provider": fieldRef?.providerId || void 0,
4640
+ "data-amplifyup-ref-entity": fieldRef?.entity || void 0,
4641
+ "data-amplifyup-ref-id": fieldRef?.id || void 0,
4642
+ dangerouslySetInnerHTML: { __html: html },
4643
+ onMouseDown: (event) => {
4644
+ event.stopPropagation();
4645
+ },
4646
+ onClick: openRichEditor,
4647
+ style: {
4648
+ cursor: "text",
4649
+ outline: "1px dashed color-mix(in srgb, currentColor 40%, transparent)",
4650
+ outlineOffset: "6px"
4651
+ }
4652
+ });
4653
+ }
4654
+ function formatFieldValue(value) {
4655
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4656
+ return String(value);
4657
+ }
4658
+ if (Array.isArray(value)) {
4659
+ const parts = value.map((item) => {
4660
+ if (typeof item === "string") return item;
4661
+ if (item && typeof item === "object" && "children" in item && Array.isArray(item.children)) {
4662
+ return item.children.map((c) => typeof c?.text === "string" ? c.text : "").join("");
4663
+ }
4664
+ return "";
4665
+ }).filter(Boolean);
4666
+ if (parts.length > 0) return parts.join(" ");
4667
+ }
4668
+ if (value && typeof value === "object") {
4669
+ return "";
4670
+ }
4671
+ return "";
4672
+ }
4673
+ var FIELD_SCALAR_HINT = "Field expects a scalar field. Did you mean <Field field={post.title} />?";
4674
+ function warnNotScalarField(component, field, fieldValue) {
4675
+ if (process.env.NODE_ENV === "production") return false;
4676
+ if (isBrandedFields(field)) {
4677
+ console.error(`[AmplifyUp SDK] ${component}: ${FIELD_SCALAR_HINT}`);
4678
+ return true;
4679
+ }
4680
+ if (isFieldEnvelope(field) && Array.isArray(field.value)) {
4681
+ console.error(`[AmplifyUp SDK] ${component}: ${FIELD_SCALAR_HINT}`);
4682
+ return true;
4683
+ }
4684
+ if (Array.isArray(fieldValue)) {
4685
+ console.error(`[AmplifyUp SDK] ${component}: ${FIELD_SCALAR_HINT}`);
4686
+ return true;
4687
+ }
4688
+ return false;
4689
+ }
4690
+ function assertNamedEnvelope(component, field) {
4691
+ if (process.env.NODE_ENV === "production") return;
4692
+ if (!field || typeof field !== "object" || Array.isArray(field)) return;
4693
+ const rec = field;
4694
+ if (!("value" in rec)) return;
4695
+ if (typeof rec.name === "string" && rec.name) return;
4696
+ throw new Error(
4697
+ `[AmplifyUp SDK] ${component} received an envelope-shaped object with a \`value\` but no \`name\` \u2014 a partial envelope was manufactured upstream (keys: ${Object.keys(
4698
+ rec
4699
+ ).join(", ")}). Find the producer; do not strip or rebuild envelopes.`
4700
+ );
4701
+ }
4702
+ var warnedReadOnlyFields = /* @__PURE__ */ new Set();
4703
+ function warnReadOnlyRowField(name) {
4704
+ if (process.env.NODE_ENV === "production") return;
4705
+ const key = name || "(unnamed)";
4706
+ if (warnedReadOnlyFields.has(key)) return;
4707
+ warnedReadOnlyFields.add(key);
4708
+ console.warn(
4709
+ `[AmplifyUp SDK] ${key} has no write target; rendered read-only.`
4710
+ );
4711
+ }
4712
+ function canComposerBind(field, ref, editName) {
4713
+ if (isReadOnlyRowField(field) || isFieldEnvelope(field) && field.readOnly) {
4714
+ warnReadOnlyRowField(editName || (isFieldEnvelope(field) ? field.name : ""));
4715
+ return false;
4716
+ }
4717
+ return true;
4718
+ }
4719
+ function warnProjectionProps(component, hasField, hasValue, name) {
4720
+ if (process.env.NODE_ENV === "production") return;
4721
+ if (!hasField && !hasValue && !name) {
4722
+ console.warn(
4723
+ `[AmplifyUp SDK] ${component} needs field={fields.yourProp} (or value + name for computed values)`
4724
+ );
4725
+ }
4726
+ }
4727
+ function hasOwnProp(props, key) {
4728
+ return Object.prototype.hasOwnProperty.call(props, key);
4729
+ }
4730
+ function Field(props) {
4731
+ const { field, value, name, className } = props;
4732
+ const context = React3.useContext(ComponentContext);
4733
+ const composerEdit = useComposerEditMode();
4734
+ const hasField = isFieldEnvelope(field);
4735
+ const hasValue = hasOwnProp(props, "value");
4736
+ const { editName, fieldValue, ref } = useBoundField(field, value, name, "Field");
4737
+ assertNamedEnvelope("Field", field);
4738
+ warnProjectionProps("Field", hasField, hasValue, name);
4739
+ if (warnNotScalarField("Field", field, fieldValue)) {
4740
+ return null;
4741
+ }
4742
+ if (!hasField && !hasValue && !name) {
4743
+ return null;
4744
+ }
4745
+ if (isBrandedFields(field) || Array.isArray(fieldValue)) {
4746
+ return null;
4747
+ }
4748
+ const empty = isComposerEmptyText(fieldValue);
4749
+ const bindComposer = composerEdit && editName && context && canInlineEdit(editName, fieldValue) && canComposerBind(field, ref, editName);
4750
+ if (bindComposer) {
4751
+ return /* @__PURE__ */ jsxRuntime.jsx(
4752
+ ComposerInlineField,
4753
+ {
4754
+ name: editName,
4755
+ value: fieldValue,
4756
+ className,
4757
+ layoutNodeId: context.layoutNodeId,
4758
+ componentId: context.componentId,
4759
+ fieldRef: ref,
4760
+ rich: looksLikeRichCanvasField(editName)
4761
+ }
4762
+ );
4763
+ }
4764
+ if (empty) return null;
4765
+ const text = formatFieldValue(fieldValue);
4766
+ if (!text) return null;
4767
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className, children: text });
4768
+ }
4769
+ function markdownToHtml(markdown) {
4770
+ try {
4771
+ const result = marked.marked.parse(markdown, { async: false });
4772
+ return typeof result === "string" ? result : "";
4773
+ } catch {
4774
+ return markdown;
4775
+ }
4776
+ }
4777
+ function RichText(props) {
4778
+ const {
4779
+ field,
4780
+ value,
4781
+ name,
4782
+ className,
4783
+ as: Tag = "div",
4784
+ children
4785
+ } = props;
4786
+ const context = React3.useContext(ComponentContext);
4787
+ const composerEdit = useComposerEditMode();
4788
+ const childrenValue = typeof children === "string" || typeof children === "number" ? String(children) : void 0;
4789
+ const hasField = isFieldEnvelope(field);
4790
+ const hasValueProp = hasOwnProp(props, "value") || childrenValue !== void 0;
4791
+ const boundValue = hasOwnProp(props, "value") ? value : childrenValue !== void 0 ? childrenValue : value;
4792
+ const { editName, fieldValue, ref } = useBoundField(
4793
+ field,
4794
+ boundValue,
4795
+ name,
4796
+ "RichText"
4797
+ );
4798
+ assertNamedEnvelope("RichText", field);
4799
+ if (!hasField && !hasValueProp && !name) {
4800
+ return null;
4801
+ }
4802
+ warnProjectionProps("RichText", hasField, hasValueProp, name);
4803
+ if (warnNotScalarField("RichText", field, fieldValue)) {
4804
+ return null;
4805
+ }
4806
+ const canEdit = !!context && canInlineEditRichText(editName, fieldValue) && canComposerBind(field, ref, editName);
4807
+ if (isComposerEmptyText(fieldValue)) {
4808
+ if (composerEdit && canEdit) {
4809
+ return /* @__PURE__ */ jsxRuntime.jsx(
4810
+ ComposerInlineField,
4811
+ {
4812
+ name: editName,
4813
+ value: fieldValue,
4814
+ className,
4815
+ layoutNodeId: context?.layoutNodeId,
4816
+ componentId: context?.componentId,
4817
+ fieldRef: ref,
4818
+ rich: true
4819
+ }
4820
+ );
4821
+ }
4822
+ return null;
4823
+ }
4824
+ let html = "";
4825
+ if (typeof fieldValue === "string") {
4826
+ const trimmed = fieldValue.trim();
4827
+ if (trimmed.startsWith("<") && trimmed.includes(">")) {
4828
+ html = fieldValue;
4829
+ } else {
4830
+ html = markdownToHtml(fieldValue);
5201
4831
  }
5202
- });
5203
- }
5204
- function formatFieldValue(value) {
5205
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
5206
- return String(value);
4832
+ } else {
4833
+ const text = formatFieldValue(fieldValue);
4834
+ html = text ? markdownToHtml(text) : "";
5207
4835
  }
5208
- if (Array.isArray(value)) {
5209
- const parts = value.map((item) => {
5210
- if (typeof item === "string") return item;
5211
- if (item && typeof item === "object" && "children" in item && Array.isArray(item.children)) {
5212
- return item.children.map((c) => typeof c?.text === "string" ? c.text : "").join("");
5213
- }
5214
- return "";
5215
- }).filter(Boolean);
5216
- if (parts.length > 0) return parts.join(" ");
4836
+ if (!html) {
4837
+ return null;
5217
4838
  }
5218
- if (value && typeof value === "object") {
5219
- return "";
4839
+ if (composerEdit && canEdit) {
4840
+ return /* @__PURE__ */ jsxRuntime.jsx(
4841
+ ComposerInlineHtml,
4842
+ {
4843
+ name: editName,
4844
+ html,
4845
+ sourceValue: typeof fieldValue === "string" ? fieldValue : html,
4846
+ className,
4847
+ Tag,
4848
+ layoutNodeId: context?.layoutNodeId,
4849
+ componentId: context?.componentId,
4850
+ fieldRef: ref
4851
+ }
4852
+ );
5220
4853
  }
4854
+ return /* @__PURE__ */ jsxRuntime.jsx(Tag, { className, dangerouslySetInnerHTML: { __html: html } });
4855
+ }
4856
+ function isPortableImageValue(value) {
4857
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
4858
+ const url = value.url;
4859
+ return typeof url === "string" && url.trim().length > 0;
4860
+ }
4861
+ function imageSrc(value) {
4862
+ if (typeof value === "string") return value.trim();
4863
+ if (isPortableImageValue(value)) return value.url.trim();
5221
4864
  return "";
5222
4865
  }
5223
- var FIELD_SCALAR_HINT = "Field expects a scalar field. Did you mean <Field field={post.title} />?";
5224
- function warnNotScalarField(component, field, fieldValue) {
5225
- if (process.env.NODE_ENV === "production") return false;
5226
- if (isBrandedFields(field)) {
5227
- console.error(`[AmplifyUp SDK] ${component}: ${FIELD_SCALAR_HINT}`);
5228
- return true;
5229
- }
5230
- if (isFieldEnvelope(field) && Array.isArray(field.value)) {
5231
- console.error(`[AmplifyUp SDK] ${component}: ${FIELD_SCALAR_HINT}`);
5232
- return true;
5233
- }
5234
- if (Array.isArray(fieldValue)) {
5235
- console.error(`[AmplifyUp SDK] ${component}: ${FIELD_SCALAR_HINT}`);
5236
- return true;
4866
+ function leafText(field) {
4867
+ if (isFieldEnvelope(field)) return field.value;
4868
+ return field;
4869
+ }
4870
+ function coerceImageField(field, value, name) {
4871
+ if (isFieldEnvelope(field)) return { field, value, name };
4872
+ if (!isBrandedFields(field) || !field || typeof field !== "object") {
4873
+ return { field: void 0, value, name };
5237
4874
  }
5238
- return false;
4875
+ const bag = field;
4876
+ const urlField = bag.url;
4877
+ const urlName = isFieldEnvelope(urlField) && typeof urlField.name === "string" ? urlField.name.replace(/\.url$/, "") : "";
4878
+ const editName = urlName || name || "";
4879
+ if (!editName) return { field: void 0, value, name };
4880
+ const ref = isFieldEnvelope(urlField) ? urlField.ref : void 0;
4881
+ const width = leafText(bag.width);
4882
+ const height = leafText(bag.height);
4883
+ return {
4884
+ field: {
4885
+ value: {
4886
+ url: String(leafText(urlField) ?? ""),
4887
+ alt: leafText(bag.alt),
4888
+ ...typeof width === "number" ? { width } : {},
4889
+ ...typeof height === "number" ? { height } : {}
4890
+ },
4891
+ name: editName,
4892
+ ...ref ? { ref } : {}
4893
+ },
4894
+ value,
4895
+ name: editName
4896
+ };
5239
4897
  }
5240
- function assertNamedEnvelope(component, field) {
5241
- if (process.env.NODE_ENV === "production") return;
5242
- if (!field || typeof field !== "object" || Array.isArray(field)) return;
5243
- const rec = field;
5244
- if (!("value" in rec)) return;
5245
- if (typeof rec.name === "string" && rec.name) return;
5246
- throw new Error(
5247
- `[AmplifyUp SDK] ${component} received an envelope-shaped object with a \`value\` but no \`name\` \u2014 a partial envelope was manufactured upstream (keys: ${Object.keys(
5248
- rec
5249
- ).join(", ")}). Find the producer; do not strip or rebuild envelopes.`
4898
+ function Image(props) {
4899
+ const {
4900
+ field,
4901
+ value,
4902
+ name,
4903
+ alt: altProp,
4904
+ className,
4905
+ width: widthProp,
4906
+ height: heightProp,
4907
+ ...imgProps
4908
+ } = props;
4909
+ const context = React3.useContext(ComponentContext);
4910
+ assertNamedEnvelope("Image", field);
4911
+ const coerced = coerceImageField(field, value, name);
4912
+ const boundField = coerced.field;
4913
+ const hasField = isFieldEnvelope(boundField);
4914
+ const hasValue = hasOwnProp(props, "value");
4915
+ const { editName, fieldValue, ref } = useBoundField(
4916
+ boundField,
4917
+ coerced.value,
4918
+ coerced.name,
4919
+ "Image"
5250
4920
  );
5251
- }
5252
- var warnedReadOnlyFields = /* @__PURE__ */ new Set();
5253
- function warnReadOnlyRowField(name) {
5254
- if (process.env.NODE_ENV === "production") return;
5255
- const key = name || "(unnamed)";
5256
- if (warnedReadOnlyFields.has(key)) return;
5257
- warnedReadOnlyFields.add(key);
5258
- console.warn(
5259
- `[AmplifyUp SDK] ${key} has no write target; rendered read-only.`
4921
+ const composerEdit = useComposerEditMode();
4922
+ warnProjectionProps("Image", hasField || isBrandedFields(field), hasValue, coerced.name || name);
4923
+ if (!isBrandedFields(field) && warnNotScalarField("Image", boundField, fieldValue)) {
4924
+ return null;
4925
+ }
4926
+ if (!hasField && !hasValue && !name && !editName) {
4927
+ return null;
4928
+ }
4929
+ const src = imageSrc(fieldValue);
4930
+ const portable = isPortableImageValue(fieldValue) ? fieldValue : null;
4931
+ const alt = altProp ?? portable?.alt ?? "";
4932
+ const width = widthProp ?? portable?.width;
4933
+ const height = heightProp ?? portable?.height;
4934
+ const fieldAttrs = composerEdit && editName && canComposerBind(boundField, ref, editName) ? {
4935
+ "data-amplifyup-field": editName,
4936
+ "data-amplifyup-field-type": "image",
4937
+ "data-amplifyup-node-id": context?.layoutNodeId || void 0,
4938
+ "data-amplifyup-ref-provider": ref?.providerId || void 0,
4939
+ "data-amplifyup-ref-entity": ref?.entity || void 0,
4940
+ "data-amplifyup-ref-id": ref?.id || void 0
4941
+ } : null;
4942
+ if (composerEdit && !editName && (hasField || hasValue)) {
4943
+ console.warn(
4944
+ '[AmplifyUp SDK] Image value={\u2026} requires name="\u2026" for computed values'
4945
+ );
4946
+ }
4947
+ if (!src) {
4948
+ if (!composerEdit || !fieldAttrs) return null;
4949
+ return /* @__PURE__ */ jsxRuntime.jsx(
4950
+ "span",
4951
+ {
4952
+ ...fieldAttrs,
4953
+ className,
4954
+ role: "img",
4955
+ "aria-label": alt || editName || "Image",
4956
+ style: {
4957
+ display: "block",
4958
+ boxSizing: "border-box",
4959
+ minWidth: width ? void 0 : 120,
4960
+ minHeight: height ? void 0 : 80,
4961
+ width: width || "100%",
4962
+ height: height || void 0,
4963
+ background: "color-mix(in srgb, currentColor 8%, transparent)",
4964
+ cursor: "pointer"
4965
+ }
4966
+ }
4967
+ );
4968
+ }
4969
+ return /* @__PURE__ */ jsxRuntime.jsx(
4970
+ "img",
4971
+ {
4972
+ ...imgProps,
4973
+ ...fieldAttrs,
4974
+ src,
4975
+ alt,
4976
+ className,
4977
+ width,
4978
+ height,
4979
+ style: {
4980
+ ...typeof imgProps.style === "object" && imgProps.style ? imgProps.style : {},
4981
+ ...composerEdit && fieldAttrs ? { cursor: "pointer" } : null
4982
+ }
4983
+ }
5260
4984
  );
5261
4985
  }
5262
- function canComposerBind(field, ref, editName) {
5263
- if (isReadOnlyRowField(field) || isFieldEnvelope(field) && field.readOnly) {
5264
- warnReadOnlyRowField(editName || (isFieldEnvelope(field) ? field.name : ""));
5265
- return false;
4986
+
4987
+ // src/component-key.ts
4988
+ var componentKey = (id) => id.toLowerCase().replace(/[^a-z0-9]/g, "");
4989
+ var REGISTRY_BRAND = Symbol.for("amplifyup.componentRegistry");
4990
+ var defineComponentRegistry = (components) => {
4991
+ const index = /* @__PURE__ */ new Map();
4992
+ for (const [name, component] of Object.entries(components)) {
4993
+ const key = componentKey(name);
4994
+ if (index.has(key)) {
4995
+ throw new Error(
4996
+ `[Amplify UP] Component registry has two components named like "${name}". Rebuild it with withAmplifyUp or \`amplifyup registry\`.`
4997
+ );
4998
+ }
4999
+ index.set(key, component);
5266
5000
  }
5267
- return true;
5268
- }
5269
- function warnProjectionProps(component, hasField, hasValue, name) {
5270
- if (process.env.NODE_ENV === "production") return;
5271
- if (!hasField && !hasValue && !name) {
5272
- console.warn(
5273
- `[AmplifyUp SDK] ${component} needs field={fields.yourProp} (or value + name for computed values)`
5001
+ return {
5002
+ [REGISTRY_BRAND]: true,
5003
+ components,
5004
+ resolve: (componentId) => index.get(componentKey(componentId))
5005
+ };
5006
+ };
5007
+ var isComponentRegistry = (value) => !!value && typeof value === "object" && value[REGISTRY_BRAND] === true;
5008
+ var warnedMissing = /* @__PURE__ */ new Set();
5009
+ var warnMissingOnce = (componentId) => {
5010
+ if (warnedMissing.has(componentId)) return;
5011
+ warnedMissing.add(componentId);
5012
+ console.warn(
5013
+ `[Amplify UP] No component in your component registry matches "${componentId}". Add a file with that name to your components folder.`
5014
+ );
5015
+ };
5016
+ var MissingComponentHint = ({ componentId }) => /* @__PURE__ */ jsxRuntime.jsxs(
5017
+ "div",
5018
+ {
5019
+ "data-amplifyup-missing-component": componentId,
5020
+ style: {
5021
+ margin: "0.5rem 0",
5022
+ padding: "0.75rem 1rem",
5023
+ border: "1.5px dashed currentColor",
5024
+ borderRadius: 8,
5025
+ opacity: 0.7,
5026
+ fontSize: 14,
5027
+ textAlign: "center"
5028
+ },
5029
+ children: [
5030
+ "\u201C",
5031
+ componentId,
5032
+ "\u201D isn\u2019t set up on this site yet."
5033
+ ]
5034
+ }
5035
+ );
5036
+ var RegistryComponent = ({
5037
+ registry,
5038
+ componentId,
5039
+ props,
5040
+ slots,
5041
+ layoutNodeId,
5042
+ composerPreview
5043
+ }) => {
5044
+ const Component2 = registry.resolve(componentId);
5045
+ if (!Component2) {
5046
+ warnMissingOnce(componentId);
5047
+ return composerPreview ? /* @__PURE__ */ jsxRuntime.jsx(MissingComponentHint, { componentId }) : null;
5048
+ }
5049
+ return /* @__PURE__ */ jsxRuntime.jsx(
5050
+ ComponentContextProvider,
5051
+ {
5052
+ props,
5053
+ slots,
5054
+ layoutNodeId,
5055
+ componentId,
5056
+ children: /* @__PURE__ */ jsxRuntime.jsx(Component2, { ...props })
5057
+ }
5058
+ );
5059
+ };
5060
+ var assertComponentRegistry = (owner, props) => {
5061
+ if ("renderComponent" in props) {
5062
+ throw new Error(
5063
+ `[Amplify UP] ${owner}: renderComponent was removed in @amplifyup/sdk 0.2.0. Components now load automatically \u2014 wrap next.config with withAmplifyUp and render <AmplifyPage /> from the generated component registry. See "Upgrading from 0.1" in the SDK README.`
5274
5064
  );
5275
5065
  }
5066
+ if (!isComponentRegistry(props.registry)) {
5067
+ throw new Error(
5068
+ `[Amplify UP] ${owner} needs your component registry. Render <AmplifyPage /> from the generated .amplifyup/component-registry module (created by withAmplifyUp or \`amplifyup registry\`).`
5069
+ );
5070
+ }
5071
+ };
5072
+ function nodeRenderProps(node) {
5073
+ const settings = node.settings || {};
5074
+ const hydrated = hydratePageResourceProps(
5075
+ node.props || {},
5076
+ getPageResourceFields()
5077
+ );
5078
+ const fields = hydrated.fields;
5079
+ const branded = isBrandedFields(fields) ? fields : brandFields(
5080
+ fields && typeof fields === "object" ? fields : {}
5081
+ );
5082
+ return {
5083
+ ...settings,
5084
+ ...hydrated,
5085
+ fields: branded
5086
+ };
5276
5087
  }
5277
- function hasOwnProp(props, key) {
5278
- return Object.prototype.hasOwnProperty.call(props, key);
5279
- }
5280
- function Field(props) {
5281
- const { field, value, name, className } = props;
5282
- const context = React3.useContext(ComponentContext);
5283
- const composerEdit = useComposerEditMode();
5284
- const hasField = isFieldEnvelope(field);
5285
- const hasValue = hasOwnProp(props, "value");
5286
- const { editName, fieldValue, ref } = useBoundField(field, value, name, "Field");
5287
- assertNamedEnvelope("Field", field);
5288
- warnProjectionProps("Field", hasField, hasValue, name);
5289
- if (warnNotScalarField("Field", field, fieldValue)) {
5290
- return null;
5088
+ var ComponentRenderBoundary = class extends React3.Component {
5089
+ constructor() {
5090
+ super(...arguments);
5091
+ this.state = { error: null };
5291
5092
  }
5292
- if (!hasField && !hasValue && !name) {
5293
- return null;
5093
+ static getDerivedStateFromError(error) {
5094
+ return { error };
5294
5095
  }
5295
- if (isBrandedFields(field) || Array.isArray(fieldValue)) {
5296
- return null;
5096
+ componentDidCatch(error) {
5097
+ console.error(
5098
+ `[AmplifyRenderer] "${this.props.componentId}" (${this.props.nodeId}) threw while rendering:`,
5099
+ error
5100
+ );
5297
5101
  }
5298
- const empty = isComposerEmptyText(fieldValue);
5299
- const bindComposer = composerEdit && editName && context && canInlineEdit(editName, fieldValue) && canComposerBind(field, ref, editName);
5300
- if (bindComposer) {
5301
- return /* @__PURE__ */ jsxRuntime.jsx(
5302
- ComposerInlineField,
5303
- {
5304
- name: editName,
5305
- value: fieldValue,
5306
- className,
5307
- layoutNodeId: context.layoutNodeId,
5308
- componentId: context.componentId,
5309
- fieldRef: ref,
5310
- rich: looksLikeRichCanvasField(editName)
5102
+ render() {
5103
+ if (this.state.error) {
5104
+ if (process.env.NODE_ENV !== "production") {
5105
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5106
+ "div",
5107
+ {
5108
+ "data-amplifyup-render-error": "",
5109
+ "data-component-id": this.props.componentId,
5110
+ "data-node-id": this.props.nodeId,
5111
+ style: {
5112
+ margin: "1rem 0",
5113
+ padding: "0.75rem 1rem",
5114
+ border: "1px solid #fca5a5",
5115
+ borderRadius: "0.5rem",
5116
+ background: "#fef2f2",
5117
+ color: "#991b1b",
5118
+ fontSize: "0.875rem"
5119
+ },
5120
+ children: [
5121
+ 'Component "',
5122
+ this.props.componentId,
5123
+ '" failed to render:',
5124
+ " ",
5125
+ this.state.error.message
5126
+ ]
5127
+ }
5128
+ );
5129
+ }
5130
+ return null;
5131
+ }
5132
+ return this.props.children;
5133
+ }
5134
+ };
5135
+ function NodeWithFields({
5136
+ nodeId,
5137
+ componentId,
5138
+ props,
5139
+ slots,
5140
+ registry,
5141
+ composerPreview
5142
+ }) {
5143
+ return /* @__PURE__ */ jsxRuntime.jsx(MaybeComposerProvider, { enabled: !!composerPreview, layoutNodeId: nodeId, children: /* @__PURE__ */ jsxRuntime.jsx(
5144
+ RegistryComponent,
5145
+ {
5146
+ registry,
5147
+ componentId,
5148
+ props,
5149
+ slots,
5150
+ layoutNodeId: nodeId,
5151
+ composerPreview: !!composerPreview
5152
+ }
5153
+ ) });
5154
+ }
5155
+ function AmplifyRendererInner(rendererProps) {
5156
+ assertComponentRegistry("AmplifyRenderer", rendererProps);
5157
+ const {
5158
+ registry,
5159
+ pageConfig: serverPageConfig,
5160
+ loadingComponent,
5161
+ errorComponent,
5162
+ emptyComponent,
5163
+ composerPreview
5164
+ } = rendererProps;
5165
+ const clientHook = useAmplifyUp();
5166
+ useRegisterPageContent(!serverPageConfig);
5167
+ const composerPreviewFlag = useComposerPreviewFlag(!!composerPreview);
5168
+ const pageConfig = serverPageConfig || clientHook.pageConfig || null;
5169
+ const loading = serverPageConfig ? false : clientHook.loading;
5170
+ const error = serverPageConfig ? null : clientHook.error;
5171
+ const contentSource = clientHook.source;
5172
+ const [variantCache, setVariantCache] = React3.useState({});
5173
+ React3.useEffect(() => {
5174
+ if (typeof window !== "undefined") {
5175
+ if (window.__AMPLIFYUP_PREVIEW_MODE__ === true) {
5176
+ return;
5177
+ }
5178
+ if (window.location.pathname.includes("/api/pages/proxy")) {
5179
+ return;
5180
+ }
5181
+ if (window.self !== window.top) {
5182
+ return;
5183
+ }
5184
+ const urlParams = new URLSearchParams(window.location.search);
5185
+ if (urlParams.get("preview") === "true" || urlParams.get("visualEditor") === "true") {
5186
+ return;
5187
+ }
5188
+ if (window.location.href.includes("preview=true") || window.location.href.includes("visualEditor=true")) {
5189
+ return;
5190
+ }
5191
+ }
5192
+ if (pageConfig && pageConfig.id !== "default") {
5193
+ trackContentView(pageConfig.id, "page", {
5194
+ route: pageConfig.route,
5195
+ title: pageConfig.title
5196
+ });
5197
+ }
5198
+ }, [pageConfig]);
5199
+ React3.useEffect(() => {
5200
+ if (!pageConfig?.eventTracking?.length) return;
5201
+ const sdk = getSDK();
5202
+ if (!sdk.isInitialized()) return;
5203
+ sdk.setupEventTracking(pageConfig.eventTracking);
5204
+ const t1 = window.setTimeout(() => {
5205
+ sdk.setupComponentViewTracking();
5206
+ refreshEventTracking();
5207
+ }, 200);
5208
+ const t2 = window.setTimeout(() => {
5209
+ sdk.setupComponentViewTracking();
5210
+ refreshEventTracking();
5211
+ }, 1e3);
5212
+ return () => {
5213
+ window.clearTimeout(t1);
5214
+ window.clearTimeout(t2);
5215
+ };
5216
+ }, [pageConfig?.id, pageConfig?.eventTracking]);
5217
+ React3.useEffect(() => {
5218
+ if (!pageConfig) return;
5219
+ const t = window.setTimeout(() => {
5220
+ getSDK().setupComponentViewTracking();
5221
+ refreshEventTracking();
5222
+ }, 100);
5223
+ return () => window.clearTimeout(t);
5224
+ }, [variantCache, pageConfig?.id]);
5225
+ React3.useEffect(() => {
5226
+ if (!isComposerPreview()) {
5227
+ return;
5228
+ }
5229
+ if (!pageConfig) {
5230
+ return;
5231
+ }
5232
+ const rawTree2 = pageConfig.layoutTree;
5233
+ const normalizedTree = Array.isArray(rawTree2) ? rawTree2 : rawTree2 && typeof rawTree2 === "object" && rawTree2.componentId ? [rawTree2] : [];
5234
+ if (normalizedTree.length === 0) {
5235
+ if (typeof window !== "undefined" && window.parent && window.parent !== window) {
5236
+ window.parent.postMessage({
5237
+ type: "COMPONENT_TREE",
5238
+ tree: []
5239
+ }, "*");
5311
5240
  }
5241
+ return;
5242
+ }
5243
+ const convertLayoutTreeToComponentTree = (nodes, parentId = null) => {
5244
+ const result = [];
5245
+ nodes.forEach((node) => {
5246
+ if (!node) return;
5247
+ const treeNode = {
5248
+ id: node.id,
5249
+ componentId: node.componentId,
5250
+ componentName: node.componentId,
5251
+ // Will be enhanced with actual name if available
5252
+ parentId,
5253
+ children: []
5254
+ };
5255
+ if (node.slots && node.slots.length > 0) {
5256
+ node.slots.forEach((slot) => {
5257
+ const kids = Array.isArray(slot?.children) ? slot.children : [];
5258
+ if (kids.length > 0) {
5259
+ const slotChildren = convertLayoutTreeToComponentTree(kids, node.id);
5260
+ treeNode.children.push(...slotChildren);
5261
+ }
5262
+ });
5263
+ }
5264
+ result.push(treeNode);
5265
+ });
5266
+ return result;
5267
+ };
5268
+ const layoutTree2 = normalizedTree;
5269
+ const componentTree = convertLayoutTreeToComponentTree(layoutTree2);
5270
+ const describeLayoutTree = (nodes, depth = 0) => {
5271
+ if (!nodes?.length) return "";
5272
+ const indent = " ".repeat(depth);
5273
+ return nodes.map((n) => {
5274
+ const slotsDesc = (n.slots || []).map((s) => {
5275
+ const childCount = Array.isArray(s.children) ? s.children.length : 0;
5276
+ const childrenDesc = childCount > 0 ? describeLayoutTree(s.children || [], depth + 1) : "";
5277
+ return `${indent} slot "${s.slotId || s.slotName || "?"}" (${childCount} children)${childrenDesc ? "\n" + childrenDesc : ""}`;
5278
+ }).join("\n");
5279
+ return `${indent}- ${n.id} (${n.componentId || "?"})${slotsDesc ? "\n" + slotsDesc : ""}`;
5280
+ }).join("\n");
5281
+ };
5282
+ sdkDebugOnce(
5283
+ `layoutTree:${pageConfig?.id || ""}:${pageConfig?.route || ""}`,
5284
+ "[AmplifyRenderer] layoutTree received:\n%s",
5285
+ describeLayoutTree(layoutTree2)
5312
5286
  );
5287
+ if (typeof window !== "undefined" && window.parent && window.parent !== window) {
5288
+ const message = {
5289
+ type: "COMPONENT_TREE",
5290
+ tree: componentTree
5291
+ };
5292
+ window.parent.postMessage(message, "*");
5293
+ sdkDebug(
5294
+ "[AmplifyRenderer] Sent component tree from layoutTree:",
5295
+ componentTree.length,
5296
+ "root components"
5297
+ );
5298
+ }
5299
+ }, [pageConfig]);
5300
+ React3.useEffect(() => {
5301
+ if (!pageConfig?.layoutTree || !pageConfig.layoutId) return;
5302
+ const roots = pageConfig.layoutTree;
5303
+ const fromEdge = contentSource === "edge" || roots.some((n) => n._contentSource === "edge");
5304
+ if (fromEdge) return;
5305
+ const sdk = getSDK();
5306
+ const instanceId = sdk.getInstanceId();
5307
+ const decisionApiUrl = sdk.getDecisionApiUrl();
5308
+ const orchestratorUrl = sdk.getOrchestratorUrl();
5309
+ if (!decisionApiUrl && !orchestratorUrl || !instanceId) return;
5310
+ const fetchVariants = async () => {
5311
+ const nodes = pageConfig.layoutTree;
5312
+ const newCache = {};
5313
+ const findZonedSlots = (nodeList) => {
5314
+ const results = [];
5315
+ for (const node of nodeList) {
5316
+ if (node.slots) {
5317
+ for (const slot of node.slots) {
5318
+ if (slot.zoneId && slot.variants) {
5319
+ const key = `${node.id}-${slot.slotId}`;
5320
+ results.push({ node, slot, key });
5321
+ }
5322
+ }
5323
+ }
5324
+ }
5325
+ return results;
5326
+ };
5327
+ const zonedSlots = findZonedSlots(nodes);
5328
+ await Promise.all(
5329
+ zonedSlots.map(async ({ node, slot, key }) => {
5330
+ try {
5331
+ let personalizationUrl;
5332
+ if (decisionApiUrl) {
5333
+ const url = new URL(decisionApiUrl);
5334
+ url.searchParams.set("instanceId", instanceId);
5335
+ const zoneId = slot.zoneId;
5336
+ if (zoneId) {
5337
+ url.searchParams.set("zoneId", zoneId);
5338
+ }
5339
+ const campaignId = slot.campaignId;
5340
+ if (campaignId) {
5341
+ url.searchParams.set("campaignId", campaignId);
5342
+ }
5343
+ personalizationUrl = url.toString();
5344
+ } else if (orchestratorUrl) {
5345
+ personalizationUrl = `${orchestratorUrl}/api/personalization/variant?instanceId=${encodeURIComponent(instanceId)}&layoutId=${encodeURIComponent(pageConfig.layoutId)}&slotId=${encodeURIComponent(slot.slotId)}&nodeId=${encodeURIComponent(node.id)}`;
5346
+ } else {
5347
+ return;
5348
+ }
5349
+ const response = await fetch(personalizationUrl);
5350
+ if (response.ok) {
5351
+ const data = await response.json();
5352
+ if (data.variantId && data.componentTree) {
5353
+ newCache[key] = {
5354
+ variantId: data.variantId,
5355
+ children: data.componentTree
5356
+ };
5357
+ if (typeof window !== "undefined") {
5358
+ if (window.__AMPLIFYUP_PREVIEW_MODE__ === true) {
5359
+ return;
5360
+ }
5361
+ if (window.location.pathname.includes("/api/pages/proxy")) {
5362
+ return;
5363
+ }
5364
+ if (window.self !== window.top) {
5365
+ return;
5366
+ }
5367
+ }
5368
+ sdk.track("Zone Impression", {
5369
+ zoneId: slot.zoneId,
5370
+ variantId: data.variantId,
5371
+ layoutId: pageConfig.layoutId,
5372
+ route: pageConfig.route
5373
+ });
5374
+ } else {
5375
+ const defaultVariant = slot.variants?.find((v) => v.isDefault);
5376
+ if (defaultVariant) {
5377
+ newCache[key] = {
5378
+ variantId: defaultVariant.variantId,
5379
+ children: defaultVariant.children
5380
+ };
5381
+ }
5382
+ }
5383
+ }
5384
+ } catch (err) {
5385
+ console.error(`Error fetching variant for slot ${key}:`, err);
5386
+ const defaultVariant = slot.variants?.find((v) => v.isDefault);
5387
+ if (defaultVariant) {
5388
+ newCache[key] = {
5389
+ variantId: defaultVariant.variantId,
5390
+ children: defaultVariant.children
5391
+ };
5392
+ }
5393
+ }
5394
+ })
5395
+ );
5396
+ setVariantCache(newCache);
5397
+ };
5398
+ fetchVariants();
5399
+ }, [pageConfig?.layoutTree, pageConfig?.layoutId, pageConfig?.route, contentSource]);
5400
+ if (loading) {
5401
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loadingComponent || /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen bg-gray-50", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container mx-auto px-4 py-16", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse", children: [
5402
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-8 bg-gray-200 rounded w-1/4 mb-4" }),
5403
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-gray-200 rounded w-1/2 mb-8" }),
5404
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
5405
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-64 bg-gray-200 rounded" }),
5406
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-32 bg-gray-200 rounded" })
5407
+ ] })
5408
+ ] }) }) }) });
5313
5409
  }
5314
- if (empty) return null;
5315
- const text = formatFieldValue(fieldValue);
5316
- if (!text) return null;
5317
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className, children: text });
5318
- }
5319
- function markdownToHtml(markdown) {
5320
- try {
5321
- const result = marked.marked.parse(markdown, { async: false });
5322
- return typeof result === "string" ? result : "";
5323
- } catch {
5324
- return markdown;
5325
- }
5326
- }
5327
- function RichText(props) {
5328
- const {
5329
- field,
5330
- value,
5331
- name,
5332
- className,
5333
- as: Tag = "div",
5334
- children
5335
- } = props;
5336
- const context = React3.useContext(ComponentContext);
5337
- const composerEdit = useComposerEditMode();
5338
- const childrenValue = typeof children === "string" || typeof children === "number" ? String(children) : void 0;
5339
- const hasField = isFieldEnvelope(field);
5340
- const hasValueProp = hasOwnProp(props, "value") || childrenValue !== void 0;
5341
- const boundValue = hasOwnProp(props, "value") ? value : childrenValue !== void 0 ? childrenValue : value;
5342
- const { editName, fieldValue, ref } = useBoundField(
5343
- field,
5344
- boundValue,
5345
- name,
5346
- "RichText"
5347
- );
5348
- assertNamedEnvelope("RichText", field);
5349
- if (!hasField && !hasValueProp && !name) {
5350
- return null;
5410
+ if (error) {
5411
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: errorComponent ? errorComponent(error) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen bg-gray-50", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container mx-auto px-4 py-16", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-red-50 border border-red-200 rounded-lg p-6", children: [
5412
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-bold text-red-900 mb-2", children: "Error Loading Page" }),
5413
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-red-700", children: error })
5414
+ ] }) }) }) });
5351
5415
  }
5352
- warnProjectionProps("RichText", hasField, hasValueProp, name);
5353
- if (warnNotScalarField("RichText", field, fieldValue)) {
5416
+ if (!pageConfig) {
5354
5417
  return null;
5355
5418
  }
5356
- const canEdit = !!context && canInlineEditRichText(editName, fieldValue) && canComposerBind(field, ref, editName);
5357
- if (isComposerEmptyText(fieldValue)) {
5358
- if (composerEdit && canEdit) {
5419
+ pageConfig.layout?.header !== false;
5420
+ pageConfig.layout?.footer !== false;
5421
+ const renderNode = (node) => {
5422
+ const zoneIdFromProps = node.componentId === "AmplifyZone" ? String(node.props?.zoneId || "") : "";
5423
+ if (node.componentId === "AmplifyZone") {
5424
+ const contentSlot = node.slots?.find((s) => s.slotId === "content") || node.slots?.[0];
5425
+ const children = Array.isArray(contentSlot?.children) ? contentSlot.children : [];
5359
5426
  return /* @__PURE__ */ jsxRuntime.jsx(
5360
- ComposerInlineField,
5427
+ "div",
5361
5428
  {
5362
- name: editName,
5363
- value: fieldValue,
5364
- className,
5365
- layoutNodeId: context?.layoutNodeId,
5366
- componentId: context?.componentId,
5367
- fieldRef: ref,
5368
- rich: true
5429
+ "data-node-id": node.id,
5430
+ "data-amplifyup-node": "",
5431
+ "data-amplifyup-component": "AmplifyZone",
5432
+ "data-amplifyup-zone": zoneIdFromProps || void 0,
5433
+ "data-zone-id": zoneIdFromProps || void 0,
5434
+ children: /* @__PURE__ */ jsxRuntime.jsx(
5435
+ "div",
5436
+ {
5437
+ "data-slot-id": "content",
5438
+ "data-amplifyup-slot": "content",
5439
+ "data-parent-node-id": node.id,
5440
+ "data-parent-component-id": "AmplifyZone",
5441
+ children: children.filter(Boolean).map((child) => /* @__PURE__ */ jsxRuntime.jsx(React3.Fragment, { children: renderNode(child) }, child.id))
5442
+ }
5443
+ )
5369
5444
  }
5370
5445
  );
5371
5446
  }
5372
- return null;
5373
- }
5374
- let html = "";
5375
- if (typeof fieldValue === "string") {
5376
- const trimmed = fieldValue.trim();
5377
- if (trimmed.startsWith("<") && trimmed.includes(">")) {
5378
- html = fieldValue;
5379
- } else {
5380
- html = markdownToHtml(fieldValue);
5381
- }
5382
- } else {
5383
- const text = formatFieldValue(fieldValue);
5384
- html = text ? markdownToHtml(text) : "";
5385
- }
5386
- if (!html) {
5387
- return null;
5388
- }
5389
- if (composerEdit && canEdit) {
5447
+ let slotChildren = {};
5448
+ sdkDebugOnce(`node:${node.id}`, `[AmplifyRenderer] Rendering node ${node.id} (${node.componentId})`, {
5449
+ hasSlots: !!(node.slots && node.slots.length > 0),
5450
+ slotCount: node.slots?.length || 0,
5451
+ slots: node.slots?.map((s) => ({ slotId: s.slotId, zoneId: s.zoneId, childrenCount: s.children?.length || 0 }))
5452
+ });
5453
+ if (node.slots && node.slots.length > 0) {
5454
+ for (const slot of node.slots) {
5455
+ const slotKey = `${node.id}-${slot.slotId}`;
5456
+ let childrenToRender = [];
5457
+ if (slot.zoneId && slot.variants && variantCache[slotKey]) {
5458
+ childrenToRender = variantCache[slotKey].children;
5459
+ } else if (slot.zoneId && slot.variants) {
5460
+ const defaultVariant = slot.variants.find((v) => v.isDefault);
5461
+ childrenToRender = defaultVariant?.children || [];
5462
+ } else {
5463
+ childrenToRender = Array.isArray(slot.children) ? slot.children : [];
5464
+ }
5465
+ const safeChildren = Array.isArray(childrenToRender) ? childrenToRender : [];
5466
+ slotChildren[slot.slotId] = /* @__PURE__ */ jsxRuntime.jsx(
5467
+ "div",
5468
+ {
5469
+ "data-slot-id": slot.slotId,
5470
+ "data-amplifyup-slot": slot.slotId,
5471
+ "data-zone-id": slot.zoneId || void 0,
5472
+ "data-parent-node-id": node.id,
5473
+ "data-parent-component-id": node.componentId,
5474
+ children: safeChildren.filter(Boolean).map((child) => /* @__PURE__ */ jsxRuntime.jsx(React3.Fragment, { children: renderNode(child) }, child.id))
5475
+ },
5476
+ slot.slotId
5477
+ );
5478
+ }
5479
+ }
5480
+ const slotsToPass = Object.keys(slotChildren).length > 0 ? slotChildren : void 0;
5390
5481
  return /* @__PURE__ */ jsxRuntime.jsx(
5391
- ComposerInlineHtml,
5482
+ "div",
5392
5483
  {
5393
- name: editName,
5394
- html,
5395
- sourceValue: typeof fieldValue === "string" ? fieldValue : html,
5396
- className,
5397
- Tag,
5398
- layoutNodeId: context?.layoutNodeId,
5399
- componentId: context?.componentId,
5400
- fieldRef: ref
5484
+ "data-node-id": node.id,
5485
+ "data-amplifyup-node": "",
5486
+ "data-component-id": node.componentId,
5487
+ "data-amplifyup-component": node.componentId,
5488
+ children: /* @__PURE__ */ jsxRuntime.jsx(
5489
+ ComponentRenderBoundary,
5490
+ {
5491
+ componentId: node.componentId,
5492
+ nodeId: node.id,
5493
+ children: /* @__PURE__ */ jsxRuntime.jsx(
5494
+ NodeWithFields,
5495
+ {
5496
+ nodeId: node.id,
5497
+ componentId: node.componentId,
5498
+ props: nodeRenderProps(node),
5499
+ slots: slotsToPass,
5500
+ registry,
5501
+ composerPreview: composerPreviewFlag
5502
+ }
5503
+ )
5504
+ }
5505
+ )
5401
5506
  }
5402
5507
  );
5508
+ };
5509
+ const rawTree = pageConfig.layoutTree;
5510
+ const layoutTree = Array.isArray(rawTree) ? rawTree : rawTree && typeof rawTree === "object" && rawTree.componentId ? [rawTree] : [];
5511
+ if (layoutTree.length === 0) {
5512
+ return /* @__PURE__ */ jsxRuntime.jsx("main", { children: emptyComponent || /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container mx-auto px-4 py-16", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: "No content configured for this page." }) }) });
5403
5513
  }
5404
- return /* @__PURE__ */ jsxRuntime.jsx(Tag, { className, dangerouslySetInnerHTML: { __html: html } });
5514
+ return /* @__PURE__ */ jsxRuntime.jsx(ComposerProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
5515
+ "main",
5516
+ {
5517
+ "data-slot-id": composerPreviewFlag ? "main" : void 0,
5518
+ "data-amplifyup-slot": composerPreviewFlag ? "main" : void 0,
5519
+ "data-slot-source": composerPreviewFlag ? "page" : void 0,
5520
+ "data-slot-state": composerPreviewFlag ? "filled" : void 0,
5521
+ children: layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx(React3.Fragment, { children: renderNode(node) }, node.id))
5522
+ }
5523
+ ) });
5405
5524
  }
5406
- function isPortableImageValue(value) {
5407
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
5408
- const url = value.url;
5409
- return typeof url === "string" && url.trim().length > 0;
5525
+ var AmplifyRenderer = React3.memo(AmplifyRendererInner);
5526
+ function previewPageSlot(state) {
5527
+ return /* @__PURE__ */ jsxRuntime.jsx(
5528
+ "div",
5529
+ {
5530
+ "data-slot-id": "main",
5531
+ "data-amplifyup-slot": "main",
5532
+ "data-slot-source": "page",
5533
+ "data-slot-state": state,
5534
+ "data-slot-empty": state === "empty" ? "true" : void 0,
5535
+ style: {
5536
+ minHeight: state === "empty" ? "50vh" : void 0,
5537
+ width: "100%",
5538
+ display: "block",
5539
+ position: "relative"
5540
+ },
5541
+ children: state === "empty" ? /* @__PURE__ */ jsxRuntime.jsx(EmptySlotHint, {}) : null
5542
+ }
5543
+ );
5410
5544
  }
5411
- function imageSrc(value) {
5412
- if (typeof value === "string") return value.trim();
5413
- if (isPortableImageValue(value)) return value.url.trim();
5414
- return "";
5545
+ function hasAmplifyLayout(pageConfig) {
5546
+ return !!(pageConfig && pageConfig.id !== "default" && Array.isArray(pageConfig.layoutTree) && pageConfig.layoutTree.length > 0);
5415
5547
  }
5416
- function leafText(field) {
5417
- if (isFieldEnvelope(field)) return field.value;
5418
- return field;
5548
+ function normalizeRoutePath(route) {
5549
+ if (!route) return "";
5550
+ const path = route.split("?")[0] || "/";
5551
+ if (path.length > 1 && path.endsWith("/")) return path.replace(/\/+$/, "");
5552
+ return path || "/";
5419
5553
  }
5420
- function coerceImageField(field, value, name) {
5421
- if (isFieldEnvelope(field)) return { field, value, name };
5422
- if (!isBrandedFields(field) || !field || typeof field !== "object") {
5423
- return { field: void 0, value, name };
5424
- }
5425
- const bag = field;
5426
- const urlField = bag.url;
5427
- const urlName = isFieldEnvelope(urlField) && typeof urlField.name === "string" ? urlField.name.replace(/\.url$/, "") : "";
5428
- const editName = urlName || name || "";
5429
- if (!editName) return { field: void 0, value, name };
5430
- const ref = isFieldEnvelope(urlField) ? urlField.ref : void 0;
5431
- const width = leafText(bag.width);
5432
- const height = leafText(bag.height);
5433
- return {
5434
- field: {
5435
- value: {
5436
- url: String(leafText(urlField) ?? ""),
5437
- alt: leafText(bag.alt),
5438
- ...typeof width === "number" ? { width } : {},
5439
- ...typeof height === "number" ? { height } : {}
5440
- },
5441
- name: editName,
5442
- ...ref ? { ref } : {}
5443
- },
5444
- value,
5445
- name: editName
5446
- };
5554
+ function samePageRoute(a, b) {
5555
+ const ar = normalizeRoutePath(a?.route);
5556
+ const br = normalizeRoutePath(b?.route);
5557
+ return !!ar && !!br && ar === br;
5447
5558
  }
5448
- function Image(props) {
5559
+ function layoutTreesEqual(a, b) {
5560
+ if (!a || !b) return a === b;
5561
+ return JSON.stringify(a.layoutTree) === JSON.stringify(b.layoutTree);
5562
+ }
5563
+ function AmplifyPageContent(contentProps) {
5564
+ assertComponentRegistry("AmplifyPageContent", contentProps);
5449
5565
  const {
5450
- field,
5451
- value,
5452
- name,
5453
- alt: altProp,
5454
- className,
5455
- width: widthProp,
5456
- height: heightProp,
5457
- ...imgProps
5458
- } = props;
5459
- const context = React3.useContext(ComponentContext);
5460
- assertNamedEnvelope("Image", field);
5461
- const coerced = coerceImageField(field, value, name);
5462
- const boundField = coerced.field;
5463
- const hasField = isFieldEnvelope(boundField);
5464
- const hasValue = hasOwnProp(props, "value");
5465
- const { editName, fieldValue, ref } = useBoundField(
5466
- boundField,
5467
- coerced.value,
5468
- coerced.name,
5469
- "Image"
5470
- );
5471
- const composerEdit = useComposerEditMode();
5472
- warnProjectionProps("Image", hasField || isBrandedFields(field), hasValue, coerced.name || name);
5473
- if (!isBrandedFields(field) && warnNotScalarField("Image", boundField, fieldValue)) {
5474
- return null;
5475
- }
5476
- if (!hasField && !hasValue && !name && !editName) {
5477
- return null;
5478
- }
5479
- const src = imageSrc(fieldValue);
5480
- const portable = isPortableImageValue(fieldValue) ? fieldValue : null;
5481
- const alt = altProp ?? portable?.alt ?? "";
5482
- const width = widthProp ?? portable?.width;
5483
- const height = heightProp ?? portable?.height;
5484
- const fieldAttrs = composerEdit && editName && canComposerBind(boundField, ref, editName) ? {
5485
- "data-amplifyup-field": editName,
5486
- "data-amplifyup-field-type": "image",
5487
- "data-amplifyup-node-id": context?.layoutNodeId || void 0,
5488
- "data-amplifyup-ref-provider": ref?.providerId || void 0,
5489
- "data-amplifyup-ref-entity": ref?.entity || void 0,
5490
- "data-amplifyup-ref-id": ref?.id || void 0
5491
- } : null;
5492
- if (composerEdit && !editName && (hasField || hasValue)) {
5493
- console.warn(
5494
- '[AmplifyUp SDK] Image value={\u2026} requires name="\u2026" for computed values'
5495
- );
5566
+ fallback,
5567
+ registry,
5568
+ pageConfig: pageConfigProp,
5569
+ forceComposerPreview = false,
5570
+ previewLoadingComponent,
5571
+ previewEmptyComponent,
5572
+ loadingComponent,
5573
+ emptyComponent,
5574
+ errorComponent
5575
+ } = contentProps;
5576
+ const client = useAmplifyUp();
5577
+ useRegisterPageContent();
5578
+ const preview = useComposerPreviewFlag(forceComposerPreview);
5579
+ const clientLayout = hasAmplifyLayout(client.pageConfig) ? client.pageConfig : null;
5580
+ const serverLayout = hasAmplifyLayout(pageConfigProp) ? pageConfigProp : null;
5581
+ let pageConfig = serverLayout ?? clientLayout;
5582
+ if (preview && clientLayout) {
5583
+ pageConfig = clientLayout;
5584
+ } else if (clientLayout && serverLayout && samePageRoute(clientLayout, serverLayout) && !layoutTreesEqual(clientLayout, serverLayout)) {
5585
+ pageConfig = clientLayout;
5586
+ } else if (clientLayout && !serverLayout) {
5587
+ pageConfig = clientLayout;
5496
5588
  }
5497
- if (!src) {
5498
- if (!composerEdit || !fieldAttrs) return null;
5499
- return /* @__PURE__ */ jsxRuntime.jsx(
5500
- "span",
5589
+ const loading = !hasAmplifyLayout(pageConfig) && client.loading;
5590
+ const error = hasAmplifyLayout(pageConfig) ? null : pageConfigProp ? null : client.error;
5591
+ const previewEmpty = previewEmptyComponent ?? previewPageSlot("empty");
5592
+ const previewLoading = previewLoadingComponent ?? previewPageSlot("loading");
5593
+ if (preview) {
5594
+ const ready = previewLayoutReady({
5595
+ clientLoading: client.loading,
5596
+ hasClientLayout: !!clientLayout,
5597
+ hasServerLayout: !!serverLayout
5598
+ });
5599
+ if (!ready) {
5600
+ return /* @__PURE__ */ jsxRuntime.jsx(ComposerLayoutStatusProvider, { ready: false, children: previewLoading });
5601
+ }
5602
+ const layoutSettled = !client.loading || !!clientLayout;
5603
+ return /* @__PURE__ */ jsxRuntime.jsx(ComposerLayoutStatusProvider, { ready: layoutSettled, children: /* @__PURE__ */ jsxRuntime.jsx(
5604
+ AmplifyRenderer,
5501
5605
  {
5502
- ...fieldAttrs,
5503
- className,
5504
- role: "img",
5505
- "aria-label": alt || editName || "Image",
5506
- style: {
5507
- display: "block",
5508
- boxSizing: "border-box",
5509
- minWidth: width ? void 0 : 120,
5510
- minHeight: height ? void 0 : 80,
5511
- width: width || "100%",
5512
- height: height || void 0,
5513
- background: "color-mix(in srgb, currentColor 8%, transparent)",
5514
- cursor: "pointer"
5515
- }
5606
+ pageConfig: pageConfig ?? void 0,
5607
+ registry,
5608
+ composerPreview: true,
5609
+ loadingComponent: loadingComponent ?? previewLoading,
5610
+ emptyComponent: emptyComponent ?? previewEmpty,
5611
+ errorComponent: errorComponent ?? (() => previewEmpty)
5516
5612
  }
5517
- );
5613
+ ) });
5518
5614
  }
5519
- return /* @__PURE__ */ jsxRuntime.jsx(
5520
- "img",
5615
+ if (loading) {
5616
+ return loadingComponent ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loadingComponent }) : null;
5617
+ }
5618
+ if (error) {
5619
+ if (errorComponent) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: errorComponent(error) });
5620
+ return fallback ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback }) : null;
5621
+ }
5622
+ if (!hasAmplifyLayout(pageConfig)) {
5623
+ return fallback ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback }) : null;
5624
+ }
5625
+ return /* @__PURE__ */ jsxRuntime.jsx(ComposerLayoutStatusProvider, { ready: true, children: /* @__PURE__ */ jsxRuntime.jsx(
5626
+ AmplifyRenderer,
5521
5627
  {
5522
- ...imgProps,
5523
- ...fieldAttrs,
5524
- src,
5525
- alt,
5526
- className,
5527
- width,
5528
- height,
5529
- style: {
5530
- ...typeof imgProps.style === "object" && imgProps.style ? imgProps.style : {},
5531
- ...composerEdit && fieldAttrs ? { cursor: "pointer" } : null
5532
- }
5628
+ pageConfig: pageConfig ?? void 0,
5629
+ registry,
5630
+ loadingComponent,
5631
+ emptyComponent,
5632
+ errorComponent
5533
5633
  }
5534
- );
5634
+ ) });
5535
5635
  }
5636
+ var bindAmplifyPage = (registry) => {
5637
+ const AmplifyPage = (props) => /* @__PURE__ */ jsxRuntime.jsx(AmplifyPageContent, { ...props, registry });
5638
+ AmplifyPage.displayName = "AmplifyPage";
5639
+ return AmplifyPage;
5640
+ };
5536
5641
  var usePathname = null;
5537
5642
  if (typeof window !== "undefined") {
5538
5643
  try {
@@ -5830,7 +5935,6 @@ function useAmplifyUp() {
5830
5935
  exports.AmplifyPageContent = AmplifyPageContent;
5831
5936
  exports.AmplifyRenderer = AmplifyRenderer;
5832
5937
  exports.AmplifyUpProvider = AmplifyUpProvider;
5833
- exports.ComponentContextProvider = ComponentContextProvider;
5834
5938
  exports.ComposerLayoutStatusProvider = ComposerLayoutStatusProvider;
5835
5939
  exports.ComposerProvider = ComposerProvider;
5836
5940
  exports.Field = Field;
@@ -5841,7 +5945,9 @@ exports.RichText = RichText;
5841
5945
  exports.SelectVariantsError = SelectVariantsError;
5842
5946
  exports.Slot = Slot;
5843
5947
  exports.attachFieldEnvelopes = attachFieldEnvelopes;
5948
+ exports.bindAmplifyPage = bindAmplifyPage;
5844
5949
  exports.composerStoreKey = composerStoreKey;
5950
+ exports.defineComponentRegistry = defineComponentRegistry;
5845
5951
  exports.envelopeListRows = envelopeListRows;
5846
5952
  exports.isBrandedFields = isBrandedFields;
5847
5953
  exports.isComposerPreview = isComposerPreview;