@aurodesignsystem-dev/auro-formkit 0.0.0-pr1400.0 → 0.0.0-pr1401.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 (38) 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 +142 -85
  6. package/components/combobox/demo/index.min.js +142 -85
  7. package/components/combobox/dist/auro-combobox.d.ts +2 -1
  8. package/components/combobox/dist/comboboxKeyboardStrategy.d.ts +1 -1
  9. package/components/combobox/dist/index.js +142 -85
  10. package/components/combobox/dist/registered.js +142 -85
  11. package/components/counter/demo/api.min.js +3 -2
  12. package/components/counter/demo/index.min.js +3 -2
  13. package/components/counter/dist/index.js +3 -2
  14. package/components/counter/dist/registered.js +3 -2
  15. package/components/datepicker/demo/api.min.js +7 -21
  16. package/components/datepicker/demo/index.min.js +7 -21
  17. package/components/datepicker/dist/index.js +7 -21
  18. package/components/datepicker/dist/registered.js +7 -21
  19. package/components/dropdown/demo/api.min.js +2 -1
  20. package/components/dropdown/demo/index.min.js +2 -1
  21. package/components/dropdown/dist/index.js +2 -1
  22. package/components/dropdown/dist/registered.js +2 -1
  23. package/components/form/demo/api.min.js +172 -133
  24. package/components/form/demo/index.min.js +172 -133
  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/radio/demo/api.min.js +1 -1
  30. package/components/radio/demo/index.min.js +1 -1
  31. package/components/radio/dist/index.js +1 -1
  32. package/components/radio/dist/registered.js +1 -1
  33. package/components/select/demo/api.min.js +17 -22
  34. package/components/select/demo/index.min.js +17 -22
  35. package/components/select/dist/index.js +17 -22
  36. package/components/select/dist/registered.js +17 -22
  37. package/custom-elements.json +1405 -1405
  38. package/package.json +1 -1
@@ -1687,7 +1687,7 @@ class AuroHelpText extends i$2 {
1687
1687
  }
1688
1688
  }
1689
1689
 
1690
- var formkitVersion = '202603262115';
1690
+ var formkitVersion = '202603262341';
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 = '202603262115';
1682
+ var formkitVersion = '202603262341';
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 = '202603262115';
1635
+ var formkitVersion = '202603262341';
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 = '202603262115';
1635
+ var formkitVersion = '202603262341';
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.
@@ -1214,33 +1214,13 @@ function guardTouchPassthrough(element) {
1214
1214
  *
1215
1215
  * @param {HTMLElement} dropdown - The `auro-dropdown` element.
1216
1216
  * @param {HTMLElement} focusTarget - The element to focus (e.g. trigger or input).
1217
- * @param {Function} [onAfterRestore] - Optional callback invoked instead of focusing
1218
- * `focusTarget`. Use when the caller needs a custom post-close focus target while
1219
- * still delegating all trigger-restoration cleanup to this function.
1220
- * When provided, `inert` removal is deferred to inside the rAF so that
1221
- * `dialog.close()`'s synchronous focus restoration (which runs in a Lit
1222
- * microtask before the rAF) cannot move focus back to the trigger and
1223
- * trigger a spurious VoiceOver announcement before the callback's custom
1224
- * focus target takes over.
1225
1217
  */
