mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-05 16:16:49 +00:00
fix: keep toasts at the bottom instead of over the composer's close button
This commit is contained in:
@@ -208,6 +208,25 @@ describe('toasts and the focused element', () => {
|
||||
expect(toastContainer()).not.toHaveAttribute('data-dodging');
|
||||
});
|
||||
|
||||
// With the focus in the composer's text or the quick reply box, "Email
|
||||
// sent" and "Sending in 5 seconds" moved to the top and covered the
|
||||
// composer's close button and the reader's toolbar. A large field the
|
||||
// stack only overlaps at a corner keeps the toasts at the bottom.
|
||||
it('stays at the bottom over a corner of a large focused field', () => {
|
||||
const h = window.innerHeight;
|
||||
vi.spyOn(HTMLElement.prototype, 'getBoundingClientRect').mockImplementation(function (this: HTMLElement) {
|
||||
if (this.hasAttribute('data-toast-container')) return rect(h - 100, 600, 360, 80);
|
||||
if (this.id === 'body') return rect(h - 400, 300, 700, 360);
|
||||
return rect(10, 10, 80, 36);
|
||||
});
|
||||
render(<><Toasts /><textarea id="body" /></>);
|
||||
act(() => { (document.getElementById('body') as HTMLElement).focus(); });
|
||||
act(() => { toast.success('Email sent'); });
|
||||
act(() => { vi.advanceTimersByTime(20); });
|
||||
expect(toastContainer()).not.toHaveAttribute('data-dodging');
|
||||
expect(toastContainer()).not.toHaveClass('top-5');
|
||||
});
|
||||
|
||||
// On a phone the top of the screen is the header with Back and the message
|
||||
// actions; an Undo toast that moved there blocked them. (#1472)
|
||||
it('stays at the bottom on a phone, clear of the header', () => {
|
||||
|
||||
+13
-5
@@ -358,10 +358,14 @@ export function ToastItem({ toast, onClose, held = false, onFocusLost }: ToastPr
|
||||
}
|
||||
|
||||
/**
|
||||
* True when the toast stack, in its usual place at the bottom, overlaps the
|
||||
* element that has the focus. The stack's own box is measured where it is
|
||||
* now; while it sits at the top, its bottom place is worked out from the gap
|
||||
* it left there (data-bottom-gap).
|
||||
* True when the toast stack, in its usual place at the bottom, hides at
|
||||
* least half of the element that has the focus: a button or a field. A
|
||||
* large element it only overlaps at a corner (the composer's text, the
|
||||
* quick reply box) stays usable, and moving the stack to the top for it put
|
||||
* the toasts over the composer's close button and the reader's toolbar. The
|
||||
* stack's own box is measured where it is now; while it sits at the top,
|
||||
* its bottom place is worked out from the gap it left there
|
||||
* (data-bottom-gap).
|
||||
*/
|
||||
export function stackWouldCoverFocus(stack: HTMLElement | null): boolean {
|
||||
if (!stack) return false;
|
||||
@@ -379,7 +383,11 @@ export function stackWouldCoverFocus(stack: HTMLElement | null): boolean {
|
||||
stack.dataset.bottomGap = String(Math.max(0, window.innerHeight - box.bottom));
|
||||
}
|
||||
const f = focused.getBoundingClientRect();
|
||||
return f.right > box.left && f.left < box.right && f.bottom > top && f.top < bottom;
|
||||
const overlapWidth = Math.min(f.right, box.right) - Math.max(f.left, box.left);
|
||||
const overlapHeight = Math.min(f.bottom, bottom) - Math.max(f.top, top);
|
||||
if (overlapWidth <= 0 || overlapHeight <= 0) return false;
|
||||
const area = Math.max(f.width, 0) * Math.max(f.height, 0);
|
||||
return area === 0 || overlapWidth * overlapHeight >= area / 2;
|
||||
}
|
||||
|
||||
export function ToastContainer({ toasts, onClose }: { toasts: Toast[]; onClose: (id: string) => void }) {
|
||||
|
||||
Reference in New Issue
Block a user