authorgravatar for maria@kuuro.netmaria <maria@kuuro.net> 2026-10-09 22:51:37-03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-09 22:51:37-03:00
log033866c7aa55c53593ca31538f7d8ac99fdfe0fd
tree53db2f7a182b52d5b3da7b42c5794b6113112d21
parent42e1a0fba2938bd56761db63f466962342d7b779
signature Signed by PGP key B5690EEEBB952194

perf(web): sidebar drags restyle only the sidebar (#17659)


1 files changed, 23 insertions(+), 9 deletions(-)

apps/web/src/components/ui/sidebar.tsx+23-9
......@@ -369,9 +369,6 @@ function SidebarRail({
369369 const suppressClickRef = React.useRef(false);
370370 const resolvedResizable = sidebarInstance?.resizable ?? null;
371371 const latestResizable = React.useRef(resolvedResizable);
372 React.useLayoutEffect(() => {
373 latestResizable.current = resolvedResizable;
374 }, [resolvedResizable]);
375372 const canResize = resolvedResizable !== null && open;
376373 const railLabel = canResize ? "Resize Sidebar" : "Toggle Sidebar";
377374 const railTitle = canResize ? "Drag to resize sidebar" : "Toggle Sidebar";
......@@ -390,14 +387,22 @@ function SidebarRail({
390387 sidebarContainer.getBoundingClientRect().width,
391388 resolvedResizable,
392389 );
393 const transitionTargets = [
390 // Drag frames write width to the gap and container only. Changing the
391 // inherited --sidebar-width on the wrapper restyles the whole app, so it is
392 // written once when the drag commits.
393 const widthTargets = [
394394 sidebarRoot.querySelector<HTMLElement>("[data-slot='sidebar-gap']"),
395395 sidebarContainer,
396396 ].filter((element): element is HTMLElement => element !== null);
397 transitionTargets.forEach((element) => {
397 const setTargetWidth = (value: number) => {
398 widthTargets.forEach((element) => {
399 element.style.setProperty("width", `${value}px`);
400 });
401 };
402 widthTargets.forEach((element) => {
398403 element.style.setProperty("transition-duration", "0ms");
399404 });
400 wrapper.style.setProperty("--sidebar-width", `${width}px`);
405 setTargetWidth(width);
401406
402407 return {
403408 width,
......@@ -416,12 +421,13 @@ function SidebarRail({
416421 wrapper,
417422 }) ?? true;
418423 if (accepted) {
419 wrapper.style.setProperty("--sidebar-width", `${nextWidth}px`);
424 setTargetWidth(nextWidth);
420425 width = nextWidth;
421426 }
422427 return width;
423428 },
424429 finish(finalWidth, moved) {
430 wrapper.style.setProperty("--sidebar-width", `${finalWidth}px`);
425431 suppressClickRef.current = moved;
426432 const options = latestResizable.current;
427433 if (options?.storageKey) {
......@@ -434,12 +440,20 @@ function SidebarRail({
434440 options?.onResize?.(finalWidth);
435441 },
436442 cleanup() {
437 transitionTargets.forEach((element) => {
443 widthTargets.forEach((element) => {
444 element.style.removeProperty("width");
438445 element.style.removeProperty("transition-duration");
439446 });
440447 },
441448 };
442 });
449 // Toggling the sidebar cancels a drag so the inline width never pins a
450 // collapsed sidebar open.
451 }, String(open));
452 React.useLayoutEffect(() => {
453 latestResizable.current = resolvedResizable;
454 // Bounds follow the window; keep an active drag's inline width inside them.
455 resize.refresh();
456 }, [resolvedResizable]);
443457
444458 const handleClick = React.useCallback(
445459 (event: React.MouseEvent<HTMLButtonElement>) => {