A React Context and hook to add support for nested, auto-dismissable layers
react-dismissable-layers
Context and hook to add support for nested, auto-dismissable layers. State can be globally controlled through context. Best used with react-popper.
npm i react-dismissable-layers
yarn add react-dismissable-layers
Quick Start
Add <DismissableLayersGlobalProvider>
on a parent component. Use the useDismissable()
hook to associate different toggleable components.
import { useDismissable } from 'react-dismissable-layers';
// open and close
const Component = () => {
const [open, toggleOpen] = useDismissable(false);
return <div>
<button onClick={toggleOpen}>Open Tooltip</button>
{open && (
<Popper>
Tooltip Content
</Popper>
)}
</div>
}
import { DismissableLayerContext } from 'react-dismissable-layers';
// close all dismissibles in context
const OtherComponent = () => {
const dismissOverlay = React.useContext(DismissableLayerContext);
const close = React.useCallback(() => {
dismissOverlay.dismissAllGlobally();
}, [])
return <button onClick={close}>Close All</button>
}
API
-
DismissableLayersGlobalProvider
- global provider for Dismissable Layers, wrap the whole app to make sure theuseDismissable
hook works with layers.interface DismissableLayersGlobalProviderProps { /** * optional prop, the HTML-node to listen close events, default is `document` */ rootNode?: HTMLElement | Document; } const DismissableLayersGlobalProvider = React.FC<DismissableLayersGlobalProviderProps>
-
useDismissable
- a hook to toggle and dismiss poppers.interface Options { /** * ref for the popper content, to not close on the content's [dismissEvent] action */ ref?: RefObject<Element>; /** * callback which will be invoked when the popper is closed */ onClose?: null | VoidFunction; /** * event on which popper will be closed, default is `'click'` */ dismissEvent?: DismissEventType; /** * the popper will be closed just by the [dismissEvent] action, without any layers logic, default is `false` */ disableLayers?: boolean; /** * do not close on default prevented events, default is `true` */ skipDefaultPrevented?: boolean; } type Api = readonly [ isOpened: boolean, /** * function to toggle popper */ toggle: VoidFunction, /** * function to force close popper */ close: VoidFunction ]; const useDismissable = (defaultValue = false, options: Options = {}) => Api;
-
DismissableLayerContext
- a context to read a dissmissable layer, in most cases shouldn't be used in app layer.interface DismissableLayerValue<T extends HTMLElement | Document = Document> { /** * for internal usage only */ readonly _subscriber: Subscriber; /** * root node of the dismiss layer */ readonly rootNode: T; /** * dismiss currently opened in the current layer */ readonly dismiss: VoidFunction; /** * has handler on the current layer */ readonly hasHandler: () => boolean; /** * add close handler to the current layer */ readonly addHandler: (eventType: DismissEventType, handler: DismissEventHandler) => void; /** * remove close handler from the current layer */ readonly removeHandler: (eventType: DismissEventType) => void; /** * dismiss all on all layers */ readonly dismissAllGlobally: VoidFunction; /** * has subscriber on any layer */ readonly hasHandlersGlobally: () => boolean; } const DismissableLayersGlobalProvider = React.FC<DismissableLayersGlobalProviderProps>
-
DismissableLayerProvider
- provider for Dismissable Layer, wrap the popper content to make the nested poppers works as a nested ones.interface DismissableLayerProviderProps { /** * optional prop, the HTML-node to listen close events, default is `document` */ rootNode?: HTMLElement | Document; } const DismissableLayerProvider = React.FC<DismissableLayerProviderProps>