@amplifyup/sdk 0.1.11 → 0.1.13

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.
@@ -283,6 +283,32 @@ function resolveAmplifyUpUrls(target) {
283
283
  };
284
284
  }
285
285
 
286
+ // src/preview.ts
287
+ function isPreviewRequest(searchParams) {
288
+ if (searchParams instanceof URLSearchParams) {
289
+ return searchParams.get("preview") === "true" || searchParams.get("visualEditor") === "true";
290
+ }
291
+ const preview = searchParams.preview;
292
+ const visualEditor = searchParams.visualEditor;
293
+ return preview === "true" || visualEditor === "true";
294
+ }
295
+ function isComposerPreview() {
296
+ if (typeof window === "undefined") return false;
297
+ if (window.__AMPLIFYUP_PREVIEW_MODE__ === true) return true;
298
+ const params = new URLSearchParams(window.location.search);
299
+ if (isPreviewRequest(params)) return true;
300
+ if (window.self !== window.top && document.referrer) {
301
+ try {
302
+ const refUrl = new URL(document.referrer);
303
+ if (refUrl.hostname === "amplifyup.ai" || refUrl.hostname.endsWith(".amplifyup.ai") || refUrl.hostname === "localhost" && refUrl.port === "5001" || refUrl.pathname.includes("/dashboard/composer") || refUrl.pathname.includes("/dashboard/routes/")) {
304
+ return true;
305
+ }
306
+ } catch {
307
+ }
308
+ }
309
+ return false;
310
+ }
311
+
286
312
  // src/index.ts
287
313
  function readPreviewQueryOverrides() {
288
314
  if (typeof window === "undefined") return {};
@@ -324,6 +350,15 @@ var AmplifyUpSDK = class {
324
350
  this.messageListener = null;
325
351
  this.mutationObserver = null;
326
352
  this.composerDragHandlers = null;
353
+ /** Last slot highlighted during Composer drag — avoid clear/re-add flicker. */
354
+ this.lastComposerDragSlot = null;
355
+ /** Consecutive miss frames before clearing highlight (anti-jitter). */
356
+ this.composerDragMissFrames = 0;
357
+ /**
358
+ * Parent overlay is driving drag via postMessage. Native iframe dragleave must
359
+ * not clear highlight — overlay takeover fires a spurious document dragleave.
360
+ */
361
+ this.composerOverlayDragActive = false;
327
362
  this.isVisualEditorMode = false;
328
363
  this.eventSelectionMode = false;
329
364
  this.eventSelectionClickHandler = null;
@@ -854,6 +889,12 @@ Available Console Commands:
854
889
  }
855
890
  throw new Error(`Failed to fetch page: ${response.statusText}`);
856
891
  }
892
+ const contentType = response.headers.get("content-type") || "";
893
+ if (!contentType.includes("application/json")) {
894
+ throw new Error(
895
+ `Layout provider returned non-JSON (${contentType || "unknown"}). Check Composer preview routing.`
896
+ );
897
+ }
857
898
  const data = await response.json();
858
899
  const pageConfig = data.page;
859
900
  if (pageConfig?.eventTracking) {
@@ -1138,33 +1179,94 @@ Available Console Commands:
1138
1179
  }
1139
1180
  return;
1140
1181
  }
