@dhis2-ui/select 10.16.5 → 10.18.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/simple-single-select/__stories__/WithMenuMaxWidth.js +34 -0
- package/build/cjs/simple-single-select/__stories__/WithMenuMinWidth.js +37 -0
- package/build/cjs/simple-single-select/menu/menu.js +17 -8
- package/build/cjs/simple-single-select/simple-single-select.js +19 -9
- package/build/cjs/simple-single-select/simple-single-select.prod.stories.js +14 -0
- package/build/cjs/simple-single-select/simple-single-select.test.js +62 -0
- package/build/cjs/simple-single-select-field/simple-single-select-field.js +4 -0
- package/build/cjs/simple-single-select-field/simple-single-select-field.prod.stories.js +53 -2
- package/build/cjs/simple-single-select-field/simple-single-select-field.test.js +4 -0
- 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/cjs/single-select-option/single-select-option.js +4 -4
- 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/simple-single-select/__stories__/WithMenuMaxWidth.js +26 -0
- package/build/es/simple-single-select/__stories__/WithMenuMinWidth.js +29 -0
- package/build/es/simple-single-select/menu/menu.js +17 -8
- package/build/es/simple-single-select/simple-single-select.js +19 -9
- package/build/es/simple-single-select/simple-single-select.prod.stories.js +2 -0
- package/build/es/simple-single-select/simple-single-select.test.js +62 -0
- package/build/es/simple-single-select-field/simple-single-select-field.js +4 -0
- package/build/es/simple-single-select-field/simple-single-select-field.prod.stories.js +49 -0
- package/build/es/simple-single-select-field/simple-single-select-field.test.js +4 -0
- 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/build/es/single-select-option/single-select-option.js +4 -4
- 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/simple-single-select/__stories__/WithMenuMaxWidth.js +24 -0
- package/src/simple-single-select/__stories__/WithMenuMinWidth.js +25 -0
- package/src/simple-single-select/menu/menu.js +26 -8
- package/src/simple-single-select/simple-single-select.js +19 -6
- package/src/simple-single-select/simple-single-select.prod.stories.js +2 -0
- package/src/simple-single-select/simple-single-select.test.js +68 -0
- package/src/simple-single-select-field/simple-single-select-field.js +6 -0
- package/src/simple-single-select-field/simple-single-select-field.prod.stories.js +49 -0
- package/src/simple-single-select-field/simple-single-select-field.test.js +4 -0
- 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
- package/src/single-select-option/single-select-option.js +5 -3
- package/types/index.d.ts +45 -1
|
@@ -22,6 +22,8 @@ const MultiSelect = ({
|
|
|
22
22
|
selected = staticArr,
|
|
23
23
|
tabIndex,
|
|
24
24
|
maxHeight,
|
|
25
|
+
menuMinWidth,
|
|
26
|
+
menuMaxWidth,
|
|
25
27
|
inputMaxHeight,
|
|
26
28
|
onChange,
|
|
27
29
|
onFocus,
|
|
@@ -77,6 +79,8 @@ const MultiSelect = ({
|
|
|
77
79
|
menu: menu,
|
|
78
80
|
tabIndex: tabIndex,
|
|
79
81
|
maxHeight: maxHeight,
|
|
82
|
+
menuMinWidth: menuMinWidth,
|
|
83
|
+
menuMaxWidth: menuMaxWidth,
|
|
80
84
|
onChange: onChange,
|
|
81
85
|
onFocus: onFocus,
|
|
82
86
|
onKeyDown: onKeyDown,
|
|
@@ -122,6 +126,10 @@ MultiSelect.propTypes = {
|
|
|
122
126
|
loading: _propTypes2.default.bool,
|
|
123
127
|
loadingText: _propTypes2.default.string,
|
|
124
128
|
maxHeight: _propTypes2.default.string,
|
|
129
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) */
|
|
130
|
+
menuMaxWidth: _propTypes2.default.string,
|
|
131
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) */
|
|
132
|
+
menuMinWidth: _propTypes2.default.string,
|
|
125
133
|
/** Required if `filterable` prop is `true` */
|
|
126
134
|
noMatchText: (0, _propTypes.requiredIf)(props => props.filterable, _propTypes2.default.string),
|
|
127
135
|
placeholder: _propTypes2.default.string,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.default = exports.WithPrefixAndSelection = exports.WithPrefix = exports.WithPlaceholderAndSelection = exports.WithPlaceholder = exports.WithOptionsLoadingAndLoadingText = exports.WithOptionsAndOnChange = exports.WithOptionsAndMultipleSelections = exports.WithOptionsAndLoading = exports.WithOptionsAndDisabled = exports.WithOptionsAndASelection = exports.WithOptionsASelectionAndDisabled = exports.WithOnFocus = exports.WithOnBlur = exports.WithMultipleSelectionsWrapped = exports.WithMoreThanThreeOptionsAndA100PxMaxHeight = exports.WithMoreThanTenOptions = exports.WithInvalidOptions = exports.WithInvalidFilterableOptions = exports.WithInitialFocus = exports.WithFilterField = exports.WithDisabledOptionAndOnChange = exports.WithCustomOptionsAndOnChange = exports.WithClearButtonSelectionAndOnChange = exports.ShiftedIntoView = exports.RTL = exports.FlippedPosition = exports.EmptyWithEmptyText = exports.EmptyWithEmptyComponent = exports.Empty = exports.DenseWithSelections = exports.Dense = exports.DefaultPosition = exports.CollapseSelectionAfterThreshold = void 0;
|
|
6
|
+
exports.default = exports.WithPrefixAndSelection = exports.WithPrefix = exports.WithPlaceholderAndSelection = exports.WithPlaceholder = exports.WithOptionsLoadingAndLoadingText = exports.WithOptionsAndOnChange = exports.WithOptionsAndMultipleSelections = exports.WithOptionsAndLoading = exports.WithOptionsAndDisabled = exports.WithOptionsAndASelection = exports.WithOptionsASelectionAndDisabled = exports.WithOnFocus = exports.WithOnBlur = exports.WithMultipleSelectionsWrapped = exports.WithMoreThanThreeOptionsAndA100PxMaxHeight = exports.WithMoreThanTenOptions = exports.WithMenuMinWidth = exports.WithMenuMaxWidth = exports.WithInvalidOptions = exports.WithInvalidFilterableOptions = exports.WithInitialFocus = exports.WithFilterField = exports.WithDisabledOptionAndOnChange = exports.WithCustomOptionsAndOnChange = exports.WithClearButtonSelectionAndOnChange = exports.ShiftedIntoView = exports.RTL = exports.FlippedPosition = exports.EmptyWithEmptyText = exports.EmptyWithEmptyComponent = exports.Empty = exports.DenseWithSelections = exports.Dense = exports.DefaultPosition = exports.CollapseSelectionAfterThreshold = void 0;
|
|
7
7
|
var _style = _interopRequireDefault(require("styled-jsx/style"));
|
|
8
8
|
var _uiConstants = require("@dhis2/ui-constants");
|
|
9
9
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
@@ -561,4 +561,43 @@ exports.RTL = RTL;
|
|
|
561
561
|
RTL.args = {
|
|
562
562
|
selected: ['1', '2'],
|
|
563
563
|
prefix: 'RTL text'
|
|
564
|
+
};
|
|
565
|
+
const WithMenuMaxWidth = args => /*#__PURE__*/_react.default.createElement("div", {
|
|
566
|
+
style: {
|
|
567
|
+
width: 120
|
|
568
|
+
}
|
|
569
|
+
}, /*#__PURE__*/_react.default.createElement(_index2.MultiSelect, args, /*#__PURE__*/_react.default.createElement(_index.MultiSelectOption, {
|
|
570
|
+
value: "1",
|
|
571
|
+
label: "option one"
|
|
572
|
+
}), /*#__PURE__*/_react.default.createElement(_index.MultiSelectOption, {
|
|
573
|
+
value: "2",
|
|
574
|
+
label: "option two"
|
|
575
|
+
}), /*#__PURE__*/_react.default.createElement(_index.MultiSelectOption, {
|
|
576
|
+
value: "3",
|
|
577
|
+
label: "A much longer option label"
|
|
578
|
+
})));
|
|
579
|
+
exports.WithMenuMaxWidth = WithMenuMaxWidth;
|
|
580
|
+
WithMenuMaxWidth.args = {
|
|
581
|
+
menuMaxWidth: '200px'
|
|
582
|
+
};
|
|
583
|
+
const WithMenuMinWidth = args => /*#__PURE__*/_react.default.createElement("div", {
|
|
584
|
+
style: {
|
|
585
|
+
width: 120
|
|
586
|
+
}
|
|
587
|
+
}, /*#__PURE__*/_react.default.createElement(_index2.MultiSelect, args, /*#__PURE__*/_react.default.createElement(_index.MultiSelectOption, {
|
|
588
|
+
value: "1",
|
|
589
|
+
label: "option one"
|
|
590
|
+
}), /*#__PURE__*/_react.default.createElement(_index.MultiSelectOption, {
|
|
591
|
+
value: "2",
|
|
592
|
+
label: "option two"
|
|
593
|
+
}), /*#__PURE__*/_react.default.createElement(_index.MultiSelectOption, {
|
|
594
|
+
value: "3",
|
|
595
|
+
label: "option three"
|
|
596
|
+
}), /*#__PURE__*/_react.default.createElement(_index.MultiSelectOption, {
|
|
597
|
+
value: "4",
|
|
598
|
+
label: "A longer option that exceeds the minimum"
|
|
599
|
+
})));
|
|
600
|
+
exports.WithMenuMinWidth = WithMenuMinWidth;
|
|
601
|
+
WithMenuMinWidth.args = {
|
|
602
|
+
menuMinWidth: '240px'
|
|
564
603
|
};
|
|
@@ -42,6 +42,8 @@ class MultiSelectField extends _react.default.Component {
|
|
|
42
42
|
helpText,
|
|
43
43
|
validationText,
|
|
44
44
|
maxHeight,
|
|
45
|
+
menuMinWidth,
|
|
46
|
+
menuMaxWidth,
|
|
45
47
|
inputMaxHeight,
|
|
46
48
|
inputWidth,
|
|
47
49
|
children,
|
|
@@ -76,6 +78,8 @@ class MultiSelectField extends _react.default.Component {
|
|
|
76
78
|
selected: selected,
|
|
77
79
|
tabIndex: tabIndex,
|
|
78
80
|
maxHeight: maxHeight,
|
|
81
|
+
menuMinWidth: menuMinWidth,
|
|
82
|
+
menuMaxWidth: menuMaxWidth,
|
|
79
83
|
inputMaxHeight: inputMaxHeight,
|
|
80
84
|
onChange: onChange,
|
|
81
85
|
onFocus: onFocus,
|
|
@@ -147,6 +151,10 @@ MultiSelectField.propTypes = {
|
|
|
147
151
|
loadingText: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func]),
|
|
148
152
|
/** Constrains height of the MultiSelect */
|
|
149
153
|
maxHeight: _propTypes.default.string,
|
|
154
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) */
|
|
155
|
+
menuMaxWidth: _propTypes.default.string,
|
|
156
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) */
|
|
157
|
+
menuMinWidth: _propTypes.default.string,
|
|
150
158
|
/** Text to display when there are no filter results */
|
|
151
159
|
noMatchText: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func]),
|
|
152
160
|
/** Placeholder text when the MultiSelect is empty */
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.default = exports.WithHelpText = exports.StatusWarning = exports.StatusValid = exports.StatusError = exports.Required = exports.InputWidth = exports.DefaultLoadingText = exports.DefaultFilterPlaceholderAndNoMatchText = exports.DefaultEmpty = exports.DefaultClearText = exports.Default = void 0;
|
|
6
|
+
exports.default = exports.WithMenuMinWidth = exports.WithMenuMaxWidth = exports.WithHelpText = exports.StatusWarning = exports.StatusValid = exports.StatusError = exports.Required = exports.InputWidth = exports.DefaultLoadingText = exports.DefaultFilterPlaceholderAndNoMatchText = exports.DefaultEmpty = exports.DefaultClearText = exports.Default = void 0;
|
|
7
7
|
var _uiConstants = require("@dhis2/ui-constants");
|
|
8
8
|
var _react = _interopRequireDefault(require("react"));
|
|
9
9
|
var _index = require("../index.js");
|
|
@@ -174,4 +174,44 @@ DefaultLoadingText.args = {
|
|
|
174
174
|
loading: true,
|
|
175
175
|
...DefaultEmpty.args
|
|
176
176
|
};
|
|
177
|
-
DefaultLoadingText.storyName = 'Default: loadingText';
|
|
177
|
+
DefaultLoadingText.storyName = 'Default: loadingText';
|
|
178
|
+
const WithMenuMaxWidth = exports.WithMenuMaxWidth = Template.bind({});
|
|
179
|
+
WithMenuMaxWidth.args = {
|
|
180
|
+
inputWidth: '120px',
|
|
181
|
+
menuMaxWidth: '200px',
|
|
182
|
+
children: [/*#__PURE__*/_react.default.createElement(_index.MultiSelectOption, {
|
|
183
|
+
key: "1",
|
|
184
|
+
value: "1",
|
|
185
|
+
label: "option one"
|
|
186
|
+
}), /*#__PURE__*/_react.default.createElement(_index.MultiSelectOption, {
|
|
187
|
+
key: "2",
|
|
188
|
+
value: "2",
|
|
189
|
+
label: "option two"
|
|
190
|
+
}), /*#__PURE__*/_react.default.createElement(_index.MultiSelectOption, {
|
|
191
|
+
key: "3",
|
|
192
|
+
value: "3",
|
|
193
|
+
label: "A much longer option label"
|
|
194
|
+
})]
|
|
195
|
+
};
|
|
196
|
+
const WithMenuMinWidth = exports.WithMenuMinWidth = Template.bind({});
|
|
197
|
+
WithMenuMinWidth.args = {
|
|
198
|
+
inputWidth: '120px',
|
|
199
|
+
menuMinWidth: '240px',
|
|
200
|
+
children: [/*#__PURE__*/_react.default.createElement(_index.MultiSelectOption, {
|
|
201
|
+
key: "1",
|
|
202
|
+
value: "1",
|
|
203
|
+
label: "option one"
|
|
204
|
+
}), /*#__PURE__*/_react.default.createElement(_index.MultiSelectOption, {
|
|
205
|
+
key: "2",
|
|
206
|
+
value: "2",
|
|
207
|
+
label: "option two"
|
|
208
|
+
}), /*#__PURE__*/_react.default.createElement(_index.MultiSelectOption, {
|
|
209
|
+
key: "3",
|
|
210
|
+
value: "3",
|
|
211
|
+
label: "option three"
|
|
212
|
+
}), /*#__PURE__*/_react.default.createElement(_index.MultiSelectOption, {
|
|
213
|
+
key: "4",
|
|
214
|
+
value: "4",
|
|
215
|
+
label: "A longer option that exceeds the minimum"
|
|
216
|
+
})]
|
|
217
|
+
};
|
|
@@ -14,11 +14,20 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
14
14
|
const MenuWrapper = ({
|
|
15
15
|
children,
|
|
16
16
|
dataTest,
|
|
17
|
+
inputWidth,
|
|
17
18
|
maxHeight = '280px',
|
|
18
|
-
|
|
19
|
+
menuMaxWidth,
|
|
20
|
+
menuMinWidth,
|
|
19
21
|
onClick,
|
|
20
22
|
selectRef
|
|
21
23
|
}) => {
|
|
24
|
+
// menuMinWidth or menuMaxWidth enables flexible sizing (fit-content), with
|
|
25
|
+
// min-width = max(input, menuMinWidth). Without them, width matches the input.
|
|
26
|
+
const flexible = menuMinWidth || menuMaxWidth;
|
|
27
|
+
const width = flexible ? 'fit-content' : inputWidth;
|
|
28
|
+
const flexibleMinWidth = menuMinWidth ? `max(${inputWidth}, ${menuMinWidth})` : inputWidth;
|
|
29
|
+
const minWidth = flexible ? flexibleMinWidth : 'auto';
|
|
30
|
+
const maxWidth = menuMaxWidth || 'none';
|
|
22
31
|
return /*#__PURE__*/_react.default.createElement(_layer.Layer, {
|
|
23
32
|
onBackdropClick: onClick,
|
|
24
33
|
transparent: true
|
|
@@ -28,18 +37,20 @@ const MenuWrapper = ({
|
|
|
28
37
|
observeReferenceResize: true
|
|
29
38
|
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
30
39
|
"data-test": `${dataTest}-menuwrapper`,
|
|
31
|
-
className: _style.default.dynamic([["
|
|
40
|
+
className: _style.default.dynamic([["3752211706", [width, minWidth, maxWidth, maxHeight, _uiConstants.colors.white, _uiConstants.colors.grey200, _uiConstants.elevations.popover]]])
|
|
32
41
|
}, children, /*#__PURE__*/_react.default.createElement(_style.default, {
|
|
33
|
-
id: "
|
|
34
|
-
dynamic: [
|
|
35
|
-
}, [`div.__jsx-style-dynamic-selector{width:${
|
|
42
|
+
id: "3752211706",
|
|
43
|
+
dynamic: [width, minWidth, maxWidth, maxHeight, _uiConstants.colors.white, _uiConstants.colors.grey200, _uiConstants.elevations.popover]
|
|
44
|
+
}, [`div.__jsx-style-dynamic-selector{width:${width};min-width:${minWidth};max-width:${maxWidth};height:auto;max-height:${maxHeight};overflow:auto;background:${_uiConstants.colors.white};border:1px solid ${_uiConstants.colors.grey200};border-radius:3px;box-shadow:${_uiConstants.elevations.popover};}`]))));
|
|
36
45
|
};
|
|
37
46
|
exports.MenuWrapper = MenuWrapper;
|
|
38
47
|
MenuWrapper.propTypes = {
|
|
39
48
|
dataTest: _propTypes.default.string.isRequired,
|
|
40
|
-
|
|
49
|
+
inputWidth: _propTypes.default.string.isRequired,
|
|
41
50
|
selectRef: _propTypes.default.object.isRequired,
|
|
42
51
|
children: _propTypes.default.node,
|
|
43
52
|
maxHeight: _propTypes.default.string,
|
|
53
|
+
menuMaxWidth: _propTypes.default.string,
|
|
54
|
+
menuMinWidth: _propTypes.default.string,
|
|
44
55
|
onClick: _propTypes.default.func
|
|
45
56
|
};
|
|
@@ -26,7 +26,7 @@ class Select extends _react.Component {
|
|
|
26
26
|
super(...args);
|
|
27
27
|
_defineProperty(this, "state", {
|
|
28
28
|
open: false,
|
|
29
|
-
|
|
29
|
+
inputWidth: 'auto'
|
|
30
30
|
});
|
|
31
31
|
_defineProperty(this, "selectRef", /*#__PURE__*/_react.default.createRef());
|
|
32
32
|
_defineProperty(this, "inputRef", /*#__PURE__*/_react.default.createRef());
|
|
@@ -40,10 +40,10 @@ class Select extends _react.Component {
|
|
|
40
40
|
* See: https://nolanlawson.com/2018/09/25/accurately-measuring-layout-on-the-web
|
|
41
41
|
*/
|
|
42
42
|
_defineProperty(this, "onResize", (0, _debounce.debounce)(() => {
|
|
43
|
-
const
|
|
44
|
-
if (this.state.
|
|
43
|
+
const inputWidth = this.getInputWidth();
|
|
44
|
+
if (this.state.inputWidth !== inputWidth) {
|
|
45
45
|
this.setState({
|
|
46
|
-
|
|
46
|
+
inputWidth
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
}, 50));
|
|
@@ -66,7 +66,7 @@ class Select extends _react.Component {
|
|
|
66
66
|
_defineProperty(this, "handleOpen", () => {
|
|
67
67
|
this.setState({
|
|
68
68
|
open: true,
|
|
69
|
-
|
|
69
|
+
inputWidth: this.getInputWidth()
|
|
70
70
|
});
|
|
71
71
|
});
|
|
72
72
|
_defineProperty(this, "handleClose", () => {
|
|
@@ -145,29 +145,29 @@ class Select extends _react.Component {
|
|
|
145
145
|
this.inputRef.current.focus();
|
|
146
146
|
}
|
|
147
147
|
this.setState({
|
|
148
|
-
|
|
148
|
+
inputWidth: this.getInputWidth()
|
|
149
149
|
});
|
|
150
150
|
window.addEventListener('resize', this.onResize);
|
|
151
151
|
}
|
|
152
152
|
componentWillUnmount() {
|
|
153
153
|
window.removeEventListener('resize', this.onResize);
|
|
154
154
|
}
|
|
155
|
-
|
|
155
|
+
getInputWidth() {
|
|
156
156
|
const {
|
|
157
157
|
offsetWidth
|
|
158
158
|
} = this.inputRef.current;
|
|
159
159
|
const {
|
|
160
|
-
|
|
160
|
+
inputWidth
|
|
161
161
|
} = this.state;
|
|
162
|
-
if (offsetWidth && `${offsetWidth}px` !==
|
|
162
|
+
if (offsetWidth && `${offsetWidth}px` !== inputWidth) {
|
|
163
163
|
return `${offsetWidth}px`;
|
|
164
164
|
}
|
|
165
|
-
return
|
|
165
|
+
return inputWidth;
|
|
166
166
|
}
|
|
167
167
|
render() {
|
|
168
168
|
const {
|
|
169
169
|
open,
|
|
170
|
-
|
|
170
|
+
inputWidth
|
|
171
171
|
} = this.state;
|
|
172
172
|
const {
|
|
173
173
|
children,
|
|
@@ -176,6 +176,8 @@ class Select extends _react.Component {
|
|
|
176
176
|
onChange,
|
|
177
177
|
tabIndex,
|
|
178
178
|
maxHeight,
|
|
179
|
+
menuMinWidth,
|
|
180
|
+
menuMaxWidth,
|
|
179
181
|
error,
|
|
180
182
|
warning,
|
|
181
183
|
valid,
|
|
@@ -222,7 +224,9 @@ class Select extends _react.Component {
|
|
|
222
224
|
onClick: this.onOutsideClick,
|
|
223
225
|
maxHeight: maxHeight,
|
|
224
226
|
selectRef: this.selectRef,
|
|
225
|
-
|
|
227
|
+
inputWidth: inputWidth,
|
|
228
|
+
menuMinWidth: menuMinWidth,
|
|
229
|
+
menuMaxWidth: menuMaxWidth,
|
|
226
230
|
dataTest: `${dataTest}-menu`
|
|
227
231
|
}, menu));
|
|
228
232
|
}
|
|
@@ -243,6 +247,8 @@ Select.propTypes = {
|
|
|
243
247
|
error: _uiConstants.sharedPropTypes.statusPropType,
|
|
244
248
|
initialFocus: _propTypes.default.bool,
|
|
245
249
|
maxHeight: _propTypes.default.string,
|
|
250
|
+
menuMaxWidth: _propTypes.default.string,
|
|
251
|
+
menuMinWidth: _propTypes.default.string,
|
|
246
252
|
tabIndex: _propTypes.default.string,
|
|
247
253
|
valid: _uiConstants.sharedPropTypes.statusPropType,
|
|
248
254
|
warning: _uiConstants.sharedPropTypes.statusPropType,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.WithMenuMaxWidth = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _simpleSingleSelect = require("../simple-single-select.js");
|
|
9
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
10
|
+
const options = [{
|
|
11
|
+
value: '1',
|
|
12
|
+
label: 'option one'
|
|
13
|
+
}, {
|
|
14
|
+
value: '2',
|
|
15
|
+
label: 'option two'
|
|
16
|
+
}, {
|
|
17
|
+
value: '3',
|
|
18
|
+
label: 'A much longer option label that gets clamped'
|
|
19
|
+
}];
|
|
20
|
+
const WithMenuMaxWidth = () => {
|
|
21
|
+
const [selected, setSelected] = (0, _react.useState)(null);
|
|
22
|
+
return /*#__PURE__*/_react.default.createElement("div", {
|
|
23
|
+
style: {
|
|
24
|
+
width: 120
|
|
25
|
+
}
|
|
26
|
+
}, /*#__PURE__*/_react.default.createElement(_simpleSingleSelect.SimpleSingleSelect, {
|
|
27
|
+
name: "simple",
|
|
28
|
+
selected: selected,
|
|
29
|
+
onChange: setSelected,
|
|
30
|
+
options: options,
|
|
31
|
+
menuMaxWidth: "200px"
|
|
32
|
+
}));
|
|
33
|
+
};
|
|
34
|
+
exports.WithMenuMaxWidth = WithMenuMaxWidth;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.WithMenuMinWidth = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _simpleSingleSelect = require("../simple-single-select.js");
|
|
9
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
10
|
+
const options = [{
|
|
11
|
+
value: '1',
|
|
12
|
+
label: 'option one'
|
|
13
|
+
}, {
|
|
14
|
+
value: '2',
|
|
15
|
+
label: 'option two'
|
|
16
|
+
}, {
|
|
17
|
+
value: '3',
|
|
18
|
+
label: 'option three'
|
|
19
|
+
}, {
|
|
20
|
+
value: '4',
|
|
21
|
+
label: 'A longer option that exceeds the minimum'
|
|
22
|
+
}];
|
|
23
|
+
const WithMenuMinWidth = () => {
|
|
24
|
+
const [selected, setSelected] = (0, _react.useState)(null);
|
|
25
|
+
return /*#__PURE__*/_react.default.createElement("div", {
|
|
26
|
+
style: {
|
|
27
|
+
width: 120
|
|
28
|
+
}
|
|
29
|
+
}, /*#__PURE__*/_react.default.createElement(_simpleSingleSelect.SimpleSingleSelect, {
|
|
30
|
+
name: "simple",
|
|
31
|
+
selected: selected,
|
|
32
|
+
onChange: setSelected,
|
|
33
|
+
options: options,
|
|
34
|
+
menuMinWidth: "240px"
|
|
35
|
+
}));
|
|
36
|
+
};
|
|
37
|
+
exports.WithMenuMinWidth = WithMenuMinWidth;
|
|
@@ -34,6 +34,8 @@ function Menu({
|
|
|
34
34
|
loading,
|
|
35
35
|
loadingText,
|
|
36
36
|
maxHeight,
|
|
37
|
+
maxWidth,
|
|
38
|
+
minWidth,
|
|
37
39
|
noMatchText,
|
|
38
40
|
optionUpdateStrategy,
|
|
39
41
|
selectRef,
|
|
@@ -42,17 +44,16 @@ function Menu({
|
|
|
42
44
|
onClose,
|
|
43
45
|
onEndReached
|
|
44
46
|
}) {
|
|
45
|
-
const [
|
|
47
|
+
const [selectWidth, setSelectWidth] = (0, _react.useState)();
|
|
46
48
|
const dataTestPrefix = `${dataTest}-menu`;
|
|
49
|
+
|
|
50
|
+
// Re-measuring whenever `hidden` changes keeps the width current when the
|
|
51
|
+
// select's container has been resized since the menu was last opened
|
|
47
52
|
(0, _react.useEffect)(() => {
|
|
48
53
|
if (selectRef) {
|
|
49
|
-
|
|
50
|
-
callback(); // We want to know the width as soon as the
|
|
51
|
-
|
|
52
|
-
selectRef.addEventListener('resize', callback);
|
|
53
|
-
return () => selectRef.removeEventListener('resize', callback);
|
|
54
|
+
setSelectWidth(`${selectRef.offsetWidth}px`);
|
|
54
55
|
}
|
|
55
|
-
}, [selectRef]);
|
|
56
|
+
}, [selectRef, hidden]);
|
|
56
57
|
if (hidden) {
|
|
57
58
|
return null;
|
|
58
59
|
}
|
|
@@ -61,6 +62,10 @@ function Menu({
|
|
|
61
62
|
// we're in the process of loading options
|
|
62
63
|
!loading;
|
|
63
64
|
const isEmpty = !options.length && !filterValue;
|
|
65
|
+
const flexible = Boolean(minWidth || maxWidth);
|
|
66
|
+
// We never want the menu narrower than the select, so a maxWidth below
|
|
67
|
+
// the select's width intentionally has no effect
|
|
68
|
+
const flexibleMinWidth = minWidth && selectWidth ? `max(${selectWidth}, ${minWidth})` : minWidth || selectWidth;
|
|
64
69
|
return /*#__PURE__*/_react.default.createElement(_layer.Layer, {
|
|
65
70
|
onBackdropClick: onClose,
|
|
66
71
|
transparent: true
|
|
@@ -70,7 +75,9 @@ function Menu({
|
|
|
70
75
|
observeReferenceResize: true
|
|
71
76
|
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
72
77
|
style: {
|
|
73
|
-
width:
|
|
78
|
+
width: flexible ? 'fit-content' : selectWidth,
|
|
79
|
+
minWidth: flexible ? flexibleMinWidth : undefined,
|
|
80
|
+
maxWidth,
|
|
74
81
|
maxHeight
|
|
75
82
|
},
|
|
76
83
|
className: _style.default.dynamic([["2949029222", [_uiConstants.colors.white, _uiConstants.colors.grey200, _uiConstants.elevations.e300]]]) + " " + "menu"
|
|
@@ -121,6 +128,8 @@ Menu.propTypes = {
|
|
|
121
128
|
loading: _propTypes.default.bool,
|
|
122
129
|
loadingText: _propTypes.default.string,
|
|
123
130
|
maxHeight: _propTypes.default.string,
|
|
131
|
+
maxWidth: _propTypes.default.string,
|
|
132
|
+
minWidth: _propTypes.default.string,
|
|
124
133
|
noMatchText: _propTypes.default.string,
|
|
125
134
|
optionComponent: _propTypes.default.elementType,
|
|
126
135
|
optionUpdateStrategy: _propTypes.default.oneOf(['off', 'polite', 'assertive']),
|
|
@@ -16,6 +16,11 @@ var _sharedPropTypes = require("./shared-prop-types.js");
|
|
|
16
16
|
var _index4 = require("./use-handle-key-press/index.js");
|
|
17
17
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
18
18
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
19
|
+
const defaultSelected = {
|
|
20
|
+
label: '',
|
|
21
|
+
value: ''
|
|
22
|
+
};
|
|
23
|
+
const noop = () => undefined;
|
|
19
24
|
function useFocussedOptionIndex({
|
|
20
25
|
filterable,
|
|
21
26
|
filterValue,
|
|
@@ -73,22 +78,21 @@ function SimpleSingleSelect({
|
|
|
73
78
|
loading = false,
|
|
74
79
|
menuLoadingText: _menuLoadingText = '',
|
|
75
80
|
menuMaxHeight = '288px',
|
|
81
|
+
menuMaxWidth,
|
|
82
|
+
menuMinWidth,
|
|
76
83
|
noMatchText: _noMatchText = '',
|
|
77
84
|
optionUpdateStrategy = 'polite',
|
|
78
85
|
placeholder = '',
|
|
79
86
|
prefix = '',
|
|
80
|
-
selected =
|
|
81
|
-
label: '',
|
|
82
|
-
value: ''
|
|
83
|
-
},
|
|
87
|
+
selected = defaultSelected,
|
|
84
88
|
tabIndex = '0',
|
|
85
89
|
valid = false,
|
|
86
90
|
warning = false,
|
|
87
|
-
onBlur =
|
|
88
|
-
onClear =
|
|
89
|
-
onEndReached =
|
|
90
|
-
onFilterChange =
|
|
91
|
-
onFocus =
|
|
91
|
+
onBlur = noop,
|
|
92
|
+
onClear = noop,
|
|
93
|
+
onEndReached = noop,
|
|
94
|
+
onFilterChange = noop,
|
|
95
|
+
onFocus = noop
|
|
92
96
|
}) {
|
|
93
97
|
// We can't translate with default props as the translation function would
|
|
94
98
|
// be called before we get any translations from the consuming app/lib
|
|
@@ -238,6 +242,8 @@ function SimpleSingleSelect({
|
|
|
238
242
|
loading: loading,
|
|
239
243
|
loadingText: menuLoadingText,
|
|
240
244
|
maxHeight: menuMaxHeight,
|
|
245
|
+
maxWidth: menuMaxWidth,
|
|
246
|
+
minWidth: menuMinWidth,
|
|
241
247
|
noMatchText: noMatchText,
|
|
242
248
|
optionUpdateStrategy: optionUpdateStrategy,
|
|
243
249
|
options: options,
|
|
@@ -295,6 +301,10 @@ SimpleSingleSelect.propTypes = {
|
|
|
295
301
|
menuLoadingText: _propTypes2.default.string,
|
|
296
302
|
/** Allows to modify the max height of the menu **/
|
|
297
303
|
menuMaxHeight: _propTypes2.default.string,
|
|
304
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) **/
|
|
305
|
+
menuMaxWidth: _propTypes2.default.string,
|
|
306
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) **/
|
|
307
|
+
menuMinWidth: _propTypes2.default.string,
|
|
298
308
|
/** String that will be displayed when the select is being filtered but the options array is empty **/
|
|
299
309
|
noMatchText: (0, _propTypes.requiredIf)(props => props.filterable, _propTypes2.default.string),
|
|
300
310
|
/** Allows to override what's rendered inside the `button[role="option"]`.
|
|
@@ -99,6 +99,18 @@ Object.defineProperty(exports, "WithManyOptions", {
|
|
|
99
99
|
return _WithManyOptions.WithManyOptions;
|
|
100
100
|
}
|
|
101
101
|
});
|
|
102
|
+
Object.defineProperty(exports, "WithMenuMaxWidth", {
|
|
103
|
+
enumerable: true,
|
|
104
|
+
get: function () {
|
|
105
|
+
return _WithMenuMaxWidth.WithMenuMaxWidth;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
Object.defineProperty(exports, "WithMenuMinWidth", {
|
|
109
|
+
enumerable: true,
|
|
110
|
+
get: function () {
|
|
111
|
+
return _WithMenuMinWidth.WithMenuMinWidth;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
102
114
|
Object.defineProperty(exports, "WithMultipleSelectsAndScrollableParent", {
|
|
103
115
|
enumerable: true,
|
|
104
116
|
get: function () {
|
|
@@ -226,6 +238,8 @@ var _WithOptionsAndLoadingText = require("./__stories__/WithOptionsAndLoadingTex
|
|
|
226
238
|
var _WithoutOptionsAndLoading = require("./__stories__/WithoutOptionsAndLoading.js");
|
|
227
239
|
var _WithManyOptions = require("./__stories__/WithManyOptions.js");
|
|
228
240
|
var _WithCustomLowMaxHeight = require("./__stories__/WithCustomLowMaxHeight.js");
|
|
241
|
+
var _WithMenuMinWidth = require("./__stories__/WithMenuMinWidth.js");
|
|
242
|
+
var _WithMenuMaxWidth = require("./__stories__/WithMenuMaxWidth.js");
|
|
229
243
|
var _WithOptionsAndDisabled = require("./__stories__/WithOptionsAndDisabled.js");
|
|
230
244
|
var _WithSelectionAndDisabled = require("./__stories__/WithSelectionAndDisabled.js");
|
|
231
245
|
var _WithPrefix = require("./__stories__/WithPrefix.js");
|
|
@@ -5,6 +5,7 @@ var _react = require("@testing-library/react");
|
|
|
5
5
|
var _react2 = _interopRequireWildcard(require("react"));
|
|
6
6
|
var _simpleSingleSelect = require("./simple-single-select.js");
|
|
7
7
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
8
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
8
9
|
describe('<SimpleSingleSelect />', () => {
|
|
9
10
|
beforeAll(() => {
|
|
10
11
|
const consoleError = console.error;
|
|
@@ -145,6 +146,67 @@ describe('<SimpleSingleSelect />', () => {
|
|
|
145
146
|
const menu = listbox.parentNode.parentNode.parentNode;
|
|
146
147
|
expect(menu.style.maxHeight).toBe('100px');
|
|
147
148
|
});
|
|
149
|
+
describe('dropdown menu width', () => {
|
|
150
|
+
let offsetWidth;
|
|
151
|
+
beforeEach(() => {
|
|
152
|
+
// The menu's width is derived from the select's measured width,
|
|
153
|
+
// which is always 0 in jsdom
|
|
154
|
+
offsetWidth = jest.spyOn(HTMLElement.prototype, 'offsetWidth', 'get').mockReturnValue(120);
|
|
155
|
+
});
|
|
156
|
+
afterEach(() => {
|
|
157
|
+
offsetWidth.mockRestore();
|
|
158
|
+
});
|
|
159
|
+
const renderAndOpen = props => {
|
|
160
|
+
(0, _react.render)(/*#__PURE__*/_react2.default.createElement(_simpleSingleSelect.SimpleSingleSelect, _extends({
|
|
161
|
+
name: "simple",
|
|
162
|
+
selected: {
|
|
163
|
+
value: 'foo',
|
|
164
|
+
label: 'Foo'
|
|
165
|
+
},
|
|
166
|
+
onChange: () => null,
|
|
167
|
+
options: [{
|
|
168
|
+
value: 'foo',
|
|
169
|
+
label: 'Foo'
|
|
170
|
+
}]
|
|
171
|
+
}, props)));
|
|
172
|
+
_react.fireEvent.click(_react.screen.getByRole('combobox'));
|
|
173
|
+
const listbox = _react.screen.getByRole('listbox');
|
|
174
|
+
return listbox.parentNode.parentNode.parentNode;
|
|
175
|
+
};
|
|
176
|
+
it('should match the width of the select by default', () => {
|
|
177
|
+
const menu = renderAndOpen();
|
|
178
|
+
expect(menu.style.width).toBe('120px');
|
|
179
|
+
});
|
|
180
|
+
it('should not be narrower than menuMinWidth or the select', () => {
|
|
181
|
+
const menu = renderAndOpen({
|
|
182
|
+
menuMinWidth: '240px'
|
|
183
|
+
});
|
|
184
|
+
expect(menu.style.minWidth).toBe('max(120px, 240px)');
|
|
185
|
+
});
|
|
186
|
+
it('should not be wider than menuMaxWidth', () => {
|
|
187
|
+
const menu = renderAndOpen({
|
|
188
|
+
menuMaxWidth: '200px'
|
|
189
|
+
});
|
|
190
|
+
expect(menu.style.maxWidth).toBe('200px');
|
|
191
|
+
expect(menu.style.minWidth).toBe('120px');
|
|
192
|
+
});
|
|
193
|
+
it('should re-measure the select when the menu is reopened', () => {
|
|
194
|
+
renderAndOpen({
|
|
195
|
+
menuMinWidth: '240px'
|
|
196
|
+
});
|
|
197
|
+
const comboBox = _react.screen.getByRole('combobox');
|
|
198
|
+
|
|
199
|
+
// close the menu
|
|
200
|
+
_react.fireEvent.click(comboBox);
|
|
201
|
+
|
|
202
|
+
// widen the select while the menu is closed, then reopen it
|
|
203
|
+
offsetWidth.mockReturnValue(300);
|
|
204
|
+
_react.fireEvent.click(comboBox);
|
|
205
|
+
const listbox = _react.screen.getByRole('listbox');
|
|
206
|
+
const menu = listbox.parentNode.parentNode.parentNode;
|
|
207
|
+
expect(menu.style.minWidth).toBe('max(300px, 240px)');
|
|
208
|
+
});
|
|
209
|
+
});
|
|
148
210
|
it('should accept a placeholder', () => {
|
|
149
211
|
(0, _react.render)(/*#__PURE__*/_react2.default.createElement(_simpleSingleSelect.SimpleSingleSelect, {
|
|
150
212
|
name: "simple",
|
|
@@ -108,6 +108,10 @@ SimpleSingleSelectField.propTypes = {
|
|
|
108
108
|
menuLoadingText: _propTypes2.default.string,
|
|
109
109
|
/** Allows to modify the max height of the menu **/
|
|
110
110
|
menuMaxHeight: _propTypes2.default.string,
|
|
111
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) **/
|
|
112
|
+
menuMaxWidth: _propTypes2.default.string,
|
|
113
|
+
/** See [dropdown menu width](https://developers.dhis2.org/docs/ui/components/select#dropdown-menu-width) **/
|
|
114
|
+
menuMinWidth: _propTypes2.default.string,
|
|
111
115
|
/** String that will be displayed when the select is being filtered but the options array is empty **/
|
|
112
116
|
noMatchText: (0, _propTypes.requiredIf)(props => props.filterable, _propTypes2.default.string),
|
|
113
117
|
/** Allows to override what's rendered inside the `button[role="option"]`.
|