@performant-software/semantic-components 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +0 -0
  3. package/build/index.js +2 -0
  4. package/build/index.js.map +1 -0
  5. package/build/main.css +786 -0
  6. package/index.js +1 -0
  7. package/package.json +37 -0
  8. package/src/components/AccordionDataList.css +8 -0
  9. package/src/components/AccordionDataList.js +224 -0
  10. package/src/components/AccordionList.css +27 -0
  11. package/src/components/AccordionList.js +596 -0
  12. package/src/components/AccordionSelector.css +3 -0
  13. package/src/components/AccordionSelector.js +359 -0
  14. package/src/components/ArrowButtons.css +4 -0
  15. package/src/components/ArrowButtons.js +38 -0
  16. package/src/components/AssociatedDropdown.css +44 -0
  17. package/src/components/AssociatedDropdown.js +338 -0
  18. package/src/components/BooleanIcon.css +0 -0
  19. package/src/components/BooleanIcon.js +33 -0
  20. package/src/components/CancelButton.css +0 -0
  21. package/src/components/CancelButton.js +25 -0
  22. package/src/components/ColorButton.css +4 -0
  23. package/src/components/ColorButton.js +34 -0
  24. package/src/components/ColorPickerModal.css +3 -0
  25. package/src/components/ColorPickerModal.js +77 -0
  26. package/src/components/ColumnResize.css +9 -0
  27. package/src/components/ColumnResize.js +20 -0
  28. package/src/components/DataList.css +0 -0
  29. package/src/components/DataList.js +531 -0
  30. package/src/components/DataTable.css +43 -0
  31. package/src/components/DataTable.js +596 -0
  32. package/src/components/DataTableColumnSelector.css +10 -0
  33. package/src/components/DataTableColumnSelector.js +146 -0
  34. package/src/components/DateInput.css +6 -0
  35. package/src/components/DateInput.js +58 -0
  36. package/src/components/DatePicker.css +72 -0
  37. package/src/components/DatePicker.js +81 -0
  38. package/src/components/DescriptorField.css +0 -0
  39. package/src/components/DescriptorField.js +42 -0
  40. package/src/components/DownloadButton.css +0 -0
  41. package/src/components/DownloadButton.js +23 -0
  42. package/src/components/Draggable.css +0 -0
  43. package/src/components/Draggable.js +94 -0
  44. package/src/components/DropdownButton.css +3 -0
  45. package/src/components/DropdownButton.js +65 -0
  46. package/src/components/DropdownMenu.css +0 -0
  47. package/src/components/DropdownMenu.js +68 -0
  48. package/src/components/EditModal.css +8 -0
  49. package/src/components/EditModal.js +99 -0
  50. package/src/components/EditPage.css +7 -0
  51. package/src/components/EditPage.js +249 -0
  52. package/src/components/EmbeddedList.css +7 -0
  53. package/src/components/EmbeddedList.js +278 -0
  54. package/src/components/FileInputButton.css +0 -0
  55. package/src/components/FileInputButton.js +54 -0
  56. package/src/components/FileUpload.css +31 -0
  57. package/src/components/FileUpload.js +188 -0
  58. package/src/components/FileUploadModal.css +0 -0
  59. package/src/components/FileUploadModal.js +408 -0
  60. package/src/components/FuzzyDate.css +8 -0
  61. package/src/components/FuzzyDate.js +575 -0
  62. package/src/components/GoogleMap.css +0 -0
  63. package/src/components/GoogleMap.js +105 -0
  64. package/src/components/GooglePlacesSearch.css +0 -0
  65. package/src/components/GooglePlacesSearch.js +43 -0
  66. package/src/components/HorizontalCards.css +50 -0
  67. package/src/components/HorizontalCards.js +226 -0
  68. package/src/components/ItemCollection.css +3 -0
  69. package/src/components/ItemCollection.js +159 -0
  70. package/src/components/ItemList.css +0 -0
  71. package/src/components/ItemList.js +126 -0
  72. package/src/components/Items.css +19 -0
  73. package/src/components/Items.js +365 -0
  74. package/src/components/ItemsToggle.css +0 -0
  75. package/src/components/ItemsToggle.js +168 -0
  76. package/src/components/KeyboardField.css +4 -0
  77. package/src/components/KeyboardField.js +147 -0
  78. package/src/components/LazyDocument.css +21 -0
  79. package/src/components/LazyDocument.js +113 -0
  80. package/src/components/LazyImage.css +21 -0
  81. package/src/components/LazyImage.js +119 -0
  82. package/src/components/LazyVideo.css +21 -0
  83. package/src/components/LazyVideo.js +131 -0
  84. package/src/components/LinkButton.css +8 -0
  85. package/src/components/LinkButton.js +23 -0
  86. package/src/components/LinkLabel.css +8 -0
  87. package/src/components/LinkLabel.js +29 -0
  88. package/src/components/List.css +8 -0
  89. package/src/components/List.js +761 -0
  90. package/src/components/ListFilters.css +0 -0
  91. package/src/components/ListFilters.js +408 -0
  92. package/src/components/ListLoader.css +8 -0
  93. package/src/components/ListLoader.js +32 -0
  94. package/src/components/ListTable.css +3 -0
  95. package/src/components/ListTable.js +86 -0
  96. package/src/components/LoginModal.css +7 -0
  97. package/src/components/LoginModal.js +102 -0
  98. package/src/components/MasonryGrid.css +48 -0
  99. package/src/components/MasonryGrid.js +202 -0
  100. package/src/components/MediaGallery.css +37 -0
  101. package/src/components/MediaGallery.js +148 -0
  102. package/src/components/MediaGrid.css +72 -0
  103. package/src/components/MediaGrid.js +74 -0
  104. package/src/components/MediaList.css +3 -0
  105. package/src/components/MediaList.js +98 -0
  106. package/src/components/ModalDropdown.css +11 -0
  107. package/src/components/ModalDropdown.js +84 -0
  108. package/src/components/NestedAccordion.css +41 -0
  109. package/src/components/NestedAccordion.js +276 -0
  110. package/src/components/PhotoViewer.css +3 -0
  111. package/src/components/PhotoViewer.js +36 -0
  112. package/src/components/PlayButton.css +3 -0
  113. package/src/components/PlayButton.js +37 -0
  114. package/src/components/RemoteDropdown.css +13 -0
  115. package/src/components/RemoteDropdown.js +368 -0
  116. package/src/components/SaveButton.css +0 -0
  117. package/src/components/SaveButton.js +31 -0
  118. package/src/components/Section.css +0 -0
  119. package/src/components/Section.js +41 -0
  120. package/src/components/Selectize.css +11 -0
  121. package/src/components/Selectize.js +297 -0
  122. package/src/components/SelectizeHeader.css +3 -0
  123. package/src/components/SelectizeHeader.js +40 -0
  124. package/src/components/TabbedModal.css +14 -0
  125. package/src/components/TabbedModal.js +165 -0
  126. package/src/components/TabsMenu.css +0 -0
  127. package/src/components/TabsMenu.js +35 -0
  128. package/src/components/TagsList.css +0 -0
  129. package/src/components/TagsList.js +43 -0
  130. package/src/components/Thumbnail.css +0 -0
  131. package/src/components/Thumbnail.js +47 -0
  132. package/src/components/Toaster.css +9 -0
  133. package/src/components/Toaster.js +73 -0
  134. package/src/components/VideoFrameSelector.css +3 -0
  135. package/src/components/VideoFrameSelector.js +148 -0
  136. package/src/components/VideoPlayer.css +3 -0
  137. package/src/components/VideoPlayer.js +55 -0
  138. package/src/components/VideoPlayerButton.css +17 -0
  139. package/src/components/VideoPlayerButton.js +17 -0
  140. package/src/components/ViewXML.css +0 -0
  141. package/src/components/ViewXML.js +72 -0
  142. package/src/i18n/en.json +204 -0
  143. package/src/i18n/i18n.js +24 -0
  144. package/src/index.js +76 -0
  145. package/types/components/AccordionDataList.js.flow +224 -0
  146. package/types/components/AccordionList.js.flow +596 -0
  147. package/types/components/AccordionSelector.js.flow +359 -0
  148. package/types/components/ArrowButtons.js.flow +38 -0
  149. package/types/components/AssociatedDropdown.js.flow +338 -0
  150. package/types/components/BooleanIcon.js.flow +33 -0
  151. package/types/components/CancelButton.js.flow +25 -0
  152. package/types/components/ColorButton.js.flow +34 -0
  153. package/types/components/ColorPickerModal.js.flow +77 -0
  154. package/types/components/ColumnResize.js.flow +20 -0
  155. package/types/components/DataList.js.flow +531 -0
  156. package/types/components/DataTable.js.flow +596 -0
  157. package/types/components/DataTableColumnSelector.js.flow +146 -0
  158. package/types/components/DataView.js.flow +125 -0
  159. package/types/components/DateInput.js.flow +58 -0
  160. package/types/components/DatePicker.js.flow +81 -0
  161. package/types/components/DescriptorField.js.flow +42 -0
  162. package/types/components/DownloadButton.js.flow +23 -0
  163. package/types/components/Draggable.js.flow +94 -0
  164. package/types/components/DropdownButton.js.flow +65 -0
  165. package/types/components/DropdownMenu.js.flow +68 -0
  166. package/types/components/EditModal.js.flow +99 -0
  167. package/types/components/EditPage.js.flow +249 -0
  168. package/types/components/EmbeddedList.js.flow +278 -0
  169. package/types/components/FileInputButton.js.flow +54 -0
  170. package/types/components/FileUpload.js.flow +188 -0
  171. package/types/components/FileUploadModal.js.flow +408 -0
  172. package/types/components/FuzzyDate.js.flow +575 -0
  173. package/types/components/GoogleMap.js.flow +105 -0
  174. package/types/components/GooglePlacesSearch.js.flow +43 -0
  175. package/types/components/HorizontalCards.js.flow +226 -0
  176. package/types/components/ItemCollection.js.flow +159 -0
  177. package/types/components/ItemList.js.flow +126 -0
  178. package/types/components/Items.js.flow +365 -0
  179. package/types/components/ItemsToggle.js.flow +168 -0
  180. package/types/components/KeyboardField.js.flow +147 -0
  181. package/types/components/LazyDocument.js.flow +113 -0
  182. package/types/components/LazyImage.js.flow +119 -0
  183. package/types/components/LazyVideo.js.flow +131 -0
  184. package/types/components/LinkButton.js.flow +23 -0
  185. package/types/components/LinkLabel.js.flow +29 -0
  186. package/types/components/List.js.flow +761 -0
  187. package/types/components/ListFilters.js.flow +408 -0
  188. package/types/components/ListLoader.js.flow +32 -0
  189. package/types/components/ListTable.js.flow +86 -0
  190. package/types/components/LoginModal.js.flow +102 -0
  191. package/types/components/MasonryGrid.js.flow +202 -0
  192. package/types/components/MediaGallery.js.flow +148 -0
  193. package/types/components/MediaGrid.js.flow +74 -0
  194. package/types/components/MediaList.js.flow +98 -0
  195. package/types/components/MenuBar.js.flow +77 -0
  196. package/types/components/MenuSidebar.js.flow +72 -0
  197. package/types/components/ModalDropdown.js.flow +84 -0
  198. package/types/components/NestedAccordion.js.flow +276 -0
  199. package/types/components/PhotoViewer.js.flow +36 -0
  200. package/types/components/PlayButton.js.flow +37 -0
  201. package/types/components/RemoteDropdown.js.flow +368 -0
  202. package/types/components/SaveButton.js.flow +31 -0
  203. package/types/components/Section.js.flow +41 -0
  204. package/types/components/Selectize.js.flow +297 -0
  205. package/types/components/SelectizeHeader.js.flow +40 -0
  206. package/types/components/TabbedModal.js.flow +165 -0
  207. package/types/components/TabsMenu.js.flow +35 -0
  208. package/types/components/TagsList.js.flow +43 -0
  209. package/types/components/Thumbnail.js.flow +47 -0
  210. package/types/components/Toaster.js.flow +73 -0
  211. package/types/components/VideoFrameSelector.js.flow +148 -0
  212. package/types/components/VideoPlayer.js.flow +55 -0
  213. package/types/components/VideoPlayerButton.js.flow +17 -0
  214. package/types/components/ViewXML.js.flow +72 -0
  215. package/types/hooks/Imageable.js.flow +54 -0
  216. package/types/i18n/i18n.js.flow +24 -0
  217. package/types/index.js.flow +78 -0
  218. package/webpack.config.js +3 -0
