Skip to content

Commit 0bacbdc

Browse files
[NGD-116] Fix palette drag preview clipping when ancestor has overflo… (#624)
* [NGD-116] Fix palette drag preview clipping when ancestor has overflow:hidden * improve * Update changelog
1 parent d6704f2 commit 0bacbdc

File tree

5 files changed

+30
-9
lines changed

5 files changed

+30
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Fixed
1111

1212
- `initializeModel` can now be safely called inside reactive contexts (`computed`, `effect`, `linkedSignal`) without throwing NG0602 ([#608](https://github.com/synergycodes/ng-diagram/issues/608), [#622](https://github.com/synergycodes/ng-diagram/pull/622))
13+
- Fixed palette drag preview not rendering when an ancestor element has `overflow: hidden` ([#624](https://github.com/synergycodes/ng-diagram/pull/624))
1314

1415
## [1.1.2] - 2026-03-17
1516

apps/angular-demo/src/app/palette/palette.component.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
background: var(--ngd-ui-bg-primary-default);
88
padding: 16px;
99
box-sizing: border-box;
10+
overflow: hidden;
1011

1112
& .palette {
1213
flex-direction: column;

apps/docs/src/content/docs/changelog.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
### Fixed
1616

1717
- `initializeModel` can now be safely called inside reactive contexts (`computed`, `effect`, `linkedSignal`) without throwing NG0602 ([#608](https://github.com/synergycodes/ng-diagram/issues/608), [#622](https://github.com/synergycodes/ng-diagram/pull/622))
18+
- Fixed palette drag preview not rendering when an ancestor element has `overflow: hidden` ([#624](https://github.com/synergycodes/ng-diagram/pull/624))
1819

1920
## [1.1.2] - 2026-03-17
2021

Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
<div #preview [class.dragged-node]="isSafari" [style.zoom]="isSafari ? scale() : null">
2-
@if (isVisible()) {
3-
<div [class.dragged-node]="!isSafari" [style.transform]="!isSafari ? scaleTransform : null">
4-
<ng-content></ng-content>
5-
</div>
6-
}
2+
<div [class.dragged-node]="!isSafari" [style.transform]="!isSafari ? scaleTransform : null">
3+
<ng-content></ng-content>
4+
</div>
75
</div>

packages/ng-diagram/projects/ng-diagram/src/lib/components/palette/item/ng-diagram-palette-item.component.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,7 @@ export class NgDiagramPaletteItemComponent {
4141

4242
/** @internal */
4343
onDragStart(event: DragEvent) {
44-
const previewHtmlElement = this.paletteItemPreviewComponent()?.preview();
45-
if (previewHtmlElement && previewHtmlElement.nativeElement) {
46-
event.dataTransfer?.setDragImage(previewHtmlElement.nativeElement, 0, 0);
47-
}
44+
this.setDragPreviewImage(event);
4845
this.paletteService.onDragStartFromPalette(event, this.item());
4946
}
5047

@@ -58,4 +55,27 @@ export class NgDiagramPaletteItemComponent {
5855
event.preventDefault();
5956
this.paletteService.onMouseDown(this.item(), this.paletteItemPreviewComponent()?.id || '');
6057
}
58+
59+
/**
60+
* Clones the preview element and appends it to document.body so that setDragImage
61+
* is immune to ancestor overflow:hidden clipping. The clone is removed on the next frame.
62+
*/
63+
private setDragPreviewImage(event: DragEvent) {
64+
const previewHtmlElement = this.paletteItemPreviewComponent()?.preview();
65+
if (!previewHtmlElement?.nativeElement || !event.dataTransfer) {
66+
return;
67+
}
68+
69+
const clone = previewHtmlElement.nativeElement.cloneNode(true) as HTMLElement;
70+
clone.classList.add('dragged-node');
71+
clone.style.position = 'fixed';
72+
73+
document.body.appendChild(clone);
74+
75+
event.dataTransfer.setDragImage(clone, 0, 0);
76+
77+
// Clean up the temporary clone. This is safe because setDragImage captures the bitmap
78+
// synchronously during dragstart — the browser already has the image before the next frame.
79+
requestAnimationFrame(() => clone.remove());
80+
}
6181
}

0 commit comments

Comments
 (0)