import {FunctionComponent, Dispatch, SetStateAction} from 'react'; import {Subject} from 'rxjs'; import {Popover, PopoverProps} from './popover'; import {PopoverRef} from './popover-ref'; import {PopoverContentComponent} from './popover-content-component'; export class PopoverManager { constructor( private _list: PopoverRef[], private setList: Dispatch> ) {} get list(): PopoverRef[] { return this._list; } set list(val: PopoverRef[]) { this._list = val; this.setList(val); } open, Out>( ContentComponent: PopoverContentComponent, contentProps: In, popoverOptions: Omit ) : PopoverRef { const { nestedGroupId = '', nestedLayerIdx = 0 } = popoverOptions; // the same nested group should not have multiple popovers on the same layer if (nestedGroupId) { // close the existing popovers if they're on/above the same layer this.list. filter(elm => elm.nestedGroupId === nestedGroupId && elm.nestedLayerIdx >= nestedLayerIdx) .forEach(elm => elm.close()) } const closeEmitter = new Subject(); const closeHandler = (res?: Out) => { // close from internal function closeEmitter.next(res); // close nested popovers against specified layer if (nestedGroupId) { this.list .filter(elm => elm.nestedGroupId === nestedGroupId && elm.nestedLayerIdx > nestedLayerIdx) .forEach(elm => elm?.close()) } } const PopoverComponent: FunctionComponent = () => ( {...popoverOptions} onClose={closeHandler} > ); const ref = new PopoverRef(closeEmitter, PopoverComponent); // nested grouping assign ref.nestedGroupId = nestedGroupId; ref.nestedLayerIdx = nestedLayerIdx; const sub = closeEmitter.subscribe(() => { this.list = this.list.filter(elm => elm !== ref); sub.unsubscribe(); }); this.list = [...this.list, ref]; return ref; } close(result?: Out, ref?: PopoverRef) { if (ref) { if (ref.nestedGroupId) { const id = ref.nestedGroupId; const idx = ref.nestedLayerIdx; this.list.filter(elm => elm.nestedGroupId === id && elm.nestedLayerIdx > idx).forEach(elm => elm?.close(result)) } else { ref?.close(result); } } else { // default to pop the last popover instance [...this.list].pop()?.close(result); } } }