/** * OverlayStack-storage for the stack of layers (overlays). * * The stack is necessary for understanding whether there are open overlays and whether they contain a background. * Is responsible for storing the stack and provides methods for changing the stack. It works based on the Context API. * Allows you to get information about the layer stack from any part of the app using OVerlayStack.Consumer * and the withoverlaystack HOC decorator */ import * as React from 'react'; import {WithOverlayStack, IRenderProps, AddToStack, RemoveFromStack, UpdateInStack} from './OverlayStack.types'; const {Consumer, ...Context} = React.createContext(null); /** * HOC decorator for getting the stack and methods for changing the stack. * * StackOverlay.Provider must be enabled to use it */ export const withOverlayStack: WithOverlayStack = (mapRenderProps) => { return (Child) => { const Wrapper: React.FC = (props) => ( {(renderProps) => { if (renderProps === null) { throw new Error(`Can't find OverlayStack.Provider in parents.`); } return ; }} ); Wrapper.displayName = `WithOverlayStack(${Child.displayName || Child.name || 'unknown'})`; return Wrapper; }; }; class Provider extends React.PureComponent<{}, IRenderProps> { private add: AddToStack = (stackItem) => { this.setState((prevState) => { const stack = [...prevState.stack]; stack.push(stackItem); return {stack}; }); }; private remove: RemoveFromStack = (id) => { this.setState((prevState) => { const stack = [...prevState.stack]; const index = stack.findIndex((stackItem) => stackItem.id === id); if (index >= 0) { stack.splice(index, 1); return {stack}; } return null; }); }; private update: UpdateInStack = (stackItem) => { this.setState((prevState) => { const stack = [...prevState.stack]; const index = stack.findIndex(({id}) => stackItem.id === id); if (index >= 0) { stack[index] = stackItem; return {stack}; } return null; }); }; override state: IRenderProps = { stack: [], add: this.add, remove: this.remove, update: this.update }; override render () { return {this.props.children}; } } export const OverlayStack = { Consumer, Provider };