feat(toolbar): auto-compact AppSwitcher based on available width

Replace hardcoded app count threshold with ResizeObserver-based
detection. Uses a two-layer layout (overflow-hidden outer + shrink-0
inner) to avoid the compact/normal oscillation problem.
This commit is contained in:
Jason
2026-02-21 20:24:49 +08:00
parent 2e676e5f53
commit ce92f37ef0
3 changed files with 288 additions and 235 deletions
+43
View File
@@ -0,0 +1,43 @@
import { useEffect, useRef, useState, type RefObject } from "react";
/**
* Detects whether the container's children overflow the available width
* and returns a `compact` flag for the AppSwitcher.
*
* Uses ResizeObserver on a flex-constrained container. The container
* must have `flex-1 min-w-0 overflow-hidden` so its width is determined
* by the parent layout, not its own content — avoiding the oscillation
* problem when toggling compact mode.
*/
export function useAutoCompact(
containerRef: RefObject<HTMLDivElement | null>,
): boolean {
const [compact, setCompact] = useState(false);
const normalWidthRef = useRef(0);
useEffect(() => {
const el = containerRef.current;
if (!el) return;
const ro = new ResizeObserver(() => {
if (!compact) {
// Cache the total content width in normal mode
normalWidthRef.current = el.scrollWidth;
// Overflow detected → switch to compact
if (el.scrollWidth > el.clientWidth + 1) {
setCompact(true);
}
} else if (normalWidthRef.current > 0) {
// In compact mode: only recover to normal if
// available space >= what normal mode needed
if (el.clientWidth >= normalWidthRef.current) {
setCompact(false);
}
}
});
ro.observe(el);
return () => ro.disconnect();
}, [compact]);
return compact;
}