From 8fb1b4be4d5d05e78af908b98a93938e10a6916d Mon Sep 17 00:00:00 2001 From: Patrick Lafrance Date: Tue, 5 Dec 2023 14:07:14 -0500 Subject: [PATCH] fix: Use the event bus for toast instead of a context (#126) * Use the event bus for toast instead of a context * Added a dedicated toast listener function --- .../basic/local-module/src/MessagePage.tsx | 4 +-- samples/basic/shared/src/ToastContext.ts | 17 ----------- samples/basic/shared/src/eventBus.ts | 2 +- samples/basic/shared/src/index.ts | 2 +- samples/basic/shared/src/useToast.ts | 14 +++++++++ samples/basic/shell/src/AppRouter.tsx | 16 ++++++++-- samples/basic/shell/src/toast.tsx | 29 ++++++++++++------- 7 files changed, 50 insertions(+), 34 deletions(-) delete mode 100644 samples/basic/shared/src/ToastContext.ts create mode 100644 samples/basic/shared/src/useToast.ts diff --git a/samples/basic/local-module/src/MessagePage.tsx b/samples/basic/local-module/src/MessagePage.tsx index dc62d3bb7..242267342 100644 --- a/samples/basic/local-module/src/MessagePage.tsx +++ b/samples/basic/local-module/src/MessagePage.tsx @@ -1,4 +1,4 @@ -import { useApplicationEventBusDispatcher, useShowToast } from "@basic/shared"; +import { useApplicationEventBusDispatcher, useToast } from "@basic/shared"; import { useCallback, useState, type ChangeEvent } from "react"; import { Link } from "react-router-dom"; @@ -10,7 +10,7 @@ export function MessagePage() { }, []); const dispatch = useApplicationEventBusDispatcher(); - const showToast = useShowToast(); + const showToast = useToast(); const handleSendMessage = useCallback(() => { dispatch("write-to-host", message); diff --git a/samples/basic/shared/src/ToastContext.ts b/samples/basic/shared/src/ToastContext.ts deleted file mode 100644 index 5f4edfb1e..000000000 --- a/samples/basic/shared/src/ToastContext.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { createContext, useContext } from "react"; - -export interface ToastContextType { - showToast: (text: string) => void; -} - -export const ToastContext = createContext(undefined); - -export function useShowToast() { - const context = useContext(ToastContext); - - if (!context) { - throw new Error("Cannot retrieve a ToastContext. Did you forget to define a ToastProvider?"); - } - - return context.showToast; -} diff --git a/samples/basic/shared/src/eventBus.ts b/samples/basic/shared/src/eventBus.ts index 62b3f0682..c38df98c5 100644 --- a/samples/basic/shared/src/eventBus.ts +++ b/samples/basic/shared/src/eventBus.ts @@ -1,6 +1,6 @@ import { useEventBusDispatcher, useEventBusListener } from "@squide/firefly"; -export type MessageTypes = "write-to-host"; +export type MessageTypes = "write-to-host" | "show-toast"; export const useApplicationEventBusDispatcher = useEventBusDispatcher; export const useApplicationEventBusListener = useEventBusListener; diff --git a/samples/basic/shared/src/index.ts b/samples/basic/shared/src/index.ts index bd845906c..bd6c58ed2 100644 --- a/samples/basic/shared/src/index.ts +++ b/samples/basic/shared/src/index.ts @@ -1,8 +1,8 @@ export * from "./BackgroundColorContext.ts"; -export * from "./ToastContext.ts"; export * from "./appContext.ts"; export * from "./eventBus.ts"; export * from "./isNetlify.ts"; export * from "./layouts/registerLayouts.tsx"; export * from "./session.ts"; +export * from "./useToast.ts"; diff --git a/samples/basic/shared/src/useToast.ts b/samples/basic/shared/src/useToast.ts new file mode 100644 index 000000000..cfe3fd5f3 --- /dev/null +++ b/samples/basic/shared/src/useToast.ts @@ -0,0 +1,14 @@ +import { useCallback } from "react"; +import { useApplicationEventBusDispatcher, useApplicationEventBusListener } from "./eventBus.ts"; + +export function useToast() { + const dispatch = useApplicationEventBusDispatcher(); + + return useCallback((message: string) => { + dispatch("show-toast", message); + }, [dispatch]); +} + +export function useToastListener(callback: (message: string) => void) { + useApplicationEventBusListener("show-toast", callback as (message: unknown) => void); +} diff --git a/samples/basic/shell/src/AppRouter.tsx b/samples/basic/shell/src/AppRouter.tsx index 0aa6e1f3c..08b2f5fc3 100644 --- a/samples/basic/shell/src/AppRouter.tsx +++ b/samples/basic/shell/src/AppRouter.tsx @@ -1,6 +1,8 @@ +import { useToastListener } from "@basic/shared"; import { AppRouter as FireflyAppRouter } from "@squide/firefly"; +import { useCallback } from "react"; import { AppRouterErrorBoundary } from "./AppRouterErrorBoundary.tsx"; -import { ToastProvider } from "./toast.tsx"; +import { ToastContainer, useToastContainer } from "./toast.tsx"; function Loading() { return ( @@ -9,13 +11,21 @@ function Loading() { } export function AppRouter() { + const { toastState, addToast } = useToastContainer(); + + const handleShowToast = useCallback((message: string) => { + addToast(message); + }, [addToast]); + + useToastListener(handleShowToast); + return ( - + } errorElement={} waitForMsw={false} /> - + ); } diff --git a/samples/basic/shell/src/toast.tsx b/samples/basic/shell/src/toast.tsx index 14e3143ed..1ea966a9b 100644 --- a/samples/basic/shell/src/toast.tsx +++ b/samples/basic/shell/src/toast.tsx @@ -1,4 +1,3 @@ -import { ToastContext } from "@basic/shared"; import type { AriaToastProps, AriaToastRegionProps } from "@react-aria/toast"; import { useToast, useToastRegion } from "@react-aria/toast"; import { useToastState, type ToastState, type ToastStateProps } from "@react-stately/toast"; @@ -50,26 +49,36 @@ export function ToastRegion({ state, ...props }: ToastRegio ); } -export interface ToastProviderProps extends ToastStateProps { - children: ReactNode; -} +export type UseToastContainerProps = ToastStateProps; -export function ToastProvider({ children, ...props }: ToastProviderProps) { +export function useToastContainer(props: UseToastContainerProps = {}) { const state = useToastState({ maxVisibleToasts: 5, ...props }); - const showToast = useCallback((text: string) => { - state.add(text, { timeout: 5000 }); + const addToast = useCallback((message: string) => { + state.add(message, { timeout: 5000 }); }, [state]); + return { + toastState: state, + addToast + }; +} + +export interface ToastContainerProps extends AriaToastRegionProps { + children: ReactNode; + state: ToastState; +} + +export function ToastContainer({ children, state, ...props }: ToastContainerProps) { return ( - + <> {children} {state.visibleToasts.length > 0 && ( - + )} - + ); }