1182
+ if (event.data?.type === "COMPOSER_DRAG_START") {
1183
+ this.composerOverlayDragActive = true;
1184
+ if (typeof document !== "undefined") {
1185
+ document.body.classList.add("amplifyup-composer-dragging");
1186
+ }
1187
+ return;
1188
+ }
1189
+ if (event.data?.type === "COMPOSER_DRAG_AT_POINT") {
1190
+ const { x, y } = event.data;
1191
+ if (typeof x === "number" && typeof y === "number") {
1192
+ this.handleComposerDragAtPoint(x, y);
1193
+ }
1194
+ return;
1195
+ }
1196
+ if (event.data?.type === "COMPOSER_DROP_AT_POINT") {
1197
+ const { x, y } = event.data;
1198
+ if (typeof x === "number" && typeof y === "number") {
1199
+ this.handleComposerDropAtPoint(x, y);
1200
+ }
1201
+ return;
1202
+ }
1203
+ if (event.data?.type === "COMPOSER_DRAG_END") {
1204
+ this.composerOverlayDragActive = false;
1205
+ this.clearComposerDragHighlight();
1206
+ return;
1207
+ }
1141
1208
  if (event.data?.type === "GET_ELEMENT_POSITION") {
1142
- const { componentId, slotName } = event.data;
1143
- const selector = slotName ? `[data-amplifyup-slot="${slotName}"], [data-slot-id="${slotName}"]` : `[data-amplifyup-component="${componentId}"], [data-component-id="${componentId}"]`;
1144
- console.log("[AmplifyUp SDK] Finding element position:", { selector, componentId, slotName });
1145
- const element = document.querySelector(selector);
1209
+ const { componentId, slotName, nodeId, isPageSlot } = event.data;
1210
+ let element = null;
1211
+ if (isPageSlot || slotName === "main" && !nodeId && !componentId) {
1212
+ element = document.querySelector(
1213
+ '[data-slot-source="page"]'
1214
+ );
1215
+ }
1216
+ if (!element && nodeId && slotName) {
1217
+ element = document.querySelector(
1218
+ `[data-parent-node-id="${nodeId}"][data-slot-id="${slotName}"], [data-parent-node-id="${nodeId}"][data-amplifyup-slot="${slotName}"]`
1219
+ );
1220
+ }
1221
+ if (!element && nodeId && !slotName) {
1222
+ element = document.querySelector(
1223
+ `[data-node-id="${nodeId}"]`
1224
+ );
1225
+ }
1226
+ if (!element && slotName) {
1227
+ element = document.querySelector(
1228
+ `[data-amplifyup-slot="${slotName}"], [data-slot-id="${slotName}"]`
1229
+ );
1230
+ }
1231
+ if (!element && componentId) {
1232
+ element = document.querySelector(
1233
+ `[data-amplifyup-component="${componentId}"], [data-component-id="${componentId}"]`
1234
+ );
1235
+ }
1236
+ console.log("[AmplifyUp SDK] Finding element position:", {
1237
+ componentId,
1238
+ slotName,
1239
+ nodeId,
1240
+ isPageSlot,
1241
+ found: !!element
1242
+ });
1146
1243
  if (element) {
1147
1244
  const rect = element.getBoundingClientRect();
1148
1245
  const position = {
1149
1246
  x: rect.left + rect.width / 2,
1150
- // Center of element
1151
1247
  y: rect.top - 50,
1152
- // Position above element
1153
1248
  width: rect.width,
1154
1249
  height: rect.height
1155
1250
  };
1156
- console.log("[AmplifyUp SDK] Element position calculated:", { rect, position });
1251
+ const bounds = {
1252
+ top: rect.top,
1253
+ left: rect.left,
1254
+ width: rect.width,
1255
+ height: rect.height
1256
+ };
1157
1257
  if (window.parent && window.parent !== window) {
1158
1258
  window.parent.postMessage({
1159
1259
  type: "ELEMENT_POSITION",
1160
- componentId,
1161
- slotName,
1162
- position
1260
+ componentId: componentId || null,
1261
+ slotName: slotName || null,
1262
+ nodeId: nodeId || null,
1263
+ isPageSlot: !!isPageSlot,
1264
+ position,
1265
+ bounds
1163
1266
  }, "*");
1164
- console.log("[AmplifyUp SDK] Sent ELEMENT_POSITION message");
1165
1267
  }
1166
1268
  } else {
1167
- console.warn("[AmplifyUp SDK] Element not found for selector:", selector);
1269
+ console.warn("[AmplifyUp SDK] Element not found for position request");
1168
1270
  }
1169
1271
  return;
1170
1272
  }
