-
-
Notifications
You must be signed in to change notification settings - Fork 31.7k
/
Card.js
153 lines (141 loc) · 4.57 KB
/
Card.js
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Paper from '../Paper';
import CardExpandable from './CardExpandable';
class Card extends Component {
static propTypes = {
/**
* Can be used to render elements inside the Card.
*/
children: PropTypes.node,
/**
* Override the inline-styles of the container element.
*/
containerStyle: PropTypes.object,
/**
* If true, this card component is expandable. Can be set on any child of the `Card` component.
*/
expandable: PropTypes.bool,
/**
* Whether this card is expanded.
* If `true` or `false` the component is controlled.
* if `null` the component is uncontrolled.
*/
expanded: PropTypes.bool,
/**
* Whether this card is initially expanded.
*/
initiallyExpanded: PropTypes.bool,
/**
* Callback function fired when the `expandable` state of the card has changed.
*
* @param {boolean} newExpandedState Represents the new `expanded` state of the card.
*/
onExpandChange: PropTypes.func,
/**
* If true, this card component will include a button to expand the card. `CardTitle`,
* `CardHeader` and `CardActions` implement `showExpandableButton`. Any child component
* of `Card` can implements `showExpandableButton` or forwards the property to a child
* component supporting it.
*/
showExpandableButton: PropTypes.bool,
/**
* Override the inline-styles of the root element.
*/
style: PropTypes.object,
};
static defaultProps = {
expandable: false,
expanded: null,
initiallyExpanded: false,
};
state = {
expanded: null,
};
componentWillMount() {
this.setState({
expanded: this.props.expanded === null ? this.props.initiallyExpanded === true : this.props.expanded,
});
}
componentWillReceiveProps(nextProps) {
// update the state when the component is controlled.
if (nextProps.expanded !== null)
this.setState({expanded: nextProps.expanded});
}
handleExpanding = (event) => {
event.preventDefault();
const newExpandedState = !this.state.expanded;
// no automatic state update when the component is controlled
if (this.props.expanded === null) {
this.setState({expanded: newExpandedState});
}
if (this.props.onExpandChange) {
this.props.onExpandChange(newExpandedState);
}
};
render() {
const {
style,
containerStyle,
children,
expandable, // eslint-disable-line no-unused-vars
expanded: expandedProp, // eslint-disable-line no-unused-vars
initiallyExpanded, // eslint-disable-line no-unused-vars
onExpandChange, // eslint-disable-line no-unused-vars
...other
} = this.props;
let lastElement;
const expanded = this.state.expanded;
const newChildren = React.Children.map(children, (currentChild) => {
let doClone = false;
let newChild = undefined;
const newProps = {};
let element = currentChild;
if (!currentChild || !currentChild.props) {
return null;
}
if (expanded === false && currentChild.props.expandable === true)
return;
if (currentChild.props.actAsExpander === true) {
doClone = true;
newProps.onClick = this.handleExpanding;
newProps.style = Object.assign({cursor: 'pointer'}, currentChild.props.style);
}
if (currentChild.props.showExpandableButton === true) {
doClone = true;
newChild = (
<CardExpandable
closeIcon={currentChild.props.closeIcon}
expanded={expanded}
onExpanding={this.handleExpanding}
openIcon={currentChild.props.openIcon}
iconStyle={currentChild.props.iconStyle}
/>
);
}
if (doClone) {
element = React.cloneElement(currentChild, newProps, currentChild.props.children, newChild);
}
lastElement = element;
return element;
}, this);
// If the last element is text or a title we should add
// 8px padding to the bottom of the card
const addBottomPadding = (lastElement && (lastElement.type.muiName === 'CardText' ||
lastElement.type.muiName === 'CardTitle'));
const mergedStyles = Object.assign({
zIndex: 1,
}, style);
const containerMergedStyles = Object.assign({
paddingBottom: addBottomPadding ? 8 : 0,
}, containerStyle);
return (
<Paper {...other} style={mergedStyles}>
<div style={containerMergedStyles}>
{newChildren}
</div>
</Paper>
);
}
}
export default Card;