@aurodesignsystem-dev/auro-formkit 0.0.0-pr1377.2 → 0.0.0-pr1377.20

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 (44) 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 +97 -61
  6. package/components/combobox/demo/index.min.js +97 -61
  7. package/components/combobox/dist/comboboxKeyboardStrategy.d.ts +3 -3
  8. package/components/combobox/dist/index.js +95 -59
  9. package/components/combobox/dist/registered.js +95 -59
  10. package/components/counter/demo/api.min.js +2 -2
  11. package/components/counter/demo/index.min.js +2 -2
  12. package/components/counter/dist/index.js +2 -2
  13. package/components/counter/dist/registered.js +2 -2
  14. package/components/datepicker/demo/api.min.js +11 -41
  15. package/components/datepicker/demo/index.min.js +11 -41
  16. package/components/datepicker/dist/auro-datepicker.d.ts +0 -7
  17. package/components/datepicker/dist/index.js +11 -41
  18. package/components/datepicker/dist/registered.js +11 -41
  19. package/components/dropdown/demo/api.min.js +1 -1
  20. package/components/dropdown/demo/index.min.js +1 -1
  21. package/components/dropdown/dist/index.js +1 -1
  22. package/components/dropdown/dist/registered.js +1 -1
  23. package/components/form/demo/api.min.js +141 -131
  24. package/components/form/demo/index.min.js +141 -131
  25. package/components/input/demo/api.min.js +1 -1
  26. package/components/input/demo/index.min.js +1 -1
  27. package/components/input/dist/index.js +1 -1
  28. package/components/input/dist/registered.js +1 -1
  29. package/components/menu/demo/api.min.js +2 -2
  30. package/components/menu/demo/index.min.js +2 -2
  31. package/components/menu/dist/index.js +2 -2
  32. package/components/menu/dist/registered.js +2 -2
  33. package/components/radio/demo/api.min.js +1 -1
  34. package/components/radio/demo/index.min.js +1 -1
  35. package/components/radio/dist/index.js +1 -1
  36. package/components/radio/dist/registered.js +1 -1
  37. package/components/select/demo/api.min.js +30 -26
  38. package/components/select/demo/index.min.js +30 -26
  39. package/components/select/dist/index.js +28 -24
  40. package/components/select/dist/registered.js +28 -24
  41. package/components/select/dist/selectKeyboardStrategy.d.ts +1 -1
  42. package/custom-elements.json +2 -137
  43. package/package.json +1 -1
  44. package/components/dropdown/dist/keyboardUtils.d.ts +0 -37
