import React from 'react';
type VersionLimits = {
softLimit?: number;
hardLimit?: number;
};
type BrowserVersionOverrides = {
Chrome?: VersionLimits;
MobileChrome?: VersionLimits;
Edge?: VersionLimits;
Firefox?: VersionLimits;
MobileFirefox?: VersionLimits;
Safari?: VersionLimits;
MobileSafari?: VersionLimits;
Opera?: VersionLimits;
SamsungInternet?: VersionLimits;
Electron?: VersionLimits;
WebKit?: VersionLimits;
};
/**
*
* A wrapper that displays a callout message for partially supported browsers
*
* (below a soft limit) along with the site content. If the browser is an
*
* unsupported version (below a hard limit), it shows a full-page message to update
*
* the browser and does not display the site content. If the browser is in the list
*
* of unsupported browsers, it displays a full-page message that the browser is
*
* unsupported and does not display the site content.
*
* @example
*
* import BrowserSupport from "@bigbinary/neeto-molecules/BrowserSupport";
*
* const App = () => (
*
* {children}
*
*
* )
* @endexample
* This placement handles browsers that load the app but cannot render it properly.
*
* It cannot help when the browser is too old to parse the app chunk at all — see
*
* the next section, which is the placement most products actually want.
*
* Wrapping Main in cannot help when the browser is old enough
*
* that the app chunk fails to parse. mount() rejects on the dynamic import and
*
* React never renders, so the user gets a blank page rather than an explanation.
*
* For that case call renderBrowserSupportGate from the pack, before mount(),
*
* where only the entry chunk has had to parse. It returns true when the browser
*
* was blocked, meaning the app must not be mounted:
*
* @example
*
* import mount from "neetocommons/react-utils/mount";
* import { renderBrowserSupportGate } from "@bigbinary/neeto-molecules/v2/BrowserSupport";
*
* const initializeAndMount = async () => {
* await initializeApplication();
*
* if (renderBrowserSupportGate()) return;
*
* mount(componentMap);
* };
* @endexample
* It renders into [data-react-class] by default, the same element mount()
*
* uses; pass element to override. When it blocks it also removes
*
* #neeto-page-loader, the loader rendered by shared/_page_loader in
*
* neeto-commons-backend, which sits outside the react root and would otherwise
*
* keep spinning over the message; pass loaderSelector if your product renders a
*
* different one. overrides and unsupportedBrowsers behave as they do on the
*
* component, and products should not normally need either — the defaults are the
*
* floor the shared stack imposes, so a product that overrides them is opting out
*
* of the guarantee rather than configuring it. Whatever the pack imports has to
*
* stay parseable on the browsers being guarded against, so keep the entry chunk
*
* free of syntax newer than the floor you are enforcing.
*
* The overrides prop changes the limits for a specific browser. The usual reason
*
* to reach for it is to open a partial band, where a browser below softLimit but
*
* at or above hardLimit gets a callout and still sees the page:
*
* @example
*
*
* @endexample
* Here Chrome 111 to 119 and Safari 16.4 to 16.6 get the callout along with the
*
* page contents. Chrome below 111 and Safari below 16.4 get the full-page message
*
* and no content. Every version of Samsung Internet is blocked outright.
*
* Lowering hardLimit below the defaults is possible but rarely a good idea. The
*
* defaults are the point at which the generated CSS stops applying, so lowering
*
* them serves a visibly broken page instead of a message explaining why.
*
* The default minimum versions are set by Tailwind v4, which hardcodes its
*
* Lightning CSS targets to Safari/iOS 16.4, Chrome 111 and Firefox 128 and exposes
*
* no option to lower them. Below that floor the generated CSS (@property,
*
* oklch(), :has(), @container) is dropped by the parser without an error, so
*
* the app renders broken rather than degraded. The remaining engines are pinned to
*
* the first release built on an equivalent core.
*
* | Browser name | Min supported version |
*
* | :-------------- | :-------------------- |
*
* | Chrome | 111 |
*
* | MobileChrome | 111 |
*
* | Edge | 111 |
*
* | Firefox | 128 |
*
* | MobileFirefox | 128 |
*
* | Safari | 16.4 |
*
* | MobileSafari | 16.4 |
*
* | Opera | 98 |
*
* | SamsungInternet | 22 |
*
* | Electron | 24 |
*
* | WebKit | 605 |
*
* softLimit and hardLimit are equal by default, so a browser below the floor
*
* gets the full-page message rather than a callout. There is no meaningful
*
* "degraded but usable" band below it — the CSS either applies or it does not. Set
*
* an explicit overrides entry if a product wants a partial band.
*
* Safari freezes the WebKit build number in its user agent (605.1.15 since
*
* Safari 12), so the WebKit entry cannot discriminate versions. It exists only
*
* to keep generic WebKit clients out of the unknown-browser branch.
*
* The default unsupported browsers are given below. These cannot reach the floor
*
* at any released version, and are blocked before overrides are consulted:
*
* Any other browser which is not in the above lists will be considered as unknown
*
* and a corresponding callout will be shown.
*
*/
declare const BrowserSupport: React.FC<{
overrides?: BrowserVersionOverrides;
unsupportedBrowsers?: string[];
children?: React.ReactNode | React.ReactNode[];
}>;
declare const renderBrowserSupportGate: (options?: {
overrides?: BrowserVersionOverrides;
unsupportedBrowsers?: string[];
element?: HTMLElement | null;
loaderSelector?: string;
}) => boolean;
export { BrowserSupport as default, renderBrowserSupportGate };