Skip to content

Commit aa2160e

Browse files
author
fink01
committed
fix: 修复纵向平移后弹层越出视口
1 parent 3ff7d68 commit aa2160e

2 files changed

Lines changed: 69 additions & 2 deletions

File tree

src/hooks/useAlign.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ export default function useAlign(
189189
const originOverflowX = popupElement.style.overflowX;
190190
const originOverflowY = popupElement.style.overflowY;
191191

192-
193192
// Placement
194193
const placementInfo: AlignType = {
195194
...builtinPlacements[placement],
@@ -666,6 +665,19 @@ export default function useAlign(
666665
nextOffsetY += targetRect.y - visibleRegionArea.bottom + numShiftY;
667666
}
668667
}
668+
669+
// 目标仍在平移范围内时,避免方向偏移量将弹层再次推到视口外。
670+
if (
671+
targetRect.y + targetHeight >= visibleRegionArea.top + numShiftY &&
672+
targetRect.y <= visibleRegionArea.bottom - numShiftY
673+
) {
674+
const minOffsetY = visibleRegionArea.top - popupRect.y;
675+
const maxOffsetY = Math.max(
676+
minOffsetY,
677+
visibleRegionArea.bottom - popupHeight - popupRect.y,
678+
);
679+
nextOffsetY = Math.min(Math.max(nextOffsetY, minOffsetY), maxOffsetY);
680+
}
669681
}
670682

671683
// ============================ Arrow ============================

tests/flipShift.test.tsx

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,10 @@ const builtinPlacements = {
8080

8181
describe('Trigger.Flip+Shift', () => {
8282
let spanRect = { x: 0, y: 0, left: 0, top: 0, width: 0, height: 0 };
83+
let popupHeight = 300;
8384

8485
beforeEach(() => {
86+
popupHeight = 300;
8587
spanRect = {
8688
x: 0,
8789
y: 100,
@@ -118,7 +120,7 @@ describe('Trigger.Flip+Shift', () => {
118120
left: 0,
119121
top: 0,
120122
width: 100,
121-
height: 300,
123+
height: popupHeight,
122124
};
123125
},
124126
});
@@ -170,6 +172,59 @@ describe('Trigger.Flip+Shift', () => {
170172
});
171173
});
172174

175+
it.each([
176+
{ placement: 'top', offset: -4, targetY: 100, top: '100px' },
177+
{ placement: 'bottom', offset: 4, targetY: 100, top: '100px' },
178+
{ placement: 'top', offset: -4, targetY: 200, top: '0px' },
179+
{ placement: 'bottom', offset: 4, targetY: 200, top: '0px' },
180+
])(
181+
'$placement 在目标位于 $targetY 时,平移不应被偏移量推回视口外',
182+
async ({ placement, offset, targetY, top }) => {
183+
spanRect.y = targetY;
184+
spanRect.top = targetY;
185+
186+
render(
187+
<Trigger
188+
popupVisible
189+
popupPlacement={placement}
190+
builtinPlacements={builtinPlacements}
191+
popupAlign={{ offset: [0, offset] }}
192+
popup={<strong>日期面板</strong>}
193+
>
194+
<span className="target" />
195+
</Trigger>,
196+
);
197+
198+
await act(async () => {
199+
await Promise.resolve();
200+
});
201+
202+
expect(document.querySelector('.rc-trigger-popup')).toHaveStyle({ top });
203+
},
204+
);
205+
206+
it('面板高于视口时优先保留顶部内容', async () => {
207+
popupHeight = 500;
208+
render(
209+
<Trigger
210+
popupVisible
211+
popupPlacement="top"
212+
builtinPlacements={builtinPlacements}
213+
popup={<strong>日期面板</strong>}
214+
>
215+
<span className="target" />
216+
</Trigger>,
217+
);
218+
219+
await act(async () => {
220+
await Promise.resolve();
221+
});
222+
223+
expect(document.querySelector('.rc-trigger-popup')).toHaveStyle({
224+
top: '0px',
225+
});
226+
});
227+
173228
it('top with visibleFirst region', async () => {
174229
spanRect.x = -1000;
175230
document.documentElement.scrollLeft = 500;

0 commit comments

Comments
 (0)