import * as React from "react"; import { toastWrapper } from "./styles/Toast.styles"; import { colors } from "pebble-shared"; import { ToastProps, ToastState, ToastType, ToastPosition } from "./typings/Toast"; import { Transition, animated } from "react-spring/renderprops.cjs"; import { cx } from "emotion"; import mitt from "mitt"; import { animationConfig } from "../utils/animation"; const emitter = /*#__PURE__*/ mitt(); export const _colors = { success: colors.emerald.base, error: colors.red.base }; const toastTransitionsLeft = { from: { transform: "translateX(-10px)" }, enter: { transform: "translateX(0)" }, leave: { transform: "translateX(-10px)" } }; const toastTransitionsRight = { from: { transform: "translateX(10px)" }, enter: { transform: "translateX(0)" }, leave: { transform: "translateX(10px)" } }; const customStyles = { TOP: { style: { top: 20, left: "50%" }, transitions: { from: { transform: "translateX(-50%) translateY(-10px)" }, enter: { transform: "translateX(-50%) translateY(0)" }, leave: { transform: "translateX(-50%) translateY(-10px)" } } }, TOP_LEFT: { style: { top: 20, left: 20 }, transitions: toastTransitionsLeft }, TOP_RIGHT: { style: { top: 20, right: 20 }, transitions: toastTransitionsRight }, BOTTOM: { style: { bottom: 20, left: "50%" }, transitions: { from: { transform: "translateX(-50%) translateY(10px)" }, enter: { transform: "translateX(-50%) translateY(0)" }, leave: { transform: "translateX(-50%) translateY(10px)" } } }, BOTTOM_LEFT: { style: { bottom: 20, left: 20 }, transitions: toastTransitionsLeft }, BOTTOM_RIGHT: { style: { bottom: 20, right: 20 }, transitions: toastTransitionsRight } }; type EventType = Partial & { text: string; time?: number; position: ToastPosition; }; class Toast extends React.PureComponent { static show( text: string, type: ToastType, { time, position }: { time?: number; position?: ToastPosition } = {} ) { emitter.emit("showToast", { text, type, time, position }); } showTimer?: number | null; static hide() { emitter.emit("hideToast"); } state: ToastState = { text: "", type: "success", show: false, position: "BOTTOM" }; componentDidMount() { emitter.on("showToast", this.show); emitter.on("hideToast", this.hide); } componentWillUnmount() { emitter.off("showToast", this.show); emitter.off("hideToast", this.hide); } private show = ({ text, type = "success", position, time }: EventType) => { this.setState({ text, type, position, show: true }); if (this.showTimer) { clearTimeout(this.showTimer); this.showTimer = null; } this.showTimer = window.setTimeout( () => this.setState({ show: false }), time ? time : this.props.defaultTime || 5000 ); }; private hide = () => this.setState({ show: false }); render() { const bColor = _colors[this.state.type]; const iconClass = cx("pi", { "pi-radio-check-filled": this.state.type === "success", "pi-close-circle-filled": this.state.type === "error" }); const position = this.state.position || this.props.defaultPosition || "BOTTOM"; return ( {show => show && (styles => ( {this.state.text} )) } ); } } export default Toast;