@mongodb-js/compass-components 0.15.0 → 1.0.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.
Files changed (139) hide show
  1. package/lib/components/accordion.d.ts.map +1 -1
  2. package/lib/components/accordion.js +14 -11
  3. package/lib/components/accordion.js.map +1 -1
  4. package/lib/components/bson-value.d.ts.map +1 -1
  5. package/lib/components/bson-value.js +6 -2
  6. package/lib/components/bson-value.js.map +1 -1
  7. package/lib/components/cancel-loader.d.ts +2 -2
  8. package/lib/components/cancel-loader.d.ts.map +1 -1
  9. package/lib/components/cancel-loader.js +2 -2
  10. package/lib/components/cancel-loader.js.map +1 -1
  11. package/lib/components/confirmation-modal.js +5 -1
  12. package/lib/components/confirmation-modal.js.map +1 -1
  13. package/lib/components/content-with-fallback.js +5 -1
  14. package/lib/components/content-with-fallback.js.map +1 -1
  15. package/lib/components/document-list/document-actions-group.js +5 -1
  16. package/lib/components/document-list/document-actions-group.js.map +1 -1
  17. package/lib/components/document-list/document-edit-actions-footer.d.ts +15 -0
  18. package/lib/components/document-list/document-edit-actions-footer.d.ts.map +1 -0
  19. package/lib/components/document-list/document-edit-actions-footer.js +259 -0
  20. package/lib/components/document-list/document-edit-actions-footer.js.map +1 -0
  21. package/lib/components/document-list/document-fields-toggle-group.js +5 -1
  22. package/lib/components/document-list/document-fields-toggle-group.js.map +1 -1
  23. package/lib/components/document-list/document.d.ts +0 -1
  24. package/lib/components/document-list/document.d.ts.map +1 -1
  25. package/lib/components/document-list/document.js +29 -17
  26. package/lib/components/document-list/document.js.map +1 -1
  27. package/lib/components/document-list/element-actions.d.ts.map +1 -1
  28. package/lib/components/document-list/element-actions.js +11 -3
  29. package/lib/components/document-list/element-actions.js.map +1 -1
  30. package/lib/components/document-list/element-editors.d.ts.map +1 -1
  31. package/lib/components/document-list/element-editors.js +9 -3
  32. package/lib/components/document-list/element-editors.js.map +1 -1
  33. package/lib/components/document-list/element.d.ts.map +1 -1
  34. package/lib/components/document-list/element.js +12 -6
  35. package/lib/components/document-list/element.js.map +1 -1
  36. package/lib/components/document-list/index.d.ts +1 -0
  37. package/lib/components/document-list/index.d.ts.map +1 -1
  38. package/lib/components/document-list/index.js +3 -1
  39. package/lib/components/document-list/index.js.map +1 -1
  40. package/lib/components/editor.d.ts +9 -4
  41. package/lib/components/editor.d.ts.map +1 -1
  42. package/lib/components/editor.js +52 -7
  43. package/lib/components/editor.js.map +1 -1
  44. package/lib/components/error-warning-summary.js +5 -1
  45. package/lib/components/error-warning-summary.js.map +1 -1
  46. package/lib/components/leafy-green/combobox/chip.d.ts +4 -0
  47. package/lib/components/leafy-green/combobox/chip.d.ts.map +1 -0
  48. package/lib/components/leafy-green/combobox/chip.js +182 -0
  49. package/lib/components/leafy-green/combobox/chip.js.map +1 -0
  50. package/lib/components/leafy-green/combobox/combobox-context.d.ts +15 -0
  51. package/lib/components/leafy-green/combobox/combobox-context.d.ts.map +1 -0
  52. package/lib/components/leafy-green/combobox/combobox-context.js +12 -0
  53. package/lib/components/leafy-green/combobox/combobox-context.js.map +1 -0
  54. package/lib/components/leafy-green/combobox/combobox-group.d.ts +9 -0
  55. package/lib/components/leafy-green/combobox/combobox-group.d.ts.map +1 -0
  56. package/lib/components/leafy-green/combobox/combobox-group.js +69 -0
  57. package/lib/components/leafy-green/combobox/combobox-group.js.map +1 -0
  58. package/lib/components/leafy-green/combobox/combobox-option.d.ts +10 -0
  59. package/lib/components/leafy-green/combobox/combobox-option.d.ts.map +1 -0
  60. package/lib/components/leafy-green/combobox/combobox-option.js +142 -0
  61. package/lib/components/leafy-green/combobox/combobox-option.js.map +1 -0
  62. package/lib/components/leafy-green/combobox/combobox-types.d.ts +94 -0
  63. package/lib/components/leafy-green/combobox/combobox-types.d.ts.map +1 -0
  64. package/lib/components/leafy-green/combobox/combobox-types.js +36 -0
  65. package/lib/components/leafy-green/combobox/combobox-types.js.map +1 -0
  66. package/lib/components/leafy-green/combobox/combobox.d.ts +4 -0
  67. package/lib/components/leafy-green/combobox/combobox.d.ts.map +1 -0
  68. package/lib/components/leafy-green/combobox/combobox.js +725 -0
  69. package/lib/components/leafy-green/combobox/combobox.js.map +1 -0
  70. package/lib/components/leafy-green/combobox/combobox.styles.d.ts +38 -0
  71. package/lib/components/leafy-green/combobox/combobox.styles.d.ts.map +1 -0
  72. package/lib/components/leafy-green/combobox/combobox.styles.js +292 -0
  73. package/lib/components/leafy-green/combobox/combobox.styles.js.map +1 -0
  74. package/lib/components/leafy-green/combobox/index.d.ts +4 -0
  75. package/lib/components/leafy-green/combobox/index.d.ts.map +1 -0
  76. package/lib/components/leafy-green/combobox/index.js +13 -0
  77. package/lib/components/leafy-green/combobox/index.js.map +1 -0
  78. package/lib/components/leafy-green/combobox/util.d.ts +27 -0
  79. package/lib/components/leafy-green/combobox/util.d.ts.map +1 -0
  80. package/lib/components/leafy-green/combobox/util.js +65 -0
  81. package/lib/components/leafy-green/combobox/util.js.map +1 -0
  82. package/lib/components/leafygreen.d.ts +3 -1
  83. package/lib/components/leafygreen.d.ts.map +1 -1
  84. package/lib/components/leafygreen.js +9 -2
  85. package/lib/components/leafygreen.js.map +1 -1
  86. package/lib/components/modal.js +5 -1
  87. package/lib/components/modal.js.map +1 -1
  88. package/lib/components/more-options-toggle.d.ts +11 -0
  89. package/lib/components/more-options-toggle.d.ts.map +1 -0
  90. package/lib/components/more-options-toggle.js +60 -0
  91. package/lib/components/more-options-toggle.js.map +1 -0
  92. package/lib/components/placeholder.d.ts +5 -4
  93. package/lib/components/placeholder.d.ts.map +1 -1
  94. package/lib/components/placeholder.js +8 -2
  95. package/lib/components/placeholder.js.map +1 -1
  96. package/lib/components/resize-handle.js +5 -1
  97. package/lib/components/resize-handle.js.map +1 -1
  98. package/lib/components/resizeable-sidebar.d.ts +8 -0
  99. package/lib/components/resizeable-sidebar.d.ts.map +1 -0
  100. package/lib/components/resizeable-sidebar.js +84 -0
  101. package/lib/components/resizeable-sidebar.js.map +1 -0
  102. package/lib/components/spin-loader.d.ts +2 -1
  103. package/lib/components/spin-loader.d.ts.map +1 -1
  104. package/lib/components/spin-loader.js +2 -2
  105. package/lib/components/spin-loader.js.map +1 -1
  106. package/lib/components/tooltip.js +5 -1
  107. package/lib/components/tooltip.js.map +1 -1
  108. package/lib/components/virtual-grid.js +5 -1
  109. package/lib/components/virtual-grid.js.map +1 -1
  110. package/lib/components/workspace-tabs/tab.js +5 -1
  111. package/lib/components/workspace-tabs/tab.js.map +1 -1
  112. package/lib/components/workspace-tabs/workspace-tabs.js +5 -1
  113. package/lib/components/workspace-tabs/workspace-tabs.js.map +1 -1
  114. package/lib/constants/mongodb-ace-theme-query.d.ts +4 -0
  115. package/lib/constants/mongodb-ace-theme-query.d.ts.map +1 -0
  116. package/lib/constants/mongodb-ace-theme-query.js +235 -0
  117. package/lib/constants/mongodb-ace-theme-query.js.map +1 -0
  118. package/lib/constants/mongodb-ace-theme.d.ts +3 -0
  119. package/lib/constants/mongodb-ace-theme.d.ts.map +1 -0
  120. package/lib/constants/mongodb-ace-theme.js +113 -0
  121. package/lib/constants/mongodb-ace-theme.js.map +1 -0
  122. package/lib/hooks/use-focus-ring.d.ts +2 -2
  123. package/lib/hooks/use-focus-ring.d.ts.map +1 -1
  124. package/lib/hooks/use-focus-ring.js +4 -4
  125. package/lib/hooks/use-focus-ring.js.map +1 -1
  126. package/lib/hooks/use-sort.d.ts.map +1 -1
  127. package/lib/hooks/use-sort.js +5 -1
  128. package/lib/hooks/use-sort.js.map +1 -1
  129. package/lib/hooks/use-theme.d.ts +2 -1
  130. package/lib/hooks/use-theme.d.ts.map +1 -1
  131. package/lib/hooks/use-theme.js +7 -2
  132. package/lib/hooks/use-theme.js.map +1 -1
  133. package/lib/hooks/use-toast.js +5 -1
  134. package/lib/hooks/use-toast.js.map +1 -1
  135. package/lib/index.d.ts +8 -4
  136. package/lib/index.d.ts.map +1 -1
  137. package/lib/index.js +20 -3
  138. package/lib/index.js.map +1 -1
  139. package/package.json +26 -22