@@ -1271,6 +1373,157 @@ Available Console Commands:
1271
1373
  }
1272
1374
  return el.tagName.toLowerCase();
1273
1375
  }
1376
+ /** Clear drag-over highlight state (Composer overlay path or native drag end). */
1377
+ clearComposerDragHighlight() {
1378
+ if (typeof document === "undefined") return;
1379
+ const slotSelector = "[data-slot-id], [data-amplifyup-slot]";
1380
+ document.querySelectorAll(`${slotSelector}.amplifyup-drag-over-slot`).forEach((el) => {
1381
+ el.classList.remove("amplifyup-drag-over-slot");
1382
+ });
1383
+ document.body.classList.remove("amplifyup-drag-no-drop");
1384
+ document.body.classList.remove("amplifyup-composer-dragging");
1385
+ this.lastComposerDragSlot = null;
1386
+ this.composerDragMissFrames = 0;
1387
+ }
1388
+ /** Re-apply drag-over class only if missing (avoids classList churn / flicker). */
1389
+ ensureDragOverClass(slot) {
1390
+ if (!slot.classList.contains("amplifyup-drag-over-slot")) {
1391
+ slot.classList.add("amplifyup-drag-over-slot");
1392
+ }
1393
+ if (document.body.classList.contains("amplifyup-drag-no-drop")) {
1394
+ document.body.classList.remove("amplifyup-drag-no-drop");
1395
+ }
1396
+ }
1397
+ /**
1398
+ * Composer drag targets the innermost (most specific) slot under the cursor.
1399
+ * e.g. FullWidthGrid's main wins over a page-level main that wraps it.
1400
+ */
1401
+ resolveSlotAtPoint(x, y) {
1402
+ if (typeof document === "undefined") return null;
1403
+ const slotSelector = "[data-slot-id], [data-amplifyup-slot]";
1404
+ const containing = [];
1405
+ document.querySelectorAll(slotSelector).forEach((node) => {
1406
+ const el = node;
1407
+ const r = el.getBoundingClientRect();
1408
+ if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) {
1409
+ containing.push(el);
1410
+ }
1411
+ });
1412
+ if (containing.length === 0) return null;
1413
+ const innermost = containing.filter(
1414
+ (el) => !containing.some((other) => other !== el && el.contains(other))
1415
+ );
1416
+ if (innermost.length === 1) return innermost[0];
1417
+ let best = innermost[0];
1418
+ let bestArea = Infinity;
1419
+ for (const el of innermost) {
1420
+ const r = el.getBoundingClientRect();
1421
+ const area = Math.max(1, r.width) * Math.max(1, r.height);
1422
+ if (area < bestArea) {
1423
+ bestArea = area;
1424
+ best = el;
1425
+ }
1426
+ }
1427
+ return best;
1428
+ }
1429
+ /** Parent layout node that owns this slot (null for page-level code main). */
1430
+ parentComponentForSlot(slotEl) {
1431
+ let componentId = slotEl.getAttribute("data-parent-component-id");
1432
+ let nodeId = slotEl.getAttribute("data-parent-node-id");
1433
+ let el = slotEl.parentElement;
1434
+ while (el && (!nodeId || !componentId)) {
1435
+ if (!nodeId && el.hasAttribute("data-node-id")) {
1436
+ nodeId = el.getAttribute("data-node-id");
1437
+ }
1438
+ if (!componentId) {
1439
+ componentId = el.getAttribute("data-amplifyup-component") || el.getAttribute("data-component-id");
1440
+ }
1441
+ if (nodeId) break;
1442
+ el = el.parentElement;
1443
+ }
1444
+ return { componentId, nodeId };
1445
+ }
1446
+ pointInRect(x, y, el, pad = 8) {
1447
+ const r = el.getBoundingClientRect();
1448
+ return x >= r.left - pad && x <= r.right + pad && y >= r.top - pad && y <= r.bottom + pad;
1449
+ }
1450
+ setComposerDragHighlight(slot, x, y) {
1451
+ if (slot && slot === this.lastComposerDragSlot) {
1452
+ this.composerDragMissFrames = 0;
1453
+ this.ensureDragOverClass(slot);
1454
+ return;
1455
+ }
1456
+ if (slot && this.lastComposerDragSlot && this.lastComposerDragSlot.contains(slot) && slot !== this.lastComposerDragSlot) {
1457
+ this.composerDragMissFrames = 0;
1458
+ this.lastComposerDragSlot.classList.remove("amplifyup-drag-over-slot");
1459
+ this.lastComposerDragSlot = slot;
1460
+ this.ensureDragOverClass(slot);
1461
+ return;
1462
+ }
1463
+ if (this.lastComposerDragSlot && typeof x === "number" && typeof y === "number" && this.pointInRect(x, y, this.lastComposerDragSlot)) {
1464
+ if (!slot || slot.contains(this.lastComposerDragSlot) || slot === this.lastComposerDragSlot) {
1465
+ this.composerDragMissFrames = 0;
1466
+ this.ensureDragOverClass(this.lastComposerDragSlot);
1467
+ return;
1468
+ }
1469
+ }
1470
+ if (slot) {
1471
+ this.composerDragMissFrames = 0;
1472
+ if (this.lastComposerDragSlot && this.lastComposerDragSlot !== slot) {
1473
+ this.lastComposerDragSlot.classList.remove("amplifyup-drag-over-slot");
1474
+ }
1475
+ this.lastComposerDragSlot = slot;
1476
+ this.ensureDragOverClass(slot);
1477
+ return;
1478
+ }
1479
+ this.composerDragMissFrames += 1;
1480
+ if (this.lastComposerDragSlot && this.composerDragMissFrames < 8) {
1481
+ this.ensureDragOverClass(this.lastComposerDragSlot);
1482
+ return;
1483
+ }
1484
+ if (this.lastComposerDragSlot) {
1485
+ this.lastComposerDragSlot.classList.remove("amplifyup-drag-over-slot");
1486
+ this.lastComposerDragSlot = null;
1487
+ }
1488
+ if (!document.body.classList.contains("amplifyup-drag-no-drop")) {
1489
+ document.body.classList.add("amplifyup-drag-no-drop");
1490
+ }
1491
+ }
1492
+ handleComposerDragAtPoint(x, y) {
1493
+ this.composerOverlayDragActive = true;
1494
+ if (!document.body.classList.contains("amplifyup-composer-dragging")) {
1495
+ document.body.classList.add("amplifyup-composer-dragging");
1496
+ }
1497
+ this.setComposerDragHighlight(this.resolveSlotAtPoint(x, y), x, y);
1498
+ }
1499
+ postDropOnSlot(slotEl) {
1500
+ const win = window;
1501
+ if (!win.parent || win.parent === win) return;
1502
+ const slotName = slotEl.getAttribute("data-amplifyup-slot") || slotEl.getAttribute("data-slot-id");
1503
+ if (!slotName) return;
1504
+ const { componentId, nodeId } = this.parentComponentForSlot(slotEl);
1505
+ const isEmpty = slotEl.getAttribute("data-slot-empty") === "true";
1506
+ win.parent.postMessage(
1507
+ {
1508
+ type: "DROP_ON_SLOT",
1509
+ slotName,
1510
+ slotElement: {
1511
+ path: slotEl.getAttribute("data-slot-path"),
1512
+ isEmpty,
1513
+ parentComponentId: componentId,
1514
+ parentNodeId: nodeId
1515
+ }
1516
+ },
1517
+ "*"
1518
+ );
1519
+ }
1520
+ handleComposerDropAtPoint(x, y) {
1521
+ if (typeof document === "undefined") return;
1522
+ const htmlEl = this.resolveSlotAtPoint(x, y);
1523
+ this.clearComposerDragHighlight();
1524
+ if (!htmlEl) return;
1525
+ this.postDropOnSlot(htmlEl);
1526
+ }
1274
1527
  /**
1275
1528
  * Enable component highlighting
1276
1529
  */
