Skip to content

Commit 9fc5b6e

Browse files
fix(grid): clip row edit overlay within visible grid area
1 parent 66a30b5 commit 9fc5b6e

1 file changed

Lines changed: 10 additions & 2 deletions

File tree

projects/igniteui-angular/grids/core/src/grid.common.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export class RowEditPositionStrategy extends ConnectedPositioningStrategy {
6464
super.position(contentElement, { width: targetElement.clientWidth, height: targetElement.clientHeight },
6565
document, initialCall, targetElement);
6666

67+
// After positioning in the top layer, keep the overlay clipped to the visible grid body.
6768
this.updateContentClip(contentElement);
6869
}
6970

@@ -77,32 +78,38 @@ export class RowEditPositionStrategy extends ConnectedPositioningStrategy {
7778
const clippingRect = this.getClippingRect(container);
7879
const contentRect = contentElement.getBoundingClientRect();
7980

81+
// Convert the clipped overflow on each side to CSS inset values.
8082
const top = Math.round(Math.max(clippingRect.top - contentRect.top, 0));
8183
const right = Math.round(Math.max(contentRect.right - clippingRect.right, 0));
8284
const bottom = Math.round(Math.max(contentRect.bottom - clippingRect.bottom, 0));
8385
const left = Math.round(Math.max(clippingRect.left - contentRect.left, 0));
8486

87+
// When the overlay is fully outside the clipping rect, hide it and block its action buttons.
8588
const fullyClipped = top >= contentRect.height || bottom >= contentRect.height ||
8689
left >= contentRect.width || right >= contentRect.width;
8790

91+
// Row-edit overlays are rendered in the top layer, so clip the content explicitly to the grid's visible area.
8892
contentElement.style.clipPath = fullyClipped ? 'inset(100%)' :
8993
(top || right || bottom || left ? `inset(${top}px ${right}px ${bottom}px ${left}px)` : '');
9094

9195
contentElement.style.pointerEvents = fullyClipped ? 'none' : '';
92-
contentElement.style.visibility = '';
96+
contentElement.style.visibility = fullyClipped ? 'hidden' : '';
9397
}
9498

9599
private getClippingRect(element: HTMLElement): Pick<DOMRect, 'top' | 'right' | 'bottom' | 'left'> {
96100
const document = element.ownerDocument;
97101
const rect = element.getBoundingClientRect();
102+
// Start with the current grid body, then narrow it by every clipping parent.
98103
const clippingRect = { top: rect.top, right: rect.right, bottom: rect.bottom, left: rect.left };
99104

100105
let parent = element.parentElement;
101106

107+
// Intersect with clipping ancestors so nested grids respect their parent grid scroll bounds.
102108
while (parent && parent !== document.body && parent !== document.documentElement) {
103-
const style = getComputedStyle(parent);
109+
const style = document.defaultView?.getComputedStyle(parent) ?? parent.style;
104110
const overflow = `${style.overflow}${style.overflowX}${style.overflowY}`;
105111

112+
// Only ancestors that clip their children should reduce the visible area.
106113
if (/(auto|scroll|hidden|clip)/.test(overflow)) {
107114
const parentRect = parent.getBoundingClientRect();
108115

@@ -115,6 +122,7 @@ export class RowEditPositionStrategy extends ConnectedPositioningStrategy {
115122
parent = parent.parentElement;
116123
}
117124

125+
// Keep the clipping area inside the viewport because popover content is viewport-positioned.
118126
return {
119127
top: Math.max(clippingRect.top, 0),
120128
right: Math.min(clippingRect.right, document.documentElement.clientWidth),

0 commit comments

Comments
 (0)