-
Notifications
You must be signed in to change notification settings - Fork 9
/
Group.js
109 lines (96 loc) 路 2.87 KB
/
Group.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
import React from "react";
import PropTypes from "prop-types";
import Collapsible from "@paprika/collapsible";
import Item from "../Item";
const propTypes = {
children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]), // are probably an array of "Items", but could be a Spinner or anything else
isDisabled: PropTypes.bool,
onChange: PropTypes.func,
onExpand: PropTypes.func,
title: PropTypes.node.isRequired,
};
const defaultProps = {
children: [],
isDisabled: false,
onChange: () => {},
onExpand: () => {},
};
function useIsIndeterminate(checkboxRef) {
const [, setIsIndeterminate] = React.useState(null);
React.useEffect(() => {
setIsIndeterminate(checkboxRef.current.indeterminate);
}, [checkboxRef.current.indeterminate]);
}
function Group(props) {
const { children, isDisabled, onChange, onExpand, title } = props;
const [isCollapsed, setIsCollapsed] = React.useState(true);
const checkboxRef = React.useRef({});
useIsIndeterminate(checkboxRef);
let allAreChecked = React.Children.count(props.children) > 0;
let noneAreChecked = true;
React.Children.forEach(children, child => {
if (child.props.isChecked) {
noneAreChecked = false;
} else {
allAreChecked = false;
}
});
if (allAreChecked || noneAreChecked) {
checkboxRef.current.indeterminate = false;
} else if (!allAreChecked && !noneAreChecked) {
checkboxRef.current.indeterminate = true;
}
function handleOnChange() {
const allChildrenAreChecked =
children.filter(child => child.props.isChecked || child.props.isDisabled).length === children.length;
let childrenToChange = [];
if (allChildrenAreChecked) {
childrenToChange = children.filter(child => !child.props.isDisabled);
} else {
childrenToChange = children.filter(child => !child.props.isChecked && !child.props.isDisabled);
}
onChange(childrenToChange);
}
const label = (
<React.Fragment>
<input
ref={checkboxRef}
checked={allAreChecked}
type="checkbox"
disabled={isDisabled}
onChange={handleOnChange}
/>
{title}
</React.Fragment>
);
const modifiedChildren = React.Children.map(children, child => {
const newProps =
child.type.displayName === Item.displayName
? {
onChange: () => onChange([child]),
}
: null;
return React.cloneElement(child, newProps);
});
return (
<Collapsible
a11yText="umm..."
hasOnlyIconToggle
isCollapsed={isCollapsed}
isDisabled={isDisabled}
label={label}
onClick={() => {
if (isCollapsed && onExpand) {
onExpand();
}
setIsCollapsed(!isCollapsed);
}}
>
{modifiedChildren}
</Collapsible>
);
}
Group.displayName = "Group";
Group.propTypes = propTypes;
Group.defaultProps = defaultProps;
export default Group;