@aurodesignsystem-dev/auro-formkit 0.0.0-pr1505.0 → 0.0.0-pr1506.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 (56) hide show
  1. package/components/checkbox/demo/customize.min.js +1 -1
  2. package/components/checkbox/demo/getting-started.min.js +1 -1
  3. package/components/checkbox/demo/index.min.js +1 -1
  4. package/components/checkbox/dist/index.js +1 -1
  5. package/components/checkbox/dist/registered.js +1 -1
  6. package/components/combobox/demo/customize.min.js +138 -266
  7. package/components/combobox/demo/getting-started.min.js +138 -266
  8. package/components/combobox/demo/index.min.js +138 -266
  9. package/components/combobox/dist/auro-combobox.d.ts +9 -0
  10. package/components/combobox/dist/index.js +138 -266
  11. package/components/combobox/dist/registered.js +138 -266
  12. package/components/counter/demo/customize.min.js +2 -2
  13. package/components/counter/demo/index.min.js +2 -2
  14. package/components/counter/dist/index.js +2 -2
  15. package/components/counter/dist/registered.js +2 -2
  16. package/components/datepicker/demo/api.md +0 -2
  17. package/components/datepicker/demo/customize.md +33 -195
  18. package/components/datepicker/demo/customize.min.js +41 -164
  19. package/components/datepicker/demo/index.min.js +40 -156
  20. package/components/datepicker/dist/index.js +40 -156
  21. package/components/datepicker/dist/registered.js +40 -156
  22. package/components/datepicker/dist/src/auro-datepicker.d.ts +0 -2
  23. package/components/dropdown/demo/customize.min.js +1 -1
  24. package/components/dropdown/demo/getting-started.min.js +1 -1
  25. package/components/dropdown/demo/index.min.js +1 -1
  26. package/components/dropdown/dist/index.js +1 -1
  27. package/components/dropdown/dist/registered.js +1 -1
  28. package/components/form/demo/customize.min.js +351 -599
  29. package/components/form/demo/getting-started.min.js +351 -599
  30. package/components/form/demo/index.min.js +351 -599
  31. package/components/form/demo/registerDemoDeps.min.js +351 -599
  32. package/components/input/demo/customize.md +55 -56
  33. package/components/input/demo/customize.min.js +36 -147
  34. package/components/input/demo/getting-started.min.js +36 -147
  35. package/components/input/demo/index.md +2 -2
  36. package/components/input/demo/index.min.js +36 -147
  37. package/components/input/dist/base-input.d.ts +0 -48
  38. package/components/input/dist/index.js +36 -147
  39. package/components/input/dist/registered.js +36 -147
  40. package/components/radio/demo/customize.min.js +1 -1
  41. package/components/radio/demo/getting-started.min.js +1 -1
  42. package/components/radio/demo/index.min.js +1 -1
  43. package/components/radio/dist/index.js +1 -1
  44. package/components/radio/dist/registered.js +1 -1
  45. package/components/select/demo/api.md +1 -0
  46. package/components/select/demo/customize.md +71 -0
  47. package/components/select/demo/customize.min.js +133 -26
  48. package/components/select/demo/getting-started.min.js +133 -26
  49. package/components/select/demo/index.min.js +133 -26
  50. package/components/select/demo/keyboard-behavior.md +18 -0
  51. package/components/select/dist/auro-select.d.ts +38 -2
  52. package/components/select/dist/index.js +133 -26
  53. package/components/select/dist/registered.js +133 -26
  54. package/components/select/dist/selectUtils.d.ts +12 -0
  55. package/custom-elements.json +114 -274
  56. package/package.json +1 -1
@@ -10460,6 +10460,7 @@ let AuroInputUtilities$3 = class AuroInputUtilities {
10460
10460
  const maskOptions = this.getMaskOptions('date', normalizedFormat);
10461
10461
 
10462
10462
  if (!(valueObject instanceof Date) || Number.isNaN(valueObject.getTime()) || !maskOptions || typeof maskOptions.format !== 'function') {
10463
+ console.debug('Invalid date object or mask options for formatting', { valueObject, maskOptions }); // eslint-disable-line no-console
10463
10464
  return undefined;
10464
10465
  }
10465
10466
 
@@ -10611,10 +10612,8 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
10611
10612
  this.layout = 'classic';
10612
10613
  this.locale = 'en-US';
10613
10614
  this.max = undefined;
10614
- this._maxObject = undefined;
10615
10615
  this.maxLength = undefined;
10616
10616
  this.min = undefined;
10617
- this._minObject = undefined;
10618
10617
  this.minLength = undefined;
10619
10618
  this.required = false;
10620
10619
  this.onDark = false;
@@ -10622,7 +10621,6 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
10622
10621
  this.size = 'lg';
10623
10622
  this.shape = 'classic';
10624
10623
  this.value = undefined;
10625
- this._valueObject = undefined;
10626
10624
 
10627
10625
  this._initializePrivateDefaults();
10628
10626
  }
@@ -11162,7 +11160,7 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
11162
11160
  * @returns {Date|undefined}
11163
11161
  */
11164
11162
  get valueObject() {
11165
- return this._valueObject || this._computeDateObjectFallback(this.value);
11163
+ return this.value && dateFormatter$3.isValidDate(this.value) ? dateFormatter$3.stringToDateInstance(this.value) : undefined;
11166
11164
  }
11167
11165
 
11168
11166
  /**
@@ -11170,7 +11168,7 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
11170
11168
  * @returns {Date|undefined}
11171
11169
  */
11172
11170
  get minObject() {
11173
- return this._minObject || this._computeDateObjectFallback(this.min);
11171
+ return this.min && dateFormatter$3.isValidDate(this.min) ? dateFormatter$3.stringToDateInstance(this.min) : undefined;
11174
11172
  }
11175
11173
 
11176
11174
  /**
@@ -11178,50 +11176,7 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
11178
11176
  * @returns {Date|undefined}
11179
11177
  */
11180
11178
  get maxObject() {
11181
- return this._maxObject || this._computeDateObjectFallback(this.max);
11182
- }
11183
-
11184
- /**
11185
- * Parses a date string into a Date object when the corresponding `_*Object`
11186
- * field hasn't been synced yet by `updated()`. Returns undefined when the
11187
- * input type/format isn't a full date or the string is not a valid date.
11188
- *
11189
- * Why this exists: a parent (datepicker) can call `inputN.validate()` from
11190
- * inside its own `updated()` before this input's `updated()` has run
11191
- * `syncDateValues()` — so `_valueObject`/`_maxObject` are still `undefined`
11192
- * and range checks would otherwise silently no-op (flipping the result to
11193
- * `valid` or `patternMismatch`).
11194
- * @private
11195
- * @param {string|undefined} dateStr - ISO date string from `value`/`min`/`max`.
11196
- * @returns {Date|undefined}
11197
- */
11198
- _computeDateObjectFallback(dateStr) {
11199
- if (!dateStr || !this.util || !this.util.isFullDateFormat(this.type, this.format)) {
11200
- return undefined;
11201
- }
11202
- if (!dateFormatter$3.isValidDate(dateStr)) {
11203
- return undefined;
11204
- }
11205
- return dateFormatter$3.stringToDateInstance(dateStr);
11206
- }
11207
-
11208
- /**
11209
- * Internal setter for readonly date object properties.
11210
- * @private
11211
- * @param {'valueObject'|'minObject'|'maxObject'} propertyName - Public object property name.
11212
- * @param {Date|undefined} propertyValue - Value to assign.
11213
- * @returns {void}
11214
- */
11215
- setDateObjectProperty(propertyName, propertyValue) {
11216
- const internalPropertyName = `_${propertyName}`;
11217
- const previousValue = this[internalPropertyName];
11218
-
11219
- if (previousValue === propertyValue) {
11220
- return;
11221
- }
11222
-
11223
- this[internalPropertyName] = propertyValue;
11224
- this.requestUpdate(propertyName, previousValue);
11179
+ return this.max && dateFormatter$3.isValidDate(this.max) ? dateFormatter$3.stringToDateInstance(this.max) : undefined;
11225
11180
  }
11226
11181
 
11227
11182
  connectedCallback() {
@@ -11250,7 +11205,6 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
11250
11205
  format: this.format
11251
11206
  });
11252
11207
  this.configureDataForType();
11253
- this.syncDateValues();
11254
11208
  }
11255
11209
 
11256
11210
  disconnectedCallback() {
@@ -11270,10 +11224,6 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
11270
11224
  this.wrapperElement.addEventListener('click', this.handleClick);
11271
11225
  }
11272
11226
 
11273
- // add attribute for query selectors when auro-input is registered under a custom name
11274
- if (this.tagName.toLowerCase() !== 'auro-input' && !this.hasAttribute('auro-input')) {
11275
- this.setAttribute('auro-input', '');
11276
- }
11277
11227
  this.inputId = this.id ? `${this.id}-input` : window.crypto.randomUUID();
11278
11228
 
11279
11229
  // use validity message override if declared when initializing the component
@@ -11284,7 +11234,6 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
11284
11234
  this.setCustomHelpTextMessage();
11285
11235
  this.configureAutoFormatting();
11286
11236
  this.configureDataForType();
11287
- this.syncDateValues();
11288
11237
  }
11289
11238
 
11290
11239
  /**
@@ -11421,8 +11370,6 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
11421
11370
  this.configureDataForType();
11422
11371
  }
11423
11372
 
11424
- this.syncDateValues(changedProperties);
11425
-
11426
11373
  if (changedProperties.has('value')) {
11427
11374
  if (this.value && this.value.length > 0) {
11428
11375
  this.hasValue = true;
@@ -11444,14 +11391,14 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
11444
11391
 
11445
11392
  if (formattedValue !== this.inputElement.value) {
11446
11393
  this.skipNextProgrammaticInputEvent = true;
11447
- if (this.maskInstance && this.type === 'credit-card') {
11394
+ if (this.maskInstance && this.type !== 'date') {
11448
11395
  // Route through the mask so its _value and el.value stay in lock-step
11449
11396
  // (set value calls updateControl which writes el.value = displayValue).
11450
11397
  // Writing el.value directly leaves the mask thinking displayValue is
11451
- // stale; _saveSelection on the next focus/click then warns. Scoped to
11452
- // credit-card so date's own formattedValue (raw ISO when calendar-invalid)
11453
- // isn't re-masked through the mm/dd/yyyy mask, which would truncate it
11454
- // and flip validity from patternMismatch to tooShort.
11398
+ // stale; _saveSelection on the next focus/click then warns. Date is
11399
+ // excluded because its formattedValue can be raw ISO when the calendar
11400
+ // is invalid, and re-masking through mm/dd/yyyy would truncate it and
11401
+ // flip validity from patternMismatch to tooShort.
11455
11402
  this.maskInstance.value = formattedValue || '';
11456
11403
  } else if (formattedValue) {
11457
11404
  this.inputElement.value = formattedValue;
@@ -11493,120 +11440,60 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
11493
11440
  }));
11494
11441
  }
11495
11442
 
11496
-
11497
- /**
11498
- * Synchronizes the ISO string values and Date object representations for date-related properties.
11499
- * This keeps the model and display values aligned when either side changes.
11500
- *
11501
- * When a full date format is in use, this method updates `value`, `min`, and `max` from their corresponding
11502
- * Date objects or vice versa, based on which properties have changed. It only runs when the current configuration
11503
- * represents a full year/month/day date format.
11504
- *
11505
- * @param {Map<string, unknown>|undefined} [changedProperties=undefined] - Optional map of changed properties used to limit which values are synchronized.
11506
- * @returns {void}
11507
- * @private
11508
- */
11509
- syncDateValues(changedProperties = undefined) {
11510
- if (!this.util.isFullDateFormat(this.type, this.format)) {
11511
- return;
11512
- }
11513
-
11514
- this.syncSingleDateValue(changedProperties, 'valueObject', 'value');
11515
- this.syncSingleDateValue(changedProperties, 'minObject', 'min');
11516
- this.syncSingleDateValue(changedProperties, 'maxObject', 'max');
11517
- }
11518
-
11519
- /**
11520
- * Synchronizes one date object/string property pair.
11521
- * @private
11522
- * @param {Map<string, unknown>|undefined} changedProperties - Map of changed properties from Lit.
11523
- * @param {string} objectProperty - Date object property name.
11524
- * @param {string} valueProperty - ISO string property name.
11525
- * @returns {void}
11526
- */
11527
- syncSingleDateValue(changedProperties, objectProperty, valueProperty) {
11528
- const objectPropertyChanged = !changedProperties || changedProperties.has(objectProperty);
11529
-
11530
- // objectProperty wins over valueProperty when both changed
11531
- if (objectPropertyChanged && this[objectProperty]) {
11532
- this[valueProperty] = dateFormatter$3.toISOFormatString(this[objectProperty]);
11533
- return;
11534
- }
11535
-
11536
- const valuePropertyChanged = !changedProperties || changedProperties.has(valueProperty);
11537
- if (!valuePropertyChanged) {
11538
- return;
11539
- }
11540
-
11541
- // when value is newly set to the same ISO string that corresponds to the existing Date object, do not clear the Date object (avoid unnecessary updates)
11542
- if (
11543
- changedProperties &&
11544
- valueProperty === 'value' &&
11545
- changedProperties.get('value') === undefined &&
11546
- this[objectProperty] instanceof Date &&
11547
- this[valueProperty] === dateFormatter$3.toISOFormatString(this[objectProperty])
11548
- ) {
11549
- return;
11550
- }
11551
-
11552
- if (dateFormatter$3.isValidDate(this[valueProperty])) {
11553
- this.setDateObjectProperty(objectProperty, dateFormatter$3.stringToDateInstance(this[valueProperty]));
11554
- } else {
11555
- this.setDateObjectProperty(objectProperty, undefined);
11556
- }
11557
- }
11558
-
11559
11443
  /**
11560
11444
  * Sets up IMasks and logic based on auto-formatting requirements.
11561
11445
  * @private
11562
11446
  * @returns {void}
11563
11447
  */
