@dhis2-ui/notice-box 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/__tests__/notice-box-icon.test.js +104 -0
- package/src/__tests__/notice-box-message.test.js +21 -0
- package/src/__tests__/notice-box-title.test.js +21 -0
- package/src/features/accepts_children/index.js +12 -0
- package/src/features/accepts_children.feature +5 -0
- package/src/features/accepts_title/index.js +12 -0
- package/src/features/accepts_title.feature +5 -0
- package/src/index.js +1 -0
- package/src/notice-box-content.js +40 -0
- package/src/notice-box-icon.js +83 -0
- package/src/notice-box-message.js +29 -0
- package/src/notice-box-title.js +30 -0
- package/src/notice-box.e2e.stories.js +6 -0
- package/src/notice-box.js +91 -0
- package/src/notice-box.prod.stories.js +146 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dhis2-ui/notice-box",
|
|
3
|
-
"version": "10.16.1",
|
|
3
|
+
"version": "10.16.3-alpha.1",
|
|
4
4
|
"description": "UI NoticeBox",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -33,14 +33,15 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@dhis2/prop-types": "^3.1.2",
|
|
36
|
-
"@dhis2/ui-constants": "10.16.1",
|
|
37
|
-
"@dhis2/ui-icons": "10.16.1",
|
|
36
|
+
"@dhis2/ui-constants": "10.16.3-alpha.1",
|
|
37
|
+
"@dhis2/ui-icons": "10.16.3-alpha.1",
|
|
38
38
|
"classnames": "^2.3.1",
|
|
39
39
|
"prop-types": "^15.7.2"
|
|
40
40
|
},
|
|
41
41
|
"files": [
|
|
42
42
|
"build",
|
|
43
|
-
"types"
|
|
43
|
+
"types",
|
|
44
|
+
"src"
|
|
44
45
|
],
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"react": "^18.3.1",
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { shallow } from 'enzyme'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { NoticeBoxIcon } from '../notice-box-icon.js'
|
|
4
|
+
|
|
5
|
+
describe('NoticeBoxIcon', () => {
|
|
6
|
+
it('should render info icon by default', () => {
|
|
7
|
+
const wrapper = shallow(<NoticeBoxIcon dataTest="test" />)
|
|
8
|
+
|
|
9
|
+
expect(wrapper.find('SvgWarningFilled24')).toHaveLength(0)
|
|
10
|
+
expect(wrapper.find('SvgErrorFilled24')).toHaveLength(0)
|
|
11
|
+
expect(wrapper.find('SvgInfoFilled24')).toHaveLength(1)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('should render 16px info icon when dense', () => {
|
|
15
|
+
const wrapper = shallow(<NoticeBoxIcon dense dataTest="test" />)
|
|
16
|
+
|
|
17
|
+
expect(wrapper.find('SvgInfoFilled16')).toHaveLength(1)
|
|
18
|
+
expect(wrapper.find('SvgInfoFilled24')).toHaveLength(0)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('should render 16px error icon when dense and error', () => {
|
|
22
|
+
const wrapper = shallow(<NoticeBoxIcon dense error dataTest="test" />)
|
|
23
|
+
|
|
24
|
+
expect(wrapper.find('SvgErrorFilled16')).toHaveLength(1)
|
|
25
|
+
expect(wrapper.find('SvgErrorFilled24')).toHaveLength(0)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('should render custom icon when icon is set', () => {
|
|
29
|
+
const wrapper = shallow(
|
|
30
|
+
<NoticeBoxIcon
|
|
31
|
+
icon={<span className="custom">x</span>}
|
|
32
|
+
dataTest="test"
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
expect(wrapper.find('.custom')).toHaveLength(1)
|
|
37
|
+
expect(wrapper.find('SvgInfoFilled24')).toHaveLength(0)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('should ignore status props when custom icon is set', () => {
|
|
41
|
+
const wrapper = shallow(
|
|
42
|
+
<NoticeBoxIcon
|
|
43
|
+
error
|
|
44
|
+
icon={<span className="custom">x</span>}
|
|
45
|
+
dataTest="test"
|
|
46
|
+
/>
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
expect(wrapper.find('.custom')).toHaveLength(1)
|
|
50
|
+
expect(wrapper.find('SvgErrorFilled24')).toHaveLength(0)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('should log errors when both warning and error flag are set', () => {
|
|
54
|
+
const spy = jest
|
|
55
|
+
.spyOn(global.console, 'error')
|
|
56
|
+
.mockImplementation(() => {})
|
|
57
|
+
shallow(<NoticeBoxIcon warning error dataTest="test" />)
|
|
58
|
+
|
|
59
|
+
expect(spy.mock.calls[0]).toEqual([
|
|
60
|
+
'Warning: Failed %s type: %s%s',
|
|
61
|
+
'prop',
|
|
62
|
+
"Invalid prop `error` supplied to `NoticeBoxIcon`, Property 'error' is mutually exclusive with 'warning', but both have a thruthy value.",
|
|
63
|
+
expect.any(String),
|
|
64
|
+
])
|
|
65
|
+
|
|
66
|
+
expect(spy.mock.calls[1]).toEqual([
|
|
67
|
+
'Warning: Failed %s type: %s%s',
|
|
68
|
+
'prop',
|
|
69
|
+
"Invalid prop `warning` supplied to `NoticeBoxIcon`, Property 'warning' is mutually exclusive with 'error', but both have a thruthy value.",
|
|
70
|
+
expect.any(String),
|
|
71
|
+
])
|
|
72
|
+
|
|
73
|
+
spy.mockRestore()
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('should render error icon when both warning and error flag are set', () => {
|
|
77
|
+
const spy = jest
|
|
78
|
+
.spyOn(global.console, 'error')
|
|
79
|
+
.mockImplementation(() => {})
|
|
80
|
+
const wrapper = shallow(<NoticeBoxIcon warning error dataTest="test" />)
|
|
81
|
+
|
|
82
|
+
expect(wrapper.find('SvgWarningFilled24')).toHaveLength(0)
|
|
83
|
+
expect(wrapper.find('SvgErrorFilled24')).toHaveLength(1)
|
|
84
|
+
expect(wrapper.find('SvgInfoFilled24')).toHaveLength(0)
|
|
85
|
+
|
|
86
|
+
spy.mockRestore()
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('should render error icon when only error flag is set', () => {
|
|
90
|
+
const wrapper = shallow(<NoticeBoxIcon error dataTest="test" />)
|
|
91
|
+
|
|
92
|
+
expect(wrapper.find('SvgWarningFilled24')).toHaveLength(0)
|
|
93
|
+
expect(wrapper.find('SvgErrorFilled24')).toHaveLength(1)
|
|
94
|
+
expect(wrapper.find('SvgInfoFilled24')).toHaveLength(0)
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('should render warning icon when only warning flag is set', () => {
|
|
98
|
+
const wrapper = shallow(<NoticeBoxIcon warning dataTest="test" />)
|
|
99
|
+
|
|
100
|
+
expect(wrapper.find('SvgWarningFilled24')).toHaveLength(1)
|
|
101
|
+
expect(wrapper.find('SvgErrorFilled24')).toHaveLength(0)
|
|
102
|
+
expect(wrapper.find('SvgInfoFilled24')).toHaveLength(0)
|
|
103
|
+
})
|
|
104
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { shallow } from 'enzyme'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { NoticeBoxMessage } from '../notice-box-message.js'
|
|
4
|
+
|
|
5
|
+
describe('NoticeBoxMessage', () => {
|
|
6
|
+
it('should return null when there are no children', () => {
|
|
7
|
+
const props = {
|
|
8
|
+
dataTest: 'test',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
expect(NoticeBoxMessage(props)).toBe(null)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('should render children', () => {
|
|
15
|
+
const wrapper = shallow(
|
|
16
|
+
<NoticeBoxMessage dataTest="test">children</NoticeBoxMessage>
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
expect(wrapper.text()).toEqual(expect.stringContaining('children'))
|
|
20
|
+
})
|
|
21
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { shallow } from 'enzyme'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { NoticeBoxTitle } from '../notice-box-title.js'
|
|
4
|
+
|
|
5
|
+
describe('NoticeBoxTitle', () => {
|
|
6
|
+
it('should return null when there is no title', () => {
|
|
7
|
+
const props = {
|
|
8
|
+
dataTest: 'test',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
expect(NoticeBoxTitle(props)).toBe(null)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('should render title', () => {
|
|
15
|
+
const wrapper = shallow(
|
|
16
|
+
<NoticeBoxTitle title="title" dataTest="test" />
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
expect(wrapper.text()).toEqual(expect.stringContaining('title'))
|
|
20
|
+
})
|
|
21
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
|
|
2
|
+
|
|
3
|
+
Given('a NoticeBox receives a message as children', () => {
|
|
4
|
+
cy.visitStory('NoticeBox', 'With children')
|
|
5
|
+
cy.get('[data-test="dhis2-uicore-noticebox"]').should('be.visible')
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
Then('the message is visible', () => {
|
|
9
|
+
cy.get('[data-test="dhis2-uicore-noticebox-content-message"]')
|
|
10
|
+
.contains('The noticebox content')
|
|
11
|
+
.should('be.visible')
|
|
12
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
|
|
2
|
+
|
|
3
|
+
Given('a NoticeBox receives a title prop', () => {
|
|
4
|
+
cy.visitStory('NoticeBox', 'With title')
|
|
5
|
+
cy.get('[data-test="dhis2-uicore-noticebox"]').should('be.visible')
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
Then('the title is visible', () => {
|
|
9
|
+
cy.get('[data-test="dhis2-uicore-noticebox-content-title"]')
|
|
10
|
+
.contains('The noticebox title')
|
|
11
|
+
.should('be.visible')
|
|
12
|
+
})
|
package/src/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { NoticeBox } from './notice-box.js'
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { spacers } from '@dhis2/ui-constants'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { NoticeBoxMessage } from './notice-box-message.js'
|
|
5
|
+
import { NoticeBoxTitle } from './notice-box-title.js'
|
|
6
|
+
|
|
7
|
+
export const NoticeBoxContent = ({
|
|
8
|
+
children,
|
|
9
|
+
dataTest = 'dhis2-uicore-noticebox-content',
|
|
10
|
+
title,
|
|
11
|
+
dense = false,
|
|
12
|
+
}) => {
|
|
13
|
+
return (
|
|
14
|
+
<div data-test={dataTest}>
|
|
15
|
+
<NoticeBoxTitle
|
|
16
|
+
title={title}
|
|
17
|
+
dense={dense}
|
|
18
|
+
dataTest={`${dataTest}-title`}
|
|
19
|
+
/>
|
|
20
|
+
<NoticeBoxMessage dense={dense} dataTest={`${dataTest}-message`}>
|
|
21
|
+
{children}
|
|
22
|
+
</NoticeBoxMessage>
|
|
23
|
+
<style jsx>{`
|
|
24
|
+
div {
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
gap: ${dense ? '2px' : spacers.dp8};
|
|
28
|
+
padding-block-start: ${dense ? '0' : '3px'};
|
|
29
|
+
}
|
|
30
|
+
`}</style>
|
|
31
|
+
</div>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
NoticeBoxContent.propTypes = {
|
|
36
|
+
children: PropTypes.node,
|
|
37
|
+
dataTest: PropTypes.string,
|
|
38
|
+
dense: PropTypes.bool,
|
|
39
|
+
title: PropTypes.string,
|
|
40
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { mutuallyExclusive } from '@dhis2/prop-types'
|
|
2
|
+
import { colors, spacers } from '@dhis2/ui-constants'
|
|
3
|
+
import {
|
|
4
|
+
IconCheckmarkCircle16,
|
|
5
|
+
IconCheckmarkCircle24,
|
|
6
|
+
IconErrorFilled16,
|
|
7
|
+
IconErrorFilled24,
|
|
8
|
+
IconInfoFilled16,
|
|
9
|
+
IconInfoFilled24,
|
|
10
|
+
IconWarningFilled16,
|
|
11
|
+
IconWarningFilled24,
|
|
12
|
+
} from '@dhis2/ui-icons'
|
|
13
|
+
import PropTypes from 'prop-types'
|
|
14
|
+
import React from 'react'
|
|
15
|
+
|
|
16
|
+
export const NoticeBoxIcon = ({
|
|
17
|
+
valid,
|
|
18
|
+
warning,
|
|
19
|
+
error,
|
|
20
|
+
dataTest,
|
|
21
|
+
dense = false,
|
|
22
|
+
icon,
|
|
23
|
+
}) => {
|
|
24
|
+
const marginInlineEnd = dense ? spacers.dp8 : spacers.dp12
|
|
25
|
+
|
|
26
|
+
if (icon != null) {
|
|
27
|
+
return (
|
|
28
|
+
<div data-test={dataTest}>
|
|
29
|
+
{icon}
|
|
30
|
+
<style jsx>{`
|
|
31
|
+
div {
|
|
32
|
+
display: flex;
|
|
33
|
+
flex-shrink: 0;
|
|
34
|
+
align-items: flex-start;
|
|
35
|
+
line-height: 0;
|
|
36
|
+
margin-inline-end: ${marginInlineEnd};
|
|
37
|
+
}
|
|
38
|
+
`}</style>
|
|
39
|
+
</div>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let color = colors.blue900
|
|
44
|
+
let Icon = dense ? IconInfoFilled16 : IconInfoFilled24
|
|
45
|
+
|
|
46
|
+
if (valid) {
|
|
47
|
+
color = colors.green700
|
|
48
|
+
Icon = dense ? IconCheckmarkCircle16 : IconCheckmarkCircle24
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (warning) {
|
|
52
|
+
color = colors.yellow700
|
|
53
|
+
Icon = dense ? IconWarningFilled16 : IconWarningFilled24
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (error) {
|
|
57
|
+
color = colors.red700
|
|
58
|
+
Icon = dense ? IconErrorFilled16 : IconErrorFilled24
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div data-test={dataTest}>
|
|
63
|
+
<Icon color={color} />
|
|
64
|
+
|
|
65
|
+
<style jsx>{`
|
|
66
|
+
margin-inline-end: ${marginInlineEnd};
|
|
67
|
+
margin-block-start: ${dense ? '1px' : '0'};
|
|
68
|
+
height: ${dense ? spacers.dp16 : spacers.dp24};
|
|
69
|
+
`}</style>
|
|
70
|
+
</div>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
NoticeBoxIcon.propTypes = {
|
|
75
|
+
dataTest: PropTypes.string.isRequired,
|
|
76
|
+
/** Uses 16px icons and tighter spacing between icon and content */
|
|
77
|
+
dense: PropTypes.bool,
|
|
78
|
+
error: mutuallyExclusive(['error', 'valid', 'warning'], PropTypes.bool),
|
|
79
|
+
/** Replaces the default status icon (error/warning/valid still affect box styling) */
|
|
80
|
+
icon: PropTypes.node,
|
|
81
|
+
valid: mutuallyExclusive(['error', 'valid', 'warning'], PropTypes.bool),
|
|
82
|
+
warning: mutuallyExclusive(['error', 'valid', 'warning'], PropTypes.bool),
|
|
83
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { colors } from '@dhis2/ui-constants'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
export const NoticeBoxMessage = ({ children, dataTest, dense = false }) => {
|
|
6
|
+
if (!children) {
|
|
7
|
+
return null
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<div data-test={dataTest}>
|
|
12
|
+
{children}
|
|
13
|
+
|
|
14
|
+
<style jsx>{`
|
|
15
|
+
div {
|
|
16
|
+
color: ${colors.grey900};
|
|
17
|
+
font-size: ${dense ? '13px' : '14px'};
|
|
18
|
+
line-height: ${dense ? '18px' : '19px'};
|
|
19
|
+
}
|
|
20
|
+
`}</style>
|
|
21
|
+
</div>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
NoticeBoxMessage.propTypes = {
|
|
26
|
+
dataTest: PropTypes.string.isRequired,
|
|
27
|
+
children: PropTypes.node,
|
|
28
|
+
dense: PropTypes.bool,
|
|
29
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { colors } from '@dhis2/ui-constants'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
export const NoticeBoxTitle = ({ title, dataTest, dense = false }) => {
|
|
6
|
+
if (!title) {
|
|
7
|
+
return null
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<h6 data-test={dataTest}>
|
|
12
|
+
{title}
|
|
13
|
+
<style jsx>{`
|
|
14
|
+
h6 {
|
|
15
|
+
color: ${colors.grey900};
|
|
16
|
+
font-size: ${dense ? '13px' : '14px'};
|
|
17
|
+
font-weight: 500;
|
|
18
|
+
line-height: ${dense ? '18px' : '19px'};
|
|
19
|
+
margin: 0;
|
|
20
|
+
}
|
|
21
|
+
`}</style>
|
|
22
|
+
</h6>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
NoticeBoxTitle.propTypes = {
|
|
27
|
+
dataTest: PropTypes.string.isRequired,
|
|
28
|
+
dense: PropTypes.bool,
|
|
29
|
+
title: PropTypes.string,
|
|
30
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { mutuallyExclusive } from '@dhis2/prop-types'
|
|
2
|
+
import { spacers, colors } from '@dhis2/ui-constants'
|
|
3
|
+
import cx from 'classnames'
|
|
4
|
+
import PropTypes from 'prop-types'
|
|
5
|
+
import React from 'react'
|
|
6
|
+
import { NoticeBoxContent } from './notice-box-content.js'
|
|
7
|
+
import { NoticeBoxIcon } from './notice-box-icon.js'
|
|
8
|
+
|
|
9
|
+
export const NoticeBox = ({
|
|
10
|
+
className,
|
|
11
|
+
children,
|
|
12
|
+
dataTest = 'dhis2-uicore-noticebox',
|
|
13
|
+
title,
|
|
14
|
+
warning,
|
|
15
|
+
error,
|
|
16
|
+
valid,
|
|
17
|
+
dense = false,
|
|
18
|
+
icon,
|
|
19
|
+
}) => {
|
|
20
|
+
const classnames = cx(className, 'root', { warning, error, valid, dense })
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className={classnames} data-test={dataTest}>
|
|
24
|
+
<NoticeBoxIcon
|
|
25
|
+
error={error}
|
|
26
|
+
warning={warning}
|
|
27
|
+
valid={valid}
|
|
28
|
+
dense={dense}
|
|
29
|
+
icon={icon}
|
|
30
|
+
dataTest={`${dataTest}-icon`}
|
|
31
|
+
/>
|
|
32
|
+
<div>
|
|
33
|
+
<NoticeBoxContent
|
|
34
|
+
title={title}
|
|
35
|
+
dense={dense}
|
|
36
|
+
dataTest={`${dataTest}-content`}
|
|
37
|
+
>
|
|
38
|
+
{children}
|
|
39
|
+
</NoticeBoxContent>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<style jsx>{`
|
|
43
|
+
.root {
|
|
44
|
+
background: ${colors.blue050};
|
|
45
|
+
border: 1px solid ${colors.blue200};
|
|
46
|
+
border-radius: 3px;
|
|
47
|
+
display: flex;
|
|
48
|
+
padding-block: ${spacers.dp12};
|
|
49
|
+
padding-inline: ${spacers.dp16};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.root.dense {
|
|
53
|
+
padding-block: ${spacers.dp8};
|
|
54
|
+
padding-inline: ${spacers.dp8};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.root.warning {
|
|
58
|
+
background: ${colors.yellow050};
|
|
59
|
+
border: 1px solid ${colors.yellow200};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.root.error {
|
|
63
|
+
background: ${colors.red050};
|
|
64
|
+
border: 2px solid ${colors.red500};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.root.valid {
|
|
68
|
+
background: ${colors.green050};
|
|
69
|
+
border: 1px solid ${colors.green200};
|
|
70
|
+
}
|
|
71
|
+
`}</style>
|
|
72
|
+
</div>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
NoticeBox.propTypes = {
|
|
77
|
+
children: PropTypes.node,
|
|
78
|
+
className: PropTypes.string,
|
|
79
|
+
dataTest: PropTypes.string,
|
|
80
|
+
/** Uses 16px icons and tighter padding and internal spacing */
|
|
81
|
+
dense: PropTypes.bool,
|
|
82
|
+
/** Applies 'error' message styles. Mutually exclusive with the `valid` and `warning` props */
|
|
83
|
+
error: mutuallyExclusive(['error', 'valid', 'warning'], PropTypes.bool),
|
|
84
|
+
/** Replaces the default status icon; `error`, `warning`, and `valid` still set box colors */
|
|
85
|
+
icon: PropTypes.node,
|
|
86
|
+
title: PropTypes.string,
|
|
87
|
+
/** Applies 'valid' message styles. Mutually exclusive with the `error` and `warning` props */
|
|
88
|
+
valid: mutuallyExclusive(['error', 'valid', 'warning'], PropTypes.bool),
|
|
89
|
+
/** Applies 'warning' message styles. Mutually exclusive with the `error` and `valid` props */
|
|
90
|
+
warning: mutuallyExclusive(['error', 'valid', 'warning'], PropTypes.bool),
|
|
91
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { colors, sharedPropTypes } from '@dhis2/ui-constants'
|
|
2
|
+
import { IconCalendar24 } from '@dhis2/ui-icons'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { NoticeBox } from './notice-box.js'
|
|
5
|
+
|
|
6
|
+
const subtitle = `Highlights useful information that is directly relevant to the page the user is viewing`
|
|
7
|
+
|
|
8
|
+
const description = `
|
|
9
|
+
Use a notice box wherever there is important, temporary information about a page or situation that the user needs to be aware of.
|
|
10
|
+
|
|
11
|
+
Notice boxes are different from alert bars in several ways. Notice boxes cannot be dismissed, so they will always display until the situation is resolved. Notice boxes are for highlighting static information or information that is ongoing. Alert bars are suited to alerting a user about something that has just happened.
|
|
12
|
+
|
|
13
|
+
Another way to decide which component to use:
|
|
14
|
+
|
|
15
|
+
- a notice box will usually be displayed when a page loads, before a user takes action
|
|
16
|
+
- an alert bar will usually display in response to an action/event
|
|
17
|
+
|
|
18
|
+
Notice boxes cannot be dismissed, so it is important to provide guidance on how to fix the problem/condition that is causing the notice box to display.
|
|
19
|
+
|
|
20
|
+
Do not use a notice box to display permanent information. If there is information that always will be displayed on a page it should be designed as part of the page itself. Notice boxes are for temporary information.
|
|
21
|
+
|
|
22
|
+
Learn more about Notice Boxes at [Design System: Notice Box](https://github.com/dhis2/design-system/blob/master/molecules/notice-box.md).
|
|
23
|
+
|
|
24
|
+
\`\`\`js
|
|
25
|
+
import { NoticeBox } from '@dhis2/ui'
|
|
26
|
+
\`\`\`
|
|
27
|
+
`
|
|
28
|
+
|
|
29
|
+
const text =
|
|
30
|
+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' +
|
|
31
|
+
'Ut semper interdum scelerisque. Suspendisse ut velit sed ' +
|
|
32
|
+
'lacus pretium convallis vitae sit amet purus. Nam ut ' +
|
|
33
|
+
'libero rhoncus, consectetur sem a, sollicitudin lectus.'
|
|
34
|
+
|
|
35
|
+
export default {
|
|
36
|
+
title: 'Notice Box',
|
|
37
|
+
component: NoticeBox,
|
|
38
|
+
parameters: {
|
|
39
|
+
componentSubtitle: subtitle,
|
|
40
|
+
docs: { description: { component: description } },
|
|
41
|
+
},
|
|
42
|
+
argTypes: {
|
|
43
|
+
dense: { control: 'boolean' },
|
|
44
|
+
error: { ...sharedPropTypes.statusArgType },
|
|
45
|
+
warning: { ...sharedPropTypes.statusArgType },
|
|
46
|
+
valid: { ...sharedPropTypes.statusArgType },
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const DashboardUpdateTemplate = (args) => (
|
|
51
|
+
<NoticeBox {...args}>
|
|
52
|
+
Data shown in this dashboard may take a few hours to update. Scheduled
|
|
53
|
+
dashboard updates can be managed in the scheduler app.
|
|
54
|
+
</NoticeBox>
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
export const Default = DashboardUpdateTemplate.bind({})
|
|
58
|
+
Default.args = { title: 'Your database was updated in the last 24 hours' }
|
|
59
|
+
|
|
60
|
+
export const WithCustomIcon = (args) => (
|
|
61
|
+
<NoticeBox {...args}>
|
|
62
|
+
Dashboard updates can be managed in the scheduler app.
|
|
63
|
+
</NoticeBox>
|
|
64
|
+
)
|
|
65
|
+
WithCustomIcon.args = {
|
|
66
|
+
title: 'Scheduled maintenance',
|
|
67
|
+
icon: <IconCalendar24 color={colors.grey900} />,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const Valid = (args) => (
|
|
71
|
+
<NoticeBox {...args}>
|
|
72
|
+
Programs using these rules are updated automatically.
|
|
73
|
+
</NoticeBox>
|
|
74
|
+
)
|
|
75
|
+
Valid.args = {
|
|
76
|
+
valid: true,
|
|
77
|
+
title: 'Program rules exported successfully',
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const Warning = (args) => (
|
|
81
|
+
<NoticeBox {...args}>
|
|
82
|
+
No one will be able to access this program. Add some Organisation Units
|
|
83
|
+
to the access list.
|
|
84
|
+
</NoticeBox>
|
|
85
|
+
)
|
|
86
|
+
Warning.args = {
|
|
87
|
+
warning: true,
|
|
88
|
+
title: 'This program has no assigned Organisation Units',
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const Error = () => (
|
|
92
|
+
<NoticeBox title="Access rules for this instance are set to 'Public'" error>
|
|
93
|
+
Data could be accessed from outside this instance. Update access rules
|
|
94
|
+
immediately.
|
|
95
|
+
</NoticeBox>
|
|
96
|
+
)
|
|
97
|
+
Error.args = {
|
|
98
|
+
error: true,
|
|
99
|
+
title: "Access rules for this instance are set to 'Public'",
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const WithALongTitle = (args) => (
|
|
103
|
+
<NoticeBox {...args}>The title text will wrap</NoticeBox>
|
|
104
|
+
)
|
|
105
|
+
WithALongTitle.args = { error: true, title: text }
|
|
106
|
+
|
|
107
|
+
export const WithoutTitle = () => (
|
|
108
|
+
<NoticeBox>This noticebox does not have a title.</NoticeBox>
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
export const TitleOnly = () => (
|
|
112
|
+
<NoticeBox title="This noticebox has only a title"></NoticeBox>
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
const RtlNoticeTemplate = (args) => (
|
|
116
|
+
<div dir="rtl">
|
|
117
|
+
<NoticeBox {...args}>هذه رسالة باللغة العربية.</NoticeBox>
|
|
118
|
+
</div>
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
export const RTL = RtlNoticeTemplate.bind({})
|
|
122
|
+
RTL.args = { title: 'مثال على العنوان' }
|
|
123
|
+
RTL.storyName = 'RTL Text'
|
|
124
|
+
|
|
125
|
+
export const Dense = DashboardUpdateTemplate.bind({})
|
|
126
|
+
Dense.args = {
|
|
127
|
+
dense: true,
|
|
128
|
+
title: 'Your database was updated in the last 24 hours',
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export const DenseWithALongTitle = (args) => (
|
|
132
|
+
<NoticeBox {...args}>The title text will wrap</NoticeBox>
|
|
133
|
+
)
|
|
134
|
+
DenseWithALongTitle.args = { dense: true, error: true, title: text }
|
|
135
|
+
|
|
136
|
+
export const DenseWithoutTitle = (args) => (
|
|
137
|
+
<NoticeBox {...args}>This noticebox does not have a title.</NoticeBox>
|
|
138
|
+
)
|
|
139
|
+
DenseWithoutTitle.args = { dense: true }
|
|
140
|
+
|
|
141
|
+
export const DenseTitleOnly = (args) => <NoticeBox {...args}></NoticeBox>
|
|
142
|
+
DenseTitleOnly.args = { dense: true, title: 'This noticebox has only a title' }
|
|
143
|
+
|
|
144
|
+
export const DenseRTL = RtlNoticeTemplate.bind({})
|
|
145
|
+
DenseRTL.args = { dense: true, title: 'مثال على العنوان' }
|
|
146
|
+
DenseRTL.storyName = 'Dense RTL Text'
|