@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.js CHANGED
@@ -352,6 +352,15 @@ var AmplifyUpSDK = class {
352
352
  this.messageListener = null;
353
353
  this.mutationObserver = null;
354
354
  this.composerDragHandlers = null;
355
+ /** Last slot highlighted during Composer drag — avoid clear/re-add flicker. */
356
+ this.lastComposerDragSlot = null;
357
+ /** Consecutive miss frames before clearing highlight (anti-jitter). */
358
+ this.composerDragMissFrames = 0;
359
+ /**
360
+ * Parent overlay is driving drag via postMessage. Native iframe dragleave must
361
+ * not clear highlight — overlay takeover fires a spurious document dragleave.
362
+ */
363
+ this.composerOverlayDragActive = false;
355
364
  this.isVisualEditorMode = false;
356
365
  this.eventSelectionMode = false;
357
366
  this.eventSelectionClickHandler = null;
@@ -882,6 +891,12 @@ Available Console Commands:
882
891
  }
883
892
  throw new Error(`Failed to fetch page: ${response.statusText}`);
884
893
  }
894
+ const contentType = response.headers.get("content-type") || "";
895
+ if (!contentType.includes("application/json")) {
896
+ throw new Error(
897
+ `Layout provider returned non-JSON (${contentType || "unknown"}). Check Composer preview routing.`
898
+ );
899
+ }
885
900
  const data = await response.json();
886
901
  const pageConfig = data.page;
887
902
  if (pageConfig?.eventTracking) {
@@ -1166,6 +1181,13 @@ Available Console Commands:
1166
1181
  }
1167
1182
  return;
1168
1183
  }
1184
+ if (event.data?.type === "COMPOSER_DRAG_START") {
1185
+ this.composerOverlayDragActive = true;
1186
+ if (typeof document !== "undefined") {
1187
+ document.body.classList.add("amplifyup-composer-dragging");
1188
+ }
1189
+ return;
1190
+ }
1169
1191
  if (event.data?.type === "COMPOSER_DRAG_AT_POINT") {
1170
1192
  const { x, y } = event.data;
1171
1193
  if (typeof x === "number" && typeof y === "number") {
@@ -1181,36 +1203,72 @@ Available Console Commands:
1181
1203
  return;
1182
1204
  }
1183
1205
  if (event.data?.type === "COMPOSER_DRAG_END") {
1206
+ this.composerOverlayDragActive = false;
1184
1207
  this.clearComposerDragHighlight();
1185
1208
  return;
1186
1209
  }
1187
1210
  if (event.data?.type === "GET_ELEMENT_POSITION") {
1188
- const { componentId, slotName } = event.data;
1189
- const selector = slotName ? `[data-amplifyup-slot="${slotName}"], [data-slot-id="${slotName}"]` : `[data-amplifyup-component="${componentId}"], [data-component-id="${componentId}"]`;
1190
- console.log("[AmplifyUp SDK] Finding element position:", { selector, componentId, slotName });
1191
- const element = document.querySelector(selector);
1211
+ const { componentId, slotName, nodeId, isPageSlot } = event.data;
1212
+ let element = null;
1213
+ if (isPageSlot || slotName === "main" && !nodeId && !componentId) {
1214
+ element = document.querySelector(
1215
+ '[data-slot-source="page"]'
1216
+ );
1217
+ }
1218
+ if (!element && nodeId && slotName) {
1219
+ element = document.querySelector(
1220
+ `[data-parent-node-id="${nodeId}"][data-slot-id="${slotName}"], [data-parent-node-id="${nodeId}"][data-amplifyup-slot="${slotName}"]`
1221
+ );
1222
+ }
1223
+ if (!element && nodeId && !slotName) {
1224
+ element = document.querySelector(
1225
+ `[data-node-id="${nodeId}"]`
1226
+ );
1227
+ }
1228
+ if (!element && slotName) {
1229
+ element = document.querySelector(
1230
+ `[data-amplifyup-slot="${slotName}"], [data-slot-id="${slotName}"]`
1231
+ );
1232
+ }
1233
+ if (!element && componentId) {
1234
+ element = document.querySelector(
1235
+ `[data-amplifyup-component="${componentId}"], [data-component-id="${componentId}"]`
1236
+ );
1237
+ }
1238
+ console.log("[AmplifyUp SDK] Finding element position:", {
1239
+ componentId,
1240
+ slotName,
1241
+ nodeId,
1242
+ isPageSlot,
1243
+ found: !!element
1244
+ });
1192
1245
  if (element) {
1193
1246
  const rect = element.getBoundingClientRect();
1194
1247
  const position = {
1195
1248
  x: rect.left + rect.width / 2,
1196
- // Center of element
1197
1249
  y: rect.top - 50,
1198
- // Position above element
1199
1250
  width: rect.width,
1200
1251
  height: rect.height
1201
1252
  };
1202
- console.log("[AmplifyUp SDK] Element position calculated:", { rect, position });
1253
+ const bounds = {
1254
+ top: rect.top,
1255
+ left: rect.left,
1256
+ width: rect.width,
1257
+ height: rect.height
1258
+ };
1203
1259
  if (window.parent && window.parent !== window) {
1204
1260
  window.parent.postMessage({
1205
1261
  type: "ELEMENT_POSITION",
1206
- componentId,
1207
- slotName,
1208
- position
1262
+ componentId: componentId || null,
1263
+ slotName: slotName || null,
1264
+ nodeId: nodeId || null,
1265
+ isPageSlot: !!isPageSlot,
1266
+ position,
1267
+ bounds
1209
1268
  }, "*");
1210
- console.log("[AmplifyUp SDK] Sent ELEMENT_POSITION message");
1211
1269
  }
1212
1270
  } else {
1213
- console.warn("[AmplifyUp SDK] Element not found for selector:", selector);
1271
+ console.warn("[AmplifyUp SDK] Element not found for position request");
1214
1272
  }
1215
1273
  return;
1216
1274
  }
@@ -1325,37 +1383,148 @@ Available Console Commands:
1325
1383
  el.classList.remove("amplifyup-drag-over-slot");
1326
1384
  });
