@aurodesignsystem-dev/auro-formkit 0.0.0-pr1346.7 → 0.0.0-pr1346.8

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 +154 -55
  6. package/components/combobox/demo/index.min.js +154 -55
  7. package/components/combobox/dist/auro-combobox.d.ts +1 -0
  8. package/components/combobox/dist/comboboxKeyboardStrategy.d.ts +6 -0
  9. package/components/combobox/dist/index.js +154 -55
  10. package/components/combobox/dist/registered.js +154 -55
  11. package/components/counter/demo/api.min.js +6 -2
  12. package/components/counter/demo/index.min.js +6 -2
  13. package/components/counter/dist/index.js +6 -2
  14. package/components/counter/dist/registered.js +6 -2
  15. package/components/datepicker/demo/api.min.js +7 -3
  16. package/components/datepicker/demo/index.min.js +7 -3
  17. package/components/datepicker/dist/index.js +7 -3
  18. package/components/datepicker/dist/registered.js +7 -3
  19. package/components/dropdown/demo/api.min.js +5 -1
  20. package/components/dropdown/demo/index.min.js +5 -1
  21. package/components/dropdown/dist/index.js +5 -1
  22. package/components/dropdown/dist/keyboardUtils.d.ts +18 -0
  23. package/components/dropdown/dist/registered.js +5 -1
  24. package/components/form/demo/api.min.js +242 -120
  25. package/components/form/demo/index.min.js +242 -120
  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 +72 -57
  35. package/components/select/demo/index.min.js +72 -57
  36. package/components/select/dist/index.js +72 -57
  37. package/components/select/dist/registered.js +72 -57
  38. package/components/select/dist/selectKeyboardStrategy.d.ts +8 -0
  39. package/custom-elements.json +1508 -1385
  40. package/package.json +1 -1
@@ -1687,7 +1687,7 @@ class AuroHelpText extends i$2 {
1687
1687
  }
1688
1688
  }
1689
1689
 
1690
- var formkitVersion = '202603022150';
1690
+ var formkitVersion = '202603031728';
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 = '202603022150';
1682
+ var formkitVersion = '202603031728';
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 = '202603022150';
1635
+ var formkitVersion = '202603031728';
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 = '202603022150';
1635
+ var formkitVersion = '202603031728';
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.
@@ -1115,6 +1115,127 @@ let AuroFormValidation$1 = class AuroFormValidation {
1115
1115
  }
1116
1116
  };
1117
1117
 
