Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions packages/@react-aria/utils/src/useViewportSize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,20 @@ export function useViewportSize(): ViewportSize {
return size;
}

/**
* Get the viewport size without the scrollbar.
*/
function getViewportSize(): ViewportSize {
return {
// Multiply by the visualViewport scale to get the "natural" size, unaffected by pinch zooming.
width: visualViewport ? visualViewport.width * visualViewport.scale : window.innerWidth,
height: visualViewport ? visualViewport.height * visualViewport.scale : window.innerHeight
width: visualViewport
// The visual viewport width may include the scrollbar gutter. We should use the minimum width between
// the visual viewport and the document element to ensure that the scrollbar width is always excluded.
// See: https://github.com/w3c/csswg-drafts/issues/8099
? Math.min(visualViewport.width * visualViewport.scale, document.documentElement.clientWidth)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, this line still cannot get the correct ICB width. We may need to insert an empty <div> with position: absolute; width: 100% inside <body> and use its clientWidth for the ICB width. document.documentElement.getBoundingClientRect().width may also work, as long as no width style applied to the <html>.

: document.documentElement.clientWidth,
height: visualViewport
? visualViewport.height * visualViewport.scale
: document.documentElement.clientHeight
};
}
7 changes: 6 additions & 1 deletion packages/react-aria-components/src/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,17 +184,22 @@ function ModalOverlayInner({UNSTABLE_portalContainer, ...props}: ModalOverlayInn
});

let viewport = useViewportSize();
let pageWidth: number | undefined = undefined;
let pageHeight: number | undefined = undefined;
if (typeof document !== 'undefined') {
let scrollingElement = isScrollable(document.body) ? document.body : document.scrollingElement || document.documentElement;
// Prevent Firefox from adding scrollbars when the page has a fractional height.
// Prevent Firefox from adding scrollbars when the page has a fractional width/height.
let fractionalWidthDifference = scrollingElement.getBoundingClientRect().width % 1;
let fractionalHeightDifference = scrollingElement.getBoundingClientRect().height % 1;
pageWidth = scrollingElement.scrollWidth - fractionalWidthDifference;
pageHeight = scrollingElement.scrollHeight - fractionalHeightDifference;
}

let style = {
...renderProps.style,
'--visual-viewport-width': viewport.width + 'px',
'--visual-viewport-height': viewport.height + 'px',
'--page-width': pageWidth !== undefined ? pageWidth + 'px' : undefined,
'--page-height': pageHeight !== undefined ? pageHeight + 'px' : undefined
};

Expand Down