From 6325e9bab0bd056dfe0244b841c8e9dd1ed4eafa Mon Sep 17 00:00:00 2001 From: Ben Howell Date: Tue, 22 Aug 2023 11:26:50 -0700 Subject: [PATCH 1/2] feat: Add documentKeyboardEvent to OnVisibleChangeData when Tooltip is hidden via Escape --- ...-79e44460-a719-40d8-9aeb-cc3737e454a2.json | 7 +++++++ .../src/components/Tooltip/Tooltip.types.ts | 11 +++++++++- .../src/components/Tooltip/useTooltip.tsx | 20 ++++++++++--------- 3 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 change/@fluentui-react-tooltip-79e44460-a719-40d8-9aeb-cc3737e454a2.json diff --git a/change/@fluentui-react-tooltip-79e44460-a719-40d8-9aeb-cc3737e454a2.json b/change/@fluentui-react-tooltip-79e44460-a719-40d8-9aeb-cc3737e454a2.json new file mode 100644 index 00000000000000..579c862ff0b7e1 --- /dev/null +++ b/change/@fluentui-react-tooltip-79e44460-a719-40d8-9aeb-cc3737e454a2.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat: Add documentKeyboardEvent to OnVisibleChangeData when Tooltip is hidden via Escape", + "packageName": "@fluentui/react-tooltip", + "email": "behowell@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-tooltip/src/components/Tooltip/Tooltip.types.ts b/packages/react-components/react-tooltip/src/components/Tooltip/Tooltip.types.ts index fb03e3901f1397..c09590c3e92b71 100644 --- a/packages/react-components/react-tooltip/src/components/Tooltip/Tooltip.types.ts +++ b/packages/react-components/react-tooltip/src/components/Tooltip/Tooltip.types.ts @@ -28,6 +28,12 @@ export type TooltipChildProps = { */ export type OnVisibleChangeData = { visible: boolean; + + /** + * The event object, if this visibility change was triggered by a keyboard event on the document element + * (such as Escape to hide the visible tooltip). Otherwise undefined. + */ + documentKeyboardEvent?: KeyboardEvent; }; /** @@ -52,7 +58,10 @@ export type TooltipProps = ComponentProps & hideDelay?: number; /** - * Notification when the visibility of the tooltip is changing + * Notification when the visibility of the tooltip is changing. + * + * **Note**: for backwards compatibility, `event` will be undefined if this was triggered by a keyboard event on + * the document element. Use `data.documentKeyboardEvent` if the keyboard event object is needed. */ onVisibleChange?: ( event: React.PointerEvent | React.FocusEvent | undefined, diff --git a/packages/react-components/react-tooltip/src/components/Tooltip/useTooltip.tsx b/packages/react-components/react-tooltip/src/components/Tooltip/useTooltip.tsx index 282b8e2f96cb3e..3ec440a2ff2028 100644 --- a/packages/react-components/react-tooltip/src/components/Tooltip/useTooltip.tsx +++ b/packages/react-components/react-tooltip/src/components/Tooltip/useTooltip.tsx @@ -17,7 +17,7 @@ import { useEventCallback, slot, } from '@fluentui/react-utilities'; -import type { TooltipProps, TooltipState, TooltipChildProps } from './Tooltip.types'; +import type { TooltipProps, TooltipState, TooltipChildProps, OnVisibleChangeData } from './Tooltip.types'; import { arrowHeight, tooltipBorderRadius } from './private/constants'; import { Escape } from '@fluentui/keyboard-keys'; @@ -50,13 +50,13 @@ export const useTooltip_unstable = (props: TooltipProps): TooltipState => { const [visible, setVisibleInternal] = useControllableState({ state: props.visible, initialState: false }); const setVisible = React.useCallback( - (newVisible: boolean, ev?: React.PointerEvent | React.FocusEvent) => { + (ev: React.PointerEvent | React.FocusEvent | undefined, data: OnVisibleChangeData) => { clearDelayTimeout(); setVisibleInternal(oldVisible => { - if (newVisible !== oldVisible) { - onVisibleChange?.(ev, { visible: newVisible }); + if (data.visible !== oldVisible) { + onVisibleChange?.(ev, data); } - return newVisible; + return data.visible; }); }, [clearDelayTimeout, setVisibleInternal, onVisibleChange], @@ -117,14 +117,16 @@ export const useTooltip_unstable = (props: TooltipProps): TooltipState => { // Also add a listener on document to hide the tooltip if Escape is pressed useIsomorphicLayoutEffect(() => { if (visible) { - const thisTooltip = { hide: () => setVisible(false) }; + const thisTooltip = { + hide: (ev?: KeyboardEvent) => setVisible(undefined, { visible: false, documentKeyboardEvent: ev }), + }; context.visibleTooltip?.hide(); context.visibleTooltip = thisTooltip; const onDocumentKeyDown = (ev: KeyboardEvent) => { if (ev.key === Escape) { - thisTooltip.hide(); + thisTooltip.hide(ev); // stop propagation to avoid conflicting with other elements that listen for `Escape` // e,g: Dialog, Popover, Menu ev.stopPropagation(); @@ -166,7 +168,7 @@ export const useTooltip_unstable = (props: TooltipProps): TooltipState => { const delay = context.visibleTooltip ? 0 : state.showDelay; setDelayTimeout(() => { - setVisible(true, ev); + setVisible(ev, { visible: true }); }, delay); ev.persist(); // Persist the event since the setVisible call will happen asynchronously @@ -187,7 +189,7 @@ export const useTooltip_unstable = (props: TooltipProps): TooltipState => { } setDelayTimeout(() => { - setVisible(false, ev); + setVisible(ev, { visible: false }); }, delay); ev.persist(); // Persist the event since the setVisible call will happen asynchronously From 75403b429b472643e75ef435680e700259cbda5b Mon Sep 17 00:00:00 2001 From: Ben Howell Date: Tue, 22 Aug 2023 11:43:43 -0700 Subject: [PATCH 2/2] api.md --- packages/react-components/react-tooltip/etc/react-tooltip.api.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-components/react-tooltip/etc/react-tooltip.api.md b/packages/react-components/react-tooltip/etc/react-tooltip.api.md index be590dd02d086c..ada8f59ee9266d 100644 --- a/packages/react-components/react-tooltip/etc/react-tooltip.api.md +++ b/packages/react-components/react-tooltip/etc/react-tooltip.api.md @@ -16,6 +16,7 @@ import type { TriggerProps } from '@fluentui/react-utilities'; // @public export type OnVisibleChangeData = { visible: boolean; + documentKeyboardEvent?: KeyboardEvent; }; // @public