import * as React from 'react'; import React__default, { useState, useEffect, useRef, useMemo, createContext, useCallback, useContext } from 'react'; import { RediError, Injector, Quantity } from '@wendellhu/redi'; import { BehaviorSubject } from 'rxjs'; var __REDI_CONTEXT_LOCK__ = 'REDI_CONTEXT_LOCK'; var isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null; var globalObject = (typeof globalThis !== 'undefined' && globalThis) || (typeof window !== 'undefined' && window) || (typeof global !== 'undefined' && global); if (!globalObject[__REDI_CONTEXT_LOCK__]) { globalObject[__REDI_CONTEXT_LOCK__] = true; } else if (!isNode) { console.error('[redi]: "RediContext" is already created. You may import "RediContext" from different paths. Use "import { RediContext } from \'@wendellhu/redi/react-bindings\'; instead."'); } var RediContext = React.createContext({ injector: null, }); RediContext.displayName = 'RediContext'; var RediProvider = RediContext.Provider; var RediConsumer = RediContext.Consumer; var __extends$1 = (undefined && undefined.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var HooksNotInRediContextError = /** @class */ (function (_super) { __extends$1(HooksNotInRediContextError, _super); function HooksNotInRediContextError() { return _super.call(this, 'Using dependency injection outside of a RediContext.') || this; } return HooksNotInRediContextError; }(RediError)); function useInjector() { var injectionContext = React.useContext(RediContext); if (!injectionContext.injector) { throw new HooksNotInRediContextError(); } return injectionContext.injector; } function useDependency(id, quantityOrLookUp, lookUp) { var injector = useInjector(); return injector.get(id, quantityOrLookUp, lookUp); } var __assign = (undefined && undefined.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function RediInjector(props) { var children = props.children, dependencies = props.dependencies; var childInjectorRef = React.useRef(null); // dispose the injector when the container Injector unmounts React.useEffect(function () { return function () { var _a; return (_a = childInjectorRef.current) === null || _a === void 0 ? void 0 : _a.dispose(); }; }, []); return (React.createElement(RediConsumer, null, function (context) { var childInjector; if (childInjectorRef.current) { childInjector = childInjectorRef.current; } else { childInjector = context.injector ? context.injector.createChild(dependencies) : new Injector(dependencies); childInjectorRef.current = childInjector; } return (React.createElement(RediProvider, { value: { injector: childInjector } }, children)); })); } /** * @param Comp * @param injector * @returns */ function connectInjector(Comp, injector) { return function ComponentWithInjector(props) { return (React.createElement(RediProvider, { value: { injector: injector } }, React.createElement(Comp, __assign({}, props)))); }; } function connectDependencies(Comp, dependencies) { return function ComponentWithInjector(props) { return (React.createElement(RediInjector, { dependencies: dependencies }, React.createElement(Comp, __assign({}, props)))); }; } var __extends = (undefined && undefined.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var ClassComponentNotInRediContextError = /** @class */ (function (_super) { __extends(ClassComponentNotInRediContextError, _super); function ClassComponentNotInRediContextError(component) { return _super.call(this, "You should make \"RediContext\" as ".concat(component.constructor.name, "'s default context type. ") + 'If you want to use multiple context, please check this on React doc site. ' + 'https://reactjs.org/docs/context.html#classcontexttype') || this; } return ClassComponentNotInRediContextError; }(RediError)); function WithDependency(id, quantity, lookUp) { return function () { return { get: function () { var thisComponent = this; var context = thisComponent.context; if (!context || !context.injector) { throw new ClassComponentNotInRediContextError(thisComponent); } var injector = context.injector; var thing = injector.get(id, quantity || Quantity.REQUIRED, lookUp); return thing; }, }; }; } var __spreadArray = (undefined && undefined.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; /** * unwrap an observable value, return it to the component for rendering, and * trigger re-render when value changes * * **IMPORTANT**. Parent and child components better not subscribe to the same * observable, otherwise unnecessary re-render would be triggered. Instead, the * top-most component should subscribe and pass value of the observable to * its offspring, by props or context. Please consider using `useDependencyContext` and * `useDependencyContextValue` in this case. * * @deprecated Please use `useObservable` instead. */ function useDependencyValue(depValue$, defaultValue) { var firstValue = depValue$ instanceof BehaviorSubject && typeof defaultValue === 'undefined' ? depValue$.getValue() : defaultValue; var _a = useState(firstValue), value = _a[0], setValue = _a[1]; useEffect(function () { var subscription = depValue$.subscribe(function (val) { return setValue(val); }); return function () { return subscription.unsubscribe(); }; }, [depValue$]); return value; } function unwrap(o) { if (typeof o === 'function') { return o(); } return o; } /** * Subscribe to an observable and return its value. The component will re-render when the observable emits a new value. * * @param observable An observable or a function that returns an observable * @param defaultValue The default value of the observable. It the `observable` can omit an initial value, this value will be neglected. * @param shouldHaveSyncValue If the observable should have a sync value. If it does not have a sync value, an error will be thrown. * @param deps A dependency array to decide if we should re-subscribe when the `observable` is a function. * @returns */ function useObservable(observable, defaultValue, shouldHaveSyncValue, deps) { if (typeof observable === 'function' && !deps) { throw new RediError("Expected deps to be provided when observable is a function!"); } var observableRef = useRef(null); var initializedRef = useRef(false); // eslint-disable-next-line react-hooks/exhaustive-deps var destObservable = useMemo(function () { return observable; }, __spreadArray([], (typeof deps !== 'undefined' ? deps : [observable]), true)); // This state is only for trigger React to re-render. We do not use `setValue` directly because it may cause // memory leaking. var _a = useState(0), _ = _a[0], setRenderCounter = _a[1]; var valueRef = useRef((function () { var innerDefaultValue; if (destObservable) { var sub = unwrap(destObservable).subscribe(function (value) { initializedRef.current = true; innerDefaultValue = value; }); sub.unsubscribe(); } return innerDefaultValue !== null && innerDefaultValue !== void 0 ? innerDefaultValue : defaultValue; })()); useEffect(function () { var subscription = null; if (destObservable) { observableRef.current = unwrap(destObservable); subscription = observableRef.current.subscribe(function (value) { valueRef.current = value; setRenderCounter(function (prev) { return prev + 1; }); }); } return function () { return subscription === null || subscription === void 0 ? void 0 : subscription.unsubscribe(); }; }, [destObservable]); if (shouldHaveSyncValue && !initializedRef.current) { throw new Error('Expect `shouldHaveSyncValue` but not getting a sync value!'); } return valueRef.current; } /** * subscribe to a signal that emits whenever data updates and re-render * * @param update$ a signal that the data the functional component depends has updated */ function useUpdateBinder(update$) { var _a = useState(0), dumpSet = _a[1]; useEffect(function () { var subscription = update$.subscribe(function () { return dumpSet(function (prev) { return prev + 1; }); }); return function () { return subscription.unsubscribe(); }; }, []); } var DepValueMapProvider = new WeakMap(); /** * subscribe to an observable value from a service, creating a context for it so * it child component won't have to subscribe again and cause unnecessary */ function useDependencyContext(depValue$, defaultValue) { var depRef = useRef(undefined); var value = useDependencyValue(depValue$, defaultValue); var Context = useMemo(function () { return createContext(value); }, [depValue$]); var Provider = useCallback(function (props) { return React__default.createElement(Context.Provider, { value: value }, props.children); }, [depValue$, value]); if (depRef.current !== depValue$) { if (depRef.current) { DepValueMapProvider.delete(depRef.current); } depRef.current = depValue$; DepValueMapProvider.set(depValue$, Context); } return { Provider: Provider, value: value, }; } function useDependencyContextValue(depValue$) { var context = DepValueMapProvider.get(depValue$); if (!context) { throw new RediError("try to read context value but no ancestor component subscribed it."); } return useContext(context); } export { RediConsumer, RediContext, RediProvider, WithDependency, connectDependencies, connectInjector, useDependency, useDependencyContext, useDependencyContextValue, useDependencyValue, useInjector, useObservable, useUpdateBinder }; //# sourceMappingURL=react-bindings.js.map