@amplifyup/sdk 0.1.12 → 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.
package/dist/react.mjs CHANGED
@@ -350,6 +350,15 @@ var AmplifyUpSDK = class {
350
350
  this.messageListener = null;
351
351
  this.mutationObserver = null;
352
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;
353
362
  this.isVisualEditorMode = false;
354
363
  this.eventSelectionMode = false;
355
364
  this.eventSelectionClickHandler = null;
@@ -880,6 +889,12 @@ Available Console Commands:
880
889
  }
881
890
  throw new Error(`Failed to fetch page: ${response.statusText}`);
882
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
+ }
883
898
  const data = await response.json();
884
899
  const pageConfig = data.page;
885
900
  if (pageConfig?.eventTracking) {
@@ -1164,6 +1179,13 @@ Available Console Commands:
1164
1179
  }
1165
1180
  return;
1166
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
+ }
1167
1189
  if (event.data?.type === "COMPOSER_DRAG_AT_POINT") {
1168
1190
  const { x, y } = event.data;
1169
1191
  if (typeof x === "number" && typeof y === "number") {
@@ -1179,36 +1201,72 @@ Available Console Commands:
1179
1201
  return;
1180
1202
  }
1181
1203
  if (event.data?.type === "COMPOSER_DRAG_END") {
1204
+ this.composerOverlayDragActive = false;
1182
1205
  this.clearComposerDragHighlight();
1183
1206
  return;
1184
1207
  }
1185
1208
  if (event.data?.type === "GET_ELEMENT_POSITION") {
1186
- const { componentId, slotName } = event.data;
1187
- const selector = slotName ? `[data-amplifyup-slot="${slotName}"], [data-slot-id="${slotName}"]` : `[data-amplifyup-component="${componentId}"], [data-component-id="${componentId}"]`;
1188
- console.log("[AmplifyUp SDK] Finding element position:", { selector, componentId, slotName });
1189
- 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
+ });
1190
1243
  if (element) {
1191
1244
  const rect = element.getBoundingClientRect();
1192
1245
  const position = {
1193
1246
  x: rect.left + rect.width / 2,
1194
- // Center of element
1195
1247
  y: rect.top - 50,
1196
- // Position above element
1197
1248
  width: rect.width,
1198
1249
  height: rect.height
1199
1250
  };
1200
- 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
+ };
1201
1257
  if (window.parent && window.parent !== window) {
1202
1258
  window.parent.postMessage({
1203
1259
  type: "ELEMENT_POSITION",
1204
- componentId,
1205
- slotName,
1206
- position
1260
+ componentId: componentId || null,
1261
+ slotName: slotName || null,
1262
+ nodeId: nodeId || null,
1263
+ isPageSlot: !!isPageSlot,
1264
+ position,
1265
+ bounds
1207
1266
  }, "*");
1208
- console.log("[AmplifyUp SDK] Sent ELEMENT_POSITION message");
1209
1267
  }
1210
1268
  } else {
1211
- console.warn("[AmplifyUp SDK] Element not found for selector:", selector);
1269
+ console.warn("[AmplifyUp SDK] Element not found for position request");
1212
1270
  }
1213
1271
  return;
1214
1272
  }
@@ -1323,37 +1381,148 @@ Available Console Commands:
1323
1381
  el.classList.remove("amplifyup-drag-over-slot");
1324
1382
  });
1325
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
+ }
1326
1396
  }
1327
1397
  /**
1328
- * Hit-test a slot at iframe-local coordinates (Composer overlay drag path).
1329
- * Required for cross-origin drags: the browser blocks native drop inside the iframe.
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.
1330
1400
  */
