Skip to content
Draft
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
7 changes: 7 additions & 0 deletions change/@fluentui-react-toast-base-hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "feat: add useToastBase_unstable, useToastTitleBase_unstable, and useToastBodyBase_unstable hooks",
"packageName": "@fluentui/react-toast",
"email": "dmytrokirpa@microsoft.com",
"dependentChangeType": "patch"
}
10 changes: 9 additions & 1 deletion packages/react-components/react-toast/library/src/Toast.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
export type { ToastContextValues, ToastProps, ToastSlots, ToastState } from './components/Toast/index';
export type {
ToastBaseProps,
ToastBaseState,
ToastContextValues,
ToastProps,
ToastSlots,
ToastState,
} from './components/Toast/index';
export {
Toast,
renderToast_unstable,
toastClassNames,
useToastStyles_unstable,
useToastBase_unstable,
useToast_unstable,
} from './components/Toast/index';
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
export type { ToastBodyProps, ToastBodySlots, ToastBodyState } from './components/ToastBody/index';
export type {
ToastBodyBaseProps,
ToastBodyBaseState,
ToastBodyProps,
ToastBodySlots,
ToastBodyState,
} from './components/ToastBody/index';
export {
ToastBody,
renderToastBody_unstable,
toastBodyClassNames,
useToastBodyStyles_unstable,
useToastBodyBase_unstable,
useToastBody_unstable,
} from './components/ToastBody/index';
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
export type { ToastTitleProps, ToastTitleSlots, ToastTitleState } from './components/ToastTitle/index';
export type {
ToastTitleBaseProps,
ToastTitleBaseState,
ToastTitleProps,
ToastTitleSlots,
ToastTitleState,
} from './components/ToastTitle/index';
export {
ToastTitle,
renderToastTitle_unstable,
toastTitleClassNames,
useToastTitleStyles_unstable,
useToastTitleBase_unstable,
useToastTitle_unstable,
} from './components/ToastTitle/index';
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import type { ComponentProps, ComponentState, DistributiveOmit, Slot } from '@fluentui/react-utilities';
import { BackgroundAppearanceContextValue } from '@fluentui/react-shared-contexts';
import type { ToastIntent } from '../../state/types';

Expand All @@ -17,10 +17,20 @@ export type ToastProps = ComponentProps<ToastSlots> & {
appearance?: BackgroundAppearanceContextValue;
};

/**
* Toast Props without design-only props.
*/
export type ToastBaseProps = DistributiveOmit<ToastProps, 'appearance'>;

/**
* State used in rendering Toast
*/
export type ToastState = ComponentState<ToastSlots> & {
backgroundAppearance: BackgroundAppearanceContextValue;
intent?: ToastIntent | undefined;
};

/**
* State used in rendering Toast, without design-only state.
*/
export type ToastBaseState = DistributiveOmit<ToastState, 'backgroundAppearance'>;
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
export { Toast } from './Toast';
export type { ToastContextValues, ToastProps, ToastSlots, ToastState } from './Toast.types';
export type {
ToastBaseProps,
ToastBaseState,
ToastContextValues,
ToastProps,
ToastSlots,
ToastState,
} from './Toast.types';
export { renderToast_unstable } from './renderToast';
export { useToast_unstable } from './useToast';
export { useToastBase_unstable, useToast_unstable } from './useToast';
export { toastClassNames, useToastStyles_unstable } from './useToastStyles.styles';
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@

import * as React from 'react';
import { getIntrinsicElementProps, slot } from '@fluentui/react-utilities';
import type { ToastProps, ToastState } from './Toast.types';
import type { ToastBaseProps, ToastBaseState, ToastProps, ToastState } from './Toast.types';
import { useToastContainerContext } from '../../contexts/toastContainerContext';

/**
* Create the state required to render Toast.
*
* The returned state can be modified with hooks such as useToastStyles_unstable,
* before being passed to renderToast_unstable.
* Create the base state required to render Toast, without design-only props.
*
* @param props - props from this instance of Toast
* @param props - props from this instance of Toast (without appearance)
* @param ref - reference to root HTMLElement of Toast
*/
export const useToast_unstable = (props: ToastProps, ref: React.Ref<HTMLElement>): ToastState => {
export const useToastBase_unstable = (props: ToastBaseProps, ref: React.Ref<HTMLElement>): ToastBaseState => {
const { intent } = useToastContainerContext();

return {
Expand All @@ -31,7 +28,22 @@ export const useToast_unstable = (props: ToastProps, ref: React.Ref<HTMLElement>
}),
{ elementType: 'div' },
),
backgroundAppearance: props.appearance,
intent,
};
};

