@khanacademy/wonder-blocks-dropdown 2.6.8 → 2.7.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/CHANGELOG.md +30 -0
- package/dist/es/index.js +172 -656
- package/dist/index.js +228 -326
- package/package.json +11 -10
- package/src/components/__tests__/dropdown-core.test.js +7 -3
- package/src/components/__tests__/search-text-input.test.js +124 -57
- package/src/components/__tests__/single-select.test.js +102 -1
- package/src/components/dropdown-core-virtualized.js +11 -34
- package/src/components/dropdown-core.js +17 -1
- package/src/components/search-text-input.js +15 -149
- package/src/components/single-select.stories.js +1 -0
- package/src/util/__tests__/dropdown-menu-styles.test.js +100 -0
- package/src/util/constants.js +7 -1
- package/src/util/dropdown-menu-styles.js +65 -0
package/dist/es/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import _extends from '@babel/runtime/helpers/extends';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import { StyleSheet
|
|
3
|
+
import { StyleSheet } from 'aphrodite';
|
|
4
4
|
import { Link } from 'react-router-dom';
|
|
5
5
|
import { __RouterContext } from 'react-router';
|
|
6
6
|
import Color, { mix, fade, SemanticColor } from '@khanacademy/wonder-blocks-color';
|
|
7
7
|
import Spacing from '@khanacademy/wonder-blocks-spacing';
|
|
8
|
-
import { LabelMedium,
|
|
8
|
+
import { LabelMedium, LabelLarge } from '@khanacademy/wonder-blocks-typography';
|
|
9
9
|
import { getClickableBehavior, isClientSideUrl, ClickableBehavior } from '@khanacademy/wonder-blocks-clickable';
|
|
10
10
|
import { addStyle, View } from '@khanacademy/wonder-blocks-core';
|
|
11
11
|
import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/objectWithoutPropertiesLoose';
|
|
@@ -13,7 +13,7 @@ import Icon, { icons } from '@khanacademy/wonder-blocks-icon';
|
|
|
13
13
|
import ReactDOM from 'react-dom';
|
|
14
14
|
import { VariableSizeList } from 'react-window';
|
|
15
15
|
import { withActionScheduler } from '@khanacademy/wonder-blocks-timing';
|
|
16
|
-
import
|
|
16
|
+
import SearchField from '@khanacademy/wonder-blocks-search-field';
|
|
17
17
|
import { Popper } from 'react-popper';
|
|
18
18
|
import { maybeGetPortalMountedModalHostElement } from '@khanacademy/wonder-blocks-modal';
|
|
19
19
|
import { Strut } from '@khanacademy/wonder-blocks-layout';
|
|
@@ -29,22 +29,18 @@ const keyCodes = {
|
|
|
29
29
|
const selectDropdownStyle = {
|
|
30
30
|
marginTop: Spacing.xSmall_8,
|
|
31
31
|
marginBottom: Spacing.xSmall_8
|
|
32
|
-
};
|
|
33
|
-
// Note that these can be overridden by the provided style if needed.
|
|
34
|
-
|
|
32
|
+
};
|
|
35
33
|
const filterableDropdownStyle = {
|
|
36
|
-
minHeight: 100
|
|
37
|
-
maxHeight: 384
|
|
34
|
+
minHeight: 100
|
|
38
35
|
};
|
|
39
36
|
const searchInputStyle = {
|
|
40
37
|
margin: Spacing.xSmall_8,
|
|
41
38
|
marginTop: Spacing.xxxSmall_4
|
|
42
|
-
};
|
|
43
|
-
|
|
39
|
+
};
|
|
44
40
|
const DROPDOWN_ITEM_HEIGHT = 40;
|
|
41
|
+
const MAX_VISIBLE_ITEMS = 9;
|
|
45
42
|
const SEPARATOR_ITEM_HEIGHT = 9;
|
|
46
|
-
const SEARCH_ITEM_HEIGHT = DROPDOWN_ITEM_HEIGHT + searchInputStyle.margin + searchInputStyle.marginTop;
|
|
47
|
-
|
|
43
|
+
const SEARCH_ITEM_HEIGHT = DROPDOWN_ITEM_HEIGHT + searchInputStyle.margin + searchInputStyle.marginTop;
|
|
48
44
|
const defaultLabels = {
|
|
49
45
|
clearSearch: "Clear search",
|
|
50
46
|
filter: "Filter",
|
|
@@ -65,12 +61,6 @@ const {
|
|
|
65
61
|
const StyledAnchor = addStyle("a");
|
|
66
62
|
const StyledButton$2 = addStyle("button");
|
|
67
63
|
const StyledLink = addStyle(Link);
|
|
68
|
-
/**
|
|
69
|
-
* The action item trigger actions, such as navigating to a different page or
|
|
70
|
-
* opening a modal. Supply the href and/or onClick props. Used as a child of
|
|
71
|
-
* ActionMenu.
|
|
72
|
-
*/
|
|
73
|
-
|
|
74
64
|
class ActionItem extends React.Component {
|
|
75
65
|
static isClassOf(instance) {
|
|
76
66
|
return instance && instance.type && instance.type.__IS_ACTION_ITEM__;
|
|
@@ -91,7 +81,7 @@ class ActionItem extends React.Component {
|
|
|
91
81
|
testId
|
|
92
82
|
} = this.props;
|
|
93
83
|
const ClickableBehavior = getClickableBehavior(href, skipClientNav, router);
|
|
94
|
-
return
|
|
84
|
+
return React.createElement(ClickableBehavior, {
|
|
95
85
|
disabled: disabled,
|
|
96
86
|
onClick: onClick,
|
|
97
87
|
href: href,
|
|
@@ -103,8 +93,7 @@ class ActionItem extends React.Component {
|
|
|
103
93
|
hovered,
|
|
104
94
|
focused
|
|
105
95
|
} = state;
|
|
106
|
-
const defaultStyle = [styles$
|
|
107
|
-
style];
|
|
96
|
+
const defaultStyle = [styles$8.shared, disabled && styles$8.disabled, !disabled && (pressed ? styles$8.active : (hovered || focused) && styles$8.focus), style];
|
|
108
97
|
|
|
109
98
|
const props = _extends({
|
|
110
99
|
"data-test-id": testId,
|
|
@@ -113,20 +102,20 @@ class ActionItem extends React.Component {
|
|
|
113
102
|
style: [defaultStyle]
|
|
114
103
|
}, childrenProps);
|
|
115
104
|
|
|
116
|
-
const children =
|
|
105
|
+
const children = React.createElement(React.Fragment, null, React.createElement(LabelMedium, {
|
|
117
106
|
lang: lang,
|
|
118
|
-
style: [indent && styles$
|
|
107
|
+
style: [indent && styles$8.indent, styles$8.label]
|
|
119
108
|
}, label));
|
|
120
109
|
|
|
121
110
|
if (href && !disabled) {
|
|
122
|
-
return router && !skipClientNav && isClientSideUrl(href) ?
|
|
111
|
+
return router && !skipClientNav && isClientSideUrl(href) ? React.createElement(StyledLink, _extends({}, props, {
|
|
123
112
|
to: href
|
|
124
|
-
}), children) :
|
|
113
|
+
}), children) : React.createElement(StyledAnchor, _extends({}, props, {
|
|
125
114
|
href: href,
|
|
126
115
|
target: target
|
|
127
116
|
}), children);
|
|
128
117
|
} else {
|
|
129
|
-
return
|
|
118
|
+
return React.createElement(StyledButton$2, _extends({
|
|
130
119
|
type: "button"
|
|
131
120
|
}, props, {
|
|
132
121
|
disabled: disabled
|
|
@@ -136,7 +125,7 @@ class ActionItem extends React.Component {
|
|
|
136
125
|
}
|
|
137
126
|
|
|
138
127
|
render() {
|
|
139
|
-
return
|
|
128
|
+
return React.createElement(__RouterContext.Consumer, null, router => this.renderClickableBehavior(router));
|
|
140
129
|
}
|
|
141
130
|
|
|
142
131
|
}
|
|
@@ -146,7 +135,7 @@ ActionItem.defaultProps = {
|
|
|
146
135
|
role: "menuitem"
|
|
147
136
|
};
|
|
148
137
|
ActionItem.__IS_ACTION_ITEM__ = true;
|
|
149
|
-
const styles$
|
|
138
|
+
const styles$8 = StyleSheet.create({
|
|
150
139
|
shared: {
|
|
151
140
|
background: white$4,
|
|
152
141
|
color: offBlack$3,
|
|
@@ -160,8 +149,6 @@ const styles$9 = StyleSheet.create({
|
|
|
160
149
|
minHeight: DROPDOWN_ITEM_HEIGHT,
|
|
161
150
|
paddingLeft: Spacing.medium_16,
|
|
162
151
|
paddingRight: Spacing.medium_16,
|
|
163
|
-
// This removes the 300ms click delay on mobile browsers by indicating that
|
|
164
|
-
// "double-tap to zoom" shouldn't be used on this element.
|
|
165
152
|
touchAction: "manipulation"
|
|
166
153
|
},
|
|
167
154
|
label: {
|
|
@@ -171,17 +158,14 @@ const styles$9 = StyleSheet.create({
|
|
|
171
158
|
indent: {
|
|
172
159
|
marginLeft: Spacing.medium_16
|
|
173
160
|
},
|
|
174
|
-
// hover and focus states
|
|
175
161
|
focus: {
|
|
176
162
|
color: white$4,
|
|
177
163
|
background: blue$3
|
|
178
164
|
},
|
|
179
|
-
// active and pressed states
|
|
180
165
|
active: {
|
|
181
166
|
color: mix(fade(blue$3, 0.32), white$4),
|
|
182
167
|
background: mix(offBlack32$4, blue$3)
|
|
183
168
|
},
|
|
184
|
-
// disabled state
|
|
185
169
|
disabled: {
|
|
186
170
|
color: offBlack32$4,
|
|
187
171
|
cursor: "default"
|
|
@@ -193,14 +177,6 @@ const {
|
|
|
193
177
|
offBlack32: offBlack32$3,
|
|
194
178
|
white: white$3
|
|
195
179
|
} = Color;
|
|
196
|
-
/**
|
|
197
|
-
* Props describing the state of the OptionItem, shared by the checkbox
|
|
198
|
-
* component,
|
|
199
|
-
*/
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* The check component used by OptionItem.
|
|
203
|
-
*/
|
|
204
180
|
function Check(props) {
|
|
205
181
|
const {
|
|
206
182
|
disabled,
|
|
@@ -209,16 +185,15 @@ function Check(props) {
|
|
|
209
185
|
hovered,
|
|
210
186
|
focused
|
|
211
187
|
} = props;
|
|
212
|
-
return
|
|
188
|
+
return React.createElement(Icon, {
|
|
213
189
|
icon: icons.check,
|
|
214
190
|
size: "small",
|
|
215
191
|
color: disabled ? offBlack32$3 : pressed || hovered || focused ? white$3 : offBlack$2,
|
|
216
|
-
style: [styles$
|
|
192
|
+
style: [styles$7.bounds, !selected && styles$7.hide]
|
|
217
193
|
});
|
|
218
194
|
}
|
|
219
|
-
const styles$
|
|
195
|
+
const styles$7 = StyleSheet.create({
|
|
220
196
|
bounds: {
|
|
221
|
-
// Semantically, this are the constants for a small-sized icon
|
|
222
197
|
minHeight: 16,
|
|
223
198
|
minWidth: 16
|
|
224
199
|
},
|
|
@@ -227,10 +202,6 @@ const styles$8 = StyleSheet.create({
|
|
|
227
202
|
}
|
|
228
203
|
});
|
|
229
204
|
|
|
230
|
-
// NOTE(sophie): This is a smaller check specifically for use in checkboxes.
|
|
231
|
-
// Please don't copy it automatically and check with designers before using.
|
|
232
|
-
// If the intended icon is a check without a checkbox, you should be using
|
|
233
|
-
// icons.check from the Wonder Blocks Icon package.
|
|
234
205
|
const checkboxCheck = {
|
|
235
206
|
small: "M11.263 4.324a1 1 0 1 1 1.474 1.352l-5.5 6a1 1 0 0 1-1.505-.036l-2.5-3a1 1 0 1 1 1.536-1.28L6.536 9.48l4.727-5.157z"
|
|
236
207
|
};
|
|
@@ -242,14 +213,6 @@ const {
|
|
|
242
213
|
offBlack50,
|
|
243
214
|
offWhite
|
|
244
215
|
} = Color;
|
|
245
|
-
/**
|
|
246
|
-
* Props describing the state of the OptionItem, shared by the check
|
|
247
|
-
* component,
|
|
248
|
-
*/
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* The checkbox component used by OptionItem.
|
|
252
|
-
*/
|
|
253
216
|
function Checkbox(props) {
|
|
254
217
|
const {
|
|
255
218
|
disabled,
|
|
@@ -262,20 +225,19 @@ function Checkbox(props) {
|
|
|
262
225
|
const clickInteraction = pressed || hovered || focused;
|
|
263
226
|
const bgColor = disabled ? offWhite : selected && !clickInteraction ? blue$2 : white$2;
|
|
264
227
|
const checkColor = disabled ? offBlack32$2 : clickInteraction ? pressed ? activeBlue : blue$2 : white$2;
|
|
265
|
-
return
|
|
266
|
-
style: [styles$
|
|
228
|
+
return React.createElement(View, {
|
|
229
|
+
style: [styles$6.checkbox, (clickInteraction || selected && !disabled) && styles$6.noBorder, disabled && styles$6.disabledCheckbox, {
|
|
267
230
|
backgroundColor: bgColor
|
|
268
231
|
}]
|
|
269
|
-
}, selected &&
|
|
232
|
+
}, selected && React.createElement(Icon, {
|
|
270
233
|
icon: checkboxCheck,
|
|
271
234
|
size: "small",
|
|
272
235
|
color: checkColor,
|
|
273
|
-
style: [disabled && selected && styles$
|
|
236
|
+
style: [disabled && selected && styles$6.disabledCheckFormatting]
|
|
274
237
|
}));
|
|
275
238
|
}
|
|
276
|
-
const styles$
|
|
239
|
+
const styles$6 = StyleSheet.create({
|
|
277
240
|
checkbox: {
|
|
278
|
-
// Semantically, this are the constants for a small-sized icon
|
|
279
241
|
minHeight: 16,
|
|
280
242
|
minWidth: 16,
|
|
281
243
|
borderRadius: 3,
|
|
@@ -290,8 +252,6 @@ const styles$7 = StyleSheet.create({
|
|
|
290
252
|
borderColor: offBlack16$1,
|
|
291
253
|
backgroundColor: offWhite
|
|
292
254
|
},
|
|
293
|
-
// The border of 1px on the selected, disabled checkbox pushes the check out
|
|
294
|
-
// of place. Move it back.
|
|
295
255
|
disabledCheckFormatting: {
|
|
296
256
|
position: "absolute",
|
|
297
257
|
top: -1,
|
|
@@ -300,12 +260,6 @@ const styles$7 = StyleSheet.create({
|
|
|
300
260
|
});
|
|
301
261
|
|
|
302
262
|
const _excluded$5 = ["disabled", "label", "role", "selected", "testId", "style", "value", "onClick", "onToggle", "variant"];
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* For option items that can be selected in a dropdown, selection denoted either
|
|
306
|
-
* with a check ✔️ or a checkbox ☑️. Use as children in SingleSelect or
|
|
307
|
-
* MultiSelect.
|
|
308
|
-
*/
|
|
309
263
|
class OptionItem extends React.Component {
|
|
310
264
|
constructor(...args) {
|
|
311
265
|
super(...args);
|
|
@@ -350,7 +304,7 @@ class OptionItem extends React.Component {
|
|
|
350
304
|
|
|
351
305
|
const ClickableBehavior = getClickableBehavior();
|
|
352
306
|
const CheckComponent = this.getCheckComponent();
|
|
353
|
-
return
|
|
307
|
+
return React.createElement(ClickableBehavior, {
|
|
354
308
|
disabled: disabled,
|
|
355
309
|
onClick: this.handleClick,
|
|
356
310
|
role: role
|
|
@@ -360,21 +314,20 @@ class OptionItem extends React.Component {
|
|
|
360
314
|
hovered,
|
|
361
315
|
focused
|
|
362
316
|
} = state;
|
|
363
|
-
const defaultStyle = [styles$
|
|
364
|
-
|
|
365
|
-
return /*#__PURE__*/React.createElement(View, _extends({}, sharedProps, {
|
|
317
|
+
const defaultStyle = [styles$5.itemContainer, pressed ? styles$5.active : (hovered || focused) && styles$5.focus, disabled && styles$5.disabled, style];
|
|
318
|
+
return React.createElement(View, _extends({}, sharedProps, {
|
|
366
319
|
testId: testId,
|
|
367
320
|
style: defaultStyle,
|
|
368
321
|
"aria-selected": selected ? "true" : "false",
|
|
369
322
|
role: role
|
|
370
|
-
}, childrenProps),
|
|
323
|
+
}, childrenProps), React.createElement(CheckComponent, {
|
|
371
324
|
disabled: disabled,
|
|
372
325
|
selected: selected,
|
|
373
326
|
pressed: pressed,
|
|
374
327
|
hovered: hovered,
|
|
375
328
|
focused: focused
|
|
376
|
-
}),
|
|
377
|
-
style: styles$
|
|
329
|
+
}), React.createElement(LabelMedium, {
|
|
330
|
+
style: styles$5.label
|
|
378
331
|
}, label));
|
|
379
332
|
});
|
|
380
333
|
}
|
|
@@ -393,7 +346,7 @@ const {
|
|
|
393
346
|
offBlack: offBlack$1,
|
|
394
347
|
offBlack32: offBlack32$1
|
|
395
348
|
} = Color;
|
|
396
|
-
const styles$
|
|
349
|
+
const styles$5 = StyleSheet.create({
|
|
397
350
|
itemContainer: {
|
|
398
351
|
flexDirection: "row",
|
|
399
352
|
background: white$1,
|
|
@@ -424,7 +377,6 @@ const styles$6 = StyleSheet.create({
|
|
|
424
377
|
whiteSpace: "nowrap",
|
|
425
378
|
userSelect: "none",
|
|
426
379
|
marginLeft: Spacing.xSmall_8,
|
|
427
|
-
// added to truncate strings that are longer than expected
|
|
428
380
|
overflow: "hidden",
|
|
429
381
|
textOverflow: "ellipsis"
|
|
430
382
|
},
|
|
@@ -433,30 +385,21 @@ const styles$6 = StyleSheet.create({
|
|
|
433
385
|
}
|
|
434
386
|
});
|
|
435
387
|
|
|
436
|
-
// Separator item in a dropdown, used to denote a semantic break.
|
|
437
|
-
|
|
438
|
-
/**
|
|
439
|
-
* A separator used in a dropdown menu.
|
|
440
|
-
*/
|
|
441
388
|
class SeparatorItem extends React.Component {
|
|
442
389
|
static isClassOf(instance) {
|
|
443
390
|
return instance && instance.type && instance.type.__IS_SEPARATOR_ITEM__;
|
|
444
391
|
}
|
|
445
392
|
|
|
446
393
|
render() {
|
|
447
|
-
return (
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
style: [styles$5.separator, this.props.style],
|
|
452
|
-
"aria-hidden": "true"
|
|
453
|
-
})
|
|
454
|
-
);
|
|
394
|
+
return React.createElement(View, {
|
|
395
|
+
style: [styles$4.separator, this.props.style],
|
|
396
|
+
"aria-hidden": "true"
|
|
397
|
+
});
|
|
455
398
|
}
|
|
456
399
|
|
|
457
400
|
}
|
|
458
401
|
SeparatorItem.__IS_SEPARATOR_ITEM__ = true;
|
|
459
|
-
const styles$
|
|
402
|
+
const styles$4 = StyleSheet.create({
|
|
460
403
|
separator: {
|
|
461
404
|
boxShadow: `0 -1px ${Color.offBlack16}`,
|
|
462
405
|
height: 1,
|
|
@@ -486,23 +429,18 @@ class DropdownOpener extends React.Component {
|
|
|
486
429
|
}));
|
|
487
430
|
const childrenProps = renderedChildren.props;
|
|
488
431
|
const childrenTestId = this.getTestIdFromProps(childrenProps);
|
|
489
|
-
return
|
|
432
|
+
return React.cloneElement(renderedChildren, _extends({}, clickableChildrenProps, {
|
|
490
433
|
disabled,
|
|
491
434
|
onClick: childrenProps.onClick ? e => {
|
|
492
|
-
// This is done to avoid overriding a
|
|
493
|
-
// custom onClick handler inside the
|
|
494
|
-
// children node
|
|
495
435
|
childrenProps.onClick(e);
|
|
496
436
|
clickableChildrenProps.onClick(e);
|
|
497
437
|
} : clickableChildrenProps.onClick,
|
|
498
|
-
// try to get the testId from the child element
|
|
499
|
-
// If it's not set, try to fallback to the parent's testId
|
|
500
438
|
"data-test-id": childrenTestId || testId
|
|
501
439
|
}));
|
|
502
440
|
}
|
|
503
441
|
|
|
504
442
|
render() {
|
|
505
|
-
return
|
|
443
|
+
return React.createElement(ClickableBehavior, {
|
|
506
444
|
onClick: this.props.onClick,
|
|
507
445
|
disabled: this.props.disabled
|
|
508
446
|
}, (eventState, handlers) => this.renderAnchorChildren(eventState, handlers));
|
|
@@ -514,11 +452,6 @@ DropdownOpener.defaultProps = {
|
|
|
514
452
|
disabled: false
|
|
515
453
|
};
|
|
516
454
|
|
|
517
|
-
/**
|
|
518
|
-
* A virtualized list item - It's created by decorating the DropdownItem
|
|
519
|
-
* (ActionItem, OptionItem, SeparatorItem) with custom styles to let
|
|
520
|
-
* react-window make its own calculations.
|
|
521
|
-
*/
|
|
522
455
|
class DropdownVirtualizedItem extends React.Component {
|
|
523
456
|
render() {
|
|
524
457
|
const {
|
|
@@ -529,9 +462,7 @@ class DropdownVirtualizedItem extends React.Component {
|
|
|
529
462
|
const item = data[index];
|
|
530
463
|
|
|
531
464
|
if (SeparatorItem.isClassOf(item.component)) {
|
|
532
|
-
|
|
533
|
-
// position
|
|
534
|
-
return /*#__PURE__*/React.cloneElement(item.component, {
|
|
465
|
+
return React.cloneElement(item.component, {
|
|
535
466
|
style
|
|
536
467
|
});
|
|
537
468
|
} else {
|
|
@@ -542,7 +473,7 @@ class DropdownVirtualizedItem extends React.Component {
|
|
|
542
473
|
role,
|
|
543
474
|
ref
|
|
544
475
|
} = item;
|
|
545
|
-
return
|
|
476
|
+
return React.cloneElement(component, _extends({
|
|
546
477
|
style
|
|
547
478
|
}, populatedProps, {
|
|
548
479
|
key: index,
|
|
@@ -556,112 +487,30 @@ class DropdownVirtualizedItem extends React.Component {
|
|
|
556
487
|
}
|
|
557
488
|
|
|
558
489
|
class SearchTextInput extends React.Component {
|
|
559
|
-
constructor(...args) {
|
|
560
|
-
super(...args);
|
|
561
|
-
this.state = {
|
|
562
|
-
focused: false,
|
|
563
|
-
labels: _extends({
|
|
564
|
-
clearSearch: defaultLabels.clearSearch,
|
|
565
|
-
filter: defaultLabels.filter
|
|
566
|
-
}, this.props.labels)
|
|
567
|
-
};
|
|
568
|
-
|
|
569
|
-
this.handleChange = e => {
|
|
570
|
-
e.preventDefault();
|
|
571
|
-
this.props.onChange(e.target.value);
|
|
572
|
-
};
|
|
573
|
-
|
|
574
|
-
this.handleDismiss = () => {
|
|
575
|
-
const {
|
|
576
|
-
onClick,
|
|
577
|
-
onChange
|
|
578
|
-
} = this.props; // Empty the search text and focus the SearchTextInput
|
|
579
|
-
|
|
580
|
-
onChange("");
|
|
581
|
-
|
|
582
|
-
if (onClick) {
|
|
583
|
-
onClick();
|
|
584
|
-
}
|
|
585
|
-
};
|
|
586
|
-
|
|
587
|
-
this.handleBlur = e => {
|
|
588
|
-
this.setState({
|
|
589
|
-
focused: false
|
|
590
|
-
});
|
|
591
|
-
};
|
|
592
|
-
|
|
593
|
-
this.handleFocus = e => {
|
|
594
|
-
this.setState({
|
|
595
|
-
focused: true
|
|
596
|
-
});
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
|
|
600
490
|
static isClassOf(instance) {
|
|
601
491
|
return instance && instance.type && instance.type.__IS_SEARCH_TEXT_INPUT__;
|
|
602
492
|
}
|
|
603
493
|
|
|
604
|
-
componentDidUpdate(prevProps) {
|
|
605
|
-
if (this.props.labels !== prevProps.labels) {
|
|
606
|
-
// eslint-disable-next-line react/no-did-update-set-state
|
|
607
|
-
this.setState({
|
|
608
|
-
labels: _extends({}, this.state.labels, this.props.labels)
|
|
609
|
-
});
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
maybeRenderDismissIconButton() {
|
|
614
|
-
const {
|
|
615
|
-
searchText
|
|
616
|
-
} = this.props;
|
|
617
|
-
const {
|
|
618
|
-
clearSearch
|
|
619
|
-
} = this.state.labels;
|
|
620
|
-
|
|
621
|
-
if (searchText.length > 0) {
|
|
622
|
-
return /*#__PURE__*/React.createElement(IconButton, {
|
|
623
|
-
icon: icons.dismiss,
|
|
624
|
-
kind: "tertiary",
|
|
625
|
-
onClick: this.handleDismiss,
|
|
626
|
-
style: styles$4.dismissIcon,
|
|
627
|
-
"aria-label": clearSearch
|
|
628
|
-
});
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
return null;
|
|
632
|
-
}
|
|
633
|
-
|
|
634
494
|
render() {
|
|
635
495
|
const {
|
|
496
|
+
labels,
|
|
497
|
+
onChange,
|
|
636
498
|
onClick,
|
|
637
499
|
itemRef,
|
|
638
500
|
searchText,
|
|
639
501
|
style,
|
|
640
502
|
testId
|
|
641
503
|
} = this.props;
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
return /*#__PURE__*/React.createElement(View, {
|
|
504
|
+
return React.createElement(SearchField, {
|
|
505
|
+
clearAriaLabel: labels.clearSearch,
|
|
506
|
+
onChange: onChange,
|
|
646
507
|
onClick: onClick,
|
|
647
|
-
|
|
648
|
-
}, /*#__PURE__*/React.createElement(Icon, {
|
|
649
|
-
icon: icons.search,
|
|
650
|
-
size: "medium",
|
|
651
|
-
color: Color.offBlack64,
|
|
652
|
-
style: styles$4.searchIcon,
|
|
653
|
-
"aria-hidden": "true"
|
|
654
|
-
}), /*#__PURE__*/React.createElement("input", {
|
|
655
|
-
type: "text",
|
|
656
|
-
onChange: this.handleChange,
|
|
657
|
-
onFocus: this.handleFocus,
|
|
658
|
-
onBlur: this.handleBlur,
|
|
508
|
+
placeholder: labels.filter,
|
|
659
509
|
ref: itemRef,
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
}), this.maybeRenderDismissIconButton());
|
|
510
|
+
style: style,
|
|
511
|
+
testId: testId,
|
|
512
|
+
value: searchText
|
|
513
|
+
});
|
|
665
514
|
}
|
|
666
515
|
|
|
667
516
|
}
|
|
@@ -672,89 +521,54 @@ SearchTextInput.defaultProps = {
|
|
|
672
521
|
}
|
|
673
522
|
};
|
|
674
523
|
SearchTextInput.__IS_SEARCH_TEXT_INPUT__ = true;
|
|
675
|
-
const styles$4 = StyleSheet.create({
|
|
676
|
-
inputContainer: {
|
|
677
|
-
flexDirection: "row",
|
|
678
|
-
border: `1px solid ${Color.offBlack16}`,
|
|
679
|
-
borderRadius: Spacing.xxxSmall_4,
|
|
680
|
-
alignItems: "center",
|
|
681
|
-
// The height of the text input is 40 in design spec and we need to
|
|
682
|
-
// specify the height as well as minHeight to make sure the search text
|
|
683
|
-
// input takes enough height to render. (otherwise, it will get
|
|
684
|
-
// squashed)
|
|
685
|
-
height: DROPDOWN_ITEM_HEIGHT,
|
|
686
|
-
minHeight: DROPDOWN_ITEM_HEIGHT
|
|
687
|
-
},
|
|
688
|
-
focused: {
|
|
689
|
-
border: `1px solid ${Color.blue}`
|
|
690
|
-
},
|
|
691
|
-
searchIcon: {
|
|
692
|
-
marginLeft: Spacing.xSmall_8,
|
|
693
|
-
marginRight: Spacing.xSmall_8
|
|
694
|
-
},
|
|
695
|
-
dismissIcon: {
|
|
696
|
-
margin: 0,
|
|
697
|
-
":hover": {
|
|
698
|
-
border: "none"
|
|
699
|
-
}
|
|
700
|
-
},
|
|
701
|
-
inputStyleReset: {
|
|
702
|
-
display: "flex",
|
|
703
|
-
flex: 1,
|
|
704
|
-
background: "inherit",
|
|
705
|
-
border: "none",
|
|
706
|
-
outline: "none",
|
|
707
|
-
"::placeholder": {
|
|
708
|
-
color: Color.offBlack64
|
|
709
|
-
},
|
|
710
|
-
width: "100%",
|
|
711
|
-
color: "inherit"
|
|
712
|
-
}
|
|
713
|
-
});
|
|
714
524
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
525
|
+
function getDropdownMenuHeight(items, initialHeight = 0) {
|
|
526
|
+
return items.slice(0, MAX_VISIBLE_ITEMS).reduce((sum, item) => {
|
|
527
|
+
if (SeparatorItem.isClassOf(item.component)) {
|
|
528
|
+
return sum + SEPARATOR_ITEM_HEIGHT;
|
|
529
|
+
} else if (SearchTextInput.isClassOf(item.component)) {
|
|
530
|
+
return sum + SEARCH_ITEM_HEIGHT;
|
|
531
|
+
} else {
|
|
532
|
+
return sum + DROPDOWN_ITEM_HEIGHT;
|
|
533
|
+
}
|
|
534
|
+
}, initialHeight);
|
|
535
|
+
}
|
|
536
|
+
function generateDropdownMenuStyles(minWidth, maxHeight) {
|
|
537
|
+
const styles = StyleSheet.create({
|
|
538
|
+
dropdownMenu: {
|
|
539
|
+
minWidth,
|
|
540
|
+
maxHeight
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
return styles.dropdownMenu;
|
|
544
|
+
}
|
|
726
545
|
|
|
727
546
|
class DropdownCoreVirtualized extends React.Component {
|
|
728
|
-
constructor(
|
|
729
|
-
super(
|
|
730
|
-
this.state = {
|
|
731
|
-
height: this.getHeight(),
|
|
732
|
-
width: this.props.width
|
|
733
|
-
};
|
|
547
|
+
constructor(props) {
|
|
548
|
+
super(props);
|
|
734
549
|
|
|
735
550
|
this.getItemSize = index => {
|
|
736
|
-
// get the current item in the list
|
|
737
551
|
const item = this.props.data[index];
|
|
738
552
|
|
|
739
553
|
if (SeparatorItem.isClassOf(item.component)) {
|
|
740
|
-
// this is the separator's height (1px) + vertical margin (8px)
|
|
741
554
|
return SEPARATOR_ITEM_HEIGHT;
|
|
742
555
|
} else if (SearchTextInput.isClassOf(item.component)) {
|
|
743
|
-
// search text input height
|
|
744
556
|
return SEARCH_ITEM_HEIGHT;
|
|
745
557
|
} else {
|
|
746
|
-
// default dropdown item height
|
|
747
558
|
return DROPDOWN_ITEM_HEIGHT;
|
|
748
559
|
}
|
|
749
560
|
};
|
|
561
|
+
|
|
562
|
+
this.state = {
|
|
563
|
+
height: getDropdownMenuHeight(props.data),
|
|
564
|
+
width: props.width
|
|
565
|
+
};
|
|
750
566
|
}
|
|
751
567
|
|
|
752
568
|
componentDidMount() {
|
|
753
569
|
const {
|
|
754
570
|
schedule
|
|
755
|
-
} = this.props;
|
|
756
|
-
// value of the container dimensions.
|
|
757
|
-
|
|
571
|
+
} = this.props;
|
|
758
572
|
schedule.animationFrame(() => {
|
|
759
573
|
this.setWidth();
|
|
760
574
|
});
|
|
@@ -764,27 +578,20 @@ class DropdownCoreVirtualized extends React.Component {
|
|
|
764
578
|
const {
|
|
765
579
|
data,
|
|
766
580
|
listRef
|
|
767
|
-
} = this.props;
|
|
581
|
+
} = this.props;
|
|
768
582
|
|
|
769
583
|
if (prevProps.data.length !== data.length) {
|
|
770
584
|
this.setHeight();
|
|
771
585
|
|
|
772
586
|
if (listRef && listRef.current) {
|
|
773
|
-
// the ref can't associate this instance method
|
|
774
|
-
// $FlowIgnore
|
|
775
587
|
listRef.current.resetAfterIndex(1);
|
|
776
588
|
}
|
|
777
589
|
}
|
|
778
590
|
}
|
|
779
|
-
/**
|
|
780
|
-
* Update container width
|
|
781
|
-
*/
|
|
782
|
-
|
|
783
591
|
|
|
784
592
|
setWidth() {
|
|
785
593
|
const rootNode = ReactDOM.findDOMNode(this);
|
|
786
|
-
const parentNode = rootNode == null ? void 0 : rootNode.parentElement;
|
|
787
|
-
// width to pass it to react-window's List
|
|
594
|
+
const parentNode = rootNode == null ? void 0 : rootNode.parentElement;
|
|
788
595
|
|
|
789
596
|
if (parentNode) {
|
|
790
597
|
const width = parentNode.getBoundingClientRect().width;
|
|
@@ -793,67 +600,27 @@ class DropdownCoreVirtualized extends React.Component {
|
|
|
793
600
|
});
|
|
794
601
|
}
|
|
795
602
|
}
|
|
796
|
-
/**
|
|
797
|
-
* Update container height
|
|
798
|
-
*/
|
|
799
|
-
|
|
800
603
|
|
|
801
604
|
setHeight() {
|
|
802
|
-
|
|
803
|
-
const height = this.getHeight();
|
|
605
|
+
const height = getDropdownMenuHeight(this.props.data);
|
|
804
606
|
this.setState({
|
|
805
607
|
height
|
|
806
608
|
});
|
|
807
609
|
}
|
|
808
|
-
/**
|
|
809
|
-
* The list height that is automatically calculated depending on the
|
|
810
|
-
* component's type of each item (e.g. Separator, Option, Search, etc)
|
|
811
|
-
*/
|
|
812
|
-
|
|
813
610
|
|
|
814
|
-
getHeight() {
|
|
815
|
-
// calculate using the first 10 items on the array as we want to display
|
|
816
|
-
// this number of elements in the visible area
|
|
817
|
-
return this.props.data.slice(0, MAX_VISIBLE_ITEMS).reduce((sum, item) => {
|
|
818
|
-
if (SeparatorItem.isClassOf(item.component)) {
|
|
819
|
-
return sum + SEPARATOR_ITEM_HEIGHT;
|
|
820
|
-
} else if (SearchTextInput.isClassOf(item.component)) {
|
|
821
|
-
// search text input height
|
|
822
|
-
return sum + SEARCH_ITEM_HEIGHT;
|
|
823
|
-
} else {
|
|
824
|
-
return sum + DROPDOWN_ITEM_HEIGHT;
|
|
825
|
-
}
|
|
826
|
-
}, 0);
|
|
827
|
-
}
|
|
828
|
-
/**
|
|
829
|
-
* Calculates item height
|
|
830
|
-
*/
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
/**
|
|
834
|
-
* render non virtualized items to calculate the container max-width that
|
|
835
|
-
* will be used by DropdownCoreVirtualized
|
|
836
|
-
*/
|
|
837
611
|
renderInitialItems() {
|
|
838
612
|
const {
|
|
839
613
|
data
|
|
840
614
|
} = this.props;
|
|
841
|
-
const allComponents = data.map(e => e.component);
|
|
842
|
-
// label length
|
|
843
|
-
|
|
615
|
+
const allComponents = data.map(e => e.component);
|
|
844
616
|
const longestItems = React.Children.toArray(allComponents).filter(Boolean).sort((a, b) => {
|
|
845
|
-
// 2. only sort elements that contain a `label` prop
|
|
846
617
|
if (b.props.label && a.props.label) {
|
|
847
618
|
return b.props.label.length - a.props.label.length;
|
|
848
619
|
}
|
|
849
620
|
|
|
850
621
|
return -1;
|
|
851
|
-
})
|
|
852
|
-
|
|
853
|
-
.slice(0, MAX_VISIBLE_ITEMS); // Append longest items to calculate the container width.
|
|
854
|
-
// We need to hide these sorted elements to avoid any FOUC.
|
|
855
|
-
|
|
856
|
-
return longestItems.map(item => /*#__PURE__*/React.cloneElement(item, {
|
|
622
|
+
}).slice(0, MAX_VISIBLE_ITEMS);
|
|
623
|
+
return longestItems.map(item => React.cloneElement(item, {
|
|
857
624
|
style: {
|
|
858
625
|
visibility: "hidden"
|
|
859
626
|
}
|
|
@@ -869,38 +636,24 @@ class DropdownCoreVirtualized extends React.Component {
|
|
|
869
636
|
height,
|
|
870
637
|
width
|
|
871
638
|
} = this.state;
|
|
872
|
-
return (
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
,
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
style: {
|
|
885
|
-
overflowX: "hidden"
|
|
886
|
-
} // react-window doesn't accept maybe numbers. It wants numbers
|
|
887
|
-
// or strings.
|
|
888
|
-
// $FlowFixMe
|
|
889
|
-
,
|
|
890
|
-
width: width,
|
|
891
|
-
overscanCount: 5,
|
|
892
|
-
ref: listRef
|
|
893
|
-
}, DropdownVirtualizedItem)
|
|
894
|
-
);
|
|
639
|
+
return React.createElement(VariableSizeList, {
|
|
640
|
+
height: height,
|
|
641
|
+
itemCount: data.length,
|
|
642
|
+
itemSize: this.getItemSize,
|
|
643
|
+
itemData: data,
|
|
644
|
+
style: {
|
|
645
|
+
overflowX: "hidden"
|
|
646
|
+
},
|
|
647
|
+
width: width,
|
|
648
|
+
overscanCount: 5,
|
|
649
|
+
ref: listRef
|
|
650
|
+
}, DropdownVirtualizedItem);
|
|
895
651
|
}
|
|
896
652
|
|
|
897
653
|
render() {
|
|
898
654
|
if (this.state.width === undefined) {
|
|
899
|
-
// if we don't pass a fixed value, then we need to render
|
|
900
|
-
// non-virtualized items to calculate width
|
|
901
655
|
return this.renderInitialItems();
|
|
902
656
|
} else {
|
|
903
|
-
// width has been provided, then render the virtualized list
|
|
904
657
|
return this.renderVirtualizedList();
|
|
905
658
|
}
|
|
906
659
|
}
|
|
@@ -913,34 +666,23 @@ const modifiers = [{
|
|
|
913
666
|
name: "preventOverflow",
|
|
914
667
|
options: {
|
|
915
668
|
rootBoundary: "viewport",
|
|
916
|
-
// Allows to overlap the popper in case there's no more vertical
|
|
917
|
-
// room in the viewport.
|
|
918
669
|
altAxis: true,
|
|
919
|
-
// Also needed to make sure the Popper will be displayed correctly
|
|
920
|
-
// in different contexts (e.g inside a Modal)
|
|
921
670
|
tether: false
|
|
922
671
|
}
|
|
923
672
|
}];
|
|
924
|
-
|
|
925
|
-
/**
|
|
926
|
-
* A wrapper for PopperJS that renders the children inside a portal.
|
|
927
|
-
*/
|
|
928
673
|
function DropdownPopper({
|
|
929
674
|
children,
|
|
930
675
|
alignment = "left",
|
|
931
676
|
onPopperElement,
|
|
932
677
|
referenceElement
|
|
933
678
|
}) {
|
|
934
|
-
// If we are in a modal, we find where we should be portalling the menu by
|
|
935
|
-
// using the helper function from the modal package on the opener element.
|
|
936
|
-
// If we are not in a modal, we use body as the location to portal to.
|
|
937
679
|
const modalHost = maybeGetPortalMountedModalHostElement(referenceElement) || document.querySelector("body");
|
|
938
680
|
|
|
939
681
|
if (!modalHost) {
|
|
940
682
|
return null;
|
|
941
683
|
}
|
|
942
684
|
|
|
943
|
-
return
|
|
685
|
+
return ReactDOM.createPortal(React.createElement(Popper, {
|
|
944
686
|
innerRef: node => {
|
|
945
687
|
if (node && onPopperElement) {
|
|
946
688
|
onPopperElement(node);
|
|
@@ -958,7 +700,7 @@ function DropdownPopper({
|
|
|
958
700
|
isReferenceHidden
|
|
959
701
|
}) => {
|
|
960
702
|
const shouldHidePopper = !!(hasPopperEscaped || isReferenceHidden);
|
|
961
|
-
return
|
|
703
|
+
return React.createElement("div", {
|
|
962
704
|
ref: ref,
|
|
963
705
|
style: style,
|
|
964
706
|
"data-test-id": "dropdown-popper",
|
|
@@ -967,34 +709,9 @@ function DropdownPopper({
|
|
|
967
709
|
}), modalHost);
|
|
968
710
|
}
|
|
969
711
|
|
|
970
|
-
/**
|
|
971
|
-
* The number of options to apply the virtualized list to.
|
|
972
|
-
*
|
|
973
|
-
* NOTE: The threshold is defined taking into account performance
|
|
974
|
-
* implications (e.g. process input events for users should not be longer
|
|
975
|
-
* than 100ms).
|
|
976
|
-
* @see https://web.dev/rail/?utm_source=devtools#goals-and-guidelines
|
|
977
|
-
*
|
|
978
|
-
* TODO(juan, WB-1263): Improve performance by refactoring this component.
|
|
979
|
-
*/
|
|
980
|
-
|
|
981
712
|
const VIRTUALIZE_THRESHOLD = 125;
|
|
982
713
|
|
|
983
|
-
/**
|
|
984
|
-
* A core dropdown component that takes an opener and children to display as
|
|
985
|
-
* part of the dropdown menu. Renders the dropdown as a portal to avoid clipping
|
|
986
|
-
* in overflow: auto containers.
|
|
987
|
-
*/
|
|
988
714
|
class DropdownCore extends React.Component {
|
|
989
|
-
// Keeps track of the index of the focused item, out of a list of focusable items
|
|
990
|
-
// Keeps track of the index of the focused item in the context of all the
|
|
991
|
-
// items contained by this menu, whether focusable or not, used for figuring
|
|
992
|
-
// out focus correctly when the items have changed in terms of whether
|
|
993
|
-
// they're focusable or not
|
|
994
|
-
// Whether any items have been selected since the menu was opened
|
|
995
|
-
// Keeps a reference of the virtualized list instance
|
|
996
|
-
// Figure out if the same items are focusable. If an item has been added or
|
|
997
|
-
// removed, this method will return false.
|
|
998
715
|
static sameItemsFocusable(prevItems, currentItems) {
|
|
999
716
|
if (prevItems.length !== currentItems.length) {
|
|
1000
717
|
return false;
|
|
@@ -1009,16 +726,13 @@ class DropdownCore extends React.Component {
|
|
|
1009
726
|
return true;
|
|
1010
727
|
}
|
|
1011
728
|
|
|
1012
|
-
// This is here to avoid calling React.createRef on each rerender. Instead,
|
|
1013
|
-
// we create the itemRefs only if it's the first time or if the set of items
|
|
1014
|
-
// that are focusable has changed.
|
|
1015
729
|
static getDerivedStateFromProps(props, state) {
|
|
1016
730
|
if (state.itemRefs.length === 0 && props.open || !DropdownCore.sameItemsFocusable(state.prevItems, props.items)) {
|
|
1017
731
|
const itemRefs = [];
|
|
1018
732
|
|
|
1019
733
|
for (let i = 0; i < props.items.length; i++) {
|
|
1020
734
|
if (props.items[i].focusable) {
|
|
1021
|
-
const ref =
|
|
735
|
+
const ref = React.createRef();
|
|
1022
736
|
itemRefs.push({
|
|
1023
737
|
ref,
|
|
1024
738
|
originalIndex: i
|
|
@@ -1040,7 +754,7 @@ class DropdownCore extends React.Component {
|
|
|
1040
754
|
}
|
|
1041
755
|
|
|
1042
756
|
constructor(props) {
|
|
1043
|
-
super(props);
|
|
757
|
+
super(props);
|
|
1044
758
|
|
|
1045
759
|
this.handleInteract = event => {
|
|
1046
760
|
const {
|
|
@@ -1061,7 +775,7 @@ class DropdownCore extends React.Component {
|
|
|
1061
775
|
open,
|
|
1062
776
|
searchText
|
|
1063
777
|
} = this.props;
|
|
1064
|
-
const keyCode = event.which || event.keyCode;
|
|
778
|
+
const keyCode = event.which || event.keyCode;
|
|
1065
779
|
|
|
1066
780
|
if (!open) {
|
|
1067
781
|
if (keyCode === keyCodes.down) {
|
|
@@ -1071,15 +785,10 @@ class DropdownCore extends React.Component {
|
|
|
1071
785
|
}
|
|
1072
786
|
|
|
1073
787
|
return;
|
|
1074
|
-
}
|
|
1075
|
-
|
|
788
|
+
}
|
|
1076
789
|
|
|
1077
790
|
switch (keyCode) {
|
|
1078
791
|
case keyCodes.tab:
|
|
1079
|
-
// When we show SearchTextInput and that is focused and the
|
|
1080
|
-
// searchText is entered at least one character, dismiss button
|
|
1081
|
-
// is displayed. When user presses tab, we should move focus
|
|
1082
|
-
// to the dismiss button.
|
|
1083
792
|
if (this.hasSearchBox() && this.focusedIndex === 0 && searchText) {
|
|
1084
793
|
return;
|
|
1085
794
|
}
|
|
@@ -1089,12 +798,9 @@ class DropdownCore extends React.Component {
|
|
|
1089
798
|
return;
|
|
1090
799
|
|
|
1091
800
|
case keyCodes.space:
|
|
1092
|
-
// When we display SearchTextInput and the focus is on it,
|
|
1093
|
-
// we should let the user type space.
|
|
1094
801
|
if (this.hasSearchBox() && this.focusedIndex === 0) {
|
|
1095
802
|
return;
|
|
1096
|
-
}
|
|
1097
|
-
|
|
803
|
+
}
|
|
1098
804
|
|
|
1099
805
|
event.preventDefault();
|
|
1100
806
|
return;
|
|
@@ -1120,19 +826,14 @@ class DropdownCore extends React.Component {
|
|
|
1120
826
|
|
|
1121
827
|
switch (keyCode) {
|
|
1122
828
|
case keyCodes.space:
|
|
1123
|
-
// When we display SearchTextInput and the focus is on it,
|
|
1124
|
-
// we should let the user type space.
|
|
1125
829
|
if (this.hasSearchBox() && this.focusedIndex === 0) {
|
|
1126
830
|
return;
|
|
1127
|
-
}
|
|
1128
|
-
|
|
831
|
+
}
|
|
1129
832
|
|
|
1130
833
|
event.preventDefault();
|
|
1131
834
|
return;
|
|
1132
835
|
|
|
1133
836
|
case keyCodes.escape:
|
|
1134
|
-
// Close only the dropdown, not other elements that are
|
|
1135
|
-
// listening for an escape press
|
|
1136
837
|
if (open) {
|
|
1137
838
|
event.stopPropagation();
|
|
1138
839
|
this.restoreTabOrder();
|
|
@@ -1144,19 +845,15 @@ class DropdownCore extends React.Component {
|
|
|
1144
845
|
};
|
|
1145
846
|
|
|
1146
847
|
this.handleClickFocus = index => {
|
|
1147
|
-
// Turn itemsClicked on so pressing up or down would focus the
|
|
1148
|
-
// appropriate item in handleKeyDown
|
|
1149
848
|
this.itemsClicked = true;
|
|
1150
849
|
this.focusedIndex = index;
|
|
1151
850
|
this.focusedOriginalIndex = this.state.itemRefs[this.focusedIndex].originalIndex;
|
|
1152
851
|
};
|
|
1153
852
|
|
|
1154
853
|
this.handleDropdownMouseUp = event => {
|
|
1155
|
-
// $FlowIgnore[method-unbinding]
|
|
1156
854
|
if (event.nativeEvent.stopImmediatePropagation) {
|
|
1157
855
|
event.nativeEvent.stopImmediatePropagation();
|
|
1158
856
|
} else {
|
|
1159
|
-
// Workaround for jsdom
|
|
1160
857
|
event.stopPropagation();
|
|
1161
858
|
}
|
|
1162
859
|
};
|
|
@@ -1182,7 +879,7 @@ class DropdownCore extends React.Component {
|
|
|
1182
879
|
noResults: defaultLabels.noResults
|
|
1183
880
|
}, props.labels)
|
|
1184
881
|
};
|
|
1185
|
-
this.virtualizedListRef =
|
|
882
|
+
this.virtualizedListRef = React.createRef();
|
|
1186
883
|
}
|
|
1187
884
|
|
|
1188
885
|
componentDidMount() {
|
|
@@ -1198,33 +895,19 @@ class DropdownCore extends React.Component {
|
|
|
1198
895
|
if (prevProps.open !== open) {
|
|
1199
896
|
this.updateEventListeners();
|
|
1200
897
|
this.initialFocusItem();
|
|
1201
|
-
}
|
|
1202
|
-
// to recalculate the focus somehow.
|
|
1203
|
-
else if (open) {
|
|
898
|
+
} else if (open) {
|
|
1204
899
|
const {
|
|
1205
900
|
itemRefs,
|
|
1206
901
|
sameItemsFocusable
|
|
1207
|
-
} = this.state;
|
|
1208
|
-
// each index and seeing if the {focusable} property is the same.
|
|
1209
|
-
// Very rarely do the set of focusable items change if the menu
|
|
1210
|
-
// hasn't been re-opened. This is for cases like a {Select all}
|
|
1211
|
-
// option that becomes disabled iff all the options are selected.
|
|
902
|
+
} = this.state;
|
|
1212
903
|
|
|
1213
904
|
if (sameItemsFocusable) {
|
|
1214
905
|
return;
|
|
1215
906
|
} else {
|
|
1216
|
-
// If the set of items that was focusabled changed, it's very
|
|
1217
|
-
// likely that the previously focused item no longer has the
|
|
1218
|
-
// same index relative to the list of focusable items. Instead,
|
|
1219
|
-
// use the focusedOriginalIndex to find the new index of the
|
|
1220
|
-
// last item that was focused before this change
|
|
1221
907
|
const newFocusableIndex = itemRefs.findIndex(ref => ref.originalIndex === this.focusedOriginalIndex);
|
|
1222
908
|
|
|
1223
909
|
if (newFocusableIndex === -1) {
|
|
1224
|
-
|
|
1225
|
-
// the first item that IS focusable
|
|
1226
|
-
this.focusedIndex = 0; // Reset the knowlege that things had been clicked
|
|
1227
|
-
|
|
910
|
+
this.focusedIndex = 0;
|
|
1228
911
|
this.itemsClicked = false;
|
|
1229
912
|
this.scheduleToFocusCurrentItem();
|
|
1230
913
|
} else {
|
|
@@ -1233,7 +916,6 @@ class DropdownCore extends React.Component {
|
|
|
1233
916
|
}
|
|
1234
917
|
|
|
1235
918
|
if (this.props.labels !== prevProps.labels) {
|
|
1236
|
-
// eslint-disable-next-line react/no-did-update-set-state
|
|
1237
919
|
this.setState({
|
|
1238
920
|
labels: _extends({}, this.state.labels, this.props.labels)
|
|
1239
921
|
});
|
|
@@ -1247,21 +929,14 @@ class DropdownCore extends React.Component {
|
|
|
1247
929
|
|
|
1248
930
|
hasSearchBox() {
|
|
1249
931
|
return !!this.props.onSearchTextChanged && typeof this.props.searchText === "string";
|
|
1250
|
-
}
|
|
1251
|
-
// via the props
|
|
1252
|
-
|
|
932
|
+
}
|
|
1253
933
|
|
|
1254
934
|
resetFocusedIndex() {
|
|
1255
935
|
const {
|
|
1256
936
|
initialFocusedIndex
|
|
1257
|
-
} = this.props;
|
|
1258
|
-
// default to the first item
|
|
937
|
+
} = this.props;
|
|
1259
938
|
|
|
1260
939
|
if (initialFocusedIndex) {
|
|
1261
|
-
// If we have a search box visible, then our focus
|
|
1262
|
-
// index is going to be offset by 1, since the orginal
|
|
1263
|
-
// index doesn't account for the search box's
|
|
1264
|
-
// existence.
|
|
1265
940
|
if (this.hasSearchBox()) {
|
|
1266
941
|
this.focusedIndex = initialFocusedIndex + 1;
|
|
1267
942
|
} else {
|
|
@@ -1270,9 +945,7 @@ class DropdownCore extends React.Component {
|
|
|
1270
945
|
} else {
|
|
1271
946
|
this.focusedIndex = 0;
|
|
1272
947
|
}
|
|
1273
|
-
}
|
|
1274
|
-
// to closed or vice versa
|
|
1275
|
-
|
|
948
|
+
}
|
|
1276
949
|
|
|
1277
950
|
initialFocusItem() {
|
|
1278
951
|
const {
|
|
@@ -1307,10 +980,8 @@ class DropdownCore extends React.Component {
|
|
|
1307
980
|
|
|
1308
981
|
scheduleToFocusCurrentItem() {
|
|
1309
982
|
if (this.shouldVirtualizeList()) {
|
|
1310
|
-
// wait for windowed items to be recalculated
|
|
1311
983
|
this.props.schedule.animationFrame(() => this.focusCurrentItem());
|
|
1312
984
|
} else {
|
|
1313
|
-
// immediately focus the current item if we're not virtualizing
|
|
1314
985
|
this.focusCurrentItem();
|
|
1315
986
|
}
|
|
1316
987
|
}
|
|
@@ -1319,21 +990,14 @@ class DropdownCore extends React.Component {
|
|
|
1319
990
|
const fousedItemRef = this.state.itemRefs[this.focusedIndex];
|
|
1320
991
|
|
|
1321
992
|
if (fousedItemRef) {
|
|
1322
|
-
// force react-window to scroll to ensure the focused item is visible
|
|
1323
993
|
if (this.virtualizedListRef.current) {
|
|
1324
|
-
// Our focused index does not include disabled items, but the
|
|
1325
|
-
// react-window index system does include the disabled items
|
|
1326
|
-
// in the count. So we need to use "originalIndex", which
|
|
1327
|
-
// does account for disabled items.
|
|
1328
994
|
this.virtualizedListRef.current.scrollToItem(fousedItemRef.originalIndex);
|
|
1329
995
|
}
|
|
1330
996
|
|
|
1331
997
|
const node = ReactDOM.findDOMNode(fousedItemRef.ref.current);
|
|
1332
998
|
|
|
1333
999
|
if (node) {
|
|
1334
|
-
node.focus();
|
|
1335
|
-
// To be used if the set of focusable items in the menu changes
|
|
1336
|
-
|
|
1000
|
+
node.focus();
|
|
1337
1001
|
this.focusedOriginalIndex = fousedItemRef.originalIndex;
|
|
1338
1002
|
}
|
|
1339
1003
|
}
|
|
@@ -1360,10 +1024,6 @@ class DropdownCore extends React.Component {
|
|
|
1360
1024
|
}
|
|
1361
1025
|
|
|
1362
1026
|
restoreTabOrder() {
|
|
1363
|
-
// NOTE: Because the dropdown is portalled out of its natural
|
|
1364
|
-
// position in the DOM, we need to manually return focus to the
|
|
1365
|
-
// opener element before we let the natural propagation of tab
|
|
1366
|
-
// shift the focus to the next element in the tab order.
|
|
1367
1027
|
if (this.props.openerElement) {
|
|
1368
1028
|
this.props.openerElement.focus();
|
|
1369
1029
|
}
|
|
@@ -1396,12 +1056,11 @@ class DropdownCore extends React.Component {
|
|
|
1396
1056
|
}
|
|
1397
1057
|
} = this.props;
|
|
1398
1058
|
const showSearchTextInput = !!onSearchTextChanged && typeof searchText === "string";
|
|
1399
|
-
const includeSearchCount = showSearchTextInput ? 1 : 0;
|
|
1400
|
-
|
|
1059
|
+
const includeSearchCount = showSearchTextInput ? 1 : 0;
|
|
1401
1060
|
const numResults = items.length - includeSearchCount;
|
|
1402
1061
|
|
|
1403
1062
|
if (numResults === 0) {
|
|
1404
|
-
return
|
|
1063
|
+
return React.createElement(LabelMedium, {
|
|
1405
1064
|
style: styles$3.noResult,
|
|
1406
1065
|
testId: "dropdown-core-no-results"
|
|
1407
1066
|
}, noResults);
|
|
@@ -1409,29 +1068,14 @@ class DropdownCore extends React.Component {
|
|
|
1409
1068
|
|
|
1410
1069
|
return null;
|
|
1411
1070
|
}
|
|
1412
|
-
/**
|
|
1413
|
-
* Handles click events for each item in the dropdown.
|
|
1414
|
-
*/
|
|
1415
1071
|
|
|
1416
|
-
|
|
1417
|
-
/**
|
|
1418
|
-
* Determines which rendering strategy we are going to apply to the options
|
|
1419
|
-
* list.
|
|
1420
|
-
*/
|
|
1421
1072
|
shouldVirtualizeList() {
|
|
1422
|
-
// Verify if the list is long enough to be virtualized (passes the
|
|
1423
|
-
// threshold).
|
|
1424
1073
|
return this.props.items.length > VIRTUALIZE_THRESHOLD;
|
|
1425
1074
|
}
|
|
1426
|
-
/**
|
|
1427
|
-
* Renders the non-virtualized list of items.
|
|
1428
|
-
*/
|
|
1429
|
-
|
|
1430
1075
|
|
|
1431
1076
|
renderList() {
|
|
1432
1077
|
let focusCounter = 0;
|
|
1433
|
-
const itemRole = this.getItemRole();
|
|
1434
|
-
|
|
1078
|
+
const itemRole = this.getItemRole();
|
|
1435
1079
|
return this.props.items.map((item, index) => {
|
|
1436
1080
|
if (SeparatorItem.isClassOf(item.component)) {
|
|
1437
1081
|
return item.component;
|
|
@@ -1447,46 +1091,31 @@ class DropdownCore extends React.Component {
|
|
|
1447
1091
|
focusCounter += 1;
|
|
1448
1092
|
}
|
|
1449
1093
|
|
|
1450
|
-
const focusIndex = focusCounter - 1;
|
|
1451
|
-
|
|
1452
|
-
const currentRef = this.state.itemRefs[focusIndex] ? this.state.itemRefs[focusIndex].ref : null; // Render the SearchField component.
|
|
1094
|
+
const focusIndex = focusCounter - 1;
|
|
1095
|
+
const currentRef = this.state.itemRefs[focusIndex] ? this.state.itemRefs[focusIndex].ref : null;
|
|
1453
1096
|
|
|
1454
1097
|
if (SearchTextInput.isClassOf(component)) {
|
|
1455
|
-
return
|
|
1098
|
+
return React.cloneElement(component, _extends({}, populatedProps, {
|
|
1456
1099
|
key: "search-text-input",
|
|
1457
|
-
// pass the current ref down to the input element
|
|
1458
1100
|
itemRef: currentRef,
|
|
1459
|
-
// override to avoid losing focus when pressing a key
|
|
1460
1101
|
onClick: () => {
|
|
1461
1102
|
this.handleClickFocus(0);
|
|
1462
1103
|
this.focusCurrentItem();
|
|
1463
1104
|
},
|
|
1464
|
-
// apply custom styles
|
|
1465
1105
|
style: searchInputStyle
|
|
1466
1106
|
}));
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1107
|
+
}
|
|
1469
1108
|
|
|
1470
|
-
return
|
|
1109
|
+
return React.cloneElement(component, _extends({}, populatedProps, {
|
|
1471
1110
|
key: index,
|
|
1472
1111
|
onClick: () => {
|
|
1473
1112
|
this.handleItemClick(focusIndex, item);
|
|
1474
1113
|
},
|
|
1475
|
-
// Only pass the ref if the item is focusable.
|
|
1476
1114
|
ref: focusable ? currentRef : null,
|
|
1477
1115
|
role: itemRole
|
|
1478
1116
|
}));
|
|
1479
1117
|
});
|
|
1480
1118
|
}
|
|
1481
|
-
/**
|
|
1482
|
-
* Process the items and wrap them into an array that react-window can
|
|
1483
|
-
* interpret.
|
|
1484
|
-
*
|
|
1485
|
-
* NOTE: The main difference with the collection in renderList() is that we
|
|
1486
|
-
* massage the items to be able to clone them later in
|
|
1487
|
-
* DropdownVirtualizedItem, where as renderList() clones the items directly.
|
|
1488
|
-
*/
|
|
1489
|
-
|
|
1490
1119
|
|
|
1491
1120
|
parseVirtualizedItems() {
|
|
1492
1121
|
let focusCounter = 0;
|
|
@@ -1500,14 +1129,12 @@ class DropdownCore extends React.Component {
|
|
|
1500
1129
|
|
|
1501
1130
|
if (SearchTextInput.isClassOf(item.component)) {
|
|
1502
1131
|
return _extends({}, item, {
|
|
1503
|
-
// override to avoid losing focus when pressing a key
|
|
1504
1132
|
onClick: () => {
|
|
1505
1133
|
this.handleClickFocus(0);
|
|
1506
1134
|
this.focusCurrentItem();
|
|
1507
1135
|
},
|
|
1508
1136
|
populatedProps: {
|
|
1509
1137
|
style: searchInputStyle,
|
|
1510
|
-
// pass the current ref down to the input element
|
|
1511
1138
|
itemRef: this.state.itemRefs[focusIndex] ? this.state.itemRefs[focusIndex].ref : null
|
|
1512
1139
|
}
|
|
1513
1140
|
});
|
|
@@ -1522,15 +1149,10 @@ class DropdownCore extends React.Component {
|
|
|
1522
1149
|
});
|
|
1523
1150
|
});
|
|
1524
1151
|
}
|
|
1525
|
-
/**
|
|
1526
|
-
* Render the items using a virtualized list
|
|
1527
|
-
*/
|
|
1528
|
-
|
|
1529
1152
|
|
|
1530
1153
|
renderVirtualizedList() {
|
|
1531
|
-
// preprocess items data to pass it to the renderer
|
|
1532
1154
|
const virtualizedItems = this.parseVirtualizedItems();
|
|
1533
|
-
return
|
|
1155
|
+
return React.createElement(DropdownCoreVirtualized$1, {
|
|
1534
1156
|
data: virtualizedItems,
|
|
1535
1157
|
listRef: this.virtualizedListRef
|
|
1536
1158
|
});
|
|
@@ -1541,19 +1163,15 @@ class DropdownCore extends React.Component {
|
|
|
1541
1163
|
dropdownStyle,
|
|
1542
1164
|
light,
|
|
1543
1165
|
openerElement
|
|
1544
|
-
} = this.props;
|
|
1545
|
-
// It's only used if the element exists in the DOM
|
|
1546
|
-
|
|
1166
|
+
} = this.props;
|
|
1547
1167
|
const openerStyle = openerElement && window.getComputedStyle(openerElement);
|
|
1548
1168
|
const minDropdownWidth = openerStyle ? openerStyle.getPropertyValue("width") : 0;
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
, {
|
|
1169
|
+
const initialHeight = 12;
|
|
1170
|
+
const maxDropdownHeight = getDropdownMenuHeight(this.props.items, initialHeight);
|
|
1171
|
+
return React.createElement(View, {
|
|
1552
1172
|
onMouseUp: this.handleDropdownMouseUp,
|
|
1553
1173
|
role: this.props.role,
|
|
1554
|
-
style: [styles$3.dropdown, light && styles$3.light, isReferenceHidden && styles$3.hidden,
|
|
1555
|
-
minWidth: minDropdownWidth
|
|
1556
|
-
}, dropdownStyle]
|
|
1174
|
+
style: [styles$3.dropdown, light && styles$3.light, isReferenceHidden && styles$3.hidden, generateDropdownMenuStyles(minDropdownWidth, maxDropdownHeight), dropdownStyle]
|
|
1557
1175
|
}, listRenderer, this.maybeRenderNoResults());
|
|
1558
1176
|
}
|
|
1559
1177
|
|
|
@@ -1561,14 +1179,9 @@ class DropdownCore extends React.Component {
|
|
|
1561
1179
|
const {
|
|
1562
1180
|
alignment,
|
|
1563
1181
|
openerElement
|
|
1564
|
-
} = this.props;
|
|
1565
|
-
// doing this, we optimize the list to be processed only one time
|
|
1566
|
-
// instead of every time popper changes.
|
|
1567
|
-
// NOTE: This improves the performance impact of the dropdown by
|
|
1568
|
-
// reducing the execution time up to 2.5X.
|
|
1569
|
-
|
|
1182
|
+
} = this.props;
|
|
1570
1183
|
const listRenderer = this.shouldVirtualizeList() ? this.renderVirtualizedList() : this.renderList();
|
|
1571
|
-
return
|
|
1184
|
+
return React.createElement(DropdownPopper, {
|
|
1572
1185
|
alignment: alignment,
|
|
1573
1186
|
onPopperElement: popperElement => {
|
|
1574
1187
|
this.popperElement = popperElement;
|
|
@@ -1584,7 +1197,7 @@ class DropdownCore extends React.Component {
|
|
|
1584
1197
|
style,
|
|
1585
1198
|
className
|
|
1586
1199
|
} = this.props;
|
|
1587
|
-
return
|
|
1200
|
+
return React.createElement(View, {
|
|
1588
1201
|
onKeyDown: this.handleKeyDown,
|
|
1589
1202
|
onKeyUp: this.handleKeyUp,
|
|
1590
1203
|
style: [styles$3.menuWrapper, style],
|
|
@@ -1615,7 +1228,6 @@ const styles$3 = StyleSheet.create({
|
|
|
1615
1228
|
overflowY: "auto"
|
|
1616
1229
|
},
|
|
1617
1230
|
light: {
|
|
1618
|
-
// Pretty much just remove the border
|
|
1619
1231
|
border: "none"
|
|
1620
1232
|
},
|
|
1621
1233
|
hidden: {
|
|
@@ -1632,13 +1244,6 @@ var DropdownCore$1 = withActionScheduler(DropdownCore);
|
|
|
1632
1244
|
|
|
1633
1245
|
const _excluded$4 = ["children", "disabled", "focused", "hovered", "pressed", "waiting", "testId", "opened", "aria-label"];
|
|
1634
1246
|
const StyledButton$1 = addStyle("button");
|
|
1635
|
-
/**
|
|
1636
|
-
* Although this component shares a lot with ButtonCore there are a couple
|
|
1637
|
-
* of differences:
|
|
1638
|
-
* - the down caret icon appears on the right instead of the left
|
|
1639
|
-
* - the down caret icon is smaller that the one that would be used by ButtonCore
|
|
1640
|
-
*/
|
|
1641
|
-
|
|
1642
1247
|
class ActionMenuOpenerCore extends React.Component {
|
|
1643
1248
|
render() {
|
|
1644
1249
|
const _this$props = this.props,
|
|
@@ -1660,10 +1265,10 @@ class ActionMenuOpenerCore extends React.Component {
|
|
|
1660
1265
|
|
|
1661
1266
|
const disabled = disabledProp;
|
|
1662
1267
|
const defaultStyle = [sharedStyles.shared, disabled && sharedStyles.disabled, buttonStyles.default, disabled && buttonStyles.disabled, !disabled && pressed && buttonStyles.active];
|
|
1663
|
-
const label =
|
|
1268
|
+
const label = React.createElement(LabelLarge, {
|
|
1664
1269
|
style: sharedStyles.text
|
|
1665
1270
|
}, children);
|
|
1666
|
-
return
|
|
1271
|
+
return React.createElement(StyledButton$1, _extends({
|
|
1667
1272
|
"aria-expanded": opened ? "true" : "false",
|
|
1668
1273
|
"aria-haspopup": "menu",
|
|
1669
1274
|
"aria-label": ariaLabel,
|
|
@@ -1672,11 +1277,11 @@ class ActionMenuOpenerCore extends React.Component {
|
|
|
1672
1277
|
type: "button"
|
|
1673
1278
|
}, restProps, {
|
|
1674
1279
|
"data-test-id": testId
|
|
1675
|
-
}),
|
|
1280
|
+
}), React.createElement(View, {
|
|
1676
1281
|
style: !disabled && (hovered || focused) && buttonStyles.focus
|
|
1677
|
-
}, label),
|
|
1282
|
+
}, label), React.createElement(Strut, {
|
|
1678
1283
|
size: Spacing.xxxSmall_4
|
|
1679
|
-
}),
|
|
1284
|
+
}), React.createElement(Icon, {
|
|
1680
1285
|
size: "small",
|
|
1681
1286
|
color: "currentColor",
|
|
1682
1287
|
icon: icons.caretDown
|
|
@@ -1697,11 +1302,8 @@ const sharedStyles = StyleSheet.create({
|
|
|
1697
1302
|
outline: "none",
|
|
1698
1303
|
textDecoration: "none",
|
|
1699
1304
|
boxSizing: "border-box",
|
|
1700
|
-
// This removes the 300ms click delay on mobile browsers by indicating that
|
|
1701
|
-
// "double-tap to zoom" shouldn't be used on this element.
|
|
1702
1305
|
touchAction: "manipulation",
|
|
1703
1306
|
":focus": {
|
|
1704
|
-
// Mobile: Removes a blue highlight style shown when the user clicks a button
|
|
1705
1307
|
WebkitTapHighlightColor: "rgba(0,0,0,0)"
|
|
1706
1308
|
}
|
|
1707
1309
|
},
|
|
@@ -1720,8 +1322,7 @@ const sharedStyles = StyleSheet.create({
|
|
|
1720
1322
|
whiteSpace: "nowrap",
|
|
1721
1323
|
overflow: "hidden",
|
|
1722
1324
|
textOverflow: "ellipsis",
|
|
1723
|
-
pointerEvents: "none"
|
|
1724
|
-
|
|
1325
|
+
pointerEvents: "none"
|
|
1725
1326
|
},
|
|
1726
1327
|
hiddenText: {
|
|
1727
1328
|
visibility: "hidden"
|
|
@@ -1774,10 +1375,6 @@ const _generateStyles$1 = color => {
|
|
|
1774
1375
|
};
|
|
1775
1376
|
|
|
1776
1377
|
const _excluded$3 = ["text"];
|
|
1777
|
-
|
|
1778
|
-
/**
|
|
1779
|
-
* A menu that consists of various types of items.
|
|
1780
|
-
*/
|
|
1781
1378
|
class ActionMenu extends React.Component {
|
|
1782
1379
|
constructor(...args) {
|
|
1783
1380
|
super(...args);
|
|
@@ -1786,8 +1383,7 @@ class ActionMenu extends React.Component {
|
|
|
1786
1383
|
};
|
|
1787
1384
|
|
|
1788
1385
|
this.handleItemSelected = () => {
|
|
1789
|
-
|
|
1790
|
-
this.handleOpenChanged(false); // Bring focus back to the opener element.
|
|
1386
|
+
this.handleOpenChanged(false);
|
|
1791
1387
|
|
|
1792
1388
|
if (this.openerElement) {
|
|
1793
1389
|
this.openerElement.focus();
|
|
@@ -1808,7 +1404,7 @@ class ActionMenu extends React.Component {
|
|
|
1808
1404
|
const {
|
|
1809
1405
|
onChange,
|
|
1810
1406
|
selectedValues
|
|
1811
|
-
} = this.props;
|
|
1407
|
+
} = this.props;
|
|
1812
1408
|
|
|
1813
1409
|
if (!onChange || !selectedValues) {
|
|
1814
1410
|
return;
|
|
@@ -1819,7 +1415,6 @@ class ActionMenu extends React.Component {
|
|
|
1819
1415
|
const updatedSelection = [].concat(selectedValues.slice(0, index), selectedValues.slice(index + 1));
|
|
1820
1416
|
onChange(updatedSelection);
|
|
1821
1417
|
} else {
|
|
1822
|
-
// Item was newly selected
|
|
1823
1418
|
onChange([].concat(selectedValues, [selectedValue]));
|
|
1824
1419
|
}
|
|
1825
1420
|
|
|
@@ -1835,10 +1430,6 @@ class ActionMenu extends React.Component {
|
|
|
1835
1430
|
};
|
|
1836
1431
|
}
|
|
1837
1432
|
|
|
1838
|
-
/**
|
|
1839
|
-
* Used to sync the `opened` state when this component acts as a controlled
|
|
1840
|
-
* component
|
|
1841
|
-
*/
|
|
1842
1433
|
static getDerivedStateFromProps(props, state) {
|
|
1843
1434
|
return {
|
|
1844
1435
|
opened: typeof props.opened === "boolean" ? props.opened : state.opened
|
|
@@ -1850,9 +1441,7 @@ class ActionMenu extends React.Component {
|
|
|
1850
1441
|
children,
|
|
1851
1442
|
selectedValues
|
|
1852
1443
|
} = this.props;
|
|
1853
|
-
const allChildren = React.Children.toArray(children).filter(Boolean);
|
|
1854
|
-
// possible Action items
|
|
1855
|
-
|
|
1444
|
+
const allChildren = React.Children.toArray(children).filter(Boolean);
|
|
1856
1445
|
const isOptionItemIncluded = allChildren.some(item => OptionItem.isClassOf(item));
|
|
1857
1446
|
return allChildren.map(item => {
|
|
1858
1447
|
const {
|
|
@@ -1896,7 +1485,7 @@ class ActionMenu extends React.Component {
|
|
|
1896
1485
|
const {
|
|
1897
1486
|
opened
|
|
1898
1487
|
} = this.state;
|
|
1899
|
-
return
|
|
1488
|
+
return React.createElement(DropdownOpener, {
|
|
1900
1489
|
onClick: this.handleClick,
|
|
1901
1490
|
disabled: numItems === 0 || disabled,
|
|
1902
1491
|
text: menuText,
|
|
@@ -1905,7 +1494,7 @@ class ActionMenu extends React.Component {
|
|
|
1905
1494
|
}, opener ? opener : openerProps => {
|
|
1906
1495
|
const eventState = _objectWithoutPropertiesLoose(openerProps, _excluded$3);
|
|
1907
1496
|
|
|
1908
|
-
return
|
|
1497
|
+
return React.createElement(ActionMenuOpenerCore, _extends({}, eventState, {
|
|
1909
1498
|
disabled: disabled,
|
|
1910
1499
|
opened: !!opened,
|
|
1911
1500
|
testId: testId
|
|
@@ -1922,7 +1511,7 @@ class ActionMenu extends React.Component {
|
|
|
1922
1511
|
} = this.props;
|
|
1923
1512
|
const items = this.getMenuItems();
|
|
1924
1513
|
const dropdownOpener = this.renderOpener(items.length);
|
|
1925
|
-
return
|
|
1514
|
+
return React.createElement(DropdownCore$1, {
|
|
1926
1515
|
role: "menu",
|
|
1927
1516
|
style: style,
|
|
1928
1517
|
className: className,
|
|
@@ -1945,14 +1534,12 @@ const styles$1 = StyleSheet.create({
|
|
|
1945
1534
|
caret: {
|
|
1946
1535
|
marginLeft: 4
|
|
1947
1536
|
},
|
|
1948
|
-
// The design calls for additional offset around the opener.
|
|
1949
1537
|
opener: {
|
|
1950
1538
|
whiteSpace: "nowrap",
|
|
1951
1539
|
userSelect: "none",
|
|
1952
1540
|
overflow: "hidden",
|
|
1953
1541
|
textOverflow: "ellipsis"
|
|
1954
1542
|
},
|
|
1955
|
-
// This is to adjust the space between the menu and the opener.
|
|
1956
1543
|
menuTopSpace: {
|
|
1957
1544
|
top: -4
|
|
1958
1545
|
}
|
|
@@ -1969,10 +1556,6 @@ const {
|
|
|
1969
1556
|
offBlack32,
|
|
1970
1557
|
offBlack64
|
|
1971
1558
|
} = Color;
|
|
1972
|
-
|
|
1973
|
-
/**
|
|
1974
|
-
* An opener that opens select boxes.
|
|
1975
|
-
*/
|
|
1976
1559
|
class SelectOpener extends React.Component {
|
|
1977
1560
|
constructor(...args) {
|
|
1978
1561
|
super(...args);
|
|
@@ -1999,7 +1582,7 @@ class SelectOpener extends React.Component {
|
|
|
1999
1582
|
sharedProps = _objectWithoutPropertiesLoose(_this$props, _excluded$2);
|
|
2000
1583
|
|
|
2001
1584
|
const ClickableBehavior = getClickableBehavior(router);
|
|
2002
|
-
return
|
|
1585
|
+
return React.createElement(ClickableBehavior, {
|
|
2003
1586
|
disabled: disabled,
|
|
2004
1587
|
onClick: this.handleClick
|
|
2005
1588
|
}, (state, childrenProps) => {
|
|
@@ -2009,12 +1592,10 @@ class SelectOpener extends React.Component {
|
|
|
2009
1592
|
hovered,
|
|
2010
1593
|
focused,
|
|
2011
1594
|
pressed
|
|
2012
|
-
} = state;
|
|
2013
|
-
// based on the zeplin design.
|
|
2014
|
-
|
|
1595
|
+
} = state;
|
|
2015
1596
|
const iconColor = light ? disabled || pressed ? "currentColor" : white : disabled ? offBlack32 : offBlack64;
|
|
2016
1597
|
const style = [styles.shared, stateStyles.default, disabled && stateStyles.disabled, !disabled && (pressed ? stateStyles.active : (hovered || focused) && stateStyles.focus)];
|
|
2017
|
-
return
|
|
1598
|
+
return React.createElement(StyledButton, _extends({}, sharedProps, {
|
|
2018
1599
|
"aria-expanded": open ? "true" : "false",
|
|
2019
1600
|
"aria-haspopup": "listbox",
|
|
2020
1601
|
"data-test-id": testId,
|
|
@@ -2022,9 +1603,9 @@ class SelectOpener extends React.Component {
|
|
|
2022
1603
|
id: id,
|
|
2023
1604
|
style: style,
|
|
2024
1605
|
type: "button"
|
|
2025
|
-
}, childrenProps),
|
|
1606
|
+
}, childrenProps), React.createElement(LabelMedium, {
|
|
2026
1607
|
style: styles.text
|
|
2027
|
-
}, children),
|
|
1608
|
+
}, children), React.createElement(Icon, {
|
|
2028
1609
|
icon: icons.caretDown,
|
|
2029
1610
|
color: iconColor,
|
|
2030
1611
|
size: "small",
|
|
@@ -2035,7 +1616,7 @@ class SelectOpener extends React.Component {
|
|
|
2035
1616
|
}
|
|
2036
1617
|
|
|
2037
1618
|
render() {
|
|
2038
|
-
return
|
|
1619
|
+
return React.createElement(__RouterContext.Consumer, null, router => this.renderClickableBehavior(router));
|
|
2039
1620
|
}
|
|
2040
1621
|
|
|
2041
1622
|
}
|
|
@@ -2046,7 +1627,6 @@ SelectOpener.defaultProps = {
|
|
|
2046
1627
|
};
|
|
2047
1628
|
const buttonRadius = 4;
|
|
2048
1629
|
const styles = StyleSheet.create({
|
|
2049
|
-
// TODO: Dedupe with Button styles
|
|
2050
1630
|
shared: {
|
|
2051
1631
|
position: "relative",
|
|
2052
1632
|
display: "inline-flex",
|
|
@@ -2054,9 +1634,6 @@ const styles = StyleSheet.create({
|
|
|
2054
1634
|
justifyContent: "space-between",
|
|
2055
1635
|
color: offBlack,
|
|
2056
1636
|
height: DROPDOWN_ITEM_HEIGHT,
|
|
2057
|
-
// This asymmetry arises from the Icon on the right side, which has
|
|
2058
|
-
// extra padding built in. To have the component look more balanced,
|
|
2059
|
-
// we need to take off some paddingRight here.
|
|
2060
1637
|
paddingLeft: 16,
|
|
2061
1638
|
paddingRight: 12,
|
|
2062
1639
|
borderWidth: 0,
|
|
@@ -2066,8 +1643,6 @@ const styles = StyleSheet.create({
|
|
|
2066
1643
|
textDecoration: "none",
|
|
2067
1644
|
boxSizing: "border-box",
|
|
2068
1645
|
whiteSpace: "nowrap",
|
|
2069
|
-
// This removes the 300ms click delay on mobile browsers by indicating that
|
|
2070
|
-
// "double-tap to zoom" shouldn't be used on this element.
|
|
2071
1646
|
touchAction: "manipulation"
|
|
2072
1647
|
},
|
|
2073
1648
|
text: {
|
|
@@ -2080,16 +1655,12 @@ const styles = StyleSheet.create({
|
|
|
2080
1655
|
caret: {
|
|
2081
1656
|
minWidth: 16
|
|
2082
1657
|
}
|
|
2083
|
-
});
|
|
2084
|
-
// changing the borderWidth to 2 messes up the button width
|
|
2085
|
-
// and causes it to move a couple pixels. This fixes that.
|
|
2086
|
-
|
|
1658
|
+
});
|
|
2087
1659
|
const adjustedPaddingLeft = 16 - 1;
|
|
2088
1660
|
const adjustedPaddingRight = 12 - 1;
|
|
2089
1661
|
const stateStyles = {};
|
|
2090
1662
|
|
|
2091
1663
|
const _generateStyles = (light, placeholder) => {
|
|
2092
|
-
// "hash" the parameters
|
|
2093
1664
|
const styleKey = `${String(light)}-${String(placeholder)}`;
|
|
2094
1665
|
|
|
2095
1666
|
if (stateStyles[styleKey]) {
|
|
@@ -2161,20 +1732,6 @@ const _generateStyles = (light, placeholder) => {
|
|
|
2161
1732
|
};
|
|
2162
1733
|
|
|
2163
1734
|
const _excluded$1 = ["children", "disabled", "id", "light", "opener", "placeholder", "selectedValue", "testId", "alignment", "dropdownStyle", "isFilterable", "onChange", "onToggle", "opened", "style", "className"];
|
|
2164
|
-
|
|
2165
|
-
/**
|
|
2166
|
-
* The single select allows the selection of one item. Clients are responsible
|
|
2167
|
-
* for keeping track of the selected item in the select.
|
|
2168
|
-
*
|
|
2169
|
-
* The single select dropdown closes after the selection of an item. If the same
|
|
2170
|
-
* item is selected, there is no callback.
|
|
2171
|
-
*
|
|
2172
|
-
* *NOTE:* The component automatically uses
|
|
2173
|
-
* [react-window](https://github.com/bvaughn/react-window) to improve
|
|
2174
|
-
* performance when rendering these elements and is capable of handling many
|
|
2175
|
-
* hundreds of items without performance problems.
|
|
2176
|
-
*
|
|
2177
|
-
*/
|
|
2178
1735
|
class SingleSelect extends React.Component {
|
|
2179
1736
|
constructor(props) {
|
|
2180
1737
|
super(props);
|
|
@@ -2191,19 +1748,16 @@ class SingleSelect extends React.Component {
|
|
|
2191
1748
|
};
|
|
2192
1749
|
|
|
2193
1750
|
this.handleToggle = selectedValue => {
|
|
2194
|
-
// Call callback if selection changed.
|
|
2195
1751
|
if (selectedValue !== this.props.selectedValue) {
|
|
2196
1752
|
this.props.onChange(selectedValue);
|
|
2197
|
-
}
|
|
2198
|
-
|
|
1753
|
+
}
|
|
2199
1754
|
|
|
2200
1755
|
if (this.state.open && this.state.openerElement) {
|
|
2201
1756
|
this.state.openerElement.focus();
|
|
2202
1757
|
}
|
|
2203
1758
|
|
|
2204
1759
|
this.setState({
|
|
2205
|
-
open: false
|
|
2206
|
-
|
|
1760
|
+
open: false
|
|
2207
1761
|
});
|
|
2208
1762
|
|
|
2209
1763
|
if (this.props.onToggle) {
|
|
@@ -2212,8 +1766,6 @@ class SingleSelect extends React.Component {
|
|
|
2212
1766
|
};
|
|
2213
1767
|
|
|
2214
1768
|
this.mapOptionItemsToDropdownItems = children => {
|
|
2215
|
-
// Figure out which index should receive focus when this select opens
|
|
2216
|
-
// Needs to exclude counting items that are disabled
|
|
2217
1769
|
let indexCounter = 0;
|
|
2218
1770
|
this.selectedIndex = 0;
|
|
2219
1771
|
return children.map(option => {
|
|
@@ -2270,11 +1822,6 @@ class SingleSelect extends React.Component {
|
|
|
2270
1822
|
openerElement: null
|
|
2271
1823
|
};
|
|
2272
1824
|
}
|
|
2273
|
-
/**
|
|
2274
|
-
* Used to sync the `opened` state when this component acts as a controlled
|
|
2275
|
-
* component
|
|
2276
|
-
*/
|
|
2277
|
-
|
|
2278
1825
|
|
|
2279
1826
|
static getDerivedStateFromProps(props, state) {
|
|
2280
1827
|
return {
|
|
@@ -2286,8 +1833,7 @@ class SingleSelect extends React.Component {
|
|
|
2286
1833
|
const {
|
|
2287
1834
|
searchText
|
|
2288
1835
|
} = this.state;
|
|
2289
|
-
const lowercasedSearchText = searchText.toLowerCase();
|
|
2290
|
-
|
|
1836
|
+
const lowercasedSearchText = searchText.toLowerCase();
|
|
2291
1837
|
return children.filter(({
|
|
2292
1838
|
props
|
|
2293
1839
|
}) => !searchText || props.label.toLowerCase().indexOf(lowercasedSearchText) > -1);
|
|
@@ -2296,9 +1842,7 @@ class SingleSelect extends React.Component {
|
|
|
2296
1842
|
getMenuItems(children) {
|
|
2297
1843
|
const {
|
|
2298
1844
|
isFilterable
|
|
2299
|
-
} = this.props;
|
|
2300
|
-
// option items to dropdown items.
|
|
2301
|
-
|
|
1845
|
+
} = this.props;
|
|
2302
1846
|
return this.mapOptionItemsToDropdownItems(isFilterable ? this.filterChildren(children) : children);
|
|
2303
1847
|
}
|
|
2304
1848
|
|
|
@@ -2308,7 +1852,7 @@ class SingleSelect extends React.Component {
|
|
|
2308
1852
|
}
|
|
2309
1853
|
|
|
2310
1854
|
return {
|
|
2311
|
-
component:
|
|
1855
|
+
component: React.createElement(SearchTextInput, {
|
|
2312
1856
|
key: "search-text-input",
|
|
2313
1857
|
onChange: this.handleSearchTextChanged,
|
|
2314
1858
|
searchText: this.state.searchText,
|
|
@@ -2336,16 +1880,14 @@ class SingleSelect extends React.Component {
|
|
|
2336
1880
|
} = _this$props,
|
|
2337
1881
|
sharedProps = _objectWithoutPropertiesLoose(_this$props, _excluded$1);
|
|
2338
1882
|
|
|
2339
|
-
const selectedItem = React.Children.toArray(children).find(option => option.props.value === selectedValue);
|
|
2340
|
-
// item in the menu, use the placeholder.
|
|
2341
|
-
|
|
1883
|
+
const selectedItem = React.Children.toArray(children).find(option => option.props.value === selectedValue);
|
|
2342
1884
|
const menuText = selectedItem ? selectedItem.props.label : placeholder;
|
|
2343
|
-
const dropdownOpener = opener ?
|
|
1885
|
+
const dropdownOpener = opener ? React.createElement(DropdownOpener, {
|
|
2344
1886
|
onClick: this.handleClick,
|
|
2345
1887
|
disabled: numItems === 0 || disabled,
|
|
2346
1888
|
ref: this.handleOpenerRef,
|
|
2347
1889
|
text: menuText
|
|
2348
|
-
}, opener) :
|
|
1890
|
+
}, opener) : React.createElement(SelectOpener, _extends({}, sharedProps, {
|
|
2349
1891
|
disabled: numItems === 0 || disabled,
|
|
2350
1892
|
id: id,
|
|
2351
1893
|
isPlaceholder: !selectedItem,
|
|
@@ -2376,7 +1918,7 @@ class SingleSelect extends React.Component {
|
|
|
2376
1918
|
const opener = this.renderOpener(allChildren.length);
|
|
2377
1919
|
const searchField = this.getSearchField();
|
|
2378
1920
|
const items = searchField ? [searchField].concat(filteredItems) : filteredItems;
|
|
2379
|
-
return
|
|
1921
|
+
return React.createElement(DropdownCore$1, {
|
|
2380
1922
|
role: "listbox",
|
|
2381
1923
|
alignment: alignment,
|
|
2382
1924
|
dropdownStyle: [isFilterable && filterableDropdownStyle, selectDropdownStyle, dropdownStyle],
|
|
@@ -2402,15 +1944,6 @@ SingleSelect.defaultProps = {
|
|
|
2402
1944
|
};
|
|
2403
1945
|
|
|
2404
1946
|
const _excluded = ["disabled", "id", "light", "opener", "testId", "alignment", "dropdownStyle", "implicitAllEnabled", "isFilterable", "labels", "onChange", "onToggle", "opened", "selectedValues", "shortcuts", "style", "className"];
|
|
2405
|
-
|
|
2406
|
-
/**
|
|
2407
|
-
* A dropdown that consists of multiple selection items. This select allows
|
|
2408
|
-
* multiple options to be selected. Clients are responsible for keeping track
|
|
2409
|
-
* of the selected items.
|
|
2410
|
-
*
|
|
2411
|
-
* The multi select stays open until closed by the user. The onChange callback
|
|
2412
|
-
* happens every time there is a change in the selection of the items.
|
|
2413
|
-
*/
|
|
2414
1947
|
class MultiSelect extends React.Component {
|
|
2415
1948
|
constructor(props) {
|
|
2416
1949
|
super(props);
|
|
@@ -2438,7 +1971,6 @@ class MultiSelect extends React.Component {
|
|
|
2438
1971
|
const updatedSelection = [].concat(selectedValues.slice(0, index), selectedValues.slice(index + 1));
|
|
2439
1972
|
onChange(updatedSelection);
|
|
2440
1973
|
} else {
|
|
2441
|
-
// Item was newly selected
|
|
2442
1974
|
onChange([].concat(selectedValues, [selectedValue]));
|
|
2443
1975
|
}
|
|
2444
1976
|
};
|
|
@@ -2499,18 +2031,11 @@ class MultiSelect extends React.Component {
|
|
|
2499
2031
|
open: false,
|
|
2500
2032
|
searchText: "",
|
|
2501
2033
|
lastSelectedValues: [],
|
|
2502
|
-
// merge custom labels with the default ones
|
|
2503
2034
|
labels: _extends({}, defaultLabels, props.labels),
|
|
2504
2035
|
openerElement: null
|
|
2505
|
-
};
|
|
2506
|
-
|
|
2036
|
+
};
|
|
2507
2037
|
this.labels = _extends({}, defaultLabels, props.labels);
|
|
2508
2038
|
}
|
|
2509
|
-
/**
|
|
2510
|
-
* Used to sync the `opened` state when this component acts as a controlled
|
|
2511
|
-
* component
|
|
2512
|
-
*/
|
|
2513
|
-
|
|
2514
2039
|
|
|
2515
2040
|
static getDerivedStateFromProps(props, state) {
|
|
2516
2041
|
return {
|
|
@@ -2520,7 +2045,6 @@ class MultiSelect extends React.Component {
|
|
|
2520
2045
|
|
|
2521
2046
|
componentDidUpdate(prevProps) {
|
|
2522
2047
|
if (this.props.labels !== prevProps.labels) {
|
|
2523
|
-
// eslint-disable-next-line react/no-did-update-set-state
|
|
2524
2048
|
this.setState({
|
|
2525
2049
|
labels: _extends({}, this.state.labels, this.props.labels)
|
|
2526
2050
|
});
|
|
@@ -2536,9 +2060,7 @@ class MultiSelect extends React.Component {
|
|
|
2536
2060
|
noneSelected,
|
|
2537
2061
|
someSelected,
|
|
2538
2062
|
allSelected
|
|
2539
|
-
} = this.state.labels;
|
|
2540
|
-
// otherwise, use the `labels.noneSelected` value
|
|
2541
|
-
|
|
2063
|
+
} = this.state.labels;
|
|
2542
2064
|
const noSelectionText = implicitAllEnabled ? allSelected : noneSelected;
|
|
2543
2065
|
|
|
2544
2066
|
switch (selectedValues.length) {
|
|
@@ -2546,9 +2068,6 @@ class MultiSelect extends React.Component {
|
|
|
2546
2068
|
return noSelectionText;
|
|
2547
2069
|
|
|
2548
2070
|
case 1:
|
|
2549
|
-
// If there is one item selected, we display its label. If for
|
|
2550
|
-
// some reason we can't find the selected item, we use the
|
|
2551
|
-
// display text for the case where nothing is selected.
|
|
2552
2071
|
const selectedItem = children.find(option => option.props.value === selectedValues[0]);
|
|
2553
2072
|
return selectedItem ? selectedItem.props.label : noSelectionText;
|
|
2554
2073
|
|
|
@@ -2570,7 +2089,7 @@ class MultiSelect extends React.Component {
|
|
|
2570
2089
|
filter
|
|
2571
2090
|
} = this.state.labels;
|
|
2572
2091
|
return [{
|
|
2573
|
-
component:
|
|
2092
|
+
component: React.createElement(SearchTextInput, {
|
|
2574
2093
|
key: "search-text-input",
|
|
2575
2094
|
onChange: this.handleSearchTextChanged,
|
|
2576
2095
|
searchText: this.state.searchText,
|
|
@@ -2592,12 +2111,12 @@ class MultiSelect extends React.Component {
|
|
|
2592
2111
|
const {
|
|
2593
2112
|
selectAllLabel,
|
|
2594
2113
|
selectNoneLabel
|
|
2595
|
-
} = this.state.labels;
|
|
2114
|
+
} = this.state.labels;
|
|
2596
2115
|
|
|
2597
2116
|
if (shortcuts && !this.state.searchText) {
|
|
2598
2117
|
const selectAllDisabled = numOptions === selectedValues.length;
|
|
2599
2118
|
const selectAll = {
|
|
2600
|
-
component:
|
|
2119
|
+
component: React.createElement(ActionItem, {
|
|
2601
2120
|
disabled: selectAllDisabled,
|
|
2602
2121
|
label: selectAllLabel(numOptions),
|
|
2603
2122
|
indent: true,
|
|
@@ -2608,7 +2127,7 @@ class MultiSelect extends React.Component {
|
|
|
2608
2127
|
};
|
|
2609
2128
|
const selectNoneDisabled = selectedValues.length === 0;
|
|
2610
2129
|
const selectNone = {
|
|
2611
|
-
component:
|
|
2130
|
+
component: React.createElement(ActionItem, {
|
|
2612
2131
|
disabled: selectNoneDisabled,
|
|
2613
2132
|
label: selectNoneLabel,
|
|
2614
2133
|
indent: true,
|
|
@@ -2618,7 +2137,7 @@ class MultiSelect extends React.Component {
|
|
|
2618
2137
|
populatedProps: {}
|
|
2619
2138
|
};
|
|
2620
2139
|
const separator = {
|
|
2621
|
-
component:
|
|
2140
|
+
component: React.createElement(SeparatorItem, {
|
|
2622
2141
|
key: "shortcuts-separator"
|
|
2623
2142
|
}),
|
|
2624
2143
|
focusable: false,
|
|
@@ -2633,8 +2152,7 @@ class MultiSelect extends React.Component {
|
|
|
2633
2152
|
getMenuItems(children) {
|
|
2634
2153
|
const {
|
|
2635
2154
|
isFilterable
|
|
2636
|
-
} = this.props;
|
|
2637
|
-
// option items to dropdown items.
|
|
2155
|
+
} = this.props;
|
|
2638
2156
|
|
|
2639
2157
|
if (!isFilterable) {
|
|
2640
2158
|
return children.map(this.mapOptionItemToDropdownItem);
|
|
@@ -2644,8 +2162,7 @@ class MultiSelect extends React.Component {
|
|
|
2644
2162
|
searchText,
|
|
2645
2163
|
lastSelectedValues
|
|
2646
2164
|
} = this.state;
|
|
2647
|
-
const lowercasedSearchText = searchText.toLowerCase();
|
|
2648
|
-
|
|
2165
|
+
const lowercasedSearchText = searchText.toLowerCase();
|
|
2649
2166
|
const filteredChildren = children.filter(({
|
|
2650
2167
|
props
|
|
2651
2168
|
}) => !searchText || props.label.toLowerCase().indexOf(lowercasedSearchText) > -1);
|
|
@@ -2660,12 +2177,11 @@ class MultiSelect extends React.Component {
|
|
|
2660
2177
|
}
|
|
2661
2178
|
}
|
|
2662
2179
|
|
|
2663
|
-
const lastSelectedItems = lastSelectedChildren.map(this.mapOptionItemToDropdownItem);
|
|
2664
|
-
// rest of the items only when both of them exists.
|
|
2180
|
+
const lastSelectedItems = lastSelectedChildren.map(this.mapOptionItemToDropdownItem);
|
|
2665
2181
|
|
|
2666
2182
|
if (lastSelectedChildren.length && restOfTheChildren.length) {
|
|
2667
2183
|
lastSelectedItems.push({
|
|
2668
|
-
component:
|
|
2184
|
+
component: React.createElement(SeparatorItem, {
|
|
2669
2185
|
key: "selected-separator"
|
|
2670
2186
|
}),
|
|
2671
2187
|
focusable: false,
|
|
@@ -2692,12 +2208,12 @@ class MultiSelect extends React.Component {
|
|
|
2692
2208
|
} = this.state.labels;
|
|
2693
2209
|
const menuText = this.getMenuText(allChildren);
|
|
2694
2210
|
const numOptions = allChildren.length;
|
|
2695
|
-
const dropdownOpener = opener ?
|
|
2211
|
+
const dropdownOpener = opener ? React.createElement(DropdownOpener, {
|
|
2696
2212
|
onClick: this.handleClick,
|
|
2697
2213
|
disabled: numOptions === 0 || disabled,
|
|
2698
2214
|
ref: this.handleOpenerRef,
|
|
2699
2215
|
text: menuText
|
|
2700
|
-
}, opener) :
|
|
2216
|
+
}, opener) : React.createElement(SelectOpener, _extends({}, sharedProps, {
|
|
2701
2217
|
disabled: numOptions === 0 || disabled,
|
|
2702
2218
|
id: id,
|
|
2703
2219
|
isPlaceholder: menuText === noneSelected,
|
|
@@ -2731,7 +2247,7 @@ class MultiSelect extends React.Component {
|
|
|
2731
2247
|
const numOptions = allChildren.length;
|
|
2732
2248
|
const filteredItems = this.getMenuItems(allChildren);
|
|
2733
2249
|
const opener = this.renderOpener(allChildren);
|
|
2734
|
-
return
|
|
2250
|
+
return React.createElement(DropdownCore$1, {
|
|
2735
2251
|
role: "listbox",
|
|
2736
2252
|
alignment: alignment,
|
|
2737
2253
|
dropdownStyle: [isFilterable && filterableDropdownStyle, selectDropdownStyle, dropdownStyle],
|