@@ -1297,35 +1550,25 @@ Available Console Commands:
1297
1550
  this.teardownComposerDragDrop();
1298
1551
  const slotSelector = "[data-slot-id], [data-amplifyup-slot]";
1299
1552
  const clearDragOverState = () => {
1300
- document.querySelectorAll(`${slotSelector}.amplifyup-drag-over-slot`).forEach((el) => {
1301
- el.classList.remove("amplifyup-drag-over-slot");
1302
- });
1303
- document.body.classList.remove("amplifyup-drag-no-drop");
1553
+ this.clearComposerDragHighlight();
1304
1554
  };
1305
1555
  const dragenter = (e) => {
1306
1556
  e.preventDefault();
1307
- if (e.dataTransfer?.types?.length) {
1308
- document.body.classList.add("amplifyup-drag-no-drop");
1309
- }
1310
1557
  };
1311
1558
  const dragover = (e) => {
1312
1559
  e.preventDefault();
1313
- const target = e.target;
1314
- const slot = target?.closest?.(slotSelector);
1560
+ if (this.composerOverlayDragActive) {
1561
+ if (e.dataTransfer) e.dataTransfer.dropEffect = "copy";
1562
+ return;
1563
+ }
1564
+ const slot = this.resolveSlotAtPoint(e.clientX, e.clientY);
1315
1565
  if (e.dataTransfer) {
1316
1566
  e.dataTransfer.dropEffect = slot ? "copy" : "none";
1317
1567
  }
1318
- document.querySelectorAll(`${slotSelector}.amplifyup-drag-over-slot`).forEach((el) => {
1319
- el.classList.remove("amplifyup-drag-over-slot");
1320
- });
1321
- if (slot) {
1322
- slot.classList.add("amplifyup-drag-over-slot");
1323
- document.body.classList.remove("amplifyup-drag-no-drop");
1324
- } else {
1325
- document.body.classList.add("amplifyup-drag-no-drop");
1326
- }
1568
+ this.setComposerDragHighlight(slot, e.clientX, e.clientY);
1327
1569
  };
