@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
|
@@ -500,15 +500,17 @@ let AuroFormValidation$1 = class AuroFormValidation {
|
|
|
500
500
|
);
|
|
501
501
|
}
|
|
502
502
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
503
|
+
const isCombobox = this.runtimeUtils.elementMatch(elem, 'auro-combobox');
|
|
504
|
+
|
|
505
|
+
// If there is a second input in the elem and that value is undefined or an empty string set hasValue to false.
|
|
506
|
+
// Skip for combobox: its second auro-input is the fullscreen-bib mirror of the same value, not an independent
|
|
507
|
+
// field (datepicker is the intended consumer — start/end are independently required).
|
|
508
|
+
if (this.auroInputElements?.length === 2 && !isCombobox) {
|
|
509
|
+
if (!this.auroInputElements[1].value || this.auroInputElements[1].value.length === 0) {
|
|
506
510
|
hasValue = false;
|
|
507
511
|
}
|
|
508
512
|
}
|
|
509
513
|
|
|
510
|
-
const isCombobox = this.runtimeUtils.elementMatch(elem, 'auro-combobox');
|
|
511
|
-
|
|
512
514
|
if (isCombobox) {
|
|
513
515
|
|
|
514
516
|
if (!elem.persistInput || elem.behavior === "filter") {
|
|
@@ -825,6 +827,8 @@ function navigateArrow(component, direction, options = {}) {
|
|
|
825
827
|
}
|
|
826
828
|
}
|
|
827
829
|
|
|
830
|
+
/* eslint-disable no-underscore-dangle */
|
|
831
|
+
|
|
828
832
|
/**
|
|
829
833
|
* Returns the clear button element from the active input's shadow
|
|
830
834
|
* DOM, if available.
|
|
@@ -860,11 +864,9 @@ function isClearBtnFocused(ctx, clearBtn = getClearBtn(ctx)) {
|
|
|
860
864
|
* @param {Object} menu - The menu component.
|
|
861
865
|
*/
|
|
862
866
|
function reconcileMenuIndex(menu) {
|
|
863
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
864
867
|
if (menu._index < 0 && menu.optionActive && menu.items) {
|
|
865
868
|
const idx = menu.items.indexOf(menu.optionActive);
|
|
866
869
|
if (idx >= 0) {
|
|
867
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
868
870
|
menu._index = idx;
|
|
869
871
|
}
|
|
870
872
|
}
|
|
@@ -883,11 +885,7 @@ const comboboxKeyboardStrategy = {
|
|
|
883
885
|
|
|
884
886
|
// navigate if bib is open otherwise open it
|
|
885
887
|
if (component.dropdown.isPopoverVisible) {
|
|
886
|
-
|
|
887
|
-
component.activateLastEnabledAvailableOption();
|
|
888
|
-
} else {
|
|
889
|
-
navigateArrow(component, 'down');
|
|
890
|
-
}
|
|
888
|
+
navigateArrow(component, 'down');
|
|
891
889
|
} else {
|
|
892
890
|
component.showBib();
|
|
893
891
|
}
|
|
@@ -906,11 +904,7 @@ const comboboxKeyboardStrategy = {
|
|
|
906
904
|
|
|
907
905
|
// navigate if bib is open otherwise open it
|
|
908
906
|
if (component.dropdown.isPopoverVisible) {
|
|
909
|
-
|
|
910
|
-
component.activateFirstEnabledAvailableOption();
|
|
911
|
-
} else {
|
|
912
|
-
navigateArrow(component, 'up');
|
|
913
|
-
}
|
|
907
|
+
navigateArrow(component, 'up');
|
|
914
908
|
} else {
|
|
915
909
|
component.showBib();
|
|
916
910
|
}
|
|
@@ -926,13 +920,18 @@ const comboboxKeyboardStrategy = {
|
|
|
926
920
|
},
|
|
927
921
|
|
|
928
922
|
Enter(component, evt, ctx) {
|
|
923
|
+
// Forms should not submit on Enter from a combobox, regardless of which
|
|
924
|
+
// child element (input, clear button, menu) is focused.
|
|
925
|
+
evt.stopPropagation();
|
|
926
|
+
|
|
929
927
|
if (isClearBtnFocused(ctx)) {
|
|
930
|
-
//
|
|
931
|
-
//
|
|
932
|
-
//
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
928
|
+
// Let the browser dispatch Enter to the focused clear button so its
|
|
929
|
+
// built-in activation fires and clears the selection. Do NOT call
|
|
930
|
+
// preventDefault — that would block the activation.
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
if (ctx.isExpanded && component.menu.optionActive) {
|
|
936
935
|
reconcileMenuIndex(component.menu);
|
|
937
936
|
component.menu.makeSelection();
|
|
938
937
|
|
|
@@ -941,14 +940,8 @@ const comboboxKeyboardStrategy = {
|
|
|
941
940
|
}
|
|
942
941
|
|
|
943
942
|
evt.preventDefault();
|
|
944
|
-
evt.stopPropagation();
|
|
945
943
|
} else {
|
|
946
|
-
// Prevent the keypress from bubbling to parent containers (e.g., forms)
|
|
947
|
-
// which could interpret Enter as a submit or trigger other unintended behavior.
|
|
948
|
-
// This is safe because showBib() opens the dialog programmatically,
|
|
949
|
-
// not via event propagation.
|
|
950
944
|
evt.preventDefault();
|
|
951
|
-
evt.stopPropagation();
|
|
952
945
|
component.showBib();
|
|
953
946
|
}
|
|
954
947
|
},
|
|
@@ -993,7 +986,7 @@ const comboboxKeyboardStrategy = {
|
|
|
993
986
|
component.setClearBtnFocus();
|
|
994
987
|
}
|
|
995
988
|
}
|
|
996
|
-
}
|
|
989
|
+
}
|
|
997
990
|
};
|
|
998
991
|
|
|
999
992
|
/**
|
|
@@ -4888,7 +4881,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$3 {
|
|
|
4888
4881
|
}
|
|
4889
4882
|
};
|
|
4890
4883
|
|
|
4891
|
-
var formkitVersion$2 = '
|
|
4884
|
+
var formkitVersion$2 = '202607010100';
|
|
4892
4885
|
|
|
4893
4886
|
let AuroElement$2 = class AuroElement extends i$3 {
|
|
4894
4887
|
static get properties() {
|
|
@@ -5839,6 +5832,14 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
5839
5832
|
};
|
|
5840
5833
|
this.addEventListener('keydown', this._bibTabHandler);
|
|
5841
5834
|
|
|
5835
|
+
// Suppress AuroFloatingUI's auto-hide-on-focus-loss while the
|
|
5836
|
+
// desktopModal trap owns focus management. Without this, the very
|
|
5837
|
+
// first focus move into the bib (from the RAF below) triggers
|
|
5838
|
+
// handleFocusLoss → hideBib, tearing down the trap before the
|
|
5839
|
+
// user can press Tab.
|
|
5840
|
+
this._priorNoHideOnFocusLoss = this.noHideOnThisFocusLoss;
|
|
5841
|
+
this.noHideOnThisFocusLoss = true;
|
|
5842
|
+
|
|
5842
5843
|
// Move initial focus into the bib content, matching FocusTrap behavior
|
|
5843
5844
|
requestAnimationFrame(() => {
|
|
5844
5845
|
const focusables = getFocusableElements(this.bibContent);
|
|
@@ -6152,6 +6153,7 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
6152
6153
|
role="${o(this.triggerContentFocusable ? undefined : this.a11yRole)}"
|
|
6153
6154
|
aria-expanded="${o(this.a11yRole === 'button' || this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
|
|
6154
6155
|
aria-controls="${o(this.a11yRole === 'button' || this.triggerContentFocusable ? undefined : this.dropdownId)}"
|
|
6156
|
+
aria-haspopup="${o(this.a11yRole === 'combobox' && !this.triggerContentFocusable ? 'listbox' : undefined)}"
|
|
6155
6157
|
aria-labelledby="${o(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
|
|
6156
6158
|
aria-disabled="${o(this.disabled ? 'true' : undefined)}"
|
|
6157
6159
|
@focusin="${this.handleFocusin}"
|
|
@@ -10661,15 +10663,17 @@ class AuroFormValidation {
|
|
|
10661
10663
|
);
|
|
10662
10664
|
}
|
|
10663
10665
|
|
|
10664
|
-
|
|
10665
|
-
|
|
10666
|
-
|
|
10666
|
+
const isCombobox = this.runtimeUtils.elementMatch(elem, 'auro-combobox');
|
|
10667
|
+
|
|
10668
|
+
// If there is a second input in the elem and that value is undefined or an empty string set hasValue to false.
|
|
10669
|
+
// Skip for combobox: its second auro-input is the fullscreen-bib mirror of the same value, not an independent
|
|
10670
|
+
// field (datepicker is the intended consumer — start/end are independently required).
|
|
10671
|
+
if (this.auroInputElements?.length === 2 && !isCombobox) {
|
|
10672
|
+
if (!this.auroInputElements[1].value || this.auroInputElements[1].value.length === 0) {
|
|
10667
10673
|
hasValue = false;
|
|
10668
10674
|
}
|
|
10669
10675
|
}
|
|
10670
10676
|
|
|
10671
|
-
const isCombobox = this.runtimeUtils.elementMatch(elem, 'auro-combobox');
|
|
10672
|
-
|
|
10673
10677
|
if (isCombobox) {
|
|
10674
10678
|
|
|
10675
10679
|
if (!elem.persistInput || elem.behavior === "filter") {
|
|
@@ -16605,10 +16609,18 @@ class AuroInputUtilities {
|
|
|
16605
16609
|
* @returns {string | undefined}
|
|
16606
16610
|
*/
|
|
16607
16611
|
toFormattedValue(valueObject, format) {
|
|
16612
|
+
// Exposed publicly via `AuroInputUtil.toFormattedValue`, so a missing
|
|
16613
|
+
// `format` argument has to fail gracefully rather than throw on
|
|
16614
|
+
// `format.toLowerCase()`. Treat any falsy value (undefined, null, '')
|
|
16615
|
+
// as "no format → no display value".
|
|
16616
|
+
if (!format) {
|
|
16617
|
+
return undefined;
|
|
16618
|
+
}
|
|
16608
16619
|
const normalizedFormat = format.toLowerCase();
|
|
16609
16620
|
const maskOptions = this.getMaskOptions('date', normalizedFormat);
|
|
16610
16621
|
|
|
16611
16622
|
if (!(valueObject instanceof Date) || Number.isNaN(valueObject.getTime()) || !maskOptions || typeof maskOptions.format !== 'function') {
|
|
16623
|
+
console.debug('Invalid date object or mask options for formatting', { valueObject, maskOptions }); // eslint-disable-line no-console
|
|
16612
16624
|
return undefined;
|
|
16613
16625
|
}
|
|
16614
16626
|
|
|
@@ -16755,79 +16767,19 @@ class BaseInput extends AuroElement$1 {
|
|
|
16755
16767
|
constructor() {
|
|
16756
16768
|
super();
|
|
16757
16769
|
|
|
16758
|
-
|
|
16759
|
-
|
|
16760
|
-
|
|
16761
|
-
|
|
16762
|
-
|
|
16763
|
-
|
|
16764
|
-
|
|
16765
|
-
|
|
16766
|
-
|
|
16767
|
-
|
|
16768
|
-
this.required = false;
|
|
16769
|
-
this.onDark = false;
|
|
16770
|
-
this.setCustomValidityForType = undefined;
|
|
16771
|
-
this.size = 'lg';
|
|
16772
|
-
this.shape = 'classic';
|
|
16773
|
-
this.value = undefined;
|
|
16774
|
-
this._valueObject = undefined;
|
|
16775
|
-
|
|
16776
|
-
this._initializePrivateDefaults();
|
|
16777
|
-
}
|
|
16778
|
-
|
|
16779
|
-
/**
|
|
16780
|
-
* Internal Defaults.
|
|
16781
|
-
* @private
|
|
16782
|
-
* @returns {void}
|
|
16783
|
-
*/
|
|
16784
|
-
_initializePrivateDefaults() {
|
|
16770
|
+
// Single-source initialization. Alphabetized so duplicate or stale
|
|
16771
|
+
// defaults are immediately obvious on a diff. Every field is assigned
|
|
16772
|
+
// exactly once here (previously the constructor + the old
|
|
16773
|
+
// `_initializePrivateDefaults` overlapped — both wrote ~14 of the same
|
|
16774
|
+
// fields and double-allocated `util` and `validation`, discarding the
|
|
16775
|
+
// first instance). `validation` is now allocated exactly once; `util`
|
|
16776
|
+
// is seeded here with an en-US default and then rebuilt in
|
|
16777
|
+
// `connectedCallback` once the consumer-resolved locale is available,
|
|
16778
|
+
// so a parent (datepicker/combobox) calling `validate()` synchronously
|
|
16779
|
+
// during its own update cycle sees a populated util instance.
|
|
16785
16780
|
this.activeLabel = false;
|
|
16786
|
-
this.appearance = "default";
|
|
16787
|
-
this.icon = false;
|
|
16788
|
-
this.disabled = false;
|
|
16789
|
-
this.dvInputOnly = false;
|
|
16790
|
-
this.hideLabelVisually = false;
|
|
16791
|
-
this.max = undefined;
|
|
16792
|
-
this.maxLength = undefined;
|
|
16793
|
-
this.min = undefined;
|
|
16794
|
-
this.minLength = undefined;
|
|
16795
|
-
this.noValidate = false;
|
|
16796
|
-
this.onDark = false;
|
|
16797
|
-
this.required = false;
|
|
16798
|
-
this.setCustomValidityForType = undefined;
|
|
16799
|
-
|
|
16800
|
-
// Used for storing raw values returned from input mask.
|
|
16801
|
-
this._rawMaskValue = undefined;
|
|
16802
|
-
|
|
16803
|
-
/**
|
|
16804
|
-
* @private
|
|
16805
|
-
*/
|
|
16806
|
-
this.layout = 'classic';
|
|
16807
|
-
|
|
16808
|
-
/**
|
|
16809
|
-
* @private
|
|
16810
|
-
*/
|
|
16811
|
-
this.shape = 'classic';
|
|
16812
|
-
|
|
16813
|
-
/**
|
|
16814
|
-
* @private
|
|
16815
|
-
*/
|
|
16816
|
-
this.size = 'lg';
|
|
16817
|
-
|
|
16818
|
-
this.touched = false;
|
|
16819
|
-
this.util = new AuroInputUtilities({
|
|
16820
|
-
locale: "en-US",
|
|
16821
|
-
format: this.format
|
|
16822
|
-
});
|
|
16823
|
-
this.validation = new AuroFormValidation();
|
|
16824
|
-
this.inputIconName = undefined;
|
|
16825
|
-
this.showPassword = false;
|
|
16826
|
-
this.validationCCLength = undefined;
|
|
16827
|
-
this.hasValue = false;
|
|
16828
|
-
this.label = 'Input label is undefined';
|
|
16829
|
-
|
|
16830
16781
|
|
|
16782
|
+
/** @private */
|
|
16831
16783
|
this.allowedInputTypes = [
|
|
16832
16784
|
"text",
|
|
16833
16785
|
"number",
|
|
@@ -16836,7 +16788,9 @@ class BaseInput extends AuroElement$1 {
|
|
|
16836
16788
|
"credit-card",
|
|
16837
16789
|
"tel"
|
|
16838
16790
|
];
|
|
16839
|
-
this.
|
|
16791
|
+
this.appearance = "default";
|
|
16792
|
+
|
|
16793
|
+
/** @private */
|
|
16840
16794
|
this.dateFormatMap = {
|
|
16841
16795
|
'mm/dd/yyyy': 'dateMMDDYYYY',
|
|
16842
16796
|
'dd/mm/yyyy': 'dateDDMMYYYY',
|
|
@@ -16853,27 +16807,62 @@ class BaseInput extends AuroElement$1 {
|
|
|
16853
16807
|
'dd/mm': 'dateDDMM',
|
|
16854
16808
|
'mm/dd': 'dateMMDD'
|
|
16855
16809
|
};
|
|
16810
|
+
this.disabled = false;
|
|
16811
|
+
|
|
16812
|
+
/** @private */
|
|
16856
16813
|
this.domHandler = new DomHandler();
|
|
16857
16814
|
this.dvInputOnly = false;
|
|
16858
16815
|
this.hasValue = false;
|
|
16816
|
+
this.hideLabelVisually = false;
|
|
16817
|
+
this.icon = false;
|
|
16818
|
+
|
|
16819
|
+
/** @private */
|
|
16859
16820
|
this.inputIconName = undefined;
|
|
16821
|
+
|
|
16822
|
+
/** @private */
|
|
16860
16823
|
this.label = 'Input label is undefined';
|
|
16824
|
+
this.layout = 'classic';
|
|
16825
|
+
this.locale = 'en-US';
|
|
16826
|
+
this.max = undefined;
|
|
16827
|
+
this.maxLength = undefined;
|
|
16828
|
+
this.min = undefined;
|
|
16829
|
+
this.minLength = undefined;
|
|
16861
16830
|
this.noValidate = false;
|
|
16862
|
-
this.
|
|
16831
|
+
this.onDark = false;
|
|
16832
|
+
// Raw values returned from the input mask before model normalization.
|
|
16833
|
+
this._rawMaskValue = undefined;
|
|
16834
|
+
this.required = false;
|
|
16835
|
+
this.setCustomValidityForType = undefined;
|
|
16836
|
+
// Credit Card is intentionally excluded — its mask manages the cursor
|
|
16837
|
+
// itself, and listing it here caused cursor placement issues in Safari.
|
|
16838
|
+
/** @private */
|
|
16863
16839
|
this.setSelectionInputTypes = [
|
|
16864
16840
|
"text",
|
|
16865
16841
|
"password",
|
|
16866
16842
|
"email"
|
|
16867
|
-
];
|
|
16843
|
+
];
|
|
16844
|
+
this.shape = 'classic';
|
|
16845
|
+
|
|
16846
|
+
/** @private */
|
|
16868
16847
|
this.showPassword = false;
|
|
16848
|
+
this.size = 'lg';
|
|
16869
16849
|
this.touched = false;
|
|
16850
|
+
|
|
16851
|
+
/** @private */
|
|
16870
16852
|
this.uniqueId = new UniqueId().create();
|
|
16853
|
+
|
|
16854
|
+
/** @private */
|
|
16871
16855
|
this.util = new AuroInputUtilities({
|
|
16872
16856
|
locale: this.locale,
|
|
16873
16857
|
format: this.format
|
|
16874
16858
|
});
|
|
16859
|
+
|
|
16860
|
+
/** @private */
|
|
16875
16861
|
this.validation = new AuroFormValidation();
|
|
16862
|
+
|
|
16863
|
+
/** @private */
|
|
16876
16864
|
this.validationCCLength = undefined;
|
|
16865
|
+
this.value = undefined;
|
|
16877
16866
|
}
|
|
16878
16867
|
|
|
16879
16868
|
// function to define props used within the scope of this component
|
|
@@ -17311,7 +17300,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17311
17300
|
* @returns {Date|undefined}
|
|
17312
17301
|
*/
|
|
17313
17302
|
get valueObject() {
|
|
17314
|
-
return this.
|
|
17303
|
+
return this.value && dateFormatter.isValidDate(this.value) ? dateFormatter.stringToDateInstance(this.value) : undefined;
|
|
17315
17304
|
}
|
|
17316
17305
|
|
|
17317
17306
|
/**
|
|
@@ -17319,7 +17308,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17319
17308
|
* @returns {Date|undefined}
|
|
17320
17309
|
*/
|
|
17321
17310
|
get minObject() {
|
|
17322
|
-
return this.
|
|
17311
|
+
return this.min && dateFormatter.isValidDate(this.min) ? dateFormatter.stringToDateInstance(this.min) : undefined;
|
|
17323
17312
|
}
|
|
17324
17313
|
|
|
17325
17314
|
/**
|
|
@@ -17327,50 +17316,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17327
17316
|
* @returns {Date|undefined}
|
|
17328
17317
|
*/
|
|
17329
17318
|
get maxObject() {
|
|
17330
|
-
return this.
|
|
17331
|
-
}
|
|
17332
|
-
|
|
17333
|
-
/**
|
|
17334
|
-
* Parses a date string into a Date object when the corresponding `_*Object`
|
|
17335
|
-
* field hasn't been synced yet by `updated()`. Returns undefined when the
|
|
17336
|
-
* input type/format isn't a full date or the string is not a valid date.
|
|
17337
|
-
*
|
|
17338
|
-
* Why this exists: a parent (datepicker) can call `inputN.validate()` from
|
|
17339
|
-
* inside its own `updated()` before this input's `updated()` has run
|
|
17340
|
-
* `syncDateValues()` — so `_valueObject`/`_maxObject` are still `undefined`
|
|
17341
|
-
* and range checks would otherwise silently no-op (flipping the result to
|
|
17342
|
-
* `valid` or `patternMismatch`).
|
|
17343
|
-
* @private
|
|
17344
|
-
* @param {string|undefined} dateStr - ISO date string from `value`/`min`/`max`.
|
|
17345
|
-
* @returns {Date|undefined}
|
|
17346
|
-
*/
|
|
17347
|
-
_computeDateObjectFallback(dateStr) {
|
|
17348
|
-
if (!dateStr || !this.util || !this.util.isFullDateFormat(this.type, this.format)) {
|
|
17349
|
-
return undefined;
|
|
17350
|
-
}
|
|
17351
|
-
if (!dateFormatter.isValidDate(dateStr)) {
|
|
17352
|
-
return undefined;
|
|
17353
|
-
}
|
|
17354
|
-
return dateFormatter.stringToDateInstance(dateStr);
|
|
17355
|
-
}
|
|
17356
|
-
|
|
17357
|
-
/**
|
|
17358
|
-
* Internal setter for readonly date object properties.
|
|
17359
|
-
* @private
|
|
17360
|
-
* @param {'valueObject'|'minObject'|'maxObject'} propertyName - Public object property name.
|
|
17361
|
-
* @param {Date|undefined} propertyValue - Value to assign.
|
|
17362
|
-
* @returns {void}
|
|
17363
|
-
*/
|
|
17364
|
-
setDateObjectProperty(propertyName, propertyValue) {
|
|
17365
|
-
const internalPropertyName = `_${propertyName}`;
|
|
17366
|
-
const previousValue = this[internalPropertyName];
|
|
17367
|
-
|
|
17368
|
-
if (previousValue === propertyValue) {
|
|
17369
|
-
return;
|
|
17370
|
-
}
|
|
17371
|
-
|
|
17372
|
-
this[internalPropertyName] = propertyValue;
|
|
17373
|
-
this.requestUpdate(propertyName, previousValue);
|
|
17319
|
+
return this.max && dateFormatter.isValidDate(this.max) ? dateFormatter.stringToDateInstance(this.max) : undefined;
|
|
17374
17320
|
}
|
|
17375
17321
|
|
|
17376
17322
|
connectedCallback() {
|
|
@@ -17399,7 +17345,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17399
17345
|
format: this.format
|
|
17400
17346
|
});
|
|
17401
17347
|
this.configureDataForType();
|
|
17402
|
-
this.syncDateValues();
|
|
17403
17348
|
}
|
|
17404
17349
|
|
|
17405
17350
|
disconnectedCallback() {
|
|
@@ -17419,12 +17364,17 @@ class BaseInput extends AuroElement$1 {
|
|
|
17419
17364
|
this.wrapperElement.addEventListener('click', this.handleClick);
|
|
17420
17365
|
}
|
|
17421
17366
|
|
|
17422
|
-
// add attribute for query selectors when auro-input is registered under a custom name
|
|
17423
|
-
if (this.tagName.toLowerCase() !== 'auro-input' && !this.hasAttribute('auro-input')) {
|
|
17424
|
-
this.setAttribute('auro-input', '');
|
|
17425
|
-
}
|
|
17426
17367
|
this.inputId = this.id ? `${this.id}-input` : window.crypto.randomUUID();
|
|
17427
17368
|
|
|
17369
|
+
// Normalize the format token to lowercase so case-mixed values supplied
|
|
17370
|
+
// via attribute (e.g. `format="MM/DD/YYYY"`) hit the `dateFormatMap`
|
|
17371
|
+
// lookup inside `setCustomHelpTextMessage`. Without this, an uppercase
|
|
17372
|
+
// format silently misses the map and leaves `setCustomValidityForType`
|
|
17373
|
+
// unset.
|
|
17374
|
+
if (this.format) {
|
|
17375
|
+
this.format = this.format.toLowerCase();
|
|
17376
|
+
}
|
|
17377
|
+
|
|
17428
17378
|
// use validity message override if declared when initializing the component
|
|
17429
17379
|
if (this.hasAttribute('setCustomValidity')) {
|
|
17430
17380
|
this.ValidityMessageOverride = this.setCustomValidity;
|
|
@@ -17433,7 +17383,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17433
17383
|
this.setCustomHelpTextMessage();
|
|
17434
17384
|
this.configureAutoFormatting();
|
|
17435
17385
|
this.configureDataForType();
|
|
17436
|
-
this.syncDateValues();
|
|
17437
17386
|
}
|
|
17438
17387
|
|
|
17439
17388
|
/**
|
|
@@ -17509,6 +17458,13 @@ class BaseInput extends AuroElement$1 {
|
|
|
17509
17458
|
|
|
17510
17459
|
if (typeToI18n.includes(this.type)) {
|
|
17511
17460
|
this.setCustomValidityForType = i18n(this.lang, this.type);
|
|
17461
|
+
// COVERAGE: this `else if` branch is unreachable in WTR. connectedCallback
|
|
17462
|
+
// (L682) calls configureDataForType, which at L1266-1268 assigns
|
|
17463
|
+
// `this.format = this.util.getDateMaskFromLocale().toLowerCase()` for any
|
|
17464
|
+
// type=date input whose `format` attribute is unset. That runs before
|
|
17465
|
+
// firstUpdated invokes setCustomHelpTextMessage, so `!this.format` is
|
|
17466
|
+
// always false here. Retained as a defensive fallback; the whole function
|
|
17467
|
+
// is @deprecated per AB#1557296 and slated for removal.
|
|
17512
17468
|
} else if (!this.format && this.type === 'date') {
|
|
17513
17469
|
this.setCustomValidityForType = i18n(this.lang, 'dateMMDDYYYY');
|
|
17514
17470
|
} else if (this.dateFormatMap[this.format]) {
|
|
@@ -17570,8 +17526,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17570
17526
|
this.configureDataForType();
|
|
17571
17527
|
}
|
|
17572
17528
|
|
|
17573
|
-
this.syncDateValues(changedProperties);
|
|
17574
|
-
|
|
17575
17529
|
if (changedProperties.has('value')) {
|
|
17576
17530
|
if (this.value && this.value.length > 0) {
|
|
17577
17531
|
this.hasValue = true;
|
|
@@ -17593,14 +17547,14 @@ class BaseInput extends AuroElement$1 {
|
|
|
17593
17547
|
|
|
17594
17548
|
if (formattedValue !== this.inputElement.value) {
|
|
17595
17549
|
this.skipNextProgrammaticInputEvent = true;
|
|
17596
|
-
if (this.maskInstance && this.type
|
|
17550
|
+
if (this.maskInstance && this.type !== 'date') {
|
|
17597
17551
|
// Route through the mask so its _value and el.value stay in lock-step
|
|
17598
17552
|
// (set value calls updateControl which writes el.value = displayValue).
|
|
17599
17553
|
// Writing el.value directly leaves the mask thinking displayValue is
|
|
17600
|
-
// stale; _saveSelection on the next focus/click then warns.
|
|
17601
|
-
//
|
|
17602
|
-
//
|
|
17603
|
-
//
|
|
17554
|
+
// stale; _saveSelection on the next focus/click then warns. Date is
|
|
17555
|
+
// excluded because its formattedValue can be raw ISO when the calendar
|
|
17556
|
+
// is invalid, and re-masking through mm/dd/yyyy would truncate it and
|
|
17557
|
+
// flip validity from patternMismatch to tooShort.
|
|
17604
17558
|
this.maskInstance.value = formattedValue || '';
|
|
17605
17559
|
} else if (formattedValue) {
|
|
17606
17560
|
this.inputElement.value = formattedValue;
|
|
@@ -17642,120 +17596,65 @@ class BaseInput extends AuroElement$1 {
|
|
|
17642
17596
|
}));
|
|
17643
17597
|
}
|
|
17644
17598
|
|
|
17645
|
-
|
|
17646
|
-
/**
|
|
17647
|
-
* Synchronizes the ISO string values and Date object representations for date-related properties.
|
|
17648
|
-
* This keeps the model and display values aligned when either side changes.
|
|
17649
|
-
*
|
|
17650
|
-
* When a full date format is in use, this method updates `value`, `min`, and `max` from their corresponding
|
|
17651
|
-
* Date objects or vice versa, based on which properties have changed. It only runs when the current configuration
|
|
17652
|
-
* represents a full year/month/day date format.
|
|
17653
|
-
*
|
|
17654
|
-
* @param {Map<string, unknown>|undefined} [changedProperties=undefined] - Optional map of changed properties used to limit which values are synchronized.
|
|
17655
|
-
* @returns {void}
|
|
17656
|
-
* @private
|
|
17657
|
-
*/
|
|
17658
|
-
syncDateValues(changedProperties = undefined) {
|
|
17659
|
-
if (!this.util.isFullDateFormat(this.type, this.format)) {
|
|
17660
|
-
return;
|
|
17661
|
-
}
|
|
17662
|
-
|
|
17663
|
-
this.syncSingleDateValue(changedProperties, 'valueObject', 'value');
|
|
17664
|
-
this.syncSingleDateValue(changedProperties, 'minObject', 'min');
|
|
17665
|
-
this.syncSingleDateValue(changedProperties, 'maxObject', 'max');
|
|
17666
|
-
}
|
|
17667
|
-
|
|
17668
|
-
/**
|
|
17669
|
-
* Synchronizes one date object/string property pair.
|
|
17670
|
-
* @private
|
|
17671
|
-
* @param {Map<string, unknown>|undefined} changedProperties - Map of changed properties from Lit.
|
|
17672
|
-
* @param {string} objectProperty - Date object property name.
|
|
17673
|
-
* @param {string} valueProperty - ISO string property name.
|
|
17674
|
-
* @returns {void}
|
|
17675
|
-
*/
|
|
17676
|
-
syncSingleDateValue(changedProperties, objectProperty, valueProperty) {
|
|
17677
|
-
const objectPropertyChanged = !changedProperties || changedProperties.has(objectProperty);
|
|
17678
|
-
|
|
17679
|
-
// objectProperty wins over valueProperty when both changed
|
|
17680
|
-
if (objectPropertyChanged && this[objectProperty]) {
|
|
17681
|
-
this[valueProperty] = dateFormatter.toISOFormatString(this[objectProperty]);
|
|
17682
|
-
return;
|
|
17683
|
-
}
|
|
17684
|
-
|
|
17685
|
-
const valuePropertyChanged = !changedProperties || changedProperties.has(valueProperty);
|
|
17686
|
-
if (!valuePropertyChanged) {
|
|
17687
|
-
return;
|
|
17688
|
-
}
|
|
17689
|
-
|
|
17690
|
-
// 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)
|
|
17691
|
-
if (
|
|
17692
|
-
changedProperties &&
|
|
17693
|
-
valueProperty === 'value' &&
|
|
17694
|
-
changedProperties.get('value') === undefined &&
|
|
17695
|
-
this[objectProperty] instanceof Date &&
|
|
17696
|
-
this[valueProperty] === dateFormatter.toISOFormatString(this[objectProperty])
|
|
17697
|
-
) {
|
|
17698
|
-
return;
|
|
17699
|
-
}
|
|
17700
|
-
|
|
17701
|
-
if (dateFormatter.isValidDate(this[valueProperty])) {
|
|
17702
|
-
this.setDateObjectProperty(objectProperty, dateFormatter.stringToDateInstance(this[valueProperty]));
|
|
17703
|
-
} else {
|
|
17704
|
-
this.setDateObjectProperty(objectProperty, undefined);
|
|
17705
|
-
}
|
|
17706
|
-
}
|
|
17707
|
-
|
|
17708
17599
|
/**
|
|
17709
17600
|
* Sets up IMasks and logic based on auto-formatting requirements.
|
|
17710
17601
|
* @private
|
|
17711
17602
|
* @returns {void}
|
|
17712
17603
|
*/
|
|
17713
17604
|
configureAutoFormatting() {
|
|
17714
|
-
//
|
|
17715
|
-
//
|
|
17716
|
-
//
|
|
17717
|
-
//
|
|
17605
|
+
// _configuringMask gates two things: external re-entry into this method
|
|
17606
|
+
// while setup is mid-flight (from property changes that call back here),
|
|
17607
|
+
// and the accept/complete listeners below — both need to ignore the mask
|
|
17608
|
+
// events fired by our own value-restore step.
|
|
17718
17609
|
if (this._configuringMask) return;
|
|
17719
17610
|
this._configuringMask = true;
|
|
17720
17611
|
try {
|
|
17612
|
+
// Destroy any prior mask so IMask can attach fresh under the new format.
|
|
17613
|
+
// Null the reference too — if the new maskOptions.mask is falsy (e.g.
|
|
17614
|
+
// type switched from credit-card to text) the IMask() reassignment
|
|
17615
|
+
// below is skipped, and downstream writes at line ~823 would otherwise
|
|
17616
|
+
// route through the destroyed instance.
|
|
17721
17617
|
if (this.maskInstance) {
|
|
17722
17618
|
this.maskInstance.destroy();
|
|
17619
|
+
this.maskInstance = null;
|
|
17723
17620
|
}
|
|
17724
17621
|
|
|
17725
|
-
// Pass new format to util
|
|
17726
17622
|
this.util.updateFormat(this.format);
|
|
17727
17623
|
|
|
17728
17624
|
const maskOptions = this.util.getMaskOptions(this.type, this.format);
|
|
17729
17625
|
|
|
17730
17626
|
if (this.inputElement && maskOptions.mask) {
|
|
17731
|
-
|
|
17732
|
-
//
|
|
17733
|
-
//
|
|
17734
|
-
//
|
|
17735
|
-
// When the format changes (e.g. locale switch) and we have a valid ISO
|
|
17736
|
-
// model value, compute the display string for the NEW format instead of
|
|
17737
|
-
// re-using the old display string, which may be invalid in the new mask.
|
|
17627
|
+
// Capture the current display so it can be re-applied after IMask
|
|
17628
|
+
// attaches. The restore at the bottom goes through maskInstance.value
|
|
17629
|
+
// (not inputElement.value directly) so the mask's internal state and
|
|
17630
|
+
// the input's displayed text stay in lock-step.
|
|
17738
17631
|
let existingValue = this.inputElement.value;
|
|
17632
|
+
|
|
17633
|
+
// Format-change case (e.g. locale switch): existingValue is the OLD
|
|
17634
|
+
// mask's display string and may not parse under the new mask. When
|
|
17635
|
+
// we have a valid date model, rebuild the display from valueObject
|
|
17636
|
+
// (the canonical source) using the new mask's format function.
|
|
17739
17637
|
if (
|
|
17740
17638
|
this.util.isFullDateFormat(this.type, this.format) &&
|
|
17741
17639
|
this.value &&
|
|
17742
|
-
|
|
17743
|
-
this.valueObject instanceof Date &&
|
|
17744
|
-
!Number.isNaN(this.valueObject.getTime()) &&
|
|
17640
|
+
this.valueObject &&
|
|
17745
17641
|
typeof maskOptions.format === 'function'
|
|
17746
17642
|
) {
|
|
17747
17643
|
existingValue = maskOptions.format(this.valueObject);
|
|
17748
17644
|
}
|
|
17749
17645
|
|
|
17646
|
+
// Clear before IMask attaches so the constructor seeds an empty
|
|
17647
|
+
// internal value. Otherwise IMask reads the stale unmasked string
|
|
17648
|
+
// and emits a spurious 'accept' before the restore below runs.
|
|
17750
17649
|
this.skipNextProgrammaticInputEvent = true;
|
|
17751
17650
|
this.inputElement.value = '';
|
|
17752
17651
|
|
|
17753
17652
|
this.maskInstance = IMask(this.inputElement, maskOptions);
|
|
17754
17653
|
|
|
17654
|
+
// Mask fires 'accept' on every value change, including the restore
|
|
17655
|
+
// step below. Skip events fired during configureAutoFormatting so
|
|
17656
|
+
// we don't overwrite a value the parent just pushed.
|
|
17755
17657
|
this.maskInstance.on('accept', () => {
|
|
17756
|
-
// Suppress propagation during configureAutoFormatting's own value-restoration
|
|
17757
|
-
// (line below) — the mask emits 'accept' on every value-set, including ours,
|
|
17758
|
-
// and we don't want to overwrite a value the parent just pushed.
|
|
17759
17658
|
if (this._configuringMask) return;
|
|
17760
17659
|
this.value = this.util.toModelValue(this.maskInstance.value, this.format);
|
|
17761
17660
|
if (this.type === "date") {
|
|
@@ -17763,6 +17662,8 @@ class BaseInput extends AuroElement$1 {
|
|
|
17763
17662
|
}
|
|
17764
17663
|
});
|
|
17765
17664
|
|
|
17665
|
+
// Mask fires 'complete' on the restore step below for any value that
|
|
17666
|
+
// happens to be a complete match. Same setup-suppression as 'accept'.
|
|
17766
17667
|
this.maskInstance.on('complete', () => {
|
|
17767
17668
|
if (this._configuringMask) return;
|
|
17768
17669
|
this.value = this.util.toModelValue(this.maskInstance.value, this.format);
|
|
@@ -17771,7 +17672,9 @@ class BaseInput extends AuroElement$1 {
|
|
|
17771
17672
|
}
|
|
17772
17673
|
});
|
|
17773
17674
|
|
|
17774
|
-
//
|
|
17675
|
+
// Write existingValue through the mask (not the input directly) so
|
|
17676
|
+
// the mask reformats it under the new rules and keeps its internal
|
|
17677
|
+
// _value aligned with the input's displayed text.
|
|
17775
17678
|
if (existingValue) {
|
|
17776
17679
|
this.maskInstance.value = existingValue;
|
|
17777
17680
|
}
|
|
@@ -17851,6 +17754,38 @@ class BaseInput extends AuroElement$1 {
|
|
|
17851
17754
|
this.touched = true;
|
|
17852
17755
|
this.validation.validate(this);
|
|
17853
17756
|
}
|
|
17757
|
+
|
|
17758
|
+
// Prevents cursor jumping in Safari. Setting `this.value` triggers a Lit
|
|
17759
|
+
// update that can re-render the input and reset the native cursor; we
|
|
17760
|
+
// capture the caret position before that update commits and restore it
|
|
17761
|
+
// via `setSelectionRange` once the update has flushed. Gated on
|
|
17762
|
+
// `setSelectionInputTypes` so credit-card (and other masked types whose
|
|
17763
|
+
// formatter manages the cursor itself) doesn't get a competing write.
|
|
17764
|
+
// Capture the caret position INSIDE the gate — reading `selectionStart`
|
|
17765
|
+
// on input types that don't support text selection (number, email in
|
|
17766
|
+
// some browsers) throws InvalidStateError, which would crash all input
|
|
17767
|
+
// handling. Wrap the read in try/catch belt-and-suspenders even though
|
|
17768
|
+
// the gated types currently support it, since the list is a public
|
|
17769
|
+
// property a consumer could mutate.
|
|
17770
|
+
if (this.setSelectionInputTypes.includes(this.type)) {
|
|
17771
|
+
let selectionStart = null;
|
|
17772
|
+
try {
|
|
17773
|
+
({ selectionStart } = this.inputElement);
|
|
17774
|
+
} catch (error) { // eslint-disable-line no-unused-vars
|
|
17775
|
+
return;
|
|
17776
|
+
}
|
|
17777
|
+
if (typeof selectionStart !== 'number') {
|
|
17778
|
+
return;
|
|
17779
|
+
}
|
|
17780
|
+
this.updateComplete.then(() => {
|
|
17781
|
+
try {
|
|
17782
|
+
this.inputElement.setSelectionRange(selectionStart, selectionStart);
|
|
17783
|
+
} catch (error) { // eslint-disable-line no-unused-vars
|
|
17784
|
+
// Some input types (number/email in certain UAs) throw on
|
|
17785
|
+
// setSelectionRange; swallow and let the native cursor stand.
|
|
17786
|
+
}
|
|
17787
|
+
});
|
|
17788
|
+
}
|
|
17854
17789
|
}
|
|
17855
17790
|
|
|
17856
17791
|
/**
|
|
@@ -17939,7 +17874,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17939
17874
|
*/
|
|
17940
17875
|
reset() {
|
|
17941
17876
|
this.value = undefined;
|
|
17942
|
-
this.setDateObjectProperty('valueObject', undefined);
|
|
17943
17877
|
this.validation.reset(this);
|
|
17944
17878
|
}
|
|
17945
17879
|
|
|
@@ -17948,7 +17882,6 @@ class BaseInput extends AuroElement$1 {
|
|
|
17948
17882
|
*/
|
|
17949
17883
|
clear() {
|
|
17950
17884
|
this.value = undefined;
|
|
17951
|
-
this.setDateObjectProperty('valueObject', undefined);
|
|
17952
17885
|
}
|
|
17953
17886
|
|
|
17954
17887
|
/**
|
|
@@ -17986,7 +17919,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
17986
17919
|
*/
|
|
17987
17920
|
get placeholderStr() {
|
|
17988
17921
|
if (!this.placeholder && this.type === 'date') {
|
|
17989
|
-
return this.format
|
|
17922
|
+
return this.format.toUpperCase();
|
|
17990
17923
|
}
|
|
17991
17924
|
return this.placeholder || "";
|
|
17992
17925
|
}
|
|
@@ -18477,7 +18410,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$3 {
|
|
|
18477
18410
|
}
|
|
18478
18411
|
};
|
|
18479
18412
|
|
|
18480
|
-
var formkitVersion$1 = '
|
|
18413
|
+
var formkitVersion$1 = '202607010100';
|
|
18481
18414
|
|
|
18482
18415
|
// Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
18483
18416
|
// See LICENSE in the project root for license information.
|
|
@@ -18980,6 +18913,7 @@ class AuroInput extends BaseInput {
|
|
|
18980
18913
|
<${this.buttonTag}
|
|
18981
18914
|
@click="${this.handleClickShowPassword}"
|
|
18982
18915
|
appearance="${this.onDark ? 'inverse' : this.appearance}"
|
|
18916
|
+
aria-pressed="${this.showPassword ? 'true' : 'false'}"
|
|
18983
18917
|
class="notificationBtn passwordBtn"
|
|
18984
18918
|
shape="circle"
|
|
18985
18919
|
size="sm"
|
|
@@ -19053,25 +18987,29 @@ class AuroInput extends BaseInput {
|
|
|
19053
18987
|
* @returns {html} - Returns HTML for the help text and error message.
|
|
19054
18988
|
*/
|
|
19055
18989
|
renderHtmlHelpText() {
|
|
18990
|
+
// Single `<p>` with stable identity across validity transitions —
|
|
18991
|
+
// previously two distinct templates (valid vs invalid) caused Lit to
|
|
18992
|
+
// replace the node entirely on a flip, and VoiceOver wouldn't
|
|
18993
|
+
// re-announce because the live-region element it was watching had been
|
|
18994
|
+
// removed and a new one inserted. Keeping one node means the `role`,
|
|
18995
|
+
// `aria-live`, and text content all change in-place, which AT does
|
|
18996
|
+
// observe and announce.
|
|
18997
|
+
const isError = this.validity && this.validity !== 'valid';
|
|
19056
18998
|
return u$7`
|
|
19057
|
-
|
|
19058
|
-
?
|
|
19059
|
-
|
|
19060
|
-
|
|
19061
|
-
|
|
19062
|
-
|
|
19063
|
-
|
|
19064
|
-
|
|
19065
|
-
|
|
19066
|
-
|
|
19067
|
-
|
|
19068
|
-
|
|
19069
|
-
|
|
19070
|
-
|
|
19071
|
-
</p>
|
|
19072
|
-
</${this.helpTextTag}>
|
|
19073
|
-
`
|
|
19074
|
-
}
|
|
18999
|
+
<${this.helpTextTag}
|
|
19000
|
+
appearance="${this.onDark ? 'inverse' : this.appearance}"
|
|
19001
|
+
?error=${isError}>
|
|
19002
|
+
<p
|
|
19003
|
+
id="${this.uniqueId}"
|
|
19004
|
+
part="helpText"
|
|
19005
|
+
role="${o(isError ? 'alert' : undefined)}"
|
|
19006
|
+
aria-live="${o(isError ? 'assertive' : undefined)}">
|
|
19007
|
+
${isError
|
|
19008
|
+
? this.errorMessage
|
|
19009
|
+
: u$7`<slot name="helpText">${this.getHelpText()}</slot>`
|
|
19010
|
+
}
|
|
19011
|
+
</p>
|
|
19012
|
+
</${this.helpTextTag}>
|
|
19075
19013
|
`;
|
|
19076
19014
|
}
|
|
19077
19015
|
|
|
@@ -19203,7 +19141,7 @@ class AuroInput extends BaseInput {
|
|
|
19203
19141
|
|
|
19204
19142
|
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)}`;
|
|
19205
19143
|
|
|
19206
|
-
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
|
|
19144
|
+
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)}`;
|
|
19207
19145
|
|
|
19208
19146
|
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)}`;
|
|
19209
19147
|
|
|
@@ -19598,7 +19536,7 @@ class AuroBibtemplate extends i$3 {
|
|
|
19598
19536
|
}
|
|
19599
19537
|
}
|
|
19600
19538
|
|
|
19601
|
-
var formkitVersion = '
|
|
19539
|
+
var formkitVersion = '202607010100';
|
|
19602
19540
|
|
|
19603
19541
|
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}`;
|
|
19604
19542
|
|
|
@@ -19966,12 +19904,23 @@ function getOptionLabel(option) {
|
|
|
19966
19904
|
if (!option) {
|
|
19967
19905
|
return '';
|
|
19968
19906
|
}
|
|
19969
|
-
|
|
19970
|
-
|
|
19971
|
-
if (
|
|
19972
|
-
|
|
19907
|
+
|
|
19908
|
+
// Consumer-provided override: short-circuit the DOM walk entirely.
|
|
19909
|
+
if (option.dataset && option.dataset.label) {
|
|
19910
|
+
return option.dataset.label;
|
|
19911
|
+
}
|
|
19912
|
+
|
|
19913
|
+
// Walk direct children — the `slot` attribute only applies to direct children
|
|
19914
|
+
// of the slot host, so a shallow filter is sufficient. Avoids the cloneNode +
|
|
19915
|
+
// querySelector allocation that ran on every keystroke via syncValuesAndStates.
|
|
19916
|
+
let text = '';
|
|
19917
|
+
for (const node of option.childNodes) {
|
|
19918
|
+
const isDisplayValueSlot = node.nodeType === Node.ELEMENT_NODE && node.getAttribute('slot') === 'displayValue';
|
|
19919
|
+
if (!isDisplayValueSlot) {
|
|
19920
|
+
text += node.textContent || '';
|
|
19921
|
+
}
|
|
19973
19922
|
}
|
|
19974
|
-
return
|
|
19923
|
+
return text.replace(/\s+/gu, ' ').trim();
|
|
19975
19924
|
}
|
|
19976
19925
|
|
|
19977
19926
|
// See https://git.io/JJ6SJ for "How to document your components using JSDoc"
|
|
@@ -20046,8 +19995,6 @@ class AuroCombobox extends AuroElement {
|
|
|
20046
19995
|
this.availableOptions = [];
|
|
20047
19996
|
this.dropdownId = undefined;
|
|
20048
19997
|
this.dropdownOpen = false;
|
|
20049
|
-
this.triggerExpandedState = false;
|
|
20050
|
-
this._expandedTimeout = null;
|
|
20051
19998
|
this._inFullscreenTransition = false;
|
|
20052
19999
|
this.errorMessage = null;
|
|
20053
20000
|
this.isHiddenWhileLoading = false;
|
|
@@ -20058,6 +20005,30 @@ class AuroCombobox extends AuroElement {
|
|
|
20058
20005
|
this.touched = false;
|
|
20059
20006
|
this.validation = new AuroFormValidation$1();
|
|
20060
20007
|
this.validity = undefined;
|
|
20008
|
+
this._userTyped = false;
|
|
20009
|
+
// Tracks every setTimeout scheduled via _scheduleTimer so
|
|
20010
|
+
// disconnectedCallback can cancel them. Without this, a detached
|
|
20011
|
+
// combobox's pending timers still fire — most are no-ops, but
|
|
20012
|
+
// configureMenu's racing-condition retry would otherwise loop.
|
|
20013
|
+
this._pendingTimers = new Set();
|
|
20014
|
+
}
|
|
20015
|
+
|
|
20016
|
+
/**
|
|
20017
|
+
* setTimeout wrapper that records the timer id so disconnectedCallback
|
|
20018
|
+
* can cancel any outstanding callbacks. The id is removed from the set
|
|
20019
|
+
* once the callback fires so the set doesn't grow unbounded.
|
|
20020
|
+
* @param {Function} fn - Callback to run.
|
|
20021
|
+
* @param {number} ms - Delay in milliseconds.
|
|
20022
|
+
* @returns {number} The timer id.
|
|
20023
|
+
* @private
|
|
20024
|
+
*/
|
|
20025
|
+
_scheduleTimer(fn, ms) {
|
|
20026
|
+
const id = setTimeout(() => {
|
|
20027
|
+
this._pendingTimers.delete(id);
|
|
20028
|
+
fn();
|
|
20029
|
+
}, ms);
|
|
20030
|
+
this._pendingTimers.add(id);
|
|
20031
|
+
return id;
|
|
20061
20032
|
}
|
|
20062
20033
|
|
|
20063
20034
|
// This function is to define props used within the scope of this component
|
|
@@ -20419,17 +20390,6 @@ class AuroCombobox extends AuroElement {
|
|
|
20419
20390
|
attribute: false
|
|
20420
20391
|
},
|
|
20421
20392
|
|
|
20422
|
-
/**
|
|
20423
|
-
* Deferred aria-expanded state for the trigger input.
|
|
20424
|
-
* Delays the "true" transition so VoiceOver finishes its character echo
|
|
20425
|
-
* before announcing "expanded".
|
|
20426
|
-
* @private
|
|
20427
|
-
*/
|
|
20428
|
-
triggerExpandedState: {
|
|
20429
|
-
type: Boolean,
|
|
20430
|
-
reflect: false,
|
|
20431
|
-
attribute: false
|
|
20432
|
-
},
|
|
20433
20393
|
};
|
|
20434
20394
|
}
|
|
20435
20395
|
|
|
@@ -20452,13 +20412,6 @@ class AuroCombobox extends AuroElement {
|
|
|
20452
20412
|
return this.input.value;
|
|
20453
20413
|
}
|
|
20454
20414
|
|
|
20455
|
-
// /**
|
|
20456
|
-
// * Sets the value of the input element within the combobox.
|
|
20457
|
-
// */
|
|
20458
|
-
// set inputValue(value) {
|
|
20459
|
-
// this.input.value = value;
|
|
20460
|
-
// }
|
|
20461
|
-
|
|
20462
20415
|
/**
|
|
20463
20416
|
* Checks if the element is valid.
|
|
20464
20417
|
* @returns {boolean} - Returns true if the element is valid, false otherwise.
|
|
@@ -20585,7 +20538,7 @@ class AuroCombobox extends AuroElement {
|
|
|
20585
20538
|
if (this.menu) {
|
|
20586
20539
|
this.menu.matchWord = normalizeFilterValue(this.input.value);
|
|
20587
20540
|
}
|
|
20588
|
-
const label = getOptionLabel(this.menu.optionSelected)
|
|
20541
|
+
const label = getOptionLabel(this.menu.optionSelected);
|
|
20589
20542
|
this.updateTriggerTextDisplay(label || this.value);
|
|
20590
20543
|
}
|
|
20591
20544
|
|
|
@@ -20599,44 +20552,16 @@ class AuroCombobox extends AuroElement {
|
|
|
20599
20552
|
// in suggestion mode, do not override input value if no selection has been made and the input currently has focus
|
|
20600
20553
|
const isInputFocusedWithNoSelection = !this.menu.value && (this.input.matches(':focus-within') || (this.inputInBib && this.inputInBib.matches(':focus-within')));
|
|
20601
20554
|
|
|
20602
|
-
|
|
20603
|
-
|
|
20604
|
-
|
|
20605
|
-
// syncValuesAndStates re-enters here during typing when both inputs
|
|
20606
|
-
// already match, and a no-op flag flip would make the bib branch's
|
|
20607
|
-
// bail eat legitimate user-input events.
|
|
20608
|
-
const triggerNeedsSync = this.input.value !== nextValue;
|
|
20609
|
-
const bibNeedsSync = Boolean(this.inputInBib && this.inputInBib !== this.input && this.inputInBib.value !== nextValue);
|
|
20610
|
-
if (triggerNeedsSync || bibNeedsSync) {
|
|
20611
|
-
this._syncingDisplayValue = true;
|
|
20612
|
-
if (triggerNeedsSync) {
|
|
20613
|
-
this.input.value = nextValue;
|
|
20614
|
-
}
|
|
20615
|
-
if (bibNeedsSync) {
|
|
20616
|
-
this.inputInBib.value = nextValue;
|
|
20617
|
-
}
|
|
20618
|
-
const pending = [];
|
|
20619
|
-
if (triggerNeedsSync) {
|
|
20620
|
-
pending.push(this.input.updateComplete);
|
|
20621
|
-
}
|
|
20622
|
-
if (bibNeedsSync) {
|
|
20623
|
-
pending.push(this.inputInBib.updateComplete);
|
|
20624
|
-
}
|
|
20625
|
-
Promise.all(pending).then(() => {
|
|
20626
|
-
// imask reasserts otherwise, and handleBlur reverts to its stale value.
|
|
20627
|
-
if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
|
|
20628
|
-
this.input.maskInstance.updateValue();
|
|
20629
|
-
}
|
|
20630
|
-
if (bibNeedsSync && this.inputInBib && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
|
|
20631
|
-
this.inputInBib.maskInstance.updateValue();
|
|
20632
|
-
}
|
|
20633
|
-
this._syncingDisplayValue = false;
|
|
20634
|
-
});
|
|
20635
|
-
}
|
|
20555
|
+
const suppressed = this.persistInput || (this.behavior === 'suggestion' && isInputFocusedWithNoSelection);
|
|
20556
|
+
if (!suppressed) {
|
|
20557
|
+
this.syncInputValuesAcrossTriggerAndBib(label || this.value);
|
|
20636
20558
|
}
|
|
20637
20559
|
|
|
20638
|
-
//
|
|
20639
|
-
|
|
20560
|
+
// Replace any previously appended displayValue clone in the trigger.
|
|
20561
|
+
// :not(slot) excludes the template's <slot name="displayValue"
|
|
20562
|
+
// slot="displayValue"> forwarder, which also has slot="displayValue"
|
|
20563
|
+
// and would otherwise be matched first and removed.
|
|
20564
|
+
const displayValueInTrigger = this.input.querySelector('[slot="displayValue"]:not(slot)');
|
|
20640
20565
|
|
|
20641
20566
|
if (displayValueInTrigger) {
|
|
20642
20567
|
displayValueInTrigger.remove();
|
|
@@ -20660,6 +20585,53 @@ class AuroCombobox extends AuroElement {
|
|
|
20660
20585
|
this.requestUpdate();
|
|
20661
20586
|
}
|
|
20662
20587
|
|
|
20588
|
+
/**
|
|
20589
|
+
* Writes nextValue to the trigger input and the bib input when their current
|
|
20590
|
+
* value differs, then re-asserts imask after Lit's update flushes.
|
|
20591
|
+
* @param {string} nextValue - The value to write to both inputs.
|
|
20592
|
+
* @returns {Promise<void>} Resolves after both inputs flush and imask
|
|
20593
|
+
* re-asserts; resolves immediately when no sync is needed.
|
|
20594
|
+
* @private
|
|
20595
|
+
*/
|
|
20596
|
+
async syncInputValuesAcrossTriggerAndBib(nextValue) {
|
|
20597
|
+
// Only set the flag when there's an actual write to suppress —
|
|
20598
|
+
// syncValuesAndStates re-enters here during typing when both inputs
|
|
20599
|
+
// already match, and a no-op flag flip would make the bib branch's
|
|
20600
|
+
// bail eat legitimate user-input events.
|
|
20601
|
+
const triggerNeedsSync = this.input.value !== nextValue;
|
|
20602
|
+
const bibNeedsSync = Boolean(this.inputInBib) && this.inputInBib.value !== nextValue;
|
|
20603
|
+
if (!triggerNeedsSync && !bibNeedsSync) {
|
|
20604
|
+
return;
|
|
20605
|
+
}
|
|
20606
|
+
|
|
20607
|
+
this._syncingDisplayValue = true;
|
|
20608
|
+
|
|
20609
|
+
const pending = [];
|
|
20610
|
+
if (triggerNeedsSync) {
|
|
20611
|
+
this.input.value = nextValue;
|
|
20612
|
+
pending.push(this.input.updateComplete);
|
|
20613
|
+
}
|
|
20614
|
+
if (bibNeedsSync) {
|
|
20615
|
+
this.inputInBib.value = nextValue;
|
|
20616
|
+
pending.push(this.inputInBib.updateComplete);
|
|
20617
|
+
}
|
|
20618
|
+
// finally — not a bare .then — so that an imask throw (see commit
|
|
20619
|
+
// d1857401c: imask can throw on credit-card format change) doesn't strand
|
|
20620
|
+
// _syncingDisplayValue=true and silently swallow every subsequent input.
|
|
20621
|
+
try {
|
|
20622
|
+
await Promise.all(pending);
|
|
20623
|
+
// imask reasserts otherwise, and handleBlur reverts to its stale value.
|
|
20624
|
+
if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
|
|
20625
|
+
this.input.maskInstance.updateValue();
|
|
20626
|
+
}
|
|
20627
|
+
if (bibNeedsSync && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
|
|
20628
|
+
this.inputInBib.maskInstance.updateValue();
|
|
20629
|
+
}
|
|
20630
|
+
} finally {
|
|
20631
|
+
this._syncingDisplayValue = false;
|
|
20632
|
+
}
|
|
20633
|
+
}
|
|
20634
|
+
|
|
20663
20635
|
/**
|
|
20664
20636
|
* Processes hidden state of all menu options and determines if there are any available options not hidden.
|
|
20665
20637
|
* @private
|
|
@@ -20668,6 +20640,13 @@ class AuroCombobox extends AuroElement {
|
|
|
20668
20640
|
handleMenuOptions() {
|
|
20669
20641
|
this.generateOptionsArray();
|
|
20670
20642
|
this.availableOptions = [];
|
|
20643
|
+
// Single source of truth for the menu's filter/highlight token per call.
|
|
20644
|
+
// syncValuesAndStates re-writes the same value on exact-match keystrokes —
|
|
20645
|
+
// Lit's hasChanged makes that a no-op — and the prior duplicate set inside
|
|
20646
|
+
// handleTriggerInputValueChange is gone.
|
|
20647
|
+
if (this.menu) {
|
|
20648
|
+
this.menu.matchWord = normalizeFilterValue(this.input.value);
|
|
20649
|
+
}
|
|
20671
20650
|
this.updateFilter();
|
|
20672
20651
|
|
|
20673
20652
|
// Set aria-setsize/aria-posinset on each visible option so screen readers
|
|
@@ -20679,17 +20658,14 @@ class AuroCombobox extends AuroElement {
|
|
|
20679
20658
|
option.setAttribute('aria-posinset', index + 1);
|
|
20680
20659
|
});
|
|
20681
20660
|
|
|
20682
|
-
if (this.value && this.
|
|
20683
|
-
|
|
20684
|
-
this.setMenuValue(this.value);
|
|
20685
|
-
}
|
|
20686
|
-
|
|
20661
|
+
if (this.input.value && this.menu.options && this.menu.options.some((opt) => opt.value === this.input.value)) {
|
|
20662
|
+
this.setMenuValue(this.input.value);
|
|
20687
20663
|
this.syncValuesAndStates();
|
|
20688
20664
|
}
|
|
20689
20665
|
|
|
20690
|
-
// Re-activate when optionActive is
|
|
20691
|
-
// been reset (e.g. by clearSelection in an async update)
|
|
20692
|
-
// makeSelection() can find the correct option.
|
|
20666
|
+
// Re-activate when optionActive is not in the current scrollable viewport,
|
|
20667
|
+
// or when _index has been reset (e.g. by clearSelection in an async update)
|
|
20668
|
+
// so that makeSelection() can find the correct option.
|
|
20693
20669
|
if (!this.availableOptions.includes(this.menu.optionActive) || this.menu._index < 0) {
|
|
20694
20670
|
this.activateFirstEnabledAvailableOption();
|
|
20695
20671
|
}
|
|
@@ -20762,18 +20738,6 @@ class AuroCombobox extends AuroElement {
|
|
|
20762
20738
|
this.dropdownOpen = ev.detail.expanded;
|
|
20763
20739
|
this.updateMenuShapeSize();
|
|
20764
20740
|
|
|
20765
|
-
// Defer aria-expanded "true" so VoiceOver finishes character echo
|
|
20766
|
-
// before announcing "expanded". Set "false" immediately on close.
|
|
20767
|
-
clearTimeout(this._expandedTimeout);
|
|
20768
|
-
if (this.dropdownOpen) {
|
|
20769
|
-
const expandedDelay = 150;
|
|
20770
|
-
this._expandedTimeout = setTimeout(() => {
|
|
20771
|
-
this.triggerExpandedState = true;
|
|
20772
|
-
}, expandedDelay);
|
|
20773
|
-
} else {
|
|
20774
|
-
this.triggerExpandedState = false;
|
|
20775
|
-
}
|
|
20776
|
-
|
|
20777
20741
|
// Clear aria-activedescendant when dropdown closes
|
|
20778
20742
|
if (!this.dropdownOpen && this.input) {
|
|
20779
20743
|
this.input.setActiveDescendant(null);
|
|
@@ -20823,28 +20787,25 @@ class AuroCombobox extends AuroElement {
|
|
|
20823
20787
|
|
|
20824
20788
|
guardTouchPassthrough(this.menu);
|
|
20825
20789
|
|
|
20826
|
-
//
|
|
20827
|
-
//
|
|
20828
|
-
//
|
|
20790
|
+
// showModal() takes focus away from the trigger. Early focus once
|
|
20791
|
+
// the dialog has painted; the shared doubleRaf below is the fallback
|
|
20792
|
+
// for when the dialog needs an extra frame and also clears the
|
|
20793
|
+
// validation guard.
|
|
20829
20794
|
requestAnimationFrame(() => {
|
|
20830
20795
|
this.setInputFocus();
|
|
20831
20796
|
});
|
|
20832
|
-
|
|
20833
|
-
doubleRaf(() => {
|
|
20834
|
-
this.setInputFocus();
|
|
20835
|
-
this._inFullscreenTransition = false;
|
|
20836
|
-
});
|
|
20837
|
-
} else {
|
|
20838
|
-
// Desktop popover-open: restore the trigger caret to end-of-text.
|
|
20839
|
-
// Clicking the trigger lands on auro-input's floating <label for="…">
|
|
20840
|
-
// overlay; Chrome resets the native input's selection to [0, 0] on
|
|
20841
|
-
// label-focus before any JS runs. setInputFocus()'s non-fullscreen
|
|
20842
|
-
// branch parks the caret at end. doubleRaf lets the dropdown layout
|
|
20843
|
-
// settle first, matching the fullscreen branch timing.
|
|
20844
|
-
doubleRaf(() => {
|
|
20845
|
-
this.setInputFocus();
|
|
20846
|
-
});
|
|
20847
20797
|
}
|
|
20798
|
+
// else (desktop popover-open): Chrome resets the trigger caret to
|
|
20799
|
+
// [0, 0] when its floating <label for="…"> overlay receives focus.
|
|
20800
|
+
// The shared doubleRaf below parks the caret back at end-of-text
|
|
20801
|
+
// after the dropdown layout settles.
|
|
20802
|
+
|
|
20803
|
+
doubleRaf(() => {
|
|
20804
|
+
this.setInputFocus();
|
|
20805
|
+
if (this._inFullscreenTransition) {
|
|
20806
|
+
this._inFullscreenTransition = false;
|
|
20807
|
+
}
|
|
20808
|
+
});
|
|
20848
20809
|
}
|
|
20849
20810
|
});
|
|
20850
20811
|
|
|
@@ -20881,7 +20842,7 @@ class AuroCombobox extends AuroElement {
|
|
|
20881
20842
|
this.dropdown.trigger.inert = false;
|
|
20882
20843
|
}
|
|
20883
20844
|
|
|
20884
|
-
|
|
20845
|
+
this._scheduleTimer(() => {
|
|
20885
20846
|
this.setInputFocus();
|
|
20886
20847
|
}, 0);
|
|
20887
20848
|
});
|
|
@@ -20949,24 +20910,7 @@ class AuroCombobox extends AuroElement {
|
|
|
20949
20910
|
nativeInput.setSelectionRange(len, len);
|
|
20950
20911
|
}
|
|
20951
20912
|
} else {
|
|
20952
|
-
|
|
20953
|
-
// fullscreen→floating switch can close the dialog and leave focus on
|
|
20954
|
-
// body. Every other Branch 2 callsite already has focus on the input
|
|
20955
|
-
// via the focusin → this.focus() redirect (L1448-1452), so this is a
|
|
20956
|
-
// no-op in the common case.
|
|
20957
|
-
if (!this.input.componentHasFocus) {
|
|
20958
|
-
this.input.focus();
|
|
20959
|
-
}
|
|
20960
|
-
|
|
20961
|
-
// Park the trigger native input's caret at end-of-text every time the
|
|
20962
|
-
// popover opens. Chrome focuses the native via the floating <label for="…">
|
|
20963
|
-
// overlay on click and resets selection to [0, 0]; no JS fires between
|
|
20964
|
-
// mousedown and selectionchange, so we restore the caret here.
|
|
20965
|
-
const triggerNativeInput = this.input.inputElement;
|
|
20966
|
-
if (triggerNativeInput && triggerNativeInput.value) {
|
|
20967
|
-
const len = triggerNativeInput.value.length;
|
|
20968
|
-
triggerNativeInput.setSelectionRange(len, len);
|
|
20969
|
-
}
|
|
20913
|
+
this.input.focus();
|
|
20970
20914
|
}
|
|
20971
20915
|
}
|
|
20972
20916
|
|
|
@@ -21042,7 +20986,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21042
20986
|
|
|
21043
20987
|
// racing condition on custom-combobox with custom-menu
|
|
21044
20988
|
if (!this.menu) {
|
|
21045
|
-
|
|
20989
|
+
this._scheduleTimer(() => {
|
|
21046
20990
|
this.configureMenu();
|
|
21047
20991
|
}, 0);
|
|
21048
20992
|
return;
|
|
@@ -21072,7 +21016,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21072
21016
|
if (this.menu.optionSelected) {
|
|
21073
21017
|
const selected = this.menu.optionSelected;
|
|
21074
21018
|
|
|
21075
|
-
if (
|
|
21019
|
+
if (this.optionSelected !== selected) {
|
|
21076
21020
|
this.optionSelected = selected;
|
|
21077
21021
|
}
|
|
21078
21022
|
|
|
@@ -21085,7 +21029,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21085
21029
|
}
|
|
21086
21030
|
|
|
21087
21031
|
// Update display
|
|
21088
|
-
this.updateTriggerTextDisplay(getOptionLabel(this.optionSelected)
|
|
21032
|
+
this.updateTriggerTextDisplay(getOptionLabel(this.optionSelected));
|
|
21089
21033
|
|
|
21090
21034
|
// Update match word for filtering
|
|
21091
21035
|
const trimmedInput = normalizeFilterValue(this.input.value);
|
|
@@ -21097,17 +21041,24 @@ class AuroCombobox extends AuroElement {
|
|
|
21097
21041
|
// Hide dropdown on selection (except during slot changes)
|
|
21098
21042
|
if (evt.detail && evt.detail.source !== 'slotchange') {
|
|
21099
21043
|
// do not close while typing in suggestion mode with no value selected, to allow freeform input
|
|
21100
|
-
|
|
21101
|
-
|
|
21044
|
+
this.hideBib();
|
|
21045
|
+
|
|
21046
|
+
// Move focus to the clear button when the user makes a selection.
|
|
21047
|
+
if (!isEcho && this.menu.value !== undefined) {
|
|
21048
|
+
this.setClearBtnFocus();
|
|
21102
21049
|
}
|
|
21103
21050
|
|
|
21104
21051
|
// Announce the selection after the dropdown closes so it isn't
|
|
21105
21052
|
// overridden by VoiceOver's "collapsed" announcement from aria-expanded.
|
|
21053
|
+
// Skip when there's no selected value (e.g. menu.clearSelection() from
|
|
21054
|
+
// the unmatched-value path), otherwise VoiceOver reads "undefined".
|
|
21106
21055
|
const selectedValue = this.menu.value;
|
|
21107
|
-
|
|
21108
|
-
|
|
21109
|
-
|
|
21110
|
-
|
|
21056
|
+
if (selectedValue) {
|
|
21057
|
+
const announcementDelay = 300;
|
|
21058
|
+
this._scheduleTimer(() => {
|
|
21059
|
+
announceToScreenReader(this._getAnnouncementRoot(), `${selectedValue}, selected`);
|
|
21060
|
+
}, announcementDelay);
|
|
21061
|
+
}
|
|
21111
21062
|
}
|
|
21112
21063
|
|
|
21113
21064
|
// Programmatic value syncs leave availableOptions stale because
|
|
@@ -21116,22 +21067,6 @@ class AuroCombobox extends AuroElement {
|
|
|
21116
21067
|
// only — fresh user selections take the existing hideBib path.
|
|
21117
21068
|
if (isEcho && this.menu.optionSelected) {
|
|
21118
21069
|
this._programmaticFilterRefresh = true;
|
|
21119
|
-
this.handleMenuOptions();
|
|
21120
|
-
setTimeout(() => {
|
|
21121
|
-
this._programmaticFilterRefresh = false;
|
|
21122
|
-
}, 0);
|
|
21123
|
-
}
|
|
21124
|
-
|
|
21125
|
-
// base-input skips auto-validate when focus is inside its own shadow,
|
|
21126
|
-
// which it is after setTriggerInputFocus — re-run so prior tooShort
|
|
21127
|
-
// clears. processCreditCard reasserts errorMessage on every render.
|
|
21128
|
-
if (!isEcho && this.menu.optionSelected && this.input.validate) {
|
|
21129
|
-
this.input.updateComplete.then(() => {
|
|
21130
|
-
this.input.validate(true);
|
|
21131
|
-
if (this.input.validity === 'valid') {
|
|
21132
|
-
this.input.errorMessage = '';
|
|
21133
|
-
}
|
|
21134
|
-
});
|
|
21135
21070
|
}
|
|
21136
21071
|
});
|
|
21137
21072
|
|
|
@@ -21144,6 +21079,14 @@ class AuroCombobox extends AuroElement {
|
|
|
21144
21079
|
// stale option. Safe from re-entrancy because any resulting
|
|
21145
21080
|
// input.value changes dispatch isProgrammatic events.
|
|
21146
21081
|
this.menu.addEventListener('auroMenu-selectValueFailure', () => {
|
|
21082
|
+
// Announce the rejection BEFORE we clear `this.value` so the live
|
|
21083
|
+
// region carries the attempted value — without this the bib closes
|
|
21084
|
+
// silently and screen-reader users get no signal that their request
|
|
21085
|
+
// (e.g. a direct setMenuValue() call) was dropped.
|
|
21086
|
+
const attemptedValue = this.value;
|
|
21087
|
+
if (attemptedValue) {
|
|
21088
|
+
announceToScreenReader(this._getAnnouncementRoot(), `No matching option for ${attemptedValue}`);
|
|
21089
|
+
}
|
|
21147
21090
|
this.value = undefined;
|
|
21148
21091
|
this.optionSelected = undefined;
|
|
21149
21092
|
});
|
|
@@ -21155,10 +21098,13 @@ class AuroCombobox extends AuroElement {
|
|
|
21155
21098
|
this.input.setActiveDescendant(this.optionActive);
|
|
21156
21099
|
}
|
|
21157
21100
|
|
|
21158
|
-
//
|
|
21159
|
-
//
|
|
21160
|
-
//
|
|
21161
|
-
|
|
21101
|
+
// In fullscreen mode the menu sits inside a nested <dialog> shadow root,
|
|
21102
|
+
// and aria-activedescendant references across that boundary are lost —
|
|
21103
|
+
// VoiceOver/NVDA don't read the active option natively, so we mirror it
|
|
21104
|
+
// into the polite live region. In popover mode aria-activedescendant on
|
|
21105
|
+
// the trigger input is read natively; double-announcing would flood the
|
|
21106
|
+
// queue on arrow-key repeat.
|
|
21107
|
+
if (this.optionActive && this.dropdown.isBibFullscreen) {
|
|
21162
21108
|
const optionText = this.optionActive.textContent.trim();
|
|
21163
21109
|
const selectedState = this.optionActive.hasAttribute('selected') ? ', selected' : ', not selected';
|
|
21164
21110
|
const optionIndex = this.availableOptions.indexOf(this.optionActive) + 1;
|
|
@@ -21191,7 +21137,12 @@ class AuroCombobox extends AuroElement {
|
|
|
21191
21137
|
* Validate every time we remove focus from the combo box.
|
|
21192
21138
|
*/
|
|
21193
21139
|
this.addEventListener('focusout', () => {
|
|
21194
|
-
|
|
21140
|
+
// Skip while the dropdown is open — focus transits out briefly on
|
|
21141
|
+
// mousedown of a menu option (popover top-layer breaks :focus-within),
|
|
21142
|
+
// and validating against the pre-selection value flashes a stale error
|
|
21143
|
+
// between mousedown and mouseup. The next focusout fires after the
|
|
21144
|
+
// dropdown closes and validates against the post-selection value.
|
|
21145
|
+
if (!this.componentHasFocus && !this._inFullscreenTransition && !this.dropdownOpen) {
|
|
21195
21146
|
this.validate();
|
|
21196
21147
|
}
|
|
21197
21148
|
});
|
|
@@ -21254,49 +21205,40 @@ class AuroCombobox extends AuroElement {
|
|
|
21254
21205
|
if (this._syncingDisplayValue) {
|
|
21255
21206
|
return;
|
|
21256
21207
|
}
|
|
21257
|
-
this._syncingBibValue = true;
|
|
21258
|
-
this.input.value = this.inputInBib.value;
|
|
21259
|
-
this.input.updateComplete.then(() => {
|
|
21260
|
-
this._syncingBibValue = false;
|
|
21261
|
-
});
|
|
21262
21208
|
|
|
21263
|
-
//
|
|
21264
|
-
|
|
21265
|
-
|
|
21266
|
-
|
|
21267
|
-
|
|
21268
|
-
|
|
21269
|
-
|
|
21270
|
-
|
|
21271
|
-
|
|
21209
|
+
// Filtering runs via re-entrance: writing this.input.value below
|
|
21210
|
+
// dispatches an 'input' event that the trigger's listener routes to
|
|
21211
|
+
// handleTriggerInputValueChange, which refreshes the menu filter.
|
|
21212
|
+
if (this.input.value !== this.inputInBib.value) {
|
|
21213
|
+
this._syncingBibValue = true;
|
|
21214
|
+
this.input.value = this.inputInBib.value;
|
|
21215
|
+
this.input.updateComplete.then(() => {
|
|
21216
|
+
this._syncingBibValue = false;
|
|
21217
|
+
});
|
|
21272
21218
|
}
|
|
21273
21219
|
|
|
21274
|
-
this.handleMenuOptions();
|
|
21275
21220
|
this.dispatchEvent(new CustomEvent('inputValue', { detail: { value: this.inputValue } }));
|
|
21276
|
-
|
|
21221
|
+
} else if (event.target === this.input) {
|
|
21222
|
+
|
|
21223
|
+
// Also sync the native input immediately so keystrokes arriving
|
|
21224
|
+
// before Lit's async update cycle (e.g. rapid Backspaces during a
|
|
21225
|
+
// fullscreen transition) operate on the correct content.
|
|
21226
|
+
// Skip the next programmatic input event to prevent the patched setter
|
|
21227
|
+
// from re-entering handleInputValueChange via the bib path.
|
|
21228
|
+
const bibNativeInput = this.inputInBib.inputElement;
|
|
21229
|
+
if (bibNativeInput && bibNativeInput.value !== this.input.value) {
|
|
21230
|
+
this.inputInBib.skipNextProgrammaticInputEvent = true;
|
|
21231
|
+
bibNativeInput.value = this.input.value || '';
|
|
21232
|
+
}
|
|
21277
21233
|
}
|
|
21278
21234
|
|
|
21235
|
+
this.value = this.input.value;
|
|
21236
|
+
|
|
21279
21237
|
// Ignore re-entrant input events caused by programmatic value sets.
|
|
21280
21238
|
if (this._syncingBibValue || this._syncingDisplayValue) {
|
|
21281
21239
|
return;
|
|
21282
21240
|
}
|
|
21283
21241
|
|
|
21284
|
-
this.inputInBib.value = this.input.value;
|
|
21285
|
-
|
|
21286
|
-
// Also sync the native input immediately so keystrokes arriving
|
|
21287
|
-
// before Lit's async update cycle (e.g. rapid Backspaces during a
|
|
21288
|
-
// fullscreen transition) operate on the correct content.
|
|
21289
|
-
// Skip the next programmatic input event to prevent the patched setter
|
|
21290
|
-
// from re-entering handleInputValueChange via the bib path.
|
|
21291
|
-
const bibNativeInput = this.inputInBib.inputElement;
|
|
21292
|
-
if (bibNativeInput && bibNativeInput.value !== this.input.value) {
|
|
21293
|
-
this.inputInBib.skipNextProgrammaticInputEvent = true;
|
|
21294
|
-
bibNativeInput.value = this.input.value || '';
|
|
21295
|
-
}
|
|
21296
|
-
|
|
21297
|
-
this.menu.matchWord = normalizeFilterValue(this.input.value);
|
|
21298
|
-
this.optionActive = null;
|
|
21299
|
-
|
|
21300
21242
|
if (this.behavior === 'suggestion') {
|
|
21301
21243
|
this.value = this.input.value;
|
|
21302
21244
|
}
|
|
@@ -21304,7 +21246,6 @@ class AuroCombobox extends AuroElement {
|
|
|
21304
21246
|
if (!this.input.value && !this._clearing) {
|
|
21305
21247
|
this.clear();
|
|
21306
21248
|
}
|
|
21307
|
-
this.handleMenuOptions();
|
|
21308
21249
|
|
|
21309
21250
|
// Validate only if the value was set programmatically (not during user
|
|
21310
21251
|
// interaction). In fullscreen dialog mode, componentHasFocus returns false
|
|
@@ -21314,34 +21255,44 @@ class AuroCombobox extends AuroElement {
|
|
|
21314
21255
|
this.validate();
|
|
21315
21256
|
}
|
|
21316
21257
|
|
|
21317
|
-
|
|
21318
|
-
|
|
21319
|
-
|
|
21320
|
-
|
|
21321
|
-
|
|
21322
|
-
|
|
21323
|
-
|
|
21324
|
-
|
|
21325
|
-
|
|
21258
|
+
this.dispatchEvent(new CustomEvent('inputValue', { detail: { value: this.inputValue } }));
|
|
21259
|
+
}
|
|
21260
|
+
|
|
21261
|
+
/**
|
|
21262
|
+
* Handles input value changes originating from the trigger input.
|
|
21263
|
+
* Refreshes menu options and filtering, delegates to handleInputValueChange
|
|
21264
|
+
* for value synchronization, and manages fullscreen bib focus.
|
|
21265
|
+
* @private
|
|
21266
|
+
* @param {Event} event - The input event from the trigger input element.
|
|
21267
|
+
* @returns {void}
|
|
21268
|
+
*/
|
|
21269
|
+
handleTriggerInputValueChange(event) {
|
|
21270
|
+
// 'input' fires for every user-initiated value change — typing, paste,
|
|
21271
|
+
// IME composition end, dead-key composition, drag-drop. Flip _userTyped
|
|
21272
|
+
// here so updated('availableOptions') auto-opens the bib for sources
|
|
21273
|
+
// that keydown alone misses: paste fires no keydown, IME uses
|
|
21274
|
+
// key='Process', and dead keys produce multi-char keys (all bypass the
|
|
21275
|
+
// prior keydown.key.length===1 gate). Skip programmatic syncs.
|
|
21276
|
+
if (!this._syncingDisplayValue && !this._syncingBibValue && !this._programmaticFilterRefresh) {
|
|
21277
|
+
this._userTyped = true;
|
|
21326
21278
|
}
|
|
21327
21279
|
|
|
21328
|
-
|
|
21329
|
-
|
|
21330
|
-
|
|
21331
|
-
|
|
21332
|
-
|
|
21333
|
-
// dialog opens — the user then has to tap the input again to resume
|
|
21334
|
-
// typing.
|
|
21335
|
-
if (this.dropdown.isBibFullscreen && this.input.value && this.input.value.length > 0) {
|
|
21336
|
-
if (!this.dropdown.isPopoverVisible) {
|
|
21337
|
-
this.showBib();
|
|
21338
|
-
}
|
|
21339
|
-
if (this.dropdown.isPopoverVisible) {
|
|
21340
|
-
this.setInputFocus();
|
|
21341
|
-
}
|
|
21280
|
+
this.handleMenuOptions();
|
|
21281
|
+
this.optionActive = null;
|
|
21282
|
+
|
|
21283
|
+
if (this.value === this.input.value) {
|
|
21284
|
+
return;
|
|
21342
21285
|
}
|
|
21343
21286
|
|
|
21344
|
-
this.
|
|
21287
|
+
this.handleInputValueChange(event);
|
|
21288
|
+
|
|
21289
|
+
if (this.dropdown.isBibFullscreen && this.input.value && this.input.value.length > 0 && this.dropdown.isPopoverVisible) {
|
|
21290
|
+
this.setInputFocus();
|
|
21291
|
+
}
|
|
21292
|
+
|
|
21293
|
+
if (this._programmaticFilterRefresh) {
|
|
21294
|
+
this._programmaticFilterRefresh = false;
|
|
21295
|
+
}
|
|
21345
21296
|
}
|
|
21346
21297
|
|
|
21347
21298
|
/**
|
|
@@ -21409,6 +21360,11 @@ class AuroCombobox extends AuroElement {
|
|
|
21409
21360
|
disconnectedCallback() {
|
|
21410
21361
|
super.disconnectedCallback();
|
|
21411
21362
|
this._inFullscreenTransition = false;
|
|
21363
|
+
// Cancel any outstanding timers so detached callbacks don't fire on
|
|
21364
|
+
// disposed DOM — most are no-ops, but configureMenu's racing-condition
|
|
21365
|
+
// retry would otherwise keep rescheduling itself indefinitely.
|
|
21366
|
+
this._pendingTimers.forEach((id) => clearTimeout(id));
|
|
21367
|
+
this._pendingTimers.clear();
|
|
21412
21368
|
}
|
|
21413
21369
|
|
|
21414
21370
|
firstUpdated() {
|
|
@@ -21450,7 +21406,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21450
21406
|
this.menu.value = value;
|
|
21451
21407
|
// Backup clear: if menu.value === menu.optionSelected.value already, the
|
|
21452
21408
|
// listener won't fire and the flag would swallow the next user click.
|
|
21453
|
-
|
|
21409
|
+
this._scheduleTimer(() => {
|
|
21454
21410
|
this._pendingMenuValueSync = false;
|
|
21455
21411
|
}, 0);
|
|
21456
21412
|
}
|
|
@@ -21467,15 +21423,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21467
21423
|
this.menu.value = undefined;
|
|
21468
21424
|
this.validation.reset(this);
|
|
21469
21425
|
this.touched = false;
|
|
21470
|
-
// Force validity back to the cleared state. validation.reset() calls
|
|
21471
|
-
// validate() at the end, and (post-credit-card-fix) the trigger input's
|
|
21472
|
-
// residual validity may still be copied into the combobox by the
|
|
21473
|
-
// auroInputElements loop. Explicitly clear here so reset() actually
|
|
21474
|
-
// leaves the component in a "no validity" state.
|
|
21475
21426
|
this.validity = undefined;
|
|
21476
|
-
this.errorMessage = '';
|
|
21477
|
-
this.input.validity = undefined;
|
|
21478
|
-
this.input.errorMessage = '';
|
|
21479
21427
|
}
|
|
21480
21428
|
|
|
21481
21429
|
/**
|
|
@@ -21493,6 +21441,17 @@ class AuroCombobox extends AuroElement {
|
|
|
21493
21441
|
this.optionSelected = undefined;
|
|
21494
21442
|
this.value = undefined;
|
|
21495
21443
|
|
|
21444
|
+
// Clear the appended displayValue clone in the trigger if present.
|
|
21445
|
+
// :not(slot) excludes the template's <slot name="displayValue"
|
|
21446
|
+
// slot="displayValue"> forwarder (line 1816), which also has
|
|
21447
|
+
// slot="displayValue" and would otherwise be matched first and removed,
|
|
21448
|
+
// permanently breaking the consumer-provided displayValue slot.
|
|
21449
|
+
const displayValueInTrigger = this.input.querySelector('[slot="displayValue"]:not(slot)');
|
|
21450
|
+
|
|
21451
|
+
if (displayValueInTrigger) {
|
|
21452
|
+
displayValueInTrigger.remove();
|
|
21453
|
+
}
|
|
21454
|
+
|
|
21496
21455
|
if (this.input.value) {
|
|
21497
21456
|
this.input.clear();
|
|
21498
21457
|
}
|
|
@@ -21516,81 +21475,50 @@ class AuroCombobox extends AuroElement {
|
|
|
21516
21475
|
}
|
|
21517
21476
|
|
|
21518
21477
|
updated(changedProperties) {
|
|
21519
|
-
// After the component is ready,
|
|
21478
|
+
// After the component is ready, propagate direct changes down to child components.
|
|
21520
21479
|
if (changedProperties.has('value')) {
|
|
21521
|
-
|
|
21522
|
-
|
|
21523
|
-
|
|
21524
|
-
|
|
21480
|
+
// Only flag programmatic refreshes — user-typed value changes must not
|
|
21481
|
+
// suppress the availableOptions branch's showBib(). Firefox batches
|
|
21482
|
+
// 'value' and 'availableOptions' into the same updated() call, so
|
|
21483
|
+
// setting the flag unconditionally here masks the user-typed open path.
|
|
21484
|
+
if (!this._userTyped) {
|
|
21485
|
+
this._programmaticFilterRefresh = true;
|
|
21525
21486
|
}
|
|
21526
21487
|
|
|
21527
|
-
if (this.
|
|
21528
|
-
|
|
21529
|
-
|
|
21488
|
+
if (this.input.value !== this.value) {
|
|
21489
|
+
// Clear menu.value AND menu.optionSelected together. Clearing only
|
|
21490
|
+
// menu.value leaves the previously-selected option element pinned
|
|
21491
|
+
// as menu.optionSelected; a later auroMenu-selectedOption event
|
|
21492
|
+
// would then write its stale .value back into combobox.value
|
|
21493
|
+
// (e.g. Tab-after-Backspace re-selecting the prior option).
|
|
21494
|
+
if (this.menu.value || this.menu.optionSelected) {
|
|
21495
|
+
this.menu.clearSelection();
|
|
21496
|
+
}
|
|
21530
21497
|
|
|
21531
|
-
|
|
21532
|
-
|
|
21533
|
-
|
|
21534
|
-
|
|
21535
|
-
|
|
21536
|
-
|
|
21537
|
-
|
|
21538
|
-
|
|
21539
|
-
|
|
21540
|
-
|
|
21541
|
-
|
|
21542
|
-
|
|
21543
|
-
|
|
21544
|
-
|
|
21545
|
-
|
|
21546
|
-
|
|
21547
|
-
|
|
21548
|
-
|
|
21549
|
-
// matches to avoid spurious events during the normal typing path.
|
|
21550
|
-
const nextValue = this.value || '';
|
|
21551
|
-
const triggerNeedsSync = this.input.value !== nextValue;
|
|
21552
|
-
const bibNeedsSync = Boolean(this.inputInBib && this.inputInBib !== this.input && this.inputInBib.value !== nextValue);
|
|
21553
|
-
if (triggerNeedsSync || bibNeedsSync) {
|
|
21554
|
-
this._syncingDisplayValue = true;
|
|
21555
|
-
if (triggerNeedsSync) {
|
|
21556
|
-
this.input.value = nextValue;
|
|
21557
|
-
}
|
|
21558
|
-
if (bibNeedsSync) {
|
|
21559
|
-
this.inputInBib.value = nextValue;
|
|
21560
|
-
}
|
|
21561
|
-
const pending = [];
|
|
21562
|
-
if (triggerNeedsSync) {
|
|
21563
|
-
pending.push(this.input.updateComplete);
|
|
21564
|
-
}
|
|
21565
|
-
if (bibNeedsSync) {
|
|
21566
|
-
pending.push(this.inputInBib.updateComplete);
|
|
21567
|
-
}
|
|
21568
|
-
Promise.all(pending).then(() => {
|
|
21569
|
-
if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
|
|
21570
|
-
this.input.maskInstance.updateValue();
|
|
21571
|
-
}
|
|
21572
|
-
if (bibNeedsSync && this.inputInBib && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
|
|
21573
|
-
this.inputInBib.maskInstance.updateValue();
|
|
21574
|
-
}
|
|
21575
|
-
this._syncingDisplayValue = false;
|
|
21576
|
-
// handleInputValueChange bailed on the flag — refresh the filter.
|
|
21577
|
-
this._programmaticFilterRefresh = true;
|
|
21578
|
-
this.handleMenuOptions();
|
|
21579
|
-
setTimeout(() => {
|
|
21580
|
-
this._programmaticFilterRefresh = false;
|
|
21581
|
-
}, 0);
|
|
21582
|
-
});
|
|
21583
|
-
}
|
|
21498
|
+
if (!this.persistInput) {
|
|
21499
|
+
this.syncInputValuesAcrossTriggerAndBib(this.value || '');
|
|
21500
|
+
}
|
|
21501
|
+
|
|
21502
|
+
// Programmatic value with no matching option: updateFilter will close
|
|
21503
|
+
// the bib silently (see line 648 — no noMatchOption + 0 results
|
|
21504
|
+
// hides). Announce so screen-reader users hear the request was
|
|
21505
|
+
// dropped. Gated on `input.value !== this.value` so this never fires
|
|
21506
|
+
// for user typing — that path always reconciles input.value to
|
|
21507
|
+
// this.value before updated() runs.
|
|
21508
|
+
if (
|
|
21509
|
+
this.value &&
|
|
21510
|
+
this.menu &&
|
|
21511
|
+
this.menu.options &&
|
|
21512
|
+
this.menu.options.length > 0 &&
|
|
21513
|
+
!this.menu.options.some((opt) => opt.value === this.value)
|
|
21514
|
+
) {
|
|
21515
|
+
announceToScreenReader(this._getAnnouncementRoot(), `No matching option for ${this.value}`);
|
|
21584
21516
|
}
|
|
21585
21517
|
}
|
|
21518
|
+
|
|
21586
21519
|
if (!this.value) {
|
|
21587
21520
|
this.clear();
|
|
21588
21521
|
}
|
|
21589
|
-
if (this.value && !this.componentHasFocus) {
|
|
21590
|
-
// If the value got set programmatically make sure we hide the bib
|
|
21591
|
-
// when input is not taking the focus (input can be in dropdown.trigger or in bibtemplate)
|
|
21592
|
-
this.hideBib();
|
|
21593
|
-
}
|
|
21594
21522
|
|
|
21595
21523
|
// Sync the input and match word, but don't directly set menu.value again
|
|
21596
21524
|
if (this.menu) {
|
|
@@ -21603,7 +21531,7 @@ class AuroCombobox extends AuroElement {
|
|
|
21603
21531
|
composed: true,
|
|
21604
21532
|
detail: {
|
|
21605
21533
|
optionSelected: this.menu.optionSelected,
|
|
21606
|
-
value: this.
|
|
21534
|
+
value: this.value
|
|
21607
21535
|
}
|
|
21608
21536
|
}));
|
|
21609
21537
|
|
|
@@ -21626,16 +21554,30 @@ class AuroCombobox extends AuroElement {
|
|
|
21626
21554
|
// from a programmatic filter refresh after a value swap — the user
|
|
21627
21555
|
// didn't interact, so we shouldn't auto-open the bib (especially for
|
|
21628
21556
|
// the no-match path where the existing condition unconditionally fires).
|
|
21629
|
-
if (this._programmaticFilterRefresh) {
|
|
21630
|
-
|
|
21631
|
-
|
|
21632
|
-
|
|
21557
|
+
if ((this.menu && !this._programmaticFilterRefresh)) {
|
|
21558
|
+
if (
|
|
21559
|
+
this.availableOptions.length > 0 ||
|
|
21560
|
+
this.menu.loading ||
|
|
21561
|
+
this.noMatchOption
|
|
21562
|
+
) {
|
|
21563
|
+
if (this._userTyped) {
|
|
21564
|
+
if (!this.dropdownOpen) {
|
|
21565
|
+
this.showBib();
|
|
21566
|
+
}
|
|
21567
|
+
this._userTyped = false;
|
|
21568
|
+
}
|
|
21569
|
+
}
|
|
21570
|
+
|
|
21633
21571
|
if (!this.availableOptions.includes(this.menu.optionActive)) {
|
|
21634
21572
|
this.activateFirstEnabledAvailableOption();
|
|
21635
21573
|
}
|
|
21636
|
-
} else if (this.dropdown
|
|
21574
|
+
} else if (!this.dropdown.isBibFullscreen) {
|
|
21637
21575
|
this.hideBib();
|
|
21638
21576
|
}
|
|
21577
|
+
|
|
21578
|
+
if (this._programmaticFilterRefresh) {
|
|
21579
|
+
this._programmaticFilterRefresh = false;
|
|
21580
|
+
}
|
|
21639
21581
|
}
|
|
21640
21582
|
|
|
21641
21583
|
if (changedProperties.has('error')) {
|
|
@@ -21777,10 +21719,10 @@ class AuroCombobox extends AuroElement {
|
|
|
21777
21719
|
shape="${this.shape}"
|
|
21778
21720
|
size="${this.size}">
|
|
21779
21721
|
<${this.inputTag}
|
|
21780
|
-
@input="${this.
|
|
21722
|
+
@input="${this.handleTriggerInputValueChange}"
|
|
21781
21723
|
appearance="${this.onDark ? 'inverse' : this.appearance}"
|
|
21782
21724
|
.a11yActivedescendant="${this.dropdownOpen && this.optionActive ? this.optionActive.id : undefined}"
|
|
21783
|
-
.a11yExpanded="${this.
|
|
21725
|
+
.a11yExpanded="${this.dropdownOpen}"
|
|
21784
21726
|
.a11yControls="${this.dropdownId}"
|
|
21785
21727
|
.autocomplete="${this.autocomplete}"
|
|
21786
21728
|
.inputmode="${this.inputmode}"
|