@dhis2-ui/node 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.
- package/package.json +5 -4
- package/src/features/accepts_children/index.js +23 -0
- package/src/features/accepts_children.feature +9 -0
- package/src/features/accepts_component/index.js +12 -0
- package/src/features/accepts_component.feature +5 -0
- package/src/features/accepts_icon/index.js +12 -0
- package/src/features/accepts_icon.feature +5 -0
- package/src/features/can_be_closed/index.js +15 -0
- package/src/features/can_be_closed.feature +6 -0
- package/src/features/can_be_opened/index.js +15 -0
- package/src/features/can_be_opened.feature +6 -0
- package/src/index.js +1 -0
- package/src/leaves.js +27 -0
- package/src/node.e2e.stories.js +33 -0
- package/src/node.js +66 -0
- package/src/node.prod.stories.js +404 -0
- package/src/spacer.js +11 -0
- package/src/toggle.js +93 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dhis2-ui/node",
|
|
3
|
-
"version": "10.16.
|
|
3
|
+
"version": "10.16.3-alpha.1",
|
|
4
4
|
"description": "UI Node",
|
|
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/loader": "10.16.
|
|
37
|
-
"@dhis2/ui-constants": "10.16.
|
|
36
|
+
"@dhis2-ui/loader": "10.16.3-alpha.1",
|
|
37
|
+
"@dhis2/ui-constants": "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,23 @@
|
|
|
1
|
+
import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
|
|
2
|
+
|
|
3
|
+
Given('a closed Node with children is rendered', () => {
|
|
4
|
+
cy.visitStory('Node', 'Closed with children')
|
|
5
|
+
cy.get('[data-test="dhis2-uicore-node"]').should('be.visible')
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
Given('an open Node with children is rendered', () => {
|
|
9
|
+
cy.visitStory('Node', 'Open with children')
|
|
10
|
+
cy.get('[data-test="dhis2-uicore-node"]').should('be.visible')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
Then('the children are visible', () => {
|
|
14
|
+
cy.get('[data-test="dhis2-uicore-node-leaves"]')
|
|
15
|
+
.contains('I am a child')
|
|
16
|
+
.should('be.visible')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
Then('the children are not visible', () => {
|
|
20
|
+
cy.get('[data-test="dhis2-uicore-node-leaves"]')
|
|
21
|
+
.contains('I am a child')
|
|
22
|
+
.should('not.be.visible')
|
|
23
|
+
})
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Feature: The Node renders children
|
|
2
|
+
|
|
3
|
+
Scenario: A closed Node with children
|
|
4
|
+
Given a closed Node with children is rendered
|
|
5
|
+
Then the children are not visible
|
|
6
|
+
|
|
7
|
+
Scenario: An open Node with children
|
|
8
|
+
Given an open Node with children is rendered
|
|
9
|
+
Then the children are visible
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
|
|
2
|
+
|
|
3
|
+
Given('a Node with component prop is rendered', () => {
|
|
4
|
+
cy.visitStory('Node', 'With component')
|
|
5
|
+
cy.get('[data-test="dhis2-uicore-node"]').should('be.visible')
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
Then('the component is visible', () => {
|
|
9
|
+
cy.get('[data-test="dhis2-uicore-node-label"]')
|
|
10
|
+
.contains('I am a component')
|
|
11
|
+
.should('be.visible')
|
|
12
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
|
|
2
|
+
|
|
3
|
+
Given('a Node with icon prop is rendered', () => {
|
|
4
|
+
cy.visitStory('Node', 'With icon')
|
|
5
|
+
cy.get('[data-test="dhis2-uicore-node"]').should('be.visible')
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
Then('the icon is visible', () => {
|
|
9
|
+
cy.get('[data-test="dhis2-uicore-node-icon"]')
|
|
10
|
+
.contains('Icon')
|
|
11
|
+
.should('be.visible')
|
|
12
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
|
|
2
|
+
|
|
3
|
+
Given('an open Node with an onClose handler is rendered', () => {
|
|
4
|
+
cy.visitStory('Node', 'Open with on close')
|
|
5
|
+
})
|
|
6
|
+
|
|
7
|
+
When('the arrow is clicked', () => {
|
|
8
|
+
cy.get('[data-test="dhis2-uicore-node-toggle"]').click()
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
Then('the onClose handler is called', () => {
|
|
12
|
+
cy.window().should((win) => {
|
|
13
|
+
expect(win.onClose).to.be.calledWith({ open: false })
|
|
14
|
+
})
|
|
15
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
|
|
2
|
+
|
|
3
|
+
Given('a closed Node with an onOpen handler is rendered', () => {
|
|
4
|
+
cy.visitStory('Node', 'Closed with on open')
|
|
5
|
+
})
|
|
6
|
+
|
|
7
|
+
When('the arrow is clicked', () => {
|
|
8
|
+
cy.get('[data-test="dhis2-uicore-node-toggle"]').click()
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
Then('the onOpen handler is called', () => {
|
|
12
|
+
cy.window().should((win) => {
|
|
13
|
+
expect(win.onOpen).to.be.calledWith({ open: true })
|
|
14
|
+
})
|
|
15
|
+
})
|
package/src/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Node } from './node.js'
|
package/src/leaves.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import cx from 'classnames'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
export const Leaves = ({ children, open, dataTest }) => (
|
|
6
|
+
<div className={cx({ open })} data-test={dataTest}>
|
|
7
|
+
{children}
|
|
8
|
+
|
|
9
|
+
<style jsx>{`
|
|
10
|
+
div {
|
|
11
|
+
height: 0;
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
flex-grow: 1;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.open {
|
|
17
|
+
height: auto;
|
|
18
|
+
}
|
|
19
|
+
`}</style>
|
|
20
|
+
</div>
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
Leaves.propTypes = {
|
|
24
|
+
children: PropTypes.node,
|
|
25
|
+
dataTest: PropTypes.string,
|
|
26
|
+
open: PropTypes.bool,
|
|
27
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Node } from './node.js'
|
|
3
|
+
|
|
4
|
+
window.onClose = window.Cypress && window.Cypress.cy.stub()
|
|
5
|
+
window.onOpen = window.Cypress && window.Cypress.cy.stub()
|
|
6
|
+
|
|
7
|
+
export default { title: 'Node' }
|
|
8
|
+
export const OpenWithOnClose = () => (
|
|
9
|
+
<Node open onClose={window.onClose} component={<div>Component</div>}>
|
|
10
|
+
Children
|
|
11
|
+
</Node>
|
|
12
|
+
)
|
|
13
|
+
export const ClosedWithOnOpen = () => (
|
|
14
|
+
<Node onOpen={window.onOpen} component={<div>Component</div>}>
|
|
15
|
+
Children
|
|
16
|
+
</Node>
|
|
17
|
+
)
|
|
18
|
+
export const ClosedWithChildren = () => (
|
|
19
|
+
<Node component={<div>Component</div>}>I am a child</Node>
|
|
20
|
+
)
|
|
21
|
+
export const OpenWithChildren = () => (
|
|
22
|
+
<Node open component={<div>Component</div>}>
|
|
23
|
+
I am a child
|
|
24
|
+
</Node>
|
|
25
|
+
)
|
|
26
|
+
export const WithComponent = () => (
|
|
27
|
+
<Node component={<div>I am a component</div>}>Children</Node>
|
|
28
|
+
)
|
|
29
|
+
export const WithIcon = () => (
|
|
30
|
+
<Node component={<div>Component</div>} icon={<div>Icon</div>}>
|
|
31
|
+
Children
|
|
32
|
+
</Node>
|
|
33
|
+
)
|
package/src/node.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import cx from 'classnames'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { Leaves } from './leaves.js'
|
|
5
|
+
import { Spacer } from './spacer.js'
|
|
6
|
+
import { Toggle } from './toggle.js'
|
|
7
|
+
|
|
8
|
+
export const Node = ({
|
|
9
|
+
open,
|
|
10
|
+
className,
|
|
11
|
+
component: label,
|
|
12
|
+
children,
|
|
13
|
+
icon,
|
|
14
|
+
onOpen,
|
|
15
|
+
onClose,
|
|
16
|
+
dataTest = 'dhis2-uicore-node',
|
|
17
|
+
}) => {
|
|
18
|
+
const hasLeaves = !!React.Children.toArray(children).filter((i) => i).length
|
|
19
|
+
const showArrow = !icon && hasLeaves
|
|
20
|
+
const showSpacer = !icon && !hasLeaves
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className={cx('node', className)} data-test={dataTest}>
|
|
24
|
+
{icon && <div data-test={`${dataTest}-icon`}>{icon}</div>}
|
|
25
|
+
|
|
26
|
+
{showArrow && (
|
|
27
|
+
<Toggle
|
|
28
|
+
open={open}
|
|
29
|
+
onOpen={onOpen}
|
|
30
|
+
onClose={onClose}
|
|
31
|
+
dataTest={`${dataTest}-toggle`}
|
|
32
|
+
/>
|
|
33
|
+
)}
|
|
34
|
+
|
|
35
|
+
{showSpacer && <Spacer />}
|
|
36
|
+
|
|
37
|
+
<div data-test={`${dataTest}-content`}>
|
|
38
|
+
<div data-test={`${dataTest}-label`}>{label}</div>
|
|
39
|
+
|
|
40
|
+
<Leaves open={open} dataTest={`${dataTest}-leaves`}>
|
|
41
|
+
{children}
|
|
42
|
+
</Leaves>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<style jsx>{`
|
|
46
|
+
.node {
|
|
47
|
+
display: flex;
|
|
48
|
+
}
|
|
49
|
+
`}</style>
|
|
50
|
+
</div>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
Node.propTypes = {
|
|
55
|
+
/** Content below this level of the hierarchy; children are revealed when this leaf is 'open' */
|
|
56
|
+
children: PropTypes.node,
|
|
57
|
+
className: PropTypes.string,
|
|
58
|
+
/** Content/label for this leaf, for example a checkbox */
|
|
59
|
+
component: PropTypes.element,
|
|
60
|
+
dataTest: PropTypes.string,
|
|
61
|
+
/** A custom icon to use instead of a toggle arrow */
|
|
62
|
+
icon: PropTypes.node,
|
|
63
|
+
open: PropTypes.bool,
|
|
64
|
+
onClose: PropTypes.func,
|
|
65
|
+
onOpen: PropTypes.func,
|
|
66
|
+
}
|
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import { Checkbox } from '@dhis2-ui/checkbox'
|
|
2
|
+
import { CircularLoader } from '@dhis2-ui/loader'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { Node } from './node.js'
|
|
5
|
+
|
|
6
|
+
const description = `
|
|
7
|
+
A tool for creating hierarchical, multi-level selectors. Applied in the Organisation Unit Tree component, for example.
|
|
8
|
+
|
|
9
|
+
\`\`\`js
|
|
10
|
+
import { Node } from '@dhis2/ui'
|
|
11
|
+
\`\`\`
|
|
12
|
+
`
|
|
13
|
+
|
|
14
|
+
const say = (something) => () => alert(something)
|
|
15
|
+
|
|
16
|
+
window.onOpen = (payload, event) => {
|
|
17
|
+
console.log('onOpen payload', payload)
|
|
18
|
+
console.log('onOpen event', event)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
window.onClose = (payload, event) => {
|
|
22
|
+
console.log('onClose payload', payload)
|
|
23
|
+
console.log('onClose event', event)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const onOpen = (...args) => window.onOpen(...args)
|
|
27
|
+
const onClose = (...args) => window.onClose(...args)
|
|
28
|
+
|
|
29
|
+
export default {
|
|
30
|
+
title: 'Node',
|
|
31
|
+
component: Node,
|
|
32
|
+
parameters: { docs: { description: { component: description } } },
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const CustomIcon = (args) => <Node {...args} />
|
|
36
|
+
CustomIcon.args = {
|
|
37
|
+
icon: <CircularLoader small />,
|
|
38
|
+
open: false,
|
|
39
|
+
onOpen: onOpen,
|
|
40
|
+
onClose: onClose,
|
|
41
|
+
component: (
|
|
42
|
+
<Checkbox
|
|
43
|
+
label="Node label 1.1"
|
|
44
|
+
value="foobar"
|
|
45
|
+
name="l1.1"
|
|
46
|
+
onChange={say('checkbox 1.1 clicked')}
|
|
47
|
+
checked={false}
|
|
48
|
+
/>
|
|
49
|
+
),
|
|
50
|
+
}
|
|
51
|
+
CustomIcon.storyName = 'Custom icon'
|
|
52
|
+
|
|
53
|
+
export const MultipleRoots = (args) => (
|
|
54
|
+
<div>
|
|
55
|
+
<Node
|
|
56
|
+
{...args}
|
|
57
|
+
component={
|
|
58
|
+
<Checkbox
|
|
59
|
+
label="Node label 1.1"
|
|
60
|
+
value="foobar"
|
|
61
|
+
name="l1.1"
|
|
62
|
+
onChange={say('checkbox 1.1 clicked')}
|
|
63
|
+
checked={false}
|
|
64
|
+
/>
|
|
65
|
+
}
|
|
66
|
+
>
|
|
67
|
+
<span>Placeholder content</span>
|
|
68
|
+
</Node>
|
|
69
|
+
|
|
70
|
+
<Node
|
|
71
|
+
{...args}
|
|
72
|
+
component={
|
|
73
|
+
<Checkbox
|
|
74
|
+
label="Node label 1.2"
|
|
75
|
+
value="foobar"
|
|
76
|
+
name="l1.2"
|
|
77
|
+
onChange={say('checkbox 1.2 clicked')}
|
|
78
|
+
checked={false}
|
|
79
|
+
/>
|
|
80
|
+
}
|
|
81
|
+
>
|
|
82
|
+
<span>Placeholder content</span>
|
|
83
|
+
</Node>
|
|
84
|
+
</div>
|
|
85
|
+
)
|
|
86
|
+
MultipleRoots.args = { open: false, onOpen, onClose }
|
|
87
|
+
MultipleRoots.storyName = 'Multiple roots'
|
|
88
|
+
|
|
89
|
+
export const _2LevelsOpen = () => (
|
|
90
|
+
<Node
|
|
91
|
+
open={true}
|
|
92
|
+
onOpen={onOpen}
|
|
93
|
+
onClose={onClose}
|
|
94
|
+
component={
|
|
95
|
+
<Checkbox
|
|
96
|
+
label="Node label"
|
|
97
|
+
value="foobar"
|
|
98
|
+
name="l1.1"
|
|
99
|
+
onChange={say('Check 1.1')}
|
|
100
|
+
checked={false}
|
|
101
|
+
/>
|
|
102
|
+
}
|
|
103
|
+
>
|
|
104
|
+
<Node
|
|
105
|
+
open={true}
|
|
106
|
+
onOpen={onOpen}
|
|
107
|
+
onClose={onClose}
|
|
108
|
+
component={
|
|
109
|
+
<Checkbox
|
|
110
|
+
label="Node label"
|
|
111
|
+
value="foobar"
|
|
112
|
+
name="l2.1"
|
|
113
|
+
onChange={say('Check 2.1')}
|
|
114
|
+
checked={false}
|
|
115
|
+
/>
|
|
116
|
+
}
|
|
117
|
+
>
|
|
118
|
+
<Node
|
|
119
|
+
component={
|
|
120
|
+
<Checkbox
|
|
121
|
+
label="Node label"
|
|
122
|
+
name="l3.1"
|
|
123
|
+
value="foobar"
|
|
124
|
+
onChange={say('Check 3.1')}
|
|
125
|
+
checked={false}
|
|
126
|
+
/>
|
|
127
|
+
}
|
|
128
|
+
/>
|
|
129
|
+
<Node
|
|
130
|
+
component={
|
|
131
|
+
<Checkbox
|
|
132
|
+
label="Node label"
|
|
133
|
+
name="l3.2"
|
|
134
|
+
onChange={say('Check 3.2')}
|
|
135
|
+
value="foobar"
|
|
136
|
+
checked={false}
|
|
137
|
+
/>
|
|
138
|
+
}
|
|
139
|
+
/>
|
|
140
|
+
<Node
|
|
141
|
+
component={
|
|
142
|
+
<Checkbox
|
|
143
|
+
label="Node label"
|
|
144
|
+
name="l3.3"
|
|
145
|
+
onChange={say('Check 3.3')}
|
|
146
|
+
checked={false}
|
|
147
|
+
value="foobar"
|
|
148
|
+
/>
|
|
149
|
+
}
|
|
150
|
+
/>
|
|
151
|
+
</Node>
|
|
152
|
+
<Node
|
|
153
|
+
open={false}
|
|
154
|
+
onOpen={onOpen}
|
|
155
|
+
onClose={say('close tree 2.2')}
|
|
156
|
+
component={
|
|
157
|
+
<Checkbox
|
|
158
|
+
label="Node label"
|
|
159
|
+
name="l3.1"
|
|
160
|
+
onChange={say('Check 2.2')}
|
|
161
|
+
value="foobar"
|
|
162
|
+
checked={false}
|
|
163
|
+
/>
|
|
164
|
+
}
|
|
165
|
+
>
|
|
166
|
+
<Node
|
|
167
|
+
component={
|
|
168
|
+
<Checkbox
|
|
169
|
+
label="Node label"
|
|
170
|
+
name="l3.4"
|
|
171
|
+
value="foobar"
|
|
172
|
+
onChange={say('Check 3.4')}
|
|
173
|
+
checked={false}
|
|
174
|
+
/>
|
|
175
|
+
}
|
|
176
|
+
/>
|
|
177
|
+
<Node
|
|
178
|
+
component={
|
|
179
|
+
<Checkbox
|
|
180
|
+
label="Node label"
|
|
181
|
+
name="l3.5"
|
|
182
|
+
onChange={say('Check 3.5')}
|
|
183
|
+
value="foobar"
|
|
184
|
+
checked={false}
|
|
185
|
+
/>
|
|
186
|
+
}
|
|
187
|
+
/>
|
|
188
|
+
<Node
|
|
189
|
+
component={
|
|
190
|
+
<Checkbox
|
|
191
|
+
label="Node label"
|
|
192
|
+
name="l3.6"
|
|
193
|
+
onChange={say('Check 3.6')}
|
|
194
|
+
value="foobar"
|
|
195
|
+
checked={false}
|
|
196
|
+
/>
|
|
197
|
+
}
|
|
198
|
+
/>
|
|
199
|
+
</Node>
|
|
200
|
+
<Node
|
|
201
|
+
open={false}
|
|
202
|
+
onOpen={onOpen}
|
|
203
|
+
onClose={onClose}
|
|
204
|
+
component={
|
|
205
|
+
<Checkbox
|
|
206
|
+
label="Node label"
|
|
207
|
+
name="l2.3"
|
|
208
|
+
value="foobar"
|
|
209
|
+
onChange={say('Check 2.3')}
|
|
210
|
+
checked={false}
|
|
211
|
+
/>
|
|
212
|
+
}
|
|
213
|
+
/>
|
|
214
|
+
<Node
|
|
215
|
+
open={false}
|
|
216
|
+
onOpen={onOpen}
|
|
217
|
+
onClose={onClose}
|
|
218
|
+
component={
|
|
219
|
+
<Checkbox
|
|
220
|
+
label="Node label"
|
|
221
|
+
name="l2.4"
|
|
222
|
+
onChange={say('Check 2.4')}
|
|
223
|
+
value="foobar"
|
|
224
|
+
checked={false}
|
|
225
|
+
/>
|
|
226
|
+
}
|
|
227
|
+
/>
|
|
228
|
+
<Node
|
|
229
|
+
open={false}
|
|
230
|
+
onOpen={onOpen}
|
|
231
|
+
onClose={onClose}
|
|
232
|
+
component={
|
|
233
|
+
<Checkbox
|
|
234
|
+
label="Node label"
|
|
235
|
+
name="l2.5"
|
|
236
|
+
value="foobar"
|
|
237
|
+
onChange={say('Check 2.5')}
|
|
238
|
+
checked={false}
|
|
239
|
+
/>
|
|
240
|
+
}
|
|
241
|
+
/>
|
|
242
|
+
<Node
|
|
243
|
+
open={false}
|
|
244
|
+
onOpen={onOpen}
|
|
245
|
+
onClose={onClose}
|
|
246
|
+
component={
|
|
247
|
+
<Checkbox
|
|
248
|
+
label="Node label"
|
|
249
|
+
name="l2.5"
|
|
250
|
+
value="foobar"
|
|
251
|
+
onChange={say('Check 2.5')}
|
|
252
|
+
checked={false}
|
|
253
|
+
/>
|
|
254
|
+
}
|
|
255
|
+
>
|
|
256
|
+
{false && 'Foo'}
|
|
257
|
+
</Node>
|
|
258
|
+
</Node>
|
|
259
|
+
)
|
|
260
|
+
_2LevelsOpen.storyName = '2 Levels open'
|
|
261
|
+
|
|
262
|
+
export const TextLeaves = () => (
|
|
263
|
+
<div>
|
|
264
|
+
<Node
|
|
265
|
+
open={true}
|
|
266
|
+
onOpen={onOpen}
|
|
267
|
+
onClose={onClose}
|
|
268
|
+
arrowTopOffset="10px"
|
|
269
|
+
component={
|
|
270
|
+
<h2>Lorem ipsum dolor sit amet, consetetur sadipscing elitr</h2>
|
|
271
|
+
}
|
|
272
|
+
>
|
|
273
|
+
Sed diam nonumy eirmod tempor invidunt ut labore et dolore magna
|
|
274
|
+
aliquyam erat, sed diam voluptua. At vero eos et accusam et justo
|
|
275
|
+
duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata
|
|
276
|
+
sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
|
|
277
|
+
consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt
|
|
278
|
+
ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero
|
|
279
|
+
eos et accusam et justo duo dolores et ea rebum. Stet clita kasd
|
|
280
|
+
gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
|
|
281
|
+
<div className="sub-tree sub-tree--open">
|
|
282
|
+
<Node
|
|
283
|
+
open={true}
|
|
284
|
+
onOpen={onOpen}
|
|
285
|
+
onClose={onClose}
|
|
286
|
+
component={
|
|
287
|
+
<h2>
|
|
288
|
+
Lorem ipsum dolor sit amet, consetetur sadipscing
|
|
289
|
+
elitr
|
|
290
|
+
</h2>
|
|
291
|
+
}
|
|
292
|
+
>
|
|
293
|
+
Sed diam nonumy eirmod tempor invidunt ut labore et dolore
|
|
294
|
+
magna aliquyam erat, sed diam voluptua. At vero eos et
|
|
295
|
+
accusam et justo duo dolores et ea rebum. Stet clita kasd
|
|
296
|
+
gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
|
|
297
|
+
amet. Lorem ipsum dolor sit amet, consetetur sadipscing
|
|
298
|
+
elitr, sed diam nonumy eirmod tempor invidunt ut labore et
|
|
299
|
+
dolore magna aliquyam erat, sed diam voluptua. At vero eos
|
|
300
|
+
et accusam et justo duo dolores et ea rebum. Stet clita kasd
|
|
301
|
+
gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
|
|
302
|
+
amet.
|
|
303
|
+
</Node>
|
|
304
|
+
</div>
|
|
305
|
+
<div className="sub-tree">
|
|
306
|
+
<Node
|
|
307
|
+
open={false}
|
|
308
|
+
onOpen={onOpen}
|
|
309
|
+
onClose={onClose}
|
|
310
|
+
component={
|
|
311
|
+
<h2>
|
|
312
|
+
Lorem ipsum dolor sit amet, consetetur sadipscing
|
|
313
|
+
elitr
|
|
314
|
+
</h2>
|
|
315
|
+
}
|
|
316
|
+
>
|
|
317
|
+
<span>Dummy content</span>
|
|
318
|
+
</Node>
|
|
319
|
+
</div>
|
|
320
|
+
<div className="sub-tree">
|
|
321
|
+
<Node
|
|
322
|
+
open={false}
|
|
323
|
+
onOpen={onOpen}
|
|
324
|
+
onClose={onClose}
|
|
325
|
+
component={
|
|
326
|
+
<h2>
|
|
327
|
+
Lorem ipsum dolor sit amet, consetetur sadipscing
|
|
328
|
+
elitr
|
|
329
|
+
</h2>
|
|
330
|
+
}
|
|
331
|
+
>
|
|
332
|
+
<span>Dummy content</span>
|
|
333
|
+
</Node>
|
|
334
|
+
</div>
|
|
335
|
+
<div className="sub-tree">
|
|
336
|
+
<Node
|
|
337
|
+
open={false}
|
|
338
|
+
onOpen={onOpen}
|
|
339
|
+
onClose={onClose}
|
|
340
|
+
component={
|
|
341
|
+
<h2>
|
|
342
|
+
Lorem ipsum dolor sit amet, consetetur sadipscing
|
|
343
|
+
elitr
|
|
344
|
+
</h2>
|
|
345
|
+
}
|
|
346
|
+
>
|
|
347
|
+
<span>Dummy content</span>
|
|
348
|
+
</Node>
|
|
349
|
+
</div>
|
|
350
|
+
<div className="sub-tree">
|
|
351
|
+
<Node
|
|
352
|
+
open={false}
|
|
353
|
+
onOpen={onOpen}
|
|
354
|
+
onClose={onClose}
|
|
355
|
+
component={
|
|
356
|
+
<h2>
|
|
357
|
+
Lorem ipsum dolor sit amet, consetetur sadipscing
|
|
358
|
+
elitr
|
|
359
|
+
</h2>
|
|
360
|
+
}
|
|
361
|
+
>
|
|
362
|
+
<span>Dummy content</span>
|
|
363
|
+
</Node>
|
|
364
|
+
</div>
|
|
365
|
+
</Node>
|
|
366
|
+
|
|
367
|
+
<style jsx>{`
|
|
368
|
+
div {
|
|
369
|
+
font-size: 16px;
|
|
370
|
+
line-height: 24px;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
h2 {
|
|
374
|
+
font-size: 24px;
|
|
375
|
+
line-height: 32px;
|
|
376
|
+
margin: 0 0 10px;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.sub-tree {
|
|
380
|
+
margin-top: 10px;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.sub-tree--open {
|
|
384
|
+
margin-bottom: 20px;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
div :global(.tree__arrow > span) {
|
|
388
|
+
padding-top: 4px;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
div :global(.tree__arrow.open:after) {
|
|
392
|
+
top: 17px;
|
|
393
|
+
height: calc(100% - 28px);
|
|
394
|
+
}
|
|
395
|
+
`}</style>
|
|
396
|
+
</div>
|
|
397
|
+
)
|
|
398
|
+
TextLeaves.storyName = 'Text leaves'
|
|
399
|
+
|
|
400
|
+
export const RTL = (args) => (
|
|
401
|
+
<div dir="rtl">
|
|
402
|
+
<MultipleRoots {...args} />
|
|
403
|
+
</div>
|
|
404
|
+
)
|
package/src/spacer.js
ADDED
package/src/toggle.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { colors } from '@dhis2/ui-constants'
|
|
2
|
+
import cx from 'classnames'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
import React from 'react'
|
|
5
|
+
|
|
6
|
+
const ArrowDown = () => (
|
|
7
|
+
<div className="nodeArrow">
|
|
8
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
9
|
+
<path d="M15.7041 10.3329L12.1495 14.3318C12.0699 14.4213 11.9301 14.4213 11.8505 14.3318L8.29589 10.3329C8.18124 10.2039 8.2728 10 8.44537 10H15.5546C15.7272 10 15.8188 10.2039 15.7041 10.3329Z" />
|
|
10
|
+
<style jsx>{`
|
|
11
|
+
svg {
|
|
12
|
+
fill: inherit;
|
|
13
|
+
height: 24px;
|
|
14
|
+
width: 24px;
|
|
15
|
+
vertical-align: middle;
|
|
16
|
+
pointer-events: none;
|
|
17
|
+
}
|
|
18
|
+
`}</style>
|
|
19
|
+
</svg>
|
|
20
|
+
</div>
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
export const Toggle = ({ open, onOpen, onClose, dataTest }) => {
|
|
24
|
+
const onClick = open ? onClose : onOpen
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div
|
|
28
|
+
className={cx({ open })}
|
|
29
|
+
data-test={dataTest}
|
|
30
|
+
onClick={(event) => onClick && onClick({ open: !open }, event)}
|
|
31
|
+
>
|
|
32
|
+
<span>
|
|
33
|
+
<ArrowDown />
|
|
34
|
+
</span>
|
|
35
|
+
|
|
36
|
+
<style jsx>{`
|
|
37
|
+
div {
|
|
38
|
+
width: 24px;
|
|
39
|
+
position: relative;
|
|
40
|
+
flex-shrink: 0;
|
|
41
|
+
}
|
|
42
|
+
div:after {
|
|
43
|
+
background: ${colors.grey400};
|
|
44
|
+
height: calc(100% - 24px);
|
|
45
|
+
inset-inline-start: 12px;
|
|
46
|
+
position: absolute;
|
|
47
|
+
top: 15px;
|
|
48
|
+
width: 1px;
|
|
49
|
+
z-index: 1;
|
|
50
|
+
}
|
|
51
|
+
.open:after {
|
|
52
|
+
content: '';
|
|
53
|
+
}
|
|
54
|
+
span {
|
|
55
|
+
display: block;
|
|
56
|
+
position: relative;
|
|
57
|
+
z-index: 2;
|
|
58
|
+
fill: ${colors.grey900};
|
|
59
|
+
}
|
|
60
|
+
div :global(.nodeArrow) {
|
|
61
|
+
vertical-align: top;
|
|
62
|
+
transform: rotate(-90deg);
|
|
63
|
+
transition: transform 0.1s ease-out;
|
|
64
|
+
}
|
|
65
|
+
div :global(.nodeArrow:dir(rtl)) {
|
|
66
|
+
transform: rotate(90deg);
|
|
67
|
+
}
|
|
68
|
+
.open :global(.nodeArrow) {
|
|
69
|
+
transform: rotate(0);
|
|
70
|
+
}
|
|
71
|
+
.open :global(.nodeArrow:dir(rtl)) {
|
|
72
|
+
transform: rotate(0);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
div:hover {
|
|
76
|
+
cursor: pointer;
|
|
77
|
+
border-radius: 3px;
|
|
78
|
+
background: ${colors.grey100};
|
|
79
|
+
}
|
|
80
|
+
div:hover:after {
|
|
81
|
+
background: #bcc8d4;
|
|
82
|
+
}
|
|
83
|
+
`}</style>
|
|
84
|
+
</div>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
Toggle.propTypes = {
|
|
89
|
+
dataTest: PropTypes.string.isRequired,
|
|
90
|
+
open: PropTypes.bool,
|
|
91
|
+
onClose: PropTypes.func,
|
|
92
|
+
onOpen: PropTypes.func,
|
|
93
|
+
}
|