1327
1385
  document.body.classList.remove("amplifyup-drag-no-drop");
1386
+ document.body.classList.remove("amplifyup-composer-dragging");
1387
+ this.lastComposerDragSlot = null;
1388
+ this.composerDragMissFrames = 0;
1389
+ }
1390
+ /** Re-apply drag-over class only if missing (avoids classList churn / flicker). */
1391
+ ensureDragOverClass(slot) {
1392
+ if (!slot.classList.contains("amplifyup-drag-over-slot")) {
1393
+ slot.classList.add("amplifyup-drag-over-slot");
1394
+ }
1395
+ if (document.body.classList.contains("amplifyup-drag-no-drop")) {
1396
+ document.body.classList.remove("amplifyup-drag-no-drop");
1397
+ }
1328
1398
  }
1329
1399
  /**
1330
- * Hit-test a slot at iframe-local coordinates (Composer overlay drag path).
1331
- * Required for cross-origin drags: the browser blocks native drop inside the iframe.
1400
+ * Composer drag targets the innermost (most specific) slot under the cursor.
1401
+ * e.g. FullWidthGrid's main wins over a page-level main that wraps it.
1332
1402
  */
1333
- handleComposerDragAtPoint(x, y) {
1334
- if (typeof document === "undefined") return;
1403
+ resolveSlotAtPoint(x, y) {
1404
+ if (typeof document === "undefined") return null;
1335
1405
  const slotSelector = "[data-slot-id], [data-amplifyup-slot]";
1336
- this.clearComposerDragHighlight();
1337
- const el = document.elementFromPoint(x, y)?.closest?.(slotSelector);
1338
- if (el) {
1339
- el.classList.add("amplifyup-drag-over-slot");
1340
- } else {
1406
+ const containing = [];
1407
+ document.querySelectorAll(slotSelector).forEach((node) => {
1408
+ const el = node;
1409
+ const r = el.getBoundingClientRect();
1410
+ if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) {
1411
+ containing.push(el);
1412
+ }
1413
+ });
1414
+ if (containing.length === 0) return null;
1415
+ const innermost = containing.filter(
1416
+ (el) => !containing.some((other) => other !== el && el.contains(other))
1417
+ );
1418
+ if (innermost.length === 1) return innermost[0];
1419
+ let best = innermost[0];
1420
+ let bestArea = Infinity;
1421
+ for (const el of innermost) {
1422
+ const r = el.getBoundingClientRect();
1423
+ const area = Math.max(1, r.width) * Math.max(1, r.height);
1424
+ if (area < bestArea) {
1425
+ bestArea = area;
1426
+ best = el;
1427
+ }
1428
+ }
1429
+ return best;
1430
+ }
1431
+ /** Parent layout node that owns this slot (null for page-level code main). */
1432
+ parentComponentForSlot(slotEl) {
1433
+ let componentId = slotEl.getAttribute("data-parent-component-id");
1434
+ let nodeId = slotEl.getAttribute("data-parent-node-id");
1435
+ let el = slotEl.parentElement;
1436
+ while (el && (!nodeId || !componentId)) {
1437
+ if (!nodeId && el.hasAttribute("data-node-id")) {
1438
+ nodeId = el.getAttribute("data-node-id");
1439
+ }
1440
+ if (!componentId) {
1441
+ componentId = el.getAttribute("data-amplifyup-component") || el.getAttribute("data-component-id");
1442
+ }
1443
+ if (nodeId) break;
1444
+ el = el.parentElement;
1445
+ }
1446
+ return { componentId, nodeId };
1447
+ }
1448
+ pointInRect(x, y, el, pad = 8) {
1449
+ const r = el.getBoundingClientRect();
1450
+ return x >= r.left - pad && x <= r.right + pad && y >= r.top - pad && y <= r.bottom + pad;
1451
+ }
1452
+ setComposerDragHighlight(slot, x, y) {
1453
+ if (slot && slot === this.lastComposerDragSlot) {
1454
+ this.composerDragMissFrames = 0;
1455
+ this.ensureDragOverClass(slot);
1456
+ return;
1457
+ }
1458
+ if (slot && this.lastComposerDragSlot && this.lastComposerDragSlot.contains(slot) && slot !== this.lastComposerDragSlot) {
1459
+ this.composerDragMissFrames = 0;
1460
+ this.lastComposerDragSlot.classList.remove("amplifyup-drag-over-slot");
1461
+ this.lastComposerDragSlot = slot;
1462
+ this.ensureDragOverClass(slot);
1463
+ return;
1464
+ }
1465
+ if (this.lastComposerDragSlot && typeof x === "number" && typeof y === "number" && this.pointInRect(x, y, this.lastComposerDragSlot)) {
1466
+ if (!slot || slot.contains(this.lastComposerDragSlot) || slot === this.lastComposerDragSlot) {
1467
+ this.composerDragMissFrames = 0;
1468
+ this.ensureDragOverClass(this.lastComposerDragSlot);
1469
+ return;
1470
+ }
1471
+ }
1472
+ if (slot) {
1473
+ this.composerDragMissFrames = 0;
1474
+ if (this.lastComposerDragSlot && this.lastComposerDragSlot !== slot) {
1475
+ this.lastComposerDragSlot.classList.remove("amplifyup-drag-over-slot");
1476
+ }
1477
+ this.lastComposerDragSlot = slot;
1478
+ this.ensureDragOverClass(slot);
1479
+ return;
1480
+ }
1481
+ this.composerDragMissFrames += 1;
1482
+ if (this.lastComposerDragSlot && this.composerDragMissFrames < 8) {
1483
+ this.ensureDragOverClass(this.lastComposerDragSlot);
1484
+ return;
1485
+ }
1486
+ if (this.lastComposerDragSlot) {
1487
+ this.lastComposerDragSlot.classList.remove("amplifyup-drag-over-slot");
1488
+ this.lastComposerDragSlot = null;
1489
+ }
1490
+ if (!document.body.classList.contains("amplifyup-drag-no-drop")) {
1341
1491
  document.body.classList.add("amplifyup-drag-no-drop");
1342
1492
  }
1343
1493
  }
1494
+ handleComposerDragAtPoint(x, y) {
1495
+ this.composerOverlayDragActive = true;
1496
+ if (!document.body.classList.contains("amplifyup-composer-dragging")) {
1497
+ document.body.classList.add("amplifyup-composer-dragging");
1498
+ }
1499
+ this.setComposerDragHighlight(this.resolveSlotAtPoint(x, y), x, y);
1500
+ }
1501
+ postDropOnSlot(slotEl) {
1502
+ const win = window;
1503
+ if (!win.parent || win.parent === win) return;
1504
+ const slotName = slotEl.getAttribute("data-amplifyup-slot") || slotEl.getAttribute("data-slot-id");
1505
+ if (!slotName) return;
1506
+ const { componentId, nodeId } = this.parentComponentForSlot(slotEl);
1507
+ const isEmpty = slotEl.getAttribute("data-slot-empty") === "true";
1508
+ win.parent.postMessage(
1509
+ {
1510
+ type: "DROP_ON_SLOT",
1511
+ slotName,
1512
+ slotElement: {
1513
+ path: slotEl.getAttribute("data-slot-path"),
1514
+ isEmpty,
1515
+ parentComponentId: componentId,
1516
+ parentNodeId: nodeId
1517
+ }
1518
+ },
1519
+ "*"
1520
+ );
1521
+ }
1344
1522
  handleComposerDropAtPoint(x, y) {
1345
1523
  if (typeof document === "undefined") return;
1346
- const win = window;
1347
- const slotSelector = "[data-slot-id], [data-amplifyup-slot]";
1524
+ const htmlEl = this.resolveSlotAtPoint(x, y);
1348
1525
  this.clearComposerDragHighlight();
1349
- const htmlEl = document.elementFromPoint(x, y)?.closest?.(slotSelector);
1350
- if (!htmlEl || !win.parent || win.parent === win) return;
1351
- const slotName = htmlEl.getAttribute("data-amplifyup-slot") || htmlEl.getAttribute("data-slot-id");
1352
- if (!slotName) return;
1353
- const isEmpty = htmlEl.getAttribute("data-slot-empty") === "true";
1354
- win.parent.postMessage({
1355
- type: "DROP_ON_SLOT",
1356
- slotName,
1357
- slotElement: { path: htmlEl.getAttribute("data-slot-path"), isEmpty }
1358
- }, "*");
1526
+ if (!htmlEl) return;
1527
+ this.postDropOnSlot(htmlEl);
1359
1528
  }
1360
1529
  /**
1361
1530
  * Enable component highlighting
@@ -1383,35 +1552,25 @@ Available Console Commands:
1383
1552
  this.teardownComposerDragDrop();
1384
1553
  const slotSelector = "[data-slot-id], [data-amplifyup-slot]";
1385
1554
  const clearDragOverState = () => {
1386
- document.querySelectorAll(`${slotSelector}.amplifyup-drag-over-slot`).forEach((el) => {
1387
- el.classList.remove("amplifyup-drag-over-slot");
1388
- });
1389
- document.body.classList.remove("amplifyup-drag-no-drop");
1555
+ this.clearComposerDragHighlight();
1390
1556
  };
1391
1557
  const dragenter = (e) => {
1392
1558
  e.preventDefault();
1393
- if (e.dataTransfer?.types?.length) {
1394
- document.body.classList.add("amplifyup-drag-no-drop");
1395
- }
1396
1559
  };
1397
1560
  const dragover = (e) => {
1398
1561
  e.preventDefault();
1399
- const target = e.target;
1400
- const slot = target?.closest?.(slotSelector);
1562
+ if (this.composerOverlayDragActive) {
1563
+ if (e.dataTransfer) e.dataTransfer.dropEffect = "copy";
1564
+ return;
1565
+ }
1566
+ const slot = this.resolveSlotAtPoint(e.clientX, e.clientY);
1401
1567
  if (e.dataTransfer) {
1402
1568
  e.dataTransfer.dropEffect = slot ? "copy" : "none";
1403
1569
  }
1404
- document.querySelectorAll(`${slotSelector}.amplifyup-drag-over-slot`).forEach((el) => {
1405
- el.classList.remove("amplifyup-drag-over-slot");
1406
- });
1407
- if (slot) {
1408
- slot.classList.add("amplifyup-drag-over-slot");
1409
- document.body.classList.remove("amplifyup-drag-no-drop");
1410
- } else {
1411
- document.body.classList.add("amplifyup-drag-no-drop");
1412
- }
1570
+ this.setComposerDragHighlight(slot, e.clientX, e.clientY);
1413
1571
  };
1414
1572
  const dragleave = (e) => {
1573
+ if (this.composerOverlayDragActive) return;
1415
1574
  const related = e.relatedTarget;
1416
1575
  if (!related || !document.body.contains(related)) {
1417
1576
  clearDragOverState();
@@ -1419,20 +1578,10 @@ Available Console Commands:
1419
1578
  };
1420
1579
  const drop = (e) => {
1421
1580
  e.preventDefault();
1422
- const target = e.target;
1423
- const slot = target?.closest?.(slotSelector);
1581
+ const slot = this.resolveSlotAtPoint(e.clientX, e.clientY);
1424
1582
  clearDragOverState();
1425
1583
  if (!slot || !this.isVisualEditorMode) return;
1426
- const slotName = slot.getAttribute("data-amplifyup-slot") || slot.getAttribute("data-slot-id");
1427
- const isEmpty = slot.getAttribute("data-slot-empty") === "true";
1428
- const win = window;
1429
- if (slotName && win.parent && win.parent !== win) {
1430
- win.parent.postMessage({
1431
- type: "DROP_ON_SLOT",
1432
- slotName,
1433
- slotElement: { path: slot.getAttribute("data-slot-path"), isEmpty }
1434
- }, "*");
1435
- }
1584
+ this.postDropOnSlot(slot);
1436
1585
  };
1437
1586
  const mouseover = (e) => {
1438
1587
  if (!this.showZonesEnabled) return;
@@ -1471,7 +1620,11 @@ Available Console Commands:
1471
1620
  document.removeEventListener("mouseover", h.mouseover, true);
1472
1621
  document.removeEventListener("mouseout", h.mouseout, true);
1473
1622
  this.composerDragHandlers = null;
1623
+ this.composerOverlayDragActive = false;
1624
+ this.lastComposerDragSlot = null;
1625
+ this.composerDragMissFrames = 0;
1474
1626
  document.body.classList.remove("amplifyup-drag-no-drop");
1627
+ document.body.classList.remove("amplifyup-composer-dragging");
1475
1628
  document.querySelectorAll("[data-slot-id].amplifyup-drag-over-slot, [data-amplifyup-slot].amplifyup-drag-over-slot").forEach((el) => {
1476
1629
  el.classList.remove("amplifyup-drag-over-slot");
1477
1630
  });
@@ -1512,21 +1665,32 @@ Available Console Commands:
1512
1665
  '[data-slot-id="main"], [data-amplifyup-slot="main"] {',
1513
1666
  " min-height: 50vh !important;",
1514
1667
  "}",
1515
- '[data-slot-id="main"][data-slot-empty="true"]::before,',
1516
- '[data-amplifyup-slot="main"][data-slot-empty="true"]::before {',
1517
- ' content: "Drop components here" !important;',
1518
- " position: absolute !important;",
1519
- " top: 50% !important; left: 50% !important;",
1520
- " transform: translate(-50%, -50%) !important;",
1521
- " font-size: 14px !important; font-weight: 500 !important;",
1522
- " color: rgba(34, 197, 94, 0.65) !important;",
1668
+ /* Single empty-state hint — Slot React label uses .amplifyup-slot-placeholder */
1669
+ ".amplifyup-slot-placeholder {",
1670
+ " display: flex !important;",
1671
+ " align-items: center !important;",
1672
+ " justify-content: center !important;",
1673
+ " min-height: inherit !important;",
1674
+ " color: rgba(34, 197, 94, 0.75) !important;",
1675
+ " font-size: 14px !important;",
1676
+ " font-weight: 500 !important;",
1523
1677
  " pointer-events: none !important;",
1524
- " white-space: nowrap !important;",
1678
+ " text-align: center !important;",
1525
1679
  "}",
1526
1680
  "[data-slot-id].amplifyup-slot-hover, [data-amplifyup-slot].amplifyup-slot-hover {",
1527
1681
  " outline-color: rgba(34, 197, 94, 1) !important;",
1528
1682
  " background: rgba(34, 197, 94, 0.06) !important;",
1529
1683
  "}",
1684
+ /* During any Composer drag, hide idle slot labels so they don't flash
1685
+ when the active drag-over class briefly changes */
1686
+ "body.amplifyup-composer-dragging .amplifyup-slot-placeholder {",
1687
+ " visibility: hidden !important;",
1688
+ " opacity: 0 !important;",
1689
+ "}",
1690
+ "body.amplifyup-composer-dragging [data-slot-id]::before,",
1691
+ "body.amplifyup-composer-dragging [data-amplifyup-slot]::before {",
1692
+ " content: none !important;",
1693
+ "}",
1530
1694
  "[data-slot-id].amplifyup-drag-over-slot, [data-amplifyup-slot].amplifyup-drag-over-slot {",
1531
1695
  " outline: 2px solid rgba(34, 197, 94, 1) !important;",
1532
1696
  " background: rgba(34, 197, 94, 0.18) !important;",
@@ -1542,7 +1706,7 @@ Available Console Commands:
1542
1706
  " color: rgb(22, 163, 74) !important;",
1543
1707
  " pointer-events: none !important;",
1544
1708
  " white-space: nowrap !important;",
1545
- " z-index: 1 !important;",
1709
+ " z-index: 2 !important;",
1546
1710
  "}",
1547
1711
  "body.amplifyup-drag-no-drop { cursor: no-drop !important; }",
1548
1712
  "body.amplifyup-drag-no-drop::before {",
@@ -1669,18 +1833,23 @@ Available Console Commands:
1669
1833
  sendSelectionMessage(element, hierarchy, isEmpty) {
1670
1834
  if (!this.isVisualEditorMode) return;
1671
1835
  const componentId = element.getAttribute("data-amplifyup-component") || element.getAttribute("data-component-id");
1672
- const slotName = element.getAttribute("data-amplifyup-slot") || element.getAttribute("data-slot-id");
1836
+ const slotName = componentId ? null : element.getAttribute("data-amplifyup-slot") || element.getAttribute("data-slot-id");
1673
1837
  const componentName = element.getAttribute("data-component-name");
1674
1838
  const hierarchyInfo = hierarchy.map((el, index) => {
1675
1839
  const elComponentId = el.getAttribute("data-amplifyup-component") || el.getAttribute("data-component-id");
1676
1840
  const elSlotName = el.getAttribute("data-amplifyup-slot") || el.getAttribute("data-slot-id");
1677
1841
  const elComponentName = el.getAttribute("data-component-name");
1842
+ const isSlot = !elComponentId && !!elSlotName;
1843
+ const isPageSlot = isSlot && el.getAttribute("data-slot-source") === "page";
1844
+ const nodeId = el.getAttribute("data-node-id") || (isSlot ? el.getAttribute("data-parent-node-id") : null);
1678
1845
  return {
1679
1846
  index,
1680
1847
  componentId: elComponentId,
1681
- componentName: elComponentName,
1682
- slotName: elSlotName,
1683
- isSlot: !!elSlotName
1848
+ componentName: isPageSlot ? "Page" : elComponentName,
1849
+ slotName: isSlot ? elSlotName : null,
1850
+ isSlot,
1851
+ isPageSlot,
1852
+ nodeId
1684
1853
  };
1685
1854
  });
1686
1855
  const rect = element.getBoundingClientRect ? element.getBoundingClientRect() : null;
@@ -1717,7 +1886,6 @@ Available Console Commands:
1717
1886
  return;
1718
1887
  }
1719
1888
  const doc = document;
1720
- const win = window;
1721
1889
  if (highlightComponents) {
1722
1890
  const componentElements = doc.querySelectorAll("[data-amplifyup-component], [data-component-id]");
1723
1891
  console.log("[AmplifyUp SDK] Found", componentElements.length, "components to highlight");
@@ -1778,52 +1946,8 @@ Available Console Commands:
1778
1946
  e.stopPropagation();
1779
1947
  this.sendSelectionMessage(htmlEl, hierarchy, isEmpty);
1780
1948
  };
1781
- const handleDrop = (e) => {
1782
- e.preventDefault();
1783
- e.stopPropagation();
1784
- htmlEl.classList.remove("amplifyup-drag-over-slot");
1785
- if (!win.parent || win.parent === win) return;
1786
- win.parent.postMessage({
1787
- type: "DROP_ON_SLOT",
1788
- slotName,
1789
- slotElement: { path: htmlEl.getAttribute("data-slot-path"), isEmpty }
1790
- }, "*");
1791
- try {
1792
- const data = JSON.parse(e.dataTransfer.getData("application/json"));
1793
- if (data.type === "component") {
1794
- win.parent.postMessage({
1795
- type: "COMPONENT_DROPPED",
1796
- componentId: data.componentId,
1797
- componentName: data.componentName,
1798
- slotName,
1799
- slotElement: { path: htmlEl.getAttribute("data-slot-path"), isEmpty }
1800
- }, "*");
1801
- }
1802
- } catch (_err) {
1803
- }
1804
- };
1805
- const handleDragOver = (e) => {
1806
- e.preventDefault();
1807
- e.stopPropagation();
1808
- e.dataTransfer.dropEffect = "copy";
1809
- htmlEl.classList.add("amplifyup-drag-over-slot");
1810
- };
1811
- const handleDragLeave = (e) => {
1812
- const related = e.relatedTarget;
1813
- if (!related || !htmlEl.contains(related)) {
1814
- htmlEl.classList.remove("amplifyup-drag-over-slot");
1815
- }
1816
- };
1817
1949
  htmlEl.addEventListener("click", handleClick);
1818
- htmlEl.addEventListener("dragover", handleDragOver);
1819
- htmlEl.addEventListener("dragleave", handleDragLeave);
1820
- htmlEl.addEventListener("drop", handleDrop);
1821
- htmlEl._amplifyupSlotHandlers = {
1822
- handleClick,
1823
- handleDragOver,
1824
- handleDragLeave,
1825
- handleDrop
1826
- };
1950
+ htmlEl._amplifyupSlotHandlers = { handleClick };
1827
1951
  });
