@dhis2-ui/select 10.16.5 → 10.17.0
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/build/cjs/multi-select/multi-select.js +8 -0
- package/build/cjs/multi-select/multi-select.prod.stories.js +40 -1
- package/build/cjs/multi-select-field/multi-select-field.js +8 -0
- package/build/cjs/multi-select-field/multi-select-field.prod.stories.js +42 -2
- package/build/cjs/select/menu-wrapper.js +17 -6
- package/build/cjs/select/select.js +18 -12
- package/build/cjs/single-select/single-select.js +8 -0
- package/build/cjs/single-select/single-select.prod.stories.js +41 -2
- package/build/cjs/single-select-field/single-select-field.js +8 -0
- package/build/cjs/single-select-field/single-select-field.prod.stories.js +42 -2
- package/build/es/multi-select/multi-select.js +8 -0
- package/build/es/multi-select/multi-select.prod.stories.js +37 -0
- package/build/es/multi-select-field/multi-select-field.js +8 -0
- package/build/es/multi-select-field/multi-select-field.prod.stories.js +41 -1
- package/build/es/select/menu-wrapper.js +17 -6
- package/build/es/select/select.js +18 -12
- package/build/es/single-select/single-select.js +8 -0
- package/build/es/single-select/single-select.prod.stories.js +38 -1
- package/build/es/single-select-field/single-select-field.js +8 -0
- package/build/es/single-select-field/single-select-field.prod.stories.js +41 -1
- package/package.json +15 -15
- package/src/multi-select/multi-select.js +8 -0
- package/src/multi-select/multi-select.prod.stories.js +26 -0
- package/src/multi-select-field/multi-select-field.js +8 -0
- package/src/multi-select-field/multi-select-field.prod.stories.js +31 -0
- package/src/select/menu-wrapper.js +19 -3
- package/src/select/select.js +18 -12
- package/src/single-select/single-select.js +8 -0
- package/src/single-select/single-select.prod.stories.js +26 -0
- package/src/single-select-field/single-select-field.js +8 -0
- package/src/single-select-field/single-select-field.prod.stories.js +31 -0
|
@@ -7,11 +7,20 @@ import React from 'react';
|
|
|
7
7
|
const MenuWrapper = ({
|
|
8
8
|
children,
|
|
9
9
|
dataTest,
|
|
10
|
+
inputWidth,
|
|
10
11
|
maxHeight = '280px',
|
|
11
|
-
|
|
12
|
+
menuMaxWidth,
|
|
13
|
+
menuMinWidth,
|
|
12
14
|
onClick,
|
|
13
15
|
selectRef
|
|
14
16
|
}) => {
|
|
17
|
+
// menuMinWidth or menuMaxWidth enables flexible sizing (fit-content), with
|
|
18
|
+
// min-width = max(input, menuMinWidth). Without them, width matches the input.
|
|
19
|
+
const flexible = menuMinWidth || menuMaxWidth;
|
|
20
|
+
const width = flexible ? 'fit-content' : inputWidth;
|
|
21
|
+
const flexibleMinWidth = menuMinWidth ? `max(${inputWidth}, ${menuMinWidth})` : inputWidth;
|
|
22
|
+
const minWidth = flexible ? flexibleMinWidth : 'auto';
|
|
23
|
+
const maxWidth = menuMaxWidth || 'none';
|
|
15
24
|
return /*#__PURE__*/React.createElement(Layer, {
|
|
16
25
|
onBackdropClick: onClick,
|
|
17
26
|
transparent: true
|
|
@@ -21,18 +30,20 @@ const MenuWrapper = ({
|
|
|
21
30
|
observeReferenceResize: true
|
|
22
31
|
}, /*#__PURE__*/React.createElement("div", {
|
|
23
32
|
"data-test": `${dataTest}-menuwrapper`,
|
|
24
|
-
className: _JSXStyle.dynamic([["
|
|
33
|
+
className: _JSXStyle.dynamic([["3752211706", [width, minWidth, maxWidth, maxHeight, colors.white, colors.grey200, elevations.popover]]])
|
|
25
34
|
}, children, /*#__PURE__*/React.createElement(_JSXStyle, {
|
|
26
|
-
id: "
|
|
27
|
-
dynamic: [
|
|
28
|
-
}, [`div.__jsx-style-dynamic-selector{width:${
|
|
35
|
+
id: "3752211706",
|
|
36
|
+
dynamic: [width, minWidth, maxWidth, maxHeight, colors.white, colors.grey200, elevations.popover]
|
|
37
|
+
}, [`div.__jsx-style-dynamic-selector{width:${width};min-width:${minWidth};max-width:${maxWidth};height:auto;max-height:${maxHeight};overflow:auto;background:${colors.white};border:1px solid ${colors.grey200};border-radius:3px;box-shadow:${elevations.popover};}`]))));
|
|
29
38
|
};
|
|
30
39
|
MenuWrapper.propTypes = {
|
|
31
40
|
dataTest: PropTypes.string.isRequired,
|
|
32
|
-
|
|
41
|
+
inputWidth: PropTypes.string.isRequired,
|
|
33
42
|
selectRef: PropTypes.object.isRequired,
|
|
34
43
|
children: PropTypes.node,
|
|
35
44
|
maxHeight: PropTypes.string,
|
|
45
|
+
menuMaxWidth: PropTypes.string,
|
|
46
|
+
menuMinWidth: PropTypes.string,
|
|
36
47
|
onClick: PropTypes.func
|
|
37
48
|
};
|
|
38
49
|
export { MenuWrapper };
|
|
@@ -19,7 +19,7 @@ export class Select extends Component {
|
|
|
19
19
|
super(...args);
|
|
20
20
|
_defineProperty(this, "state", {
|
|
21
21
|
open: false,
|
|
22
|
-
|
|
22
|
+
inputWidth: 'auto'
|
|
23
23
|
});
|
|
24
24
|
_defineProperty(this, "selectRef", /*#__PURE__*/React.createRef());
|
|
25
25
|
_defineProperty(this, "inputRef", /*#__PURE__*/React.createRef());
|
|
@@ -33,10 +33,10 @@ export class Select extends Component {
|
|
|
33
33
|
* See: https://nolanlawson.com/2018/09/25/accurately-measuring-layout-on-the-web
|
|
34
34
|
*/
|
|
35
35
|
_defineProperty(this, "onResize", debounce(() => {
|
|
36
|
-
const
|
|
37
|
-
if (this.state.
|
|
36
|
+
const inputWidth = this.getInputWidth();
|
|
37
|
+
if (this.state.inputWidth !== inputWidth) {
|
|
38
38
|
this.setState({
|
|
39
|
-
|
|
39
|
+
inputWidth
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
42
|
}, 50));
|
|
@@ -59,7 +59,7 @@ export class Select extends Component {
|
|
|
59
59
|
_defineProperty(this, "handleOpen", () => {
|
|
60
60
|
this.setState({
|
|
61
61
|
open: true,
|
|
62
|
-
|
|
62
|
+
inputWidth: this.getInputWidth()
|
|
63
63
|
});
|
|
64
64
|
});
|
|
65
65
|
_defineProperty(this, "handleClose", () => {
|
|
@@ -138,29 +138,29 @@ export class Select extends Component {
|
|
|
138
138
|
this.inputRef.current.focus();
|
|
139
139
|
}
|
|
140
140
|
this.setState({
|
|
141
|
-
|
|
141
|
+
inputWidth: this.getInputWidth()
|
|
142
142
|
});
|
|
143
143
|
window.addEventListener('resize', this.onResize);
|
|
144
144
|
}
|
|
145
145
|
componentWillUnmount() {
|
|
146
146
|
window.removeEventListener('resize', this.onResize);
|
|
147
147
|
}
|
|
148
|
-
|
|
148
|
+
getInputWidth() {
|
|
149
149
|
const {
|
|
150
150
|
offsetWidth
|
|
151
151
|
} = this.inputRef.current;
|
|
152
152
|
const {
|
|
153
|
-
|
|
153
|
+
inputWidth
|
|
154
154
|
} = this.state;
|
|
155
|
-
if (offsetWidth && `${offsetWidth}px` !==
|
|
155
|
+
if (offsetWidth && `${offsetWidth}px` !== inputWidth) {
|
|
156
156
|
return `${offsetWidth}px`;
|
|
157
157
|
}
|
|
158
|
-
return
|
|
158
|
+
return inputWidth;
|
|
159
159
|
}
|
|
160
160
|
render() {
|
|
161
161
|
const {
|
|
162
162
|
open,
|
|
163
|
-
|
|
163
|
+
inputWidth
|
|
164
164
|
} = this.state;
|
|
165
165
|
const {
|
|
166
166
|
children,
|
|
@@ -169,6 +169,8 @@ export class Select extends Component {
|
|
|
169
169
|
onChange,
|
|
170
170
|
tabIndex,
|
|
171
171
|
maxHeight,
|
|
172
|
+
menuMinWidth,
|
|
173
|
+
menuMaxWidth,
|
|
172
174
|
error,
|
|
173
175
|
warning,
|
|
174
176
|
valid,
|
|
@@ -215,7 +217,9 @@ export class Select extends Component {
|
|
|
215
217
|
onClick: this.onOutsideClick,
|
|
216
218
|
maxHeight: maxHeight,
|
|
217
219
|
selectRef: this.selectRef,
|
|
218
|
-
|
|
220
|
+
inputWidth: inputWidth,
|
|
221
|
+
menuMinWidth: menuMinWidth,
|
|
222
|
+
menuMaxWidth: menuMaxWidth,
|
|
219
223
|
dataTest: `${dataTest}-menu`
|
|
220
224
|
}, menu));
|
|
221
225
|
}
|
|
@@ -235,6 +239,8 @@ Select.propTypes = {
|
|
|
235
239
|
error: sharedPropTypes.statusPropType,
|
|
236
240
|
initialFocus: PropTypes.bool,
|
|
237
241
|
maxHeight: PropTypes.string,
|
|
242
|
+
menuMaxWidth: PropTypes.string,
|
|
243
|
+
menuMinWidth: PropTypes.string,
|
|
238
244
|
tabIndex: PropTypes.string,
|
|
239
245
|
valid: sharedPropTypes.statusPropType,
|
|
240
246
|
warning: sharedPropTypes.statusPropType,
|
|
@@ -13,6 +13,8 @@ const SingleSelect = ({
|
|
|
13
13
|
selected = '',
|
|
14
14
|
tabIndex,
|
|
15
15
|
maxHeight,
|
|
16
|
+
menuMinWidth,
|
|
17
|
+
menuMaxWidth,
|
|
16
18
|
inputMaxHeight,
|
|
17
19
|
onChange,
|
|
18
20
|
onFocus,
|
|
@@ -66,6 +68,8 @@ const SingleSelect = ({
|
|
|
66
68
|
menu: menu,
|
|
67
69
|
tabIndex: tabIndex,
|
|
68
70
|
maxHeight: maxHeight,
|
|
71
|
+
menuMinWidth: menuMinWidth,
|
|
72
|
+
menuMaxWidth: menuMaxWidth,
|
|
69
73
|
onChange: onChange,
|
|
70
74
|
onFocus: onFocus,
|
|
71
75
|
onKeyDown: onKeyDown,
|
|
@@ -110,6 +114,10 @@ SingleSelect.propTypes = {
|
|
|
110
114
|
loading: PropTypes.bool,
|
|
111
115
|
loadingText: PropTypes.string,
|
|
112
116
|
maxHeight: PropTypes.string,
|
|
117
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) */
|
|
118
|
+
menuMaxWidth: PropTypes.string,
|
|
119
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) */
|
|
120
|
+
menuMinWidth: PropTypes.string,
|
|
113
121
|
/** Text to show when filter returns no results. Required if `filterable` prop is true */
|
|
114
122
|
noMatchText: requiredIf(props => props.filterable, PropTypes.string),
|
|
115
123
|
placeholder: PropTypes.string,
|
|
@@ -462,4 +462,41 @@ export const ShiftedIntoView = args => /*#__PURE__*/React.createElement(React.Fr
|
|
|
462
462
|
label: "option twelve"
|
|
463
463
|
})), /*#__PURE__*/React.createElement(_JSXStyle, {
|
|
464
464
|
id: "1828862170"
|
|
465
|
-
}, ["html,body,#root{position:relative;height:300px !important;max-height:300px;}", "#root{padding-top:130px !important;}"]));
|
|
465
|
+
}, ["html,body,#root{position:relative;height:300px !important;max-height:300px;}", "#root{padding-top:130px !important;}"]));
|
|
466
|
+
export const WithMenuMaxWidth = args => /*#__PURE__*/React.createElement("div", {
|
|
467
|
+
style: {
|
|
468
|
+
width: 120
|
|
469
|
+
}
|
|
470
|
+
}, /*#__PURE__*/React.createElement(SingleSelect, args, /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
471
|
+
value: "1",
|
|
472
|
+
label: "option one"
|
|
473
|
+
}), /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
474
|
+
value: "2",
|
|
475
|
+
label: "option two"
|
|
476
|
+
}), /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
477
|
+
value: "3",
|
|
478
|
+
label: "A much longer option label"
|
|
479
|
+
})));
|
|
480
|
+
WithMenuMaxWidth.args = {
|
|
481
|
+
menuMaxWidth: '200px'
|
|
482
|
+
};
|
|
483
|
+
export const WithMenuMinWidth = args => /*#__PURE__*/React.createElement("div", {
|
|
484
|
+
style: {
|
|
485
|
+
width: 120
|
|
486
|
+
}
|
|
487
|
+
}, /*#__PURE__*/React.createElement(SingleSelect, args, /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
488
|
+
value: "1",
|
|
489
|
+
label: "option one"
|
|
490
|
+
}), /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
491
|
+
value: "2",
|
|
492
|
+
label: "option two"
|
|
493
|
+
}), /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
494
|
+
value: "3",
|
|
495
|
+
label: "option three"
|
|
496
|
+
}), /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
497
|
+
value: "4",
|
|
498
|
+
label: "A longer option that exceeds the minimum"
|
|
499
|
+
})));
|
|
500
|
+
WithMenuMinWidth.args = {
|
|
501
|
+
menuMinWidth: '240px'
|
|
502
|
+
};
|
|
@@ -36,6 +36,8 @@ class SingleSelectField extends React.Component {
|
|
|
36
36
|
helpText,
|
|
37
37
|
validationText,
|
|
38
38
|
maxHeight,
|
|
39
|
+
menuMinWidth,
|
|
40
|
+
menuMaxWidth,
|
|
39
41
|
inputMaxHeight,
|
|
40
42
|
inputWidth,
|
|
41
43
|
children,
|
|
@@ -70,6 +72,8 @@ class SingleSelectField extends React.Component {
|
|
|
70
72
|
selected: selected,
|
|
71
73
|
tabIndex: tabIndex,
|
|
72
74
|
maxHeight: maxHeight,
|
|
75
|
+
menuMinWidth: menuMinWidth,
|
|
76
|
+
menuMaxWidth: menuMaxWidth,
|
|
73
77
|
inputMaxHeight: inputMaxHeight,
|
|
74
78
|
onChange: onChange,
|
|
75
79
|
onFocus: onFocus,
|
|
@@ -140,6 +144,10 @@ SingleSelectField.propTypes = {
|
|
|
140
144
|
loadingText: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
|
141
145
|
/** Constrains height of the SingleSelect */
|
|
142
146
|
maxHeight: PropTypes.string,
|
|
147
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) */
|
|
148
|
+
menuMaxWidth: PropTypes.string,
|
|
149
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) */
|
|
150
|
+
menuMinWidth: PropTypes.string,
|
|
143
151
|
/** Text to display when there are no filter results */
|
|
144
152
|
noMatchText: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
|
145
153
|
/** Placeholder text when the SingleSelect is empty */
|
|
@@ -173,4 +173,44 @@ DefaultLoadingText.args = {
|
|
|
173
173
|
loading: true,
|
|
174
174
|
...DefaultEmpty.args
|
|
175
175
|
};
|
|
176
|
-
DefaultLoadingText.storyName = 'Default: loadingText';
|
|
176
|
+
DefaultLoadingText.storyName = 'Default: loadingText';
|
|
177
|
+
export const WithMenuMaxWidth = Template.bind({});
|
|
178
|
+
WithMenuMaxWidth.args = {
|
|
179
|
+
inputWidth: '120px',
|
|
180
|
+
menuMaxWidth: '200px',
|
|
181
|
+
children: [/*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
182
|
+
key: "1",
|
|
183
|
+
value: "1",
|
|
184
|
+
label: "option one"
|
|
185
|
+
}), /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
186
|
+
key: "2",
|
|
187
|
+
value: "2",
|
|
188
|
+
label: "option two"
|
|
189
|
+
}), /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
190
|
+
key: "3",
|
|
191
|
+
value: "3",
|
|
192
|
+
label: "A much longer option label"
|
|
193
|
+
})]
|
|
194
|
+
};
|
|
195
|
+
export const WithMenuMinWidth = Template.bind({});
|
|
196
|
+
WithMenuMinWidth.args = {
|
|
197
|
+
inputWidth: '120px',
|
|
198
|
+
menuMinWidth: '240px',
|
|
199
|
+
children: [/*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
200
|
+
key: "1",
|
|
201
|
+
value: "1",
|
|
202
|
+
label: "option one"
|
|
203
|
+
}), /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
204
|
+
key: "2",
|
|
205
|
+
value: "2",
|
|
206
|
+
label: "option two"
|
|
207
|
+
}), /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
208
|
+
key: "3",
|
|
209
|
+
value: "3",
|
|
210
|
+
label: "option three"
|
|
211
|
+
}), /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
212
|
+
key: "4",
|
|
213
|
+
value: "4",
|
|
214
|
+
label: "A longer option that exceeds the minimum"
|
|
215
|
+
})]
|
|
216
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dhis2-ui/select",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.17.0",
|
|
4
4
|
"description": "UI Select",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -33,21 +33,21 @@
|
|
|
33
33
|
"styled-jsx": "^4"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@dhis2-ui/box": "10.
|
|
37
|
-
"@dhis2-ui/button": "10.
|
|
38
|
-
"@dhis2-ui/card": "10.
|
|
39
|
-
"@dhis2-ui/checkbox": "10.
|
|
40
|
-
"@dhis2-ui/chip": "10.
|
|
41
|
-
"@dhis2-ui/field": "10.
|
|
42
|
-
"@dhis2-ui/input": "10.
|
|
43
|
-
"@dhis2-ui/layer": "10.
|
|
44
|
-
"@dhis2-ui/loader": "10.
|
|
45
|
-
"@dhis2-ui/popper": "10.
|
|
46
|
-
"@dhis2-ui/status-icon": "10.
|
|
47
|
-
"@dhis2-ui/tooltip": "10.
|
|
36
|
+
"@dhis2-ui/box": "10.17.0",
|
|
37
|
+
"@dhis2-ui/button": "10.17.0",
|
|
38
|
+
"@dhis2-ui/card": "10.17.0",
|
|
39
|
+
"@dhis2-ui/checkbox": "10.17.0",
|
|
40
|
+
"@dhis2-ui/chip": "10.17.0",
|
|
41
|
+
"@dhis2-ui/field": "10.17.0",
|
|
42
|
+
"@dhis2-ui/input": "10.17.0",
|
|
43
|
+
"@dhis2-ui/layer": "10.17.0",
|
|
44
|
+
"@dhis2-ui/loader": "10.17.0",
|
|
45
|
+
"@dhis2-ui/popper": "10.17.0",
|
|
46
|
+
"@dhis2-ui/status-icon": "10.17.0",
|
|
47
|
+
"@dhis2-ui/tooltip": "10.17.0",
|
|
48
48
|
"@dhis2/prop-types": "^3.1.2",
|
|
49
|
-
"@dhis2/ui-constants": "10.
|
|
50
|
-
"@dhis2/ui-icons": "10.
|
|
49
|
+
"@dhis2/ui-constants": "10.17.0",
|
|
50
|
+
"@dhis2/ui-icons": "10.17.0",
|
|
51
51
|
"classnames": "^2.3.1",
|
|
52
52
|
"prop-types": "^15.7.2"
|
|
53
53
|
},
|
|
@@ -15,6 +15,8 @@ const MultiSelect = ({
|
|
|
15
15
|
selected = staticArr,
|
|
16
16
|
tabIndex,
|
|
17
17
|
maxHeight,
|
|
18
|
+
menuMinWidth,
|
|
19
|
+
menuMaxWidth,
|
|
18
20
|
inputMaxHeight,
|
|
19
21
|
onChange,
|
|
20
22
|
onFocus,
|
|
@@ -72,6 +74,8 @@ const MultiSelect = ({
|
|
|
72
74
|
menu={menu}
|
|
73
75
|
tabIndex={tabIndex}
|
|
74
76
|
maxHeight={maxHeight}
|
|
77
|
+
menuMinWidth={menuMinWidth}
|
|
78
|
+
menuMaxWidth={menuMaxWidth}
|
|
75
79
|
onChange={onChange}
|
|
76
80
|
onFocus={onFocus}
|
|
77
81
|
onKeyDown={onKeyDown}
|
|
@@ -131,6 +135,10 @@ MultiSelect.propTypes = {
|
|
|
131
135
|
loading: PropTypes.bool,
|
|
132
136
|
loadingText: PropTypes.string,
|
|
133
137
|
maxHeight: PropTypes.string,
|
|
138
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) */
|
|
139
|
+
menuMaxWidth: PropTypes.string,
|
|
140
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) */
|
|
141
|
+
menuMinWidth: PropTypes.string,
|
|
134
142
|
/** Required if `filterable` prop is `true` */
|
|
135
143
|
noMatchText: requiredIf((props) => props.filterable, PropTypes.string),
|
|
136
144
|
placeholder: PropTypes.string,
|
|
@@ -406,3 +406,29 @@ export const RTL = (args) => {
|
|
|
406
406
|
)
|
|
407
407
|
}
|
|
408
408
|
RTL.args = { selected: ['1', '2'], prefix: 'RTL text' }
|
|
409
|
+
|
|
410
|
+
export const WithMenuMaxWidth = (args) => (
|
|
411
|
+
<div style={{ width: 120 }}>
|
|
412
|
+
<MultiSelect {...args}>
|
|
413
|
+
<MultiSelectOption value="1" label="option one" />
|
|
414
|
+
<MultiSelectOption value="2" label="option two" />
|
|
415
|
+
<MultiSelectOption value="3" label="A much longer option label" />
|
|
416
|
+
</MultiSelect>
|
|
417
|
+
</div>
|
|
418
|
+
)
|
|
419
|
+
WithMenuMaxWidth.args = { menuMaxWidth: '200px' }
|
|
420
|
+
|
|
421
|
+
export const WithMenuMinWidth = (args) => (
|
|
422
|
+
<div style={{ width: 120 }}>
|
|
423
|
+
<MultiSelect {...args}>
|
|
424
|
+
<MultiSelectOption value="1" label="option one" />
|
|
425
|
+
<MultiSelectOption value="2" label="option two" />
|
|
426
|
+
<MultiSelectOption value="3" label="option three" />
|
|
427
|
+
<MultiSelectOption
|
|
428
|
+
value="4"
|
|
429
|
+
label="A longer option that exceeds the minimum"
|
|
430
|
+
/>
|
|
431
|
+
</MultiSelect>
|
|
432
|
+
</div>
|
|
433
|
+
)
|
|
434
|
+
WithMenuMinWidth.args = { menuMinWidth: '240px' }
|
|
@@ -46,6 +46,8 @@ class MultiSelectField extends React.Component {
|
|
|
46
46
|
helpText,
|
|
47
47
|
validationText,
|
|
48
48
|
maxHeight,
|
|
49
|
+
menuMinWidth,
|
|
50
|
+
menuMaxWidth,
|
|
49
51
|
inputMaxHeight,
|
|
50
52
|
inputWidth,
|
|
51
53
|
children,
|
|
@@ -81,6 +83,8 @@ class MultiSelectField extends React.Component {
|
|
|
81
83
|
selected={selected}
|
|
82
84
|
tabIndex={tabIndex}
|
|
83
85
|
maxHeight={maxHeight}
|
|
86
|
+
menuMinWidth={menuMinWidth}
|
|
87
|
+
menuMaxWidth={menuMaxWidth}
|
|
84
88
|
inputMaxHeight={inputMaxHeight}
|
|
85
89
|
onChange={onChange}
|
|
86
90
|
onFocus={onFocus}
|
|
@@ -148,6 +152,10 @@ MultiSelectField.propTypes = {
|
|
|
148
152
|
loadingText: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
|
149
153
|
/** Constrains height of the MultiSelect */
|
|
150
154
|
maxHeight: PropTypes.string,
|
|
155
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) */
|
|
156
|
+
menuMaxWidth: PropTypes.string,
|
|
157
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) */
|
|
158
|
+
menuMinWidth: PropTypes.string,
|
|
151
159
|
/** Text to display when there are no filter results */
|
|
152
160
|
noMatchText: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
|
153
161
|
/** Placeholder text when the MultiSelect is empty */
|
|
@@ -135,3 +135,34 @@ DefaultFilterPlaceholderAndNoMatchText.storyName =
|
|
|
135
135
|
export const DefaultLoadingText = Template.bind({})
|
|
136
136
|
DefaultLoadingText.args = { loading: true, ...DefaultEmpty.args }
|
|
137
137
|
DefaultLoadingText.storyName = 'Default: loadingText'
|
|
138
|
+
|
|
139
|
+
export const WithMenuMaxWidth = Template.bind({})
|
|
140
|
+
WithMenuMaxWidth.args = {
|
|
141
|
+
inputWidth: '120px',
|
|
142
|
+
menuMaxWidth: '200px',
|
|
143
|
+
children: [
|
|
144
|
+
<MultiSelectOption key="1" value="1" label="option one" />,
|
|
145
|
+
<MultiSelectOption key="2" value="2" label="option two" />,
|
|
146
|
+
<MultiSelectOption
|
|
147
|
+
key="3"
|
|
148
|
+
value="3"
|
|
149
|
+
label="A much longer option label"
|
|
150
|
+
/>,
|
|
151
|
+
],
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export const WithMenuMinWidth = Template.bind({})
|
|
155
|
+
WithMenuMinWidth.args = {
|
|
156
|
+
inputWidth: '120px',
|
|
157
|
+
menuMinWidth: '240px',
|
|
158
|
+
children: [
|
|
159
|
+
<MultiSelectOption key="1" value="1" label="option one" />,
|
|
160
|
+
<MultiSelectOption key="2" value="2" label="option two" />,
|
|
161
|
+
<MultiSelectOption key="3" value="3" label="option three" />,
|
|
162
|
+
<MultiSelectOption
|
|
163
|
+
key="4"
|
|
164
|
+
value="4"
|
|
165
|
+
label="A longer option that exceeds the minimum"
|
|
166
|
+
/>,
|
|
167
|
+
],
|
|
168
|
+
}
|
|
@@ -7,11 +7,23 @@ import React from 'react'
|
|
|
7
7
|
const MenuWrapper = ({
|
|
8
8
|
children,
|
|
9
9
|
dataTest,
|
|
10
|
+
inputWidth,
|
|
10
11
|
maxHeight = '280px',
|
|
11
|
-
|
|
12
|
+
menuMaxWidth,
|
|
13
|
+
menuMinWidth,
|
|
12
14
|
onClick,
|
|
13
15
|
selectRef,
|
|
14
16
|
}) => {
|
|
17
|
+
// menuMinWidth or menuMaxWidth enables flexible sizing (fit-content), with
|
|
18
|
+
// min-width = max(input, menuMinWidth). Without them, width matches the input.
|
|
19
|
+
const flexible = menuMinWidth || menuMaxWidth
|
|
20
|
+
const width = flexible ? 'fit-content' : inputWidth
|
|
21
|
+
const flexibleMinWidth = menuMinWidth
|
|
22
|
+
? `max(${inputWidth}, ${menuMinWidth})`
|
|
23
|
+
: inputWidth
|
|
24
|
+
const minWidth = flexible ? flexibleMinWidth : 'auto'
|
|
25
|
+
const maxWidth = menuMaxWidth || 'none'
|
|
26
|
+
|
|
15
27
|
return (
|
|
16
28
|
<Layer onBackdropClick={onClick} transparent>
|
|
17
29
|
<Popper
|
|
@@ -24,7 +36,9 @@ const MenuWrapper = ({
|
|
|
24
36
|
|
|
25
37
|
<style jsx>{`
|
|
26
38
|
div {
|
|
27
|
-
width: ${
|
|
39
|
+
width: ${width};
|
|
40
|
+
min-width: ${minWidth};
|
|
41
|
+
max-width: ${maxWidth};
|
|
28
42
|
height: auto;
|
|
29
43
|
max-height: ${maxHeight};
|
|
30
44
|
overflow: auto;
|
|
@@ -42,10 +56,12 @@ const MenuWrapper = ({
|
|
|
42
56
|
|
|
43
57
|
MenuWrapper.propTypes = {
|
|
44
58
|
dataTest: PropTypes.string.isRequired,
|
|
45
|
-
|
|
59
|
+
inputWidth: PropTypes.string.isRequired,
|
|
46
60
|
selectRef: PropTypes.object.isRequired,
|
|
47
61
|
children: PropTypes.node,
|
|
48
62
|
maxHeight: PropTypes.string,
|
|
63
|
+
menuMaxWidth: PropTypes.string,
|
|
64
|
+
menuMinWidth: PropTypes.string,
|
|
49
65
|
onClick: PropTypes.func,
|
|
50
66
|
}
|
|
51
67
|
|
package/src/select/select.js
CHANGED
|
@@ -15,7 +15,7 @@ const DOWN_KEY = 40
|
|
|
15
15
|
export class Select extends Component {
|
|
16
16
|
state = {
|
|
17
17
|
open: false,
|
|
18
|
-
|
|
18
|
+
inputWidth: 'auto',
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
static defaultProps = {
|
|
@@ -30,7 +30,7 @@ export class Select extends Component {
|
|
|
30
30
|
this.inputRef.current.focus()
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
this.setState({
|
|
33
|
+
this.setState({ inputWidth: this.getInputWidth() })
|
|
34
34
|
window.addEventListener('resize', this.onResize)
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -48,21 +48,21 @@ export class Select extends Component {
|
|
|
48
48
|
* See: https://nolanlawson.com/2018/09/25/accurately-measuring-layout-on-the-web
|
|
49
49
|
*/
|
|
50
50
|
onResize = debounce(() => {
|
|
51
|
-
const
|
|
51
|
+
const inputWidth = this.getInputWidth()
|
|
52
52
|
|
|
53
|
-
if (this.state.
|
|
54
|
-
this.setState({
|
|
53
|
+
if (this.state.inputWidth !== inputWidth) {
|
|
54
|
+
this.setState({ inputWidth })
|
|
55
55
|
}
|
|
56
56
|
}, 50)
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
getInputWidth() {
|
|
59
59
|
const { offsetWidth } = this.inputRef.current
|
|
60
|
-
const {
|
|
60
|
+
const { inputWidth } = this.state
|
|
61
61
|
|
|
62
|
-
if (offsetWidth && `${offsetWidth}px` !==
|
|
62
|
+
if (offsetWidth && `${offsetWidth}px` !== inputWidth) {
|
|
63
63
|
return `${offsetWidth}px`
|
|
64
64
|
}
|
|
65
|
-
return
|
|
65
|
+
return inputWidth
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
handleFocusInput = () => {
|
|
@@ -82,7 +82,7 @@ export class Select extends Component {
|
|
|
82
82
|
handleOpen = () => {
|
|
83
83
|
this.setState({
|
|
84
84
|
open: true,
|
|
85
|
-
|
|
85
|
+
inputWidth: this.getInputWidth(),
|
|
86
86
|
})
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -159,7 +159,7 @@ export class Select extends Component {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
render() {
|
|
162
|
-
const { open,
|
|
162
|
+
const { open, inputWidth } = this.state
|
|
163
163
|
const {
|
|
164
164
|
children,
|
|
165
165
|
className,
|
|
@@ -167,6 +167,8 @@ export class Select extends Component {
|
|
|
167
167
|
onChange,
|
|
168
168
|
tabIndex,
|
|
169
169
|
maxHeight,
|
|
170
|
+
menuMinWidth,
|
|
171
|
+
menuMaxWidth,
|
|
170
172
|
error,
|
|
171
173
|
warning,
|
|
172
174
|
valid,
|
|
@@ -220,7 +222,9 @@ export class Select extends Component {
|
|
|
220
222
|
onClick={this.onOutsideClick}
|
|
221
223
|
maxHeight={maxHeight}
|
|
222
224
|
selectRef={this.selectRef}
|
|
223
|
-
|
|
225
|
+
inputWidth={inputWidth}
|
|
226
|
+
menuMinWidth={menuMinWidth}
|
|
227
|
+
menuMaxWidth={menuMaxWidth}
|
|
224
228
|
dataTest={`${dataTest}-menu`}
|
|
225
229
|
>
|
|
226
230
|
{menu}
|
|
@@ -246,6 +250,8 @@ Select.propTypes = {
|
|
|
246
250
|
error: sharedPropTypes.statusPropType,
|
|
247
251
|
initialFocus: PropTypes.bool,
|
|
248
252
|
maxHeight: PropTypes.string,
|
|
253
|
+
menuMaxWidth: PropTypes.string,
|
|
254
|
+
menuMinWidth: PropTypes.string,
|
|
249
255
|
tabIndex: PropTypes.string,
|
|
250
256
|
valid: sharedPropTypes.statusPropType,
|
|
251
257
|
warning: sharedPropTypes.statusPropType,
|
|
@@ -13,6 +13,8 @@ const SingleSelect = ({
|
|
|
13
13
|
selected = '',
|
|
14
14
|
tabIndex,
|
|
15
15
|
maxHeight,
|
|
16
|
+
menuMinWidth,
|
|
17
|
+
menuMaxWidth,
|
|
16
18
|
inputMaxHeight,
|
|
17
19
|
onChange,
|
|
18
20
|
onFocus,
|
|
@@ -68,6 +70,8 @@ const SingleSelect = ({
|
|
|
68
70
|
menu={menu}
|
|
69
71
|
tabIndex={tabIndex}
|
|
70
72
|
maxHeight={maxHeight}
|
|
73
|
+
menuMinWidth={menuMinWidth}
|
|
74
|
+
menuMaxWidth={menuMaxWidth}
|
|
71
75
|
onChange={onChange}
|
|
72
76
|
onFocus={onFocus}
|
|
73
77
|
onKeyDown={onKeyDown}
|
|
@@ -127,6 +131,10 @@ SingleSelect.propTypes = {
|
|
|
127
131
|
loading: PropTypes.bool,
|
|
128
132
|
loadingText: PropTypes.string,
|
|
129
133
|
maxHeight: PropTypes.string,
|
|
134
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) */
|
|
135
|
+
menuMaxWidth: PropTypes.string,
|
|
136
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) */
|
|
137
|
+
menuMinWidth: PropTypes.string,
|
|
130
138
|
/** Text to show when filter returns no results. Required if `filterable` prop is true */
|
|
131
139
|
noMatchText: requiredIf((props) => props.filterable, PropTypes.string),
|
|
132
140
|
placeholder: PropTypes.string,
|
|
@@ -356,3 +356,29 @@ export const ShiftedIntoView = (args) => (
|
|
|
356
356
|
`}</style>
|
|
357
357
|
</>
|
|
358
358
|
)
|
|
359
|
+
|
|
360
|
+
export const WithMenuMaxWidth = (args) => (
|
|
361
|
+
<div style={{ width: 120 }}>
|
|
362
|
+
<SingleSelect {...args}>
|
|
363
|
+
<SingleSelectOption value="1" label="option one" />
|
|
364
|
+
<SingleSelectOption value="2" label="option two" />
|
|
365
|
+
<SingleSelectOption value="3" label="A much longer option label" />
|
|
366
|
+
</SingleSelect>
|
|
367
|
+
</div>
|
|
368
|
+
)
|
|
369
|
+
WithMenuMaxWidth.args = { menuMaxWidth: '200px' }
|
|
370
|
+
|
|
371
|
+
export const WithMenuMinWidth = (args) => (
|
|
372
|
+
<div style={{ width: 120 }}>
|
|
373
|
+
<SingleSelect {...args}>
|
|
374
|
+
<SingleSelectOption value="1" label="option one" />
|
|
375
|
+
<SingleSelectOption value="2" label="option two" />
|
|
376
|
+
<SingleSelectOption value="3" label="option three" />
|
|
377
|
+
<SingleSelectOption
|
|
378
|
+
value="4"
|
|
379
|
+
label="A longer option that exceeds the minimum"
|
|
380
|
+
/>
|
|
381
|
+
</SingleSelect>
|
|
382
|
+
</div>
|
|
383
|
+
)
|
|
384
|
+
WithMenuMinWidth.args = { menuMinWidth: '240px' }
|