UNPKG

5.32 kBJavaScriptView Raw
1/* eslint-disable react/jsx-no-literals */
2import React, {PureComponent} from 'react';
3import PropTypes from 'prop-types';
4import chevronRightIcon from '@jetbrains/icons/chevron-right.svg';
5import chevronDownIcon from '@jetbrains/icons/chevron-down.svg';
6
7import Link from '../link/link';
8import Text from '../text/text';
9import LoaderInline from '../loader-inline/loader-inline';
10
11import Icon from '../icon';
12
13import Title from './title';
14
15import styles from './data-list.css';
16
17export const moreLessButtonStates = {
18 UNUSED: 0,
19 MORE: 1,
20 MORE_LOADING: 2,
21 LESS: 3
22};
23
24const ITEM_LEFT_OFFSET = 32;
25const LIST_LEFT_OFFSET = 24;
26
27
28export default class Item extends PureComponent {
29 static propTypes = {
30 item: PropTypes.object,
31 title: PropTypes.node,
32 items: PropTypes.array,
33 className: PropTypes.string,
34 level: PropTypes.number,
35 parentShift: PropTypes.number,
36
37 itemFormatter: PropTypes.func,
38
39 collapsible: PropTypes.bool,
40 collapsed: PropTypes.bool,
41 onCollapse: PropTypes.func,
42 onExpand: PropTypes.func,
43
44 showFocus: PropTypes.bool,
45 onFocus: PropTypes.func,
46
47 selection: PropTypes.object,
48 selectable: PropTypes.bool,
49 selected: PropTypes.bool,
50 onSelect: PropTypes.func,
51
52 showMoreLessButton: PropTypes.number,
53 onItemMoreLess: PropTypes.func
54 };
55
56 static defaultProps = {
57 items: [],
58 level: 0,
59 parentShift: 0,
60 showMoreLessButton: moreLessButtonStates.UNUSED,
61 onItemMoreLess: () => {}
62 };
63
64
65 onShowMore = () => {
66 const {onItemMoreLess, item} = this.props;
67 onItemMoreLess(item, true);
68 };
69
70 onShowLess = () => {
71 const {onItemMoreLess, item} = this.props;
72 onItemMoreLess(item, false);
73 };
74
75 onFocus = () => {
76 const {onFocus, item} = this.props;
77 onFocus(item);
78 };
79
80 onSelect = selected => {
81 const {onSelect, item} = this.props;
82 onSelect(item, selected);
83 };
84
85 renderItem = (model, parentShift) => {
86 const {
87 onFocus, onSelect, selection, level,
88 itemFormatter
89 } = this.props;
90
91 const item = itemFormatter(model);
92
93 return (
94 <Item
95 key={item.key || item.id}
96 item={model}
97 title={item.title}
98 items={item.items}
99 level={level + 1}
100 parentShift={parentShift}
101
102 itemFormatter={itemFormatter}
103
104 collapsible={item.collapsible}
105 collapsed={item.collapsed}
106 onCollapse={item.onCollapse}
107 onExpand={item.onExpand}
108
109 focused={selection.isFocused(model)}
110 showFocus={selection.isFocused(model)}
111 onFocus={onFocus}
112
113 selection={selection}
114 selectable={item.selectable}
115 selected={selection.isSelected(model)}
116 onSelect={onSelect}
117 />
118 );
119 };
120
121 render() {
122 const {
123 title, items, showMoreLessButton,
124 level, parentShift, showFocus,
125 selectable, selected,
126 collapsible, collapsed, onCollapse, onExpand
127 } = this.props;
128
129 let moreLessButton;
130 if (showMoreLessButton === moreLessButtonStates.MORE ||
131 showMoreLessButton === moreLessButtonStates.MORE_LOADING) {
132 moreLessButton = (
133 <Text comment>
134 <Link
135 inherit
136 pseudo
137 onClick={this.onShowMore}
138 >Show more</Link>
139 {showMoreLessButton === moreLessButtonStates.MORE_LOADING &&
140 <LoaderInline className={styles.showMoreLoader}/>
141 }
142 </Text>
143 );
144 } else if (showMoreLessButton === moreLessButtonStates.LESS) {
145 moreLessButton = (
146 <Text comment>
147 <Link
148 inherit
149 pseudo
150 onClick={this.onShowLess}
151 >Show less</Link>
152 </Text>
153 );
154 }
155
156 let collapserExpander = null;
157 if (collapsible) {
158 if (collapsed) {
159 collapserExpander = (
160 <div
161 className={styles.expanderBox}
162 onClick={onExpand}
163 >
164 <Icon
165 glyph={chevronRightIcon}
166 className={styles.collapseIcon}
167 data-test="ring-data-list-expand"
168 />
169 </div>
170 );
171 } else {
172 collapserExpander = (
173 <div
174 className={styles.expanderBox}
175 onClick={onCollapse}
176 >
177 <Icon
178 glyph={chevronDownIcon}
179 className={styles.collapseIcon}
180 data-test="ring-data-list-collapse"
181 />
182 </div>
183 );
184 }
185 }
186
187 const itemIsEmpty = !items.length || (collapsible && collapsed);
188 const offset = level * LIST_LEFT_OFFSET + ITEM_LEFT_OFFSET + parentShift;
189
190 return (
191 <li>
192 <Title
193 title={title}
194 focused={showFocus}
195 showFocus={showFocus}
196 selectable={selectable}
197 selected={selected}
198 collapserExpander={collapserExpander}
199 onFocus={this.onFocus}
200 onSelect={this.onSelect}
201 offset={offset}
202 />
203
204 {!itemIsEmpty ? (
205 <ul className={styles.itemContent}>
206 {items.map(model => this.renderItem(model, parentShift))}
207
208 {showMoreLessButton !== moreLessButtonStates.UNUSED
209 ? <li className={styles.showMore}>{moreLessButton}</li>
210 : null
211 }
212 </ul>
213 ) : null}
214 </li>
215 );
216 }
217}