@aurodesignsystem/auro-formkit 6.0.0 → 6.0.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 (46) hide show
  1. package/CHANGELOG.md +5 -240
  2. package/components/checkbox/demo/customize.min.js +1 -1
  3. package/components/checkbox/demo/getting-started.min.js +1 -1
  4. package/components/checkbox/demo/index.min.js +1 -1
  5. package/components/checkbox/dist/index.js +1 -1
  6. package/components/checkbox/dist/registered.js +1 -1
  7. package/components/combobox/demo/customize.min.js +172 -46
  8. package/components/combobox/demo/getting-started.min.js +172 -46
  9. package/components/combobox/demo/index.min.js +172 -46
  10. package/components/combobox/dist/index.js +172 -46
  11. package/components/combobox/dist/registered.js +172 -46
  12. package/components/counter/demo/customize.min.js +59 -7
  13. package/components/counter/demo/index.min.js +59 -7
  14. package/components/counter/dist/index.js +59 -7
  15. package/components/counter/dist/registered.js +59 -7
  16. package/components/datepicker/demo/customize.min.js +106 -18
  17. package/components/datepicker/demo/index.min.js +106 -18
  18. package/components/datepicker/dist/index.js +106 -18
  19. package/components/datepicker/dist/registered.js +106 -18
  20. package/components/dropdown/demo/customize.min.js +58 -6
  21. package/components/dropdown/demo/getting-started.min.js +58 -6
  22. package/components/dropdown/demo/index.min.js +58 -6
  23. package/components/dropdown/dist/auro-dropdown.d.ts +16 -1
  24. package/components/dropdown/dist/index.js +58 -6
  25. package/components/dropdown/dist/registered.js +58 -6
  26. package/components/form/demo/customize.min.js +445 -91
  27. package/components/form/demo/getting-started.min.js +445 -91
  28. package/components/form/demo/index.min.js +445 -91
  29. package/components/form/demo/registerDemoDeps.min.js +445 -91
  30. package/components/input/demo/customize.min.js +47 -11
  31. package/components/input/demo/getting-started.min.js +47 -11
  32. package/components/input/demo/index.min.js +47 -11
  33. package/components/input/dist/index.js +47 -11
  34. package/components/input/dist/registered.js +47 -11
  35. package/components/radio/demo/customize.min.js +1 -1
  36. package/components/radio/demo/getting-started.min.js +1 -1
  37. package/components/radio/demo/index.min.js +1 -1
  38. package/components/radio/dist/index.js +1 -1
  39. package/components/radio/dist/registered.js +1 -1
  40. package/components/select/demo/customize.min.js +59 -7
  41. package/components/select/demo/getting-started.min.js +59 -7
  42. package/components/select/demo/index.min.js +59 -7
  43. package/components/select/dist/index.js +59 -7
  44. package/components/select/dist/registered.js +59 -7
  45. package/custom-elements.json +1500 -1484
  46. package/package.json +1 -1
@@ -4971,7 +4971,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$3 {
4971
4971
  }
4972
4972
  };
4973
4973
 
4974
- var formkitVersion$2 = '202607102309';
4974
+ var formkitVersion$2 = '202607161943';
4975
4975
 