1328
1570
  const dragleave = (e) => {
1571
+ if (this.composerOverlayDragActive) return;
1329
1572
  const related = e.relatedTarget;
1330
1573
  if (!related || !document.body.contains(related)) {
1331
1574
  clearDragOverState();
@@ -1333,20 +1576,10 @@ Available Console Commands:
1333
1576
  };
1334
1577
  const drop = (e) => {
1335
1578
  e.preventDefault();
1336
- const target = e.target;
1337
- const slot = target?.closest?.(slotSelector);
1579
+ const slot = this.resolveSlotAtPoint(e.clientX, e.clientY);
1338
1580
  clearDragOverState();
1339
1581
  if (!slot || !this.isVisualEditorMode) return;
1340
- const slotName = slot.getAttribute("data-amplifyup-slot") || slot.getAttribute("data-slot-id");
1341
- const isEmpty = slot.getAttribute("data-slot-empty") === "true";
1342
- const win = window;
1343
- if (slotName && win.parent && win.parent !== win) {
1344
- win.parent.postMessage({
1345
- type: "DROP_ON_SLOT",
1346
- slotName,
1347
- slotElement: { path: slot.getAttribute("data-slot-path"), isEmpty }
1348
- }, "*");
1349
- }
1582
+ this.postDropOnSlot(slot);
1350
1583
  };
1351
1584
  const mouseover = (e) => {
1352
1585
  if (!this.showZonesEnabled) return;
@@ -1385,7 +1618,11 @@ Available Console Commands:
1385
1618
  document.removeEventListener("mouseover", h.mouseover, true);
1386
1619
  document.removeEventListener("mouseout", h.mouseout, true);
1387
1620
  this.composerDragHandlers = null;
1621
+ this.composerOverlayDragActive = false;
1622
+ this.lastComposerDragSlot = null;
1623
+ this.composerDragMissFrames = 0;
1388
1624
  document.body.classList.remove("amplifyup-drag-no-drop");
1625
+ document.body.classList.remove("amplifyup-composer-dragging");
1389
1626
  document.querySelectorAll("[data-slot-id].amplifyup-drag-over-slot, [data-amplifyup-slot].amplifyup-drag-over-slot").forEach((el) => {
1390
1627
  el.classList.remove("amplifyup-drag-over-slot");
1391
1628
  });
@@ -1426,21 +1663,32 @@ Available Console Commands:
1426
1663
  '[data-slot-id="main"], [data-amplifyup-slot="main"] {',
1427
1664
  " min-height: 50vh !important;",
1428
1665
  "}",
1429
- '[data-slot-id="main"][data-slot-empty="true"]::before,',
1430
- '[data-amplifyup-slot="main"][data-slot-empty="true"]::before {',
1431
- ' content: "Drop components here" !important;',
1432
- " position: absolute !important;",
1433
- " top: 50% !important; left: 50% !important;",
1434
- " transform: translate(-50%, -50%) !important;",
1435
- " font-size: 14px !important; font-weight: 500 !important;",
1436
- " color: rgba(34, 197, 94, 0.65) !important;",
1666
+ /* Single empty-state hint — Slot React label uses .amplifyup-slot-placeholder */
1667
+ ".amplifyup-slot-placeholder {",
1668
+ " display: flex !important;",
1669
+ " align-items: center !important;",
1670
+ " justify-content: center !important;",
1671
+ " min-height: inherit !important;",
1672
+ " color: rgba(34, 197, 94, 0.75) !important;",
1673
+ " font-size: 14px !important;",
1674
+ " font-weight: 500 !important;",
1437
1675
  " pointer-events: none !important;",
1438
- " white-space: nowrap !important;",
1676
+ " text-align: center !important;",
1439
1677
  "}",
1440
1678
  "[data-slot-id].amplifyup-slot-hover, [data-amplifyup-slot].amplifyup-slot-hover {",
1441
1679
  " outline-color: rgba(34, 197, 94, 1) !important;",
1442
1680
  " background: rgba(34, 197, 94, 0.06) !important;",
1443
1681
  "}",
1682
+ /* During any Composer drag, hide idle slot labels so they don't flash
1683
+ when the active drag-over class briefly changes */
1684
+ "body.amplifyup-composer-dragging .amplifyup-slot-placeholder {",
1685
+ " visibility: hidden !important;",
1686
+ " opacity: 0 !important;",
1687
+ "}",
1688
+ "body.amplifyup-composer-dragging [data-slot-id]::before,",
1689
+ "body.amplifyup-composer-dragging [data-amplifyup-slot]::before {",
1690
+ " content: none !important;",
1691
+ "}",
1444
1692
  "[data-slot-id].amplifyup-drag-over-slot, [data-amplifyup-slot].amplifyup-drag-over-slot {",
1445
1693
  " outline: 2px solid rgba(34, 197, 94, 1) !important;",
1446
1694
  " background: rgba(34, 197, 94, 0.18) !important;",
@@ -1456,7 +1704,7 @@ Available Console Commands:
1456
1704
  " color: rgb(22, 163, 74) !important;",
1457
1705
  " pointer-events: none !important;",
1458
1706
  " white-space: nowrap !important;",
1459
- " z-index: 1 !important;",
1707
+ " z-index: 2 !important;",
1460
1708
  "}",
1461
1709
  "body.amplifyup-drag-no-drop { cursor: no-drop !important; }",
1462
1710
  "body.amplifyup-drag-no-drop::before {",
@@ -1583,18 +1831,23 @@ Available Console Commands:
1583
1831
  sendSelectionMessage(element, hierarchy, isEmpty) {
1584
1832
  if (!this.isVisualEditorMode) return;
1585
1833
  const componentId = element.getAttribute("data-amplifyup-component") || element.getAttribute("data-component-id");
1586
- const slotName = element.getAttribute("data-amplifyup-slot") || element.getAttribute("data-slot-id");
1834
+ const slotName = componentId ? null : element.getAttribute("data-amplifyup-slot") || element.getAttribute("data-slot-id");
1587
1835
  const componentName = element.getAttribute("data-component-name");
1588
1836
  const hierarchyInfo = hierarchy.map((el, index) => {
1589
1837
  const elComponentId = el.getAttribute("data-amplifyup-component") || el.getAttribute("data-component-id");
1590
1838
  const elSlotName = el.getAttribute("data-amplifyup-slot") || el.getAttribute("data-slot-id");
1591
1839
  const elComponentName = el.getAttribute("data-component-name");
1840
+ const isSlot = !elComponentId && !!elSlotName;
1841
+ const isPageSlot = isSlot && el.getAttribute("data-slot-source") === "page";
1842
+ const nodeId = el.getAttribute("data-node-id") || (isSlot ? el.getAttribute("data-parent-node-id") : null);
1592
1843
  return {
1593
1844
  index,
1594
1845
  componentId: elComponentId,
1595
- componentName: elComponentName,
1596
- slotName: elSlotName,
1597
- isSlot: !!elSlotName
1846
+ componentName: isPageSlot ? "Page" : elComponentName,
1847
+ slotName: isSlot ? elSlotName : null,
1848
+ isSlot,
1849
+ isPageSlot,
1850
+ nodeId
1598
1851
  };
1599
1852
  });
1600
1853
  const rect = element.getBoundingClientRect ? element.getBoundingClientRect() : null;
@@ -1631,7 +1884,6 @@ Available Console Commands:
1631
1884
  return;
1632
1885
  }
1633
1886
  const doc = document;
1634
- const win = window;
1635
1887
  if (highlightComponents) {
1636
1888
  const componentElements = doc.querySelectorAll("[data-amplifyup-component], [data-component-id]");
1637
1889
  console.log("[AmplifyUp SDK] Found", componentElements.length, "components to highlight");
@@ -1692,52 +1944,8 @@ Available Console Commands:
1692
1944
  e.stopPropagation();
1693
1945
  this.sendSelectionMessage(htmlEl, hierarchy, isEmpty);
1694
1946
  };
1695
- const handleDrop = (e) => {
1696
- e.preventDefault();
1697
- e.stopPropagation();
1698
- htmlEl.classList.remove("amplifyup-drag-over-slot");
1699
- if (!win.parent || win.parent === win) return;
1700
- win.parent.postMessage({
1701
- type: "DROP_ON_SLOT",
1702
- slotName,
1703
- slotElement: { path: htmlEl.getAttribute("data-slot-path"), isEmpty }
1704
- }, "*");
1705
- try {
1706
- const data = JSON.parse(e.dataTransfer.getData("application/json"));
1707
- if (data.type === "component") {
1708
- win.parent.postMessage({
1709
- type: "COMPONENT_DROPPED",
1710
- componentId: data.componentId,
1711
- componentName: data.componentName,
1712
- slotName,
1713
- slotElement: { path: htmlEl.getAttribute("data-slot-path"), isEmpty }
1714
- }, "*");
1715
- }
1716
- } catch (_err) {
1717
- }
1718
- };
1719
- const handleDragOver = (e) => {
1720
- e.preventDefault();
1721
- e.stopPropagation();
1722
- e.dataTransfer.dropEffect = "copy";
1723
- htmlEl.classList.add("amplifyup-drag-over-slot");
1724
- };
1725
- const handleDragLeave = (e) => {
1726
- const related = e.relatedTarget;
1727
- if (!related || !htmlEl.contains(related)) {
1728
- htmlEl.classList.remove("amplifyup-drag-over-slot");
1729
- }
1730
- };
1731
1947
  htmlEl.addEventListener("click", handleClick);
1732
- htmlEl.addEventListener("dragover", handleDragOver);
1733
- htmlEl.addEventListener("dragleave", handleDragLeave);
1734
- htmlEl.addEventListener("drop", handleDrop);
1735
- htmlEl._amplifyupSlotHandlers = {
1736
- handleClick,
1737
- handleDragOver,
1738
- handleDragLeave,
1739
- handleDrop
1740
- };
1948
+ htmlEl._amplifyupSlotHandlers = { handleClick };
1741
1949
  });
