Skip to content

Commit

Permalink
fix(PageLayout): use dvh to support the correct height on iOS devices (
Browse files Browse the repository at this point in the history
…#2251)

* fix(PageLayout): use dvh to support the correct height on iOS devices

* Create few-spoons-hear.md

* fix: add support for dvh on iPad

* chore: add support for CSS.supports in JSDOM

* chore: update mock implementation
  • Loading branch information
joshblack committed Oct 3, 2022
1 parent 845001b commit 4a4e47c
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .changeset/few-spoons-hear.md
@@ -0,0 +1,5 @@
---
"@primer/react": patch
---

Add support for the dvh unit in `PageLayout` in order to correctly display pane contents on iOS devices
8 changes: 4 additions & 4 deletions examples/nextjs/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 2 additions & 5 deletions jest.config.js
Expand Up @@ -3,11 +3,8 @@ module.exports = {
testEnvironment: 'jsdom',
cacheDirectory: '.test',
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!src/stories/**', '!**/*.stories.{js,jsx,ts,tsx}'],
setupFilesAfterEnv: [
'<rootDir>/src/utils/test-matchers.tsx',
'<rootDir>/src/utils/test-deprecations.tsx',
'<rootDir>/src/utils/test-helpers.tsx'
],
setupFiles: ['<rootDir>/src/utils/test-helpers.tsx'],
setupFilesAfterEnv: ['<rootDir>/src/utils/test-matchers.tsx', '<rootDir>/src/utils/test-deprecations.tsx'],
testMatch: ['<rootDir>/(src|codemods)/**/*.test.[jt]s?(x)', '!**/*.types.test.[jt]s?(x)'],
transformIgnorePatterns: [
'node_modules/(?!@github/combobox-nav|@koddsson/textarea-caret|@github/markdown-toolbar-element)'
Expand Down
27 changes: 25 additions & 2 deletions src/PageLayout/useStickyPaneHeight.ts
@@ -1,5 +1,6 @@
import React from 'react'
import {useInView} from 'react-intersection-observer'
import {canUseDOM} from '../utils/environment'

/**
* Calculates the height of the sticky pane such that it always
Expand All @@ -9,7 +10,7 @@ export function useStickyPaneHeight() {
const rootRef = React.useRef<HTMLDivElement>(null)

// Default the height to the viewport height
const [height, setHeight] = React.useState('100vh')
const [height, setHeight] = React.useState(dvh(100))
const [offsetHeader, setOffsetHeader] = React.useState<number | string>(0)

// Create intersection observers to track the top and bottom of the content region
Expand Down Expand Up @@ -47,7 +48,9 @@ export function useStickyPaneHeight() {
// We need to account for this when calculating the offset.
const overflowScroll = Math.max(window.scrollY + window.innerHeight - document.body.scrollHeight, 0)

calculatedHeight = `calc(100vh - (max(${topOffset}px, ${offsetHeaderWithUnits}) + ${bottomOffset}px - ${overflowScroll}px))`
calculatedHeight = `calc(${dvh(
100
)} - (max(${topOffset}px, ${offsetHeaderWithUnits}) + ${bottomOffset}px - ${overflowScroll}px))`
}

setHeight(calculatedHeight)
Expand Down Expand Up @@ -131,3 +134,23 @@ function isScrollable(element: Element) {

return hasScrollableContent && !isOverflowHidden
}

// TODO: there is currently an issue with dvh on Desktop Safari 15.6, 16.0. To
// work around it, we check to see if the device supports touch along with the
// dvh unit in order to target iPad. When the bug is addressed this check will
// no longer be needed
//
// @see https://bugs.webkit.org/show_bug.cgi?id=242758
const supportsTouchCallout = canUseDOM ? CSS.supports('-webkit-touch-callout', 'none') : false
const supportsDVH = canUseDOM ? CSS.supports('max-height', '100dvh') && supportsTouchCallout : false

/**
* Convert the given value to a dvh value, if supported, otherwise it falls back
* to vh
*/
function dvh(value: number): string {
if (supportsDVH) {
return `${value}dvh`
}
return `${value}vh`
}
7 changes: 7 additions & 0 deletions src/utils/test-helpers.tsx
Expand Up @@ -5,3 +5,10 @@ global.ResizeObserver = jest.fn().mockImplementation(() => {
disconnect: jest.fn()
}
})

global.CSS = {
escape: jest.fn(),
supports: jest.fn().mockImplementation(() => {
return false
})
}

0 comments on commit 4a4e47c

Please sign in to comment.