Files
webmail/lib/standalone-display.ts

40 lines
1.7 KiB
TypeScript

/**
* Installed-app (PWA) display modes and what they break.
*
* In an installed web app, window.open(url, "_blank") is handed to the system
* browser: a separate browsing context that cannot resolve the app's blob:
* URLs, so the new window opens blank or errors (#865). Callers that would
* open a blob: URL in a new window ask here first and show the file in-app
* instead.
*/
type StandaloneNavigator = Navigator & { standalone?: boolean };
const APP_DISPLAY_MODES = ["standalone", "fullscreen", "window-controls-overlay"] as const;
/** Whether the page runs as an installed app rather than in a browser tab. */
export function isStandaloneDisplayMode(): boolean {
if (typeof window === "undefined") return false;
// iOS Safari home-screen apps report navigator.standalone and (on older
// versions) no display-mode media feature at all.
if ((window.navigator as StandaloneNavigator).standalone === true) return true;
if (typeof window.matchMedia !== "function") return false;
return APP_DISPLAY_MODES.some((mode) => window.matchMedia(`(display-mode: ${mode})`).matches);
}
/** Whether a new window could load this URL. Only blob: URLs in an installed app cannot. */
export function canOpenUrlInNewWindow(url: string): boolean {
return !url.startsWith("blob:") || !isStandaloneDisplayMode();
}
/**
* Opens a preview URL in a new window when that window can load it. Returns
* false without opening anything when it cannot, so the caller shows the
* file in-app (or downloads it) instead of leaving the user a dead window.
*/
export function openPreviewInNewWindow(url: string): boolean {
if (!canOpenUrlInNewWindow(url)) return false;
window.open(url, "_blank", "noopener,noreferrer");
return true;
}