Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
5 changes: 5 additions & 0 deletions .changeset/rich-singers-double.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': minor
---

Rename `stickyTop` prop name for the PageLayout to `offsetHeader` and improve docs
8 changes: 5 additions & 3 deletions docs/content/PageLayout.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ See [storybook](https://primer.style/react/storybook?path=/story/layout-pagelayo

### With a custom sticky header

Add `offsetHeader` prop to specify the height of the custom sticky header along with `sticky` prop

```jsx live
<Box sx={{height: 320, overflowY: 'auto', border: '1px solid', borderColor: 'border.default'}}>
<Box
Expand All @@ -190,7 +192,7 @@ See [storybook](https://primer.style/react/storybook?path=/story/layout-pagelayo
<PageLayout.Content>
<Placeholder label="Content" height={320} />
</PageLayout.Content>
<PageLayout.Pane position="start" stickyTop={64} sticky>
<PageLayout.Pane position="start" sticky offsetHeader={64}>
<Placeholder label="Pane" height={120} />
</PageLayout.Pane>
<PageLayout.Footer>
Expand Down Expand Up @@ -370,10 +372,10 @@ See [storybook](https://primer.style/react/storybook?path=/story/layout-pagelayo
description="Whether the pane should stick to the top of the screen while the content scrolls."
/>
<PropsTableRow
name="stickyTop"
name="offsetHeader"
type="number | string"
defaultValue="0"
description="Use stickyTop to push the sticky pane down to make room for a sticky header if necessary. Use the type `string` to specify the height with a unit i.e. 5rem; otherwise the type `number` will be taken as px."
description="Use offsetHeader along with the sticky prop to push the sticky pane down to make room for a sticky header if necessary. Use the type `string` to specify the height with a unit i.e. 5rem; otherwise the type `number` will be taken as px."
/>
<PropsTableRow
name="padding"
Expand Down
6 changes: 3 additions & 3 deletions docs/content/SplitPageLayout.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ If you need a more flexible layout component, consider using the [PageLayout](/P
<SplitPageLayout.Content>
<Placeholder label="Content" height={320} />
</SplitPageLayout.Content>
<SplitPageLayout.Pane stickyTop={64}>
<SplitPageLayout.Pane sticky offsetHeader={64}>
<Placeholder label="Pane" height={120} />
</SplitPageLayout.Pane>
<SplitPageLayout.Footer>
Expand Down Expand Up @@ -383,10 +383,10 @@ If you need a more flexible layout component, consider using the [PageLayout](/P
description="Whether the pane should stick to the top of the screen while the content scrolls."
/>
<PropsTableRow
name="stickyTop"
name="offsetHeader"
type="number | string"
defaultValue="0"
description="Use stickyTop to push the sticky pane down to make room for a sticky header if necessary. Use the type `string` to specify the height with a unit i.e. 5rem; otherwise the type `number` will be taken as px."
description="Use offsetHeader along with the sticky prop to push the sticky pane down to make room for a sticky header if necessary. Use the type `string` to specify the height with a unit i.e. 5rem; otherwise the type `number` will be taken as px."
/>
<PropsTableRow
name="padding"
Expand Down
6 changes: 3 additions & 3 deletions src/PageLayout/PageLayout.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ export const CustomStickyHeader: Story = args => (
sx={{
position: 'sticky',
top: 0,
height: args.stickyTop,
height: args.offsetHeader,
display: 'grid',
placeItems: 'center',
backgroundColor: 'canvas.subtle',
Expand All @@ -619,7 +619,7 @@ export const CustomStickyHeader: Story = args => (
))}
</Box>
</PageLayout.Content>
<PageLayout.Pane position="start" padding="normal" divider="line" sticky stickyTop={args.stickyTop}>
<PageLayout.Pane position="start" padding="normal" divider="line" sticky offsetHeader={args.offsetHeader}>
<Box sx={{display: 'grid', gap: 3}}>
{Array.from({length: args.numParagraphsInPane}).map((_, i) => (
<Box key={i} as="p" sx={{margin: 0}}>
Expand All @@ -643,7 +643,7 @@ CustomStickyHeader.argTypes = {
type: 'boolean',
defaultValue: true
},
stickyTop: {
offsetHeader: {
type: 'string',
defaultValue: '8rem'
},
Expand Down
14 changes: 7 additions & 7 deletions src/PageLayout/PageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ export type PageLayoutPaneProps = {
*/
dividerWhenNarrow?: 'inherit' | 'none' | 'line' | 'filled'
sticky?: boolean
stickyTop?: string | number
offsetHeader?: string | number
hidden?: boolean | ResponsiveValue<boolean>
} & SxProp

Expand All @@ -384,7 +384,7 @@ const Pane: React.FC<React.PropsWithChildren<PageLayoutPaneProps>> = ({
divider: responsiveDivider = 'none',
dividerWhenNarrow = 'inherit',
sticky = false,
stickyTop = 0,
offsetHeader = 0,
hidden: responsiveHidden = false,
children,
sx = {}
Expand All @@ -411,11 +411,11 @@ const Pane: React.FC<React.PropsWithChildren<PageLayoutPaneProps>> = ({

React.useEffect(() => {
if (sticky) {
enableStickyPane?.(stickyTop)
enableStickyPane?.(offsetHeader)
} else {
disableStickyPane?.()
}
}, [sticky, enableStickyPane, disableStickyPane, stickyTop])
}, [sticky, enableStickyPane, disableStickyPane, offsetHeader])

return (
<Box
Expand All @@ -440,9 +440,9 @@ const Pane: React.FC<React.PropsWithChildren<PageLayoutPaneProps>> = ({
...(sticky
? {
position: 'sticky',
// If stickyTop has value, it will stick the pane to the position where the sticky top ends
// else top will be 0 as the default value of stickyTop
top: typeof stickyTop === 'number' ? `${stickyTop}px` : stickyTop,
// If offsetHeader has value, it will stick the pane to the position where the sticky top ends
// else top will be 0 as the default value of offsetHeader
top: typeof offsetHeader === 'number' ? `${offsetHeader}px` : offsetHeader,
overflow: 'hidden',
maxHeight: 'var(--sticky-pane-height)'
}
Expand Down
13 changes: 7 additions & 6 deletions src/PageLayout/useStickyPaneHeight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function useStickyPaneHeight() {

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

// Create intersection observers to track the top and bottom of the content region
const [contentTopRef, contentTopInView, contentTopEntry] = useInView()
Expand All @@ -29,15 +29,16 @@ export function useStickyPaneHeight() {
const topRect = contentTopEntry?.target.getBoundingClientRect()
const bottomRect = contentBottomEntry?.target.getBoundingClientRect()

const stickyTopWithUnits = typeof stickyTop === 'number' ? `${stickyTop}px` : stickyTop
// Custom sticky header's height with units
const offsetHeaderWithUnits = typeof offsetHeader === 'number' ? `${offsetHeader}px` : offsetHeader

if (scrollContainer) {
const scrollRect = scrollContainer.getBoundingClientRect()

const topOffset = topRect ? Math.max(topRect.top - scrollRect.top, 0) : 0
const bottomOffset = bottomRect ? Math.max(scrollRect.bottom - bottomRect.bottom, 0) : 0

calculatedHeight = `calc(${scrollRect.height}px - (max(${topOffset}px, ${stickyTopWithUnits}) + ${bottomOffset}px))`
calculatedHeight = `calc(${scrollRect.height}px - (max(${topOffset}px, ${offsetHeaderWithUnits}) + ${bottomOffset}px))`
} else {
const topOffset = topRect ? Math.max(topRect.top, 0) : 0
const bottomOffset = bottomRect ? Math.max(window.innerHeight - bottomRect.bottom, 0) : 0
Expand All @@ -46,11 +47,11 @@ 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, ${stickyTopWithUnits}) + ${bottomOffset}px - ${overflowScroll}px))`
calculatedHeight = `calc(100vh - (max(${topOffset}px, ${offsetHeaderWithUnits}) + ${bottomOffset}px - ${overflowScroll}px))`
}

setHeight(calculatedHeight)
}, [contentTopEntry, contentBottomEntry, stickyTop])
}, [contentTopEntry, contentBottomEntry, offsetHeader])

// We only want to add scroll and resize listeners if the pane is sticky.
// Since hooks can't be called conditionally, we need to use state to track
Expand Down Expand Up @@ -92,7 +93,7 @@ export function useStickyPaneHeight() {

function enableStickyPane(top: string | number) {
setIsEnabled(true)
setStickyTop(top)
setOffsetHeader(top)
}

function disableStickyPane() {
Expand Down