@performant-software/semantic-components 0.5.5 → 0.5.8

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 (36) hide show
  1. package/build/index.js +1 -1
  2. package/build/index.js.map +1 -1
  3. package/build/main.css +4 -4
  4. package/build/semantic-ui.css +1 -1
  5. package/package.json +3 -3
  6. package/src/components/DataTable.js +12 -1
  7. package/src/components/DataTableColumnSelector.js +2 -1
  8. package/src/components/ListTable.js +19 -10
  9. package/src/css/theme.config +1 -1
  10. package/src/css/themes/default/elements/step.overrides +2 -2
  11. package/src/index.js +1 -0
  12. package/types/components/AccordionList.js.flow +2 -2
  13. package/types/components/AccordionSelector.js.flow +93 -86
  14. package/types/components/ColorPickerModal.js.flow +36 -31
  15. package/types/components/DataTable.js.flow +12 -1
  16. package/types/components/DataTableColumnSelector.js.flow +12 -0
  17. package/types/components/DataView.js.flow +36 -30
  18. package/types/components/DatabaseView.js.flow +126 -0
  19. package/types/components/DropdownMenu.js.flow +11 -1
  20. package/types/components/FileUploadModal.js.flow +43 -38
  21. package/types/components/FuzzyDate.js.flow +114 -99
  22. package/types/components/ListFilters.js.flow +115 -109
  23. package/types/components/ListTable.js.flow +22 -10
  24. package/types/components/LoginModal.js.flow +72 -65
  25. package/types/components/MenuBar.js.flow +1 -0
  26. package/types/components/PhotoViewer.js.flow +23 -15
  27. package/types/components/ReferenceCodeModal.js.flow +27 -21
  28. package/types/components/ReferenceTableModal.js.flow +61 -55
  29. package/types/components/Selectize.js.flow +50 -45
  30. package/types/components/TabbedModal.js.flow +30 -24
  31. package/types/components/VideoFrameSelector.js.flow +90 -78
  32. package/types/components/VideoPlayer.js.flow +58 -30
  33. package/types/components/ViewXML.js.flow +38 -32
  34. package/types/context/ModalContext.js.flow +5 -0
  35. package/types/index.js.flow +1 -0
  36. package/webpack.config.js +2 -1
@@ -23,6 +23,7 @@ import i18n from '../i18n/i18n';
23
23
  import AssociatedDropdown from './AssociatedDropdown';
24
24
  import DropdownButton from './DropdownButton';
25
25
  import FuzzyDate from './FuzzyDate';
26
+ import ModalContext from '../context/ModalContext';
26
27
 
27
28
  type Option = {
28
29
  key: string | number,
@@ -286,118 +287,123 @@ const ListFilters = (props: Props) => {
286
287
  }, []);
287
288
 