/**
* Create the state required to render Toast.
*
* The returned state can be modified with hooks such as useToastStyles_unstable,
* before being passed to renderToast_unstable.
*
* @param props - props from this instance of Toast
* @param ref - reference to root HTMLElement of Toast
*/
export const useToast_unstable = (props: ToastProps, ref: React.Ref<HTMLElement>): ToastState => {
return {
...useToastBase_unstable(props, ref),
backgroundAppearance: props.appearance,
};
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import type { ComponentProps, ComponentState, DistributiveOmit, Slot } from '@fluentui/react-utilities';
import { BackgroundAppearanceContextValue } from '@fluentui/react-shared-contexts';

export type ToastBodySlots = {
Expand All @@ -11,9 +11,19 @@ export type ToastBodySlots = {
*/
export type ToastBodyProps = ComponentProps<ToastBodySlots> & {};

/**
* ToastBody Props without design-only props.
*/
export type ToastBodyBaseProps = ToastBodyProps;

/**
* State used in rendering ToastBody
*/
export type ToastBodyState = ComponentState<ToastBodySlots> & {
backgroundAppearance: BackgroundAppearanceContextValue;
};

/**
* State used in rendering ToastBody, without design-only state.
*/
export type ToastBodyBaseState = DistributiveOmit<ToastBodyState, 'backgroundAppearance'>;
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export { ToastBody } from './ToastBody';
export type { ToastBodyProps, ToastBodySlots, ToastBodyState } from './ToastBody.types';
export type {
ToastBodyBaseProps,
ToastBodyBaseState,
ToastBodyProps,
ToastBodySlots,
ToastBodyState,
} from './ToastBody.types';
export { renderToastBody_unstable } from './renderToastBody';
export { useToastBody_unstable } from './useToastBody';
export { useToastBodyBase_unstable, useToastBody_unstable } from './useToastBody';
export { toastBodyClassNames, useToastBodyStyles_unstable } from './useToastBodyStyles.styles';
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@

import * as React from 'react';
import { getIntrinsicElementProps, slot } from '@fluentui/react-utilities';
import type { ToastBodyProps, ToastBodyState } from './ToastBody.types';
import type { ToastBodyBaseProps, ToastBodyBaseState, ToastBodyProps, ToastBodyState } from './ToastBody.types';
import { useToastContainerContext } from '../../contexts/toastContainerContext';
import { useBackgroundAppearance } from '@fluentui/react-shared-contexts';

/**
* Create the state required to render ToastBody.
*
* The returned state can be modified with hooks such as useToastBodyStyles_unstable,
* before being passed to renderToastBody_unstable.
* Create the base state required to render ToastBody, without design-only props.
*
* @param props - props from this instance of ToastBody
* @param ref - reference to root HTMLElement of ToastBody
*/
export const useToastBody_unstable = (props: ToastBodyProps, ref: React.Ref<HTMLElement>): ToastBodyState => {
const backgroundAppearance = useBackgroundAppearance();
export const useToastBodyBase_unstable = (
props: ToastBodyBaseProps,
ref: React.Ref<HTMLElement>,
): ToastBodyBaseState => {
const { bodyId } = useToastContainerContext();
return {
components: {
Expand All @@ -35,6 +34,22 @@ export const useToastBody_unstable = (props: ToastBodyProps, ref: React.Ref<HTML
}),
{ elementType: 'div' },
),
};
};

/**
* Create the state required to render ToastBody.
*
* The returned state can be modified with hooks such as useToastBodyStyles_unstable,
* before being passed to renderToastBody_unstable.
*
* @param props - props from this instance of ToastBody
* @param ref - reference to root HTMLElement of ToastBody
*/
export const useToastBody_unstable = (props: ToastBodyProps, ref: React.Ref<HTMLElement>): ToastBodyState => {
const backgroundAppearance = useBackgroundAppearance();
return {
...useToastBodyBase_unstable(props, ref),
backgroundAppearance,
};
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import type { ComponentProps, ComponentState, DistributiveOmit, Slot } from '@fluentui/react-utilities';
import { BackgroundAppearanceContextValue } from '@fluentui/react-shared-contexts';
import { ToastContainerContextValue } from '../../contexts/toastContainerContext';

Expand All @@ -13,10 +13,20 @@ export type ToastTitleSlots = {
*/
export type ToastTitleProps = ComponentProps<ToastTitleSlots> & {};

/**
* ToastTitle Props without design-only props.
*/
export type ToastTitleBaseProps = ToastTitleProps;

/**
* State used in rendering ToastTitle
*/
export type ToastTitleState = ComponentState<ToastTitleSlots> &
Pick<ToastContainerContextValue, 'intent'> & {
backgroundAppearance: BackgroundAppearanceContextValue;
};

/**
* State used in rendering ToastTitle, without design-only state.
*/
export type ToastTitleBaseState = DistributiveOmit<ToastTitleState, 'backgroundAppearance'>;
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export { ToastTitle } from './ToastTitle';
export type { ToastTitleProps, ToastTitleSlots, ToastTitleState } from './ToastTitle.types';
export type {
ToastTitleBaseProps,
ToastTitleBaseState,
ToastTitleProps,
ToastTitleSlots,
ToastTitleState,
} from './ToastTitle.types';
export { renderToastTitle_unstable } from './renderToastTitle';
export { useToastTitle_unstable } from './useToastTitle';
export { useToastTitleBase_unstable, useToastTitle_unstable } from './useToastTitle';
export { toastTitleClassNames, useToastTitleStyles_unstable } from './useToastTitleStyles.styles';
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,44 @@ import { CheckmarkCircleFilled, DiamondDismissFilled, InfoFilled, WarningFilled
import { getIntrinsicElementProps, slot } from '@fluentui/react-utilities';
import { useBackgroundAppearance } from '@fluentui/react-shared-contexts';

import type { ToastTitleProps, ToastTitleState } from './ToastTitle.types';
import type { ToastTitleBaseProps, ToastTitleBaseState, ToastTitleProps, ToastTitleState } from './ToastTitle.types';
import { useToastContainerContext } from '../../contexts/toastContainerContext';

/**
* Create the base state required to render ToastTitle, without design-only props.
*
* @param props - props from this instance of ToastTitle
* @param ref - reference to root HTMLElement of ToastTitle
*/
export const useToastTitleBase_unstable = (
props: ToastTitleBaseProps,
ref: React.Ref<HTMLElement>,
): ToastTitleBaseState => {
const { intent, titleId } = useToastContainerContext();

return {
action: slot.optional(props.action, { elementType: 'div' }),
components: { root: 'div', media: 'div', action: 'div' },
media: slot.optional(props.media, {
renderByDefault: !!intent,
elementType: 'div',
}),
root: slot.always(
getIntrinsicElementProps('div', {
// FIXME:
// `ref` is wrongly assigned to be `HTMLElement` instead of `HTMLDivElement`
// but since it would be a breaking change to fix it, we are casting ref to it's proper type
ref: ref as React.Ref<HTMLDivElement>,
children: props.children,
id: titleId,
...props,
}),
{ elementType: 'div' },
),
intent,
};
};

/**
* Create the state required to render ToastTitle.
*
Expand All @@ -19,12 +54,12 @@ import { useToastContainerContext } from '../../contexts/toastContainerContext';
* @param ref - reference to root HTMLElement of ToastTitle
*/
export const useToastTitle_unstable = (props: ToastTitleProps, ref: React.Ref<HTMLElement>): ToastTitleState => {
const { intent, titleId } = useToastContainerContext();
const backgroundAppearance = useBackgroundAppearance();
const baseState = useToastTitleBase_unstable(props, ref);

/** Determine the role and media to render based on the intent */
let defaultIcon;
switch (intent) {
switch (baseState.intent) {
case 'success':
defaultIcon = <CheckmarkCircleFilled />;
break;
Expand All @@ -40,26 +75,10 @@ export const useToastTitle_unstable = (props: ToastTitleProps, ref: React.Ref<HT
}

return {
action: slot.optional(props.action, { elementType: 'div' }),
components: { root: 'div', media: 'div', action: 'div' },
media: slot.optional(props.media, {
renderByDefault: !!intent,
defaultProps: { children: defaultIcon },
elementType: 'div',
}),
root: slot.always(
getIntrinsicElementProps('div', {
// FIXME:
// `ref` is wrongly assigned to be `HTMLElement` instead of `HTMLDivElement`
// but since it would be a breaking change to fix it, we are casting ref to it's proper type
ref: ref as React.Ref<HTMLDivElement>,
children: props.children,
id: titleId,
...props,
}),
{ elementType: 'div' },
),
intent,
...baseState,
backgroundAppearance,
media: baseState.media
? { ...baseState.media, children: baseState.media.children ?? defaultIcon }
: baseState.media,
};
};
Loading
Loading