-
Notifications
You must be signed in to change notification settings - Fork 26
/
collapsible.js
76 lines (65 loc) 路 2.25 KB
/
collapsible.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
import React from 'react';
import PropTypes from 'prop-types';
import isNil from 'lodash/isNil';
import { useToggleState } from '@commercetools-uikit/hooks';
const collapsiblePropTypes = {
// This is only used to initialize the `isOpen` state once,
// when the component mounts. Therefore there should not be
// any `componentWillReceiveProps` to update the state from
// an external source.
isDefaultClosed: PropTypes.bool,
children: PropTypes.func.isRequired,
// The component can be controlled or uncontrolled.
// when uncontrolled (no isClosed passed)
// -> There may not be `onToggle`
// when controlled (isClosed passed)
// -> `onToggle` is required
isClosed: PropTypes.bool,
onToggle(props, propName, componentName, ...rest) {
const isControlledComponent = !isNil(props.isClosed);
const hasOnToggle = !isNil(props.onToggle);
// controlled
if (isControlledComponent)
return PropTypes.func.isRequired(props, propName, componentName, ...rest);
if (hasOnToggle)
return new Error(
`Invalid prop \`${propName}\` supplied to \`${componentName}\`. \`${propName}\` does not have any effect when the component is uncontrolled.`
);
// uncontrolled component does not have `onToggle` so no validation needed.
return null;
},
};
const ControlledCollapsible = props => (
<>
{props.children({
isOpen: !props.isClosed,
toggle: props.onToggle,
})}
</>
);
ControlledCollapsible.displayName = 'ControlledCollapsible';
ControlledCollapsible.propTypes = collapsiblePropTypes;
const UncontrolledCollapsible = props => {
const [isOpen, toggle] = useToggleState(!props.isDefaultClosed);
return (
<>
{props.children({
isOpen,
toggle,
})}
</>
);
};
UncontrolledCollapsible.displayName = 'UncontrolledCollapsible';
UncontrolledCollapsible.propTypes = collapsiblePropTypes;
const Collapsible = props => {
const isControlledComponent = !isNil(props.isClosed);
if (isControlledComponent) {
return <ControlledCollapsible {...props} />;
}
return <UncontrolledCollapsible {...props} />;
};
Collapsible.displayName = 'Collapsible';
Collapsible.propTypes = collapsiblePropTypes;
Collapsible.defaultProps = { isDefaultClosed: false };
export default Collapsible;