@@ -1104,40 +1104,45 @@ function guardTouchPassthrough(element) {
1104
1104
  function restoreTriggerAfterClose(dropdown, focusTarget) {
1105
1105
  dropdown.trigger.inert = false;
1106
1106
 
1107
- if (dropdown.isBibFullscreen) {
1108
- requestAnimationFrame(() => {
1109
- if (!dropdown.isPopoverVisible) {
1110
- focusTarget.focus();
1111
- }
1112
- });
1113
- }
1107
+ requestAnimationFrame(() => {
1108
+ if (!dropdown.isPopoverVisible) {
1109
+ focusTarget.focus();
1110
+ }
1111
+ });
1114
1112
  }
1115
1113
 
1116
1114
  /**
1117
- * Computes display state once per keydown event and returns a frozen context object.
1115
+ * Computes display state once per keydown event.
1118
1116
  * Centralizes null-safety checks and makes the shared/modal/popover branching explicit.
1117
+ *
1119
1118
  * @param {HTMLElement} component - The component with a dropdown reference.
1120
1119
  * @param {Object} [options] - Optional config.
1120
+ * @param {HTMLElement} [options.dropdown] - Explicit dropdown reference. Falls back to component.dropdown.
1121
1121
  * @param {Function} [options.inputResolver] - Called with (component, ctx) to resolve the active input element.
1122
- * @returns {Readonly<{isVisible: boolean, isModal: boolean, isPopover: boolean, activeInput: HTMLElement|null}>}
1122
+ * @returns {{isExpanded: boolean, isModal: boolean, isPopover: boolean, activeInput: HTMLElement|null}}
1123
+ * isModal and isPopover reflect the display mode (fullscreen vs not) regardless of expanded state.
1123
1124
  */
1124
1125
  function createDisplayContext(component, options = {}) {
1125
- const dd = component.dropdown;
1126
- const isVisible = Boolean(dd && dd.isPopoverVisible);
1126
+ const dd = options.dropdown || component.dropdown;
1127
+ // isPopoverVisible reflects as the `open` attribute.
1128
+ // It reports whether the bib is open in any mode (popover or modal).
1129
+ const isExpanded = Boolean(dd && dd.isPopoverVisible);
1127
1130
  const isFullscreen = Boolean(dd && dd.isBibFullscreen);
1128
1131
 
1129
1132
  const ctx = {
1130
- isVisible,
1131
- isModal: isVisible && isFullscreen,
1132
- isPopover: isVisible && !isFullscreen,
1133
+ isExpanded,
1134
+ isModal: isFullscreen,
1135
+ isPopover: !isFullscreen,
1133
1136
  activeInput: null,
1134
1137
  };
1135
1138
 
1136
1139
  if (options.inputResolver) {
1137
- ctx.activeInput = options.inputResolver(component, ctx);
1140
+ const resolvedInput = options.inputResolver(component, ctx);
1141
+ // Guard against resolvers returning undefined or non-HTMLElement values.
1142
+ ctx.activeInput = resolvedInput instanceof HTMLElement ? resolvedInput : null;
1138
1143
  }
1139
1144
 
1140
- return Object.freeze(ctx);
1145
+ return ctx;
1141
1146
  }
1142
1147
 
1143
1148
  /**
@@ -1150,7 +1155,7 @@ function createDisplayContext(component, options = {}) {
1150
1155
  function applyKeyboardStrategy(component, strategy, options = {}) {
1151
1156
  component.addEventListener('keydown', async (evt) => {
1152
1157
  const handler = strategy[evt.key] || strategy.default;
1153
- if (handler) {
1158
+ if (typeof handler === 'function') {
1154
1159
  const ctx = createDisplayContext(component, options);
1155
1160
  await handler(component, evt, ctx);
1156
1161
  }
@@ -1167,7 +1172,7 @@ function applyKeyboardStrategy(component, strategy, options = {}) {
1167
1172
  * @param {Object} [options.ctx] - Display context to avoid re-checking visibility.
1168
1173
  */
1169
1174
  function navigateArrow(component, direction, options = {}) {
1170
- const visible = options.ctx ? options.ctx.isVisible : component.dropdown.isPopoverVisible;
1175
+ const visible = options.ctx ? options.ctx.isExpanded : component.dropdown.isPopoverVisible;
1171
1176
  if (visible) {
1172
1177
  component.menu.navigateOptions(direction);
1173
1178
  } else if (options.showFn) {
@@ -1175,22 +1180,47 @@ function navigateArrow(component, direction, options = {}) {
1175
1180
  }
1176
1181
  }
1177
1182
 
1183
+ /**
1184
+ * Returns the clear button element from the active input's shadow
1185
+ * DOM, if available.
1186
+ * @param {Object} ctx - Display context with activeInput.
1187
+ * @returns {Element|null}
1188
+ */
1189
+ function getClearBtn(ctx) {
1190
+ const root = ctx && ctx.activeInput && ctx.activeInput.shadowRoot;
1191
+ if (!root) {
1192
+ return null;
1193
+ }
1194
+ return root.querySelector('.clearBtn');
1195
+ }
1196
+
1197
+ /**
1198
+ * Returns true when the clear button inside the active input's shadow DOM has focus.
1199
+ * Uses shadowRoot.activeElement to detect focus inside auro-button,
1200
+ * since Safari does not propagate :focus-within through shadow DOM.
1201
+ * @param {Object} ctx - Display context with activeInput.
1202
+ * @param {Element} [clearBtn=getClearBtn(ctx)] - Pre-fetched clear button element.
1203
+ * @returns {boolean}
1204
+ */
1205
+ function isClearBtnFocused(ctx, clearBtn = getClearBtn(ctx)) {
1206
+ if (!clearBtn) {
1207
+ return false;
1208
+ }
1209
+ return Boolean(clearBtn.shadowRoot && clearBtn.shadowRoot.activeElement !== null);
1210
+ }
1211
+
1178
1212
  const comboboxKeyboardStrategy = {
1179
1213
  async Enter(component, evt, ctx) {
1180
1214
  // If the clear button has focus, let the browser activate it normally.
1181
1215
  // stopPropagation prevents parent containers (e.g., forms) from treating
1182
1216
  // Enter as a submit, but we must NOT call preventDefault — that would
1183
1217
  // block the browser's built-in "Enter activates focused button" behavior.
1184
- const clearBtn =
1185
- ctx.activeInput && ctx.activeInput.shadowRoot
1186
- ? ctx.activeInput.shadowRoot.querySelector('.clearBtn')
1187
- : null;
1188
- if (clearBtn && clearBtn.shadowRoot && clearBtn.shadowRoot.activeElement !== null) {
1218
+ if (isClearBtnFocused(ctx)) {
1189
1219
  evt.stopPropagation();
1190
1220
  return;
1191
1221
  }
1192
1222
 
1193
- if (ctx.isVisible && component.optionActive) {
1223
+ if (ctx.isExpanded && component.optionActive) {
1194
1224
  component.menu.makeSelection();
1195
1225
  await component.updateComplete;
1196
1226
  evt.preventDefault();
@@ -1207,8 +1237,8 @@ const comboboxKeyboardStrategy = {
1207
1237
  }
1208
1238
  },
1209
1239
 
1210
- Tab(component, evt, ctx) {
1211
- if (!ctx.isVisible) {
1240
+ Tab(component, _evt, ctx) {
1241
+ if (!ctx.isExpanded) {
1212
1242
  return;
1213
1243
  }
1214
1244
 
@@ -1216,22 +1246,8 @@ const comboboxKeyboardStrategy = {
1216
1246
  if (!ctx.activeInput) {
1217
1247
  return;
1218
1248
  }
1219
- const clearBtn = ctx.activeInput.shadowRoot.querySelector('.clearBtn');
1220
-
1221
- // Use shadowRoot.activeElement to detect focus inside auro-button,
1222
- // since Safari does not propagate :focus-within through shadow DOM.
1223
- const clearBtnHasFocus = clearBtn && clearBtn.shadowRoot && clearBtn.shadowRoot.activeElement !== null;
1224
-
1225
- if (evt.shiftKey) {
1226
- // Shift+Tab from clear button: move focus back to the input
1227
- if (clearBtnHasFocus) {
1228
- ctx.activeInput.focus();
1229
- return;
1230
- }
1231
- // Shift+Tab from input (or no clear button): close without selecting
1232
- component.hideBib();
1233
- return;
1234
- }
1249
+ const clearBtn = getClearBtn(ctx);
1250
+ const clearBtnHasFocus = isClearBtnFocused(ctx, clearBtn);
1235
1251
 
1236
1252
  // Tab from input: if clear button exists and doesn't have focus, focus it
1237
1253
  if (clearBtn && !clearBtnHasFocus && ctx.activeInput.value) {
@@ -1270,29 +1286,41 @@ const comboboxKeyboardStrategy = {
1270
1286
  return;
1271
1287
  }
1272
1288
 
1273
- // Non-fullscreen: select + close (Shift+Tab closes without selecting)
1274
- if (!evt.shiftKey && component.menu.optionActive && component.menu.optionActive.value) {
1289
+ // Non-fullscreen: select + close
1290
+ if (component.menu.optionActive && component.menu.optionActive.value) {
1275
1291
  component.menu.value = component.menu.optionActive.value;
1276
1292
  }
1277
1293
  component.hideBib();
1278
1294
  },
1279
1295
 
1280
- ArrowUp(component, evt) {
1296
+ ArrowUp(component, evt, ctx) {
1297
+ // If the clear button has focus, let the browser handle ArrowUp normally.
1298
+ if (isClearBtnFocused(ctx)) {
1299
+ return;
1300
+ }
1301
+
1281
1302
  if (component.availableOptions.length > 0) {
1282
1303
  component.showBib();
1283
1304
  }
1284
- // Check live visibility: showBib() above may have just opened the dropdown.
1305
+ // Read live visibility ctx.isExpanded was computed before showBib() above,
1306
+ // so it wouldn't reflect the state change.
1285
1307
  if (component.dropdown.isPopoverVisible) {
1286
1308
  evt.preventDefault();
1287
1309
  navigateArrow(component, 'up');
1288
1310
  }
1289
1311
  },
1290
1312
 
1291
- ArrowDown(component, evt) {
1313
+ ArrowDown(component, evt, ctx) {
1314
+ // If the clear button has focus, let the browser handle ArrowDown normally.
1315
+ if (isClearBtnFocused(ctx)) {
1316
+ return;
1317
+ }
1318
+
1292
1319
  if (component.availableOptions.length > 0) {
1293
1320
  component.showBib();
1294
1321
  }
1295
- // Check live visibility: showBib() above may have just opened the dropdown.
1322
+ // Read live visibility ctx.isExpanded was computed before showBib() above,
1323
+ // so it wouldn't reflect the state change.
1296
1324
  if (component.dropdown.isPopoverVisible) {
1297
1325
  evt.preventDefault();
1298
1326
  navigateArrow(component, 'down');
@@ -4864,7 +4892,7 @@ let AuroHelpText$2 = class AuroHelpText extends LitElement {
4864
4892
  }
4865
4893
  };
4866
4894
 
4867
- var formkitVersion$2 = '202603181736';
4895
+ var formkitVersion$2 = '202603192334';
4868
4896
 
4869
4897
  let AuroElement$2 = class AuroElement extends LitElement {
4870
4898
  static get properties() {
@@ -12612,7 +12640,7 @@ let AuroHelpText$1 = class AuroHelpText extends LitElement {
12612
12640
  }
12613
12641
  };
12614
12642
 
12615
- var formkitVersion$1 = '202603181736';
12643
+ var formkitVersion$1 = '202603192334';
12616
12644
 
12617
12645
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
12618
12646
  // See LICENSE in the project root for license information.
@@ -13651,7 +13679,7 @@ class AuroBibtemplate extends LitElement {
13651
13679
  }
13652
13680
  }
13653
13681
 
13654
- var formkitVersion = '202603181736';
13682
+ var formkitVersion = '202603192334';
13655
13683
 
13656
13684
  var styleCss$1 = css`.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}`;
13657
13685
 
@@ -14508,6 +14536,13 @@ class AuroCombobox extends AuroElement {
14508
14536
 
14509
14537
  this.noMatchOption = undefined;
14510
14538
 
14539
+ // Remove trailing whitespace only when the input contains
14540
+ // non-whitespace characters, so residual spaces from cursor
14541
+ // editing don't break matching. Whitespace-only input is
14542
+ // preserved as-is so a lone space doesn't show all options.
14543
+ const raw = this.input.value || '';
14544
+ const filterValue = (raw.trim() ? raw.trimEnd() : raw).toLowerCase();
14545
+
14511
14546
  this.options.forEach((option) => {
14512
14547
  let matchString = option.textContent.toLowerCase();
14513
14548
 
@@ -14524,12 +14559,12 @@ class AuroCombobox extends AuroElement {
14524
14559
  }
14525
14560
 
14526
14561
  // If input is empty, show all options (except static ones)
14527
- if (!this.input.value || this.input.value.length === 0) {
14562
+ if (!filterValue) {
14528
14563
  if (!option.hasAttribute('static')) {
14529
14564
  option.removeAttribute('hidden');
14530
14565
  this.availableOptions.push(option);
14531
14566
  }
14532
- } else if (matchString.includes(this.input.value.toLowerCase()) && !option.hasAttribute('static')) {
14567
+ } else if (matchString.includes(filterValue) && !option.hasAttribute('static')) {
14533
14568
  // only count options that match the typed input value AND are not static
14534
14569
  option.removeAttribute('hidden');
14535
14570
  this.availableOptions.push(option);
@@ -14560,7 +14595,7 @@ class AuroCombobox extends AuroElement {
14560
14595
  syncValuesAndStates() {
14561
14596
  // Only sync matchWord, don't set menu.value here since setMenuValue should handle that
14562
14597
  if (this.menu) {
14563
- this.menu.matchWord = this.input.value;
14598
+ this.menu.matchWord = (this.input.value || '').trimEnd();
14564
14599
  }
14565
14600
  const label = this.menu.currentLabel;
14566
14601
  this.updateTriggerTextDisplay(label || this.value);
@@ -14924,8 +14959,9 @@ class AuroCombobox extends AuroElement {
14924
14959
  this.updateTriggerTextDisplay(event.detail.label || event.detail.value);
14925
14960
 
14926
14961
  // Update match word for filtering
14927
- if (this.menu.matchWord !== this.input.value) {
14928
- this.menu.matchWord = this.input.value;
14962
+ const trimmedInput = (this.input.value || '').trimEnd();
14963
+ if (this.menu.matchWord !== trimmedInput) {
14964
+ this.menu.matchWord = trimmedInput;
14929
14965
  }
14930
14966
 
14931
14967
  // Update available options based on selection
@@ -15063,7 +15099,7 @@ class AuroCombobox extends AuroElement {
15063
15099
  });
15064
15100
 
15065
15101
  // Run filtering inline — the re-entrant event won't reach this code.
15066
- this.menu.matchWord = this.inputInBib.value;
15102
+ this.menu.matchWord = (this.inputInBib.value || '').trimEnd();
15067
15103
  this.optionActive = null;
15068
15104
  this.handleMenuOptions();
15069
15105
  this.dispatchEvent(new CustomEvent('inputValue', { detail: { value: this.inputValue } }));
@@ -15077,7 +15113,7 @@ class AuroCombobox extends AuroElement {
15077
15113
 
15078
15114
  this.inputInBib.value = this.input.value;
15079
15115
 
15080
- this.menu.matchWord = this.input.value;
15116
+ this.menu.matchWord = (this.input.value || '').trimEnd();
15081
15117
  this.optionActive = null;
15082
15118
 
15083
15119
  if (!this.input.value) {
@@ -15291,7 +15327,7 @@ class AuroCombobox extends AuroElement {
15291
15327
 
15292
15328
  // Sync the input and match word, but don't directly set menu.value again
15293
15329
  if (this.menu) {
15294
- this.menu.matchWord = this.input.value;
15330
+ this.menu.matchWord = (this.input.value || '').trimEnd();
15295
15331
  }
15296
15332
 
15297
15333
  this.dispatchEvent(new CustomEvent('input', {
@@ -1104,40 +1104,45 @@ function guardTouchPassthrough(element) {
1104
1104
  function restoreTriggerAfterClose(dropdown, focusTarget) {
1105
1105
  dropdown.trigger.inert = false;
1106
1106
 
1107
- if (dropdown.isBibFullscreen) {
1108
- requestAnimationFrame(() => {
1109
- if (!dropdown.isPopoverVisible) {
1110
- focusTarget.focus();
1111
- }
1112
- });
1113
- }
1107
+ requestAnimationFrame(() => {
1108
+ if (!dropdown.isPopoverVisible) {
1109
+ focusTarget.focus();
1110
+ }
1111
+ });
1114
1112
  }
1115
1113
 
1116
1114
  /**
1117
- * Computes display state once per keydown event and returns a frozen context object.
1115
+ * Computes display state once per keydown event.
1118
1116
  * Centralizes null-safety checks and makes the shared/modal/popover branching explicit.
1117
+ *
1119
1118
  * @param {HTMLElement} component - The component with a dropdown reference.
1120
1119
  * @param {Object} [options] - Optional config.
1120
+ * @param {HTMLElement} [options.dropdown] - Explicit dropdown reference. Falls back to component.dropdown.
1121
1121
  * @param {Function} [options.inputResolver] - Called with (component, ctx) to resolve the active input element.
1122
- * @returns {Readonly<{isVisible: boolean, isModal: boolean, isPopover: boolean, activeInput: HTMLElement|null}>}
1122
+ * @returns {{isExpanded: boolean, isModal: boolean, isPopover: boolean, activeInput: HTMLElement|null}}
1123
+ * isModal and isPopover reflect the display mode (fullscreen vs not) regardless of expanded state.
1123
1124
  */
1124
1125
  function createDisplayContext(component, options = {}) {
1125
- const dd = component.dropdown;
1126
- const isVisible = Boolean(dd && dd.isPopoverVisible);
1126
+ const dd = options.dropdown || component.dropdown;
1127
+ // isPopoverVisible reflects as the `open` attribute.
1128
+ // It reports whether the bib is open in any mode (popover or modal).
1129
+ const isExpanded = Boolean(dd && dd.isPopoverVisible);
1127
1130
  const isFullscreen = Boolean(dd && dd.isBibFullscreen);
1128
1131
 
1129
1132
  const ctx = {
1130
- isVisible,
1131
- isModal: isVisible && isFullscreen,
1132
- isPopover: isVisible && !isFullscreen,
1133
+ isExpanded,
1134
+ isModal: isFullscreen,
1135
+ isPopover: !isFullscreen,
1133
1136
  activeInput: null,
1134
1137
  };
1135
1138
 
1136
1139
  if (options.inputResolver) {
1137
- ctx.activeInput = options.inputResolver(component, ctx);
1140
+ const resolvedInput = options.inputResolver(component, ctx);
1141
+ // Guard against resolvers returning undefined or non-HTMLElement values.
1142
+ ctx.activeInput = resolvedInput instanceof HTMLElement ? resolvedInput : null;
1138
1143
  }
1139
1144
 
1140
- return Object.freeze(ctx);
1145
+ return ctx;
1141
1146
  }
1142
1147
 
1143
1148
  /**
@@ -1150,7 +1155,7 @@ function createDisplayContext(component, options = {}) {
1150
1155
  function applyKeyboardStrategy(component, strategy, options = {}) {
1151
1156
  component.addEventListener('keydown', async (evt) => {
1152
1157
  const handler = strategy[evt.key] || strategy.default;
1153
- if (handler) {
1158
+ if (typeof handler === 'function') {
1154
1159
  const ctx = createDisplayContext(component, options);
1155
1160
  await handler(component, evt, ctx);
1156
1161
  }
@@ -1167,7 +1172,7 @@ function applyKeyboardStrategy(component, strategy, options = {}) {
1167
1172
  * @param {Object} [options.ctx] - Display context to avoid re-checking visibility.
1168
1173
  */
1169
1174
  function navigateArrow(component, direction, options = {}) {
1170
- const visible = options.ctx ? options.ctx.isVisible : component.dropdown.isPopoverVisible;
1175
+ const visible = options.ctx ? options.ctx.isExpanded : component.dropdown.isPopoverVisible;
1171
1176
  if (visible) {
1172
1177
  component.menu.navigateOptions(direction);
1173
1178
  } else if (options.showFn) {
@@ -1175,22 +1180,47 @@ function navigateArrow(component, direction, options = {}) {
1175
1180
  }
1176
1181
  }
1177
1182
 
1183
+ /**
1184
+ * Returns the clear button element from the active input's shadow
1185
+ * DOM, if available.
1186
+ * @param {Object} ctx - Display context with activeInput.
1187
+ * @returns {Element|null}
1188
+ */
1189
+ function getClearBtn(ctx) {
1190
+ const root = ctx && ctx.activeInput && ctx.activeInput.shadowRoot;
1191
+ if (!root) {
1192
+ return null;
1193
+ }
1194
+ return root.querySelector('.clearBtn');
1195
+ }
1196
+
1197
+ /**
1198
+ * Returns true when the clear button inside the active input's shadow DOM has focus.
1199
+ * Uses shadowRoot.activeElement to detect focus inside auro-button,
1200
+ * since Safari does not propagate :focus-within through shadow DOM.
1201
+ * @param {Object} ctx - Display context with activeInput.
1202
+ * @param {Element} [clearBtn=getClearBtn(ctx)] - Pre-fetched clear button element.
1203
+ * @returns {boolean}
1204
+ */
1205
+ function isClearBtnFocused(ctx, clearBtn = getClearBtn(ctx)) {
1206
+ if (!clearBtn) {
1207
+ return false;
1208
+ }
1209
+ return Boolean(clearBtn.shadowRoot && clearBtn.shadowRoot.activeElement !== null);
1210
+ }
1211
+
1178
1212
  const comboboxKeyboardStrategy = {
1179
1213
  async Enter(component, evt, ctx) {
1180
1214
  // If the clear button has focus, let the browser activate it normally.
1181
1215
  // stopPropagation prevents parent containers (e.g., forms) from treating
1182
1216
  // Enter as a submit, but we must NOT call preventDefault — that would
1183
1217
  // block the browser's built-in "Enter activates focused button" behavior.
1184
- const clearBtn =
1185
- ctx.activeInput && ctx.activeInput.shadowRoot
1186
- ? ctx.activeInput.shadowRoot.querySelector('.clearBtn')
1187
- : null;
1188
- if (clearBtn && clearBtn.shadowRoot && clearBtn.shadowRoot.activeElement !== null) {
1218
+ if (isClearBtnFocused(ctx)) {
1189
1219
  evt.stopPropagation();
1190
1220
  return;
1191
1221
  }
1192
1222
 
1193
- if (ctx.isVisible && component.optionActive) {
1223
+ if (ctx.isExpanded && component.optionActive) {
1194
1224
  component.menu.makeSelection();
1195
1225
  await component.updateComplete;
1196
1226
  evt.preventDefault();
@@ -1207,8 +1237,8 @@ const comboboxKeyboardStrategy = {
1207
1237
  }
1208
1238
  },
1209
1239
 
1210
- Tab(component, evt, ctx) {
1211
- if (!ctx.isVisible) {
1240
+ Tab(component, _evt, ctx) {
1241
+ if (!ctx.isExpanded) {
1212
1242
  return;
1213
1243
  }
1214
1244
 
@@ -1216,22 +1246,8 @@ const comboboxKeyboardStrategy = {
1216
1246
  if (!ctx.activeInput) {
1217
1247
  return;
1218
1248
  }
1219
- const clearBtn = ctx.activeInput.shadowRoot.querySelector('.clearBtn');
1220
-
1221
- // Use shadowRoot.activeElement to detect focus inside auro-button,
1222
- // since Safari does not propagate :focus-within through shadow DOM.
1223
- const clearBtnHasFocus = clearBtn && clearBtn.shadowRoot && clearBtn.shadowRoot.activeElement !== null;
1224
-
1225
- if (evt.shiftKey) {
1226
- // Shift+Tab from clear button: move focus back to the input
1227
- if (clearBtnHasFocus) {
1228
- ctx.activeInput.focus();
1229
- return;
1230
- }
1231
- // Shift+Tab from input (or no clear button): close without selecting
1232
- component.hideBib();
1233
- return;
1234
- }
1249
+ const clearBtn = getClearBtn(ctx);
1250
+ const clearBtnHasFocus = isClearBtnFocused(ctx, clearBtn);
1235
1251
 
1236
1252
  // Tab from input: if clear button exists and doesn't have focus, focus it
1237
1253
  if (clearBtn && !clearBtnHasFocus && ctx.activeInput.value) {
@@ -1270,29 +1286,41 @@ const comboboxKeyboardStrategy = {
1270
1286
  return;
1271
1287
  }
1272
1288
 
1273
- // Non-fullscreen: select + close (Shift+Tab closes without selecting)
1274
- if (!evt.shiftKey && component.menu.optionActive && component.menu.optionActive.value) {
1289
+ // Non-fullscreen: select + close
1290
+ if (component.menu.optionActive && component.menu.optionActive.value) {
1275
1291
  component.menu.value = component.menu.optionActive.value;
1276
1292
  }
1277
1293
  component.hideBib();
1278
1294
  },
1279
1295
 
1280
- ArrowUp(component, evt) {
1296
+ ArrowUp(component, evt, ctx) {
1297
+ // If the clear button has focus, let the browser handle ArrowUp normally.
1298
+ if (isClearBtnFocused(ctx)) {
1299
+ return;
1300
+ }
1301
+
1281
1302
  if (component.availableOptions.length > 0) {
1282
1303
  component.showBib();
1283
1304
  }
1284
- // Check live visibility: showBib() above may have just opened the dropdown.
1305
+ // Read live visibility ctx.isExpanded was computed before showBib() above,
1306
+ // so it wouldn't reflect the state change.
1285
1307
  if (component.dropdown.isPopoverVisible) {
1286
1308
  evt.preventDefault();
1287
1309
  navigateArrow(component, 'up');
1288
1310
  }
1289
1311
  },
1290
1312
 
1291
- ArrowDown(component, evt) {
1313
+ ArrowDown(component, evt, ctx) {
1314
+ // If the clear button has focus, let the browser handle ArrowDown normally.
1315
+ if (isClearBtnFocused(ctx)) {
1316
+ return;
1317
+ }
1318
+
1292
1319
  if (component.availableOptions.length > 0) {
1293
1320
  component.showBib();
1294
1321
  }
1295
- // Check live visibility: showBib() above may have just opened the dropdown.
1322
+ // Read live visibility ctx.isExpanded was computed before showBib() above,
1323
+ // so it wouldn't reflect the state change.
1296
1324
  if (component.dropdown.isPopoverVisible) {
1297
1325
  evt.preventDefault();
1298
1326
  navigateArrow(component, 'down');
@@ -4864,7 +4892,7 @@ let AuroHelpText$2 = class AuroHelpText extends LitElement {
4864
4892
  }
4865
4893
  };
4866
4894
 
4867
- var formkitVersion$2 = '202603181736';
4895
+ var formkitVersion$2 = '202603192334';
4868
4896
 
4869
4897
  let AuroElement$2 = class AuroElement extends LitElement {
4870
4898
  static get properties() {
@@ -12612,7 +12640,7 @@ let AuroHelpText$1 = class AuroHelpText extends LitElement {
12612
12640
  }
12613
12641
  };
12614
12642
 
12615
- var formkitVersion$1 = '202603181736';
12643
+ var formkitVersion$1 = '202603192334';
12616
12644
 
12617
12645
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
12618
12646
  // See LICENSE in the project root for license information.
@@ -13651,7 +13679,7 @@ class AuroBibtemplate extends LitElement {
13651
13679
  }
13652
13680
  }
13653
13681
 
13654
- var formkitVersion = '202603181736';
13682
+ var formkitVersion = '202603192334';
13655
13683
 
13656
13684
  var styleCss$1 = css`.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}`;
13657
13685
 
@@ -14508,6 +14536,13 @@ class AuroCombobox extends AuroElement {
14508
14536
 
14509
14537
  this.noMatchOption = undefined;
14510
14538
 
14539
+ // Remove trailing whitespace only when the input contains
14540
+ // non-whitespace characters, so residual spaces from cursor
14541
+ // editing don't break matching. Whitespace-only input is
14542
+ // preserved as-is so a lone space doesn't show all options.
14543
+ const raw = this.input.value || '';
14544
+ const filterValue = (raw.trim() ? raw.trimEnd() : raw).toLowerCase();
14545
+
14511
14546
  this.options.forEach((option) => {
14512
14547
  let matchString = option.textContent.toLowerCase();
14513
14548
 
@@ -14524,12 +14559,12 @@ class AuroCombobox extends AuroElement {
14524
14559
  }
14525
14560
 
14526
14561
  // If input is empty, show all options (except static ones)
14527
- if (!this.input.value || this.input.value.length === 0) {
14562
+ if (!filterValue) {
14528
14563
  if (!option.hasAttribute('static')) {
14529
14564
  option.removeAttribute('hidden');
14530
14565
  this.availableOptions.push(option);
14531
14566
  }
14532
- } else if (matchString.includes(this.input.value.toLowerCase()) && !option.hasAttribute('static')) {
14567
+ } else if (matchString.includes(filterValue) && !option.hasAttribute('static')) {
14533
14568
  // only count options that match the typed input value AND are not static
14534
14569
  option.removeAttribute('hidden');
14535
14570
  this.availableOptions.push(option);
@@ -14560,7 +14595,7 @@ class AuroCombobox extends AuroElement {
14560
14595
  syncValuesAndStates() {
14561
14596
  // Only sync matchWord, don't set menu.value here since setMenuValue should handle that
14562
14597
  if (this.menu) {
14563
- this.menu.matchWord = this.input.value;
14598
+ this.menu.matchWord = (this.input.value || '').trimEnd();
14564
14599
  }
14565
14600
  const label = this.menu.currentLabel;
14566
14601
  this.updateTriggerTextDisplay(label || this.value);
@@ -14924,8 +14959,9 @@ class AuroCombobox extends AuroElement {
14924
14959
  this.updateTriggerTextDisplay(event.detail.label || event.detail.value);
14925
14960
 
14926
14961
  // Update match word for filtering
14927
- if (this.menu.matchWord !== this.input.value) {
14928
- this.menu.matchWord = this.input.value;
14962
+ const trimmedInput = (this.input.value || '').trimEnd();
14963
+ if (this.menu.matchWord !== trimmedInput) {
14964
+ this.menu.matchWord = trimmedInput;
14929
14965
  }
14930
14966
 
14931
14967
  // Update available options based on selection
@@ -15063,7 +15099,7 @@ class AuroCombobox extends AuroElement {
15063
15099
  });
15064
15100
 
15065
15101
  // Run filtering inline — the re-entrant event won't reach this code.
15066
- this.menu.matchWord = this.inputInBib.value;
15102
+ this.menu.matchWord = (this.inputInBib.value || '').trimEnd();
15067
15103
  this.optionActive = null;
15068
15104
  this.handleMenuOptions();
15069
15105
  this.dispatchEvent(new CustomEvent('inputValue', { detail: { value: this.inputValue } }));
@@ -15077,7 +15113,7 @@ class AuroCombobox extends AuroElement {
15077
15113
 
15078
15114
  this.inputInBib.value = this.input.value;
15079
15115
 
15080
- this.menu.matchWord = this.input.value;
15116
+ this.menu.matchWord = (this.input.value || '').trimEnd();
15081
15117
  this.optionActive = null;
15082
15118
 
15083
15119
  if (!this.input.value) {
@@ -15291,7 +15327,7 @@ class AuroCombobox extends AuroElement {
15291
15327
 
15292
15328
  // Sync the input and match word, but don't directly set menu.value again
15293
15329
  if (this.menu) {
15294
- this.menu.matchWord = this.input.value;
15330
+ this.menu.matchWord = (this.input.value || '').trimEnd();
15295
15331
  }
15296
15332
 
15297
15333
  this.dispatchEvent(new CustomEvent('input', {
@@ -1470,7 +1470,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$2 {
1470
1470
  }
1471
1471
  };
1472
1472
 
1473
- var formkitVersion$1 = '202603181736';
1473
+ var formkitVersion$1 = '202603192334';
1474
1474
 
1475
1475
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
1476
1476
  // See LICENSE in the project root for license information.
@@ -5476,7 +5476,7 @@ class AuroHelpText extends i$2 {
5476
5476
  }
5477
5477
  }
5478
5478
 
5479
- var formkitVersion = '202603181736';
5479
+ var formkitVersion = '202603192334';
5480
5480
 
5481
5481
  let AuroElement$1 = class AuroElement extends i$2 {
5482
5482
  static get properties() {
@@ -1470,7 +1470,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$2 {
1470
1470
  }
1471
1471
  };
1472
1472
 
1473
- var formkitVersion$1 = '202603181736';
1473
+ var formkitVersion$1 = '202603192334';
1474
1474
 
1475
1475
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
1476
1476
  // See LICENSE in the project root for license information.
@@ -5476,7 +5476,7 @@ class AuroHelpText extends i$2 {
5476
5476
  }
5477
5477
  }
5478
5478
 
5479
- var formkitVersion = '202603181736';
5479
+ var formkitVersion = '202603192334';
5480
5480
 
5481
5481
  let AuroElement$1 = class AuroElement extends i$2 {
5482
5482
  static get properties() {