1828
1952
  }
1829
1953
  }
@@ -2134,6 +2258,8 @@ function AmplifyRenderer({
2134
2258
  "data-slot-id": slot.slotId,
2135
2259
  "data-amplifyup-slot": slot.slotId,
2136
2260
  "data-zone-id": slot.zoneId || void 0,
2261
+ "data-parent-node-id": node.id,
2262
+ "data-parent-component-id": node.componentId,
2137
2263
  children: childrenToRender.map((child) => renderNode(child))
2138
2264
  },
2139
2265
  slot.slotId
@@ -2149,17 +2275,25 @@ function AmplifyRenderer({
2149
2275
  hasSlots: !!slotsToPass,
2150
2276
  slotKeys: slotsToPass ? Object.keys(slotsToPass) : []
2151
2277
  });
2152
- return renderComponent(
2153
- node.componentId,
2154
- node.props || {},
2155
- slotsToPass
2156
- );
2278
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-node-id": node.id, "data-amplifyup-node": "", children: renderComponent(node.componentId, node.props || {}, slotsToPass, {
2279
+ layoutNodeId: node.id
2280
+ }) });
2157
2281
  };
2158
- const layoutTree = pageConfig.layoutTree;
2159
- if (!layoutTree || layoutTree.length === 0) {
2282
+ const rawTree = pageConfig.layoutTree;
2283
+ const layoutTree = Array.isArray(rawTree) ? rawTree : rawTree && typeof rawTree === "object" && rawTree.componentId ? [rawTree] : [];
2284
+ if (layoutTree.length === 0) {
2160
2285
  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." }) }) });
2161
2286
  }
2162
- return /* @__PURE__ */ jsxRuntime.jsx("main", { children: layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderNode(node) }, node.id)) });
2287
+ return /* @__PURE__ */ jsxRuntime.jsx("main", { children: isComposerPreview() ? /* @__PURE__ */ jsxRuntime.jsx(
2288
+ "div",
2289
+ {
2290
+ "data-slot-id": "main",
2291
+ "data-amplifyup-slot": "main",
2292
+ "data-slot-source": "page",
2293
+ "data-slot-empty": layoutTree.length === 0 ? "true" : void 0,
2294
+ children: layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderNode(node) }, node.id))
2295
+ }
2296
+ ) : layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderNode(node) }, node.id)) });
2163
2297
  }