1226
- function restoreTriggerAfterClose(dropdown, focusTarget, onAfterRestore) {
1227
- // Default path: clear inert immediately so the trigger is focusable when
1228
- // the rAF fires. With no callback there is no custom focus target, so
1229
- // dialog.close() restoring focus to the trigger is fine.
1230
- if (!onAfterRestore) {
1231
- dropdown.trigger.inert = false;
1232
- }
1218
+ function restoreTriggerAfterClose(dropdown, focusTarget) {
1219
+ dropdown.trigger.inert = false;
1233
1220
 
1234
1221
  requestAnimationFrame(() => {
1235
1222
  if (!dropdown.isPopoverVisible) {
1236
- if (typeof onAfterRestore === 'function') {
1237
- // Defer inert removal to here so dialog.close() (microtask) cannot
1238
- // restore focus to the trigger before the callback's target takes over.
1239
- dropdown.trigger.inert = false;
1240
- onAfterRestore();
1241
- } else {
1242
- focusTarget.focus();
1243
- }
1223
+ focusTarget.focus();
1244
1224
  }
1245
1225
  });
1246
1226
  }
@@ -1322,7 +1302,6 @@ function navigateArrow(component, direction, options = {}) {
1322
1302
 
1323
1303
  /* eslint-disable no-underscore-dangle */
1324
1304
 
1325
-
1326
1305
  /**
1327
1306
  * Returns the clear button element from the active input's shadow
1328
1307
  * DOM, if available.
@@ -1353,7 +1332,7 @@ function isClearBtnFocused(ctx, clearBtn = getClearBtn(ctx)) {
1353
1332
  }
1354
1333
 
1355
1334
  const comboboxKeyboardStrategy = {
1356
- Enter(component, evt, ctx) {
1335
+ async Enter(component, evt, ctx) {
1357
1336
  // If the clear button has focus, let the browser activate it normally.
1358
1337
  // stopPropagation prevents parent containers (e.g., forms) from treating
1359
1338
  // Enter as a submit, but we must NOT call preventDefault — that would
@@ -1364,10 +1343,11 @@ const comboboxKeyboardStrategy = {
1364
1343
  }
1365
1344
 
1366
1345
  if (ctx.isExpanded && component.optionActive) {
1346
+ component.menu.makeSelection();
1347
+ await component.updateComplete;
1367
1348
  evt.preventDefault();
1368
1349
  evt.stopPropagation();
1369
- component._pendingClearBtnFocus = true;
1370
- component.menu.makeSelection();
1350
+ component.setClearBtnFocus();
1371
1351
  } else {
1372
1352
  // Prevent the keypress from bubbling to parent containers (e.g., forms)
1373
1353
  // which could interpret Enter as a submit or trigger other unintended behavior.
@@ -1395,16 +1375,67 @@ const comboboxKeyboardStrategy = {
1395
1375
  return;
1396
1376
  }
1397
1377
 
1378
+ if (ctx.isModal) {
1379
+ if (!ctx.activeInput) {
1380
+ return;
1381
+ }
1382
+
1383
+ // Active option → select immediately and close the dialog.
1384
+ // Flag the component so the close handler focuses the trigger's
1385
+ // clear button instead of the input. Set flags before makeSelection
1386
+ // because the value change triggers showBib via Lit's updated().
1387
+ if (component.optionActive) {
1388
+ evt.preventDefault();
1389
+ component._focusClearBtnAfterClose = true;
1390
+ component._clearBtnFocusPending = true;
1391
+ component.menu.makeSelection();
1392
+ component.hideBib();
1393
+ return;
1394
+ }
1395
+
1396
+ const clearBtn = getClearBtn(ctx);
1397
+ const clearBtnHasFocus = isClearBtnFocused(ctx, clearBtn);
1398
+
1399
+ // No active option, input has a value, clear button not focused →
1400
+ // move focus to the dialog's clear button.
1401
+ if (clearBtn && !clearBtnHasFocus && ctx.activeInput.value) {
1402
+ // Force clear button container visible to work around Safari not
1403
+ // propagating :focus-within through shadow DOM boundaries, which
1404
+ // causes .wrapper:not(:focus-within) to hide .notification.clear.
1405
+ const clearContainer = clearBtn.closest('.clear');
1406
+ if (clearContainer) {
1407
+ clearContainer.style.display = 'flex';
1408
+ clearBtn.addEventListener('focusout', () => {
1409
+ // Delay cleanup so :focus-within settles when focus moves
1410
+ // to a sibling (e.g., Shift+Tab back to the input).
1411
+ requestAnimationFrame(() => {
1412
+ clearContainer.style.display = '';
1413
+ });
1414
+ }, { once: true });
1415
+ }
1416
+
1417
+ // Focus the native button inside auro-button so the browser
1418
+ // treats it as a real focusable element inside the dialog.
1419
+ const nativeBtn = clearBtn.shadowRoot && clearBtn.shadowRoot.querySelector('button');
1420
+ if (nativeBtn) {
1421
+ nativeBtn.focus();
1422
+ } else {
1423
+ clearBtn.focus();
1424
+ }
1425
+ return;
1426
+ }
1427
+
1428
+ // No active option, no clear button (or already focused) → just close.
1429
+ component.hideBib();
1430
+ return;
1431
+ }
1432
+
1433
+ // Non-fullscreen: select + close
1398
1434
  if (component.optionActive) {
1399
1435
  evt.preventDefault();
1400
- component._pendingClearBtnFocus = true;
1436
+ component._focusClearBtnAfterClose = true;
1437
+ component._clearBtnFocusPending = true;
1401
1438
  component.menu.makeSelection();
1402
- // Do NOT call hideBib() here — makeSelection() defers it via
1403
- // auroMenu-selectedOption's setTimeout(hideBib). Calling hideBib()
1404
- // synchronously sets isPopoverVisible=false, causing
1405
- // handleInputValueChange's Lit microtask to call showBib() (iOS guard),
1406
- // re-opening the dialog and trapping focus before setClearBtnFocus fires.
1407
- return;
1408
1439
  }
1409
1440
  component.hideBib();
1410
1441
  },
@@ -4807,6 +4838,7 @@ class AuroDropdownBib extends i$4 {
4807
4838
  return u$7`
4808
4839
  <dialog class="${e$3(classes)}" part="bibContainer" role="${o(this.dialogRole)}" aria-labelledby="${o(this.dialogLabel ? 'dialogLabel' : undefined)}">
4809
4840
  ${this.dialogLabel ? u$7`<span id="dialogLabel" class="util_displayHiddenVisually">${this.dialogLabel}</span>` : ''}
4841
+ <span id="srAnnouncement" class="util_displayHiddenVisually" aria-live="polite" role="status"></span>
4810
4842
  <slot></slot>
4811
4843
  </dialog>
4812
4844
  `;
@@ -5055,7 +5087,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$4 {
5055
5087
  }
5056
5088
  };
5057
5089
 
5058
- var formkitVersion$2 = '202603262115';
5090
+ var formkitVersion$2 = '202603262341';
5059
5091
 
5060
5092
  let AuroElement$2 = class AuroElement extends i$4 {
5061
5093
  static get properties() {
@@ -12819,7 +12851,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$4 {
12819
12851
  }
12820
12852
  };
12821
12853
 
12822
- var formkitVersion$1 = '202603262115';
12854
+ var formkitVersion$1 = '202603262341';
12823
12855
 
12824
12856
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
12825
12857
  // See LICENSE in the project root for license information.
@@ -13858,7 +13890,7 @@ class AuroBibtemplate extends i$4 {
13858
13890
  }
13859
13891
  }
13860
13892
 
13861
- var formkitVersion = '202603262115';
13893
+ var formkitVersion = '202603262341';
13862
13894
 
13863
13895
  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}`;
13864
13896
 
@@ -14290,7 +14322,6 @@ class AuroCombobox extends AuroElement {
14290
14322
  this.dropdownOpen = false;
14291
14323
  this.triggerExpandedState = false;
14292
14324
  this._expandedTimeout = null;
14293
- this._pendingClearBtnFocus = false;
14294
14325
  this._inFullscreenTransition = false;
14295
14326
  this.errorMessage = null;
14296
14327
  this.isHiddenWhileLoading = false;
@@ -14869,6 +14900,12 @@ class AuroCombobox extends AuroElement {
14869
14900
  * @returns {void}
14870
14901
  */
14871
14902
  showBib() {
14903
+ // Suppress reopening the bib when a Tab selection is in progress —
14904
+ // the value change from makeSelection triggers availableOptions update
14905
+ // which calls showBib from updated(), but the bib should stay closed.
14906
+ if (this._clearBtnFocusPending) {
14907
+ return;
14908
+ }
14872
14909
  if (!this.input.value && !this.dropdown.isBibFullscreen) {
14873
14910
  this.dropdown.hide();
14874
14911
  return;
@@ -14924,6 +14961,11 @@ class AuroCombobox extends AuroElement {
14924
14961
  // Clear aria-activedescendant when dropdown closes
14925
14962
  if (!this.dropdownOpen && this.input) {
14926
14963
  this.input.setActiveDescendant(null);
14964
+ // Also clear on inputInBib since fullscreen mode sets
14965
+ // aria-activedescendant on both inputs.
14966
+ if (this.inputInBib) {
14967
+ this.inputInBib.setActiveDescendant(null);
14968
+ }
14927
14969
  this.optionActive = null;
14928
14970
 
14929
14971
  // Remove the highlighted state from all menu options so re-opening
@@ -14939,25 +14981,36 @@ class AuroCombobox extends AuroElement {
14939
14981
  // during fullscreen open to prevent touch pass-through.
14940
14982
  this.menu.style.pointerEvents = '';
14941
14983
 
14942
- if (this._pendingClearBtnFocus) {
14943
- this._pendingClearBtnFocus = false;
14944
-
14945
- // Delegate all trigger-restoration cleanup to restoreTriggerAfterClose
14946
- // (inert, and any future ARIA/tabindex work), but override the final
14947
- // focus target via the callback. setTimeout(0) inside the rAF ensures
14948
- // setClearBtnFocus() wins after all Lit update microtasks and the
14949
- // dialog.close() native focus restoration have fully settled.
14950
- restoreTriggerAfterClose(this.dropdown, this.input, () => {
14951
- setTimeout(() => {
14952
- // Only move focus to the clear button if this component is still
14953
- // connected and the dropdown has not been reopened in the meantime.
14954
- if (!this.isConnected || this.dropdownOpen) {
14955
- return;
14956
- }
14984
+ const shouldFocusClearBtn = this._focusClearBtnAfterClose;
14985
+ this._focusClearBtnAfterClose = false;
14986
+
14987
+ if (shouldFocusClearBtn) {
14988
+ // Set a guard so duplicate toggle events don't call
14989
+ // restoreTriggerAfterClose and steal focus from the clear button.
14990
+ this._clearBtnFocusPending = true;
14991
+
14992
+ restoreTriggerAfterClose(this.dropdown, this.input);
14993
+
14994
+ if (this.input.componentHasFocus) {
14995
+ // Desktop: input already has focus, redirect to clear button
14996
+ // after restoreTriggerAfterClose's rAF settles.
14997
+ requestAnimationFrame(() => {
14957
14998
  this.setClearBtnFocus();
14958
- }, 0);
14959
- });
14960
- } else {
14999
+ this._clearBtnFocusPending = false;
15000
+ });
15001
+ } else {
15002
+ // Fullscreen: input will receive focus after dialog.close().
15003
+ // Listen for that focus event then redirect to clear button.
15004
+ const onFocus = () => {
15005
+ this.input.removeEventListener('focusin', onFocus);
15006
+ requestAnimationFrame(() => {
15007
+ this.setClearBtnFocus();
15008
+ this._clearBtnFocusPending = false;
15009
+ });
15010
+ };
15011
+ this.input.addEventListener('focusin', onFocus);
15012
+ }
15013
+ } else if (!this._clearBtnFocusPending) {
14961
15014
  restoreTriggerAfterClose(this.dropdown, this.input);
14962
15015
  }
14963
15016
  }
@@ -15049,40 +15102,27 @@ class AuroCombobox extends AuroElement {
15049
15102
  */
15050
15103
  setClearBtnFocus() {
15051
15104
  const clearBtn = this.input.shadowRoot.querySelector('.clearBtn');
15052
- if (!clearBtn) {
15053
- return;
15054
- }
15055
-
15056
- // .notification.clear is hidden by CSS when the wrapper lacks :focus-within.
15057
- // Force it visible so the native button is focusable, then clean up on blur.
15058
- const clearContainer = clearBtn.closest('.clear');
15059
-
15060
- if (clearContainer) {
15061
- clearContainer.style.display = 'flex';
15062
- }
15063
- const nativeBtn = clearBtn.shadowRoot && clearBtn.shadowRoot.querySelector('button');
15064
-
15065
- if (nativeBtn) {
15066
- nativeBtn.focus();
15067
- } else {
15068
- clearBtn.focus();
15069
- }
15070
-
15071
- // If focus failed (e.g. element inert, disabled, or hidden for another reason),
15072
- // clean up the inline style immediately so the clear UI does not stay visible.
15073
- const focusLanded = clearBtn.shadowRoot
15074
- ? clearBtn.shadowRoot.activeElement !== null
15075
- : document.activeElement === clearBtn;
15076
-
15077
- if (clearContainer) {
15078
- if (focusLanded) {
15105
+ if (clearBtn) {
15106
+ // Force the clear button container visible — without :focus-within
15107
+ // the CSS rule `.wrapper:not(:focus-within) .notification.clear`
15108
+ // hides the container with display:none, preventing focus.
15109
+ const clearContainer = clearBtn.closest('.clear');
15110
+ if (clearContainer) {
15111
+ clearContainer.style.display = 'flex';
15079
15112
  clearBtn.addEventListener('focusout', () => {
15080
15113
  requestAnimationFrame(() => {
15081
15114
  clearContainer.style.display = '';
15082
15115
  });
15083
15116
  }, { once: true });
15117
+ }
15118
+
15119
+ // Focus the native button inside auro-button so the browser
15120
+ // treats it as a real focusable element.
15121
+ const nativeBtn = clearBtn.shadowRoot && clearBtn.shadowRoot.querySelector('button');
15122
+ if (nativeBtn) {
15123
+ nativeBtn.focus();
15084
15124
  } else {
15085
- clearContainer.style.display = '';
15125
+ clearBtn.focus();
15086
15126
  }
15087
15127
  }
15088
15128
  }
@@ -15235,6 +15275,13 @@ class AuroCombobox extends AuroElement {
15235
15275
  this.input.setActiveDescendant(this.optionActive);
15236
15276
  }
15237
15277
 
15278
+ // In fullscreen mode, focus is on inputInBib inside the dialog, so
15279
+ // aria-activedescendant must also be set there for screen readers to
15280
+ // follow the active option from the focused element.
15281
+ if (this.inputInBib && this.dropdown.isBibFullscreen) {
15282
+ this.inputInBib.setActiveDescendant(this.optionActive);
15283
+ }
15284
+
15238
15285
  // Announce the active option for screen readers including position,
15239
15286
  // since shadow DOM boundaries prevent native reading of
15240
15287
  // aria-setsize/aria-posinset via aria-activedescendant.
@@ -15243,7 +15290,17 @@ class AuroCombobox extends AuroElement {
15243
15290
  const selectedState = this.optionActive.hasAttribute('selected') ? ', selected' : ', not selected';
15244
15291
  const optionIndex = this.availableOptions.indexOf(this.optionActive) + 1;
15245
15292
  const optionCount = this.availableOptions.length;
15246
- announceToScreenReader(this.shadowRoot, `${optionText}${selectedState}, ${optionIndex} of ${optionCount}`);
15293
+
15294
+ // In fullscreen mode the combobox's live region is outside the modal
15295
+ // dialog and inert, so route announcements to the bib's live region
15296
+ // which is inside the dialog.
15297
+ const bibEl = this.dropdown.bibElement && this.dropdown.bibElement.value;
15298
+ const bibShadowRoot = bibEl && bibEl.shadowRoot;
15299
+ const announcementRoot = this.dropdown.isBibFullscreen && bibShadowRoot
15300
+ ? bibShadowRoot
15301
+ : this.shadowRoot;
15302
+
15303
+ announceToScreenReader(announcementRoot, `${optionText}${selectedState}, ${optionIndex} of ${optionCount}`);
15247
15304
  }
15248
15305
 
15249
15306
  // Check if user prefers reduced motion for accessibility