@aurodesignsystem-dev/auro-formkit 0.0.0-pr1507.0 → 0.0.0-pr1508.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.
- package/components/bibtemplate/dist/index.js +1 -1
- package/components/bibtemplate/dist/registered.js +1 -1
- package/components/checkbox/demo/customize.html +1 -2
- package/components/checkbox/demo/customize.min.js +8 -6
- package/components/checkbox/demo/getting-started.min.js +8 -6
- package/components/checkbox/demo/index.min.js +8 -6
- package/components/checkbox/dist/index.js +8 -6
- package/components/checkbox/dist/registered.js +8 -6
- package/components/combobox/demo/customize.html +1 -2
- package/components/combobox/demo/customize.md +105 -137
- package/components/combobox/demo/customize.min.js +506 -568
- package/components/combobox/demo/getting-started.min.js +506 -564
- package/components/combobox/demo/index.min.js +506 -564
- package/components/combobox/demo/keyboard-behavior.md +2 -142
- package/components/combobox/demo/why-combobox.md +1 -1
- package/components/combobox/dist/auro-combobox.d.ts +30 -14
- package/components/combobox/dist/index.js +505 -563
- package/components/combobox/dist/registered.js +505 -563
- package/components/counter/demo/customize.min.js +26 -8
- package/components/counter/demo/index.min.js +26 -8
- package/components/counter/dist/index.js +26 -8
- package/components/counter/dist/registered.js +26 -8
- package/components/datepicker/demo/accessibility.md +2 -1
- package/components/datepicker/demo/api.md +65 -62
- package/components/datepicker/demo/customize.md +150 -39
- package/components/datepicker/demo/customize.min.js +988 -500
- package/components/datepicker/demo/index.min.js +988 -482
- package/components/datepicker/dist/{src/auro-calendar-cell.d.ts → auro-calendar-cell.d.ts} +20 -3
- package/components/datepicker/dist/{src/auro-calendar.d.ts → auro-calendar.d.ts} +121 -7
- package/components/datepicker/dist/{src/auro-datepicker.d.ts → auro-datepicker.d.ts} +80 -5
- package/components/datepicker/dist/blackoutUtils.d.ts +43 -0
- package/components/datepicker/dist/index.js +988 -482
- package/components/datepicker/dist/registered.js +988 -482
- package/components/dropdown/demo/customize.min.js +10 -1
- package/components/dropdown/demo/getting-started.min.js +10 -1
- package/components/dropdown/demo/index.min.js +10 -1
- package/components/dropdown/dist/auro-dropdown.d.ts +1 -0
- package/components/dropdown/dist/index.js +10 -1
- package/components/dropdown/dist/registered.js +10 -1
- package/components/form/demo/customize.html +6 -6
- package/components/form/demo/customize.md +203 -51
- package/components/form/demo/customize.min.js +2357 -1419
- package/components/form/demo/getting-started.min.js +2285 -1419
- package/components/form/demo/index.min.js +2285 -1419
- package/components/form/demo/registerDemoDeps.min.js +1922 -1382
- 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/api.md +5 -5
- package/components/input/demo/customize.html +1 -2
- package/components/input/demo/customize.md +62 -61
- package/components/input/demo/customize.min.js +177 -241
- package/components/input/demo/getting-started.min.js +177 -241
- package/components/input/demo/index.min.js +177 -241
- package/components/input/dist/base-input.d.ts +34 -93
- package/components/input/dist/index.js +190 -242
- package/components/input/dist/registered.js +177 -241
- package/components/radio/demo/customize.min.js +8 -6
- package/components/radio/demo/getting-started.min.js +8 -6
- package/components/radio/demo/index.min.js +8 -6
- package/components/radio/dist/index.js +8 -6
- package/components/radio/dist/registered.js +8 -6
- package/components/select/demo/customize.html +1 -2
- package/components/select/demo/customize.md +86 -0
- package/components/select/demo/customize.min.js +202 -68
- package/components/select/demo/getting-started.min.js +204 -115
- package/components/select/demo/index.min.js +202 -68
- package/components/select/demo/keyboard-behavior.md +18 -4
- package/components/select/dist/auro-select.d.ts +20 -8
- package/components/select/dist/index.js +202 -68
- package/components/select/dist/registered.js +202 -68
- package/custom-elements.json +1035 -604
- package/package.json +6 -2
- package/components/checkbox/demo/customize.js +0 -22
- package/components/checkbox/demo/demo-support.js +0 -1
- package/components/checkbox/demo/getting-started.js +0 -22
- package/components/checkbox/demo/index.js +0 -8
- package/components/checkbox/demo/styles.scss +0 -1
- package/components/combobox/demo/customize.js +0 -24
- package/components/combobox/demo/demo-support.js +0 -1
- package/components/combobox/demo/getting-started.js +0 -21
- package/components/combobox/demo/index.js +0 -23
- package/components/combobox/demo/styles.scss +0 -1
- package/components/counter/demo/customize.js +0 -21
- package/components/counter/demo/demo-support.js +0 -1
- package/components/counter/demo/index.js +0 -21
- package/components/counter/demo/styles.scss +0 -1
- package/components/datepicker/demo/customize.js +0 -19
- package/components/datepicker/demo/demo-support.js +0 -1
- package/components/datepicker/demo/index.js +0 -23
- package/components/datepicker/demo/styles.scss +0 -1
- package/components/dropdown/demo/customize.js +0 -9
- package/components/dropdown/demo/demo-support.js +0 -1
- package/components/dropdown/demo/getting-started.js +0 -9
- package/components/dropdown/demo/index.js +0 -16
- package/components/dropdown/demo/styles.scss +0 -1
- package/components/form/demo/customize.js +0 -9
- package/components/form/demo/demo-support.js +0 -1
- package/components/form/demo/getting-started.js +0 -9
- package/components/form/demo/index.js +0 -5
- package/components/form/demo/registerDemoDeps.js +0 -23
- package/components/form/demo/styles.scss +0 -1
- package/components/input/demo/customize.js +0 -25
- package/components/input/demo/demo-support.js +0 -1
- package/components/input/demo/getting-started.js +0 -8
- package/components/input/demo/index.js +0 -8
- package/components/input/demo/styles.css +0 -974
- package/components/input/demo/styles.scss +0 -1
- package/components/menu/demo/demo-support.js +0 -1
- package/components/menu/demo/index.js +0 -25
- package/components/menu/demo/styles.scss +0 -1
- package/components/radio/demo/customize.js +0 -22
- package/components/radio/demo/demo-support.js +0 -1
- package/components/radio/demo/getting-started.js +0 -24
- package/components/radio/demo/index.js +0 -8
- package/components/radio/demo/styles.scss +0 -1
- package/components/select/demo/customize.js +0 -11
- package/components/select/demo/demo-support.js +0 -1
- package/components/select/demo/getting-started.js +0 -26
- package/components/select/demo/index.js +0 -11
- package/components/select/demo/styles.scss +0 -1
- /package/components/datepicker/dist/{src/auro-calendar-month.d.ts → auro-calendar-month.d.ts} +0 -0
- /package/components/datepicker/dist/{src/buttonVersion.d.ts → buttonVersion.d.ts} +0 -0
- /package/components/datepicker/dist/{src/datepickerKeyboardStrategy.d.ts → datepickerKeyboardStrategy.d.ts} +0 -0
- /package/components/datepicker/dist/{src/iconVersion.d.ts → iconVersion.d.ts} +0 -0
- /package/components/datepicker/dist/{src/index.d.ts → index.d.ts} +0 -0
- /package/components/datepicker/dist/{src/popoverVersion.d.ts → popoverVersion.d.ts} +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/classic/color-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/classic/style-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/color-calendar-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/color-cell-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/color-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/color-month-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/shapeSize-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/snowflake/color-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/snowflake/style-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/style-auro-calendar-cell-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/style-auro-calendar-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/style-auro-calendar-month-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/style-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/tokens-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/utilities.d.ts → utilities.d.ts} +0 -0
- /package/components/datepicker/dist/{src/utilitiesCalendar.d.ts → utilitiesCalendar.d.ts} +0 -0
- /package/components/datepicker/dist/{src/utilitiesCalendarRender.d.ts → utilitiesCalendarRender.d.ts} +0 -0
- /package/components/datepicker/dist/{src/vendor → vendor}/wc-range-datepicker/day.d.ts +0 -0
- /package/components/datepicker/dist/{src/vendor → vendor}/wc-range-datepicker/range-datepicker-calendar.d.ts +0 -0
- /package/components/datepicker/dist/{src/vendor → vendor}/wc-range-datepicker/range-datepicker-cell.d.ts +0 -0
- /package/components/datepicker/dist/{src/vendor → vendor}/wc-range-datepicker/range-datepicker.d.ts +0 -0
|
@@ -448,15 +448,17 @@ let AuroFormValidation$1 = class AuroFormValidation {
|
|
|
448
448
|
);
|
|
449
449
|
}
|
|
450
450
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
451
|
+
const isCombobox = this.runtimeUtils.elementMatch(elem, 'auro-combobox');
|
|
452
|
+
|
|
453
|
+
// If there is a second input in the elem and that value is undefined or an empty string set hasValue to false.
|
|
454
|
+
// Skip for combobox: its second auro-input is the fullscreen-bib mirror of the same value, not an independent
|
|
455
|
+
// field (datepicker is the intended consumer — start/end are independently required).
|
|
456
|
+
if (this.auroInputElements?.length === 2 && !isCombobox) {
|
|
457
|
+
if (!this.auroInputElements[1].value || this.auroInputElements[1].value.length === 0) {
|
|
454
458
|
hasValue = false;
|
|
455
459
|
}
|
|
456
460
|
}
|
|
457
461
|
|
|
458
|
-
const isCombobox = this.runtimeUtils.elementMatch(elem, 'auro-combobox');
|
|
459
|
-
|
|
460
462
|
if (isCombobox) {
|
|
461
463
|
|
|
462
464
|
if (!elem.persistInput || elem.behavior === "filter") {
|
|
@@ -767,6 +769,8 @@ function navigateArrow(component, direction, options = {}) {
|
|
|
767
769
|
}
|
|
768
770
|
}
|
|
769
771
|
|
|
772
|
+
/* eslint-disable no-underscore-dangle */
|
|
773
|
+
|
|
770
774
|
/**
|
|
771
775
|
* Returns the clear button element from the active input's shadow
|
|
772
776
|
* DOM, if available.
|
|
@@ -802,11 +806,9 @@ function isClearBtnFocused(ctx, clearBtn = getClearBtn(ctx)) {
|
|
|
802
806
|
* @param {Object} menu - The menu component.
|
|
803
807
|
*/
|
|
804
808
|
function reconcileMenuIndex(menu) {
|
|
805
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
806
809
|
if (menu._index < 0 && menu.optionActive && menu.items) {
|
|
807
810
|
const idx = menu.items.indexOf(menu.optionActive);
|
|
808
811
|
if (idx >= 0) {
|
|
809
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
810
812
|
menu._index = idx;
|
|
811
813
|
}
|
|
812
814
|
}
|
|
@@ -825,11 +827,7 @@ const comboboxKeyboardStrategy = {
|
|
|
825
827
|
|
|
826
828
|
// navigate if bib is open otherwise open it
|
|
827
829
|
if (component.dropdown.isPopoverVisible) {
|
|
828
|
-
|
|
829
|
-
component.activateLastEnabledAvailableOption();
|
|
830
|
-
} else {
|
|
831
|
-
navigateArrow(component, 'down');
|
|
832
|
-
}
|
|
830
|
+
navigateArrow(component, 'down');
|
|
833
831
|
} else {
|
|
834
832
|
component.showBib();
|
|
835
833
|
}
|
|
@@ -848,11 +846,7 @@ const comboboxKeyboardStrategy = {
|
|
|
848
846
|
|
|
849
847
|
// navigate if bib is open otherwise open it
|
|
850
848
|
if (component.dropdown.isPopoverVisible) {
|
|
851
|
-
|
|
852
|
-
component.activateFirstEnabledAvailableOption();
|
|
853
|
-
} else {
|
|
854
|
-
navigateArrow(component, 'up');
|
|
855
|
-
}
|
|
849
|
+
navigateArrow(component, 'up');
|
|
856
850
|
} else {
|
|
857
851
|
component.showBib();
|
|
858
852
|
}
|
|
@@ -868,13 +862,18 @@ const comboboxKeyboardStrategy = {
|
|
|
868
862
|
},
|
|
869
863
|
|
|
870
864
|
Enter(component, evt, ctx) {
|
|
865
|
+
// Forms should not submit on Enter from a combobox, regardless of which
|
|
866
|
+
// child element (input, clear button, menu) is focused.
|
|
867
|
+
evt.stopPropagation();
|
|
868
|
+
|
|
871
869
|
if (isClearBtnFocused(ctx)) {
|
|
872
|
-
//
|
|
873
|
-
//
|
|
874
|
-
//
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
870
|
+
// Let the browser dispatch Enter to the focused clear button so its
|
|
871
|
+
// built-in activation fires and clears the selection. Do NOT call
|
|
872
|
+
// preventDefault — that would block the activation.
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
if (ctx.isExpanded && component.menu.optionActive) {
|
|
878
877
|
reconcileMenuIndex(component.menu);
|
|
879
878
|
component.menu.makeSelection();
|
|
880
879
|
|
|
@@ -883,14 +882,8 @@ const comboboxKeyboardStrategy = {
|
|
|
883
882
|
}
|
|
884
883
|
|
|
885
884
|
evt.preventDefault();
|
|
886
|
-
evt.stopPropagation();
|
|
887
885
|
} else {
|
|
888
|
-
// Prevent the keypress from bubbling to parent containers (e.g., forms)
|
|
889
|
-
// which could interpret Enter as a submit or trigger other unintended behavior.
|
|
890
|
-
// This is safe because showBib() opens the dialog programmatically,
|
|
891
|
-
// not via event propagation.
|
|
892
886
|
evt.preventDefault();
|
|
893
|
-
evt.stopPropagation();
|
|
894
887
|
component.showBib();
|
|
895
888
|
}
|
|
896
889
|
},
|
|
@@ -935,7 +928,7 @@ const comboboxKeyboardStrategy = {
|
|
|
935
928
|
component.setClearBtnFocus();
|
|
936
929
|
}
|
|
937
930
|
}
|
|
938
|
-
}
|
|
931
|
+
}
|
|
939
932
|
};
|
|
940
933
|
|
|
941
934
|
// Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
|
|
@@ -4806,7 +4799,7 @@ let AuroHelpText$2 = class AuroHelpText extends LitElement {
|
|
|
4806
4799
|
}
|
|
4807
4800
|
};
|
|
4808
4801
|
|
|
4809
|
-
var formkitVersion$2 = '
|
|
4802
|
+
var formkitVersion$2 = '202607010100';
|
|
4810
4803
|
|
|
4811
4804
|
let AuroElement$2 = class AuroElement extends LitElement {
|
|
4812
4805
|
static get properties() {
|
|
@@ -5757,6 +5750,14 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
5757
5750
|
};
|
|
5758
5751
|
this.addEventListener('keydown', this._bibTabHandler);
|
|
5759
5752
|
|
|
5753
|
+
// Suppress AuroFloatingUI's auto-hide-on-focus-loss while the
|
|
5754
|
+
// desktopModal trap owns focus management. Without this, the very
|
|
5755
|
+
// first focus move into the bib (from the RAF below) triggers
|
|
5756
|
+
// handleFocusLoss → hideBib, tearing down the trap before the
|
|
5757
|
+
// user can press Tab.
|
|
5758
|
+
this._priorNoHideOnFocusLoss = this.noHideOnThisFocusLoss;
|
|
5759
|
+
this.noHideOnThisFocusLoss = true;
|
|
5760
|
+
|
|
5760
5761
|
// Move initial focus into the bib content, matching FocusTrap behavior
|
|
5761
5762
|
requestAnimationFrame(() => {
|
|
5762
5763
|
const focusables = getFocusableElements(this.bibContent);
|
|
@@ -6070,6 +6071,7 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
6070
6071
|
role="${ifDefined(this.triggerContentFocusable ? undefined : this.a11yRole)}"
|
|
6071
6072
|
aria-expanded="${ifDefined(this.a11yRole === 'button' || this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
|
|
6072
6073
|
aria-controls="${ifDefined(this.a11yRole === 'button' || this.triggerContentFocusable ? undefined : this.dropdownId)}"
|
|
6074
|
+
aria-haspopup="${ifDefined(this.a11yRole === 'combobox' && !this.triggerContentFocusable ? 'listbox' : undefined)}"
|
|
6073
6075
|
aria-labelledby="${ifDefined(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
|
|
6074
6076
|
aria-disabled="${ifDefined(this.disabled ? 'true' : undefined)}"
|
|
6075
6077
|
@focusin="${this.handleFocusin}"
|
|
@@ -10572,15 +10574,17 @@ class AuroFormValidation {
|
|
|
10572
10574
|
);
|
|
10573
10575
|
}
|
|
10574
10576
|
|
|
10575
|
-
|
|
10576
|
-
|
|
10577
|
-
|
|
10577
|
+
const isCombobox = this.runtimeUtils.elementMatch(elem, 'auro-combobox');
|
|
10578
|
+
|
|
10579
|
+
// If there is a second input in the elem and that value is undefined or an empty string set hasValue to false.
|
|
10580
|
+
// Skip for combobox: its second auro-input is the fullscreen-bib mirror of the same value, not an independent
|
|
10581
|
+
// field (datepicker is the intended consumer — start/end are independently required).
|
|
10582
|
+
if (this.auroInputElements?.length === 2 && !isCombobox) {
|
|
10583
|
+
if (!this.auroInputElements[1].value || this.auroInputElements[1].value.length === 0) {
|
|
10578
10584
|
hasValue = false;
|
|
10579
10585
|
}
|
|
10580
10586
|
}
|
|
10581
10587
|
|
|
10582
|
-
const isCombobox = this.runtimeUtils.elementMatch(elem, 'auro-combobox');
|
|
10583
|
-
|
|
10584
10588
|
if (isCombobox) {
|
|
10585
10589
|
|
|
10586
10590
|
if (!elem.persistInput || elem.behavior === "filter") {
|
|
@@ -16516,10 +16520,18 @@ class AuroInputUtilities {
|
|
|
16516
16520
|
* @returns {string | undefined}
|
|
16517
16521
|
*/
|
|
16518
16522
|
toFormattedValue(valueObject, format) {
|
|
16523
|
+
// Exposed publicly via `AuroInputUtil.toFormattedValue`, so a missing
|
|
16524
|
+
// `format` argument has to fail gracefully rather than throw on
|
|
16525
|
+
// `format.toLowerCase()`. Treat any falsy value (undefined, null, '')
|
|
16526
|
+
// as "no format → no display value".
|
|
16527
|
+
if (!format) {
|
|
16528
|
+
return undefined;
|
|
16529
|
+
}
|
|
16519
16530
|
const normalizedFormat = format.toLowerCase();
|
|
16520
16531
|
const maskOptions = this.getMaskOptions('date', normalizedFormat);
|
|
16521
16532
|
|
|
16522
16533
|
if (!(valueObject instanceof Date) || Number.isNaN(valueObject.getTime()) || !maskOptions || typeof maskOptions.format !== 'function') {
|
|
16534
|
+
console.debug('Invalid date object or mask options for formatting', { valueObject, maskOptions }); // eslint-disable-line no-console
|
|
16523
16535
|
return undefined;
|
|
16524
16536
|
}
|
|
16525
16537
|
|
|
@@ -16666,79 +16678,19 @@ class BaseInput extends AuroElement$1 {
|
|
|
16666
16678
|
constructor() {
|
|
16667
16679
|
super();
|
|
16668
16680
|
|
|
16669
|
-
|
|
16670
|
-
|
|
16671
|
-
|
|
16672
|
-
|
|
16673
|
-
|
|
16674
|
-
|
|
16675
|
-
|
|
16676
|
-
|
|
16677
|
-
|
|
16678
|
-
|
|
16679
|
-
this.required = false;
|
|
16680
|
-
this.onDark = false;
|
|
16681
|
-
this.setCustomValidityForType = undefined;
|
|
16682
|
-
this.size = 'lg';
|
|
16683
|
-
this.shape = 'classic';
|
|
16684
|
-
this.value = undefined;
|
|
16685
|
-
this._valueObject = undefined;
|
|
16686
|
-
|
|
16687
|
-
this._initializePrivateDefaults();
|
|
16688
|
-
}
|
|
16689
|
-
|
|
16690
|
-
/**
|
|
16691
|
-
* Internal Defaults.
|
|
16692
|
-
* @private
|
|
16693
|
-
* @returns {void}
|
|
16694
|
-
*/
|
|
16695
|
-
_initializePrivateDefaults() {
|
|
16681
|
+
// Single-source initialization. Alphabetized so duplicate or stale
|
|
16682
|
+
// defaults are immediately obvious on a diff. Every field is assigned
|
|
16683
|
+
// exactly once here (previously the constructor + the old
|
|
16684
|
+
// `_initializePrivateDefaults` overlapped — both wrote ~14 of the same
|
|
16685
|
+
// fields and double-allocated `util` and `validation`, discarding the
|
|
16686
|
+
// first instance). `validation` is now allocated exactly once; `util`
|
|
16687
|
+
// is seeded here with an en-US default and then rebuilt in
|
|
16688
|
+
// `connectedCallback` once the consumer-resolved locale is available,
|
|
16689
|
+
// so a parent (datepicker/combobox) calling `validate()` synchronously
|
|
16690
|
+
// during its own update cycle sees a populated util instance.
|
|
16696
16691
|
this.activeLabel = false;
|
|
16697
|
-
this.appearance = "default";
|
|
16698
|
-
this.icon = false;
|
|
16699
|
-
this.disabled = false;
|
|
16700
|
-
this.dvInputOnly = false;
|
|
16701
|
-
this.hideLabelVisually = false;
|
|
16702
|
-
this.max = undefined;
|
|
16703
|
-
this.maxLength = undefined;
|
|
16704
|
-
this.min = undefined;
|
|
16705
|
-
this.minLength = undefined;
|
|
16706
|
-
this.noValidate = false;
|
|
16707
|
-
this.onDark = false;
|
|
16708
|
-
this.required = false;
|
|
16709
|
-
this.setCustomValidityForType = undefined;
|
|
16710
|
-
|
|
16711
|
-
// Used for storing raw values returned from input mask.
|
|
16712
|
-
this._rawMaskValue = undefined;
|
|
16713
|
-
|
|
16714
|
-
/**
|
|
16715
|
-
* @private
|
|
16716
|
-
*/
|
|
16717
|
-
this.layout = 'classic';
|
|
16718
|
-
|
|
16719
|
-
/**
|
|
16720
|
-
* @private
|
|
16721
|
-
*/
|
|
16722
|
-
this.shape = 'classic';
|
|
16723
|
-
|
|
16724
|
-
/**
|
|
16725
|
-
* @private
|
|
16726
|
-
*/
|
|
16727
|
-
this.size = 'lg';
|
|
16728
|
-
|
|
16729
|
-
this.touched = false;
|
|
16730
|
-
this.util = new AuroInputUtilities({
|
|
16731
|
-
locale: "en-US",
|
|
16732
|
-
format: this.format
|
|
16733
|
-
});
|
|
16734
|
-
this.validation = new AuroFormValidation();
|
|
16735
|
-
this.inputIconName = undefined;
|
|
16736
|
-
this.showPassword = false;
|
|
16737
|
-
this.validationCCLength = undefined;
|
|
16738
|
-
this.hasValue = false;
|
|
16739
|
-
this.label = 'Input label is undefined';
|
|
16740
|
-
|
|
16741
16692
|
|
|
16693
|
+
/** @private */
|
|
16742
16694
|
this.allowedInputTypes = [
|
|
16743
16695
|
"text",
|
|
16744
16696
|
"number",
|
|
@@ -16747,7 +16699,9 @@ class BaseInput extends AuroElement$1 {
|
|
|
16747
16699
|
"credit-card",
|
|
16748
16700
|
"tel"
|
|
16749
16701
|
];
|
|
16750
|
-
this.
|
|
16702
|
+
this.appearance = "default";
|
|
16703
|
+
|
|
16704
|
+
/** @private */
|
|
16751
16705
|
this.dateFormatMap = {
|
|
16752
16706
|
'mm/dd/yyyy': 'dateMMDDYYYY',
|
|
16753
16707
|
'dd/mm/yyyy': 'dateDDMMYYYY',
|
|
@@ -16764,27 +16718,62 @@ class BaseInput extends AuroElement$1 {
|
|
|
16764
16718
|
'dd/mm': 'dateDDMM',
|
|
16765
16719
|
'mm/dd': 'dateMMDD'
|
|
16766
16720
|
};
|
|
16721
|
+
this.disabled = false;
|
|
16722
|
+
|
|
16723
|
+
/** @private */
|
|
16767
16724
|
this.domHandler = new DomHandler();
|
|
16768
16725
|
this.dvInputOnly = false;
|
|
16769
16726
|
this.hasValue = false;
|
|
16727
|
+
this.hideLabelVisually = false;
|
|
16728
|
+
this.icon = false;
|
|
16729
|
+
|
|
16730
|
+
/** @private */
|
|
16770
16731
|
this.inputIconName = undefined;
|
|
16732
|
+
|
|
16733
|
+
/** @private */
|
|
16771
16734
|
this.label = 'Input label is undefined';
|
|
16735
|
+
this.layout = 'classic';
|
|
16736
|
+
this.locale = 'en-US';
|
|
16737
|
+
this.max = undefined;
|
|
16738
|
+
this.maxLength = undefined;
|
|
16739
|
+
this.min = undefined;
|
|
16740
|
+
this.minLength = undefined;
|
|
16772
16741
|
this.noValidate = false;
|
|
16773
|
-
this.
|
|
16742
|
+
this.onDark = false;
|
|
16743
|
+
// Raw values returned from the input mask before model normalization.
|
|
16744
|
+
this._rawMaskValue = undefined;
|
|
16745
|
+
this.required = false;
|
|
16746
|
+
this.setCustomValidityForType = undefined;
|
|
16747
|
+
// Credit Card is intentionally excluded — its mask manages the cursor
|
|
16748
|
+
// itself, and listing it here caused cursor placement issues in Safari.
|
|
16749
|
+
/** @private */
|
|
16774
16750
|
this.setSelectionInputTypes = [
|
|
16775
16751
|
"text",
|
|
16776
16752
|
"password",
|
|
16777
16753
|
"email"
|
|
16778
|
-
];
|
|
16754
|
+
];
|
|
16755
|
+
this.shape = 'classic';
|
|
16756
|
+
|
|
16757
|
+
/** @private */
|
|
16779
16758
|
this.showPassword = false;
|
|
16759
|
+
this.size = 'lg';
|
|
16780
16760
|
this.touched = false;
|
|
16761
|
+
|
|
16762
|
+
/** @private */
|
|
16781
16763
|
this.uniqueId = new UniqueId().create();
|
|
16764
|
+
|
|
16765
|
+
/** @private */
|
|
16782
16766
|
this.util = new AuroInputUtilities({
|
|
16783
16767
|
locale: this.locale,
|
|
16784
16768
|
format: this.format
|
|
16785
16769
|
});
|
|
16770
|
+
|
|
16771
|
+
/** @private */
|
|
16786
16772
|
this.validation = new AuroFormValidation();
|
|
16773
|
+
|
|
16774
|
+
/** @private */
|
|
16787
16775
|
this.validationCCLength = undefined;
|
|
16776
|
+
this.value = undefined;
|
|
16788
16777
|
}
|
|
16789
16778
|
|
|
16790
16779
|
// function to define props used within the scope of this component
|
|
@@ -17222,7 +17211,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17222
17211
|
* @returns {Date|undefined}
|
|
17223
17212
|
*/
|
|
17224
17213
|
get valueObject() {
|
|
17225
|
-
return this.
|
|
17214
|
+
return this.value && dateFormatter.isValidDate(this.value) ? dateFormatter.stringToDateInstance(this.value) : undefined;
|
|
17226
17215
|
}
|
|
17227
17216
|
|
|
17228
17217
|
/**
|
|
@@ -17230,7 +17219,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17230
17219
|
* @returns {Date|undefined}
|
|
17231
17220
|
*/
|
|
17232
17221
|
get minObject() {
|
|
17233
|
-
return this.
|
|
17222
|
+
return this.min && dateFormatter.isValidDate(this.min) ? dateFormatter.stringToDateInstance(this.min) : undefined;
|
|
17234
17223
|
}
|
|
17235
17224
|
|
|
17236
17225
|
/**
|
|
@@ -17238,50 +17227,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17238
17227
|
* @returns {Date|undefined}
|
|
17239
17228
|
*/
|
|
17240
17229
|
get maxObject() {
|
|
17241
|
-
return this.
|
|
17242
|
-
}
|
|
17243
|
-
|
|
17244
|
-
/**
|
|
17245
|
-
* Parses a date string into a Date object when the corresponding `_*Object`
|
|
17246
|
-
* field hasn't been synced yet by `updated()`. Returns undefined when the
|
|
17247
|
-
* input type/format isn't a full date or the string is not a valid date.
|
|
17248
|
-
*
|
|
17249
|
-
* Why this exists: a parent (datepicker) can call `inputN.validate()` from
|
|
17250
|
-
* inside its own `updated()` before this input's `updated()` has run
|
|
17251
|
-
* `syncDateValues()` — so `_valueObject`/`_maxObject` are still `undefined`
|
|
17252
|
-
* and range checks would otherwise silently no-op (flipping the result to
|
|
17253
|
-
* `valid` or `patternMismatch`).
|
|
17254
|
-
* @private
|
|
17255
|
-
* @param {string|undefined} dateStr - ISO date string from `value`/`min`/`max`.
|
|
17256
|
-
* @returns {Date|undefined}
|
|
17257
|
-
*/
|
|
17258
|
-
_computeDateObjectFallback(dateStr) {
|
|
17259
|
-
if (!dateStr || !this.util || !this.util.isFullDateFormat(this.type, this.format)) {
|
|
17260
|
-
return undefined;
|
|
17261
|
-
}
|
|
17262
|
-
if (!dateFormatter.isValidDate(dateStr)) {
|
|
17263
|
-
return undefined;
|
|
17264
|
-
}
|
|
17265
|
-
return dateFormatter.stringToDateInstance(dateStr);
|
|
17266
|
-
}
|
|
17267
|
-
|
|
17268
|
-
/**
|
|
17269
|
-
* Internal setter for readonly date object properties.
|
|
17270
|
-
* @private
|
|
17271
|
-
* @param {'valueObject'|'minObject'|'maxObject'} propertyName - Public object property name.
|
|
17272
|
-
* @param {Date|undefined} propertyValue - Value to assign.
|
|
17273
|
-
* @returns {void}
|
|
17274
|
-
*/
|
|
17275
|
-
setDateObjectProperty(propertyName, propertyValue) {
|
|
17276
|
-
const internalPropertyName = `_${propertyName}`;
|
|
17277
|
-
const previousValue = this[internalPropertyName];
|
|
17278
|
-
|
|
17279
|
-
if (previousValue === propertyValue) {
|
|
17280
|
-
return;
|
|
17281
|
-
}
|
|
17282
|
-
|
|
17283
|
-
this[internalPropertyName] = propertyValue;
|
|
17284
|
-
this.requestUpdate(propertyName, previousValue);
|
|
17230
|
+
return this.max && dateFormatter.isValidDate(this.max) ? dateFormatter.stringToDateInstance(this.max) : undefined;
|
|
17285
17231
|
}
|
|
17286
17232
|
|
|
17287
17233
|
connectedCallback() {
|
|
@@ -17310,7 +17256,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17310
17256
|
format: this.format
|
|
17311
17257
|
});
|
|
17312
17258
|
this.configureDataForType();
|
|
17313
|
-
this.syncDateValues();
|
|
17314
17259
|
}
|
|
17315
17260
|
|
|
17316
17261
|
disconnectedCallback() {
|
|
@@ -17330,12 +17275,17 @@ class BaseInput extends AuroElement$1 {
|
|
|
17330
17275
|
this.wrapperElement.addEventListener('click', this.handleClick);
|
|
17331
17276
|
}
|
|
17332
17277
|
|
|
17333
|
-
// add attribute for query selectors when auro-input is registered under a custom name
|
|
17334
|
-
if (this.tagName.toLowerCase() !== 'auro-input' && !this.hasAttribute('auro-input')) {
|
|
17335
|
-
this.setAttribute('auro-input', '');
|
|
17336
|
-
}
|
|
17337
17278
|
this.inputId = this.id ? `${this.id}-input` : window.crypto.randomUUID();
|
|
17338
17279
|
|
|
17280
|
+
// Normalize the format token to lowercase so case-mixed values supplied
|
|
17281
|
+
// via attribute (e.g. `format="MM/DD/YYYY"`) hit the `dateFormatMap`
|
|
17282
|
+
// lookup inside `setCustomHelpTextMessage`. Without this, an uppercase
|
|
17283
|
+
// format silently misses the map and leaves `setCustomValidityForType`
|
|
17284
|
+
// unset.
|
|
17285
|
+
if (this.format) {
|
|
17286
|
+
this.format = this.format.toLowerCase();
|
|
17287
|
+
}
|
|
17288
|
+
|
|
17339
17289
|
// use validity message override if declared when initializing the component
|
|
17340
17290
|
if (this.hasAttribute('setCustomValidity')) {
|
|
17341
17291
|
this.ValidityMessageOverride = this.setCustomValidity;
|
|
@@ -17344,7 +17294,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17344
17294
|
this.setCustomHelpTextMessage();
|
|
17345
17295
|
this.configureAutoFormatting();
|
|
17346
17296
|
this.configureDataForType();
|
|
17347
|
-
this.syncDateValues();
|
|
17348
17297
|
}
|
|
17349
17298
|
|
|
17350
17299
|
/**
|
|
@@ -17420,6 +17369,13 @@ class BaseInput extends AuroElement$1 {
|
|
|
17420
17369
|
|
|
17421
17370
|
if (typeToI18n.includes(this.type)) {
|
|
17422
17371
|
this.setCustomValidityForType = i18n(this.lang, this.type);
|
|
17372
|
+
// COVERAGE: this `else if` branch is unreachable in WTR. connectedCallback
|
|
17373
|
+
// (L682) calls configureDataForType, which at L1266-1268 assigns
|
|
17374
|
+
// `this.format = this.util.getDateMaskFromLocale().toLowerCase()` for any
|
|
17375
|
+
// type=date input whose `format` attribute is unset. That runs before
|
|
17376
|
+
// firstUpdated invokes setCustomHelpTextMessage, so `!this.format` is
|
|
17377
|
+
// always false here. Retained as a defensive fallback; the whole function
|
|
17378
|
+
// is @deprecated per AB#1557296 and slated for removal.
|
|
17423
17379
|
} else if (!this.format && this.type === 'date') {
|
|
17424
17380
|
this.setCustomValidityForType = i18n(this.lang, 'dateMMDDYYYY');
|
|
17425
17381
|
} else if (this.dateFormatMap[this.format]) {
|
|
@@ -17481,8 +17437,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17481
17437
|
this.configureDataForType();
|
|
17482
17438
|
}
|
|
17483
17439
|
|
|
17484
|
-
this.syncDateValues(changedProperties);
|
|
17485
|
-
|
|
17486
17440
|
if (changedProperties.has('value')) {
|
|
17487
17441
|
if (this.value && this.value.length > 0) {
|
|
17488
17442
|
this.hasValue = true;
|
|
@@ -17504,14 +17458,14 @@ class BaseInput extends AuroElement$1 {
|
|
|
17504
17458
|
|
|
17505
17459
|
if (formattedValue !== this.inputElement.value) {
|
|
17506
17460
|
this.skipNextProgrammaticInputEvent = true;
|
|
17507
|
-
if (this.maskInstance && this.type
|
|
17461
|
+
if (this.maskInstance && this.type !== 'date') {
|
|
17508
17462
|
// Route through the mask so its _value and el.value stay in lock-step
|
|
17509
17463
|
// (set value calls updateControl which writes el.value = displayValue).
|
|
17510
17464
|
// Writing el.value directly leaves the mask thinking displayValue is
|
|
17511
|
-
// stale; _saveSelection on the next focus/click then warns.
|
|
17512
|
-
//
|
|
17513
|
-
//
|
|
17514
|
-
//
|
|
17465
|
+
// stale; _saveSelection on the next focus/click then warns. Date is
|
|
17466
|
+
// excluded because its formattedValue can be raw ISO when the calendar
|
|
17467
|
+
// is invalid, and re-masking through mm/dd/yyyy would truncate it and
|
|
17468
|
+
// flip validity from patternMismatch to tooShort.
|
|
17515
17469
|
this.maskInstance.value = formattedValue || '';
|
|
17516
17470
|
} else if (formattedValue) {
|
|
17517
17471
|
this.inputElement.value = formattedValue;
|
|
@@ -17553,120 +17507,65 @@ class BaseInput extends AuroElement$1 {
|
|
|
17553
17507
|
}));
|
|
17554
17508
|
}
|
|
17555
17509
|
|
|
17556
|
-
|
|
17557
|
-
/**
|
|
17558
|
-
* Synchronizes the ISO string values and Date object representations for date-related properties.
|
|
17559
|
-
* This keeps the model and display values aligned when either side changes.
|
|
17560
|
-
*
|
|
17561
|
-
* When a full date format is in use, this method updates `value`, `min`, and `max` from their corresponding
|
|
17562
|
-
* Date objects or vice versa, based on which properties have changed. It only runs when the current configuration
|
|
17563
|
-
* represents a full year/month/day date format.
|
|
17564
|
-
*
|
|
17565
|
-
* @param {Map<string, unknown>|undefined} [changedProperties=undefined] - Optional map of changed properties used to limit which values are synchronized.
|
|
17566
|
-
* @returns {void}
|
|
17567
|
-
* @private
|
|
17568
|
-
*/
|
|
17569
|
-
syncDateValues(changedProperties = undefined) {
|
|
17570
|
-
if (!this.util.isFullDateFormat(this.type, this.format)) {
|
|
17571
|
-
return;
|
|
17572
|
-
}
|
|
17573
|
-
|
|
17574
|
-
this.syncSingleDateValue(changedProperties, 'valueObject', 'value');
|
|
17575
|
-
this.syncSingleDateValue(changedProperties, 'minObject', 'min');
|
|
17576
|
-
this.syncSingleDateValue(changedProperties, 'maxObject', 'max');
|
|
17577
|
-
}
|
|
17578
|
-
|
|
17579
|
-
/**
|
|
17580
|
-
* Synchronizes one date object/string property pair.
|
|
17581
|
-
* @private
|
|
17582
|
-
* @param {Map<string, unknown>|undefined} changedProperties - Map of changed properties from Lit.
|
|
17583
|
-
* @param {string} objectProperty - Date object property name.
|
|
17584
|
-
* @param {string} valueProperty - ISO string property name.
|
|
17585
|
-
* @returns {void}
|
|
17586
|
-
*/
|
|
17587
|
-
syncSingleDateValue(changedProperties, objectProperty, valueProperty) {
|
|
17588
|
-
const objectPropertyChanged = !changedProperties || changedProperties.has(objectProperty);
|
|
17589
|
-
|
|
17590
|
-
// objectProperty wins over valueProperty when both changed
|
|
17591
|
-
if (objectPropertyChanged && this[objectProperty]) {
|
|
17592
|
-
this[valueProperty] = dateFormatter.toISOFormatString(this[objectProperty]);
|
|
17593
|
-
return;
|
|
17594
|
-
}
|
|
17595
|
-
|
|
17596
|
-
const valuePropertyChanged = !changedProperties || changedProperties.has(valueProperty);
|
|
17597
|
-
if (!valuePropertyChanged) {
|
|
17598
|
-
return;
|
|
17599
|
-
}
|
|
17600
|
-
|
|
17601
|
-
// 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)
|
|
17602
|
-
if (
|
|
17603
|
-
changedProperties &&
|
|
17604
|
-
valueProperty === 'value' &&
|
|
17605
|
-
changedProperties.get('value') === undefined &&
|
|
17606
|
-
this[objectProperty] instanceof Date &&
|
|
17607
|
-
this[valueProperty] === dateFormatter.toISOFormatString(this[objectProperty])
|
|
17608
|
-
) {
|
|
17609
|
-
return;
|
|
17610
|
-
}
|
|
17611
|
-
|
|
17612
|
-
if (dateFormatter.isValidDate(this[valueProperty])) {
|
|
17613
|
-
this.setDateObjectProperty(objectProperty, dateFormatter.stringToDateInstance(this[valueProperty]));
|
|
17614
|
-
} else {
|
|
17615
|
-
this.setDateObjectProperty(objectProperty, undefined);
|
|
17616
|
-
}
|
|
17617
|
-
}
|
|
17618
|
-
|
|
17619
17510
|
/**
|
|
17620
17511
|
* Sets up IMasks and logic based on auto-formatting requirements.
|
|
17621
17512
|
* @private
|
|
17622
17513
|
* @returns {void}
|
|
17623
17514
|
*/
|
|
17624
17515
|
configureAutoFormatting() {
|
|
17625
|
-
//
|
|
17626
|
-
//
|
|
17627
|
-
//
|
|
17628
|
-
//
|
|
17516
|
+
// _configuringMask gates two things: external re-entry into this method
|
|
17517
|
+
// while setup is mid-flight (from property changes that call back here),
|
|
17518
|
+
// and the accept/complete listeners below — both need to ignore the mask
|
|
17519
|
+
// events fired by our own value-restore step.
|
|
17629
17520
|
if (this._configuringMask) return;
|
|
17630
17521
|
this._configuringMask = true;
|
|
17631
17522
|
try {
|
|
17523
|
+
// Destroy any prior mask so IMask can attach fresh under the new format.
|
|
17524
|
+
// Null the reference too — if the new maskOptions.mask is falsy (e.g.
|
|
17525
|
+
// type switched from credit-card to text) the IMask() reassignment
|
|
17526
|
+
// below is skipped, and downstream writes at line ~823 would otherwise
|
|
17527
|
+
// route through the destroyed instance.
|
|
17632
17528
|
if (this.maskInstance) {
|
|
17633
17529
|
this.maskInstance.destroy();
|
|
17530
|
+
this.maskInstance = null;
|
|
17634
17531
|
}
|
|
17635
17532
|
|
|
17636
|
-
// Pass new format to util
|
|
17637
17533
|
this.util.updateFormat(this.format);
|
|
17638
17534
|
|
|
17639
17535
|
const maskOptions = this.util.getMaskOptions(this.type, this.format);
|
|
17640
17536
|
|
|
17641
17537
|
if (this.inputElement && maskOptions.mask) {
|
|
17642
|
-
|
|
17643
|
-
//
|
|
17644
|
-
//
|
|
17645
|
-
//
|
|
17646
|
-
// When the format changes (e.g. locale switch) and we have a valid ISO
|
|
17647
|
-
// model value, compute the display string for the NEW format instead of
|
|
17648
|
-
// re-using the old display string, which may be invalid in the new mask.
|
|
17538
|
+
// Capture the current display so it can be re-applied after IMask
|
|
17539
|
+
// attaches. The restore at the bottom goes through maskInstance.value
|
|
17540
|
+
// (not inputElement.value directly) so the mask's internal state and
|
|
17541
|
+
// the input's displayed text stay in lock-step.
|
|
17649
17542
|
let existingValue = this.inputElement.value;
|
|
17543
|
+
|
|
17544
|
+
// Format-change case (e.g. locale switch): existingValue is the OLD
|
|
17545
|
+
// mask's display string and may not parse under the new mask. When
|
|
17546
|
+
// we have a valid date model, rebuild the display from valueObject
|
|
17547
|
+
// (the canonical source) using the new mask's format function.
|
|
17650
17548
|
if (
|
|
17651
17549
|
this.util.isFullDateFormat(this.type, this.format) &&
|
|
17652
17550
|
this.value &&
|
|
17653
|
-
|
|
17654
|
-
this.valueObject instanceof Date &&
|
|
17655
|
-
!Number.isNaN(this.valueObject.getTime()) &&
|
|
17551
|
+
this.valueObject &&
|
|
17656
17552
|
typeof maskOptions.format === 'function'
|
|
17657
17553
|
) {
|
|
17658
17554
|
existingValue = maskOptions.format(this.valueObject);
|
|
17659
17555
|
}
|
|
17660
17556
|
|
|
17557
|
+
// Clear before IMask attaches so the constructor seeds an empty
|
|
17558
|
+
// internal value. Otherwise IMask reads the stale unmasked string
|
|
17559
|
+
// and emits a spurious 'accept' before the restore below runs.
|
|
17661
17560
|
this.skipNextProgrammaticInputEvent = true;
|
|
17662
17561
|
this.inputElement.value = '';
|
|
17663
17562
|
|
|
17664
17563
|
this.maskInstance = IMask(this.inputElement, maskOptions);
|
|
17665
17564
|
|
|
17565
|
+
// Mask fires 'accept' on every value change, including the restore
|
|
17566
|
+
// step below. Skip events fired during configureAutoFormatting so
|
|
17567
|
+
// we don't overwrite a value the parent just pushed.
|
|
17666
17568
|
this.maskInstance.on('accept', () => {
|
|
17667
|
-
// Suppress propagation during configureAutoFormatting's own value-restoration
|
|
17668
|
-
// (line below) — the mask emits 'accept' on every value-set, including ours,
|
|
17669
|
-
// and we don't want to overwrite a value the parent just pushed.
|
|
17670
17569
|
if (this._configuringMask) return;
|
|
17671
17570
|
this.value = this.util.toModelValue(this.maskInstance.value, this.format);
|
|
17672
17571
|
if (this.type === "date") {
|
|
@@ -17674,6 +17573,8 @@ class BaseInput extends AuroElement$1 {
|
|
|
17674
17573
|
}
|
|
17675
17574
|
});
|
|
17676
17575
|
|
|
17576
|
+
// Mask fires 'complete' on the restore step below for any value that
|
|
17577
|
+
// happens to be a complete match. Same setup-suppression as 'accept'.
|
|
17677
17578
|
this.maskInstance.on('complete', () => {
|
|
17678
17579
|
if (this._configuringMask) return;
|
|
17679
17580
|
this.value = this.util.toModelValue(this.maskInstance.value, this.format);
|
|
@@ -17682,7 +17583,9 @@ class BaseInput extends AuroElement$1 {
|
|
|
17682
17583
|
}
|
|
17683
17584
|
});
|
|
17684
17585
|
|
|
17685
|
-
//
|
|
17586
|
+
// Write existingValue through the mask (not the input directly) so
|
|
17587
|
+
// the mask reformats it under the new rules and keeps its internal
|
|
17588
|
+
// _value aligned with the input's displayed text.
|
|
17686
17589
|
if (existingValue) {
|
|
17687
17590
|
this.maskInstance.value = existingValue;
|
|
17688
17591
|
}
|
|
@@ -17762,6 +17665,38 @@ class BaseInput extends AuroElement$1 {
|
|
|
17762
17665
|
this.touched = true;
|
|
17763
17666
|
this.validation.validate(this);
|
|
17764
17667
|
}
|
|
17668
|
+
|
|
17669
|
+
// Prevents cursor jumping in Safari. Setting `this.value` triggers a Lit
|
|
17670
|
+
// update that can re-render the input and reset the native cursor; we
|
|
17671
|
+
// capture the caret position before that update commits and restore it
|
|
17672
|
+
// via `setSelectionRange` once the update has flushed. Gated on
|
|
17673
|
+
// `setSelectionInputTypes` so credit-card (and other masked types whose
|
|
17674
|
+
// formatter manages the cursor itself) doesn't get a competing write.
|
|
17675
|
+
// Capture the caret position INSIDE the gate — reading `selectionStart`
|
|
17676
|
+
// on input types that don't support text selection (number, email in
|
|
17677
|
+
// some browsers) throws InvalidStateError, which would crash all input
|
|
17678
|
+
// handling. Wrap the read in try/catch belt-and-suspenders even though
|
|
17679
|
+
// the gated types currently support it, since the list is a public
|
|
17680
|
+
// property a consumer could mutate.
|
|
17681
|
+
if (this.setSelectionInputTypes.includes(this.type)) {
|
|
17682
|
+
let selectionStart = null;
|
|
17683
|
+
try {
|
|
17684
|
+
({ selectionStart } = this.inputElement);
|
|
17685
|
+
} catch (error) { // eslint-disable-line no-unused-vars
|
|
17686
|
+
return;
|
|
17687
|
+
}
|
|
17688
|
+
if (typeof selectionStart !== 'number') {
|
|
17689
|
+
return;
|
|
17690
|
+
}
|
|
17691
|
+
this.updateComplete.then(() => {
|
|
17692
|
+
try {
|
|
17693
|
+
this.inputElement.setSelectionRange(selectionStart, selectionStart);
|
|
17694
|
+
} catch (error) { // eslint-disable-line no-unused-vars
|
|
17695
|
+
// Some input types (number/email in certain UAs) throw on
|
|
17696
|
+
// setSelectionRange; swallow and let the native cursor stand.
|
|
17697
|
+
}
|
|
17698
|
+
});
|
|
17699
|
+
}
|
|
17765
17700
|
}
|
|
17766
17701
|
|
|
17767
17702
|
/**
|
|
@@ -17850,7 +17785,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17850
17785
|
*/
|
|
17851
17786
|
reset() {
|
|
17852
17787
|
this.value = undefined;
|
|
17853
|
-
this.setDateObjectProperty('valueObject', undefined);
|
|
17854
17788
|
this.validation.reset(this);
|
|
17855
17789
|
}
|
|
17856
17790
|
|
|
@@ -17859,7 +17793,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17859
17793
|
*/
|
|
17860
17794
|
clear() {
|
|
17861
17795
|
this.value = undefined;
|
|
17862
|
-
this.setDateObjectProperty('valueObject', undefined);
|
|
17863
17796
|
}
|
|
17864
17797
|
|
|
17865
17798
|
/**
|
|
@@ -17897,7 +17830,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17897
17830
|
*/
|
|
17898
17831
|
get placeholderStr() {
|
|
17899
17832
|
if (!this.placeholder && this.type === 'date') {
|
|
17900
|
-
return this.format
|
|
17833
|
+
return this.format.toUpperCase();
|
|
17901
17834
|
}
|
|
17902
17835
|
return this.placeholder || "";
|
|
17903
17836
|
}
|
|
@@ -18388,7 +18321,7 @@ let AuroHelpText$1 = class AuroHelpText extends LitElement {
|
|
|
18388
18321
|
}
|
|
18389
18322
|
};
|
|
18390
18323
|
|
|
18391
|
-
var formkitVersion$1 = '
|
|
18324
|
+
var formkitVersion$1 = '202607010100';
|
|
18392
18325
|
|
|
18393
18326
|
// Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
18394
18327
|
// See LICENSE in the project root for license information.
|
|
@@ -18891,6 +18824,7 @@ class AuroInput extends BaseInput {
|
|
|
18891
18824
|
<${this.buttonTag}
|
|
18892
18825
|
@click="${this.handleClickShowPassword}"
|
|
18893
18826
|
appearance="${this.onDark ? 'inverse' : this.appearance}"
|
|
18827
|
+
aria-pressed="${this.showPassword ? 'true' : 'false'}"
|
|
18894
18828
|
class="notificationBtn passwordBtn"
|
|
18895
18829
|
shape="circle"
|
|
18896
18830
|
size="sm"
|
|
@@ -18964,25 +18898,29 @@ class AuroInput extends BaseInput {
|
|
|
18964
18898
|
* @returns {html} - Returns HTML for the help text and error message.
|
|
18965
18899
|
*/
|
|
18966
18900
|
renderHtmlHelpText() {
|
|
18901
|
+
// Single `<p>` with stable identity across validity transitions —
|
|
18902
|
+
// previously two distinct templates (valid vs invalid) caused Lit to
|
|
18903
|
+
// replace the node entirely on a flip, and VoiceOver wouldn't
|
|
18904
|
+
// re-announce because the live-region element it was watching had been
|
|
18905
|
+
// removed and a new one inserted. Keeping one node means the `role`,
|
|
18906
|
+
// `aria-live`, and text content all change in-place, which AT does
|
|
18907
|
+
// observe and announce.
|
|
18908
|
+
const isError = this.validity && this.validity !== 'valid';
|
|
18967
18909
|
return html`
|
|
18968
|
-
|
|
18969
|
-
?
|
|
18970
|
-
|
|
18971
|
-
|
|
18972
|
-
|
|
18973
|
-
|
|
18974
|
-
|
|
18975
|
-
|
|
18976
|
-
|
|
18977
|
-
|
|
18978
|
-
|
|
18979
|
-
appearance="${this.onDark ? 'inverse' : this.appearance}">
|
|
18980
|
-
<p id="${this.uniqueId}" role="alert" aria-live="assertive" part="helpText">
|
|
18981
|
-
${this.errorMessage}
|
|
18982
|
-
</p>
|
|
18983
|
-
</${this.helpTextTag}>
|
|
18984
|
-
`
|
|
18910
|
+
<${this.helpTextTag}
|
|
18911
|
+
appearance="${this.onDark ? 'inverse' : this.appearance}"
|
|
18912
|
+
?error=${isError}>
|
|
18913
|
+
<p
|
|
18914
|
+
id="${this.uniqueId}"
|
|
18915
|
+
part="helpText"
|
|
18916
|
+
role="${ifDefined(isError ? 'alert' : undefined)}"
|
|
18917
|
+
aria-live="${ifDefined(isError ? 'assertive' : undefined)}">
|
|
18918
|
+
${isError
|
|
18919
|
+
? this.errorMessage
|
|
18920
|
+
: html`<slot name="helpText">${this.getHelpText()}</slot>`
|
|
18985
18921
|
}
|
|
18922
|
+
</p>
|
|
18923
|
+
</${this.helpTextTag}>
|
|
18986
18924
|
`;
|
|
18987
18925
|
}
|
|
18988
18926
|
|
|
@@ -19114,7 +19052,7 @@ class AuroInput extends BaseInput {
|
|
|
19114
19052
|
|
|
19115
19053
|
var colorCss$1 = css`#headerContainer{box-shadow:var(--ds-auro-dropdownbib-header-boxshadow-color)}#footerContainer{background-color:var(--ds-auro-dropdownbib-footer-container-color)}`;
|
|
19116
19054
|
|
|
19117
|
-
var styleCss$2 = css`#bibTemplate{display:flex;overflow:hidden;height:100%;max-height:100%;flex-direction:column}#headerContainer{display:flex;flex-direction:column;padding:var(--ds-size-200, 1rem);padding-top:var(--ds-size-400, 2rem);padding-bottom:0}#headerContainer .titleRow{display:flex;flex-direction:row;justify-content:space-between;gap:var(--ds-size-100, 0.5rem)}#headerContainer .header{max-width:calc(100vw - var(--ds-size-900, 4.5rem));padding-top:var(--ds-size-200, 1rem)}#headerContainer .subheader{width:100%}#closeButton [auro-icon]{--ds-auro-icon-size: var(--ds-size-500, 2.5rem)}#bodyContainer{position:relative;overflow:auto;flex:1
|
|
19055
|
+
var styleCss$2 = css`#bibTemplate{display:flex;overflow:hidden;height:100%;max-height:100%;flex-direction:column}#headerContainer{display:flex;flex-direction:column;padding:var(--ds-size-200, 1rem);padding-top:var(--ds-size-400, 2rem);padding-bottom:0}#headerContainer .titleRow{display:flex;flex-direction:row;justify-content:space-between;gap:var(--ds-size-100, 0.5rem)}#headerContainer .header{max-width:calc(100vw - var(--ds-size-900, 4.5rem));padding-top:var(--ds-size-200, 1rem)}#headerContainer .subheader{width:100%}#closeButton [auro-icon]{--ds-auro-icon-size: var(--ds-size-500, 2.5rem)}#bodyContainer{position:relative;overflow:auto;flex:1}:host([isfullscreen]) #bibTemplate{max-height:100dvh}:host([isfullscreen]) #bodyContainer{margin-top:var(--ds-size-100, 0.5rem)}#footerContainer{padding:var(--ds-size-200, 1rem)}`;
|
|
19118
19056
|
|
|
19119
19057
|
var tokenCss = css`:host{--ds-auro-dropdownbib-header-boxshadow-color: var(--ds-elevation-200, 0px 0px 10px rgba(0, 0, 0, 0.15));--ds-auro-dropdownbib-footer-container-color: var(--ds-basic-color-surface-default, #ffffff)}`;
|
|
19120
19058
|
|
|
@@ -19509,7 +19447,7 @@ class AuroBibtemplate extends LitElement {
|
|
|
19509
19447
|
}
|
|
19510
19448
|
}
|
|
19511
19449
|
|
|
19512
|
-
var formkitVersion = '
|
|
19450
|
+
var formkitVersion = '202607010100';
|
|
19513
19451
|
|
|
19514
19452
|
var styleCss$1 = css`.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}`;
|
|
19515
19453
|
|
|
@@ -19877,12 +19815,23 @@ function getOptionLabel(option) {
|
|
|
19877
19815
|
if (!option) {
|
|
19878
19816
|
return '';
|
|
19879
19817
|
}
|
|
19880
|
-
|
|
19881
|
-
|
|
19882
|
-
if (
|
|
19883
|
-
|
|
19818
|
+
|
|
19819
|
+
// Consumer-provided override: short-circuit the DOM walk entirely.
|
|
19820
|
+
if (option.dataset && option.dataset.label) {
|
|
19821
|
+
return option.dataset.label;
|
|
19822
|
+
}
|
|
19823
|
+
|
|
19824
|
+
// Walk direct children — the `slot` attribute only applies to direct children
|
|
19825
|
+
// of the slot host, so a shallow filter is sufficient. Avoids the cloneNode +
|
|
19826
|
+
// querySelector allocation that ran on every keystroke via syncValuesAndStates.
|
|
19827
|
+
let text = '';
|
|
19828
|
+
for (const node of option.childNodes) {
|
|
19829
|
+
const isDisplayValueSlot = node.nodeType === Node.ELEMENT_NODE && node.getAttribute('slot') === 'displayValue';
|
|
19830
|
+
if (!isDisplayValueSlot) {
|
|
19831
|
+
text += node.textContent || '';
|
|
19832
|
+
}
|
|
19884
19833
|
}
|
|
19885
|
-
return
|
|
19834
|
+
return text.replace(/\s+/gu, ' ').trim();
|
|
19886
19835
|
}
|
|
19887
19836
|
|
|
19888
19837
|
// See https://git.io/JJ6SJ for "How to document your components using JSDoc"
|
|
@@ -19957,8 +19906,6 @@ class AuroCombobox extends AuroElement {
|
|
|
19957
19906
|
this.availableOptions = [];
|
|
19958
19907
|
this.dropdownId = undefined;
|
|
19959
19908
|
this.dropdownOpen = false;
|
|
19960
|
-
this.triggerExpandedState = false;
|
|
19961
|
-
this._expandedTimeout = null;
|
|
19962
19909
|
this._inFullscreenTransition = false;
|
|
19963
19910
|
this.errorMessage = null;
|
|
19964
19911
|
this.isHiddenWhileLoading = false;
|
|
@@ -19969,6 +19916,30 @@ class AuroCombobox extends AuroElement {
|
|
|
19969
19916
|
this.touched = false;
|
|
19970
19917
|
this.validation = new AuroFormValidation$1();
|
|
19971
19918
|
this.validity = undefined;
|
|
19919
|
+
this._userTyped = false;
|
|
19920
|
+
// Tracks every setTimeout scheduled via _scheduleTimer so
|
|
19921
|
+
// disconnectedCallback can cancel them. Without this, a detached
|
|
19922
|
+
// combobox's pending timers still fire — most are no-ops, but
|
|
19923
|
+
// configureMenu's racing-condition retry would otherwise loop.
|
|
19924
|
+
this._pendingTimers = new Set();
|
|
19925
|
+
}
|
|
19926
|
+
|
|
19927
|
+
/**
|
|
19928
|
+
* setTimeout wrapper that records the timer id so disconnectedCallback
|
|
19929
|
+
* can cancel any outstanding callbacks. The id is removed from the set
|
|
19930
|
+
* once the callback fires so the set doesn't grow unbounded.
|
|
19931
|
+
* @param {Function} fn - Callback to run.
|
|
19932
|
+
* @param {number} ms - Delay in milliseconds.
|
|
19933
|
+
* @returns {number} The timer id.
|
|
19934
|
+
* @private
|
|
19935
|
+
*/
|
|
19936
|
+
_scheduleTimer(fn, ms) {
|
|
19937
|
+
const id = setTimeout(() => {
|
|
19938
|
+
this._pendingTimers.delete(id);
|
|
19939
|
+
fn();
|
|
19940
|
+
}, ms);
|
|
19941
|
+
this._pendingTimers.add(id);
|
|
19942
|
+
return id;
|
|
19972
19943
|
}
|
|
19973
19944
|
|
|
19974
19945
|
// This function is to define props used within the scope of this component
|
|
@@ -20330,17 +20301,6 @@ class AuroCombobox extends AuroElement {
|
|
|
20330
20301
|
attribute: false
|
|
20331
20302
|
},
|
|
20332
20303
|
|
|
20333
|
-
/**
|
|
20334
|
-
* Deferred aria-expanded state for the trigger input.
|
|
20335
|
-
* Delays the "true" transition so VoiceOver finishes its character echo
|
|
20336
|
-
* before announcing "expanded".
|
|
20337
|
-
* @private
|
|
20338
|
-
*/
|
|
20339
|
-
triggerExpandedState: {
|
|
20340
|
-
type: Boolean,
|
|
20341
|
-
reflect: false,
|
|
20342
|
-
attribute: false
|
|
20343
|
-
},
|
|
20344
20304
|
};
|
|
20345
20305
|
}
|
|
20346
20306
|
|
|
@@ -20363,13 +20323,6 @@ class AuroCombobox extends AuroElement {
|
|
|
20363
20323
|
return this.input.value;
|
|
20364
20324
|
}
|
|
20365
20325
|
|
|
20366
|
-
// /**
|
|
20367
|
-
// * Sets the value of the input element within the combobox.
|
|
20368
|
-
// */
|
|
20369
|
-
// set inputValue(value) {
|
|
20370
|
-
// this.input.value = value;
|
|
20371
|
-
// }
|
|
20372
|
-
|
|
20373
20326
|
/**
|
|
20374
20327
|
* Checks if the element is valid.
|
|
20375
20328
|
* @returns {boolean} - Returns true if the element is valid, false otherwise.
|
|
@@ -20496,7 +20449,7 @@ class AuroCombobox extends AuroElement {
|
|
|
20496
20449
|
if (this.menu) {
|
|
20497
20450
|
this.menu.matchWord = normalizeFilterValue(this.input.value);
|
|
20498
20451
|
}
|
|
20499
|
-
const label = getOptionLabel(this.menu.optionSelected)
|
|
20452
|
+
const label = getOptionLabel(this.menu.optionSelected);
|
|
20500
20453
|
this.updateTriggerTextDisplay(label || this.value);
|
|
20501
20454
|
}
|
|
20502
20455
|
|
|
@@ -20510,44 +20463,16 @@ class AuroCombobox extends AuroElement {
|
|
|
20510
20463
|
// in suggestion mode, do not override input value if no selection has been made and the input currently has focus
|
|
20511
20464
|
const isInputFocusedWithNoSelection = !this.menu.value && (this.input.matches(':focus-within') || (this.inputInBib && this.inputInBib.matches(':focus-within')));
|
|
20512
20465
|
|
|
20513
|
-
|
|
20514
|
-
|
|
20515
|
-
|
|
20516
|
-
// syncValuesAndStates re-enters here during typing when both inputs
|
|
20517
|
-
// already match, and a no-op flag flip would make the bib branch's
|
|
20518
|
-
// bail eat legitimate user-input events.
|
|
20519
|
-
const triggerNeedsSync = this.input.value !== nextValue;
|
|
20520
|
-
const bibNeedsSync = Boolean(this.inputInBib && this.inputInBib !== this.input && this.inputInBib.value !== nextValue);
|
|
20521
|
-
if (triggerNeedsSync || bibNeedsSync) {
|
|
20522
|
-
this._syncingDisplayValue = true;
|
|
20523
|
-
if (triggerNeedsSync) {
|
|
20524
|
-
this.input.value = nextValue;
|
|
20525
|
-
}
|
|
20526
|
-
if (bibNeedsSync) {
|
|
20527
|
-
this.inputInBib.value = nextValue;
|
|
20528
|
-
}
|
|
20529
|
-
const pending = [];
|
|
20530
|
-
if (triggerNeedsSync) {
|
|
20531
|
-
pending.push(this.input.updateComplete);
|
|
20532
|
-
}
|
|
20533
|
-
if (bibNeedsSync) {
|
|
20534
|
-
pending.push(this.inputInBib.updateComplete);
|
|
20535
|
-
}
|
|
20536
|
-
Promise.all(pending).then(() => {
|
|
20537
|
-
// imask reasserts otherwise, and handleBlur reverts to its stale value.
|
|
20538
|
-
if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
|
|
20539
|
-
this.input.maskInstance.updateValue();
|
|
20540
|
-
}
|
|
20541
|
-
if (bibNeedsSync && this.inputInBib && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
|
|
20542
|
-
this.inputInBib.maskInstance.updateValue();
|
|
20543
|
-
}
|
|
20544
|
-
this._syncingDisplayValue = false;
|
|
20545
|
-
});
|
|
20546
|
-
}
|
|
20466
|
+
const suppressed = this.persistInput || (this.behavior === 'suggestion' && isInputFocusedWithNoSelection);
|
|
20467
|
+
if (!suppressed) {
|
|
20468
|
+
this.syncInputValuesAcrossTriggerAndBib(label || this.value);
|
|
20547
20469
|
}
|
|
20548
20470
|
|
|
20549
|
-
//
|
|
20550
|
-
|
|
20471
|
+
// Replace any previously appended displayValue clone in the trigger.
|
|
20472
|
+
// :not(slot) excludes the template's <slot name="displayValue"
|
|
20473
|
+
// slot="displayValue"> forwarder, which also has slot="displayValue"
|
|
20474
|
+
// and would otherwise be matched first and removed.
|
|
20475
|
+
const displayValueInTrigger = this.input.querySelector('[slot="displayValue"]:not(slot)');
|
|
20551
20476
|
|
|
20552
20477
|
if (displayValueInTrigger) {
|
|
20553
20478
|
displayValueInTrigger.remove();
|
|
@@ -20571,6 +20496,53 @@ class AuroCombobox extends AuroElement {
|
|
|
20571
20496
|
this.requestUpdate();
|
|
20572
20497
|
}
|
|
20573
20498
|
|
|
20499
|
+
/**
|
|
20500
|
+
* Writes nextValue to the trigger input and the bib input when their current
|
|
20501
|
+
* value differs, then re-asserts imask after Lit's update flushes.
|
|
20502
|
+
* @param {string} nextValue - The value to write to both inputs.
|
|
20503
|
+
* @returns {Promise<void>} Resolves after both inputs flush and imask
|
|
20504
|
+
* re-asserts; resolves immediately when no sync is needed.
|
|
20505
|
+
* @private
|
|
20506
|
+
*/
|
|
20507
|
+
async syncInputValuesAcrossTriggerAndBib(nextValue) {
|
|
20508
|
+
// Only set the flag when there's an actual write to suppress —
|
|
20509
|
+
// syncValuesAndStates re-enters here during typing when both inputs
|
|
20510
|
+
// already match, and a no-op flag flip would make the bib branch's
|
|
20511
|
+
// bail eat legitimate user-input events.
|
|
20512
|
+
const triggerNeedsSync = this.input.value !== nextValue;
|
|
20513
|
+
const bibNeedsSync = Boolean(this.inputInBib) && this.inputInBib.value !== nextValue;
|
|
20514
|
+
if (!triggerNeedsSync && !bibNeedsSync) {
|
|
20515
|
+
return;
|
|
20516
|
+
}
|
|
20517
|
+
|
|
20518
|
+
this._syncingDisplayValue = true;
|
|
20519
|
+
|
|
20520
|
+
const pending = [];
|
|
20521
|
+
if (triggerNeedsSync) {
|
|
20522
|
+
this.input.value = nextValue;
|
|
20523
|
+
pending.push(this.input.updateComplete);
|
|
20524
|
+
}
|
|
20525
|
+
if (bibNeedsSync) {
|
|
20526
|
+
this.inputInBib.value = nextValue;
|
|
20527
|
+
pending.push(this.inputInBib.updateComplete);
|
|
20528
|
+
}
|
|
20529
|
+
// finally — not a bare .then — so that an imask throw (see commit
|
|
20530
|
+
// d1857401c: imask can throw on credit-card format change) doesn't strand
|
|
20531
|
+
// _syncingDisplayValue=true and silently swallow every subsequent input.
|
|
20532
|
+
try {
|
|
20533
|
+
await Promise.all(pending);
|
|
20534
|
+
// imask reasserts otherwise, and handleBlur reverts to its stale value.
|
|
20535
|
+
if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
|
|
20536
|
+
this.input.maskInstance.updateValue();
|
|
20537
|
+
}
|
|
20538
|
+
if (bibNeedsSync && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
|
|
20539
|
+
this.inputInBib.maskInstance.updateValue();
|
|
20540
|
+
}
|
|
20541
|
+
} finally {
|
|
20542
|
+
this._syncingDisplayValue = false;
|
|
20543
|
+
}
|
|
20544
|
+
}
|
|
20545
|
+
|
|
20574
20546
|
/**
|
|
20575
20547
|
* Processes hidden state of all menu options and determines if there are any available options not hidden.
|
|
20576
20548
|
* @private
|
|
@@ -20579,6 +20551,13 @@ class AuroCombobox extends AuroElement {
|
|
|
20579
20551
|
handleMenuOptions() {
|
|
20580
20552
|
this.generateOptionsArray();
|
|
20581
20553
|
this.availableOptions = [];
|
|
20554
|
+
// Single source of truth for the menu's filter/highlight token per call.
|
|
20555
|
+
// syncValuesAndStates re-writes the same value on exact-match keystrokes —
|
|
20556
|
+
// Lit's hasChanged makes that a no-op — and the prior duplicate set inside
|
|
20557
|
+
// handleTriggerInputValueChange is gone.
|
|
20558
|
+
if (this.menu) {
|
|
20559
|
+
this.menu.matchWord = normalizeFilterValue(this.input.value);
|
|
20560
|
+
}
|
|
20582
20561
|
this.updateFilter();
|
|
20583
20562
|
|
|
20584
20563
|
// Set aria-setsize/aria-posinset on each visible option so screen readers
|
|
@@ -20590,17 +20569,14 @@ class AuroCombobox extends AuroElement {
|
|
|
20590
20569
|
option.setAttribute('aria-posinset', index + 1);
|
|
20591
20570
|
});
|
|
20592
20571
|
|
|
20593
|
-
if (this.value && this.
|
|
20594
|
-
|
|
20595
|
-
this.setMenuValue(this.value);
|
|
20596
|
-
}
|
|
20597
|
-
|
|
20572
|
+
if (this.input.value && this.menu.options && this.menu.options.some((opt) => opt.value === this.input.value)) {
|
|
20573
|
+
this.setMenuValue(this.input.value);
|
|
20598
20574
|
this.syncValuesAndStates();
|
|
20599
20575
|
}
|
|
20600
20576
|
|
|
20601
|
-
// Re-activate when optionActive is
|
|
20602
|
-
// been reset (e.g. by clearSelection in an async update)
|
|
20603
|
-
// makeSelection() can find the correct option.
|
|
20577
|
+
// Re-activate when optionActive is not in the current scrollable viewport,
|
|
20578
|
+
// or when _index has been reset (e.g. by clearSelection in an async update)
|
|
20579
|
+
// so that makeSelection() can find the correct option.
|
|
20604
20580
|
if (!this.availableOptions.includes(this.menu.optionActive) || this.menu._index < 0) {
|
|
20605
20581
|
this.activateFirstEnabledAvailableOption();
|
|
20606
20582
|
}
|
|
@@ -20673,18 +20649,6 @@ class AuroCombobox extends AuroElement {
|
|
|
20673
20649
|
this.dropdownOpen = ev.detail.expanded;
|
|
20674
20650
|
this.updateMenuShapeSize();
|
|
20675
20651
|
|
|
20676
|
-
// Defer aria-expanded "true" so VoiceOver finishes character echo
|
|
20677
|
-
// before announcing "expanded". Set "false" immediately on close.
|
|
20678
|
-
clearTimeout(this._expandedTimeout);
|
|
20679
|
-
if (this.dropdownOpen) {
|
|
20680
|
-
const expandedDelay = 150;
|
|
20681
|
-
this._expandedTimeout = setTimeout(() => {
|
|
20682
|
-
this.triggerExpandedState = true;
|
|
20683
|
-
}, expandedDelay);
|
|
20684
|
-
} else {
|
|
20685
|
-
this.triggerExpandedState = false;
|
|
20686
|
-
}
|
|
20687
|
-
|
|
20688
20652
|
// Clear aria-activedescendant when dropdown closes
|
|
20689
20653
|
if (!this.dropdownOpen && this.input) {
|
|
20690
20654
|
this.input.setActiveDescendant(null);
|
|
@@ -20734,28 +20698,25 @@ class AuroCombobox extends AuroElement {
|
|
|
20734
20698
|
|
|
20735
20699
|
guardTouchPassthrough(this.menu);
|
|
20736
20700
|
|
|
20737
|
-
//
|
|
20738
|
-
//
|
|
20739
|
-
//
|
|
20701
|
+
// showModal() takes focus away from the trigger. Early focus once
|
|
20702
|
+
// the dialog has painted; the shared doubleRaf below is the fallback
|
|
20703
|
+
// for when the dialog needs an extra frame and also clears the
|
|
20704
|
+
// validation guard.
|
|
20740
20705
|
requestAnimationFrame(() => {
|
|
20741
20706
|
this.setInputFocus();
|
|
20742
20707
|
});
|
|
20743
|
-
|
|
20744
|
-
doubleRaf(() => {
|
|
20745
|
-
this.setInputFocus();
|
|
20746
|
-
this._inFullscreenTransition = false;
|
|
20747
|
-
});
|
|
20748
|
-
} else {
|
|
20749
|
-
// Desktop popover-open: restore the trigger caret to end-of-text.
|
|
20750
|
-
// Clicking the trigger lands on auro-input's floating <label for="…">
|
|
20751
|
-
// overlay; Chrome resets the native input's selection to [0, 0] on
|
|
20752
|
-
// label-focus before any JS runs. setInputFocus()'s non-fullscreen
|
|
20753
|
-
// branch parks the caret at end. doubleRaf lets the dropdown layout
|
|
20754
|
-
// settle first, matching the fullscreen branch timing.
|
|
20755
|
-
doubleRaf(() => {
|
|
20756
|
-
this.setInputFocus();
|
|
20757
|
-
});
|
|
20758
20708
|
}
|
|
20709
|
+
// else (desktop popover-open): Chrome resets the trigger caret to
|
|
20710
|
+
// [0, 0] when its floating <label for="…"> overlay receives focus.
|
|
20711
|
+
// The shared doubleRaf below parks the caret back at end-of-text
|
|
20712
|
+
// after the dropdown layout settles.
|
|
20713
|
+
|
|
20714
|
+
doubleRaf(() => {
|
|
20715
|
+
this.setInputFocus();
|
|
20716
|
+
if (this._inFullscreenTransition) {
|
|
20717
|
+
this._inFullscreenTransition = false;
|
|
20718
|
+
}
|
|
20719
|
+
});
|
|
20759
20720
|
}
|
|
20760
20721
|
});
|
|
20761
20722
|
|
|
@@ -20792,7 +20753,7 @@ class AuroCombobox extends AuroElement {
|
|
|
20792
20753
|
this.dropdown.trigger.inert = false;
|
|
20793
20754
|
}
|
|
20794
20755
|
|
|
20795
|
-
|
|
20756
|
+
this._scheduleTimer(() => {
|
|
20796
20757
|
this.setInputFocus();
|
|
20797
20758
|
}, 0);
|
|
20798
20759
|
});
|
|
@@ -20860,24 +20821,7 @@ class AuroCombobox extends AuroElement {
|
|
|
20860
20821
|
nativeInput.setSelectionRange(len, len);
|
|
20861
20822
|
}
|
|
20862
20823
|
} else {
|
|
20863
|
-
|
|
20864
|
-
// fullscreen→floating switch can close the dialog and leave focus on
|
|
20865
|
-
// body. Every other Branch 2 callsite already has focus on the input
|
|
20866
|
-
// via the focusin → this.focus() redirect (L1448-1452), so this is a
|
|
20867
|
-
// no-op in the common case.
|
|
20868
|
-
if (!this.input.componentHasFocus) {
|
|
20869
|
-
this.input.focus();
|
|
20870
|
-
}
|
|
20871
|
-
|
|
20872
|
-
// Park the trigger native input's caret at end-of-text every time the
|
|
20873
|
-
// popover opens. Chrome focuses the native via the floating <label for="…">
|
|
20874
|
-
// overlay on click and resets selection to [0, 0]; no JS fires between
|
|
20875
|
-
// mousedown and selectionchange, so we restore the caret here.
|
|
20876
|
-
const triggerNativeInput = this.input.inputElement;
|
|
20877
|
-
if (triggerNativeInput && triggerNativeInput.value) {
|
|
20878
|
-
const len = triggerNativeInput.value.length;
|
|
20879
|
-
triggerNativeInput.setSelectionRange(len, len);
|
|
20880
|
-
}
|
|
20824
|
+
this.input.focus();
|
|
20881
20825
|
}
|
|
20882
20826
|
}
|
|
20883
20827
|
|
|
@@ -20953,7 +20897,7 @@ class AuroCombobox extends AuroElement {
|
|
|
20953
20897
|
|
|
20954
20898
|
// racing condition on custom-combobox with custom-menu
|
|
20955
20899
|
if (!this.menu) {
|
|
20956
|
-
|
|
20900
|
+
this._scheduleTimer(() => {
|
|
20957
20901
|
this.configureMenu();
|
|
20958
20902
|
}, 0);
|
|
20959
20903
|
return;
|
|
@@ -20983,7 +20927,7 @@ class AuroCombobox extends AuroElement {
|
|
|
20983
20927
|
if (this.menu.optionSelected) {
|
|
20984
20928
|
const selected = this.menu.optionSelected;
|
|
20985
20929
|
|
|
20986
|
-
if (
|
|
20930
|
+
if (this.optionSelected !== selected) {
|
|
20987
20931
|
this.optionSelected = selected;
|
|
20988
20932
|
}
|
|
20989
20933
|
|
|
@@ -20996,7 +20940,7 @@ class AuroCombobox extends AuroElement {
|
|
|
20996
20940
|
}
|
|
20997
20941
|
|
|
20998
20942
|
// Update display
|
|
20999
|
-
this.updateTriggerTextDisplay(getOptionLabel(this.optionSelected)
|
|
20943
|
+
this.updateTriggerTextDisplay(getOptionLabel(this.optionSelected));
|
|
21000
20944
|
|
|
21001
20945
|
// Update match word for filtering
|
|
21002
20946
|
const trimmedInput = normalizeFilterValue(this.input.value);
|
|
@@ -21008,17 +20952,24 @@ class AuroCombobox extends AuroElement {
|
|
|
21008
20952
|
// Hide dropdown on selection (except during slot changes)
|
|
21009
20953
|
if (evt.detail && evt.detail.source !== 'slotchange') {
|
|
21010
20954
|
// do not close while typing in suggestion mode with no value selected, to allow freeform input
|
|
21011
|
-
|
|
21012
|
-
|
|
20955
|
+
this.hideBib();
|
|
20956
|
+
|
|
20957
|
+
// Move focus to the clear button when the user makes a selection.
|
|
20958
|
+
if (!isEcho && this.menu.value !== undefined) {
|
|
20959
|
+
this.setClearBtnFocus();
|
|
21013
20960
|
}
|
|
21014
20961
|
|
|
21015
20962
|
// Announce the selection after the dropdown closes so it isn't
|
|
21016
20963
|
// overridden by VoiceOver's "collapsed" announcement from aria-expanded.
|
|
20964
|
+
// Skip when there's no selected value (e.g. menu.clearSelection() from
|
|
20965
|
+
// the unmatched-value path), otherwise VoiceOver reads "undefined".
|
|
21017
20966
|
const selectedValue = this.menu.value;
|
|
21018
|
-
|
|
21019
|
-
|
|
21020
|
-
|
|
21021
|
-
|
|
20967
|
+
if (selectedValue) {
|
|
20968
|
+
const announcementDelay = 300;
|
|
20969
|
+
this._scheduleTimer(() => {
|
|
20970
|
+
announceToScreenReader(this._getAnnouncementRoot(), `${selectedValue}, selected`);
|
|
20971
|
+
}, announcementDelay);
|
|
20972
|
+
}
|
|
21022
20973
|
}
|
|
21023
20974
|
|
|
21024
20975
|
// Programmatic value syncs leave availableOptions stale because
|
|
@@ -21027,22 +20978,6 @@ class AuroCombobox extends AuroElement {
|
|
|
21027
20978
|
// only — fresh user selections take the existing hideBib path.
|
|
21028
20979
|
if (isEcho && this.menu.optionSelected) {
|
|
21029
20980
|
this._programmaticFilterRefresh = true;
|
|
21030
|
-
this.handleMenuOptions();
|
|
21031
|
-
setTimeout(() => {
|
|
21032
|
-
this._programmaticFilterRefresh = false;
|
|
21033
|
-
}, 0);
|
|
21034
|
-
}
|
|
21035
|
-
|
|
21036
|
-
// base-input skips auto-validate when focus is inside its own shadow,
|
|
21037
|
-
// which it is after setTriggerInputFocus — re-run so prior tooShort
|
|
21038
|
-
// clears. processCreditCard reasserts errorMessage on every render.
|
|
21039
|
-
if (!isEcho && this.menu.optionSelected && this.input.validate) {
|
|
21040
|
-
this.input.updateComplete.then(() => {
|
|
21041
|
-
this.input.validate(true);
|
|
21042
|
-
if (this.input.validity === 'valid') {
|
|
21043
|
-
this.input.errorMessage = '';
|
|
21044
|
-
}
|
|
21045
|
-
});
|
|
21046
20981
|
}
|
|
21047
20982
|
});
|
|
21048
20983
|
|
|
@@ -21055,6 +20990,14 @@ class AuroCombobox extends AuroElement {
|
|
|
21055
20990
|
// stale option. Safe from re-entrancy because any resulting
|
|
21056
20991
|
// input.value changes dispatch isProgrammatic events.
|
|
21057
20992
|
this.menu.addEventListener('auroMenu-selectValueFailure', () => {
|
|
20993
|
+
// Announce the rejection BEFORE we clear `this.value` so the live
|
|
20994
|
+
// region carries the attempted value — without this the bib closes
|
|
20995
|
+
// silently and screen-reader users get no signal that their request
|
|
20996
|
+
// (e.g. a direct setMenuValue() call) was dropped.
|
|
20997
|
+
const attemptedValue = this.value;
|
|
20998
|
+
if (attemptedValue) {
|
|
20999
|
+
announceToScreenReader(this._getAnnouncementRoot(), `No matching option for ${attemptedValue}`);
|
|
21000
|
+
}
|
|
21058
21001
|
this.value = undefined;
|
|
21059
21002
|
this.optionSelected = undefined;
|
|
21060
21003
|
});
|
|
@@ -21066,10 +21009,13 @@ class AuroCombobox extends AuroElement {
|
|
|
21066
21009
|
this.input.setActiveDescendant(this.optionActive);
|
|
21067
21010
|
}
|
|
21068
21011
|
|
|
21069
|
-
//
|
|
21070
|
-
//
|
|
21071
|
-
//
|
|
21072
|
-
|
|
21012
|
+
// In fullscreen mode the menu sits inside a nested <dialog> shadow root,
|
|
21013
|
+
// and aria-activedescendant references across that boundary are lost —
|
|
21014
|
+
// VoiceOver/NVDA don't read the active option natively, so we mirror it
|
|
21015
|
+
// into the polite live region. In popover mode aria-activedescendant on
|
|
21016
|
+
// the trigger input is read natively; double-announcing would flood the
|
|
21017
|
+
// queue on arrow-key repeat.
|
|
21018
|
+
if (this.optionActive && this.dropdown.isBibFullscreen) {
|
|
21073
21019
|
const optionText = this.optionActive.textContent.trim();
|
|
21074
21020
|
const selectedState = this.optionActive.hasAttribute('selected') ? ', selected' : ', not selected';
|
|
21075
21021
|
const optionIndex = this.availableOptions.indexOf(this.optionActive) + 1;
|
|
@@ -21102,7 +21048,12 @@ class AuroCombobox extends AuroElement {
|
|
|
21102
21048
|
* Validate every time we remove focus from the combo box.
|
|
21103
21049
|
*/
|
|
21104
21050
|
this.addEventListener('focusout', () => {
|
|
21105
|
-
|
|
21051
|
+
// Skip while the dropdown is open — focus transits out briefly on
|
|
21052
|
+
// mousedown of a menu option (popover top-layer breaks :focus-within),
|
|
21053
|
+
// and validating against the pre-selection value flashes a stale error
|
|
21054
|
+
// between mousedown and mouseup. The next focusout fires after the
|
|
21055
|
+
// dropdown closes and validates against the post-selection value.
|
|
21056
|
+
if (!this.componentHasFocus && !this._inFullscreenTransition && !this.dropdownOpen) {
|
|
21106
21057
|
this.validate();
|
|
21107
21058
|
}
|
|
21108
21059
|
});
|
|
@@ -21165,49 +21116,40 @@ class AuroCombobox extends AuroElement {
|
|
|
21165
21116
|
if (this._syncingDisplayValue) {
|
|
21166
21117
|
return;
|
|
21167
21118
|
}
|
|
21168
|
-
this._syncingBibValue = true;
|
|
21169
|
-
this.input.value = this.inputInBib.value;
|
|
21170
|
-
this.input.updateComplete.then(() => {
|
|
21171
|
-
this._syncingBibValue = false;
|
|
21172
|
-
});
|
|
21173
21119
|
|
|
21174
|
-
//
|
|
21175
|
-
|
|
21176
|
-
|
|
21177
|
-
|
|
21178
|
-
|
|
21179
|
-
|
|
21180
|
-
|
|
21181
|
-
|
|
21182
|
-
|
|
21120
|
+
// Filtering runs via re-entrance: writing this.input.value below
|
|
21121
|
+
// dispatches an 'input' event that the trigger's listener routes to
|
|
21122
|
+
// handleTriggerInputValueChange, which refreshes the menu filter.
|
|
21123
|
+
if (this.input.value !== this.inputInBib.value) {
|
|
21124
|
+
this._syncingBibValue = true;
|
|
21125
|
+
this.input.value = this.inputInBib.value;
|
|
21126
|
+
this.input.updateComplete.then(() => {
|
|
21127
|
+
this._syncingBibValue = false;
|
|
21128
|
+
});
|
|
21183
21129
|
}
|
|
21184
21130
|
|
|
21185
|
-
this.handleMenuOptions();
|
|
21186
21131
|
this.dispatchEvent(new CustomEvent('inputValue', { detail: { value: this.inputValue } }));
|
|
21187
|
-
|
|
21132
|
+
} else if (event.target === this.input) {
|
|
21133
|
+
|
|
21134
|
+
// Also sync the native input immediately so keystrokes arriving
|
|
21135
|
+
// before Lit's async update cycle (e.g. rapid Backspaces during a
|
|
21136
|
+
// fullscreen transition) operate on the correct content.
|
|
21137
|
+
// Skip the next programmatic input event to prevent the patched setter
|
|
21138
|
+
// from re-entering handleInputValueChange via the bib path.
|
|
21139
|
+
const bibNativeInput = this.inputInBib.inputElement;
|
|
21140
|
+
if (bibNativeInput && bibNativeInput.value !== this.input.value) {
|
|
21141
|
+
this.inputInBib.skipNextProgrammaticInputEvent = true;
|
|
21142
|
+
bibNativeInput.value = this.input.value || '';
|
|
21143
|
+
}
|
|
21188
21144
|
}
|
|
21189
21145
|
|
|
21146
|
+
this.value = this.input.value;
|
|
21147
|
+
|
|
21190
21148
|
// Ignore re-entrant input events caused by programmatic value sets.
|
|
21191
21149
|
if (this._syncingBibValue || this._syncingDisplayValue) {
|
|
21192
21150
|
return;
|
|
21193
21151
|
}
|
|
21194
21152
|
|
|
21195
|
-
this.inputInBib.value = this.input.value;
|
|
21196
|
-
|
|
21197
|
-
// Also sync the native input immediately so keystrokes arriving
|
|
21198
|
-
// before Lit's async update cycle (e.g. rapid Backspaces during a
|
|
21199
|
-
// fullscreen transition) operate on the correct content.
|
|
21200
|
-
// Skip the next programmatic input event to prevent the patched setter
|
|
21201
|
-
// from re-entering handleInputValueChange via the bib path.
|
|
21202
|
-
const bibNativeInput = this.inputInBib.inputElement;
|
|
21203
|
-
if (bibNativeInput && bibNativeInput.value !== this.input.value) {
|
|
21204
|
-
this.inputInBib.skipNextProgrammaticInputEvent = true;
|
|
21205
|
-
bibNativeInput.value = this.input.value || '';
|
|
21206
|
-
}
|
|
21207
|
-
|
|
21208
|
-
this.menu.matchWord = normalizeFilterValue(this.input.value);
|
|
21209
|
-
this.optionActive = null;
|
|
21210
|
-
|
|
21211
21153
|
if (this.behavior === 'suggestion') {
|
|
21212
21154
|
this.value = this.input.value;
|
|
21213
21155
|
}
|
|
@@ -21215,7 +21157,6 @@ class AuroCombobox extends AuroElement {
|
|
|
21215
21157
|
if (!this.input.value && !this._clearing) {
|
|
21216
21158
|
this.clear();
|
|
21217
21159
|
}
|
|
21218
|
-
this.handleMenuOptions();
|
|
21219
21160
|
|
|
21220
21161
|
// Validate only if the value was set programmatically (not during user
|
|
21221
21162
|
// interaction). In fullscreen dialog mode, componentHasFocus returns false
|
|
@@ -21225,34 +21166,44 @@ class AuroCombobox extends AuroElement {
|
|
|
21225
21166
|
this.validate();
|
|
21226
21167
|
}
|
|
21227
21168
|
|
|
21228
|
-
|
|
21229
|
-
|
|
21230
|
-
|
|
21231
|
-
|
|
21232
|
-
|
|
21233
|
-
|
|
21234
|
-
|
|
21235
|
-
|
|
21236
|
-
|
|
21169
|
+
this.dispatchEvent(new CustomEvent('inputValue', { detail: { value: this.inputValue } }));
|
|
21170
|
+
}
|
|
21171
|
+
|
|
21172
|
+
/**
|
|
21173
|
+
* Handles input value changes originating from the trigger input.
|
|
21174
|
+
* Refreshes menu options and filtering, delegates to handleInputValueChange
|
|
21175
|
+
* for value synchronization, and manages fullscreen bib focus.
|
|
21176
|
+
* @private
|
|
21177
|
+
* @param {Event} event - The input event from the trigger input element.
|
|
21178
|
+
* @returns {void}
|
|
21179
|
+
*/
|
|
21180
|
+
handleTriggerInputValueChange(event) {
|
|
21181
|
+
// 'input' fires for every user-initiated value change — typing, paste,
|
|
21182
|
+
// IME composition end, dead-key composition, drag-drop. Flip _userTyped
|
|
21183
|
+
// here so updated('availableOptions') auto-opens the bib for sources
|
|
21184
|
+
// that keydown alone misses: paste fires no keydown, IME uses
|
|
21185
|
+
// key='Process', and dead keys produce multi-char keys (all bypass the
|
|
21186
|
+
// prior keydown.key.length===1 gate). Skip programmatic syncs.
|
|
21187
|
+
if (!this._syncingDisplayValue && !this._syncingBibValue && !this._programmaticFilterRefresh) {
|
|
21188
|
+
this._userTyped = true;
|
|
21237
21189
|
}
|
|
21238
21190
|
|
|
21239
|
-
|
|
21240
|
-
|
|
21241
|
-
|
|
21242
|
-
|
|
21243
|
-
|
|
21244
|
-
// dialog opens — the user then has to tap the input again to resume
|
|
21245
|
-
// typing.
|
|
21246
|
-
if (this.dropdown.isBibFullscreen && this.input.value && this.input.value.length > 0) {
|
|
21247
|
-
if (!this.dropdown.isPopoverVisible) {
|
|
21248
|
-
this.showBib();
|
|
21249
|
-
}
|
|
21250
|
-
if (this.dropdown.isPopoverVisible) {
|
|
21251
|
-
this.setInputFocus();
|
|
21252
|
-
}
|
|
21191
|
+
this.handleMenuOptions();
|
|
21192
|
+
this.optionActive = null;
|
|
21193
|
+
|
|
21194
|
+
if (this.value === this.input.value) {
|
|
21195
|
+
return;
|
|
21253
21196
|
}
|
|
21254
21197
|
|
|
21255
|
-
this.
|
|
21198
|
+
this.handleInputValueChange(event);
|
|
21199
|
+
|
|
21200
|
+
if (this.dropdown.isBibFullscreen && this.input.value && this.input.value.length > 0 && this.dropdown.isPopoverVisible) {
|
|
21201
|
+
this.setInputFocus();
|
|
21202
|
+
}
|
|
21203
|
+
|
|
21204
|
+
if (this._programmaticFilterRefresh) {
|
|
21205
|
+
this._programmaticFilterRefresh = false;
|
|
21206
|
+
}
|
|
21256
21207
|
}
|
|
21257
21208
|
|
|
21258
21209
|
/**
|
|
@@ -21320,6 +21271,11 @@ class AuroCombobox extends AuroElement {
|
|
|
21320
21271
|
disconnectedCallback() {
|
|
21321
21272
|
super.disconnectedCallback();
|
|
21322
21273
|
this._inFullscreenTransition = false;
|
|
21274
|
+
// Cancel any outstanding timers so detached callbacks don't fire on
|
|
21275
|
+
// disposed DOM — most are no-ops, but configureMenu's racing-condition
|
|
21276
|
+
// retry would otherwise keep rescheduling itself indefinitely.
|
|
21277
|
+
this._pendingTimers.forEach((id) => clearTimeout(id));
|
|
21278
|
+
this._pendingTimers.clear();
|
|
21323
21279
|
}
|
|
21324
21280
|
|
|
21325
21281
|
firstUpdated() {
|
|
@@ -21361,7 +21317,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21361
21317
|
this.menu.value = value;
|
|
21362
21318
|
// Backup clear: if menu.value === menu.optionSelected.value already, the
|
|
21363
21319
|
// listener won't fire and the flag would swallow the next user click.
|
|
21364
|
-
|
|
21320
|
+
this._scheduleTimer(() => {
|
|
21365
21321
|
this._pendingMenuValueSync = false;
|
|
21366
21322
|
}, 0);
|
|
21367
21323
|
}
|
|
@@ -21378,15 +21334,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21378
21334
|
this.menu.value = undefined;
|
|
21379
21335
|
this.validation.reset(this);
|
|
21380
21336
|
this.touched = false;
|
|
21381
|
-
// Force validity back to the cleared state. validation.reset() calls
|
|
21382
|
-
// validate() at the end, and (post-credit-card-fix) the trigger input's
|
|
21383
|
-
// residual validity may still be copied into the combobox by the
|
|
21384
|
-
// auroInputElements loop. Explicitly clear here so reset() actually
|
|
21385
|
-
// leaves the component in a "no validity" state.
|
|
21386
21337
|
this.validity = undefined;
|
|
21387
|
-
this.errorMessage = '';
|
|
21388
|
-
this.input.validity = undefined;
|
|
21389
|
-
this.input.errorMessage = '';
|
|
21390
21338
|
}
|
|
21391
21339
|
|
|
21392
21340
|
/**
|
|
@@ -21404,6 +21352,17 @@ class AuroCombobox extends AuroElement {
|
|
|
21404
21352
|
this.optionSelected = undefined;
|
|
21405
21353
|
this.value = undefined;
|
|
21406
21354
|
|
|
21355
|
+
// Clear the appended displayValue clone in the trigger if present.
|
|
21356
|
+
// :not(slot) excludes the template's <slot name="displayValue"
|
|
21357
|
+
// slot="displayValue"> forwarder (line 1816), which also has
|
|
21358
|
+
// slot="displayValue" and would otherwise be matched first and removed,
|
|
21359
|
+
// permanently breaking the consumer-provided displayValue slot.
|
|
21360
|
+
const displayValueInTrigger = this.input.querySelector('[slot="displayValue"]:not(slot)');
|
|
21361
|
+
|
|
21362
|
+
if (displayValueInTrigger) {
|
|
21363
|
+
displayValueInTrigger.remove();
|
|
21364
|
+
}
|
|
21365
|
+
|
|
21407
21366
|
if (this.input.value) {
|
|
21408
21367
|
this.input.clear();
|
|
21409
21368
|
}
|
|
@@ -21427,81 +21386,50 @@ class AuroCombobox extends AuroElement {
|
|
|
21427
21386
|
}
|
|
21428
21387
|
|
|
21429
21388
|
updated(changedProperties) {
|
|
21430
|
-
// After the component is ready,
|
|
21389
|
+
// After the component is ready, propagate direct changes down to child components.
|
|
21431
21390
|
if (changedProperties.has('value')) {
|
|
21432
|
-
|
|
21433
|
-
|
|
21434
|
-
|
|
21435
|
-
|
|
21391
|
+
// Only flag programmatic refreshes — user-typed value changes must not
|
|
21392
|
+
// suppress the availableOptions branch's showBib(). Firefox batches
|
|
21393
|
+
// 'value' and 'availableOptions' into the same updated() call, so
|
|
21394
|
+
// setting the flag unconditionally here masks the user-typed open path.
|
|
21395
|
+
if (!this._userTyped) {
|
|
21396
|
+
this._programmaticFilterRefresh = true;
|
|
21436
21397
|
}
|
|
21437
21398
|
|
|
21438
|
-
if (this.
|
|
21439
|
-
|
|
21440
|
-
|
|
21399
|
+
if (this.input.value !== this.value) {
|
|
21400
|
+
// Clear menu.value AND menu.optionSelected together. Clearing only
|
|
21401
|
+
// menu.value leaves the previously-selected option element pinned
|
|
21402
|
+
// as menu.optionSelected; a later auroMenu-selectedOption event
|
|
21403
|
+
// would then write its stale .value back into combobox.value
|
|
21404
|
+
// (e.g. Tab-after-Backspace re-selecting the prior option).
|
|
21405
|
+
if (this.menu.value || this.menu.optionSelected) {
|
|
21406
|
+
this.menu.clearSelection();
|
|
21407
|
+
}
|
|
21441
21408
|
|
|
21442
|
-
|
|
21443
|
-
|
|
21444
|
-
|
|
21445
|
-
|
|
21446
|
-
|
|
21447
|
-
|
|
21448
|
-
|
|
21449
|
-
|
|
21450
|
-
|
|
21451
|
-
|
|
21452
|
-
|
|
21453
|
-
|
|
21454
|
-
|
|
21455
|
-
|
|
21456
|
-
|
|
21457
|
-
|
|
21458
|
-
|
|
21459
|
-
|
|
21460
|
-
// matches to avoid spurious events during the normal typing path.
|
|
21461
|
-
const nextValue = this.value || '';
|
|
21462
|
-
const triggerNeedsSync = this.input.value !== nextValue;
|
|
21463
|
-
const bibNeedsSync = Boolean(this.inputInBib && this.inputInBib !== this.input && this.inputInBib.value !== nextValue);
|
|
21464
|
-
if (triggerNeedsSync || bibNeedsSync) {
|
|
21465
|
-
this._syncingDisplayValue = true;
|
|
21466
|
-
if (triggerNeedsSync) {
|
|
21467
|
-
this.input.value = nextValue;
|
|
21468
|
-
}
|
|
21469
|
-
if (bibNeedsSync) {
|
|
21470
|
-
this.inputInBib.value = nextValue;
|
|
21471
|
-
}
|
|
21472
|
-
const pending = [];
|
|
21473
|
-
if (triggerNeedsSync) {
|
|
21474
|
-
pending.push(this.input.updateComplete);
|
|
21475
|
-
}
|
|
21476
|
-
if (bibNeedsSync) {
|
|
21477
|
-
pending.push(this.inputInBib.updateComplete);
|
|
21478
|
-
}
|
|
21479
|
-
Promise.all(pending).then(() => {
|
|
21480
|
-
if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
|
|
21481
|
-
this.input.maskInstance.updateValue();
|
|
21482
|
-
}
|
|
21483
|
-
if (bibNeedsSync && this.inputInBib && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
|
|
21484
|
-
this.inputInBib.maskInstance.updateValue();
|
|
21485
|
-
}
|
|
21486
|
-
this._syncingDisplayValue = false;
|
|
21487
|
-
// handleInputValueChange bailed on the flag — refresh the filter.
|
|
21488
|
-
this._programmaticFilterRefresh = true;
|
|
21489
|
-
this.handleMenuOptions();
|
|
21490
|
-
setTimeout(() => {
|
|
21491
|
-
this._programmaticFilterRefresh = false;
|
|
21492
|
-
}, 0);
|
|
21493
|
-
});
|
|
21494
|
-
}
|
|
21409
|
+
if (!this.persistInput) {
|
|
21410
|
+
this.syncInputValuesAcrossTriggerAndBib(this.value || '');
|
|
21411
|
+
}
|
|
21412
|
+
|
|
21413
|
+
// Programmatic value with no matching option: updateFilter will close
|
|
21414
|
+
// the bib silently (see line 648 — no noMatchOption + 0 results
|
|
21415
|
+
// hides). Announce so screen-reader users hear the request was
|
|
21416
|
+
// dropped. Gated on `input.value !== this.value` so this never fires
|
|
21417
|
+
// for user typing — that path always reconciles input.value to
|
|
21418
|
+
// this.value before updated() runs.
|
|
21419
|
+
if (
|
|
21420
|
+
this.value &&
|
|
21421
|
+
this.menu &&
|
|
21422
|
+
this.menu.options &&
|
|
21423
|
+
this.menu.options.length > 0 &&
|
|
21424
|
+
!this.menu.options.some((opt) => opt.value === this.value)
|
|
21425
|
+
) {
|
|
21426
|
+
announceToScreenReader(this._getAnnouncementRoot(), `No matching option for ${this.value}`);
|
|
21495
21427
|
}
|
|
21496
21428
|
}
|
|
21429
|
+
|
|
21497
21430
|
if (!this.value) {
|
|
21498
21431
|
this.clear();
|
|
21499
21432
|
}
|
|
21500
|
-
if (this.value && !this.componentHasFocus) {
|
|
21501
|
-
// If the value got set programmatically make sure we hide the bib
|
|
21502
|
-
// when input is not taking the focus (input can be in dropdown.trigger or in bibtemplate)
|
|
21503
|
-
this.hideBib();
|
|
21504
|
-
}
|
|
21505
21433
|
|
|
21506
21434
|
// Sync the input and match word, but don't directly set menu.value again
|
|
21507
21435
|
if (this.menu) {
|
|
@@ -21514,7 +21442,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21514
21442
|
composed: true,
|
|
21515
21443
|
detail: {
|
|
21516
21444
|
optionSelected: this.menu.optionSelected,
|
|
21517
|
-
value: this.
|
|
21445
|
+
value: this.value
|
|
21518
21446
|
}
|
|
21519
21447
|
}));
|
|
21520
21448
|
|
|
@@ -21537,16 +21465,30 @@ class AuroCombobox extends AuroElement {
|
|
|
21537
21465
|
// from a programmatic filter refresh after a value swap — the user
|
|
21538
21466
|
// didn't interact, so we shouldn't auto-open the bib (especially for
|
|
21539
21467
|
// the no-match path where the existing condition unconditionally fires).
|
|
21540
|
-
if (this._programmaticFilterRefresh) {
|
|
21541
|
-
|
|
21542
|
-
|
|
21543
|
-
|
|
21468
|
+
if ((this.menu && !this._programmaticFilterRefresh)) {
|
|
21469
|
+
if (
|
|
21470
|
+
this.availableOptions.length > 0 ||
|
|
21471
|
+
this.menu.loading ||
|
|
21472
|
+
this.noMatchOption
|
|
21473
|
+
) {
|
|
21474
|
+
if (this._userTyped) {
|
|
21475
|
+
if (!this.dropdownOpen) {
|
|
21476
|
+
this.showBib();
|
|
21477
|
+
}
|
|
21478
|
+
this._userTyped = false;
|
|
21479
|
+
}
|
|
21480
|
+
}
|
|
21481
|
+
|
|
21544
21482
|
if (!this.availableOptions.includes(this.menu.optionActive)) {
|
|
21545
21483
|
this.activateFirstEnabledAvailableOption();
|
|
21546
21484
|
}
|
|
21547
|
-
} else if (this.dropdown
|
|
21485
|
+
} else if (!this.dropdown.isBibFullscreen) {
|
|
21548
21486
|
this.hideBib();
|
|
21549
21487
|
}
|
|
21488
|
+
|
|
21489
|
+
if (this._programmaticFilterRefresh) {
|
|
21490
|
+
this._programmaticFilterRefresh = false;
|
|
21491
|
+
}
|
|
21550
21492
|
}
|
|
21551
21493
|
|
|
21552
21494
|
if (changedProperties.has('error')) {
|
|
@@ -21688,10 +21630,10 @@ class AuroCombobox extends AuroElement {
|
|
|
21688
21630
|
shape="${this.shape}"
|
|
21689
21631
|
size="${this.size}">
|
|
21690
21632
|
<${this.inputTag}
|
|
21691
|
-
@input="${this.
|
|
21633
|
+
@input="${this.handleTriggerInputValueChange}"
|
|
21692
21634
|
appearance="${this.onDark ? 'inverse' : this.appearance}"
|
|
21693
21635
|
.a11yActivedescendant="${this.dropdownOpen && this.optionActive ? this.optionActive.id : undefined}"
|
|
21694
|
-
.a11yExpanded="${this.
|
|
21636
|
+
.a11yExpanded="${this.dropdownOpen}"
|
|
21695
21637
|
.a11yControls="${this.dropdownId}"
|
|
21696
21638
|
.autocomplete="${this.autocomplete}"
|
|
21697
21639
|
.inputmode="${this.inputmode}"
|