@aurodesignsystem-dev/auro-formkit 0.0.0-pr1507.0 → 0.0.0-pr1508.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/checkbox/demo/customize.html +1 -2
- package/components/checkbox/demo/customize.min.js +1 -1
- package/components/checkbox/demo/getting-started.min.js +1 -1
- package/components/checkbox/demo/index.min.js +1 -1
- package/components/checkbox/dist/index.js +1 -1
- package/components/checkbox/dist/registered.js +1 -1
- package/components/combobox/demo/customize.html +1 -2
- package/components/combobox/demo/customize.md +108 -132
- package/components/combobox/demo/customize.min.js +150 -293
- package/components/combobox/demo/getting-started.min.js +150 -293
- package/components/combobox/demo/index.min.js +150 -293
- package/components/combobox/dist/auro-combobox.d.ts +9 -0
- package/components/combobox/dist/index.js +150 -293
- package/components/combobox/dist/registered.js +150 -293
- package/components/counter/demo/customize.min.js +10 -2
- package/components/counter/demo/index.min.js +10 -2
- package/components/counter/dist/index.js +10 -2
- package/components/counter/dist/registered.js +10 -2
- package/components/datepicker/demo/api.md +2 -0
- package/components/datepicker/demo/customize.js +0 -2
- package/components/datepicker/demo/customize.md +138 -38
- package/components/datepicker/demo/customize.min.js +59 -168
- package/components/datepicker/demo/index.min.js +59 -150
- package/components/datepicker/dist/index.js +59 -150
- package/components/datepicker/dist/registered.js +59 -150
- package/components/datepicker/dist/src/auro-datepicker.d.ts +2 -0
- package/components/dropdown/demo/customize.min.js +9 -1
- package/components/dropdown/demo/getting-started.min.js +9 -1
- package/components/dropdown/demo/index.min.js +9 -1
- package/components/dropdown/dist/auro-dropdown.d.ts +1 -0
- package/components/dropdown/dist/index.js +9 -1
- package/components/dropdown/dist/registered.js +9 -1
- package/components/form/demo/customize.html +6 -6
- package/components/form/demo/customize.js +19 -0
- package/components/form/demo/customize.md +203 -51
- package/components/form/demo/customize.min.js +707 -633
- package/components/form/demo/getting-started.min.js +635 -633
- package/components/form/demo/index.min.js +635 -633
- package/components/form/demo/registerDemoDeps.min.js +272 -596
- package/components/form/dist/auro-form.d.ts +122 -4
- package/components/form/dist/index.js +363 -37
- package/components/form/dist/registered.js +363 -37
- package/components/input/demo/customize.html +1 -2
- package/components/input/demo/customize.md +54 -53
- package/components/input/demo/customize.min.js +41 -147
- package/components/input/demo/getting-started.min.js +41 -147
- package/components/input/demo/index.min.js +41 -147
- package/components/input/dist/base-input.d.ts +1 -49
- package/components/input/dist/index.js +41 -147
- package/components/input/dist/registered.js +41 -147
- package/components/radio/demo/customize.min.js +1 -1
- package/components/radio/demo/getting-started.min.js +1 -1
- package/components/radio/demo/index.min.js +1 -1
- package/components/radio/dist/index.js +1 -1
- package/components/radio/dist/registered.js +1 -1
- package/components/select/demo/customize.html +1 -2
- package/components/select/demo/customize.min.js +10 -2
- package/components/select/demo/getting-started.min.js +10 -2
- package/components/select/demo/index.min.js +10 -2
- package/components/select/dist/index.js +10 -2
- package/components/select/dist/registered.js +10 -2
- package/custom-elements.json +1592 -1707
- package/package.json +1 -1
|
@@ -810,6 +810,8 @@ function navigateArrow(component, direction, options = {}) {
|
|
|
810
810
|
}
|
|
811
811
|
}
|
|
812
812
|
|
|
813
|
+
/* eslint-disable no-underscore-dangle */
|
|
814
|
+
|
|
813
815
|
/**
|
|
814
816
|
* Returns the clear button element from the active input's shadow
|
|
815
817
|
* DOM, if available.
|
|
@@ -845,11 +847,9 @@ function isClearBtnFocused(ctx, clearBtn = getClearBtn(ctx)) {
|
|
|
845
847
|
* @param {Object} menu - The menu component.
|
|
846
848
|
*/
|
|
847
849
|
function reconcileMenuIndex(menu) {
|
|
848
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
849
850
|
if (menu._index < 0 && menu.optionActive && menu.items) {
|
|
850
851
|
const idx = menu.items.indexOf(menu.optionActive);
|
|
851
852
|
if (idx >= 0) {
|
|
852
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
853
853
|
menu._index = idx;
|
|
854
854
|
}
|
|
855
855
|
}
|
|
@@ -4873,7 +4873,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$3 {
|
|
|
4873
4873
|
}
|
|
4874
4874
|
};
|
|
4875
4875
|
|
|
4876
|
-
var formkitVersion$2 = '
|
|
4876
|
+
var formkitVersion$2 = '202606231948';
|
|
4877
4877
|
|
|
4878
4878
|
let AuroElement$2 = class AuroElement extends i$3 {
|
|
4879
4879
|
static get properties() {
|
|
@@ -5824,6 +5824,14 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
5824
5824
|
};
|
|
5825
5825
|
this.addEventListener('keydown', this._bibTabHandler);
|
|
5826
5826
|
|
|
5827
|
+
// Suppress AuroFloatingUI's auto-hide-on-focus-loss while the
|
|
5828
|
+
// desktopModal trap owns focus management. Without this, the very
|
|
5829
|
+
// first focus move into the bib (from the RAF below) triggers
|
|
5830
|
+
// handleFocusLoss → hideBib, tearing down the trap before the
|
|
5831
|
+
// user can press Tab.
|
|
5832
|
+
this._priorNoHideOnFocusLoss = this.noHideOnThisFocusLoss;
|
|
5833
|
+
this.noHideOnThisFocusLoss = true;
|
|
5834
|
+
|
|
5827
5835
|
// Move initial focus into the bib content, matching FocusTrap behavior
|
|
5828
5836
|
requestAnimationFrame(() => {
|
|
5829
5837
|
const focusables = getFocusableElements(this.bibContent);
|
|
@@ -16594,6 +16602,7 @@ class AuroInputUtilities {
|
|
|
16594
16602
|
const maskOptions = this.getMaskOptions('date', normalizedFormat);
|
|
16595
16603
|
|
|
16596
16604
|
if (!(valueObject instanceof Date) || Number.isNaN(valueObject.getTime()) || !maskOptions || typeof maskOptions.format !== 'function') {
|
|
16605
|
+
console.debug('Invalid date object or mask options for formatting', { valueObject, maskOptions }); // eslint-disable-line no-console
|
|
16597
16606
|
return undefined;
|
|
16598
16607
|
}
|
|
16599
16608
|
|
|
@@ -16745,10 +16754,8 @@ class BaseInput extends AuroElement$1 {
|
|
|
16745
16754
|
this.layout = 'classic';
|
|
16746
16755
|
this.locale = 'en-US';
|
|
16747
16756
|
this.max = undefined;
|
|
16748
|
-
this._maxObject = undefined;
|
|
16749
16757
|
this.maxLength = undefined;
|
|
16750
16758
|
this.min = undefined;
|
|
16751
|
-
this._minObject = undefined;
|
|
16752
16759
|
this.minLength = undefined;
|
|
16753
16760
|
this.required = false;
|
|
16754
16761
|
this.onDark = false;
|
|
@@ -16756,7 +16763,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
16756
16763
|
this.size = 'lg';
|
|
16757
16764
|
this.shape = 'classic';
|
|
16758
16765
|
this.value = undefined;
|
|
16759
|
-
this._valueObject = undefined;
|
|
16760
16766
|
|
|
16761
16767
|
this._initializePrivateDefaults();
|
|
16762
16768
|
}
|
|
@@ -17296,7 +17302,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17296
17302
|
* @returns {Date|undefined}
|
|
17297
17303
|
*/
|
|
17298
17304
|
get valueObject() {
|
|
17299
|
-
return this.
|
|
17305
|
+
return this.value && dateFormatter.isValidDate(this.value) ? dateFormatter.stringToDateInstance(this.value) : undefined;
|
|
17300
17306
|
}
|
|
17301
17307
|
|
|
17302
17308
|
/**
|
|
@@ -17304,7 +17310,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17304
17310
|
* @returns {Date|undefined}
|
|
17305
17311
|
*/
|
|
17306
17312
|
get minObject() {
|
|
17307
|
-
return this.
|
|
17313
|
+
return this.min && dateFormatter.isValidDate(this.min) ? dateFormatter.stringToDateInstance(this.min) : undefined;
|
|
17308
17314
|
}
|
|
17309
17315
|
|
|
17310
17316
|
/**
|
|
@@ -17312,50 +17318,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17312
17318
|
* @returns {Date|undefined}
|
|
17313
17319
|
*/
|
|
17314
17320
|
get maxObject() {
|
|
17315
|
-
return this.
|
|
17316
|
-
}
|
|
17317
|
-
|
|
17318
|
-
/**
|
|
17319
|
-
* Parses a date string into a Date object when the corresponding `_*Object`
|
|
17320
|
-
* field hasn't been synced yet by `updated()`. Returns undefined when the
|
|
17321
|
-
* input type/format isn't a full date or the string is not a valid date.
|
|
17322
|
-
*
|
|
17323
|
-
* Why this exists: a parent (datepicker) can call `inputN.validate()` from
|
|
17324
|
-
* inside its own `updated()` before this input's `updated()` has run
|
|
17325
|
-
* `syncDateValues()` — so `_valueObject`/`_maxObject` are still `undefined`
|
|
17326
|
-
* and range checks would otherwise silently no-op (flipping the result to
|
|
17327
|
-
* `valid` or `patternMismatch`).
|
|
17328
|
-
* @private
|
|
17329
|
-
* @param {string|undefined} dateStr - ISO date string from `value`/`min`/`max`.
|
|
17330
|
-
* @returns {Date|undefined}
|
|
17331
|
-
*/
|
|
17332
|
-
_computeDateObjectFallback(dateStr) {
|
|
17333
|
-
if (!dateStr || !this.util || !this.util.isFullDateFormat(this.type, this.format)) {
|
|
17334
|
-
return undefined;
|
|
17335
|
-
}
|
|
17336
|
-
if (!dateFormatter.isValidDate(dateStr)) {
|
|
17337
|
-
return undefined;
|
|
17338
|
-
}
|
|
17339
|
-
return dateFormatter.stringToDateInstance(dateStr);
|
|
17340
|
-
}
|
|
17341
|
-
|
|
17342
|
-
/**
|
|
17343
|
-
* Internal setter for readonly date object properties.
|
|
17344
|
-
* @private
|
|
17345
|
-
* @param {'valueObject'|'minObject'|'maxObject'} propertyName - Public object property name.
|
|
17346
|
-
* @param {Date|undefined} propertyValue - Value to assign.
|
|
17347
|
-
* @returns {void}
|
|
17348
|
-
*/
|
|
17349
|
-
setDateObjectProperty(propertyName, propertyValue) {
|
|
17350
|
-
const internalPropertyName = `_${propertyName}`;
|
|
17351
|
-
const previousValue = this[internalPropertyName];
|
|
17352
|
-
|
|
17353
|
-
if (previousValue === propertyValue) {
|
|
17354
|
-
return;
|
|
17355
|
-
}
|
|
17356
|
-
|
|
17357
|
-
this[internalPropertyName] = propertyValue;
|
|
17358
|
-
this.requestUpdate(propertyName, previousValue);
|
|
17321
|
+
return this.max && dateFormatter.isValidDate(this.max) ? dateFormatter.stringToDateInstance(this.max) : undefined;
|
|
17359
17322
|
}
|
|
17360
17323
|
|
|
17361
17324
|
connectedCallback() {
|
|
@@ -17384,7 +17347,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17384
17347
|
format: this.format
|
|
17385
17348
|
});
|
|
17386
17349
|
this.configureDataForType();
|
|
17387
|
-
this.syncDateValues();
|
|
17388
17350
|
}
|
|
17389
17351
|
|
|
17390
17352
|
disconnectedCallback() {
|
|
@@ -17404,10 +17366,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17404
17366
|
this.wrapperElement.addEventListener('click', this.handleClick);
|
|
17405
17367
|
}
|
|
17406
17368
|
|
|
17407
|
-
// add attribute for query selectors when auro-input is registered under a custom name
|
|
17408
|
-
if (this.tagName.toLowerCase() !== 'auro-input' && !this.hasAttribute('auro-input')) {
|
|
17409
|
-
this.setAttribute('auro-input', '');
|
|
17410
|
-
}
|
|
17411
17369
|
this.inputId = this.id ? `${this.id}-input` : window.crypto.randomUUID();
|
|
17412
17370
|
|
|
17413
17371
|
// use validity message override if declared when initializing the component
|
|
@@ -17418,7 +17376,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17418
17376
|
this.setCustomHelpTextMessage();
|
|
17419
17377
|
this.configureAutoFormatting();
|
|
17420
17378
|
this.configureDataForType();
|
|
17421
|
-
this.syncDateValues();
|
|
17422
17379
|
}
|
|
17423
17380
|
|
|
17424
17381
|
/**
|
|
@@ -17555,8 +17512,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17555
17512
|
this.configureDataForType();
|
|
17556
17513
|
}
|
|
17557
17514
|
|
|
17558
|
-
this.syncDateValues(changedProperties);
|
|
17559
|
-
|
|
17560
17515
|
if (changedProperties.has('value')) {
|
|
17561
17516
|
if (this.value && this.value.length > 0) {
|
|
17562
17517
|
this.hasValue = true;
|
|
@@ -17578,14 +17533,14 @@ class BaseInput extends AuroElement$1 {
|
|
|
17578
17533
|
|
|
17579
17534
|
if (formattedValue !== this.inputElement.value) {
|
|
17580
17535
|
this.skipNextProgrammaticInputEvent = true;
|
|
17581
|
-
if (this.maskInstance && this.type
|
|
17536
|
+
if (this.maskInstance && this.type !== 'date') {
|
|
17582
17537
|
// Route through the mask so its _value and el.value stay in lock-step
|
|
17583
17538
|
// (set value calls updateControl which writes el.value = displayValue).
|
|
17584
17539
|
// Writing el.value directly leaves the mask thinking displayValue is
|
|
17585
|
-
// stale; _saveSelection on the next focus/click then warns.
|
|
17586
|
-
//
|
|
17587
|
-
//
|
|
17588
|
-
//
|
|
17540
|
+
// stale; _saveSelection on the next focus/click then warns. Date is
|
|
17541
|
+
// excluded because its formattedValue can be raw ISO when the calendar
|
|
17542
|
+
// is invalid, and re-masking through mm/dd/yyyy would truncate it and
|
|
17543
|
+
// flip validity from patternMismatch to tooShort.
|
|
17589
17544
|
this.maskInstance.value = formattedValue || '';
|
|
17590
17545
|
} else if (formattedValue) {
|
|
17591
17546
|
this.inputElement.value = formattedValue;
|
|
@@ -17627,120 +17582,65 @@ class BaseInput extends AuroElement$1 {
|
|
|
17627
17582
|
}));
|
|
17628
17583
|
}
|
|
17629
17584
|
|
|
17630
|
-
|
|
17631
|
-
/**
|
|
17632
|
-
* Synchronizes the ISO string values and Date object representations for date-related properties.
|
|
17633
|
-
* This keeps the model and display values aligned when either side changes.
|
|
17634
|
-
*
|
|
17635
|
-
* When a full date format is in use, this method updates `value`, `min`, and `max` from their corresponding
|
|
17636
|
-
* Date objects or vice versa, based on which properties have changed. It only runs when the current configuration
|
|
17637
|
-
* represents a full year/month/day date format.
|
|
17638
|
-
*
|
|
17639
|
-
* @param {Map<string, unknown>|undefined} [changedProperties=undefined] - Optional map of changed properties used to limit which values are synchronized.
|
|
17640
|
-
* @returns {void}
|
|
17641
|
-
* @private
|
|
17642
|
-
*/
|
|
17643
|
-
syncDateValues(changedProperties = undefined) {
|
|
17644
|
-
if (!this.util.isFullDateFormat(this.type, this.format)) {
|
|
17645
|
-
return;
|
|
17646
|
-
}
|
|
17647
|
-
|
|
17648
|
-
this.syncSingleDateValue(changedProperties, 'valueObject', 'value');
|
|
17649
|
-
this.syncSingleDateValue(changedProperties, 'minObject', 'min');
|
|
17650
|
-
this.syncSingleDateValue(changedProperties, 'maxObject', 'max');
|
|
17651
|
-
}
|
|
17652
|
-
|
|
17653
|
-
/**
|
|
17654
|
-
* Synchronizes one date object/string property pair.
|
|
17655
|
-
* @private
|
|
17656
|
-
* @param {Map<string, unknown>|undefined} changedProperties - Map of changed properties from Lit.
|
|
17657
|
-
* @param {string} objectProperty - Date object property name.
|
|
17658
|
-
* @param {string} valueProperty - ISO string property name.
|
|
17659
|
-
* @returns {void}
|
|
17660
|
-
*/
|
|
17661
|
-
syncSingleDateValue(changedProperties, objectProperty, valueProperty) {
|
|
17662
|
-
const objectPropertyChanged = !changedProperties || changedProperties.has(objectProperty);
|
|
17663
|
-
|
|
17664
|
-
// objectProperty wins over valueProperty when both changed
|
|
17665
|
-
if (objectPropertyChanged && this[objectProperty]) {
|
|
17666
|
-
this[valueProperty] = dateFormatter.toISOFormatString(this[objectProperty]);
|
|
17667
|
-
return;
|
|
17668
|
-
}
|
|
17669
|
-
|
|
17670
|
-
const valuePropertyChanged = !changedProperties || changedProperties.has(valueProperty);
|
|
17671
|
-
if (!valuePropertyChanged) {
|
|
17672
|
-
return;
|
|
17673
|
-
}
|
|
17674
|
-
|
|
17675
|
-
// 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)
|
|
17676
|
-
if (
|
|
17677
|
-
changedProperties &&
|
|
17678
|
-
valueProperty === 'value' &&
|
|
17679
|
-
changedProperties.get('value') === undefined &&
|
|
17680
|
-
this[objectProperty] instanceof Date &&
|
|
17681
|
-
this[valueProperty] === dateFormatter.toISOFormatString(this[objectProperty])
|
|
17682
|
-
) {
|
|
17683
|
-
return;
|
|
17684
|
-
}
|
|
17685
|
-
|
|
17686
|
-
if (dateFormatter.isValidDate(this[valueProperty])) {
|
|
17687
|
-
this.setDateObjectProperty(objectProperty, dateFormatter.stringToDateInstance(this[valueProperty]));
|
|
17688
|
-
} else {
|
|
17689
|
-
this.setDateObjectProperty(objectProperty, undefined);
|
|
17690
|
-
}
|
|
17691
|
-
}
|
|
17692
|
-
|
|
17693
17585
|
/**
|
|
17694
17586
|
* Sets up IMasks and logic based on auto-formatting requirements.
|
|
17695
17587
|
* @private
|
|
17696
17588
|
* @returns {void}
|
|
17697
17589
|
*/
|
|
17698
17590
|
configureAutoFormatting() {
|
|
17699
|
-
//
|
|
17700
|
-
//
|
|
17701
|
-
//
|
|
17702
|
-
//
|
|
17591
|
+
// _configuringMask gates two things: external re-entry into this method
|
|
17592
|
+
// while setup is mid-flight (from property changes that call back here),
|
|
17593
|
+
// and the accept/complete listeners below — both need to ignore the mask
|
|
17594
|
+
// events fired by our own value-restore step.
|
|
17703
17595
|
if (this._configuringMask) return;
|
|
17704
17596
|
this._configuringMask = true;
|
|
17705
17597
|
try {
|
|
17598
|
+
// Destroy any prior mask so IMask can attach fresh under the new format.
|
|
17599
|
+
// Null the reference too — if the new maskOptions.mask is falsy (e.g.
|
|
17600
|
+
// type switched from credit-card to text) the IMask() reassignment
|
|
17601
|
+
// below is skipped, and downstream writes at line ~823 would otherwise
|
|
17602
|
+
// route through the destroyed instance.
|
|
17706
17603
|
if (this.maskInstance) {
|
|
17707
17604
|
this.maskInstance.destroy();
|
|
17605
|
+
this.maskInstance = null;
|
|
17708
17606
|
}
|
|
17709
17607
|
|
|
17710
|
-
// Pass new format to util
|
|
17711
17608
|
this.util.updateFormat(this.format);
|
|
17712
17609
|
|
|
17713
17610
|
const maskOptions = this.util.getMaskOptions(this.type, this.format);
|
|
17714
17611
|
|
|
17715
17612
|
if (this.inputElement && maskOptions.mask) {
|
|
17716
|
-
|
|
17717
|
-
//
|
|
17718
|
-
//
|
|
17719
|
-
//
|
|
17720
|
-
// When the format changes (e.g. locale switch) and we have a valid ISO
|
|
17721
|
-
// model value, compute the display string for the NEW format instead of
|
|
17722
|
-
// re-using the old display string, which may be invalid in the new mask.
|
|
17613
|
+
// Capture the current display so it can be re-applied after IMask
|
|
17614
|
+
// attaches. The restore at the bottom goes through maskInstance.value
|
|
17615
|
+
// (not inputElement.value directly) so the mask's internal state and
|
|
17616
|
+
// the input's displayed text stay in lock-step.
|
|
17723
17617
|
let existingValue = this.inputElement.value;
|
|
17618
|
+
|
|
17619
|
+
// Format-change case (e.g. locale switch): existingValue is the OLD
|
|
17620
|
+
// mask's display string and may not parse under the new mask. When
|
|
17621
|
+
// we have a valid date model, rebuild the display from valueObject
|
|
17622
|
+
// (the canonical source) using the new mask's format function.
|
|
17724
17623
|
if (
|
|
17725
17624
|
this.util.isFullDateFormat(this.type, this.format) &&
|
|
17726
17625
|
this.value &&
|
|
17727
|
-
|
|
17728
|
-
this.valueObject instanceof Date &&
|
|
17729
|
-
!Number.isNaN(this.valueObject.getTime()) &&
|
|
17626
|
+
this.valueObject &&
|
|
17730
17627
|
typeof maskOptions.format === 'function'
|
|
17731
17628
|
) {
|
|
17732
17629
|
existingValue = maskOptions.format(this.valueObject);
|
|
17733
17630
|
}
|
|
17734
17631
|
|
|
17632
|
+
// Clear before IMask attaches so the constructor seeds an empty
|
|
17633
|
+
// internal value. Otherwise IMask reads the stale unmasked string
|
|
17634
|
+
// and emits a spurious 'accept' before the restore below runs.
|
|
17735
17635
|
this.skipNextProgrammaticInputEvent = true;
|
|
17736
17636
|
this.inputElement.value = '';
|
|
17737
17637
|
|
|
17738
17638
|
this.maskInstance = IMask(this.inputElement, maskOptions);
|
|
17739
17639
|
|
|
17640
|
+
// Mask fires 'accept' on every value change, including the restore
|
|
17641
|
+
// step below. Skip events fired during configureAutoFormatting so
|
|
17642
|
+
// we don't overwrite a value the parent just pushed.
|
|
17740
17643
|
this.maskInstance.on('accept', () => {
|
|
17741
|
-
// Suppress propagation during configureAutoFormatting's own value-restoration
|
|
17742
|
-
// (line below) — the mask emits 'accept' on every value-set, including ours,
|
|
17743
|
-
// and we don't want to overwrite a value the parent just pushed.
|
|
17744
17644
|
if (this._configuringMask) return;
|
|
17745
17645
|
this.value = this.util.toModelValue(this.maskInstance.value, this.format);
|
|
17746
17646
|
if (this.type === "date") {
|
|
@@ -17748,6 +17648,8 @@ class BaseInput extends AuroElement$1 {
|
|
|
17748
17648
|
}
|
|
17749
17649
|
});
|
|
17750
17650
|
|
|
17651
|
+
// Mask fires 'complete' on the restore step below for any value that
|
|
17652
|
+
// happens to be a complete match. Same setup-suppression as 'accept'.
|
|
17751
17653
|
this.maskInstance.on('complete', () => {
|
|
17752
17654
|
if (this._configuringMask) return;
|
|
17753
17655
|
this.value = this.util.toModelValue(this.maskInstance.value, this.format);
|
|
@@ -17756,7 +17658,9 @@ class BaseInput extends AuroElement$1 {
|
|
|
17756
17658
|
}
|
|
17757
17659
|
});
|
|
17758
17660
|
|
|
17759
|
-
//
|
|
17661
|
+
// Write existingValue through the mask (not the input directly) so
|
|
17662
|
+
// the mask reformats it under the new rules and keeps its internal
|
|
17663
|
+
// _value aligned with the input's displayed text.
|
|
17760
17664
|
if (existingValue) {
|
|
17761
17665
|
this.maskInstance.value = existingValue;
|
|
17762
17666
|
}
|
|
@@ -17924,7 +17828,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17924
17828
|
*/
|
|
17925
17829
|
reset() {
|
|
17926
17830
|
this.value = undefined;
|
|
17927
|
-
this.setDateObjectProperty('valueObject', undefined);
|
|
17928
17831
|
this.validation.reset(this);
|
|
17929
17832
|
}
|
|
17930
17833
|
|
|
@@ -17933,7 +17836,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17933
17836
|
*/
|
|
17934
17837
|
clear() {
|
|
17935
17838
|
this.value = undefined;
|
|
17936
|
-
this.setDateObjectProperty('valueObject', undefined);
|
|
17937
17839
|
}
|
|
17938
17840
|
|
|
17939
17841
|
/**
|
|
@@ -18462,7 +18364,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$3 {
|
|
|
18462
18364
|
}
|
|
18463
18365
|
};
|
|
18464
18366
|
|
|
18465
|
-
var formkitVersion$1 = '
|
|
18367
|
+
var formkitVersion$1 = '202606231948';
|
|
18466
18368
|
|
|
18467
18369
|
// Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
18468
18370
|
// See LICENSE in the project root for license information.
|
|
@@ -19583,7 +19485,7 @@ class AuroBibtemplate extends i$3 {
|
|
|
19583
19485
|
}
|
|
19584
19486
|
}
|
|
19585
19487
|
|
|
19586
|
-
var formkitVersion = '
|
|
19488
|
+
var formkitVersion = '202606231948';
|
|
19587
19489
|
|
|
19588
19490
|
var styleCss$3 = i$6`.util_displayInline{display:inline}.util_displayInlineBlock{display:inline-block}.util_displayBlock{display:block}.util_displayFlex{display:flex}.util_displayHidden{display:none}.util_displayHiddenVisually{position:absolute;overflow:hidden;clip:rect(1px, 1px, 1px, 1px);width:1px;height:1px;padding:0;border:0}:host{display:block;text-align:left}:host [auro-dropdown]{--ds-auro-dropdown-trigger-background-color: transparent}:host #inputInBib::part(wrapper){box-shadow:none}:host #inputInBib::part(accent-left){display:none}:host([layout*=classic]) [auro-input]{width:100%}:host([layout*=classic]) [auro-input]::part(helpText){display:none}:host([layout*=classic]) #slotHolder{display:none}`;
|
|
19589
19491
|
|
|
@@ -20570,7 +20472,7 @@ class AuroCombobox extends AuroElement {
|
|
|
20570
20472
|
if (this.menu) {
|
|
20571
20473
|
this.menu.matchWord = normalizeFilterValue(this.input.value);
|
|
20572
20474
|
}
|
|
20573
|
-
const label = getOptionLabel(this.menu.optionSelected)
|
|
20475
|
+
const label = getOptionLabel(this.menu.optionSelected);
|
|
20574
20476
|
this.updateTriggerTextDisplay(label || this.value);
|
|
20575
20477
|
}
|
|
20576
20478
|
|
|
@@ -20584,40 +20486,9 @@ class AuroCombobox extends AuroElement {
|
|
|
20584
20486
|
// in suggestion mode, do not override input value if no selection has been made and the input currently has focus
|
|
20585
20487
|
const isInputFocusedWithNoSelection = !this.menu.value && (this.input.matches(':focus-within') || (this.inputInBib && this.inputInBib.matches(':focus-within')));
|
|
20586
20488
|
|
|
20587
|
-
|
|
20588
|
-
|
|
20589
|
-
|
|
20590
|
-
// syncValuesAndStates re-enters here during typing when both inputs
|
|
20591
|
-
// already match, and a no-op flag flip would make the bib branch's
|
|
20592
|
-
// bail eat legitimate user-input events.
|
|
20593
|
-
const triggerNeedsSync = this.input.value !== nextValue;
|
|
20594
|
-
const bibNeedsSync = Boolean(this.inputInBib && this.inputInBib !== this.input && this.inputInBib.value !== nextValue);
|
|
20595
|
-
if (triggerNeedsSync || bibNeedsSync) {
|
|
20596
|
-
this._syncingDisplayValue = true;
|
|
20597
|
-
if (triggerNeedsSync) {
|
|
20598
|
-
this.input.value = nextValue;
|
|
20599
|
-
}
|
|
20600
|
-
if (bibNeedsSync) {
|
|
20601
|
-
this.inputInBib.value = nextValue;
|
|
20602
|
-
}
|
|
20603
|
-
const pending = [];
|
|
20604
|
-
if (triggerNeedsSync) {
|
|
20605
|
-
pending.push(this.input.updateComplete);
|
|
20606
|
-
}
|
|
20607
|
-
if (bibNeedsSync) {
|
|
20608
|
-
pending.push(this.inputInBib.updateComplete);
|
|
20609
|
-
}
|
|
20610
|
-
Promise.all(pending).then(() => {
|
|
20611
|
-
// imask reasserts otherwise, and handleBlur reverts to its stale value.
|
|
20612
|
-
if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
|
|
20613
|
-
this.input.maskInstance.updateValue();
|
|
20614
|
-
}
|
|
20615
|
-
if (bibNeedsSync && this.inputInBib && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
|
|
20616
|
-
this.inputInBib.maskInstance.updateValue();
|
|
20617
|
-
}
|
|
20618
|
-
this._syncingDisplayValue = false;
|
|
20619
|
-
});
|
|
20620
|
-
}
|
|
20489
|
+
const suppressed = this.persistInput || (this.behavior === 'suggestion' && isInputFocusedWithNoSelection);
|
|
20490
|
+
if (!suppressed) {
|
|
20491
|
+
this.syncInputValuesAcrossTriggerAndBib(label || this.value);
|
|
20621
20492
|
}
|
|
20622
20493
|
|
|
20623
20494
|
// update the displayValue in the trigger if displayValue slot content is present
|
|
@@ -20645,6 +20516,48 @@ class AuroCombobox extends AuroElement {
|
|
|
20645
20516
|
this.requestUpdate();
|
|
20646
20517
|
}
|
|
20647
20518
|
|
|
20519
|
+
/**
|
|
20520
|
+
* Writes nextValue to the trigger input and the bib input when their current
|
|
20521
|
+
* value differs, then re-asserts imask after Lit's update flushes.
|
|
20522
|
+
* @param {string} nextValue - The value to write to both inputs.
|
|
20523
|
+
* @returns {Promise<void> | null} Promise that resolves after the inputs flush,
|
|
20524
|
+
* or null when no sync was needed (so callers can skip post-flush work).
|
|
20525
|
+
* @private
|
|
20526
|
+
*/
|
|
20527
|
+
syncInputValuesAcrossTriggerAndBib(nextValue) {
|
|
20528
|
+
// Only set the flag when there's an actual write to suppress —
|
|
20529
|
+
// syncValuesAndStates re-enters here during typing when both inputs
|
|
20530
|
+
// already match, and a no-op flag flip would make the bib branch's
|
|
20531
|
+
// bail eat legitimate user-input events.
|
|
20532
|
+
const triggerNeedsSync = this.input.value !== nextValue;
|
|
20533
|
+
const bibNeedsSync = this.inputInBib.value !== nextValue;
|
|
20534
|
+
if (!triggerNeedsSync && !bibNeedsSync) {
|
|
20535
|
+
return null;
|
|
20536
|
+
}
|
|
20537
|
+
|
|
20538
|
+
this._syncingDisplayValue = true;
|
|
20539
|
+
|
|
20540
|
+
const pending = [];
|
|
20541
|
+
if (triggerNeedsSync) {
|
|
20542
|
+
this.input.value = nextValue;
|
|
20543
|
+
pending.push(this.input.updateComplete);
|
|
20544
|
+
}
|
|
20545
|
+
if (bibNeedsSync) {
|
|
20546
|
+
this.inputInBib.value = nextValue;
|
|
20547
|
+
pending.push(this.inputInBib.updateComplete);
|
|
20548
|
+
}
|
|
20549
|
+
return Promise.all(pending).then(() => {
|
|
20550
|
+
// imask reasserts otherwise, and handleBlur reverts to its stale value.
|
|
20551
|
+
if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
|
|
20552
|
+
this.input.maskInstance.updateValue();
|
|
20553
|
+
}
|
|
20554
|
+
if (bibNeedsSync && this.inputInBib && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
|
|
20555
|
+
this.inputInBib.maskInstance.updateValue();
|
|
20556
|
+
}
|
|
20557
|
+
this._syncingDisplayValue = false;
|
|
20558
|
+
});
|
|
20559
|
+
}
|
|
20560
|
+
|
|
20648
20561
|
/**
|
|
20649
20562
|
* Processes hidden state of all menu options and determines if there are any available options not hidden.
|
|
20650
20563
|
* @private
|
|
@@ -20672,9 +20585,9 @@ class AuroCombobox extends AuroElement {
|
|
|
20672
20585
|
this.syncValuesAndStates();
|
|
20673
20586
|
}
|
|
20674
20587
|
|
|
20675
|
-
// Re-activate when optionActive is
|
|
20676
|
-
// been reset (e.g. by clearSelection in an async update)
|
|
20677
|
-
// makeSelection() can find the correct option.
|
|
20588
|
+
// Re-activate when optionActive is not in the current scrollable viewport,
|
|
20589
|
+
// or when _index has been reset (e.g. by clearSelection in an async update)
|
|
20590
|
+
// so that makeSelection() can find the correct option.
|
|
20678
20591
|
if (!this.availableOptions.includes(this.menu.optionActive) || this.menu._index < 0) {
|
|
20679
20592
|
this.activateFirstEnabledAvailableOption();
|
|
20680
20593
|
}
|
|
@@ -20808,28 +20721,25 @@ class AuroCombobox extends AuroElement {
|
|
|
20808
20721
|
|
|
20809
20722
|
guardTouchPassthrough(this.menu);
|
|
20810
20723
|
|
|
20811
|
-
//
|
|
20812
|
-
//
|
|
20813
|
-
//
|
|
20724
|
+
// showModal() takes focus away from the trigger. Early focus once
|
|
20725
|
+
// the dialog has painted; the shared doubleRaf below is the fallback
|
|
20726
|
+
// for when the dialog needs an extra frame and also clears the
|
|
20727
|
+
// validation guard.
|
|
20814
20728
|
requestAnimationFrame(() => {
|
|
20815
20729
|
this.setInputFocus();
|
|
20816
20730
|
});
|
|
20817
|
-
|
|
20818
|
-
doubleRaf(() => {
|
|
20819
|
-
this.setInputFocus();
|
|
20820
|
-
this._inFullscreenTransition = false;
|
|
20821
|
-
});
|
|
20822
|
-
} else {
|
|
20823
|
-
// Desktop popover-open: restore the trigger caret to end-of-text.
|
|
20824
|
-
// Clicking the trigger lands on auro-input's floating <label for="…">
|
|
20825
|
-
// overlay; Chrome resets the native input's selection to [0, 0] on
|
|
20826
|
-
// label-focus before any JS runs. setInputFocus()'s non-fullscreen
|
|
20827
|
-
// branch parks the caret at end. doubleRaf lets the dropdown layout
|
|
20828
|
-
// settle first, matching the fullscreen branch timing.
|
|
20829
|
-
doubleRaf(() => {
|
|
20830
|
-
this.setInputFocus();
|
|
20831
|
-
});
|
|
20832
20731
|
}
|
|
20732
|
+
// else (desktop popover-open): Chrome resets the trigger caret to
|
|
20733
|
+
// [0, 0] when its floating <label for="…"> overlay receives focus.
|
|
20734
|
+
// The shared doubleRaf below parks the caret back at end-of-text
|
|
20735
|
+
// after the dropdown layout settles.
|
|
20736
|
+
|
|
20737
|
+
doubleRaf(() => {
|
|
20738
|
+
this.setInputFocus();
|
|
20739
|
+
if (this._inFullscreenTransition) {
|
|
20740
|
+
this._inFullscreenTransition = false;
|
|
20741
|
+
}
|
|
20742
|
+
});
|
|
20833
20743
|
}
|
|
20834
20744
|
});
|
|
20835
20745
|
|
|
@@ -20934,24 +20844,7 @@ class AuroCombobox extends AuroElement {
|
|
|
20934
20844
|
nativeInput.setSelectionRange(len, len);
|
|
20935
20845
|
}
|
|
20936
20846
|
} else {
|
|
20937
|
-
|
|
20938
|
-
// fullscreen→floating switch can close the dialog and leave focus on
|
|
20939
|
-
// body. Every other Branch 2 callsite already has focus on the input
|
|
20940
|
-
// via the focusin → this.focus() redirect (L1448-1452), so this is a
|
|
20941
|
-
// no-op in the common case.
|
|
20942
|
-
if (!this.input.componentHasFocus) {
|
|
20943
|
-
this.input.focus();
|
|
20944
|
-
}
|
|
20945
|
-
|
|
20946
|
-
// Park the trigger native input's caret at end-of-text every time the
|
|
20947
|
-
// popover opens. Chrome focuses the native via the floating <label for="…">
|
|
20948
|
-
// overlay on click and resets selection to [0, 0]; no JS fires between
|
|
20949
|
-
// mousedown and selectionchange, so we restore the caret here.
|
|
20950
|
-
const triggerNativeInput = this.input.inputElement;
|
|
20951
|
-
if (triggerNativeInput && triggerNativeInput.value) {
|
|
20952
|
-
const len = triggerNativeInput.value.length;
|
|
20953
|
-
triggerNativeInput.setSelectionRange(len, len);
|
|
20954
|
-
}
|
|
20847
|
+
this.input.focus();
|
|
20955
20848
|
}
|
|
20956
20849
|
}
|
|
20957
20850
|
|
|
@@ -21057,7 +20950,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21057
20950
|
if (this.menu.optionSelected) {
|
|
21058
20951
|
const selected = this.menu.optionSelected;
|
|
21059
20952
|
|
|
21060
|
-
if (
|
|
20953
|
+
if (this.optionSelected !== selected) {
|
|
21061
20954
|
this.optionSelected = selected;
|
|
21062
20955
|
}
|
|
21063
20956
|
|
|
@@ -21070,7 +20963,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21070
20963
|
}
|
|
21071
20964
|
|
|
21072
20965
|
// Update display
|
|
21073
|
-
this.updateTriggerTextDisplay(getOptionLabel(this.optionSelected)
|
|
20966
|
+
this.updateTriggerTextDisplay(getOptionLabel(this.optionSelected));
|
|
21074
20967
|
|
|
21075
20968
|
// Update match word for filtering
|
|
21076
20969
|
const trimmedInput = normalizeFilterValue(this.input.value);
|
|
@@ -21086,13 +20979,22 @@ class AuroCombobox extends AuroElement {
|
|
|
21086
20979
|
this.hideBib();
|
|
21087
20980
|
}
|
|
21088
20981
|
|
|
20982
|
+
// Move focus to the clear button when the user makes a selection.
|
|
20983
|
+
if (!isEcho && this.menu.value !== undefined) {
|
|
20984
|
+
this.setClearBtnFocus();
|
|
20985
|
+
}
|
|
20986
|
+
|
|
21089
20987
|
// Announce the selection after the dropdown closes so it isn't
|
|
21090
20988
|
// overridden by VoiceOver's "collapsed" announcement from aria-expanded.
|
|
20989
|
+
// Skip when there's no selected value (e.g. menu.clearSelection() from
|
|
20990
|
+
// the unmatched-value path), otherwise VoiceOver reads "undefined".
|
|
21091
20991
|
const selectedValue = this.menu.value;
|
|
21092
|
-
|
|
21093
|
-
|
|
21094
|
-
|
|
21095
|
-
|
|
20992
|
+
if (selectedValue) {
|
|
20993
|
+
const announcementDelay = 300;
|
|
20994
|
+
setTimeout(() => {
|
|
20995
|
+
announceToScreenReader(this._getAnnouncementRoot(), `${selectedValue}, selected`);
|
|
20996
|
+
}, announcementDelay);
|
|
20997
|
+
}
|
|
21096
20998
|
}
|
|
21097
20999
|
|
|
21098
21000
|
// Programmatic value syncs leave availableOptions stale because
|
|
@@ -21106,18 +21008,6 @@ class AuroCombobox extends AuroElement {
|
|
|
21106
21008
|
this._programmaticFilterRefresh = false;
|
|
21107
21009
|
}, 0);
|
|
21108
21010
|
}
|
|
21109
|
-
|
|
21110
|
-
// base-input skips auto-validate when focus is inside its own shadow,
|
|
21111
|
-
// which it is after setTriggerInputFocus — re-run so prior tooShort
|
|
21112
|
-
// clears. processCreditCard reasserts errorMessage on every render.
|
|
21113
|
-
if (!isEcho && this.menu.optionSelected && this.input.validate) {
|
|
21114
|
-
this.input.updateComplete.then(() => {
|
|
21115
|
-
this.input.validate(true);
|
|
21116
|
-
if (this.input.validity === 'valid') {
|
|
21117
|
-
this.input.errorMessage = '';
|
|
21118
|
-
}
|
|
21119
|
-
});
|
|
21120
|
-
}
|
|
21121
21011
|
});
|
|
21122
21012
|
|
|
21123
21013
|
this.menu.addEventListener('auroMenu-customEventFired', () => {
|
|
@@ -21452,15 +21342,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21452
21342
|
this.menu.value = undefined;
|
|
21453
21343
|
this.validation.reset(this);
|
|
21454
21344
|
this.touched = false;
|
|
21455
|
-
// Force validity back to the cleared state. validation.reset() calls
|
|
21456
|
-
// validate() at the end, and (post-credit-card-fix) the trigger input's
|
|
21457
|
-
// residual validity may still be copied into the combobox by the
|
|
21458
|
-
// auroInputElements loop. Explicitly clear here so reset() actually
|
|
21459
|
-
// leaves the component in a "no validity" state.
|
|
21460
21345
|
this.validity = undefined;
|
|
21461
|
-
this.errorMessage = '';
|
|
21462
|
-
this.input.validity = undefined;
|
|
21463
|
-
this.input.errorMessage = '';
|
|
21464
21346
|
}
|
|
21465
21347
|
|
|
21466
21348
|
/**
|
|
@@ -21513,52 +21395,27 @@ class AuroCombobox extends AuroElement {
|
|
|
21513
21395
|
this.input.value = this.value;
|
|
21514
21396
|
}
|
|
21515
21397
|
|
|
21516
|
-
// Sync menu.value only when an option actually matches
|
|
21398
|
+
// Sync menu.value only when an option actually matches, or when filter
|
|
21399
|
+
// mode needs setMenuValue to dispatch auroMenu-selectValueFailure (the
|
|
21400
|
+
// listener at line 1206 clears combobox.value, mirroring select's
|
|
21401
|
+
// pattern). Otherwise sync the input display for freeform values.
|
|
21517
21402
|
if (this.menu.options && this.menu.options.length > 0) {
|
|
21518
|
-
if (this.menu.options.some((opt) => opt.value === this.value)) {
|
|
21519
|
-
this.setMenuValue(this.value);
|
|
21520
|
-
} else if (this.behavior === 'filter') {
|
|
21521
|
-
// In filter mode, freeform values aren't allowed. Push the unmatched
|
|
21522
|
-
// value through setMenuValue so menu dispatches auroMenu-selectValueFailure
|
|
21523
|
-
// and the listener at line 1206 clears combobox.value (mirrors select's
|
|
21524
|
-
// pattern). Bypassing setMenuValue here would skip the failure cascade.
|
|
21403
|
+
if (this.menu.options.some((opt) => opt.value === this.value) || this.behavior === 'filter') {
|
|
21525
21404
|
this.setMenuValue(this.value);
|
|
21526
21405
|
} else {
|
|
21527
|
-
|
|
21528
|
-
|
|
21406
|
+
// Clear menu.value AND menu.optionSelected together. Clearing only
|
|
21407
|
+
// menu.value leaves the previously-selected option element pinned
|
|
21408
|
+
// as menu.optionSelected; a later auroMenu-selectedOption event
|
|
21409
|
+
// would then write its stale .value back into combobox.value.
|
|
21410
|
+
if (this.menu.value || this.menu.optionSelected) {
|
|
21411
|
+
this.menu.clearSelection();
|
|
21529
21412
|
}
|
|
21530
|
-
//
|
|
21531
|
-
//
|
|
21532
|
-
//
|
|
21533
|
-
|
|
21534
|
-
|
|
21535
|
-
|
|
21536
|
-
const triggerNeedsSync = this.input.value !== nextValue;
|
|
21537
|
-
const bibNeedsSync = Boolean(this.inputInBib && this.inputInBib !== this.input && this.inputInBib.value !== nextValue);
|
|
21538
|
-
if (triggerNeedsSync || bibNeedsSync) {
|
|
21539
|
-
this._syncingDisplayValue = true;
|
|
21540
|
-
if (triggerNeedsSync) {
|
|
21541
|
-
this.input.value = nextValue;
|
|
21542
|
-
}
|
|
21543
|
-
if (bibNeedsSync) {
|
|
21544
|
-
this.inputInBib.value = nextValue;
|
|
21545
|
-
}
|
|
21546
|
-
const pending = [];
|
|
21547
|
-
if (triggerNeedsSync) {
|
|
21548
|
-
pending.push(this.input.updateComplete);
|
|
21549
|
-
}
|
|
21550
|
-
if (bibNeedsSync) {
|
|
21551
|
-
pending.push(this.inputInBib.updateComplete);
|
|
21552
|
-
}
|
|
21553
|
-
Promise.all(pending).then(() => {
|
|
21554
|
-
if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
|
|
21555
|
-
this.input.maskInstance.updateValue();
|
|
21556
|
-
}
|
|
21557
|
-
if (bibNeedsSync && this.inputInBib && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
|
|
21558
|
-
this.inputInBib.maskInstance.updateValue();
|
|
21559
|
-
}
|
|
21560
|
-
this._syncingDisplayValue = false;
|
|
21561
|
-
// handleInputValueChange bailed on the flag — refresh the filter.
|
|
21413
|
+
// Suggestion-mode freeform value: sync the trigger + bib to show it,
|
|
21414
|
+
// then refresh the filter once the inputs flush (handleInputValueChange
|
|
21415
|
+
// bailed on _syncingDisplayValue).
|
|
21416
|
+
const syncPromise = this.syncInputValuesAcrossTriggerAndBib(this.value || '');
|
|
21417
|
+
if (syncPromise) {
|
|
21418
|
+
syncPromise.then(() => {
|
|
21562
21419
|
this._programmaticFilterRefresh = true;
|
|
21563
21420
|
this.handleMenuOptions();
|
|
21564
21421
|
setTimeout(() => {
|