1331
- handleComposerDragAtPoint(x, y) {
1332
- if (typeof document === "undefined") return;
1401
+ resolveSlotAtPoint(x, y) {
1402
+ if (typeof document === "undefined") return null;
1333
1403
  const slotSelector = "[data-slot-id], [data-amplifyup-slot]";
1334
- this.clearComposerDragHighlight();
1335
- const el = document.elementFromPoint(x, y)?.closest?.(slotSelector);
1336
- if (el) {
1337
- el.classList.add("amplifyup-drag-over-slot");
1338
- } else {
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")) {
1339
1489
  document.body.classList.add("amplifyup-drag-no-drop");
1340
1490
  }
1341
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
+ }
1342
1520
  handleComposerDropAtPoint(x, y) {
1343
1521
  if (typeof document === "undefined") return;
1344
- const win = window;
1345
- const slotSelector = "[data-slot-id], [data-amplifyup-slot]";
1522
+ const htmlEl = this.resolveSlotAtPoint(x, y);
1346
1523
  this.clearComposerDragHighlight();
1347
- const htmlEl = document.elementFromPoint(x, y)?.closest?.(slotSelector);
1348
- if (!htmlEl || !win.parent || win.parent === win) return;
1349
- const slotName = htmlEl.getAttribute("data-amplifyup-slot") || htmlEl.getAttribute("data-slot-id");
1350
- if (!slotName) return;
1351
- const isEmpty = htmlEl.getAttribute("data-slot-empty") === "true";
1352
- win.parent.postMessage({
1353
- type: "DROP_ON_SLOT",
1354
- slotName,
1355
- slotElement: { path: htmlEl.getAttribute("data-slot-path"), isEmpty }
1356
- }, "*");
1524
+ if (!htmlEl) return;
1525
+ this.postDropOnSlot(htmlEl);
1357
1526
  }
1358
1527
  /**
1359
1528
  * Enable component highlighting
@@ -1381,35 +1550,25 @@ Available Console Commands:
1381
1550
  this.teardownComposerDragDrop();
1382
1551
  const slotSelector = "[data-slot-id], [data-amplifyup-slot]";
1383
1552
  const clearDragOverState = () => {
1384
- document.querySelectorAll(`${slotSelector}.amplifyup-drag-over-slot`).forEach((el) => {
1385
- el.classList.remove("amplifyup-drag-over-slot");
1386
- });
1387
- document.body.classList.remove("amplifyup-drag-no-drop");
1553
+ this.clearComposerDragHighlight();
1388
1554
  };
1389
1555
  const dragenter = (e) => {
1390
1556
  e.preventDefault();
1391
- if (e.dataTransfer?.types?.length) {
1392
- document.body.classList.add("amplifyup-drag-no-drop");
1393
- }
1394
1557
  };
1395
1558
  const dragover = (e) => {
1396
1559
  e.preventDefault();
1397
- const target = e.target;
1398
- 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);
1399
1565
  if (e.dataTransfer) {
1400
1566
  e.dataTransfer.dropEffect = slot ? "copy" : "none";
1401
1567
  }
1402
- document.querySelectorAll(`${slotSelector}.amplifyup-drag-over-slot`).forEach((el) => {
1403
- el.classList.remove("amplifyup-drag-over-slot");
1404
- });
1405
- if (slot) {
1406
- slot.classList.add("amplifyup-drag-over-slot");
1407
- document.body.classList.remove("amplifyup-drag-no-drop");
1408
- } else {
1409
- document.body.classList.add("amplifyup-drag-no-drop");
1410
- }
1568
+ this.setComposerDragHighlight(slot, e.clientX, e.clientY);
1411
1569
  };
1412
1570
  const dragleave = (e) => {
1571
+ if (this.composerOverlayDragActive) return;
1413
1572
  const related = e.relatedTarget;
1414
1573
  if (!related || !document.body.contains(related)) {
1415
1574
  clearDragOverState();
@@ -1417,20 +1576,10 @@ Available Console Commands:
1417
1576
  };
1418
1577
  const drop = (e) => {
1419
1578
  e.preventDefault();
1420
- const target = e.target;
1421
- const slot = target?.closest?.(slotSelector);
1579
+ const slot = this.resolveSlotAtPoint(e.clientX, e.clientY);
1422
1580
  clearDragOverState();
1423
1581
  if (!slot || !this.isVisualEditorMode) return;
1424
- const slotName = slot.getAttribute("data-amplifyup-slot") || slot.getAttribute("data-slot-id");
1425
- const isEmpty = slot.getAttribute("data-slot-empty") === "true";
1426
- const win = window;
1427
- if (slotName && win.parent && win.parent !== win) {
1428
- win.parent.postMessage({
1429
- type: "DROP_ON_SLOT",
1430
- slotName,
1431
- slotElement: { path: slot.getAttribute("data-slot-path"), isEmpty }
1432
- }, "*");
1433
- }
1582
+ this.postDropOnSlot(slot);
1434
1583
  };
1435
1584
  const mouseover = (e) => {
1436
1585
  if (!this.showZonesEnabled) return;
@@ -1469,7 +1618,11 @@ Available Console Commands:
1469
1618
  document.removeEventListener("mouseover", h.mouseover, true);
1470
1619
  document.removeEventListener("mouseout", h.mouseout, true);
1471
1620
  this.composerDragHandlers = null;
1621
+ this.composerOverlayDragActive = false;
1622
+ this.lastComposerDragSlot = null;
1623
+ this.composerDragMissFrames = 0;
1472
1624
  document.body.classList.remove("amplifyup-drag-no-drop");
1625
+ document.body.classList.remove("amplifyup-composer-dragging");
1473
1626
  document.querySelectorAll("[data-slot-id].amplifyup-drag-over-slot, [data-amplifyup-slot].amplifyup-drag-over-slot").forEach((el) => {
1474
1627
  el.classList.remove("amplifyup-drag-over-slot");
1475
1628
  });
@@ -1510,21 +1663,32 @@ Available Console Commands:
1510
1663
  '[data-slot-id="main"], [data-amplifyup-slot="main"] {',
1511
1664
  " min-height: 50vh !important;",
1512
1665
  "}",
1513
- '[data-slot-id="main"][data-slot-empty="true"]::before,',
1514
- '[data-amplifyup-slot="main"][data-slot-empty="true"]::before {',
1515
- ' content: "Drop components here" !important;',
1516
- " position: absolute !important;",
1517
- " top: 50% !important; left: 50% !important;",
1518
- " transform: translate(-50%, -50%) !important;",
1519
- " font-size: 14px !important; font-weight: 500 !important;",
1520
- " 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;",
1521
1675
  " pointer-events: none !important;",
1522
- " white-space: nowrap !important;",
1676
+ " text-align: center !important;",
1523
1677
  "}",
1524
1678
  "[data-slot-id].amplifyup-slot-hover, [data-amplifyup-slot].amplifyup-slot-hover {",
1525
1679
  " outline-color: rgba(34, 197, 94, 1) !important;",
1526
1680
  " background: rgba(34, 197, 94, 0.06) !important;",
1527
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
+ "}",
1528
1692
  "[data-slot-id].amplifyup-drag-over-slot, [data-amplifyup-slot].amplifyup-drag-over-slot {",
1529
1693
  " outline: 2px solid rgba(34, 197, 94, 1) !important;",
1530
1694
  " background: rgba(34, 197, 94, 0.18) !important;",
@@ -1540,7 +1704,7 @@ Available Console Commands:
1540
1704
  " color: rgb(22, 163, 74) !important;",
1541
1705
  " pointer-events: none !important;",
1542
1706
  " white-space: nowrap !important;",
1543
- " z-index: 1 !important;",
1707
+ " z-index: 2 !important;",
1544
1708
  "}",
1545
1709
  "body.amplifyup-drag-no-drop { cursor: no-drop !important; }",
1546
1710
  "body.amplifyup-drag-no-drop::before {",
@@ -1667,18 +1831,23 @@ Available Console Commands:
1667
1831
  sendSelectionMessage(element, hierarchy, isEmpty) {
1668
1832
  if (!this.isVisualEditorMode) return;
1669
1833
  const componentId = element.getAttribute("data-amplifyup-component") || element.getAttribute("data-component-id");
1670
- 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");
1671
1835
  const componentName = element.getAttribute("data-component-name");
1672
1836
  const hierarchyInfo = hierarchy.map((el, index) => {
1673
1837
  const elComponentId = el.getAttribute("data-amplifyup-component") || el.getAttribute("data-component-id");
1674
1838
  const elSlotName = el.getAttribute("data-amplifyup-slot") || el.getAttribute("data-slot-id");
1675
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);
1676
1843
  return {
1677
1844
  index,
1678
1845
  componentId: elComponentId,
1679
- componentName: elComponentName,
1680
- slotName: elSlotName,
1681
- isSlot: !!elSlotName
1846
+ componentName: isPageSlot ? "Page" : elComponentName,
1847
+ slotName: isSlot ? elSlotName : null,
1848
+ isSlot,
1849
+ isPageSlot,
1850
+ nodeId
1682
1851
  };
1683
1852
  });
1684
1853
  const rect = element.getBoundingClientRect ? element.getBoundingClientRect() : null;
@@ -1715,7 +1884,6 @@ Available Console Commands:
1715
1884
  return;
1716
1885
  }
1717
1886
  const doc = document;
1718
- const win = window;
1719
1887
  if (highlightComponents) {
1720
1888
  const componentElements = doc.querySelectorAll("[data-amplifyup-component], [data-component-id]");
1721
1889
  console.log("[AmplifyUp SDK] Found", componentElements.length, "components to highlight");
@@ -1776,52 +1944,8 @@ Available Console Commands:
1776
1944
  e.stopPropagation();
1777
1945
  this.sendSelectionMessage(htmlEl, hierarchy, isEmpty);
1778
1946
  };
1779
- const handleDrop = (e) => {
1780
- e.preventDefault();
1781
- e.stopPropagation();
1782
- htmlEl.classList.remove("amplifyup-drag-over-slot");
1783
- if (!win.parent || win.parent === win) return;
1784
- win.parent.postMessage({
1785
- type: "DROP_ON_SLOT",
1786
- slotName,
1787
- slotElement: { path: htmlEl.getAttribute("data-slot-path"), isEmpty }
1788
- }, "*");
1789
- try {
1790
- const data = JSON.parse(e.dataTransfer.getData("application/json"));
1791
- if (data.type === "component") {
1792
- win.parent.postMessage({
1793
- type: "COMPONENT_DROPPED",
1794
- componentId: data.componentId,
1795
- componentName: data.componentName,
1796
- slotName,
1797
- slotElement: { path: htmlEl.getAttribute("data-slot-path"), isEmpty }
1798
- }, "*");
1799
- }
1800
- } catch (_err) {
1801
- }
1802
- };
1803
- const handleDragOver = (e) => {
1804
- e.preventDefault();
1805
- e.stopPropagation();
1806
- e.dataTransfer.dropEffect = "copy";
1807
- htmlEl.classList.add("amplifyup-drag-over-slot");
1808
- };
1809
- const handleDragLeave = (e) => {
1810
- const related = e.relatedTarget;
1811
- if (!related || !htmlEl.contains(related)) {
1812
- htmlEl.classList.remove("amplifyup-drag-over-slot");
1813
- }
1814
- };
1815
1947
  htmlEl.addEventListener("click", handleClick);
1816
- htmlEl.addEventListener("dragover", handleDragOver);
1817
- htmlEl.addEventListener("dragleave", handleDragLeave);
1818
- htmlEl.addEventListener("drop", handleDrop);
1819
- htmlEl._amplifyupSlotHandlers = {
1820
- handleClick,
1821
- handleDragOver,
1822
- handleDragLeave,
1823
- handleDrop
1824
- };
1948
+ htmlEl._amplifyupSlotHandlers = { handleClick };
1825
1949
  });
1826
1950
  }
1827
1951
  }
@@ -2132,6 +2256,8 @@ function AmplifyRenderer({
2132
2256
  "data-slot-id": slot.slotId,
2133
2257
  "data-amplifyup-slot": slot.slotId,
2134
2258
  "data-zone-id": slot.zoneId || void 0,
2259
+ "data-parent-node-id": node.id,
2260
+ "data-parent-component-id": node.componentId,
2135
2261
  children: childrenToRender.map((child) => renderNode(child))
2136
2262
  },
2137
2263
  slot.slotId
@@ -2147,17 +2273,25 @@ function AmplifyRenderer({
2147
2273
  hasSlots: !!slotsToPass,
2148
2274
  slotKeys: slotsToPass ? Object.keys(slotsToPass) : []
2149
2275
  });
2150
- return renderComponent(
2151
- node.componentId,
2152
- node.props || {},
2153
- slotsToPass
2154
- );
2276
+ return /* @__PURE__ */ jsx("div", { "data-node-id": node.id, "data-amplifyup-node": "", children: renderComponent(node.componentId, node.props || {}, slotsToPass, {
2277
+ layoutNodeId: node.id
2278
+ }) });
2155
2279
  };
