web: fix mobile nav stuck-open on rejoin + paste-chip code fence
useViewport re-syncs the snapshot on pageshow/visibilitychange/resize/orientationchange — iOS reported a stale width on backgrounded-tab restore, leaving isMobile=false so the sidebar rendered as a permanent column with no close affordance. flattenToMessage now inserts pasted-text chips verbatim instead of wrapping them in a triple-backtick fence. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,13 +31,48 @@ export function useViewport(): ViewportSnapshot {
|
||||
if (typeof window === 'undefined') return;
|
||||
const mobileMq = window.matchMedia(`(max-width: ${MOBILE_MAX}px)`);
|
||||
const tabletMq = window.matchMedia(`(min-width: ${MOBILE_MAX + 1}px) and (max-width: ${TABLET_MAX}px)`);
|
||||
const update = () => setState(snapshot());
|
||||
const update = () =>
|
||||
setState((prev) => {
|
||||
const next = snapshot();
|
||||
// Bail if nothing changed — visualViewport 'resize' fires on every
|
||||
// URL-bar show/hide and scroll, and a fresh object would re-render
|
||||
// every consumer needlessly.
|
||||
if (
|
||||
prev.isMobile === next.isMobile &&
|
||||
prev.isTablet === next.isTablet &&
|
||||
prev.width === next.width
|
||||
) {
|
||||
return prev;
|
||||
}
|
||||
return next;
|
||||
});
|
||||
|
||||
// matchMedia 'change' alone is not enough on iOS Safari/Vivaldi: when a
|
||||
// backgrounded tab is restored (bfcache) or refocused, no 'change' fires,
|
||||
// and the width captured at first paint can be a stale/oversized value
|
||||
// (iOS reports the wrong innerWidth for a beat before layout settles). That
|
||||
// leaves isMobile=false on a phone, so the sidebar renders as a permanent
|
||||
// desktop column with no way to close it. Re-snapshot on every signal that
|
||||
// accompanies a rejoin/viewport correction, not just breakpoint crossings.
|
||||
const onVisibility = () => {
|
||||
if (document.visibilityState === 'visible') update();
|
||||
};
|
||||
mobileMq.addEventListener('change', update);
|
||||
tabletMq.addEventListener('change', update);
|
||||
window.addEventListener('resize', update);
|
||||
window.addEventListener('orientationchange', update);
|
||||
window.addEventListener('pageshow', update);
|
||||
document.addEventListener('visibilitychange', onVisibility);
|
||||
window.visualViewport?.addEventListener('resize', update);
|
||||
update();
|
||||
return () => {
|
||||
mobileMq.removeEventListener('change', update);
|
||||
tabletMq.removeEventListener('change', update);
|
||||
window.removeEventListener('resize', update);
|
||||
window.removeEventListener('orientationchange', update);
|
||||
window.removeEventListener('pageshow', update);
|
||||
document.removeEventListener('visibilitychange', onVisibility);
|
||||
window.visualViewport?.removeEventListener('resize', update);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user