diff --git a/site/components/sections/toast-example.tsx b/site/components/sections/toast-example.tsx index 4ac4478..a2ebb23 100644 --- a/site/components/sections/toast-example.tsx +++ b/site/components/sections/toast-example.tsx @@ -169,6 +169,18 @@ const examples: Array<{ }); }, }, + { + title: 'Custom Position', + emoji: '⬇️', + snippet: `toast.success('Always at the bottom.', { + position: "bottom-center" +})`, + action: () => { + toast.success('Always at the bottom.', { + position: 'bottom-center', + }); + }, + }, ]; export const ToastExample = () => { diff --git a/site/pages/docs/use-toaster.mdx b/site/pages/docs/use-toaster.mdx index 748da2b..0177feb 100644 --- a/site/pages/docs/use-toaster.mdx +++ b/site/pages/docs/use-toaster.mdx @@ -23,16 +23,18 @@ Headless mode is perfectly suited to add notifications to your React Native app. ```jsx const Notifications = () => { - const { visibleToasts, handlers } = useToaster(); + const { toasts, handlers } = useToaster(); const { startPause, endPause } = handlers; return (
- {visibleToasts.map((toast) => ( -
- {toast.message} -
- ))} + {toasts + .filter((toast) => toast.visible) + .map((toast) => ( +
+ {toast.message} +
+ ))}
); }; diff --git a/src/components/toaster.tsx b/src/components/toaster.tsx index 4861445..133fbcf 100644 --- a/src/components/toaster.tsx +++ b/src/components/toaster.tsx @@ -73,10 +73,12 @@ export const Toaster: React.FC = ({ onMouseLeave={handlers.endPause} > {toasts.map((t) => { - const offset = handlers.calculateOffset(t.id, { + const toastPosition = t.position || position; + const offset = handlers.calculateOffset(t, { reverseOrder, + defaultPosition: position, }); - const positionStyle = getPositionStyle(position, offset); + const positionStyle = getPositionStyle(toastPosition, offset); const ref = t.height ? undefined @@ -96,7 +98,7 @@ export const Toaster: React.FC = ({ {renderToast ? ( renderToast(t) ) : ( - + )} ); diff --git a/src/core/types.ts b/src/core/types.ts index e680861..16a1f5b 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -38,6 +38,7 @@ export interface Toast { icon?: Renderable; duration?: number; pauseDuration: number; + position?: ToastPosition; role: 'status' | 'alert'; ariaLive: 'assertive' | 'off' | 'polite'; diff --git a/src/core/use-toaster.ts b/src/core/use-toaster.ts index 736c638..73cf841 100644 --- a/src/core/use-toaster.ts +++ b/src/core/use-toaster.ts @@ -1,11 +1,10 @@ import { useEffect, useMemo } from 'react'; import { dispatch, ActionType, useStore } from './store'; import { toast } from './toast'; -import { DefaultToastOptions } from './types'; +import { DefaultToastOptions, Toast, ToastPosition } from './types'; export const useToaster = (toastOptions?: DefaultToastOptions) => { const { toasts, pausedAt } = useStore(toastOptions); - const visibleToasts = toasts.filter((t) => t.visible); useEffect(() => { if (pausedAt) { @@ -54,28 +53,39 @@ export const useToaster = (toastOptions?: DefaultToastOptions) => { toast: { id: toastId, height }, }), calculateOffset: ( - toastId: string, - opts?: { reverseOrder?: boolean; margin?: number } + toast: Toast, + opts?: { + reverseOrder?: boolean; + gutter?: number; + defaultPosition?: ToastPosition; + } ) => { - const { reverseOrder = false, margin = 8 } = opts || {}; - const toastIndex = toasts.findIndex((toast) => toast.id === toastId); - const toastsBefore = toasts.filter( + const { reverseOrder = false, gutter = 8, defaultPosition } = + opts || {}; + + const relevantToasts = toasts.filter( + (t) => + (t.position || defaultPosition) === + (toast.position || defaultPosition) + ); + const toastIndex = relevantToasts.findIndex((t) => t.id === toast.id); + const toastsBefore = relevantToasts.filter( (toast, i) => i < toastIndex && toast.visible ).length; - const offset = visibleToasts + const offset = relevantToasts + .filter((t) => t.visible) .slice(...(reverseOrder ? [toastsBefore + 1] : [0, toastsBefore])) - .reduce((acc, t) => acc + (t.height || 0) + margin, 0); + .reduce((acc, t) => acc + (t.height || 0) + gutter, 0); return offset; }, }), - [toasts, visibleToasts, pausedAt] + [toasts, pausedAt] ); return { toasts, - visibleToasts, handlers, }; };