2156
- const layoutTree = pageConfig.layoutTree;
2157
- if (!layoutTree || layoutTree.length === 0) {
2280
+ const rawTree = pageConfig.layoutTree;
2281
+ const layoutTree = Array.isArray(rawTree) ? rawTree : rawTree && typeof rawTree === "object" && rawTree.componentId ? [rawTree] : [];
2282
+ if (layoutTree.length === 0) {
2158
2283
  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." }) }) });
2159
2284
  }
2160
- return /* @__PURE__ */ jsx("main", { children: layoutTree.map((node) => /* @__PURE__ */ jsx("div", { children: renderNode(node) }, node.id)) });
2285
+ return /* @__PURE__ */ jsx("main", { children: isComposerPreview() ? /* @__PURE__ */ jsx(
2286
+ "div",
2287
+ {
2288
+ "data-slot-id": "main",
2289
+ "data-amplifyup-slot": "main",
2290
+ "data-slot-source": "page",
2291
+ "data-slot-empty": layoutTree.length === 0 ? "true" : void 0,
2292
+ children: layoutTree.map((node) => /* @__PURE__ */ jsx("div", { children: renderNode(node) }, node.id))
2293
+ }
2294
+ ) : layoutTree.map((node) => /* @__PURE__ */ jsx("div", { children: renderNode(node) }, node.id)) });
2161
2295
  }
