forked from TanStack/query
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(core): unify focusManager and onlineManager
into an eventManager, which is function based
- Loading branch information
Showing
5 changed files
with
140 additions
and
152 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { isServer } from './utils' | ||
|
||
type ListenerFn = () => void | ||
|
||
export function createEventManager( | ||
events: ReadonlyArray<Parameters<typeof window['addEventListener']>[0]> | ||
) { | ||
let value: boolean | undefined | ||
let removeEventListener: ListenerFn | undefined | ||
let listeners: ListenerFn[] = [] | ||
let setupFn: ( | ||
param: (newValue?: boolean) => void | ||
) => ListenerFn | undefined = onEvent => { | ||
if (!isServer && window?.addEventListener) { | ||
const listener = () => onEvent() | ||
events.forEach(eventName => { | ||
window.addEventListener(eventName, listener, false) | ||
}) | ||
|
||
return () => { | ||
events.forEach(eventName => { | ||
window.removeEventListener(eventName, listener) | ||
}) | ||
} | ||
} | ||
} | ||
|
||
const subscribe = (listener: ListenerFn): ListenerFn => { | ||
listeners.push(listener) | ||
|
||
if (!removeEventListener) { | ||
setEventListener(setupFn) | ||
} | ||
|
||
return () => { | ||
listeners = listeners.filter(x => x !== listener) | ||
if (listeners.length === 0) { | ||
removeEventListener?.() | ||
removeEventListener = undefined | ||
} | ||
} | ||
} | ||
|
||
const setValue = (newValue?: boolean): void => { | ||
value = newValue | ||
|
||
if (newValue) { | ||
onEvent() | ||
} | ||
} | ||
|
||
const setEventListener = ( | ||
setup: (param: (newValue?: boolean) => void) => ListenerFn | undefined | ||
): void => { | ||
removeEventListener?.() | ||
setupFn = setup | ||
removeEventListener = setupFn(newValue => { | ||
if (typeof newValue === 'boolean') { | ||
setValue(newValue) | ||
} else { | ||
onEvent() | ||
} | ||
}) | ||
} | ||
|
||
const onEvent = (): void => { | ||
listeners.forEach(listener => { | ||
listener() | ||
}) | ||
} | ||
|
||
return { | ||
setEventListener, | ||
subscribe, | ||
setValue, | ||
getValue: () => value, | ||
} as const | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,31 @@ | ||
import { Subscribable } from './subscribable' | ||
import { isServer } from './utils' | ||
|
||
class FocusManager extends Subscribable { | ||
private focused?: boolean | ||
private removeEventListener?: () => void | ||
|
||
protected onSubscribe(): void { | ||
if (!this.removeEventListener) { | ||
this.setDefaultEventListener() | ||
} | ||
} | ||
|
||
setEventListener( | ||
setup: (setFocused: (focused?: boolean) => void) => () => void | ||
): void { | ||
if (this.removeEventListener) { | ||
this.removeEventListener() | ||
} | ||
this.removeEventListener = setup(focused => { | ||
if (typeof focused === 'boolean') { | ||
this.setFocused(focused) | ||
} else { | ||
this.onFocus() | ||
import { createEventManager } from './eventManager' | ||
|
||
export const createFocusManager = () => { | ||
const { setEventListener, subscribe, ...manager } = createEventManager([ | ||
'visibilitychange', | ||
'focus', | ||
]) | ||
|
||
return { | ||
subscribe, | ||
setEventListener, | ||
setFocused: manager.setValue, | ||
isFocused: (): boolean => { | ||
const value = manager.getValue() | ||
if (typeof value === 'boolean') { | ||
return value | ||
} | ||
}) | ||
} | ||
|
||
setFocused(focused?: boolean): void { | ||
this.focused = focused | ||
|
||
if (focused) { | ||
this.onFocus() | ||
} | ||
} | ||
|
||
onFocus(): void { | ||
this.listeners.forEach(listener => { | ||
listener() | ||
}) | ||
} | ||
|
||
isFocused(): boolean { | ||
if (typeof this.focused === 'boolean') { | ||
return this.focused | ||
} | ||
|
||
// document global can be unavailable in react native | ||
if (typeof document === 'undefined') { | ||
return true | ||
} | ||
|
||
return [undefined, 'visible', 'prerender'].includes( | ||
document.visibilityState | ||
) | ||
} | ||
|
||
private setDefaultEventListener() { | ||
if (!isServer && window?.addEventListener) { | ||
this.setEventListener(onFocus => { | ||
const listener = () => onFocus() | ||
// Listen to visibillitychange and focus | ||
window.addEventListener('visibilitychange', listener, false) | ||
window.addEventListener('focus', listener, false) | ||
// document global can be unavailable in react native | ||
if (typeof document === 'undefined') { | ||
return true | ||
} | ||
|
||
return () => { | ||
// Be sure to unsubscribe if a new handler is set | ||
window.removeEventListener('visibilitychange', listener) | ||
window.removeEventListener('focus', listener) | ||
} | ||
}) | ||
} | ||
return [undefined, 'visible', 'prerender'].includes( | ||
document.visibilityState | ||
) | ||
}, | ||
} | ||
} | ||
|
||
export const focusManager = new FocusManager() | ||
export const focusManager = createFocusManager() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,31 @@ | ||
import { Subscribable } from './subscribable' | ||
import { isServer } from './utils' | ||
|
||
class OnlineManager extends Subscribable { | ||
private online?: boolean | ||
private removeEventListener?: () => void | ||
|
||
protected onSubscribe(): void { | ||
if (!this.removeEventListener) { | ||
this.setDefaultEventListener() | ||
} | ||
} | ||
|
||
setEventListener( | ||
setup: (setOnline: (online?: boolean) => void) => () => void | ||
): void { | ||
if (this.removeEventListener) { | ||
this.removeEventListener() | ||
} | ||
this.removeEventListener = setup((online?: boolean) => { | ||
if (typeof online === 'boolean') { | ||
this.setOnline(online) | ||
} else { | ||
this.onOnline() | ||
import { createEventManager } from './eventManager' | ||
|
||
export const createOnlineManager = () => { | ||
const { setEventListener, subscribe, ...manager } = createEventManager([ | ||
'online', | ||
'offline', | ||
]) | ||
|
||
return { | ||
subscribe, | ||
setEventListener, | ||
setOnline: manager.setValue, | ||
isOnline: (): boolean => { | ||
const value = manager.getValue() | ||
if (typeof value === 'boolean') { | ||
return value | ||
} | ||
}) | ||
} | ||
|
||
setOnline(online?: boolean): void { | ||
this.online = online | ||
|
||
if (online) { | ||
this.onOnline() | ||
} | ||
} | ||
|
||
onOnline(): void { | ||
this.listeners.forEach(listener => { | ||
listener() | ||
}) | ||
} | ||
|
||
isOnline(): boolean { | ||
if (typeof this.online === 'boolean') { | ||
return this.online | ||
} | ||
|
||
if ( | ||
typeof navigator === 'undefined' || | ||
typeof navigator.onLine === 'undefined' | ||
) { | ||
return true | ||
} | ||
|
||
return navigator.onLine | ||
} | ||
|
||
private setDefaultEventListener() { | ||
if (!isServer && window?.addEventListener) { | ||
this.setEventListener(onOnline => { | ||
const listener = () => onOnline() | ||
// Listen to online | ||
window.addEventListener('online', listener, false) | ||
window.addEventListener('offline', listener, false) | ||
if ( | ||
typeof navigator === 'undefined' || | ||
typeof navigator.onLine === 'undefined' | ||
) { | ||
return true | ||
} | ||
|
||
return () => { | ||
// Be sure to unsubscribe if a new handler is set | ||
window.removeEventListener('online', listener) | ||
window.removeEventListener('offline', listener) | ||
} | ||
}) | ||
} | ||
return navigator.onLine | ||
}, | ||
} | ||
} | ||
|
||
export const onlineManager = new OnlineManager() | ||
export const onlineManager = createOnlineManager() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters