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
@@ -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"
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type { TriggerProps } from '@fluentui/react-utilities';
// @public
export type OnVisibleChangeData = {
visible: boolean;
documentKeyboardEvent?: KeyboardEvent;
};

// @public
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

/**
Expand All @@ -52,7 +58,10 @@ export type TooltipProps = ComponentProps<TooltipSlots> &
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<HTMLElement> | React.FocusEvent<HTMLElement> | undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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<HTMLElement> | React.FocusEvent<HTMLElement>) => {
(ev: React.PointerEvent<HTMLElement> | React.FocusEvent<HTMLElement> | 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],
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down