Skip to content

Commit 604b37c

Browse files
committed
[ExpansioPanel] use context
1 parent e88b9ba commit 604b37c

File tree

5 files changed

+97
-70
lines changed

5 files changed

+97
-70
lines changed

packages/material-ui/src/ExpansionPanel/ExpansionPanel.js

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Collapse from '../Collapse';
88
import Paper from '../Paper';
99
import withStyles from '../styles/withStyles';
1010
import { isMuiElement } from '../utils/reactHelpers';
11+
import { PureProvider } from './ExpansionPanelContext';
1112

1213
export const styles = theme => {
1314
const transition = {
@@ -113,12 +114,15 @@ function ExpansionPanel(props) {
113114

114115
const [expanded, setExpanded] = useMaybeControlled(expandedProp, defaultExpanded);
115116

116-
function handleChange(event) {
117-
setExpanded(isExpanded => !isExpanded);
118-
if (onChange) {
119-
onChange(event, !expanded);
120-
}
121-
}
117+
const handleChange = React.useCallback(
118+
event => {
119+
setExpanded(isExpanded => !isExpanded);
120+
if (onChange) {
121+
onChange(event, !expanded);
122+
}
123+
},
124+
[expanded, setExpanded, onChange],
125+
);
122126

123127
let summary = null;
124128

@@ -136,37 +140,35 @@ function ExpansionPanel(props) {
136140
);
137141

138142
if (isMuiElement(child, ['ExpansionPanelSummary'])) {
139-
summary = React.cloneElement(child, {
140-
disabled,
141-
expanded,
142-
onChange: handleChange,
143-
});
143+
summary = child;
144144
return null;
145145
}
146146

147147
return child;
148148
});
149149

150150
return (
151-
<Paper
152-
className={clsx(
153-
classes.root,
154-
{
155-
[classes.expanded]: expanded,
156-
[classes.disabled]: disabled,
157-
[classes.rounded]: !square,
158-
},
159-
classNameProp,
160-
)}
161-
elevation={1}
162-
square={square}
163-
{...other}
164-
>
165-
{summary}
166-
<TransitionComponent in={expanded} timeout="auto" {...TransitionProps}>
167-
{children}
168-
</TransitionComponent>
169-
</Paper>
151+
<PureProvider disabled={disabled} expanded={expanded} onChange={handleChange}>
152+
<Paper
153+
className={clsx(
154+
classes.root,
155+
{
156+
[classes.expanded]: expanded,
157+
[classes.disabled]: disabled,
158+
[classes.rounded]: !square,
159+
},
160+
classNameProp,
161+
)}
162+
elevation={1}
163+
square={square}
164+
{...other}
165+
>
166+
{summary}
167+
<TransitionComponent in={expanded} timeout="auto" {...TransitionProps}>
168+
{children}
169+
</TransitionComponent>
170+
</Paper>
171+
</PureProvider>
170172
);
171173
}
172174