2162
2296
  function defaultPreviewCanvas() {
2163
2297
  return /* @__PURE__ */ jsx(
@@ -2165,8 +2299,10 @@ function defaultPreviewCanvas() {
2165
2299
  {
2166
2300
  "data-slot-id": "main",
2167
2301
  "data-amplifyup-slot": "main",
2302
+ "data-slot-source": "page",
2168
2303
  "data-slot-empty": "true",
2169
- style: { minHeight: "50vh", width: "100%", display: "block" }
2304
+ style: { minHeight: "50vh", width: "100%", display: "block", position: "relative" },
2305
+ children: /* @__PURE__ */ jsx("div", { className: "amplifyup-slot-placeholder", children: "Drop components here" })
2170
2306
  }
2171
2307
  );
2172
2308
  }
@@ -2256,7 +2392,9 @@ var ComponentContext = createContext(null);
2256
2392
  function ComponentContextProvider({
2257
2393
  children,
2258
2394
  slots,
2259
- props
2395
+ props,
2396
+ layoutNodeId,
2397
+ componentId
2260
2398
  }) {
2261
2399
  console.log("[ComponentContextProvider] Providing context", {
2262
2400
  hasSlots: !!slots,
@@ -2267,9 +2405,11 @@ function ComponentContextProvider({
2267
2405
  contentType: slots[key] ? typeof slots[key] : "null"
2268
2406
  })) : [],
2269
2407
  hasProps: !!props,
2270
- propKeys: props ? Object.keys(props) : []
2408
+ propKeys: props ? Object.keys(props) : [],
2409
+ layoutNodeId,
2410
+ componentId
2271
2411
  });
2272
- return /* @__PURE__ */ jsx(ComponentContext.Provider, { value: { slots, props }, children });
2412
+ return /* @__PURE__ */ jsx(ComponentContext.Provider, { value: { slots, props, layoutNodeId, componentId }, children });
2273
2413
  }
