diff --git a/packages/react-components/react-toast/etc/react-toast.api.md b/packages/react-components/react-toast/etc/react-toast.api.md index 5195dc9f64a1cf..dd505bcd7ea9ea 100644 --- a/packages/react-components/react-toast/etc/react-toast.api.md +++ b/packages/react-components/react-toast/etc/react-toast.api.md @@ -13,7 +13,10 @@ export const Toaster: React_2.FC; export type ToastId = string; // @public (undocumented) -export type ToastPosition = 'top-right' | 'top-center' | 'top-left' | 'bottom-right' | 'bottom-center' | 'bottom-left'; +export type ToastOffset = Partial> | ToastOffsetObject; + +// @public (undocumented) +export type ToastPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'; // @public (undocumented) export function useToastController(): { diff --git a/packages/react-components/react-toast/src/components/Toaster.tsx b/packages/react-components/react-toast/src/components/Toaster.tsx index 73891e4d25662d..76a17aba77300b 100644 --- a/packages/react-components/react-toast/src/components/Toaster.tsx +++ b/packages/react-components/react-toast/src/components/Toaster.tsx @@ -17,6 +17,7 @@ const useStyles = makeStyles({ export type ToasterProps = Partial; export const Toaster: React.FC = props => { + const { offset } = props; const { getToastsToRender, isToastVisible, toasterRef } = useToaster(props); const styles = useStyles(); @@ -26,7 +27,7 @@ export const Toaster: React.FC = props => {
{getToastsToRender((position, toasts) => { return ( -
+
{toasts.map(toastProps => { return ( diff --git a/packages/react-components/react-toast/src/index.ts b/packages/react-components/react-toast/src/index.ts index ac38826fe71822..6a260c497b646c 100644 --- a/packages/react-components/react-toast/src/index.ts +++ b/packages/react-components/react-toast/src/index.ts @@ -1,4 +1,4 @@ export { Toaster } from './components/Toaster'; export { useToastController } from './state'; -export type { ToastPosition, ToastId } from './state'; +export type { ToastPosition, ToastId, ToastOffset } from './state'; diff --git a/packages/react-components/react-toast/src/state/types.ts b/packages/react-components/react-toast/src/state/types.ts index 7966d6011303be..175e8ccd97ba2a 100644 --- a/packages/react-components/react-toast/src/state/types.ts +++ b/packages/react-components/react-toast/src/state/types.ts @@ -3,7 +3,7 @@ import { EVENTS } from './constants'; export type ToastId = string; export type ToasterId = string; -export type ToastPosition = 'top-right' | 'top-center' | 'top-left' | 'bottom-right' | 'bottom-center' | 'bottom-left'; +export type ToastPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'; export interface ToastOptions { toastId: ToastId; @@ -17,9 +17,16 @@ export interface ToastOptions { dispatchedAt: number; } +export interface ToastOffsetObject { + horizontal?: number; + vertical?: number; +} + +export type ToastOffset = Partial> | ToastOffsetObject; + export interface ToasterOptions extends Pick { - offset?: number[]; + offset?: ToastOffset; toasterId?: ToasterId; limit?: number; } diff --git a/packages/react-components/react-toast/src/state/vanilla/getPositionStyles.ts b/packages/react-components/react-toast/src/state/vanilla/getPositionStyles.ts index 96c06fc01bd466..8f162ed13d1ace 100644 --- a/packages/react-components/react-toast/src/state/vanilla/getPositionStyles.ts +++ b/packages/react-components/react-toast/src/state/vanilla/getPositionStyles.ts @@ -1,4 +1,4 @@ -import { ToastPosition } from '../types'; +import { ToastOffsetObject, ToastOffset, ToastPosition } from '../types'; interface PositionStyles { position: 'fixed'; @@ -8,37 +8,45 @@ interface PositionStyles { bottom?: number; } -export const getPositionStyles = (position: ToastPosition) => { +export const getPositionStyles = (position: ToastPosition, offset?: ToastOffset) => { const positionStyles: PositionStyles = { position: 'fixed', }; + const offsetStyles: ToastOffsetObject = offset ? (isShorthandOffset(offset) ? offset : offset[position] ?? {}) : {}; + + const { horizontal = 0, vertical = 0 } = offsetStyles; + switch (position) { case 'top-left': Object.assign(positionStyles, { - top: 0, - left: 0, + top: vertical, + left: horizontal, }); break; case 'top-right': Object.assign(positionStyles, { - top: 0, - right: 0, + top: vertical, + right: horizontal, }); break; case 'bottom-left': Object.assign(positionStyles, { - bottom: 0, - left: 0, + bottom: vertical, + left: horizontal, }); break; case 'bottom-right': Object.assign(positionStyles, { - bottom: 0, - right: 0, + bottom: vertical, + right: horizontal, }); break; } return positionStyles; }; + +function isShorthandOffset(offset: ToastOffset): offset is ToastOffsetObject { + return 'horizontal' in offset || 'vertical' in offset; +} diff --git a/packages/react-components/react-toast/stories/Toast/Offset.stories.tsx b/packages/react-components/react-toast/stories/Toast/Offset.stories.tsx new file mode 100644 index 00000000000000..7d8fa269ca9dc0 --- /dev/null +++ b/packages/react-components/react-toast/stories/Toast/Offset.stories.tsx @@ -0,0 +1,29 @@ +import * as React from 'react'; +import { ToastPosition, Toaster, useToastController } from '@fluentui/react-toast'; +import { useId } from '@fluentui/react-components'; + +export const Offset = () => { + const toasterId = useId('toaster'); + const { dispatchToast } = useToastController(); + const notify = (position: ToastPosition) => dispatchToast('This is a toast', { position, toasterId }); + const [horizontal, setHorizontal] = React.useState(10); + const [vertical, setVertical] = React.useState(10); + + return ( + <> + + + + + +
+ + setHorizontal(Number(e.target.value))} /> +
+
+ + setVertical(Number(e.target.value))} /> +
+ + ); +}; diff --git a/packages/react-components/react-toast/stories/Toast/index.stories.tsx b/packages/react-components/react-toast/stories/Toast/index.stories.tsx index 7e1b0cda0f8689..e24500eab61c7c 100644 --- a/packages/react-components/react-toast/stories/Toast/index.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/index.stories.tsx @@ -2,6 +2,7 @@ export { Default } from './Default.stories'; export { DefaultToastOptions } from './DefaultToastOptions.stories'; export { CustomTimeout } from './CustomTimeout.stories'; export { ToastPositions } from './ToastPositions.stories'; +export { Offset } from './Offset.stories'; export { DismissToast } from './DismissToast.stories'; export { DismissAll } from './DismissAll.stories'; export { PauseOnWindowBlur } from './PauseOnWindowBlur.stories';