Skip to content

Commit 5dcc87c

Browse files
mattcosta7Copilot
andauthored
Improve PageLayout pane drag performance with pointer capture and GPU-accelerated transforms (#7307)
Co-authored-by: Copilot <[email protected]>
1 parent 3f4462f commit 5dcc87c

File tree

8 files changed

+2058
-224
lines changed

8 files changed

+2058
-224
lines changed

.changeset/shiny-buckets-study.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/react': patch
3+
---
4+
5+
reapplies PageLayout resizable enhancements without INP drop from expensive selectors

e2e/components/Axe.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ const SKIPPED_TESTS = [
1414
'components-flash-features--with-icon-action-dismiss', // TODO: Remove once color-contrast issues have been resolved
1515
'components-flash-features--with-icon-and-action', // TODO: Remove once color-contrast issues have been resolved
1616
'components-filteredactionlist--default',
17+
'components-pagelayout-performance-tests--medium-content',
18+
'components-pagelayout-performance-tests--heavy-content',
1719
]
1820

1921
type Component = {

packages/react/src/PageLayout/PageLayout.module.css

Lines changed: 74 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
/* Maintain resize cursor while dragging */
2-
/* stylelint-disable-next-line selector-no-qualifying-type */
3-
body[data-page-layout-dragging='true'] {
4-
cursor: col-resize;
5-
}
6-
7-
/* Disable text selection while dragging */
8-
/* stylelint-disable-next-line selector-no-qualifying-type */
9-
body[data-page-layout-dragging='true'] * {
10-
user-select: none;
1+
/* Exported values for JavaScript consumption */
2+
:export {
3+
/* Breakpoint where --pane-max-width-diff changes (used in usePaneWidth.ts) */
4+
paneMaxWidthDiffBreakpoint: 1280;
5+
/* Default value for --pane-max-width-diff below the breakpoint */
6+
paneMaxWidthDiffDefault: 511;
117
}
128

139
.PageLayoutRoot {
@@ -31,6 +27,7 @@ body[data-page-layout-dragging='true'] * {
3127
--pane-width-small: 100%;
3228
--pane-width-medium: 100%;
3329
--pane-width-large: 100%;
30+
/* NOTE: This value is exported via :export for use in usePaneWidth.ts */
3431
--pane-max-width-diff: 511px;
3532

3633
@media screen and (min-width: 768px) {
@@ -45,6 +42,7 @@ body[data-page-layout-dragging='true'] * {
4542
--pane-width-large: 320px;
4643
}
4744

45+
/* NOTE: This breakpoint value is exported via :export for use in usePaneWidth.ts */
4846
@media screen and (min-width: 1280px) {
4947
--pane-max-width-diff: 959px;
5048
}
@@ -383,6 +381,26 @@ body[data-page-layout-dragging='true'] * {
383381
}
384382
}
385383

384+
/**
385+
* OPTIMIZATION: Aggressive containment during drag for ContentWrapper
386+
* data-dragging is set on PageLayoutContent by JavaScript
387+
* This avoids expensive :has() selectors
388+
*/
389+
.PageLayoutContent[data-dragging='true'] .ContentWrapper {
390+
/* Add paint containment during drag - safe since user can't interact */
391+
contain: layout style paint;
392+
393+
/* Disable interactions */
394+
pointer-events: none;
395+
396+
/* Disable transitions to prevent expensive recalculations */
397+
transition: none;
398+
399+
/* Force compositor layer for hardware acceleration */
400+
will-change: width;
401+
transform: translateZ(0);
402+
}
403+
386404
.Content {
387405
width: 100%;
388406

@@ -409,6 +427,16 @@ body[data-page-layout-dragging='true'] * {
409427
}
410428
}
411429

430+
/**
431+
* OPTIMIZATION: Freeze content layout during resize drag
432+
* This prevents expensive recalculations of large content areas
433+
* while keeping content visible (just frozen in place)
434+
*/
435+
.PageLayoutContent[data-dragging='true'] .Content {
436+
/* Full containment (without size) - isolate from layout recalculations */
437+
contain: layout style paint;
438+
}
439+
412440
.PaneWrapper {
413441
display: flex;
414442
width: 100%;
@@ -593,11 +621,36 @@ body[data-page-layout-dragging='true'] * {
593621
width: 100%;
594622

595623
@media screen and (min-width: 768px) {
624+
/*
625+
* --pane-max-width is set by JS on mount and updated on resize (debounced).
626+
* JS calculates viewport - margin to avoid scrollbar discrepancy with 100vw.
627+
*/
596628
width: clamp(var(--pane-min-width), var(--pane-width), var(--pane-max-width));
597629
}
598630
}
599631
}
600632

633+
/**
634+
* OPTIMIZATION: Performance enhancements for Pane during drag
635+
* data-dragging is set on PageLayoutContent by JavaScript
636+
* This avoids expensive :has() selectors
637+
*/
638+
.PageLayoutContent[data-dragging='true'] .Pane {
639+
/* Full containment - isolate from layout recalculations */
640+
contain: layout style paint;
641+
642+
/* Disable interactions during drag */
643+
pointer-events: none;
644+
645+
/* Disable transitions during drag */
646+
transition: none;
647+
648+
/* Force hardware acceleration */
649+
will-change: width, transform;
650+
transform: translateZ(0);
651+
backface-visibility: hidden;
652+
}
653+
601654
.PaneHorizontalDivider {
602655
&:where([data-position='start']) {
603656
/* stylelint-disable-next-line primer/spacing */
@@ -696,12 +749,22 @@ body[data-page-layout-dragging='true'] * {
696749
padding: var(--spacing);
697750
}
698751

752+
/**
753+
* DraggableHandle - Interactive resize handle
754+
*/
699755
.DraggableHandle {
700756
position: absolute;
701757
inset: 0 -2px;
702758
cursor: col-resize;
703759
background-color: transparent;
704760
transition-delay: 0.1s;
761+
762+
/**
763+
* OPTIMIZATION: Prevent touch scrolling and text selection during drag
764+
* This is done in CSS because it needs to be set before any pointer events
765+
*/
766+
touch-action: none;
767+
user-select: none;
705768
}
706769

707770
.DraggableHandle:hover {
@@ -710,6 +773,7 @@ body[data-page-layout-dragging='true'] * {
710773

711774
.DraggableHandle[data-dragging='true'] {
712775
background-color: var(--bgColor-accent-emphasis);
776+
cursor: col-resize;
713777
}
714778

715779
.DraggableHandle[data-dragging='true']:hover {

0 commit comments

Comments
 (0)