lucid-ui
Version:
A UI component library from Xandr.
262 lines • 12.1 kB
JavaScript
;
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