@aurodesignsystem-dev/auro-formkit 0.0.0-pr1376.0 → 0.0.0-pr1377.1

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 (40) hide show
  1. package/components/checkbox/demo/api.min.js +1 -1
  2. package/components/checkbox/demo/index.min.js +1 -1
  3. package/components/checkbox/dist/index.js +1 -1
  4. package/components/checkbox/dist/registered.js +1 -1
  5. package/components/combobox/demo/api.min.js +108 -37
  6. package/components/combobox/demo/index.min.js +108 -37
  7. package/components/combobox/dist/auro-combobox.d.ts +1 -0
  8. package/components/combobox/dist/comboboxKeyboardStrategy.d.ts +2 -2
  9. package/components/combobox/dist/index.js +108 -37
  10. package/components/combobox/dist/registered.js +108 -37
  11. package/components/counter/demo/api.min.js +26 -13
  12. package/components/counter/demo/index.min.js +26 -13
  13. package/components/counter/dist/index.js +26 -13
  14. package/components/counter/dist/registered.js +26 -13
  15. package/components/datepicker/demo/api.min.js +27 -14
  16. package/components/datepicker/demo/index.min.js +27 -14
  17. package/components/datepicker/dist/index.js +27 -14
  18. package/components/datepicker/dist/registered.js +27 -14
  19. package/components/dropdown/demo/api.min.js +25 -12
  20. package/components/dropdown/demo/index.min.js +25 -12
  21. package/components/dropdown/dist/index.js +25 -12
  22. package/components/dropdown/dist/keyboardUtils.d.ts +20 -1
  23. package/components/dropdown/dist/registered.js +25 -12
  24. package/components/form/demo/api.min.js +238 -90
  25. package/components/form/demo/index.min.js +238 -90
  26. package/components/input/demo/api.min.js +1 -1
  27. package/components/input/demo/index.min.js +1 -1
  28. package/components/input/dist/index.js +1 -1
  29. package/components/input/dist/registered.js +1 -1
  30. package/components/radio/demo/api.min.js +1 -1
  31. package/components/radio/demo/index.min.js +1 -1
  32. package/components/radio/dist/index.js +1 -1
  33. package/components/radio/dist/registered.js +1 -1
  34. package/components/select/demo/api.min.js +74 -23
  35. package/components/select/demo/index.min.js +74 -23
  36. package/components/select/dist/index.js +74 -23
  37. package/components/select/dist/registered.js +74 -23
  38. package/components/select/dist/selectKeyboardStrategy.d.ts +3 -3
  39. package/custom-elements.json +1434 -1385
  40. package/package.json +2 -2
@@ -1687,7 +1687,7 @@ class AuroHelpText extends i$2 {
1687
1687
  }
1688
1688
  }
1689
1689
 
1690
- var formkitVersion = '202603171954';
1690
+ var formkitVersion = '202603181732';
1691
1691
 
1692
1692
  // Copyright (c) 2026 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
1693
1693
  // See LICENSE in the project root for license information.
@@ -1679,7 +1679,7 @@ class AuroHelpText extends i$2 {
1679
1679
  }
1680
1680
  }
1681
1681
 
1682
- var formkitVersion = '202603171954';
1682
+ var formkitVersion = '202603181732';
1683
1683
 
1684
1684
  // Copyright (c) 2026 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
1685
1685
  // See LICENSE in the project root for license information.
@@ -1632,7 +1632,7 @@ class AuroHelpText extends LitElement {
1632
1632
  }
1633
1633
  }
1634
1634
 
1635
- var formkitVersion = '202603171954';
1635
+ var formkitVersion = '202603181732';
1636
1636
 
1637
1637
  // Copyright (c) 2026 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
1638
1638
  // See LICENSE in the project root for license information.
@@ -1632,7 +1632,7 @@ class AuroHelpText extends LitElement {
1632
1632
  }
1633
1633
  }
1634
1634
 
1635
- var formkitVersion = '202603171954';
1635
+ var formkitVersion = '202603181732';
1636
1636
 
1637
1637
  // Copyright (c) 2026 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
1638
1638
  // See LICENSE in the project root for license information.
