@mongodb-js/compass-components 1.32.1 → 1.32.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.
Files changed (169) hide show
  1. package/lib/components/actions/action-glyph.d.ts +11 -0
  2. package/lib/components/actions/action-glyph.d.ts.map +1 -0
  3. package/lib/components/actions/action-glyph.js +19 -0
  4. package/lib/components/actions/action-glyph.js.map +1 -0
  5. package/lib/components/actions/constants.d.ts +7 -0
  6. package/lib/components/actions/constants.d.ts.map +1 -0
  7. package/lib/components/actions/constants.js +9 -0
  8. package/lib/components/actions/constants.js.map +1 -0
  9. package/lib/components/actions/dropdown-menu-button.d.ts +19 -0
  10. package/lib/components/actions/dropdown-menu-button.d.ts.map +1 -0
  11. package/lib/components/actions/dropdown-menu-button.js +75 -0
  12. package/lib/components/actions/dropdown-menu-button.js.map +1 -0
  13. package/lib/components/actions/item-action-button.d.ts +4 -0
  14. package/lib/components/actions/item-action-button.d.ts.map +1 -0
  15. package/lib/components/actions/item-action-button.js +22 -0
  16. package/lib/components/actions/item-action-button.js.map +1 -0
  17. package/lib/components/actions/item-action-controls.d.ts +20 -0
  18. package/lib/components/actions/item-action-controls.d.ts.map +1 -0
  19. package/lib/components/actions/item-action-controls.js +85 -0
  20. package/lib/components/actions/item-action-controls.js.map +1 -0
  21. package/lib/components/actions/item-action-group.d.ts +19 -0
  22. package/lib/components/actions/item-action-group.d.ts.map +1 -0
  23. package/lib/components/actions/item-action-group.js +69 -0
  24. package/lib/components/actions/item-action-group.js.map +1 -0
  25. package/lib/components/actions/item-action-menu.d.ts +20 -0
  26. package/lib/components/actions/item-action-menu.d.ts.map +1 -0
  27. package/lib/components/actions/item-action-menu.js +89 -0
  28. package/lib/components/actions/item-action-menu.js.map +1 -0
  29. package/lib/components/actions/small-icon-button.d.ts +11 -0
  30. package/lib/components/actions/small-icon-button.d.ts.map +1 -0
  31. package/lib/components/actions/small-icon-button.js +66 -0
  32. package/lib/components/actions/small-icon-button.js.map +1 -0
  33. package/lib/components/actions/types.d.ts +32 -0
  34. package/lib/components/actions/types.d.ts.map +1 -0
  35. package/lib/components/actions/types.js +3 -0
  36. package/lib/components/actions/types.js.map +1 -0
  37. package/lib/components/actions/utils.d.ts +2 -0
  38. package/lib/components/actions/utils.d.ts.map +1 -0
  39. package/lib/components/actions/utils.js +8 -0
  40. package/lib/components/actions/utils.js.map +1 -0
  41. package/lib/components/combobox-with-custom-option.d.ts +1 -1
  42. package/lib/components/combobox-with-custom-option.d.ts.map +1 -1
  43. package/lib/components/combobox-with-custom-option.js +3 -3
  44. package/lib/components/combobox-with-custom-option.js.map +1 -1
  45. package/lib/components/document-list/element-actions.d.ts.map +1 -1
  46. package/lib/components/document-list/element-actions.js +1 -1
  47. package/lib/components/document-list/element-actions.js.map +1 -1
  48. package/lib/components/document-list/element-editors.d.ts.map +1 -1
  49. package/lib/components/document-list/element-editors.js +12 -5
  50. package/lib/components/document-list/element-editors.js.map +1 -1
  51. package/lib/components/document-list/element.d.ts.map +1 -1
  52. package/lib/components/document-list/element.js +10 -3
  53. package/lib/components/document-list/element.js.map +1 -1
  54. package/lib/components/feedback-popover.d.ts +2 -5
  55. package/lib/components/feedback-popover.d.ts.map +1 -1
  56. package/lib/components/feedback-popover.js +1 -5
  57. package/lib/components/feedback-popover.js.map +1 -1
  58. package/lib/components/file-input.js +3 -3
  59. package/lib/components/file-input.js.map +1 -1
  60. package/lib/components/guide-cue/guide-cue.d.ts +1 -2
  61. package/lib/components/guide-cue/guide-cue.d.ts.map +1 -1
  62. package/lib/components/guide-cue/guide-cue.js +1 -3
  63. package/lib/components/guide-cue/guide-cue.js.map +1 -1
  64. package/lib/components/interactive-popover.d.ts +4 -4
  65. package/lib/components/interactive-popover.d.ts.map +1 -1
  66. package/lib/components/interactive-popover.js +1 -1
  67. package/lib/components/interactive-popover.js.map +1 -1
  68. package/lib/components/leafygreen.d.ts +4 -54
  69. package/lib/components/leafygreen.d.ts.map +1 -1
  70. package/lib/components/leafygreen.js +7 -6
  71. package/lib/components/leafygreen.js.map +1 -1
  72. package/lib/components/links/link.d.ts +7 -7
  73. package/lib/components/tab-nav-bar.d.ts.map +1 -1
  74. package/lib/components/tab-nav-bar.js +8 -1
  75. package/lib/components/tab-nav-bar.js.map +1 -1
  76. package/lib/components/virtual-list.d.ts +3 -5
  77. package/lib/components/virtual-list.d.ts.map +1 -1
  78. package/lib/components/virtual-list.js +2 -2
  79. package/lib/components/virtual-list.js.map +1 -1
  80. package/lib/components/workspace-tabs/tab.d.ts +2 -3
  81. package/lib/components/workspace-tabs/tab.d.ts.map +1 -1
  82. package/lib/components/workspace-tabs/tab.js.map +1 -1
  83. package/lib/components/workspace-tabs/workspace-tabs.d.ts +2 -2
  84. package/lib/components/workspace-tabs/workspace-tabs.d.ts.map +1 -1
  85. package/lib/hooks/use-confirmation.d.ts +0 -1
  86. package/lib/hooks/use-confirmation.d.ts.map +1 -1
  87. package/lib/hooks/use-confirmation.js +0 -1
  88. package/lib/hooks/use-confirmation.js.map +1 -1
  89. package/lib/hooks/use-stacked-component.d.ts +1 -6
  90. package/lib/hooks/use-stacked-component.d.ts.map +1 -1
  91. package/lib/hooks/use-stacked-component.js +9 -28
  92. package/lib/hooks/use-stacked-component.js.map +1 -1
  93. package/lib/hooks/use-virtual-list-item-observer.d.ts +2 -4
  94. package/lib/hooks/use-virtual-list-item-observer.d.ts.map +1 -1
  95. package/lib/hooks/use-virtual-list-item-observer.js +1 -1
  96. package/lib/hooks/use-virtual-list-item-observer.js.map +1 -1
  97. package/lib/index.d.ts +9 -6
  98. package/lib/index.d.ts.map +1 -1
  99. package/lib/index.js +8 -9
  100. package/lib/index.js.map +1 -1
  101. package/package.json +47 -49
  102. package/lib/components/combobox/Chip.d.ts +0 -4
  103. package/lib/components/combobox/Chip.d.ts.map +0 -1
  104. package/lib/components/combobox/Chip.js +0 -230
  105. package/lib/components/combobox/Chip.js.map +0 -1
  106. package/lib/components/combobox/Combobox.d.ts +0 -48
  107. package/lib/components/combobox/Combobox.d.ts.map +0 -1
  108. package/lib/components/combobox/Combobox.js +0 -1029
  109. package/lib/components/combobox/Combobox.js.map +0 -1
  110. package/lib/components/combobox/Combobox.styles.d.ts +0 -53
  111. package/lib/components/combobox/Combobox.styles.d.ts.map +0 -1
  112. package/lib/components/combobox/Combobox.styles.js +0 -294
  113. package/lib/components/combobox/Combobox.styles.js.map +0 -1
  114. package/lib/components/combobox/Combobox.types.d.ts +0 -295
  115. package/lib/components/combobox/Combobox.types.d.ts.map +0 -1
  116. package/lib/components/combobox/Combobox.types.js +0 -66
  117. package/lib/components/combobox/Combobox.types.js.map +0 -1
  118. package/lib/components/combobox/ComboboxContext.d.ts +0 -21
  119. package/lib/components/combobox/ComboboxContext.d.ts.map +0 -1
  120. package/lib/components/combobox/ComboboxContext.js +0 -19
  121. package/lib/components/combobox/ComboboxContext.js.map +0 -1
  122. package/lib/components/combobox/ComboboxGroup.d.ts +0 -15
  123. package/lib/components/combobox/ComboboxGroup.d.ts.map +0 -1
  124. package/lib/components/combobox/ComboboxGroup.js +0 -84
  125. package/lib/components/combobox/ComboboxGroup.js.map +0 -1
  126. package/lib/components/combobox/ComboboxMenu/ComboboxMenu.d.ts +0 -9
  127. package/lib/components/combobox/ComboboxMenu/ComboboxMenu.d.ts.map +0 -1
  128. package/lib/components/combobox/ComboboxMenu/ComboboxMenu.js +0 -91
  129. package/lib/components/combobox/ComboboxMenu/ComboboxMenu.js.map +0 -1
  130. package/lib/components/combobox/ComboboxMenu/Menu.styles.d.ts +0 -26
  131. package/lib/components/combobox/ComboboxMenu/Menu.styles.d.ts.map +0 -1
  132. package/lib/components/combobox/ComboboxMenu/Menu.styles.js +0 -119
  133. package/lib/components/combobox/ComboboxMenu/Menu.styles.js.map +0 -1
  134. package/lib/components/combobox/ComboboxOption.d.ts +0 -20
  135. package/lib/components/combobox/ComboboxOption.d.ts.map +0 -1
  136. package/lib/components/combobox/ComboboxOption.js +0 -272
  137. package/lib/components/combobox/ComboboxOption.js.map +0 -1
  138. package/lib/components/combobox/Menu.styles.d.ts +0 -22
  139. package/lib/components/combobox/Menu.styles.d.ts.map +0 -1
  140. package/lib/components/combobox/Menu.styles.js +0 -102
  141. package/lib/components/combobox/Menu.styles.js.map +0 -1
  142. package/lib/components/combobox/index.d.ts +0 -6
  143. package/lib/components/combobox/index.d.ts.map +0 -1
  144. package/lib/components/combobox/index.js +0 -15
  145. package/lib/components/combobox/index.js.map +0 -1
  146. package/lib/components/combobox/utils/OptionObjectUtils.d.ts +0 -23
  147. package/lib/components/combobox/utils/OptionObjectUtils.d.ts.map +0 -1
  148. package/lib/components/combobox/utils/OptionObjectUtils.js +0 -40
  149. package/lib/components/combobox/utils/OptionObjectUtils.js.map +0 -1
  150. package/lib/components/combobox/utils/flattenChildren.d.ts +0 -12
  151. package/lib/components/combobox/utils/flattenChildren.d.ts.map +0 -1
  152. package/lib/components/combobox/utils/flattenChildren.js +0 -47
  153. package/lib/components/combobox/utils/flattenChildren.js.map +0 -1
  154. package/lib/components/combobox/utils/getNameAndValue.d.ts +0 -15
  155. package/lib/components/combobox/utils/getNameAndValue.d.ts.map +0 -1
  156. package/lib/components/combobox/utils/getNameAndValue.js +0 -24
  157. package/lib/components/combobox/utils/getNameAndValue.js.map +0 -1
  158. package/lib/components/combobox/utils/index.d.ts +0 -5
  159. package/lib/components/combobox/utils/index.d.ts.map +0 -1
  160. package/lib/components/combobox/utils/index.js +0 -14
  161. package/lib/components/combobox/utils/index.js.map +0 -1
  162. package/lib/components/combobox/utils/wrapJSX.d.ts +0 -15
  163. package/lib/components/combobox/utils/wrapJSX.d.ts.map +0 -1
  164. package/lib/components/combobox/utils/wrapJSX.js +0 -53
  165. package/lib/components/combobox/utils/wrapJSX.js.map +0 -1
  166. package/lib/components/item-action-controls.d.ts +0 -87
  167. package/lib/components/item-action-controls.d.ts.map +0 -1
  168. package/lib/components/item-action-controls.js +0 -239
  169. package/lib/components/item-action-controls.js.map +0 -1
