@momentum-ui/react-collaboration
Version:
Cisco Momentum UI Framework for React Collaboration Applications
69 lines (58 loc) • 2.44 kB
text/typescript
import { useEffect, useLayoutEffect, useState } from 'react';
import * as PopoverEvents from '../components/Popover/Popover.events';
/**
* A custom React hook that manages the ability to close a component which can contain Popovers when the escape key is pressed.
*
* The hook listens for custom events indicating the addition or removal of tippy instances
* that should close when Esc is pressed (e.g., instances with `hideOnEsc = true`).
* It maintains a set of such instances and provides a `shouldCloseOnEsc` boolean that determines
* whether the parent component should close on Esc press.
*
* The hook leverages two custom events defined in `Popover.events`:
* - `EventType.TIPPY_INSTANCE_ADDED`: Indicates a new Popover instance has been added.
* - `EventType.TIPPY_INSTANCE_REMOVED`: Indicates a Popover instance has been removed.
*
* Each Popover instance is expected to dispatch these events with the instance itself when it is shown and hidden.
*
* @returns An object containing a single property `shouldCloseOnEsc`, which is `true` if no Popover instances
* are currently active (i.e., all have been hidden), and `false` otherwise.
*
*/
export const useShouldCloseOnEsc = (): { shouldCloseOnEsc: boolean } => {
const [popoverInstances, setPopoverInstances] = useState(new Set());
const [shouldCloseOnEsc, setShouldCloseOnEsc] = useState(true);
const add = (e: CustomEvent) => {
setPopoverInstances((prev) => {
const newSet = new Set(prev);
newSet.add(e);
return newSet;
});
};
const remove = (e: CustomEvent) => {
setPopoverInstances((prev) => {
const newSet = new Set(prev);
newSet.delete(e);
return newSet;
});
};
useLayoutEffect(() => {
const addId = PopoverEvents.addListener(PopoverEvents.EventType.TIPPY_INSTANCE_ADDED, add);
const removeId = PopoverEvents.addListener(
PopoverEvents.EventType.TIPPY_INSTANCE_REMOVED,
remove
);
return () => {
PopoverEvents.removeListener(PopoverEvents.EventType.TIPPY_INSTANCE_ADDED, addId);
PopoverEvents.removeListener(PopoverEvents.EventType.TIPPY_INSTANCE_REMOVED, removeId);
};
}, []);
useEffect(() => {
const newShouldCloseOnEsc = popoverInstances.size === 0;
if (newShouldCloseOnEsc !== shouldCloseOnEsc) {
setShouldCloseOnEsc(newShouldCloseOnEsc);
}
}, [popoverInstances]);
return {
shouldCloseOnEsc,
};
};