@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
|
@@ -485,15 +485,17 @@ let AuroFormValidation$1 = class AuroFormValidation {
|
|
|
485
485
|
);
|
|
486
486
|
}
|
|
487
487
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
488
|
+
const isCombobox = this.runtimeUtils.elementMatch(elem, 'auro-combobox');
|
|
489
|
+
|
|
490
|
+
// If there is a second input in the elem and that value is undefined or an empty string set hasValue to false.
|
|
491
|
+
// Skip for combobox: its second auro-input is the fullscreen-bib mirror of the same value, not an independent
|
|
492
|
+
// field (datepicker is the intended consumer — start/end are independently required).
|
|
493
|
+
if (this.auroInputElements?.length === 2 && !isCombobox) {
|
|
494
|
+
if (!this.auroInputElements[1].value || this.auroInputElements[1].value.length === 0) {
|
|
491
495
|
hasValue = false;
|
|
492
496
|
}
|
|
493
497
|
}
|
|
494
498
|
|
|
495
|
-
const isCombobox = this.runtimeUtils.elementMatch(elem, 'auro-combobox');
|
|
496
|
-
|
|
497
499
|
if (isCombobox) {
|
|
498
500
|
|
|
499
501
|
if (!elem.persistInput || elem.behavior === "filter") {
|
|
@@ -810,6 +812,8 @@ function navigateArrow(component, direction, options = {}) {
|
|
|
810
812
|
}
|
|
811
813
|
}
|
|
812
814
|
|
|
815
|
+
/* eslint-disable no-underscore-dangle */
|
|
816
|
+
|
|
813
817
|
/**
|
|
814
818
|
* Returns the clear button element from the active input's shadow
|
|
815
819
|
* DOM, if available.
|
|
@@ -845,11 +849,9 @@ function isClearBtnFocused(ctx, clearBtn = getClearBtn(ctx)) {
|
|
|
845
849
|
* @param {Object} menu - The menu component.
|
|
846
850
|
*/
|
|
847
851
|
function reconcileMenuIndex(menu) {
|
|
848
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
849
852
|
if (menu._index < 0 && menu.optionActive && menu.items) {
|
|
850
853
|
const idx = menu.items.indexOf(menu.optionActive);
|
|
851
854
|
if (idx >= 0) {
|
|
852
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
853
855
|
menu._index = idx;
|
|
854
856
|
}
|
|
855
857
|
}
|
|
@@ -868,11 +870,7 @@ const comboboxKeyboardStrategy = {
|
|
|
868
870
|
|
|
869
871
|
// navigate if bib is open otherwise open it
|
|
870
872
|
if (component.dropdown.isPopoverVisible) {
|
|
871
|
-
|
|
872
|
-
component.activateLastEnabledAvailableOption();
|
|
873
|
-
} else {
|
|
874
|
-
navigateArrow(component, 'down');
|
|
875
|
-
}
|
|
873
|
+
navigateArrow(component, 'down');
|
|
876
874
|
} else {
|
|
877
875
|
component.showBib();
|
|
878
876
|
}
|
|
@@ -891,11 +889,7 @@ const comboboxKeyboardStrategy = {
|
|
|
891
889
|
|
|
892
890
|
// navigate if bib is open otherwise open it
|
|
893
891
|
if (component.dropdown.isPopoverVisible) {
|
|
894
|
-
|
|
895
|
-
component.activateFirstEnabledAvailableOption();
|
|
896
|
-
} else {
|
|
897
|
-
navigateArrow(component, 'up');
|
|
898
|
-
}
|
|
892
|
+
navigateArrow(component, 'up');
|
|
899
893
|
} else {
|
|
900
894
|
component.showBib();
|
|
901
895
|
}
|
|
@@ -911,13 +905,18 @@ const comboboxKeyboardStrategy = {
|
|
|
911
905
|
},
|
|
912
906
|
|
|
913
907
|
Enter(component, evt, ctx) {
|
|
908
|
+
// Forms should not submit on Enter from a combobox, regardless of which
|
|
909
|
+
// child element (input, clear button, menu) is focused.
|
|
910
|
+
evt.stopPropagation();
|
|
911
|
+
|
|
914
912
|
if (isClearBtnFocused(ctx)) {
|
|
915
|
-
//
|
|
916
|
-
//
|
|
917
|
-
//
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
913
|
+
// Let the browser dispatch Enter to the focused clear button so its
|
|
914
|
+
// built-in activation fires and clears the selection. Do NOT call
|
|
915
|
+
// preventDefault — that would block the activation.
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
if (ctx.isExpanded && component.menu.optionActive) {
|
|
921
920
|
reconcileMenuIndex(component.menu);
|
|
922
921
|
component.menu.makeSelection();
|
|
923
922
|
|
|
@@ -926,14 +925,8 @@ const comboboxKeyboardStrategy = {
|
|
|
926
925
|
}
|
|
927
926
|
|
|
928
927
|
evt.preventDefault();
|
|
929
|
-
evt.stopPropagation();
|
|
930
928
|
} else {
|
|
931
|
-
// Prevent the keypress from bubbling to parent containers (e.g., forms)
|
|
932
|
-
// which could interpret Enter as a submit or trigger other unintended behavior.
|
|
933
|
-
// This is safe because showBib() opens the dialog programmatically,
|
|
934
|
-
// not via event propagation.
|
|
935
929
|
evt.preventDefault();
|
|
936
|
-
evt.stopPropagation();
|
|
937
930
|
component.showBib();
|
|
938
931
|
}
|
|
939
932
|
},
|
|
@@ -978,7 +971,7 @@ const comboboxKeyboardStrategy = {
|
|
|
978
971
|
component.setClearBtnFocus();
|
|
979
972
|
}
|
|
980
973
|
}
|
|
981
|
-
}
|
|
974
|
+
}
|
|
982
975
|
};
|
|
983
976
|
|
|
984
977
|
/**
|
|
@@ -4873,7 +4866,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$3 {
|
|
|
4873
4866
|
}
|
|
4874
4867
|
};
|
|
4875
4868
|
|
|
4876
|
-
var formkitVersion$2 = '
|
|
4869
|
+
var formkitVersion$2 = '202607010100';
|
|
4877
4870
|
|
|
4878
4871
|
let AuroElement$2 = class AuroElement extends i$3 {
|
|
4879
4872
|
static get properties() {
|
|
@@ -5824,6 +5817,14 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
5824
5817
|
};
|
|
5825
5818
|
this.addEventListener('keydown', this._bibTabHandler);
|
|
5826
5819
|
|
|
5820
|
+
// Suppress AuroFloatingUI's auto-hide-on-focus-loss while the
|
|
5821
|
+
// desktopModal trap owns focus management. Without this, the very
|
|
5822
|
+
// first focus move into the bib (from the RAF below) triggers
|
|
5823
|
+
// handleFocusLoss → hideBib, tearing down the trap before the
|
|
5824
|
+
// user can press Tab.
|
|
5825
|
+
this._priorNoHideOnFocusLoss = this.noHideOnThisFocusLoss;
|
|
5826
|
+
this.noHideOnThisFocusLoss = true;
|
|
5827
|
+
|
|
5827
5828
|
// Move initial focus into the bib content, matching FocusTrap behavior
|
|
5828
5829
|
requestAnimationFrame(() => {
|
|
5829
5830
|
const focusables = getFocusableElements(this.bibContent);
|
|
@@ -6137,6 +6138,7 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
6137
6138
|
role="${o(this.triggerContentFocusable ? undefined : this.a11yRole)}"
|
|
6138
6139
|
aria-expanded="${o(this.a11yRole === 'button' || this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
|
|
6139
6140
|
aria-controls="${o(this.a11yRole === 'button' || this.triggerContentFocusable ? undefined : this.dropdownId)}"
|
|
6141
|
+
aria-haspopup="${o(this.a11yRole === 'combobox' && !this.triggerContentFocusable ? 'listbox' : undefined)}"
|
|
6140
6142
|
aria-labelledby="${o(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
|
|
6141
6143
|
aria-disabled="${o(this.disabled ? 'true' : undefined)}"
|
|
6142
6144
|
@focusin="${this.handleFocusin}"
|
|
@@ -10646,15 +10648,17 @@ class AuroFormValidation {
|
|
|
10646
10648
|
);
|
|
10647
10649
|
}
|
|
10648
10650
|
|
|
10649
|
-
|
|
10650
|
-
|
|
10651
|
-
|
|
10651
|
+
const isCombobox = this.runtimeUtils.elementMatch(elem, 'auro-combobox');
|
|
10652
|
+
|
|
10653
|
+
// If there is a second input in the elem and that value is undefined or an empty string set hasValue to false.
|
|
10654
|
+
// Skip for combobox: its second auro-input is the fullscreen-bib mirror of the same value, not an independent
|
|
10655
|
+
// field (datepicker is the intended consumer — start/end are independently required).
|
|
10656
|
+
if (this.auroInputElements?.length === 2 && !isCombobox) {
|
|
10657
|
+
if (!this.auroInputElements[1].value || this.auroInputElements[1].value.length === 0) {
|
|
10652
10658
|
hasValue = false;
|
|
10653
10659
|
}
|
|
10654
10660
|
}
|
|
10655
10661
|
|
|
10656
|
-
const isCombobox = this.runtimeUtils.elementMatch(elem, 'auro-combobox');
|
|
10657
|
-
|
|
10658
10662
|
if (isCombobox) {
|
|
10659
10663
|
|
|
10660
10664
|
if (!elem.persistInput || elem.behavior === "filter") {
|
|
@@ -16590,10 +16594,18 @@ class AuroInputUtilities {
|
|
|
16590
16594
|
* @returns {string | undefined}
|
|
16591
16595
|
*/
|
|
16592
16596
|
toFormattedValue(valueObject, format) {
|
|
16597
|
+
// Exposed publicly via `AuroInputUtil.toFormattedValue`, so a missing
|
|
16598
|
+
// `format` argument has to fail gracefully rather than throw on
|
|
16599
|
+
// `format.toLowerCase()`. Treat any falsy value (undefined, null, '')
|
|
16600
|
+
// as "no format → no display value".
|
|
16601
|
+
if (!format) {
|
|
16602
|
+
return undefined;
|
|
16603
|
+
}
|
|
16593
16604
|
const normalizedFormat = format.toLowerCase();
|
|
16594
16605
|
const maskOptions = this.getMaskOptions('date', normalizedFormat);
|
|
16595
16606
|
|
|
16596
16607
|
if (!(valueObject instanceof Date) || Number.isNaN(valueObject.getTime()) || !maskOptions || typeof maskOptions.format !== 'function') {
|
|
16608
|
+
console.debug('Invalid date object or mask options for formatting', { valueObject, maskOptions }); // eslint-disable-line no-console
|
|
16597
16609
|
return undefined;
|
|
16598
16610
|
}
|
|
16599
16611
|
|
|
@@ -16740,79 +16752,19 @@ class BaseInput extends AuroElement$1 {
|
|
|
16740
16752
|
constructor() {
|
|
16741
16753
|
super();
|
|
16742
16754
|
|
|
16743
|
-
|
|
16744
|
-
|
|
16745
|
-
|
|
16746
|
-
|
|
16747
|
-
|
|
16748
|
-
|
|
16749
|
-
|
|
16750
|
-
|
|
16751
|
-
|
|
16752
|
-
|
|
16753
|
-
this.required = false;
|
|
16754
|
-
this.onDark = false;
|
|
16755
|
-
this.setCustomValidityForType = undefined;
|
|
16756
|
-
this.size = 'lg';
|
|
16757
|
-
this.shape = 'classic';
|
|
16758
|
-
this.value = undefined;
|
|
16759
|
-
this._valueObject = undefined;
|
|
16760
|
-
|
|
16761
|
-
this._initializePrivateDefaults();
|
|
16762
|
-
}
|
|
16763
|
-
|
|
16764
|
-
/**
|
|
16765
|
-
* Internal Defaults.
|
|
16766
|
-
* @private
|
|
16767
|
-
* @returns {void}
|
|
16768
|
-
*/
|
|
16769
|
-
_initializePrivateDefaults() {
|
|
16755
|
+
// Single-source initialization. Alphabetized so duplicate or stale
|
|
16756
|
+
// defaults are immediately obvious on a diff. Every field is assigned
|
|
16757
|
+
// exactly once here (previously the constructor + the old
|
|
16758
|
+
// `_initializePrivateDefaults` overlapped — both wrote ~14 of the same
|
|
16759
|
+
// fields and double-allocated `util` and `validation`, discarding the
|
|
16760
|
+
// first instance). `validation` is now allocated exactly once; `util`
|
|
16761
|
+
// is seeded here with an en-US default and then rebuilt in
|
|
16762
|
+
// `connectedCallback` once the consumer-resolved locale is available,
|
|
16763
|
+
// so a parent (datepicker/combobox) calling `validate()` synchronously
|
|
16764
|
+
// during its own update cycle sees a populated util instance.
|
|
16770
16765
|
this.activeLabel = false;
|
|
16771
|
-
this.appearance = "default";
|
|
16772
|
-
this.icon = false;
|
|
16773
|
-
this.disabled = false;
|
|
16774
|
-
this.dvInputOnly = false;
|
|
16775
|
-
this.hideLabelVisually = false;
|
|
16776
|
-
this.max = undefined;
|
|
16777
|
-
this.maxLength = undefined;
|
|
16778
|
-
this.min = undefined;
|
|
16779
|
-
this.minLength = undefined;
|
|
16780
|
-
this.noValidate = false;
|
|
16781
|
-
this.onDark = false;
|
|
16782
|
-
this.required = false;
|
|
16783
|
-
this.setCustomValidityForType = undefined;
|
|
16784
|
-
|
|
16785
|
-
// Used for storing raw values returned from input mask.
|
|
16786
|
-
this._rawMaskValue = undefined;
|
|
16787
|
-
|
|
16788
|
-
/**
|
|
16789
|
-
* @private
|
|
16790
|
-
*/
|
|
16791
|
-
this.layout = 'classic';
|
|
16792
|
-
|
|
16793
|
-
/**
|
|
16794
|
-
* @private
|
|
16795
|
-
*/
|
|
16796
|
-
this.shape = 'classic';
|
|
16797
|
-
|
|
16798
|
-
/**
|
|
16799
|
-
* @private
|
|
16800
|
-
*/
|
|
16801
|
-
this.size = 'lg';
|
|
16802
|
-
|
|
16803
|
-
this.touched = false;
|
|
16804
|
-
this.util = new AuroInputUtilities({
|
|
16805
|
-
locale: "en-US",
|
|
16806
|
-
format: this.format
|
|
16807
|
-
});
|
|
16808
|
-
this.validation = new AuroFormValidation();
|
|
16809
|
-
this.inputIconName = undefined;
|
|
16810
|
-
this.showPassword = false;
|
|
16811
|
-
this.validationCCLength = undefined;
|
|
16812
|
-
this.hasValue = false;
|
|
16813
|
-
this.label = 'Input label is undefined';
|
|
16814
|
-
|
|
16815
16766
|
|
|
16767
|
+
/** @private */
|
|
16816
16768
|
this.allowedInputTypes = [
|
|
16817
16769
|
"text",
|
|
16818
16770
|
"number",
|
|
@@ -16821,7 +16773,9 @@ class BaseInput extends AuroElement$1 {
|
|
|
16821
16773
|
"credit-card",
|
|
16822
16774
|
"tel"
|
|
16823
16775
|
];
|
|
16824
|
-
this.
|
|
16776
|
+
this.appearance = "default";
|
|
16777
|
+
|
|
16778
|
+
/** @private */
|
|
16825
16779
|
this.dateFormatMap = {
|
|
16826
16780
|
'mm/dd/yyyy': 'dateMMDDYYYY',
|
|
16827
16781
|
'dd/mm/yyyy': 'dateDDMMYYYY',
|
|
@@ -16838,27 +16792,62 @@ class BaseInput extends AuroElement$1 {
|
|
|
16838
16792
|
'dd/mm': 'dateDDMM',
|
|
16839
16793
|
'mm/dd': 'dateMMDD'
|
|
16840
16794
|
};
|
|
16795
|
+
this.disabled = false;
|
|
16796
|
+
|
|
16797
|
+
/** @private */
|
|
16841
16798
|
this.domHandler = new DomHandler();
|
|
16842
16799
|
this.dvInputOnly = false;
|
|
16843
16800
|
this.hasValue = false;
|
|
16801
|
+
this.hideLabelVisually = false;
|
|
16802
|
+
this.icon = false;
|
|
16803
|
+
|
|
16804
|
+
/** @private */
|
|
16844
16805
|
this.inputIconName = undefined;
|
|
16806
|
+
|
|
16807
|
+
/** @private */
|
|
16845
16808
|
this.label = 'Input label is undefined';
|
|
16809
|
+
this.layout = 'classic';
|
|
16810
|
+
this.locale = 'en-US';
|
|
16811
|
+
this.max = undefined;
|
|
16812
|
+
this.maxLength = undefined;
|
|
16813
|
+
this.min = undefined;
|
|
16814
|
+
this.minLength = undefined;
|
|
16846
16815
|
this.noValidate = false;
|
|
16847
|
-
this.
|
|
16816
|
+
this.onDark = false;
|
|
16817
|
+
// Raw values returned from the input mask before model normalization.
|
|
16818
|
+
this._rawMaskValue = undefined;
|
|
16819
|
+
this.required = false;
|
|
16820
|
+
this.setCustomValidityForType = undefined;
|
|
16821
|
+
// Credit Card is intentionally excluded — its mask manages the cursor
|
|
16822
|
+
// itself, and listing it here caused cursor placement issues in Safari.
|
|
16823
|
+
/** @private */
|
|
16848
16824
|
this.setSelectionInputTypes = [
|
|
16849
16825
|
"text",
|
|
16850
16826
|
"password",
|
|
16851
16827
|
"email"
|
|
16852
|
-
];
|
|
16828
|
+
];
|
|
16829
|
+
this.shape = 'classic';
|
|
16830
|
+
|
|
16831
|
+
/** @private */
|
|
16853
16832
|
this.showPassword = false;
|
|
16833
|
+
this.size = 'lg';
|
|
16854
16834
|
this.touched = false;
|
|
16835
|
+
|
|
16836
|
+
/** @private */
|
|
16855
16837
|
this.uniqueId = new UniqueId().create();
|
|
16838
|
+
|
|
16839
|
+
/** @private */
|
|
16856
16840
|
this.util = new AuroInputUtilities({
|
|
16857
16841
|
locale: this.locale,
|
|
16858
16842
|
format: this.format
|
|
16859
16843
|
});
|
|
16844
|
+
|
|
16845
|
+
/** @private */
|
|
16860
16846
|
this.validation = new AuroFormValidation();
|
|
16847
|
+
|
|
16848
|
+
/** @private */
|
|
16861
16849
|
this.validationCCLength = undefined;
|
|
16850
|
+
this.value = undefined;
|
|
16862
16851
|
}
|
|
16863
16852
|
|
|
16864
16853
|
// function to define props used within the scope of this component
|
|
@@ -17296,7 +17285,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17296
17285
|
* @returns {Date|undefined}
|
|
17297
17286
|
*/
|
|
17298
17287
|
get valueObject() {
|
|
17299
|
-
return this.
|
|
17288
|
+
return this.value && dateFormatter.isValidDate(this.value) ? dateFormatter.stringToDateInstance(this.value) : undefined;
|
|
17300
17289
|
}
|
|
17301
17290
|
|
|
17302
17291
|
/**
|
|
@@ -17304,7 +17293,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17304
17293
|
* @returns {Date|undefined}
|
|
17305
17294
|
*/
|
|
17306
17295
|
get minObject() {
|
|
17307
|
-
return this.
|
|
17296
|
+
return this.min && dateFormatter.isValidDate(this.min) ? dateFormatter.stringToDateInstance(this.min) : undefined;
|
|
17308
17297
|
}
|
|
17309
17298
|
|
|
17310
17299
|
/**
|
|
@@ -17312,50 +17301,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17312
17301
|
* @returns {Date|undefined}
|
|
17313
17302
|
*/
|
|
17314
17303
|
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);
|
|
17304
|
+
return this.max && dateFormatter.isValidDate(this.max) ? dateFormatter.stringToDateInstance(this.max) : undefined;
|
|
17359
17305
|
}
|
|
17360
17306
|
|
|
17361
17307
|
connectedCallback() {
|
|
@@ -17384,7 +17330,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17384
17330
|
format: this.format
|
|
17385
17331
|
});
|
|
17386
17332
|
this.configureDataForType();
|
|
17387
|
-
this.syncDateValues();
|
|
17388
17333
|
}
|
|
17389
17334
|
|
|
17390
17335
|
disconnectedCallback() {
|
|
@@ -17404,12 +17349,17 @@ class BaseInput extends AuroElement$1 {
|
|
|
17404
17349
|
this.wrapperElement.addEventListener('click', this.handleClick);
|
|
17405
17350
|
}
|
|
17406
17351
|
|
|
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
17352
|
this.inputId = this.id ? `${this.id}-input` : window.crypto.randomUUID();
|
|
17412
17353
|
|
|
17354
|
+
// Normalize the format token to lowercase so case-mixed values supplied
|
|
17355
|
+
// via attribute (e.g. `format="MM/DD/YYYY"`) hit the `dateFormatMap`
|
|
17356
|
+
// lookup inside `setCustomHelpTextMessage`. Without this, an uppercase
|
|
17357
|
+
// format silently misses the map and leaves `setCustomValidityForType`
|
|
17358
|
+
// unset.
|
|
17359
|
+
if (this.format) {
|
|
17360
|
+
this.format = this.format.toLowerCase();
|
|
17361
|
+
}
|
|
17362
|
+
|
|
17413
17363
|
// use validity message override if declared when initializing the component
|
|
17414
17364
|
if (this.hasAttribute('setCustomValidity')) {
|
|
17415
17365
|
this.ValidityMessageOverride = this.setCustomValidity;
|
|
@@ -17418,7 +17368,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17418
17368
|
this.setCustomHelpTextMessage();
|
|
17419
17369
|
this.configureAutoFormatting();
|
|
17420
17370
|
this.configureDataForType();
|
|
17421
|
-
this.syncDateValues();
|
|
17422
17371
|
}
|
|
17423
17372
|
|
|
17424
17373
|
/**
|
|
@@ -17494,6 +17443,13 @@ class BaseInput extends AuroElement$1 {
|
|
|
17494
17443
|
|
|
17495
17444
|
if (typeToI18n.includes(this.type)) {
|
|
17496
17445
|
this.setCustomValidityForType = i18n(this.lang, this.type);
|
|
17446
|
+
// COVERAGE: this `else if` branch is unreachable in WTR. connectedCallback
|
|
17447
|
+
// (L682) calls configureDataForType, which at L1266-1268 assigns
|
|
17448
|
+
// `this.format = this.util.getDateMaskFromLocale().toLowerCase()` for any
|
|
17449
|
+
// type=date input whose `format` attribute is unset. That runs before
|
|
17450
|
+
// firstUpdated invokes setCustomHelpTextMessage, so `!this.format` is
|
|
17451
|
+
// always false here. Retained as a defensive fallback; the whole function
|
|
17452
|
+
// is @deprecated per AB#1557296 and slated for removal.
|
|
17497
17453
|
} else if (!this.format && this.type === 'date') {
|
|
17498
17454
|
this.setCustomValidityForType = i18n(this.lang, 'dateMMDDYYYY');
|
|
17499
17455
|
} else if (this.dateFormatMap[this.format]) {
|
|
@@ -17555,8 +17511,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17555
17511
|
this.configureDataForType();
|
|
17556
17512
|
}
|
|
17557
17513
|
|
|
17558
|
-
this.syncDateValues(changedProperties);
|
|
17559
|
-
|
|
17560
17514
|
if (changedProperties.has('value')) {
|
|
17561
17515
|
if (this.value && this.value.length > 0) {
|
|
17562
17516
|
this.hasValue = true;
|
|
@@ -17578,14 +17532,14 @@ class BaseInput extends AuroElement$1 {
|
|
|
17578
17532
|
|
|
17579
17533
|
if (formattedValue !== this.inputElement.value) {
|
|
17580
17534
|
this.skipNextProgrammaticInputEvent = true;
|
|
17581
|
-
if (this.maskInstance && this.type
|
|
17535
|
+
if (this.maskInstance && this.type !== 'date') {
|
|
17582
17536
|
// Route through the mask so its _value and el.value stay in lock-step
|
|
17583
17537
|
// (set value calls updateControl which writes el.value = displayValue).
|
|
17584
17538
|
// Writing el.value directly leaves the mask thinking displayValue is
|
|
17585
|
-
// stale; _saveSelection on the next focus/click then warns.
|
|
17586
|
-
//
|
|
17587
|
-
//
|
|
17588
|
-
//
|
|
17539
|
+
// stale; _saveSelection on the next focus/click then warns. Date is
|
|
17540
|
+
// excluded because its formattedValue can be raw ISO when the calendar
|
|
17541
|
+
// is invalid, and re-masking through mm/dd/yyyy would truncate it and
|
|
17542
|
+
// flip validity from patternMismatch to tooShort.
|
|
17589
17543
|
this.maskInstance.value = formattedValue || '';
|
|
17590
17544
|
} else if (formattedValue) {
|
|
17591
17545
|
this.inputElement.value = formattedValue;
|
|
@@ -17627,120 +17581,65 @@ class BaseInput extends AuroElement$1 {
|
|
|
17627
17581
|
}));
|
|
17628
17582
|
}
|
|
17629
17583
|
|
|
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
17584
|
/**
|
|
17694
17585
|
* Sets up IMasks and logic based on auto-formatting requirements.
|
|
17695
17586
|
* @private
|
|
17696
17587
|
* @returns {void}
|
|
17697
17588
|
*/
|
|
17698
17589
|
configureAutoFormatting() {
|
|
17699
|
-
//
|
|
17700
|
-
//
|
|
17701
|
-
//
|
|
17702
|
-
//
|
|
17590
|
+
// _configuringMask gates two things: external re-entry into this method
|
|
17591
|
+
// while setup is mid-flight (from property changes that call back here),
|
|
17592
|
+
// and the accept/complete listeners below — both need to ignore the mask
|
|
17593
|
+
// events fired by our own value-restore step.
|
|
17703
17594
|
if (this._configuringMask) return;
|
|
17704
17595
|
this._configuringMask = true;
|
|
17705
17596
|
try {
|
|
17597
|
+
// Destroy any prior mask so IMask can attach fresh under the new format.
|
|
17598
|
+
// Null the reference too — if the new maskOptions.mask is falsy (e.g.
|
|
17599
|
+
// type switched from credit-card to text) the IMask() reassignment
|
|
17600
|
+
// below is skipped, and downstream writes at line ~823 would otherwise
|
|
17601
|
+
// route through the destroyed instance.
|
|
17706
17602
|
if (this.maskInstance) {
|
|
17707
17603
|
this.maskInstance.destroy();
|
|
17604
|
+
this.maskInstance = null;
|
|
17708
17605
|
}
|
|
17709
17606
|
|
|
17710
|
-
// Pass new format to util
|
|
17711
17607
|
this.util.updateFormat(this.format);
|
|
17712
17608
|
|
|
17713
17609
|
const maskOptions = this.util.getMaskOptions(this.type, this.format);
|
|
17714
17610
|
|
|
17715
17611
|
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.
|
|
17612
|
+
// Capture the current display so it can be re-applied after IMask
|
|
17613
|
+
// attaches. The restore at the bottom goes through maskInstance.value
|
|
17614
|
+
// (not inputElement.value directly) so the mask's internal state and
|
|
17615
|
+
// the input's displayed text stay in lock-step.
|
|
17723
17616
|
let existingValue = this.inputElement.value;
|
|
17617
|
+
|
|
17618
|
+
// Format-change case (e.g. locale switch): existingValue is the OLD
|
|
17619
|
+
// mask's display string and may not parse under the new mask. When
|
|
17620
|
+
// we have a valid date model, rebuild the display from valueObject
|
|
17621
|
+
// (the canonical source) using the new mask's format function.
|
|
17724
17622
|
if (
|
|
17725
17623
|
this.util.isFullDateFormat(this.type, this.format) &&
|
|
17726
17624
|
this.value &&
|
|
17727
|
-
|
|
17728
|
-
this.valueObject instanceof Date &&
|
|
17729
|
-
!Number.isNaN(this.valueObject.getTime()) &&
|
|
17625
|
+
this.valueObject &&
|
|
17730
17626
|
typeof maskOptions.format === 'function'
|
|
17731
17627
|
) {
|
|
17732
17628
|
existingValue = maskOptions.format(this.valueObject);
|
|
17733
17629
|
}
|
|
17734
17630
|
|
|
17631
|
+
// Clear before IMask attaches so the constructor seeds an empty
|
|
17632
|
+
// internal value. Otherwise IMask reads the stale unmasked string
|
|
17633
|
+
// and emits a spurious 'accept' before the restore below runs.
|
|
17735
17634
|
this.skipNextProgrammaticInputEvent = true;
|
|
17736
17635
|
this.inputElement.value = '';
|
|
17737
17636
|
|
|
17738
17637
|
this.maskInstance = IMask(this.inputElement, maskOptions);
|
|
17739
17638
|
|
|
17639
|
+
// Mask fires 'accept' on every value change, including the restore
|
|
17640
|
+
// step below. Skip events fired during configureAutoFormatting so
|
|
17641
|
+
// we don't overwrite a value the parent just pushed.
|
|
17740
17642
|
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
17643
|
if (this._configuringMask) return;
|
|
17745
17644
|
this.value = this.util.toModelValue(this.maskInstance.value, this.format);
|
|
17746
17645
|
if (this.type === "date") {
|
|
@@ -17748,6 +17647,8 @@ class BaseInput extends AuroElement$1 {
|
|
|
17748
17647
|
}
|
|
17749
17648
|
});
|
|
17750
17649
|
|
|
17650
|
+
// Mask fires 'complete' on the restore step below for any value that
|
|
17651
|
+
// happens to be a complete match. Same setup-suppression as 'accept'.
|
|
17751
17652
|
this.maskInstance.on('complete', () => {
|
|
17752
17653
|
if (this._configuringMask) return;
|
|
17753
17654
|
this.value = this.util.toModelValue(this.maskInstance.value, this.format);
|
|
@@ -17756,7 +17657,9 @@ class BaseInput extends AuroElement$1 {
|
|
|
17756
17657
|
}
|
|
17757
17658
|
});
|
|
17758
17659
|
|
|
17759
|
-
//
|
|
17660
|
+
// Write existingValue through the mask (not the input directly) so
|
|
17661
|
+
// the mask reformats it under the new rules and keeps its internal
|
|
17662
|
+
// _value aligned with the input's displayed text.
|
|
17760
17663
|
if (existingValue) {
|
|
17761
17664
|
this.maskInstance.value = existingValue;
|
|
17762
17665
|
}
|
|
@@ -17836,6 +17739,38 @@ class BaseInput extends AuroElement$1 {
|
|
|
17836
17739
|
this.touched = true;
|
|
17837
17740
|
this.validation.validate(this);
|
|
17838
17741
|
}
|
|
17742
|
+
|
|
17743
|
+
// Prevents cursor jumping in Safari. Setting `this.value` triggers a Lit
|
|
17744
|
+
// update that can re-render the input and reset the native cursor; we
|
|
17745
|
+
// capture the caret position before that update commits and restore it
|
|
17746
|
+
// via `setSelectionRange` once the update has flushed. Gated on
|
|
17747
|
+
// `setSelectionInputTypes` so credit-card (and other masked types whose
|
|
17748
|
+
// formatter manages the cursor itself) doesn't get a competing write.
|
|
17749
|
+
// Capture the caret position INSIDE the gate — reading `selectionStart`
|
|
17750
|
+
// on input types that don't support text selection (number, email in
|
|
17751
|
+
// some browsers) throws InvalidStateError, which would crash all input
|
|
17752
|
+
// handling. Wrap the read in try/catch belt-and-suspenders even though
|
|
17753
|
+
// the gated types currently support it, since the list is a public
|
|
17754
|
+
// property a consumer could mutate.
|
|
17755
|
+
if (this.setSelectionInputTypes.includes(this.type)) {
|
|
17756
|
+
let selectionStart = null;
|
|
17757
|
+
try {
|
|
17758
|
+
({ selectionStart } = this.inputElement);
|
|
17759
|
+
} catch (error) { // eslint-disable-line no-unused-vars
|
|
17760
|
+
return;
|
|
17761
|
+
}
|
|
17762
|
+
if (typeof selectionStart !== 'number') {
|
|
17763
|
+
return;
|
|
17764
|
+
}
|
|
17765
|
+
this.updateComplete.then(() => {
|
|
17766
|
+
try {
|
|
17767
|
+
this.inputElement.setSelectionRange(selectionStart, selectionStart);
|
|
17768
|
+
} catch (error) { // eslint-disable-line no-unused-vars
|
|
17769
|
+
// Some input types (number/email in certain UAs) throw on
|
|
17770
|
+
// setSelectionRange; swallow and let the native cursor stand.
|
|
17771
|
+
}
|
|
17772
|
+
});
|
|
17773
|
+
}
|
|
17839
17774
|
}
|
|
17840
17775
|
|
|
17841
17776
|
/**
|
|
@@ -17924,7 +17859,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17924
17859
|
*/
|
|
17925
17860
|
reset() {
|
|
17926
17861
|
this.value = undefined;
|
|
17927
|
-
this.setDateObjectProperty('valueObject', undefined);
|
|
17928
17862
|
this.validation.reset(this);
|
|
17929
17863
|
}
|
|
17930
17864
|
|
|
@@ -17933,7 +17867,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17933
17867
|
*/
|
|
17934
17868
|
clear() {
|
|
17935
17869
|
this.value = undefined;
|
|
17936
|
-
this.setDateObjectProperty('valueObject', undefined);
|
|
17937
17870
|
}
|
|
17938
17871
|
|
|
17939
17872
|
/**
|
|
@@ -17971,7 +17904,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17971
17904
|
*/
|
|
17972
17905
|
get placeholderStr() {
|
|
17973
17906
|
if (!this.placeholder && this.type === 'date') {
|
|
17974
|
-
return this.format
|
|
17907
|
+
return this.format.toUpperCase();
|
|
17975
17908
|
}
|
|
17976
17909
|
return this.placeholder || "";
|
|
17977
17910
|
}
|
|
@@ -18462,7 +18395,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$3 {
|
|
|
18462
18395
|
}
|
|
18463
18396
|
};
|
|
18464
18397
|
|
|
18465
|
-
var formkitVersion$1 = '
|
|
18398
|
+
var formkitVersion$1 = '202607010100';
|
|
18466
18399
|
|
|
18467
18400
|
// Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
18468
18401
|
// See LICENSE in the project root for license information.
|
|
@@ -18965,6 +18898,7 @@ class AuroInput extends BaseInput {
|
|
|
18965
18898
|
<${this.buttonTag}
|
|
18966
18899
|
@click="${this.handleClickShowPassword}"
|
|
18967
18900
|
appearance="${this.onDark ? 'inverse' : this.appearance}"
|
|
18901
|
+
aria-pressed="${this.showPassword ? 'true' : 'false'}"
|
|
18968
18902
|
class="notificationBtn passwordBtn"
|
|
18969
18903
|
shape="circle"
|
|
18970
18904
|
size="sm"
|
|
@@ -19038,25 +18972,29 @@ class AuroInput extends BaseInput {
|
|
|
19038
18972
|
* @returns {html} - Returns HTML for the help text and error message.
|
|
19039
18973
|
*/
|
|
19040
18974
|
renderHtmlHelpText() {
|
|
18975
|
+
// Single `<p>` with stable identity across validity transitions —
|
|
18976
|
+
// previously two distinct templates (valid vs invalid) caused Lit to
|
|
18977
|
+
// replace the node entirely on a flip, and VoiceOver wouldn't
|
|
18978
|
+
// re-announce because the live-region element it was watching had been
|
|
18979
|
+
// removed and a new one inserted. Keeping one node means the `role`,
|
|
18980
|
+
// `aria-live`, and text content all change in-place, which AT does
|
|
18981
|
+
// observe and announce.
|
|
18982
|
+
const isError = this.validity && this.validity !== 'valid';
|
|
19041
18983
|
return u$7`
|
|
19042
|
-
|
|
19043
|
-
?
|
|
19044
|
-
|
|
19045
|
-
|
|
19046
|
-
|
|
19047
|
-
|
|
19048
|
-
|
|
19049
|
-
|
|
19050
|
-
|
|
19051
|
-
|
|
19052
|
-
|
|
19053
|
-
|
|
19054
|
-
|
|
19055
|
-
|
|
19056
|
-
</p>
|
|
19057
|
-
</${this.helpTextTag}>
|
|
19058
|
-
`
|
|
19059
|
-
}
|
|
18984
|
+
<${this.helpTextTag}
|
|
18985
|
+
appearance="${this.onDark ? 'inverse' : this.appearance}"
|
|
18986
|
+
?error=${isError}>
|
|
18987
|
+
<p
|
|
18988
|
+
id="${this.uniqueId}"
|
|
18989
|
+
part="helpText"
|
|
18990
|
+
role="${o(isError ? 'alert' : undefined)}"
|
|
18991
|
+
aria-live="${o(isError ? 'assertive' : undefined)}">
|
|
18992
|
+
${isError
|
|
18993
|
+
? this.errorMessage
|
|
18994
|
+
: u$7`<slot name="helpText">${this.getHelpText()}</slot>`
|
|
18995
|
+
}
|
|
18996
|
+
</p>
|
|
18997
|
+
</${this.helpTextTag}>
|
|
19060
18998
|
`;
|
|
19061
18999
|
}
|
|
19062
19000
|
|
|
@@ -19188,7 +19126,7 @@ class AuroInput extends BaseInput {
|
|
|
19188
19126
|
|
|
19189
19127
|
var colorCss$3 = i$6`#headerContainer{box-shadow:var(--ds-auro-dropdownbib-header-boxshadow-color)}#footerContainer{background-color:var(--ds-auro-dropdownbib-footer-container-color)}`;
|
|
19190
19128
|
|
|
19191
|
-
var styleCss$4 = i$6`#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
|
|
19129
|
+
var styleCss$4 = i$6`#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)}`;
|
|
19192
19130
|
|
|
19193
19131
|
var tokenCss = i$6`: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)}`;
|
|
19194
19132
|
|
|
@@ -19583,7 +19521,7 @@ class AuroBibtemplate extends i$3 {
|
|
|
19583
19521
|
}
|
|
19584
19522
|
}
|
|
19585
19523
|
|
|
19586
|
-
var formkitVersion = '
|
|
19524
|
+
var formkitVersion = '202607010100';
|
|
19587
19525
|
|
|
19588
19526
|
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
19527
|
|
|
@@ -19951,12 +19889,23 @@ function getOptionLabel(option) {
|
|
|
19951
19889
|
if (!option) {
|
|
19952
19890
|
return '';
|
|
19953
19891
|
}
|
|
19954
|
-
|
|
19955
|
-
|
|
19956
|
-
if (
|
|
19957
|
-
|
|
19892
|
+
|
|
19893
|
+
// Consumer-provided override: short-circuit the DOM walk entirely.
|
|
19894
|
+
if (option.dataset && option.dataset.label) {
|
|
19895
|
+
return option.dataset.label;
|
|
19896
|
+
}
|
|
19897
|
+
|
|
19898
|
+
// Walk direct children — the `slot` attribute only applies to direct children
|
|
19899
|
+
// of the slot host, so a shallow filter is sufficient. Avoids the cloneNode +
|
|
19900
|
+
// querySelector allocation that ran on every keystroke via syncValuesAndStates.
|
|
19901
|
+
let text = '';
|
|
19902
|
+
for (const node of option.childNodes) {
|
|
19903
|
+
const isDisplayValueSlot = node.nodeType === Node.ELEMENT_NODE && node.getAttribute('slot') === 'displayValue';
|
|
19904
|
+
if (!isDisplayValueSlot) {
|
|
19905
|
+
text += node.textContent || '';
|
|
19906
|
+
}
|
|
19958
19907
|
}
|
|
19959
|
-
return
|
|
19908
|
+
return text.replace(/\s+/gu, ' ').trim();
|
|
19960
19909
|
}
|
|
19961
19910
|
|
|
19962
19911
|
// See https://git.io/JJ6SJ for "How to document your components using JSDoc"
|
|
@@ -20031,8 +19980,6 @@ class AuroCombobox extends AuroElement {
|
|
|
20031
19980
|
this.availableOptions = [];
|
|
20032
19981
|
this.dropdownId = undefined;
|
|
20033
19982
|
this.dropdownOpen = false;
|
|
20034
|
-
this.triggerExpandedState = false;
|
|
20035
|
-
this._expandedTimeout = null;
|
|
20036
19983
|
this._inFullscreenTransition = false;
|
|
20037
19984
|
this.errorMessage = null;
|
|
20038
19985
|
this.isHiddenWhileLoading = false;
|
|
@@ -20043,6 +19990,30 @@ class AuroCombobox extends AuroElement {
|
|
|
20043
19990
|
this.touched = false;
|
|
20044
19991
|
this.validation = new AuroFormValidation$1();
|
|
20045
19992
|
this.validity = undefined;
|
|
19993
|
+
this._userTyped = false;
|
|
19994
|
+
// Tracks every setTimeout scheduled via _scheduleTimer so
|
|
19995
|
+
// disconnectedCallback can cancel them. Without this, a detached
|
|
19996
|
+
// combobox's pending timers still fire — most are no-ops, but
|
|
19997
|
+
// configureMenu's racing-condition retry would otherwise loop.
|
|
19998
|
+
this._pendingTimers = new Set();
|
|
19999
|
+
}
|
|
20000
|
+
|
|
20001
|
+
/**
|
|
20002
|
+
* setTimeout wrapper that records the timer id so disconnectedCallback
|
|
20003
|
+
* can cancel any outstanding callbacks. The id is removed from the set
|
|
20004
|
+
* once the callback fires so the set doesn't grow unbounded.
|
|
20005
|
+
* @param {Function} fn - Callback to run.
|
|
20006
|
+
* @param {number} ms - Delay in milliseconds.
|
|
20007
|
+
* @returns {number} The timer id.
|
|
20008
|
+
* @private
|
|
20009
|
+
*/
|
|
20010
|
+
_scheduleTimer(fn, ms) {
|
|
20011
|
+
const id = setTimeout(() => {
|
|
20012
|
+
this._pendingTimers.delete(id);
|
|
20013
|
+
fn();
|
|
20014
|
+
}, ms);
|
|
20015
|
+
this._pendingTimers.add(id);
|
|
20016
|
+
return id;
|
|
20046
20017
|
}
|
|
20047
20018
|
|
|
20048
20019
|
// This function is to define props used within the scope of this component
|
|
@@ -20404,17 +20375,6 @@ class AuroCombobox extends AuroElement {
|
|
|
20404
20375
|
attribute: false
|
|
20405
20376
|
},
|
|
20406
20377
|
|
|
20407
|
-
/**
|
|
20408
|
-
* Deferred aria-expanded state for the trigger input.
|
|
20409
|
-
* Delays the "true" transition so VoiceOver finishes its character echo
|
|
20410
|
-
* before announcing "expanded".
|
|
20411
|
-
* @private
|
|
20412
|
-
*/
|
|
20413
|
-
triggerExpandedState: {
|
|
20414
|
-
type: Boolean,
|
|
20415
|
-
reflect: false,
|
|
20416
|
-
attribute: false
|
|
20417
|
-
},
|
|
20418
20378
|
};
|
|
20419
20379
|
}
|
|
20420
20380
|
|
|
@@ -20437,13 +20397,6 @@ class AuroCombobox extends AuroElement {
|
|
|
20437
20397
|
return this.input.value;
|
|
20438
20398
|
}
|
|
20439
20399
|
|
|
20440
|
-
// /**
|
|
20441
|
-
// * Sets the value of the input element within the combobox.
|
|
20442
|
-
// */
|
|
20443
|
-
// set inputValue(value) {
|
|
20444
|
-
// this.input.value = value;
|
|
20445
|
-
// }
|
|
20446
|
-
|
|
20447
20400
|
/**
|
|
20448
20401
|
* Checks if the element is valid.
|
|
20449
20402
|
* @returns {boolean} - Returns true if the element is valid, false otherwise.
|
|
@@ -20570,7 +20523,7 @@ class AuroCombobox extends AuroElement {
|
|
|
20570
20523
|
if (this.menu) {
|
|
20571
20524
|
this.menu.matchWord = normalizeFilterValue(this.input.value);
|
|
20572
20525
|
}
|
|
20573
|
-
const label = getOptionLabel(this.menu.optionSelected)
|
|
20526
|
+
const label = getOptionLabel(this.menu.optionSelected);
|
|
20574
20527
|
this.updateTriggerTextDisplay(label || this.value);
|
|
20575
20528
|
}
|
|
20576
20529
|
|
|
@@ -20584,44 +20537,16 @@ class AuroCombobox extends AuroElement {
|
|
|
20584
20537
|
// in suggestion mode, do not override input value if no selection has been made and the input currently has focus
|
|
20585
20538
|
const isInputFocusedWithNoSelection = !this.menu.value && (this.input.matches(':focus-within') || (this.inputInBib && this.inputInBib.matches(':focus-within')));
|
|
20586
20539
|
|
|
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
|
-
}
|
|
20540
|
+
const suppressed = this.persistInput || (this.behavior === 'suggestion' && isInputFocusedWithNoSelection);
|
|
20541
|
+
if (!suppressed) {
|
|
20542
|
+
this.syncInputValuesAcrossTriggerAndBib(label || this.value);
|
|
20621
20543
|
}
|
|
20622
20544
|
|
|
20623
|
-
//
|
|
20624
|
-
|
|
20545
|
+
// Replace any previously appended displayValue clone in the trigger.
|
|
20546
|
+
// :not(slot) excludes the template's <slot name="displayValue"
|
|
20547
|
+
// slot="displayValue"> forwarder, which also has slot="displayValue"
|
|
20548
|
+
// and would otherwise be matched first and removed.
|
|
20549
|
+
const displayValueInTrigger = this.input.querySelector('[slot="displayValue"]:not(slot)');
|
|
20625
20550
|
|
|
20626
20551
|
if (displayValueInTrigger) {
|
|
20627
20552
|
displayValueInTrigger.remove();
|
|
@@ -20645,6 +20570,53 @@ class AuroCombobox extends AuroElement {
|
|
|
20645
20570
|
this.requestUpdate();
|
|
20646
20571
|
}
|
|
20647
20572
|
|
|
20573
|
+
/**
|
|
20574
|
+
* Writes nextValue to the trigger input and the bib input when their current
|
|
20575
|
+
* value differs, then re-asserts imask after Lit's update flushes.
|
|
20576
|
+
* @param {string} nextValue - The value to write to both inputs.
|
|
20577
|
+
* @returns {Promise<void>} Resolves after both inputs flush and imask
|
|
20578
|
+
* re-asserts; resolves immediately when no sync is needed.
|
|
20579
|
+
* @private
|
|
20580
|
+
*/
|
|
20581
|
+
async syncInputValuesAcrossTriggerAndBib(nextValue) {
|
|
20582
|
+
// Only set the flag when there's an actual write to suppress —
|
|
20583
|
+
// syncValuesAndStates re-enters here during typing when both inputs
|
|
20584
|
+
// already match, and a no-op flag flip would make the bib branch's
|
|
20585
|
+
// bail eat legitimate user-input events.
|
|
20586
|
+
const triggerNeedsSync = this.input.value !== nextValue;
|
|
20587
|
+
const bibNeedsSync = Boolean(this.inputInBib) && this.inputInBib.value !== nextValue;
|
|
20588
|
+
if (!triggerNeedsSync && !bibNeedsSync) {
|
|
20589
|
+
return;
|
|
20590
|
+
}
|
|
20591
|
+
|
|
20592
|
+
this._syncingDisplayValue = true;
|
|
20593
|
+
|
|
20594
|
+
const pending = [];
|
|
20595
|
+
if (triggerNeedsSync) {
|
|
20596
|
+
this.input.value = nextValue;
|
|
20597
|
+
pending.push(this.input.updateComplete);
|
|
20598
|
+
}
|
|
20599
|
+
if (bibNeedsSync) {
|
|
20600
|
+
this.inputInBib.value = nextValue;
|
|
20601
|
+
pending.push(this.inputInBib.updateComplete);
|
|
20602
|
+
}
|
|
20603
|
+
// finally — not a bare .then — so that an imask throw (see commit
|
|
20604
|
+
// d1857401c: imask can throw on credit-card format change) doesn't strand
|
|
20605
|
+
// _syncingDisplayValue=true and silently swallow every subsequent input.
|
|
20606
|
+
try {
|
|
20607
|
+
await Promise.all(pending);
|
|
20608
|
+
// imask reasserts otherwise, and handleBlur reverts to its stale value.
|
|
20609
|
+
if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
|
|
20610
|
+
this.input.maskInstance.updateValue();
|
|
20611
|
+
}
|
|
20612
|
+
if (bibNeedsSync && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
|
|
20613
|
+
this.inputInBib.maskInstance.updateValue();
|
|
20614
|
+
}
|
|
20615
|
+
} finally {
|
|
20616
|
+
this._syncingDisplayValue = false;
|
|
20617
|
+
}
|
|
20618
|
+
}
|
|
20619
|
+
|
|
20648
20620
|
/**
|
|
20649
20621
|
* Processes hidden state of all menu options and determines if there are any available options not hidden.
|
|
20650
20622
|
* @private
|
|
@@ -20653,6 +20625,13 @@ class AuroCombobox extends AuroElement {
|
|
|
20653
20625
|
handleMenuOptions() {
|
|
20654
20626
|
this.generateOptionsArray();
|
|
20655
20627
|
this.availableOptions = [];
|
|
20628
|
+
// Single source of truth for the menu's filter/highlight token per call.
|
|
20629
|
+
// syncValuesAndStates re-writes the same value on exact-match keystrokes —
|
|
20630
|
+
// Lit's hasChanged makes that a no-op — and the prior duplicate set inside
|
|
20631
|
+
// handleTriggerInputValueChange is gone.
|
|
20632
|
+
if (this.menu) {
|
|
20633
|
+
this.menu.matchWord = normalizeFilterValue(this.input.value);
|
|
20634
|
+
}
|
|
20656
20635
|
this.updateFilter();
|
|
20657
20636
|
|
|
20658
20637
|
// Set aria-setsize/aria-posinset on each visible option so screen readers
|
|
@@ -20664,17 +20643,14 @@ class AuroCombobox extends AuroElement {
|
|
|
20664
20643
|
option.setAttribute('aria-posinset', index + 1);
|
|
20665
20644
|
});
|
|
20666
20645
|
|
|
20667
|
-
if (this.value && this.
|
|
20668
|
-
|
|
20669
|
-
this.setMenuValue(this.value);
|
|
20670
|
-
}
|
|
20671
|
-
|
|
20646
|
+
if (this.input.value && this.menu.options && this.menu.options.some((opt) => opt.value === this.input.value)) {
|
|
20647
|
+
this.setMenuValue(this.input.value);
|
|
20672
20648
|
this.syncValuesAndStates();
|
|
20673
20649
|
}
|
|
20674
20650
|
|
|
20675
|
-
// Re-activate when optionActive is
|
|
20676
|
-
// been reset (e.g. by clearSelection in an async update)
|
|
20677
|
-
// makeSelection() can find the correct option.
|
|
20651
|
+
// Re-activate when optionActive is not in the current scrollable viewport,
|
|
20652
|
+
// or when _index has been reset (e.g. by clearSelection in an async update)
|
|
20653
|
+
// so that makeSelection() can find the correct option.
|
|
20678
20654
|
if (!this.availableOptions.includes(this.menu.optionActive) || this.menu._index < 0) {
|
|
20679
20655
|
this.activateFirstEnabledAvailableOption();
|
|
20680
20656
|
}
|
|
@@ -20747,18 +20723,6 @@ class AuroCombobox extends AuroElement {
|
|
|
20747
20723
|
this.dropdownOpen = ev.detail.expanded;
|
|
20748
20724
|
this.updateMenuShapeSize();
|
|
20749
20725
|
|
|
20750
|
-
// Defer aria-expanded "true" so VoiceOver finishes character echo
|
|
20751
|
-
// before announcing "expanded". Set "false" immediately on close.
|
|
20752
|
-
clearTimeout(this._expandedTimeout);
|
|
20753
|
-
if (this.dropdownOpen) {
|
|
20754
|
-
const expandedDelay = 150;
|
|
20755
|
-
this._expandedTimeout = setTimeout(() => {
|
|
20756
|
-
this.triggerExpandedState = true;
|
|
20757
|
-
}, expandedDelay);
|
|
20758
|
-
} else {
|
|
20759
|
-
this.triggerExpandedState = false;
|
|
20760
|
-
}
|
|
20761
|
-
|
|
20762
20726
|
// Clear aria-activedescendant when dropdown closes
|
|
20763
20727
|
if (!this.dropdownOpen && this.input) {
|
|
20764
20728
|
this.input.setActiveDescendant(null);
|
|
@@ -20808,28 +20772,25 @@ class AuroCombobox extends AuroElement {
|
|
|
20808
20772
|
|
|
20809
20773
|
guardTouchPassthrough(this.menu);
|
|
20810
20774
|
|
|
20811
|
-
//
|
|
20812
|
-
//
|
|
20813
|
-
//
|
|
20775
|
+
// showModal() takes focus away from the trigger. Early focus once
|
|
20776
|
+
// the dialog has painted; the shared doubleRaf below is the fallback
|
|
20777
|
+
// for when the dialog needs an extra frame and also clears the
|
|
20778
|
+
// validation guard.
|
|
20814
20779
|
requestAnimationFrame(() => {
|
|
20815
20780
|
this.setInputFocus();
|
|
20816
20781
|
});
|
|
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
20782
|
}
|
|
20783
|
+
// else (desktop popover-open): Chrome resets the trigger caret to
|
|
20784
|
+
// [0, 0] when its floating <label for="…"> overlay receives focus.
|
|
20785
|
+
// The shared doubleRaf below parks the caret back at end-of-text
|
|
20786
|
+
// after the dropdown layout settles.
|
|
20787
|
+
|
|
20788
|
+
doubleRaf(() => {
|
|
20789
|
+
this.setInputFocus();
|
|
20790
|
+
if (this._inFullscreenTransition) {
|
|
20791
|
+
this._inFullscreenTransition = false;
|
|
20792
|
+
}
|
|
20793
|
+
});
|
|
20833
20794
|
}
|
|
20834
20795
|
});
|
|
20835
20796
|
|
|
@@ -20866,7 +20827,7 @@ class AuroCombobox extends AuroElement {
|
|
|
20866
20827
|
this.dropdown.trigger.inert = false;
|
|
20867
20828
|
}
|
|
20868
20829
|
|
|
20869
|
-
|
|
20830
|
+
this._scheduleTimer(() => {
|
|
20870
20831
|
this.setInputFocus();
|
|
20871
20832
|
}, 0);
|
|
20872
20833
|
});
|
|
@@ -20934,24 +20895,7 @@ class AuroCombobox extends AuroElement {
|
|
|
20934
20895
|
nativeInput.setSelectionRange(len, len);
|
|
20935
20896
|
}
|
|
20936
20897
|
} 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
|
-
}
|
|
20898
|
+
this.input.focus();
|
|
20955
20899
|
}
|
|
20956
20900
|
}
|
|
20957
20901
|
|
|
@@ -21027,7 +20971,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21027
20971
|
|
|
21028
20972
|
// racing condition on custom-combobox with custom-menu
|
|
21029
20973
|
if (!this.menu) {
|
|
21030
|
-
|
|
20974
|
+
this._scheduleTimer(() => {
|
|
21031
20975
|
this.configureMenu();
|
|
21032
20976
|
}, 0);
|
|
21033
20977
|
return;
|
|
@@ -21057,7 +21001,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21057
21001
|
if (this.menu.optionSelected) {
|
|
21058
21002
|
const selected = this.menu.optionSelected;
|
|
21059
21003
|
|
|
21060
|
-
if (
|
|
21004
|
+
if (this.optionSelected !== selected) {
|
|
21061
21005
|
this.optionSelected = selected;
|
|
21062
21006
|
}
|
|
21063
21007
|
|
|
@@ -21070,7 +21014,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21070
21014
|
}
|
|
21071
21015
|
|
|
21072
21016
|
// Update display
|
|
21073
|
-
this.updateTriggerTextDisplay(getOptionLabel(this.optionSelected)
|
|
21017
|
+
this.updateTriggerTextDisplay(getOptionLabel(this.optionSelected));
|
|
21074
21018
|
|
|
21075
21019
|
// Update match word for filtering
|
|
21076
21020
|
const trimmedInput = normalizeFilterValue(this.input.value);
|
|
@@ -21082,17 +21026,24 @@ class AuroCombobox extends AuroElement {
|
|
|
21082
21026
|
// Hide dropdown on selection (except during slot changes)
|
|
21083
21027
|
if (evt.detail && evt.detail.source !== 'slotchange') {
|
|
21084
21028
|
// do not close while typing in suggestion mode with no value selected, to allow freeform input
|
|
21085
|
-
|
|
21086
|
-
|
|
21029
|
+
this.hideBib();
|
|
21030
|
+
|
|
21031
|
+
// Move focus to the clear button when the user makes a selection.
|
|
21032
|
+
if (!isEcho && this.menu.value !== undefined) {
|
|
21033
|
+
this.setClearBtnFocus();
|
|
21087
21034
|
}
|
|
21088
21035
|
|
|
21089
21036
|
// Announce the selection after the dropdown closes so it isn't
|
|
21090
21037
|
// overridden by VoiceOver's "collapsed" announcement from aria-expanded.
|
|
21038
|
+
// Skip when there's no selected value (e.g. menu.clearSelection() from
|
|
21039
|
+
// the unmatched-value path), otherwise VoiceOver reads "undefined".
|
|
21091
21040
|
const selectedValue = this.menu.value;
|
|
21092
|
-
|
|
21093
|
-
|
|
21094
|
-
|
|
21095
|
-
|
|
21041
|
+
if (selectedValue) {
|
|
21042
|
+
const announcementDelay = 300;
|
|
21043
|
+
this._scheduleTimer(() => {
|
|
21044
|
+
announceToScreenReader(this._getAnnouncementRoot(), `${selectedValue}, selected`);
|
|
21045
|
+
}, announcementDelay);
|
|
21046
|
+
}
|
|
21096
21047
|
}
|
|
21097
21048
|
|
|
21098
21049
|
// Programmatic value syncs leave availableOptions stale because
|
|
@@ -21101,22 +21052,6 @@ class AuroCombobox extends AuroElement {
|
|
|
21101
21052
|
// only — fresh user selections take the existing hideBib path.
|
|
21102
21053
|
if (isEcho && this.menu.optionSelected) {
|
|
21103
21054
|
this._programmaticFilterRefresh = true;
|
|
21104
|
-
this.handleMenuOptions();
|
|
21105
|
-
setTimeout(() => {
|
|
21106
|
-
this._programmaticFilterRefresh = false;
|
|
21107
|
-
}, 0);
|
|
21108
|
-
}
|
|
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
21055
|
}
|
|
21121
21056
|
});
|
|
21122
21057
|
|
|
@@ -21129,6 +21064,14 @@ class AuroCombobox extends AuroElement {
|
|
|
21129
21064
|
// stale option. Safe from re-entrancy because any resulting
|
|
21130
21065
|
// input.value changes dispatch isProgrammatic events.
|
|
21131
21066
|
this.menu.addEventListener('auroMenu-selectValueFailure', () => {
|
|
21067
|
+
// Announce the rejection BEFORE we clear `this.value` so the live
|
|
21068
|
+
// region carries the attempted value — without this the bib closes
|
|
21069
|
+
// silently and screen-reader users get no signal that their request
|
|
21070
|
+
// (e.g. a direct setMenuValue() call) was dropped.
|
|
21071
|
+
const attemptedValue = this.value;
|
|
21072
|
+
if (attemptedValue) {
|
|
21073
|
+
announceToScreenReader(this._getAnnouncementRoot(), `No matching option for ${attemptedValue}`);
|
|
21074
|
+
}
|
|
21132
21075
|
this.value = undefined;
|
|
21133
21076
|
this.optionSelected = undefined;
|
|
21134
21077
|
});
|
|
@@ -21140,10 +21083,13 @@ class AuroCombobox extends AuroElement {
|
|
|
21140
21083
|
this.input.setActiveDescendant(this.optionActive);
|
|
21141
21084
|
}
|
|
21142
21085
|
|
|
21143
|
-
//
|
|
21144
|
-
//
|
|
21145
|
-
//
|
|
21146
|
-
|
|
21086
|
+
// In fullscreen mode the menu sits inside a nested <dialog> shadow root,
|
|
21087
|
+
// and aria-activedescendant references across that boundary are lost —
|
|
21088
|
+
// VoiceOver/NVDA don't read the active option natively, so we mirror it
|
|
21089
|
+
// into the polite live region. In popover mode aria-activedescendant on
|
|
21090
|
+
// the trigger input is read natively; double-announcing would flood the
|
|
21091
|
+
// queue on arrow-key repeat.
|
|
21092
|
+
if (this.optionActive && this.dropdown.isBibFullscreen) {
|
|
21147
21093
|
const optionText = this.optionActive.textContent.trim();
|
|
21148
21094
|
const selectedState = this.optionActive.hasAttribute('selected') ? ', selected' : ', not selected';
|
|
21149
21095
|
const optionIndex = this.availableOptions.indexOf(this.optionActive) + 1;
|
|
@@ -21176,7 +21122,12 @@ class AuroCombobox extends AuroElement {
|
|
|
21176
21122
|
* Validate every time we remove focus from the combo box.
|
|
21177
21123
|
*/
|
|
21178
21124
|
this.addEventListener('focusout', () => {
|
|
21179
|
-
|
|
21125
|
+
// Skip while the dropdown is open — focus transits out briefly on
|
|
21126
|
+
// mousedown of a menu option (popover top-layer breaks :focus-within),
|
|
21127
|
+
// and validating against the pre-selection value flashes a stale error
|
|
21128
|
+
// between mousedown and mouseup. The next focusout fires after the
|
|
21129
|
+
// dropdown closes and validates against the post-selection value.
|
|
21130
|
+
if (!this.componentHasFocus && !this._inFullscreenTransition && !this.dropdownOpen) {
|
|
21180
21131
|
this.validate();
|
|
21181
21132
|
}
|
|
21182
21133
|
});
|
|
@@ -21239,49 +21190,40 @@ class AuroCombobox extends AuroElement {
|
|
|
21239
21190
|
if (this._syncingDisplayValue) {
|
|
21240
21191
|
return;
|
|
21241
21192
|
}
|
|
21242
|
-
this._syncingBibValue = true;
|
|
21243
|
-
this.input.value = this.inputInBib.value;
|
|
21244
|
-
this.input.updateComplete.then(() => {
|
|
21245
|
-
this._syncingBibValue = false;
|
|
21246
|
-
});
|
|
21247
21193
|
|
|
21248
|
-
//
|
|
21249
|
-
|
|
21250
|
-
|
|
21251
|
-
|
|
21252
|
-
|
|
21253
|
-
|
|
21254
|
-
|
|
21255
|
-
|
|
21256
|
-
|
|
21194
|
+
// Filtering runs via re-entrance: writing this.input.value below
|
|
21195
|
+
// dispatches an 'input' event that the trigger's listener routes to
|
|
21196
|
+
// handleTriggerInputValueChange, which refreshes the menu filter.
|
|
21197
|
+
if (this.input.value !== this.inputInBib.value) {
|
|
21198
|
+
this._syncingBibValue = true;
|
|
21199
|
+
this.input.value = this.inputInBib.value;
|
|
21200
|
+
this.input.updateComplete.then(() => {
|
|
21201
|
+
this._syncingBibValue = false;
|
|
21202
|
+
});
|
|
21257
21203
|
}
|
|
21258
21204
|
|
|
21259
|
-
this.handleMenuOptions();
|
|
21260
21205
|
this.dispatchEvent(new CustomEvent('inputValue', { detail: { value: this.inputValue } }));
|
|
21261
|
-
|
|
21206
|
+
} else if (event.target === this.input) {
|
|
21207
|
+
|
|
21208
|
+
// Also sync the native input immediately so keystrokes arriving
|
|
21209
|
+
// before Lit's async update cycle (e.g. rapid Backspaces during a
|
|
21210
|
+
// fullscreen transition) operate on the correct content.
|
|
21211
|
+
// Skip the next programmatic input event to prevent the patched setter
|
|
21212
|
+
// from re-entering handleInputValueChange via the bib path.
|
|
21213
|
+
const bibNativeInput = this.inputInBib.inputElement;
|
|
21214
|
+
if (bibNativeInput && bibNativeInput.value !== this.input.value) {
|
|
21215
|
+
this.inputInBib.skipNextProgrammaticInputEvent = true;
|
|
21216
|
+
bibNativeInput.value = this.input.value || '';
|
|
21217
|
+
}
|
|
21262
21218
|
}
|
|
21263
21219
|
|
|
21220
|
+
this.value = this.input.value;
|
|
21221
|
+
|
|
21264
21222
|
// Ignore re-entrant input events caused by programmatic value sets.
|
|
21265
21223
|
if (this._syncingBibValue || this._syncingDisplayValue) {
|
|
21266
21224
|
return;
|
|
21267
21225
|
}
|
|
21268
21226
|
|
|
21269
|
-
this.inputInBib.value = this.input.value;
|
|
21270
|
-
|
|
21271
|
-
// Also sync the native input immediately so keystrokes arriving
|
|
21272
|
-
// before Lit's async update cycle (e.g. rapid Backspaces during a
|
|
21273
|
-
// fullscreen transition) operate on the correct content.
|
|
21274
|
-
// Skip the next programmatic input event to prevent the patched setter
|
|
21275
|
-
// from re-entering handleInputValueChange via the bib path.
|
|
21276
|
-
const bibNativeInput = this.inputInBib.inputElement;
|
|
21277
|
-
if (bibNativeInput && bibNativeInput.value !== this.input.value) {
|
|
21278
|
-
this.inputInBib.skipNextProgrammaticInputEvent = true;
|
|
21279
|
-
bibNativeInput.value = this.input.value || '';
|
|
21280
|
-
}
|
|
21281
|
-
|
|
21282
|
-
this.menu.matchWord = normalizeFilterValue(this.input.value);
|
|
21283
|
-
this.optionActive = null;
|
|
21284
|
-
|
|
21285
21227
|
if (this.behavior === 'suggestion') {
|
|
21286
21228
|
this.value = this.input.value;
|
|
21287
21229
|
}
|
|
@@ -21289,7 +21231,6 @@ class AuroCombobox extends AuroElement {
|
|
|
21289
21231
|
if (!this.input.value && !this._clearing) {
|
|
21290
21232
|
this.clear();
|
|
21291
21233
|
}
|
|
21292
|
-
this.handleMenuOptions();
|
|
21293
21234
|
|
|
21294
21235
|
// Validate only if the value was set programmatically (not during user
|
|
21295
21236
|
// interaction). In fullscreen dialog mode, componentHasFocus returns false
|
|
@@ -21299,34 +21240,44 @@ class AuroCombobox extends AuroElement {
|
|
|
21299
21240
|
this.validate();
|
|
21300
21241
|
}
|
|
21301
21242
|
|
|
21302
|
-
|
|
21303
|
-
|
|
21304
|
-
|
|
21305
|
-
|
|
21306
|
-
|
|
21307
|
-
|
|
21308
|
-
|
|
21309
|
-
|
|
21310
|
-
|
|
21243
|
+
this.dispatchEvent(new CustomEvent('inputValue', { detail: { value: this.inputValue } }));
|
|
21244
|
+
}
|
|
21245
|
+
|
|
21246
|
+
/**
|
|
21247
|
+
* Handles input value changes originating from the trigger input.
|
|
21248
|
+
* Refreshes menu options and filtering, delegates to handleInputValueChange
|
|
21249
|
+
* for value synchronization, and manages fullscreen bib focus.
|
|
21250
|
+
* @private
|
|
21251
|
+
* @param {Event} event - The input event from the trigger input element.
|
|
21252
|
+
* @returns {void}
|
|
21253
|
+
*/
|
|
21254
|
+
handleTriggerInputValueChange(event) {
|
|
21255
|
+
// 'input' fires for every user-initiated value change — typing, paste,
|
|
21256
|
+
// IME composition end, dead-key composition, drag-drop. Flip _userTyped
|
|
21257
|
+
// here so updated('availableOptions') auto-opens the bib for sources
|
|
21258
|
+
// that keydown alone misses: paste fires no keydown, IME uses
|
|
21259
|
+
// key='Process', and dead keys produce multi-char keys (all bypass the
|
|
21260
|
+
// prior keydown.key.length===1 gate). Skip programmatic syncs.
|
|
21261
|
+
if (!this._syncingDisplayValue && !this._syncingBibValue && !this._programmaticFilterRefresh) {
|
|
21262
|
+
this._userTyped = true;
|
|
21311
21263
|
}
|
|
21312
21264
|
|
|
21313
|
-
|
|
21314
|
-
|
|
21315
|
-
|
|
21316
|
-
|
|
21317
|
-
|
|
21318
|
-
// dialog opens — the user then has to tap the input again to resume
|
|
21319
|
-
// typing.
|
|
21320
|
-
if (this.dropdown.isBibFullscreen && this.input.value && this.input.value.length > 0) {
|
|
21321
|
-
if (!this.dropdown.isPopoverVisible) {
|
|
21322
|
-
this.showBib();
|
|
21323
|
-
}
|
|
21324
|
-
if (this.dropdown.isPopoverVisible) {
|
|
21325
|
-
this.setInputFocus();
|
|
21326
|
-
}
|
|
21265
|
+
this.handleMenuOptions();
|
|
21266
|
+
this.optionActive = null;
|
|
21267
|
+
|
|
21268
|
+
if (this.value === this.input.value) {
|
|
21269
|
+
return;
|
|
21327
21270
|
}
|
|
21328
21271
|
|
|
21329
|
-
this.
|
|
21272
|
+
this.handleInputValueChange(event);
|
|
21273
|
+
|
|
21274
|
+
if (this.dropdown.isBibFullscreen && this.input.value && this.input.value.length > 0 && this.dropdown.isPopoverVisible) {
|
|
21275
|
+
this.setInputFocus();
|
|
21276
|
+
}
|
|
21277
|
+
|
|
21278
|
+
if (this._programmaticFilterRefresh) {
|
|
21279
|
+
this._programmaticFilterRefresh = false;
|
|
21280
|
+
}
|
|
21330
21281
|
}
|
|
21331
21282
|
|
|
21332
21283
|
/**
|
|
@@ -21394,6 +21345,11 @@ class AuroCombobox extends AuroElement {
|
|
|
21394
21345
|
disconnectedCallback() {
|
|
21395
21346
|
super.disconnectedCallback();
|
|
21396
21347
|
this._inFullscreenTransition = false;
|
|
21348
|
+
// Cancel any outstanding timers so detached callbacks don't fire on
|
|
21349
|
+
// disposed DOM — most are no-ops, but configureMenu's racing-condition
|
|
21350
|
+
// retry would otherwise keep rescheduling itself indefinitely.
|
|
21351
|
+
this._pendingTimers.forEach((id) => clearTimeout(id));
|
|
21352
|
+
this._pendingTimers.clear();
|
|
21397
21353
|
}
|
|
21398
21354
|
|
|
21399
21355
|
firstUpdated() {
|
|
@@ -21435,7 +21391,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21435
21391
|
this.menu.value = value;
|
|
21436
21392
|
// Backup clear: if menu.value === menu.optionSelected.value already, the
|
|
21437
21393
|
// listener won't fire and the flag would swallow the next user click.
|
|
21438
|
-
|
|
21394
|
+
this._scheduleTimer(() => {
|
|
21439
21395
|
this._pendingMenuValueSync = false;
|
|
21440
21396
|
}, 0);
|
|
21441
21397
|
}
|
|
@@ -21452,15 +21408,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21452
21408
|
this.menu.value = undefined;
|
|
21453
21409
|
this.validation.reset(this);
|
|
21454
21410
|
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
21411
|
this.validity = undefined;
|
|
21461
|
-
this.errorMessage = '';
|
|
21462
|
-
this.input.validity = undefined;
|
|
21463
|
-
this.input.errorMessage = '';
|
|
21464
21412
|
}
|
|
21465
21413
|
|
|
21466
21414
|
/**
|
|
@@ -21478,6 +21426,17 @@ class AuroCombobox extends AuroElement {
|
|
|
21478
21426
|
this.optionSelected = undefined;
|
|
21479
21427
|
this.value = undefined;
|
|
21480
21428
|
|
|
21429
|
+
// Clear the appended displayValue clone in the trigger if present.
|
|
21430
|
+
// :not(slot) excludes the template's <slot name="displayValue"
|
|
21431
|
+
// slot="displayValue"> forwarder (line 1816), which also has
|
|
21432
|
+
// slot="displayValue" and would otherwise be matched first and removed,
|
|
21433
|
+
// permanently breaking the consumer-provided displayValue slot.
|
|
21434
|
+
const displayValueInTrigger = this.input.querySelector('[slot="displayValue"]:not(slot)');
|
|
21435
|
+
|
|
21436
|
+
if (displayValueInTrigger) {
|
|
21437
|
+
displayValueInTrigger.remove();
|
|
21438
|
+
}
|
|
21439
|
+
|
|
21481
21440
|
if (this.input.value) {
|
|
21482
21441
|
this.input.clear();
|
|
21483
21442
|
}
|
|
@@ -21501,81 +21460,50 @@ class AuroCombobox extends AuroElement {
|
|
|
21501
21460
|
}
|
|
21502
21461
|
|
|
21503
21462
|
updated(changedProperties) {
|
|
21504
|
-
// After the component is ready,
|
|
21463
|
+
// After the component is ready, propagate direct changes down to child components.
|
|
21505
21464
|
if (changedProperties.has('value')) {
|
|
21506
|
-
|
|
21507
|
-
|
|
21508
|
-
|
|
21509
|
-
|
|
21465
|
+
// Only flag programmatic refreshes — user-typed value changes must not
|
|
21466
|
+
// suppress the availableOptions branch's showBib(). Firefox batches
|
|
21467
|
+
// 'value' and 'availableOptions' into the same updated() call, so
|
|
21468
|
+
// setting the flag unconditionally here masks the user-typed open path.
|
|
21469
|
+
if (!this._userTyped) {
|
|
21470
|
+
this._programmaticFilterRefresh = true;
|
|
21510
21471
|
}
|
|
21511
21472
|
|
|
21512
|
-
if (this.
|
|
21513
|
-
|
|
21514
|
-
|
|
21473
|
+
if (this.input.value !== this.value) {
|
|
21474
|
+
// Clear menu.value AND menu.optionSelected together. Clearing only
|
|
21475
|
+
// menu.value leaves the previously-selected option element pinned
|
|
21476
|
+
// as menu.optionSelected; a later auroMenu-selectedOption event
|
|
21477
|
+
// would then write its stale .value back into combobox.value
|
|
21478
|
+
// (e.g. Tab-after-Backspace re-selecting the prior option).
|
|
21479
|
+
if (this.menu.value || this.menu.optionSelected) {
|
|
21480
|
+
this.menu.clearSelection();
|
|
21481
|
+
}
|
|
21515
21482
|
|
|
21516
|
-
|
|
21517
|
-
|
|
21518
|
-
|
|
21519
|
-
|
|
21520
|
-
|
|
21521
|
-
|
|
21522
|
-
|
|
21523
|
-
|
|
21524
|
-
|
|
21525
|
-
|
|
21526
|
-
|
|
21527
|
-
|
|
21528
|
-
|
|
21529
|
-
|
|
21530
|
-
|
|
21531
|
-
|
|
21532
|
-
|
|
21533
|
-
|
|
21534
|
-
// matches to avoid spurious events during the normal typing path.
|
|
21535
|
-
const nextValue = this.value || '';
|
|
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.
|
|
21562
|
-
this._programmaticFilterRefresh = true;
|
|
21563
|
-
this.handleMenuOptions();
|
|
21564
|
-
setTimeout(() => {
|
|
21565
|
-
this._programmaticFilterRefresh = false;
|
|
21566
|
-
}, 0);
|
|
21567
|
-
});
|
|
21568
|
-
}
|
|
21483
|
+
if (!this.persistInput) {
|
|
21484
|
+
this.syncInputValuesAcrossTriggerAndBib(this.value || '');
|
|
21485
|
+
}
|
|
21486
|
+
|
|
21487
|
+
// Programmatic value with no matching option: updateFilter will close
|
|
21488
|
+
// the bib silently (see line 648 — no noMatchOption + 0 results
|
|
21489
|
+
// hides). Announce so screen-reader users hear the request was
|
|
21490
|
+
// dropped. Gated on `input.value !== this.value` so this never fires
|
|
21491
|
+
// for user typing — that path always reconciles input.value to
|
|
21492
|
+
// this.value before updated() runs.
|
|
21493
|
+
if (
|
|
21494
|
+
this.value &&
|
|
21495
|
+
this.menu &&
|
|
21496
|
+
this.menu.options &&
|
|
21497
|
+
this.menu.options.length > 0 &&
|
|
21498
|
+
!this.menu.options.some((opt) => opt.value === this.value)
|
|
21499
|
+
) {
|
|
21500
|
+
announceToScreenReader(this._getAnnouncementRoot(), `No matching option for ${this.value}`);
|
|
21569
21501
|
}
|
|
21570
21502
|
}
|
|
21503
|
+
|
|
21571
21504
|
if (!this.value) {
|
|
21572
21505
|
this.clear();
|
|
21573
21506
|
}
|
|
21574
|
-
if (this.value && !this.componentHasFocus) {
|
|
21575
|
-
// If the value got set programmatically make sure we hide the bib
|
|
21576
|
-
// when input is not taking the focus (input can be in dropdown.trigger or in bibtemplate)
|
|
21577
|
-
this.hideBib();
|
|
21578
|
-
}
|
|
21579
21507
|
|
|
21580
21508
|
// Sync the input and match word, but don't directly set menu.value again
|
|
21581
21509
|
if (this.menu) {
|
|
@@ -21588,7 +21516,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21588
21516
|
composed: true,
|
|
21589
21517
|
detail: {
|
|
21590
21518
|
optionSelected: this.menu.optionSelected,
|
|
21591
|
-
value: this.
|
|
21519
|
+
value: this.value
|
|
21592
21520
|
}
|
|
21593
21521
|
}));
|
|
21594
21522
|
|
|
@@ -21611,16 +21539,30 @@ class AuroCombobox extends AuroElement {
|
|
|
21611
21539
|
// from a programmatic filter refresh after a value swap — the user
|
|
21612
21540
|
// didn't interact, so we shouldn't auto-open the bib (especially for
|
|
21613
21541
|
// the no-match path where the existing condition unconditionally fires).
|
|
21614
|
-
if (this._programmaticFilterRefresh) {
|
|
21615
|
-
|
|
21616
|
-
|
|
21617
|
-
|
|
21542
|
+
if ((this.menu && !this._programmaticFilterRefresh)) {
|
|
21543
|
+
if (
|
|
21544
|
+
this.availableOptions.length > 0 ||
|
|
21545
|
+
this.menu.loading ||
|
|
21546
|
+
this.noMatchOption
|
|
21547
|
+
) {
|
|
21548
|
+
if (this._userTyped) {
|
|
21549
|
+
if (!this.dropdownOpen) {
|
|
21550
|
+
this.showBib();
|
|
21551
|
+
}
|
|
21552
|
+
this._userTyped = false;
|
|
21553
|
+
}
|
|
21554
|
+
}
|
|
21555
|
+
|
|
21618
21556
|
if (!this.availableOptions.includes(this.menu.optionActive)) {
|
|
21619
21557
|
this.activateFirstEnabledAvailableOption();
|
|
21620
21558
|
}
|
|
21621
|
-
} else if (this.dropdown
|
|
21559
|
+
} else if (!this.dropdown.isBibFullscreen) {
|
|
21622
21560
|
this.hideBib();
|
|
21623
21561
|
}
|
|
21562
|
+
|
|
21563
|
+
if (this._programmaticFilterRefresh) {
|
|
21564
|
+
this._programmaticFilterRefresh = false;
|
|
21565
|
+
}
|
|
21624
21566
|
}
|
|
21625
21567
|
|
|
21626
21568
|
if (changedProperties.has('error')) {
|
|
@@ -21762,10 +21704,10 @@ class AuroCombobox extends AuroElement {
|
|
|
21762
21704
|
shape="${this.shape}"
|
|
21763
21705
|
size="${this.size}">
|
|
21764
21706
|
<${this.inputTag}
|
|
21765
|
-
@input="${this.
|
|
21707
|
+
@input="${this.handleTriggerInputValueChange}"
|
|
21766
21708
|
appearance="${this.onDark ? 'inverse' : this.appearance}"
|
|
21767
21709
|
.a11yActivedescendant="${this.dropdownOpen && this.optionActive ? this.optionActive.id : undefined}"
|
|
21768
|
-
.a11yExpanded="${this.
|
|
21710
|
+
.a11yExpanded="${this.dropdownOpen}"
|
|
21769
21711
|
.a11yControls="${this.dropdownId}"
|
|
21770
21712
|
.autocomplete="${this.autocomplete}"
|
|
21771
21713
|
.inputmode="${this.inputmode}"
|
|
@@ -23370,14 +23312,10 @@ async function dynamicMenuExample() {
|
|
|
23370
23312
|
// Helper function that generates HTML for menuoptions
|
|
23371
23313
|
function generateMenuOptionHtml(menu, label, value) {
|
|
23372
23314
|
const option = document.createElement('auro-menuoption');
|
|
23373
|
-
const displayValue = document.createElement('div');
|
|
23374
|
-
displayValue.setAttribute("slot", "displayValue");
|
|
23375
|
-
displayValue.innerHTML = value;
|
|
23376
23315
|
|
|
23377
23316
|
option.value = value;
|
|
23378
23317
|
option.innerHTML = label;
|
|
23379
23318
|
menu.appendChild(option);
|
|
23380
|
-
option.appendChild(displayValue);
|
|
23381
23319
|
}
|
|
23382
23320
|
|
|
23383
23321
|
// Main javascript that runs all JS to create example
|