mirror of
https://github.com/Boof2015/astra-mobile.git
synced 2026-08-19 04:06:43 +02:00
52 lines
1.5 KiB
TypeScript
52 lines
1.5 KiB
TypeScript
import { useEffect, useReducer } from 'react';
|
|
|
|
export type DelayedPresenceEvent = 'show' | 'hide' | 'drop';
|
|
|
|
/**
|
|
* Tiny state machine shared by heavyweight render surfaces. `hide` is emitted
|
|
* only after the caller's linger timer, while `drop` releases the surface
|
|
* immediately (for example when Android backgrounds the activity).
|
|
*/
|
|
export function delayedPresenceReducer(
|
|
retained: boolean,
|
|
event: DelayedPresenceEvent
|
|
): boolean {
|
|
if (event === 'show') return true;
|
|
if (event === 'hide' || event === 'drop') return false;
|
|
return retained;
|
|
}
|
|
|
|
export function scheduleDelayedPresenceHide(delayMs: number, onHide: () => void) {
|
|
const timer = setTimeout(onHide, delayMs);
|
|
return () => clearTimeout(timer);
|
|
}
|
|
|
|
/**
|
|
* Keep a subtree mounted briefly after `active` turns false so its exit
|
|
* animation can finish, then release it. Re-activation cancels the pending
|
|
* release. `drop` bypasses the delay for background/low-visibility teardown.
|
|
*/
|
|
export function useDelayedUnmountPresence(
|
|
active: boolean,
|
|
delayMs: number,
|
|
drop = false
|
|
): boolean {
|
|
const [retained, dispatch] = useReducer(delayedPresenceReducer, active && !drop);
|
|
|
|
useEffect(() => {
|
|
if (drop) {
|
|
dispatch('drop');
|
|
return undefined;
|
|
}
|
|
if (active) {
|
|
dispatch('show');
|
|
return undefined;
|
|
}
|
|
if (!retained) return undefined;
|
|
|
|
return scheduleDelayedPresenceHide(delayMs, () => dispatch('hide'));
|
|
}, [active, delayMs, drop, retained]);
|
|
|
|
return !drop && (active || retained);
|
|
}
|