1118
+ /**
1119
+ * Wires up a keydown listener that dispatches to strategy[evt.key] or strategy.default.
1120
+ * Handles both sync and async handlers.
1121
+ * @param {HTMLElement} component - The component to attach the listener to.
1122
+ * @param {Object} strategy - Map of key names to handler functions.
1123
+ */
1124
+ function applyKeyboardStrategy(component, strategy) {
1125
+ component.addEventListener('keydown', async (evt) => {
1126
+ const handler = strategy[evt.key] || strategy.default;
1127
+ if (handler) {
1128
+ await handler(component, evt);
1129
+ }
1130
+ });
1131
+ }
1132
+
1133
+ /**
1134
+ * Shared arrow navigation. Calls menu.navigateOptions(direction) if visible.
1135
+ * Optionally opens dropdown via showFn when closed.
1136
+ * @param {HTMLElement} component - The component with dropdown and menu references.
1137
+ * @param {string} direction - 'up' or 'down'.
1138
+ * @param {Object} [options] - Optional config.
1139
+ * @param {Function} [options.showFn] - Called to open the dropdown when closed.
1140
+ */
1141
+ function navigateArrow(component, direction, options = {}) {
1142
+ if (component.dropdown.isPopoverVisible) {
1143
+ component.menu.navigateOptions(direction);
1144
+ } else if (options.showFn) {
1145
+ options.showFn();
1146
+ }
1147
+ }
1148
+
1149
+ const comboboxKeyboardStrategy = {
1150
+ async Enter(component, evt) {
1151
+ if (component.dropdown.isPopoverVisible && component.optionActive) {
1152
+ component.menu.makeSelection();
1153
+ await component.updateComplete;
1154
+ evt.preventDefault();
1155
+ evt.stopPropagation();
1156
+ component.setClearBtnFocus();
1157
+ } else {
1158
+ component.showBib();
1159
+ }
1160
+ },
1161
+
1162
+ Tab(component) {
1163
+ if (!component.dropdown.isPopoverVisible) {
1164
+ return;
1165
+ }
1166
+
1167
+ if (component.dropdown.isBibFullscreen) {
1168
+ const clearBtn = component.inputInBib.shadowRoot.querySelector('.clearBtn');
1169
+
1170
+ // Use shadowRoot.activeElement to detect focus inside auro-button,
1171
+ // since Safari does not propagate :focus-within through shadow DOM.
1172
+ const clearBtnHasFocus = clearBtn && clearBtn.shadowRoot && clearBtn.shadowRoot.activeElement !== null;
1173
+
1174
+ // Tab from input: if clear button exists and doesn't have focus, focus it
1175
+ if (clearBtn && !clearBtnHasFocus && component.inputInBib.value) {
1176
+ // Force clear button container visible to work around Safari not
1177
+ // propagating :focus-within through shadow DOM boundaries, which
1178
+ // causes .wrapper:not(:focus-within) to hide .notification.clear.
1179
+ const clearContainer = clearBtn.closest('.clear');
1180
+ if (clearContainer) {
1181
+ clearContainer.style.display = 'flex';
1182
+ clearBtn.addEventListener('focusout', () => {
1183
+ // Delay cleanup so :focus-within settles when focus moves
1184
+ // to a sibling (e.g., Shift+Tab back to the input).
1185
+ requestAnimationFrame(() => {
1186
+ clearContainer.style.display = '';
1187
+ });
1188
+ }, { once: true });
1189
+ }
1190
+
1191
+ // Focus the native button inside auro-button so the browser
1192
+ // treats it as a real focusable element inside the dialog.
1193
+ const nativeBtn = clearBtn.shadowRoot && clearBtn.shadowRoot.querySelector('button');
1194
+ if (nativeBtn) {
1195
+ nativeBtn.focus();
1196
+ } else {
1197
+ clearBtn.focus();
1198
+ }
1199
+ return;
1200
+ }
1201
+
1202
+ // Tab from clear button (or no clear button / no value) →
1203
+ // select the highlighted option if any, then close
1204
+ if (component.optionActive) {
1205
+ component.menu.makeSelection();
1206
+ }
1207
+ component.hideBib();
1208
+ return;
1209
+ }
1210
+
1211
+ // Non-fullscreen: select + close
1212
+ if (component.menu.optionActive && component.menu.optionActive.value) {
1213
+ component.menu.value = component.menu.optionActive.value;
1214
+ }
1215
+ component.hideBib();
1216
+ },
1217
+
1218
+ ArrowUp(component, evt) {
1219
+ if (component.availableOptions.length > 0) {
1220
+ component.showBib();
1221
+ }
1222
+ if (component.dropdown.isPopoverVisible) {
1223
+ evt.preventDefault();
1224
+ navigateArrow(component, 'up');
1225
+ }
1226
+ },
1227
+
1228
+ ArrowDown(component, evt) {
1229
+ if (component.availableOptions.length > 0) {
1230
+ component.showBib();
1231
+ }
1232
+ if (component.dropdown.isPopoverVisible) {
1233
+ evt.preventDefault();
1234
+ navigateArrow(component, 'down');
1235
+ }
1236
+ },
1237
+ };
1238
+
1118
1239
  /**
1119
1240
  * @license
1120
1241
  * Copyright 2020 Google LLC
@@ -4202,6 +4323,10 @@ class AuroDropdownBib extends i$4 {
4202
4323
  const newEvent = new KeyboardEvent('keydown', {
4203
4324
  key: event.key,
4204
4325
  code: event.code,
4326
+ shiftKey: event.shiftKey,
4327
+ altKey: event.altKey,
4328
+ ctrlKey: event.ctrlKey,
4329
+ metaKey: event.metaKey,
4205
4330
  bubbles: true,
4206
4331
  composed: true,
4207
4332
  cancelable: true
@@ -4568,7 +4693,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$4 {
4568
4693
  }
4569
4694
  };
4570
4695
 
4571
- var formkitVersion$2 = '202603022150';
4696
+ var formkitVersion$2 = '202603031728';
4572
4697
 
4573
4698
  let AuroElement$2 = class AuroElement extends i$4 {
4574
4699
  static get properties() {
@@ -12310,7 +12435,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$4 {
12310
12435
  }
12311
12436
  };
12312
12437
 
12313
- var formkitVersion$1 = '202603022150';
12438
+ var formkitVersion$1 = '202603031728';
12314
12439
 
12315
12440
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
12316
12441
  // See LICENSE in the project root for license information.
@@ -13337,7 +13462,7 @@ class AuroBibtemplate extends i$4 {
13337
13462
  }
13338
13463
  }
13339
13464
 
13340
- var formkitVersion = '202603022150';
13465
+ var formkitVersion = '202603031728';
13341
13466
 
13342
13467
  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}`;
13343
13468
 
@@ -14779,8 +14904,33 @@ class AuroCombobox extends AuroElement {
14779
14904
  * @returns {void}
14780
14905
  */
