Skip to content

Commit

Permalink
Adding toasts support with event emitter
Browse files Browse the repository at this point in the history
  • Loading branch information
fneves committed Nov 13, 2023
1 parent 6ef0617 commit 96395f0
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 5 deletions.
21 changes: 18 additions & 3 deletions src/components/Toast/Toast.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { ReactNode, createContext, useState } from "react";
import { ReactNode, createContext, useEffect, useState } from "react";
import * as RadixUIToast from "@radix-ui/react-toast";
import { Button, ButtonProps, Icon, IconButton, IconName } from "@/components";
import styled, { keyframes } from "styled-components";
import { toastsEventEmitter } from "./toastEmitter";

interface ToastContextProps {
export interface ToastContextProps {
createToast: (toast: ToastProps) => void;
}
export const ToastContext = createContext<ToastContextProps>({
createToast: () => null,
});

type ToastType = "danger" | "warning" | "default" | "success";
export type ToastType = "danger" | "warning" | "default" | "success";
export interface ToastProps {
id?: string;
type?: ToastType;
Expand Down Expand Up @@ -192,6 +193,20 @@ const Viewport = styled(RadixUIToast.Viewport)`
export const ToastProvider = ({ children, ...props }: RadixUIToast.ToastProps) => {
const [toasts, setToasts] = useState<Map<string, ToastProps>>(new Map());

useEffect(() => {
const listener = (toast: ToastProps) => {
setToasts(currentToasts => {
const newMap = new Map(currentToasts);
newMap.set(toast?.id ?? String(Date.now()), toast);
return newMap;
});
}

toastsEventEmitter.on(listener);

return () => toastsEventEmitter.off(listener);
}, []);

const onClose = (id: string) => (open: boolean) => {
if (!open) {
setToasts(currentToasts => {
Expand Down
8 changes: 8 additions & 0 deletions src/components/Toast/toastEmitter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { EventEmitter } from "@/lib/EventEmitter";
import type { ToastProps } from "..";

export const toastsEventEmitter = new EventEmitter<ToastProps>();

export const createToast = (toast: ToastProps): void => {
toastsEventEmitter.emit(toast);
};
5 changes: 3 additions & 2 deletions src/components/Toast/useToast.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useContext } from "react";
import { ToastContext } from "./Toast";
export const useToast = () => {
import { ToastContext, ToastContextProps } from "./Toast";

export const useToast = (): ToastContextProps => {
const result = useContext(ToastContext);
if (!result) {
throw new Error("Context used outside of its Provider!");
Expand Down
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,5 @@ export { Title } from "./Typography/Title/Title";
export { Tooltip } from "./Tooltip/Tooltip";
export { default as ClickUIProvider } from "./ClickUIProvider/ClickUIProvider";
export { useToast } from "./Toast/useToast";
export { createToast } from "./Toast/toastEmitter";
export { UserIcon as ProfileIcon } from "./icons/UserIcon";
31 changes: 31 additions & 0 deletions src/lib/EventEmitter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export interface Listener<T> {
(event: T): void;
}

export interface Disposable {
dispose: () => void;
}

/** passes through events as they happen. You will not get events from before you start listening */
export class EventEmitter<T> {
private listeners: Listener<T>[] = [];

on = (listener: Listener<T>): Disposable => {
this.listeners.push(listener);
return {
dispose: () => this.off(listener)
};
}

off = (listener: Listener<T>) => {
const callbackIndex = this.listeners.indexOf(listener);
if (callbackIndex > -1) {
this.listeners.splice(callbackIndex, 1);
}
}

emit = (event: T) => {
/** Update any general listeners */
this.listeners.forEach((listener: Listener<T>) => listener(event));
}
}

0 comments on commit 96395f0

Please sign in to comment.