Skip to content
Draft
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
5 changes: 5 additions & 0 deletions .changeset/swift-forks-sneeze.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': patch
---

PageLayout: Move pane and sidebar viewport clamping to CSS so window resize stays smooth and JS sync runs only after resizing ends
37 changes: 31 additions & 6 deletions packages/react/src/PageLayout/PageLayout.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,23 @@
--pane-width-small: 100%;
--pane-width-medium: 100%;
--pane-width-large: 100%;
--page-layout-viewport-width: 100vw;
/* NOTE: This value is exported via :export for use in usePaneWidth.ts */
--pane-max-width-diff: 511px;
/* Sidebar uses a smaller diff since it doesn't need to reserve space for a file tree pane */
--sidebar-max-width-diff: 256px;
--pane-viewport-max: max(
var(--pane-min-width, 0px),
calc(var(--page-layout-viewport-width) - var(--pane-max-width-diff))
);
--sidebar-viewport-max: max(
var(--pane-min-width, 0px),
calc(var(--page-layout-viewport-width) - var(--sidebar-max-width-diff))
);

@supports (width: 100dvw) {
--page-layout-viewport-width: 100dvw;
}

@media screen and (min-width: 768px) {
--pane-width-small: 240px;
Expand Down Expand Up @@ -602,11 +615,13 @@
width: 100%;

@media screen and (min-width: 768px) {
/*
* --pane-max-width is set by JS on mount and updated on resize (debounced).
* JS calculates viewport - margin to avoid scrollbar discrepancy with 100vw.
*/
width: clamp(var(--pane-min-width), var(--pane-width), var(--pane-max-width));
width: clamp(var(--pane-min-width), var(--pane-width), min(var(--pane-max-width), var(--pane-viewport-max)));
}

&:where([data-constrain-to-viewport='false']) {
@media screen and (min-width: 768px) {
width: clamp(var(--pane-min-width), var(--pane-width), var(--pane-max-width));
}
}
}
}
Expand Down Expand Up @@ -846,7 +861,17 @@
width: 100%;

@media screen and (min-width: 768px) {
width: clamp(var(--pane-min-width), var(--pane-width), var(--pane-max-width));
width: clamp(
var(--pane-min-width),
var(--pane-width),
min(var(--pane-max-width), var(--sidebar-viewport-max))
);
}

&:where([data-constrain-to-viewport='false']) {
@media screen and (min-width: 768px) {
width: clamp(var(--pane-min-width), var(--pane-width), var(--pane-max-width));
}
}
}

Expand Down
8 changes: 4 additions & 4 deletions packages/react/src/PageLayout/PageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -897,11 +897,12 @@ const Pane = React.forwardRef<HTMLDivElement, React.PropsWithChildren<PageLayout
{...(id && {id: paneId})}
className={classes.Pane}
data-resizable={resizable || undefined}
data-constrain-to-viewport={isCustomWidthOptions(width) ? 'false' : undefined}
style={
{
'--spacing': `var(--spacing-${padding})`,
'--pane-min-width': isCustomWidthOptions(width) ? width.min : `${minWidth}px`,
'--pane-max-width': isCustomWidthOptions(width) ? width.max : `calc(100vw - var(--pane-max-width-diff))`,
'--pane-max-width': isCustomWidthOptions(width) ? width.max : 'var(--page-layout-viewport-width)',
'--pane-width-custom': isCustomWidthOptions(width) ? width.default : undefined,
'--pane-width-size': `var(--pane-width-${isPaneWidth(width) ? width : 'custom'})`,
'--pane-width': `${currentWidth}px`,
Expand Down Expand Up @@ -1201,13 +1202,12 @@ const Sidebar = React.forwardRef<HTMLDivElement, React.PropsWithChildren<PageLay
{...(id && {id: sidebarId})}
className={classes.Sidebar}
data-resizable={resizable || undefined}
data-constrain-to-viewport={isCustomWidthOptions(width) ? 'true' : undefined}
style={
{
'--spacing': `var(--spacing-${padding})`,
'--pane-min-width': isCustomWidthOptions(width) ? width.min : `${minWidth}px`,
'--pane-max-width': isCustomWidthOptions(width)
? width.max
: `calc(100vw - var(--sidebar-max-width-diff))`,
'--pane-max-width': isCustomWidthOptions(width) ? width.max : 'var(--page-layout-viewport-width)',
'--pane-width-custom': isCustomWidthOptions(width) ? width.default : undefined,
'--pane-width-size': `var(--pane-width-${isPaneWidth(width) ? width : 'custom'})`,
'--pane-width': `${currentWidth}px`,
Expand Down
Loading
Loading