UNPKG

reactant

Version:

A framework for building React web applications

373 lines (357 loc) 12.7 kB
'use strict'; var reactantModule = require('reactant-module'); var React = require('react'); var reactRedux = require('react-redux'); /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ var __assign = function() { __assign = Object.assign || function __assign(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 __values(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } function __spreadArray(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)); } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; var ContainerContext = React.createContext(null); /** * ## Description * * You can create an app with `createApp()` passing app configuration, * which will return an object including `instance`, `store`, * and `bootstrap()` method(You can run `bootstrap` to start the app inject into the browser or mobile). * * ## Example * * ```typescript * import { createApp, injectable } from 'reactant'; * * @injectable() * class Foo {} * * const app = createApp({ * modules: [], * main: Foo, * render: () => {}, * }); * * expect(app.instance instanceof Foo).toBeTruthy(); * ``` */ function createApp(_a) { var /** * As the main start-up module. */ main = _a.main, /** * As a rendering function for any React renderer. */ render = _a.render, /** * Importing the injected dependency modules. */ _b = _a.modules, /** * Importing the injected dependency modules. */ _modules = _b === void 0 ? [] : _b, /** * Dependent injection container options. */ containerOptions = _a.containerOptions, /** * Preloaded state of shared state for Redux. */ preloadedState = _a.preloadedState, /** * Reactant's development setting options. */ devOptions = _a.devOptions; var modules = __spreadArray(__spreadArray([], __read(_modules), false), [main], false); var ServiceIdentifiers = new Map(); var dynamicModules = new Map(); var modulesMap = {}; var container = reactantModule.createContainer({ ServiceIdentifiers: ServiceIdentifiers, modules: modules, options: __assign(__assign({ defaultScope: 'Singleton' }, containerOptions), { skipBaseClassChecks: true }), }); var pluginHooks = { middleware: [], beforeCombineRootReducers: [], afterCombineRootReducers: [], enhancer: [], preloadedStateHandler: [], afterCreateStore: [], provider: [], }; var loadedModules = new Set(); var loader = function (loadModules, beforeReplaceReducer) { var multipleInjectMap = reactantModule.getMetadata(reactantModule.METADATA_KEY.multiple); var filteredModules = loadModules.filter(function (module) { var serviceIdentifier = typeof module === 'function' ? module : typeof module === 'object' ? module.provide : undefined; if (serviceIdentifier) { return (multipleInjectMap.has(serviceIdentifier) || (!multipleInjectMap.has(serviceIdentifier) && !container.isBound(serviceIdentifier))); } return true; }); reactantModule.bindModules(container, filteredModules); reactantModule.createStore({ modules: filteredModules, container: container, ServiceIdentifiers: ServiceIdentifiers, loadedModules: loadedModules, load: loader, dynamicModules: dynamicModules, pluginHooks: pluginHooks, preloadedState: undefined, devOptions: devOptions, // eslint-disable-next-line no-use-before-define originalStore: store, beforeReplaceReducer: function () { beforeReplaceReducer === null || beforeReplaceReducer === void 0 ? void 0 : beforeReplaceReducer(container); }, modulesMap: modulesMap, }); }; var store = reactantModule.createStore({ modules: modules, container: container, ServiceIdentifiers: ServiceIdentifiers, loadedModules: loadedModules, load: loader, dynamicModules: dynamicModules, pluginHooks: pluginHooks, preloadedState: preloadedState, devOptions: devOptions, modulesMap: modulesMap, }); var withoutReducers = store.getState() === null; var instance = container.get(typeof main === 'object' ? main.provide : main); return { /** * App's main module instance. */ instance: instance, /** * The container for modules collection */ container: container, /** * Redux store. */ store: withoutReducers ? null : store, /** * all modules collection */ modules: instance[reactantModule.modulesKey], /** * destroy all subscriptions */ destroy: function () { var modulesMap = instance[reactantModule.modulesKey]; Object.keys(modulesMap).forEach(function (key) { var e_1, _a; var module = modulesMap[key]; var unsubscriptions = module === null || module === void 0 ? void 0 : module[reactantModule.unsubscriptionsKey]; if (unsubscriptions) { try { for (var unsubscriptions_1 = __values(unsubscriptions), unsubscriptions_1_1 = unsubscriptions_1.next(); !unsubscriptions_1_1.done; unsubscriptions_1_1 = unsubscriptions_1.next()) { var unsubscribe = unsubscriptions_1_1.value; unsubscribe(); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (unsubscriptions_1_1 && !unsubscriptions_1_1.done && (_a = unsubscriptions_1.return)) _a.call(unsubscriptions_1); } finally { if (e_1) throw e_1.error; } } } }); }, /** * Bootstrap app with a renderer. */ bootstrap: function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (!(instance instanceof reactantModule.ViewModule)) { throw new Error("Main module should be a 'ViewModule'."); } var callback = args[0]; var InstanceElement = typeof callback === 'function' ? callback(instance.component) : (React.createElement(instance.component, null)); var RootElement = pluginHooks.provider .reverse() .reduce(function (WrappedComponent, ProviderComponent) { return (React.createElement(ProviderComponent, null, WrappedComponent)); }, InstanceElement); var element = withoutReducers ? (React.createElement(ContainerContext.Provider, { value: container }, RootElement)) : (React.createElement(ContainerContext.Provider, { value: container }, React.createElement(reactRedux.Provider, { store: store }, RootElement))); return render.apply(void 0, __spreadArray([(devOptions === null || devOptions === void 0 ? void 0 : devOptions.strict) ? React.createElement(React.StrictMode, null, element) : element], __read(args), false)); }, }; } /** * ## Description * * You can use `testBed` to build your test code without `render`(`render` function is optional.). * * ## Example * * ```ts * @injectable() * class Bar { * getValue() { * return 'bar'; * } * } * * @injectable() * class Foo { * constructor(public bar: Bar) {} * } * * const foo = testBed({ * modules: [{ provide: Bar, useValue: { getValue: () => 'test' } }], * main: Foo, * }); * * expect(foo.instance.bar.getValue()).toBe('test'); * ``` */ function testBed(config) { return createApp(__assign(__assign({}, config), { render: config.render || (function () { console.log("No render function is configured."); }) })); } var batch = reactRedux.batch; /* eslint-disable no-console */ /** * ## Description * * `useConnector` is a React Hooks, which you can use to inject any shared state and derived data that you want to render using. * And it supports both `useConnector(() => this.renderPropsValue)` and `useConnector(() => this.getMapStateToProps())` uses. * * ## Example * * ```tsx * @injectable() * class FooView extends ViewModule { * @state * key = 'str'; * * @action * setValue(value: any) { * this.key = value; * } * * component() { * const { key } = useConnector(() => ({ key: this.key })); * // or `const key = useConnector(() => this.key);` * return <span>{key}</span>; * } * } * * const container = document.createElement('div'); * document.body.appendChild(container); * * act(() => { * createApp({ * modules: [], * main: FooView, * render, * }).bootstrap(container); * }); * * expect(container.querySelector('span')?.textContent).toBe('str'); * ``` */ function useConnector(selector, shallowEqual) { try { var container_1 = React.useContext(ContainerContext); return reactRedux.useSelector(function () { return selector(container_1); }, shallowEqual || reactantModule.areShallowEqualWithObject); } catch (e) { try { reactRedux.useStore(); } catch (error) { console.error("No class with a field decorated by '@state' is injected."); throw e; } throw e; } } exports.ContainerContext = ContainerContext; exports.batch = batch; exports.createApp = createApp; exports.testBed = testBed; exports.useConnector = useConnector; Object.keys(reactantModule).forEach(function (k) { if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, { enumerable: true, get: function () { return reactantModule[k]; } }); });