@workday/canvas-kit-preview-react 9.0.0-alpha.364-next.3 → 9.0.0-alpha.382-next.2
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/dist/commonjs/color-picker/lib/ColorPicker.js +24 -47
- package/dist/commonjs/color-picker/lib/parts/ColorReset.js +32 -23
- package/dist/commonjs/color-picker/lib/parts/SwatchBook.js +26 -39
- package/dist/commonjs/form-field/lib/FormField.js +10 -33
- package/dist/commonjs/form-field/lib/FormFieldHint.js +8 -31
- package/dist/commonjs/form-field/lib/FormFieldInput.js +6 -17
- package/dist/commonjs/form-field/lib/FormFieldLabel.js +8 -31
- package/dist/commonjs/form-field/lib/hooks/useFormFieldHint.js +4 -5
- package/dist/commonjs/form-field/lib/hooks/useFormFieldInput.js +5 -6
- package/dist/commonjs/form-field/lib/hooks/useFormFieldLabel.js +4 -5
- package/dist/commonjs/form-field/lib/hooks/useFormFieldModel.js +8 -16
- package/dist/commonjs/form-field/lib/hooks/useFormFieldOrientation.js +3 -3
- package/dist/commonjs/menu/lib/Menu.js +96 -129
- package/dist/commonjs/menu/lib/MenuItem.js +94 -109
- package/dist/commonjs/pill/lib/Pill.js +55 -60
- package/dist/commonjs/pill/lib/PillAvatar.js +6 -17
- package/dist/commonjs/pill/lib/PillCount.js +7 -30
- package/dist/commonjs/pill/lib/PillIcon.js +8 -31
- package/dist/commonjs/pill/lib/PillIconButton.js +13 -36
- package/dist/commonjs/pill/lib/PillLabel.js +10 -33
- package/dist/commonjs/pill/lib/usePillModel.js +8 -16
- package/dist/commonjs/segmented-control/lib/SegmentedControl.js +6 -7
- package/dist/commonjs/segmented-control/lib/SegmentedControlItem.js +24 -49
- package/dist/commonjs/segmented-control/lib/SegmentedControlList.js +13 -38
- package/dist/commonjs/segmented-control/lib/hooks/useSegmentedControlItem.js +8 -10
- package/dist/commonjs/segmented-control/lib/hooks/useSegmentedControlModel.js +31 -31
- package/dist/commonjs/select/lib/Select.js +147 -189
- package/dist/commonjs/select/lib/SelectBase.js +106 -101
- package/dist/commonjs/select/lib/SelectMenu.js +53 -84
- package/dist/commonjs/select/lib/SelectOption.js +33 -47
- package/dist/commonjs/select/lib/scrolling.js +6 -7
- package/dist/commonjs/select/lib/utils.js +4 -4
- package/dist/commonjs/side-panel/lib/SidePanel.js +36 -51
- package/dist/commonjs/side-panel/lib/SidePanelToggleButton.js +17 -40
- package/dist/commonjs/side-panel/lib/hooks.js +20 -20
- package/dist/commonjs/status-indicator/lib/StatusIndicator.js +10 -34
- package/dist/commonjs/status-indicator/lib/StatusIndicatorIcon.js +9 -21
- package/dist/commonjs/status-indicator/lib/StatusIndicatorLabel.js +5 -28
- package/dist/commonjs/status-indicator/lib/hooks/useStatusIndicatorModel.js +6 -15
- package/dist/commonjs/text-area/lib/TextArea.js +8 -31
- package/dist/commonjs/text-area/lib/TextAreaField.d.ts.map +1 -1
- package/dist/commonjs/text-area/lib/TextAreaField.js +12 -36
- package/dist/commonjs/text-input/lib/TextInput.js +8 -31
- package/dist/commonjs/text-input/lib/TextInputField.d.ts.map +1 -1
- package/dist/commonjs/text-input/lib/TextInputField.js +12 -24
- package/dist/commonjs/text-input/lib/hooks/useTextInputField.js +3 -3
- package/dist/commonjs/text-input/lib/hooks/useTextInputModel.js +1 -1
- package/dist/es6/color-picker/lib/ColorPicker.js +15 -38
- package/dist/es6/color-picker/lib/parts/ColorReset.js +27 -18
- package/dist/es6/color-picker/lib/parts/SwatchBook.js +21 -34
- package/dist/es6/form-field/lib/FormField.js +4 -27
- package/dist/es6/form-field/lib/FormFieldHint.js +4 -27
- package/dist/es6/form-field/lib/FormFieldInput.js +3 -14
- package/dist/es6/form-field/lib/FormFieldLabel.js +4 -27
- package/dist/es6/form-field/lib/hooks/useFormFieldHint.js +2 -3
- package/dist/es6/form-field/lib/hooks/useFormFieldInput.js +3 -4
- package/dist/es6/form-field/lib/hooks/useFormFieldLabel.js +2 -3
- package/dist/es6/form-field/lib/hooks/useFormFieldModel.js +8 -16
- package/dist/es6/form-field/lib/hooks/useFormFieldOrientation.js +2 -2
- package/dist/es6/menu/lib/Menu.js +91 -125
- package/dist/es6/menu/lib/MenuItem.js +90 -106
- package/dist/es6/pill/lib/Pill.js +45 -50
- package/dist/es6/pill/lib/PillAvatar.js +3 -14
- package/dist/es6/pill/lib/PillCount.js +4 -27
- package/dist/es6/pill/lib/PillIcon.js +3 -26
- package/dist/es6/pill/lib/PillIconButton.js +7 -30
- package/dist/es6/pill/lib/PillLabel.js +5 -28
- package/dist/es6/pill/lib/usePillModel.js +8 -16
- package/dist/es6/segmented-control/lib/SegmentedControl.js +2 -3
- package/dist/es6/segmented-control/lib/SegmentedControlItem.js +17 -42
- package/dist/es6/segmented-control/lib/SegmentedControlList.js +9 -34
- package/dist/es6/segmented-control/lib/hooks/useSegmentedControlItem.js +5 -7
- package/dist/es6/segmented-control/lib/hooks/useSegmentedControlModel.js +29 -29
- package/dist/es6/select/lib/Select.js +144 -186
- package/dist/es6/select/lib/SelectBase.js +99 -94
- package/dist/es6/select/lib/SelectMenu.js +49 -80
- package/dist/es6/select/lib/SelectOption.js +30 -44
- package/dist/es6/select/lib/scrolling.js +6 -7
- package/dist/es6/select/lib/utils.js +4 -4
- package/dist/es6/side-panel/lib/SidePanel.js +31 -46
- package/dist/es6/side-panel/lib/SidePanelToggleButton.js +10 -33
- package/dist/es6/side-panel/lib/hooks.js +19 -19
- package/dist/es6/status-indicator/lib/StatusIndicator.js +5 -29
- package/dist/es6/status-indicator/lib/StatusIndicatorIcon.js +6 -18
- package/dist/es6/status-indicator/lib/StatusIndicatorLabel.js +3 -26
- package/dist/es6/status-indicator/lib/hooks/useStatusIndicatorModel.js +6 -15
- package/dist/es6/text-area/lib/TextArea.js +4 -27
- package/dist/es6/text-area/lib/TextAreaField.d.ts.map +1 -1
- package/dist/es6/text-area/lib/TextAreaField.js +9 -33
- package/dist/es6/text-input/lib/TextInput.js +4 -27
- package/dist/es6/text-input/lib/TextInputField.d.ts.map +1 -1
- package/dist/es6/text-input/lib/TextInputField.js +9 -21
- package/dist/es6/text-input/lib/hooks/useTextInputField.js +1 -1
- package/dist/es6/text-input/lib/hooks/useTextInputModel.js +1 -1
- package/package.json +3 -4
- package/text-area/lib/TextAreaField.tsx +6 -2
- package/text-input/lib/TextInputField.tsx +6 -2
|
@@ -1,63 +1,25 @@
|
|
|
1
|
-
var __extends = (this && this.__extends) || (function () {
|
|
2
|
-
var extendStatics = function (d, b) {
|
|
3
|
-
extendStatics = Object.setPrototypeOf ||
|
|
4
|
-
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
5
|
-
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
6
|
-
return extendStatics(d, b);
|
|
7
|
-
};
|
|
8
|
-
return function (d, b) {
|
|
9
|
-
if (typeof b !== "function" && b !== null)
|
|
10
|
-
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
11
|
-
extendStatics(d, b);
|
|
12
|
-
function __() { this.constructor = d; }
|
|
13
|
-
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
14
|
-
};
|
|
15
|
-
})();
|
|
16
|
-
var __assign = (this && this.__assign) || function () {
|
|
17
|
-
__assign = Object.assign || function(t) {
|
|
18
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
19
|
-
s = arguments[i];
|
|
20
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
21
|
-
t[p] = s[p];
|
|
22
|
-
}
|
|
23
|
-
return t;
|
|
24
|
-
};
|
|
25
|
-
return __assign.apply(this, arguments);
|
|
26
|
-
};
|
|
27
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
28
|
-
var t = {};
|
|
29
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
30
|
-
t[p] = s[p];
|
|
31
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
32
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
33
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
34
|
-
t[p[i]] = s[p[i]];
|
|
35
|
-
}
|
|
36
|
-
return t;
|
|
37
|
-
};
|
|
38
1
|
import * as React from 'react';
|
|
39
2
|
import { ErrorType, createComponent, useForkRef, generateUniqueId, } from '@workday/canvas-kit-react/common';
|
|
40
3
|
import { menuAnimationDuration } from './SelectMenu';
|
|
41
4
|
import { SelectBase } from './SelectBase';
|
|
42
5
|
import { getCorrectedIndexByValue } from './utils';
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
_this.state = {
|
|
6
|
+
class SelectContainer extends React.Component {
|
|
7
|
+
constructor(props) {
|
|
8
|
+
super(props);
|
|
9
|
+
this.state = {
|
|
48
10
|
focusedOptionIndex: 0,
|
|
49
11
|
menuVisibility: 'closed',
|
|
50
12
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
13
|
+
this.localButtonRef = React.createRef();
|
|
14
|
+
this.inputRef = React.createRef();
|
|
15
|
+
this.menuRef = React.createRef();
|
|
54
16
|
// For type-ahead functionality
|
|
55
|
-
|
|
56
|
-
|
|
17
|
+
this.keysSoFar = '';
|
|
18
|
+
this.clearKeysSoFarTimeout = 500;
|
|
57
19
|
// Cached values
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
20
|
+
this.normalizedOptions = [];
|
|
21
|
+
this.areOptionsDefined = () => {
|
|
22
|
+
const { options } = this.props;
|
|
61
23
|
if (!options || options.length === 0) {
|
|
62
24
|
return false;
|
|
63
25
|
}
|
|
@@ -66,15 +28,15 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
66
28
|
// Store normalized options since the options prop can take on multiple
|
|
67
29
|
// forms: an array of strings or an array of objects (sometimes with
|
|
68
30
|
// arbitrary keys)
|
|
69
|
-
|
|
70
|
-
|
|
31
|
+
this.setNormalizedOptions = () => {
|
|
32
|
+
const { options } = this.props;
|
|
71
33
|
// Abort if options weren't defined
|
|
72
|
-
if (!
|
|
34
|
+
if (!this.areOptionsDefined()) {
|
|
73
35
|
return;
|
|
74
36
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
37
|
+
this.normalizedOptions = options.map(option => {
|
|
38
|
+
let data = {};
|
|
39
|
+
let disabled, id, label, value;
|
|
78
40
|
if (typeof option === 'string') {
|
|
79
41
|
disabled = false;
|
|
80
42
|
id = generateUniqueId();
|
|
@@ -89,21 +51,19 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
89
51
|
label = option.label || option.value;
|
|
90
52
|
}
|
|
91
53
|
return {
|
|
92
|
-
data
|
|
93
|
-
disabled
|
|
94
|
-
id
|
|
95
|
-
label
|
|
96
|
-
value
|
|
54
|
+
data,
|
|
55
|
+
disabled,
|
|
56
|
+
id,
|
|
57
|
+
label,
|
|
58
|
+
value,
|
|
97
59
|
};
|
|
98
60
|
});
|
|
99
61
|
};
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
for (var i = startIndex; i < endIndex; i++) {
|
|
104
|
-
var label = _this.normalizedOptions[i].label.toLowerCase();
|
|
62
|
+
this.getIndexByStartString = (startIndex, startString, endIndex = this.normalizedOptions.length, ignoreDisabled = true) => {
|
|
63
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
64
|
+
const label = this.normalizedOptions[i].label.toLowerCase();
|
|
105
65
|
if (label.indexOf(startString.toLowerCase()) === 0) {
|
|
106
|
-
if (!ignoreDisabled || (ignoreDisabled && !
|
|
66
|
+
if (!ignoreDisabled || (ignoreDisabled && !this.normalizedOptions[i].disabled)) {
|
|
107
67
|
return i;
|
|
108
68
|
}
|
|
109
69
|
}
|
|
@@ -119,64 +79,64 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
119
79
|
// Up/Down key means "focus the first enabled option above/below the currently
|
|
120
80
|
// focused option", or pressing the Home/End key means "focus the first/last
|
|
121
81
|
// enabled option on the menu."
|
|
122
|
-
|
|
82
|
+
this.focusNextEnabledOption = (startIndex, direction) => {
|
|
123
83
|
// Ensure direction is non-zero
|
|
124
84
|
if (direction === 0) {
|
|
125
85
|
return;
|
|
126
86
|
}
|
|
127
|
-
|
|
128
|
-
|
|
87
|
+
const numOptions = this.normalizedOptions.length;
|
|
88
|
+
let currentIndex = startIndex;
|
|
129
89
|
// Check if currentIndex refers to an enabled option. If not, keep moving
|
|
130
90
|
// the index in the prescribed direction until we find an enabled option.
|
|
131
91
|
while (currentIndex >= 0 &&
|
|
132
92
|
currentIndex < numOptions &&
|
|
133
|
-
|
|
93
|
+
this.normalizedOptions[currentIndex].disabled) {
|
|
134
94
|
currentIndex += direction;
|
|
135
95
|
}
|
|
136
96
|
// Update the focused index only if currentIndex is inbounds and
|
|
137
97
|
// refers to an enabled option
|
|
138
98
|
if (currentIndex >= 0 &&
|
|
139
99
|
currentIndex < numOptions &&
|
|
140
|
-
!
|
|
141
|
-
|
|
100
|
+
!this.normalizedOptions[currentIndex].disabled) {
|
|
101
|
+
this.setState({ focusedOptionIndex: currentIndex });
|
|
142
102
|
}
|
|
143
103
|
};
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
focusedOptionIndex: getCorrectedIndexByValue(
|
|
104
|
+
this.updateStateFromValue = () => {
|
|
105
|
+
this.setState({
|
|
106
|
+
focusedOptionIndex: getCorrectedIndexByValue(this.normalizedOptions, this.props.value),
|
|
147
107
|
});
|
|
148
108
|
};
|
|
149
|
-
|
|
150
|
-
if (
|
|
151
|
-
|
|
109
|
+
this.focusButton = () => {
|
|
110
|
+
if (this.localButtonRef.current) {
|
|
111
|
+
this.localButtonRef.current.focus();
|
|
152
112
|
}
|
|
153
113
|
};
|
|
154
|
-
|
|
155
|
-
if (
|
|
156
|
-
clearTimeout(
|
|
114
|
+
this.setMenuAnimationTimeout = (callback) => {
|
|
115
|
+
if (this.menuAnimationTimer) {
|
|
116
|
+
clearTimeout(this.menuAnimationTimer);
|
|
157
117
|
}
|
|
158
|
-
|
|
118
|
+
this.menuAnimationTimer = setTimeout(callback, menuAnimationDuration);
|
|
159
119
|
};
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
120
|
+
this.openMenu = () => {
|
|
121
|
+
this.setState({ menuVisibility: 'opening' });
|
|
122
|
+
this.setMenuAnimationTimeout(() => {
|
|
123
|
+
this.setState({ menuVisibility: 'opened' });
|
|
164
124
|
});
|
|
165
125
|
};
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
126
|
+
this.closeMenu = () => {
|
|
127
|
+
this.setState({ menuVisibility: 'closing' });
|
|
128
|
+
this.setMenuAnimationTimeout(() => {
|
|
129
|
+
this.setState({
|
|
170
130
|
// Reset the focused option to the currently selected option in case
|
|
171
131
|
// the user focused a different option but chose not to select it. The
|
|
172
132
|
// next time the menu opens, focus should begin on the selected option.
|
|
173
|
-
focusedOptionIndex: getCorrectedIndexByValue(
|
|
133
|
+
focusedOptionIndex: getCorrectedIndexByValue(this.normalizedOptions, this.props.value),
|
|
174
134
|
menuVisibility: 'closed',
|
|
175
135
|
});
|
|
176
136
|
});
|
|
177
137
|
};
|
|
178
|
-
|
|
179
|
-
|
|
138
|
+
this.toggleMenu = (open) => {
|
|
139
|
+
const { menuVisibility } = this.state;
|
|
180
140
|
if (open) {
|
|
181
141
|
switch (menuVisibility) {
|
|
182
142
|
// We're opening a menu which is currently closed: set the menu state
|
|
@@ -184,14 +144,14 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
184
144
|
// from 0 opacity in the open state to the targeted 1.0 opacity in
|
|
185
145
|
// the opening state.
|
|
186
146
|
case 'closed':
|
|
187
|
-
|
|
147
|
+
this.setState({ menuVisibility: 'open' }, this.openMenu);
|
|
188
148
|
break;
|
|
189
149
|
// We're opening a menu which is in the process of closing. Since the
|
|
190
150
|
// menu isn't closed, there's no need to set the open state: kick off
|
|
191
151
|
// openMenu immediately.
|
|
192
152
|
case 'close':
|
|
193
153
|
case 'closing':
|
|
194
|
-
|
|
154
|
+
this.openMenu();
|
|
195
155
|
break;
|
|
196
156
|
// Otherwise, we're opening a menu is already opened or in the process of
|
|
197
157
|
// opening; no need to do anything further.
|
|
@@ -204,14 +164,14 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
204
164
|
// We're closing a menu which is currently opened: set the menu state to
|
|
205
165
|
// close before kicking off closeMenu.
|
|
206
166
|
case 'opened':
|
|
207
|
-
|
|
167
|
+
this.setState({ menuVisibility: 'close' }, this.closeMenu);
|
|
208
168
|
break;
|
|
209
169
|
// We're closing a menu which is in the process of opening. Since the
|
|
210
170
|
// menu isn't opened, there's no need to set the close state: kick off
|
|
211
171
|
// closeMenu immediately.
|
|
212
172
|
case 'open':
|
|
213
173
|
case 'opening':
|
|
214
|
-
|
|
174
|
+
this.closeMenu();
|
|
215
175
|
break;
|
|
216
176
|
// Otherwise, we're closing a menu which is already closed or in the process
|
|
217
177
|
// of closing; no need to do anything further.
|
|
@@ -224,28 +184,28 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
224
184
|
// In order for Select to be usable as a controlled component, we
|
|
225
185
|
// need to programmatically change the value of the SelectInput
|
|
226
186
|
// in such a way that triggers its change event
|
|
227
|
-
|
|
228
|
-
if (
|
|
229
|
-
|
|
187
|
+
this.fireChangeEvent = (value) => {
|
|
188
|
+
if (this.inputRef && this.inputRef.current) {
|
|
189
|
+
const nativeInputValue = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this.inputRef.current), 'value');
|
|
230
190
|
if (nativeInputValue && nativeInputValue.set) {
|
|
231
|
-
nativeInputValue.set.call(
|
|
191
|
+
nativeInputValue.set.call(this.inputRef.current, value);
|
|
232
192
|
}
|
|
233
|
-
|
|
193
|
+
let event;
|
|
234
194
|
if (typeof Event === 'function') {
|
|
235
195
|
// Modern browsers
|
|
236
|
-
|
|
196
|
+
event = new Event('change', { bubbles: true });
|
|
237
197
|
}
|
|
238
198
|
else {
|
|
239
199
|
// IE 11
|
|
240
|
-
|
|
241
|
-
|
|
200
|
+
event = document.createEvent('Event');
|
|
201
|
+
event.initEvent('change', true, true);
|
|
242
202
|
}
|
|
243
|
-
|
|
203
|
+
this.inputRef.current.dispatchEvent(event);
|
|
244
204
|
}
|
|
245
205
|
};
|
|
246
|
-
|
|
206
|
+
this.handleKeyboardTypeAhead = (key, numOptions) => {
|
|
247
207
|
// Abort immediately if the menu is the process of closing
|
|
248
|
-
if (
|
|
208
|
+
if (this.state.menuVisibility === 'closing') {
|
|
249
209
|
return;
|
|
250
210
|
}
|
|
251
211
|
// Set the starting point of the search to one of two locations
|
|
@@ -262,45 +222,45 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
262
222
|
// "San Francisco" as you type "san " (because "san " still matches
|
|
263
223
|
// "San Francisco") and then advances focus to "San Jose" after you
|
|
264
224
|
// type the "j" at the end.
|
|
265
|
-
|
|
266
|
-
?
|
|
267
|
-
:
|
|
225
|
+
let start = this.keysSoFar.length === 0
|
|
226
|
+
? this.state.focusedOptionIndex + 1
|
|
227
|
+
: this.state.focusedOptionIndex;
|
|
268
228
|
// If the starting point is beyond the list of options, reset it
|
|
269
229
|
// to the beginning of the list
|
|
270
230
|
start = start === numOptions ? 0 : start;
|
|
271
|
-
|
|
272
|
-
|
|
231
|
+
this.keysSoFar += key;
|
|
232
|
+
this.startClearKeysSoFarTimer();
|
|
273
233
|
// First, look for a match from start to end
|
|
274
|
-
|
|
275
|
-
matchIndex =
|
|
234
|
+
let matchIndex;
|
|
235
|
+
matchIndex = this.getIndexByStartString(start, this.keysSoFar);
|
|
276
236
|
// If a match isn't found between start and end, wrap the search
|
|
277
237
|
// around and search again from the beginning (0) to start
|
|
278
238
|
if (matchIndex === -1) {
|
|
279
|
-
matchIndex =
|
|
239
|
+
matchIndex = this.getIndexByStartString(0, this.keysSoFar, start);
|
|
280
240
|
}
|
|
281
241
|
// A match was found...
|
|
282
242
|
if (matchIndex > -1) {
|
|
283
|
-
if (
|
|
243
|
+
if (this.state.menuVisibility === 'closed') {
|
|
284
244
|
// If the menu is closed, fire the change event
|
|
285
|
-
|
|
245
|
+
this.fireChangeEvent(this.normalizedOptions[matchIndex].value);
|
|
286
246
|
}
|
|
287
247
|
else {
|
|
288
248
|
// Otherwise the menu is visible (or at least partially visible);
|
|
289
249
|
// focus the matched option
|
|
290
|
-
|
|
250
|
+
this.setState({ focusedOptionIndex: matchIndex });
|
|
291
251
|
}
|
|
292
252
|
}
|
|
293
253
|
};
|
|
294
|
-
|
|
295
|
-
if (
|
|
296
|
-
clearTimeout(
|
|
254
|
+
this.startClearKeysSoFarTimer = () => {
|
|
255
|
+
if (this.clearKeysSoFarTimer) {
|
|
256
|
+
clearTimeout(this.clearKeysSoFarTimer);
|
|
297
257
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
},
|
|
258
|
+
this.clearKeysSoFarTimer = setTimeout(() => {
|
|
259
|
+
this.keysSoFar = '';
|
|
260
|
+
}, this.clearKeysSoFarTimeout);
|
|
301
261
|
};
|
|
302
|
-
|
|
303
|
-
|
|
262
|
+
this.handleClick = (event) => {
|
|
263
|
+
const { menuVisibility } = this.state;
|
|
304
264
|
switch (menuVisibility) {
|
|
305
265
|
// If we click the button while the menu is in the process of closing,
|
|
306
266
|
// we want to toggle the menu back on. However, we also need to focus
|
|
@@ -308,48 +268,48 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
308
268
|
// callback (because the menu already exists).
|
|
309
269
|
case 'close':
|
|
310
270
|
case 'closing':
|
|
311
|
-
if (
|
|
312
|
-
|
|
271
|
+
if (this.menuRef.current) {
|
|
272
|
+
this.menuRef.current.focus();
|
|
313
273
|
}
|
|
314
|
-
|
|
274
|
+
this.toggleMenu(true);
|
|
315
275
|
break;
|
|
316
276
|
case 'closed':
|
|
317
|
-
|
|
277
|
+
this.toggleMenu(true);
|
|
318
278
|
break;
|
|
319
279
|
// Otherwise, the menu is opened or in the process of opening; toggle
|
|
320
280
|
// the menu off.
|
|
321
281
|
default:
|
|
322
|
-
|
|
282
|
+
this.toggleMenu(false);
|
|
323
283
|
break;
|
|
324
284
|
}
|
|
325
285
|
};
|
|
326
|
-
|
|
286
|
+
this.handleOptionSelection = (index) => {
|
|
327
287
|
// Abort if a disabled option was clicked (we ignore these clicks)
|
|
328
|
-
if (
|
|
288
|
+
if (this.normalizedOptions[index].disabled) {
|
|
329
289
|
return;
|
|
330
290
|
}
|
|
331
291
|
// Toggle menu off, shift focus back to the button, and fire change event
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
292
|
+
this.toggleMenu(false);
|
|
293
|
+
this.focusButton();
|
|
294
|
+
this.fireChangeEvent(this.normalizedOptions[index].value);
|
|
335
295
|
};
|
|
336
|
-
|
|
296
|
+
this.handleMenuCloseOnKeyPress = () => {
|
|
337
297
|
// Toggle menu off and shift focus back to the button
|
|
338
|
-
|
|
339
|
-
|
|
298
|
+
this.handleClose();
|
|
299
|
+
this.focusButton();
|
|
340
300
|
};
|
|
341
|
-
|
|
342
|
-
|
|
301
|
+
this.handleClose = () => {
|
|
302
|
+
this.toggleMenu(false);
|
|
343
303
|
};
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
304
|
+
this.handleKeyDown = (event) => {
|
|
305
|
+
const { options } = this.props;
|
|
306
|
+
const numOptions = options.length;
|
|
307
|
+
const { focusedOptionIndex, menuVisibility } = this.state;
|
|
308
|
+
let isShortcut = false;
|
|
349
309
|
// Check for type-ahead first
|
|
350
310
|
if (event.key.length === 1 && event.key.match(/\S/)) {
|
|
351
311
|
isShortcut = true;
|
|
352
|
-
|
|
312
|
+
this.handleKeyboardTypeAhead(event.key, numOptions);
|
|
353
313
|
}
|
|
354
314
|
else {
|
|
355
315
|
switch (event.key) {
|
|
@@ -359,25 +319,25 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
359
319
|
case 'Down': // IE/Edge specific value
|
|
360
320
|
isShortcut = true;
|
|
361
321
|
if (menuVisibility === 'closed' || menuVisibility === 'closing') {
|
|
362
|
-
|
|
322
|
+
this.toggleMenu(true);
|
|
363
323
|
}
|
|
364
324
|
else {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
325
|
+
const direction = event.key === 'ArrowUp' || event.key === 'Up' ? -1 : 1;
|
|
326
|
+
const startIndex = focusedOptionIndex + direction;
|
|
327
|
+
this.focusNextEnabledOption(startIndex, direction);
|
|
368
328
|
}
|
|
369
329
|
break;
|
|
370
330
|
case 'Home':
|
|
371
331
|
case 'End':
|
|
372
332
|
isShortcut = true;
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
333
|
+
const direction = event.key === 'Home' ? 1 : -1;
|
|
334
|
+
const startIndex = event.key === 'Home' ? 0 : numOptions - 1;
|
|
335
|
+
this.focusNextEnabledOption(startIndex, direction);
|
|
376
336
|
break;
|
|
377
337
|
case 'Tab':
|
|
378
338
|
if (menuVisibility !== 'closed') {
|
|
379
339
|
isShortcut = true;
|
|
380
|
-
|
|
340
|
+
this.handleMenuCloseOnKeyPress();
|
|
381
341
|
}
|
|
382
342
|
break;
|
|
383
343
|
case 'Spacebar':
|
|
@@ -385,14 +345,14 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
385
345
|
isShortcut = true;
|
|
386
346
|
// If the user is in the middle of typing a string, treat
|
|
387
347
|
// space key as type-ahead rather than option selection
|
|
388
|
-
if (
|
|
389
|
-
|
|
348
|
+
if (this.keysSoFar !== '') {
|
|
349
|
+
this.handleKeyboardTypeAhead(' ', numOptions);
|
|
390
350
|
}
|
|
391
351
|
else if (menuVisibility === 'closed' || menuVisibility === 'closing') {
|
|
392
|
-
|
|
352
|
+
this.toggleMenu(true);
|
|
393
353
|
}
|
|
394
354
|
else {
|
|
395
|
-
|
|
355
|
+
this.handleOptionSelection(focusedOptionIndex);
|
|
396
356
|
}
|
|
397
357
|
break;
|
|
398
358
|
case 'Enter':
|
|
@@ -402,7 +362,7 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
402
362
|
isShortcut = false;
|
|
403
363
|
}
|
|
404
364
|
else {
|
|
405
|
-
|
|
365
|
+
this.handleOptionSelection(focusedOptionIndex);
|
|
406
366
|
}
|
|
407
367
|
break;
|
|
408
368
|
default:
|
|
@@ -423,7 +383,7 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
423
383
|
event.preventDefault();
|
|
424
384
|
}
|
|
425
385
|
};
|
|
426
|
-
|
|
386
|
+
this.setNormalizedOptions();
|
|
427
387
|
// We need a local ref (RefObject) to the Select component's underlying
|
|
428
388
|
// button to manage focus within the component and to serve as its Popper
|
|
429
389
|
// Menu's anchorElement. If the buttonRef prop (to be forwarded to the
|
|
@@ -442,14 +402,13 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
442
402
|
// or call buttonRef with the underlying button element if it was a
|
|
443
403
|
// callback ref.
|
|
444
404
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
445
|
-
|
|
446
|
-
return _this;
|
|
405
|
+
this.forwardedButtonRef = useForkRef(props.buttonRef, this.localButtonRef);
|
|
447
406
|
}
|
|
448
|
-
|
|
407
|
+
componentDidMount() {
|
|
449
408
|
this.updateStateFromValue();
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
|
|
409
|
+
}
|
|
410
|
+
componentDidUpdate(prevProps) {
|
|
411
|
+
const { options, value } = this.props;
|
|
453
412
|
if (options !== prevProps.options) {
|
|
454
413
|
this.setNormalizedOptions();
|
|
455
414
|
this.updateStateFromValue();
|
|
@@ -457,8 +416,8 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
457
416
|
if (value !== prevProps.value) {
|
|
458
417
|
this.updateStateFromValue();
|
|
459
418
|
}
|
|
460
|
-
}
|
|
461
|
-
|
|
419
|
+
}
|
|
420
|
+
componentWillUnmount() {
|
|
462
421
|
// Clear timers
|
|
463
422
|
if (this.menuAnimationTimer) {
|
|
464
423
|
clearTimeout(this.menuAnimationTimer);
|
|
@@ -466,14 +425,14 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
466
425
|
if (this.clearKeysSoFarTimer) {
|
|
467
426
|
clearTimeout(this.clearKeysSoFarTimer);
|
|
468
427
|
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
|
|
428
|
+
}
|
|
429
|
+
render() {
|
|
430
|
+
const { value,
|
|
472
431
|
// Strip props we don't want to pass down from elemProps
|
|
473
|
-
buttonRef
|
|
474
|
-
|
|
432
|
+
buttonRef, options, onKeyDown, ...elemProps } = this.props;
|
|
433
|
+
const { focusedOptionIndex, menuVisibility } = this.state;
|
|
475
434
|
// Don't pass in event handlers if options weren't defined
|
|
476
|
-
|
|
435
|
+
const eventHandlers = this.areOptionsDefined()
|
|
477
436
|
? {
|
|
478
437
|
onClick: this.handleClick,
|
|
479
438
|
onKeyDown: this.handleKeyDown,
|
|
@@ -481,18 +440,17 @@ var SelectContainer = /** @class */ (function (_super) {
|
|
|
481
440
|
onOptionSelection: this.handleOptionSelection,
|
|
482
441
|
}
|
|
483
442
|
: {};
|
|
484
|
-
return (React.createElement(SelectBase,
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
export var Select = createComponent('button')({
|
|
443
|
+
return (React.createElement(SelectBase, Object.assign({ forwardedButtonRef: this.forwardedButtonRef, localButtonRef: this.localButtonRef, focusedOptionIndex: focusedOptionIndex, inputRef: this.inputRef, menuRef: this.menuRef, menuVisibility: menuVisibility, options: this.normalizedOptions, value: value }, eventHandlers, elemProps)));
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
SelectContainer.ErrorType = ErrorType;
|
|
447
|
+
export const Select = createComponent('button')({
|
|
490
448
|
displayName: 'Select',
|
|
491
|
-
Component:
|
|
449
|
+
Component: (props, ref, Element) => (
|
|
492
450
|
// Select is still a class component, so we render a renamed version of it
|
|
493
451
|
// (SelectContainer) and pass it ref and Element
|
|
494
|
-
React.createElement(SelectContainer,
|
|
452
|
+
React.createElement(SelectContainer, Object.assign({ as: Element, buttonRef: ref }, props))),
|
|
495
453
|
subComponents: {
|
|
496
|
-
ErrorType
|
|
454
|
+
ErrorType,
|
|
497
455
|
},
|
|
498
456
|
});
|