UNPKG

impact-context

Version:
148 lines 5.61 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.context = exports.componentConsumptionHooks = exports.cleanup = exports.ContextProvider = exports.getActiveContextContainer = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const currentContextContainer = []; function getActiveContextContainer() { return currentContextContainer[currentContextContainer.length - 1]; } exports.getActiveContextContainer = getActiveContextContainer; class ContextContainer { get isDisposed() { return this._isDisposed; } constructor(ref, constr, _parent) { this._parent = _parent; this._disposers = new Set(); this._isDisposed = false; this._state = { isResolved: false, ref, constr, }; } registerCleanup(cleaner) { this._disposers.add(cleaner); } resolve(context) { if (this._resolvementError) { throw this._resolvementError; } if (this._state.isResolved && context === this._state.ref) { return this._state.value; } if (!this._state.isResolved && this._state.ref === context) { try { currentContextContainer.push(this); this._state = { isResolved: true, value: this._state.constr(), ref: context, }; currentContextContainer.pop(); return this._state.value; } catch (e) { this._resolvementError = new Error(`Could not initialize context "${context === null || context === void 0 ? void 0 : context.name}": ${String(e)}`); throw this._resolvementError; } } if (!this._parent) { throw new Error(`The context "${context.name}" is not provided`); } return this._parent.resolve(context); } clear() { this._disposers.forEach((cleaner) => { cleaner(); }); } dispose() { this.clear(); this._isDisposed = true; } } const reactContext = (0, react_1.createContext)(null); class ContextProvider extends react_1.Component { componentWillUnmount() { this.container.dispose(); } render() { // React can keep the component reference and mount/unmount it multiple times. Because of that // we need to ensure to always have a hooks container instantiated when rendering, as it could // have been disposed due to an unmount if (!this.container || this.container.isDisposed) { this.container = new ContextContainer(this.props.context, () => this.props.context(this.props.props), // eslint-disable-next-line // @ts-ignore this.context); } return ((0, jsx_runtime_1.jsx)(reactContext.Provider, { value: this.container, children: this.props.children })); } } exports.ContextProvider = ContextProvider; ContextProvider.contextType = reactContext; function cleanup(cleaner) { const activeContextContainer = getActiveContextContainer(); if (!activeContextContainer) { throw new Error("You are cleaning up in an invalid context"); } activeContextContainer.registerCleanup(cleaner); } exports.cleanup = cleanup; exports.componentConsumptionHooks = { isConsuming: false, onConsume: () => { }, onConsumed: () => { }, }; function context(context) { const useReactiveContext = () => { const activeContextContainer = getActiveContextContainer(); if (!activeContextContainer) { if (!exports.componentConsumptionHooks.isConsuming) { exports.componentConsumptionHooks.isConsuming = true; exports.componentConsumptionHooks.onConsume(); } const contextContainer = (0, react_1.useContext)(reactContext); if (!contextContainer) { throw new Error("You are using a store outside its provider"); } return contextContainer.resolve(context); } return activeContextContainer.resolve(context); }; useReactiveContext.Provider = (props) => { // To avoid TSLIB const propsCopy = Object.assign({}, props); const children = propsCopy.children; delete propsCopy.children; return ((0, jsx_runtime_1.jsx)(ContextProvider, { props: propsCopy, context: context, children: children })); }; // @ts-ignore useReactiveContext.Provider.displayName = context.name || "ReactiveContextProvider"; return useReactiveContext; } exports.context = context; if (typeof window !== "undefined") { let currentDispatcher = null; Object.defineProperty(react_1.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher, "current", { get() { return currentDispatcher; }, set(nextDispatcher) { currentDispatcher = nextDispatcher; if (exports.componentConsumptionHooks.isConsuming && // When the hooks has the same implementation, it is to throw an error, meaning // we are done consuming a hooks context currentDispatcher.useReducer === currentDispatcher.useEffect) { exports.componentConsumptionHooks.isConsuming = false; exports.componentConsumptionHooks.onConsumed(); } }, }); } //# sourceMappingURL=index.js.map