4976
4976
  let AuroElement$2 = class AuroElement extends i$3 {
4977
4977
  static get properties() {
@@ -5100,7 +5100,6 @@ class AuroDropdown extends AuroElement$2 {
5100
5100
  static get shadowRootOptions() {
5101
5101
  return {
5102
5102
  ...AuroElement$2.shadowRootOptions,
5103
- delegatesFocus: true,
5104
5103
  };
5105
5104
  }
5106
5105
 
@@ -5112,6 +5111,15 @@ class AuroDropdown extends AuroElement$2 {
5112
5111
  this.matchWidth = false;
5113
5112
  this.noHideOnThisFocusLoss = false;
5114
5113
 
5114
+ /**
5115
+ * When true, the dropdown skips its generic focus restoration on close.
5116
+ * Set by consumers (e.g. combobox) that manage their own focus routing
5117
+ * via setClearBtnFocus / setInputFocus / keyboard strategy.
5118
+ * Separate from noHideOnThisFocusLoss (which controls auto-close behavior).
5119
+ * @private
5120
+ */
5121
+ this.noFocusRestoreOnClose = false;
5122
+
5115
5123
  this.errorMessage = undefined; // TODO - check with Doug if there is still more to do here
5116
5124
 
5117
5125
  // Layout Config
@@ -5267,7 +5275,49 @@ class AuroDropdown extends AuroElement$2 {
5267
5275
  focusables[0].focus();
5268
5276
  }
5269
5277
  } else {
5278
+ this.focusTrigger();
5279
+ }
5280
+ }
5281
+
5282
+ /**
5283
+ * Focus the trigger content. When the trigger wrapper itself is focusable
5284
+ * (has tabindex), focus it directly. Otherwise, focus the first focusable
5285
+ * element slotted into the trigger slot (e.g. the auro-input).
5286
+ * @private
5287
+ */
5288
+ focusTrigger() {
5289
+ if (this.trigger.hasAttribute('tabindex')) {
5270
5290
  this.trigger.focus();
5291
+ } else {
5292
+ // Slotted content isn't a DOM child of the trigger div, so
5293
+ // getFocusableElements can't find it. Query assigned nodes directly.
5294
+ const slot = this.trigger.querySelector('slot[name="trigger"]');
5295
+ if (slot) {
5296
+ const assigned = slot.assignedElements();
5297
+ for (const el of assigned) {
5298
+ if (el.hasAttribute('disabled')) {
5299
+ continue;
5300
+ }
5301
+ // Try finding a focusable descendant first (handles non-focusable
5302
+ // wrappers like <div> containing a <button>). If none found, try
5303
+ // focusing the element directly (works for custom elements like
5304
+ // auro-input that have delegatesFocus or a custom focus() method).
5305
+ const descendants = getFocusableElements(el);
5306
+ if (descendants.length > 0) {
5307
+ descendants[0].focus();
5308
+ return;
5309
+ }
5310
+ el.focus();
5311
+ if (document.activeElement === el) {
5312
+ return;
5313
+ }
5314
+ }
5315
+ }
5316
+ // Fallback: try DOM children (non-slotted content)
5317
+ const focusables = getFocusableElements(this.trigger);
5318
+ if (focusables.length > 0) {
5319
+ focusables[0].focus();
5320
+ }
5271
5321
  }
5272
5322
  }
5273
5323
 
@@ -5720,15 +5770,17 @@ class AuroDropdown extends AuroElement$2 {
5720
5770
  }
5721
5771
 
5722
5772
  const eventType = event.detail.eventType || "unknown";
5723
- if (!this.isPopoverVisible && this.hasFocus && eventType === "keydown") {
5724
- this.trigger.focus();
5773
+ if (!this.isPopoverVisible && this.hasFocus && eventType === "keydown" && !this.noFocusRestoreOnClose) {
5774
+ this.focusTrigger();
5725
5775
  }
5726
5776
 
5727
5777
 
5728
5778
  // On Tab-driven close (eventType "focusloss"), let focus advance naturally
5729
5779
  // — restoring to the trigger would trap the user on this dropdown, forcing
5730
5780
  // an extra Tab to move on. Escape and outside-click still restore.
5731
- if (!this.isPopoverVisible && eventType !== "focusloss") {
5781
+ // When noFocusRestoreOnClose is true, the consumer (e.g. combobox) manages
5782
+ // its own focus restoration — skip the generic trigger focus to avoid races.
5783
+ if (!this.isPopoverVisible && eventType !== "focusloss" && !this.noFocusRestoreOnClose) {
5732
5784
  // wait til the bib gets fully closed and rendered
5733
5785
  setTimeout(() => {
5734
5786
  // Skip if the bib re-opened, or if focus moved intentionally outside the dropdown (not to body).
@@ -5740,7 +5792,7 @@ class AuroDropdown extends AuroElement$2 {
5740
5792
  return;
5741
5793
  }
5742
5794
  // Restore focus to the trigger.
5743
- this.trigger.focus();
5795
+ this.focusTrigger();
5744
5796
  });
5745
5797
  }
5746
5798
  }
@@ -16921,9 +16973,10 @@ class DomHandler {
16921
16973
  class BaseInput extends AuroElement$1 {
16922
16974
 
16923
16975
  // Delegate focus to the native <input> inside the shadow root so that
16924
- // showModal()'s dialog focusing steps reach the input element.
16925
- // This keeps the mobile virtual keyboard open when the fullscreen dialog
16926
- // opens, because the browser sees an input-to-input focus transfer.
16976
+ // clicking anywhere on the input wrapper focuses the native input, and
16977
+ // programmatic .focus() calls on elements in the shadow DOM work correctly.
16978
+ // The initial-load focus theft was caused by the static `autofocus`
16979
+ // attribute on the bib input (now conditional), not by delegatesFocus.
16927
16980
  static get shadowRootOptions() {
16928
16981
  return {
16929
16982
  ...AuroElement$1.shadowRootOptions,
@@ -18600,7 +18653,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$3 {
18600
18653
  }
18601
18654
  };
18602
18655
 
18603
- var formkitVersion$1 = '202607102309';
18656
+ var formkitVersion$1 = '202607161943';
18604
18657
 
18605
18658
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
18606
18659
  // See LICENSE in the project root for license information.
@@ -18886,15 +18939,50 @@ class AuroInput extends BaseInput {
18886
18939
  * @returns {void}
18887
18940
  */
18888
18941
  checkDisplayValueSlotChange() {
18889
- // flatten:true resolves through auro-combobox's forwarding slot
18890
- // (<slot name="displayValue" slot="displayValue">) so a clone appended
18891
- // directly to auro-input's light DOM alongside the forwarder still
18892
- // counts as content. The prior nodes[0].tagName === 'SLOT' recursion
18893
- // discarded any siblings past the forwarder.
18894
- const slot = this.shadowRoot.querySelector('slot[name="displayValue"]');
18942
+ const slot = this.shadowRoot?.querySelector('slot[name="displayValue"]');
18943
+ if (!slot) {
18944
+ // Shadow slot not yet rendered fall back to checking light-DOM
18945
+ // children so hasDisplayValueContent isn't stuck false when called
18946
+ // before firstUpdated (e.g. from auro-combobox during mount).
18947
+ // Check for any element (including custom elements like <auro-icon>
18948
+ // that render via shadow DOM with no text content).
18949
+ const lightDomNodes = Array.from(this.querySelectorAll('[slot="displayValue"]:not(slot)'));
18950
+ const hasContent = lightDomNodes.some((node) => (
18951
+ node.textContent.trim().length > 0 ||
18952
+ node.children.length > 0 ||
18953
+ node.shadowRoot !== null
18954
+ ));
18955
+ if (this.hasDisplayValueContent !== hasContent) {
18956
+ this.hasDisplayValueContent = hasContent;
18957
+ this.requestUpdate();
18958
+ }
18959
+ return;
18960
+ }
18895
18961
  const nodes = slot.assignedNodes({ flatten: true });
18896
18962
 
18897
- this.hasDisplayValueContent = nodes.length > 0;
18963
+ // Check for actual visible content, not just node existence.
18964
+ // An empty <span slot="displayValue"></span> forwarded from the
18965
+ // consumer should not be treated as "has content" — it causes the
18966
+ // displayValue wrapper to render (with hasContent class) but show
18967
+ // nothing, blocking the combobox's synthetic displayValue from
18968
+ // being visible on preset/deeplink load.
18969
+ // Custom elements (e.g. <auro-icon>) that render via shadow DOM are
18970
+ // treated as content even when they have no text or light-DOM children.
18971
+ const hasContent = nodes.some((node) => {
18972
+ if (node.nodeType === Node.TEXT_NODE) {
18973
+ return node.textContent.trim().length > 0;
18974
+ }
18975
+ if (node.nodeType === Node.ELEMENT_NODE) {
18976
+ return node.textContent.trim().length > 0 ||
18977
+ node.children.length > 0 ||
18978
+ node.shadowRoot !== null;
18979
+ }
18980
+ return false;
18981
+ });
18982
+ if (this.hasDisplayValueContent !== hasContent) {
18983
+ this.hasDisplayValueContent = hasContent;
18984
+ this.requestUpdate();
18985
+ }
18898
18986
  }
18899
18987
 
18900
18988
  firstUpdated() {
@@ -19721,7 +19809,7 @@ class AuroBibtemplate extends i$3 {
19721
19809
  }
19722
19810
  }
19723
19811
 
19724
- var formkitVersion = '202607102309';
19812
+ var formkitVersion = '202607161943';
19725
19813
 
19726
19814
  var styleCss$3 = i$6`.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}`;
19727
19815
 
@@ -20758,14 +20846,34 @@ class AuroCombobox extends AuroElement {
20758
20846
  const displayValueEl = this.menu.optionSelected.querySelector("[slot='displayValue']");
20759
20847
  if (displayValueEl) {
20760
20848
  this.input.appendChild(displayValueEl.cloneNode(true));
20761
- // auro-input's hasDisplayValueContent is non-reactive; nudge it to
20762
- // re-evaluate the slot and re-render so the displayValue wrapper
20763
- // gets its hasContent class. Without this, the apple/icon stays
20764
- // hidden when input.value is set in the same tick as the append.
20765
- if (typeof this.input.checkDisplayValueSlotChange === 'function') {
20766
- this.input.checkDisplayValueSlotChange();
20767
- this.input.requestUpdate();
20768
- }
20849
+ }
20850
+
20851
+ // auro-input's hasDisplayValueContent is non-reactive; nudge it to
20852
+ // re-evaluate the slot and re-render so the displayValue wrapper
20853
+ // gets its hasContent class. Without this, the apple/icon stays
20854
+ // hidden when input.value is set in the same tick as the append.
20855
+ if (typeof this.input.checkDisplayValueSlotChange === 'function') {
20856
+ this.input.checkDisplayValueSlotChange();
20857
+ }
20858
+ } else if (this.value) {
20859
+ // No optionSelected yet (e.g. setMenuValue was called but the menu's
20860
+ // auroMenu-selectedOption event hasn't fired yet, or we're on remount
20861
+ // with no options loaded). Synthesize a displayValue from the value so
20862
+ // the overlay isn't blank.
20863
+ //
20864
+ // NOTE: This renders the raw machine value (e.g. "SEA"), not the
20865
+ // human-readable label (e.g. "Seattle, WA"). For consumers where
20866
+ // value ≠ label, this produces a brief flash of the raw value until
20867
+ // the option elements load and updateTriggerTextDisplay re-runs with
20868
+ // the correct label. This is intentionally preferred over a blank
20869
+ // state — the displayValueInTrigger.remove() cleanup above ensures
20870
+ // this placeholder is replaced once the real option is available.
20871
+ const syntheticDV = document.createElement('span');
20872
+ syntheticDV.setAttribute('slot', 'displayValue');
20873
+ syntheticDV.textContent = this.value;
20874
+ this.input.appendChild(syntheticDV);
20875
+ if (typeof this.input.checkDisplayValueSlotChange === 'function') {
20876
+ this.input.checkDisplayValueSlotChange();
20769
20877
  }
20770
20878
  }
20771
20879
 
@@ -20938,6 +21046,10 @@ class AuroCombobox extends AuroElement {
20938
21046
  // from combobox's light DOM and won't be detected by dropdown's contains() check.
20939
21047
  this.dropdown.noHideOnThisFocusLoss = true;
20940
21048
 
21049
+ // Suppress the dropdown's generic focus restoration on close — the combobox
21050
+ // manages its own focus via setClearBtnFocus / setInputFocus / keyboard strategy.
21051
+ this.dropdown.noFocusRestoreOnClose = true;
21052
+
20941
21053
  // Listen for the ID to be added to the dropdown so we can capture it and use it for accessibility.
20942
21054
  this.dropdown.addEventListener('auroDropdown-idAdded', (event) => {
20943
21055
  this.dropdownId = event.detail.id;
@@ -21011,7 +21123,11 @@ class AuroCombobox extends AuroElement {
21011
21123
  // after the dropdown layout settles.
21012
21124
 
21013
21125
  doubleRaf(() => {
21014
- this.setInputFocus();
21126
+ // Guard: skip if the dropdown closed before this rAF fired
21127
+ // (e.g. user selected an option immediately after the bib opened).
21128
+ if (this.dropdownOpen) {
21129
+ this.setInputFocus();
21130
+ }
21015
21131
  if (this._inFullscreenTransition) {
21016
21132
  this._inFullscreenTransition = false;
21017
21133
  }
@@ -21058,7 +21174,9 @@ class AuroCombobox extends AuroElement {
21058
21174
  }
21059
21175
 
21060
21176
  this._scheduleTimer(() => {
21061
- this.setInputFocus();
21177
+ if (this.dropdown.isPopoverVisible) {
21178
+ this.setInputFocus();
21179
+ }
21062
21180
  }, 0);
21063
21181
  });
21064
21182
  }
@@ -21067,14 +21185,19 @@ class AuroCombobox extends AuroElement {
21067
21185
  * @private
21068
21186
  */
21069
21187
  setClearBtnFocus() {
21070
- const clearBtn = this.input.shadowRoot.querySelector('.clearBtn');
21071
- if (clearBtn) {
21072
- // Wait for the element to fully render across
21073
- // multiple Lit update cycles before moving focus
21074
- doubleRaf(() => {
21188
+ doubleRaf(() => {
21189
+ // First establish focus inside the input's shadow root.
21190
+ // Without this, clearBtn.focus() silently fails when focus is on
21191
+ // document.body (e.g. after a click selection closes the bib dialog).
21192
+ // delegatesFocus on BaseInput routes this to the native <input>.
21193
+ this.input.focus();
21194
+
21195
+ // Now move focus to the clear button within the same shadow root.
21196
+ const clearBtn = this.input.shadowRoot.querySelector('.clearBtn');
21197
+ if (clearBtn) {
21075
21198
  clearBtn.focus();
21076
- });
21077
- }
21199
+ }
21200
+ });
21078
21201
  }
21079
21202
 
21080
21203
  /**
@@ -21285,6 +21408,9 @@ class AuroCombobox extends AuroElement {
21285
21408
  // only — fresh user selections take the existing hideBib path.
21286
21409
  if (isEcho && this.menu.optionSelected) {
21287
21410
  this._programmaticFilterRefresh = true;
21411
+ this.updateComplete.then(() => {
21412
+ this._programmaticFilterRefresh = false;
21413
+ });
21288
21414
  }
21289
21415
  });
21290
21416
 
@@ -21537,10 +21663,6 @@ class AuroCombobox extends AuroElement {
21537
21663
  if (this.dropdown.isBibFullscreen && this.input.value && this.input.value.length > 0 && this.dropdown.isPopoverVisible) {
21538
21664
  this.setInputFocus();
21539
21665
  }
21540
-
21541
- if (this._programmaticFilterRefresh) {
21542
- this._programmaticFilterRefresh = false;
21543
- }
21544
21666
  }
21545
21667
 
21546
21668
  /**
@@ -21554,10 +21676,12 @@ class AuroCombobox extends AuroElement {
21554
21676
  inputResolver: (comp, ctx) => (ctx.isModal && comp.inputInBib ? comp.inputInBib : comp.input),
21555
21677
  });
21556
21678
 
21557
- this.addEventListener('focusin', () => {
21679
+ this.addEventListener('focusin', (event) => {
21558
21680
  this.touched = true;
21559
21681
 
21560
- this.focus();
21682
+ if (event.composedPath()[0] === this) {
21683
+ this.focus();
21684
+ }
21561
21685
  });
21562
21686
 
21563
21687
  this.addEventListener('auroFormElement-validated', (evt) => {
@@ -21737,6 +21861,12 @@ class AuroCombobox extends AuroElement {
21737
21861
  // setting the flag unconditionally here masks the user-typed open path.
21738
21862
  if (!this._userTyped) {
21739
21863
  this._programmaticFilterRefresh = true;
21864
+ // Self-clear after this update cycle completes. This collapses
21865
+ // the previous scattered clear-points into one and prevents the
21866
+ // flag from surviving into the next user interaction.
21867
+ this.updateComplete.then(() => {
21868
+ this._programmaticFilterRefresh = false;
21869
+ });
21740
21870
  }
21741
21871
 
21742
21872
  if (this.input.value !== this.value) {
@@ -21826,10 +21956,6 @@ class AuroCombobox extends AuroElement {
21826
21956
  } else if (!this.dropdown.isBibFullscreen) {
21827
21957
  this.hideBib();
21828
21958
  }
21829
-
21830
- if (this._programmaticFilterRefresh) {
21831
- this._programmaticFilterRefresh = false;
21832
- }
21833
21959
  }
21834
21960
 
21835
21961
  if (changedProperties.has('error')) {
@@ -22011,7 +22137,7 @@ class AuroCombobox extends AuroElement {
22011
22137
  <slot @slotchange="${this.handleSlotChange}"></slot>
22012
22138
  <${this.inputTag}
22013
22139
  id="inputInBib"
22014
- autofocus
22140
+ ?autofocus="${this.dropdownOpen && this.dropdown?.isBibFullscreen}"
22015
22141
  @input="${this.handleInputValueChange}"
22016
22142
  .a11yActivedescendant="${this.dropdownOpen && this.optionActive ? this.optionActive.id : undefined}"
22017
22143
  .a11yControls=${`${this.dropdownId}-floater-bib`}