-
Notifications
You must be signed in to change notification settings - Fork 647
Removes a resize subscription and expensive :has selectors from pagelayout
#7302
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Removes a resize subscription and expensive :has selectors from pagelayout
#7302
Conversation
🦋 Changeset detectedLatest commit: 8c5edd0 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
👋 Hi, this pull request contains changes to the source code that github/github-ui depends on. If you are GitHub staff, test these changes with github/github-ui using the integration workflow. Or, apply the |
| handleRef={handleRef} | ||
| onDrag={(delta, isKeyboard = false) => { | ||
| const deltaWithDirection = isKeyboard ? delta : position === 'end' ? -delta : delta | ||
| const maxWidth = maxPaneWidthRef.current | ||
|
|
||
| if (isKeyboard) { | ||
| // Clamp keyboard delta to stay within bounds | ||
| const newWidth = Math.max(minPaneWidth, Math.min(maxWidth, currentWidthRef.current! + deltaWithDirection)) | ||
| if (newWidth !== currentWidthRef.current) { | ||
| currentWidthRef.current = newWidth | ||
| paneRef.current?.style.setProperty('--pane-width', `${newWidth}px`) | ||
| updateAriaValues(handleRef.current, {current: newWidth}) | ||
| } | ||
| } else { | ||
| // Apply delta directly via CSS variable for immediate visual feedback | ||
| if (paneRef.current) { | ||
| const newWidth = currentWidthRef.current! + deltaWithDirection | ||
| const clampedWidth = Math.max(minPaneWidth, Math.min(maxWidth, newWidth)) | ||
|
|
||
| // Only update if the clamped width actually changed | ||
| // This prevents drift when dragging against min/max constraints | ||
| if (clampedWidth !== currentWidthRef.current) { | ||
| paneRef.current.style.setProperty('--pane-width', `${clampedWidth}px`) | ||
| currentWidthRef.current = clampedWidth | ||
| updateAriaValues(handleRef.current, {current: clampedWidth}) | ||
| } | ||
| } | ||
| } | ||
| }} | ||
| // Save final width to localStorage (skip React state update to avoid reconciliation) | ||
| onDragEnd={() => { | ||
| // For mouse drag: The CSS variable is already set and currentWidthRef is in sync. | ||
| // We intentionally skip setPaneWidth() to avoid triggering expensive React | ||
| // reconciliation with large DOM trees. The ref is the source of truth for | ||
| // subsequent drag operations. | ||
| setWidthInLocalStorage(currentWidthRef.current!) | ||
| }} | ||
| position={positionProp} | ||
| // Reset pane width on double click | ||
| onDoubleClick={() => { | ||
| const defaultWidth = getDefaultPaneWidth(width) | ||
| // Update CSS variable and ref directly - skip React state to avoid reconciliation | ||
| if (paneRef.current) { | ||
| paneRef.current.style.setProperty('--pane-width', `${defaultWidth}px`) | ||
| currentWidthRef.current = defaultWidth | ||
| updateAriaValues(handleRef.current, {current: defaultWidth}) | ||
| } | ||
| setWidthInLocalStorage(defaultWidth) | ||
| }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved into the drag handle
| } | ||
| } | ||
| }) | ||
| viewportWidthObserver.observe(document.documentElement) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was causing observation on any change inside the body, not just page resizing
| * ARIA values are set in JSX for SSR accessibility, | ||
| * then updated via DOM manipulation during drag for performance | ||
| */ | ||
| const DragHandle: React.FC<DragHandleProps> = ({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pulls this out to a a child, and avoid passing through props to the divider
| } | ||
| // If pane is resizable, the divider should be draggable | ||
| draggable={resizable} | ||
| handleRef={handleRef} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moves the draghandle to a child - so we can keep VerticalDividerslimmer
| // ResizeObserver on document.documentElement fires on any content change (typing, etc), | ||
| // causing INP regressions. Window resize only fires on viewport changes. | ||
| // eslint-disable-next-line github/prefer-observers | ||
| window.addEventListener('resize', throttledUpdateMax) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
replaces the resize observer with a more granular raf
c7abafa to
70f8c48
Compare
|
👋 Hi from github/github-ui! Your integration PR is ready: https://github.com/github/github-ui/pull/8678 |
:has selectors from pagelayout
8b08d12
into
revert-7305-revert-7275-revert-7274-revert-7251-mc/copilot/sub-pr-7248
This pull request addresses a ResizeObserver performance regression in
@primer/react'sPageLayoutcomponent and introduces several optimizations and improvements. The main changes focus on improving drag performance by replacing expensive CSS selectors with a more efficient JavaScript-driven approach, updating the drag handle logic, and enhancing performance testing stories.Performance and architectural optimizations:
:has()CSS selectors with a JavaScript-manageddata-draggingattribute on.PageLayoutContent, improving drag performance by avoiding costly style recalculations. [1] [2] [3]ResizeObserversubscription logic for viewport width tracking, simplifying code and relying on more direct CSS variable reads for pane sizing.Accessibility and usability improvements:
aria-valuemin,aria-valuemax,aria-valuenow,aria-valuetext) to the drag handle for improved accessibility, updating them efficiently during drag operations. [1] [2] [3]ARROW_KEY_STEP), making adjustments easier and more consistent. [1] [2]Performance testing enhancements:
SearchInput(withAutocomplete), making the test scenarios more representative of real-world usage. [1] [2] [3] [4] [5] [6]Bug fixes:
ResizeObserverby simplifying how pane sizing and drag state are managed.Context and maintainability:
contentRefin thePageLayoutContextto allow coordinated updates and more maintainable code when managing drag state. [1] [2] [3] [4]These changes collectively result in smoother drag interactions, better accessibility, and more maintainable code in the
PageLayoutcomponent.Changelog
New
Changed
Removed
Rollout strategy
Testing & Reviewing
Merge checklist