@mongodb-js/compass-components 1.29.3 → 1.30.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/lib/components/breadcrumb.js +1 -1
- package/lib/components/breadcrumb.js.map +1 -1
- package/lib/components/bson-value.js +4 -0
- package/lib/components/bson-value.js.map +1 -1
- package/lib/components/collapsible-field-set.js +4 -1
- package/lib/components/collapsible-field-set.js.map +1 -1
- package/lib/components/combobox/Chip.js +5 -2
- package/lib/components/combobox/Chip.js.map +1 -1
- package/lib/components/combobox/Combobox.d.ts +9 -0
- package/lib/components/combobox/Combobox.d.ts.map +1 -1
- package/lib/components/combobox/Combobox.js +225 -5
- package/lib/components/combobox/Combobox.js.map +1 -1
- package/lib/components/combobox/Combobox.styles.d.ts +15 -0
- package/lib/components/combobox/Combobox.styles.d.ts.map +1 -1
- package/lib/components/combobox/Combobox.styles.js +19 -2
- package/lib/components/combobox/Combobox.styles.js.map +1 -1
- package/lib/components/combobox/Combobox.types.d.ts +174 -0
- package/lib/components/combobox/Combobox.types.d.ts.map +1 -1
- package/lib/components/combobox/Combobox.types.js +20 -0
- package/lib/components/combobox/Combobox.types.js.map +1 -1
- package/lib/components/combobox/ComboboxMenu/ComboboxMenu.js +5 -0
- package/lib/components/combobox/ComboboxMenu/ComboboxMenu.js.map +1 -1
- package/lib/components/combobox/ComboboxMenu/Menu.styles.d.ts +4 -0
- package/lib/components/combobox/ComboboxMenu/Menu.styles.d.ts.map +1 -1
- package/lib/components/combobox/ComboboxMenu/Menu.styles.js +4 -0
- package/lib/components/combobox/ComboboxMenu/Menu.styles.js.map +1 -1
- package/lib/components/combobox/ComboboxOption.d.ts +3 -0
- package/lib/components/combobox/ComboboxOption.d.ts.map +1 -1
- package/lib/components/combobox/ComboboxOption.js +14 -0
- package/lib/components/combobox/ComboboxOption.js.map +1 -1
- package/lib/components/combobox/Menu.styles.d.ts +4 -0
- package/lib/components/combobox/Menu.styles.d.ts.map +1 -1
- package/lib/components/combobox/Menu.styles.js +7 -3
- package/lib/components/combobox/Menu.styles.js.map +1 -1
- package/lib/components/combobox/utils/OptionObjectUtils.d.ts +18 -0
- package/lib/components/combobox/utils/OptionObjectUtils.d.ts.map +1 -1
- package/lib/components/combobox/utils/OptionObjectUtils.js +18 -0
- package/lib/components/combobox/utils/OptionObjectUtils.js.map +1 -1
- package/lib/components/combobox/utils/flattenChildren.d.ts +8 -0
- package/lib/components/combobox/utils/flattenChildren.d.ts.map +1 -1
- package/lib/components/combobox/utils/flattenChildren.js +13 -1
- package/lib/components/combobox/utils/flattenChildren.js.map +1 -1
- package/lib/components/combobox/utils/getNameAndValue.d.ts +9 -0
- package/lib/components/combobox/utils/getNameAndValue.d.ts.map +1 -1
- package/lib/components/combobox/utils/getNameAndValue.js +10 -1
- package/lib/components/combobox/utils/getNameAndValue.js.map +1 -1
- package/lib/components/combobox/utils/wrapJSX.d.ts +12 -0
- package/lib/components/combobox/utils/wrapJSX.d.ts.map +1 -1
- package/lib/components/combobox/utils/wrapJSX.js +21 -0
- package/lib/components/combobox/utils/wrapJSX.js.map +1 -1
- package/lib/components/combobox-with-custom-option.js +2 -0
- package/lib/components/combobox-with-custom-option.js.map +1 -1
- package/lib/components/compass-components-provider.d.ts +23 -0
- package/lib/components/compass-components-provider.d.ts.map +1 -1
- package/lib/components/compass-components-provider.js +22 -1
- package/lib/components/compass-components-provider.js.map +1 -1
- package/lib/components/content-with-fallback.js +3 -0
- package/lib/components/content-with-fallback.js.map +1 -1
- package/lib/components/document-list/document-actions-group.js +10 -1
- package/lib/components/document-list/document-actions-group.js.map +1 -1
- package/lib/components/document-list/document-edit-actions-footer.js +3 -0
- package/lib/components/document-list/document-edit-actions-footer.js.map +1 -1
- package/lib/components/document-list/document.js +23 -1
- package/lib/components/document-list/document.js.map +1 -1
- package/lib/components/document-list/element-actions.js +2 -0
- package/lib/components/document-list/element-actions.js.map +1 -1
- package/lib/components/document-list/element-editors.js +51 -9
- package/lib/components/document-list/element-editors.js.map +1 -1
- package/lib/components/document-list/element.js +45 -5
- package/lib/components/document-list/element.js.map +1 -1
- package/lib/components/empty-content.js +1 -1
- package/lib/components/empty-content.js.map +1 -1
- package/lib/components/error-boundary.js +3 -0
- package/lib/components/error-boundary.js.map +1 -1
- package/lib/components/feedback-popover.js +3 -0
- package/lib/components/feedback-popover.js.map +1 -1
- package/lib/components/file-input.js +22 -3
- package/lib/components/file-input.js.map +1 -1
- package/lib/components/guide-cue/guide-cue-groups.js +3 -0
- package/lib/components/guide-cue/guide-cue-groups.js.map +1 -1
- package/lib/components/guide-cue/guide-cue-service.js +5 -0
- package/lib/components/guide-cue/guide-cue-service.js.map +1 -1
- package/lib/components/guide-cue/guide-cue.js +14 -1
- package/lib/components/guide-cue/guide-cue.js.map +1 -1
- package/lib/components/icons/favorite-icon.js +3 -1
- package/lib/components/icons/favorite-icon.js.map +1 -1
- package/lib/components/index-keys-badge.js +1 -0
- package/lib/components/index-keys-badge.js.map +1 -1
- package/lib/components/inline-definition.js +1 -0
- package/lib/components/inline-definition.js.map +1 -1
- package/lib/components/interactive-popover.d.ts +3 -0
- package/lib/components/interactive-popover.d.ts.map +1 -1
- package/lib/components/interactive-popover.js +6 -0
- package/lib/components/interactive-popover.js.map +1 -1
- package/lib/components/item-action-controls.d.ts +2 -1
- package/lib/components/item-action-controls.d.ts.map +1 -1
- package/lib/components/item-action-controls.js +31 -4
- package/lib/components/item-action-controls.js.map +1 -1
- package/lib/components/keyline-card.d.ts +7 -0
- package/lib/components/keyline-card.d.ts.map +1 -1
- package/lib/components/leafygreen.js +8 -0
- package/lib/components/leafygreen.js.map +1 -1
- package/lib/components/links/link.js +2 -0
- package/lib/components/links/link.js.map +1 -1
- package/lib/components/modals/modal-body.js +2 -0
- package/lib/components/modals/modal-body.js.map +1 -1
- package/lib/components/modals/modal.js +8 -0
- package/lib/components/modals/modal.js.map +1 -1
- package/lib/components/options-toggle.js +5 -1
- package/lib/components/options-toggle.js.map +1 -1
- package/lib/components/placeholder.js +1 -0
- package/lib/components/placeholder.js.map +1 -1
- package/lib/components/resize-handle.js +4 -0
- package/lib/components/resize-handle.js.map +1 -1
- package/lib/components/resizeable-sidebar.js +2 -0
- package/lib/components/resizeable-sidebar.js.map +1 -1
- package/lib/components/signal-popover.d.ts +19 -0
- package/lib/components/signal-popover.d.ts.map +1 -1
- package/lib/components/signal-popover.js +43 -3
- package/lib/components/signal-popover.js.map +1 -1
- package/lib/components/tab-nav-bar.d.ts +11 -4
- package/lib/components/tab-nav-bar.d.ts.map +1 -1
- package/lib/components/tab-nav-bar.js +14 -11
- package/lib/components/tab-nav-bar.js.map +1 -1
- package/lib/components/toast-body.js +1 -0
- package/lib/components/toast-body.js.map +1 -1
- package/lib/components/virtual-grid.d.ts +42 -0
- package/lib/components/virtual-grid.d.ts.map +1 -1
- package/lib/components/virtual-grid.js +3 -0
- package/lib/components/virtual-grid.js.map +1 -1
- package/lib/components/virtual-list.d.ts +69 -0
- package/lib/components/virtual-list.d.ts.map +1 -1
- package/lib/components/virtual-list.js +9 -1
- package/lib/components/virtual-list.js.map +1 -1
- package/lib/components/workspace-container.js +10 -0
- package/lib/components/workspace-container.js.map +1 -1
- package/lib/components/workspace-tabs/tab.js +15 -1
- package/lib/components/workspace-tabs/tab.js.map +1 -1
- package/lib/components/workspace-tabs/workspace-tabs.js +5 -1
- package/lib/components/workspace-tabs/workspace-tabs.js.map +1 -1
- package/lib/hooks/use-confirmation.js +12 -1
- package/lib/hooks/use-confirmation.js.map +1 -1
- package/lib/hooks/use-default-action.d.ts +8 -0
- package/lib/hooks/use-default-action.d.ts.map +1 -1
- package/lib/hooks/use-default-action.js +11 -1
- package/lib/hooks/use-default-action.js.map +1 -1
- package/lib/hooks/use-effect-on-change.d.ts +6 -0
- package/lib/hooks/use-effect-on-change.d.ts.map +1 -1
- package/lib/hooks/use-effect-on-change.js +18 -1
- package/lib/hooks/use-effect-on-change.js.map +1 -1
- package/lib/hooks/use-focus-ring.d.ts +19 -0
- package/lib/hooks/use-focus-ring.d.ts.map +1 -1
- package/lib/hooks/use-focus-ring.js +21 -0
- package/lib/hooks/use-focus-ring.js.map +1 -1
- package/lib/hooks/use-hotkeys.d.ts +14 -0
- package/lib/hooks/use-hotkeys.d.ts.map +1 -1
- package/lib/hooks/use-hotkeys.js +18 -3
- package/lib/hooks/use-hotkeys.js.map +1 -1
- package/lib/hooks/use-persisted-state.d.ts +9 -0
- package/lib/hooks/use-persisted-state.d.ts.map +1 -1
- package/lib/hooks/use-persisted-state.js +9 -0
- package/lib/hooks/use-persisted-state.js.map +1 -1
- package/lib/hooks/use-scrollbars.d.ts +7 -0
- package/lib/hooks/use-scrollbars.d.ts.map +1 -1
- package/lib/hooks/use-scrollbars.js +19 -0
- package/lib/hooks/use-scrollbars.js.map +1 -1
- package/lib/hooks/use-sort.js +6 -0
- package/lib/hooks/use-sort.js.map +1 -1
- package/lib/hooks/use-stacked-component.js +1 -0
- package/lib/hooks/use-stacked-component.js.map +1 -1
- package/lib/hooks/use-theme.js +10 -1
- package/lib/hooks/use-theme.js.map +1 -1
- package/lib/hooks/use-toast.d.ts +15 -0
- package/lib/hooks/use-toast.d.ts.map +1 -1
- package/lib/hooks/use-toast.js +30 -0
- package/lib/hooks/use-toast.js.map +1 -1
- package/lib/hooks/use-virtual-grid.d.ts +8 -0
- package/lib/hooks/use-virtual-grid.d.ts.map +1 -1
- package/lib/hooks/use-virtual-grid.js +29 -0
- package/lib/hooks/use-virtual-grid.js.map +1 -1
- package/lib/hooks/use-virtual-list-item-observer.js +23 -0
- package/lib/hooks/use-virtual-list-item-observer.js.map +1 -1
- package/lib/utils/format-date.js +2 -0
- package/lib/utils/format-date.js.map +1 -1
- package/lib/utils/merge-props.js +1 -0
- package/lib/utils/merge-props.js.map +1 -1
- package/lib/utils/rafraf.d.ts +10 -0
- package/lib/utils/rafraf.d.ts.map +1 -1
- package/lib/utils/rafraf.js +10 -0
- package/lib/utils/rafraf.js.map +1 -1
- package/package.json +7 -10
- package/lib/hooks/use-virtual-grid.test.d.ts +0 -2
- package/lib/hooks/use-virtual-grid.test.d.ts.map +0 -1
- package/lib/hooks/use-virtual-grid.test.js +0 -210
- package/lib/hooks/use-virtual-grid.test.js.map +0 -1
|
@@ -27,6 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.Combobox = void 0;
|
|
30
|
+
/* eslint-disable filename-rules/match */
|
|
30
31
|
const react_1 = __importStar(require("react"));
|
|
31
32
|
const clone_1 = __importDefault(require("lodash/clone"));
|
|
32
33
|
const isArray_1 = __importDefault(require("lodash/isArray"));
|
|
@@ -53,6 +54,8 @@ const ComboboxOption_1 = require("./ComboboxOption");
|
|
|
53
54
|
const utils_1 = require("./utils");
|
|
54
55
|
const tokens_1 = require("@leafygreen-ui/tokens");
|
|
55
56
|
const descriptionWidth = tokens_1.spacing[5] * 14;
|
|
57
|
+
// By default we want the menu option to be the same width as the input
|
|
58
|
+
// If the user has specified a description, we add extra space to fit the description.
|
|
56
59
|
const popoverMenuStyles = (width, numDescChars) => {
|
|
57
60
|
if (numDescChars === 0) {
|
|
58
61
|
return (0, emotion_1.css) `
|
|
@@ -70,6 +73,11 @@ const popoverMenuStyles = (width, numDescChars) => {
|
|
|
70
73
|
);
|
|
71
74
|
`;
|
|
72
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* Combobox is a combination of a Select and TextInput,
|
|
78
|
+
* allowing the user to either type a value directly or select a value from the list.
|
|
79
|
+
* Can be configured to select a single or multiple options.
|
|
80
|
+
*/
|
|
73
81
|
function Combobox({ children, label, description, placeholder = 'Select', 'aria-label': ariaLabel, disabled = false, size = Combobox_types_1.ComboboxSize.Default, darkMode: darkModeProp, state = 'none', errorMessage, searchState = 'unset', searchEmptyMessage = 'No results found', searchErrorMessage = 'Could not get results!', searchLoadingMessage = 'Loading results...', filteredOptions, onFilter, clearable = true, onClear, overflow = 'expand-y', multiselect = false, initialValue, onChange, value, chipTruncationLocation, chipCharacterLimit = 12, className, usePortal = true, portalClassName, portalContainer, scrollContainer, popoverZIndex, popoverClassName, ...rest }) {
|
|
74
82
|
const { darkMode, theme } = (0, leafygreen_provider_1.useDarkMode)(darkModeProp);
|
|
75
83
|
const getOptionRef = (0, hooks_1.useDynamicRefs)({ prefix: 'option' });
|
|
@@ -97,7 +105,13 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
97
105
|
: placeholder;
|
|
98
106
|
const closeMenu = () => setOpen(false);
|
|
99
107
|
const openMenu = () => setOpen(true);
|
|
108
|
+
/**
|
|
109
|
+
* Array of all of the options objects
|
|
110
|
+
*/
|
|
100
111
|
const allOptions = (0, react_1.useMemo)(() => (0, utils_1.flattenChildren)(children), [children]);
|
|
112
|
+
/**
|
|
113
|
+
* Utility function that tells Typescript whether selection is multiselect
|
|
114
|
+
*/
|
|
101
115
|
const isMultiselect = (0, react_1.useCallback)((val) => {
|
|
102
116
|
if (multiselect && (typeof val === 'string' || typeof val === 'number')) {
|
|
103
117
|
lib_1.consoleOnce.error(`Error in Combobox: multiselect is set to \`true\`, but received a ${typeof val} value: "${val}"`);
|
|
@@ -107,6 +121,10 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
107
121
|
}
|
|
108
122
|
return multiselect && (0, isArray_1.default)(val);
|
|
109
123
|
}, [multiselect]);
|
|
124
|
+
/**
|
|
125
|
+
* Forces focus of input box
|
|
126
|
+
* @param cursorPos index the cursor should be set to
|
|
127
|
+
*/
|
|
110
128
|
const setInputFocus = (0, react_1.useCallback)((cursorPos) => {
|
|
111
129
|
if (!disabled && inputRef && inputRef.current) {
|
|
112
130
|
inputRef.current.focus();
|
|
@@ -115,18 +133,27 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
115
133
|
}
|
|
116
134
|
}
|
|
117
135
|
}, [disabled]);
|
|
136
|
+
/**
|
|
137
|
+
* Update selection.
|
|
138
|
+
* This behaves differently in multi. vs single select.
|
|
139
|
+
* @param value option value the selection should be set to
|
|
140
|
+
*/
|
|
118
141
|
const updateSelection = (0, react_1.useCallback)((value) => {
|
|
119
142
|
if (isMultiselect(selection)) {
|
|
143
|
+
// We know M is true here
|
|
120
144
|
const newSelection = (0, clone_1.default)(selection);
|
|
121
145
|
if ((0, isNull_1.default)(value)) {
|
|
122
146
|
newSelection.length = 0;
|
|
123
147
|
}
|
|
124
148
|
else {
|
|
125
149
|
if (selection.includes(value)) {
|
|
150
|
+
// remove from array
|
|
126
151
|
newSelection.splice(newSelection.indexOf(value), 1);
|
|
127
152
|
}
|
|
128
153
|
else {
|
|
154
|
+
// add to array
|
|
129
155
|
newSelection.push(value);
|
|
156
|
+
// clear text
|
|
130
157
|
setInputValue('');
|
|
131
158
|
}
|
|
132
159
|
}
|
|
@@ -139,15 +166,28 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
139
166
|
onChange?.(newSelection);
|
|
140
167
|
}
|
|
141
168
|
}, [isMultiselect, onChange, selection]);
|
|
169
|
+
/**
|
|
170
|
+
* Returns whether a given value is included in, or equal to, the current selection
|
|
171
|
+
* @param value the option value to check
|
|
172
|
+
*/
|
|
142
173
|
const isValueCurrentSelection = (0, react_1.useCallback)((value) => {
|
|
143
174
|
return isMultiselect(selection)
|
|
144
175
|
? selection.includes(value)
|
|
145
176
|
: value === selection;
|
|
146
177
|
}, [isMultiselect, selection]);
|
|
178
|
+
/**
|
|
179
|
+
* Returns whether given text is included in, or equal to, the current selection.
|
|
180
|
+
* Similar to `isValueCurrentSelection`, but assumes the text argument is the `displayName` for the selection
|
|
181
|
+
* @param text the text to check
|
|
182
|
+
*/
|
|
147
183
|
const isTextCurrentSelection = (0, react_1.useCallback)((text) => {
|
|
148
184
|
const value = (0, utils_1.getValueForDisplayName)(text, allOptions);
|
|
149
185
|
return isValueCurrentSelection(value);
|
|
150
186
|
}, [allOptions, isValueCurrentSelection]);
|
|
187
|
+
/**
|
|
188
|
+
* Returns whether the provided option is disabled
|
|
189
|
+
* @param option the option value or OptionObject to check
|
|
190
|
+
*/
|
|
151
191
|
const isOptionDisabled = (option) => {
|
|
152
192
|
if (typeof option === 'string') {
|
|
153
193
|
const optionObj = (0, utils_1.getOptionObjectFromValue)(option, allOptions);
|
|
@@ -157,14 +197,23 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
157
197
|
return !!option.isDisabled;
|
|
158
198
|
}
|
|
159
199
|
};
|
|
200
|
+
/**
|
|
201
|
+
* Computes whether the option is visible based on the current input
|
|
202
|
+
* @param option the option value or OptionObject to compute
|
|
203
|
+
*/
|
|
160
204
|
const shouldOptionBeVisible = (0, react_1.useCallback)((option) => {
|
|
161
205
|
const value = typeof option === 'string' ? option : option.value;
|
|
206
|
+
// If filtered options are provided
|
|
162
207
|
if (filteredOptions && filteredOptions.length > 0) {
|
|
163
208
|
return filteredOptions.includes(value);
|
|
164
209
|
}
|
|
210
|
+
// If the text input value is the current selection
|
|
211
|
+
// (or included in the selection)
|
|
212
|
+
// then all options should be visible
|
|
165
213
|
if (isTextCurrentSelection(inputValue)) {
|
|
166
214
|
return true;
|
|
167
215
|
}
|
|
216
|
+
// otherwise, we do our own filtering
|
|
168
217
|
const displayName = typeof option === 'string'
|
|
169
218
|
? (0, utils_1.getDisplayNameForValue)(value, allOptions)
|
|
170
219
|
: option.displayName;
|
|
@@ -173,30 +222,58 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
173
222
|
.includes(inputValue.toLowerCase());
|
|
174
223
|
return isValueInDisplayName;
|
|
175
224
|
}, [filteredOptions, isTextCurrentSelection, inputValue, allOptions]);
|
|
225
|
+
/**
|
|
226
|
+
* The array of visible options objects
|
|
227
|
+
*/
|
|
176
228
|
const visibleOptions = (0, react_1.useMemo)(() => allOptions.filter(shouldOptionBeVisible), [allOptions, shouldOptionBeVisible]);
|
|
229
|
+
/**
|
|
230
|
+
* Returns whether the given value is in the options array
|
|
231
|
+
* @param value the value to check
|
|
232
|
+
*/
|
|
177
233
|
const isValueValid = (0, react_1.useCallback)((value) => {
|
|
178
234
|
return value ? !!allOptions.find((opt) => opt.value === value) : false;
|
|
179
235
|
}, [allOptions]);
|
|
236
|
+
/**
|
|
237
|
+
* Returns the index of a given value in the array of visible (filtered) options
|
|
238
|
+
* @param value the option value to get the index of
|
|
239
|
+
*/
|
|
180
240
|
const getIndexOfValue = (0, react_1.useCallback)((value) => {
|
|
181
241
|
return visibleOptions
|
|
182
242
|
? visibleOptions.findIndex((option) => option.value === value)
|
|
183
243
|
: -1;
|
|
184
244
|
}, [visibleOptions]);
|
|
245
|
+
/**
|
|
246
|
+
* Returns the option value of a given index in the array of visible (filtered) options
|
|
247
|
+
* @param index the option index to get the value of
|
|
248
|
+
*/
|
|
185
249
|
const getValueAtIndex = (0, react_1.useCallback)((index) => {
|
|
186
250
|
if (visibleOptions && visibleOptions.length >= index) {
|
|
187
251
|
const option = visibleOptions[index];
|
|
188
252
|
return option ? option.value : undefined;
|
|
189
253
|
}
|
|
190
254
|
}, [visibleOptions]);
|
|
255
|
+
/**
|
|
256
|
+
* Returns the index of the active chip in the selection array
|
|
257
|
+
*/
|
|
191
258
|
const getActiveChipIndex = (0, react_1.useCallback)(() => isMultiselect(selection)
|
|
192
259
|
? selection.findIndex((value) => getChipRef(value)?.current?.contains(document.activeElement))
|
|
193
260
|
: -1, [getChipRef, isMultiselect, selection]);
|
|
261
|
+
/**
|
|
262
|
+
*
|
|
263
|
+
* Focus Management
|
|
264
|
+
*
|
|
265
|
+
*/
|
|
194
266
|
const [focusedElementName, trackFocusedElement] = (0, react_1.useState)();
|
|
195
267
|
const isElementFocused = (elementName) => elementName === focusedElementName;
|
|
268
|
+
/**
|
|
269
|
+
* Updates the highlighted menu option based on the provided direction
|
|
270
|
+
* @param direction the direction to move the focus. `'next' | 'prev' | 'first' | 'last'`
|
|
271
|
+
*/
|
|
196
272
|
const updateHighlightedOption = (0, react_1.useCallback)((direction) => {
|
|
197
273
|
const optionsCount = visibleOptions?.length ?? 0;
|
|
198
274
|
const lastIndex = optionsCount - 1 > 0 ? optionsCount - 1 : 0;
|
|
199
275
|
const indexOfHighlight = getIndexOfValue(highlightedOption);
|
|
276
|
+
// Remove focus from chip
|
|
200
277
|
if (direction && isOpen) {
|
|
201
278
|
setFocusedChip(null);
|
|
202
279
|
setInputFocus();
|
|
@@ -235,6 +312,11 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
235
312
|
setInputFocus,
|
|
236
313
|
visibleOptions?.length,
|
|
237
314
|
]);
|
|
315
|
+
/**
|
|
316
|
+
* Updates the focused chip based on the provided direction
|
|
317
|
+
* @param direction the direction to move the focus. `'next' | 'prev' | 'first' | 'last'`
|
|
318
|
+
* @param relativeToIndex the chip index to move focus relative to
|
|
319
|
+
*/
|
|
238
320
|
const updateFocusedChip = (0, react_1.useCallback)((direction, relativeToIndex) => {
|
|
239
321
|
if (isMultiselect(selection)) {
|
|
240
322
|
switch (direction) {
|
|
@@ -274,13 +356,18 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
274
356
|
}
|
|
275
357
|
}
|
|
276
358
|
}, [getActiveChipIndex, isMultiselect, selection]);
|
|
359
|
+
/**
|
|
360
|
+
* Handles an arrow key press
|
|
361
|
+
*/
|
|
277
362
|
const handleArrowKey = (0, react_1.useCallback)((direction, event) => {
|
|
363
|
+
// Remove focus from menu
|
|
278
364
|
if (direction)
|
|
279
365
|
setHighlightedOption(null);
|
|
280
366
|
switch (direction) {
|
|
281
367
|
case 'right':
|
|
282
368
|
switch (focusedElementName) {
|
|
283
369
|
case Combobox_types_1.ComboboxElement.Input: {
|
|
370
|
+
// If cursor is at the end of the input
|
|
284
371
|
if (inputRef.current?.selectionEnd ===
|
|
285
372
|
inputRef.current?.value.length) {
|
|
286
373
|
clearButtonRef.current?.focus();
|
|
@@ -291,12 +378,15 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
291
378
|
case Combobox_types_1.ComboboxElement.MiddleChip:
|
|
292
379
|
case Combobox_types_1.ComboboxElement.LastChip: {
|
|
293
380
|
if (focusedElementName === Combobox_types_1.ComboboxElement.LastChip ||
|
|
381
|
+
// the first chip is also the last chip (i.e. only one)
|
|
294
382
|
selection?.length === 1) {
|
|
383
|
+
// if focus is on last chip, go to input
|
|
295
384
|
setInputFocus(0);
|
|
296
385
|
updateFocusedChip(null);
|
|
297
386
|
event.preventDefault();
|
|
298
387
|
break;
|
|
299
388
|
}
|
|
389
|
+
// First/middle chips
|
|
300
390
|
updateFocusedChip('next');
|
|
301
391
|
break;
|
|
302
392
|
}
|
|
@@ -316,6 +406,7 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
316
406
|
case Combobox_types_1.ComboboxElement.MiddleChip:
|
|
317
407
|
case Combobox_types_1.ComboboxElement.LastChip: {
|
|
318
408
|
if (isMultiselect(selection)) {
|
|
409
|
+
// Break if cursor is not at the start of the input
|
|
319
410
|
if (focusedElementName === Combobox_types_1.ComboboxElement.Input &&
|
|
320
411
|
inputRef.current?.selectionStart !== 0) {
|
|
321
412
|
break;
|
|
@@ -340,11 +431,14 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
340
431
|
setInputFocus,
|
|
341
432
|
updateFocusedChip,
|
|
342
433
|
]);
|
|
434
|
+
// When the input value changes (or when the menu opens)
|
|
435
|
+
// Update the focused option
|
|
343
436
|
(0, react_1.useEffect)(() => {
|
|
344
437
|
if (inputValue !== prevValue) {
|
|
345
438
|
updateHighlightedOption('first');
|
|
346
439
|
}
|
|
347
440
|
}, [inputValue, isOpen, prevValue, updateHighlightedOption]);
|
|
441
|
+
// When the focused option changes, update the menu scroll if necessary
|
|
348
442
|
(0, react_1.useEffect)(() => {
|
|
349
443
|
if (highlightedOption) {
|
|
350
444
|
const focusedElementRef = getOptionRef(highlightedOption);
|
|
@@ -357,6 +451,12 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
357
451
|
}
|
|
358
452
|
}
|
|
359
453
|
}, [highlightedOption, getOptionRef]);
|
|
454
|
+
/**
|
|
455
|
+
* Rendering
|
|
456
|
+
*/
|
|
457
|
+
/**
|
|
458
|
+
* Callback to render a child as an <InternalComboboxOption> element
|
|
459
|
+
*/
|
|
360
460
|
const renderOption = (0, react_1.useCallback)((child) => {
|
|
361
461
|
if ((0, lib_1.isComponentType)(child, 'ComboboxOption')) {
|
|
362
462
|
const { value, displayName } = (0, utils_1.getNameAndValue)(child.props);
|
|
@@ -395,7 +495,13 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
395
495
|
shouldOptionBeVisible,
|
|
396
496
|
updateSelection,
|
|
397
497
|
]);
|
|
498
|
+
/**
|
|
499
|
+
* The rendered JSX elements for the options
|
|
500
|
+
*/
|
|
398
501
|
const renderedOptionsJSX = (0, react_1.useMemo)(() => react_1.default.Children.map(children, renderOption), [children, renderOption]);
|
|
502
|
+
/**
|
|
503
|
+
* The rendered JSX for the selection Chips
|
|
504
|
+
*/
|
|
399
505
|
const renderedChips = (0, react_1.useMemo)(() => {
|
|
400
506
|
if (isMultiselect(selection)) {
|
|
401
507
|
return selection.filter(isValueValid).map((value, index) => {
|
|
@@ -405,6 +511,7 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
405
511
|
const isLastChip = index >= selection.length - 1;
|
|
406
512
|
const onRemove = () => {
|
|
407
513
|
if (isLastChip) {
|
|
514
|
+
// Focus the input if this is the last chip in the set
|
|
408
515
|
setInputFocus();
|
|
409
516
|
updateFocusedChip(null);
|
|
410
517
|
}
|
|
@@ -433,6 +540,9 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
433
540
|
const handleClearButtonFocus = () => {
|
|
434
541
|
setHighlightedOption(null);
|
|
435
542
|
};
|
|
543
|
+
/**
|
|
544
|
+
* The rendered JSX for the input icons (clear, warn & caret)
|
|
545
|
+
*/
|
|
436
546
|
const renderedInputIcons = (0, react_1.useMemo)(() => {
|
|
437
547
|
const handleClearButtonClick = (e) => {
|
|
438
548
|
if (!disabled) {
|
|
@@ -460,14 +570,27 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
460
570
|
onFilter,
|
|
461
571
|
isOpen,
|
|
462
572
|
]);
|
|
573
|
+
/**
|
|
574
|
+
* Flag to determine whether the rendered options have icons
|
|
575
|
+
*/
|
|
463
576
|
const withIcons = (0, react_1.useMemo)(() => allOptions.some((opt) => opt.hasGlyph), [allOptions]);
|
|
577
|
+
/**
|
|
578
|
+
*
|
|
579
|
+
* Selection Management
|
|
580
|
+
*
|
|
581
|
+
*/
|
|
464
582
|
const onCloseMenu = (0, react_1.useCallback)(() => {
|
|
583
|
+
// Single select, and no change to selection
|
|
465
584
|
if (!isMultiselect(selection) && selection === prevSelection) {
|
|
466
585
|
const exactMatchedOption = visibleOptions.find((option) => option.displayName === inputValue || option.value === inputValue);
|
|
586
|
+
// check if inputValue is matches a valid option
|
|
587
|
+
// Set the selection to that value if the component is not controlled
|
|
467
588
|
if (exactMatchedOption && !value) {
|
|
468
589
|
setSelection(exactMatchedOption.value);
|
|
469
590
|
}
|
|
470
591
|
else if (selection) {
|
|
592
|
+
// Revert the value to the previous selection.
|
|
593
|
+
// Set the value instead of displayName to align with handleInputChange COMPASS-6511
|
|
471
594
|
setInputValue(selection);
|
|
472
595
|
}
|
|
473
596
|
}
|
|
@@ -483,9 +606,12 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
483
606
|
const onSelect = (0, react_1.useCallback)(() => {
|
|
484
607
|
if (doesSelectionExist) {
|
|
485
608
|
if (isMultiselect(selection)) {
|
|
609
|
+
// Scroll the wrapper to the end. No effect if not `overflow="scroll-x"`
|
|
486
610
|
scrollInputToEnd();
|
|
487
611
|
}
|
|
488
612
|
else if (!isMultiselect(selection)) {
|
|
613
|
+
// Update the text input.
|
|
614
|
+
// Set the value instead of displayName to align with handleInputChange COMPASS-6511
|
|
489
615
|
setInputValue(selection);
|
|
490
616
|
closeMenu();
|
|
491
617
|
}
|
|
@@ -494,9 +620,11 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
494
620
|
setInputValue('');
|
|
495
621
|
}
|
|
496
622
|
}, [doesSelectionExist, allOptions, isMultiselect, selection]);
|
|
623
|
+
// Set the initialValue
|
|
497
624
|
(0, react_1.useEffect)(() => {
|
|
498
625
|
if (initialValue) {
|
|
499
626
|
if ((0, isArray_1.default)(initialValue)) {
|
|
627
|
+
// Ensure the values we set are real options
|
|
500
628
|
const filteredValue = initialValue.filter((value) => isValueValid(value)) ?? [];
|
|
501
629
|
setSelection(filteredValue);
|
|
502
630
|
}
|
|
@@ -509,13 +637,16 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
509
637
|
else {
|
|
510
638
|
setSelection((0, Combobox_types_1.getNullSelection)(multiselect));
|
|
511
639
|
}
|
|
640
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
512
641
|
}, []);
|
|
642
|
+
// When controlled value changes, update the selection
|
|
513
643
|
(0, react_1.useEffect)(() => {
|
|
514
644
|
if (!(0, isUndefined_1.default)(value) && value !== prevValue) {
|
|
515
645
|
if ((0, isNull_1.default)(value)) {
|
|
516
646
|
setSelection(null);
|
|
517
647
|
}
|
|
518
648
|
else if (isMultiselect(value)) {
|
|
649
|
+
// Ensure the value(s) passed in are valid options
|
|
519
650
|
const newSelection = value.filter(isValueValid);
|
|
520
651
|
setSelection(newSelection);
|
|
521
652
|
}
|
|
@@ -524,29 +655,49 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
524
655
|
}
|
|
525
656
|
}
|
|
526
657
|
}, [isMultiselect, isValueValid, prevValue, value]);
|
|
658
|
+
// onSelect
|
|
659
|
+
// Side effects to run when the selection changes
|
|
527
660
|
(0, react_1.useEffect)(() => {
|
|
528
661
|
if (!(0, isEqual_1.default)(selection, prevSelection)) {
|
|
529
662
|
onSelect();
|
|
530
663
|
}
|
|
531
664
|
}, [onSelect, prevSelection, selection]);
|
|
665
|
+
// when the menu closes, update the value if needed
|
|
532
666
|
(0, react_1.useEffect)(() => {
|
|
533
667
|
if (!isOpen && wasOpen) {
|
|
534
668
|
onCloseMenu();
|
|
535
669
|
}
|
|
536
670
|
}, [isOpen, wasOpen, onCloseMenu]);
|
|
671
|
+
/**
|
|
672
|
+
*
|
|
673
|
+
* Menu management
|
|
674
|
+
*
|
|
675
|
+
*/
|
|
537
676
|
const [popoverMenuWidth, setPopoverMenuWidth] = (0, react_1.useState)(0);
|
|
677
|
+
// When the menu opens, or the selection changes, or the focused option changes
|
|
678
|
+
// update the menu width
|
|
538
679
|
(0, react_1.useEffect)(() => {
|
|
539
680
|
setPopoverMenuWidth(comboboxRef.current?.clientWidth ?? 0);
|
|
540
681
|
}, [comboboxRef, isOpen, highlightedOption, selection]);
|
|
682
|
+
// Handler fired when the menu has finished transitioning in/out
|
|
541
683
|
const handleTransitionEnd = () => {
|
|
542
684
|
setPopoverMenuWidth(comboboxRef.current?.clientWidth ?? 0);
|
|
543
685
|
};
|
|
686
|
+
/**
|
|
687
|
+
*
|
|
688
|
+
* Event Handlers
|
|
689
|
+
*
|
|
690
|
+
*/
|
|
691
|
+
// Prevent combobox from gaining focus by default
|
|
544
692
|
const handleInputWrapperMousedown = (e) => {
|
|
545
693
|
if (disabled) {
|
|
546
694
|
e.preventDefault();
|
|
547
695
|
}
|
|
548
696
|
};
|
|
697
|
+
// Set focus to the input element on click
|
|
549
698
|
const handleComboboxClick = (e) => {
|
|
699
|
+
// If we clicked the wrapper, not the input itself.
|
|
700
|
+
// (Focus is set automatically if the click is on the input)
|
|
550
701
|
if (e.target !== inputRef.current) {
|
|
551
702
|
let cursorPos = 0;
|
|
552
703
|
if (inputRef.current) {
|
|
@@ -556,21 +707,29 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
556
707
|
}
|
|
557
708
|
setInputFocus(cursorPos);
|
|
558
709
|
}
|
|
710
|
+
// Only open the menu in response to a click
|
|
559
711
|
openMenu();
|
|
560
712
|
};
|
|
713
|
+
// Fired whenever the wrapper gains focus,
|
|
714
|
+
// and any time the focus within changes
|
|
561
715
|
const handleComboboxFocus = (e) => {
|
|
562
716
|
scrollInputToEnd();
|
|
563
717
|
trackFocusedElement(getNameFromElement(e.target));
|
|
564
718
|
};
|
|
719
|
+
// Fired onChange
|
|
565
720
|
const handleInputChange = ({ target: { value }, }) => {
|
|
566
721
|
setInputValue(value);
|
|
722
|
+
// fire any filter function passed in
|
|
567
723
|
onFilter?.(value);
|
|
568
724
|
};
|
|
569
725
|
const handleKeyDown = (event) => {
|
|
570
726
|
const isFocusInMenu = menuRef.current?.contains(document.activeElement);
|
|
571
727
|
const isFocusOnCombobox = comboboxRef.current?.contains(document.activeElement);
|
|
572
728
|
const isFocusInComponent = isFocusOnCombobox || isFocusInMenu;
|
|
729
|
+
// Only run if the focus is in the component
|
|
573
730
|
if (isFocusInComponent) {
|
|
731
|
+
// No support for modifiers yet
|
|
732
|
+
// TODO - Handle support for multiple chip selection
|
|
574
733
|
if (event.ctrlKey || event.shiftKey || event.altKey) {
|
|
575
734
|
return;
|
|
576
735
|
}
|
|
@@ -583,14 +742,17 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
583
742
|
updateHighlightedOption('first');
|
|
584
743
|
updateFocusedChip(null);
|
|
585
744
|
}
|
|
745
|
+
// else use default behavior
|
|
586
746
|
break;
|
|
587
747
|
}
|
|
588
748
|
case 'LastChip': {
|
|
749
|
+
// use default behavior
|
|
589
750
|
updateFocusedChip(null);
|
|
590
751
|
break;
|
|
591
752
|
}
|
|
592
753
|
case 'FirstChip':
|
|
593
754
|
case 'MiddleChip': {
|
|
755
|
+
// use default behavior
|
|
594
756
|
break;
|
|
595
757
|
}
|
|
596
758
|
case 'ClearButton':
|
|
@@ -606,32 +768,45 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
606
768
|
}
|
|
607
769
|
case lib_1.keyMap.Enter: {
|
|
608
770
|
if (!isOpen) {
|
|
771
|
+
// If the menu is not open, enter should open the menu
|
|
609
772
|
openMenu();
|
|
610
773
|
}
|
|
611
|
-
else if (
|
|
774
|
+
else if (
|
|
775
|
+
// Select the highlighted option iff
|
|
776
|
+
// the menu is open,
|
|
777
|
+
// we're focused on input element,
|
|
778
|
+
// and the highlighted option is not disabled
|
|
779
|
+
focusedElementName === Combobox_types_1.ComboboxElement.Input &&
|
|
612
780
|
!(0, isNull_1.default)(highlightedOption) &&
|
|
613
781
|
!isOptionDisabled(highlightedOption)) {
|
|
614
782
|
updateSelection(highlightedOption);
|
|
615
783
|
}
|
|
616
|
-
else if (
|
|
784
|
+
else if (
|
|
785
|
+
// Focused on clear button
|
|
786
|
+
focusedElementName === Combobox_types_1.ComboboxElement.ClearButton) {
|
|
617
787
|
updateSelection(null);
|
|
618
788
|
setInputFocus();
|
|
619
789
|
}
|
|
620
790
|
break;
|
|
621
791
|
}
|
|
622
792
|
case lib_1.keyMap.Backspace: {
|
|
793
|
+
// Backspace key focuses last chip if the input is focused
|
|
794
|
+
// Note: Chip removal behavior is handled in `onRemove` defined in `renderChips`
|
|
623
795
|
if (isMultiselect(selection)) {
|
|
624
796
|
if (focusedElementName === 'Input' &&
|
|
625
797
|
inputRef.current?.selectionStart === 0) {
|
|
626
798
|
updateFocusedChip('last');
|
|
627
799
|
}
|
|
628
800
|
}
|
|
801
|
+
// Open the menu regardless
|
|
629
802
|
openMenu();
|
|
630
803
|
break;
|
|
631
804
|
}
|
|
632
805
|
case lib_1.keyMap.ArrowDown: {
|
|
633
806
|
if (isOpen) {
|
|
807
|
+
// Prevent the page from scrolling
|
|
634
808
|
event.preventDefault();
|
|
809
|
+
// only change option if the menu is already open
|
|
635
810
|
updateHighlightedOption('next');
|
|
636
811
|
}
|
|
637
812
|
else {
|
|
@@ -641,7 +816,9 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
641
816
|
}
|
|
642
817
|
case lib_1.keyMap.ArrowUp: {
|
|
643
818
|
if (isOpen) {
|
|
819
|
+
// Prevent the page from scrolling
|
|
644
820
|
event.preventDefault();
|
|
821
|
+
// only change option if the menu is already open
|
|
645
822
|
updateHighlightedOption('prev');
|
|
646
823
|
}
|
|
647
824
|
else {
|
|
@@ -665,17 +842,34 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
665
842
|
}
|
|
666
843
|
}
|
|
667
844
|
};
|
|
845
|
+
/**
|
|
846
|
+
*
|
|
847
|
+
* Global Event Handler
|
|
848
|
+
*
|
|
849
|
+
*/
|
|
850
|
+
/**
|
|
851
|
+
* We add two event handlers to the document to handle the backdrop click behavior.
|
|
852
|
+
* Intended behavior is to close the menu, and keep focus on the Combobox.
|
|
853
|
+
* No other click event handlers should fire on backdrop click
|
|
854
|
+
*
|
|
855
|
+
* 1. Mousedown event fires
|
|
856
|
+
* 2. We prevent `mousedown`'s default behavior, to prevent focus from being applied to the body (or other target)
|
|
857
|
+
* 3. Click event fires
|
|
858
|
+
* 4. We handle this event on _capture_, and stop propagation before the `click` event propagates all the way to any other element.
|
|
859
|
+
* This ensures that even if we click on a button, that handler is not fired
|
|
860
|
+
* 5. Then we call `closeMenu`, setting `isOpen = false`, and rerender the component
|
|
861
|
+
*/
|
|
668
862
|
(0, hooks_1.useEventListener)('mousedown', (mousedown) => {
|
|
669
863
|
if (!doesComponentContainEventTarget(mousedown)) {
|
|
670
|
-
mousedown.preventDefault();
|
|
671
|
-
mousedown.stopPropagation();
|
|
864
|
+
mousedown.preventDefault(); // Prevent focus from being applied to body
|
|
865
|
+
mousedown.stopPropagation(); // Stop any other mousedown events from firing
|
|
672
866
|
}
|
|
673
867
|
}, {
|
|
674
868
|
enabled: isOpen,
|
|
675
869
|
});
|
|
676
870
|
(0, hooks_1.useEventListener)('click', (click) => {
|
|
677
871
|
if (!doesComponentContainEventTarget(click)) {
|
|
678
|
-
click.stopPropagation();
|
|
872
|
+
click.stopPropagation(); // Stop any other click events from firing
|
|
679
873
|
closeMenu();
|
|
680
874
|
}
|
|
681
875
|
}, {
|
|
@@ -710,6 +904,12 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
710
904
|
chipTruncationLocation,
|
|
711
905
|
chipCharacterLimit,
|
|
712
906
|
inputValue,
|
|
907
|
+
// When we open the menu (popover), we want the width of
|
|
908
|
+
// menu options to be same as the size of the input by default.
|
|
909
|
+
// If user has specifed a description with the option, we want
|
|
910
|
+
// the width of the option display value to be the same as the
|
|
911
|
+
// width of the input and the accomodate the description
|
|
912
|
+
// in rest of the popover width.
|
|
713
913
|
searchInputSize: popoverMenuWidth,
|
|
714
914
|
} },
|
|
715
915
|
react_1.default.createElement("div", { className: (0, emotion_1.cx)((0, Combobox_styles_1.comboboxParentStyle)(size), className), ...rest },
|
|
@@ -733,16 +933,29 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
733
933
|
renderedInputIcons),
|
|
734
934
|
state === 'error' && errorMessage && (react_1.default.createElement("div", { className: (0, emotion_1.cx)(Combobox_styles_1.errorMessageThemeStyle[theme], Combobox_styles_1.errorMessageSizeStyle[size]) }, errorMessage)),
|
|
735
935
|
react_1.default.createElement(ComboboxMenu_1.ComboboxMenu, { id: menuId, labelId: labelId, refEl: comboboxRef, ref: menuRef, className: (0, emotion_1.cx)(popoverMenuStyles(popoverMenuWidth, descriptionCharacters), popoverClassName), searchLoadingMessage: searchLoadingMessage, searchErrorMessage: searchErrorMessage, searchEmptyMessage: searchEmptyMessage, ...popoverProps }, renderedOptionsJSX))));
|
|
936
|
+
// Closure-dependant utils
|
|
937
|
+
/**
|
|
938
|
+
* Returns whether the event target is a Combobox element
|
|
939
|
+
*/
|
|
736
940
|
function doesComponentContainEventTarget({ target }) {
|
|
737
941
|
return (menuRef.current?.contains(target) ||
|
|
738
942
|
comboboxRef.current?.contains(target) ||
|
|
739
943
|
false);
|
|
740
944
|
}
|
|
945
|
+
/**
|
|
946
|
+
* Scrolls the combobox to the far right.
|
|
947
|
+
* Used when `overflow === 'scroll-x'`.
|
|
948
|
+
* Has no effect otherwise
|
|
949
|
+
*/
|
|
741
950
|
function scrollInputToEnd() {
|
|
742
951
|
if (inputWrapperRef && inputWrapperRef.current) {
|
|
952
|
+
// TODO - consider converting to .scrollTo(). This is not yet supported in IE or jsdom
|
|
743
953
|
inputWrapperRef.current.scrollLeft = inputWrapperRef.current.scrollWidth;
|
|
744
954
|
}
|
|
745
955
|
}
|
|
956
|
+
/**
|
|
957
|
+
* Returns the provided element as a ComboboxElement string
|
|
958
|
+
*/
|
|
746
959
|
function getNameFromElement(element) {
|
|
747
960
|
if (!element)
|
|
748
961
|
return;
|
|
@@ -769,6 +982,7 @@ function Combobox({ children, label, description, placeholder = 'Select', 'aria-
|
|
|
769
982
|
}
|
|
770
983
|
exports.Combobox = Combobox;
|
|
771
984
|
Combobox.propTypes = {
|
|
985
|
+
// Multiselect props
|
|
772
986
|
multiselect: prop_types_1.default.bool,
|
|
773
987
|
value: prop_types_1.default.oneOfType([
|
|
774
988
|
prop_types_1.default.string,
|
|
@@ -779,6 +993,7 @@ Combobox.propTypes = {
|
|
|
779
993
|
prop_types_1.default.arrayOf(prop_types_1.default.string),
|
|
780
994
|
]),
|
|
781
995
|
overflow: prop_types_1.default.oneOf(Object.values(Combobox_types_1.Overflow)),
|
|
996
|
+
// Standard Props
|
|
782
997
|
darkMode: prop_types_1.default.bool,
|
|
783
998
|
label: prop_types_1.default.string,
|
|
784
999
|
'aria-label': prop_types_1.default.string,
|
|
@@ -800,10 +1015,15 @@ Combobox.propTypes = {
|
|
|
800
1015
|
description: prop_types_1.default.string,
|
|
801
1016
|
placeholder: prop_types_1.default.string,
|
|
802
1017
|
filteredOptions: prop_types_1.default.arrayOf(prop_types_1.default.string),
|
|
1018
|
+
// Popover Props
|
|
803
1019
|
popoverZIndex: prop_types_1.default.number,
|
|
804
1020
|
usePortal: prop_types_1.default.bool,
|
|
805
1021
|
scrollContainer: prop_types_1.default.elementType,
|
|
806
1022
|
portalContainer: prop_types_1.default.elementType,
|
|
807
1023
|
portalClassName: prop_types_1.default.string,
|
|
808
1024
|
};
|
|
1025
|
+
/**
|
|
1026
|
+
* Why'd you have to go and make things so complicated?
|
|
1027
|
+
* - Avril; and also me to myself about this component
|
|
1028
|
+
*/
|
|
809
1029
|
//# sourceMappingURL=Combobox.js.map
|