All files / util component-types.js

93.1% Statements 27/29
84.21% Branches 32/38
100% Functions 13/13
93.1% Lines 27/29
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132                                      30x   28163x   28163x                             12062x         28163x   28163x         3205x   3205x   7753x           243x   243x   449x           2450x     223x 1x 222x     91x 131x     131x                   2412x     2449x 2449x 2449x               2412x         1176x                       3387x       3387x          
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import _ from 'lodash';
import { omitFunctionPropsDeep } from './state-management';
 
// creates a React component
export function createClass(definition = {}) {
	const {
		_isPrivate = false,
		getDefaultProps,
		statics = {},
		components = {},
		reducers = {},
		selectors = {},
		initialState = getDefaultProps &&
			omitFunctionPropsDeep(getDefaultProps.apply(definition)),
		propName = null,
		propTypes = {},
		render = () => null,
		...restDefinition
	} = definition;
 
	const newDefinition = {
		getDefaultProps,
		...restDefinition,
		statics: {
			...statics,
			...components,
			_isPrivate,
			reducers,
			selectors,
			initialState,
			propName,
		},
		propTypes: _.assign(
			{},
			propTypes,
			_.mapValues(definition.components, () => PropTypes.any)
		),
		render,
	};
 
	newDefinition.statics.definition = newDefinition;
 
	return createReactClass(newDefinition);
}
 
// return all elements matching the specified types
export function filterTypes(children, types = []) {
	types = [].concat(types); // coerce to Array
 
	return _.filter(
		React.Children.toArray(children),
		element => React.isValidElement(element) && _.includes(types, element.type)
	);
}
 
// return all elements not matching the specified types
export function rejectTypes(children, types = []) {
	types = [].concat(types); // coerce to Array
 
	return _.reject(
		React.Children.toArray(children),
		element => React.isValidElement(element) && _.includes(types, element.type)
	);
}
 
// return an array of elements (of the given type) for each of the values
export function createElements(type, values = []) {
	return _.reduce(
		[].concat(values),
		(elements, typeValue) => {
			if (React.isValidElement(typeValue) && typeValue.type === type) {
				return elements.concat(typeValue);
			} else if (
				_.isPlainObject(typeValue) && !React.isValidElement(typeValue)
			) {
				return elements.concat(React.createElement(type, typeValue));
			} else Iif (_.isUndefined(typeValue)) {
				return elements;
			} else {
				return elements.concat(React.createElement(type, null, typeValue));
			}
		},
		[]
	);
}
 
// return all elements found in props and children of the specified types
export function findTypes(props, types = []) {
	// get elements from props (using type.propName)
	const elementsFromProps = _.reduce(
		_.castArray(types),
		(acc, type) => {
			Eif (!_.isUndefined(type.propName)) {
				const propMatches = _.flatten(_.values(_.pick(props, type.propName)));
				return acc.concat(createElements(type, propMatches));
			}
			return acc;
		},
		[]
	);
 
	// return elements from props and elements from children
	return elementsFromProps.concat(filterTypes(props.children, types));
}
 
// return the first element found in props and children of the specificed type(s)
export function getFirst(props, types, defaultValue) {
	return _.first(findTypes(props, types)) || defaultValue;
}
 
// Omit props defined in propTypes of the given type and any extra keys given
// in third argument
//
// We also have a "magic" prop that's always excluded called `callbackId`. That
// prop can be used to identify a component in a list without having to create
// extra closures.
export function omitProps(props, type, keys = [], targetIsDOMElement = true) {
	// We only want to exclude the `callbackId` key when we're omitting props
	// destined for a dom element
	const additionalOmittedKeys = targetIsDOMElement
		? ['initialState', 'callbackId']
		: ['initialState'];
 
	return _.omit(
		props,
		_.keys(type.propTypes).concat(keys).concat(additionalOmittedKeys)
	);
}