Skip to content

Commit

Permalink
Add support for per toast position
Browse files Browse the repository at this point in the history
- Breaking: Remove visibleToasts
- Rename `margin` to `gutter`
  • Loading branch information
timolins committed Mar 21, 2021
1 parent 207bf66 commit 345aac0
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 20 deletions.
12 changes: 12 additions & 0 deletions site/components/sections/toast-example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = () => {
Expand Down
14 changes: 8 additions & 6 deletions site/pages/docs/use-toaster.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div onMouseEnter={startPause} onMouseLeave={endPause}>
{visibleToasts.map((toast) => (
<div key={toast.id} role={toast.role} aria-live={toast.ariaLive}>
{toast.message}
</div>
))}
{toasts
.filter((toast) => toast.visible)
.map((toast) => (
<div key={toast.id} role={toast.role} aria-live={toast.ariaLive}>
{toast.message}
</div>
))}
</div>
);
};
Expand Down
8 changes: 5 additions & 3 deletions src/components/toaster.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,12 @@ export const Toaster: React.FC<ToasterProps> = ({
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
Expand All @@ -96,7 +98,7 @@ export const Toaster: React.FC<ToasterProps> = ({
{renderToast ? (
renderToast(t)
) : (
<ToastBar toast={t} position={position} />
<ToastBar toast={t} position={toastPosition} />
)}
</div>
);
Expand Down
1 change: 1 addition & 0 deletions src/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export interface Toast {
icon?: Renderable;
duration?: number;
pauseDuration: number;
position?: ToastPosition;

role: 'status' | 'alert';
ariaLive: 'assertive' | 'off' | 'polite';
Expand Down
32 changes: 21 additions & 11 deletions src/core/use-toaster.ts
Original file line number Diff line number Diff line change
@@ -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) {
Expand Down Expand Up @@ -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,
};
};

0 comments on commit 345aac0

Please sign in to comment.