@@ -1,1029 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.Combobox = void 0;
30
- /* eslint-disable filename-rules/match */
31
- const react_1 = __importStar(require("react"));
32
- const clone_1 = __importDefault(require("lodash/clone"));
33
- const isArray_1 = __importDefault(require("lodash/isArray"));
34
- const isEqual_1 = __importDefault(require("lodash/isEqual"));
35
- const isNull_1 = __importDefault(require("lodash/isNull"));
36
- const isString_1 = __importDefault(require("lodash/isString"));
37
- const isUndefined_1 = __importDefault(require("lodash/isUndefined"));
38
- const prop_types_1 = __importDefault(require("prop-types"));
39
- const emotion_1 = require("@leafygreen-ui/emotion");
40
- const hooks_1 = require("@leafygreen-ui/hooks");
41
- const icon_1 = __importDefault(require("@leafygreen-ui/icon"));
42
- const icon_button_1 = __importDefault(require("@leafygreen-ui/icon-button"));
43
- const leafygreen_provider_1 = require("@leafygreen-ui/leafygreen-provider");
44
- const lib_1 = require("@leafygreen-ui/lib");
45
- const palette_1 = require("@leafygreen-ui/palette");
46
- const typography_1 = require("@leafygreen-ui/typography");
47
- const ComboboxMenu_1 = require("./ComboboxMenu/ComboboxMenu");
48
- const Chip_1 = require("./Chip");
49
- const Combobox_styles_1 = require("./Combobox.styles");
50
- const Combobox_types_1 = require("./Combobox.types");
51
- const ComboboxContext_1 = require("./ComboboxContext");
52
- const ComboboxGroup_1 = require("./ComboboxGroup");
53
- const ComboboxOption_1 = require("./ComboboxOption");
54
- const utils_1 = require("./utils");
55
- const tokens_1 = require("@leafygreen-ui/tokens");
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.
59
- const popoverMenuStyles = (width, numDescChars) => {
60
- if (numDescChars === 0) {
61
- return (0, emotion_1.css) `
62
- width: ${width}px;
63
- `;
64
- }
65
- const descWithExtraSpace = numDescChars + 5;
66
- return (0, emotion_1.css) `
67
- width: calc(
68
- ${width}px + min(${descriptionWidth}px, ${descWithExtraSpace}ch)
69
- );
70
-
71
- margin-left: calc(
72
- min(${descriptionWidth / 2}px, ${descWithExtraSpace / 2}ch)
73
- );
74
- `;
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
- */
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 }) {
82
- const { darkMode, theme } = (0, leafygreen_provider_1.useDarkMode)(darkModeProp);
83
- const getOptionRef = (0, hooks_1.useDynamicRefs)({ prefix: 'option' });
84
- const getChipRef = (0, hooks_1.useDynamicRefs)({ prefix: 'chip' });
85
- const inputId = (0, hooks_1.useIdAllocator)({ prefix: 'combobox-input' });
86
- const labelId = (0, hooks_1.useIdAllocator)({ prefix: 'combobox-label' });
87
- const menuId = (0, hooks_1.useIdAllocator)({ prefix: 'combobox-menu' });
88
- const comboboxRef = (0, react_1.useRef)(null);
89
- const clearButtonRef = (0, react_1.useRef)(null);
90
- const inputWrapperRef = (0, react_1.useRef)(null);
91
- const inputRef = (0, react_1.useRef)(null);
92
- const menuRef = (0, react_1.useRef)(null);
93
- const [isOpen, setOpen] = (0, react_1.useState)(false);
94
- const wasOpen = (0, hooks_1.usePrevious)(isOpen);
95
- const [highlightedOption, setHighlightedOption] = (0, react_1.useState)(null);
96
- const [selection, setSelection] = (0, react_1.useState)(null);
97
- const prevSelection = (0, hooks_1.usePrevious)(selection);
98
- const [inputValue, setInputValue] = (0, react_1.useState)('');
99
- const prevValue = (0, hooks_1.usePrevious)(inputValue);
100
- const [focusedChip, setFocusedChip] = (0, react_1.useState)(null);
101
- const doesSelectionExist = !(0, isNull_1.default)(selection) &&
102
- (((0, isArray_1.default)(selection) && selection.length > 0) || (0, isString_1.default)(selection));
103
- const placeholderValue = multiselect && (0, isArray_1.default)(selection) && selection.length > 0
104
- ? undefined
105
- : placeholder;
106
- const closeMenu = () => setOpen(false);
107
- const openMenu = () => setOpen(true);
108
- /**
109
- * Array of all of the options objects
110
- */
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
- */
115
- const isMultiselect = (0, react_1.useCallback)((val) => {
116
- if (multiselect && (typeof val === 'string' || typeof val === 'number')) {
117
- lib_1.consoleOnce.error(`Error in Combobox: multiselect is set to \`true\`, but received a ${typeof val} value: "${val}"`);
118
- }
119
- else if (!multiselect && (0, isArray_1.default)(val)) {
120
- lib_1.consoleOnce.error('Error in Combobox: multiselect is set to `false`, but received an Array value');
121
- }
122
- return multiselect && (0, isArray_1.default)(val);
123
- }, [multiselect]);
124
- /**
125
- * Forces focus of input box
126
- * @param cursorPos index the cursor should be set to
127
- */
128
- const setInputFocus = (0, react_1.useCallback)((cursorPos) => {
129
- if (!disabled && inputRef && inputRef.current) {
130
- inputRef.current.focus();
131
- if (!(0, isUndefined_1.default)(cursorPos)) {
132
- inputRef.current.setSelectionRange(cursorPos, cursorPos);
133
- }
134
- }
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
- */
141
- const updateSelection = (0, react_1.useCallback)((value) => {
142
- if (isMultiselect(selection)) {
143
- // We know M is true here
144
- const newSelection = (0, clone_1.default)(selection);
145
- if ((0, isNull_1.default)(value)) {
146
- newSelection.length = 0;
147
- }
148
- else {
149
- if (selection.includes(value)) {
150
- // remove from array
151
- newSelection.splice(newSelection.indexOf(value), 1);
152
- }
153
- else {
154
- // add to array
155
- newSelection.push(value);
156
- // clear text
157
- setInputValue('');
158
- }
159
- }
160
- setSelection(newSelection);
161
- onChange?.(newSelection);
162
- }
163
- else {
164
- const newSelection = value;
165
- setSelection(newSelection);
166
- onChange?.(newSelection);
167
- }
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
- */
173
- const isValueCurrentSelection = (0, react_1.useCallback)((value) => {
174
- return isMultiselect(selection)
175
- ? selection.includes(value)
176
- : value === selection;
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
- */
183
- const isTextCurrentSelection = (0, react_1.useCallback)((text) => {
184
- const value = (0, utils_1.getValueForDisplayName)(text, allOptions);
185
- return isValueCurrentSelection(value);
186
- }, [allOptions, isValueCurrentSelection]);
187
- /**
188
- * Returns whether the provided option is disabled
189
- * @param option the option value or OptionObject to check
190
- */
191
- const isOptionDisabled = (option) => {
192
- if (typeof option === 'string') {
193
- const optionObj = (0, utils_1.getOptionObjectFromValue)(option, allOptions);
194
- return !!optionObj?.isDisabled;
195
- }
196
- else {
197
- return !!option.isDisabled;
198
- }
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
- */
204
- const shouldOptionBeVisible = (0, react_1.useCallback)((option) => {
205
- const value = typeof option === 'string' ? option : option.value;
206
- // If filtered options are provided
207
- if (filteredOptions && filteredOptions.length > 0) {
208
- return filteredOptions.includes(value);
209
- }
210
- // If the text input value is the current selection
211
- // (or included in the selection)
212
- // then all options should be visible
213
- if (isTextCurrentSelection(inputValue)) {
214
- return true;
215
- }
216
- // otherwise, we do our own filtering
217
- const displayName = typeof option === 'string'
218
- ? (0, utils_1.getDisplayNameForValue)(value, allOptions)
219
- : option.displayName;
220
- const isValueInDisplayName = displayName
221
- .toLowerCase()
222
- .includes(inputValue.toLowerCase());
223
- return isValueInDisplayName;
224
- }, [filteredOptions, isTextCurrentSelection, inputValue, allOptions]);
225
- /**
226
- * The array of visible options objects
227
- */
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
- */
233
- const isValueValid = (0, react_1.useCallback)((value) => {
234
- return value ? !!allOptions.find((opt) => opt.value === value) : false;
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
- */
240
- const getIndexOfValue = (0, react_1.useCallback)((value) => {
241
- return visibleOptions
242
- ? visibleOptions.findIndex((option) => option.value === value)
243
- : -1;
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
- */
249
- const getValueAtIndex = (0, react_1.useCallback)((index) => {
250
- if (visibleOptions && visibleOptions.length >= index) {
251
- const option = visibleOptions[index];
252
- return option ? option.value : undefined;
253
- }
254
- }, [visibleOptions]);
255
- /**
256
- * Returns the index of the active chip in the selection array
257
- */
258
- const getActiveChipIndex = (0, react_1.useCallback)(() => isMultiselect(selection)
259
- ? selection.findIndex((value) => getChipRef(value)?.current?.contains(document.activeElement))
260
- : -1, [getChipRef, isMultiselect, selection]);
261
- /**
262
- *
263
- * Focus Management
264
- *
265
- */
266
- const [focusedElementName, trackFocusedElement] = (0, react_1.useState)();
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
- */
272
- const updateHighlightedOption = (0, react_1.useCallback)((direction) => {
273
- const optionsCount = visibleOptions?.length ?? 0;
274
- const lastIndex = optionsCount - 1 > 0 ? optionsCount - 1 : 0;
275
- const indexOfHighlight = getIndexOfValue(highlightedOption);
276
- // Remove focus from chip
277
- if (direction && isOpen) {
278
- setFocusedChip(null);
279
- setInputFocus();
280
- }
281
- switch (direction) {
282
- case 'next': {
283
- const newValue = indexOfHighlight + 1 < optionsCount
284
- ? getValueAtIndex(indexOfHighlight + 1)
285
- : getValueAtIndex(0);
286
- setHighlightedOption(newValue ?? null);
287
- break;
288
- }
289
- case 'prev': {
290
- const newValue = indexOfHighlight - 1 >= 0
291
- ? getValueAtIndex(indexOfHighlight - 1)
292
- : getValueAtIndex(lastIndex);
293
- setHighlightedOption(newValue ?? null);
294
- break;
295
- }
296
- case 'last': {
297
- const newValue = getValueAtIndex(lastIndex);
298
- setHighlightedOption(newValue ?? null);
299
- break;
300
- }
301
- case 'first':
302
- default: {
303
- const newValue = getValueAtIndex(0);
304
- setHighlightedOption(newValue ?? null);
305
- }
306
- }
307
- }, [
308
- highlightedOption,
309
- getIndexOfValue,
310
- getValueAtIndex,
311
- isOpen,
312
- setInputFocus,
313
- visibleOptions?.length,
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
- */
320
- const updateFocusedChip = (0, react_1.useCallback)((direction, relativeToIndex) => {
321
- if (isMultiselect(selection)) {
322
- switch (direction) {
323
- case 'next': {
324
- const referenceChipIndex = relativeToIndex ?? getActiveChipIndex();
325
- const nextChipIndex = referenceChipIndex + 1 < selection.length
326
- ? referenceChipIndex + 1
327
- : selection.length - 1;
328
- const nextChipValue = selection[nextChipIndex];
329
- setFocusedChip(nextChipValue);
330
- break;
331
- }
332
- case 'prev': {
333
- const referenceChipIndex = relativeToIndex ?? getActiveChipIndex();
334
- const prevChipIndex = referenceChipIndex > 0
335
- ? referenceChipIndex - 1
336
- : referenceChipIndex < 0
337
- ? selection.length - 1
338
- : 0;
339
- const prevChipValue = selection[prevChipIndex];
340
- setFocusedChip(prevChipValue);
341
- break;
342
- }
343
- case 'first': {
344
- const firstChipValue = selection[0];
345
- setFocusedChip(firstChipValue);
346
- break;
347
- }
348
- case 'last': {
349
- const lastChipValue = selection[selection.length - 1];
350
- setFocusedChip(lastChipValue);
351
- break;
352
- }
353
- default:
354
- setFocusedChip(null);
355
- break;
356
- }
357
- }
358
- }, [getActiveChipIndex, isMultiselect, selection]);
359
- /**
360
- * Handles an arrow key press
361
- */
362
- const handleArrowKey = (0, react_1.useCallback)((direction, event) => {
363
- // Remove focus from menu
364
- if (direction)
365
- setHighlightedOption(null);
366
- switch (direction) {
367
- case 'right':
368
- switch (focusedElementName) {
369
- case Combobox_types_1.ComboboxElement.Input: {
370
- // If cursor is at the end of the input
371
- if (inputRef.current?.selectionEnd ===
372
- inputRef.current?.value.length) {
373
- clearButtonRef.current?.focus();
374
- }
375
- break;
376
- }
377
- case Combobox_types_1.ComboboxElement.FirstChip:
378
- case Combobox_types_1.ComboboxElement.MiddleChip:
379
- case Combobox_types_1.ComboboxElement.LastChip: {
380
- if (focusedElementName === Combobox_types_1.ComboboxElement.LastChip ||
381
- // the first chip is also the last chip (i.e. only one)
382
- selection?.length === 1) {
383
- // if focus is on last chip, go to input
384
- setInputFocus(0);
385
- updateFocusedChip(null);
386
- event.preventDefault();
387
- break;
388
- }
389
- // First/middle chips
390
- updateFocusedChip('next');
391
- break;
392
- }
393
- case Combobox_types_1.ComboboxElement.ClearButton:
394
- default:
395
- break;
396
- }
397
- break;
398
- case 'left':
399
- switch (focusedElementName) {
400
- case Combobox_types_1.ComboboxElement.ClearButton: {
401
- event.preventDefault();
402
- setInputFocus(inputRef?.current?.value.length);
403
- break;
404
- }
405
- case Combobox_types_1.ComboboxElement.Input:
406
- case Combobox_types_1.ComboboxElement.MiddleChip:
407
- case Combobox_types_1.ComboboxElement.LastChip: {
408
- if (isMultiselect(selection)) {
409
- // Break if cursor is not at the start of the input
410
- if (focusedElementName === Combobox_types_1.ComboboxElement.Input &&
411
- inputRef.current?.selectionStart !== 0) {
412
- break;
413
- }
414
- updateFocusedChip('prev');
415
- }
416
- break;
417
- }
418
- case Combobox_types_1.ComboboxElement.FirstChip:
419
- default:
420
- break;
421
- }
422
- break;
423
- default:
424
- updateFocusedChip(null);
425
- break;
426
- }
427
- }, [
428
- focusedElementName,
429
- isMultiselect,
430
- selection,
431
- setInputFocus,
432
- updateFocusedChip,
433
- ]);
434
- // When the input value changes (or when the menu opens)
435
- // Update the focused option
436
- (0, react_1.useEffect)(() => {
437
- if (inputValue !== prevValue) {
438
- updateHighlightedOption('first');
439
- }
440
- }, [inputValue, isOpen, prevValue, updateHighlightedOption]);
441
- // When the focused option changes, update the menu scroll if necessary
442
- (0, react_1.useEffect)(() => {
443
- if (highlightedOption) {
444
- const focusedElementRef = getOptionRef(highlightedOption);
445
- if (focusedElementRef && focusedElementRef.current && menuRef.current) {
446
- const { offsetTop: optionTop } = focusedElementRef.current;
447
- const { scrollTop: menuScroll, offsetHeight: menuHeight } = menuRef.current;
448
- if (optionTop > menuHeight || optionTop < menuScroll) {
449
- menuRef.current.scrollTop = optionTop;
450
- }
451
- }
452
- }
453
- }, [highlightedOption, getOptionRef]);
454
- /**
455
- * Rendering
456
- */
457
- /**
458
- * Callback to render a child as an <InternalComboboxOption> element
459
- */
460
- const renderOption = (0, react_1.useCallback)((child) => {
461
- if ((0, lib_1.isComponentType)(child, 'ComboboxOption')) {
462
- const { value, displayName } = (0, utils_1.getNameAndValue)(child.props);
463
- if (shouldOptionBeVisible(value)) {
464
- const { className, glyph, disabled } = child.props;
465
- const index = allOptions.findIndex((opt) => opt.value === value);
466
- const isFocused = highlightedOption === value;
467
- const isSelected = isMultiselect(selection)
468
- ? selection.includes(value)
469
- : selection === value;
470
- const setSelected = () => {
471
- setHighlightedOption(value);
472
- updateSelection(value);
473
- setInputFocus();
474
- if (value === selection) {
475
- closeMenu();
476
- }
477
- };
478
- const optionRef = getOptionRef(value);
479
- return (react_1.default.createElement(ComboboxOption_1.InternalComboboxOption, { value: value, displayName: displayName, isFocused: isFocused, isSelected: isSelected, disabled: disabled, setSelected: setSelected, glyph: glyph, className: className, index: index, ref: optionRef, description: child.props.description }));
480
- }
481
- }
482
- else if ((0, lib_1.isComponentType)(child, 'ComboboxGroup')) {
483
- const nestedChildren = react_1.default.Children.map(child.props.children, renderOption);
484
- if (nestedChildren && nestedChildren?.length > 0) {
485
- return (react_1.default.createElement(ComboboxGroup_1.InternalComboboxGroup, { label: child.props.label, className: child.props.className }, react_1.default.Children.map(nestedChildren, renderOption)));
486
- }
487
- }
488
- }, [
489
- allOptions,
490
- getOptionRef,
491
- highlightedOption,
492
- isMultiselect,
493
- selection,
494
- setInputFocus,
495
- shouldOptionBeVisible,
496
- updateSelection,
497
- ]);
498
- /**
499
- * The rendered JSX elements for the options
500
- */
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
- */
505
- const renderedChips = (0, react_1.useMemo)(() => {
506
- if (isMultiselect(selection)) {
507
- return selection.filter(isValueValid).map((value, index) => {
508
- const displayName = (0, utils_1.getDisplayNameForValue)(value, allOptions);
509
- const isFocused = focusedChip === value;
510
- const chipRef = getChipRef(value);
511
- const isLastChip = index >= selection.length - 1;
512
- const onRemove = () => {
513
- if (isLastChip) {
514
- // Focus the input if this is the last chip in the set
515
- setInputFocus();
516
- updateFocusedChip(null);
517
- }
518
- else {
519
- updateFocusedChip('next', index);
520
- }
521
- updateSelection(value);
522
- };
523
- const onFocus = () => {
524
- setFocusedChip(value);
525
- };
526
- return (react_1.default.createElement(Chip_1.Chip, { key: value, displayName: displayName, isFocused: isFocused, onRemove: onRemove, onFocus: onFocus, ref: chipRef }));
527
- });
528
- }
529
- }, [
530
- isMultiselect,
531
- selection,
532
- isValueValid,
533
- allOptions,
534
- focusedChip,
535
- getChipRef,
536
- updateSelection,
537
- setInputFocus,
538
- updateFocusedChip,
539
- ]);
540
- const handleClearButtonFocus = () => {
541
- setHighlightedOption(null);
542
- };
543
- /**
544
- * The rendered JSX for the input icons (clear, warn & caret)
545
- */
546
- const renderedInputIcons = (0, react_1.useMemo)(() => {
547
- const handleClearButtonClick = (e) => {
548
- if (!disabled) {
549
- updateSelection(null);
550
- onClear?.(e);
551
- onFilter?.('');
552
- if (!isOpen) {
553
- openMenu();
554
- }
555
- }
556
- };
557
- return (react_1.default.createElement(react_1.default.Fragment, null,
558
- clearable && doesSelectionExist && (react_1.default.createElement(icon_button_1.default, { "aria-label": "Clear selection", "aria-disabled": disabled, disabled: disabled, ref: clearButtonRef, onClick: handleClearButtonClick, onFocus: handleClearButtonFocus, className: (0, emotion_1.cx)(Combobox_styles_1.clearButtonStyle), darkMode: darkMode },
559
- react_1.default.createElement(icon_1.default, { glyph: "XWithCircle" }))),
560
- state === 'error' ? (react_1.default.createElement(icon_1.default, { glyph: "Warning", color: darkMode ? palette_1.palette.red.light1 : palette_1.palette.red.base, className: (0, Combobox_styles_1.endIconStyle)(size) })) : (react_1.default.createElement(icon_1.default, { glyph: "CaretDown", className: (0, Combobox_styles_1.endIconStyle)(size) }))));
561
- }, [
562
- clearable,
563
- doesSelectionExist,
564
- disabled,
565
- state,
566
- darkMode,
567
- size,
568
- updateSelection,
569
- onClear,
570
- onFilter,
571
- isOpen,
572
- ]);
573
- /**
574
- * Flag to determine whether the rendered options have icons
575
- */
576
- const withIcons = (0, react_1.useMemo)(() => allOptions.some((opt) => opt.hasGlyph), [allOptions]);
577
- /**
578
- *
579
- * Selection Management
580
- *
581
- */
582
- const onCloseMenu = (0, react_1.useCallback)(() => {
583
- // Single select, and no change to selection
584
- if (!isMultiselect(selection) && selection === prevSelection) {
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
588
- if (exactMatchedOption && !value) {
589
- setSelection(exactMatchedOption.value);
590
- }
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
594
- setInputValue(selection);
595
- }
596
- }
597
- }, [
598
- allOptions,
599
- inputValue,
600
- isMultiselect,
601
- prevSelection,
602
- selection,
603
- value,
604
- visibleOptions,
605
- ]);
606
- const onSelect = (0, react_1.useCallback)(() => {
607
- if (doesSelectionExist) {
608
- if (isMultiselect(selection)) {
609
- // Scroll the wrapper to the end. No effect if not `overflow="scroll-x"`
610
- scrollInputToEnd();
611
- }
612
- else if (!isMultiselect(selection)) {
613
- // Update the text input.
614
- // Set the value instead of displayName to align with handleInputChange COMPASS-6511
615
- setInputValue(selection);
616
- closeMenu();
617
- }
618
- }
619
- else {
620
- setInputValue('');
621
- }
622
- }, [doesSelectionExist, allOptions, isMultiselect, selection]);
623
- // Set the initialValue
624
- (0, react_1.useEffect)(() => {
625
- if (initialValue) {
626
- if ((0, isArray_1.default)(initialValue)) {
627
- // Ensure the values we set are real options
628
- const filteredValue = initialValue.filter((value) => isValueValid(value)) ?? [];
629
- setSelection(filteredValue);
630
- }
631
- else {
632
- if (isValueValid(initialValue)) {
633
- setSelection(initialValue);
634
- }
635
- }
636
- }
637
- else {
638
- setSelection((0, Combobox_types_1.getNullSelection)(multiselect));
639
- }
640
- // eslint-disable-next-line react-hooks/exhaustive-deps
641
- }, []);
642
- // When controlled value changes, update the selection
643
- (0, react_1.useEffect)(() => {
644
- if (!(0, isUndefined_1.default)(value) && value !== prevValue) {
645
- if ((0, isNull_1.default)(value)) {
646
- setSelection(null);
647
- }
648
- else if (isMultiselect(value)) {
649
- // Ensure the value(s) passed in are valid options
650
- const newSelection = value.filter(isValueValid);
651
- setSelection(newSelection);
652
- }
653
- else {
654
- setSelection(isValueValid(value) ? value : null);
655
- }
656
- }
657
- }, [isMultiselect, isValueValid, prevValue, value]);
658
- // onSelect
659
- // Side effects to run when the selection changes
660
- (0, react_1.useEffect)(() => {
661
- if (!(0, isEqual_1.default)(selection, prevSelection)) {
662
- onSelect();
663
- }
664
- }, [onSelect, prevSelection, selection]);
665
- // when the menu closes, update the value if needed
666
- (0, react_1.useEffect)(() => {
667
- if (!isOpen && wasOpen) {
668
- onCloseMenu();
669
- }
670
- }, [isOpen, wasOpen, onCloseMenu]);
671
- /**
672
- *
673
- * Menu management
674
- *
675
- */
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
679
- (0, react_1.useEffect)(() => {
680
- setPopoverMenuWidth(comboboxRef.current?.clientWidth ?? 0);
681
- }, [comboboxRef, isOpen, highlightedOption, selection]);
682
- // Handler fired when the menu has finished transitioning in/out
683
- const handleTransitionEnd = () => {
684
- setPopoverMenuWidth(comboboxRef.current?.clientWidth ?? 0);
685
- };
686
- /**
687
- *
688
- * Event Handlers
689
- *
690
- */
691
- // Prevent combobox from gaining focus by default
692
- const handleInputWrapperMousedown = (e) => {
693
- if (disabled) {
694
- e.preventDefault();
695
- }
696
- };
697
- // Set focus to the input element on click
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)
701
- if (e.target !== inputRef.current) {
702
- let cursorPos = 0;
703
- if (inputRef.current) {
704
- const mouseX = e.nativeEvent.offsetX;
705
- const inputRight = inputRef.current.offsetLeft + inputRef.current.clientWidth;
706
- cursorPos = mouseX > inputRight ? inputValue.length : 0;
707
- }
708
- setInputFocus(cursorPos);
709
- }
710
- // Only open the menu in response to a click
711
- openMenu();
712
- };
713
- // Fired whenever the wrapper gains focus,
714
- // and any time the focus within changes
715
- const handleComboboxFocus = (e) => {
716
- scrollInputToEnd();
717
- trackFocusedElement(getNameFromElement(e.target));
718
- };
719
- // Fired onChange
720
- const handleInputChange = ({ target: { value }, }) => {
721
- setInputValue(value);
722
- // fire any filter function passed in
723
- onFilter?.(value);
724
- };
725
- const handleKeyDown = (event) => {
726
- const isFocusInMenu = menuRef.current?.contains(document.activeElement);
727
- const isFocusOnCombobox = comboboxRef.current?.contains(document.activeElement);
728
- const isFocusInComponent = isFocusOnCombobox || isFocusInMenu;
729
- // Only run if the focus is in the component
730
- if (isFocusInComponent) {
731
- // No support for modifiers yet
732
- // TODO - Handle support for multiple chip selection
733
- if (event.ctrlKey || event.shiftKey || event.altKey) {
734
- return;
735
- }
736
- switch (event.key) {
737
- case lib_1.keyMap.Tab: {
738
- switch (focusedElementName) {
739
- case 'Input': {
740
- if (!doesSelectionExist) {
741
- closeMenu();
742
- updateHighlightedOption('first');
743
- updateFocusedChip(null);
744
- }
745
- // else use default behavior
746
- break;
747
- }
748
- case 'LastChip': {
749
- // use default behavior
750
- updateFocusedChip(null);
751
- break;
752
- }
753
- case 'FirstChip':
754
- case 'MiddleChip': {
755
- // use default behavior
756
- break;
757
- }
758
- case 'ClearButton':
759
- default:
760
- break;
761
- }
762
- break;
763
- }
764
- case lib_1.keyMap.Escape: {
765
- closeMenu();
766
- updateHighlightedOption('first');
767
- break;
768
- }
769
- case lib_1.keyMap.Enter: {
770
- if (!isOpen) {
771
- // If the menu is not open, enter should open the menu
772
- openMenu();
773
- }
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 &&
780
- !(0, isNull_1.default)(highlightedOption) &&
781
- !isOptionDisabled(highlightedOption)) {
782
- updateSelection(highlightedOption);
783
- }
784
- else if (
785
- // Focused on clear button
786
- focusedElementName === Combobox_types_1.ComboboxElement.ClearButton) {
787
- updateSelection(null);
788
- setInputFocus();
789
- }
790
- break;
791
- }
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`
795
- if (isMultiselect(selection)) {
796
- if (focusedElementName === 'Input' &&
797
- inputRef.current?.selectionStart === 0) {
798
- updateFocusedChip('last');
799
- }
800
- }
801
- // Open the menu regardless
802
- openMenu();
803
- break;
804
- }
805
- case lib_1.keyMap.ArrowDown: {
806
- if (isOpen) {
807
- // Prevent the page from scrolling
808
- event.preventDefault();
809
- // only change option if the menu is already open
810
- updateHighlightedOption('next');
811
- }
812
- else {
813
- openMenu();
814
- }
815
- break;
816
- }
817
- case lib_1.keyMap.ArrowUp: {
818
- if (isOpen) {
819
- // Prevent the page from scrolling
820
- event.preventDefault();
821
- // only change option if the menu is already open
822
- updateHighlightedOption('prev');
823
- }
824
- else {
825
- openMenu();
826
- }
827
- break;
828
- }
829
- case lib_1.keyMap.ArrowRight: {
830
- handleArrowKey('right', event);
831
- break;
832
- }
833
- case lib_1.keyMap.ArrowLeft: {
834
- handleArrowKey('left', event);
835
- break;
836
- }
837
- default: {
838
- if (!isOpen) {
839
- openMenu();
840
- }
841
- }
842
- }
843
- }
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
- */
862
- (0, hooks_1.useEventListener)('mousedown', (mousedown) => {
863
- if (!doesComponentContainEventTarget(mousedown)) {
864
- mousedown.preventDefault(); // Prevent focus from being applied to body
865
- mousedown.stopPropagation(); // Stop any other mousedown events from firing
866
- }
867
- }, {
868
- enabled: isOpen,
869
- });
870
- (0, hooks_1.useEventListener)('click', (click) => {
871
- if (!doesComponentContainEventTarget(click)) {
872
- click.stopPropagation(); // Stop any other click events from firing
873
- closeMenu();
874
- }
875
- }, {
876
- options: { capture: true },
877
- enabled: isOpen,
878
- });
879
- const popoverProps = {
880
- popoverZIndex,
881
- ...(usePortal
882
- ? {
883
- usePortal,
884
- portalClassName,
885
- portalContainer,
886
- scrollContainer,
887
- }
888
- : { usePortal }),
889
- };
890
- const descriptionCharacters = (0, react_1.useMemo)(() => {
891
- const characters = react_1.default.Children.map(children, (child) => child?.props?.description?.length ?? 0) ?? [];
892
- return characters.length === 0 ? 0 : Math.max(...characters);
893
- }, [children]);
894
- return (react_1.default.createElement(ComboboxContext_1.ComboboxContext.Provider, { value: {
895
- multiselect,
896
- darkMode,
897
- theme,
898
- size,
899
- withIcons,
900
- disabled,
901
- isOpen,
902
- state,
903
- searchState,
904
- chipTruncationLocation,
905
- chipCharacterLimit,
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.
913
- searchInputSize: popoverMenuWidth,
914
- } },
915
- react_1.default.createElement("div", { className: (0, emotion_1.cx)((0, Combobox_styles_1.comboboxParentStyle)(size), className), ...rest },
916
- (label || description) && (react_1.default.createElement("div", { className: Combobox_styles_1.labelDescriptionContainerStyle },
917
- label && (react_1.default.createElement(typography_1.Label, { id: labelId, htmlFor: inputId, darkMode: darkMode }, label)),
918
- description && (react_1.default.createElement(typography_1.Description, { darkMode: darkMode }, description)))),
919
- react_1.default.createElement("div", { ref: comboboxRef, role: "combobox", "aria-expanded": isOpen, "aria-controls": menuId, "aria-owns": menuId, tabIndex: -1, onMouseDown: handleInputWrapperMousedown, onClick: handleComboboxClick, onFocus: handleComboboxFocus, onKeyDown: handleKeyDown, onTransitionEnd: handleTransitionEnd, className: (0, emotion_1.cx)(Combobox_styles_1.baseComboboxStyles, Combobox_styles_1.comboboxThemeStyles[theme], (0, Combobox_styles_1.comboboxSizeStyles)(size), {
920
- [Combobox_styles_1.comboboxSelectionStyles]: clearable && doesSelectionExist,
921
- [Combobox_styles_1.comboboxDisabledStyles[theme]]: disabled,
922
- [Combobox_styles_1.comboboxErrorStyles[theme]]: state === Combobox_types_1.State.error,
923
- [Combobox_styles_1.comboboxFocusStyle[theme]]: isElementFocused(Combobox_types_1.ComboboxElement.Input),
924
- }) },
925
- react_1.default.createElement("div", { ref: inputWrapperRef, className: (0, Combobox_styles_1.inputWrapperStyle)({
926
- size,
927
- overflow,
928
- }) },
929
- renderedChips,
930
- react_1.default.createElement("input", { "aria-label": ariaLabel ?? label, "aria-autocomplete": "list", "aria-controls": menuId, "aria-labelledby": labelId, ref: inputRef, id: inputId, className: (0, emotion_1.cx)(Combobox_styles_1.baseInputElementStyle, Combobox_styles_1.inputElementSizeStyle[size], Combobox_styles_1.inputElementThemeStyle[theme], (0, Combobox_styles_1.inputElementTransitionStyles)(isOpen), {
931
- [(0, Combobox_styles_1.multiselectInputElementStyle)(size, inputValue)]: isMultiselect(selection),
932
- }), placeholder: placeholderValue, disabled: disabled ?? undefined, onChange: handleInputChange, value: inputValue, autoComplete: "off" })),
933
- renderedInputIcons),
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)),
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
- */
940
- function doesComponentContainEventTarget({ target }) {
941
- return (menuRef.current?.contains(target) ||
942
- comboboxRef.current?.contains(target) ||
943
- false);
944
- }
945
- /**
946
- * Scrolls the combobox to the far right.
947
- * Used when `overflow === 'scroll-x'`.
948
- * Has no effect otherwise
949
- */
950
- function scrollInputToEnd() {
951
- if (inputWrapperRef && inputWrapperRef.current) {
952
- // TODO - consider converting to .scrollTo(). This is not yet supported in IE or jsdom
953
- inputWrapperRef.current.scrollLeft = inputWrapperRef.current.scrollWidth;
954
- }
955
- }
956
- /**
957
- * Returns the provided element as a ComboboxElement string
958
- */
959
- function getNameFromElement(element) {
960
- if (!element)
961
- return;
962
- if (inputRef.current?.contains(element))
963
- return Combobox_types_1.ComboboxElement.Input;
964
- if (clearButtonRef.current?.contains(element))
965
- return Combobox_types_1.ComboboxElement.ClearButton;
966
- const activeChipIndex = isMultiselect(selection)
967
- ? selection.findIndex((value) => getChipRef(value)?.current?.contains(element))
968
- : -1;
969
- if (isMultiselect(selection)) {
970
- if (activeChipIndex === 0)
971
- return Combobox_types_1.ComboboxElement.FirstChip;
972
- if (activeChipIndex === selection.length - 1)
973
- return Combobox_types_1.ComboboxElement.LastChip;
974
- if (activeChipIndex > 0)
975
- return Combobox_types_1.ComboboxElement.MiddleChip;
976
- }
977
- if (menuRef.current?.contains(element))
978
- return Combobox_types_1.ComboboxElement.Menu;
979
- if (comboboxRef.current?.contains(element))
980
- return Combobox_types_1.ComboboxElement.Combobox;
981
- }
982
- }
983
- exports.Combobox = Combobox;
984
- Combobox.propTypes = {
985
- // Multiselect props
986
- multiselect: prop_types_1.default.bool,
987
- value: prop_types_1.default.oneOfType([
988
- prop_types_1.default.string,
989
- prop_types_1.default.arrayOf(prop_types_1.default.string),
990
- ]),
991
- initialValue: prop_types_1.default.oneOfType([
992
- prop_types_1.default.string,
993
- prop_types_1.default.arrayOf(prop_types_1.default.string),
994
- ]),
995
- overflow: prop_types_1.default.oneOf(Object.values(Combobox_types_1.Overflow)),
996
- // Standard Props
997
- darkMode: prop_types_1.default.bool,
998
- label: prop_types_1.default.string,
999
- 'aria-label': prop_types_1.default.string,
1000
- children: prop_types_1.default.node,
1001
- onChange: prop_types_1.default.func,
1002
- chipCharacterLimit: prop_types_1.default.number,
1003
- chipTruncationLocation: prop_types_1.default.oneOf(Object.values(Combobox_types_1.TruncationLocation)),
1004
- onClear: prop_types_1.default.func,
1005
- onFilter: prop_types_1.default.func,
1006
- clearable: prop_types_1.default.bool,
1007
- searchLoadingMessage: prop_types_1.default.string,
1008
- searchErrorMessage: prop_types_1.default.string,
1009
- searchEmptyMessage: prop_types_1.default.string,
1010
- searchState: prop_types_1.default.oneOf(Object.values(Combobox_types_1.SearchState)),
1011
- errorMessage: prop_types_1.default.string,
1012
- state: prop_types_1.default.oneOf(Object.values(Combobox_types_1.State)),
1013
- size: prop_types_1.default.oneOf(Object.values(Combobox_types_1.ComboboxSize)),
1014
- disabled: prop_types_1.default.bool,
1015
- description: prop_types_1.default.string,
1016
- placeholder: prop_types_1.default.string,
1017
- filteredOptions: prop_types_1.default.arrayOf(prop_types_1.default.string),
1018
- // Popover Props
1019
- popoverZIndex: prop_types_1.default.number,
1020
- usePortal: prop_types_1.default.bool,
1021
- scrollContainer: prop_types_1.default.elementType,
1022
- portalContainer: prop_types_1.default.elementType,
1023
- portalClassName: prop_types_1.default.string,
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
- */
1029
- //# sourceMappingURL=Combobox.js.map