Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ import * as React_2 from 'react';
// @public (undocumented)
export const Toaster: React_2.FC;

// @public (undocumented)
export type ToastId = string;

// @public (undocumented)
export type ToastPosition = 'top-right' | 'top-center' | 'top-left' | 'bottom-right' | 'bottom-center' | 'bottom-left';

// @public (undocumented)
export function useToastController(): {
dispatchToast: (content: React_2.ReactNode, options?: ToastOptions | undefined) => void;
dismissToast: (toastId?: string | undefined) => void;
};

// (No @packageDocumentation comment for this package)
Expand Down
2 changes: 1 addition & 1 deletion packages/react-components/react-toast/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { Toaster } from './components/Toaster';

export { useToastController } from './state';
export type { ToastPosition } from './state';
export type { ToastPosition, ToastId } from './state';
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const EVENTS = {
show: 'fui-toast-show',
dismiss: 'fui-toast-dismiss',
} as const;
8 changes: 6 additions & 2 deletions packages/react-components/react-toast/src/state/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ export interface Toast extends Required<Omit<ToastOptions, 'toasterId'>> {
remove: () => void;
}

export interface DismissToastEventDetail {
toastId: ToastId | undefined;
}

export interface ToastEventMap {
[EVENTS.show]: CustomEvent<ToastOptions>;
[EVENTS.dismiss]: CustomEvent<DismissToastEventDetail>;
}

export type ToastEventListenerGeneric<K extends keyof ToastEventMap> = (e: ToastEventMap[K]) => void;
export type ToastShowEventListener = ToastEventListenerGeneric<typeof EVENTS.show>;
export type ToastEventListener = ToastShowEventListener;
export type ToastEventListener = <K extends keyof ToastEventMap>(e: ToastEventMap[K]) => void;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
import { dispatchToast as dispatchToastVanilla } from './vanilla/dispatchToast';
import { dispatchToast as dispatchToastVanilla, dismissToast as dismissToastVanilla } from './vanilla';
import * as React from 'react';
import { ToastOptions } from './types';
import { ToastId, ToastOptions } from './types';

export function useToastController() {
const { targetDocument } = useFluent();
Expand All @@ -15,7 +15,17 @@ export function useToastController() {
[targetDocument],
);

const dismissToast = React.useCallback(
(toastId?: ToastId) => {
if (targetDocument) {
dismissToastVanilla(toastId, targetDocument);
}
},
[targetDocument],
);

return {
dispatchToast,
dismissToast,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { EVENTS } from '../constants';
import { DismissToastEventDetail, ToastId } from '../types';

export function dismissToast(toastId: ToastId | undefined = undefined, targetDocument: Document) {
const event = new CustomEvent<DismissToastEventDetail>(EVENTS.dismiss, {
bubbles: false,
cancelable: false,
detail: { toastId },
});
targetDocument.dispatchEvent(event);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ let counter = 0;

export function dispatchToast(content: unknown, options: ToastOptions = {}, targetDocument: Document) {
options.toastId ??= (counter++).toString();
const event = new CustomEvent(EVENTS.show, { bubbles: false, cancelable: false, detail: { ...options, content } });
const event = new CustomEvent<ToastOptions>(EVENTS.show, {
bubbles: false,
cancelable: false,
detail: { ...options, content },
});
targetDocument.dispatchEvent(event);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './dispatchToast';
export * from './dismissToast';
export * from './toast';
export * from './toaster';
export * from './getPositionStyles';
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,20 @@ export class Toaster {

private _initEvents() {
const buildToast: ToastEventListener = e => this._buildToast(e.detail);
const dismissToast: ToastEventListener = e => {
const { toastId } = e.detail;
if (toastId) {
this._dismissToast(toastId);
} else {
this._dismissAllToasts();
}
};

this.listeners.set(EVENTS.show, buildToast);
this.listeners.set(EVENTS.dismiss, dismissToast);

this._addEventListener(EVENTS.show, buildToast);
this._addEventListener(EVENTS.dismiss, dismissToast);
}

private _addEventListener<TEvent extends keyof ToastEventMap>(
Expand All @@ -53,6 +63,16 @@ export class Toaster {
this.targetDocument.removeEventListener(eventType, callback as () => void);
}

private _dismissToast(toastId: ToastId) {
this.visibleToasts.delete(toastId);
this.onUpdate();
}

private _dismissAllToasts() {
this.visibleToasts.clear();
this.onUpdate();
}

private _buildToast(toastOptions: ToastOptions) {
const { toastId = '', position = 'bottom-right', timeout = 3000, content = '' } = toastOptions;
if (this.toasts.has(toastId)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as React from 'react';
import { Toaster, useToastController } from '@fluentui/react-toast';

export const DismissAll = () => {
const { dispatchToast, dismissToast } = useToastController();
const notify = () => dispatchToast('This is a toast');

return (
<>
<Toaster />
<button onClick={() => notify()}>Make toast</button>
<button onClick={() => dismissToast()}>Dismiss all</button>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as React from 'react';
import { Toaster, useToastController, ToastId } from '@fluentui/react-toast';

export const DismissToast = () => {
const { dispatchToast, dismissToast } = useToastController();
const notify = (id: ToastId) => dispatchToast('This is a toast', { toastId: id });

return (
<>
<Toaster />
<button onClick={() => notify('example')}>Make toast</button>
<button onClick={() => dismissToast('example')}>Dismiss all</button>
</>
);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export { Default } from './Default.stories';
export { CustomTimeout } from './CustomTimeout.stories';
export { ToastPositions } from './ToastPositions.stories';
export { DismissToast } from './DismissToast.stories';
export { DismissAll } from './DismissAll.stories';

export default {
title: 'Preview Components/Toast',
Expand Down