@dhis2-ui/table 10.16.2 → 10.16.3-alpha.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 (101) hide show
  1. package/package.json +5 -4
  2. package/src/data-table/__tests__/data-table-cell.test.js +168 -0
  3. package/src/data-table/__tests__/data-table-column-header/filter-handle.test.js +43 -0
  4. package/src/data-table/__tests__/data-table-column-header/sorter.test.js +41 -0
  5. package/src/data-table/__tests__/data-table-column-header.test.js +227 -0
  6. package/src/data-table/__tests__/data-table-row/expand-handle-cell.js +32 -0
  7. package/src/data-table/__tests__/data-table-row/expanded-row.test.js +57 -0
  8. package/src/data-table/__tests__/data-table-row.test.js +162 -0
  9. package/src/data-table/__tests__/data-table.test.js +85 -0
  10. package/src/data-table/data-table-body.js +3 -0
  11. package/src/data-table/data-table-cell.js +111 -0
  12. package/src/data-table/data-table-column-header/data-table-column-header.js +130 -0
  13. package/src/data-table/data-table-column-header/data-table-column-header.styles.js +30 -0
  14. package/src/data-table/data-table-column-header/filter-handle.js +30 -0
  15. package/src/data-table/data-table-column-header/sorter.js +67 -0
  16. package/src/data-table/data-table-foot.js +3 -0
  17. package/src/data-table/data-table-head.js +3 -0
  18. package/src/data-table/data-table-row/data-table-row.js +103 -0
  19. package/src/data-table/data-table-row/data-table-row.styles.js +20 -0
  20. package/src/data-table/data-table-row/drag-handle-cell.js +9 -0
  21. package/src/data-table/data-table-row/expand-handle-cell.js +28 -0
  22. package/src/data-table/data-table-row/expanded-row.js +51 -0
  23. package/src/data-table/data-table-toolbar.js +3 -0
  24. package/src/data-table/data-table.e2e.stories.js +192 -0
  25. package/src/data-table/data-table.js +75 -0
  26. package/src/data-table/data-table.prod.stories.js +1342 -0
  27. package/src/data-table/features/can_scroll/index.js +48 -0
  28. package/src/data-table/features/can_scroll.feature +31 -0
  29. package/src/data-table/index.js +8 -0
  30. package/src/data-table/table-elements/__tests__/table-body.test.js +40 -0
  31. package/src/data-table/table-elements/__tests__/table-data-cell.test.js +123 -0
  32. package/src/data-table/table-elements/__tests__/table-foot.test.js +40 -0
  33. package/src/data-table/table-elements/__tests__/table-head.test.js +40 -0
  34. package/src/data-table/table-elements/__tests__/table-header-cell-action.test.js +46 -0
  35. package/src/data-table/table-elements/__tests__/table-header-cell.test.js +130 -0
  36. package/src/data-table/table-elements/__tests__/table-row.test.js +52 -0
  37. package/src/data-table/table-elements/__tests__/table-scroll-box.test.js +40 -0
  38. package/src/data-table/table-elements/__tests__/table-toolbar.test.js +44 -0
  39. package/src/data-table/table-elements/__tests__/table.test.js +53 -0
  40. package/src/data-table/table-elements/features/can_scroll/index.js +42 -0
  41. package/src/data-table/table-elements/features/can_scroll.feature +31 -0
  42. package/src/data-table/table-elements/index.js +10 -0
  43. package/src/data-table/table-elements/table-body.js +75 -0
  44. package/src/data-table/table-elements/table-data-cell/table-data-cell.js +126 -0
  45. package/src/data-table/table-elements/table-data-cell/table-data-cell.styles.js +42 -0
  46. package/src/data-table/table-elements/table-foot.js +35 -0
  47. package/src/data-table/table-elements/table-head.js +26 -0
  48. package/src/data-table/table-elements/table-header-cell/table-header-cell.js +121 -0
  49. package/src/data-table/table-elements/table-header-cell/table-header-cell.styles.js +71 -0
  50. package/src/data-table/table-elements/table-header-cell-action.js +62 -0
  51. package/src/data-table/table-elements/table-row.js +52 -0
  52. package/src/data-table/table-elements/table-scroll-box.js +41 -0
  53. package/src/data-table/table-elements/table-toolbar.js +50 -0
  54. package/src/data-table/table-elements/table.e2e.stories.js +190 -0
  55. package/src/data-table/table-elements/table.js +70 -0
  56. package/src/data-table/table-elements/table.stories.internal.js +1144 -0
  57. package/src/index.js +32 -0
  58. package/src/locales/ar/translations.json +4 -0
  59. package/src/locales/cs/translations.json +4 -0
  60. package/src/locales/en/translations.json +4 -0
  61. package/src/locales/es/translations.json +4 -0
  62. package/src/locales/es_419/translations.json +4 -0
  63. package/src/locales/fr/translations.json +4 -0
  64. package/src/locales/index.js +44 -0
  65. package/src/locales/km/translations.json +4 -0
  66. package/src/locales/lo/translations.json +4 -0
  67. package/src/locales/nb/translations.json +4 -0
  68. package/src/locales/nl/translations.json +4 -0
  69. package/src/locales/pt/translations.json +4 -0
  70. package/src/locales/ru/translations.json +4 -0
  71. package/src/locales/uk/translations.json +4 -0
  72. package/src/locales/uz_UZ_Cyrl/translations.json +4 -0
  73. package/src/locales/zh/translations.json +4 -0
  74. package/src/stacked-table/add-col-num-to-children.js +16 -0
  75. package/src/stacked-table/content-with-title.js +40 -0
  76. package/src/stacked-table/extract-header-labels.js +99 -0
  77. package/src/stacked-table/index.js +8 -0
  78. package/src/stacked-table/stacked-table-body.js +23 -0
  79. package/src/stacked-table/stacked-table-cell-head.js +39 -0
  80. package/src/stacked-table/stacked-table-cell.js +60 -0
  81. package/src/stacked-table/stacked-table-foot.js +24 -0
  82. package/src/stacked-table/stacked-table-head.js +23 -0
  83. package/src/stacked-table/stacked-table-row-head.js +19 -0
  84. package/src/stacked-table/stacked-table-row.js +50 -0
  85. package/src/stacked-table/stacked-table.js +33 -0
  86. package/src/stacked-table/stacked-table.prod.stories.js +463 -0
  87. package/src/stacked-table/stacked-table.test.js +127 -0
  88. package/src/stacked-table/supply-header-labels-to-children.js +7 -0
  89. package/src/stacked-table/table-context.js +4 -0
  90. package/src/stacked-table/table.js +28 -0
  91. package/src/table/index.js +8 -0
  92. package/src/table/table-body.js +21 -0
  93. package/src/table/table-cell-head.js +56 -0
  94. package/src/table/table-cell.js +56 -0
  95. package/src/table/table-context.js +7 -0
  96. package/src/table/table-foot.js +21 -0
  97. package/src/table/table-head.js +21 -0
  98. package/src/table/table-row-head.js +30 -0
  99. package/src/table/table-row.js +51 -0
  100. package/src/table/table.js +41 -0
  101. package/src/table/table.prod.stories.js +724 -0