288
289
  return (
289
- <Modal
290
- as={Form}
291
- centered={false}
292
- className='list-filters-modal'
293
- noValidate
294
- open
295
- size='small'
296
- >
297
- <Modal.Header>
298
- <Grid
299
- columns={2}
290
+ <ModalContext.Consumer>
291
+ { (mountNode) => (
292
+ <Modal
293
+ as={Form}
294
+ centered={false}
295
+ className='list-filters-modal'
296
+ mountNode={mountNode}
297
+ noValidate
298
+ open
299
+ size='small'
300
300
  >
301
- <Grid.Column
302
- verticalAlign='middle'
303
- >
304
- <Header
305
- content={i18n.t('ListFilters.title')}
306
- />
307
- </Grid.Column>
308
- <Grid.Column
309
- textAlign='right'
310
- >
311
- <DropdownButton
312
- color='green'
313
- icon='plus'
314
- options={_.map(filters, (filter) => ({
315
- key: filter.key,
316
- value: filter.key,
317
- text: filter.label
318
- }))}
319
- onChange={(e, { value }) => {
320
- const filter = _.findWhere(props.filters, { key: value });
321
- props.onSaveChildAssociation('filters', {
322
- ...filter,
323
- uid: uuid(),
324
- operator: Operators.equal
325
- });
326
- }}
327
- scrolling
328
- text={i18n.t('ListFilters.buttons.add')}
329
- value=''
330
- />
331
- <Button
332
- color='red'
333
- content={i18n.t('ListFilters.buttons.reset')}
334
- icon='repeat'
335
- onClick={() => props.onReset()}
336
- style={{
337
- marginLeft: '1em'
338
- }}
339
- />
340
- </Grid.Column>
341
- </Grid>
342
- </Modal.Header>
343
- <Modal.Content>
344
- { !_.isEmpty(props.item.filters) && (
345
- <Grid>
346
- { _.map(props.item.filters, (filter) => (
347
- <Grid.Row
348
- columns={4}
349
- key={filter.key}
301
+ <Modal.Header>
302
+ <Grid
303
+ columns={2}
304
+ >
305
+ <Grid.Column
350
306
  verticalAlign='middle'
351
307
  >
352
- <Grid.Column>
353
- <Header
354
- content={filter.label}
355
- />
356
- </Grid.Column>
357
- <Grid.Column
358
- width={5}
359
- >
360
- <Dropdown
361
- options={getOperatorsByType(filter.type)}
362
- onChange={(e, { value }) => props.onSaveChildAssociation('filters', {
363
- ..._.omit(filter, 'value'),
364
- operator: value,
365
- })}
366
- selection
367
- value={filter.operator}
368
- />
369
- </Grid.Column>
370
- <Grid.Column
371
- width={5}
372
- >
373
- { renderInput(filter) }
374
- </Grid.Column>
375
- <Grid.Column
376
- width={1}
377
- >
378
- <Button
379
- basic
380
- icon='times'
381
- onClick={() => {
382
- /*
383
- * If we're removing the last filter, call the onReset prop to ensure the UI doesn't display
384
- * as active.
385
- */
386
- if (props.item.filters && props.item.filters.length === 1) {
387
- props.onReset();
388
- } else {
389
- props.onDeleteChildAssociation('filters', filter);
390
- }
391
- }}
392
- />
393
- </Grid.Column>
394
- </Grid.Row>
395
- ))}
396
- </Grid>
397
- )}
398
- </Modal.Content>
399
- { props.children }
400
- </Modal>
308
+ <Header
309
+ content={i18n.t('ListFilters.title')}
310
+ />
311
+ </Grid.Column>
312
+ <Grid.Column
313
+ textAlign='right'
314
+ >
315
+ <DropdownButton
316
+ color='green'
317
+ icon='plus'
318
+ options={_.map(filters, (filter) => ({
319
+ key: filter.key,
320
+ value: filter.key,
321
+ text: filter.label
322
+ }))}
323
+ onChange={(e, { value }) => {
324
+ const filter = _.findWhere(props.filters, { key: value });
325
+ props.onSaveChildAssociation('filters', {
326
+ ...filter,
327
+ uid: uuid(),
328
+ operator: Operators.equal
329
+ });
330
+ }}
331
+ scrolling
332
+ text={i18n.t('ListFilters.buttons.add')}
333
+ value=''
334
+ />
335
+ <Button
336
+ color='red'
337
+ content={i18n.t('ListFilters.buttons.reset')}
338
+ icon='repeat'
339
+ onClick={() => props.onReset()}
340
+ style={{
341
+ marginLeft: '1em'
342
+ }}
343
+ />
344
+ </Grid.Column>
345
+ </Grid>
346
+ </Modal.Header>
347
+ <Modal.Content>
348
+ { !_.isEmpty(props.item.filters) && (
349
+ <Grid>
350
+ { _.map(props.item.filters, (filter) => (
351
+ <Grid.Row
352
+ columns={4}
353
+ key={filter.key}
354
+ verticalAlign='middle'
355
+ >
356
+ <Grid.Column>
357
+ <Header
358
+ content={filter.label}
359
+ />
360
+ </Grid.Column>
361
+ <Grid.Column
362
+ width={5}
363
+ >
364
+ <Dropdown
365
+ options={getOperatorsByType(filter.type)}
366
+ onChange={(e, { value }) => props.onSaveChildAssociation('filters', {
367
+ ..._.omit(filter, 'value'),
368
+ operator: value,
369
+ })}
370
+ selection
371
+ value={filter.operator}
372
+ />
373
+ </Grid.Column>
374
+ <Grid.Column
375
+ width={5}
376
+ >
377
+ { renderInput(filter) }
378
+ </Grid.Column>
379
+ <Grid.Column
380
+ width={1}
381
+ >
382
+ <Button
383
+ basic
384
+ icon='times'
385
+ onClick={() => {
386
+ /*
387
+ * If we're removing the last filter, call the onReset prop to ensure the UI doesn't display
388
+ * as active.
389
+ */
390
+ if (props.item.filters && props.item.filters.length === 1) {
391
+ props.onReset();
392
+ } else {
393
+ props.onDeleteChildAssociation('filters', filter);
394
+ }
395
+ }}
396
+ />
397
+ </Grid.Column>
398
+ </Grid.Row>
399
+ ))}
400
+ </Grid>
401
+ )}
402
+ </Modal.Content>
403
+ { props.children }
404
+ </Modal>
405
+ )}
406
+ </ModalContext.Consumer>
401
407
  );
