UNPKG

react-native-toast-hybrid

Version:

A toast that can be used for react-native, while available for native android, ios.

172 lines (143 loc) 3.88 kB
import { useRef, useEffect } from 'react'; import { BackHandler } from 'react-native'; import ToastHybrid from './NativeToast'; export interface ToastConfig { backgroundColor?: string tintColor?: string fontSize?: number cornerRadius?: number duration?: number graceTime?: number minShowTime?: number loadingText?: string } let defaultDuration = 2000; export default class Toast { private static instances = new Set<Toast>(); static config(options: ToastConfig = {}) { defaultDuration = options.duration || defaultDuration; ToastHybrid.config(options); } static text(text: string, duration = defaultDuration) { new Toast().text(text, duration); } static info(text: string, duration = defaultDuration) { new Toast().info(text, duration); } static done(text: string, duration = defaultDuration) { new Toast().done(text, duration); } static error(text: string, duration = defaultDuration) { new Toast().error(text, duration); } static loading(text?: string) { return new Toast().loading(text); } static hideAll() { Array.from(Toast.instances).forEach(t => t.hide()); } private underlying: Promise<number> | null = null; constructor() { Toast.instances.add(this); } private ensure(): Promise<number> { if (this.underlying !== null) { return this.underlying; } const underlying = ToastHybrid.createToast(); return underlying; } private closed = false; private timer: number | null = null; loading(text?: string) { if (!this.closed) { this.clearTimeout(); this.underlying = this.ensure(); this.underlying.then(key => { this.clearTimeout(); ToastHybrid.loading(key, text); }); } return this; } private clearTimeout() { if (this.timer !== null) { clearTimeout(this.timer); this.timer = null; } } text(text: string, duration = defaultDuration) { return this.show(ToastHybrid.text, text, duration); } private show(fn: (key: number, text: string) => void, text: string, duration: number) { if (duration === 0) { if (this.underlying === null) { return this; } this.hide(); return this; } if (!this.closed) { this.clearTimeout(); this.underlying = this.ensure(); this.underlying.then(key => { if (!this.closed) { fn(key, text); this.clearTimeout(); this.timer = <any>setTimeout(() => this.hide(), duration); } else { this.hide(); } }); } return this; } info(text: string, duration = defaultDuration) { return this.show(ToastHybrid.info, text, duration); } done(text: string, duration = defaultDuration) { return this.show(ToastHybrid.done, text, duration); } error(text: string, duration = defaultDuration) { return this.show(ToastHybrid.error, text, duration); } hide() { Toast.instances.delete(this); this.clearTimeout(); if (this.underlying !== null) { this.underlying.then(key => { ToastHybrid.hide(key); }); this.underlying = null; } } private shutdown() { this.closed = true; this.hide(); } } export function useToast() { const toastRef = useRef(new Toast()); useEffect(() => { const toast = toastRef.current ;(toast as any).closed = false; return () => { (toast as any).shutdown(); }; }, []); useEffect(() => { function handleHardwareBack() { const toast = toastRef.current; if ((toast as any).underlying !== null) { toast.hide(); return true; } return false; } const subscription = BackHandler.addEventListener('hardwareBackPress', handleHardwareBack); return () => { subscription.remove(); }; }, []); return toastRef.current; }