2164
2298
  function defaultPreviewCanvas() {
2165
2299
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -2167,8 +2301,10 @@ function defaultPreviewCanvas() {
2167
2301
  {
2168
2302
  "data-slot-id": "main",
2169
2303
  "data-amplifyup-slot": "main",
2304
+ "data-slot-source": "page",
2170
2305
  "data-slot-empty": "true",
2171
- style: { minHeight: "50vh", width: "100%", display: "block" }
2306
+ style: { minHeight: "50vh", width: "100%", display: "block", position: "relative" },
2307
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "amplifyup-slot-placeholder", children: "Drop components here" })
2172
2308
  }
2173
2309
  );
2174
2310
  }
@@ -2258,7 +2394,9 @@ var ComponentContext = react.createContext(null);
2258
2394
  function ComponentContextProvider({
2259
2395
  children,
2260
2396
  slots,
2261
- props
2397
+ props,
2398
+ layoutNodeId,
2399
+ componentId
2262
2400
  }) {
2263
2401
  console.log("[ComponentContextProvider] Providing context", {
2264
2402
  hasSlots: !!slots,
@@ -2269,9 +2407,11 @@ function ComponentContextProvider({
2269
2407
  contentType: slots[key] ? typeof slots[key] : "null"
2270
2408
  })) : [],
2271
2409
  hasProps: !!props,
2272
- propKeys: props ? Object.keys(props) : []
2410
+ propKeys: props ? Object.keys(props) : [],
2411
+ layoutNodeId,
2412
+ componentId
2273
2413
  });
