@carbon/web-components 2.43.0 → 2.44.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 (217) hide show
  1. package/custom-elements.json +8 -15
  2. package/dist/accordion.min.js +3 -3
  3. package/dist/ai-label.min.js +3 -3
  4. package/dist/ai-skeleton.min.js +3 -3
  5. package/dist/badge-indicator.min.js +3 -3
  6. package/dist/breadcrumb.min.js +6 -6
  7. package/dist/{button-eTloXzqX.js → button-CKgb4gp4.js} +4 -3
  8. package/dist/{button-skeleton-Dk3chlBc.js → button-skeleton-CXiEp3M8.js} +3 -3
  9. package/dist/button.min.js +3 -3
  10. package/dist/chat-button.min.js +3 -3
  11. package/dist/{checkbox-cr5-wvt1.js → checkbox-cQAHKwqU.js} +3 -3
  12. package/dist/checkbox.min.js +3 -3
  13. package/dist/{class-map-CJoc5JjN.js → class-map-warKt-hW.js} +3 -3
  14. package/dist/code-snippet.min.js +3 -3
  15. package/dist/combo-box.min.js +20 -9
  16. package/dist/combo-button.min.js +3 -3
  17. package/dist/{content-switcher-item-3fTDI2Aq.js → content-switcher-item-Cvkk1snv.js} +3 -3
  18. package/dist/content-switcher.min.js +3 -3
  19. package/dist/copy-button.min.js +3 -3
  20. package/dist/data-table.min.js +3 -3
  21. package/dist/date-picker.min.js +3 -3
  22. package/dist/dropdown-item-BHkaXms6.js +100 -0
  23. package/dist/dropdown.min.js +6 -10
  24. package/dist/feature-flags.min.js +3 -3
  25. package/dist/file-uploader.min.js +3 -3
  26. package/dist/floating-menu.min.js +3 -3
  27. package/dist/fluid-search.min.js +3 -3
  28. package/dist/fluid-select.min.js +3 -3
  29. package/dist/fluid-text-input.min.js +3 -3
  30. package/dist/fluid-textarea.min.js +3 -3
  31. package/dist/{focus-yD1Q_pDt.js → focus-Bwk_lgHl.js} +3 -3
  32. package/dist/{form-BaYTr2z0.js → form-CfvlKX6g.js} +3 -3
  33. package/dist/form-group.min.js +3 -3
  34. package/dist/form.min.js +3 -3
  35. package/dist/grid.min.js +3 -3
  36. package/dist/heading.min.js +3 -3
  37. package/dist/{host-listener-BJsBtsIt.js → host-listener-DJH6yN4y.js} +3 -3
  38. package/dist/icon-button.min.js +3 -3
  39. package/dist/icon-indicator.min.js +3 -3
  40. package/dist/{icon-loader-CqB9WRMP.js → icon-loader-pxyCrZwZ.js} +3 -3
  41. package/dist/{icon-loader-utils-DUl0vwdh.js → icon-loader-utils-lPqg1iFP.js} +3 -3
  42. package/dist/icon.min.js +3 -3
  43. package/dist/{if-defined-IxozbDOJ.js → if-defined-zhGxRN9M.js} +3 -3
  44. package/dist/{if-non-empty-CqQHBHdQ.js → if-non-empty-CTDui88C.js} +3 -3
  45. package/dist/inline-loading.min.js +4 -4
  46. package/dist/layer.min.js +3 -3
  47. package/dist/link.min.js +3 -3
  48. package/dist/list.min.js +3 -3
  49. package/dist/{loading-icon-CSgLYhyw.js → loading-icon-DfL1aC0N.js} +3 -3
  50. package/dist/loading.min.js +3 -3
  51. package/dist/menu-button.min.js +3 -3
  52. package/dist/menu.min.js +3 -3
  53. package/dist/modal.min.js +3 -3
  54. package/dist/multi-select.min.js +4 -3
  55. package/dist/notification.min.js +3 -3
  56. package/dist/number-input.min.js +3 -3
  57. package/dist/overflow-menu.min.js +3 -3
  58. package/dist/page-header.min.js +3 -3
  59. package/dist/pagination.min.js +3 -3
  60. package/dist/password-input.min.js +3 -3
  61. package/dist/popover.min.js +3 -3
  62. package/dist/progress-bar.min.js +3 -3
  63. package/dist/progress-indicator.min.js +3 -3
  64. package/dist/{property-B_F7V5eB.js → property-CoShOfqo.js} +3 -3
  65. package/dist/{query-assigned-elements-DeMmXVMb.js → query-assigned-elements-DvdLJjH_.js} +3 -3
  66. package/dist/radio-button.min.js +3 -3
  67. package/dist/{search-DhwzN9sI.js → search-mXlboHWm.js} +3 -3
  68. package/dist/search.min.js +3 -3
  69. package/dist/{select-BIi12O8B.js → select-BLrQXy2c.js} +4 -3
  70. package/dist/{select-item-Be7OL9mD.js → select-item-CMDCy7c6.js} +3 -3
  71. package/dist/{select-skeleton-8uIIQzNt.js → select-skeleton-D_qjQ9lZ.js} +3 -3
  72. package/dist/select.min.js +3 -3
  73. package/dist/shape-indicator.min.js +3 -3
  74. package/dist/side-panel.min.js +3 -3
  75. package/dist/skeleton-icon.min.js +3 -3
  76. package/dist/skeleton-placeholder.min.js +3 -3
  77. package/dist/skeleton-text.min.js +3 -3
  78. package/dist/skip-to-content.min.js +3 -3
  79. package/dist/slider.min.js +3 -3
  80. package/dist/slug.min.js +3 -3
  81. package/dist/stack.min.js +3 -3
  82. package/dist/{state-CJQmj6wG.js → state-D7rtIkB2.js} +3 -3
  83. package/dist/structured-list.min.js +3 -3
  84. package/dist/tabs.min.js +3 -3
  85. package/dist/tag.min.js +3 -3
  86. package/dist/tearsheet.min.js +3 -3
  87. package/dist/{text-input-C0qeKR9e.js → text-input-CIM-jSOC.js} +3 -3
  88. package/dist/text-input.min.js +3 -3
  89. package/dist/textarea.min.js +3 -3
  90. package/dist/tile.min.js +3 -3
  91. package/dist/time-picker.min.js +3 -3
  92. package/dist/toggle-tip.min.js +3 -3
  93. package/dist/toggle.min.js +3 -3
  94. package/dist/{tooltip-content-CMbdEoxb.js → tooltip-content-D25Rgp9z.js} +3 -3
  95. package/dist/tooltip.min.js +3 -3
  96. package/dist/tree-view.min.js +3 -3
  97. package/dist/ui-shell.min.js +3 -3
  98. package/dist/{unsafe-html-Dqv0UqC_.js → unsafe-html-C26Gpb7O.js} +3 -3
  99. package/es/components/ai-label/ai-label.scss.js +1 -1
  100. package/es/components/breadcrumb/breadcrumb.scss.js +1 -1
  101. package/es/components/button/button.js +1 -0
  102. package/es/components/button/button.js.map +1 -1
  103. package/es/components/combo-box/combo-box-item.d.ts +10 -1
  104. package/es/components/combo-box/combo-box-item.js +65 -1
  105. package/es/components/combo-box/combo-box-item.js.map +1 -1
  106. package/es/components/combo-box/combo-box.d.ts +6 -9
  107. package/es/components/combo-box/combo-box.js +108 -65
  108. package/es/components/combo-box/combo-box.js.map +1 -1
  109. package/es/components/combo-box/combo-box.scss.js +1 -1
  110. package/es/components/data-table/data-table.scss.js +1 -1
  111. package/es/components/dropdown/dropdown-skeleton.d.ts +10 -1
  112. package/es/components/dropdown/dropdown-skeleton.js +31 -7
  113. package/es/components/dropdown/dropdown-skeleton.js.map +1 -1
  114. package/es/components/dropdown/dropdown.d.ts +41 -7
  115. package/es/components/dropdown/dropdown.js +438 -65
  116. package/es/components/dropdown/dropdown.js.map +1 -1
  117. package/es/components/dropdown/dropdown.scss.js +1 -1
  118. package/es/components/icon-button/icon-button.scss.js +1 -1
  119. package/es/components/inline-loading/inline-loading.js +1 -1
  120. package/es/components/inline-loading/inline-loading.js.map +1 -1
  121. package/es/components/inline-loading/inline-loading.scss.js +1 -1
  122. package/es/components/multi-select/multi-select.d.ts +13 -1
  123. package/es/components/multi-select/multi-select.js +53 -0
  124. package/es/components/multi-select/multi-select.js.map +1 -1
  125. package/es/components/multi-select/multi-select.scss.js +1 -1
  126. package/es/components/popover/popover.scss.js +1 -1
  127. package/es/components/select/select.js +1 -0
  128. package/es/components/select/select.js.map +1 -1
  129. package/es/components/slug/slug.scss.js +1 -1
  130. package/es/components/toggle-tip/toggletip.scss.js +1 -1
  131. package/es/components/tooltip/tooltip.js +1 -1
  132. package/es/components/tooltip/tooltip.js.map +1 -1
  133. package/es/components/tooltip/tooltip.scss.js +1 -1
  134. package/es-custom/components/ai-label/ai-label.scss.js +1 -1
  135. package/es-custom/components/breadcrumb/breadcrumb.scss.js +1 -1
  136. package/es-custom/components/button/button.js +1 -0
  137. package/es-custom/components/button/button.js.map +1 -1
  138. package/es-custom/components/combo-box/combo-box-item.d.ts +10 -1
  139. package/es-custom/components/combo-box/combo-box-item.js +65 -1
  140. package/es-custom/components/combo-box/combo-box-item.js.map +1 -1
  141. package/es-custom/components/combo-box/combo-box.d.ts +6 -9
  142. package/es-custom/components/combo-box/combo-box.js +108 -65
  143. package/es-custom/components/combo-box/combo-box.js.map +1 -1
  144. package/es-custom/components/combo-box/combo-box.scss.js +1 -1
  145. package/es-custom/components/data-table/data-table.scss.js +1 -1
  146. package/es-custom/components/dropdown/dropdown-skeleton.d.ts +10 -1
  147. package/es-custom/components/dropdown/dropdown-skeleton.js +31 -7
  148. package/es-custom/components/dropdown/dropdown-skeleton.js.map +1 -1
  149. package/es-custom/components/dropdown/dropdown.d.ts +41 -7
  150. package/es-custom/components/dropdown/dropdown.js +438 -65
  151. package/es-custom/components/dropdown/dropdown.js.map +1 -1
  152. package/es-custom/components/dropdown/dropdown.scss.js +1 -1
  153. package/es-custom/components/icon-button/icon-button.scss.js +1 -1
  154. package/es-custom/components/inline-loading/inline-loading.js +1 -1
  155. package/es-custom/components/inline-loading/inline-loading.js.map +1 -1
  156. package/es-custom/components/inline-loading/inline-loading.scss.js +1 -1
  157. package/es-custom/components/multi-select/multi-select.d.ts +13 -1
  158. package/es-custom/components/multi-select/multi-select.js +53 -0
  159. package/es-custom/components/multi-select/multi-select.js.map +1 -1
  160. package/es-custom/components/multi-select/multi-select.scss.js +1 -1
  161. package/es-custom/components/popover/popover.scss.js +1 -1
  162. package/es-custom/components/select/select.js +1 -0
  163. package/es-custom/components/select/select.js.map +1 -1
  164. package/es-custom/components/slug/slug.scss.js +1 -1
  165. package/es-custom/components/toggle-tip/toggletip.scss.js +1 -1
  166. package/es-custom/components/tooltip/tooltip.js +1 -1
  167. package/es-custom/components/tooltip/tooltip.js.map +1 -1
  168. package/es-custom/components/tooltip/tooltip.scss.js +1 -1
  169. package/lib/components/combo-box/combo-box-item.d.ts +10 -1
  170. package/lib/components/combo-box/combo-box.d.ts +6 -9
  171. package/lib/components/dropdown/dropdown-skeleton.d.ts +10 -1
  172. package/lib/components/dropdown/dropdown.d.ts +41 -7
  173. package/lib/components/multi-select/multi-select.d.ts +13 -1
  174. package/package.json +6 -6
  175. package/scss/components/breadcrumb/breadcrumb.scss +1 -3
  176. package/scss/components/combo-box/combo-box.scss +72 -3
  177. package/scss/components/data-table/_table-core.scss +10 -0
  178. package/scss/components/data-table/_table-expandable.scss +6 -0
  179. package/scss/components/data-table/_table-selection.scss +7 -0
  180. package/scss/components/data-table/_table-sizes.scss +4 -0
  181. package/scss/components/data-table/data-table.scss +6 -9
  182. package/scss/components/dropdown/dropdown.scss +174 -22
  183. package/scss/components/menu/menu-variables.scss +0 -2
  184. package/scss/components/menu/menu.scss +1 -1
  185. package/scss/components/multi-select/multi-select.scss +7 -0
  186. package/scss/components/overflow-menu/overflow-menu.scss +0 -2
  187. package/scss/components/popover/popover.scss +58 -11
  188. package/scss/components/tooltip/tooltip-story.scss +8 -4
  189. package/telemetry.yml +0 -1
  190. package/dist/dropdown-item-BO7AhHPd.js +0 -96
  191. package/dist/{16-DhAznVKm.js → 16-5c5jFrXp.js} +2 -2
  192. package/dist/{16-B7MRS_3W.js → 16-B9Uo1cvh.js} +2 -2
  193. package/dist/{16-BWlgPBcu.js → 16-BMXNUlRI.js} +2 -2
  194. package/dist/{16-CdxGkvXO.js → 16-C-j0eQg7.js} +2 -2
  195. package/dist/{16-CJNlj_0b.js → 16-CZiCF7iO.js} +2 -2
  196. package/dist/{16-DoN7q01_.js → 16-CmZExt83.js} +2 -2
  197. package/dist/{16-DTvjc9uv.js → 16-DbvtK9-e.js} +2 -2
  198. package/dist/{16-GKRs-ALp.js → 16-INlZq7cB.js} +2 -2
  199. package/dist/{16-B46MLj4i.js → 16-dlAJdf7K.js} +2 -2
  200. package/dist/{16-B3Yskhl0.js → 16-tP236nqZ.js} +2 -2
  201. package/dist/{16-Bf2P7KMJ.js → 16-u6yXz6wM.js} +2 -2
  202. package/dist/{16-Bxm7Omxq.js → 16-vHbYZhS2.js} +2 -2
  203. package/dist/{20-CuEbZLGA.js → 20-ClE5EQkn.js} +2 -2
  204. package/dist/{20-DlknbFYR.js → 20-seUgpuwc.js} +2 -2
  205. package/dist/{carbon-element-DDrYm3XO.js → carbon-element-sn5DFO1t.js} +2 -2
  206. package/dist/{collection-helpers-C5emLOnk.js → collection-helpers-DwvpKeJx.js} +2 -2
  207. package/dist/{consume-BeeFGGfo.js → consume-C6px77x6.js} +2 -2
  208. package/dist/{directive-Dlo2OKiC.js → directive-CwtBJVHj.js} +2 -2
  209. package/dist/{floating-controller-DLpRVhGd.js → floating-controller-qGN47tO7.js} +2 -2
  210. package/dist/{host-listener-BCnAWDV7.js → host-listener-6VuJ4xzb.js} +2 -2
  211. package/dist/{lit-element-eFlPHqE1.js → lit-element-ljyXx2IF.js} +2 -2
  212. package/dist/{on-DvnWS_DB.js → on-CsYzs_5y.js} +2 -2
  213. package/dist/{query-BdmT5Ln1.js → query-BpyCOA3I.js} +2 -2
  214. package/dist/{radio-group-manager-B_pENWmT.js → radio-group-manager-DCfD4e6U.js} +2 -2
  215. package/dist/{settings-BBN_bDP6.js → settings-BYFrjJ1N.js} +2 -2
  216. package/dist/{shared-enums-D8TrS6Ts.js → shared-enums-BhRvRKoR.js} +2 -2
  217. package/dist/{validity-BUGyJDQ6.js → validity-wk0CEz9X.js} +2 -2
