UNPKG

lucid-ui

Version:

A UI component library from Xandr.

262 lines 12.1 kB
"use strict"; var __assign = (this && this.__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); }; var __spreadArray = (this && this.__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)); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.cleanArgs = exports.getReduxPrimitives = exports.thunk = void 0; var lodash_1 = __importDefault(require("lodash")); var reselect_1 = require("reselect"); var state_management_1 = require("./state-management"); var logger_1 = require("./logger"); /** * Marks a function on the reducer tree as a thunk action creator so it doesn't * get incorporated into the redux reducer * * @return {function} with `isThunk` set to `true` */ function thunk(fn) { fn.isThunk = true; return fn; } exports.thunk = thunk; function getReduxPrimitives(_a) { var initialState = _a.initialState, reducers = _a.reducers, _b = _a.rootPath, rootPath = _b === void 0 ? [] : _b, _c = _a.rootSelector, rootSelector = _c === void 0 ? lodash_1.default.identity : _c, selectors = _a.selectors; /* istanbul ignore if */ if (logger_1.isDevMode && lodash_1.default.isEmpty(rootPath)) { logger_1.logger.warn("`getReduxPrimitives` warning:\n`rootPath` is empty"); } /* istanbul ignore if */ if (logger_1.isDevMode && !initialState) { logger_1.logger.warn("`getReduxPrimitives` warning:\nMissing `initialState` for component at `rootPath` ".concat(lodash_1.default.isArray(rootPath) ? rootPath.join(',') : rootPath, "\nComponents should have an `initialState` property or a `getDefaultProps` defined.\n")); } // we need this in scope so actionCreators can refer to it var dispatchTree; var reducer = createReduxReducer(reducers, initialState, rootPath); var selector = selectors ? (0, state_management_1.reduceSelectors)(selectors) : lodash_1.default.identity; var rootPathSelector = function (state) { return lodash_1.default.isEmpty(rootPath) ? state : lodash_1.default.get(state, rootPath); }; var mapStateToProps = (0, reselect_1.createSelector)([rootPathSelector], function (rootState) { return rootSelector(selector(rootState)); }); // dispatch could be store.dispatch's return value or an async lib's return value? var mapDispatchToProps = function (dispatch) { return getDispatchTree(reducers, rootPath, dispatch); }; var devModeMapStateToProps = function (rootState) { /* istanbul ignore if */ if (logger_1.isDevMode && !lodash_1.default.has(rootState, rootPath)) { logger_1.logger.warn("`getReduxPrimitives` warning:\n`rootPath` ".concat(rootPath, " does not exist in the redux store.\nMake sure your `rootPath` is correct.\n")); } return mapStateToProps(rootState); }; return { reducer: reducer, connectors: [ logger_1.isDevMode ? devModeMapStateToProps : mapStateToProps, mapDispatchToProps, mergeProps, ], }; /** * @param {function} node - a node in the the reducer tree, either a reducer or a thunk * @param {string[]} path - the path to the reducer in the reducer tree * @param {string[]} rootPath - array of strings representing the path to local state in global state * @return {function} action creator that returns either an action or a thunk */ function createActionCreator(node, rootPath, path) { if (node.isThunk) { return function thunk() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return function thunkInner(dispatch, getState) { var rest = []; for (var _i = 2; _i < arguments.length; _i++) { rest[_i - 2] = arguments[_i]; } var pathToLocalDispatchTree = lodash_1.default.slice(path, rootPath.length, -1); var pathToLocalState = lodash_1.default.dropRight(path); var localDispatchTree = lodash_1.default.isEmpty(pathToLocalDispatchTree) ? dispatchTree : lodash_1.default.get(dispatchTree, pathToLocalDispatchTree); var getLocalState = lodash_1.default.isEmpty(pathToLocalState) ? getState : function () { return lodash_1.default.get(getState(), pathToLocalState); }; return node.apply(void 0, args).apply(void 0, __spreadArray([localDispatchTree, getLocalState, dispatch, getState], rest, false)); }; }; } return function actionCreator() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var _a = logger_1.isDevMode ? cleanArgs(args) : args, payload = _a[0], meta = _a.slice(1); return { type: path.join('.'), payload: payload, meta: meta, }; }; } /** * Walks the reducer tree and generates a tree of action creators that correspond to each reducer * @param {Object} reducers - a tree of lucid reducers * @param {string[]} rootPath - array of strings representing the path to local state in global state * @returns {Object} action creator tree */ function createActionCreatorTree(reducers, rootPath, path) { if (path === void 0) { path = rootPath; } return lodash_1.default.reduce(reducers, function (memo, node, key) { var _a; var currentPath = path.concat(key); return __assign(__assign({}, memo), (_a = {}, _a[key] = lodash_1.default.isFunction(node) ? createActionCreator(node, rootPath, currentPath) : createActionCreatorTree(node, rootPath, currentPath), _a)); }, {}); } /** * Walks the reducer tree and generates an action creator tree, then binds dispatch to each node * @param {Object} reducers - a tree of lucid reducers * @param {string[]} rootPath - array of strings representing the path to local state in global state * @param {function} dispatch - the redux store's `dispatch` function */ function getDispatchTree(reducers, rootPath, dispatch) { var actionCreatorTree = createActionCreatorTree(reducers, rootPath); dispatchTree = bindActionCreatorTree(actionCreatorTree, dispatch); /* istanbul ignore if */ if (logger_1.isDevMode) { //@ts-ignore window.lucidReduxUtil = window.lucidReduxUtil || {}; //@ts-ignore window.lucidReduxUtil[rootPath] = { actionCreatorTree: actionCreatorTree, dispatchTree: dispatchTree, }; } return dispatchTree; } } exports.getReduxPrimitives = getReduxPrimitives; function createReduxReducerTree(reducers, path) { if (path === void 0) { path = []; } return lodash_1.default.reduce(reducers, function (memo, node, key) { var _a; // filter out thunks from the reducer tree if (node.isThunk) { return memo; } var currentPath = path.concat(key); return __assign(__assign({}, memo), (_a = {}, _a[key] = lodash_1.default.isFunction(node) ? function reduxReducer(state, action) { var type = action.type, payload = action.payload, _a = action.meta, meta = _a === void 0 ? [] : _a; if (lodash_1.default.isUndefined(state) || type !== currentPath.join('.')) { return state; } return node.apply(void 0, __spreadArray([state, payload], meta, false)); } : createReduxReducerTree(node, currentPath), _a)); }, {}); } /** * Returns a function that calls every reducer in the reducer tree with the reducer's local state and action * @param {Object} reduxReducerTree - tree of redux reducers with signature `(state, action) => state` * @param {Object} initialState - the initial state object that the reducer will return * @return {function} the redux reducer */ function createReducerFromReducerTree(reduxReducerTree, initialState) { return function reduxReducer(state, action) { if (lodash_1.default.isUndefined(state)) { return initialState; } return lodash_1.default.reduce(reduxReducerTree, function (state, node, key) { var _a; return __assign(__assign({}, state), (lodash_1.default.isFunction(node) ? node(state, action) : (_a = {}, _a[key] = createReducerFromReducerTree(node, {})(state[key], action), _a))); }, state); }; } /** * Generates a redux reducer from a tree of lucid reducers * @param {Object} reducers - a tree of lucid reducers * @param {Object} initialState - the initial state object that the reducer will return * @param {string[]} rootPath - array of strings representing the path to part of global state this reducer applies to * @return {function} the redux reducer */ function createReduxReducer(reducers, initialState, rootPath) { var reducerTree = createReduxReducerTree(reducers, rootPath); return createReducerFromReducerTree(reducerTree, initialState); } /** * Binds redux store.dispatch to actionCreators in a tree * @param {Object} actionCreatorTree - a tree of redux action creator functions * @param {function} dispatch - the redux store's `dispatch` function * @param {string[]} path - array of strings representing the path to the action creator */ function bindActionCreatorTree(actionCreatorTree, dispatch, path) { if (path === void 0) { path = []; } return lodash_1.default.reduce(actionCreatorTree, function (memo, node, key) { var _a; return (__assign(__assign({}, memo), (_a = {}, _a[key] = lodash_1.default.isFunction(node) ? function boundActionCreator() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var action = actionCreatorTree[key].apply(actionCreatorTree, args); return dispatch(action); } : bindActionCreatorTree(node, dispatch, path.concat(key)), _a))); }, // @ts-ignore {}); } /** * Merges state, dispatchTree, and ownProps into a single props object * @param {Object} state * @param {Object} dispatchTree * @param {Object} ownProps * @return {Object} */ var mergeProps = lodash_1.default.memoize(function (state, dispatchTree, ownProps) { return lodash_1.default.mergeWith({}, state, dispatchTree, ownProps, state_management_1.safeMerge); }); /** * Checks the last element of the array and * if it is an 'event' object, it removes it * Otherwise it just returns the array * @param {any[]} - an array of args */ function cleanArgs(args) { return lodash_1.default.has(lodash_1.default.last(args), 'event') ? lodash_1.default.dropRight(args) : args; } exports.cleanArgs = cleanArgs; //# sourceMappingURL=redux.js.map