2274
- return /* @__PURE__ */ jsxRuntime.jsx(ComponentContext.Provider, { value: { slots, props }, children });
2414
+ return /* @__PURE__ */ jsxRuntime.jsx(ComponentContext.Provider, { value: { slots, props, layoutNodeId, componentId }, children });
2275
2415
  }
2276
2416
  function Slot({
2277
2417
  name,
@@ -2322,33 +2462,50 @@ function Slot({
2322
2462
  {
2323
2463
  className,
2324
2464
  "data-slot-name": name,
2465
+ "data-slot-id": name,
2325
2466
  "data-amplifyup-slot": name,
2326
2467
  "data-slot-empty": isEmpty ? "true" : void 0,
2468
+ "data-parent-node-id": context.layoutNodeId || void 0,
2469
+ "data-parent-component-id": context.componentId || void 0,
2327
2470
  style: {
2328
2471
  // Only add minimum height when empty (for drop target visibility)
2329
2472
  minHeight: isEmpty ? "60px" : void 0,
2330
2473
  // Only add position relative for overlay positioning in editor mode
2331
2474
  position: isEditorMode ? "relative" : void 0
2332
2475
  },
2333
- children: isEmpty ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2334
- // Only style the empty state indicator, not the container
2335
- minHeight: "60px",
2336
- color: "#9ca3af",
2337
- fontSize: "14px",
2338
- pointerEvents: "none"
2339
- }, children: isEditorMode ? `[Slot: ${name}]` : `Empty slot: ${name}` }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2340
- isEditorMode && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
2341
- position: "absolute",
2342
- top: "4px",
2343
- left: "4px",
2344
- fontSize: "10px",
2345
- color: "#9ca3af",
2346
- pointerEvents: "none",
2347
- zIndex: 1
2348
- }, children: [
2349
- "Slot: ",
2350
- name
2351
- ] }),
2476
+ children: isEmpty ? /* @__PURE__ */ jsxRuntime.jsx(
2477
+ "div",
2478
+ {
2479
+ className: "amplifyup-slot-placeholder",
2480
+ style: {
2481
+ minHeight: "60px",
2482
+ color: "#9ca3af",
2483
+ fontSize: "14px",
2484
+ pointerEvents: "none"
2485
+ },
2486
+ children: isEditorMode ? `Drop components here` : `Empty slot: ${name}`
2487
+ }
2488
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2489
+ isEditorMode && /* @__PURE__ */ jsxRuntime.jsxs(
2490
+ "div",
2491
+ {
2492
+ className: "amplifyup-slot-placeholder",
2493
+ style: {
2494
+ position: "absolute",
2495
+ top: "4px",
2496
+ left: "4px",
2497
+ fontSize: "10px",
2498
+ color: "#9ca3af",
2499
+ pointerEvents: "none",
2500
+ zIndex: 1,
2501
+ minHeight: "auto"
2502
+ },
2503
+ children: [
2504
+ "Slot: ",
2505
+ name
2506
+ ]
2507
+ }
2508
+ ),
2352
2509
  slotContent
2353
2510
  ] })
2354
2511
  }
@@ -2400,7 +2557,8 @@ function AmplifyUpProvider({ children, config }) {
2400
2557
  return routeFromQuery;
2401
2558
  }
2402
2559
  const actualRoute = window.__AMPLIFYUP_ACTUAL_ROUTE__;
2403
- if (actualRoute && typeof actualRoute === "string" && (currentPath === "/api/pages/proxy" || currentPath.startsWith("/api/pages/proxy"))) {
2560
+ const inComposerShell = currentPath === "/api/pages/proxy" || currentPath.startsWith("/api/pages/proxy") || currentPath.includes("/preview-frame");
2561
+ if (actualRoute && typeof actualRoute === "string" && inComposerShell) {
2404
2562
  return actualRoute;
2405
2563
  }
2406
2564
  return currentPath;