11564
11448
  configureAutoFormatting() {
11565
- // Re-entrancy guard. The patched-setter's synthetic input event (suppressed
11566
- // by _configuringMask above) could otherwise trigger handleInput
11567
- // processCreditCard configureAutoFormatting before the outer call's
11568
- // set value has finished its alignCursor pass.
11449
+ // _configuringMask gates two things: external re-entry into this method
11450
+ // while setup is mid-flight (from property changes that call back here),
11451
+ // and the accept/complete listeners below — both need to ignore the mask
11452
+ // events fired by our own value-restore step.
11569
11453
  if (this._configuringMask) return;
11570
11454
  this._configuringMask = true;
11571
11455
  try {
11456
+ // Destroy any prior mask so IMask can attach fresh under the new format.
11572
11457
  if (this.maskInstance) {
11573
11458
  this.maskInstance.destroy();
11574
11459
  }
11575
11460
 
11576
- // Pass new format to util
11577
11461
  this.util.updateFormat(this.format);
11578
11462
 
11579
11463
  const maskOptions = this.util.getMaskOptions(this.type, this.format);
11580
11464
 
11581
11465
  if (this.inputElement && maskOptions.mask) {
11582
-
11583
- // Stash and clear any existing value before IMask init.
11584
- // IMask's constructor processes the current input value which requires
11585
- // selection state clearing first avoids that scenario entirely.
11586
- // When the format changes (e.g. locale switch) and we have a valid ISO
11587
- // model value, compute the display string for the NEW format instead of
11588
- // re-using the old display string, which may be invalid in the new mask.
11466
+ // Capture the current display so it can be re-applied after IMask
11467
+ // attaches. The restore at the bottom goes through maskInstance.value
11468
+ // (not inputElement.value directly) so the mask's internal state and
11469
+ // the input's displayed text stay in lock-step.
11589
11470
  let existingValue = this.inputElement.value;
11471
+
11472
+ // Format-change case (e.g. locale switch): existingValue is the OLD
11473
+ // mask's display string and may not parse under the new mask. When
11474
+ // we have a valid date model, rebuild the display from valueObject
11475
+ // (the canonical source) using the new mask's format function.
11590
11476
  if (
11591
11477
  this.util.isFullDateFormat(this.type, this.format) &&
11592
11478
  this.value &&
11593
- dateFormatter$3.isValidDate(this.value) &&
11594
- this.valueObject instanceof Date &&
11595
- !Number.isNaN(this.valueObject.getTime()) &&
11479
+ this.valueObject &&
11596
11480
  typeof maskOptions.format === 'function'
11597
11481
  ) {
11598
11482
  existingValue = maskOptions.format(this.valueObject);
11599
11483
  }
11600
11484
 
11485
+ // Clear before IMask attaches so the constructor seeds an empty
11486
+ // internal value. Otherwise IMask reads the stale unmasked string
11487
+ // and emits a spurious 'accept' before the restore below runs.
11601
11488
  this.skipNextProgrammaticInputEvent = true;
11602
11489
  this.inputElement.value = '';
11603
11490
 
11604
11491
  this.maskInstance = IMask$3(this.inputElement, maskOptions);
11605
11492
 
11493
+ // Mask fires 'accept' on every value change, including the restore
11494
+ // step below. Skip events fired during configureAutoFormatting so
11495
+ // we don't overwrite a value the parent just pushed.
11606
11496
  this.maskInstance.on('accept', () => {
11607
- // Suppress propagation during configureAutoFormatting's own value-restoration
11608
- // (line below) — the mask emits 'accept' on every value-set, including ours,
11609
- // and we don't want to overwrite a value the parent just pushed.
11610
11497
  if (this._configuringMask) return;
11611
11498
  this.value = this.util.toModelValue(this.maskInstance.value, this.format);
11612
11499
  if (this.type === "date") {
@@ -11614,6 +11501,8 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
11614
11501
  }
11615
11502
  });
11616
11503
 
11504
+ // Mask fires 'complete' on the restore step below for any value that
11505
+ // happens to be a complete match. Same setup-suppression as 'accept'.
11617
11506
  this.maskInstance.on('complete', () => {
11618
11507
  if (this._configuringMask) return;
11619
11508
  this.value = this.util.toModelValue(this.maskInstance.value, this.format);
@@ -11622,7 +11511,9 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
11622
11511
  }
11623
11512
  });
11624
11513
 
11625
- // Restore the stashed value through IMask so it's properly masked
11514
+ // Write existingValue through the mask (not the input directly) so
11515
+ // the mask reformats it under the new rules and keeps its internal
11516
+ // _value aligned with the input's displayed text.
11626
11517
  if (existingValue) {
11627
11518
  this.maskInstance.value = existingValue;
11628
11519
  }
@@ -11790,7 +11681,6 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
11790
11681
  */
11791
11682
  reset() {
11792
11683
  this.value = undefined;
11793
- this.setDateObjectProperty('valueObject', undefined);
11794
11684
  this.validation.reset(this);
11795
11685
  }
11796
11686
 
@@ -11799,7 +11689,6 @@ let BaseInput$2 = class BaseInput extends AuroElement$6 {
11799
11689
  */
11800
11690
  clear() {
11801
11691
  this.value = undefined;
11802
- this.setDateObjectProperty('valueObject', undefined);
11803
11692
  }
11804
11693
 
11805
11694
  /**
@@ -12328,7 +12217,7 @@ let AuroHelpText$8 = class AuroHelpText extends i$2 {
12328
12217
  }
12329
12218
  };
12330
12219
 
12331
- var formkitVersion$8 = '202606171946';
12220
+ var formkitVersion$8 = '202606192004';
12332
12221
 
12333
12222
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
12334
12223
  // See LICENSE in the project root for license information.
@@ -23567,6 +23456,7 @@ let AuroInputUtilities$1 = class AuroInputUtilities {
23567
23456
  const maskOptions = this.getMaskOptions('date', normalizedFormat);
23568
23457
 
23569
23458
  if (!(valueObject instanceof Date) || Number.isNaN(valueObject.getTime()) || !maskOptions || typeof maskOptions.format !== 'function') {
23459
+ console.debug('Invalid date object or mask options for formatting', { valueObject, maskOptions }); // eslint-disable-line no-console
23570
23460
  return undefined;
23571
23461
  }
23572
23462
 
@@ -26447,7 +26337,7 @@ let AuroBibtemplate$3 = class AuroBibtemplate extends i$2 {
26447
26337
  }
26448
26338
  };
26449
26339
 
26450
- var formkitVersion$2$1 = '202606171946';
26340
+ var formkitVersion$2$1 = '202606192004';
26451
26341
 
26452
26342
  let l$1$2 = class l{generateElementName(t,e){let o=t;return o+="-",o+=e.replace(/[.]/g,"_"),o}generateTag(o,s,a){const r=this.generateElementName(o,s),i=i$5`${s$5(r)}`;return customElements.get(r)||customElements.define(r,class extends a{}),i}};let d$1$2 = class d{registerComponent(t,e){customElements.get(t)||customElements.define(t,class extends e{});}closestElement(t,e=this,o=(e,s=e&&e.closest(t))=>e&&e!==document&&e!==window?s||o(e.getRootNode().host):null){return o(e)}handleComponentTagRename(t,e){const o=e.toLowerCase();t.tagName.toLowerCase()!==o&&t.setAttribute(o,true);}elementMatch(t,e){const o=e.toLowerCase();return t.tagName.toLowerCase()===o||t.hasAttribute(o)}getSlotText(t,e){const o=t.shadowRoot?.querySelector(`slot[name="${e}"]`),s=(o?.assignedNodes({flatten:true})||[]).map(t=>t.textContent?.trim()).join(" ").trim();return s||null}};let h$1$2 = class h{registerComponent(t,e){customElements.get(t)||customElements.define(t,class extends e{});}closestElement(t,e=this,o=(e,s=e&&e.closest(t))=>e&&e!==document&&e!==window?s||o(e.getRootNode().host):null){return o(e)}handleComponentTagRename(t,e){const o=e.toLowerCase();t.tagName.toLowerCase()!==o&&t.setAttribute(o,true);}elementMatch(t,e){const o=e.toLowerCase();return t.tagName.toLowerCase()===o||t.hasAttribute(o)}};var c$1$3=i$4`:host{color:var(--ds-auro-loader-color)}:host>span{background-color:var(--ds-auro-loader-background-color);border-color:var(--ds-auro-loader-border-color)}:host([onlight]),:host([appearance=brand]){--ds-auro-loader-color: var(--ds-basic-color-brand-primary, #01426a)}:host([ondark]),:host([appearance=inverse]){--ds-auro-loader-color: var(--ds-basic-color-texticon-inverse, #ffffff)}:host([orbit])>span{--ds-auro-loader-background-color: transparent}:host([orbit])>span:nth-child(1){--ds-auro-loader-border-color: currentcolor;opacity:.25}:host([orbit])>span:nth-child(2){--ds-auro-loader-border-color: currentcolor;border-right-color:transparent;border-bottom-color:transparent;border-left-color:transparent}
26453
26343
  `,u$4$2=i$4`.body-default{font-size:var(--wcss-body-default-font-size, 1rem);line-height:var(--wcss-body-default-line-height, 1.5rem)}.body-default,.body-lg{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-lg{font-size:var(--wcss-body-lg-font-size, 1.125rem);line-height:var(--wcss-body-lg-line-height, 1.625rem)}.body-sm{font-size:var(--wcss-body-sm-font-size, .875rem);line-height:var(--wcss-body-sm-line-height, 1.25rem)}.body-sm,.body-xs{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-xs{font-size:var(--wcss-body-xs-font-size, .75rem);line-height:var(--wcss-body-xs-line-height, 1rem)}.body-2xs{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-size:var(--wcss-body-2xs-font-size, .625rem);font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);line-height:var(--wcss-body-2xs-line-height, .875rem)}.display-2xl{font-family:var(--wcss-display-2xl-family, "AS Circular"),var(--wcss-display-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-2xl-font-size, clamp(3.5rem, 6vw, 5.375rem));font-weight:var(--wcss-display-2xl-weight, 300);letter-spacing:var(--wcss-display-2xl-letter-spacing, 0);line-height:var(--wcss-display-2xl-line-height, 1.3)}.display-xl{font-family:var(--wcss-display-xl-family, "AS Circular"),var(--wcss-display-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-xl-font-size, clamp(3rem, 5.3333333333vw, 4.5rem));font-weight:var(--wcss-display-xl-weight, 300);letter-spacing:var(--wcss-display-xl-letter-spacing, 0);line-height:var(--wcss-display-xl-line-height, 1.3)}.display-lg{font-family:var(--wcss-display-lg-family, "AS Circular"),var(--wcss-display-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-lg-font-size, clamp(2.75rem, 4.6666666667vw, 4rem));font-weight:var(--wcss-display-lg-weight, 300);letter-spacing:var(--wcss-display-lg-letter-spacing, 0);line-height:var(--wcss-display-lg-line-height, 1.3)}.display-md{font-family:var(--wcss-display-md-family, "AS Circular"),var(--wcss-display-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-md-font-size, clamp(2.5rem, 4vw, 3.5rem));font-weight:var(--wcss-display-md-weight, 300);letter-spacing:var(--wcss-display-md-letter-spacing, 0);line-height:var(--wcss-display-md-line-height, 1.3)}.display-sm{font-family:var(--wcss-display-sm-family, "AS Circular"),var(--wcss-display-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-sm-font-size, clamp(2rem, 3.6666666667vw, 3rem));font-weight:var(--wcss-display-sm-weight, 300);letter-spacing:var(--wcss-display-sm-letter-spacing, 0);line-height:var(--wcss-display-sm-line-height, 1.3)}.display-xs{font-family:var(--wcss-display-xs-family, "AS Circular"),var(--wcss-display-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-xs-font-size, clamp(1.75rem, 3vw, 2.375rem));font-weight:var(--wcss-display-xs-weight, 300);letter-spacing:var(--wcss-display-xs-letter-spacing, 0);line-height:var(--wcss-display-xs-line-height, 1.3)}.heading-xl{font-family:var(--wcss-heading-xl-family, "AS Circular"),var(--wcss-heading-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-xl-font-size, clamp(2rem, 3vw, 2.5rem));font-weight:var(--wcss-heading-xl-weight, 300);letter-spacing:var(--wcss-heading-xl-letter-spacing, 0);line-height:var(--wcss-heading-xl-line-height, 1.3)}.heading-lg{font-family:var(--wcss-heading-lg-family, "AS Circular"),var(--wcss-heading-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-lg-font-size, clamp(1.75rem, 2.6666666667vw, 2.25rem));font-weight:var(--wcss-heading-lg-weight, 300);letter-spacing:var(--wcss-heading-lg-letter-spacing, 0);line-height:var(--wcss-heading-lg-line-height, 1.3)}.heading-md{font-family:var(--wcss-heading-md-family, "AS Circular"),var(--wcss-heading-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-md-font-size, clamp(1.625rem, 2.3333333333vw, 1.75rem));font-weight:var(--wcss-heading-md-weight, 300);letter-spacing:var(--wcss-heading-md-letter-spacing, 0);line-height:var(--wcss-heading-md-line-height, 1.3)}.heading-sm{font-family:var(--wcss-heading-sm-family, "AS Circular"),var(--wcss-heading-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-sm-font-size, clamp(1.375rem, 2vw, 1.5rem));font-weight:var(--wcss-heading-sm-weight, 300);letter-spacing:var(--wcss-heading-sm-letter-spacing, 0);line-height:var(--wcss-heading-sm-line-height, 1.3)}.heading-xs{font-family:var(--wcss-heading-xs-family, "AS Circular"),var(--wcss-heading-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-xs-font-size, clamp(1.25rem, 1.6666666667vw, 1.25rem));font-weight:var(--wcss-heading-xs-weight, 450);letter-spacing:var(--wcss-heading-xs-letter-spacing, 0);line-height:var(--wcss-heading-xs-line-height, 1.3)}.heading-2xs{font-family:var(--wcss-heading-2xs-family, "AS Circular"),var(--wcss-heading-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-2xs-font-size, clamp(1.125rem, 1.5vw, 1.125rem));font-weight:var(--wcss-heading-2xs-weight, 450);letter-spacing:var(--wcss-heading-2xs-letter-spacing, 0);line-height:var(--wcss-heading-2xs-line-height, 1.3)}.accent-2xl{font-family:var(--wcss-accent-2xl-family, "Good OT"),var(--wcss-accent-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-2xl-font-size, clamp(2rem, 3.1666666667vw, 2.375rem));font-weight:var(--wcss-accent-2xl-weight, 450);letter-spacing:var(--wcss-accent-2xl-letter-spacing, .05em);line-height:var(--wcss-accent-2xl-line-height, 1)}.accent-2xl,.accent-xl{text-transform:uppercase}.accent-xl{font-family:var(--wcss-accent-xl-family, "Good OT"),var(--wcss-accent-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-xl-font-size, clamp(1.625rem, 2.3333333333vw, 2rem));font-weight:var(--wcss-accent-xl-weight, 450);letter-spacing:var(--wcss-accent-xl-letter-spacing, .05em);line-height:var(--wcss-accent-xl-line-height, 1.3)}.accent-lg{font-family:var(--wcss-accent-lg-family, "Good OT"),var(--wcss-accent-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-lg-font-size, clamp(1.5rem, 2.1666666667vw, 1.75rem));font-weight:var(--wcss-accent-lg-weight, 450);letter-spacing:var(--wcss-accent-lg-letter-spacing, .05em);line-height:var(--wcss-accent-lg-line-height, 1.3)}.accent-lg,.accent-md{text-transform:uppercase}.accent-md{font-family:var(--wcss-accent-md-family, "Good OT"),var(--wcss-accent-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-md-font-size, clamp(1.375rem, 1.8333333333vw, 1.5rem));font-weight:var(--wcss-accent-md-weight, 500);letter-spacing:var(--wcss-accent-md-letter-spacing, .05em);line-height:var(--wcss-accent-md-line-height, 1.3)}.accent-sm{font-family:var(--wcss-accent-sm-family, "Good OT"),var(--wcss-accent-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-sm-font-size, clamp(1.125rem, 1.5vw, 1.25rem));font-weight:var(--wcss-accent-sm-weight, 500);letter-spacing:var(--wcss-accent-sm-letter-spacing, .05em);line-height:var(--wcss-accent-sm-line-height, 1.3)}.accent-sm,.accent-xs{text-transform:uppercase}.accent-xs{font-family:var(--wcss-accent-xs-family, "Good OT"),var(--wcss-accent-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-xs-font-size, clamp(1rem, 1.3333333333vw, 1rem));font-weight:var(--wcss-accent-xs-weight, 500);letter-spacing:var(--wcss-accent-xs-letter-spacing, .1em);line-height:var(--wcss-accent-xs-line-height, 1.3)}.accent-2xs{font-family:var(--wcss-accent-2xs-family, "Good OT"),var(--wcss-accent-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-2xs-font-size, clamp(.875rem, 1.1666666667vw, .875rem));font-weight:var(--wcss-accent-2xs-weight, 450);letter-spacing:var(--wcss-accent-2xs-letter-spacing, .1em);line-height:var(--wcss-accent-2xs-line-height, 1.3);text-transform:uppercase}:focus:not(:focus-visible){outline:3px solid transparent}:host,:host>span{position:relative}:host{width:2rem;height:2rem;display:inline-block;font-size:0}:host>span{position:absolute;display:inline-block;float:none;top:0;left:0;width:2rem;height:2rem;border-radius:100%;border-style:solid;border-width:0;box-sizing:border-box}:host([xs]),:host([xs])>span{width:1.2rem;height:1.2rem}:host([sm]),:host([sm])>span{width:3rem;height:3rem}:host([md]),:host([md])>span{width:5rem;height:5rem}:host([lg]),:host([lg])>span{width:8rem;height:8rem}:host{--margin: .375rem;--margin-xs: .2rem;--margin-sm: .5rem;--margin-md: .75rem;--margin-lg: 1rem}:host([pulse]),:host([pulse])>span{position:relative}:host([pulse]){width:calc(3rem + var(--margin) * 6);height:calc(1rem + var(--margin) * 2)}:host([pulse])>span{width:1rem;height:1rem;margin:var(--margin);animation:pulse 1.5s ease infinite}:host([pulse][xs]){width:calc(1.95rem + var(--margin-xs) * 6);height:calc(.65rem + var(--margin-xs) * 2)}:host([pulse][xs])>span{margin:var(--margin-xs);width:.65rem;height:.65rem}:host([pulse][sm]){width:calc(6rem + var(--margin-sm) * 6);height:calc(2rem + var(--margin-sm) * 2)}:host([pulse][sm])>span{margin:var(--margin-sm);width:2rem;height:2rem}:host([pulse][md]){width:calc(9rem + var(--margin-md) * 6);height:calc(3rem + var(--margin-md) * 2)}:host([pulse][md])>span{margin:var(--margin-md);width:3rem;height:3rem}:host([pulse][lg]){width:calc(15rem + var(--margin-lg) * 6);height:calc(5rem + var(--margin-lg) * 2)}:host([pulse][lg])>span{margin:var(--margin-lg);width:5rem;height:5rem}:host([pulse])>span:nth-child(1){animation-delay:-.4s}:host([pulse])>span:nth-child(2){animation-delay:-.2s}:host([pulse])>span:nth-child(3){animation-delay:0ms}@keyframes pulse{0%,to{opacity:.1;transform:scale(.9)}50%{opacity:1;transform:scale(1.1)}}:host([orbit]),:host([orbit])>span{opacity:1}:host([orbit])>span{border-width:5px}:host([orbit])>span:nth-child(2){animation:orbit 2s linear infinite}:host([orbit][sm])>span{border-width:8px}:host([orbit][md])>span{border-width:13px}:host([orbit][lg])>span{border-width:21px}@keyframes orbit{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host([ringworm])>svg{animation:rotate 2s linear infinite;height:100%;width:100%;stroke:currentcolor;stroke-width:8}:host([ringworm]) .path{stroke-dashoffset:0;animation:ringworm 1.5s ease-in-out infinite;stroke-linecap:round}@keyframes rotate{to{transform:rotate(360deg)}}@keyframes ringworm{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:89,200;stroke-dashoffset:-35px}to{stroke-dasharray:89,200;stroke-dashoffset:-124px}}:host([laser]){position:static;width:100%;display:block;height:0;overflow:hidden;font-size:unset}:host([laser])>span{position:fixed;width:100%;height:.25rem;border-radius:0;z-index:100}:host([laser])>span:nth-child(1){border-color:currentcolor;opacity:.25}:host([laser])>span:nth-child(2){border-color:currentcolor;animation:laser 2s linear infinite;opacity:1;width:50%}:host([laser][sm])>span:nth-child(2){width:20%}:host([laser][md])>span:nth-child(2){width:30%}:host([laser][lg])>span:nth-child(2){width:50%;animation-duration:1.5s}:host([laser][xl])>span:nth-child(2){width:80%;animation-duration:1.5s}@keyframes laser{0%{left:-100%}to{left:110%}}:host>.no-animation{display:none}@media (prefers-reduced-motion: reduce){:host{display:flex;align-items:center;justify-content:center}:host>span{opacity:1}:host>.loader{display:none}:host>svg{display:none}:host>.no-animation{display:block}}
@@ -31958,7 +31848,7 @@ let AuroHelpText$2$1 = class AuroHelpText extends i$2 {
31958
31848
  }
31959
31849
  };
31960
31850
 
31961
- var formkitVersion$1$3 = '202606171946';
31851
+ var formkitVersion$1$3 = '202606192004';
31962
31852
 
31963
31853
  let AuroElement$2$2 = class AuroElement extends i$2 {
31964
31854
  static get properties() {
@@ -43672,6 +43562,7 @@ let AuroInputUtilities$2 = class AuroInputUtilities {
43672
43562
  const maskOptions = this.getMaskOptions('date', normalizedFormat);
43673
43563
 
43674
43564
  if (!(valueObject instanceof Date) || Number.isNaN(valueObject.getTime()) || !maskOptions || typeof maskOptions.format !== 'function') {
43565
+ console.debug('Invalid date object or mask options for formatting', { valueObject, maskOptions }); // eslint-disable-line no-console
43675
43566
  return undefined;
43676
43567
  }
43677
43568
 
@@ -43823,10 +43714,8 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
43823
43714
  this.layout = 'classic';
43824
43715
  this.locale = 'en-US';
43825
43716
  this.max = undefined;
43826
- this._maxObject = undefined;
43827
43717
  this.maxLength = undefined;
43828
43718
  this.min = undefined;
43829
- this._minObject = undefined;
43830
43719
  this.minLength = undefined;
43831
43720
  this.required = false;
43832
43721
  this.onDark = false;
@@ -43834,7 +43723,6 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
43834
43723
  this.size = 'lg';
43835
43724
  this.shape = 'classic';
43836
43725
  this.value = undefined;
43837
- this._valueObject = undefined;
43838
43726
 
43839
43727
  this._initializePrivateDefaults();
43840
43728
  }
@@ -44374,7 +44262,7 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
44374
44262
  * @returns {Date|undefined}
44375
44263
  */
44376
44264
  get valueObject() {
44377
- return this._valueObject || this._computeDateObjectFallback(this.value);
44265
+ return this.value && dateFormatter$2.isValidDate(this.value) ? dateFormatter$2.stringToDateInstance(this.value) : undefined;
44378
44266
  }
44379
44267
 
44380
44268
  /**
@@ -44382,7 +44270,7 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
44382
44270
  * @returns {Date|undefined}
44383
44271
  */
44384
44272
  get minObject() {
44385
- return this._minObject || this._computeDateObjectFallback(this.min);
44273
+ return this.min && dateFormatter$2.isValidDate(this.min) ? dateFormatter$2.stringToDateInstance(this.min) : undefined;
44386
44274
  }
44387
44275
 
44388
44276
  /**
@@ -44390,50 +44278,7 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
44390
44278
  * @returns {Date|undefined}
44391
44279
  */
44392
44280
  get maxObject() {
44393
- return this._maxObject || this._computeDateObjectFallback(this.max);
44394
- }
44395
-
44396
- /**
44397
- * Parses a date string into a Date object when the corresponding `_*Object`
44398
- * field hasn't been synced yet by `updated()`. Returns undefined when the
44399
- * input type/format isn't a full date or the string is not a valid date.
44400
- *
44401
- * Why this exists: a parent (datepicker) can call `inputN.validate()` from
44402
- * inside its own `updated()` before this input's `updated()` has run
44403
- * `syncDateValues()` — so `_valueObject`/`_maxObject` are still `undefined`
44404
- * and range checks would otherwise silently no-op (flipping the result to
44405
- * `valid` or `patternMismatch`).
44406
- * @private
44407
- * @param {string|undefined} dateStr - ISO date string from `value`/`min`/`max`.
44408
- * @returns {Date|undefined}
44409
- */
44410
- _computeDateObjectFallback(dateStr) {
44411
- if (!dateStr || !this.util || !this.util.isFullDateFormat(this.type, this.format)) {
44412
- return undefined;
44413
- }
44414
- if (!dateFormatter$2.isValidDate(dateStr)) {
44415
- return undefined;
44416
- }
44417
- return dateFormatter$2.stringToDateInstance(dateStr);
44418
- }
44419
-
44420
- /**
44421
- * Internal setter for readonly date object properties.
44422
- * @private
44423
- * @param {'valueObject'|'minObject'|'maxObject'} propertyName - Public object property name.
44424
- * @param {Date|undefined} propertyValue - Value to assign.
44425
- * @returns {void}
44426
- */
44427
- setDateObjectProperty(propertyName, propertyValue) {
44428
- const internalPropertyName = `_${propertyName}`;
44429
- const previousValue = this[internalPropertyName];
44430
-
44431
- if (previousValue === propertyValue) {
44432
- return;
44433
- }
44434
-
44435
- this[internalPropertyName] = propertyValue;
44436
- this.requestUpdate(propertyName, previousValue);
44281
+ return this.max && dateFormatter$2.isValidDate(this.max) ? dateFormatter$2.stringToDateInstance(this.max) : undefined;
44437
44282
  }
44438
44283
 
44439
44284
  connectedCallback() {
@@ -44462,7 +44307,6 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
44462
44307
  format: this.format
44463
44308
  });
44464
44309
  this.configureDataForType();
44465
- this.syncDateValues();
44466
44310
  }
44467
44311
 
44468
44312
  disconnectedCallback() {
@@ -44482,10 +44326,6 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
44482
44326
  this.wrapperElement.addEventListener('click', this.handleClick);
44483
44327
  }
44484
44328
 
44485
- // add attribute for query selectors when auro-input is registered under a custom name
44486
- if (this.tagName.toLowerCase() !== 'auro-input' && !this.hasAttribute('auro-input')) {
44487
- this.setAttribute('auro-input', '');
44488
- }
44489
44329
  this.inputId = this.id ? `${this.id}-input` : window.crypto.randomUUID();
44490
44330
 
44491
44331
  // use validity message override if declared when initializing the component
@@ -44496,7 +44336,6 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
44496
44336
  this.setCustomHelpTextMessage();
44497
44337
  this.configureAutoFormatting();
44498
44338
  this.configureDataForType();
44499
- this.syncDateValues();
44500
44339
  }
