@dhis2-ui/button 7.7.9 → 7.9.0
Sign up to get free protection for your applications and to get access to all the features.
- package/build/cjs/button-strip/button-strip.js +5 -5
- package/build/cjs/dropdown-button/__tests__/dropdown-button.test.js +73 -0
- package/build/cjs/dropdown-button/dropdown-button.js +39 -26
- package/build/cjs/dropdown-button/dropdown-button.stories.js +43 -12
- package/build/es/button-strip/button-strip.js +5 -5
- package/build/es/dropdown-button/__tests__/dropdown-button.test.js +60 -0
- package/build/es/dropdown-button/dropdown-button.js +24 -12
- package/build/es/dropdown-button/dropdown-button.stories.js +36 -11
- package/package.json +6 -6
@@ -31,17 +31,17 @@ const ButtonStrip = ({
|
|
31
31
|
dataTest
|
32
32
|
}) => /*#__PURE__*/_react.default.createElement("div", {
|
33
33
|
"data-test": dataTest,
|
34
|
-
className: _style.default.dynamic([["
|
34
|
+
className: _style.default.dynamic([["1268901109", [_uiConstants.spacers.dp8]]]) + " " + ((0, _classnames.default)(className, {
|
35
35
|
start: !middle && !end,
|
36
36
|
middle,
|
37
37
|
end
|
38
38
|
}) || "")
|
39
39
|
}, _react.Children.map(children, child => /*#__PURE__*/_react.default.createElement("div", {
|
40
|
-
className: _style.default.dynamic([["
|
40
|
+
className: _style.default.dynamic([["1268901109", [_uiConstants.spacers.dp8]]]) + " " + "box"
|
41
41
|
}, child)), /*#__PURE__*/_react.default.createElement(_style.default, {
|
42
|
-
id: "
|
43
|
-
dynamic: [_uiConstants.spacers.
|
44
|
-
}, ["div.__jsx-style-dynamic-selector{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}", "div.middle.__jsx-style-dynamic-selector{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}", "div.end.__jsx-style-dynamic-selector{-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end;}", `.box.__jsx-style-dynamic-selector{margin-left:${_uiConstants.spacers.
|
42
|
+
id: "1268901109",
|
43
|
+
dynamic: [_uiConstants.spacers.dp8]
|
44
|
+
}, ["div.__jsx-style-dynamic-selector{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}", "div.middle.__jsx-style-dynamic-selector{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}", "div.end.__jsx-style-dynamic-selector{-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end;}", `.box.__jsx-style-dynamic-selector{margin-left:${_uiConstants.spacers.dp8};}`, ".box.__jsx-style-dynamic-selector:first-child{margin-left:0;}"]));
|
45
45
|
|
46
46
|
exports.ButtonStrip = ButtonStrip;
|
47
47
|
const alignmentPropType = (0, _propTypes.mutuallyExclusive)(['middle', 'end'], _propTypes2.default.bool);
|
@@ -0,0 +1,73 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
var _layer = require("@dhis2-ui/layer");
|
4
|
+
|
5
|
+
var _popper = require("@dhis2-ui/popper");
|
6
|
+
|
7
|
+
var _enzyme = require("enzyme");
|
8
|
+
|
9
|
+
var _react = _interopRequireDefault(require("react"));
|
10
|
+
|
11
|
+
var _testUtils = require("react-dom/test-utils");
|
12
|
+
|
13
|
+
var _index = require("../../index.js");
|
14
|
+
|
15
|
+
var _dropdownButton = require("../dropdown-button.js");
|
16
|
+
|
17
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
18
|
+
|
19
|
+
describe('<DropdownButton>', () => {
|
20
|
+
describe('controlled mode', () => {
|
21
|
+
describe('open state', () => {
|
22
|
+
const onClick = jest.fn();
|
23
|
+
|
24
|
+
const Component = /*#__PURE__*/_react.default.createElement(_dropdownButton.DropdownButton, {
|
25
|
+
onClick: onClick,
|
26
|
+
open: true,
|
27
|
+
component: /*#__PURE__*/_react.default.createElement("span", null, "test")
|
28
|
+
});
|
29
|
+
|
30
|
+
it('shows the Popper when open is true', async () => {
|
31
|
+
// TODO: https://github.com/popperjs/react-popper/issues/350
|
32
|
+
const wrapper = (0, _enzyme.mount)(Component);
|
33
|
+
await (0, _testUtils.act)(async () => await null);
|
34
|
+
const popper = wrapper.find(_popper.Popper);
|
35
|
+
expect(popper).toHaveLength(1);
|
36
|
+
expect(popper.find('span').text()).toEqual('test');
|
37
|
+
});
|
38
|
+
it('passes an "open" property to the callback payload with the next open state', async () => {
|
39
|
+
// TODO: https://github.com/popperjs/react-popper/issues/350
|
40
|
+
const wrapper = (0, _enzyme.mount)(Component);
|
41
|
+
await (0, _testUtils.act)(async () => await null);
|
42
|
+
wrapper.find(_layer.Layer).simulate('click');
|
43
|
+
expect(onClick).toHaveBeenCalledTimes(1);
|
44
|
+
const args = onClick.mock.calls[0];
|
45
|
+
expect(args).toHaveLength(2);
|
46
|
+
expect(args[0]).toEqual(expect.objectContaining({
|
47
|
+
open: false
|
48
|
+
}));
|
49
|
+
});
|
50
|
+
});
|
51
|
+
describe('closed state', () => {
|
52
|
+
const onClick = jest.fn();
|
53
|
+
const wrapper = (0, _enzyme.mount)( /*#__PURE__*/_react.default.createElement(_dropdownButton.DropdownButton, {
|
54
|
+
onClick: onClick,
|
55
|
+
open: false,
|
56
|
+
component: /*#__PURE__*/_react.default.createElement("span", null, "test")
|
57
|
+
}));
|
58
|
+
it('it does not show the Popper when open is false', () => {
|
59
|
+
const popper = wrapper.find(_popper.Popper);
|
60
|
+
expect(popper).toHaveLength(0);
|
61
|
+
});
|
62
|
+
it('passes an "open" property to the callback payload with the next open state (false)', () => {
|
63
|
+
wrapper.find(_index.Button).simulate('click');
|
64
|
+
expect(onClick).toHaveBeenCalledTimes(1);
|
65
|
+
const args = onClick.mock.calls[0];
|
66
|
+
expect(args).toHaveLength(2);
|
67
|
+
expect(args[0]).toEqual(expect.objectContaining({
|
68
|
+
open: true
|
69
|
+
}));
|
70
|
+
});
|
71
|
+
});
|
72
|
+
});
|
73
|
+
});
|
@@ -11,9 +11,11 @@ var _layer = require("@dhis2-ui/layer");
|
|
11
11
|
|
12
12
|
var _popper = require("@dhis2-ui/popper");
|
13
13
|
|
14
|
+
var _propTypes = require("@dhis2/prop-types");
|
15
|
+
|
14
16
|
var _uiConstants = require("@dhis2/ui-constants");
|
15
17
|
|
16
|
-
var
|
18
|
+
var _propTypes2 = _interopRequireDefault(require("prop-types"));
|
17
19
|
|
18
20
|
var _react = _interopRequireWildcard(require("react"));
|
19
21
|
|
@@ -43,7 +45,7 @@ function ArrowDown({
|
|
43
45
|
}
|
44
46
|
|
45
47
|
ArrowDown.propTypes = {
|
46
|
-
className:
|
48
|
+
className: _propTypes2.default.string
|
47
49
|
};
|
48
50
|
|
49
51
|
function ArrowUp({
|
@@ -63,7 +65,7 @@ function ArrowUp({
|
|
63
65
|
}
|
64
66
|
|
65
67
|
ArrowUp.propTypes = {
|
66
|
-
className:
|
68
|
+
className: _propTypes2.default.string
|
67
69
|
};
|
68
70
|
const arrow = {
|
69
71
|
styles: /*#__PURE__*/_react.default.createElement(_style.default, {
|
@@ -82,28 +84,33 @@ class DropdownButton extends _react.Component {
|
|
82
84
|
|
83
85
|
_defineProperty(this, "anchorRef", /*#__PURE__*/_react.default.createRef());
|
84
86
|
|
85
|
-
_defineProperty(this, "
|
87
|
+
_defineProperty(this, "onClickHandler", ({
|
86
88
|
name,
|
87
89
|
value
|
88
90
|
}, event) => {
|
89
|
-
|
90
|
-
open: !this.state.open
|
91
|
-
}, () => {
|
91
|
+
const handleClick = open => {
|
92
92
|
if (this.props.onClick) {
|
93
93
|
this.props.onClick({
|
94
94
|
name,
|
95
95
|
value,
|
96
|
-
open
|
96
|
+
open
|
97
97
|
}, event);
|
98
98
|
}
|
99
|
-
}
|
99
|
+
};
|
100
|
+
|
101
|
+
if (typeof this.props.open === 'boolean') {
|
102
|
+
handleClick(!this.props.open);
|
103
|
+
} else {
|
104
|
+
this.setState({
|
105
|
+
open: !this.state.open
|
106
|
+
}, () => {
|
107
|
+
handleClick(this.state.open);
|
108
|
+
});
|
109
|
+
}
|
100
110
|
});
|
101
111
|
}
|
102
112
|
|
103
113
|
render() {
|
104
|
-
const {
|
105
|
-
open
|
106
|
-
} = this.state;
|
107
114
|
const {
|
108
115
|
component,
|
109
116
|
children,
|
@@ -122,6 +129,7 @@ class DropdownButton extends _react.Component {
|
|
122
129
|
initialFocus,
|
123
130
|
dataTest
|
124
131
|
} = this.props;
|
132
|
+
const open = typeof this.props.open === 'boolean' ? this.props.open : this.state.open;
|
125
133
|
const ArrowIconComponent = open ? ArrowUp : ArrowDown;
|
126
134
|
return /*#__PURE__*/_react.default.createElement("div", {
|
127
135
|
ref: this.anchorRef,
|
@@ -136,7 +144,7 @@ class DropdownButton extends _react.Component {
|
|
136
144
|
primary: primary,
|
137
145
|
secondary: secondary,
|
138
146
|
small: small,
|
139
|
-
onClick: this.
|
147
|
+
onClick: this.onClickHandler,
|
140
148
|
name: name,
|
141
149
|
value: value,
|
142
150
|
tabIndex: tabIndex,
|
@@ -145,7 +153,7 @@ class DropdownButton extends _react.Component {
|
|
145
153
|
}, children, /*#__PURE__*/_react.default.createElement(ArrowIconComponent, {
|
146
154
|
className: "jsx-3163060161" + " " + (arrow.className || "")
|
147
155
|
})), open && /*#__PURE__*/_react.default.createElement(_layer.Layer, {
|
148
|
-
onClick: this.
|
156
|
+
onClick: this.onClickHandler,
|
149
157
|
transparent: true
|
150
158
|
}, /*#__PURE__*/_react.default.createElement(_popper.Popper, {
|
151
159
|
dataTest: `${dataTest}-popper`,
|
@@ -164,26 +172,29 @@ DropdownButton.defaultProps = {
|
|
164
172
|
};
|
165
173
|
DropdownButton.propTypes = {
|
166
174
|
/** Children to render inside the buton */
|
167
|
-
children:
|
168
|
-
className:
|
175
|
+
children: _propTypes2.default.node,
|
176
|
+
className: _propTypes2.default.string,
|
169
177
|
|
170
178
|
/** Component to show/hide when button is clicked */
|
171
|
-
component:
|
172
|
-
dataTest:
|
179
|
+
component: _propTypes2.default.element,
|
180
|
+
dataTest: _propTypes2.default.string,
|
173
181
|
|
174
182
|
/** Button variant. Mutually exclusive with `primary` and `secondary` props */
|
175
183
|
destructive: _uiConstants.sharedPropTypes.buttonVariantPropType,
|
176
184
|
|
177
185
|
/** Make the button non-interactive */
|
178
|
-
disabled:
|
179
|
-
icon:
|
186
|
+
disabled: _propTypes2.default.bool,
|
187
|
+
icon: _propTypes2.default.element,
|
180
188
|
|
181
189
|
/** Grants button initial focus on the page */
|
182
|
-
initialFocus:
|
190
|
+
initialFocus: _propTypes2.default.bool,
|
183
191
|
|
184
192
|
/** Button size. Mutually exclusive with `small` prop */
|
185
193
|
large: _uiConstants.sharedPropTypes.sizePropType,
|
186
|
-
name:
|
194
|
+
name: _propTypes2.default.string,
|
195
|
+
|
196
|
+
/** Controls popper visibility. When implementing this prop the component becomes a controlled component */
|
197
|
+
open: _propTypes2.default.bool,
|
187
198
|
|
188
199
|
/** Button variant. Mutually exclusive with `destructive` and `secondary` props */
|
189
200
|
primary: _uiConstants.sharedPropTypes.buttonVariantPropType,
|
@@ -193,15 +204,17 @@ DropdownButton.propTypes = {
|
|
193
204
|
|
194
205
|
/** Button size. Mutually exclusive with `large` prop */
|
195
206
|
small: _uiConstants.sharedPropTypes.sizePropType,
|
196
|
-
tabIndex:
|
207
|
+
tabIndex: _propTypes2.default.string,
|
197
208
|
|
198
209
|
/** Type of button. Can take advantage of different default behavior */
|
199
|
-
type:
|
200
|
-
value:
|
210
|
+
type: _propTypes2.default.oneOf(['submit', 'reset', 'button']),
|
211
|
+
value: _propTypes2.default.string,
|
201
212
|
|
202
213
|
/**
|
203
214
|
* Callback triggered on click.
|
204
215
|
* Called with signature `({ name: string, value: string, open: bool }, event)`
|
216
|
+
* Is required when using the `open` prop to override the internal
|
217
|
+
* state.
|
205
218
|
*/
|
206
|
-
onClick: _propTypes.default.func
|
219
|
+
onClick: (0, _propTypes.requiredIf)(props => typeof props.open === 'boolean', _propTypes2.default.func)
|
207
220
|
};
|
@@ -3,17 +3,21 @@
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
4
4
|
value: true
|
5
5
|
});
|
6
|
-
exports.InitialFocus = exports.WithMenu = exports.Large = exports.Small = exports.Disabled = exports.Destructive = exports.Secondary = exports.Primary = exports.WithClick = exports.Default = exports.default = void 0;
|
6
|
+
exports.ManualControl = exports.Open = exports.InitialFocus = exports.WithMenu = exports.Large = exports.Small = exports.Disabled = exports.Destructive = exports.Secondary = exports.Primary = exports.WithClick = exports.Default = exports.default = void 0;
|
7
7
|
|
8
8
|
var _menu = require("@dhis2-ui/menu");
|
9
9
|
|
10
10
|
var _uiConstants = require("@dhis2/ui-constants");
|
11
11
|
|
12
|
-
var _react =
|
12
|
+
var _react = _interopRequireWildcard(require("react"));
|
13
13
|
|
14
14
|
var _index = require("./index.js");
|
15
15
|
|
16
|
-
function
|
16
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
17
|
+
|
18
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
19
|
+
|
20
|
+
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
17
21
|
|
18
22
|
const description = `
|
19
23
|
Presents several actions to a user in a small space. Can replace single, individual buttons. Should only be used for actions that are related to one another. Ensure the button has a useful level that communicates that actions are contained within. Dropdown buttons do not have an explicit action, only expanding the list of contained actions.
|
@@ -23,13 +27,6 @@ import { DropdownButton } from '@dhis2/ui'
|
|
23
27
|
\`\`\`
|
24
28
|
`;
|
25
29
|
|
26
|
-
window.onClick = (payload, event) => {
|
27
|
-
console.log('onClick payload', payload);
|
28
|
-
console.log('onClick event', event);
|
29
|
-
};
|
30
|
-
|
31
|
-
const onClick = (...args) => window.onClick(...args);
|
32
|
-
|
33
30
|
const Simple = /*#__PURE__*/_react.default.createElement("span", null, "Simplest thing");
|
34
31
|
|
35
32
|
const {
|
@@ -75,7 +72,9 @@ exports.Default = Default;
|
|
75
72
|
const WithClick = Template.bind({});
|
76
73
|
exports.WithClick = WithClick;
|
77
74
|
WithClick.args = {
|
78
|
-
onClick:
|
75
|
+
onClick: ({
|
76
|
+
open
|
77
|
+
}) => console.log('onClick: the dropdown is open: ', open)
|
79
78
|
};
|
80
79
|
const Primary = Template.bind({});
|
81
80
|
exports.Primary = Primary;
|
@@ -140,4 +139,36 @@ InitialFocus.parameters = {
|
|
140
139
|
docs: {
|
141
140
|
disable: true
|
142
141
|
}
|
143
|
-
};
|
142
|
+
};
|
143
|
+
|
144
|
+
const OpenTemplate = args => {
|
145
|
+
return /*#__PURE__*/_react.default.createElement(_index.DropdownButton, args);
|
146
|
+
};
|
147
|
+
|
148
|
+
const Open = OpenTemplate.bind({});
|
149
|
+
exports.Open = Open;
|
150
|
+
Open.args = {
|
151
|
+
open: true,
|
152
|
+
component: Simple,
|
153
|
+
onClick: () => {}
|
154
|
+
};
|
155
|
+
|
156
|
+
const ManualControlTemplate = args => {
|
157
|
+
const [isOpen, setIsOpen] = (0, _react.useState)(true);
|
158
|
+
|
159
|
+
const handleOpen = () => setIsOpen(false);
|
160
|
+
|
161
|
+
const Menu = /*#__PURE__*/_react.default.createElement("ul", null, /*#__PURE__*/_react.default.createElement("li", null, "First option does nothing"), /*#__PURE__*/_react.default.createElement("li", {
|
162
|
+
onClick: handleOpen
|
163
|
+
}, "Close the dropdown"));
|
164
|
+
|
165
|
+
return /*#__PURE__*/_react.default.createElement(_index.DropdownButton, _extends({}, args, {
|
166
|
+
onClick: () => setIsOpen(!isOpen),
|
167
|
+
open: isOpen,
|
168
|
+
component: Menu
|
169
|
+
}));
|
170
|
+
};
|
171
|
+
|
172
|
+
const ManualControl = ManualControlTemplate.bind({});
|
173
|
+
exports.ManualControl = ManualControl;
|
174
|
+
ManualControl.args = {};
|
@@ -13,17 +13,17 @@ const ButtonStrip = ({
|
|
13
13
|
dataTest
|
14
14
|
}) => /*#__PURE__*/React.createElement("div", {
|
15
15
|
"data-test": dataTest,
|
16
|
-
className: _JSXStyle.dynamic([["
|
16
|
+
className: _JSXStyle.dynamic([["1268901109", [spacers.dp8]]]) + " " + (cx(className, {
|
17
17
|
start: !middle && !end,
|
18
18
|
middle,
|
19
19
|
end
|
20
20
|
}) || "")
|
21
21
|
}, Children.map(children, child => /*#__PURE__*/React.createElement("div", {
|
22
|
-
className: _JSXStyle.dynamic([["
|
22
|
+
className: _JSXStyle.dynamic([["1268901109", [spacers.dp8]]]) + " " + "box"
|
23
23
|
}, child)), /*#__PURE__*/React.createElement(_JSXStyle, {
|
24
|
-
id: "
|
25
|
-
dynamic: [spacers.
|
26
|
-
}, ["div.__jsx-style-dynamic-selector{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}", "div.middle.__jsx-style-dynamic-selector{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}", "div.end.__jsx-style-dynamic-selector{-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end;}", `.box.__jsx-style-dynamic-selector{margin-left:${spacers.
|
24
|
+
id: "1268901109",
|
25
|
+
dynamic: [spacers.dp8]
|
26
|
+
}, ["div.__jsx-style-dynamic-selector{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}", "div.middle.__jsx-style-dynamic-selector{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}", "div.end.__jsx-style-dynamic-selector{-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end;}", `.box.__jsx-style-dynamic-selector{margin-left:${spacers.dp8};}`, ".box.__jsx-style-dynamic-selector:first-child{margin-left:0;}"]));
|
27
27
|
|
28
28
|
const alignmentPropType = mutuallyExclusive(['middle', 'end'], PropTypes.bool);
|
29
29
|
ButtonStrip.defaultProps = {
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import { Layer } from '@dhis2-ui/layer';
|
2
|
+
import { Popper } from '@dhis2-ui/popper';
|
3
|
+
import { mount } from 'enzyme';
|
4
|
+
import React from 'react';
|
5
|
+
import { act } from 'react-dom/test-utils';
|
6
|
+
import { Button } from '../../index.js';
|
7
|
+
import { DropdownButton } from '../dropdown-button.js';
|
8
|
+
describe('<DropdownButton>', () => {
|
9
|
+
describe('controlled mode', () => {
|
10
|
+
describe('open state', () => {
|
11
|
+
const onClick = jest.fn();
|
12
|
+
const Component = /*#__PURE__*/React.createElement(DropdownButton, {
|
13
|
+
onClick: onClick,
|
14
|
+
open: true,
|
15
|
+
component: /*#__PURE__*/React.createElement("span", null, "test")
|
16
|
+
});
|
17
|
+
it('shows the Popper when open is true', async () => {
|
18
|
+
// TODO: https://github.com/popperjs/react-popper/issues/350
|
19
|
+
const wrapper = mount(Component);
|
20
|
+
await act(async () => await null);
|
21
|
+
const popper = wrapper.find(Popper);
|
22
|
+
expect(popper).toHaveLength(1);
|
23
|
+
expect(popper.find('span').text()).toEqual('test');
|
24
|
+
});
|
25
|
+
it('passes an "open" property to the callback payload with the next open state', async () => {
|
26
|
+
// TODO: https://github.com/popperjs/react-popper/issues/350
|
27
|
+
const wrapper = mount(Component);
|
28
|
+
await act(async () => await null);
|
29
|
+
wrapper.find(Layer).simulate('click');
|
30
|
+
expect(onClick).toHaveBeenCalledTimes(1);
|
31
|
+
const args = onClick.mock.calls[0];
|
32
|
+
expect(args).toHaveLength(2);
|
33
|
+
expect(args[0]).toEqual(expect.objectContaining({
|
34
|
+
open: false
|
35
|
+
}));
|
36
|
+
});
|
37
|
+
});
|
38
|
+
describe('closed state', () => {
|
39
|
+
const onClick = jest.fn();
|
40
|
+
const wrapper = mount( /*#__PURE__*/React.createElement(DropdownButton, {
|
41
|
+
onClick: onClick,
|
42
|
+
open: false,
|
43
|
+
component: /*#__PURE__*/React.createElement("span", null, "test")
|
44
|
+
}));
|
45
|
+
it('it does not show the Popper when open is false', () => {
|
46
|
+
const popper = wrapper.find(Popper);
|
47
|
+
expect(popper).toHaveLength(0);
|
48
|
+
});
|
49
|
+
it('passes an "open" property to the callback payload with the next open state (false)', () => {
|
50
|
+
wrapper.find(Button).simulate('click');
|
51
|
+
expect(onClick).toHaveBeenCalledTimes(1);
|
52
|
+
const args = onClick.mock.calls[0];
|
53
|
+
expect(args).toHaveLength(2);
|
54
|
+
expect(args[0]).toEqual(expect.objectContaining({
|
55
|
+
open: true
|
56
|
+
}));
|
57
|
+
});
|
58
|
+
});
|
59
|
+
});
|
60
|
+
});
|
@@ -4,6 +4,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
|
4
4
|
|
5
5
|
import { Layer } from '@dhis2-ui/layer';
|
6
6
|
import { Popper } from '@dhis2-ui/popper';
|
7
|
+
import { requiredIf } from '@dhis2/prop-types';
|
7
8
|
import { spacers, sharedPropTypes } from '@dhis2/ui-constants';
|
8
9
|
import PropTypes from 'prop-types';
|
9
10
|
import React, { Component } from 'react';
|
@@ -64,28 +65,33 @@ class DropdownButton extends Component {
|
|
64
65
|
|
65
66
|
_defineProperty(this, "anchorRef", /*#__PURE__*/React.createRef());
|
66
67
|
|
67
|
-
_defineProperty(this, "
|
68
|
+
_defineProperty(this, "onClickHandler", ({
|
68
69
|
name,
|
69
70
|
value
|
70
71
|
}, event) => {
|
71
|
-
|
72
|
-
open: !this.state.open
|
73
|
-
}, () => {
|
72
|
+
const handleClick = open => {
|
74
73
|
if (this.props.onClick) {
|
75
74
|
this.props.onClick({
|
76
75
|
name,
|
77
76
|
value,
|
78
|
-
open
|
77
|
+
open
|
79
78
|
}, event);
|
80
79
|
}
|
81
|
-
}
|
80
|
+
};
|
81
|
+
|
82
|
+
if (typeof this.props.open === 'boolean') {
|
83
|
+
handleClick(!this.props.open);
|
84
|
+
} else {
|
85
|
+
this.setState({
|
86
|
+
open: !this.state.open
|
87
|
+
}, () => {
|
88
|
+
handleClick(this.state.open);
|
89
|
+
});
|
90
|
+
}
|
82
91
|
});
|
83
92
|
}
|
84
93
|
|
85
94
|
render() {
|
86
|
-
const {
|
87
|
-
open
|
88
|
-
} = this.state;
|
89
95
|
const {
|
90
96
|
component,
|
91
97
|
children,
|
@@ -104,6 +110,7 @@ class DropdownButton extends Component {
|
|
104
110
|
initialFocus,
|
105
111
|
dataTest
|
106
112
|
} = this.props;
|
113
|
+
const open = typeof this.props.open === 'boolean' ? this.props.open : this.state.open;
|
107
114
|
const ArrowIconComponent = open ? ArrowUp : ArrowDown;
|
108
115
|
return /*#__PURE__*/React.createElement("div", {
|
109
116
|
ref: this.anchorRef,
|
@@ -118,7 +125,7 @@ class DropdownButton extends Component {
|
|
118
125
|
primary: primary,
|
119
126
|
secondary: secondary,
|
120
127
|
small: small,
|
121
|
-
onClick: this.
|
128
|
+
onClick: this.onClickHandler,
|
122
129
|
name: name,
|
123
130
|
value: value,
|
124
131
|
tabIndex: tabIndex,
|
@@ -127,7 +134,7 @@ class DropdownButton extends Component {
|
|
127
134
|
}, children, /*#__PURE__*/React.createElement(ArrowIconComponent, {
|
128
135
|
className: "jsx-3163060161" + " " + (arrow.className || "")
|
129
136
|
})), open && /*#__PURE__*/React.createElement(Layer, {
|
130
|
-
onClick: this.
|
137
|
+
onClick: this.onClickHandler,
|
131
138
|
transparent: true
|
132
139
|
}, /*#__PURE__*/React.createElement(Popper, {
|
133
140
|
dataTest: `${dataTest}-popper`,
|
@@ -166,6 +173,9 @@ DropdownButton.propTypes = {
|
|
166
173
|
large: sharedPropTypes.sizePropType,
|
167
174
|
name: PropTypes.string,
|
168
175
|
|
176
|
+
/** Controls popper visibility. When implementing this prop the component becomes a controlled component */
|
177
|
+
open: PropTypes.bool,
|
178
|
+
|
169
179
|
/** Button variant. Mutually exclusive with `destructive` and `secondary` props */
|
170
180
|
primary: sharedPropTypes.buttonVariantPropType,
|
171
181
|
|
@@ -183,7 +193,9 @@ DropdownButton.propTypes = {
|
|
183
193
|
/**
|
184
194
|
* Callback triggered on click.
|
185
195
|
* Called with signature `({ name: string, value: string, open: bool }, event)`
|
196
|
+
* Is required when using the `open` prop to override the internal
|
197
|
+
* state.
|
186
198
|
*/
|
187
|
-
onClick: PropTypes.func
|
199
|
+
onClick: requiredIf(props => typeof props.open === 'boolean', PropTypes.func)
|
188
200
|
};
|
189
201
|
export { DropdownButton };
|
@@ -1,6 +1,8 @@
|
|
1
|
+
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
2
|
+
|
1
3
|
import { FlyoutMenu, MenuItem } from '@dhis2-ui/menu';
|
2
4
|
import { sharedPropTypes } from '@dhis2/ui-constants';
|
3
|
-
import React from 'react';
|
5
|
+
import React, { useState } from 'react';
|
4
6
|
import { DropdownButton } from './index.js';
|
5
7
|
const description = `
|
6
8
|
Presents several actions to a user in a small space. Can replace single, individual buttons. Should only be used for actions that are related to one another. Ensure the button has a useful level that communicates that actions are contained within. Dropdown buttons do not have an explicit action, only expanding the list of contained actions.
|
@@ -9,14 +11,6 @@ Presents several actions to a user in a small space. Can replace single, individ
|
|
9
11
|
import { DropdownButton } from '@dhis2/ui'
|
10
12
|
\`\`\`
|
11
13
|
`;
|
12
|
-
|
13
|
-
window.onClick = (payload, event) => {
|
14
|
-
console.log('onClick payload', payload);
|
15
|
-
console.log('onClick event', event);
|
16
|
-
};
|
17
|
-
|
18
|
-
const onClick = (...args) => window.onClick(...args);
|
19
|
-
|
20
14
|
const Simple = /*#__PURE__*/React.createElement("span", null, "Simplest thing");
|
21
15
|
const {
|
22
16
|
sizeArgType,
|
@@ -58,7 +52,9 @@ const Template = args => /*#__PURE__*/React.createElement(DropdownButton, args);
|
|
58
52
|
export const Default = Template.bind({});
|
59
53
|
export const WithClick = Template.bind({});
|
60
54
|
WithClick.args = {
|
61
|
-
onClick:
|
55
|
+
onClick: ({
|
56
|
+
open
|
57
|
+
}) => console.log('onClick: the dropdown is open: ', open)
|
62
58
|
};
|
63
59
|
export const Primary = Template.bind({});
|
64
60
|
Primary.args = {
|
@@ -115,4 +111,33 @@ InitialFocus.parameters = {
|
|
115
111
|
docs: {
|
116
112
|
disable: true
|
117
113
|
}
|
118
|
-
};
|
114
|
+
};
|
115
|
+
|
116
|
+
const OpenTemplate = args => {
|
117
|
+
return /*#__PURE__*/React.createElement(DropdownButton, args);
|
118
|
+
};
|
119
|
+
|
120
|
+
export const Open = OpenTemplate.bind({});
|
121
|
+
Open.args = {
|
122
|
+
open: true,
|
123
|
+
component: Simple,
|
124
|
+
onClick: () => {}
|
125
|
+
};
|
126
|
+
|
127
|
+
const ManualControlTemplate = args => {
|
128
|
+
const [isOpen, setIsOpen] = useState(true);
|
129
|
+
|
130
|
+
const handleOpen = () => setIsOpen(false);
|
131
|
+
|
132
|
+
const Menu = /*#__PURE__*/React.createElement("ul", null, /*#__PURE__*/React.createElement("li", null, "First option does nothing"), /*#__PURE__*/React.createElement("li", {
|
133
|
+
onClick: handleOpen
|
134
|
+
}, "Close the dropdown"));
|
135
|
+
return /*#__PURE__*/React.createElement(DropdownButton, _extends({}, args, {
|
136
|
+
onClick: () => setIsOpen(!isOpen),
|
137
|
+
open: isOpen,
|
138
|
+
component: Menu
|
139
|
+
}));
|
140
|
+
};
|
141
|
+
|
142
|
+
export const ManualControl = ManualControlTemplate.bind({});
|
143
|
+
ManualControl.args = {};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@dhis2-ui/button",
|
3
|
-
"version": "7.
|
3
|
+
"version": "7.9.0",
|
4
4
|
"description": "UI Button",
|
5
5
|
"repository": {
|
6
6
|
"type": "git",
|
@@ -32,11 +32,11 @@
|
|
32
32
|
},
|
33
33
|
"dependencies": {
|
34
34
|
"@dhis2/prop-types": "^3.0.0-beta.1",
|
35
|
-
"@dhis2-ui/layer": "7.
|
36
|
-
"@dhis2-ui/loader": "7.
|
37
|
-
"@dhis2-ui/popper": "7.
|
38
|
-
"@dhis2/ui-constants": "7.
|
39
|
-
"@dhis2/ui-icons": "7.
|
35
|
+
"@dhis2-ui/layer": "7.9.0",
|
36
|
+
"@dhis2-ui/loader": "7.9.0",
|
37
|
+
"@dhis2-ui/popper": "7.9.0",
|
38
|
+
"@dhis2/ui-constants": "7.9.0",
|
39
|
+
"@dhis2/ui-icons": "7.9.0",
|
40
40
|
"classnames": "^2.3.1",
|
41
41
|
"prop-types": "^15.7.2"
|
42
42
|
},
|