use availableWidth instead of useContainerWidth for grid layout

The useContainerWidth hook from react-grid-layout v2 returns raw
container width without accounting for scrollbar width, causing the
grid to not fill the full available space. Use the existing
availableWidth value from useResizeObserver which already compensates
for scrollbar width, matching the working implementation.
This commit is contained in:
Josh Hawkins 2026-03-04 20:15:18 -06:00
parent 1c7f1095d8
commit b48647b967

View File

@ -16,8 +16,7 @@ import React, {
import { import {
Layout, Layout,
LayoutItem, LayoutItem,
Responsive, ResponsiveGridLayout as Responsive,
useContainerWidth,
} from "react-grid-layout"; } from "react-grid-layout";
import "react-grid-layout/css/styles.css"; import "react-grid-layout/css/styles.css";
import "react-resizable/css/styles.css"; import "react-resizable/css/styles.css";
@ -322,24 +321,6 @@ export default function DraggableGridLayout({
const gridContainerRef = useRef<HTMLDivElement>(null); const gridContainerRef = useRef<HTMLDivElement>(null);
const {
width: gridWidth,
containerRef: gridWidthRef,
mounted: gridMounted,
} = useContainerWidth();
// Combine gridContainerRef and gridWidthRef into a single callback ref
const combinedGridRef = useCallback(
(node: HTMLDivElement | null) => {
(
gridContainerRef as React.MutableRefObject<HTMLDivElement | null>
).current = node;
(gridWidthRef as React.MutableRefObject<HTMLDivElement | null>).current =
node;
},
[gridWidthRef],
);
const [{ width: containerWidth, height: containerHeight }] = const [{ width: containerWidth, height: containerHeight }] =
useResizeObserver(gridContainerRef); useResizeObserver(gridContainerRef);
@ -546,7 +527,7 @@ export default function DraggableGridLayout({
) : ( ) : (
<div <div
className="no-scrollbar my-2 select-none overflow-x-hidden px-2 pb-8" className="no-scrollbar my-2 select-none overflow-x-hidden px-2 pb-8"
ref={combinedGridRef} ref={gridContainerRef}
> >
<EditGroupDialog <EditGroupDialog
open={editGroup} open={editGroup}
@ -554,10 +535,9 @@ export default function DraggableGridLayout({
currentGroups={groups} currentGroups={groups}
activeGroup={group} activeGroup={group}
/> />
{gridMounted && (
<Responsive <Responsive
className="grid-layout" className="grid-layout"
width={gridWidth} width={availableWidth ?? window.innerWidth}
layouts={{ layouts={{
lg: currentGridLayout, lg: currentGridLayout,
md: currentGridLayout, md: currentGridLayout,
@ -608,12 +588,10 @@ export default function DraggableGridLayout({
grow = "aspect-video"; grow = "aspect-video";
} }
const availableStreams = camera.live.streams || {}; const availableStreams = camera.live.streams || {};
const firstStreamEntry = const firstStreamEntry = Object.values(availableStreams)[0] || "";
Object.values(availableStreams)[0] || "";
const streamNameFromSettings = const streamNameFromSettings =
currentGroupStreamingSettings?.[camera.name]?.streamName || currentGroupStreamingSettings?.[camera.name]?.streamName || "";
"";
const streamExists = const streamExists =
streamNameFromSettings && streamNameFromSettings &&
Object.values(availableStreams).includes( Object.values(availableStreams).includes(
@ -670,9 +648,7 @@ export default function DraggableGridLayout({
key={camera.name} key={camera.name}
streamName={streamName} streamName={streamName}
autoLive={autoLive ?? globalAutoLive} autoLive={autoLive ?? globalAutoLive}
showStillWithoutActivity={ showStillWithoutActivity={showStillWithoutActivity ?? true}
showStillWithoutActivity ?? true
}
alwaysShowCameraName={displayCameraNames} alwaysShowCameraName={displayCameraNames}
useWebGL={useWebGL} useWebGL={useWebGL}
cameraRef={cameraRef} cameraRef={cameraRef}
@ -687,9 +663,7 @@ export default function DraggableGridLayout({
windowVisible && visibleCameras.includes(camera.name) windowVisible && visibleCameras.includes(camera.name)
} }
cameraConfig={camera} cameraConfig={camera}
preferredLiveMode={ preferredLiveMode={preferredLiveModes[camera.name] ?? "mse"}
preferredLiveModes[camera.name] ?? "mse"
}
playInBackground={false} playInBackground={false}
showStats={statsStates[camera.name]} showStats={statsStates[camera.name]}
onClick={() => { onClick={() => {
@ -706,9 +680,7 @@ export default function DraggableGridLayout({
return newModes; return newModes;
}); });
}} }}
onResetLiveMode={() => onResetLiveMode={() => resetPreferredLiveMode(camera.name)}
resetPreferredLiveMode(camera.name)
}
playAudio={audioStates[camera.name]} playAudio={audioStates[camera.name]}
volume={volumeStates[camera.name]} volume={volumeStates[camera.name]}
/> />
@ -717,7 +689,6 @@ export default function DraggableGridLayout({
); );
})} })}
</Responsive> </Responsive>
)}
{isDesktop && ( {isDesktop && (
<div <div
className={cn( className={cn(