@@ -0,0 +1,596 @@
1
+ // @flow
2
+
3
+ import { Browser } from '@performant-software/shared-components';
4
+ import React, { Component, createRef, type Element } from 'react';
5
+ import {
6
+ Checkbox,
7
+ Button,
8
+ Loader,
9
+ Popup,
10
+ Ref,
11
+ Table
12
+ } from 'semantic-ui-react';
13
+ import _ from 'underscore';
14
+ import i18n from '../i18n/i18n';
15
+ import ColumnResize from './ColumnResize';
16
+ import useColumnSelector from './DataTableColumnSelector';
17
+ import useList from './List';
18
+ import './DataTable.css';
19
+
20
+ import type { Action } from './List';
21
+
22
+ type Column = {
23
+ className?: string,
24
+ hidden?: boolean,
25
+ label?: string,
26
+ name: string,
27
+ render?: (item: any) => void,
28
+ renderHeader?: (item: any) => void,
29
+ resolve?: (item: any) => void,
30
+ sortable: boolean
31
+ };
32
+
33
+ type Props = {
34
+ actions: Array<Action>,
35
+ className: string,
36
+ columns: Array<Column>,
37
+ expandableRows: boolean,
38
+ expandPanel: (item: any, activePanel: any) => Component<any>,
39
+ isRowSelected: (item: any) => boolean,
40
+ items: ?Array<any>,
41
+ loading: boolean,
42
+ onClearSelected: () => void,
43
+ onColumnClick: (column: Column) => void,
44
+ onRowSelect?: (item: any)=>void,
45
+ onSelectAll: (items: Array<any>)=>void,
46
+ renderEmptyMessage: () => Element<any>,
47
+ renderEmptyRow?: () => void,
48
+ renderItem?: (item: any, index: number, children?: any) => Element<any>,
49
+ sortColumn?: string,
50
+ sortDirection?: string,
51
+ t: (key: string) => string,
52
+ tableProps: any,
53
+ selectable?: boolean,
54
+ selectedRows: Array<{id: number}>,
55
+ };
56
+
57
+ type State = {
58
+ activePanel: any,
59
+ resize: ?{
60
+ columnRef: typeof Ref,
61
+ offset: number
62
+ }
63
+ };
64
+
65
+ class DataTable extends Component<Props, State> {
66
+ static defaultProps: any;
67
+
68
+ columnRefs: any;
69
+ onClick: (e: Event) => void;
70
+ onMouseMove: (e: Event) => void;
71
+ onMouseUp: (e: Event) => void;
72
+
73
+ /**
74
+ * Constructs a new DataTable component.
75
+ *
76
+ * @param props
77
+ */
78
+ constructor(props: Props) {
79
+ super(props);
80
+
81
+ this.state = {
82
+ resize: null,
83
+ activePanel: null
84
+ };
85
+
86
+ this.initializeColumnRefs();
87
+
88
+ this.onClick = this.onPreventClick.bind(this);
89
+ this.onMouseMove = this.onColumnResize.bind(this);
90
+ this.onMouseUp = this.afterColumnResize.bind(this);
91
+ }
92
+
93
+ /**
94
+ * If the resize object is present on the state, sets the capture click handler on the document and
95
+ * clears the resize object on the state.
96
+ */
97
+ afterColumnResize() {
98
+ if (this.state.resize && Browser.isBrowser()) {
99
+ document.addEventListener('click', this.onClick, true);
100
+ this.setState({ resize: undefined });
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Initializes a ref for each table column.
106
+ */
107
+ initializeColumnRefs() {
108
+ this.columnRefs = {};
109
+
110
+ _.each(this.props.columns, (c) => {
111
+ this.columnRefs[c.name] = createRef();
112
+ });
113
+ }
114
+
115
+ /**
116
+ * Adds the mousemove and mouseup event listeners for dynamic column resizing.
117
+ */
118
+ componentDidMount() {
119
+ if (Browser.isBrowser()) {
120
+ document.addEventListener('mousemove', this.onMouseMove);
121
+ document.addEventListener('mouseup', this.onMouseUp);
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Removes the mousemove and mouseup event listeners.
127
+ */
128
+ componentWillUnmount() {
129
+ if (Browser.isBrowser()) {
130
+ document.removeEventListener('mousemove', this.onMouseMove);
131
+ document.removeEventListener('mouseup', this.onMouseUp);
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Returns the actual column count. This will be the number of columns +1 if the table allows actions.
137
+ *
138
+ * @returns {number}
139
+ */
140
+ getColumnCount() {
141
+ let columnCount = this.props.columns.length;
142
+
143
+ if (this.props.actions && this.props.actions.length) {
144
+ columnCount += 1;
145
+ }
146
+
147
+ return columnCount;
148
+ }
149
+
150
+ /**
151
+ * Resizes the current column based on the user's mouse position.
152
+ *
153
+ * @param e
154
+ */
155
+ onColumnResize(e: MouseEvent) {
156
+ const { resize } = this.state;
157
+
158
+ if (resize) {
159
+ const { columnRef, offset } = resize;
160
+ columnRef.current.style.width = `${offset + e.pageX}px`;
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Stops progagation of the onclick event. The column resizing seems to trigger the 'click' event on the <th>
166
+ * containing the <div> used to resize the column. Since the <th> already provides a 'click' event, this makes for
167
+ * an awkward user experience because it will trigger a column sort each time a column is resized.
168
+ *
169
+ * This function will capture the onclick prior to it bubbling to the <th> element and prevent it from happening. It
170
+ * will also remove the event listener from the document so that clicks elsewhere in the document are not prevented.
171
+ *
172
+ * @param e
173
+ */
174
+ onPreventClick(e: Event) {
175
+ e.stopPropagation();
176
+
177
+ if (Browser.isBrowser()) {
178
+ document.removeEventListener('click', this.onClick, true);
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Selects all of the items in the current collection.
184
+ *
185
+ * @param allSelected
186
+ */
187
+ onSelectAll(allSelected) {
188
+ let items;
189
+
190
+ if (allSelected) {
191
+ items = [...this.props.items || []];
192
+ } else {
193
+ items = _.reject(this.props.items, this.props.isRowSelected.bind(this));
194
+ }
195
+
196
+ _.each(items, this.props.onRowSelect && this.props.onRowSelect.bind(this));
197
+ }
198
+
199
+ /**
200
+ * Renders the DataTable component.
201
+ *
202
+ * @returns {*}
203
+ */
204
+ render() {
205
+ return (
206
+ <Table
207
+ className='data-table'
208
+ {...this.props.tableProps}
209
+ >
210
+ <Table.Header>
211
+ <Table.Row>
212
+ { this.renderSelectHeader() }
213
+ { this.props.columns.map(this.renderHeaderCell.bind(this)) }
214
+ { this.renderActionsHeader() }
215
+ </Table.Row>
216
+ </Table.Header>
217
+ <Table.Body>
218
+ { this.props.items && this.props.items.map(this.renderItem.bind(this)) }
219
+ { this.renderEmptyTableRow() }
220
+ { this.renderLoading() }
221
+ </Table.Body>
222
+ </Table>
223
+ );
224
+ }
225
+
226
+ /**
227
+ * Renders the action button for the passed item and action.
228
+ *
229
+ * @param item
230
+ * @param action
231
+ * @param index
232
+ *
233
+ * @returns {*}
234
+ */
235
+ renderActionButton(item: any, index: number, action: Action) {
236
+ // If the action specified its own render function, return the result of the function call
237
+ if (action.render) {
238
+ return action.render(item, index);
239
+ }
240
+
241
+ const actionButton = (
242
+ <Button
243
+ basic
244
+ compact
245
+ color={action.color}
246
+ icon={action.icon}
247
+ key={`${action.name}-${index}`}
248
+ onClick={action.onClick && action.onClick.bind(this, item)}
249
+ title={action.title}
250
+ />
251
+ );
252
+
253
+ // Wrap the button in a popup if the action specifies a popup attribute
254
+ if (action.popup) {
255
+ const { content, title } = action.popup;
256
+
257
+ return (
258
+ <Popup
259
+ content={content}
260
+ header={title}
261
+ hideOnScroll
262
+ mouseEnterDelay={500}
263
+ position='top right'
264
+ trigger={actionButton}
265
+ />
266
+ );
267
+ }
268
+
269
+ // Otherwise, simply return the button
270
+ return actionButton;
271
+ }
272
+
273
+ /**
274
+ * Renders the actions for the passed item.
275
+ *
276
+ * @param item
277
+ * @param index
278
+ *
279
+ * @returns {null|*}
280
+ */
281
+ renderActions(item: any, index: number) {
282
+ if (!(this.props.actions && this.props.actions.length)) {
283
+ return null;
284
+ }
285
+
286
+ const actions = this.props.actions
287
+ .filter((action) => !action.accept || action.accept(item))
288
+ .map((action) => {
289
+ let defaults = {};
290
+
291
+ if (action.name === 'edit') {
292
+ defaults = {
293
+ popup: {
294
+ title: i18n.t('DataTable.actions.edit.title'),
295
+ content: i18n.t('DataTable.actions.edit.content')
296
+ }
297
+ };
298
+ } else if (action.name === 'copy') {
299
+ defaults = {
300
+ popup: {
301
+ title: i18n.t('DataTable.actions.copy.title'),
302
+ content: i18n.t('DataTable.actions.copy.content')
303
+ }
304
+ };
305
+ } else if (action.name === 'delete') {
306
+ defaults = {
307
+ popup: {
308
+ title: i18n.t('DataTable.actions.delete.title'),
309
+ content: i18n.t('DataTable.actions.delete.content')
310
+ }
311
+ };
312
+ }
313
+
314
+ return _.defaults(action, defaults);
315
+ });
316
+
317
+ return (
318
+ <Table.Cell
319
+ className='actions-cell'
320
+ key={index}
321
+ >
322
+ { actions.map(this.renderActionButton.bind(this, item, index)) }
323
+ </Table.Cell>
324
+ );
325
+ }
326
+
327
+ /**
328
+ * Renders the action list header.
329
+ *
330
+ * @returns {null|*}
331
+ */
332
+ renderActionsHeader() {
333
+ if (!(this.props.actions && this.props.actions.length)) {
334
+ return null;
335
+ }
336
+
337
+ return (
338
+ <Table.HeaderCell>
339
+ { i18n.t('DataTable.columns.actions') }
340
+ </Table.HeaderCell>
341
+ );
342
+ }
343
+
344
+ /**
345
+ * Renders the table cell for the passed item/column.
346
+ *
347
+ * @param item
348
+ * @param column
349
+ *
350
+ * @returns {*}
351
+ */
352
+ renderCell(item: any, column: Column) {
353
+ if (column.hidden) {
354
+ return null;
355
+ }
356
+
357
+ let value;
358
+
359
+ if (column.render) {
360
+ value = column.render(item);
361
+ } else if (column.resolve) {
362
+ value = column.resolve(item);
363
+ } else {
364
+ value = item[column.name];
365
+ }
366
+
367
+ return (
368
+ <Table.Cell
369
+ key={`${item.id}-${column.name}`}
370
+ className={column.className}
371
+ >
372
+ { value }
373
+ </Table.Cell>
374
+ );
375
+ }
376
+
377
+ /**
378
+ * Renders the empty table row.
379
+ *
380
+ * @returns {null|*}
381
+ */
382
+ renderEmptyTableRow() {
383
+ if (this.props.loading || (this.props.items && this.props.items.length)) {
384
+ return null;
385
+ }
386
+
387
+ if (this.props.renderEmptyRow) {
388
+ return this.props.renderEmptyRow();
389
+ }
390
+
391
+ return (
392
+ <Table.Row>
393
+ <Table.Cell
394
+ colSpan={this.getColumnCount()}
395
+ textAlign='center'
396
+ >
397
+ <div className='empty-container'>
398
+ { this.props.renderEmptyMessage() }
399
+ </div>
400
+ </Table.Cell>
401
+ </Table.Row>
402
+ );
403
+ }
404
+
405
+ /**
406
+ * Renders the table header cell for the passed column.
407
+ *
408
+ * @param column
409
+ *
410
+ * @returns {*}
411
+ */
412
+ renderHeaderCell(column: Column) {
413
+ if (column.hidden) {
414
+ return null;
415
+ }
416
+
417
+ if (column.renderHeader) {
418
+ return column.renderHeader();
419
+ }
420
+
421
+ return (
422
+ <Ref
423
+ innerRef={this.columnRefs[column.name]}
424
+ >
425
+ <Table.HeaderCell
426
+ key={column.name}
427
+ sorted={this.props.sortColumn === column.name ? this.props.sortDirection : null}
428
+ onClick={this.props.onColumnClick.bind(this, column)}
429
+ >
430
+ { column.label }
431
+ <ColumnResize
432
+ onMouseDown={(e: MouseEvent) => {
433
+ const columnRef = this.columnRefs[column.name];
434
+ const offset = columnRef.current.offsetWidth - e.pageX;
435
+ this.setState({ resize: { columnRef, offset } });
436
+ }}
437
+ />
438
+ </Table.HeaderCell>
439
+ </Ref>
440
+ );
441
+ }
442
+
443
+ /**
444
+ * Renders the table row for the passed item.
445
+ *
446
+ * @param item
447
+ * @param index
448
+ *
449
+ * @returns {*}
450
+ */
451
+ renderItem(item: any, index: number) {
452
+ const children = [
453
+ this.renderSelectCheckbox(item, index),
454
+ this.props.columns.map(this.renderCell.bind(this, item)),
455
+ this.renderActions(item, index)
456
+ ];
457
+
458
+ const handleCellClick = (e) => {
459
+ // only target table cells, not action buttons or checkboxes, etc.
460
+ if (e.target.nodeName === 'TD') {
461
+ this.setState((state) => ({
462
+ activePanel: state.activePanel === item.id ? '' : item.id
463
+ }));
464
+ }
465
+ };
466
+
467
+ if (this.props.renderItem) {
468
+ return this.props.renderItem(item, index, children);
469
+ }
470
+
471
+ return (
472
+ <>
473
+ <Table.Row
474
+ key={index}
475
+ onClick={this.props.expandableRows ? handleCellClick : () => { }}
476
+ className={this.props.expandableRows ? 'expandable' : ''}
477
+ >
478
+ { children }
479
+ </Table.Row>
480
+ { this.props.expandableRows && (
481
+ <Table.Row
482
+ className={this.state.activePanel === item.id ? 'expanded-panel' : 'hidden'}
483
+ >
484
+ { this.props.expandPanel && this.props.expandPanel(item, this.state.activePanel) }
485
+ </Table.Row>
486
+ )}
487
+ </>
488
+ );
489
+ }
490
+
491
+ renderLoading() {
492
+ if (!this.props.loading) {
493
+ return null;
494
+ }
495
+
496
+ return (
497
+ <Table.Row>
498
+ <Table.Cell
499
+ colSpan={this.getColumnCount()}
500
+ textAlign='center'
501
+ >
502
+ <Loader
503
+ active
504
+ content={i18n.t('DataTable.loading')}
505
+ inline
506
+ />
507
+ </Table.Cell>
508
+ </Table.Row>
509
+ );
510
+ }
511
+
512
+ /**
513
+ * Renders the select checkbox for the passed item.
514
+ *
515
+ * @returns {null|*}
516
+ */
517
+ renderSelectCheckbox(item, index) {
518
+ if (!(this.props.selectable && this.props.onRowSelect && this.props.isRowSelected)) {
519
+ return null;
520
+ }
521
+
522
+ return (
523
+ <Table.Cell
524
+ className='select-cell'
525
+ key={`select-cell-${index}`}
526
+ >
527
+ <Checkbox
528
+ onClick={this.props.onRowSelect.bind(this, item)}
529
+ checked={this.props.isRowSelected(item)}
530
+ />
531
+ </Table.Cell>
532
+ );
533
+ }
534
+
535
+ /**
536
+ * Renders the select list header.
537
+ *
538
+ * @returns {null|*}
539
+ */
540
+ renderSelectHeader() {
541
+ if (!this.props.selectable) {
542
+ return null;
543
+ }
544
+
545
+ const allSelected = this.props.items
546
+ && this.props.items.length
547
+ && _.every(this.props.items, this.props.isRowSelected.bind(this));
548
+
549
+ return (
550
+ <Table.HeaderCell
551
+ className='select-cell'
552
+ >
553
+ <Checkbox
554
+ onClick={this.onSelectAll.bind(this, allSelected)}
555
+ checked={allSelected}
556
+ />
557
+ </Table.HeaderCell>
558
+ );
559
+ }
560
+ }
561
+
562
+ DataTable.defaultProps = {
563
+ actions: undefined,
564
+ addButton: {
565
+ location: 'top',
566
+ color: 'green'
567
+ },
568
+ buttons: [],
569
+ count: 0,
570
+ className: '',
571
+ expandableRows: false,
572
+ expandPanel: undefined,
573
+ filters: undefined,
574
+ items: [],
575
+ loading: false,
576
+ modal: undefined,
577
+ page: 1,
578
+ pages: 1,
579
+ onColumnClick: () => {},
580
+ onCopy: undefined,
581
+ onPageChange: () => {},
582
+ renderDeleteModal: undefined,
583
+ renderEmptyRow: undefined,
584
+ renderSearch: undefined,
585
+ renderItem: undefined,
586
+ showRecordCount: false,
587
+ selectedRows: [],
588
+ sortColumn: undefined,
589
+ sortDirection: undefined,
590
+ };
591
+
592
+ export default useColumnSelector(useList(DataTable));
593
+
594
+ export type {
595
+ Column
596
+ };