@dhis2-ui/table 10.16.1 → 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.
- package/package.json +5 -4
- package/src/data-table/__tests__/data-table-cell.test.js +168 -0
- package/src/data-table/__tests__/data-table-column-header/filter-handle.test.js +43 -0
- package/src/data-table/__tests__/data-table-column-header/sorter.test.js +41 -0
- package/src/data-table/__tests__/data-table-column-header.test.js +227 -0
- package/src/data-table/__tests__/data-table-row/expand-handle-cell.js +32 -0
- package/src/data-table/__tests__/data-table-row/expanded-row.test.js +57 -0
- package/src/data-table/__tests__/data-table-row.test.js +162 -0
- package/src/data-table/__tests__/data-table.test.js +85 -0
- package/src/data-table/data-table-body.js +3 -0
- package/src/data-table/data-table-cell.js +111 -0
- package/src/data-table/data-table-column-header/data-table-column-header.js +130 -0
- package/src/data-table/data-table-column-header/data-table-column-header.styles.js +30 -0
- package/src/data-table/data-table-column-header/filter-handle.js +30 -0
- package/src/data-table/data-table-column-header/sorter.js +67 -0
- package/src/data-table/data-table-foot.js +3 -0
- package/src/data-table/data-table-head.js +3 -0
- package/src/data-table/data-table-row/data-table-row.js +103 -0
- package/src/data-table/data-table-row/data-table-row.styles.js +20 -0
- package/src/data-table/data-table-row/drag-handle-cell.js +9 -0
- package/src/data-table/data-table-row/expand-handle-cell.js +28 -0
- package/src/data-table/data-table-row/expanded-row.js +51 -0
- package/src/data-table/data-table-toolbar.js +3 -0
- package/src/data-table/data-table.e2e.stories.js +192 -0
- package/src/data-table/data-table.js +75 -0
- package/src/data-table/data-table.prod.stories.js +1342 -0
- package/src/data-table/features/can_scroll/index.js +48 -0
- package/src/data-table/features/can_scroll.feature +31 -0
- package/src/data-table/index.js +8 -0
- package/src/data-table/table-elements/__tests__/table-body.test.js +40 -0
- package/src/data-table/table-elements/__tests__/table-data-cell.test.js +123 -0
- package/src/data-table/table-elements/__tests__/table-foot.test.js +40 -0
- package/src/data-table/table-elements/__tests__/table-head.test.js +40 -0
- package/src/data-table/table-elements/__tests__/table-header-cell-action.test.js +46 -0
- package/src/data-table/table-elements/__tests__/table-header-cell.test.js +130 -0
- package/src/data-table/table-elements/__tests__/table-row.test.js +52 -0
- package/src/data-table/table-elements/__tests__/table-scroll-box.test.js +40 -0
- package/src/data-table/table-elements/__tests__/table-toolbar.test.js +44 -0
- package/src/data-table/table-elements/__tests__/table.test.js +53 -0
- package/src/data-table/table-elements/features/can_scroll/index.js +42 -0
- package/src/data-table/table-elements/features/can_scroll.feature +31 -0
- package/src/data-table/table-elements/index.js +10 -0
- package/src/data-table/table-elements/table-body.js +75 -0
- package/src/data-table/table-elements/table-data-cell/table-data-cell.js +126 -0
- package/src/data-table/table-elements/table-data-cell/table-data-cell.styles.js +42 -0
- package/src/data-table/table-elements/table-foot.js +35 -0
- package/src/data-table/table-elements/table-head.js +26 -0
- package/src/data-table/table-elements/table-header-cell/table-header-cell.js +121 -0
- package/src/data-table/table-elements/table-header-cell/table-header-cell.styles.js +71 -0
- package/src/data-table/table-elements/table-header-cell-action.js +62 -0
- package/src/data-table/table-elements/table-row.js +52 -0
- package/src/data-table/table-elements/table-scroll-box.js +41 -0
- package/src/data-table/table-elements/table-toolbar.js +50 -0
- package/src/data-table/table-elements/table.e2e.stories.js +190 -0
- package/src/data-table/table-elements/table.js +70 -0
- package/src/data-table/table-elements/table.stories.internal.js +1144 -0
- package/src/index.js +32 -0
- package/src/locales/ar/translations.json +4 -0
- package/src/locales/cs/translations.json +4 -0
- package/src/locales/en/translations.json +4 -0
- package/src/locales/es/translations.json +4 -0
- package/src/locales/es_419/translations.json +4 -0
- package/src/locales/fr/translations.json +4 -0
- package/src/locales/index.js +44 -0
- package/src/locales/km/translations.json +4 -0
- package/src/locales/lo/translations.json +4 -0
- package/src/locales/nb/translations.json +4 -0
- package/src/locales/nl/translations.json +4 -0
- package/src/locales/pt/translations.json +4 -0
- package/src/locales/ru/translations.json +4 -0
- package/src/locales/uk/translations.json +4 -0
- package/src/locales/uz_UZ_Cyrl/translations.json +4 -0
- package/src/locales/zh/translations.json +4 -0
- package/src/stacked-table/add-col-num-to-children.js +16 -0
- package/src/stacked-table/content-with-title.js +40 -0
- package/src/stacked-table/extract-header-labels.js +99 -0
- package/src/stacked-table/index.js +8 -0
- package/src/stacked-table/stacked-table-body.js +23 -0
- package/src/stacked-table/stacked-table-cell-head.js +39 -0
- package/src/stacked-table/stacked-table-cell.js +60 -0
- package/src/stacked-table/stacked-table-foot.js +24 -0
- package/src/stacked-table/stacked-table-head.js +23 -0
- package/src/stacked-table/stacked-table-row-head.js +19 -0
- package/src/stacked-table/stacked-table-row.js +50 -0
- package/src/stacked-table/stacked-table.js +33 -0
- package/src/stacked-table/stacked-table.prod.stories.js +463 -0
- package/src/stacked-table/stacked-table.test.js +127 -0
- package/src/stacked-table/supply-header-labels-to-children.js +7 -0
- package/src/stacked-table/table-context.js +4 -0
- package/src/stacked-table/table.js +28 -0
- package/src/table/index.js +8 -0
- package/src/table/table-body.js +21 -0
- package/src/table/table-cell-head.js +56 -0
- package/src/table/table-cell.js +56 -0
- package/src/table/table-context.js +7 -0
- package/src/table/table-foot.js +21 -0
- package/src/table/table-head.js +21 -0
- package/src/table/table-row-head.js +30 -0
- package/src/table/table-row.js +51 -0
- package/src/table/table.js +41 -0
- package/src/table/table.prod.stories.js +724 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { shallow, mount } from 'enzyme'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { Table } from '../table.js'
|
|
4
|
+
|
|
5
|
+
describe('<Table>', () => {
|
|
6
|
+
it('renders children', () => {
|
|
7
|
+
const children = 'children'
|
|
8
|
+
const wrapper = shallow(<Table>{children}</Table>)
|
|
9
|
+
|
|
10
|
+
expect(wrapper.containsMatchingElement(children)).toBe(true)
|
|
11
|
+
})
|
|
12
|
+
it('accepts a ref', () => {
|
|
13
|
+
const ref = React.createRef()
|
|
14
|
+
const wrapper = mount(<Table ref={ref} />)
|
|
15
|
+
|
|
16
|
+
expect(wrapper.find('table').getDOMNode()).toBe(ref.current)
|
|
17
|
+
})
|
|
18
|
+
it('accepts a borderless prop', () => {
|
|
19
|
+
const wrapper = shallow(<Table borderless />)
|
|
20
|
+
|
|
21
|
+
expect(wrapper.find('table').hasClass('borderless')).toBe(true)
|
|
22
|
+
})
|
|
23
|
+
it('accepts a className prop', () => {
|
|
24
|
+
const className = 'test'
|
|
25
|
+
const wrapper = shallow(<Table className={className} />)
|
|
26
|
+
|
|
27
|
+
expect(wrapper.find('table').hasClass(className)).toBe(true)
|
|
28
|
+
})
|
|
29
|
+
it('accepts a dataTest prop', () => {
|
|
30
|
+
const dataTest = 'test'
|
|
31
|
+
const wrapper = shallow(<Table dataTest={dataTest} />)
|
|
32
|
+
|
|
33
|
+
expect(wrapper.find('table').prop('data-test')).toBe(dataTest)
|
|
34
|
+
})
|
|
35
|
+
it('accepts a layout prop', () => {
|
|
36
|
+
const layout = 'fixed'
|
|
37
|
+
const wrapper = shallow(<Table layout={layout} />)
|
|
38
|
+
|
|
39
|
+
expect(wrapper.html()).toContain(`table-layout: ${layout};`)
|
|
40
|
+
})
|
|
41
|
+
it('accepts a role prop', () => {
|
|
42
|
+
const role = 'test'
|
|
43
|
+
const wrapper = shallow(<Table role={role} />)
|
|
44
|
+
|
|
45
|
+
expect(wrapper.find('table').prop('role')).toBe(role)
|
|
46
|
+
})
|
|
47
|
+
it('accepts a width prop', () => {
|
|
48
|
+
const width = '200px'
|
|
49
|
+
const wrapper = shallow(<Table width={width} />)
|
|
50
|
+
|
|
51
|
+
expect(wrapper.html()).toContain(`width: ${width};`)
|
|
52
|
+
})
|
|
53
|
+
})
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
|
|
2
|
+
|
|
3
|
+
Given('a scrolling table is rendered', () => {
|
|
4
|
+
cy.visitStory('Table', 'Fixed Header And Columns')
|
|
5
|
+
})
|
|
6
|
+
When('the user scrolls down', () => {
|
|
7
|
+
cy.get('[data-test="dhis2-uicore-tablescrollbox"]').scrollTo('bottomLeft')
|
|
8
|
+
})
|
|
9
|
+
When('the user scrolls right', () => {
|
|
10
|
+
cy.get('[data-test="dhis2-uicore-tablescrollbox"]').scrollTo('topRight')
|
|
11
|
+
})
|
|
12
|
+
When('the user scrolls down and right', () => {
|
|
13
|
+
cy.get('[data-test="dhis2-uicore-tablescrollbox"]').scrollTo('bottomRight')
|
|
14
|
+
})
|
|
15
|
+
Then('the header row is visible', () => {
|
|
16
|
+
cy.get('thead > tr > th').should('be.visible')
|
|
17
|
+
})
|
|
18
|
+
Then('the first two table columns are visible', () => {
|
|
19
|
+
cy.get('tbody > tr > th:nth-child(1)').should('be.visible')
|
|
20
|
+
cy.get('tbody > tr > th:nth-child(2)').should('be.visible')
|
|
21
|
+
})
|
|
22
|
+
Then('the bottom right scrolling table cell is visible', () => {
|
|
23
|
+
cy.get('td').contains('scrolling bottom-right').should('be.visible')
|
|
24
|
+
})
|
|
25
|
+
Then('the top left scrolling table cell is not visible', () => {
|
|
26
|
+
cy.get('td').contains('scrolling top-left').should('not.be.visible')
|
|
27
|
+
})
|
|
28
|
+
Then('the bottom left scrolling table cell is not visible', () => {
|
|
29
|
+
cy.get('td').contains('scrolling bottom-left').should('not.be.visible')
|
|
30
|
+
})
|
|
31
|
+
Then('the top right scrolling table cell is not visible', () => {
|
|
32
|
+
cy.get('td').contains('scrolling top-right').should('not.be.visible')
|
|
33
|
+
})
|
|
34
|
+
Then('the top right scrolling table cell is visible', () => {
|
|
35
|
+
cy.get('td').contains('scrolling top-right').should('be.visible')
|
|
36
|
+
})
|
|
37
|
+
Then('the bottom left scrolling table cell is visible', () => {
|
|
38
|
+
cy.get('td').contains('scrolling bottom-left').should('be.visible')
|
|
39
|
+
})
|
|
40
|
+
Then('the bottom right scrolling table cell is not visible', () => {
|
|
41
|
+
cy.get('td').contains('scrolling bottom-right').should('not.be.visible')
|
|
42
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Feature: Scrolling a Table
|
|
2
|
+
|
|
3
|
+
Scenario: The user vertically scrolls the Table
|
|
4
|
+
Given a scrolling table is rendered
|
|
5
|
+
When the user scrolls down
|
|
6
|
+
Then the header row is visible
|
|
7
|
+
And the first two table columns are visible
|
|
8
|
+
And the bottom left scrolling table cell is visible
|
|
9
|
+
But the bottom right scrolling table cell is not visible
|
|
10
|
+
And the top left scrolling table cell is not visible
|
|
11
|
+
And the top right scrolling table cell is not visible
|
|
12
|
+
|
|
13
|
+
Scenario: The user horizontally scrolls the Table
|
|
14
|
+
Given a scrolling table is rendered
|
|
15
|
+
When the user scrolls right
|
|
16
|
+
Then the header row is visible
|
|
17
|
+
And the first two table columns are visible
|
|
18
|
+
And the top right scrolling table cell is visible
|
|
19
|
+
But the bottom right scrolling table cell is not visible
|
|
20
|
+
And the top left scrolling table cell is not visible
|
|
21
|
+
And the bottom left scrolling table cell is not visible
|
|
22
|
+
|
|
23
|
+
Scenario: The user vertically and horizontally scrolls the Table
|
|
24
|
+
Given a scrolling table is rendered
|
|
25
|
+
When the user scrolls down and right
|
|
26
|
+
Then the header row is visible
|
|
27
|
+
And the first two table columns are visible
|
|
28
|
+
And the bottom right scrolling table cell is visible
|
|
29
|
+
But the top left scrolling table cell is not visible
|
|
30
|
+
And the bottom left scrolling table cell is not visible
|
|
31
|
+
And the top right scrolling table cell is not visible
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { Table } from './table.js'
|
|
2
|
+
export { TableBody } from './table-body.js'
|
|
3
|
+
export { TableDataCell } from './table-data-cell/table-data-cell.js'
|
|
4
|
+
export { TableHeaderCell } from './table-header-cell/table-header-cell.js'
|
|
5
|
+
export { TableHeaderCellAction } from './table-header-cell-action.js'
|
|
6
|
+
export { TableFoot } from './table-foot.js'
|
|
7
|
+
export { TableHead } from './table-head.js'
|
|
8
|
+
export { TableRow } from './table-row.js'
|
|
9
|
+
export { TableScrollBox } from './table-scroll-box.js'
|
|
10
|
+
export { TableToolbar } from './table-toolbar.js'
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { colors } from '@dhis2/ui-constants'
|
|
2
|
+
import cx from 'classnames'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
import React, { forwardRef } from 'react'
|
|
5
|
+
|
|
6
|
+
export const TableBody = forwardRef(
|
|
7
|
+
(
|
|
8
|
+
{
|
|
9
|
+
children,
|
|
10
|
+
className,
|
|
11
|
+
dataTest = 'dhis2-uicore-tablebody',
|
|
12
|
+
role,
|
|
13
|
+
loading,
|
|
14
|
+
...props
|
|
15
|
+
},
|
|
16
|
+
ref
|
|
17
|
+
) => (
|
|
18
|
+
<tbody
|
|
19
|
+
{...props}
|
|
20
|
+
className={cx(className, {
|
|
21
|
+
loading,
|
|
22
|
+
})}
|
|
23
|
+
data-test={dataTest}
|
|
24
|
+
ref={ref}
|
|
25
|
+
role={role}
|
|
26
|
+
>
|
|
27
|
+
{children}
|
|
28
|
+
<style jsx>{`
|
|
29
|
+
tbody {
|
|
30
|
+
position: relative;
|
|
31
|
+
}
|
|
32
|
+
.loading:before {
|
|
33
|
+
content: '';
|
|
34
|
+
position: absolute;
|
|
35
|
+
top: 0;
|
|
36
|
+
bottom: 0;
|
|
37
|
+
inset-inline-start: 0;
|
|
38
|
+
inset-inline-end: 0;
|
|
39
|
+
background-color: rgba(255, 255, 255, 0.8);
|
|
40
|
+
}
|
|
41
|
+
.loading:after {
|
|
42
|
+
content: '';
|
|
43
|
+
position: absolute;
|
|
44
|
+
top: calc(50% - 24px);
|
|
45
|
+
inset-inline-start: calc(50% - 24px);
|
|
46
|
+
width: 48px;
|
|
47
|
+
height: 48px;
|
|
48
|
+
border: 6px solid rgba(110, 122, 138, 0.15);
|
|
49
|
+
border-bottom-color: ${colors.blue600};
|
|
50
|
+
border-radius: 50%;
|
|
51
|
+
animation: rotation 1s linear infinite;
|
|
52
|
+
}
|
|
53
|
+
@keyframes rotation {
|
|
54
|
+
0% {
|
|
55
|
+
transform: rotate(0);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
100% {
|
|
59
|
+
transform: rotate(360deg);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
`}</style>
|
|
63
|
+
</tbody>
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
TableBody.displayName = 'TableBody'
|
|
67
|
+
|
|
68
|
+
TableBody.propTypes = {
|
|
69
|
+
/** Should be `<TableRow>` components */
|
|
70
|
+
children: PropTypes.node,
|
|
71
|
+
className: PropTypes.string,
|
|
72
|
+
dataTest: PropTypes.string,
|
|
73
|
+
loading: PropTypes.bool,
|
|
74
|
+
role: PropTypes.string,
|
|
75
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { mutuallyExclusive, requiredIf } from '@dhis2/prop-types'
|
|
2
|
+
import { colors } from '@dhis2/ui-constants'
|
|
3
|
+
import cx from 'classnames'
|
|
4
|
+
import PropTypes from 'prop-types'
|
|
5
|
+
import React, { forwardRef } from 'react'
|
|
6
|
+
import styles from './table-data-cell.styles.js'
|
|
7
|
+
|
|
8
|
+
const rtlCorrespondingAlignments = {
|
|
9
|
+
left: 'right',
|
|
10
|
+
right: 'left',
|
|
11
|
+
center: 'center',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const TableDataCell = forwardRef(
|
|
15
|
+
(
|
|
16
|
+
{
|
|
17
|
+
active,
|
|
18
|
+
|
|
19
|
+
align = 'left',
|
|
20
|
+
backgroundColor,
|
|
21
|
+
bordered,
|
|
22
|
+
children,
|
|
23
|
+
className,
|
|
24
|
+
colSpan,
|
|
25
|
+
dataTest = 'dhis2-uicore-tabledatacel',
|
|
26
|
+
error,
|
|
27
|
+
large,
|
|
28
|
+
left = 'auto',
|
|
29
|
+
muted,
|
|
30
|
+
role,
|
|
31
|
+
rowSpan,
|
|
32
|
+
scope,
|
|
33
|
+
staticStyle,
|
|
34
|
+
valid,
|
|
35
|
+
width = 'auto',
|
|
36
|
+
onClick,
|
|
37
|
+
...props
|
|
38
|
+
},
|
|
39
|
+
ref
|
|
40
|
+
) => {
|
|
41
|
+
const rtlAlign = rtlCorrespondingAlignments[align] ?? align
|
|
42
|
+
return (
|
|
43
|
+
<td
|
|
44
|
+
{...props}
|
|
45
|
+
ref={ref}
|
|
46
|
+
colSpan={colSpan}
|
|
47
|
+
rowSpan={rowSpan}
|
|
48
|
+
onClick={onClick}
|
|
49
|
+
className={cx(className, {
|
|
50
|
+
active,
|
|
51
|
+
bordered,
|
|
52
|
+
error,
|
|
53
|
+
large,
|
|
54
|
+
muted,
|
|
55
|
+
staticStyle,
|
|
56
|
+
valid,
|
|
57
|
+
})}
|
|
58
|
+
data-test={dataTest}
|
|
59
|
+
role={role}
|
|
60
|
+
scope={scope}
|
|
61
|
+
>
|
|
62
|
+
{children}
|
|
63
|
+
<style jsx>{styles}</style>
|
|
64
|
+
<style jsx>{`
|
|
65
|
+
td {
|
|
66
|
+
inset-inline-start: ${left};
|
|
67
|
+
text-align: ${align};
|
|
68
|
+
width: ${width};
|
|
69
|
+
background-color: ${backgroundColor || colors.white};
|
|
70
|
+
}
|
|
71
|
+
:dir(rtl) {
|
|
72
|
+
text-align: ${rtlAlign};
|
|
73
|
+
}
|
|
74
|
+
:global(tr.selected) > td {
|
|
75
|
+
background-color: ${backgroundColor || colors.teal100};
|
|
76
|
+
}
|
|
77
|
+
:global(tr:hover) > td:not(.staticStyle) {
|
|
78
|
+
background-color: ${backgroundColor || colors.grey100};
|
|
79
|
+
}
|
|
80
|
+
:global(tr:active) > td:not(.staticStyle) {
|
|
81
|
+
background-color: ${backgroundColor || colors.grey200};
|
|
82
|
+
}
|
|
83
|
+
:global(tr.selected:hover) > td:not(.staticStyle) {
|
|
84
|
+
background-color: ${backgroundColor || '#cdeae8'};
|
|
85
|
+
}
|
|
86
|
+
`}</style>
|
|
87
|
+
</td>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
TableDataCell.displayName = 'TableDataCell'
|
|
93
|
+
|
|
94
|
+
const stylePropType = mutuallyExclusive(
|
|
95
|
+
['valid', 'error', 'muted'],
|
|
96
|
+
PropTypes.bool
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
TableDataCell.propTypes = {
|
|
100
|
+
/** To toggle border color, for example for editing */
|
|
101
|
+
active: PropTypes.bool,
|
|
102
|
+
align: PropTypes.oneOf(['left', 'center', 'right']),
|
|
103
|
+
/** Sets background color of the cell. Disables dynamic background colors from active, hover, and selected states */
|
|
104
|
+
backgroundColor: PropTypes.string,
|
|
105
|
+
bordered: PropTypes.bool,
|
|
106
|
+
children: PropTypes.node,
|
|
107
|
+
className: PropTypes.string,
|
|
108
|
+
colSpan: PropTypes.string,
|
|
109
|
+
dataTest: PropTypes.string,
|
|
110
|
+
/** Mutually exclusive with muted and valid */
|
|
111
|
+
error: stylePropType,
|
|
112
|
+
large: PropTypes.bool,
|
|
113
|
+
/** Required when fixed */
|
|
114
|
+
left: requiredIf((props) => props.fixed, PropTypes.string),
|
|
115
|
+
/** Mutually exclusive with error and valid */
|
|
116
|
+
muted: stylePropType,
|
|
117
|
+
role: PropTypes.string,
|
|
118
|
+
rowSpan: PropTypes.string,
|
|
119
|
+
scope: PropTypes.string,
|
|
120
|
+
/** Surpress hover and active event styles */
|
|
121
|
+
staticStyle: PropTypes.bool,
|
|
122
|
+
/** Mutually exclusive with error and muted */
|
|
123
|
+
valid: stylePropType,
|
|
124
|
+
width: PropTypes.string,
|
|
125
|
+
onClick: PropTypes.func,
|
|
126
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { colors } from '@dhis2/ui-constants'
|
|
2
|
+
import css from 'styled-jsx/css'
|
|
3
|
+
|
|
4
|
+
export default css`
|
|
5
|
+
td {
|
|
6
|
+
padding: 14px 12px;
|
|
7
|
+
font-size: 14px;
|
|
8
|
+
border: 1px solid transparant;
|
|
9
|
+
border-bottom: 1px solid ${colors.grey300};
|
|
10
|
+
color: ${colors.grey900};
|
|
11
|
+
}
|
|
12
|
+
td.active {
|
|
13
|
+
outline: 2px solid ${colors.grey600};
|
|
14
|
+
outline-offset: -2px;
|
|
15
|
+
}
|
|
16
|
+
td.bordered {
|
|
17
|
+
border-inline-end: 1px solid ${colors.grey300};
|
|
18
|
+
}
|
|
19
|
+
td.bordered:last-child {
|
|
20
|
+
border-inline-end: 1px solid transparent;
|
|
21
|
+
}
|
|
22
|
+
td.error {
|
|
23
|
+
color: ${colors.red700};
|
|
24
|
+
}
|
|
25
|
+
td.muted {
|
|
26
|
+
color: ${colors.grey700};
|
|
27
|
+
font-style: italic;
|
|
28
|
+
}
|
|
29
|
+
td.valid {
|
|
30
|
+
color: ${colors.green700};
|
|
31
|
+
}
|
|
32
|
+
td.large {
|
|
33
|
+
padding: 20px 12px;
|
|
34
|
+
font-size: 16px;
|
|
35
|
+
}
|
|
36
|
+
:global(tr:last-child) td {
|
|
37
|
+
border-bottom: 1px solid transparent;
|
|
38
|
+
}
|
|
39
|
+
:global(tfoot) :global(tr:first-child) td {
|
|
40
|
+
border-top: 1px solid ${colors.grey300};
|
|
41
|
+
}
|
|
42
|
+
`
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
2
|
+
import React, { forwardRef } from 'react'
|
|
3
|
+
|
|
4
|
+
export const TableFoot = forwardRef(
|
|
5
|
+
(
|
|
6
|
+
{
|
|
7
|
+
children,
|
|
8
|
+
className,
|
|
9
|
+
dataTest = 'dhis2-uicore-tablefoot',
|
|
10
|
+
role,
|
|
11
|
+
...props
|
|
12
|
+
},
|
|
13
|
+
ref
|
|
14
|
+
) => (
|
|
15
|
+
<tfoot
|
|
16
|
+
{...props}
|
|
17
|
+
className={className}
|
|
18
|
+
data-test={dataTest}
|
|
19
|
+
ref={ref}
|
|
20
|
+
role={role}
|
|
21
|
+
>
|
|
22
|
+
{children}
|
|
23
|
+
</tfoot>
|
|
24
|
+
)
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
TableFoot.displayName = 'TableFoot'
|
|
28
|
+
|
|
29
|
+
TableFoot.propTypes = {
|
|
30
|
+
/** Should be `<TableRow>` components */
|
|
31
|
+
children: PropTypes.node,
|
|
32
|
+
className: PropTypes.string,
|
|
33
|
+
dataTest: PropTypes.string,
|
|
34
|
+
role: PropTypes.string,
|
|
35
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
2
|
+
import React, { forwardRef } from 'react'
|
|
3
|
+
|
|
4
|
+
export const TableHead = forwardRef(
|
|
5
|
+
({ children, className, dataTest, role, ...props }, ref) => (
|
|
6
|
+
<thead
|
|
7
|
+
{...props}
|
|
8
|
+
className={className}
|
|
9
|
+
data-test={dataTest}
|
|
10
|
+
ref={ref}
|
|
11
|
+
role={role}
|
|
12
|
+
>
|
|
13
|
+
{children}
|
|
14
|
+
</thead>
|
|
15
|
+
)
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
TableHead.displayName = 'TableHead'
|
|
19
|
+
|
|
20
|
+
TableHead.propTypes = {
|
|
21
|
+
/** Should be `<TableRowHead>` components */
|
|
22
|
+
children: PropTypes.node,
|
|
23
|
+
className: PropTypes.string,
|
|
24
|
+
dataTest: PropTypes.string,
|
|
25
|
+
role: PropTypes.string,
|
|
26
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { mutuallyExclusive, requiredIf } from '@dhis2/prop-types'
|
|
2
|
+
import { colors } from '@dhis2/ui-constants'
|
|
3
|
+
import cx from 'classnames'
|
|
4
|
+
import PropTypes from 'prop-types'
|
|
5
|
+
import React, { forwardRef } from 'react'
|
|
6
|
+
import styles from './table-header-cell.styles.js'
|
|
7
|
+
|
|
8
|
+
const AUTO = 'auto'
|
|
9
|
+
|
|
10
|
+
export const TableHeaderCell = forwardRef(
|
|
11
|
+
(
|
|
12
|
+
{
|
|
13
|
+
active,
|
|
14
|
+
align = 'left',
|
|
15
|
+
backgroundColor,
|
|
16
|
+
bordered,
|
|
17
|
+
children,
|
|
18
|
+
className,
|
|
19
|
+
colSpan,
|
|
20
|
+
dataTest = 'dhis2-uicore-tablecell',
|
|
21
|
+
error,
|
|
22
|
+
fixed,
|
|
23
|
+
large,
|
|
24
|
+
left = AUTO,
|
|
25
|
+
muted,
|
|
26
|
+
rowSpan,
|
|
27
|
+
role,
|
|
28
|
+
scope,
|
|
29
|
+
staticStyle,
|
|
30
|
+
top = AUTO,
|
|
31
|
+
valid,
|
|
32
|
+
width = AUTO,
|
|
33
|
+
onClick,
|
|
34
|
+
...props
|
|
35
|
+
},
|
|
36
|
+
ref
|
|
37
|
+
) => (
|
|
38
|
+
<th
|
|
39
|
+
{...props}
|
|
40
|
+
ref={ref}
|
|
41
|
+
colSpan={colSpan}
|
|
42
|
+
rowSpan={rowSpan}
|
|
43
|
+
onClick={onClick}
|
|
44
|
+
className={cx(className, {
|
|
45
|
+
active,
|
|
46
|
+
bordered,
|
|
47
|
+
error,
|
|
48
|
+
fixed,
|
|
49
|
+
fixedHorizontally: fixed && left !== AUTO,
|
|
50
|
+
large,
|
|
51
|
+
muted,
|
|
52
|
+
staticStyle,
|
|
53
|
+
valid,
|
|
54
|
+
})}
|
|
55
|
+
data-test={dataTest}
|
|
56
|
+
role={role}
|
|
57
|
+
scope={scope}
|
|
58
|
+
>
|
|
59
|
+
{children}
|
|
60
|
+
<style jsx>{styles}</style>
|
|
61
|
+
<style jsx>{`
|
|
62
|
+
th {
|
|
63
|
+
inset-inline-start: ${left};
|
|
64
|
+
top: ${top};
|
|
65
|
+
text-align: ${align};
|
|
66
|
+
width: ${width};
|
|
67
|
+
background-color: ${backgroundColor || colors.grey200};
|
|
68
|
+
}
|
|
69
|
+
:global(thead) th.fixedHorizontally {
|
|
70
|
+
background-color: ${backgroundColor || colors.grey300};
|
|
71
|
+
}
|
|
72
|
+
:global(tbody) > :global(tr:hover) > th:not(.staticStyle),
|
|
73
|
+
:global(tfoot) > :global(tr:hover) > th:not(.staticStyle) {
|
|
74
|
+
background-color: ${backgroundColor || colors.grey300};
|
|
75
|
+
}
|
|
76
|
+
:global(tbody) > :global(tr:active) > th:not(.staticStyle) {
|
|
77
|
+
background-color: ${backgroundColor || colors.grey200};
|
|
78
|
+
}
|
|
79
|
+
`}</style>
|
|
80
|
+
</th>
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
TableHeaderCell.displayName = 'TableHeaderCell'
|
|
85
|
+
|
|
86
|
+
const stylePropType = mutuallyExclusive(
|
|
87
|
+
['valid', 'error', 'muted'],
|
|
88
|
+
PropTypes.bool
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
TableHeaderCell.propTypes = {
|
|
92
|
+
/** To toggle border color, for example for editing */
|
|
93
|
+
active: PropTypes.bool,
|
|
94
|
+
align: PropTypes.oneOf(['left', 'center', 'right']),
|
|
95
|
+
/** Sets background color of the cell. Disables dynamic background colors from active, hover, and selected states */
|
|
96
|
+
backgroundColor: PropTypes.string,
|
|
97
|
+
bordered: PropTypes.bool,
|
|
98
|
+
children: PropTypes.node,
|
|
99
|
+
className: PropTypes.string,
|
|
100
|
+
colSpan: PropTypes.string,
|
|
101
|
+
dataTest: PropTypes.string,
|
|
102
|
+
/** Mutually exclusive with muted and valid */
|
|
103
|
+
error: stylePropType,
|
|
104
|
+
fixed: PropTypes.bool,
|
|
105
|
+
large: PropTypes.bool,
|
|
106
|
+
/** Left or top required when fixed */
|
|
107
|
+
left: requiredIf((props) => props.fixed && !props.top, PropTypes.string),
|
|
108
|
+
/** Mutually exclusive with error and valid */
|
|
109
|
+
muted: stylePropType,
|
|
110
|
+
role: PropTypes.string,
|
|
111
|
+
rowSpan: PropTypes.string,
|
|
112
|
+
scope: PropTypes.string,
|
|
113
|
+
/** Surpress hover and active event styles */
|
|
114
|
+
staticStyle: PropTypes.bool,
|
|
115
|
+
/** Left or top required when fixed */
|
|
116
|
+
top: requiredIf((props) => props.fixed && !props.left, PropTypes.string),
|
|
117
|
+
/** Mutually exclusive with error and muted */
|
|
118
|
+
valid: stylePropType,
|
|
119
|
+
width: PropTypes.string,
|
|
120
|
+
onClick: PropTypes.func,
|
|
121
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { colors } from '@dhis2/ui-constants'
|
|
2
|
+
import css from 'styled-jsx/css'
|
|
3
|
+
|
|
4
|
+
export default css`
|
|
5
|
+
th {
|
|
6
|
+
padding: 12px;
|
|
7
|
+
border: 1px solid transparant;
|
|
8
|
+
border-bottom: 1px solid ${colors.grey300};
|
|
9
|
+
color: ${colors.grey800};
|
|
10
|
+
font-weight: normal;
|
|
11
|
+
font-size: 14px;
|
|
12
|
+
vertical-align: top;
|
|
13
|
+
}
|
|
14
|
+
:global(thead) th {
|
|
15
|
+
padding: 8px 12px;
|
|
16
|
+
font-size: 13px;
|
|
17
|
+
}
|
|
18
|
+
th:last-of-type {
|
|
19
|
+
border-inline-end: 1px solid ${colors.grey300};
|
|
20
|
+
}
|
|
21
|
+
th.active {
|
|
22
|
+
outline: 2px solid ${colors.grey600};
|
|
23
|
+
outline-offset: -2px;
|
|
24
|
+
}
|
|
25
|
+
th.bordered {
|
|
26
|
+
border-inline-end: 1px solid ${colors.grey300};
|
|
27
|
+
}
|
|
28
|
+
th.bordered:last-child {
|
|
29
|
+
border-inline-end: 1px solid transparent;
|
|
30
|
+
}
|
|
31
|
+
th.error {
|
|
32
|
+
color: ${colors.red700};
|
|
33
|
+
}
|
|
34
|
+
th.muted {
|
|
35
|
+
color: ${colors.grey700};
|
|
36
|
+
font-style: italic;
|
|
37
|
+
}
|
|
38
|
+
th.valid {
|
|
39
|
+
color: ${colors.green700};
|
|
40
|
+
}
|
|
41
|
+
th.large {
|
|
42
|
+
padding: 14px 12px;
|
|
43
|
+
font-size: 16px;
|
|
44
|
+
}
|
|
45
|
+
:global(thead) th.large {
|
|
46
|
+
padding: 13px 12px;
|
|
47
|
+
font-size: 15px;
|
|
48
|
+
}
|
|
49
|
+
th.fixed {
|
|
50
|
+
position: sticky;
|
|
51
|
+
z-index: 1;
|
|
52
|
+
}
|
|
53
|
+
:global(thead) th.fixed {
|
|
54
|
+
position: sticky;
|
|
55
|
+
/* ensure on top of scrolling body cells */
|
|
56
|
+
z-index: 2;
|
|
57
|
+
}
|
|
58
|
+
:global(thead) th.fixedHorizontally {
|
|
59
|
+
/* ensure on top of all scrolling cells */
|
|
60
|
+
z-index: 3;
|
|
61
|
+
}
|
|
62
|
+
:global(tr:last-child) th {
|
|
63
|
+
border-bottom: 1px solid transparent;
|
|
64
|
+
}
|
|
65
|
+
:global(thead) :global(tr:last-child) th {
|
|
66
|
+
border-bottom: 1px solid ${colors.grey300};
|
|
67
|
+
}
|
|
68
|
+
:global(tfoot) > :global(tr:first-child) th {
|
|
69
|
+
border-top: 1px solid ${colors.grey300};
|
|
70
|
+
}
|
|
71
|
+
`
|