| 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)
);
}
|