f-react-use-modal
Version:
f-react-use-modal
88 lines (87 loc) • 2.56 kB
JavaScript
import invariant from 'invariant';
import * as React from 'react';
import { ModalsContext } from "./context.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
* Provider for Modals stacks. The subtree of this component can use the `useDialogs` hook to
* access the modals API. The modals are rendered in the order they are requested.
*
*/
const ModalsProvider = props => {
const {
children,
unmountAfter = 1000
} = props;
const [stack, setStack] = React.useState([]);
const keyPrefix = React.useId();
const nextId = React.useRef(0);
const requestModal = React.useCallback(function open(Component, payload, options = {}) {
const {
onClose = async () => {}
} = options;
let resolve;
const promise = new Promise(resolveImpl => {
resolve = resolveImpl;
});
invariant(resolve, 'resolve not set');
const key = `${keyPrefix}-${nextId.current}`;
nextId.current += 1;
const newEntry = {
key,
open: true,
promise,
Component,
payload,
onClose,
resolve
};
setStack(prevStack => [...prevStack, newEntry]);
return promise;
}, [keyPrefix]);
const closeModalUi = React.useCallback(function closeDialogUi(modal) {
const updateStack = prevStack => prevStack.map(entry => entry.promise === modal ? {
...entry,
open: false
} : entry);
const filterStack = prevStack => prevStack.filter(entry => entry.promise !== modal);
setStack(updateStack);
setTimeout(() => {
setStack(filterStack);
}, unmountAfter);
}, [unmountAfter]);
const closeModal = React.useCallback(async function closeModal(modal, result) {
const entryToClose = stack.find(entry => entry.promise === modal);
invariant(entryToClose, 'Dialog not found');
const {
onClose,
resolve
} = entryToClose;
await onClose(result);
resolve(result);
closeModalUi(modal);
return modal;
}, [stack, closeModalUi]);
const contextValue = React.useMemo(() => ({
open: requestModal,
close: closeModal
}), [requestModal, closeModal]);
return /*#__PURE__*/_jsxs(ModalsContext.Provider, {
value: contextValue,
children: [children, stack.map(({
key,
open,
Component,
payload,
promise
}) => /*#__PURE__*/_jsx(Component, {
payload: payload,
open: open,
onClose: async result => {
await closeModal(promise, result);
}
}, key))]
});
};
export { ModalsProvider };
//# sourceMappingURL=provider.js.map
;