@@ -0,0 +1,725 @@
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
+ const react_1 = __importStar(require("react"));
30
+ const lodash_1 = require("lodash");
31
+ const typography_1 = require("@leafygreen-ui/typography");
32
+ const popover_1 = __importDefault(require("@leafygreen-ui/popover"));
33
+ const hooks_1 = require("@leafygreen-ui/hooks");
34
+ const interaction_ring_1 = __importDefault(require("@leafygreen-ui/interaction-ring"));
35
+ const icon_1 = __importDefault(require("@leafygreen-ui/icon"));
36
+ const icon_button_1 = __importDefault(require("@leafygreen-ui/icon-button"));
37
+ const emotion_1 = require("@leafygreen-ui/emotion");
38
+ const palette_1 = require("@leafygreen-ui/palette");
39
+ const lib_1 = require("@leafygreen-ui/lib");
40
+ const combobox_types_1 = require("./combobox-types");
41
+ const combobox_context_1 = require("./combobox-context");
42
+ const combobox_option_1 = require("./combobox-option");
43
+ const chip_1 = require("./chip");
44
+ const combobox_styles_1 = require("./combobox.styles");
45
+ const combobox_group_1 = require("./combobox-group");
46
+ const util_1 = require("./util");
47
+ function Combobox({ children, label, description, placeholder = 'Select', 'aria-label': ariaLabel, disabled = false, size = 'default', darkMode = false, 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, ...rest }) {
48
+ const getOptionRef = (0, hooks_1.useDynamicRefs)({ prefix: 'option' });
49
+ const getChipRef = (0, hooks_1.useDynamicRefs)({ prefix: 'chip' });
50
+ const inputId = (0, hooks_1.useIdAllocator)({ prefix: 'combobox-input' });
51
+ const labelId = (0, hooks_1.useIdAllocator)({ prefix: 'combobox-label' });
52
+ const menuId = (0, hooks_1.useIdAllocator)({ prefix: 'combobox-menu' });
53
+ const comboboxRef = (0, react_1.useRef)(null);
54
+ const clearButtonRef = (0, react_1.useRef)(null);
55
+ const inputWrapperRef = (0, react_1.useRef)(null);
56
+ const inputRef = (0, react_1.useRef)(null);
57
+ const menuRef = (0, react_1.useRef)(null);
58
+ const [isOpen, setOpen] = (0, react_1.useState)(false);
59
+ const prevOpenState = (0, hooks_1.usePrevious)(isOpen);
60
+ const [focusedOption, setFocusedOption] = (0, react_1.useState)(null);
61
+ const [selection, setSelection] = (0, react_1.useState)(null);
62
+ const prevSelection = (0, hooks_1.usePrevious)(selection);
63
+ const [inputValue, setInputValue] = (0, react_1.useState)('');
64
+ const prevValue = (0, hooks_1.usePrevious)(inputValue);
65
+ const [focusedChip, setFocusedChip] = (0, react_1.useState)(null);
66
+ const doesSelectionExist = !(0, lodash_1.isNull)(selection) &&
67
+ (((0, lodash_1.isArray)(selection) && selection.length > 0) || (0, lodash_1.isString)(selection));
68
+ const isMultiselect = (0, react_1.useCallback)((test) => multiselect && (0, lodash_1.isArray)(test), [multiselect]);
69
+ const setInputFocus = (0, react_1.useCallback)((cursorPos) => {
70
+ if (!disabled && inputRef && inputRef.current) {
71
+ inputRef.current.focus();
72
+ if (!(0, lodash_1.isUndefined)(cursorPos)) {
73
+ inputRef.current.setSelectionRange(cursorPos, cursorPos);
74
+ }
75
+ }
76
+ }, [disabled]);
77
+ const updateSelection = (0, react_1.useCallback)((value) => {
78
+ if (isMultiselect(selection)) {
79
+ const newSelection = (0, lodash_1.clone)(selection);
80
+ if ((0, lodash_1.isNull)(value)) {
81
+ newSelection.length = 0;
82
+ }
83
+ else {
84
+ if (selection.includes(value)) {
85
+ newSelection.splice(newSelection.indexOf(value), 1);
86
+ }
87
+ else {
88
+ newSelection.push(value);
89
+ setInputValue('');
90
+ }
91
+ }
92
+ setSelection(newSelection);
93
+ onChange === null || onChange === void 0 ? void 0 : onChange(newSelection);
94
+ }
95
+ else {
96
+ const newSelection = value;
97
+ setSelection(newSelection);
98
+ onChange === null || onChange === void 0 ? void 0 : onChange(newSelection);
99
+ }
100
+ }, [isMultiselect, onChange, selection]);
101
+ const scrollToEnd = () => {
102
+ if (inputWrapperRef && inputWrapperRef.current) {
103
+ inputWrapperRef.current.scrollLeft = inputWrapperRef.current.scrollWidth;
104
+ }
105
+ };
106
+ const placeholderValue = multiselect && (0, lodash_1.isArray)(selection) && selection.length > 0
107
+ ? undefined
108
+ : placeholder;
109
+ const allOptions = (0, react_1.useMemo)(() => (0, util_1.flattenChildren)(children), [children]);
110
+ const getDisplayNameForValue = (0, react_1.useCallback)((value) => {
111
+ var _a, _b;
112
+ return value
113
+ ? (_b = (_a = allOptions.find((opt) => opt.value === value)) === null || _a === void 0 ? void 0 : _a.displayName) !== null && _b !== void 0 ? _b : value
114
+ : '';
115
+ }, [allOptions]);
116
+ const isOptionVisible = (0, react_1.useCallback)((option) => {
117
+ const value = typeof option === 'string' ? option : option.value;
118
+ if (filteredOptions && filteredOptions.length > 0) {
119
+ return filteredOptions.includes(value);
120
+ }
121
+ const displayName = typeof option === 'string'
122
+ ? getDisplayNameForValue(value)
123
+ : option.displayName;
124
+ return displayName.toLowerCase().includes(inputValue.toLowerCase());
125
+ }, [filteredOptions, getDisplayNameForValue, inputValue]);
126
+ const visibleOptions = (0, react_1.useMemo)(() => allOptions.filter(isOptionVisible), [allOptions, isOptionVisible]);
127
+ const isValueValid = (0, react_1.useCallback)((value) => {
128
+ return value ? !!allOptions.find((opt) => opt.value === value) : false;
129
+ }, [allOptions]);
130
+ const getIndexOfValue = (0, react_1.useCallback)((value) => {
131
+ return visibleOptions
132
+ ? visibleOptions.findIndex((option) => option.value === value)
133
+ : -1;
134
+ }, [visibleOptions]);
135
+ const getValueAtIndex = (0, react_1.useCallback)((index) => {
136
+ if (visibleOptions && visibleOptions.length >= index) {
137
+ const option = visibleOptions[index];
138
+ return option ? option.value : undefined;
139
+ }
140
+ }, [visibleOptions]);
141
+ const getActiveChipIndex = (0, react_1.useCallback)(() => isMultiselect(selection)
142
+ ? selection.findIndex((value) => { var _a, _b; return (_b = (_a = getChipRef(value)) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.contains(document.activeElement); })
143
+ : -1, [getChipRef, isMultiselect, selection]);
144
+ const getFocusedElementName = (0, react_1.useCallback)(() => {
145
+ var _a, _b, _c;
146
+ const isFocusOn = {
147
+ Input: (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement),
148
+ ClearButton: (_b = clearButtonRef.current) === null || _b === void 0 ? void 0 : _b.contains(document.activeElement),
149
+ Chip: isMultiselect(selection) &&
150
+ selection.some((value) => { var _a, _b; return (_b = (_a = getChipRef(value)) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.contains(document.activeElement); }),
151
+ };
152
+ const getActiveChipIndex = () => isMultiselect(selection)
153
+ ? selection.findIndex((value) => { var _a, _b; return (_b = (_a = getChipRef(value)) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.contains(document.activeElement); })
154
+ : -1;
155
+ if (isMultiselect(selection) && isFocusOn.Chip) {
156
+ if (getActiveChipIndex() === 0) {
157
+ return 'FirstChip';
158
+ }
159
+ else if (getActiveChipIndex() === selection.length - 1) {
160
+ return 'LastChip';
161
+ }
162
+ return 'MiddleChip';
163
+ }
164
+ else if (isFocusOn.Input) {
165
+ return 'Input';
166
+ }
167
+ else if (isFocusOn.ClearButton) {
168
+ return 'ClearButton';
169
+ }
170
+ else if ((_c = comboboxRef.current) === null || _c === void 0 ? void 0 : _c.contains(document.activeElement)) {
171
+ return 'Combobox';
172
+ }
173
+ }, [getChipRef, isMultiselect, selection]);
174
+ const updateFocusedOption = (0, react_1.useCallback)((direction) => {
175
+ var _a;
176
+ const optionsCount = (_a = visibleOptions === null || visibleOptions === void 0 ? void 0 : visibleOptions.length) !== null && _a !== void 0 ? _a : 0;
177
+ const lastIndex = optionsCount - 1 > 0 ? optionsCount - 1 : 0;
178
+ const indexOfFocus = getIndexOfValue(focusedOption);
179
+ if (direction && isOpen) {
180
+ setFocusedChip(null);
181
+ setInputFocus();
182
+ }
183
+ switch (direction) {
184
+ case 'next': {
185
+ const newValue = indexOfFocus + 1 < optionsCount
186
+ ? getValueAtIndex(indexOfFocus + 1)
187
+ : getValueAtIndex(0);
188
+ setFocusedOption(newValue !== null && newValue !== void 0 ? newValue : null);
189
+ break;
190
+ }
191
+ case 'prev': {
192
+ const newValue = indexOfFocus - 1 >= 0
193
+ ? getValueAtIndex(indexOfFocus - 1)
194
+ : getValueAtIndex(lastIndex);
195
+ setFocusedOption(newValue !== null && newValue !== void 0 ? newValue : null);
196
+ break;
197
+ }
198
+ case 'last': {
199
+ const newValue = getValueAtIndex(lastIndex);
200
+ setFocusedOption(newValue !== null && newValue !== void 0 ? newValue : null);
201
+ break;
202
+ }
203
+ case 'first':
204
+ default: {
205
+ const newValue = getValueAtIndex(0);
206
+ setFocusedOption(newValue !== null && newValue !== void 0 ? newValue : null);
207
+ }
208
+ }
209
+ }, [
210
+ focusedOption,
211
+ getIndexOfValue,
212
+ getValueAtIndex,
213
+ isOpen,
214
+ setInputFocus,
215
+ visibleOptions === null || visibleOptions === void 0 ? void 0 : visibleOptions.length,
216
+ ]);
217
+ const updateFocusedChip = (0, react_1.useCallback)((direction, relativeToIndex) => {
218
+ if (isMultiselect(selection)) {
219
+ switch (direction) {
220
+ case 'next': {
221
+ const referenceChipIndex = relativeToIndex !== null && relativeToIndex !== void 0 ? relativeToIndex : getActiveChipIndex();
222
+ const nextChipIndex = referenceChipIndex + 1 < selection.length
223
+ ? referenceChipIndex + 1
224
+ : selection.length - 1;
225
+ const nextChipValue = selection[nextChipIndex];
226
+ setFocusedChip(nextChipValue);
227
+ break;
228
+ }
229
+ case 'prev': {
230
+ const referenceChipIndex = relativeToIndex !== null && relativeToIndex !== void 0 ? relativeToIndex : getActiveChipIndex();
231
+ const prevChipIndex = referenceChipIndex > 0
232
+ ? referenceChipIndex - 1
233
+ : referenceChipIndex < 0
234
+ ? selection.length - 1
235
+ : 0;
236
+ const prevChipValue = selection[prevChipIndex];
237
+ setFocusedChip(prevChipValue);
238
+ break;
239
+ }
240
+ case 'first': {
241
+ const firstChipValue = selection[0];
242
+ setFocusedChip(firstChipValue);
243
+ break;
244
+ }
245
+ case 'last': {
246
+ const lastChipValue = selection[selection.length - 1];
247
+ setFocusedChip(lastChipValue);
248
+ break;
249
+ }
250
+ default:
251
+ setFocusedChip(null);
252
+ break;
253
+ }
254
+ }
255
+ }, [getActiveChipIndex, isMultiselect, selection]);
256
+ const handleArrowKey = (0, react_1.useCallback)((direction, event) => {
257
+ var _a, _b, _c, _d, _e;
258
+ if (direction)
259
+ setFocusedOption(null);
260
+ const focusedElementName = getFocusedElementName();
261
+ switch (direction) {
262
+ case 'right':
263
+ switch (focusedElementName) {
264
+ case 'Input': {
265
+ if (((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.selectionEnd) ===
266
+ ((_b = inputRef.current) === null || _b === void 0 ? void 0 : _b.value.length)) {
267
+ (_c = clearButtonRef.current) === null || _c === void 0 ? void 0 : _c.focus();
268
+ }
269
+ break;
270
+ }
271
+ case 'LastChip': {
272
+ event.preventDefault();
273
+ setInputFocus(0);
274
+ updateFocusedChip(null);
275
+ break;
276
+ }
277
+ case 'FirstChip':
278
+ case 'MiddleChip': {
279
+ updateFocusedChip('next');
280
+ break;
281
+ }
282
+ case 'ClearButton':
283
+ default:
284
+ break;
285
+ }
286
+ break;
287
+ case 'left':
288
+ switch (focusedElementName) {
289
+ case 'ClearButton': {
290
+ event.preventDefault();
291
+ setInputFocus((_d = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) === null || _d === void 0 ? void 0 : _d.value.length);
292
+ break;
293
+ }
294
+ case 'Input':
295
+ case 'MiddleChip':
296
+ case 'LastChip': {
297
+ if (isMultiselect(selection)) {
298
+ if (focusedElementName === 'Input' &&
299
+ ((_e = inputRef.current) === null || _e === void 0 ? void 0 : _e.selectionStart) !== 0) {
300
+ break;
301
+ }
302
+ updateFocusedChip('prev');
303
+ }
304
+ break;
305
+ }
306
+ case 'FirstChip':
307
+ default:
308
+ break;
309
+ }
310
+ break;
311
+ default:
312
+ updateFocusedChip(null);
313
+ break;
314
+ }
315
+ }, [
316
+ getFocusedElementName,
317
+ isMultiselect,
318
+ selection,
319
+ setInputFocus,
320
+ updateFocusedChip,
321
+ ]);
322
+ (0, react_1.useEffect)(() => {
323
+ if (inputValue !== prevValue) {
324
+ updateFocusedOption('first');
325
+ }
326
+ }, [inputValue, isOpen, prevValue, updateFocusedOption]);
327
+ (0, react_1.useEffect)(() => {
328
+ if (focusedOption) {
329
+ const focusedElementRef = getOptionRef(focusedOption);
330
+ if (focusedElementRef && focusedElementRef.current && menuRef.current) {
331
+ const { offsetTop: optionTop } = focusedElementRef.current;
332
+ const { scrollTop: menuScroll, offsetHeight: menuHeight } = menuRef.current;
333
+ if (optionTop > menuHeight || optionTop < menuScroll) {
334
+ menuRef.current.scrollTop = optionTop;
335
+ }
336
+ }
337
+ }
338
+ }, [focusedOption, getOptionRef]);
339
+ const renderInternalOptions = (0, react_1.useCallback)((_children) => {
340
+ return react_1.default.Children.map(_children, (child) => {
341
+ if ((0, lib_1.isComponentType)(child, 'ComboboxOption')) {
342
+ const { value, displayName } = (0, util_1.getNameAndValue)(child.props);
343
+ if (isOptionVisible(value)) {
344
+ const { className, glyph } = child.props;
345
+ const index = allOptions.findIndex((opt) => opt.value === value);
346
+ const isFocused = focusedOption === value;
347
+ const isSelected = isMultiselect(selection)
348
+ ? selection.includes(value)
349
+ : selection === value;
350
+ const setSelected = () => {
351
+ setFocusedOption(value);
352
+ updateSelection(value);
353
+ setInputFocus();
354
+ if (value === selection) {
355
+ closeMenu();
356
+ }
357
+ };
358
+ const optionRef = getOptionRef(value);
359
+ return (react_1.default.createElement(combobox_option_1.InternalComboboxOption, { value: value, displayName: displayName, isFocused: isFocused, isSelected: isSelected, setSelected: setSelected, glyph: glyph, className: className, index: index, ref: optionRef }));
360
+ }
361
+ }
362
+ else if ((0, lib_1.isComponentType)(child, 'ComboboxGroup')) {
363
+ const nestedChildren = renderInternalOptions(child.props.children);
364
+ if (nestedChildren && (nestedChildren === null || nestedChildren === void 0 ? void 0 : nestedChildren.length) > 0) {
365
+ return (react_1.default.createElement(combobox_group_1.InternalComboboxGroup, { label: child.props.label, className: child.props.className }, renderInternalOptions(nestedChildren)));
366
+ }
367
+ }
368
+ });
369
+ }, [
370
+ allOptions,
371
+ focusedOption,
372
+ getOptionRef,
373
+ isMultiselect,
374
+ isOptionVisible,
375
+ selection,
376
+ setInputFocus,
377
+ updateSelection,
378
+ ]);
379
+ const renderedOptions = (0, react_1.useMemo)(() => renderInternalOptions(children), [children, renderInternalOptions]);
380
+ const renderedChips = (0, react_1.useMemo)(() => {
381
+ if (isMultiselect(selection)) {
382
+ return selection.filter(isValueValid).map((value, index) => {
383
+ const displayName = getDisplayNameForValue(value);
384
+ const onRemove = () => {
385
+ updateFocusedChip('next', index);
386
+ updateSelection(value);
387
+ };
388
+ const isFocused = focusedChip === value;
389
+ const chipRef = getChipRef(value);
390
+ const onFocus = () => {
391
+ setFocusedChip(value);
392
+ };
393
+ return (react_1.default.createElement(chip_1.Chip, { key: value, displayName: displayName, isFocused: isFocused, onRemove: onRemove, onFocus: onFocus, ref: chipRef }));
394
+ });
395
+ }
396
+ }, [
397
+ isMultiselect,
398
+ selection,
399
+ isValueValid,
400
+ getDisplayNameForValue,
401
+ focusedChip,
402
+ getChipRef,
403
+ updateFocusedChip,
404
+ updateSelection,
405
+ ]);
406
+ const renderedInputIcons = (0, react_1.useMemo)(() => {
407
+ const handleClearButtonClick = (e) => {
408
+ if (!disabled) {
409
+ updateSelection(null);
410
+ onClear === null || onClear === void 0 ? void 0 : onClear(e);
411
+ onFilter === null || onFilter === void 0 ? void 0 : onFilter('');
412
+ if (!isOpen) {
413
+ openMenu();
414
+ }
415
+ }
416
+ };
417
+ return (react_1.default.createElement(react_1.default.Fragment, null,
418
+ 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: combobox_styles_1.clearButton },
419
+ react_1.default.createElement(icon_1.default, { glyph: "XWithCircle" }))),
420
+ state === 'error' ? (react_1.default.createElement(icon_1.default, { glyph: "Warning", color: palette_1.uiColors.red.base, className: combobox_styles_1.endIcon })) : (react_1.default.createElement(icon_1.default, { glyph: "CaretDown", className: combobox_styles_1.endIcon }))));
421
+ }, [
422
+ clearable,
423
+ doesSelectionExist,
424
+ disabled,
425
+ state,
426
+ updateSelection,
427
+ onClear,
428
+ onFilter,
429
+ isOpen,
430
+ ]);
431
+ const withIcons = (0, react_1.useMemo)(() => allOptions.some((opt) => opt.hasGlyph), [allOptions]);
432
+ const onCloseMenu = (0, react_1.useCallback)(() => {
433
+ var _a;
434
+ if (!isMultiselect(selection) && selection === prevSelection) {
435
+ const exactMatchedOption = visibleOptions.find((option) => option.displayName === inputValue || option.value === inputValue);
436
+ if (exactMatchedOption && !value) {
437
+ setSelection(exactMatchedOption.value);
438
+ }
439
+ else {
440
+ const displayName = (_a = getDisplayNameForValue(selection)) !== null && _a !== void 0 ? _a : '';
441
+ setInputValue(displayName);
442
+ }
443
+ }
444
+ }, [
445
+ getDisplayNameForValue,
446
+ inputValue,
447
+ isMultiselect,
448
+ prevSelection,
449
+ selection,
450
+ value,
451
+ visibleOptions,
452
+ ]);
453
+ const onSelect = (0, react_1.useCallback)(() => {
454
+ var _a;
455
+ if (doesSelectionExist) {
456
+ if (isMultiselect(selection)) {
457
+ scrollToEnd();
458
+ }
459
+ else if (!isMultiselect(selection)) {
460
+ const displayName = (_a = getDisplayNameForValue(selection)) !== null && _a !== void 0 ? _a : '';
461
+ setInputValue(displayName);
462
+ closeMenu();
463
+ }
464
+ }
465
+ else {
466
+ setInputValue('');
467
+ }
468
+ }, [doesSelectionExist, getDisplayNameForValue, isMultiselect, selection]);
469
+ (0, react_1.useEffect)(() => {
470
+ var _a;
471
+ if (initialValue) {
472
+ if ((0, lodash_1.isArray)(initialValue)) {
473
+ const filteredValue = (_a = initialValue.filter((value) => isValueValid(value))) !== null && _a !== void 0 ? _a : [];
474
+ setSelection(filteredValue);
475
+ }
476
+ else {
477
+ if (isValueValid(initialValue)) {
478
+ setSelection(initialValue);
479
+ }
480
+ }
481
+ }
482
+ else {
483
+ setSelection((0, combobox_types_1.getNullSelection)(multiselect));
484
+ }
485
+ }, []);
486
+ (0, react_1.useEffect)(() => {
487
+ if (!(0, lodash_1.isUndefined)(value) && value !== prevValue) {
488
+ if ((0, lodash_1.isNull)(value)) {
489
+ setSelection(null);
490
+ }
491
+ else if (isMultiselect(value)) {
492
+ const newSelection = value.filter(isValueValid);
493
+ setSelection(newSelection);
494
+ }
495
+ else {
496
+ setSelection(isValueValid(value) ? value : null);
497
+ }
498
+ }
499
+ }, [isMultiselect, isValueValid, prevValue, value]);
500
+ (0, react_1.useEffect)(() => {
501
+ if (selection !== prevSelection) {
502
+ onSelect();
503
+ }
504
+ }, [onSelect, prevSelection, selection]);
505
+ (0, react_1.useEffect)(() => {
506
+ if (!isOpen && prevOpenState !== isOpen) {
507
+ onCloseMenu();
508
+ }
509
+ }, [isOpen, prevOpenState, onCloseMenu]);
510
+ const closeMenu = () => setOpen(false);
511
+ const openMenu = () => setOpen(true);
512
+ const [menuWidth, setMenuWidth] = (0, react_1.useState)(0);
513
+ (0, react_1.useEffect)(() => {
514
+ var _a, _b;
515
+ setMenuWidth((_b = (_a = comboboxRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth) !== null && _b !== void 0 ? _b : 0);
516
+ }, [comboboxRef, isOpen, focusedOption, selection]);
517
+ const handleTransitionEnd = () => {
518
+ var _a, _b;
519
+ setMenuWidth((_b = (_a = comboboxRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth) !== null && _b !== void 0 ? _b : 0);
520
+ };
521
+ const renderedMenuContents = (0, react_1.useMemo)(() => {
522
+ switch (searchState) {
523
+ case 'loading': {
524
+ return (react_1.default.createElement("span", { className: combobox_styles_1.menuMessage },
525
+ react_1.default.createElement(icon_1.default, { glyph: "Refresh", color: palette_1.uiColors.blue.base, className: combobox_styles_1.loadingIconStyle }),
526
+ searchLoadingMessage));
527
+ }
528
+ case 'error': {
529
+ return (react_1.default.createElement("span", { className: combobox_styles_1.menuMessage },
530
+ react_1.default.createElement(icon_1.default, { glyph: "Warning", color: palette_1.uiColors.red.base }),
531
+ searchErrorMessage));
532
+ }
533
+ case 'unset':
534
+ default: {
535
+ if (renderedOptions && renderedOptions.length > 0) {
536
+ return react_1.default.createElement("ul", { className: combobox_styles_1.menuList }, renderedOptions);
537
+ }
538
+ return react_1.default.createElement("span", { className: combobox_styles_1.menuMessage }, searchEmptyMessage);
539
+ }
540
+ }
541
+ }, [
542
+ renderedOptions,
543
+ searchEmptyMessage,
544
+ searchErrorMessage,
545
+ searchLoadingMessage,
546
+ searchState,
547
+ ]);
548
+ const viewportSize = (0, hooks_1.useViewportSize)();
549
+ const maxHeight = (0, react_1.useMemo)(() => {
550
+ const maxMenuHeight = 274;
551
+ const menuMargin = 8;
552
+ if (viewportSize && comboboxRef.current && menuRef.current) {
553
+ const { top: triggerTop, bottom: triggerBottom } = comboboxRef.current.getBoundingClientRect();
554
+ const safeSpace = Math.max(viewportSize.height - triggerBottom, triggerTop);
555
+ return Math.min(maxMenuHeight, safeSpace - menuMargin);
556
+ }
557
+ return maxMenuHeight;
558
+ }, [viewportSize, comboboxRef, menuRef]);
559
+ (0, react_1.useEffect)(() => {
560
+ }, [focusedOption]);
561
+ const handleInputWrapperMousedown = (e) => {
562
+ if (e.target !== inputRef.current) {
563
+ e.preventDefault();
564
+ }
565
+ };
566
+ const handleInputWrapperClick = (e) => {
567
+ if (e.target !== inputRef.current) {
568
+ let cursorPos = 0;
569
+ if (inputRef.current) {
570
+ const mouseX = e.nativeEvent.offsetX;
571
+ const inputRight = inputRef.current.offsetLeft + inputRef.current.clientWidth;
572
+ cursorPos = mouseX > inputRight ? inputValue.length : 0;
573
+ }
574
+ setInputFocus(cursorPos);
575
+ }
576
+ };
577
+ const handleInputWrapperFocus = () => {
578
+ scrollToEnd();
579
+ openMenu();
580
+ };
581
+ const handleInputChange = ({ target: { value }, }) => {
582
+ setInputValue(value);
583
+ onFilter === null || onFilter === void 0 ? void 0 : onFilter(value);
584
+ };
585
+ const handleClearButtonFocus = () => {
586
+ setFocusedOption(null);
587
+ };
588
+ const handleKeyDown = (event) => {
589
+ var _a, _b, _c;
590
+ const isFocusInMenu = (_a = menuRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);
591
+ const isFocusOnCombobox = (_b = comboboxRef.current) === null || _b === void 0 ? void 0 : _b.contains(document.activeElement);
592
+ const isFocusInComponent = isFocusOnCombobox || isFocusInMenu;
593
+ if (isFocusInComponent) {
594
+ if (event.ctrlKey || event.shiftKey || event.altKey) {
595
+ return;
596
+ }
597
+ const focusedElement = getFocusedElementName();
598
+ switch (event.keyCode) {
599
+ case util_1.keyMap.Tab: {
600
+ switch (focusedElement) {
601
+ case 'Input': {
602
+ if (!doesSelectionExist) {
603
+ closeMenu();
604
+ updateFocusedOption('first');
605
+ updateFocusedChip(null);
606
+ }
607
+ break;
608
+ }
609
+ case 'LastChip': {
610
+ updateFocusedChip(null);
611
+ break;
612
+ }
613
+ case 'FirstChip':
614
+ case 'MiddleChip': {
615
+ break;
616
+ }
617
+ case 'ClearButton':
618
+ default:
619
+ break;
620
+ }
621
+ break;
622
+ }
623
+ case util_1.keyMap.Escape: {
624
+ closeMenu();
625
+ updateFocusedOption('first');
626
+ break;
627
+ }
628
+ case util_1.keyMap.Enter:
629
+ case util_1.keyMap.Space: {
630
+ if (isOpen) {
631
+ event.preventDefault();
632
+ }
633
+ if (document.activeElement === inputRef.current &&
634
+ isOpen &&
635
+ !(0, lodash_1.isNull)(focusedOption)) {
636
+ updateSelection(focusedOption);
637
+ }
638
+ else if (document.activeElement === clearButtonRef.current) {
639
+ updateSelection(null);
640
+ setInputFocus();
641
+ }
642
+ break;
643
+ }
644
+ case util_1.keyMap.Backspace: {
645
+ if (isMultiselect(selection) &&
646
+ ((_c = inputRef.current) === null || _c === void 0 ? void 0 : _c.selectionStart) === 0) {
647
+ updateFocusedChip('last');
648
+ }
649
+ else {
650
+ openMenu();
651
+ }
652
+ break;
653
+ }
654
+ case util_1.keyMap.ArrowDown: {
655
+ if (isOpen) {
656
+ event.preventDefault();
657
+ }
658
+ openMenu();
659
+ updateFocusedOption('next');
660
+ break;
661
+ }
662
+ case util_1.keyMap.ArrowUp: {
663
+ if (isOpen) {
664
+ event.preventDefault();
665
+ }
666
+ updateFocusedOption('prev');
667
+ break;
668
+ }
669
+ case util_1.keyMap.ArrowRight: {
670
+ handleArrowKey('right', event);
671
+ break;
672
+ }
673
+ case util_1.keyMap.ArrowLeft: {
674
+ handleArrowKey('left', event);
675
+ break;
676
+ }
677
+ default: {
678
+ if (!isOpen) {
679
+ openMenu();
680
+ }
681
+ }
682
+ }
683
+ }
684
+ };
685
+ const handleBackdropClick = ({ target }) => {
686
+ var _a, _b;
687
+ const isChildFocused = ((_a = menuRef.current) === null || _a === void 0 ? void 0 : _a.contains(target)) ||
688
+ ((_b = comboboxRef.current) === null || _b === void 0 ? void 0 : _b.contains(target)) ||
689
+ false;
690
+ if (!isChildFocused) {
691
+ setOpen(false);
692
+ }
693
+ };
694
+ (0, hooks_1.useEventListener)('mousedown', handleBackdropClick);
695
+ return (react_1.default.createElement(combobox_context_1.ComboboxContext.Provider, { value: {
696
+ multiselect,
697
+ darkMode,
698
+ size,
699
+ withIcons,
700
+ disabled,
701
+ chipTruncationLocation,
702
+ chipCharacterLimit,
703
+ inputValue,
704
+ } },
705
+ react_1.default.createElement("div", { className: (0, emotion_1.cx)((0, combobox_styles_1.comboboxParentStyle)({ darkMode, size, overflow }), className), ...rest },
706
+ react_1.default.createElement("div", null,
707
+ label && (react_1.default.createElement(typography_1.Label, { id: labelId, htmlFor: inputId }, label)),
708
+ description && react_1.default.createElement(typography_1.Description, null, description)),
709
+ react_1.default.createElement(interaction_ring_1.default, { className: combobox_styles_1.interactionRingStyle, disabled: disabled, color: (0, combobox_styles_1.interactionRingColor)({ state, darkMode }) },
710
+ react_1.default.createElement("div", { ref: comboboxRef, role: "combobox", "aria-expanded": isOpen, "aria-controls": menuId, "aria-owns": menuId, tabIndex: -1, className: combobox_styles_1.comboboxStyle, onMouseDown: handleInputWrapperMousedown, onClick: handleInputWrapperClick, onFocus: handleInputWrapperFocus, onKeyDown: handleKeyDown, onTransitionEnd: handleTransitionEnd, "data-disabled": disabled, "data-state": state },
711
+ react_1.default.createElement("div", { ref: inputWrapperRef, className: (0, combobox_styles_1.inputWrapperStyle)({
712
+ overflow,
713
+ isOpen,
714
+ selection,
715
+ value: inputValue,
716
+ }) },
717
+ renderedChips,
718
+ react_1.default.createElement("input", { "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : label, "aria-autocomplete": "list", "aria-controls": menuId, "aria-labelledby": labelId, ref: inputRef, id: inputId, className: combobox_styles_1.inputElementStyle, placeholder: placeholderValue, disabled: disabled !== null && disabled !== void 0 ? disabled : undefined, onChange: handleInputChange, value: inputValue, autoComplete: "off" })),
719
+ renderedInputIcons)),
720
+ state === 'error' && errorMessage && (react_1.default.createElement("div", { className: combobox_styles_1.errorMessageStyle }, errorMessage)),
721
+ react_1.default.createElement(popover_1.default, { active: isOpen && !disabled, spacing: 4, align: "bottom", justify: "middle", refEl: comboboxRef, adjustOnMutation: true, className: (0, combobox_styles_1.menuWrapperStyle)({ darkMode, size, width: menuWidth }) },
722
+ react_1.default.createElement("div", { id: menuId, role: "listbox", "aria-labelledby": labelId, "aria-expanded": isOpen, ref: menuRef, className: (0, combobox_styles_1.menuStyle)({ maxHeight }), onMouseDownCapture: (e) => e.preventDefault() }, renderedMenuContents)))));
723
+ }
724
+ exports.default = Combobox;
725
+ //# sourceMappingURL=combobox.js.map