14781
14906
  handleInputValueChange(event) {
14907
+ // When the event comes from the fullscreen bib input, sync the value to
14908
+ // the trigger input. Setting trigger.value triggers Lit's updated()
14909
+ // (async, microtask) which fires notifyValueChanged() → another 'input'
14910
+ // event from the trigger. The _syncingBibValue guard persists across the
14911
+ // async boundary and prevents that re-entrant event from running the
14912
+ // non-fullscreen path (which would call clear() → hideBib()).
14913
+ // When the event comes from the fullscreen bib input, sync the value to
14914
+ // the trigger and run filtering, but suppress the re-entrant input event
14915
+ // that the trigger fires (via Lit updated() → notifyValueChanged()) so
14916
+ // the non-fullscreen hide/clear logic doesn't close the dialog.
14782
14917
  if (event.target === this.inputInBib) {
14918
+ this._syncingBibValue = true;
14783
14919
  this.input.value = this.inputInBib.value;
14920
+ this.input.updateComplete.then(() => {
14921
+ this._syncingBibValue = false;
14922
+ });
14923
+
14924
+ // Run filtering inline — the re-entrant event won't reach this code.
14925
+ this.menu.matchWord = this.inputInBib.value;
14926
+ this.optionActive = null;
14927
+ this.handleMenuOptions();
14928
+ this.dispatchEvent(new CustomEvent('inputValue', { detail: { value: this.inputValue } }));
14929
+ return;
14930
+ }
14931
+
14932
+ // Ignore re-entrant input events caused by the bib→trigger sync above.
14933
+ if (this._syncingBibValue) {
14784
14934
  return;
14785
14935
  }
14786
14936
 
@@ -14838,58 +14988,7 @@ class AuroCombobox extends AuroElement {
14838
14988
  * @returns {void}
14839
14989
  */
14840
14990
  configureCombobox() {
14841
- this.addEventListener('keydown', async (evt) => {
14842
- if (evt.key === 'Enter') {
14843
- if (this.dropdown.isPopoverVisible && this.optionActive) {
14844
- this.menu.makeSelection();
14845
-
14846
- await this.updateComplete;
14847
-
14848
- evt.preventDefault();
14849
- evt.stopPropagation();
14850
- this.setClearBtnFocus();
14851
- } else {
14852
- this.showBib();
14853
- }
14854
- }
14855
-
14856
- if (evt.key === 'Tab' && this.dropdown.isPopoverVisible) {
14857
- // Tab accepts the focused option and closes the popup per the
14858
- // WAI-ARIA APG combobox / listbox pattern.
14859
- // https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-select-only/
14860
- //
14861
- // In fullscreen mode the popup is inside a <dialog> which provides
14862
- // containment (inert background, VoiceOver focus trapping), but
14863
- // the content is a role="listbox" navigated via
14864
- // aria-activedescendant, not Tab focus. The dialog's native Tab
14865
- // trap only reaches the close button, so Tab is overridden (via
14866
- // re-dispatch from auro-dropdownBib) to follow listbox keyboard
14867
- // conventions in both modes.
14868
- if (this.menu.optionActive && this.menu.optionActive.value) {
14869
- this.menu.value = this.menu.optionActive.value;
14870
- }
14871
- this.hideBib();
14872
- }
14873
-
14874
- /**
14875
- * Prevent moving the cursor position while navigating the menu options.
14876
- */
14877
- if (evt.key === 'ArrowUp' || evt.key === 'ArrowDown') {
14878
- if (this.availableOptions.length > 0) {
14879
- this.showBib();
14880
- }
14881
-
14882
- if (this.dropdown.isPopoverVisible) {
14883
- evt.preventDefault();
14884
-
14885
- // navigate on menu only when the focus is on input
14886
- if (!this.dropdown.isBibFullscreen || this.dropdown.isPopoverVisible) {
14887
- const direction = evt.key.replace('Arrow', '').toLowerCase();
14888
- this.menu.navigateOptions(direction);
14889
- }
14890
- }
14891
- }
14892
- });
14991
+ applyKeyboardStrategy(this, comboboxKeyboardStrategy);
14893
14992
 
14894
14993
  this.addEventListener('focusin', () => {
14895
14994
  this.touched = true;
@@ -1038,6 +1038,127 @@ let AuroFormValidation$1 = class AuroFormValidation {
1038
1038
  }
1039
1039
  };
1040
1040
 
1041
+ /**
1042
+ * Wires up a keydown listener that dispatches to strategy[evt.key] or strategy.default.
1043
+ * Handles both sync and async handlers.
1044
+ * @param {HTMLElement} component - The component to attach the listener to.
1045
+ * @param {Object} strategy - Map of key names to handler functions.
1046
+ */
1047
+ function applyKeyboardStrategy(component, strategy) {
1048
+ component.addEventListener('keydown', async (evt) => {
1049
+ const handler = strategy[evt.key] || strategy.default;
1050
+ if (handler) {
1051
+ await handler(component, evt);
1052
+ }
1053
+ });
1054
+ }
1055
+
1056
+ /**
1057
+ * Shared arrow navigation. Calls menu.navigateOptions(direction) if visible.
1058
+ * Optionally opens dropdown via showFn when closed.
1059
+ * @param {HTMLElement} component - The component with dropdown and menu references.
1060
+ * @param {string} direction - 'up' or 'down'.
1061
+ * @param {Object} [options] - Optional config.
1062
+ * @param {Function} [options.showFn] - Called to open the dropdown when closed.
1063
+ */
1064
+ function navigateArrow(component, direction, options = {}) {
1065
+ if (component.dropdown.isPopoverVisible) {
1066
+ component.menu.navigateOptions(direction);
1067
+ } else if (options.showFn) {
1068
+ options.showFn();
1069
+ }
1070
+ }
1071
+
1072
+ const comboboxKeyboardStrategy = {
1073
+ async Enter(component, evt) {
1074
+ if (component.dropdown.isPopoverVisible && component.optionActive) {
1075
+ component.menu.makeSelection();
1076
+ await component.updateComplete;
1077
+ evt.preventDefault();
1078
+ evt.stopPropagation();
1079
+ component.setClearBtnFocus();
1080
+ } else {
1081
+ component.showBib();
1082
+ }
1083
+ },
1084
+
1085
+ Tab(component) {
1086
+ if (!component.dropdown.isPopoverVisible) {
1087
+ return;
1088
+ }
1089
+
1090
+ if (component.dropdown.isBibFullscreen) {
1091
+ const clearBtn = component.inputInBib.shadowRoot.querySelector('.clearBtn');
1092
+
1093
+ // Use shadowRoot.activeElement to detect focus inside auro-button,
1094
+ // since Safari does not propagate :focus-within through shadow DOM.
1095
+ const clearBtnHasFocus = clearBtn && clearBtn.shadowRoot && clearBtn.shadowRoot.activeElement !== null;
1096
+
1097
+ // Tab from input: if clear button exists and doesn't have focus, focus it
1098
+ if (clearBtn && !clearBtnHasFocus && component.inputInBib.value) {
1099
+ // Force clear button container visible to work around Safari not
1100
+ // propagating :focus-within through shadow DOM boundaries, which
1101
+ // causes .wrapper:not(:focus-within) to hide .notification.clear.
1102
+ const clearContainer = clearBtn.closest('.clear');
1103
+ if (clearContainer) {
1104
+ clearContainer.style.display = 'flex';
1105
+ clearBtn.addEventListener('focusout', () => {
1106
+ // Delay cleanup so :focus-within settles when focus moves
1107
+ // to a sibling (e.g., Shift+Tab back to the input).
1108
+ requestAnimationFrame(() => {
1109
+ clearContainer.style.display = '';
1110
+ });
1111
+ }, { once: true });
1112
+ }
1113
+
1114
+ // Focus the native button inside auro-button so the browser
1115
+ // treats it as a real focusable element inside the dialog.
1116
+ const nativeBtn = clearBtn.shadowRoot && clearBtn.shadowRoot.querySelector('button');
1117
+ if (nativeBtn) {
1118
+ nativeBtn.focus();
1119
+ } else {
1120
+ clearBtn.focus();
1121
+ }
1122
+ return;
1123
+ }
1124
+
1125
+ // Tab from clear button (or no clear button / no value) →
1126
+ // select the highlighted option if any, then close
1127
+ if (component.optionActive) {
1128
+ component.menu.makeSelection();
1129
+ }
1130
+ component.hideBib();
1131
+ return;
1132
+ }
1133
+
1134
+ // Non-fullscreen: select + close
1135
+ if (component.menu.optionActive && component.menu.optionActive.value) {
1136
+ component.menu.value = component.menu.optionActive.value;
1137
+ }
1138
+ component.hideBib();
1139
+ },
1140
+
1141
+ ArrowUp(component, evt) {
1142
+ if (component.availableOptions.length > 0) {
1143
+ component.showBib();
1144
+ }
1145
+ if (component.dropdown.isPopoverVisible) {
1146
+ evt.preventDefault();
1147
+ navigateArrow(component, 'up');
1148
+ }
1149
+ },
1150
+
1151
+ ArrowDown(component, evt) {
1152
+ if (component.availableOptions.length > 0) {
1153
+ component.showBib();
1154
+ }
1155
+ if (component.dropdown.isPopoverVisible) {
1156
+ evt.preventDefault();
1157
+ navigateArrow(component, 'down');
1158
+ }
1159
+ },
1160
+ };
1161
+
1041
1162
  /**
1042
1163
  * @license
1043
1164
  * Copyright 2020 Google LLC
@@ -4125,6 +4246,10 @@ class AuroDropdownBib extends i$4 {
4125
4246
  const newEvent = new KeyboardEvent('keydown', {
4126
4247
  key: event.key,
4127
4248
  code: event.code,
4249
+ shiftKey: event.shiftKey,
4250
+ altKey: event.altKey,
4251
+ ctrlKey: event.ctrlKey,
4252
+ metaKey: event.metaKey,
4128
4253
  bubbles: true,
4129
4254
  composed: true,
4130
4255
  cancelable: true
@@ -4491,7 +4616,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$4 {
4491
4616
  }
4492
4617
  };
4493
4618
 
4494
- var formkitVersion$2 = '202603022150';
4619
+ var formkitVersion$2 = '202603031728';
4495
4620
 
4496
4621
  let AuroElement$2 = class AuroElement extends i$4 {
4497
4622
  static get properties() {
@@ -12233,7 +12358,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$4 {
12233
12358
  }
12234
12359
  };
12235
12360
 
12236
- var formkitVersion$1 = '202603022150';
12361
+ var formkitVersion$1 = '202603031728';
12237
12362
 
12238
12363
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
12239
12364
  // See LICENSE in the project root for license information.
@@ -13260,7 +13385,7 @@ class AuroBibtemplate extends i$4 {
13260
13385
  }
13261
13386
  }
13262
13387
 
13263
- var formkitVersion = '202603022150';
13388
+ var formkitVersion = '202603031728';
13264
13389
 
13265
13390
  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}`;
13266
13391
 
@@ -14702,8 +14827,33 @@ class AuroCombobox extends AuroElement {
14702
14827
  * @returns {void}
14703
14828
  */
14704
14829
  handleInputValueChange(event) {
14830
+ // When the event comes from the fullscreen bib input, sync the value to
14831
+ // the trigger input. Setting trigger.value triggers Lit's updated()
14832
+ // (async, microtask) which fires notifyValueChanged() → another 'input'
14833
+ // event from the trigger. The _syncingBibValue guard persists across the
14834
+ // async boundary and prevents that re-entrant event from running the
14835
+ // non-fullscreen path (which would call clear() → hideBib()).
14836
+ // When the event comes from the fullscreen bib input, sync the value to
14837
+ // the trigger and run filtering, but suppress the re-entrant input event
14838
+ // that the trigger fires (via Lit updated() → notifyValueChanged()) so
14839
+ // the non-fullscreen hide/clear logic doesn't close the dialog.
14705
14840
  if (event.target === this.inputInBib) {
14841
+ this._syncingBibValue = true;
14706
14842
  this.input.value = this.inputInBib.value;
14843
+ this.input.updateComplete.then(() => {
14844
+ this._syncingBibValue = false;
14845
+ });
14846
+
14847
+ // Run filtering inline — the re-entrant event won't reach this code.
14848
+ this.menu.matchWord = this.inputInBib.value;
14849
+ this.optionActive = null;
14850
+ this.handleMenuOptions();
14851
+ this.dispatchEvent(new CustomEvent('inputValue', { detail: { value: this.inputValue } }));
14852
+ return;
14853
+ }
14854
+
14855
+ // Ignore re-entrant input events caused by the bib→trigger sync above.
14856
+ if (this._syncingBibValue) {
14707
14857
  return;
14708
14858
  }
14709
14859
 
@@ -14761,58 +14911,7 @@ class AuroCombobox extends AuroElement {
14761
14911
  * @returns {void}
14762
14912
  */
14763
14913
  configureCombobox() {
14764
- this.addEventListener('keydown', async (evt) => {
14765
- if (evt.key === 'Enter') {
14766
- if (this.dropdown.isPopoverVisible && this.optionActive) {
14767
- this.menu.makeSelection();
14768
-
14769
- await this.updateComplete;
14770
-
14771
- evt.preventDefault();
14772
- evt.stopPropagation();
14773
- this.setClearBtnFocus();
14774
- } else {
14775
- this.showBib();
14776
- }
14777
- }
14778
-
14779
- if (evt.key === 'Tab' && this.dropdown.isPopoverVisible) {
14780
- // Tab accepts the focused option and closes the popup per the
14781
- // WAI-ARIA APG combobox / listbox pattern.
14782
- // https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-select-only/
14783
- //
14784
- // In fullscreen mode the popup is inside a <dialog> which provides
14785
- // containment (inert background, VoiceOver focus trapping), but
14786
- // the content is a role="listbox" navigated via
14787
- // aria-activedescendant, not Tab focus. The dialog's native Tab
14788
- // trap only reaches the close button, so Tab is overridden (via
14789
- // re-dispatch from auro-dropdownBib) to follow listbox keyboard
14790
- // conventions in both modes.
14791
- if (this.menu.optionActive && this.menu.optionActive.value) {
14792
- this.menu.value = this.menu.optionActive.value;
14793
- }
14794
- this.hideBib();
14795
- }
14796
-
14797
- /**
14798
- * Prevent moving the cursor position while navigating the menu options.
14799
- */
14800
- if (evt.key === 'ArrowUp' || evt.key === 'ArrowDown') {
14801
- if (this.availableOptions.length > 0) {
14802
- this.showBib();
14803
- }
14804
-
14805
- if (this.dropdown.isPopoverVisible) {
14806
- evt.preventDefault();
14807
-
14808
- // navigate on menu only when the focus is on input
14809
- if (!this.dropdown.isBibFullscreen || this.dropdown.isPopoverVisible) {
14810
- const direction = evt.key.replace('Arrow', '').toLowerCase();
14811
- this.menu.navigateOptions(direction);
14812
- }
14813
- }
14814
- }
14815
- });
14914
+ applyKeyboardStrategy(this, comboboxKeyboardStrategy);
14816
14915
 
14817
14916
  this.addEventListener('focusin', () => {
14818
14917
  this.touched = true;
@@ -492,6 +492,7 @@ export class AuroCombobox extends AuroElement {
492
492
  * @returns {void}
493
493
  */
494
494
  private handleInputValueChange;
495
+ _syncingBibValue: boolean;
495
496
  /**
496
497
  * Binds all behavior needed to the combobox after rendering.
497
498
  * @private
@@ -0,0 +1,6 @@
1
+ export namespace comboboxKeyboardStrategy {
2
+ function Enter(component: any, evt: any): Promise<void>;
3
+ function Tab(component: any): void;
4
+ function ArrowUp(component: any, evt: any): void;
5
+ function ArrowDown(component: any, evt: any): void;
6
+ }