@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,365 @@
1
+ // @flow
2
+
3
+ import React, { Component, type Element } from 'react';
4
+ import {
5
+ Button,
6
+ Card,
7
+ Checkbox,
8
+ Header,
9
+ Icon,
10
+ Item,
11
+ Segment
12
+ } from 'semantic-ui-react';
13
+ import _ from 'underscore';
14
+ import i18n from '../i18n/i18n';
15
+ import useList from './List';
16
+ import useItemsToggle, { Views } from './ItemsToggle';
17
+ import Draggable from './Draggable';
18
+ import './Items.css';
19
+
20
+ import type { Props as ListProps } from './List';
21
+
22
+ type Props = ListProps & {
23
+ children: Element<any>,
24
+ className: string,
25
+ isRowSelected?: (item: any) => boolean,
26
+ items: Array<any>,
27
+ loading: boolean,
28
+ onDrag?: (dragIndex: number, hoverIndex: number) => void,
29
+ onRowSelect?: (item: any) => void,
30
+ onSelectAllRows?: (items: Array<any>) => void,
31
+ renderAdditionalContent?: (item: any) => Element<any>,
32
+ renderDescription?: (item: any) => Element<any>,
33
+ renderEmptyList: () => Element<any>,
34
+ renderExtra?: (item: any) => Element<any>,
35
+ renderHeader?: (item: any) => Element<any>,
36
+ renderImage?: (item: any) => Element<any>,
37
+ renderMeta?: (item: any) => Element<any>,
38
+ selectable?: boolean,
39
+ view: number
40
+ };
41
+
42
+ /**
43
+ * The Items component is used as the presentation for a list of records. The component renders both a list
44
+ * (see Semantic-UI List) and grid (see Semantic-UI Card) views.
45
+ */
46
+ class Items extends Component<Props, {}> {
47
+ static defaultProps: any;
48
+
49
+ /**
50
+ * Returns the list of actions for the passed item.
51
+ *
52
+ * @param item
53
+ *
54
+ * @returns {Array<*>}
55
+ */
56
+ getActions(item) {
57
+ return this.props.actions
58
+ .filter((action) => !action.accept || action.accept(item))
59
+ .map((action) => {
60
+ let defaults = {};
61
+
62
+ if (action.name === 'edit') {
63
+ defaults = {
64
+ basic: true,
65
+ label: i18n.t('ItemList.actions.edit')
66
+ };
67
+ } else if (action.name === 'copy') {
68
+ defaults = {
69
+ basic: true,
70
+ label: i18n.t('ItemList.actions.copy')
71
+ };
72
+ } else if (action.name === 'delete') {
73
+ defaults = {
74
+ basic: true,
75
+ color: 'red',
76
+ label: i18n.t('ItemList.actions.delete')
77
+ };
78
+ }
79
+
80
+ return _.defaults(action, defaults);
81
+ });
82
+ }
83
+
84
+ /**
85
+ * Returns a space delimited string of class names.
86
+ *
87
+ * @returns {string}
88
+ */
89
+ getClassName() {
90
+ const classNames = ['item-list'];
91
+
92
+ if (this.props.className) {
93
+ classNames.push(this.props.className);
94
+ }
95
+
96
+ return classNames.join(' ');
97
+ }
98
+
99
+ /**
100
+ * Returns true if the component has the necessary props to render itself in the "selectable" state.
101
+ *
102
+ * @returns {boolean}
103
+ */
104
+ isSelectable() {
105
+ return !!(this.props.selectable && this.props.isRowSelected && this.props.onRowSelect);
106
+ }
107
+
108
+ /**
109
+ * Renders the Items component.
110
+ *
111
+ * @returns {*}
112
+ */
113
+ render() {
114
+ return (
115
+ <div
116
+ className={this.getClassName()}
117
+ >
118
+ { this.renderList() }
119
+ { this.renderGrid() }
120
+ { this.renderEmptyList() }
121
+ { this.props.children }
122
+ </div>
123
+ );
124
+ }
125
+
126
+ /**
127
+ * Renders the card for the passed item.
128
+ *
129
+ * @param item
130
+ * @param index
131
+ *
132
+ * @returns {*}
133
+ */
134
+ renderCard(item, index) {
135
+ const card = (
136
+ <Card
137
+ key={item.id || index}
138
+ >
139
+ { this.props.renderImage && this.props.renderImage(item) }
140
+ <Card.Content>
141
+ { this.props.renderHeader && (
142
+ <Card.Header>
143
+ { this.props.renderHeader(item) }
144
+ </Card.Header>
145
+ )}
146
+ { this.props.renderMeta && (
147
+ <Card.Meta>
148
+ { this.props.renderMeta(item) }
149
+ </Card.Meta>
150
+ )}
151
+ { this.props.renderDescription && (
152
+ <Card.Description>
153
+ { this.props.renderDescription(item) }
154
+ </Card.Description>
155
+ )}
156
+ </Card.Content>
157
+ { this.props.renderExtra && (
158
+ <Card.Content
159
+ extra
160
+ >
161
+ { this.props.renderExtra(item) }
162
+ </Card.Content>
163
+ )}
164
+ { this.props.actions && this.props.actions.length && (
165
+ <Card.Content
166
+ extra
167
+ textAlign='center'
168
+ >
169
+ { _.map(this.getActions(item), (action, actionIndex) => (
170
+ <Button
171
+ basic
172
+ color={action.resolveColor ? action.resolveColor(item) : action.color}
173
+ icon={action.resolveIcon ? action.resolveIcon(item) : action.icon}
174
+ key={actionIndex}
175
+ onClick={action.onClick.bind(this, item)}
176
+ />
177
+ ))}
178
+ { this.isSelectable() && (
179
+ <Button
180
+ basic
181
+ color={this.props.isRowSelected && this.props.isRowSelected(item) ? 'green' : undefined}
182
+ icon='checkmark'
183
+ onClick={this.props.onRowSelect && this.props.onRowSelect.bind(this, item)}
184
+ />
185
+ )}
186
+ </Card.Content>
187
+ )}
188
+ </Card>
189
+ );
190
+
191
+ if (!this.props.onDrag) {
192
+ return card;
193
+ }
194
+
195
+ return (
196
+ <Draggable
197
+ id={item.id || item.uid}
198
+ index={index}
199
+ item={item}
200
+ key={item.id || item.uid}
201
+ onDrag={this.props.onDrag.bind(this)}
202
+ >
203
+ { card }
204
+ </Draggable>
205
+ );
206
+ }
207
+
208
+ /**
209
+ * Renders the empty list.
210
+ *
211
+ * @returns {null|*}
212
+ */
213
+ renderEmptyList() {
214
+ if (this.props.loading || (this.props.items && this.props.items.length)) {
215
+ return null;
216
+ }
217
+
218
+ if (this.props.renderEmptyList) {
219
+ return this.props.renderEmptyList();
220
+ }
221
+
222
+ return (
223
+ <Segment
224
+ className='empty-list'
225
+ padded='very'
226
+ textAlign='center'
227
+ >
228
+ <Header
229
+ icon
230
+ >
231
+ <Icon
232
+ name='file outline'
233
+ />
234
+ </Header>
235
+ { this.props.renderEmptyMessage() }
236
+ </Segment>
237
+ );
238
+ }
239
+
240
+ /**
241
+ * Renders the grid view.
242
+ *
243
+ * @returns {null|*}
244
+ */
245
+ renderGrid() {
246
+ if (this.props.view !== Views.grid || !(this.props.items && this.props.items.length)) {
247
+ return null;
248
+ }
249
+
250
+ return (
251
+ <Card.Group>
252
+ { _.map(this.props.items, this.renderCard.bind(this)) }
253
+ </Card.Group>
254
+ );
255
+ }
256
+
257
+ /**
258
+ * Renders the list item for the passed item.
259
+ *
260
+ * @param item
261
+ * @param index
262
+ *
263
+ * @returns {*}
264
+ */
265
+ renderItem(item, index) {
266
+ const listItem = (
267
+ <Item
268
+ key={item.id || index}
269
+ >
270
+ { this.props.renderImage && (
271
+ <Item.Image>
272
+ { this.props.renderImage(item) }
273
+ </Item.Image>
274
+ )}
275
+ <Item.Content
276
+ className='primary-content'
277
+ >
278
+ { this.props.renderHeader && (
279
+ <Item.Header>
280
+ { this.props.renderHeader(item) }
281
+ </Item.Header>
282
+ )}
283
+ { this.props.renderMeta && (
284
+ <Item.Meta>
285
+ { this.props.renderMeta(item) }
286
+ </Item.Meta>
287
+ )}
288
+ { this.props.renderDescription && (
289
+ <Item.Description>
290
+ { this.props.renderDescription(item) }
291
+ </Item.Description>
292
+ )}
293
+ { this.props.renderExtra && (
294
+ <Item.Extra>
295
+ { this.props.renderExtra(item) }
296
+ </Item.Extra>
297
+ )}
298
+ { _.map(this.getActions(item), (action, actionIndex) => (
299
+ <Button
300
+ basic={action.basic}
301
+ color={action.resolveColor ? action.resolveColor(item) : action.color}
302
+ content={action.resolveName ? action.resolveName(item) : action.label}
303
+ key={actionIndex}
304
+ icon={action.resolveIcon ? action.resolveIcon(item) : action.icon}
305
+ onClick={action.onClick.bind(this, item)}
306
+ />
307
+ ))}
308
+ </Item.Content>
309
+ { this.props.renderAdditionalContent && this.props.renderAdditionalContent(item) }
310
+ { this.isSelectable() && (
311
+ <div
312
+ className='checkbox-container'
313
+ >
314
+ <Checkbox
315
+ checked={this.props.isRowSelected && this.props.isRowSelected(item)}
316
+ onChange={this.props.onRowSelect && this.props.onRowSelect.bind(this, item)}
317
+ />
318
+ </div>
319
+ )}
320
+ </Item>
321
+ );
322
+
323
+ if (!this.props.onDrag) {
324
+ return listItem;
325
+ }
326
+
327
+ return (
328
+ <Draggable
329
+ id={item.id || item.uid}
330
+ index={index}
331
+ item={item}
332
+ key={item.id || item.uid}
333
+ onDrag={this.props.onDrag.bind(this)}
334
+ >
335
+ { listItem }
336
+ </Draggable>
337
+ );
338
+ }
339
+
340
+ /**
341
+ * Renders the list view.
342
+ *
343
+ * @returns {null|*}
344
+ */
345
+ renderList() {
346
+ if (this.props.view !== Views.list || !(this.props.items && this.props.items.length)) {
347
+ return null;
348
+ }
349
+
350
+ return (
351
+ <Item.Group
352
+ divided
353
+ relaxed='very'
354
+ >
355
+ { _.map(this.props.items, this.renderItem.bind(this)) }
356
+ </Item.Group>
357
+ );
358
+ }
359
+ }
360
+
361
+ Items.defaultProps = {
362
+ actions: []
363
+ };
364
+
365
+ export default useItemsToggle(useList(Items));
File without changes
@@ -0,0 +1,168 @@
1
+ // @flow
2
+
3
+ import React, { Component, type ComponentType } from 'react';
4
+ import { Button, Dropdown } from 'semantic-ui-react';
5
+ import _ from 'underscore';
6
+ import { SORT_ASCENDING } from './DataList';
7
+
8
+ type Sort = {
9
+ key: string,
10
+ text: string,
11
+ value: string,
12
+ direction?: ?string
13
+ };
14
+
15
+ type Props = {
16
+ onSort?: (sortColumn: string, sortDirection?: ?string) => void,
17
+ sort?: Array<Sort>,
18
+ sortColumn?: string,
19
+ sortDirection?: string
20
+ };
21
+
22
+ type State = {
23
+ view: number
24
+ };
25
+
26
+ const Views = {
27
+ list: 0,
28
+ grid: 1
29
+ };
30
+
31
+ /**
32
+ * Returns a function to wrap the passed component in a ItemToggle. The ItemToggle component can be used to toggle a
33
+ * list of records between list and grid views. It will also render a sort dropdown component if a list of sort
34
+ * properties is provided.
35
+ *
36
+ * @param WrappedComponent
37
+ */
38
+ const useItemsToggle = (WrappedComponent: ComponentType<any>) => (
39
+ class extends Component<Props, State> {
40
+ // Default props
41
+ static defaultProps = {
42
+ sort: []
43
+ };
44
+
45
+ // Sort dropdown ref
46
+ sortDropdown: typeof Dropdown;
47
+
48
+ /**
49
+ * Constructs a new ItemsToggle component.
50
+ *
51
+ * @param props
52
+ */
53
+ constructor(props: any) {
54
+ super(props);
55
+
56
+ this.state = {
57
+ view: Views.list
58
+ };
59
+ }
60
+
61
+ /**
62
+ * Renders the sort value for the current option.
63
+ *
64
+ * @returns {*}
65
+ */
66
+ getSortValue() {
67
+ const sort = _.find(this.props.sort, { value: this.props.sortColumn });
68
+ return sort && sort.text;
69
+ }
70
+
71
+ /**
72
+ * Calls the onSort prop.
73
+ *
74
+ * @param sort
75
+ *
76
+ * @returns {*|void}
77
+ */
78
+ onSort(sort: Sort) {
79
+ if (!this.props.onSort) {
80
+ return;
81
+ }
82
+
83
+ let sortDirection;
84
+
85
+ if (sort.value !== this.props.sortColumn) {
86
+ sortDirection = sort.direction;
87
+ }
88
+
89
+ this.props.onSort(sort.value, sortDirection);
90
+ }
91
+
92
+ /**
93
+ * Renders the ItemsToggle component.
94
+ *
95
+ * @returns {*}
96
+ */
97
+ render() {
98
+ return (
99
+ <WrappedComponent
100
+ {...this.props}
101
+ renderListHeader={this.renderHeader.bind(this)}
102
+ view={this.state.view}
103
+ />
104
+ );
105
+ }
106
+
107
+ /**
108
+ * Renders the list header icons:
109
+ * <ul>
110
+ * <li>List/Grid view toggle</li>
111
+ * <li>Sort dropdown</li>
112
+ * </ul>
113
+ *
114
+ * @returns {*}
115
+ */
116
+ renderHeader() {
117
+ return (
118
+ <>
119
+ <Button
120
+ active={this.state.view === Views.list}
121
+ basic
122
+ icon='list'
123
+ onClick={() => this.setState({ view: Views.list })}
124
+ />
125
+ <Button
126
+ active={this.state.view === Views.grid}
127
+ basic
128
+ icon='grid layout'
129
+ onClick={() => this.setState({ view: Views.grid })}
130
+ />
131
+ { this.props.sort && this.props.sort.length > 1 && this.props.onSort && (
132
+ <Button.Group
133
+ basic
134
+ style={{
135
+ fontSize: 'inherit'
136
+ }}
137
+ >
138
+ <Button
139
+ content={this.getSortValue()}
140
+ icon={this.props.sortDirection === SORT_ASCENDING ? 'sort alphabet up' : 'sort alphabet down'}
141
+ onClick={(e) => this.sortDropdown.handleClick(e)}
142
+ />
143
+ <Dropdown
144
+ className='button icon'
145
+ floating
146
+ options={_.map(this.props.sort, (sort) => ({
147
+ ...sort,
148
+ onClick: this.onSort.bind(this, sort)
149
+ }))}
150
+ ref={(sortDropdown) => {
151
+ this.sortDropdown = sortDropdown;
152
+ }}
153
+ trigger={<></>}
154
+ value={this.props.sortColumn}
155
+ />
156
+ </Button.Group>
157
+ )}
158
+ </>
159
+ );
160
+ }
161
+ }
162
+ );
163
+
164
+ export default useItemsToggle;
165
+
166
+ export {
167
+ Views
168
+ };
@@ -0,0 +1,4 @@
1
+ .field.keyboard-field .hg-candidate-box {
2
+ top: 56px;
3
+ left: 4px;
4
+ }
@@ -0,0 +1,147 @@
1
+ // @flow
2
+
3
+ import { Keyboard } from '@performant-software/shared-components';
4
+ import React, { Component, type Node } from 'react';
5
+ import { Form, Segment, Transition } from 'semantic-ui-react';
6
+ import i18n from '../i18n/i18n';
7
+ import LinkLabel from './LinkLabel';
8
+ import './KeyboardField.css';
9
+
10
+ type Props = {
11
+ autoFocus?: boolean,
12
+ children: Node<any>,
13
+ className?: string,
14
+ error?: boolean,
15
+ id?: string,
16
+ label: string,
17
+ layout: any,
18
+ name: string,
19
+ onChange: (e: ?Event, { value: string }) => void,
20
+ required: boolean,
21
+ value: string,
22
+ visible: boolean
23
+ };
24
+
25
+ type State = {
26
+ showKeyboard: boolean
27
+ };
28
+
29
+ class KeyboardField extends Component<Props, State> {
30
+ static defaultProps: any;
31
+
32
+ /**
33
+ * Constructs a new KeyboardField component.
34
+ *
35
+ * @param props
36
+ */
37
+ constructor(props: Props) {
38
+ super(props);
39
+
40
+ this.state = {
41
+ showKeyboard: false
42
+ };
43
+ }
44
+
45
+ /**
46
+ * Hides the keyboard when the parent component is no longer visible.
47
+ *
48
+ * @param prevProps
49
+ */
50
+ componentDidUpdate(prevProps: Props) {
51
+ if (prevProps.visible && !this.props.visible) {
52
+ this.setState({ showKeyboard: false });
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Triggers the text input change.
58
+ *
59
+ * @param e
60
+ * @param value
61
+ */
62
+ onInputChange(e: Event, value: any) {
63
+ this.props.onChange(e, value);
64
+ }
65
+
66
+ /**
67
+ * Triggers the keyboard input change.
68
+ *
69
+ * @param value
70
+ */
71
+ onKeyboardChange(value: any) {
72
+ this.props.onChange(null, { value });
73
+ }
74
+
75
+ /**
76
+ * Renders the KeyboardField component.
77
+ *
78
+ * @returns {*}
79
+ */
80
+ render() {
81
+ return (
82
+ <Form.Field
83
+ className='keyboard-field'
84
+ >
85
+ <Form.Input
86
+ autoFocus={this.props.autoFocus}
87
+ className={this.props.className}
88
+ error={this.props.error}
89
+ id={this.props.id}
90
+ input={{
91
+ 'aria-label': this.props.name
92
+ }}
93
+ label={this.renderLabel()}
94
+ name={this.props.name}
95
+ onChange={this.onInputChange.bind(this)}
96
+ required={this.props.required}
97
+ value={this.props.value}
98
+ >
99
+ { this.props.children }
100
+ </Form.Input>
101
+ <Transition
102
+ duration={{
103
+ hide: 50,
104
+ show: 500
105
+ }}
106
+ visible={this.state.showKeyboard}
107
+ >
108
+ <Segment>
109
+ <Keyboard
110
+ layout={this.props.layout}
111
+ onChange={this.onKeyboardChange.bind(this)}
112
+ value={this.props.value}
113
+ keyboardClass={this.props.name}
114
+ />
115
+ </Segment>
116
+ </Transition>
117
+ </Form.Field>
118
+ );
119
+ }
120
+
121
+ /**
122
+ * Renders the input label.
123
+ *
124
+ * @returns {*}
125
+ */
126
+ renderLabel() {
127
+ return (
128
+ <LinkLabel
129
+ content={this.state.showKeyboard
130
+ ? i18n.t('KeyboardField.labels.hideKeyboard')
131
+ : i18n.t('KeyboardField.labels.showKeyboard')}
132
+ htmlFor={this.props.name}
133
+ label={this.props.label}
134
+ onClick={() => this.setState((state) => ({ showKeyboard: !state.showKeyboard }))}
135
+ />
136
+ );
137
+ }
138
+ }
139
+
140
+ KeyboardField.defaultProps = {
141
+ autoFocus: false,
142
+ className: '',
143
+ error: false,
144
+ id: ''
145
+ };
146
+
147
+ export default KeyboardField;
@@ -0,0 +1,21 @@
1
+ .lazy-document.ui.segment {
2
+ padding: 0;
3
+ }
4
+
5
+ .lazy-document.ui.segment .buttons {
6
+ display: flex;
7
+ flex-direction: column;
8
+ }
9
+
10
+ .lazy-document.ui.segment .buttons .ui.button {
11
+ margin-top: 5px;
12
+ margin-bottom: 5px;
13
+ }
14
+
15
+ .lazy-document .placeholder-image.ui.image {
16
+ background-color: #f9fafb;
17
+ box-shadow: 0 1px 3px 0 #d4d4d5, 0 0 0 1px #d4d4d5;
18
+ padding-top: 20%;
19
+ padding-bottom: 20%;
20
+ text-align: center;
21
+ }