File size: 2,608 Bytes
9b906ea | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | // Module-level store for the environment-switch overlay.
//
// This file is intentionally separate from `environment-switch-overlay.tsx`
// (which contains the React component and an inline SVG icon) so that the
// always-mounted sidebar can import `triggerEnvironmentSwitch` /
// `dismissEnvironmentSwitch` without dragging the overlay's render code
// into the eager graph. The overlay component is loaded lazily from
// `routes/root-layout.tsx`.
//
// The overlay state must survive the unmount of the component that triggers a
// switch — the user-context menu remounts (`menuResetCount` key flip in
// user-actions.tsx) the moment the dropdown's portaled option list is
// clicked, because that click registers as outside the menu's
// `useClickOutsideElement` ref. If state lived inside BackendSelector, the
// trigger would fire and immediately get torn down before React paints the
// overlay.
export const ENVIRONMENT_SWITCH_DURATION_MS = 980;
export const ENVIRONMENT_SWITCH_SETACTIVE_DELAY_MS = 400;
export interface EnvironmentSwitchSnapshot {
visible: boolean;
target: string;
}
let snapshot: EnvironmentSwitchSnapshot = { visible: false, target: "" };
const listeners = new Set<() => void>();
let hideTimeoutId: ReturnType<typeof setTimeout> | null = null;
function setSnapshot(next: EnvironmentSwitchSnapshot) {
snapshot = next;
if (typeof document !== "undefined") {
if (next.visible) {
document.body.setAttribute("data-environment-switching", "true");
} else {
document.body.removeAttribute("data-environment-switching");
}
}
listeners.forEach((listener) => listener());
}
export function triggerEnvironmentSwitch(target: string) {
setSnapshot({ visible: true, target });
if (hideTimeoutId) clearTimeout(hideTimeoutId);
hideTimeoutId = setTimeout(() => {
setSnapshot({ visible: false, target: "" });
hideTimeoutId = null;
}, ENVIRONMENT_SWITCH_DURATION_MS);
}
export function dismissEnvironmentSwitch() {
if (hideTimeoutId) {
clearTimeout(hideTimeoutId);
hideTimeoutId = null;
}
setSnapshot({ visible: false, target: "" });
}
export function subscribeEnvironmentSwitch(listener: () => void) {
listeners.add(listener);
return () => {
listeners.delete(listener);
};
}
export function getEnvironmentSwitchSnapshot() {
return snapshot;
}
/** Test-only: clear the pending hide timer and reset the snapshot. */
export function __resetEnvironmentSwitchOverlayForTests() {
if (hideTimeoutId) {
clearTimeout(hideTimeoutId);
hideTimeoutId = null;
}
setSnapshot({ visible: false, target: "" });
}
|