@@ -1233,17 +1233,46 @@ function restoreTriggerAfterClose(dropdown, focusTarget) {
1233
1233
  * SPDX-License-Identifier: BSD-3-Clause
1234
1234
  */let e$2 = class e extends i$2{constructor(i){if(super(i),this.it=A$2,i.type!==t$1.CHILD)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(r){if(r===A$2||null==r)return this._t=void 0,this.it=r;if(r===E)return r;if("string"!=typeof r)throw Error(this.constructor.directiveName+"() called with a non-string value");if(r===this.it)return this._t;this.it=r;const s=[r];return s.raw=s,this._t={_$litType$:this.constructor.resultType,strings:s,values:[]}}};e$2.directiveName="unsafeHTML",e$2.resultType=1;
1235
1235
 
1236
+ /**
1237
+ * Computes display state once per keydown event and returns a frozen context object.
1238
+ * Centralizes null-safety checks and makes the shared/modal/popover branching explicit.
1239
+ * @param {HTMLElement} component - The component with a dropdown reference.
1240
+ * @param {Object} [options] - Optional config.
1241
+ * @param {Function} [options.inputResolver] - Called with (component, ctx) to resolve the active input element.
1242
+ * @returns {Readonly<{isVisible: boolean, isModal: boolean, isPopover: boolean, activeInput: HTMLElement|null}>}
1243
+ */
1244
+ function createDisplayContext(component, options = {}) {
1245
+ const dd = component.dropdown;
1246
+ const isVisible = Boolean(dd && dd.isPopoverVisible);
1247
+ const isFullscreen = Boolean(dd && dd.isBibFullscreen);
1248
+
1249
+ const ctx = {
1250
+ isVisible,
1251
+ isModal: isVisible && isFullscreen,
1252
+ isPopover: isVisible && !isFullscreen,
1253
+ activeInput: null,
1254
+ };
1255
+
1256
+ if (options.inputResolver) {
1257
+ ctx.activeInput = options.inputResolver(component, ctx);
1258
+ }
1259
+
1260
+ return Object.freeze(ctx);
1261
+ }
1262
+
1236
1263
  /**
1237
1264
  * Wires up a keydown listener that dispatches to strategy[evt.key] or strategy.default.
1238
1265
  * Handles both sync and async handlers.
1239
1266
  * @param {HTMLElement} component - The component to attach the listener to.
1240
1267
  * @param {Object} strategy - Map of key names to handler functions.
1268
+ * @param {Object} [options] - Optional config passed to createDisplayContext.
1241
1269
  */
1242
- function applyKeyboardStrategy(component, strategy) {
1270
+ function applyKeyboardStrategy(component, strategy, options = {}) {
1243
1271
  component.addEventListener('keydown', async (evt) => {
1244
1272
  const handler = strategy[evt.key] || strategy.default;
1245
1273
  if (handler) {
1246
- await handler(component, evt);
1274
+ const ctx = createDisplayContext(component, options);
1275
+ await handler(component, evt, ctx);
1247
1276
  }
1248
1277
  });
1249
1278
  }
@@ -1255,9 +1284,11 @@ function applyKeyboardStrategy(component, strategy) {
1255
1284
  * @param {string} direction - 'up' or 'down'.
1256
1285
  * @param {Object} [options] - Optional config.
1257
1286
  * @param {Function} [options.showFn] - Called to open the dropdown when closed.
1287
+ * @param {Object} [options.ctx] - Display context to avoid re-checking visibility.
1258
1288
  */
1259
1289
  function navigateArrow(component, direction, options = {}) {
1260
- if (component.dropdown.isPopoverVisible) {
1290
+ const visible = options.ctx ? options.ctx.isVisible : component.dropdown.isPopoverVisible;
1291
+ if (visible) {
1261
1292
  component.menu.navigateOptions(direction);
1262
1293
  } else if (options.showFn) {
1263
1294
  options.showFn();
@@ -1265,29 +1296,21 @@ function navigateArrow(component, direction, options = {}) {
1265
1296
  }
1266
1297
 
1267
1298
  const comboboxKeyboardStrategy = {
1268
- async Enter(component, evt) {
1299
+ async Enter(component, evt, ctx) {
1269
1300
  // If the clear button has focus, let the browser activate it normally.
1270
1301
  // stopPropagation prevents parent containers (e.g., forms) from treating
1271
1302
  // Enter as a submit, but we must NOT call preventDefault — that would
1272
1303
  // block the browser's built-in "Enter activates focused button" behavior.
1273
- const isBibFullscreenActive =
1274
- component.dropdown &&
1275
- component.dropdown.isBibFullscreen &&
1276
- component.dropdown.isPopoverVisible;
1277
- const activeInput =
1278
- isBibFullscreenActive && component.inputInBib
1279
- ? component.inputInBib
1280
- : component.input;
1281
1304
  const clearBtn =
1282
- activeInput && activeInput.shadowRoot
1283
- ? activeInput.shadowRoot.querySelector('.clearBtn')
1305
+ ctx.activeInput && ctx.activeInput.shadowRoot
1306
+ ? ctx.activeInput.shadowRoot.querySelector('.clearBtn')
1284
1307
  : null;
1285
1308
  if (clearBtn && clearBtn.shadowRoot && clearBtn.shadowRoot.activeElement !== null) {
1286
1309
  evt.stopPropagation();
1287
1310
  return;
1288
1311
  }
1289
1312
 
1290
- if (component.dropdown.isPopoverVisible && component.optionActive) {
1313
+ if (ctx.isVisible && component.optionActive) {
1291
1314
  component.menu.makeSelection();
1292
1315
  await component.updateComplete;
1293
1316
  evt.preventDefault();
@@ -1304,20 +1327,34 @@ const comboboxKeyboardStrategy = {
1304
1327
  }
1305
1328
  },
1306
1329
 
1307
- Tab(component) {
1308
- if (!component.dropdown.isPopoverVisible) {
1330
+ Tab(component, evt, ctx) {
1331
+ if (!ctx.isVisible) {
1309
1332
  return;
1310
1333
  }
1311
1334
 
1312
- if (component.dropdown.isBibFullscreen) {
1313
- const clearBtn = component.inputInBib.shadowRoot.querySelector('.clearBtn');
1335
+ if (ctx.isModal) {
1336
+ if (!ctx.activeInput) {
1337
+ return;
1338
+ }
1339
+ const clearBtn = ctx.activeInput.shadowRoot.querySelector('.clearBtn');
1314
1340
 
1315
1341
  // Use shadowRoot.activeElement to detect focus inside auro-button,
1316
1342
  // since Safari does not propagate :focus-within through shadow DOM.
1317
1343
  const clearBtnHasFocus = clearBtn && clearBtn.shadowRoot && clearBtn.shadowRoot.activeElement !== null;
1318
1344
 
1345
+ if (evt.shiftKey) {
1346
+ // Shift+Tab from clear button: move focus back to the input
1347
+ if (clearBtnHasFocus) {
1348
+ ctx.activeInput.focus();
1349
+ return;
1350
+ }
1351
+ // Shift+Tab from input (or no clear button): close without selecting
1352
+ component.hideBib();
1353
+ return;
1354
+ }
1355
+
1319
1356
  // Tab from input: if clear button exists and doesn't have focus, focus it
1320
- if (clearBtn && !clearBtnHasFocus && component.inputInBib.value) {
1357
+ if (clearBtn && !clearBtnHasFocus && ctx.activeInput.value) {
1321
1358
  // Force clear button container visible to work around Safari not
1322
1359
  // propagating :focus-within through shadow DOM boundaries, which
1323
1360
  // causes .wrapper:not(:focus-within) to hide .notification.clear.
@@ -1353,8 +1390,8 @@ const comboboxKeyboardStrategy = {
1353
1390
  return;
1354
1391
  }
1355
1392
 
1356
- // Non-fullscreen: select + close
1357
- if (component.menu.optionActive && component.menu.optionActive.value) {
1393
+ // Non-fullscreen: select + close (Shift+Tab closes without selecting)
1394
+ if (!evt.shiftKey && component.menu.optionActive && component.menu.optionActive.value) {
1358
1395
  component.menu.value = component.menu.optionActive.value;
1359
1396
  }
1360
1397
  component.hideBib();
@@ -1364,6 +1401,7 @@ const comboboxKeyboardStrategy = {
1364
1401
  if (component.availableOptions.length > 0) {
1365
1402
  component.showBib();
1366
1403
  }
1404
+ // Check live visibility: showBib() above may have just opened the dropdown.
1367
1405
  if (component.dropdown.isPopoverVisible) {
1368
1406
  evt.preventDefault();
1369
1407
  navigateArrow(component, 'up');
@@ -1374,6 +1412,7 @@ const comboboxKeyboardStrategy = {
1374
1412
  if (component.availableOptions.length > 0) {
1375
1413
  component.showBib();
1376
1414
  }
1415
+ // Check live visibility: showBib() above may have just opened the dropdown.
1377
1416
  if (component.dropdown.isPopoverVisible) {
1378
1417
  evt.preventDefault();
1379
1418
  navigateArrow(component, 'down');
@@ -3611,19 +3650,32 @@ class AuroFloatingUI {
3611
3650
  * @param {String} eventType - The event type that triggered the hiding action.
3612
3651
  */
3613
3652
  hideBib(eventType = "unknown") {
3614
- if (!this.element.disabled && !this.element.noToggle) {
3615
- this.lockScroll(false);
3616
- this.element.triggerChevron?.removeAttribute("data-expanded");
3653
+ if (this.element.disabled) {
3654
+ return;
3655
+ }
3617
3656
 
3618
- if (this.element.isPopoverVisible) {
3619
- this.element.isPopoverVisible = false;
3620
- }
3621
- if (this.showing) {
3622
- this.cleanupHideHandlers();
3623
- this.showing = false;
3624
- this.dispatchEventDropdownToggle(eventType);
3625
- }
3657
+ // noToggle dropdowns should not close when the trigger is clicked (the
3658
+ // "toggle" behavior), but they CAN still close via other interactions like
3659
+ // Escape key or focus loss.
3660
+ if (this.element.noToggle && eventType === "click") {
3661
+ return;
3662
+ }
3663
+
3664
+ this.lockScroll(false);
3665
+ this.element.triggerChevron?.removeAttribute("data-expanded");
3666
+
3667
+ if (this.element.isPopoverVisible) {
3668
+ this.element.isPopoverVisible = false;
3669
+ }
3670
+ if (this.showing) {
3671
+ this.cleanupHideHandlers();
3672
+ this.showing = false;
3673
+ this.dispatchEventDropdownToggle(eventType);
3626
3674
  }
3675
+
3676
+ // Only clear the global reference if the bib was actually hidden.
3677
+ // Clearing it when hideBib is blocked (e.g. noToggle + click) corrupts
3678
+ // the singleton state so other dropdowns can't detect this one is still open.
3627
3679
  document.expandedAuroFloater = null;
3628
3680
  }
3629
3681
 
@@ -4956,7 +5008,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$4 {
4956
5008
  }
4957
5009
  };
4958
5010
 
4959
- var formkitVersion$2 = '202603171954';
5011
+ var formkitVersion$2 = '202603181732';
4960
5012
 
4961
5013
  let AuroElement$2 = class AuroElement extends i$4 {
4962
5014
  static get properties() {
@@ -12711,7 +12763,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$4 {
12711
12763
  }
12712
12764
  };
12713
12765
 
12714
- var formkitVersion$1 = '202603171954';
12766
+ var formkitVersion$1 = '202603181732';
12715
12767
 
12716
12768
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
12717
12769
  // See LICENSE in the project root for license information.
@@ -13750,7 +13802,7 @@ class AuroBibtemplate extends i$4 {
13750
13802
  }
13751
13803
  }
13752
13804
 
13753
- var formkitVersion = '202603171954';
13805
+ var formkitVersion = '202603181732';
13754
13806
 
13755
13807
  var styleCss$3 = i$7`.util_displayInline{display:inline}.util_displayInlineBlock{display:inline-block}.util_displayBlock{display:block}.util_displayFlex{display:flex}.util_displayHidden{display:none}.util_displayHiddenVisually{position:absolute;overflow:hidden;clip:rect(1px, 1px, 1px, 1px);width:1px;height:1px;padding:0;border:0}:host{display:block;text-align:left}:host [auro-dropdown]{--ds-auro-dropdown-trigger-background-color: transparent}:host #inputInBib::part(wrapper){box-shadow:none}:host #inputInBib::part(accent-left){display:none}:host([layout*=classic]) [auro-input]{width:100%}:host([layout*=classic]) [auro-input]::part(helpText){display:none}:host([layout*=classic]) #slotHolder{display:none}`;
13756
13808
 
@@ -14137,6 +14189,7 @@ class AuroCombobox extends AuroElement {
14137
14189
  this.value = undefined;
14138
14190
  this.typedValue = undefined;
14139
14191
  this.behavior = "suggestion";
14192
+ this.clearBtnFocused = false;
14140
14193
 
14141
14194
  // Defaults that effect the overall layout of the combobox
14142
14195
  this.checkmark = false;
@@ -15096,6 +15149,21 @@ class AuroCombobox extends AuroElement {
15096
15149
  this.validate();
15097
15150
  }
15098
15151
  });
15152
+
15153
+ /**
15154
+ * Track focus on the clear button within the input.
15155
+ * This is used to prevent unwanted interactions when the clear button is focused.
15156
+ *
15157
+ * Use event delegation on the shadow root so the listener works regardless
15158
+ * of when .clearBtn is rendered (it only exists after a value is set).
15159
+ */
15160
+ this.input.shadowRoot.addEventListener('focusin', (event) => {
15161
+ if (event.target.closest('.clearBtn')) {
15162
+ this.clearBtnFocused = true;
15163
+ } else {
15164
+ this.clearBtnFocused = false;
15165
+ }
15166
+ });
15099
15167
  }
15100
15168
 
15101
15169
  /**
@@ -15212,7 +15280,10 @@ class AuroCombobox extends AuroElement {
15212
15280
  * @returns {void}
15213
15281
  */
15214
15282
  configureCombobox() {
15215
- applyKeyboardStrategy(this, comboboxKeyboardStrategy);
15283
+ applyKeyboardStrategy(this, comboboxKeyboardStrategy, {
15284
+ // In modal mode the input moves into the bib; route keyboard events to that element instead.
15285
+ inputResolver: (comp, ctx) => (ctx.isModal && comp.inputInBib ? comp.inputInBib : comp.input),
15286
+ });
15216
15287
 
15217
15288
  this.addEventListener('focusin', () => {
15218
15289
  this.touched = true;
@@ -1156,17 +1156,46 @@ function restoreTriggerAfterClose(dropdown, focusTarget) {
1156
1156
  * SPDX-License-Identifier: BSD-3-Clause
1157
1157
  */let e$2 = class e extends i$2{constructor(i){if(super(i),this.it=A$2,i.type!==t$1.CHILD)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(r){if(r===A$2||null==r)return this._t=void 0,this.it=r;if(r===E)return r;if("string"!=typeof r)throw Error(this.constructor.directiveName+"() called with a non-string value");if(r===this.it)return this._t;this.it=r;const s=[r];return s.raw=s,this._t={_$litType$:this.constructor.resultType,strings:s,values:[]}}};e$2.directiveName="unsafeHTML",e$2.resultType=1;
1158
1158
 
1159
+ /**
1160
+ * Computes display state once per keydown event and returns a frozen context object.
1161
+ * Centralizes null-safety checks and makes the shared/modal/popover branching explicit.
1162
+ * @param {HTMLElement} component - The component with a dropdown reference.
1163
+ * @param {Object} [options] - Optional config.
1164
+ * @param {Function} [options.inputResolver] - Called with (component, ctx) to resolve the active input element.
1165
+ * @returns {Readonly<{isVisible: boolean, isModal: boolean, isPopover: boolean, activeInput: HTMLElement|null}>}
1166
+ */
1167
+ function createDisplayContext(component, options = {}) {
1168
+ const dd = component.dropdown;
1169
+ const isVisible = Boolean(dd && dd.isPopoverVisible);
1170
+ const isFullscreen = Boolean(dd && dd.isBibFullscreen);
1171
+
1172
+ const ctx = {
1173
+ isVisible,
1174
+ isModal: isVisible && isFullscreen,
1175
+ isPopover: isVisible && !isFullscreen,
1176
+ activeInput: null,
1177
+ };
1178
+
1179
+ if (options.inputResolver) {
1180
+ ctx.activeInput = options.inputResolver(component, ctx);
1181
+ }
1182
+
1183
+ return Object.freeze(ctx);
1184
+ }
1185
+
1159
1186
  /**
1160
1187
  * Wires up a keydown listener that dispatches to strategy[evt.key] or strategy.default.
1161
1188
  * Handles both sync and async handlers.
1162
1189
  * @param {HTMLElement} component - The component to attach the listener to.
1163
1190
  * @param {Object} strategy - Map of key names to handler functions.
1191
+ * @param {Object} [options] - Optional config passed to createDisplayContext.
1164
1192
  */
1165
- function applyKeyboardStrategy(component, strategy) {
1193
+ function applyKeyboardStrategy(component, strategy, options = {}) {
1166
1194
  component.addEventListener('keydown', async (evt) => {
1167
1195
  const handler = strategy[evt.key] || strategy.default;
1168
1196
  if (handler) {
1169
- await handler(component, evt);
1197
+ const ctx = createDisplayContext(component, options);
1198
+ await handler(component, evt, ctx);
1170
1199
  }
1171
1200
  });
1172
1201
  }
@@ -1178,9 +1207,11 @@ function applyKeyboardStrategy(component, strategy) {
1178
1207
  * @param {string} direction - 'up' or 'down'.
1179
1208
  * @param {Object} [options] - Optional config.
1180
1209
  * @param {Function} [options.showFn] - Called to open the dropdown when closed.
1210
+ * @param {Object} [options.ctx] - Display context to avoid re-checking visibility.
1181
1211
  */
1182
1212
  function navigateArrow(component, direction, options = {}) {
1183
- if (component.dropdown.isPopoverVisible) {
1213
+ const visible = options.ctx ? options.ctx.isVisible : component.dropdown.isPopoverVisible;
1214
+ if (visible) {
1184
1215
  component.menu.navigateOptions(direction);
1185
1216
  } else if (options.showFn) {
1186
1217
  options.showFn();
@@ -1188,29 +1219,21 @@ function navigateArrow(component, direction, options = {}) {
1188
1219
  }
1189
1220
 
1190
1221
  const comboboxKeyboardStrategy = {
1191
- async Enter(component, evt) {
1222
+ async Enter(component, evt, ctx) {
1192
1223
  // If the clear button has focus, let the browser activate it normally.
1193
1224
  // stopPropagation prevents parent containers (e.g., forms) from treating
1194
1225
  // Enter as a submit, but we must NOT call preventDefault — that would
1195
1226
  // block the browser's built-in "Enter activates focused button" behavior.
1196
- const isBibFullscreenActive =
1197
- component.dropdown &&
1198
- component.dropdown.isBibFullscreen &&
1199
- component.dropdown.isPopoverVisible;
1200
- const activeInput =
1201
- isBibFullscreenActive && component.inputInBib
1202
- ? component.inputInBib
1203
- : component.input;
1204
1227
  const clearBtn =
1205
- activeInput && activeInput.shadowRoot
1206
- ? activeInput.shadowRoot.querySelector('.clearBtn')
1228
+ ctx.activeInput && ctx.activeInput.shadowRoot
1229
+ ? ctx.activeInput.shadowRoot.querySelector('.clearBtn')
1207
1230
  : null;
1208
1231
  if (clearBtn && clearBtn.shadowRoot && clearBtn.shadowRoot.activeElement !== null) {
1209
1232
  evt.stopPropagation();
1210
1233
  return;
1211
1234
  }
1212
1235
 
1213
- if (component.dropdown.isPopoverVisible && component.optionActive) {
1236
+ if (ctx.isVisible && component.optionActive) {
1214
1237
  component.menu.makeSelection();
1215
1238
  await component.updateComplete;
1216
1239
  evt.preventDefault();
@@ -1227,20 +1250,34 @@ const comboboxKeyboardStrategy = {
1227
1250
  }
1228
1251
  },
1229
1252
 
1230
- Tab(component) {
1231
- if (!component.dropdown.isPopoverVisible) {
1253
+ Tab(component, evt, ctx) {
1254
+ if (!ctx.isVisible) {
1232
1255
  return;
1233
1256
  }
1234
1257
 
1235
- if (component.dropdown.isBibFullscreen) {
1236
- const clearBtn = component.inputInBib.shadowRoot.querySelector('.clearBtn');
1258
+ if (ctx.isModal) {
1259
+ if (!ctx.activeInput) {
1260
+ return;
1261
+ }
1262
+ const clearBtn = ctx.activeInput.shadowRoot.querySelector('.clearBtn');
1237
1263
 
1238
1264
  // Use shadowRoot.activeElement to detect focus inside auro-button,
1239
1265
  // since Safari does not propagate :focus-within through shadow DOM.
1240
1266
  const clearBtnHasFocus = clearBtn && clearBtn.shadowRoot && clearBtn.shadowRoot.activeElement !== null;
1241
1267
 
1268
+ if (evt.shiftKey) {
1269
+ // Shift+Tab from clear button: move focus back to the input
1270
+ if (clearBtnHasFocus) {
1271
+ ctx.activeInput.focus();
1272
+ return;
1273
+ }
1274
+ // Shift+Tab from input (or no clear button): close without selecting
1275
+ component.hideBib();
1276
+ return;
1277
+ }
1278
+
1242
1279
  // Tab from input: if clear button exists and doesn't have focus, focus it
1243
- if (clearBtn && !clearBtnHasFocus && component.inputInBib.value) {
1280
+ if (clearBtn && !clearBtnHasFocus && ctx.activeInput.value) {
1244
1281
  // Force clear button container visible to work around Safari not
1245
1282
  // propagating :focus-within through shadow DOM boundaries, which
1246
1283
  // causes .wrapper:not(:focus-within) to hide .notification.clear.
@@ -1276,8 +1313,8 @@ const comboboxKeyboardStrategy = {
1276
1313
  return;
1277
1314
  }
1278
1315
 
1279
- // Non-fullscreen: select + close
1280
- if (component.menu.optionActive && component.menu.optionActive.value) {
1316
+ // Non-fullscreen: select + close (Shift+Tab closes without selecting)
1317
+ if (!evt.shiftKey && component.menu.optionActive && component.menu.optionActive.value) {
1281
1318
  component.menu.value = component.menu.optionActive.value;
1282
1319
  }
1283
1320
  component.hideBib();
@@ -1287,6 +1324,7 @@ const comboboxKeyboardStrategy = {
1287
1324
  if (component.availableOptions.length > 0) {
1288
1325
  component.showBib();
1289
1326
  }
1327
+ // Check live visibility: showBib() above may have just opened the dropdown.
1290
1328
  if (component.dropdown.isPopoverVisible) {
1291
1329
  evt.preventDefault();
1292
1330
  navigateArrow(component, 'up');
@@ -1297,6 +1335,7 @@ const comboboxKeyboardStrategy = {
1297
1335
  if (component.availableOptions.length > 0) {
1298
1336
  component.showBib();
1299
1337
  }
1338
+ // Check live visibility: showBib() above may have just opened the dropdown.
1300
1339
  if (component.dropdown.isPopoverVisible) {
1301
1340
  evt.preventDefault();
1302
1341
  navigateArrow(component, 'down');
@@ -3534,19 +3573,32 @@ class AuroFloatingUI {
3534
3573
  * @param {String} eventType - The event type that triggered the hiding action.
3535
3574
  */
3536
3575
  hideBib(eventType = "unknown") {
3537
- if (!this.element.disabled && !this.element.noToggle) {
3538
- this.lockScroll(false);
3539
- this.element.triggerChevron?.removeAttribute("data-expanded");
3576
+ if (this.element.disabled) {
3577
+ return;
3578
+ }
3540
3579
 
3541
- if (this.element.isPopoverVisible) {
3542
- this.element.isPopoverVisible = false;
3543
- }
3544
- if (this.showing) {
3545
- this.cleanupHideHandlers();
3546
- this.showing = false;
3547
- this.dispatchEventDropdownToggle(eventType);
3548
- }
3580
+ // noToggle dropdowns should not close when the trigger is clicked (the
3581
+ // "toggle" behavior), but they CAN still close via other interactions like
3582
+ // Escape key or focus loss.
3583
+ if (this.element.noToggle && eventType === "click") {
3584
+ return;
3585
+ }
3586
+
3587
+ this.lockScroll(false);
3588
+ this.element.triggerChevron?.removeAttribute("data-expanded");
3589
+
3590
+ if (this.element.isPopoverVisible) {
3591
+ this.element.isPopoverVisible = false;
3592
+ }
3593
+ if (this.showing) {
3594
+ this.cleanupHideHandlers();
3595
+ this.showing = false;
3596
+ this.dispatchEventDropdownToggle(eventType);
3549
3597
  }
3598
+
3599
+ // Only clear the global reference if the bib was actually hidden.
3600
+ // Clearing it when hideBib is blocked (e.g. noToggle + click) corrupts
3601
+ // the singleton state so other dropdowns can't detect this one is still open.
3550
3602
  document.expandedAuroFloater = null;
3551
3603
  }
3552
3604
 
@@ -4879,7 +4931,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$4 {
4879
4931
  }
4880
4932
  };
4881
4933
 
4882
- var formkitVersion$2 = '202603171954';
4934
+ var formkitVersion$2 = '202603181732';
4883
4935
 
4884
4936
  let AuroElement$2 = class AuroElement extends i$4 {
4885
4937
  static get properties() {
@@ -12634,7 +12686,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$4 {
12634
12686
  }
12635
12687
  };
12636
12688
 
12637
- var formkitVersion$1 = '202603171954';
12689
+ var formkitVersion$1 = '202603181732';
12638
12690
 
12639
12691
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
12640
12692
  // See LICENSE in the project root for license information.
@@ -13673,7 +13725,7 @@ class AuroBibtemplate extends i$4 {
13673
13725
  }
13674
13726
  }
13675
13727
 
13676
- var formkitVersion = '202603171954';
13728
+ var formkitVersion = '202603181732';
13677
13729
 
13678
13730
  var styleCss$3 = i$7`.util_displayInline{display:inline}.util_displayInlineBlock{display:inline-block}.util_displayBlock{display:block}.util_displayFlex{display:flex}.util_displayHidden{display:none}.util_displayHiddenVisually{position:absolute;overflow:hidden;clip:rect(1px, 1px, 1px, 1px);width:1px;height:1px;padding:0;border:0}:host{display:block;text-align:left}:host [auro-dropdown]{--ds-auro-dropdown-trigger-background-color: transparent}:host #inputInBib::part(wrapper){box-shadow:none}:host #inputInBib::part(accent-left){display:none}:host([layout*=classic]) [auro-input]{width:100%}:host([layout*=classic]) [auro-input]::part(helpText){display:none}:host([layout*=classic]) #slotHolder{display:none}`;
13679
13731
 
@@ -14060,6 +14112,7 @@ class AuroCombobox extends AuroElement {
14060
14112
  this.value = undefined;
14061
14113
  this.typedValue = undefined;
14062
14114
  this.behavior = "suggestion";
14115
+ this.clearBtnFocused = false;
14063
14116
 
14064
14117
  // Defaults that effect the overall layout of the combobox
14065
14118
  this.checkmark = false;
@@ -15019,6 +15072,21 @@ class AuroCombobox extends AuroElement {
15019
15072
  this.validate();
15020
15073
  }
15021
15074
  });
15075
+
15076
+ /**
15077
+ * Track focus on the clear button within the input.
15078
+ * This is used to prevent unwanted interactions when the clear button is focused.
15079
+ *
15080
+ * Use event delegation on the shadow root so the listener works regardless
15081
+ * of when .clearBtn is rendered (it only exists after a value is set).
15082
+ */
15083
+ this.input.shadowRoot.addEventListener('focusin', (event) => {
15084
+ if (event.target.closest('.clearBtn')) {
15085
+ this.clearBtnFocused = true;
15086
+ } else {
15087
+ this.clearBtnFocused = false;
15088
+ }
15089
+ });
15022
15090
  }
15023
15091
 
15024
15092
  /**
@@ -15135,7 +15203,10 @@ class AuroCombobox extends AuroElement {
15135
15203
  * @returns {void}
15136
15204
  */
15137
15205
  configureCombobox() {
15138
- applyKeyboardStrategy(this, comboboxKeyboardStrategy);
15206
+ applyKeyboardStrategy(this, comboboxKeyboardStrategy, {
15207
+ // In modal mode the input moves into the bib; route keyboard events to that element instead.
15208
+ inputResolver: (comp, ctx) => (ctx.isModal && comp.inputInBib ? comp.inputInBib : comp.input),
15209
+ });
15139
15210
 
15140
15211
  this.addEventListener('focusin', () => {
15141
15212
  this.touched = true;
@@ -339,6 +339,7 @@ export class AuroCombobox extends AuroElement {
339
339
  value: any;
340
340
  typedValue: any;
341
341
  behavior: string;
342
+ clearBtnFocused: boolean;
342
343
  checkmark: boolean;
343
344
  dvInputOnly: boolean;
344
345
  fullscreenBreakpoint: string;
@@ -1,6 +1,6 @@
1
1
  export namespace comboboxKeyboardStrategy {
2
- function Enter(component: any, evt: any): Promise<void>;
3
- function Tab(component: any): void;
2
+ function Enter(component: any, evt: any, ctx: any): Promise<void>;
3
+ function Tab(component: any, evt: any, ctx: any): void;
4
4
  function ArrowUp(component: any, evt: any): void;
5
5
  function ArrowDown(component: any, evt: any): void;
6
6
  }