@@ -221,6 +223,7 @@ ExpansionPanel.propTypes = {
221223
ExpansionPanel.defaultProps = {
222224
defaultExpanded: false,
223225
disabled: false,
226+
onChange: noop,
224227
square: false,
225228
TransitionComponent: Collapse,
226229
};

packages/material-ui/src/ExpansionPanel/ExpansionPanel.test.js

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,16 @@ import React from 'react';
22
import PropTypes from 'prop-types';
33
import { assert } from 'chai';
44
import { spy } from 'sinon';
5-
import { createShallow, createMount, getClasses } from '@material-ui/core/test-utils';
6-
import Collapse from '../Collapse';
5+
import { createMount, getClasses } from '@material-ui/core/test-utils';
76
import Paper from '../Paper';
87
import ExpansionPanel from './ExpansionPanel';
98
import ExpansionPanelSummary from '../ExpansionPanelSummary';
109

1110
describe('<ExpansionPanel />', () => {
1211
let mount;
13-
let shallow;
1412
let classes;
1513

1614
before(() => {
17-
shallow = createShallow({ dive: true });
1815
mount = createMount();
1916
classes = getClasses(<ExpansionPanel>foo</ExpansionPanel>);
2017
});
@@ -48,23 +45,29 @@ describe('<ExpansionPanel />', () => {
4845
});
4946

5047
it('should render the custom className and the root class', () => {
51-
const wrapper = shallow(<ExpansionPanel className="test-class-name">foo</ExpansionPanel>);
52-
assert.strictEqual(wrapper.hasClass('test-class-name'), true);
53-
assert.strictEqual(wrapper.hasClass(classes.root), true);
48+
const wrapper = mount(<ExpansionPanel className="test-class-name">foo</ExpansionPanel>);
49+
const root = wrapper.find(`.${classes.root}`).first();
50+
assert.strictEqual(root.hasClass('test-class-name'), true);
5451
});
5552

5653
it('should render the summary and collapse elements', () => {
57-
const wrapper = shallow(
58-
<ExpansionPanel>
59-
<ExpansionPanelSummary />
54+
const wrapper = mount(
55+
<ExpansionPanel expanded>
56+
<ExpansionPanelSummary>summary</ExpansionPanelSummary>
6057
<div>Hello</div>
6158
</ExpansionPanel>,
6259
);
6360

64-
assert.strictEqual(wrapper.childAt(0).type(), ExpansionPanelSummary);
65-
const collapse = wrapper.childAt(1);
66-
assert.strictEqual(collapse.type(), Collapse);
67-
assert.strictEqual(collapse.children().length, 1, 'collapse should have 1 children div');
61+
assert.strictEqual(
62+
wrapper
63+
.find('[aria-expanded=true]')
64+
.first()
65+
.text(),
66+
'summary',
67+
);
68+
69+
const collapse = wrapper.find('Collapse');
70+
assert.strictEqual(collapse.text(), 'Hello');
6871
});
6972

7073
it('should handle the expanded prop', () => {
@@ -101,21 +104,15 @@ describe('<ExpansionPanel />', () => {
101104
assert.strictEqual(handleChange.args[0][1], false);
102105
});
103106

104-
it('when undefined onChange and controlled should not call the onChange', () => {
105-
const handleChange = spy();
106-
const wrapper = mount(
107-
<ExpansionPanel onChange={handleChange} expanded>
108-
<ExpansionPanelSummary />
109-
</ExpansionPanel>,
110-
);
111-
wrapper.setProps({ onChange: undefined });
112-
wrapper.find(ExpansionPanelSummary).simulate('click');
113-
assert.strictEqual(handleChange.callCount, 0);
114-
});
115-
116107
it('when disabled should have the disabled class', () => {
117-
const wrapper = shallow(<ExpansionPanel disabled>foo</ExpansionPanel>);
118-
assert.strictEqual(wrapper.hasClass(classes.disabled), true);
108+
const wrapper = mount(<ExpansionPanel disabled>foo</ExpansionPanel>);
109+
assert.strictEqual(
110+
wrapper
111+
.find(`.${classes.root}`)
112+
.first()
113+
.hasClass(classes.disabled),
114+
true,
115+
);
119116
});
120117

121118
it('should handle the TransitionComponent prop', () => {
@@ -149,8 +146,8 @@ describe('<ExpansionPanel />', () => {
149146

150147
describe('prop: children', () => {
151148
it('should accept an empty child', () => {
152-
shallow(
153-
<ExpansionPanel>
149+
mount(
150+
<ExpansionPanel expanded>
154151
<ExpansionPanelSummary />
155152
{null}
156153
</ExpansionPanel>,

packages/material-ui/src/ExpansionPanel/ExpansionPanelContext.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React from 'react';
2+
import PropTypes from 'prop-types';
23
import warning from 'warning';
34

45
const ExpansionPanelContext = React.createContext({
@@ -15,4 +16,14 @@ const ExpansionPanelContext = React.createContext({
1516
},
1617
});
1718

19+
export const PureProvider = React.memo(props => {
20+
const { children, ...value } = props;
21+
22+
return <ExpansionPanelContext.Provider value={value}>{children}</ExpansionPanelContext.Provider>;
23+
});
24+
25+
PureProvider.propTypes = {
26+
children: PropTypes.node,
27+
};
28+
1829
export default ExpansionPanelContext;

packages/material-ui/src/ExpansionPanelSummary/ExpansionPanelSummary.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import React from 'react';
44
import PropTypes from 'prop-types';
55
import clsx from 'clsx';
66
import ButtonBase from '../ButtonBase';
7+
import { useExpansionPanel } from '../ExpansionPanel';
78
import withStyles from '../styles/withStyles';
89

910
export const styles = theme => {
@@ -75,17 +76,15 @@ function ExpansionPanelSummary(props) {
7576
children,
7677
classes,
7778
className,
78-
disabled,
79-
expanded,
8079
expandIcon,
8180
IconButtonProps,
8281
onBlur,
83-
onChange,
8482
onClick,
8583
onFocusVisible,
8684
...other
8785
} = props;
8886
const [focused, setFocused] = React.useState(false);
87+
const { disabled, expanded, onChange } = useExpansionPanel();
8988

9089
function handleFocusVisible(event) {
9190
setFocused(true);
@@ -191,7 +190,6 @@ const noop = () => {};
191190
ExpansionPanelSummary.defaultProps = {
192191
disabled: false,
193192
onBlur: noop,
194-
onChange: noop,
195193
onClick: noop,
196194
onFocusVisible: noop,
197195
};

packages/material-ui/src/ExpansionPanelSummary/ExpansionPanelSummary.test.js

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import {
88
getClasses,
99
} from '@material-ui/core/test-utils';
1010
import ButtonBase from '../ButtonBase';
11+
import ExpansionPanel from '../ExpansionPanel';
1112
import ExpansionPanelSummary from './ExpansionPanelSummary';
1213

13-
describe('<ExpansionPanelSummary />', () => {
14+
describe.only('<ExpansionPanelSummary />', () => {
1415
let mount;
1516
let shallow;
1617
let classes;
@@ -105,11 +106,17 @@ describe('<ExpansionPanelSummary />', () => {
105106
return result;
106107
}, {});
107108

108-
const wrapper = shallow(<ExpansionPanelSummary {...handlers} />);
109+
const wrapper = mount(
110+
<ExpansionPanel expanded>
111+
<ExpansionPanelSummary {...handlers} />
112+
</ExpansionPanel>,
113+
);
114+
115+
const summary = wrapper.find('[aria-expanded]').first();
109116

110117
events.forEach(n => {
111118
const event = n.charAt(2).toLowerCase() + n.slice(3);
112-
wrapper.simulate(event, { persist: () => {} });
119+
summary.simulate(event, { persist: () => {} });
113120
assert.strictEqual(handlers[n].callCount, 1, `should have called the ${n} handler`);
114121
});
115122
});
@@ -118,7 +125,11 @@ describe('<ExpansionPanelSummary />', () => {
118125
describe('prop: onChange', () => {
119126
it('fires onChange if the summary control is clicked', () => {
120127
const handleChange = spy();
121-
const wrapper = mount(<ExpansionPanelSummary expanded={false} onChange={handleChange} />);
128+
const wrapper = mount(
129+
<ExpansionPanel expanded={false} onChange={handleChange}>
130+
<ExpansionPanelSummary />
131+
</ExpansionPanel>,
132+
);
122133

123134
const control = findOutermostIntrinsic(wrapper.find('[aria-expanded]'));
124135
const eventMock = 'woofExpansionPanelSummary';
@@ -132,8 +143,15 @@ describe('<ExpansionPanelSummary />', () => {
132143
describe('prop: click', () => {
133144
it('should trigger onClick', () => {
134145
const handleClick = spy();
135-
const wrapper = shallow(<ExpansionPanelSummary onClick={handleClick} />);
136-
wrapper.simulate('click');
146+
const wrapper = mount(
147+
<ExpansionPanel expanded={false} onChange={() => {}}>
148+
<ExpansionPanelSummary onClick={handleClick} />
149+
</ExpansionPanel>,
150+
);
151+
wrapper
152+
.find('[aria-expanded]')
153+
.first()
154+
.simulate('click');
137155
assert.strictEqual(handleClick.callCount, 1);
138156
});
139157
});

0 commit comments

Comments
 (0)