1742
1950
  }
1743
1951
  }
@@ -2067,6 +2275,8 @@ function AmplifyRenderer({
2067
2275
  "data-slot-id": slot.slotId,
2068
2276
  "data-amplifyup-slot": slot.slotId,
2069
2277
  "data-zone-id": slot.zoneId || void 0,
2278
+ "data-parent-node-id": node.id,
2279
+ "data-parent-component-id": node.componentId,
2070
2280
  children: childrenToRender.map((child) => renderNode(child))
2071
2281
  },
2072
2282
  slot.slotId
@@ -2082,17 +2292,25 @@ function AmplifyRenderer({
2082
2292
  hasSlots: !!slotsToPass,
2083
2293
  slotKeys: slotsToPass ? Object.keys(slotsToPass) : []
2084
2294
  });
2085
- return renderComponent(
2086
- node.componentId,
2087
- node.props || {},
2088
- slotsToPass
2089
- );
2295
+ return /* @__PURE__ */ jsx("div", { "data-node-id": node.id, "data-amplifyup-node": "", children: renderComponent(node.componentId, node.props || {}, slotsToPass, {
2296
+ layoutNodeId: node.id
2297
+ }) });
2090
2298
  };
2091
- const layoutTree = pageConfig.layoutTree;
2092
- if (!layoutTree || layoutTree.length === 0) {
2299
+ const rawTree = pageConfig.layoutTree;
2300
+ const layoutTree = Array.isArray(rawTree) ? rawTree : rawTree && typeof rawTree === "object" && rawTree.componentId ? [rawTree] : [];
2301
+ if (layoutTree.length === 0) {
2093
2302
  return /* @__PURE__ */ jsx("main", { children: emptyComponent || /* @__PURE__ */ jsx("div", { className: "container mx-auto px-4 py-16", children: /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "No content configured for this page." }) }) });
2094
2303
  }
2095
- return /* @__PURE__ */ jsx("main", { children: layoutTree.map((node) => /* @__PURE__ */ jsx("div", { children: renderNode(node) }, node.id)) });
2304
+ return /* @__PURE__ */ jsx("main", { children: isComposerPreview() ? /* @__PURE__ */ jsx(
2305
+ "div",
2306
+ {
2307
+ "data-slot-id": "main",
2308
+ "data-amplifyup-slot": "main",
2309
+ "data-slot-source": "page",
2310
+ "data-slot-empty": layoutTree.length === 0 ? "true" : void 0,
2311
+ children: layoutTree.map((node) => /* @__PURE__ */ jsx("div", { children: renderNode(node) }, node.id))
2312
+ }
2313
+ ) : layoutTree.map((node) => /* @__PURE__ */ jsx("div", { children: renderNode(node) }, node.id)) });
2096
2314
  }
2097
2315
 
2098
2316
  export { AmplifyRenderer };