@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
@@ -4986,7 +4986,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$3 {
4986
4986
  }
4987
4987
  };
4988
4988
 
4989
- var formkitVersion$2 = '202607102309';
4989
+ var formkitVersion$2 = '202607161943';
4990
4990
 
4991
4991
  let AuroElement$2 = class AuroElement extends i$3 {
4992
4992
  static get properties() {
@@ -5115,7 +5115,6 @@ class AuroDropdown extends AuroElement$2 {
5115
5115
  static get shadowRootOptions() {
5116
5116
  return {
5117
5117
  ...AuroElement$2.shadowRootOptions,
5118
- delegatesFocus: true,
5119
5118
  };
5120
5119
  }
5121
5120
 
@@ -5127,6 +5126,15 @@ class AuroDropdown extends AuroElement$2 {
5127
5126
  this.matchWidth = false;
5128
5127
  this.noHideOnThisFocusLoss = false;
5129
5128
 
5129
+ /**
5130
+ * When true, the dropdown skips its generic focus restoration on close.
5131
+ * Set by consumers (e.g. combobox) that manage their own focus routing
5132
+ * via setClearBtnFocus / setInputFocus / keyboard strategy.
5133
+ * Separate from noHideOnThisFocusLoss (which controls auto-close behavior).
5134
+ * @private
5135
+ */
5136
+ this.noFocusRestoreOnClose = false;
5137
+
5130
5138
  this.errorMessage = undefined; // TODO - check with Doug if there is still more to do here
5131
5139
 
5132
5140
  // Layout Config
@@ -5282,7 +5290,49 @@ class AuroDropdown extends AuroElement$2 {
5282
5290
  focusables[0].focus();
5283
5291
  }
5284
5292
  } else {
5293
+ this.focusTrigger();
5294
+ }
5295
+ }
5296
+
5297
+ /**
5298
+ * Focus the trigger content. When the trigger wrapper itself is focusable
5299
+ * (has tabindex), focus it directly. Otherwise, focus the first focusable
5300
+ * element slotted into the trigger slot (e.g. the auro-input).
5301
+ * @private
5302
+ */
5303
+ focusTrigger() {
5304
+ if (this.trigger.hasAttribute('tabindex')) {
5285
5305
  this.trigger.focus();
5306
+ } else {
5307
+ // Slotted content isn't a DOM child of the trigger div, so
5308
+ // getFocusableElements can't find it. Query assigned nodes directly.
5309
+ const slot = this.trigger.querySelector('slot[name="trigger"]');
5310
+ if (slot) {
5311
+ const assigned = slot.assignedElements();
5312
+ for (const el of assigned) {
5313
+ if (el.hasAttribute('disabled')) {
5314
+ continue;
5315
+ }
5316
+ // Try finding a focusable descendant first (handles non-focusable
5317
+ // wrappers like <div> containing a <button>). If none found, try
5318
+ // focusing the element directly (works for custom elements like
5319
+ // auro-input that have delegatesFocus or a custom focus() method).
5320
+ const descendants = getFocusableElements(el);
5321
+ if (descendants.length > 0) {
5322
+ descendants[0].focus();
5323
+ return;
5324
+ }
5325
+ el.focus();
5326
+ if (document.activeElement === el) {
5327
+ return;
5328
+ }
5329
+ }
5330
+ }
5331
+ // Fallback: try DOM children (non-slotted content)
5332
+ const focusables = getFocusableElements(this.trigger);
5333
+ if (focusables.length > 0) {
5334
+ focusables[0].focus();
5335
+ }
5286
5336
  }
5287
5337
  }
5288
5338
 
@@ -5735,15 +5785,17 @@ class AuroDropdown extends AuroElement$2 {
5735
5785
  }
5736
5786
 
5737
5787
  const eventType = event.detail.eventType || "unknown";
5738
- if (!this.isPopoverVisible && this.hasFocus && eventType === "keydown") {
5739
- this.trigger.focus();
5788
+ if (!this.isPopoverVisible && this.hasFocus && eventType === "keydown" && !this.noFocusRestoreOnClose) {
5789
+ this.focusTrigger();
5740
5790
  }
5741
5791
 
5742
5792
 
5743
5793
  // On Tab-driven close (eventType "focusloss"), let focus advance naturally
5744
5794
  // — restoring to the trigger would trap the user on this dropdown, forcing
5745
5795
  // an extra Tab to move on. Escape and outside-click still restore.
5746
- if (!this.isPopoverVisible && eventType !== "focusloss") {
5796
+ // When noFocusRestoreOnClose is true, the consumer (e.g. combobox) manages
5797
+ // its own focus restoration — skip the generic trigger focus to avoid races.
5798
+ if (!this.isPopoverVisible && eventType !== "focusloss" && !this.noFocusRestoreOnClose) {
5747
5799
  // wait til the bib gets fully closed and rendered
5748
5800
  setTimeout(() => {
5749
5801
  // Skip if the bib re-opened, or if focus moved intentionally outside the dropdown (not to body).
@@ -5755,7 +5807,7 @@ class AuroDropdown extends AuroElement$2 {
5755
5807
  return;
5756
5808
  }
5757
5809
  // Restore focus to the trigger.
5758
- this.trigger.focus();
5810
+ this.focusTrigger();
5759
5811
  });
5760
5812
  }
5761
5813
  }
@@ -16936,9 +16988,10 @@ class DomHandler {
16936
16988
  class BaseInput extends AuroElement$1 {
16937
16989
 
16938
16990
  // Delegate focus to the native <input> inside the shadow root so that
16939
- // showModal()'s dialog focusing steps reach the input element.
16940
- // This keeps the mobile virtual keyboard open when the fullscreen dialog
16941
- // opens, because the browser sees an input-to-input focus transfer.
16991
+ // clicking anywhere on the input wrapper focuses the native input, and
16992
+ // programmatic .focus() calls on elements in the shadow DOM work correctly.
16993
+ // The initial-load focus theft was caused by the static `autofocus`
16994
+ // attribute on the bib input (now conditional), not by delegatesFocus.
16942
16995
  static get shadowRootOptions() {
16943
16996
  return {
16944
16997
  ...AuroElement$1.shadowRootOptions,
@@ -18615,7 +18668,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$3 {
18615
18668
  }
18616
18669
  };
18617
18670
 
18618
- var formkitVersion$1 = '202607102309';
18671
+ var formkitVersion$1 = '202607161943';
18619
18672
 
18620
18673
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
18621
18674
  // See LICENSE in the project root for license information.
@@ -18901,15 +18954,50 @@ class AuroInput extends BaseInput {
18901
18954
  * @returns {void}
18902
18955
  */
18903
18956
  checkDisplayValueSlotChange() {
18904
- // flatten:true resolves through auro-combobox's forwarding slot
18905
- // (<slot name="displayValue" slot="displayValue">) so a clone appended
18906
- // directly to auro-input's light DOM alongside the forwarder still
18907
- // counts as content. The prior nodes[0].tagName === 'SLOT' recursion
18908
- // discarded any siblings past the forwarder.
18909
- const slot = this.shadowRoot.querySelector('slot[name="displayValue"]');
18957
+ const slot = this.shadowRoot?.querySelector('slot[name="displayValue"]');
18958
+ if (!slot) {
18959
+ // Shadow slot not yet rendered fall back to checking light-DOM
18960
+ // children so hasDisplayValueContent isn't stuck false when called
18961
+ // before firstUpdated (e.g. from auro-combobox during mount).
18962
+ // Check for any element (including custom elements like <auro-icon>
18963
+ // that render via shadow DOM with no text content).
18964
+ const lightDomNodes = Array.from(this.querySelectorAll('[slot="displayValue"]:not(slot)'));
18965
+ const hasContent = lightDomNodes.some((node) => (
18966
+ node.textContent.trim().length > 0 ||
18967
+ node.children.length > 0 ||
18968
+ node.shadowRoot !== null
18969
+ ));
18970
+ if (this.hasDisplayValueContent !== hasContent) {
18971
+ this.hasDisplayValueContent = hasContent;
18972
+ this.requestUpdate();
18973
+ }
18974
+ return;
18975
+ }
18910
18976
  const nodes = slot.assignedNodes({ flatten: true });
18911
18977
 
18912
- this.hasDisplayValueContent = nodes.length > 0;
18978
+ // Check for actual visible content, not just node existence.
18979
+ // An empty <span slot="displayValue"></span> forwarded from the
18980
+ // consumer should not be treated as "has content" — it causes the
18981
+ // displayValue wrapper to render (with hasContent class) but show
18982
+ // nothing, blocking the combobox's synthetic displayValue from
18983
+ // being visible on preset/deeplink load.
18984
+ // Custom elements (e.g. <auro-icon>) that render via shadow DOM are
18985
+ // treated as content even when they have no text or light-DOM children.
18986
+ const hasContent = nodes.some((node) => {
18987
+ if (node.nodeType === Node.TEXT_NODE) {
18988
+ return node.textContent.trim().length > 0;
18989
+ }
18990
+ if (node.nodeType === Node.ELEMENT_NODE) {
18991
+ return node.textContent.trim().length > 0 ||
18992
+ node.children.length > 0 ||
18993
+ node.shadowRoot !== null;
18994
+ }
18995
+ return false;
18996
+ });
18997
+ if (this.hasDisplayValueContent !== hasContent) {
18998
+ this.hasDisplayValueContent = hasContent;
18999
+ this.requestUpdate();
19000
+ }
18913
19001
  }
18914
19002
 
18915
19003
  firstUpdated() {
@@ -19736,7 +19824,7 @@ class AuroBibtemplate extends i$3 {
19736
19824
  }
19737
19825
  }
19738
19826
 
19739
- var formkitVersion = '202607102309';
19827
+ var formkitVersion = '202607161943';
19740
19828
 
19741
19829
  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}`;
19742
19830
 
@@ -20773,14 +20861,34 @@ class AuroCombobox extends AuroElement {
20773
20861
  const displayValueEl = this.menu.optionSelected.querySelector("[slot='displayValue']");
20774
20862
  if (displayValueEl) {
20775
20863
  this.input.appendChild(displayValueEl.cloneNode(true));
20776
- // auro-input's hasDisplayValueContent is non-reactive; nudge it to
20777
- // re-evaluate the slot and re-render so the displayValue wrapper
20778
- // gets its hasContent class. Without this, the apple/icon stays
20779
- // hidden when input.value is set in the same tick as the append.
20780
- if (typeof this.input.checkDisplayValueSlotChange === 'function') {
20781
- this.input.checkDisplayValueSlotChange();
20782
- this.input.requestUpdate();
20783
- }
20864
+ }
20865
+
20866
+ // auro-input's hasDisplayValueContent is non-reactive; nudge it to
20867
+ // re-evaluate the slot and re-render so the displayValue wrapper
20868
+ // gets its hasContent class. Without this, the apple/icon stays
20869
+ // hidden when input.value is set in the same tick as the append.
20870
+ if (typeof this.input.checkDisplayValueSlotChange === 'function') {
20871
+ this.input.checkDisplayValueSlotChange();
20872
+ }
20873
+ } else if (this.value) {
20874
+ // No optionSelected yet (e.g. setMenuValue was called but the menu's
20875
+ // auroMenu-selectedOption event hasn't fired yet, or we're on remount
20876
+ // with no options loaded). Synthesize a displayValue from the value so
20877
+ // the overlay isn't blank.
20878
+ //
20879
+ // NOTE: This renders the raw machine value (e.g. "SEA"), not the
20880
+ // human-readable label (e.g. "Seattle, WA"). For consumers where
20881
+ // value ≠ label, this produces a brief flash of the raw value until
20882
+ // the option elements load and updateTriggerTextDisplay re-runs with
20883
+ // the correct label. This is intentionally preferred over a blank
20884
+ // state — the displayValueInTrigger.remove() cleanup above ensures
20885
+ // this placeholder is replaced once the real option is available.
20886
+ const syntheticDV = document.createElement('span');
20887
+ syntheticDV.setAttribute('slot', 'displayValue');
20888
+ syntheticDV.textContent = this.value;
20889
+ this.input.appendChild(syntheticDV);
20890
+ if (typeof this.input.checkDisplayValueSlotChange === 'function') {
20891
+ this.input.checkDisplayValueSlotChange();
20784
20892
  }
20785
20893
  }
20786
20894
 
@@ -20953,6 +21061,10 @@ class AuroCombobox extends AuroElement {
20953
21061
  // from combobox's light DOM and won't be detected by dropdown's contains() check.
20954
21062
  this.dropdown.noHideOnThisFocusLoss = true;
20955
21063
 
21064
+ // Suppress the dropdown's generic focus restoration on close — the combobox
21065
+ // manages its own focus via setClearBtnFocus / setInputFocus / keyboard strategy.
21066
+ this.dropdown.noFocusRestoreOnClose = true;
21067
+
20956
21068
  // Listen for the ID to be added to the dropdown so we can capture it and use it for accessibility.
20957
21069
  this.dropdown.addEventListener('auroDropdown-idAdded', (event) => {
20958
21070
  this.dropdownId = event.detail.id;
@@ -21026,7 +21138,11 @@ class AuroCombobox extends AuroElement {
21026
21138
  // after the dropdown layout settles.
21027
21139
 
21028
21140
  doubleRaf(() => {
21029
- this.setInputFocus();
21141
+ // Guard: skip if the dropdown closed before this rAF fired
21142
+ // (e.g. user selected an option immediately after the bib opened).
21143
+ if (this.dropdownOpen) {
21144
+ this.setInputFocus();
21145
+ }
21030
21146
  if (this._inFullscreenTransition) {
21031
21147
  this._inFullscreenTransition = false;
21032
21148
  }
@@ -21073,7 +21189,9 @@ class AuroCombobox extends AuroElement {
21073
21189
  }
21074
21190
 
21075
21191
  this._scheduleTimer(() => {
21076
- this.setInputFocus();
21192
+ if (this.dropdown.isPopoverVisible) {
21193
+ this.setInputFocus();
21194
+ }
21077
21195
  }, 0);
21078
21196
  });
21079
21197
  }
@@ -21082,14 +21200,19 @@ class AuroCombobox extends AuroElement {
21082
21200
  * @private
21083
21201
  */
21084
21202
  setClearBtnFocus() {
21085
- const clearBtn = this.input.shadowRoot.querySelector('.clearBtn');
21086
- if (clearBtn) {
21087
- // Wait for the element to fully render across
21088
- // multiple Lit update cycles before moving focus
21089
- doubleRaf(() => {
21203
+ doubleRaf(() => {
21204
+ // First establish focus inside the input's shadow root.
21205
+ // Without this, clearBtn.focus() silently fails when focus is on
21206
+ // document.body (e.g. after a click selection closes the bib dialog).
21207
+ // delegatesFocus on BaseInput routes this to the native <input>.
21208
+ this.input.focus();
21209
+
21210
+ // Now move focus to the clear button within the same shadow root.
21211
+ const clearBtn = this.input.shadowRoot.querySelector('.clearBtn');
21212
+ if (clearBtn) {
21090
21213
  clearBtn.focus();
21091
- });
21092
- }
21214
+ }
21215
+ });
21093
21216
  }
21094
21217
 
21095
21218
  /**
@@ -21300,6 +21423,9 @@ class AuroCombobox extends AuroElement {
21300
21423
  // only — fresh user selections take the existing hideBib path.
21301
21424
  if (isEcho && this.menu.optionSelected) {
21302
21425
  this._programmaticFilterRefresh = true;
21426
+ this.updateComplete.then(() => {
21427
+ this._programmaticFilterRefresh = false;
21428
+ });
21303
21429
  }
21304
21430
  });
21305
21431
 
@@ -21552,10 +21678,6 @@ class AuroCombobox extends AuroElement {
21552
21678
  if (this.dropdown.isBibFullscreen && this.input.value && this.input.value.length > 0 && this.dropdown.isPopoverVisible) {
21553
21679
  this.setInputFocus();
21554
21680
  }
21555
-
21556
- if (this._programmaticFilterRefresh) {
21557
- this._programmaticFilterRefresh = false;
21558
- }
21559
21681
  }
21560
21682
 
21561
21683
  /**
@@ -21569,10 +21691,12 @@ class AuroCombobox extends AuroElement {
21569
21691
  inputResolver: (comp, ctx) => (ctx.isModal && comp.inputInBib ? comp.inputInBib : comp.input),
21570
21692
  });
21571
21693
 
21572
- this.addEventListener('focusin', () => {
21694
+ this.addEventListener('focusin', (event) => {
21573
21695
  this.touched = true;
21574
21696
 
21575
- this.focus();
21697
+ if (event.composedPath()[0] === this) {
21698
+ this.focus();
21699
+ }
21576
21700
  });
21577
21701
 
21578
21702
  this.addEventListener('auroFormElement-validated', (evt) => {
@@ -21752,6 +21876,12 @@ class AuroCombobox extends AuroElement {
21752
21876
  // setting the flag unconditionally here masks the user-typed open path.
21753
21877
  if (!this._userTyped) {
21754
21878
  this._programmaticFilterRefresh = true;
21879
+ // Self-clear after this update cycle completes. This collapses
21880
+ // the previous scattered clear-points into one and prevents the
21881
+ // flag from surviving into the next user interaction.
21882
+ this.updateComplete.then(() => {
21883
+ this._programmaticFilterRefresh = false;
21884
+ });
21755
21885
  }
21756
21886
 
21757
21887
  if (this.input.value !== this.value) {
@@ -21841,10 +21971,6 @@ class AuroCombobox extends AuroElement {
21841
21971
  } else if (!this.dropdown.isBibFullscreen) {
21842
21972
  this.hideBib();
21843
21973
  }
21844
-
21845
- if (this._programmaticFilterRefresh) {
21846
- this._programmaticFilterRefresh = false;
21847
- }
21848
21974
  }
21849
21975
 
21850
21976
  if (changedProperties.has('error')) {
@@ -22026,7 +22152,7 @@ class AuroCombobox extends AuroElement {
22026
22152
  <slot @slotchange="${this.handleSlotChange}"></slot>
22027
22153
  <${this.inputTag}
22028
22154
  id="inputInBib"
22029
- autofocus
22155
+ ?autofocus="${this.dropdownOpen && this.dropdown?.isBibFullscreen}"
22030
22156
  @input="${this.handleInputValueChange}"
22031
22157
  .a11yActivedescendant="${this.dropdownOpen && this.optionActive ? this.optionActive.id : undefined}"
22032
22158
  .a11yControls=${`${this.dropdownId}-floater-bib`}