mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-26 14:35:22 +08:00
eb1cd17ab2
useAutoCompact cached normalWidthRef = el.scrollWidth on every non-compact resize, but per DOM spec scrollWidth === clientWidth when content fits. Maximizing the window (content no longer overflows) therefore wrote the container width into normalWidthRef, making it impossible to re-enter compact when the window was restored to its original size. Move the assignment inside the overflow branch so the cache is only written at the actual compact threshold, where scrollWidth reflects the real content width.
53 lines
1.9 KiB
TypeScript
53 lines
1.9 KiB
TypeScript
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);
|
|
const lockUntilRef = useRef(0);
|
|
|
|
useEffect(() => {
|
|
const el = containerRef.current;
|
|
if (!el) return;
|
|
|
|
const ro = new ResizeObserver(() => {
|
|
// During expand animation, ignore resize events to prevent flicker
|
|
if (Date.now() < lockUntilRef.current) return;
|
|
|
|
if (!compact) {
|
|
// Overflow detected → switch to compact
|
|
if (el.scrollWidth > el.clientWidth + 1) {
|
|
// Cache only at the overflow edge: when content fits,
|
|
// scrollWidth === clientWidth (DOM spec), so caching unconditionally
|
|
// would pollute normalWidthRef with the container width (e.g. after
|
|
// maximizing), making the expand threshold unreachable.
|
|
normalWidthRef.current = el.scrollWidth;
|
|
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) {
|
|
// Lock out resize events during the expand animation (200ms + 50ms margin)
|
|
lockUntilRef.current = Date.now() + 250;
|
|
setCompact(false);
|
|
}
|
|
}
|
|
});
|
|
ro.observe(el);
|
|
return () => ro.disconnect();
|
|
}, [compact]);
|
|
|
|
return compact;
|
|
}
|