Skip to content

Commit ec9fc30

Browse files
committed
fix(ui5-dialog): prevent native drag behavior only for header
fixes: #13131
1 parent 4180a6a commit ec9fc30

File tree

3 files changed

+128
-1
lines changed

3 files changed

+128
-1
lines changed

packages/main/cypress/specs/Dialog.cy.tsx

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1698,3 +1698,96 @@ describe("Event Registration", () => {
16981698
});
16991699
});
17001700
});
1701+
1702+
describe("Native drag-and-drop in draggable dialogs", () => {
1703+
it("_handleDragStart should NOT prevent default for content elements", () => {
1704+
cy.mount(
1705+
<Dialog id="test-dialog" draggable={true} headerText="Test">
1706+
<div id="content-item">Content</div>
1707+
</Dialog>
1708+
);
1709+
1710+
cy.get("#test-dialog").invoke("prop", "open", true);
1711+
cy.get<Dialog>("#test-dialog").ui5DialogOpened();
1712+
1713+
cy.get("#test-dialog").then($dialog => {
1714+
const dialog = $dialog.get(0) as Dialog;
1715+
const content = document.getElementById("content-item");
1716+
1717+
// Create a mock event
1718+
let preventDefaultCalled = false;
1719+
const mockEvent = {
1720+
target: content,
1721+
preventDefault: () => { preventDefaultCalled = true; },
1722+
defaultPrevented: false
1723+
} as unknown as DragEvent;
1724+
1725+
// Call the handler directly
1726+
dialog._handleDragStart(mockEvent);
1727+
1728+
expect(preventDefaultCalled).to.be.false;
1729+
});
1730+
});
1731+
1732+
it("_handleDragStart should prevent default for header element", () => {
1733+
cy.mount(
1734+
<Dialog id="test-dialog" draggable={true} headerText="Test">
1735+
<div>Content</div>
1736+
</Dialog>
1737+
);
1738+
1739+
cy.get("#test-dialog").invoke("prop", "open", true);
1740+
cy.get<Dialog>("#test-dialog").ui5DialogOpened();
1741+
1742+
cy.get("#test-dialog")
1743+
.shadow()
1744+
.find(".ui5-popup-header-root")
1745+
.then($header => {
1746+
const dialog = document.getElementById("test-dialog") as Dialog;
1747+
const header = $header.get(0) as HTMLElement;
1748+
1749+
// Create a mock event
1750+
let preventDefaultCalled = false;
1751+
const mockEvent = {
1752+
target: header,
1753+
preventDefault: () => { preventDefaultCalled = true; },
1754+
defaultPrevented: false
1755+
} as unknown as DragEvent;
1756+
1757+
// Call the handler directly
1758+
dialog._handleDragStart(mockEvent);
1759+
1760+
expect(preventDefaultCalled).to.be.true;
1761+
});
1762+
});
1763+
1764+
it("_handleDragStart should prevent default for custom header slot", () => {
1765+
cy.mount(
1766+
<Dialog id="test-dialog" draggable={true}>
1767+
<div slot="header" id="custom-header">Header</div>
1768+
<div>Content</div>
1769+
</Dialog>
1770+
);
1771+
1772+
cy.get("#test-dialog").invoke("prop", "open", true);
1773+
cy.get<Dialog>("#test-dialog").ui5DialogOpened();
1774+
1775+
cy.get("#custom-header").then($header => {
1776+
const dialog = document.getElementById("test-dialog") as Dialog;
1777+
const header = $header.get(0) as HTMLElement;
1778+
1779+
// Create a mock event
1780+
let preventDefaultCalled = false;
1781+
const mockEvent = {
1782+
target: header,
1783+
preventDefault: () => { preventDefaultCalled = true; },
1784+
defaultPrevented: false
1785+
} as unknown as DragEvent;
1786+
1787+
// Call the handler directly
1788+
dialog._handleDragStart(mockEvent);
1789+
1790+
expect(preventDefaultCalled).to.be.true;
1791+
});
1792+
});
1793+
});

packages/main/src/Dialog.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,9 @@ class Dialog extends Popup {
669669
}
670670

671671
_handleDragStart(e: DragEvent) {
672-
if (this.draggable) {
672+
// Only prevent native drag behavior when dragging from the header
673+
// This allows native drag-and-drop to work in the dialog content
674+
if (this.draggable && e.target instanceof HTMLElement && Dialog._isHeader(e.target)) {
673675
e.preventDefault();
674676
}
675677
}

packages/main/test/pages/Dialog.html

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@
9595
<br>
9696
<br>
9797
<ui5-button id="open-big-content">Open dialog with big content</ui5-button>
98+
<br>
99+
<br>
100+
<ui5-button id="native-dnd-open">Open draggable dialog with native DnD</ui5-button>
98101
</div>
99102
<ui5-block-layer></ui5-block-layer>
100103

@@ -452,6 +455,16 @@
452455
</ui5-dialog>
453456
</div>
454457

458+
<ui5-dialog id="native-dnd-dialog" header-text="Draggable Dialog with Native DnD" draggable>
459+
<p>Drag items to drop zone:</p>
460+
<div id="dnd-item-1" draggable="true">Item 1</div>
461+
<div id="dnd-item-2" draggable="true">Item 2</div>
462+
<div id="drop-zone">Drop Zone</div>
463+
<div slot="footer" class="dialogFooter">
464+
<ui5-button id="native-dnd-close">Close</ui5-button>
465+
</div>
466+
</ui5-dialog>
467+
455468
<ui5-popover header-text="My Heading" id="pop" class="dialog8auto" placement="Top">
456469
<!-- <div slot="header">
457470
Hello World
@@ -1127,6 +1140,25 @@
11271140
document.getElementById("open-big-content").addEventListener("click", function () {
11281141
window["dlgBigContent"].open = true;
11291142
});
1143+
1144+
window["native-dnd-open"].addEventListener("click", () => window["native-dnd-dialog"].open = true);
1145+
window["native-dnd-close"].addEventListener("click", () => window["native-dnd-dialog"].open = false);
1146+
1147+
document.getElementById("dnd-item-1").addEventListener("dragstart", (e) => {
1148+
e.dataTransfer.setData("text", "item-1");
1149+
});
1150+
1151+
document.getElementById("dnd-item-2").addEventListener("dragstart", (e) => {
1152+
e.dataTransfer.setData("text", "item-2");
1153+
});
1154+
1155+
const dropZone = document.getElementById("drop-zone");
1156+
dropZone.addEventListener("dragover", (e) => e.preventDefault());
1157+
dropZone.addEventListener("drop", (e) => {
1158+
e.preventDefault();
1159+
const data = e.dataTransfer.getData("text");
1160+
dropZone.textContent = `Dropped: ${data}`;
1161+
});
11301162
</script>
11311163
</body>
11321164

0 commit comments

Comments
 (0)