402
408
  };
403
409
 
@@ -1,5 +1,6 @@
1
1
  // @flow
2
2
 
3
+ import { Hooks, Object as ObjectUtils } from '@performant-software/shared-components';
3
4
  import React, { useEffect } from 'react';
4
5
  import _ from 'underscore';
5
6
  import DataTable from './DataTable';
@@ -10,6 +11,8 @@ import type { Column } from './DataTable';
10
11
 
11
12
  type Props = {
12
13
  columns: Array<Column>,
14
+ defaultSort?: string,
15
+ defaultSortDirection?: string,
13
16
  page: number,
14
17
  onSort: (sortColumn: string, sortDirection: string, page?: number) => void,
15
18
  onInit: (page?: number) => void,
@@ -18,6 +21,8 @@ type Props = {
18
21
  };
19
22
 
20
23
  const ListTable = (props: Props) => {
24
+ const prevColumns = Hooks.usePrevious(props.columns);
25
+
21
26
  /**
22
27
  * Sorts the list by the selected column, and/or reverse the direction.
23
28
  *
@@ -49,20 +54,27 @@ const ListTable = (props: Props) => {
49
54
  * sortable column.
50
55
  */
51
56
  useEffect(() => {
52
- const { page, sortColumn, sortDirection = SORT_ASCENDING } = props;
57
+ if (!ObjectUtils.isEqual(props.columns, prevColumns)) {
58
+ const {
59
+ page,
60
+ defaultSort,
61
+ defaultSortDirection = SORT_ASCENDING
62
+ } = props;
53
63
 
54
- if (props.sortColumn) {
55
- props.onSort(sortColumn, sortDirection, page);
56
- } else {
57
- const sortableColumn = _.findWhere(props.columns, { sortable: true });
58
- if (sortableColumn) {
59
- onColumnClick(sortableColumn);
64
+ if (defaultSort) {
65
+ props.onSort(defaultSort, defaultSortDirection, page);
60
66
  } else {
61
- // If no columns are sortable, load the data as is
62
- props.onInit();
67
+ const sortableColumn = _.findWhere(props.columns, { sortable: true });
68
+
69
+ if (sortableColumn) {
70
+ onColumnClick(sortableColumn);
71
+ } else {
72
+ // If no columns are sortable, load the data as is
73
+ props.onInit();
74
+ }
63
75
  }
64
76
  }
65
- }, []);
77
+ }, [props.columns]);
66
78
 
67
79
  return (
68
80
  <DataTable
@@ -12,6 +12,7 @@ import {
12
12
  Modal
13
13
  } from 'semantic-ui-react';
14
14
  import i18n from '../i18n/i18n';
15
+ import ModalContext from '../context/ModalContext';
15
16
  import './LoginModal.css';
16
17
 
17
18
  type Props = {
@@ -27,72 +28,78 @@ type Props = {
27
28
  };
28
29
 
29
30
  const LoginModal = (props: Props) => (
30
- <Modal
31
- as={Form}
32
- className='login-modal'
33
- error={props.loginFailed}
34
- open={props.open}
35
- size='small'
36
- trigger={props.trigger}
37
- >
38
- <Header
39
- icon='user circle'
40
- content={i18n.t('LoginModal.header')}
41
- />
42
- <Message
43
- error
44
- header={i18n.t('LoginModal.loginErrorHeader')}
45
- content={i18n.t('LoginModal.loginErrorContent')}
46
- />
47
- <Grid
48
- padded='vertically'
49
- textAlign='center'
50
- >
51
- <Grid.Column>
52
- <Grid.Row>
53
- <Input
54
- autoFocus
55
- className='form-field'
56
- icon={<Icon name='at' />}
57
- onChange={props.onUsernameChange.bind(this)}
58
- placeholder={props.placeholder}
59
- size='huge'
60
- />
61
- </Grid.Row>
62
- <Grid.Row
63
- className='row'
64
- >
65
- <Input
66
- className='form-field'
67
- icon={<Icon name='lock' />}
68
- onChange={props.onPasswordChange.bind(this)}
69
- placeholder={i18n.t('LoginModal.password')}
70
- size='huge'
71
- type='password'
72
- />
73
- </Grid.Row>
74
- </Grid.Column>
75
- </Grid>
76
- <Modal.Actions>
77
- <Button
78
- disabled={props.disabled}
79
- onClick={props.onLogin.bind(this)}
80
- primary
81
- size='large'
82
- type='submit'
83
- >
84
- { i18n.t('LoginModal.buttonLogin') }
85
- </Button>
86
- <Button
87
- inverted
88
- onClick={props.onClose.bind(this)}
89
- primary
90
- size='large'
31
+ <ModalContext.Consumer>
32
+ { (mountNode) => (
33
+ <Modal
34
+ as={Form}
35
+ className='login-modal'
36
+ error={props.loginFailed}
37
+ mountNode={mountNode}
38
+ open={props.open}
39
+ size='small'
40
+ trigger={props.trigger}
91
41
  >
92
- { i18n.t('LoginModal.buttonCancel') }
93
- </Button>
94
- </Modal.Actions>
95
- </Modal>
42
+ <Header
43
+ icon='user circle'
44
+ content={i18n.t('LoginModal.header')}
45
+ />
46
+ <Message
47
+ error
48
+ header={i18n.t('LoginModal.loginErrorHeader')}
49
+ content={i18n.t('LoginModal.loginErrorContent')}
50
+ />
51
+ <Grid
52
+ padded='vertically'
53
+ textAlign='center'
54
+ >
55
+ <Grid.Column>
56
+ <Grid.Row>
57
+ <Input
58
+ autoFocus
59
+ className='form-field'
60
+ icon={<Icon name='at' />}
61
+ onChange={props.onUsernameChange.bind(this)}
62
+ placeholder={props.placeholder}
63
+ size='huge'
64
+ />
65
+ </Grid.Row>
66
+ <Grid.Row
67
+ className='row'
68
+ >
69
+ <Input
70
+ className='form-field'
71
+ icon={<Icon name='lock' />}
72
+ onChange={props.onPasswordChange.bind(this)}
73
+ placeholder={i18n.t('LoginModal.password')}
74
+ size='huge'
75
+ type='password'
76
+ />
77
+ </Grid.Row>
78
+ </Grid.Column>
79
+ </Grid>
80
+ <Modal.Actions>
81
+ <Button
82
+ disabled={props.disabled}
83
+ onClick={props.onLogin.bind(this)}
84
+ primary
85
+ size='large'
86
+ type='submit'
87
+ >
88
+ { i18n.t('LoginModal.buttonLogin') }
89
+ </Button>
90
+ { props.onClose && (
91
+ <Button
92
+ basic
93
+ onClick={props.onClose.bind(this)}
94
+ size='large'
95
+ >
96
+ { i18n.t('LoginModal.buttonCancel') }
97
+ </Button>
98
+ )}
99
+ </Modal.Actions>
100
+ </Modal>
101
+ )}
102
+ </ModalContext.Consumer>
96
103
  );
97
104
 
98
105
  LoginModal.defaultProps = {
@@ -53,6 +53,7 @@ const MenuBar = ({ header, items, ...props }: Props) => {
53
53
  aria-label={item.content}
54
54
  item
55
55
  key={index}
56
+ role='group'
56
57
  text={item.content}
57
58
  >
58
59
  { _.map(item.items, (i) => (i.items ? renderDropdown(i) : renderDropdownItem(i)))}
@@ -2,9 +2,11 @@
2
2
 
3
3
  import React from 'react';
4
4
  import { Image, Modal } from 'semantic-ui-react';
5
+ import ModalContext from '../context/ModalContext';
5
6
  import './PhotoViewer.css';
6
7
 
7
8
  type Props = {
9
+ alt?: string,
8
10
  image: string,
9
11
  onClose: () => void,
10
12
  open: boolean,
@@ -12,21 +14,27 @@ type Props = {
12
14
  };
13
15
 
14
16
  const PhotoViewer = (props: Props) => (
15
- <Modal
16
- centered={false}
17
- className='photo-viewer'
18
- closeIcon
19
- onClose={props.onClose.bind(this)}
20
- open={props.open}
21
- size={props.size}
22
- >
23
- <Modal.Content>
24
- <Image
25
- fluid
26
- src={props.image}
27
- />
28
- </Modal.Content>
29
- </Modal>
17
+ <ModalContext.Consumer>
18
+ { (mountNode) => (
19
+ <Modal
20
+ centered={false}
21
+ className='photo-viewer'
22
+ closeIcon
23
+ mountNode={mountNode}
24
+ onClose={props.onClose.bind(this)}
25
+ open={props.open}
26
+ size={props.size}
27
+ >
28
+ <Modal.Content>
29
+ <Image
30
+ alt={props.alt}
31
+ fluid
32
+ src={props.image}
33
+ />
34
+ </Modal.Content>
35
+ </Modal>
36
+ )}
37
+ </ModalContext.Consumer>
30
38
  );
31
39
 
32
40
  PhotoViewer.defaultProps = {
@@ -4,29 +4,35 @@ import type { EditContainerProps } from '@performant-software/shared-components'
4
4
  import React from 'react';
5
5
  import { Form, Modal } from 'semantic-ui-react';
6
6
  import i18n from '../i18n/i18n';
7
+ import ModalContext from '../context/ModalContext';
7
8
 
8
9
  const ReferenceCodeModal = (props: EditContainerProps) => (
9
- <Modal
10
- as={Form}
11
- centered={false}
12
- open
13
- >
14
- <Modal.Header
15
- content={props.item.id
16
- ? i18n.t('ReferenceCodeModal.title.edit')
17
- : i18n.t('ReferenceCodeModal.title.add')}
18
- />
19
- <Modal.Content>
20
- <Form.Input
21
- error={props.isError('name')}
22
- label={i18n.t('ReferenceCodeModal.labels.name')}
23
- onChange={props.onTextInputChange.bind(this, 'name')}
24
- required={props.isRequired('name')}
25
- value={props.item.name}
26
- />
27
- </Modal.Content>
28
- { props.children }
29
- </Modal>
10
+ <ModalContext.Consumer>
11
+ { (mountNode) => (
12
+ <Modal
13
+ as={Form}
14
+ centered={false}
15
+ mountNode={mountNode}
16
+ open
17
+ >
18
+ <Modal.Header
19
+ content={props.item.id
20
+ ? i18n.t('ReferenceCodeModal.title.edit')
21
+ : i18n.t('ReferenceCodeModal.title.add')}
22
+ />
23
+ <Modal.Content>
24
+ <Form.Input
25
+ error={props.isError('name')}
26
+ label={i18n.t('ReferenceCodeModal.labels.name')}
27
+ onChange={props.onTextInputChange.bind(this, 'name')}
28
+ required={props.isRequired('name')}
29
+ value={props.item.name}
30
+ />
31
+ </Modal.Content>
32
+ { props.children }
33
+ </Modal>
34
+ )}
35
+ </ModalContext.Consumer>
30
36
  );
31
37
 
32
38
  export default ReferenceCodeModal;