Skip to content

Commit

Permalink
feat: Add documentKeyboardEvent to OnVisibleChangeData when Tooltip i…
Browse files Browse the repository at this point in the history
…s hidden via Escape (microsoft#28951)

Add new field `documentKeyboardEvent` in `OnVisibleChangeData`, which is set when the visibility change happens in response to a keyboard event on the document object. Currently this only happens for the Escape key.
  • Loading branch information
behowell authored Aug 23, 2023
1 parent fa10a47 commit 45b2bea
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 10 deletions.
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": "[email protected]",
"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

0 comments on commit 45b2bea

Please sign in to comment.