44501
44340
 
44502
44341
  /**
@@ -44633,8 +44472,6 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
44633
44472
  this.configureDataForType();
44634
44473
  }
44635
44474
 
44636
- this.syncDateValues(changedProperties);
44637
-
44638
44475
  if (changedProperties.has('value')) {
44639
44476
  if (this.value && this.value.length > 0) {
44640
44477
  this.hasValue = true;
@@ -44656,14 +44493,14 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
44656
44493
 
44657
44494
  if (formattedValue !== this.inputElement.value) {
44658
44495
  this.skipNextProgrammaticInputEvent = true;
44659
- if (this.maskInstance && this.type === 'credit-card') {
44496
+ if (this.maskInstance && this.type !== 'date') {
44660
44497
  // Route through the mask so its _value and el.value stay in lock-step
44661
44498
  // (set value calls updateControl which writes el.value = displayValue).
44662
44499
  // Writing el.value directly leaves the mask thinking displayValue is
44663
- // stale; _saveSelection on the next focus/click then warns. Scoped to
44664
- // credit-card so date's own formattedValue (raw ISO when calendar-invalid)
44665
- // isn't re-masked through the mm/dd/yyyy mask, which would truncate it
44666
- // and flip validity from patternMismatch to tooShort.
44500
+ // stale; _saveSelection on the next focus/click then warns. Date is
44501
+ // excluded because its formattedValue can be raw ISO when the calendar
44502
+ // is invalid, and re-masking through mm/dd/yyyy would truncate it and
44503
+ // flip validity from patternMismatch to tooShort.
44667
44504
  this.maskInstance.value = formattedValue || '';
44668
44505
  } else if (formattedValue) {
44669
44506
  this.inputElement.value = formattedValue;
@@ -44705,120 +44542,60 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
44705
44542
  }));
44706
44543
  }
44707
44544
 
44708
-
44709
- /**
44710
- * Synchronizes the ISO string values and Date object representations for date-related properties.
44711
- * This keeps the model and display values aligned when either side changes.
44712
- *
44713
- * When a full date format is in use, this method updates `value`, `min`, and `max` from their corresponding
44714
- * Date objects or vice versa, based on which properties have changed. It only runs when the current configuration
44715
- * represents a full year/month/day date format.
44716
- *
44717
- * @param {Map<string, unknown>|undefined} [changedProperties=undefined] - Optional map of changed properties used to limit which values are synchronized.
44718
- * @returns {void}
44719
- * @private
44720
- */
44721
- syncDateValues(changedProperties = undefined) {
44722
- if (!this.util.isFullDateFormat(this.type, this.format)) {
44723
- return;
44724
- }
44725
-
44726
- this.syncSingleDateValue(changedProperties, 'valueObject', 'value');
44727
- this.syncSingleDateValue(changedProperties, 'minObject', 'min');
44728
- this.syncSingleDateValue(changedProperties, 'maxObject', 'max');
44729
- }
44730
-
44731
- /**
44732
- * Synchronizes one date object/string property pair.
44733
- * @private
44734
- * @param {Map<string, unknown>|undefined} changedProperties - Map of changed properties from Lit.
44735
- * @param {string} objectProperty - Date object property name.
44736
- * @param {string} valueProperty - ISO string property name.
44737
- * @returns {void}
44738
- */
44739
- syncSingleDateValue(changedProperties, objectProperty, valueProperty) {
44740
- const objectPropertyChanged = !changedProperties || changedProperties.has(objectProperty);
44741
-
44742
- // objectProperty wins over valueProperty when both changed
44743
- if (objectPropertyChanged && this[objectProperty]) {
44744
- this[valueProperty] = dateFormatter$2.toISOFormatString(this[objectProperty]);
44745
- return;
44746
- }
44747
-
44748
- const valuePropertyChanged = !changedProperties || changedProperties.has(valueProperty);
44749
- if (!valuePropertyChanged) {
44750
- return;
44751
- }
44752
-
44753
- // when value is newly set to the same ISO string that corresponds to the existing Date object, do not clear the Date object (avoid unnecessary updates)
44754
- if (
44755
- changedProperties &&
44756
- valueProperty === 'value' &&
44757
- changedProperties.get('value') === undefined &&
44758
- this[objectProperty] instanceof Date &&
44759
- this[valueProperty] === dateFormatter$2.toISOFormatString(this[objectProperty])
44760
- ) {
44761
- return;
44762
- }
44763
-
44764
- if (dateFormatter$2.isValidDate(this[valueProperty])) {
44765
- this.setDateObjectProperty(objectProperty, dateFormatter$2.stringToDateInstance(this[valueProperty]));
44766
- } else {
44767
- this.setDateObjectProperty(objectProperty, undefined);
44768
- }
44769
- }
44770
-
44771
44545
  /**
44772
44546
  * Sets up IMasks and logic based on auto-formatting requirements.
44773
44547
  * @private
44774
44548
  * @returns {void}
44775
44549
  */
