diff --git a/change/@fluentui-react-f312783a-5543-4ccb-bb23-86fa0c830e89.json b/change/@fluentui-react-f312783a-5543-4ccb-bb23-86fa0c830e89.json new file mode 100644 index 00000000000000..e585bb567d5b32 --- /dev/null +++ b/change/@fluentui-react-f312783a-5543-4ccb-bb23-86fa0c830e89.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: Coachmark remove possible recursive loop", + "packageName": "@fluentui/react", + "email": "mgodbolt@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react/src/components/Coachmark/Coachmark.base.tsx b/packages/react/src/components/Coachmark/Coachmark.base.tsx index 4b4b72678011fc..6ffe5df171362a 100644 --- a/packages/react/src/components/Coachmark/Coachmark.base.tsx +++ b/packages/react/src/components/Coachmark/Coachmark.base.tsx @@ -23,6 +23,7 @@ import { FocusTrapZone } from '../../FocusTrapZone'; import { useAsync, useOnEvent, useSetTimeout, useWarnings } from '@fluentui/react-hooks'; import type { IRectangle } from '../../Utilities'; import type { IPositionedData } from '../../Positioning'; +import type { IPositioningContainerProps } from './PositioningContainer/PositioningContainer.types'; import type { ICoachmarkProps, ICoachmarkStyles, ICoachmarkStyleProps } from './Coachmark.types'; import type { IBeakProps } from './Beak/Beak.types'; @@ -401,6 +402,15 @@ function useDeprecationWarning(props: ICoachmarkProps) { } } +function useGetBounds(props: ICoachmarkProps): IRectangle | undefined { + const async = useAsync(); + const [bounds, setBounds] = React.useState(); + React.useEffect(() => { + async.requestAnimationFrame(() => setBounds(getBounds(props.isPositionForced, props.positioningContainerProps))); + }, [async, props.isPositionForced, props.positioningContainerProps]); + return bounds; +} + const COMPONENT_NAME = 'CoachmarkBase'; export const CoachmarkBase: React.FunctionComponent = React.forwardRef< @@ -467,16 +477,6 @@ export const CoachmarkBase: React.FunctionComponent = React.for const finalHeight: number | undefined = isCollapsed ? COACHMARK_HEIGHT : entityInnerHostRect.height; - function useGetBounds(): IRectangle | undefined { - const async = useAsync(); - const [bounds, setBounds] = React.useState(); - const updateAsyncPosition = (): void => { - async.requestAnimationFrame(() => setBounds(getBounds(props))); - }; - React.useEffect(updateAsyncPosition); - return bounds; - } - return ( = React.for finalHeight={finalHeight} ref={forwardedRef} onPositioned={onPositioned} - bounds={useGetBounds()} + bounds={useGetBounds(props)} {...positioningContainerProps} >
@@ -536,7 +536,10 @@ export const CoachmarkBase: React.FunctionComponent = React.for }); CoachmarkBase.displayName = COMPONENT_NAME; -function getBounds({ isPositionForced, positioningContainerProps }: ICoachmarkProps): IRectangle | undefined { +function getBounds( + isPositionForced?: boolean, + positioningContainerProps?: IPositioningContainerProps, +): IRectangle | undefined { if (isPositionForced) { // If directionalHint direction is the top or bottom auto edge, then we want to set the left/right bounds // to the window x-axis to have auto positioning work correctly.