@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,226 @@
1
+ // @flow
2
+
3
+ import React, {
4
+ useCallback,
5
+ useEffect,
6
+ useRef,
7
+ useState
8
+ } from 'react';
9
+ import _ from 'underscore';
10
+ import {
11
+ Button,
12
+ Card,
13
+ Header,
14
+ Image,
15
+ Ref
16
+ } from 'semantic-ui-react';
17
+ import './HorizontalCards.css';
18
+
19
+ type Props = {
20
+ inlineImage?: boolean,
21
+ items: Array<any>,
22
+ onClick?: (item: any, index: number) => void,
23
+ perPage: number,
24
+ renderDescription?: (item: any) => Element<any> | string,
25
+ renderExtra?: (item: any) => Element<any> | string,
26
+ renderHeader?: (item: any) => Element<any> | string,
27
+ renderImage: (item: any) => string,
28
+ renderMeta?: (item: any) => Element<any> | string,
29
+ };
30
+
31
+ const HorizontalCards = (props: Props) => {
32
+ const [marginWidth, setMarginWidth] = useState(0);
33
+ const [pageWidth, setPageWidth] = useState(0);
34
+ const [scrollPage, setScrollPage] = useState(0);
35
+ const [scrollPages, setScrollPages] = useState(0);
36
+
37
+ const ref = useRef();
38
+
39
+ /**
40
+ * Sets the number of pages and total page width on the state.
41
+ */
42
+ useEffect(() => {
43
+ const instance = ref.current;
44
+
45
+ if (instance) {
46
+ const { clientWidth, scrollWidth } = instance;
47
+
48
+ setPageWidth(clientWidth);
49
+ setScrollPages(Math.ceil(scrollWidth / clientWidth));
50
+
51
+ const child = instance.firstChild;
52
+ if (child) {
53
+ const style = window.getComputedStyle(child);
54
+ const leftMargin = parseFloat(style.marginLeft) || 0;
55
+ const rightMargin = parseFloat(style.marginRight) || 0;
56
+
57
+ setMarginWidth(leftMargin + rightMargin);
58
+ }
59
+ }
60
+ }, []);
61
+
62
+ /**
63
+ * Sets the total number of pages on the state.
64
+ */
65
+ useEffect(() => {
66
+ const instance = ref.current;
67
+
68
+ if (instance) {
69
+ const { scrollWidth } = instance;
70
+ setScrollPages(Math.ceil(scrollWidth / pageWidth));
71
+ }
72
+ }, [pageWidth]);
73
+
74
+ /**
75
+ * Scrolls to the new position once the page changes.
76
+ */
77
+ useEffect(() => {
78
+ const instance = ref.current;
79
+
80
+ if (instance) {
81
+ instance.scrollTo({ left: (scrollPage * pageWidth), behavior: 'smooth' });
82
+ }
83
+ }, [scrollPage, pageWidth]);
84
+
85
+ /**
86
+ * Sets the current page number on the state.
87
+ *
88
+ * @type {function(*): void}
89
+ */
90
+ const onPageChange = useCallback((increment) => {
91
+ let nextPage = scrollPage + increment;
92
+
93
+ if (nextPage < 0) {
94
+ nextPage = scrollPages;
95
+ } else if (nextPage >= scrollPages) {
96
+ nextPage = 0;
97
+ }
98
+
99
+ setScrollPage(nextPage);
100
+ }, [scrollPage, scrollPages]);
101
+
102
+ /**
103
+ * Returns the flex-box style based on the page width.
104
+ *
105
+ * @type {function(): {flex: string}}
106
+ */
107
+ const getCardStyle = useCallback(() => ({
108
+ flex: `0 0 ${(pageWidth / props.perPage) - marginWidth}px`
109
+ }), [pageWidth, marginWidth, props.perPage]);
110
+
111
+ /**
112
+ * Renders the card component. If a "route" prop is passed, the component is wrapped in a Link.
113
+ *
114
+ * @param item
115
+ * @param index
116
+ *
117
+ * @returns {JSX.Element}
118
+ */
119
+ const renderCard = (item, index) => (
120
+ <Card
121
+ link
122
+ onClick={() => {
123
+ if (props.onClick) {
124
+ props.onClick(item, index);
125
+ }
126
+ }}
127
+ style={getCardStyle()}
128
+ >
129
+ { !props.inlineImage && renderImage(item) }
130
+ <Card.Content>
131
+ { props.inlineImage && renderImage(item) }
132
+ { props.renderHeader && (
133
+ <Card.Header
134
+ as={Header}
135
+ size='small'
136
+ >
137
+ { props.renderHeader(item) }
138
+ </Card.Header>
139
+ )}
140
+ { props.renderMeta && (
141
+ <Card.Meta>
142
+ { props.renderMeta(item) }
143
+ </Card.Meta>
144
+ )}
145
+ { props.renderDescription && (
146
+ <Card.Description>
147
+ { props.renderDescription(item) }
148
+ </Card.Description>
149
+ )}
150
+ </Card.Content>
151
+ { props.renderExtra && (
152
+ <Card.Content
153
+ extra
154
+ >
155
+ { props.renderExtra(item) }
156
+ </Card.Content>
157
+ )}
158
+ </Card>
159
+ );
160
+
161
+ /**
162
+ * Renders the image based on the return type of the renderImage prop. String values returned will be assumed to be
163
+ * a src attribute for the image.
164
+ *
165
+ * @type {(function(*=): (*))|*}
166
+ */
167
+ const renderImage = useCallback((item) => {
168
+ const image = props.renderImage(item);
169
+
170
+ if (_.isString(image) || !image) {
171
+ return (
172
+ <Image
173
+ className='image-placeholder'
174
+ src={image}
175
+ style={{
176
+ objectFit: 'cover'
177
+ }}
178
+ />
179
+ );
180
+ }
181
+
182
+ return image;
183
+ }, [props.renderImage]);
184
+
185
+ return (
186
+ <div
187
+ className='horizontal-cards'
188
+ >
189
+ <Ref
190
+ innerRef={ref}
191
+ >
192
+ <Card.Group>
193
+ { _.map(props.items, renderCard.bind(this)) }
194
+ </Card.Group>
195
+ </Ref>
196
+ <div
197
+ className='button-container'
198
+ >
199
+ { scrollPages > 1 && (
200
+ <div
201
+ className='pagination'
202
+ >
203
+ <Button
204
+ basic
205
+ circular
206
+ icon='angle left'
207
+ onClick={onPageChange.bind(this, -1)}
208
+ />
209
+ <Button
210
+ basic
211
+ circular
212
+ icon='angle right'
213
+ onClick={onPageChange.bind(this, 1)}
214
+ />
215
+ </div>
216
+ )}
217
+ </div>
218
+ </div>
219
+ );
220
+ };
221
+
222
+ HorizontalCards.defaultProps = {
223
+ perPage: 4
224
+ };
225
+
226
+ export default HorizontalCards;
@@ -0,0 +1,159 @@
1
+ // @flow
2
+
3
+ import { InfiniteScroll } from '@performant-software/shared-components';
4
+ import React, { Component } from 'react';
5
+ import uuid from 'react-uuid';
6
+ import { Loader } from 'semantic-ui-react';
7
+ import i18n from '../i18n/i18n';
8
+ import Items from './Items';
9
+ import './ItemCollection.css';
10
+
11
+ type Props = {
12
+ className?: string,
13
+ context: {
14
+ current: HTMLElement
15
+ },
16
+ items: Array<any>,
17
+ loading?: boolean,
18
+ onBottomReached?: (page: number) => void,
19
+ onDelete: (item: any) => void,
20
+ onSave?: (item: any) => void,
21
+ perPage: number,
22
+ scrollOffset: number
23
+ };
24
+
25
+ type State = {
26
+ page: number
27
+ };
28
+
29
+ class ItemCollection extends Component<Props, State> {
30
+ static defaultProps: any;
31
+
32
+ /**
33
+ * Constructs a new ItemCollection component.
34
+ *
35
+ * @param props
36
+ */
37
+ constructor(props: Props) {
38
+ super(props);
39
+
40
+ this.state = {
41
+ page: 1
42
+ };
43
+ }
44
+
45
+ /**
46
+ * Returns the concatenated class names.
47
+ *
48
+ * @returns {string}
49
+ */
50
+ getClassName() {
51
+ const classNames = ['item-collection'];
52
+
53
+ if (this.props.className) {
54
+ classNames.push(this.props.className);
55
+ }
56
+
57
+ return classNames.join(' ');
58
+ }
59
+
60
+ /**
61
+ * Returns the list of items to render based on the current page.
62
+ *
63
+ * @returns {Array<T>|*[]}
64
+ */
65
+ getItems(): Array<any> {
66
+ const endIndex = this.state.page * this.props.perPage;
67
+ return (this.props.items && this.props.items.slice(0, endIndex)) || [];
68
+ }
69
+
70
+ /**
71
+ * Increments the page number and fetches the data.
72
+ */
73
+ onBottomReached() {
74
+ if (this.props.loading) {
75
+ return;
76
+ }
77
+
78
+ this.setState((state) => ({ page: state.page + 1 }), () => {
79
+ if (this.props.onBottomReached) {
80
+ this.props.onBottomReached(this.state.page);
81
+ }
82
+ });
83
+ }
84
+
85
+ /**
86
+ * Calls the onDelete prop and returns a promise.
87
+ *
88
+ * @param item
89
+ *
90
+ * @returns {Promise<unknown>}
91
+ */
92
+ onDelete(item: any) {
93
+ this.props.onDelete(item);
94
+ return Promise.resolve();
95
+ }
96
+
97
+ /**
98
+ * Calls the onSave prop and returns a promise.
99
+ *
100
+ * @param item
101
+ *
102
+ * @returns {Promise<unknown>}
103
+ */
104
+ onSave(item: any) {
105
+ if (this.props.onSave) {
106
+ const uid = item.uid ? item.uid : uuid();
107
+ this.props.onSave({ ...item, uid });
108
+ }
109
+
110
+ return Promise.resolve();
111
+ }
112
+
113
+ /**
114
+ * Renders the ItemCollection component.
115
+ *
116
+ * @returns {*}
117
+ */
118
+ render() {
119
+ return (
120
+ <InfiniteScroll
121
+ context={this.props.context}
122
+ offset={this.props.scrollOffset}
123
+ onBottomReached={this.onBottomReached.bind(this)}
124
+ >
125
+ <Items
126
+ {...this.props}
127
+ items={this.getItems()}
128
+ className={this.getClassName()}
129
+ onDelete={this.onDelete.bind(this)}
130
+ onSave={this.onSave.bind(this)}
131
+ >
132
+ <Loader
133
+ active={this.props.loading}
134
+ content={i18n.t('Common.messages.loading')}
135
+ />
136
+ </Items>
137
+ </InfiniteScroll>
138
+ );
139
+ }
140
+ }
141
+
142
+ ItemCollection.defaultProps = {
143
+ addButton: {
144
+ location: 'top'
145
+ },
146
+ buttons: [],
147
+ className: '',
148
+ configurable: true,
149
+ modal: undefined,
150
+ onCopy: undefined,
151
+ onDrag: undefined,
152
+ onSave: () => {},
153
+ perPage: Number.MAX_SAFE_INTEGER,
154
+ renderDeleteModal: undefined,
155
+ renderEmptyRow: undefined,
156
+ scrollOffset: 0
157
+ };
158
+
159
+ export default ItemCollection;
@@ -0,0 +1,126 @@
1
+ // @flow
2
+
3
+ import React, { useCallback, useEffect, useMemo } from 'react';
4
+ import { Button, Dimmer, Loader } from 'semantic-ui-react';
5
+ import _ from 'underscore';
6
+ import i18n from '../i18n/i18n';
7
+ import Items from './Items';
8
+ import useDataList, { SORT_ASCENDING } from './DataList';
9
+
10
+ type ListButton = {
11
+ ...typeof Button,
12
+ accept: () => boolean
13
+ };
14
+
15
+ type Sort = {
16
+ key: any,
17
+ value: any,
18
+ text: string,
19
+ direction: ?string
20
+ };
21
+
22
+ type Props = {
23
+ buttons: Array<ListButton>,
24
+ isRowSelected: (item: any) => boolean,
25
+ items: Array<any>,
26
+ loading?: boolean,
27
+ page: number,
28
+ onRowSelect: (item: any) => void,
29
+ onSort: (column: string, direction: ?string, page?: number) => void,
30
+ selectable?: boolean,
31
+ sort?: Array<Sort>,
32
+ sortColumn?: string,
33
+ sortDirection?: string
34
+ };
35
+
36
+ /**
37
+ * An ItemList component can be used to render a list of records returned from an API. Under the hood, the DataList
38
+ * component handles calling the API, storing the records, filters, etc, and the Items component handles the
39
+ * presentation.
40
+ *
41
+ * @param props
42
+ *
43
+ * @returns {*}
44
+ */
45
+ const ItemList = (props: Props) => {
46
+ useEffect(() => {
47
+ const { page } = props;
48
+
49
+ let { sortColumn = '', sortDirection = SORT_ASCENDING } = props;
50
+
51
+ if (!sortColumn) {
52
+ const defaultSort = _.first(props.sort);
53
+
54
+ if (defaultSort) {
55
+ sortColumn = defaultSort.value;
56
+
57
+ if (defaultSort.direction) {
58
+ sortDirection = defaultSort.direction;
59
+ }
60
+ }
61
+ }
62
+
63
+ props.onSort(sortColumn, sortDirection, page);
64
+ }, []);
65
+
66
+ /**
67
+ * Sets the variable to true if every item in the passed collection is selected.
68
+ */
69
+ const allSelected = useMemo(() => props.isRowSelected && props.items && props.items.length && _.every(
70
+ props.items,
71
+ props.isRowSelected.bind(this)
72
+ ), [props.items, props.isRowSelected]);
73
+
74
+ /**
75
+ * Selects all items in the collection. If all items are currently selected, deselects all items.
76
+ *
77
+ * @type {(function(): void)|*}
78
+ */
79
+ const onSelectAll = useCallback(() => {
80
+ if (props.items && props.isRowSelected && props.onRowSelect) {
81
+ let items;
82
+
83
+ if (allSelected) {
84
+ items = [...props.items];
85
+ } else {
86
+ items = _.reject(props.items, props.isRowSelected.bind(this));
87
+ }
88
+
89
+ _.each(items, props.onRowSelect.bind(this));
90
+ }
91
+ }, [allSelected, props.isRowSelected, props.items, props.onRowSelect]);
92
+
93
+ return (
94
+ <>
95
+ <Dimmer
96
+ active={props.loading}
97
+ inverted
98
+ >
99
+ <Loader
100
+ content={i18n.t('Common.messages.loading')}
101
+ />
102
+ </Dimmer>
103
+ <Items
104
+ {...props}
105
+ buttons={[...(props.buttons || []), {
106
+ accept: () => props.selectable,
107
+ color: 'green',
108
+ content: allSelected ? i18n.t('ItemList.buttons.deselectAll') : i18n.t('ItemList.buttons.selectAll'),
109
+ icon: 'checkmark',
110
+ onClick: onSelectAll.bind(this)
111
+ }]}
112
+ />
113
+ </>
114
+ );
115
+ };
116
+
117
+ ItemList.defaultProps = {
118
+ filters: {},
119
+ onCopy: undefined,
120
+ onSort: () => {},
121
+ renderDeleteModal: undefined,
122
+ renderEmptyRow: undefined,
123
+ searchable: true,
124
+ };
125
+
126
+ export default useDataList(ItemList);