-
Notifications
You must be signed in to change notification settings - Fork 3
/
useTimeZone.tsx
69 lines (59 loc) · 2.18 KB
/
useTimeZone.tsx
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
import * as React from "react";
import { useSyncExternalStore } from "use-sync-external-store/shim";
declare global {
interface WindowEventHandlersEventMap {
timezonechange: Event;
}
interface WindowEventHandlers {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ontimezonechange?: ((this: Window, ev: Event) => any) | null;
}
}
function subscribe(callback: () => void): () => void {
// @see https://github.com/whatwg/html/pull/3047
if ("ontimezonechange" in window) {
window.addEventListener("timezonechange", callback);
return () => {
window.removeEventListener("timezonechange", callback);
};
}
// If the "timezonechange" event is not supported, use "visibilitychange" as a proxy
document.addEventListener("visibilitychange", callback);
return () => document.removeEventListener("visibilitychange", callback);
}
function getSnapshot() {
return new Intl.DateTimeFormat().resolvedOptions().timeZone;
}
const SSRTimeZoneContext = React.createContext("Etc/UTC");
/**
* Custom hook which returns the current `timeZone`.
*
* Defaults to `"Etc/UTC"` during SSR and hydration, but this may be overriden with a provider
* `<TimeZoneProvider ssrTimeZone={timeZone}>`. Ensure that the value used during SSR and hydration is the same.
* @returns IANA tz database identifier
* @see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
*/
export default function useTimeZone() {
const ssrTimeZone = React.useContext(SSRTimeZoneContext);
const getServerSnapshot = React.useCallback(() => ssrTimeZone, [ssrTimeZone]);
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
}
export interface TimeZoneProviderProps {
children?: React.ReactNode;
/** IANA tz database identifier */
ssrTimeZone: string;
}
/**
* Context Provider for the `useTimeZone` hook. May be used to override the default `"Etc/UTC"` `timeZone` value during
* SSR and hydration.
* @param props.children
* @param props.ssrTimeZone IANA tz database identifier
*/
export const TimeZoneProvider = ({
children,
ssrTimeZone,
}: TimeZoneProviderProps) => (
<SSRTimeZoneContext.Provider value={ssrTimeZone}>
{children}
</SSRTimeZoneContext.Provider>
);