Skip to content

Commit 61daffe

Browse files
committed
Fix diff sidebar flash on page load
1 parent 0d907a2 commit 61daffe

File tree

3 files changed

+33
-7
lines changed

3 files changed

+33
-7
lines changed

src/features/sidebar/view/SecondarySplitHeader.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,12 @@ const ToggleDiffButton = ({
123123
isDiffAvailable: boolean
124124
}) => {
125125
const [isMac, setIsMac] = useState(false)
126+
// Prevent flash of button during SSR/hydration. Only render after client mount.
127+
const [mounted, setMounted] = useState(false)
126128
useEffect(() => {
127129
// checkIsMac uses window so we delay the check.
128130
const timeout = window.setTimeout(() => {
131+
setMounted(true)
129132
setIsMac(checkIsMac())
130133
}, 0)
131134
return () => window.clearTimeout(timeout)
@@ -138,6 +141,7 @@ const ToggleDiffButton = ({
138141
: isDiffbarOpen
139142
? "Hide changes"
140143
: "Show changes"
144+
if (!mounted) return null
141145
return (
142146
<Box sx={{ display: isSidebarTogglable ? "block" : "none" }}>
143147

src/features/sidebar/view/internal/secondary/Container.tsx

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
"use client"
2+
3+
import { useState, useEffect } from "react"
14
import { SxProps } from "@mui/system"
25
import { Box, Stack } from "@mui/material"
36
import { styled } from "@mui/material/styles"
@@ -18,15 +21,23 @@ const SecondaryContainer = ({
1821
children?: React.ReactNode,
1922
isSM: boolean,
2023
}) => {
24+
// Disable transitions on initial render to prevent layout shift
25+
const [enableTransitions, setEnableTransitions] = useState(false)
26+
useEffect(() => {
27+
// Enable transitions after first paint
28+
const rafId = requestAnimationFrame(() => setEnableTransitions(true))
29+
return () => cancelAnimationFrame(rafId)
30+
}, [])
31+
2132
const sx = { overflow: "hidden" }
2233
return (
2334
<>
2435
<InnerSecondaryContainer
25-
2636
sidebarWidth={isSM ? sidebarWidth : 0}
2737
isSidebarOpen={isSM ? offsetContent: false}
2838
diffWidth={isSM ? (diffWidth || 0) : 0}
2939
isDiffOpen={isSM ? (offsetDiffContent || false) : false}
40+
enableTransitions={enableTransitions}
3041
sx={{ ...sx }}
3142
>
3243
{children}
@@ -43,19 +54,20 @@ interface WrapperStackProps {
4354
readonly isSidebarOpen: boolean
4455
readonly diffWidth: number
4556
readonly isDiffOpen: boolean
57+
readonly enableTransitions: boolean
4658
}
4759

4860
const WrapperStack = styled(Stack, {
49-
shouldForwardProp: (prop) => prop !== "isSidebarOpen" && prop !== "sidebarWidth" && prop !== "diffWidth" && prop !== "isDiffOpen"
50-
})<WrapperStackProps>(({ theme, sidebarWidth, isSidebarOpen, diffWidth, isDiffOpen }) => {
61+
shouldForwardProp: (prop) => prop !== "isSidebarOpen" && prop !== "sidebarWidth" && prop !== "diffWidth" && prop !== "isDiffOpen" && prop !== "enableTransitions"
62+
})<WrapperStackProps>(({ theme, sidebarWidth, isSidebarOpen, diffWidth, isDiffOpen, enableTransitions }) => {
5163
return {
52-
transition: theme.transitions.create(["margin", "width"], {
64+
transition: enableTransitions ? theme.transitions.create(["margin", "width"], {
5365
easing: theme.transitions.easing.sharp,
5466
duration: theme.transitions.duration.leavingScreen
55-
}),
67+
}) : "none",
5668
marginLeft: isSidebarOpen ? 0 : `-${sidebarWidth}px`,
5769
marginRight: isDiffOpen ? 0 : `-${diffWidth}px`,
58-
...((isSidebarOpen || isDiffOpen) && {
70+
...((isSidebarOpen || isDiffOpen) && enableTransitions && {
5971
transition: theme.transitions.create(["margin", "width"], {
6072
easing: theme.transitions.easing.easeOut,
6173
duration: theme.transitions.duration.enteringScreen,
@@ -69,13 +81,15 @@ const InnerSecondaryContainer = ({
6981
isSidebarOpen,
7082
diffWidth,
7183
isDiffOpen,
84+
enableTransitions,
7285
children,
7386
sx
7487
}: {
7588
sidebarWidth: number
7689
isSidebarOpen: boolean
7790
diffWidth: number
7891
isDiffOpen: boolean
92+
enableTransitions: boolean
7993
children: React.ReactNode
8094
sx?: SxProps
8195
}) => {
@@ -87,8 +101,9 @@ const InnerSecondaryContainer = ({
87101
isSidebarOpen={isSidebarOpen}
88102
diffWidth={diffWidth}
89103
isDiffOpen={isDiffOpen}
104+
enableTransitions={enableTransitions}
90105
sx={{ ...sx, width: "100%", overflowY: "auto" }}
91-
106+
92107
>
93108
<RaisedMainContent>
94109
{children}

src/features/sidebar/view/internal/tertiary/RightContainer.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use client'
22

3+
import { useState, useEffect } from "react"
34
import { SxProps } from "@mui/system"
45
import { Drawer as MuiDrawer } from "@mui/material"
56
import { useTheme } from "@mui/material/styles"
@@ -15,6 +16,12 @@ const RightContainer = ({
1516
onClose?: () => void
1617
children?: React.ReactNode
1718
}) => {
19+
// Don't render drawer until client-side to prevent flash
20+
const [mounted, setMounted] = useState(false)
21+
useEffect(() => {
22+
requestAnimationFrame(() => setMounted(true))
23+
}, [])
24+
if (!mounted) return null
1825
return (
1926
<>
2027
<InnerRightContainer

0 commit comments

Comments
 (0)