@@ -56,6 +56,19 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
56
56
  * `true` if there is an AI Label.
57
57
  */
58
58
  this._hasAILabel = false;
59
+ /**
60
+ * Currently slotted AI decorator nodes (`cds-custom-ai-label`/slug) with listeners attached.
61
+ */
62
+ this._aiDecoratorNodes = [];
63
+ /**
64
+ * Handles interaction on an AI decorator while the menu is open.
65
+ */
66
+ this._handleAIDecoratorInteraction = () => {
67
+ if (!this.open) {
68
+ return;
69
+ }
70
+ this._handleUserInitiatedToggle(false);
71
+ };
59
72
  /**
60
73
  * The content of the selected item.
61
74
  */
@@ -170,16 +183,20 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
170
183
  * Absense of this argument means clearing selection, which may be handled by a derived class.
171
184
  */
172
185
  _selectionDidChange(itemToSelect) {
186
+ const constructor = this.constructor;
173
187
  if (itemToSelect) {
174
188
  this.value = itemToSelect.value;
175
189
  this._activeDescendant = itemToSelect.id;
176
- forEach(this.querySelectorAll(this.constructor.selectorItemSelected), (item) => {
190
+ forEach(this.querySelectorAll(constructor.selectorItemSelected), (item) => {
177
191
  item.selected = false;
178
192
  item.setAttribute('aria-selected', 'false');
179
193
  });
180
194
  itemToSelect.selected = true;
181
195
  itemToSelect.setAttribute('aria-selected', 'true');
182
- this._handleUserInitiatedToggle(false);
196
+ this._updateSelectedNextSibling(itemToSelect);
197
+ }
198
+ else {
199
+ this._updateSelectedNextSibling();
183
200
  }
184
201
  }
185
202
  /**
@@ -193,7 +210,21 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
193
210
  }
194
211
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- https://github.com/carbon-design-system/carbon/issues/20452
195
212
  if (this.shadowRoot.contains(event.target)) {
196
- this._handleUserInitiatedToggle();
213
+ const opening = !this.open;
214
+ const constructor = this.constructor;
215
+ const selectedItem = this.querySelector(constructor.selectorItemSelected);
216
+ if (opening) {
217
+ const shouldFocusMenu = Boolean(selectedItem);
218
+ this._handleUserInitiatedToggle(true, {
219
+ focusMenu: shouldFocusMenu,
220
+ highlightSelectedOnOpen: shouldFocusMenu,
221
+ });
222
+ }
223
+ else {
224
+ this._handleUserInitiatedToggle(false, {
225
+ restoreTriggerFocus: true,
226
+ });
227
+ }
197
228
  }
198
229
  else {
199
230
  const item = event.target.closest(this.constructor.selectorItem);
@@ -206,56 +237,229 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
206
237
  * Handler for the `keydown` event on the top-level element in the shadow DOM.
207
238
  */
208
239
  _handleKeydownInner(event) {
240
+ var _a;
241
+ if (this._handleMenuInputKeydown(event)) {
242
+ return;
243
+ }
209
244
  const { key } = event;
210
245
  const action = this.constructor.getAction(key);
211
246
  if (!this.open) {
212
247
  switch (action) {
213
- case DROPDOWN_KEYBOARD_ACTION.NAVIGATING:
214
- this._handleUserInitiatedToggle(true);
215
- // If this menu gets open with an arrow key, reset the highlight
216
- this._clearHighlight();
248
+ case DROPDOWN_KEYBOARD_ACTION.NAVIGATING: {
249
+ const shouldKeepInputFocus = this._shouldRetainMenuInputFocus(event);
250
+ const menuInputNode = this._menuInputNode;
251
+ if (this.readOnly) {
252
+ event.preventDefault();
253
+ return;
254
+ }
255
+ const direction = NAVIGATION_DIRECTION[key];
256
+ event.preventDefault();
257
+ if (direction === -1) {
258
+ break;
259
+ }
260
+ const constructor = this.constructor;
261
+ const selectedItem = this.querySelector(constructor.selectorItemSelected);
262
+ const shouldHighlightSelected = Boolean(selectedItem);
263
+ this._handleUserInitiatedToggle(true, {
264
+ focusMenu: false,
265
+ highlightSelectedOnOpen: shouldHighlightSelected,
266
+ });
267
+ this.updateComplete.then(() => {
268
+ var _a;
269
+ const constructor = this.constructor;
270
+ const items = this.querySelectorAll(constructor.selectorItem);
271
+ if (items.length > 0) {
272
+ const selectedItem = this.querySelector(constructor.selectorItemSelected);
273
+ const firstEnabledItem = Array.from(items).find((item) => !item.hasAttribute('disabled'));
274
+ const initialItem = selectedItem && !selectedItem.hasAttribute('disabled')
275
+ ? selectedItem
276
+ : (firstEnabledItem !== null && firstEnabledItem !== void 0 ? firstEnabledItem : null);
277
+ if (initialItem) {
278
+ this._setHighlightedItem(initialItem, { scrollIntoView: true });
279
+ }
280
+ else {
281
+ this._clearHighlight();
282
+ }
283
+ const menu = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.getElementById('menu-body');
284
+ if (shouldKeepInputFocus && menuInputNode) {
285
+ menuInputNode.focus({ preventScroll: true });
286
+ }
287
+ else if (menu) {
288
+ menu.focus();
289
+ }
290
+ }
291
+ });
217
292
  break;
293
+ }
218
294
  }
219
295
  }
220
296
  else {
221
297
  switch (action) {
222
298
  case DROPDOWN_KEYBOARD_ACTION.CLOSING:
223
- this._handleUserInitiatedToggle(false);
299
+ this._handleUserInitiatedToggle(false, {
300
+ restoreTriggerFocus: true,
301
+ });
224
302
  break;
225
- case DROPDOWN_KEYBOARD_ACTION.NAVIGATING:
303
+ case DROPDOWN_KEYBOARD_ACTION.NAVIGATING: {
226
304
  event.preventDefault();
305
+ const menu = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.getElementById('menu-body');
306
+ const menuInputNode = this._menuInputNode;
307
+ const shouldKeepInputFocus = this._shouldRetainMenuInputFocus(event);
308
+ if (shouldKeepInputFocus && menuInputNode) {
309
+ menuInputNode.focus({ preventScroll: true });
310
+ }
311
+ else if (menu) {
312
+ menu.focus();
313
+ }
227
314
  this._navigate(NAVIGATION_DIRECTION[key]);
228
315
  break;
316
+ }
317
+ }
318
+ }
319
+ }
320
+ _handleMenuInputKeydown(event) {
321
+ if (event.defaultPrevented ||
322
+ !this._supportsMenuInputFiltering ||
323
+ !this._menuInputNode) {
324
+ return false;
325
+ }
326
+ const input = this._menuInputNode;
327
+ if (!input) {
328
+ return false;
329
+ }
330
+ const isInputTarget = event.target === input;
331
+ const hasFilterValue = Boolean(input.value || this.value);
332
+ if (event.key === 'Escape' &&
333
+ hasFilterValue &&
334
+ this._shouldClearMenuInputOnEscape({
335
+ event,
336
+ menuOpen: this.open,
337
+ isInputTarget,
338
+ })) {
339
+ event.preventDefault();
340
+ this._clearMenuInputFiltering();
341
+ return true;
342
+ }
343
+ if (!this.open || isInputTarget) {
344
+ return false;
345
+ }
346
+ if (this._shouldForwardKeyToMenuInput(event)) {
347
+ event.preventDefault();
348
+ this._forwardKeyToMenuInput(event, input);
349
+ return true;
350
+ }
351
+ return false;
352
+ }
353
+ _shouldClearMenuInputOnEscape({ menuOpen, }) {
354
+ return menuOpen;
355
+ }
356
+ get _supportsMenuInputFiltering() {
357
+ return false;
358
+ }
359
+ get _menuInputNode() {
360
+ return null;
361
+ }
362
+ _clearMenuInputFiltering() { }
363
+ _shouldForwardKeyToMenuInput(event) {
364
+ if (event.altKey || event.metaKey || event.ctrlKey) {
365
+ return false;
366
+ }
367
+ const { key } = event;
368
+ if (key === 'Backspace' || key === 'Delete') {
369
+ return true;
370
+ }
371
+ return key.length === 1;
372
+ }
373
+ _forwardKeyToMenuInput(event, input) {
374
+ var _a, _b;
375
+ input.focus({ preventScroll: true });
376
+ const key = event.key;
377
+ const selectionStart = (_a = input.selectionStart) !== null && _a !== void 0 ? _a : input.value.length;
378
+ const selectionEnd = (_b = input.selectionEnd) !== null && _b !== void 0 ? _b : input.value.length;
379
+ if (key === 'Backspace') {
380
+ if (selectionStart === 0 && selectionEnd === 0) {
381
+ return;
229
382
  }
383
+ const start = selectionStart === selectionEnd
384
+ ? Math.max(0, selectionStart - 1)
385
+ : selectionStart;
386
+ input.setRangeText('', start, selectionEnd, 'end');
387
+ }
388
+ else if (key === 'Delete') {
389
+ if (selectionStart === input.value.length &&
390
+ selectionStart === selectionEnd) {
391
+ return;
392
+ }
393
+ const end = selectionStart === selectionEnd
394
+ ? Math.min(input.value.length, selectionEnd + 1)
395
+ : selectionEnd;
396
+ input.setRangeText('', selectionStart, end, 'end');
397
+ }
398
+ else if (key.length === 1) {
399
+ input.setRangeText(key, selectionStart, selectionEnd, 'end');
230
400
  }
401
+ input.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
402
+ }
403
+ _shouldRetainMenuInputFocus(event) {
404
+ if (!this._supportsMenuInputFiltering || !this._menuInputNode) {
405
+ return false;
406
+ }
407
+ if (event.target === this._menuInputNode) {
408
+ return true;
409
+ }
410
+ const path = typeof event.composedPath === 'function' ? event.composedPath() : [];
411
+ return path.includes(this._menuInputNode);
231
412
  }
232
413
  /**
233
- * Handler for the `keypress` event on the top-level element in the shadow DOM.
414
+ * Handles keypress events (Space, Enter)
234
415
  */
235
416
  _handleKeypressInner(event) {
236
417
  const { key } = event;
237
418
  const action = this.constructor.getAction(key);
419
+ // When closed
238
420
  if (!this.open) {
421
+ if (this.readOnly && action === DROPDOWN_KEYBOARD_ACTION.TRIGGERING) {
422
+ if (key === ' ' || key === 'Space') {
423
+ event.preventDefault();
424
+ }
425
+ return;
426
+ }
239
427
  switch (action) {
240
- case DROPDOWN_KEYBOARD_ACTION.TRIGGERING:
241
- this._handleUserInitiatedToggle(true);
428
+ case DROPDOWN_KEYBOARD_ACTION.TRIGGERING: {
429
+ if (key === ' ' || key === 'Space') {
430
+ event.preventDefault();
431
+ }
432
+ const constructor = this.constructor;
433
+ const selectedItem = this.querySelector(constructor.selectorItemSelected);
434
+ const shouldFocusMenu = Boolean(selectedItem);
435
+ this._handleUserInitiatedToggle(true, {
436
+ focusMenu: shouldFocusMenu,
437
+ highlightSelectedOnOpen: shouldFocusMenu,
438
+ });
242
439
  break;
440
+ }
243
441
  }
244
442
  }
245
443
  else {
444
+ // When open
246
445
  switch (action) {
247
- case DROPDOWN_KEYBOARD_ACTION.TRIGGERING:
248
- {
249
- const constructor = this.constructor;
250
- const highlightedItem = this.querySelector(constructor.selectorItemHighlighted);
251
- if (highlightedItem) {
252
- this._handleUserInitiatedSelectItem(highlightedItem);
253
- }
254
- else {
255
- this._handleUserInitiatedToggle(false);
256
- }
446
+ case DROPDOWN_KEYBOARD_ACTION.TRIGGERING: {
447
+ const constructor = this.constructor;
448
+ const selectedItem = this.querySelector(constructor.selectorItemSelected);
449
+ const highlightedItem = this.querySelector(constructor.selectorItemHighlighted);
450
+ if (highlightedItem) {
451
+ this._handleUserInitiatedSelectItem(highlightedItem);
452
+ }
453
+ else if (selectedItem) {
454
+ this._handleUserInitiatedSelectItem(selectedItem);
455
+ }
456
+ else {
457
+ this._handleUserInitiatedToggle(false, {
458
+ restoreTriggerFocus: true,
459
+ });
257
460
  }
258
461
  break;
462
+ }
259
463
  }
260
464
  }
261
465
  }
@@ -264,6 +468,41 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
264
468
  *
265
469
  * @param event The event.
266
470
  */
471
+ _handleMouseoverInner(event) {
472
+ if (!this.open) {
473
+ return;
474
+ }
475
+ const item = this._getDropdownItemFromEvent(event);
476
+ if (!item) {
477
+ return;
478
+ }
479
+ if (item.hasAttribute('disabled')) {
480
+ this._clearHighlight();
481
+ return;
482
+ }
483
+ this._setHighlightedItem(item);
484
+ }
485
+ _handleMouseleaveInner(event) {
486
+ var _a, _b, _c;
487
+ if (!this.open) {
488
+ return;
489
+ }
490
+ const menu = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.getElementById('menu-body');
491
+ const relatedTarget = event.relatedTarget;
492
+ if (menu && relatedTarget && menu.contains(relatedTarget)) {
493
+ return;
494
+ }
495
+ const shadowActiveElement = (_b = this.shadowRoot) === null || _b === void 0 ? void 0 : _b.activeElement;
496
+ if (menu && shadowActiveElement && menu.contains(shadowActiveElement)) {
497
+ return;
498
+ }
499
+ if (this._supportsMenuInputFiltering &&
500
+ this._menuInputNode &&
501
+ ((_c = this.shadowRoot) === null || _c === void 0 ? void 0 : _c.activeElement) === this._menuInputNode) {
502
+ return;
503
+ }
504
+ this._clearHighlight();
505
+ }
267
506
  _handleFocusOut(event) {
268
507
  if (!this.contains(event.relatedTarget)) {
269
508
  this._handleUserInitiatedToggle(false);
@@ -285,17 +524,36 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
285
524
  * Handles `slotchange` event.
286
525
  */
287
526
  _handleAILabelSlotChange({ target }) {
288
- const hasContent = target
527
+ var _a;
528
+ const decoratorNodes = target
289
529
  .assignedNodes()
290
530
  .filter((elem) => elem.matches !== undefined
291
531
  ? elem.matches(this.constructor.aiLabelItem) ||
292
532
  // remove reference to slug in v12
293
533
  elem.matches(this.constructor.slugItem)
294
534
  : false);
295
- this._hasAILabel = Boolean(hasContent);
296
- hasContent[0].setAttribute('size', 'mini');
535
+ const decoratorElements = decoratorNodes.filter((node) => node instanceof HTMLElement);
536
+ this._updateAIDecoratorListeners(decoratorElements);
537
+ this._hasAILabel = Boolean(decoratorElements.length);
538
+ (_a = decoratorElements[0]) === null || _a === void 0 ? void 0 : _a.setAttribute('size', 'mini');
297
539
  this.requestUpdate();
298
540
  }
541
+ disconnectedCallback() {
542
+ super.disconnectedCallback();
543
+ this._updateAIDecoratorListeners([]);
544
+ }
545
+ /**
546
+ * Updates listeners for AI decorator nodes to ensure only one menu stays open.
547
+ */
548
+ _updateAIDecoratorListeners(nodes) {
549
+ this._aiDecoratorNodes.forEach((node) => {
550
+ node.removeEventListener('click', this._handleAIDecoratorInteraction);
551
+ });
552
+ this._aiDecoratorNodes = nodes;
553
+ this._aiDecoratorNodes.forEach((node) => {
554
+ node.addEventListener('click', this._handleAIDecoratorInteraction);
555
+ });
556
+ }
299
557
  /**
300
558
  * Handles user-initiated selection of a dropdown item.
301
559
  *
@@ -305,6 +563,7 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
305
563
  if (item === null || item === void 0 ? void 0 : item.hasAttribute('disabled')) {
306
564
  return;
307
565
  }
566
+ const shouldClose = this._shouldCloseAfterSelection(item);
308
567
  if (this._selectionShouldChange(item)) {
309
568
  const init = {
310
569
  bubbles: true,
@@ -319,15 +578,31 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
319
578
  this._selectionDidChange(item);
320
579
  const afterSelectEvent = new CustomEvent(constructor.eventSelect, init);
321
580
  this.dispatchEvent(afterSelectEvent);
581
+ if (shouldClose) {
582
+ this._handleUserInitiatedToggle(false, {
583
+ restoreTriggerFocus: true,
584
+ });
585
+ }
322
586
  }
323
587
  }
588
+ else if (item && shouldClose) {
589
+ this._handleUserInitiatedToggle(false, {
590
+ restoreTriggerFocus: true,
591
+ });
592
+ }
593
+ }
594
+ // Default dropdowns close after user selection.
595
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- https://github.com/carbon-design-system/carbon/issues/20452
596
+ _shouldCloseAfterSelection(_item) {
597
+ return true;
324
598
  }
325
599
  /**
326
600
  * Handles user-initiated toggling the open state.
327
601
  *
328
602
  * @param [force] If specified, forces the open state to the given one.
329
603
  */
330
- _handleUserInitiatedToggle(force = !this.open) {
604
+ _handleUserInitiatedToggle(force = !this.open, { restoreTriggerFocus = false, focusMenu = true, highlightSelectedOnOpen = false, } = {}) {
605
+ var _a;
331
606
  const { eventBeforeToggle, eventToggle } = this
332
607
  .constructor;
333
608
  const { disabled } = this;
@@ -342,11 +617,37 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
342
617
  if (!disabled) {
343
618
  if (this.dispatchEvent(new CustomEvent(eventBeforeToggle, init))) {
344
619
  this.open = force;
345
- if (!this.open) {
346
- forEach(this.querySelectorAll(this.constructor.selectorItemHighlighted), (item) => {
347
- item.highlighted = false;
620
+ if (this.open) {
621
+ const activeElement = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.activeElement;
622
+ const preserveFocusTarget = activeElement instanceof HTMLInputElement ? activeElement : null;
623
+ this.updateComplete.then(() => {
624
+ var _a, _b;
625
+ if (preserveFocusTarget) {
626
+ preserveFocusTarget.focus();
627
+ }
628
+ else if (focusMenu) {
629
+ const menu = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.getElementById('menu-body');
630
+ menu === null || menu === void 0 ? void 0 : menu.focus();
631
+ }
632
+ else if (this._shouldTriggerBeFocusable) {
633
+ const trigger = (_b = this.shadowRoot) === null || _b === void 0 ? void 0 : _b.getElementById('trigger-button');
634
+ trigger === null || trigger === void 0 ? void 0 : trigger.focus();
635
+ }
636
+ if (highlightSelectedOnOpen) {
637
+ this._highlightSelectedItem();
638
+ }
639
+ });
640
+ }
641
+ else if (restoreTriggerFocus && this._shouldTriggerBeFocusable) {
642
+ this.updateComplete.then(() => {
643
+ var _a;
644
+ const trigger = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.getElementById('trigger-button');
645
+ trigger === null || trigger === void 0 ? void 0 : trigger.focus();
348
646
  });
349
647
  }
648
+ if (!this.open) {
649
+ this._clearHighlight();
650
+ }
350
651
  this.requestUpdate();
351
652
  this.dispatchEvent(new CustomEvent(eventToggle, init));
352
653
  }
@@ -356,44 +657,106 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
356
657
  * Clears the selection of dropdown items.
357
658
  */
358
659
  _clearHighlight() {
359
- forEach(this.querySelectorAll(this.constructor.selectorItem), (item) => {
360
- item.highlighted = false;
660
+ this._setHighlightedItem();
661
+ }
662
+ _getDropdownItemFromEvent(event) {
663
+ const constructor = this.constructor;
664
+ const selector = constructor.selectorItem;
665
+ const path = event.composedPath();
666
+ for (const node of path) {
667
+ if (node instanceof Element &&
668
+ typeof node.matches === 'function' &&
669
+ node.matches(selector)) {
670
+ return node;
671
+ }
672
+ }
673
+ return null;
674
+ }
675
+ _setHighlightedItem(item, { scrollIntoView = false } = {}) {
676
+ const constructor = this.constructor;
677
+ const items = this.querySelectorAll(constructor.selectorItem);
678
+ const target = item && !item.hasAttribute('disabled') ? item : null;
679
+ forEach(items, (listItem) => {
680
+ const dropdownItem = listItem;
681
+ dropdownItem.highlighted = dropdownItem === target;
682
+ dropdownItem.removeAttribute('highlighted-next-sibling');
361
683
  });
684
+ if (target) {
685
+ const nextSibling = this._getNextDropdownItem(target);
686
+ if (nextSibling) {
687
+ nextSibling.setAttribute('highlighted-next-sibling', '');
688
+ }
689
+ const itemId = target.id;
690
+ if (itemId) {
691
+ this._activeDescendant = itemId;
692
+ }
693
+ if (scrollIntoView) {
694
+ target.scrollIntoView({ block: 'nearest' });
695
+ }
696
+ }
697
+ else {
698
+ this._activeDescendant = undefined;
699
+ }
700
+ }
701
+ _getNextDropdownItem(item) {
702
+ const constructor = this.constructor;
703
+ const selector = constructor.selectorItem;
704
+ let next = item.nextElementSibling;
705
+ while (next) {
706
+ if (typeof next.matches === 'function' && next.matches(selector)) {
707
+ return next;
708
+ }
709
+ next = next.nextElementSibling;
710
+ }
711
+ return null;
712
+ }
713
+ _updateSelectedNextSibling(item) {
714
+ const constructor = this.constructor;
715
+ forEach(this.querySelectorAll(constructor.selectorItem), (listItem) => {
716
+ listItem.removeAttribute('selected-next-sibling');
717
+ });
718
+ if (item) {
719
+ const nextSibling = this._getNextDropdownItem(item);
720
+ if (nextSibling) {
721
+ nextSibling.setAttribute('selected-next-sibling', '');
722
+ }
723
+ }
724
+ }
725
+ _highlightSelectedItem() {
726
+ const constructor = this.constructor;
727
+ const selectedItem = this.querySelector(constructor.selectorItemSelected);
728
+ if (selectedItem && !selectedItem.hasAttribute('disabled')) {
729
+ this._setHighlightedItem(selectedItem, { scrollIntoView: true });
730
+ }
731
+ else {
732
+ this._clearHighlight();
733
+ }
362
734
  }
363
- /**
364
- * Navigate through dropdown items.
365
- *
366
- * @param direction `-1` to navigate backward, `1` to navigate forward.
367
- */
368
735
  _navigate(direction) {
369
736
  var _a;
370
737
  const constructor = this.constructor;
371
738
  const items = this.querySelectorAll(constructor.selectorItem);
739
+ if (!items.length) {
740
+ return;
741
+ }
372
742
  const highlightedItem = this.querySelector(constructor.selectorItemHighlighted);
373
743
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- https://github.com/carbon-design-system/carbon/issues/20452
374
744
  const highlightedIndex = indexOf(items, highlightedItem);
375
- let nextIndex = highlightedIndex + direction;
376
- if ((_a = items[nextIndex]) === null || _a === void 0 ? void 0 : _a.hasAttribute('disabled')) {
745
+ let nextIndex = highlightedIndex === -1
746
+ ? direction > 0
747
+ ? 0
748
+ : items.length - 1
749
+ : highlightedIndex + direction;
750
+ while (nextIndex >= 0 &&
751
+ nextIndex < items.length &&
752
+ ((_a = items[nextIndex]) === null || _a === void 0 ? void 0 : _a.hasAttribute('disabled'))) {
377
753
  nextIndex += direction;
378
754
  }
379
- if (nextIndex < 0) {
380
- nextIndex = items.length - 1;
381
- }
382
- if (nextIndex >= items.length) {
383
- nextIndex = 0;
755
+ if (nextIndex < 0 || nextIndex >= items.length) {
756
+ return;
384
757
  }
385
- forEach(items, (item, i) => {
386
- item.highlighted = i === nextIndex;
387
- });
388
758
  const nextItem = items[nextIndex];
389
- // Using `{ block: 'nearest' }` to prevent scrolling unless scrolling is absolutely necessary.
390
- // `scrollIntoViewOptions` seems to work in latest Safari despite of MDN/caniuse table.
391
- // IE falls back to the old behavior.
392
- nextItem.scrollIntoView({ block: 'nearest' });
393
- const nextItemId = nextItem.id;
394
- if (nextItemId) {
395
- this._activeDescendant = nextItemId;
396
- }
759
+ this._setHighlightedItem(nextItem, { scrollIntoView: true });
397
760
  }
398
761
  /**
399
762
  * @returns The content preceding the trigger button.
@@ -470,15 +833,20 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
470
833
  elem.size = this.size;
471
834
  });
472
835
  }
473
- if (changedProperties.has('disabled') && this.disabled) {
836
+ if (changedProperties.has('disabled')) {
474
837
  const { disabled } = this;
475
838
  // Propagate `disabled` attribute to descendants until `:host-context()` gets supported in all major browsers
476
839
  forEach(this.querySelectorAll(selectorItem), (elem) => {
840
+ const item = elem;
477
841
  if (disabled) {
478
- elem.disabled = disabled;
842
+ if (!item.disabled) {
843
+ item.setAttribute('parent-disabled', '');
844
+ }
845
+ item.disabled = true;
479
846
  }
480
- else {
481
- elem.removeAttribute('disabled');
847
+ else if (item.hasAttribute('parent-disabled')) {
848
+ item.removeAttribute('parent-disabled');
849
+ item.disabled = false;
482
850
  }
483
851
  });
484
852
  }
@@ -489,16 +857,17 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
489
857
  elem.selected =
490
858
  elem.value === this.value;
491
859
  });
492
- const item = find(this.querySelectorAll(selectorItem), (elem) => elem.value === this.value);
493
- if (item) {
860
+ const selectedItem = find(this.querySelectorAll(selectorItem), (elem) => elem.value === this.value);
861
+ if (selectedItem) {
494
862
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- https://github.com/carbon-design-system/carbon/issues/20452
495
863
  const range = this.ownerDocument.createRange();
496
- range.selectNodeContents(item);
864
+ range.selectNodeContents(selectedItem);
497
865
  this._selectedItemContent = range.cloneContents();
498
866
  }
499
867
  else {
500
868
  this._selectedItemContent = null;
501
869
  }
870
+ this._updateSelectedNextSibling(selectedItem);
502
871
  }
503
872
  return true;
504
873
  }
@@ -553,7 +922,7 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
553
922
  }
554
923
  render() {
555
924
  var _a;
556
- const { ariaLabel, _classes: classes, helperText, invalidText, open, toggleLabelClosed, toggleLabelOpen, type, warn, warnText, _activeDescendant: activeDescendant, _shouldTriggerBeFocusable: shouldTriggerBeFocusable, _handleClickInner: handleClickInner, _handleKeydownInner: handleKeydownInner, _handleKeypressInner: handleKeypressInner, _handleSlotchangeHelperText: handleSlotchangeHelperText, _handleAILabelSlotChange: handleAILabelSlotChange, _slotHelperTextNode: slotHelperTextNode, } = this;
925
+ const { ariaLabel, _classes: classes, helperText, invalidText, open, toggleLabelClosed, toggleLabelOpen, type, warn, warnText, _activeDescendant: activeDescendant, _shouldTriggerBeFocusable: shouldTriggerBeFocusable, _handleClickInner: handleClickInner, _handleKeydownInner: handleKeydownInner, _handleKeypressInner: handleKeypressInner, _handleMouseleaveInner: handleMouseleaveInner, _handleMouseoverInner: handleMouseoverInner, _handleSlotchangeHelperText: handleSlotchangeHelperText, _handleAILabelSlotChange: handleAILabelSlotChange, _slotHelperTextNode: slotHelperTextNode, } = this;
557
926
  const inline = type === DROPDOWN_TYPE.INLINE;
558
927
  const normalizedProps = this._normalizedProps;
559
928
  let activeDescendantFallback;
@@ -601,7 +970,9 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
601
970
  class="${prefix}--list-box__menu"
602
971
  role="listbox"
603
972
  tabindex="-1"
604
- ?hidden=${!open}>
973
+ ?hidden=${!open}
974
+ @mouseover=${handleMouseoverInner}
975
+ @mouseleave=${handleMouseleaveInner}>
605
976
  <slot></slot>
606
977
  </div>
607
978
  `;
@@ -613,12 +984,14 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
613
984
  @click=${handleClickInner}
614
985
  @keydown=${handleKeydownInner}
615
986
  @keypress=${handleKeypressInner}>
987
+ ${validityIcon}${warningIcon}
616
988
  <div
617
989
  id="${ifDefined(!shouldTriggerBeFocusable ? undefined : 'trigger-button')}"
618
990
  class="${prefix}--list-box__field"
619
991
  part="trigger-button"
620
992
  tabindex="${ifDefined(!shouldTriggerBeFocusable ? undefined : '0')}"
621
993
  role="${ifDefined(!shouldTriggerBeFocusable ? undefined : 'combobox')}"
994
+ aria-label="${ifDefined(ariaLabel ? ariaLabel : undefined)}"
622
995
  aria-labelledby="${ifDefined(!shouldTriggerBeFocusable ? undefined : 'dropdown-label')}"
623
996
  aria-expanded="${ifDefined(!shouldTriggerBeFocusable ? undefined : String(open))}"
624
997
  aria-haspopup="${ifDefined(!shouldTriggerBeFocusable ? undefined : 'listbox')}"
@@ -628,7 +1001,7 @@ let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(Form
628
1001
  : open
629
1002
  ? (activeDescendant !== null && activeDescendant !== void 0 ? activeDescendant : activeDescendantFallback)
630
1003
  : '')}">
631
- ${this._renderPrecedingLabel()}${this._renderLabel()}${validityIcon}${warningIcon}${this._renderFollowingLabel()}
1004
+ ${this._renderPrecedingLabel()}${this._renderLabel()}${this._renderFollowingLabel()}
632
1005
  <div id="trigger-caret" class="${iconContainerClasses}">
633
1006
  ${iconLoader(ChevronDown16, { 'aria-label': toggleLabel })}
634
1007
  </div>
@@ -746,7 +1119,7 @@ __decorate([
746
1119
  // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to
747
1120
  ], CDSDropdown.prototype, "_handleFocusOut", null);
748
1121
  __decorate([
749
- property({ type: String, reflect: true, attribute: 'aria-label' })
1122
+ property({ type: String, attribute: 'aria-label' })
750
1123
  ], CDSDropdown.prototype, "ariaLabel", void 0);
751
1124
  __decorate([
752
1125
  property({ type: String, reflect: true })