44776
44550
  configureAutoFormatting() {
44777
- // Re-entrancy guard. The patched-setter's synthetic input event (suppressed
44778
- // by _configuringMask above) could otherwise trigger handleInput
44779
- // processCreditCard configureAutoFormatting before the outer call's
44780
- // set value has finished its alignCursor pass.
44551
+ // _configuringMask gates two things: external re-entry into this method
44552
+ // while setup is mid-flight (from property changes that call back here),
44553
+ // and the accept/complete listeners below — both need to ignore the mask
44554
+ // events fired by our own value-restore step.
44781
44555
  if (this._configuringMask) return;
44782
44556
  this._configuringMask = true;
44783
44557
  try {
44558
+ // Destroy any prior mask so IMask can attach fresh under the new format.
44784
44559
  if (this.maskInstance) {
44785
44560
  this.maskInstance.destroy();
44786
44561
  }
44787
44562
 
44788
- // Pass new format to util
44789
44563
  this.util.updateFormat(this.format);
44790
44564
 
44791
44565
  const maskOptions = this.util.getMaskOptions(this.type, this.format);
44792
44566
 
44793
44567
  if (this.inputElement && maskOptions.mask) {
44794
-
44795
- // Stash and clear any existing value before IMask init.
44796
- // IMask's constructor processes the current input value which requires
44797
- // selection state clearing first avoids that scenario entirely.
44798
- // When the format changes (e.g. locale switch) and we have a valid ISO
44799
- // model value, compute the display string for the NEW format instead of
44800
- // re-using the old display string, which may be invalid in the new mask.
44568
+ // Capture the current display so it can be re-applied after IMask
44569
+ // attaches. The restore at the bottom goes through maskInstance.value
44570
+ // (not inputElement.value directly) so the mask's internal state and
44571
+ // the input's displayed text stay in lock-step.
44801
44572
  let existingValue = this.inputElement.value;
44573
+
44574
+ // Format-change case (e.g. locale switch): existingValue is the OLD
44575
+ // mask's display string and may not parse under the new mask. When
44576
+ // we have a valid date model, rebuild the display from valueObject
44577
+ // (the canonical source) using the new mask's format function.
44802
44578
  if (
44803
44579
  this.util.isFullDateFormat(this.type, this.format) &&
44804
44580
  this.value &&
44805
- dateFormatter$2.isValidDate(this.value) &&
44806
- this.valueObject instanceof Date &&
44807
- !Number.isNaN(this.valueObject.getTime()) &&
44581
+ this.valueObject &&
44808
44582
  typeof maskOptions.format === 'function'
44809
44583
  ) {
44810
44584
  existingValue = maskOptions.format(this.valueObject);
44811
44585
  }
44812
44586
 
44587
+ // Clear before IMask attaches so the constructor seeds an empty
44588
+ // internal value. Otherwise IMask reads the stale unmasked string
44589
+ // and emits a spurious 'accept' before the restore below runs.
44813
44590
  this.skipNextProgrammaticInputEvent = true;
44814
44591
  this.inputElement.value = '';
44815
44592
 
44816
44593
  this.maskInstance = IMask$2(this.inputElement, maskOptions);
44817
44594
 
44595
+ // Mask fires 'accept' on every value change, including the restore
44596
+ // step below. Skip events fired during configureAutoFormatting so
44597
+ // we don't overwrite a value the parent just pushed.
44818
44598
  this.maskInstance.on('accept', () => {
44819
- // Suppress propagation during configureAutoFormatting's own value-restoration
44820
- // (line below) — the mask emits 'accept' on every value-set, including ours,
44821
- // and we don't want to overwrite a value the parent just pushed.
44822
44599
  if (this._configuringMask) return;
44823
44600
  this.value = this.util.toModelValue(this.maskInstance.value, this.format);
44824
44601
  if (this.type === "date") {
@@ -44826,6 +44603,8 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
44826
44603
  }
44827
44604
  });
44828
44605
 
44606
+ // Mask fires 'complete' on the restore step below for any value that
44607
+ // happens to be a complete match. Same setup-suppression as 'accept'.
44829
44608
  this.maskInstance.on('complete', () => {
44830
44609
  if (this._configuringMask) return;
44831
44610
  this.value = this.util.toModelValue(this.maskInstance.value, this.format);
@@ -44834,7 +44613,9 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
44834
44613
  }
44835
44614
  });
44836
44615
 
44837
- // Restore the stashed value through IMask so it's properly masked
44616
+ // Write existingValue through the mask (not the input directly) so
44617
+ // the mask reformats it under the new rules and keeps its internal
44618
+ // _value aligned with the input's displayed text.
44838
44619
  if (existingValue) {
44839
44620
  this.maskInstance.value = existingValue;
44840
44621
  }
@@ -45002,7 +44783,6 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
45002
44783
  */
45003
44784
  reset() {
45004
44785
  this.value = undefined;
45005
- this.setDateObjectProperty('valueObject', undefined);
45006
44786
  this.validation.reset(this);
45007
44787
  }
45008
44788
 
@@ -45011,7 +44791,6 @@ let BaseInput$1 = class BaseInput extends AuroElement$1$3 {
45011
44791
  */
45012
44792
  clear() {
45013
44793
  this.value = undefined;
45014
- this.setDateObjectProperty('valueObject', undefined);
45015
44794
  }
45016
44795
 
45017
44796
  /**
@@ -45540,7 +45319,7 @@ let AuroHelpText$1$3 = class AuroHelpText extends i$2 {
45540
45319
  }
45541
45320
  };
45542
45321
 
45543
- var formkitVersion$7 = '202606171946';
45322
+ var formkitVersion$7 = '202606192004';
45544
45323
 
45545
45324
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
45546
45325
  // See LICENSE in the project root for license information.
@@ -46960,8 +46739,6 @@ const datepickerKeyboardStrategy = {
46960
46739
  * @slot label - Defines the label content for the entire datepicker when `layout="snowflake"`.
46961
46740
  * @slot toLabel - Defines the label content for the second input when the `range` attribute is used.
46962
46741
  * @slot fromLabel - Defines the label content for the first input.
46963
- * @slot optionalFromLabel - Overrides the "(optional)" text rendered next to the first input's label when the datepicker is not `required`.
46964
- * @slot optionalToLabel - Overrides the "(optional)" text rendered next to the second input's label when `range` is set and the datepicker is not `required`.
46965
46742
  * @slot date_YYYY_MM_DD - Defines the content to display in the auro-calendar-cell for the specified date. The content text is colored using the success state token when the `highlight` attribute is applied to the slot.
46966
46743
  * @slot popover_YYYY_MM_DD - Defines the content to display in the auro-calendar-cell popover for the specified date.
46967
46744
  * @csspart dropdown - Use for customizing the style of the dropdown.
@@ -48557,9 +48334,7 @@ class AuroDatePicker extends AuroElement$5 {
48557
48334
  // update the calendar
48558
48335
  if (this.valueEndObject) {
48559
48336
  this.calendar.dateTo = this.convertToWcValidTime(this.valueEndObject);
48560
- if (!(this.wasCellClick && this.range)) {
48561
- this.calendarRenderUtil.updateCentralDate(this, this.valueEndObject);
48562
- }
48337
+ this.calendarRenderUtil.updateCentralDate(this, this.valueEndObject);
48563
48338
  } else {
48564
48339
  if (this.inputList[1].value !== this.valueEnd) {
48565
48340
  this.inputList[1].value = this.valueEnd || '';
@@ -48954,7 +48729,6 @@ class AuroDatePicker extends AuroElement$5 {
48954
48729
  }
48955
48730
  <span slot="ariaLabel.clear">${this.runtimeUtils.getSlotText(this, 'ariaLabel.input.clear') || i18n$2(this.lang, 'clearInput')}</span>
48956
48731
  <span slot="label"><slot name="fromLabel"></slot></span>
48957
- <span slot="optionalLabel"><slot name="optionalFromLabel"> (optional)</slot></span>
48958
48732
  </${this.inputTag}>
48959
48733
  </div>
48960
48734
 
@@ -48999,7 +48773,6 @@ class AuroDatePicker extends AuroElement$5 {
48999
48773
  }
49000
48774
  <span slot="ariaLabel.clear">${this.runtimeUtils.getSlotText(this, 'ariaLabel.input.clear') || this.runtimeUtils.getSlotText(this, 'ariaLabel.input.clear') || i18n$2(this.lang, 'clearInput')}</span>
49001
48775
  <span slot="label"><slot name="toLabel"></slot></span>
49002
- <span slot="optionalLabel"><slot name="optionalToLabel"> (optional)</slot></span>
49003
48776
  </${this.inputTag}>
49004
48777
  </div>
49005
48778
  ` : undefined}
@@ -50243,7 +50016,7 @@ let AuroHelpText$1$2 = class AuroHelpText extends i$2 {
50243
50016
  }
50244
50017
  };
50245
50018
 
50246
- var formkitVersion$1$2 = '202606171946';
50019
+ var formkitVersion$1$2 = '202606192004';
50247
50020
 
50248
50021
  // Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
50249
50022
  // See LICENSE in the project root for license information.
@@ -54571,7 +54344,7 @@ let AuroHelpText$6 = class AuroHelpText extends i$2 {
54571
54344
  }
54572
54345
  };
54573
54346
 
54574
- var formkitVersion$6 = '202606171946';
54347
+ var formkitVersion$6 = '202606192004';
54575
54348
 
54576
54349
  let AuroElement$1$2 = class AuroElement extends i$2 {
54577
54350
  static get properties() {
@@ -58503,7 +58276,7 @@ let AuroHelpText$5 = class AuroHelpText extends i$2 {
58503
58276
  }
58504
58277
  };
58505
58278
 
58506
- var formkitVersion$5 = '202606171946';
58279
+ var formkitVersion$5 = '202606192004';
58507
58280
 
58508
58281
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
58509
58282
  // See LICENSE in the project root for license information.
@@ -60253,7 +60026,7 @@ let AuroHelpText$4 = class AuroHelpText extends i$2 {
60253
60026
  }
60254
60027
  };
60255
60028
 
60256
- var formkitVersion$4 = '202606171946';
60029
+ var formkitVersion$4 = '202606192004';
60257
60030
 
60258
60031
  // Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
60259
60032
  // See LICENSE in the project root for license information.
@@ -61429,6 +61202,8 @@ function navigateArrow$1(component, direction, options = {}) {
61429
61202
  }
61430
61203
  }
61431
61204
 
61205
+ /* eslint-disable no-underscore-dangle */
61206
+
61432
61207
  /**
61433
61208
  * Returns the clear button element from the active input's shadow
61434
61209
  * DOM, if available.
@@ -61464,11 +61239,9 @@ function isClearBtnFocused(ctx, clearBtn = getClearBtn(ctx)) {
61464
61239
  * @param {Object} menu - The menu component.
61465
61240
  */
61466
61241
  function reconcileMenuIndex(menu) {
61467
- // eslint-disable-next-line no-underscore-dangle
61468
61242
  if (menu._index < 0 && menu.optionActive && menu.items) {
61469
61243
  const idx = menu.items.indexOf(menu.optionActive);
61470
61244
  if (idx >= 0) {
61471
- // eslint-disable-next-line no-underscore-dangle
61472
61245
  menu._index = idx;
61473
61246
  }
61474
61247
  }
@@ -65468,7 +65241,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$2 {
65468
65241
  }
65469
65242
  };
65470
65243
 
65471
- var formkitVersion$2 = '202606171946';
65244
+ var formkitVersion$2 = '202606192004';
65472
65245
 
65473
65246
  let AuroElement$2$1 = class AuroElement extends i$2 {
65474
65247
  static get properties() {
@@ -77182,6 +76955,7 @@ class AuroInputUtilities {
77182
76955
  const maskOptions = this.getMaskOptions('date', normalizedFormat);
77183
76956
 
77184
76957
  if (!(valueObject instanceof Date) || Number.isNaN(valueObject.getTime()) || !maskOptions || typeof maskOptions.format !== 'function') {
76958
+ console.debug('Invalid date object or mask options for formatting', { valueObject, maskOptions }); // eslint-disable-line no-console
77185
76959
  return undefined;
77186
76960
  }
77187
76961
 
@@ -77333,10 +77107,8 @@ class BaseInput extends AuroElement$1$1 {
77333
77107
  this.layout = 'classic';
77334
77108
  this.locale = 'en-US';
77335
77109
  this.max = undefined;
77336
- this._maxObject = undefined;
77337
77110
  this.maxLength = undefined;
77338
77111
  this.min = undefined;
77339
- this._minObject = undefined;
77340
77112
  this.minLength = undefined;
77341
77113
  this.required = false;
77342
77114
  this.onDark = false;
@@ -77344,7 +77116,6 @@ class BaseInput extends AuroElement$1$1 {
77344
77116
  this.size = 'lg';
77345
77117
  this.shape = 'classic';
77346
77118
  this.value = undefined;
77347
- this._valueObject = undefined;
77348
77119
 
77349
77120
  this._initializePrivateDefaults();
77350
77121
  }
@@ -77884,7 +77655,7 @@ class BaseInput extends AuroElement$1$1 {
77884
77655
  * @returns {Date|undefined}
77885
77656
  */
77886
77657
  get valueObject() {
77887
- return this._valueObject || this._computeDateObjectFallback(this.value);
77658
+ return this.value && dateFormatter.isValidDate(this.value) ? dateFormatter.stringToDateInstance(this.value) : undefined;
77888
77659
  }
77889
77660
 
77890
77661
  /**
@@ -77892,7 +77663,7 @@ class BaseInput extends AuroElement$1$1 {
77892
77663
  * @returns {Date|undefined}
77893
77664
  */
77894
77665
  get minObject() {
77895
- return this._minObject || this._computeDateObjectFallback(this.min);
77666
+ return this.min && dateFormatter.isValidDate(this.min) ? dateFormatter.stringToDateInstance(this.min) : undefined;
77896
77667
  }
77897
77668
 
77898
77669
  /**
@@ -77900,50 +77671,7 @@ class BaseInput extends AuroElement$1$1 {
77900
77671
  * @returns {Date|undefined}
77901
77672
  */
77902
77673
  get maxObject() {
77903
- return this._maxObject || this._computeDateObjectFallback(this.max);
77904
- }
77905
-
77906
- /**
77907
- * Parses a date string into a Date object when the corresponding `_*Object`
77908
- * field hasn't been synced yet by `updated()`. Returns undefined when the
77909
- * input type/format isn't a full date or the string is not a valid date.
77910
- *
77911
- * Why this exists: a parent (datepicker) can call `inputN.validate()` from
77912
- * inside its own `updated()` before this input's `updated()` has run
77913
- * `syncDateValues()` — so `_valueObject`/`_maxObject` are still `undefined`
77914
- * and range checks would otherwise silently no-op (flipping the result to
77915
- * `valid` or `patternMismatch`).
77916
- * @private
77917
- * @param {string|undefined} dateStr - ISO date string from `value`/`min`/`max`.
77918
- * @returns {Date|undefined}
77919
- */
77920
- _computeDateObjectFallback(dateStr) {
77921
- if (!dateStr || !this.util || !this.util.isFullDateFormat(this.type, this.format)) {
77922
- return undefined;
77923
- }
77924
- if (!dateFormatter.isValidDate(dateStr)) {
77925
- return undefined;
77926
- }
77927
- return dateFormatter.stringToDateInstance(dateStr);
77928
- }
77929
-
77930
- /**
77931
- * Internal setter for readonly date object properties.
77932
- * @private
77933
- * @param {'valueObject'|'minObject'|'maxObject'} propertyName - Public object property name.
77934
- * @param {Date|undefined} propertyValue - Value to assign.
77935
- * @returns {void}
77936
- */
77937
- setDateObjectProperty(propertyName, propertyValue) {
77938
- const internalPropertyName = `_${propertyName}`;
77939
- const previousValue = this[internalPropertyName];
77940
-
77941
- if (previousValue === propertyValue) {
77942
- return;
77943
- }
77944
-
77945
- this[internalPropertyName] = propertyValue;
77946
- this.requestUpdate(propertyName, previousValue);
77674
+ return this.max && dateFormatter.isValidDate(this.max) ? dateFormatter.stringToDateInstance(this.max) : undefined;
77947
77675
  }
77948
77676
 
77949
77677
  connectedCallback() {
@@ -77972,7 +77700,6 @@ class BaseInput extends AuroElement$1$1 {
77972
77700
  format: this.format
77973
77701
  });
77974
77702
  this.configureDataForType();
77975
- this.syncDateValues();
77976
77703
  }
77977
77704
 
77978
77705
  disconnectedCallback() {
@@ -77992,10 +77719,6 @@ class BaseInput extends AuroElement$1$1 {
77992
77719
  this.wrapperElement.addEventListener('click', this.handleClick);
77993
77720
  }
77994
77721
 
77995
- // add attribute for query selectors when auro-input is registered under a custom name
77996
- if (this.tagName.toLowerCase() !== 'auro-input' && !this.hasAttribute('auro-input')) {
77997
- this.setAttribute('auro-input', '');
77998
- }
77999
77722
  this.inputId = this.id ? `${this.id}-input` : window.crypto.randomUUID();
78000
77723
 
78001
77724
  // use validity message override if declared when initializing the component
@@ -78006,7 +77729,6 @@ class BaseInput extends AuroElement$1$1 {
78006
77729
  this.setCustomHelpTextMessage();
78007
77730
  this.configureAutoFormatting();
78008
77731
  this.configureDataForType();
78009
- this.syncDateValues();
78010
77732
  }
78011
77733
 
78012
77734
  /**
@@ -78143,8 +77865,6 @@ class BaseInput extends AuroElement$1$1 {
78143
77865
  this.configureDataForType();
78144
77866
  }
78145
77867
 
78146
- this.syncDateValues(changedProperties);
78147
-
78148
77868
  if (changedProperties.has('value')) {
78149
77869
  if (this.value && this.value.length > 0) {
78150
77870
  this.hasValue = true;
@@ -78166,14 +77886,14 @@ class BaseInput extends AuroElement$1$1 {
78166
77886
 
78167
77887
  if (formattedValue !== this.inputElement.value) {
78168
77888
  this.skipNextProgrammaticInputEvent = true;
78169
- if (this.maskInstance && this.type === 'credit-card') {
77889
+ if (this.maskInstance && this.type !== 'date') {
78170
77890
  // Route through the mask so its _value and el.value stay in lock-step
78171
77891
  // (set value calls updateControl which writes el.value = displayValue).
78172
77892
  // Writing el.value directly leaves the mask thinking displayValue is
78173
- // stale; _saveSelection on the next focus/click then warns. Scoped to
78174
- // credit-card so date's own formattedValue (raw ISO when calendar-invalid)
78175
- // isn't re-masked through the mm/dd/yyyy mask, which would truncate it
78176
- // and flip validity from patternMismatch to tooShort.
77893
+ // stale; _saveSelection on the next focus/click then warns. Date is
77894
+ // excluded because its formattedValue can be raw ISO when the calendar
77895
+ // is invalid, and re-masking through mm/dd/yyyy would truncate it and
77896
+ // flip validity from patternMismatch to tooShort.
78177
77897
  this.maskInstance.value = formattedValue || '';
78178
77898
  } else if (formattedValue) {
78179
77899
  this.inputElement.value = formattedValue;
@@ -78215,120 +77935,60 @@ class BaseInput extends AuroElement$1$1 {
78215
77935
  }));
78216
77936
  }
78217
77937
 
78218
-
78219
- /**
78220
- * Synchronizes the ISO string values and Date object representations for date-related properties.
78221
- * This keeps the model and display values aligned when either side changes.
78222
- *
78223
- * When a full date format is in use, this method updates `value`, `min`, and `max` from their corresponding
78224
- * Date objects or vice versa, based on which properties have changed. It only runs when the current configuration
78225
- * represents a full year/month/day date format.
78226
- *
78227
- * @param {Map<string, unknown>|undefined} [changedProperties=undefined] - Optional map of changed properties used to limit which values are synchronized.
78228
- * @returns {void}
78229
- * @private
78230
- */
78231
- syncDateValues(changedProperties = undefined) {
78232
- if (!this.util.isFullDateFormat(this.type, this.format)) {
78233
- return;
78234
- }
78235
-
78236
- this.syncSingleDateValue(changedProperties, 'valueObject', 'value');
78237
- this.syncSingleDateValue(changedProperties, 'minObject', 'min');
78238
- this.syncSingleDateValue(changedProperties, 'maxObject', 'max');
78239
- }
78240
-
78241
- /**
78242
- * Synchronizes one date object/string property pair.
78243
- * @private
78244
- * @param {Map<string, unknown>|undefined} changedProperties - Map of changed properties from Lit.
78245
- * @param {string} objectProperty - Date object property name.
78246
- * @param {string} valueProperty - ISO string property name.
78247
- * @returns {void}
78248
- */
78249
- syncSingleDateValue(changedProperties, objectProperty, valueProperty) {
78250
- const objectPropertyChanged = !changedProperties || changedProperties.has(objectProperty);
78251
-
78252
- // objectProperty wins over valueProperty when both changed
78253
- if (objectPropertyChanged && this[objectProperty]) {
78254
- this[valueProperty] = dateFormatter.toISOFormatString(this[objectProperty]);
78255
- return;
78256
- }
78257
-
78258
- const valuePropertyChanged = !changedProperties || changedProperties.has(valueProperty);
78259
- if (!valuePropertyChanged) {
78260
- return;
78261
- }
78262
-
78263
- // when value is newly set to the same ISO string that corresponds to the existing Date object, do not clear the Date object (avoid unnecessary updates)
78264
- if (
78265
- changedProperties &&
78266
- valueProperty === 'value' &&
78267
- changedProperties.get('value') === undefined &&
78268
- this[objectProperty] instanceof Date &&
78269
- this[valueProperty] === dateFormatter.toISOFormatString(this[objectProperty])
78270
- ) {
78271
- return;
78272
- }
78273
-
78274
- if (dateFormatter.isValidDate(this[valueProperty])) {
78275
- this.setDateObjectProperty(objectProperty, dateFormatter.stringToDateInstance(this[valueProperty]));
78276
- } else {
78277
- this.setDateObjectProperty(objectProperty, undefined);
78278
- }
78279
- }
78280
-
78281
77938
  /**
78282
77939
  * Sets up IMasks and logic based on auto-formatting requirements.
78283
77940
  * @private
78284
77941
  * @returns {void}
78285
77942
  */
78286
77943
  configureAutoFormatting() {
78287
- // Re-entrancy guard. The patched-setter's synthetic input event (suppressed
78288
- // by _configuringMask above) could otherwise trigger handleInput
78289
- // processCreditCard configureAutoFormatting before the outer call's
78290
- // set value has finished its alignCursor pass.
77944
+ // _configuringMask gates two things: external re-entry into this method
77945
+ // while setup is mid-flight (from property changes that call back here),
77946
+ // and the accept/complete listeners below — both need to ignore the mask
77947
+ // events fired by our own value-restore step.
78291
77948
  if (this._configuringMask) return;
78292
77949
  this._configuringMask = true;
78293
77950
  try {
77951
+ // Destroy any prior mask so IMask can attach fresh under the new format.
78294
77952
  if (this.maskInstance) {
78295
77953
  this.maskInstance.destroy();
78296
77954
  }
78297
77955
 
78298
- // Pass new format to util
78299
77956
  this.util.updateFormat(this.format);
78300
77957
 
78301
77958
  const maskOptions = this.util.getMaskOptions(this.type, this.format);
78302
77959
 
78303
77960
  if (this.inputElement && maskOptions.mask) {
78304
-
78305
- // Stash and clear any existing value before IMask init.
78306
- // IMask's constructor processes the current input value which requires
78307
- // selection state clearing first avoids that scenario entirely.
78308
- // When the format changes (e.g. locale switch) and we have a valid ISO
78309
- // model value, compute the display string for the NEW format instead of
78310
- // re-using the old display string, which may be invalid in the new mask.
77961
+ // Capture the current display so it can be re-applied after IMask
77962
+ // attaches. The restore at the bottom goes through maskInstance.value
77963
+ // (not inputElement.value directly) so the mask's internal state and
77964
+ // the input's displayed text stay in lock-step.
78311
77965
  let existingValue = this.inputElement.value;
77966
+
77967
+ // Format-change case (e.g. locale switch): existingValue is the OLD
77968
+ // mask's display string and may not parse under the new mask. When
77969
+ // we have a valid date model, rebuild the display from valueObject
77970
+ // (the canonical source) using the new mask's format function.
78312
77971
  if (
78313
77972
  this.util.isFullDateFormat(this.type, this.format) &&
78314
77973
  this.value &&
78315
- dateFormatter.isValidDate(this.value) &&
78316
- this.valueObject instanceof Date &&
78317
- !Number.isNaN(this.valueObject.getTime()) &&
77974
+ this.valueObject &&
78318
77975
  typeof maskOptions.format === 'function'
78319
77976
  ) {
78320
77977
  existingValue = maskOptions.format(this.valueObject);
78321
77978
  }
78322
77979
 
77980
+ // Clear before IMask attaches so the constructor seeds an empty
77981
+ // internal value. Otherwise IMask reads the stale unmasked string
77982
+ // and emits a spurious 'accept' before the restore below runs.
78323
77983
  this.skipNextProgrammaticInputEvent = true;
78324
77984
  this.inputElement.value = '';
78325
77985
 
78326
77986
  this.maskInstance = IMask(this.inputElement, maskOptions);
78327
77987
 
77988
+ // Mask fires 'accept' on every value change, including the restore
77989
+ // step below. Skip events fired during configureAutoFormatting so
77990
+ // we don't overwrite a value the parent just pushed.
78328
77991
  this.maskInstance.on('accept', () => {
78329
- // Suppress propagation during configureAutoFormatting's own value-restoration
78330
- // (line below) — the mask emits 'accept' on every value-set, including ours,
78331
- // and we don't want to overwrite a value the parent just pushed.
78332
77992
  if (this._configuringMask) return;
78333
77993
  this.value = this.util.toModelValue(this.maskInstance.value, this.format);
78334
77994
  if (this.type === "date") {
@@ -78336,6 +77996,8 @@ class BaseInput extends AuroElement$1$1 {
78336
77996
  }
78337
77997
  });
78338
77998
 
77999
+ // Mask fires 'complete' on the restore step below for any value that
78000
+ // happens to be a complete match. Same setup-suppression as 'accept'.
78339
78001
  this.maskInstance.on('complete', () => {
78340
78002
  if (this._configuringMask) return;
78341
78003
  this.value = this.util.toModelValue(this.maskInstance.value, this.format);
@@ -78344,7 +78006,9 @@ class BaseInput extends AuroElement$1$1 {
78344
78006
  }
78345
78007
  });
78346
78008
 
78347
- // Restore the stashed value through IMask so it's properly masked
78009
+ // Write existingValue through the mask (not the input directly) so
78010
+ // the mask reformats it under the new rules and keeps its internal
78011
+ // _value aligned with the input's displayed text.
78348
78012
  if (existingValue) {
78349
78013
  this.maskInstance.value = existingValue;
78350
78014
  }
@@ -78512,7 +78176,6 @@ class BaseInput extends AuroElement$1$1 {
78512
78176
  */
78513
78177
  reset() {
78514
78178
  this.value = undefined;
78515
- this.setDateObjectProperty('valueObject', undefined);
78516
78179
  this.validation.reset(this);
78517
78180
  }
78518
78181
 
@@ -78521,7 +78184,6 @@ class BaseInput extends AuroElement$1$1 {
78521
78184
  */
78522
78185
  clear() {
78523
78186
  this.value = undefined;
78524
- this.setDateObjectProperty('valueObject', undefined);
78525
78187
  }
78526
78188
 
78527
78189
  /**
@@ -79050,7 +78712,7 @@ let AuroHelpText$1$1 = class AuroHelpText extends i$2 {
79050
78712
  }
79051
78713
  };
79052
78714
 
79053
- var formkitVersion$1$1 = '202606171946';
78715
+ var formkitVersion$1$1 = '202606192004';
79054
78716
 
79055
78717
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
79056
78718
  // See LICENSE in the project root for license information.
@@ -80171,7 +79833,7 @@ let AuroBibtemplate$1 = class AuroBibtemplate extends i$2 {
80171
79833
  }
80172
79834
  };
80173
79835
 
80174
- var formkitVersion$3 = '202606171946';
79836
+ var formkitVersion$3 = '202606192004';
80175
79837
 
80176
79838
  var styleCss$1$3 = i$4`.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}`;
80177
79839
 
@@ -81158,7 +80820,7 @@ class AuroCombobox extends AuroElement$3 {
81158
80820
  if (this.menu) {
81159
80821
  this.menu.matchWord = normalizeFilterValue(this.input.value);
81160
80822
  }
81161
- const label = getOptionLabel(this.menu.optionSelected) || this.menu.currentLabel;
80823
+ const label = getOptionLabel(this.menu.optionSelected);
81162
80824
  this.updateTriggerTextDisplay(label || this.value);
81163
80825
  }
81164
80826
 
@@ -81172,40 +80834,9 @@ class AuroCombobox extends AuroElement$3 {
81172
80834
  // in suggestion mode, do not override input value if no selection has been made and the input currently has focus
81173
80835
  const isInputFocusedWithNoSelection = !this.menu.value && (this.input.matches(':focus-within') || (this.inputInBib && this.inputInBib.matches(':focus-within')));
81174
80836
 
81175
- if (!this.persistInput && !(this.behavior === 'suggestion' && isInputFocusedWithNoSelection)) {
81176
- const nextValue = label || this.value;
81177
- // Only set the flag when there's an actual write to suppress —
81178
- // syncValuesAndStates re-enters here during typing when both inputs
81179
- // already match, and a no-op flag flip would make the bib branch's
81180
- // bail eat legitimate user-input events.
81181
- const triggerNeedsSync = this.input.value !== nextValue;
81182
- const bibNeedsSync = Boolean(this.inputInBib && this.inputInBib !== this.input && this.inputInBib.value !== nextValue);
81183
- if (triggerNeedsSync || bibNeedsSync) {
81184
- this._syncingDisplayValue = true;
81185
- if (triggerNeedsSync) {
81186
- this.input.value = nextValue;
81187
- }
81188
- if (bibNeedsSync) {
81189
- this.inputInBib.value = nextValue;
81190
- }
81191
- const pending = [];
81192
- if (triggerNeedsSync) {
81193
- pending.push(this.input.updateComplete);
81194
- }
81195
- if (bibNeedsSync) {
81196
- pending.push(this.inputInBib.updateComplete);
81197
- }
81198
- Promise.all(pending).then(() => {
81199
- // imask reasserts otherwise, and handleBlur reverts to its stale value.
81200
- if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
81201
- this.input.maskInstance.updateValue();
81202
- }
81203
- if (bibNeedsSync && this.inputInBib && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
81204
- this.inputInBib.maskInstance.updateValue();
81205
- }
81206
- this._syncingDisplayValue = false;
81207
- });
81208
- }
80837
+ const suppressed = this.persistInput || (this.behavior === 'suggestion' && isInputFocusedWithNoSelection);
80838
+ if (!suppressed) {
80839
+ this.syncInputValuesAcrossTriggerAndBib(label || this.value);
81209
80840
  }
81210
80841
 
81211
80842
  // update the displayValue in the trigger if displayValue slot content is present
@@ -81233,6 +80864,52 @@ class AuroCombobox extends AuroElement$3 {
81233
80864
  this.requestUpdate();
81234
80865
  }
81235
80866
 
80867
+ /**
80868
+ * Writes nextValue to the trigger input and the bib input when their current
80869
+ * value differs, then re-asserts imask after Lit's update flushes.
80870
+ * @param {string} nextValue - The value to write to both inputs.
80871
+ * @returns {Promise<void> | null} Promise that resolves after the inputs flush,
80872
+ * or null when no sync was needed (so callers can skip post-flush work).
80873
+ * @private
80874
+ */
80875
+ syncInputValuesAcrossTriggerAndBib(nextValue) {
80876
+ // Only set the flag when there's an actual write to suppress —
80877
+ // syncValuesAndStates re-enters here during typing when both inputs
80878
+ // already match, and a no-op flag flip would make the bib branch's
80879
+ // bail eat legitimate user-input events.
80880
+ const triggerNeedsSync = this.input.value !== nextValue;
80881
+ const bibNeedsSync = Boolean(this.inputInBib && this.inputInBib !== this.input && this.inputInBib.value !== nextValue);
80882
+ if (!triggerNeedsSync && !bibNeedsSync) {
80883
+ return null;
80884
+ }
80885
+
80886
+ this._syncingDisplayValue = true;
80887
+ if (triggerNeedsSync) {
80888
+ this.input.value = nextValue;
80889
+ }
80890
+ if (bibNeedsSync) {
80891
+ this.inputInBib.value = nextValue;
80892
+ }
80893
+
80894
+ const pending = [];
80895
+ if (triggerNeedsSync) {
80896
+ pending.push(this.input.updateComplete);
80897
+ }
80898
+ if (bibNeedsSync) {
80899
+ pending.push(this.inputInBib.updateComplete);
80900
+ }
80901
+ return Promise.all(pending).then(() => {
80902
+ // imask reasserts otherwise, and handleBlur reverts to its stale value.
80903
+ if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
80904
+ this.input.maskInstance.updateValue();
80905
+ }
80906
+ if (bibNeedsSync && this.inputInBib && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
80907
+ this.inputInBib.maskInstance.updateValue();
80908
+ }
80909
+ this._syncingDisplayValue = false;
80910
+ });
80911
+ }
80912
+
81236
80913
  /**
81237
80914
  * Processes hidden state of all menu options and determines if there are any available options not hidden.
81238
80915
  * @private
@@ -81260,9 +80937,9 @@ class AuroCombobox extends AuroElement$3 {
81260
80937
  this.syncValuesAndStates();
81261
80938
  }
81262
80939
 
81263
- // Re-activate when optionActive is no longer visible, or when _index has
81264
- // been reset (e.g. by clearSelection in an async update) so that
81265
- // makeSelection() can find the correct option.
80940
+ // Re-activate when optionActive is not in the current scrollable viewport,
80941
+ // or when _index has been reset (e.g. by clearSelection in an async update)
80942
+ // so that makeSelection() can find the correct option.
81266
80943
  if (!this.availableOptions.includes(this.menu.optionActive) || this.menu._index < 0) {
81267
80944
  this.activateFirstEnabledAvailableOption();
81268
80945
  }
@@ -81396,28 +81073,25 @@ class AuroCombobox extends AuroElement$3 {
81396
81073
 
81397
81074
  guardTouchPassthrough$1(this.menu);
81398
81075
 
81399
- // The dialog's showModal() steals focus from the trigger.
81400
- // A single rAF is enough for the dialog DOM to be painted and
81401
- // focusable, then doubleRaf finalizes the transition.
81076
+ // showModal() takes focus away from the trigger. Early focus once
81077
+ // the dialog has painted; the shared doubleRaf below is the fallback
81078
+ // for when the dialog needs an extra frame and also clears the
81079
+ // validation guard.
81402
81080
  requestAnimationFrame(() => {
81403
81081
  this.setInputFocus();
81404
81082
  });
81405
-
81406
- doubleRaf$1(() => {
81407
- this.setInputFocus();
81408
- this._inFullscreenTransition = false;
81409
- });
81410
- } else {
81411
- // Desktop popover-open: restore the trigger caret to end-of-text.
81412
- // Clicking the trigger lands on auro-input's floating <label for="…">
81413
- // overlay; Chrome resets the native input's selection to [0, 0] on
81414
- // label-focus before any JS runs. setInputFocus()'s non-fullscreen
81415
- // branch parks the caret at end. doubleRaf lets the dropdown layout
81416
- // settle first, matching the fullscreen branch timing.
81417
- doubleRaf$1(() => {
81418
- this.setInputFocus();
81419
- });
81420
81083
  }
81084
+ // else (desktop popover-open): Chrome resets the trigger caret to
81085
+ // [0, 0] when its floating <label for="…"> overlay receives focus.
81086
+ // The shared doubleRaf below parks the caret back at end-of-text
81087
+ // after the dropdown layout settles.
81088
+
81089
+ doubleRaf$1(() => {
81090
+ this.setInputFocus();
81091
+ if (this._inFullscreenTransition) {
81092
+ this._inFullscreenTransition = false;
81093
+ }
81094
+ });
81421
81095
  }
81422
81096
  });
81423
81097
 
@@ -81524,9 +81198,9 @@ class AuroCombobox extends AuroElement$3 {
81524
81198
  } else {
81525
81199
  // Safety net for the strategy-change setTimeout: a viewport-crossing
81526
81200
  // fullscreen→floating switch can close the dialog and leave focus on
81527
- // body. Every other Branch 2 callsite already has focus on the input
81528
- // via the focusin → this.focus() redirect (L1448-1452), so this is a
81529
- // no-op in the common case.
81201
+ // body. Every other call into this branch already has focus on the
81202
+ // input via the combobox-level focusin → this.focus() redirect, so
81203
+ // this is a no-op in the common case.
81530
81204
  if (!this.input.componentHasFocus) {
81531
81205
  this.input.focus();
81532
81206
  }
@@ -81645,7 +81319,7 @@ class AuroCombobox extends AuroElement$3 {
81645
81319
  if (this.menu.optionSelected) {
81646
81320
  const selected = this.menu.optionSelected;
81647
81321
 
81648
- if (!this.optionSelected || this.optionSelected !== selected) {
81322
+ if (this.optionSelected !== selected) {
81649
81323
  this.optionSelected = selected;
81650
81324
  }
81651
81325
 
@@ -81658,7 +81332,7 @@ class AuroCombobox extends AuroElement$3 {
81658
81332
  }
81659
81333
 
81660
81334
  // Update display
81661
- this.updateTriggerTextDisplay(getOptionLabel(this.optionSelected) || this.menu.value);
81335
+ this.updateTriggerTextDisplay(getOptionLabel(this.optionSelected));
81662
81336
 
81663
81337
  // Update match word for filtering
81664
81338
  const trimmedInput = normalizeFilterValue(this.input.value);
@@ -81676,11 +81350,15 @@ class AuroCombobox extends AuroElement$3 {
81676
81350
 
81677
81351
  // Announce the selection after the dropdown closes so it isn't
81678
81352
  // overridden by VoiceOver's "collapsed" announcement from aria-expanded.
81353
+ // Skip when there's no selected value (e.g. menu.clearSelection() from
81354
+ // the unmatched-value path), otherwise VoiceOver reads "undefined".
81679
81355
  const selectedValue = this.menu.value;
81680
- const announcementDelay = 300;
81681
- setTimeout(() => {
81682
- announceToScreenReader$1(this._getAnnouncementRoot(), `${selectedValue}, selected`);
81683
- }, announcementDelay);
81356
+ if (selectedValue) {
81357
+ const announcementDelay = 300;
81358
+ setTimeout(() => {
81359
+ announceToScreenReader$1(this._getAnnouncementRoot(), `${selectedValue}, selected`);
81360
+ }, announcementDelay);
81361
+ }
81684
81362
  }
81685
81363
 
81686
81364
  // Programmatic value syncs leave availableOptions stale because
@@ -82040,15 +81718,7 @@ class AuroCombobox extends AuroElement$3 {
82040
81718
  this.menu.value = undefined;
82041
81719
  this.validation.reset(this);
82042
81720
  this.touched = false;
82043
- // Force validity back to the cleared state. validation.reset() calls
82044
- // validate() at the end, and (post-credit-card-fix) the trigger input's
82045
- // residual validity may still be copied into the combobox by the
82046
- // auroInputElements loop. Explicitly clear here so reset() actually
82047
- // leaves the component in a "no validity" state.
82048
81721
  this.validity = undefined;
82049
- this.errorMessage = '';
82050
- this.input.validity = undefined;
82051
- this.input.errorMessage = '';
82052
81722
  }
82053
81723
 
82054
81724
  /**
@@ -82101,52 +81771,27 @@ class AuroCombobox extends AuroElement$3 {
82101
81771
  this.input.value = this.value;
82102
81772
  }
82103
81773
 
82104
- // Sync menu.value only when an option actually matches; otherwise clear it.
81774
+ // Sync menu.value only when an option actually matches, or when filter
81775
+ // mode needs setMenuValue to dispatch auroMenu-selectValueFailure (the
81776
+ // listener at line 1206 clears combobox.value, mirroring select's
81777
+ // pattern). Otherwise sync the input display for freeform values.
82105
81778
  if (this.menu.options && this.menu.options.length > 0) {
82106
- if (this.menu.options.some((opt) => opt.value === this.value)) {
82107
- this.setMenuValue(this.value);
82108
- } else if (this.behavior === 'filter') {
82109
- // In filter mode, freeform values aren't allowed. Push the unmatched
82110
- // value through setMenuValue so menu dispatches auroMenu-selectValueFailure
82111
- // and the listener at line 1206 clears combobox.value (mirrors select's
82112
- // pattern). Bypassing setMenuValue here would skip the failure cascade.
81779
+ if (this.menu.options.some((opt) => opt.value === this.value) || this.behavior === 'filter') {
82113
81780
  this.setMenuValue(this.value);
82114
81781
  } else {
82115
- if (this.menu.value) {
82116
- this.menu.value = undefined;
81782
+ // Clear menu.value AND menu.optionSelected together. Clearing only
81783
+ // menu.value leaves the previously-selected option element pinned
81784
+ // as menu.optionSelected; a later auroMenu-selectedOption event
81785
+ // would then write its stale .value back into combobox.value.
81786
+ if (this.menu.value || this.menu.optionSelected) {
81787
+ this.menu.clearSelection();
82117
81788
  }
82118
- // Sync the display for programmatic freeform value changes (e.g. the
82119
- // swap-values pattern). Guard with _syncingDisplayValue so that the
82120
- // re-entrant input event from base-input.notifyValueChanged() is
82121
- // ignored by handleInputValueChange. Skip the sync when input already
82122
- // matches to avoid spurious events during the normal typing path.
82123
- const nextValue = this.value || '';
82124
- const triggerNeedsSync = this.input.value !== nextValue;
82125
- const bibNeedsSync = Boolean(this.inputInBib && this.inputInBib !== this.input && this.inputInBib.value !== nextValue);
82126
- if (triggerNeedsSync || bibNeedsSync) {
82127
- this._syncingDisplayValue = true;
82128
- if (triggerNeedsSync) {
82129
- this.input.value = nextValue;
82130
- }
82131
- if (bibNeedsSync) {
82132
- this.inputInBib.value = nextValue;
82133
- }
82134
- const pending = [];
82135
- if (triggerNeedsSync) {
82136
- pending.push(this.input.updateComplete);
82137
- }
82138
- if (bibNeedsSync) {
82139
- pending.push(this.inputInBib.updateComplete);
82140
- }
82141
- Promise.all(pending).then(() => {
82142
- if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
82143
- this.input.maskInstance.updateValue();
82144
- }
82145
- if (bibNeedsSync && this.inputInBib && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
82146
- this.inputInBib.maskInstance.updateValue();
82147
- }
82148
- this._syncingDisplayValue = false;
82149
- // handleInputValueChange bailed on the flag — refresh the filter.
81789
+ // Suggestion-mode freeform value: sync the trigger + bib to show it,
81790
+ // then refresh the filter once the inputs flush (handleInputValueChange
81791
+ // bailed on _syncingDisplayValue).
81792
+ const syncPromise = this.syncInputValuesAcrossTriggerAndBib(this.value || '');
81793
+ if (syncPromise) {
81794
+ syncPromise.then(() => {
82150
81795
  this._programmaticFilterRefresh = true;
82151
81796
  this.handleMenuOptions();
82152
81797
  setTimeout(() => {
@@ -84935,6 +84580,21 @@ function getEnabledOptions(menu) {
84935
84580
  return (menu?.options || []).filter((option) => !option.disabled);
84936
84581
  }
84937
84582
 
84583
+ /**
84584
+ * Returns the active (selectable + visible) options for type-ahead navigation.
84585
+ *
84586
+ * Uses auro-menuoption's `isActive` getter, which excludes disabled, hidden,
84587
+ * and static options (e.g. `static nomatch` placeholders) so the type-ahead
84588
+ * cursor never lands on a non-actionable item. Same empty-safe handling as
84589
+ * `getEnabledOptions`.
84590
+ *
84591
+ * @param {HTMLElement | null | undefined} menu - The auro-menu element.
84592
+ * @returns {Array<HTMLElement>} Active options, empty array when none.
84593
+ */
84594
+ function getActiveOptions(menu) {
84595
+ return (menu?.options || []).filter((option) => option.isActive);
84596
+ }
84597
+
84938
84598
  /* eslint-disable new-cap */
84939
84599
 
84940
84600
  const selectKeyboardStrategy = {
@@ -84967,6 +84627,14 @@ const selectKeyboardStrategy = {
84967
84627
  },
84968
84628
 
84969
84629
  Escape(component, evt, ctx) {
84630
+ // Always clear the type-ahead buffer — Escape is a universal cancel.
84631
+ // Safe to call when the buffer is empty.
84632
+ // eslint-disable-next-line no-underscore-dangle
84633
+ if (typeof component._clearTypeaheadBuffer === 'function') {
84634
+ // eslint-disable-next-line no-underscore-dangle
84635
+ component._clearTypeaheadBuffer();
84636
+ }
84637
+
84970
84638
  if (!ctx.isExpanded) {
84971
84639
  return;
84972
84640
  }
@@ -85026,16 +84694,25 @@ const selectKeyboardStrategy = {
85026
84694
  },
85027
84695
 
85028
84696
  default(component, evt, ctx) {
85029
- component.updateActiveOptionBasedOnKey(evt.key);
84697
+ // Space resolves to either typeahead-buffer extension or bib toggle
84698
+ // depending on whether a type-ahead buffer is active. Mirrors native
84699
+ // <select> and the WAI-ARIA APG Listbox guidance: mid-typeahead space
84700
+ // is a search character (e.g. "San Francisco"); otherwise it toggles.
85030
84701
  if (evt.key === ' ') {
85031
84702
  evt.preventDefault();
85032
84703
  evt.stopPropagation();
84704
+ if (component.typeaheadBuffer && component.typeaheadBuffer.length > 0) {
84705
+ component.updateActiveOptionBasedOnKey(evt.key);
84706
+ return;
84707
+ }
85033
84708
  if (ctx.isExpanded) {
85034
84709
  component.dropdown.hide();
85035
- return;
84710
+ } else {
84711
+ component.dropdown.show();
85036
84712
  }
85037
- component.dropdown.show();
84713
+ return;
85038
84714
  }
84715
+ component.updateActiveOptionBasedOnKey(evt.key);
85039
84716
  },
85040
84717
  };
85041
84718
 
@@ -88947,7 +88624,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$2 {
88947
88624
  }
88948
88625
  };
88949
88626
 
88950
- var formkitVersion$1 = '202606171946';
88627
+ var formkitVersion$1 = '202606192004';
88951
88628
 
88952
88629
  class AuroElement extends i$2 {
88953
88630
  static get properties() {
@@ -90960,7 +90637,7 @@ class AuroHelpText extends i$2 {
90960
90637
  }
90961
90638
  }
90962
90639
 
90963
- var formkitVersion = '202606171946';
90640
+ var formkitVersion = '202606192004';
90964
90641
 
90965
90642
  var styleCss = i$4`.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}.body-default{font-size:var(--wcss-body-default-font-size, 1rem);font-weight:var(--wcss-body-default-weight, );line-height:var(--wcss-body-default-line-height, 1.5rem)}.body-default,.body-default-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-default-emphasized{font-size:var(--wcss-body-default-emphasized-font-size, 1rem);font-weight:var(--wcss-body-default-emphasized-weight, );line-height:var(--wcss-body-default-emphasized-line-height, 1.5rem)}.body-lg{font-size:var(--wcss-body-lg-font-size, 1.125rem);font-weight:var(--wcss-body-lg-weight, );line-height:var(--wcss-body-lg-line-height, 1.625rem)}.body-lg,.body-lg-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-lg-emphasized{font-size:var(--wcss-body-lg-emphasized-font-size, 1.125rem);font-weight:var(--wcss-body-lg-emphasized-weight, );line-height:var(--wcss-body-lg-emphasized-line-height, 1.625rem)}.body-sm{font-size:var(--wcss-body-sm-font-size, 0.875rem);font-weight:var(--wcss-body-sm-weight, );line-height:var(--wcss-body-sm-line-height, 1.25rem)}.body-sm,.body-sm-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-sm-emphasized{font-size:var(--wcss-body-sm-emphasized-font-size, 0.875rem);font-weight:var(--wcss-body-sm-emphasized-weight, );line-height:var(--wcss-body-sm-emphasized-line-height, 1.25rem)}.body-xs{font-size:var(--wcss-body-xs-font-size, 0.75rem);font-weight:var(--wcss-body-xs-weight, );line-height:var(--wcss-body-xs-line-height, 1rem)}.body-xs,.body-xs-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-xs-emphasized{font-size:var(--wcss-body-xs-emphasized-font-size, 0.75rem);font-weight:var(--wcss-body-xs-emphasized-weight, );line-height:var(--wcss-body-xs-emphasized-line-height, 1rem)}.body-2xs{font-size:var(--wcss-body-2xs-font-size, 0.625rem);font-weight:var(--wcss-body-2xs-weight, );line-height:var(--wcss-body-2xs-line-height, 0.875rem)}.body-2xs,.body-2xs-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-2xs-emphasized{font-size:var(--wcss-body-2xs-emphasized-font-size, 0.625rem);font-weight:var(--wcss-body-2xs-emphasized-weight, );line-height:var(--wcss-body-2xs-emphasized-line-height, 0.875rem)}.display-2xl{font-family:var(--wcss-display-2xl-family, "AS Circular"),var(--wcss-display-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-2xl-font-size, clamp(3.5rem, 6vw, 5.375rem));font-weight:var(--wcss-display-2xl-weight, 300);letter-spacing:var(--wcss-display-2xl-letter-spacing, 0);line-height:var(--wcss-display-2xl-line-height, 1.3)}.display-xl{font-family:var(--wcss-display-xl-family, "AS Circular"),var(--wcss-display-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-xl-font-size, clamp(3rem, 5.3333333333vw, 4.5rem));font-weight:var(--wcss-display-xl-weight, 300);letter-spacing:var(--wcss-display-xl-letter-spacing, 0);line-height:var(--wcss-display-xl-line-height, 1.3)}.display-lg{font-family:var(--wcss-display-lg-family, "AS Circular"),var(--wcss-display-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-lg-font-size, clamp(2.75rem, 4.6666666667vw, 4rem));font-weight:var(--wcss-display-lg-weight, 300);letter-spacing:var(--wcss-display-lg-letter-spacing, 0);line-height:var(--wcss-display-lg-line-height, 1.3)}.display-md{font-family:var(--wcss-display-md-family, "AS Circular"),var(--wcss-display-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-md-font-size, clamp(2.5rem, 4vw, 3.5rem));font-weight:var(--wcss-display-md-weight, 300);letter-spacing:var(--wcss-display-md-letter-spacing, 0);line-height:var(--wcss-display-md-line-height, 1.3)}.display-sm{font-family:var(--wcss-display-sm-family, "AS Circular"),var(--wcss-display-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-sm-font-size, clamp(2rem, 3.6666666667vw, 3rem));font-weight:var(--wcss-display-sm-weight, 300);letter-spacing:var(--wcss-display-sm-letter-spacing, 0);line-height:var(--wcss-display-sm-line-height, 1.3)}.display-xs{font-family:var(--wcss-display-xs-family, "AS Circular"),var(--wcss-display-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-xs-font-size, clamp(1.75rem, 3vw, 2.375rem));font-weight:var(--wcss-display-xs-weight, 300);letter-spacing:var(--wcss-display-xs-letter-spacing, 0);line-height:var(--wcss-display-xs-line-height, 1.3)}.heading-xl{font-family:var(--wcss-heading-xl-family, "AS Circular"),var(--wcss-heading-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-xl-font-size, clamp(2rem, 3vw, 2.5rem));font-weight:var(--wcss-heading-xl-weight, 300);letter-spacing:var(--wcss-heading-xl-letter-spacing, 0);line-height:var(--wcss-heading-xl-line-height, 1.3)}.heading-lg{font-family:var(--wcss-heading-lg-family, "AS Circular"),var(--wcss-heading-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-lg-font-size, clamp(1.75rem, 2.6666666667vw, 2.25rem));font-weight:var(--wcss-heading-lg-weight, 300);letter-spacing:var(--wcss-heading-lg-letter-spacing, 0);line-height:var(--wcss-heading-lg-line-height, 1.3)}.heading-md{font-family:var(--wcss-heading-md-family, "AS Circular"),var(--wcss-heading-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-md-font-size, clamp(1.625rem, 2.3333333333vw, 1.75rem));font-weight:var(--wcss-heading-md-weight, 300);letter-spacing:var(--wcss-heading-md-letter-spacing, 0);line-height:var(--wcss-heading-md-line-height, 1.3)}.heading-sm{font-family:var(--wcss-heading-sm-family, "AS Circular"),var(--wcss-heading-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-sm-font-size, clamp(1.375rem, 2vw, 1.5rem));font-weight:var(--wcss-heading-sm-weight, 300);letter-spacing:var(--wcss-heading-sm-letter-spacing, 0);line-height:var(--wcss-heading-sm-line-height, 1.3)}.heading-xs{font-family:var(--wcss-heading-xs-family, "AS Circular"),var(--wcss-heading-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-xs-font-size, clamp(1.25rem, 1.6666666667vw, 1.25rem));font-weight:var(--wcss-heading-xs-weight, 300);letter-spacing:var(--wcss-heading-xs-letter-spacing, 0);line-height:var(--wcss-heading-xs-line-height, 1.3)}.heading-2xs{font-family:var(--wcss-heading-2xs-family, "AS Circular"),var(--wcss-heading-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-2xs-font-size, clamp(1.125rem, 1.5vw, 1.125rem));font-weight:var(--wcss-heading-2xs-weight, 300);letter-spacing:var(--wcss-heading-2xs-letter-spacing, 0);line-height:var(--wcss-heading-2xs-line-height, 1.3)}.accent-2xl{font-family:var(--wcss-accent-2xl-family, "Good OT"),var(--wcss-accent-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-2xl-font-size, clamp(2rem, 3.1666666667vw, 2.375rem));font-weight:var(--wcss-accent-2xl-weight, 450);letter-spacing:var(--wcss-accent-2xl-letter-spacing, 0.05em);line-height:var(--wcss-accent-2xl-line-height, 1)}.accent-2xl,.accent-xl{text-transform:uppercase}.accent-xl{font-family:var(--wcss-accent-xl-family, "Good OT"),var(--wcss-accent-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-xl-font-size, clamp(1.625rem, 2.3333333333vw, 2rem));font-weight:var(--wcss-accent-xl-weight, 450);letter-spacing:var(--wcss-accent-xl-letter-spacing, 0.05em);line-height:var(--wcss-accent-xl-line-height, 1.3)}.accent-lg{font-family:var(--wcss-accent-lg-family, "Good OT"),var(--wcss-accent-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-lg-font-size, clamp(1.5rem, 2.1666666667vw, 1.75rem));font-weight:var(--wcss-accent-lg-weight, 450);letter-spacing:var(--wcss-accent-lg-letter-spacing, 0.05em);line-height:var(--wcss-accent-lg-line-height, 1.3)}.accent-lg,.accent-md{text-transform:uppercase}.accent-md{font-family:var(--wcss-accent-md-family, "Good OT"),var(--wcss-accent-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-md-font-size, clamp(1.375rem, 1.8333333333vw, 1.5rem));font-weight:var(--wcss-accent-md-weight, 500);letter-spacing:var(--wcss-accent-md-letter-spacing, 0.05em);line-height:var(--wcss-accent-md-line-height, 1.3)}.accent-sm{font-family:var(--wcss-accent-sm-family, "Good OT"),var(--wcss-accent-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-sm-font-size, clamp(1.125rem, 1.5vw, 1.25rem));font-weight:var(--wcss-accent-sm-weight, 500);letter-spacing:var(--wcss-accent-sm-letter-spacing, 0.05em);line-height:var(--wcss-accent-sm-line-height, 1.3)}.accent-sm,.accent-xs{text-transform:uppercase}.accent-xs{font-family:var(--wcss-accent-xs-family, "Good OT"),var(--wcss-accent-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-xs-font-size, clamp(1rem, 1.3333333333vw, 1rem));font-weight:var(--wcss-accent-xs-weight, 500);letter-spacing:var(--wcss-accent-xs-letter-spacing, 0.1em);line-height:var(--wcss-accent-xs-line-height, 1.3)}.accent-2xs{font-family:var(--wcss-accent-2xs-family, "Good OT"),var(--wcss-accent-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-2xs-font-size, clamp(0.875rem, 1.1666666667vw, 0.875rem));font-weight:var(--wcss-accent-2xs-weight, 450);letter-spacing:var(--wcss-accent-2xs-letter-spacing, 0.1em);line-height:var(--wcss-accent-2xs-line-height, 1.3);text-transform:uppercase}[auro-dropdown]{--ds-auro-dropdown-trigger-border-color: var(--ds-auro-select-border-color);--ds-auro-dropdown-trigger-background-color: var(--ds-auro-select-background-color);--ds-auro-dropdown-trigger-container-color: var(--ds-auro-select-background-color);--ds-auro-dropdown-trigger-outline-color: var(--ds-auro-select-outline-color)}:host{display:inline-block;text-align:left;vertical-align:top}:host([layout*=emphasized]) [auro-dropdown],:host([layout*=snowflake]) [auro-dropdown]{--ds-auro-select-border-color: transparent}:host([layout*=emphasized]) .mainContent,:host([layout*=snowflake]) .mainContent{text-align:center}.mainContent{position:relative;display:flex;overflow:hidden;flex:1;flex-direction:column;align-items:center;justify-content:center}.valueContainer [slot=displayValue]{display:none}.accents{display:flex;flex-direction:row;align-items:center;justify-content:center}::slotted([slot=typeIcon]){margin-right:var(--ds-size-100, 0.5rem)}.displayValue{display:block}.displayValue:not(.force){display:none}.displayValue:not(.force).hasContent:is(.withValue):not(.hasFocus){display:block}.triggerContent{display:flex;width:100%;align-items:center;justify-content:center}:host([layout*=emphasized]) .triggerContent{padding:0 var(--ds-size-100, 0.5rem) 0 var(--ds-size-300, 1.5rem)}:host([layout*=snowflake]) .triggerContent{padding:0 var(--ds-size-100, 0.5rem) 0 var(--ds-size-200, 1rem)}:host([layout*=snowflake]) label{padding-block:var(--ds-size-25, 0.125rem)}:host([layout*=classic]) .triggerContent{padding:0 var(--ds-size-100, 0.5rem)}:host([layout*=classic]) .mainContent{align-items:start}:host([layout*=classic]) label{overflow:hidden;cursor:text;text-overflow:ellipsis;white-space:nowrap}:host([layout*=classic]) .value{height:auto}label{color:var(--ds-auro-select-label-text-color)}:host(:is([validity]:not([validity=valid]))) [auro-dropdown]{--ds-auro-select-border-color: var(--ds-basic-color-status-error, #e31f26);--ds-auro-select-outline-color: var(--ds-basic-color-status-error, #e31f26);--ds-auro-dropdown-helptext-text-color: var(--ds-basic-color-texticon-default, #2a2a2a)}:host([ondark]:is([validity]:not([validity=valid]))) [auro-dropdown],:host([appearance=inverse]:is([validity]:not([validity=valid]))) [auro-dropdown]{--ds-auro-select-border-color: var(--ds-advanced-color-state-error-inverse, #f9a4a8);--ds-auro-select-outline-color: var(--ds-advanced-color-state-error-inverse, #f9a4a8);--ds-auro-dropdown-helptext-text-color: var(--ds-basic-color-texticon-inverse, #ffffff)}#slotHolder{display:none}:host([fluid]){width:100%}:host([disabled]){pointer-events:none;user-select:none}:host([disabled]:not([ondark])) [auro-dropdown],:host([disabled]:not([appearance=inverse])) [auro-dropdown]{--ds-auro-select-border-color: var(--ds-basic-color-border-subtle, #dddddd)}:host(:not([layout*=classic])[disabled][ondark]) [auro-dropdown],:host(:not([layout*=classic])[disabled][appearance=inverse]) [auro-dropdown]{--ds-auro-select-border-color: transparent}`;
90966
90643
 
@@ -91065,6 +90742,16 @@ class AuroSelect extends AuroElement$1 {
91065
90742
  * @private
91066
90743
  */
91067
90744
  this.hasDisplayValueContent = false;
90745
+
90746
+ /**
90747
+ * @private
90748
+ */
90749
+ this.typeaheadBuffer = '';
90750
+
90751
+ /**
90752
+ * @private
90753
+ */
90754
+ this._typeaheadTimeout = null;
91068
90755
  }
91069
90756
 
91070
90757
  /**
@@ -91077,6 +90764,7 @@ class AuroSelect extends AuroElement$1 {
91077
90764
  this.fullscreenBreakpoint = 'sm';
91078
90765
  this.onDark = false;
91079
90766
  this.isPopoverVisible = false;
90767
+ this.typeaheadTimeoutMs = 500;
91080
90768
 
91081
90769
  // Layout Config
91082
90770
  this.layout = 'classic';
@@ -91380,6 +91068,16 @@ class AuroSelect extends AuroElement$1 {
91380
91068
  attribute: false
91381
91069
  },
91382
91070
 
91071
+ /**
91072
+ * Milliseconds of keyboard inactivity before the type-ahead buffer resets.
91073
+ * Increase for users who type slowly.
91074
+ * @default 500
91075
+ */
91076
+ typeaheadTimeoutMs: {
91077
+ type: Number,
91078
+ reflect: true
91079
+ },
91080
+
91383
91081
  /**
91384
91082
  * Specifies the `validityState` this element is in.
91385
91083
  */
@@ -91819,6 +91517,7 @@ class AuroSelect extends AuroElement$1 {
91819
91517
  this.addEventListener('blur', () => {
91820
91518
  this.validate();
91821
91519
  this.hasFocus = false;
91520
+ this._clearTypeaheadBuffer();
91822
91521
  });
91823
91522
  }
91824
91523
 
@@ -91832,41 +91531,89 @@ class AuroSelect extends AuroElement$1 {
91832
91531
  }
91833
91532
  }
91834
91533
 
91534
+ /**
91535
+ * Returns the lowercase, trimmed text content of a menu option.
91536
+ * @private
91537
+ * @param {HTMLElement} option - The menu option element.
91538
+ * @returns {string}
91539
+ */
91540
+ _getOptionDisplayText(option) {
91541
+ return (option.textContent || '').trim().toLowerCase();
91542
+ }
91543
+
91544
+ /**
91545
+ * Empties the type-ahead buffer and cancels any pending reset timeout.
91546
+ * Called when focus leaves the component, when Escape closes the bib, and on disconnect
91547
+ * so a stale buffer never bridges into a fresh interaction.
91548
+ * @private
91549
+ */
91550
+ _clearTypeaheadBuffer() {
91551
+ if (this._typeaheadTimeout) {
91552
+ clearTimeout(this._typeaheadTimeout);
91553
+ this._typeaheadTimeout = null;
91554
+ }
91555
+ this.typeaheadBuffer = '';
91556
+ }
91557
+
91835
91558
  /**
91836
91559
  * Updates the active option in the menu based on keyboard input.
91560
+ *
91561
+ * Implements the WAI-ARIA APG Listbox type-ahead pattern: accumulates printable
91562
+ * keystrokes into a buffer that resets after `typeaheadTimeoutMs` of inactivity.
91563
+ * A multi-character buffer matches the first option whose displayed text starts
91564
+ * with the buffer; repeating a single character cycles through options that start
91565
+ * with that character.
91837
91566
  * @private
91838
91567
  * @param {string} _key - The key pressed by the user.
91839
91568
  * @returns {void}
91840
91569
  */
91841
91570
  updateActiveOptionBasedOnKey(_key) {
91571
+ // Ignore non-printable keys (Shift, ArrowDown, Tab, etc.)
91572
+ if (typeof _key !== 'string' || _key.length !== 1) {
91573
+ return;
91574
+ }
91842
91575
 
91843
- // Get a lowercase version of the key pressed
91844
- const key = _key.toLowerCase();
91845
-
91846
- // Calculate how many times the same letter has been pressed
91847
- this.sameLetterTimes = key === this.lastLetter ? this.sameLetterTimes + 1 : 0;
91576
+ // No selectable options to match against clear any stale buffer/timer so
91577
+ // Space stays a bib toggle and the next keystroke after fresh options load
91578
+ // starts cleanly. `getActiveOptions` excludes disabled, hidden, and static
91579
+ // options (e.g. `static nomatch` placeholders). Checked BEFORE mutating
91580
+ // the buffer.
91581
+ const options = getActiveOptions(this.menu);
91582
+ if (!options.length) {
91583
+ this._clearTypeaheadBuffer();
91584
+ return;
91585
+ }
91848
91586
 
91849
- // Set last letter for tracking
91850
- this.lastLetter = key;
91587
+ const key = _key.toLowerCase();
91851
91588
 
91852
- // Get all the options that start with the last letter pressed
91853
- const letterOptions = this.menu.options.filter((option) => {
91854
- const optionText = option.value || '';
91855
- return optionText.toLowerCase().startsWith(this.lastLetter);
91856
- });
91589
+ // Reset the buffer after a period of inactivity
91590
+ if (this._typeaheadTimeout) {
91591
+ clearTimeout(this._typeaheadTimeout);
91592
+ }
91593
+ this._typeaheadTimeout = setTimeout(() => {
91594
+ this._clearTypeaheadBuffer();
91595
+ }, this.typeaheadTimeoutMs);
91857
91596
 
91858
- // If we have options that match the letter pressed
91859
- if (letterOptions.length) {
91597
+ this.typeaheadBuffer += key;
91860
91598
 
91861
- // Show the dropdown if it is not already visible
91862
- this.dropdown.show();
91599
+ const isRepeatedChar = this.typeaheadBuffer.length > 1 && new Set(this.typeaheadBuffer).size === 1;
91863
91600
 
91864
- // Get the index we're after based on how many times the letter has been pressed and the length of the letterOptions array
91865
- const index = this.sameLetterTimes < letterOptions.length ? this.sameLetterTimes : this.sameLetterTimes % letterOptions.length;
91601
+ let match = null;
91602
+ if (isRepeatedChar) {
91603
+ const matches = options.filter((option) => this._getOptionDisplayText(option).startsWith(key));
91604
+ if (matches.length) {
91605
+ const cycleIndex = (this.typeaheadBuffer.length - 1) % matches.length;
91606
+ match = matches[cycleIndex];
91607
+ }
91608
+ } else {
91609
+ match = options.find((option) => this._getOptionDisplayText(option).startsWith(this.typeaheadBuffer));
91610
+ }
91866
91611
 
91867
- // Select the new option in the menu
91868
- const newOption = letterOptions[index];
91869
- this.menu.updateActiveOption(newOption);
91612
+ if (match) {
91613
+ if (!this.dropdown.isPopoverVisible) {
91614
+ this.dropdown.show();
91615
+ }
91616
+ this.menu.updateActiveOption(match);
91870
91617
  }
91871
91618
  }
91872
91619
 
@@ -91980,6 +91727,11 @@ class AuroSelect extends AuroElement$1 {
91980
91727
  }
91981
91728
  }
91982
91729
 
91730
+ disconnectedCallback() {
91731
+ super.disconnectedCallback();
91732
+ this._clearTypeaheadBuffer();
91733
+ }
91734
+
91983
91735
  // lifecycle runs only after the element's DOM has been updated the first time
91984
91736
  firstUpdated() {
91985
91737
  // Add the tag name as an attribute if it is different than the component name