@@ -0,0 +1,162 @@
1
+ import { shallow, mount } from 'enzyme'
2
+ import React from 'react'
3
+ import { DataTableRow } from '../data-table-row/data-table-row.js'
4
+ import { DragHandleCell } from '../data-table-row/drag-handle-cell.js'
5
+ import { ExpandHandleCell } from '../data-table-row/expand-handle-cell.js'
6
+ import { ExpandedRow } from '../data-table-row/expanded-row.js'
7
+ import { TableRow } from '../table-elements/index.js'
8
+
9
+ describe('<DataTableRow>', () => {
10
+ it('renders children', () => {
11
+ const children = 'children'
12
+ const wrapper = shallow(<DataTableRow>{children}</DataTableRow>)
13
+
14
+ expect(wrapper.containsMatchingElement(children)).toBe(true)
15
+ })
16
+ it('accepts a ref', () => {
17
+ const ref = React.createRef()
18
+ const wrapper = mount(
19
+ <table>
20
+ <thead>
21
+ <DataTableRow ref={ref} />
22
+ </thead>
23
+ </table>
24
+ )
25
+
26
+ expect(wrapper.find('tr').getDOMNode()).toBe(ref.current)
27
+ })
28
+ it('accepts a className prop', () => {
29
+ const className = 'test'
30
+ const wrapper = shallow(<DataTableRow className={className} />)
31
+
32
+ expect(wrapper.find(TableRow).prop('className')).toBe(className)
33
+ })
34
+ it('accepts a dataTest prop', () => {
35
+ const dataTest = 'test'
36
+ const wrapper = shallow(<DataTableRow dataTest={dataTest} />)
37
+
38
+ expect(wrapper.find(TableRow).prop('dataTest')).toBe(dataTest)
39
+ })
40
+ it('accepts a draggable prop', () => {
41
+ const wrapper = shallow(<DataTableRow draggable />)
42
+
43
+ expect(wrapper.find(TableRow).prop('draggable')).toBe(true)
44
+ expect(wrapper.find(DragHandleCell)).toHaveLength(1)
45
+ })
46
+ it('accepts an expandable prop', () => {
47
+ const wrapper = shallow(
48
+ <DataTableRow
49
+ expandable
50
+ expandableContent="test"
51
+ onExpandToggle={() => {}}
52
+ />
53
+ )
54
+
55
+ expect(wrapper.find(ExpandHandleCell)).toHaveLength(1)
56
+ })
57
+ it('accepts an expandableContent prop', () => {
58
+ const expandableContent = <div>content</div>
59
+ const wrapper = shallow(
60
+ <DataTableRow
61
+ expandableContent={expandableContent}
62
+ expanded
63
+ expandable
64
+ onExpandToggle={() => {}}
65
+ />
66
+ )
67
+
68
+ const additionalRowTag = wrapper
69
+ .find(ExpandedRow)
70
+ .dive()
71
+ .find(TableRow)
72
+ .dive()
73
+ .find('tr')
74
+
75
+ // render expandableContent in additional row
76
+ expect(additionalRowTag).toHaveLength(1)
77
+
78
+ // Hover styles
79
+ additionalRowTag.simulate('mouseover')
80
+ expect(
81
+ wrapper
82
+ .find(TableRow)
83
+ .dive()
84
+ .find('tr')
85
+ .hasClass('isHoveringExpandedContent')
86
+ ).toBe(true)
87
+
88
+ additionalRowTag.simulate('mouseout')
89
+ expect(
90
+ wrapper
91
+ .find(TableRow)
92
+ .dive()
93
+ .find('tr')
94
+ .hasClass('isHoveringExpandedContent')
95
+ ).toBe(false)
96
+ })
97
+ it('accepts an expanded prop', () => {
98
+ const wrapperClosed = shallow(
99
+ <DataTableRow
100
+ expandable
101
+ expandableContent="test"
102
+ onExpandToggle={() => {}}
103
+ />
104
+ )
105
+ const wrapperOpen = shallow(
106
+ <DataTableRow
107
+ expanded
108
+ expandable
109
+ expandableContent="test"
110
+ onExpandToggle={() => {}}
111
+ />
112
+ )
113
+
114
+ expect(wrapperClosed.find(ExpandedRow)).toHaveLength(0)
115
+ expect(wrapperOpen.find(ExpandedRow)).toHaveLength(1)
116
+ })
117
+ it('accepts a role prop', () => {
118
+ const role = 'test'
119
+ const wrapper = shallow(<DataTableRow role={role} />)
120
+
121
+ expect(wrapper.find(TableRow).prop('role')).toBe(role)
122
+ })
123
+ it('accepts a selected prop', () => {
124
+ const wrapper = shallow(<DataTableRow selected />)
125
+
126
+ expect(wrapper.find(TableRow).prop('selected')).toBe(true)
127
+ })
128
+ it('accepts an onExpandToggle prop', () => {
129
+ const cb = jest.fn()
130
+ const wrapper = shallow(
131
+ <DataTableRow
132
+ expandable
133
+ expandableContent="test"
134
+ onExpandToggle={cb}
135
+ />
136
+ )
137
+
138
+ wrapper.find(ExpandHandleCell).dive().simulate('click')
139
+
140
+ expect(cb).toHaveBeenCalledTimes(1)
141
+ expect(cb).toHaveBeenCalledWith({ expanded: true })
142
+ })
143
+
144
+ it('accepts a hover prop', () => {
145
+ const cb = jest.fn()
146
+ const wrapper = mount(
147
+ <DataTableRow
148
+ expandable
149
+ expandableContent="test"
150
+ onExpandToggle={cb}
151
+ onMouseOver={cb}
152
+ onClick={cb}
153
+ />
154
+ )
155
+
156
+ wrapper.find('tr').simulate('mouseover')
157
+
158
+ wrapper.find('tr').simulate('click')
159
+
160
+ expect(cb).toHaveBeenCalledTimes(2)
161
+ })
162
+ })
@@ -0,0 +1,85 @@
1
+ import { shallow, mount } from 'enzyme'
2
+ import React from 'react'
3
+ import { DataTable } from '../data-table.js'
4
+ import { Table, TableScrollBox } from '../table-elements/index.js'
5
+
6
+ describe('<DataTable>', () => {
7
+ it('renders children', () => {
8
+ const children = 'children'
9
+ const wrapper = shallow(<DataTable>{children}</DataTable>)
10
+
11
+ expect(wrapper.containsMatchingElement(children)).toBe(true)
12
+ })
13
+ it('accepts a ref', () => {
14
+ const ref = React.createRef()
15
+ const wrapper = mount(<DataTable ref={ref} />)
16
+
17
+ expect(wrapper.find('table').getDOMNode()).toBe(ref.current)
18
+ })
19
+ it('accepts a className prop', () => {
20
+ const className = 'test'
21
+ const wrapper = shallow(<DataTable className={className} />)
22
+
23
+ expect(wrapper.find(Table).prop('className')).toBe(className)
24
+ })
25
+ it('accepts a dataTest prop', () => {
26
+ const dataTest = 'test'
27
+ const wrapper = shallow(<DataTable dataTest={dataTest} />)
28
+
29
+ expect(wrapper.find(Table).prop('dataTest')).toBe(dataTest)
30
+ })
31
+ it('accepts a layout prop', () => {
32
+ const layout = 'fixed'
33
+ const wrapper = shallow(<DataTable layout={layout} />)
34
+
35
+ expect(wrapper.find(Table).prop('layout')).toBe(layout)
36
+ })
37
+ it('accepts a role prop', () => {
38
+ const role = 'test'
39
+ const wrapper = shallow(<DataTable role={role} />)
40
+
41
+ expect(wrapper.find(Table).prop('role')).toBe(role)
42
+ })
43
+ it('renders a datatable when no scrollHeight or scrollWidth are provided', () => {
44
+ const wrapper = shallow(<DataTable />)
45
+
46
+ expect(wrapper.find(Table)).toHaveLength(1)
47
+ expect(wrapper.find(TableScrollBox)).toHaveLength(0)
48
+ })
49
+ it('wraps the datatable in a scroll box when scrollHeight is provided', () => {
50
+ const height = '200px'
51
+ const wrapper = shallow(<DataTable scrollHeight={height} />)
52
+
53
+ expect(wrapper.dive().type()).toBe('div')
54
+ expect(wrapper.find(TableScrollBox)).toHaveLength(1)
55
+ expect(wrapper.find(TableScrollBox).dive().find(Table)).toHaveLength(1)
56
+ expect(wrapper.find(TableScrollBox).prop('maxHeight')).toBe(height)
57
+ })
58
+ it('wraps the datatable in a scroll box when scrollWidth is provided', () => {
59
+ const width = '200px'
60
+ const wrapper = shallow(<DataTable scrollWidth={width} />)
61
+
62
+ expect(wrapper.dive().type()).toBe('div')
63
+ expect(wrapper.find(TableScrollBox)).toHaveLength(1)
64
+ expect(wrapper.find(TableScrollBox).dive().find(Table)).toHaveLength(1)
65
+ expect(wrapper.find(TableScrollBox).prop('maxWidth')).toBe(width)
66
+ })
67
+ it('wraps the datatable in a scroll box when both scrollHeight and scrollWidth are provided', () => {
68
+ const size = '200px'
69
+ const wrapper = shallow(
70
+ <DataTable scrollHeight={size} scrollWidth={size} />
71
+ )
72
+
73
+ expect(wrapper.dive().type()).toBe('div')
74
+ expect(wrapper.find(TableScrollBox)).toHaveLength(1)
75
+ expect(wrapper.find(TableScrollBox).dive().find(Table)).toHaveLength(1)
76
+ expect(wrapper.find(TableScrollBox).prop('maxHeight')).toBe(size)
77
+ expect(wrapper.find(TableScrollBox).prop('maxWidth')).toBe(size)
78
+ })
79
+ it('accepts a width prop', () => {
80
+ const width = '200px'
81
+ const wrapper = shallow(<DataTable width={width} />)
82
+
83
+ expect(wrapper.find(Table).prop('width')).toBe(width)
84
+ })
85
+ })
@@ -0,0 +1,3 @@
1
+ // This component does not need additional behaviour but is
2
+ // exposed as DataTableBody for component name consistency
3
+ export { TableBody as DataTableBody } from './table-elements/index.js'
@@ -0,0 +1,111 @@
1
+ import { mutuallyExclusive, requiredIf } from '@dhis2/prop-types'
2
+ import PropTypes from 'prop-types'
3
+ import React, { forwardRef } from 'react'
4
+ import { TableDataCell, TableHeaderCell } from './table-elements/index.js'
5
+
6
+ export const DataTableCell = forwardRef(
7
+ (
8
+ {
9
+ active,
10
+ align = 'left',
11
+ backgroundColor,
12
+ bordered,
13
+ children,
14
+ className,
15
+ colSpan,
16
+ dataTest = 'dhis2-uicore-datatablecell',
17
+ error,
18
+ fixed,
19
+ large,
20
+
21
+ left = 'auto',
22
+ muted,
23
+ rowSpan,
24
+ role,
25
+ scope,
26
+ staticStyle,
27
+ tag,
28
+ valid,
29
+ width = 'auto',
30
+ onClick,
31
+ ...props
32
+ },
33
+ ref
34
+ ) => {
35
+ const TableCell =
36
+ (!tag && fixed) || (tag && tag === 'th')
37
+ ? TableHeaderCell
38
+ : TableDataCell
39
+ return (
40
+ <TableCell
41
+ {...props}
42
+ active={active}
43
+ align={align}
44
+ backgroundColor={backgroundColor}
45
+ bordered={bordered}
46
+ className={className}
47
+ colSpan={colSpan}
48
+ dataTest={dataTest}
49
+ error={error}
50
+ fixed={fixed}
51
+ large={large}
52
+ left={left}
53
+ muted={muted}
54
+ rowSpan={rowSpan}
55
+ ref={ref}
56
+ role={role}
57
+ staticStyle={staticStyle}
58
+ scope={scope}
59
+ valid={valid}
60
+ width={width}
61
+ onClick={onClick}
62
+ >
63
+ {children}
64
+ </TableCell>
65
+ )
66
+ }
67
+ )
68
+
69
+ DataTableCell.displayName = 'DataTableCell'
70
+
71
+ const stylePropType = mutuallyExclusive(
72
+ ['valid', 'error', 'muted'],
73
+ PropTypes.bool
74
+ )
75
+ const requiredIfFixedPropType = requiredIf(
76
+ (props) => props.fixed,
77
+ PropTypes.string
78
+ )
79
+ DataTableCell.propTypes = {
80
+ /** To toggle border color, for example for editing */
81
+ active: PropTypes.bool,
82
+ align: PropTypes.oneOf(['left', 'center', 'right']),
83
+ /** Sets background color of the cell. Disables dynamic background colors from active, hover, and selected states */
84
+ backgroundColor: PropTypes.string,
85
+ bordered: PropTypes.bool,
86
+ children: PropTypes.node,
87
+ className: PropTypes.string,
88
+ colSpan: PropTypes.string,
89
+ dataTest: PropTypes.string,
90
+ /** Mutually exclusive with muted and valid */
91
+ error: stylePropType,
92
+ /** When true a TableHeaderCell with sticky positioning will be rendered */
93
+ fixed: PropTypes.bool,
94
+ large: PropTypes.bool,
95
+ /** Required when fixed */
96
+ left: requiredIfFixedPropType,
97
+ /** Mutually exclusive with error and valid */
98
+ muted: stylePropType,
99
+ role: PropTypes.string,
100
+ rowSpan: PropTypes.string,
101
+ scope: PropTypes.string,
102
+ /** Surpress hover and active event styles */
103
+ staticStyle: PropTypes.bool,
104
+ /** Render a TableDataCell or TableHeaderCell respectively */
105
+ tag: PropTypes.oneOf(['td', 'th']),
106
+ /** Mutually exclusive with error and muted */
107
+ valid: stylePropType,
108
+ /** Required when fixed */
109
+ width: requiredIfFixedPropType,
110
+ onClick: PropTypes.func,
111
+ }
@@ -0,0 +1,130 @@
1
+ import { requiredIf } from '@dhis2/prop-types'
2
+ import cx from 'classnames'
3
+ import PropTypes from 'prop-types'
4
+ import React, { forwardRef } from 'react'
5
+ import { TableHeaderCell } from '../table-elements/index.js'
6
+ import {
7
+ styles,
8
+ resolvedTableHeaderCss,
9
+ } from './data-table-column-header.styles.js'
10
+ import { FilterHandle } from './filter-handle.js'
11
+ import { Sorter, SORT_DIRECTIONS } from './sorter.js'
12
+
13
+ const flexboxAlignLookup = {
14
+ left: 'flex-start',
15
+ center: 'center',
16
+ right: 'flex-end',
17
+ }
18
+
19
+ export const DataTableColumnHeader = forwardRef(
20
+ (
21
+ {
22
+ align,
23
+ children,
24
+ className,
25
+ colSpan,
26
+ dataTest = 'dhis2-uicore-datatablecellhead',
27
+ filter,
28
+ fixed,
29
+ large,
30
+ left,
31
+ name,
32
+ role,
33
+ rowSpan,
34
+ scope,
35
+ showFilter,
36
+ sortDirection,
37
+ sortIconTitle,
38
+ top,
39
+ width,
40
+ onFilterIconClick,
41
+ onSortIconClick,
42
+ },
43
+ ref
44
+ ) => (
45
+ <TableHeaderCell
46
+ align={align}
47
+ className={cx(
48
+ className,
49
+ 'DataTableColumnHeader',
50
+ resolvedTableHeaderCss.className
51
+ )}
52
+ colSpan={colSpan}
53
+ dataTest={dataTest}
54
+ fixed={fixed}
55
+ large={large}
56
+ left={left}
57
+ ref={ref}
58
+ rowSpan={rowSpan}
59
+ role={role}
60
+ scope={scope}
61
+ top={top}
62
+ width={width}
63
+ >
64
+ <span className="container">
65
+ <span className={cx('top', { large })}>
66
+ <span className="content">{children}</span>
67
+ {sortDirection && (
68
+ <Sorter
69
+ name={name}
70
+ sortDirection={sortDirection}
71
+ onClick={onSortIconClick}
72
+ title={sortIconTitle}
73
+ />
74
+ )}
75
+ {filter && (
76
+ <FilterHandle
77
+ name={name}
78
+ active={showFilter}
79
+ onClick={onFilterIconClick}
80
+ />
81
+ )}
82
+ </span>
83
+ {showFilter && filter}
84
+ </span>
85
+ {resolvedTableHeaderCss.styles}
86
+ <style jsx>{styles}</style>
87
+ <style jsx>{`
88
+ .label {
89
+ justify-content: ${flexboxAlignLookup[align]};
90
+ }
91
+ `}</style>
92
+ </TableHeaderCell>
93
+ )
94
+ )
95
+
96
+ DataTableColumnHeader.displayName = 'DataTableColumnHeader'
97
+
98
+ DataTableColumnHeader.propTypes = {
99
+ align: PropTypes.oneOf(['left', 'center', 'right']),
100
+ children: PropTypes.node,
101
+ className: PropTypes.string,
102
+ colSpan: PropTypes.string,
103
+ dataTest: PropTypes.string,
104
+ /** The filter element (JSX), required when onFilterIconClick or showFilter are present */
105
+ filter: requiredIf(
106
+ (props) => props.onFilterIconClick || props.showFilter,
107
+ PropTypes.node
108
+ ),
109
+ fixed: PropTypes.bool,
110
+ large: PropTypes.bool,
111
+ /** Left or top required when fixed */
112
+ left: requiredIf((props) => props.fixed && !props.top, PropTypes.string),
113
+ /** Can be used to match a column with a property name */
114
+ name: PropTypes.string,
115
+ role: PropTypes.string,
116
+ rowSpan: PropTypes.string,
117
+ scope: PropTypes.string,
118
+ showFilter: requiredIf((props) => props.filter, PropTypes.bool),
119
+ sortDirection: requiredIf(
120
+ (props) => props.onSortIconClick,
121
+ PropTypes.oneOf(SORT_DIRECTIONS)
122
+ ),
123
+ sortIconTitle: PropTypes.string,
124
+ /** Left or top required when fixed */
125
+ top: requiredIf((props) => props.fixed && !props.left, PropTypes.string),
126
+ width: PropTypes.string,
127
+ onFilterIconClick: requiredIf((props) => props.filter, PropTypes.func),
128
+ /** Sort icon click callback with `nextSortDirection` and `name` in payload */
129
+ onSortIconClick: requiredIf((props) => props.sortDirection, PropTypes.func),
130
+ }
@@ -0,0 +1,30 @@
1
+ import css from 'styled-jsx/css'
2
+
3
+ export const styles = css`
4
+ span.container {
5
+ display: flex;
6
+ flex-direction: column;
7
+ height: 100%;
8
+ }
9
+ span.top {
10
+ display: flex;
11
+ flex-direction: row;
12
+ align-items: flex-start;
13
+ }
14
+ span.content {
15
+ display: flex;
16
+ align-items: center;
17
+ min-height: 24px;
18
+ }
19
+ `
20
+
21
+ export const resolvedTableHeaderCss = css.resolve`
22
+ :global(thead) > :global(tr) > th.DataTableColumnHeader {
23
+ padding-top: 6px;
24
+ padding-bottom: 6px;
25
+ }
26
+ :global(thead) > :global(tr) > th.DataTableColumnHeader.large {
27
+ padding-top: 12px;
28
+ padding-bottom: 12px;
29
+ }
30
+ `
@@ -0,0 +1,30 @@
1
+ import { colors } from '@dhis2/ui-constants'
2
+ import { IconSearch16 } from '@dhis2/ui-icons'
3
+ import PropTypes from 'prop-types'
4
+ import React from 'react'
5
+ import i18n from '../../locales/index.js'
6
+ import { TableHeaderCellAction } from '../table-elements/index.js'
7
+
8
+ export const FilterHandle = ({ active, name, onClick }) => {
9
+ const filterIconColor = active ? colors.blue700 : colors.grey600
10
+ const clickHandler = onClick
11
+ ? (event) => {
12
+ onClick({ name, show: !active }, event)
13
+ }
14
+ : undefined
15
+
16
+ return (
17
+ <TableHeaderCellAction
18
+ onClick={clickHandler}
19
+ title={i18n.t('Toggle filter')}
20
+ >
21
+ <IconSearch16 color={filterIconColor} />
22
+ </TableHeaderCellAction>
23
+ )
24
+ }
25
+
26
+ FilterHandle.propTypes = {
27
+ active: PropTypes.bool,
28
+ name: PropTypes.string,
29
+ onClick: PropTypes.func,
30
+ }
@@ -0,0 +1,67 @@
1
+ import { requiredIf } from '@dhis2/prop-types'
2
+ import { colors } from '@dhis2/ui-constants'
3
+ import PropTypes from 'prop-types'
4
+ import React from 'react'
5
+ import i18n from '../../locales/index.js'
6
+ import { TableHeaderCellAction } from '../table-elements/index.js'
7
+
8
+ export const ASC = 'asc'
9
+ export const DESC = 'desc'
10
+ export const DEFAULT = 'default'
11
+ export const SORT_DIRECTIONS = [DEFAULT, ASC, DESC]
12
+
13
+ export const getNextSortDirection = (currentDirection) => {
14
+ const currentIndex = SORT_DIRECTIONS.indexOf(currentDirection)
15
+ const nextIndex = (currentIndex + 1) % SORT_DIRECTIONS.length
16
+
17
+ return SORT_DIRECTIONS[nextIndex]
18
+ }
19
+
20
+ export const Sorter = ({ name, sortDirection, title, onClick }) => {
21
+ const nextSortDirection = getNextSortDirection(sortDirection)
22
+ const clickHandler = onClick
23
+ ? (event) => {
24
+ onClick({ name, direction: nextSortDirection }, event)
25
+ }
26
+ : undefined
27
+
28
+ return (
29
+ <TableHeaderCellAction
30
+ onClick={clickHandler}
31
+ title={title || i18n.t('Sort items')}
32
+ >
33
+ <svg
34
+ xmlns="http://www.w3.org/2000/svg"
35
+ width="16"
36
+ height="16"
37
+ viewBox="0 0 16 16"
38
+ className={sortDirection}
39
+ >
40
+ <g fill="none" fillRule="evenodd">
41
+ <polygon className="top" points="4 9 12 9 8 14" />
42
+ <polygon className="bottom" points="4 7 12 7 8 2" />
43
+ </g>
44
+ </svg>
45
+ <style jsx>{`
46
+ svg .top,
47
+ svg .bottom {
48
+ fill: ${colors.grey500};
49
+ }
50
+ svg.asc .top,
51
+ svg.desc .bottom {
52
+ fill: ${colors.blue700};
53
+ }
54
+ `}</style>
55
+ </TableHeaderCellAction>
56
+ )
57
+ }
58
+
59
+ Sorter.propTypes = {
60
+ name: PropTypes.string,
61
+ sortDirection: requiredIf(
62
+ (props) => props.onClick,
63
+ PropTypes.oneOf(SORT_DIRECTIONS)
64
+ ),
65
+ title: PropTypes.string,
66
+ onClick: PropTypes.func,
67
+ }
@@ -0,0 +1,3 @@
1
+ // This component does not need additional behaviour but is
2
+ // exposed as DataTableFoot for component name consistency
3
+ export { TableFoot as DataTableFoot } from './table-elements/index.js'
@@ -0,0 +1,3 @@
1
+ // This component does not need additional behaviour but is
2
+ // exposed as DataTableHead for component name consistency
3
+ export { TableHead as DataTableHead } from './table-elements/index.js'