2274
2414
  function Slot({
2275
2415
  name,
@@ -2320,33 +2460,50 @@ function Slot({
2320
2460
  {
2321
2461
  className,
2322
2462
  "data-slot-name": name,
2463
+ "data-slot-id": name,
2323
2464
  "data-amplifyup-slot": name,
2324
2465
  "data-slot-empty": isEmpty ? "true" : void 0,
2466
+ "data-parent-node-id": context.layoutNodeId || void 0,
2467
+ "data-parent-component-id": context.componentId || void 0,
2325
2468
  style: {
2326
2469
  // Only add minimum height when empty (for drop target visibility)
2327
2470
  minHeight: isEmpty ? "60px" : void 0,
2328
2471
  // Only add position relative for overlay positioning in editor mode
2329
2472
  position: isEditorMode ? "relative" : void 0
2330
2473
  },
2331
- children: isEmpty ? /* @__PURE__ */ jsx("div", { style: {
2332
- // Only style the empty state indicator, not the container
2333
- minHeight: "60px",
2334
- color: "#9ca3af",
2335
- fontSize: "14px",
2336
- pointerEvents: "none"
2337
- }, children: isEditorMode ? `[Slot: ${name}]` : `Empty slot: ${name}` }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2338
- isEditorMode && /* @__PURE__ */ jsxs("div", { style: {
2339
- position: "absolute",
2340
- top: "4px",
2341
- left: "4px",
2342
- fontSize: "10px",
2343
- color: "#9ca3af",
2344
- pointerEvents: "none",
2345
- zIndex: 1
2346
- }, children: [
2347
- "Slot: ",
2348
- name
2349
- ] }),
2474
+ children: isEmpty ? /* @__PURE__ */ jsx(
2475
+ "div",
2476
+ {
2477
+ className: "amplifyup-slot-placeholder",
2478
+ style: {
2479
+ minHeight: "60px",
2480
+ color: "#9ca3af",
2481
+ fontSize: "14px",
2482
+ pointerEvents: "none"
2483
+ },
2484
+ children: isEditorMode ? `Drop components here` : `Empty slot: ${name}`
2485
+ }
2486
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
2487
+ isEditorMode && /* @__PURE__ */ jsxs(
2488
+ "div",
2489
+ {
2490
+ className: "amplifyup-slot-placeholder",
2491
+ style: {
2492
+ position: "absolute",
2493
+ top: "4px",
2494
+ left: "4px",
2495
+ fontSize: "10px",
2496
+ color: "#9ca3af",
2497
+ pointerEvents: "none",
2498
+ zIndex: 1,
2499
+ minHeight: "auto"
2500
+ },
2501
+ children: [
2502
+ "Slot: ",
2503
+ name
2504
+ ]
2505
+ }
2506
+ ),
2350
2507
  slotContent
2351
2508
  ] })
2352
2509
  }
@@ -2398,7 +2555,8 @@ function AmplifyUpProvider({ children, config }) {
2398
2555
  return routeFromQuery;
2399
2556
  }
2400
2557
  const actualRoute = window.__AMPLIFYUP_ACTUAL_ROUTE__;
2401
- if (actualRoute && typeof actualRoute === "string" && (currentPath === "/api/pages/proxy" || currentPath.startsWith("/api/pages/proxy"))) {
2558
+ const inComposerShell = currentPath === "/api/pages/proxy" || currentPath.startsWith("/api/pages/proxy") || currentPath.includes("/preview-frame");
2559
+ if (actualRoute && typeof actualRoute === "string" && inComposerShell) {
2402
2560
  return actualRoute;
2403
2561
  }
2404
2562
  return currentPath;