50 lines
1.8 KiB
JavaScript
50 lines
1.8 KiB
JavaScript
/**
|
|
* The React seams the components share: two subscriptions this plugin needs
|
|
* beyond the ones the slot owner already provides, plus the seat rule for
|
|
* translation.
|
|
*
|
|
* @module @dsh-plugin/session-notify/client/ui/hooks
|
|
*/
|
|
|
|
import * as React from 'react'
|
|
import { windowIsAway } from '../platform.js'
|
|
|
|
/** Subscribe to this plugin's own store from inside a component. */
|
|
export function useOwnStore(source) {
|
|
return React.useSyncExternalStore(source.subscribe, source.getSnapshot, source.getSnapshot)
|
|
}
|
|
|
|
/**
|
|
* Subscribe to every browser signal that says whether the app is visible:
|
|
* the window's focus events and the document's visibility change. The value
|
|
* itself is a boolean, so the observer re-renders once per transition.
|
|
*/
|
|
export function useWindowState() {
|
|
const subscribe = React.useCallback((listener) => {
|
|
try {
|
|
window.addEventListener('focus', listener)
|
|
window.addEventListener('blur', listener)
|
|
document.addEventListener('visibilitychange', listener)
|
|
} catch {
|
|
return () => {}
|
|
}
|
|
return () => {
|
|
window.removeEventListener('focus', listener)
|
|
window.removeEventListener('blur', listener)
|
|
document.removeEventListener('visibilitychange', listener)
|
|
}
|
|
}, [])
|
|
return React.useSyncExternalStore(subscribe, () => !windowIsAway(), () => true)
|
|
}
|
|
|
|
/**
|
|
* Every component translates through this: the slot's own seat when the owner
|
|
* supplies one, else this package's own translator.
|
|
* @param props - the slot entry's props, which carry the owner's `t` when it has one.
|
|
* @param fallback - the plugin's own translator, used when the seat has none.
|
|
* @returns the translate function this render should use.
|
|
*/
|
|
export function seatTranslator(props, fallback) {
|
|
return typeof props.t === 'function' ? props.t : fallback
|
|
}
|