@aurodesignsystem/auro-formkit 5.10.0 → 5.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +55 -15
- package/components/bibtemplate/dist/auro-bibtemplate.d.ts +6 -0
- package/components/bibtemplate/dist/index.js +12 -0
- package/components/bibtemplate/dist/registered.js +12 -0
- package/components/checkbox/demo/api.min.js +3 -3
- package/components/checkbox/demo/index.min.js +3 -3
- package/components/checkbox/dist/index.js +3 -3
- package/components/checkbox/dist/registered.js +3 -3
- package/components/combobox/demo/api.min.js +1140 -305
- package/components/combobox/demo/index.min.js +1140 -305
- package/components/combobox/dist/auro-combobox.d.ts +24 -1
- package/components/combobox/dist/comboboxKeyboardStrategy.d.ts +6 -0
- package/components/combobox/dist/index.js +1082 -264
- package/components/combobox/dist/registered.js +1082 -264
- package/components/counter/demo/api.min.js +583 -172
- package/components/counter/demo/index.min.js +583 -172
- package/components/counter/dist/auro-counter.d.ts +8 -0
- package/components/counter/dist/buttonVersion.d.ts +1 -1
- package/components/counter/dist/iconVersion.d.ts +1 -1
- package/components/counter/dist/index.js +583 -172
- package/components/counter/dist/registered.js +583 -172
- package/components/datepicker/demo/api.md +108 -85
- package/components/datepicker/demo/api.min.js +872 -257
- package/components/datepicker/demo/index.md +18 -12
- package/components/datepicker/demo/index.min.js +872 -257
- package/components/datepicker/dist/auro-calendar.d.ts +6 -0
- package/components/datepicker/dist/auro-datepicker.d.ts +11 -1
- package/components/datepicker/dist/index.js +819 -208
- package/components/datepicker/dist/registered.js +819 -208
- package/components/dropdown/demo/api.md +15 -17
- package/components/dropdown/demo/api.min.js +537 -183
- package/components/dropdown/demo/index.min.js +537 -183
- package/components/dropdown/dist/auro-dropdown.d.ts +27 -1
- package/components/dropdown/dist/auro-dropdownBib.d.ts +87 -0
- package/components/dropdown/dist/index.js +514 -160
- package/components/dropdown/dist/keyboardUtils.d.ts +18 -0
- package/components/dropdown/dist/registered.js +514 -160
- package/components/form/README.md +47 -2
- package/components/form/demo/api.js +2 -0
- package/components/form/demo/api.md +303 -30
- package/components/form/demo/api.min.js +69256 -62
- package/components/form/demo/index.html +0 -1
- package/components/form/demo/index.js +1 -0
- package/components/form/demo/index.md +1 -275
- package/components/form/demo/index.min.js +69255 -62
- package/components/form/demo/readme.md +47 -2
- package/components/form/demo/working.html +123 -32
- package/components/form/dist/auro-form.d.ts +98 -61
- package/components/form/dist/index.js +135 -51
- package/components/form/dist/registered.js +135 -51
- package/components/input/demo/api.md +1 -0
- package/components/input/demo/api.min.js +78 -24
- package/components/input/demo/index.min.js +78 -24
- package/components/input/dist/base-input.d.ts +34 -0
- package/components/input/dist/index.js +78 -24
- package/components/input/dist/registered.js +78 -24
- package/components/menu/demo/api.md +4 -10
- package/components/menu/demo/api.min.js +18 -5
- package/components/menu/demo/index.min.js +18 -5
- package/components/menu/dist/auro-menuoption.d.ts +0 -8
- package/components/menu/dist/iconVersion.d.ts +1 -1
- package/components/menu/dist/index.js +18 -5
- package/components/menu/dist/registered.js +18 -5
- package/components/radio/demo/api.min.js +3 -3
- package/components/radio/demo/index.min.js +3 -3
- package/components/radio/dist/index.js +3 -3
- package/components/radio/dist/registered.js +3 -3
- package/components/select/demo/api.js +2 -0
- package/components/select/demo/api.md +333 -78
- package/components/select/demo/api.min.js +945 -282
- package/components/select/demo/index.min.js +933 -282
- package/components/select/dist/auro-select.d.ts +26 -0
- package/components/select/dist/index.js +881 -247
- package/components/select/dist/registered.js +881 -247
- package/components/select/dist/selectKeyboardStrategy.d.ts +8 -0
- package/custom-elements.json +596 -89
- package/package.json +7 -5
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { css, LitElement, html as html$1 } from 'lit';
|
|
2
2
|
import { unsafeStatic, literal, html } from 'lit/static-html.js';
|
|
3
3
|
import { classMap } from 'lit/directives/class-map.js';
|
|
4
|
+
import 'lit-html';
|
|
5
|
+
import 'lit-html/directives/unsafe-html.js';
|
|
4
6
|
import { createRef, ref } from 'lit/directives/ref.js';
|
|
5
7
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
6
8
|
import { repeat } from 'lit/directives/repeat.js';
|
|
@@ -884,7 +886,7 @@ let AuroFormValidation$1 = class AuroFormValidation {
|
|
|
884
886
|
}
|
|
885
887
|
}
|
|
886
888
|
|
|
887
|
-
if (!hasValue && elem.required && elem.touched) {
|
|
889
|
+
if (!hasValue && elem.required && (force || elem.touched)) {
|
|
888
890
|
elem.validity = 'valueMissing';
|
|
889
891
|
elem.errorMessage = elem.setCustomValidityValueMissing || elem.setCustomValidity || '';
|
|
890
892
|
} else if (hasValue && this.runtimeUtils.elementMatch(elem, 'auro-input')) {
|
|
@@ -908,7 +910,7 @@ let AuroFormValidation$1 = class AuroFormValidation {
|
|
|
908
910
|
if (!isCombobox || isCombobox && !elem.persistInput) {
|
|
909
911
|
|
|
910
912
|
// run validation on all inputs since we're going to use them to set the validity of this component
|
|
911
|
-
this.auroInputElements.forEach(input => input.validate());
|
|
913
|
+
this.auroInputElements.forEach(input => input.validate(force));
|
|
912
914
|
|
|
913
915
|
// Reset element validity to the validity of the input
|
|
914
916
|
elem.validity = this.auroInputElements[0].validity;
|
|
@@ -999,6 +1001,233 @@ let AuroFormValidation$1 = class AuroFormValidation {
|
|
|
999
1001
|
}
|
|
1000
1002
|
};
|
|
1001
1003
|
|
|
1004
|
+
/**
|
|
1005
|
+
* Announces text to screen readers via an `aria-live` region inside the given shadow root.
|
|
1006
|
+
*
|
|
1007
|
+
* Expects the shadow root to contain an element with `id="srAnnouncement"`.
|
|
1008
|
+
* The text is cleared and re-set inside a `requestAnimationFrame` so that
|
|
1009
|
+
* repeated identical announcements still fire, and is cleared again after
|
|
1010
|
+
* {@link ANNOUNCEMENT_DURATION_MS} so VoiceOver cannot swipe to stale text.
|
|
1011
|
+
*
|
|
1012
|
+
* @param {ShadowRoot} shadowRoot - The shadow root containing the live region.
|
|
1013
|
+
* @param {string} text - The text to announce.
|
|
1014
|
+
*/
|
|
1015
|
+
|
|
1016
|
+
const ANNOUNCEMENT_DURATION_MS = 1000;
|
|
1017
|
+
|
|
1018
|
+
function announceToScreenReader(shadowRoot, text) {
|
|
1019
|
+
const liveRegion = shadowRoot.querySelector('#srAnnouncement');
|
|
1020
|
+
if (liveRegion) {
|
|
1021
|
+
// Clear and re-set to ensure the announcement fires even with same text
|
|
1022
|
+
liveRegion.textContent = '';
|
|
1023
|
+
requestAnimationFrame(() => {
|
|
1024
|
+
liveRegion.textContent = text;
|
|
1025
|
+
|
|
1026
|
+
// Clear after the announcement so VoiceOver cannot swipe to stale text
|
|
1027
|
+
setTimeout(() => {
|
|
1028
|
+
liveRegion.textContent = '';
|
|
1029
|
+
}, ANNOUNCEMENT_DURATION_MS);
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* Schedules a callback after two animation frames.
|
|
1036
|
+
*
|
|
1037
|
+
* Used when opening a fullscreen dialog to wait for the dialog to render
|
|
1038
|
+
* (first frame) and then for a Lit update cycle to complete (second frame)
|
|
1039
|
+
* before performing an action like focusing the close button.
|
|
1040
|
+
*
|
|
1041
|
+
* @param {Function} fn - The callback to execute after two animation frames.
|
|
1042
|
+
*/
|
|
1043
|
+
function doubleRaf(fn) {
|
|
1044
|
+
requestAnimationFrame(() => {
|
|
1045
|
+
requestAnimationFrame(fn);
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
/**
|
|
1050
|
+
* Prevents touch pass-through when a fullscreen dialog opens on a touch device.
|
|
1051
|
+
*
|
|
1052
|
+
* On coarse-pointer devices (phones / tablets), the tap that opens the
|
|
1053
|
+
* fullscreen dialog can "pass through" to content beneath the finger —
|
|
1054
|
+
* the touchstart opens the dialog, but the finger is still on the screen,
|
|
1055
|
+
* so the subsequent touchend / click lands on whatever element sits at
|
|
1056
|
+
* those coordinates (e.g. a menu option or calendar cell), selecting it
|
|
1057
|
+
* unintentionally. This does NOT happen with mouse clicks because
|
|
1058
|
+
* showModal() promotes the dialog to the top layer synchronously and the
|
|
1059
|
+
* click has already completed.
|
|
1060
|
+
*
|
|
1061
|
+
* Guard: only activates on devices whose primary input is coarse.
|
|
1062
|
+
* Laptops with a touchscreen report `pointer: fine` (trackpad / mouse is
|
|
1063
|
+
* primary) so they are unaffected. Re-enables on the next touchstart,
|
|
1064
|
+
* which is the user's first deliberate gesture inside the dialog.
|
|
1065
|
+
*
|
|
1066
|
+
* @param {HTMLElement} element - The element to disable pointer events on
|
|
1067
|
+
* (e.g. the menu or calendar wrapper).
|
|
1068
|
+
*/
|
|
1069
|
+
function guardTouchPassthrough(element) {
|
|
1070
|
+
if (!element || !window.matchMedia('(pointer: coarse)').matches) return;
|
|
1071
|
+
|
|
1072
|
+
element.style.pointerEvents = 'none';
|
|
1073
|
+
document.addEventListener('touchstart', () => {
|
|
1074
|
+
element.style.pointerEvents = '';
|
|
1075
|
+
}, { once: true });
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
/**
|
|
1079
|
+
* Restores the dropdown trigger after a fullscreen dialog closes.
|
|
1080
|
+
*
|
|
1081
|
+
* Removes the `inert` attribute from the trigger so it is accessible again,
|
|
1082
|
+
* and restores focus to the given target after one animation frame. The rAF
|
|
1083
|
+
* delay lets Lit's microtask update cycle call `dialog.close()` first —
|
|
1084
|
+
* without it the browser's native dialog focus restoration can conflict.
|
|
1085
|
+
*
|
|
1086
|
+
* The focus is only applied if the dropdown is still closed at the time the
|
|
1087
|
+
* rAF fires, guarding against a rapid close-then-reopen race.
|
|
1088
|
+
*
|
|
1089
|
+
* @param {HTMLElement} dropdown - The `auro-dropdown` element.
|
|
1090
|
+
* @param {HTMLElement} focusTarget - The element to focus (e.g. trigger or input).
|
|
1091
|
+
*/
|
|
1092
|
+
function restoreTriggerAfterClose(dropdown, focusTarget) {
|
|
1093
|
+
dropdown.trigger.inert = false;
|
|
1094
|
+
|
|
1095
|
+
if (dropdown.isBibFullscreen) {
|
|
1096
|
+
requestAnimationFrame(() => {
|
|
1097
|
+
if (!dropdown.isPopoverVisible) {
|
|
1098
|
+
focusTarget.focus();
|
|
1099
|
+
}
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
/**
|
|
1105
|
+
* Wires up a keydown listener that dispatches to strategy[evt.key] or strategy.default.
|
|
1106
|
+
* Handles both sync and async handlers.
|
|
1107
|
+
* @param {HTMLElement} component - The component to attach the listener to.
|
|
1108
|
+
* @param {Object} strategy - Map of key names to handler functions.
|
|
1109
|
+
*/
|
|
1110
|
+
function applyKeyboardStrategy(component, strategy) {
|
|
1111
|
+
component.addEventListener('keydown', async (evt) => {
|
|
1112
|
+
const handler = strategy[evt.key] || strategy.default;
|
|
1113
|
+
if (handler) {
|
|
1114
|
+
await handler(component, evt);
|
|
1115
|
+
}
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/**
|
|
1120
|
+
* Shared arrow navigation. Calls menu.navigateOptions(direction) if visible.
|
|
1121
|
+
* Optionally opens dropdown via showFn when closed.
|
|
1122
|
+
* @param {HTMLElement} component - The component with dropdown and menu references.
|
|
1123
|
+
* @param {string} direction - 'up' or 'down'.
|
|
1124
|
+
* @param {Object} [options] - Optional config.
|
|
1125
|
+
* @param {Function} [options.showFn] - Called to open the dropdown when closed.
|
|
1126
|
+
*/
|
|
1127
|
+
function navigateArrow(component, direction, options = {}) {
|
|
1128
|
+
if (component.dropdown.isPopoverVisible) {
|
|
1129
|
+
component.menu.navigateOptions(direction);
|
|
1130
|
+
} else if (options.showFn) {
|
|
1131
|
+
options.showFn();
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
const comboboxKeyboardStrategy = {
|
|
1136
|
+
async Enter(component, evt) {
|
|
1137
|
+
// If the clear button has focus, let the browser activate it normally.
|
|
1138
|
+
const clearBtn = component.input.shadowRoot.querySelector('.clearBtn');
|
|
1139
|
+
if (clearBtn && clearBtn.shadowRoot && clearBtn.shadowRoot.activeElement !== null) {
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
if (component.dropdown.isPopoverVisible && component.optionActive) {
|
|
1144
|
+
component.menu.makeSelection();
|
|
1145
|
+
await component.updateComplete;
|
|
1146
|
+
evt.preventDefault();
|
|
1147
|
+
evt.stopPropagation();
|
|
1148
|
+
component.setClearBtnFocus();
|
|
1149
|
+
} else {
|
|
1150
|
+
component.showBib();
|
|
1151
|
+
}
|
|
1152
|
+
},
|
|
1153
|
+
|
|
1154
|
+
Tab(component) {
|
|
1155
|
+
if (!component.dropdown.isPopoverVisible) {
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
if (component.dropdown.isBibFullscreen) {
|
|
1160
|
+
const clearBtn = component.inputInBib.shadowRoot.querySelector('.clearBtn');
|
|
1161
|
+
|
|
1162
|
+
// Use shadowRoot.activeElement to detect focus inside auro-button,
|
|
1163
|
+
// since Safari does not propagate :focus-within through shadow DOM.
|
|
1164
|
+
const clearBtnHasFocus = clearBtn && clearBtn.shadowRoot && clearBtn.shadowRoot.activeElement !== null;
|
|
1165
|
+
|
|
1166
|
+
// Tab from input: if clear button exists and doesn't have focus, focus it
|
|
1167
|
+
if (clearBtn && !clearBtnHasFocus && component.inputInBib.value) {
|
|
1168
|
+
// Force clear button container visible to work around Safari not
|
|
1169
|
+
// propagating :focus-within through shadow DOM boundaries, which
|
|
1170
|
+
// causes .wrapper:not(:focus-within) to hide .notification.clear.
|
|
1171
|
+
const clearContainer = clearBtn.closest('.clear');
|
|
1172
|
+
if (clearContainer) {
|
|
1173
|
+
clearContainer.style.display = 'flex';
|
|
1174
|
+
clearBtn.addEventListener('focusout', () => {
|
|
1175
|
+
// Delay cleanup so :focus-within settles when focus moves
|
|
1176
|
+
// to a sibling (e.g., Shift+Tab back to the input).
|
|
1177
|
+
requestAnimationFrame(() => {
|
|
1178
|
+
clearContainer.style.display = '';
|
|
1179
|
+
});
|
|
1180
|
+
}, { once: true });
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
// Focus the native button inside auro-button so the browser
|
|
1184
|
+
// treats it as a real focusable element inside the dialog.
|
|
1185
|
+
const nativeBtn = clearBtn.shadowRoot && clearBtn.shadowRoot.querySelector('button');
|
|
1186
|
+
if (nativeBtn) {
|
|
1187
|
+
nativeBtn.focus();
|
|
1188
|
+
} else {
|
|
1189
|
+
clearBtn.focus();
|
|
1190
|
+
}
|
|
1191
|
+
return;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
// Tab from clear button (or no clear button / no value) →
|
|
1195
|
+
// select the highlighted option if any, then close
|
|
1196
|
+
if (component.optionActive) {
|
|
1197
|
+
component.menu.makeSelection();
|
|
1198
|
+
}
|
|
1199
|
+
component.hideBib();
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
// Non-fullscreen: select + close
|
|
1204
|
+
if (component.menu.optionActive && component.menu.optionActive.value) {
|
|
1205
|
+
component.menu.value = component.menu.optionActive.value;
|
|
1206
|
+
}
|
|
1207
|
+
component.hideBib();
|
|
1208
|
+
},
|
|
1209
|
+
|
|
1210
|
+
ArrowUp(component, evt) {
|
|
1211
|
+
if (component.availableOptions.length > 0) {
|
|
1212
|
+
component.showBib();
|
|
1213
|
+
}
|
|
1214
|
+
if (component.dropdown.isPopoverVisible) {
|
|
1215
|
+
evt.preventDefault();
|
|
1216
|
+
navigateArrow(component, 'up');
|
|
1217
|
+
}
|
|
1218
|
+
},
|
|
1219
|
+
|
|
1220
|
+
ArrowDown(component, evt) {
|
|
1221
|
+
if (component.availableOptions.length > 0) {
|
|
1222
|
+
component.showBib();
|
|
1223
|
+
}
|
|
1224
|
+
if (component.dropdown.isPopoverVisible) {
|
|
1225
|
+
evt.preventDefault();
|
|
1226
|
+
navigateArrow(component, 'down');
|
|
1227
|
+
}
|
|
1228
|
+
},
|
|
1229
|
+
};
|
|
1230
|
+
|
|
1002
1231
|
// Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
|
|
1003
1232
|
// See LICENSE in the project root for license information.
|
|
1004
1233
|
|
|
@@ -2726,11 +2955,9 @@ const computePosition = (reference, floating, options) => {
|
|
|
2726
2955
|
/* eslint-disable line-comment-position, no-inline-comments */
|
|
2727
2956
|
|
|
2728
2957
|
|
|
2729
|
-
|
|
2730
2958
|
const MAX_CONFIGURATION_COUNT = 10;
|
|
2731
2959
|
|
|
2732
2960
|
class AuroFloatingUI {
|
|
2733
|
-
|
|
2734
2961
|
/**
|
|
2735
2962
|
* @private
|
|
2736
2963
|
*/
|
|
@@ -2745,7 +2972,11 @@ class AuroFloatingUI {
|
|
|
2745
2972
|
* @private
|
|
2746
2973
|
*/
|
|
2747
2974
|
static setupMousePressChecker() {
|
|
2748
|
-
if (
|
|
2975
|
+
if (
|
|
2976
|
+
!AuroFloatingUI.isMousePressHandlerInitialized &&
|
|
2977
|
+
window &&
|
|
2978
|
+
window.addEventListener
|
|
2979
|
+
) {
|
|
2749
2980
|
AuroFloatingUI.isMousePressHandlerInitialized = true;
|
|
2750
2981
|
|
|
2751
2982
|
// Track timeout for isMousePressed reset to avoid race conditions
|
|
@@ -2753,7 +2984,7 @@ class AuroFloatingUI {
|
|
|
2753
2984
|
AuroFloatingUI._mousePressedTimeout = null;
|
|
2754
2985
|
}
|
|
2755
2986
|
const mouseEventGlobalHandler = (event) => {
|
|
2756
|
-
const isPressed = event.type ===
|
|
2987
|
+
const isPressed = event.type === "mousedown";
|
|
2757
2988
|
if (isPressed) {
|
|
2758
2989
|
// Clear any pending timeout to prevent race condition
|
|
2759
2990
|
if (AuroFloatingUI._mousePressedTimeout !== null) {
|
|
@@ -2772,8 +3003,8 @@ class AuroFloatingUI {
|
|
|
2772
3003
|
}
|
|
2773
3004
|
};
|
|
2774
3005
|
|
|
2775
|
-
window.addEventListener(
|
|
2776
|
-
window.addEventListener(
|
|
3006
|
+
window.addEventListener("mousedown", mouseEventGlobalHandler);
|
|
3007
|
+
window.addEventListener("mouseup", mouseEventGlobalHandler);
|
|
2777
3008
|
}
|
|
2778
3009
|
}
|
|
2779
3010
|
|
|
@@ -2821,11 +3052,12 @@ class AuroFloatingUI {
|
|
|
2821
3052
|
// mirror the boxsize from bibSizer
|
|
2822
3053
|
if (this.element.bibSizer && this.element.matchWidth) {
|
|
2823
3054
|
const sizerStyle = window.getComputedStyle(this.element.bibSizer);
|
|
2824
|
-
const bibContent =
|
|
2825
|
-
|
|
3055
|
+
const bibContent =
|
|
3056
|
+
this.element.bib.shadowRoot.querySelector(".container");
|
|
3057
|
+
if (sizerStyle.width !== "0px") {
|
|
2826
3058
|
bibContent.style.width = sizerStyle.width;
|
|
2827
3059
|
}
|
|
2828
|
-
if (sizerStyle.height !==
|
|
3060
|
+
if (sizerStyle.height !== "0px") {
|
|
2829
3061
|
bibContent.style.height = sizerStyle.height;
|
|
2830
3062
|
}
|
|
2831
3063
|
bibContent.style.maxWidth = sizerStyle.maxWidth;
|
|
@@ -2843,28 +3075,34 @@ class AuroFloatingUI {
|
|
|
2843
3075
|
* @returns {String} The positioning strategy, one of 'fullscreen', 'floating', 'cover'.
|
|
2844
3076
|
*/
|
|
2845
3077
|
getPositioningStrategy() {
|
|
2846
|
-
const breakpoint =
|
|
3078
|
+
const breakpoint =
|
|
3079
|
+
this.element.bib.mobileFullscreenBreakpoint ||
|
|
3080
|
+
this.element.floaterConfig?.fullscreenBreakpoint;
|
|
2847
3081
|
switch (this.behavior) {
|
|
2848
3082
|
case "tooltip":
|
|
2849
3083
|
return "floating";
|
|
2850
3084
|
case "dialog":
|
|
2851
3085
|
case "drawer":
|
|
2852
3086
|
if (breakpoint) {
|
|
2853
|
-
const smallerThanBreakpoint = window.matchMedia(
|
|
3087
|
+
const smallerThanBreakpoint = window.matchMedia(
|
|
3088
|
+
`(max-width: ${breakpoint})`,
|
|
3089
|
+
).matches;
|
|
2854
3090
|
|
|
2855
3091
|
this.element.expanded = smallerThanBreakpoint;
|
|
2856
3092
|
}
|
|
2857
3093
|
if (this.element.nested) {
|
|
2858
3094
|
return "cover";
|
|
2859
3095
|
}
|
|
2860
|
-
return
|
|
3096
|
+
return "fullscreen";
|
|
2861
3097
|
case "dropdown":
|
|
2862
3098
|
case undefined:
|
|
2863
3099
|
case null:
|
|
2864
3100
|
if (breakpoint) {
|
|
2865
|
-
const smallerThanBreakpoint = window.matchMedia(
|
|
3101
|
+
const smallerThanBreakpoint = window.matchMedia(
|
|
3102
|
+
`(max-width: ${breakpoint})`,
|
|
3103
|
+
).matches;
|
|
2866
3104
|
if (smallerThanBreakpoint) {
|
|
2867
|
-
return
|
|
3105
|
+
return "fullscreen";
|
|
2868
3106
|
}
|
|
2869
3107
|
}
|
|
2870
3108
|
return "floating";
|
|
@@ -2885,37 +3123,39 @@ class AuroFloatingUI {
|
|
|
2885
3123
|
const strategy = this.getPositioningStrategy();
|
|
2886
3124
|
this.configureBibStrategy(strategy);
|
|
2887
3125
|
|
|
2888
|
-
if (strategy ===
|
|
3126
|
+
if (strategy === "floating") {
|
|
2889
3127
|
this.mirrorSize();
|
|
2890
3128
|
// Define the middlware for the floater configuration
|
|
2891
3129
|
const middleware = [
|
|
2892
3130
|
offset(this.element.floaterConfig?.offset || 0),
|
|
2893
|
-
...this.element.floaterConfig?.shift ? [shift()] : [], // Add shift middleware if shift is enabled.
|
|
2894
|
-
...this.element.floaterConfig?.flip ? [flip()] : [], // Add flip middleware if flip is enabled.
|
|
2895
|
-
...this.element.floaterConfig?.autoPlacement ? [autoPlacement()] : [], // Add autoPlacement middleware if autoPlacement is enabled.
|
|
3131
|
+
...(this.element.floaterConfig?.shift ? [shift()] : []), // Add shift middleware if shift is enabled.
|
|
3132
|
+
...(this.element.floaterConfig?.flip ? [flip()] : []), // Add flip middleware if flip is enabled.
|
|
3133
|
+
...(this.element.floaterConfig?.autoPlacement ? [autoPlacement()] : []), // Add autoPlacement middleware if autoPlacement is enabled.
|
|
2896
3134
|
];
|
|
2897
3135
|
|
|
2898
3136
|
// Compute the position of the bib
|
|
2899
3137
|
computePosition(this.element.trigger, this.element.bib, {
|
|
2900
|
-
strategy: this.element.floaterConfig?.strategy ||
|
|
3138
|
+
strategy: this.element.floaterConfig?.strategy || "fixed",
|
|
2901
3139
|
placement: this.element.floaterConfig?.placement,
|
|
2902
|
-
middleware: middleware || []
|
|
2903
|
-
}).then(({ x, y }) => {
|
|
3140
|
+
middleware: middleware || [],
|
|
3141
|
+
}).then(({ x, y }) => {
|
|
3142
|
+
// eslint-disable-line id-length
|
|
2904
3143
|
Object.assign(this.element.bib.style, {
|
|
2905
3144
|
left: `${x}px`,
|
|
2906
3145
|
top: `${y}px`,
|
|
2907
3146
|
});
|
|
2908
3147
|
});
|
|
2909
|
-
} else if (strategy ===
|
|
3148
|
+
} else if (strategy === "cover") {
|
|
2910
3149
|
// Compute the position of the bib
|
|
2911
3150
|
computePosition(this.element.parentNode, this.element.bib, {
|
|
2912
|
-
placement:
|
|
2913
|
-
}).then(({ x, y }) => {
|
|
3151
|
+
placement: "bottom-start",
|
|
3152
|
+
}).then(({ x, y }) => {
|
|
3153
|
+
// eslint-disable-line id-length
|
|
2914
3154
|
Object.assign(this.element.bib.style, {
|
|
2915
3155
|
left: `${x}px`,
|
|
2916
3156
|
top: `${y - this.element.parentNode.offsetHeight}px`,
|
|
2917
3157
|
width: `${this.element.parentNode.offsetWidth}px`,
|
|
2918
|
-
height: `${this.element.parentNode.offsetHeight}px
|
|
3158
|
+
height: `${this.element.parentNode.offsetHeight}px`,
|
|
2919
3159
|
});
|
|
2920
3160
|
});
|
|
2921
3161
|
}
|
|
@@ -2928,12 +3168,12 @@ class AuroFloatingUI {
|
|
|
2928
3168
|
*/
|
|
2929
3169
|
lockScroll(lock = true) {
|
|
2930
3170
|
if (lock) {
|
|
2931
|
-
document.body.style.overflow =
|
|
3171
|
+
document.body.style.overflow = "hidden"; // hide body's scrollbar
|
|
2932
3172
|
|
|
2933
3173
|
// Move `bib` by the amount the viewport is shifted to stay aligned in fullscreen.
|
|
2934
3174
|
this.element.bib.style.transform = `translateY(${window?.visualViewport?.offsetTop}px)`;
|
|
2935
3175
|
} else {
|
|
2936
|
-
document.body.style.overflow =
|
|
3176
|
+
document.body.style.overflow = "";
|
|
2937
3177
|
}
|
|
2938
3178
|
}
|
|
2939
3179
|
|
|
@@ -2947,23 +3187,24 @@ class AuroFloatingUI {
|
|
|
2947
3187
|
* @param {string} strategy - The positioning strategy ('fullscreen' or 'floating').
|
|
2948
3188
|
*/
|
|
2949
3189
|
configureBibStrategy(value) {
|
|
2950
|
-
if (value ===
|
|
3190
|
+
if (value === "fullscreen") {
|
|
2951
3191
|
this.element.isBibFullscreen = true;
|
|
2952
3192
|
// reset the prev position
|
|
2953
|
-
this.element.bib.setAttribute(
|
|
2954
|
-
this.element.bib.style.position =
|
|
3193
|
+
this.element.bib.setAttribute("isfullscreen", "");
|
|
3194
|
+
this.element.bib.style.position = "fixed";
|
|
2955
3195
|
this.element.bib.style.top = "0px";
|
|
2956
3196
|
this.element.bib.style.left = "0px";
|
|
2957
|
-
this.element.bib.style.width =
|
|
2958
|
-
this.element.bib.style.height =
|
|
2959
|
-
this.element.style.contain =
|
|
3197
|
+
this.element.bib.style.width = "";
|
|
3198
|
+
this.element.bib.style.height = "";
|
|
3199
|
+
this.element.style.contain = "";
|
|
2960
3200
|
|
|
2961
3201
|
// reset the size that was mirroring `size` css-part
|
|
2962
|
-
const bibContent =
|
|
3202
|
+
const bibContent =
|
|
3203
|
+
this.element.bib.shadowRoot.querySelector(".container");
|
|
2963
3204
|
if (bibContent) {
|
|
2964
|
-
bibContent.style.width =
|
|
2965
|
-
bibContent.style.height =
|
|
2966
|
-
bibContent.style.maxWidth =
|
|
3205
|
+
bibContent.style.width = "";
|
|
3206
|
+
bibContent.style.height = "";
|
|
3207
|
+
bibContent.style.maxWidth = "";
|
|
2967
3208
|
bibContent.style.maxHeight = `${window?.visualViewport?.height}px`;
|
|
2968
3209
|
this.configureTrial = 0;
|
|
2969
3210
|
} else if (this.configureTrial < MAX_CONFIGURATION_COUNT) {
|
|
@@ -2978,21 +3219,26 @@ class AuroFloatingUI {
|
|
|
2978
3219
|
this.lockScroll(true);
|
|
2979
3220
|
}
|
|
2980
3221
|
} else {
|
|
2981
|
-
this.element.bib.style.position =
|
|
2982
|
-
this.element.bib.removeAttribute(
|
|
3222
|
+
this.element.bib.style.position = "";
|
|
3223
|
+
this.element.bib.removeAttribute("isfullscreen");
|
|
2983
3224
|
this.element.isBibFullscreen = false;
|
|
2984
|
-
this.element.style.contain =
|
|
3225
|
+
this.element.style.contain = "layout";
|
|
2985
3226
|
}
|
|
2986
3227
|
|
|
2987
3228
|
const isChanged = this.strategy && this.strategy !== value;
|
|
2988
3229
|
this.strategy = value;
|
|
2989
3230
|
if (isChanged) {
|
|
2990
|
-
const event = new CustomEvent(
|
|
2991
|
-
|
|
2992
|
-
|
|
3231
|
+
const event = new CustomEvent(
|
|
3232
|
+
this.eventPrefix
|
|
3233
|
+
? `${this.eventPrefix}-strategy-change`
|
|
3234
|
+
: "strategy-change",
|
|
3235
|
+
{
|
|
3236
|
+
detail: {
|
|
3237
|
+
value,
|
|
3238
|
+
},
|
|
3239
|
+
composed: true,
|
|
2993
3240
|
},
|
|
2994
|
-
|
|
2995
|
-
});
|
|
3241
|
+
);
|
|
2996
3242
|
|
|
2997
3243
|
this.element.dispatchEvent(event);
|
|
2998
3244
|
}
|
|
@@ -3024,19 +3270,24 @@ class AuroFloatingUI {
|
|
|
3024
3270
|
return;
|
|
3025
3271
|
}
|
|
3026
3272
|
|
|
3027
|
-
if (
|
|
3028
|
-
this.element.
|
|
3273
|
+
if (
|
|
3274
|
+
this.element.noHideOnThisFocusLoss ||
|
|
3275
|
+
this.element.hasAttribute("noHideOnThisFocusLoss")
|
|
3276
|
+
) {
|
|
3029
3277
|
return;
|
|
3030
3278
|
}
|
|
3031
3279
|
|
|
3032
3280
|
const { activeElement } = document;
|
|
3033
3281
|
// if focus is still inside of trigger or bib, do not close
|
|
3034
|
-
if (
|
|
3282
|
+
if (
|
|
3283
|
+
this.element.contains(activeElement) ||
|
|
3284
|
+
this.element.bib?.contains(activeElement)
|
|
3285
|
+
) {
|
|
3035
3286
|
return;
|
|
3036
3287
|
}
|
|
3037
3288
|
|
|
3038
3289
|
// if fullscreen bib is in fullscreen mode, do not close
|
|
3039
|
-
if (this.element.bib.hasAttribute(
|
|
3290
|
+
if (this.element.bib.hasAttribute("isfullscreen")) {
|
|
3040
3291
|
return;
|
|
3041
3292
|
}
|
|
3042
3293
|
|
|
@@ -3048,12 +3299,27 @@ class AuroFloatingUI {
|
|
|
3048
3299
|
this.focusHandler = () => this.handleFocusLoss();
|
|
3049
3300
|
|
|
3050
3301
|
this.clickHandler = (evt) => {
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3302
|
+
// When the bib is fullscreen (modal dialog), don't close on outside
|
|
3303
|
+
// clicks. VoiceOver's synthetic click events inside a top-layer modal
|
|
3304
|
+
// <dialog> may not include the bib in composedPath(), causing false
|
|
3305
|
+
// positives. This mirrors the fullscreen guard in handleFocusLoss().
|
|
3306
|
+
if (this.element.bib && this.element.bib.hasAttribute("isfullscreen")) {
|
|
3307
|
+
return;
|
|
3308
|
+
}
|
|
3055
3309
|
|
|
3056
|
-
|
|
3310
|
+
if (
|
|
3311
|
+
(!evt.composedPath().includes(this.element.trigger) &&
|
|
3312
|
+
!evt.composedPath().includes(this.element.bib)) ||
|
|
3313
|
+
(this.element.bib.backdrop &&
|
|
3314
|
+
evt.composedPath().includes(this.element.bib.backdrop))
|
|
3315
|
+
) {
|
|
3316
|
+
const existedVisibleFloatingUI =
|
|
3317
|
+
document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
|
|
3318
|
+
|
|
3319
|
+
if (
|
|
3320
|
+
existedVisibleFloatingUI &&
|
|
3321
|
+
existedVisibleFloatingUI.element.isPopoverVisible
|
|
3322
|
+
) {
|
|
3057
3323
|
// if something else is open, close that
|
|
3058
3324
|
existedVisibleFloatingUI.hideBib();
|
|
3059
3325
|
document.expandedAuroFormkitDropdown = null;
|
|
@@ -3066,9 +3332,14 @@ class AuroFloatingUI {
|
|
|
3066
3332
|
|
|
3067
3333
|
// ESC key handler
|
|
3068
3334
|
this.keyDownHandler = (evt) => {
|
|
3069
|
-
if (evt.key ===
|
|
3070
|
-
const existedVisibleFloatingUI =
|
|
3071
|
-
|
|
3335
|
+
if (evt.key === "Escape" && this.element.isPopoverVisible) {
|
|
3336
|
+
const existedVisibleFloatingUI =
|
|
3337
|
+
document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
|
|
3338
|
+
if (
|
|
3339
|
+
existedVisibleFloatingUI &&
|
|
3340
|
+
existedVisibleFloatingUI !== this &&
|
|
3341
|
+
existedVisibleFloatingUI.element.isPopoverVisible
|
|
3342
|
+
) {
|
|
3072
3343
|
// if something else is open, let it handle itself
|
|
3073
3344
|
return;
|
|
3074
3345
|
}
|
|
@@ -3076,17 +3347,17 @@ class AuroFloatingUI {
|
|
|
3076
3347
|
}
|
|
3077
3348
|
};
|
|
3078
3349
|
|
|
3079
|
-
if (this.behavior !==
|
|
3350
|
+
if (this.behavior !== "drawer" && this.behavior !== "dialog") {
|
|
3080
3351
|
// Add event listeners using the stored references
|
|
3081
|
-
document.addEventListener(
|
|
3352
|
+
document.addEventListener("focusin", this.focusHandler);
|
|
3082
3353
|
}
|
|
3083
3354
|
|
|
3084
|
-
document.addEventListener(
|
|
3355
|
+
document.addEventListener("keydown", this.keyDownHandler);
|
|
3085
3356
|
|
|
3086
3357
|
// send this task to the end of queue to prevent conflicting
|
|
3087
3358
|
// it conflicts if showBib gets call from a button that's not this.element.trigger
|
|
3088
3359
|
setTimeout(() => {
|
|
3089
|
-
window.addEventListener(
|
|
3360
|
+
window.addEventListener("click", this.clickHandler);
|
|
3090
3361
|
}, 0);
|
|
3091
3362
|
}
|
|
3092
3363
|
|
|
@@ -3094,34 +3365,38 @@ class AuroFloatingUI {
|
|
|
3094
3365
|
// Remove event listeners if they exist
|
|
3095
3366
|
|
|
3096
3367
|
if (this.focusHandler) {
|
|
3097
|
-
document.removeEventListener(
|
|
3368
|
+
document.removeEventListener("focusin", this.focusHandler);
|
|
3098
3369
|
this.focusHandler = null;
|
|
3099
3370
|
}
|
|
3100
3371
|
|
|
3101
3372
|
if (this.clickHandler) {
|
|
3102
|
-
window.removeEventListener(
|
|
3373
|
+
window.removeEventListener("click", this.clickHandler);
|
|
3103
3374
|
this.clickHandler = null;
|
|
3104
3375
|
}
|
|
3105
3376
|
|
|
3106
3377
|
if (this.keyDownHandler) {
|
|
3107
|
-
document.removeEventListener(
|
|
3378
|
+
document.removeEventListener("keydown", this.keyDownHandler);
|
|
3108
3379
|
this.keyDownHandler = null;
|
|
3109
3380
|
}
|
|
3110
3381
|
}
|
|
3111
3382
|
|
|
3112
3383
|
handleUpdate(changedProperties) {
|
|
3113
|
-
if (changedProperties.has(
|
|
3384
|
+
if (changedProperties.has("isPopoverVisible")) {
|
|
3114
3385
|
this.updateState();
|
|
3115
3386
|
}
|
|
3116
3387
|
}
|
|
3117
3388
|
|
|
3118
3389
|
updateCurrentExpandedDropdown() {
|
|
3119
3390
|
// Close any other dropdown that is already open
|
|
3120
|
-
const existedVisibleFloatingUI =
|
|
3121
|
-
|
|
3391
|
+
const existedVisibleFloatingUI =
|
|
3392
|
+
document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
|
|
3393
|
+
if (
|
|
3394
|
+
existedVisibleFloatingUI &&
|
|
3395
|
+
existedVisibleFloatingUI !== this &&
|
|
3122
3396
|
existedVisibleFloatingUI.element.isPopoverVisible &&
|
|
3123
|
-
|
|
3124
|
-
|
|
3397
|
+
existedVisibleFloatingUI.eventPrefix === this.eventPrefix
|
|
3398
|
+
) {
|
|
3399
|
+
existedVisibleFloatingUI.hideBib();
|
|
3125
3400
|
}
|
|
3126
3401
|
|
|
3127
3402
|
document.expandedAuroFloater = this;
|
|
@@ -3130,7 +3405,7 @@ class AuroFloatingUI {
|
|
|
3130
3405
|
showBib() {
|
|
3131
3406
|
if (!this.element.disabled && !this.showing) {
|
|
3132
3407
|
this.updateCurrentExpandedDropdown();
|
|
3133
|
-
this.element.triggerChevron?.setAttribute(
|
|
3408
|
+
this.element.triggerChevron?.setAttribute("data-expanded", true);
|
|
3134
3409
|
|
|
3135
3410
|
// prevent double showing: isPopovervisible gets first and showBib gets called later
|
|
3136
3411
|
if (!this.showing) {
|
|
@@ -3144,9 +3419,13 @@ class AuroFloatingUI {
|
|
|
3144
3419
|
}
|
|
3145
3420
|
|
|
3146
3421
|
// Setup auto update to handle resize and scroll
|
|
3147
|
-
this.element.cleanup = autoUpdate(
|
|
3148
|
-
this.
|
|
3149
|
-
|
|
3422
|
+
this.element.cleanup = autoUpdate(
|
|
3423
|
+
this.element.trigger || this.element.parentNode,
|
|
3424
|
+
this.element.bib,
|
|
3425
|
+
() => {
|
|
3426
|
+
this.position();
|
|
3427
|
+
},
|
|
3428
|
+
);
|
|
3150
3429
|
}
|
|
3151
3430
|
}
|
|
3152
3431
|
|
|
@@ -3157,7 +3436,7 @@ class AuroFloatingUI {
|
|
|
3157
3436
|
hideBib(eventType = "unknown") {
|
|
3158
3437
|
if (!this.element.disabled && !this.element.noToggle) {
|
|
3159
3438
|
this.lockScroll(false);
|
|
3160
|
-
this.element.triggerChevron?.removeAttribute(
|
|
3439
|
+
this.element.triggerChevron?.removeAttribute("data-expanded");
|
|
3161
3440
|
|
|
3162
3441
|
if (this.element.isPopoverVisible) {
|
|
3163
3442
|
this.element.isPopoverVisible = false;
|
|
@@ -3177,13 +3456,16 @@ class AuroFloatingUI {
|
|
|
3177
3456
|
* @param {String} eventType - The event type that triggered the toggle action.
|
|
3178
3457
|
*/
|
|
3179
3458
|
dispatchEventDropdownToggle(eventType) {
|
|
3180
|
-
const event = new CustomEvent(
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3459
|
+
const event = new CustomEvent(
|
|
3460
|
+
this.eventPrefix ? `${this.eventPrefix}-toggled` : "toggled",
|
|
3461
|
+
{
|
|
3462
|
+
detail: {
|
|
3463
|
+
expanded: this.showing,
|
|
3464
|
+
eventType: eventType || "unknown",
|
|
3465
|
+
},
|
|
3466
|
+
composed: true,
|
|
3184
3467
|
},
|
|
3185
|
-
|
|
3186
|
-
});
|
|
3468
|
+
);
|
|
3187
3469
|
|
|
3188
3470
|
this.element.dispatchEvent(event);
|
|
3189
3471
|
}
|
|
@@ -3195,12 +3477,15 @@ class AuroFloatingUI {
|
|
|
3195
3477
|
this.showBib();
|
|
3196
3478
|
}
|
|
3197
3479
|
|
|
3198
|
-
const event = new CustomEvent(
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3480
|
+
const event = new CustomEvent(
|
|
3481
|
+
this.eventPrefix ? `${this.eventPrefix}-triggerClick` : "triggerClick",
|
|
3482
|
+
{
|
|
3483
|
+
composed: true,
|
|
3484
|
+
detail: {
|
|
3485
|
+
expanded: this.element.isPopoverVisible,
|
|
3486
|
+
},
|
|
3487
|
+
},
|
|
3488
|
+
);
|
|
3204
3489
|
|
|
3205
3490
|
this.element.dispatchEvent(event);
|
|
3206
3491
|
}
|
|
@@ -3208,30 +3493,32 @@ class AuroFloatingUI {
|
|
|
3208
3493
|
handleEvent(event) {
|
|
3209
3494
|
if (!this.element.disableEventShow) {
|
|
3210
3495
|
switch (event.type) {
|
|
3211
|
-
case
|
|
3496
|
+
case "keydown": {
|
|
3212
3497
|
// Support both Enter and Space keys for accessibility
|
|
3213
3498
|
// Space is included as it's expected behavior for interactive elements
|
|
3214
3499
|
|
|
3215
3500
|
const origin = event.composedPath()[0];
|
|
3216
|
-
if (
|
|
3217
|
-
|
|
3501
|
+
if (
|
|
3502
|
+
event.key === "Enter" ||
|
|
3503
|
+
(event.key === " " && (!origin || origin.tagName !== "INPUT"))
|
|
3504
|
+
) {
|
|
3218
3505
|
event.preventDefault();
|
|
3219
3506
|
this.handleClick();
|
|
3220
3507
|
}
|
|
3221
3508
|
break;
|
|
3222
|
-
|
|
3509
|
+
}
|
|
3510
|
+
case "mouseenter":
|
|
3223
3511
|
if (this.element.hoverToggle) {
|
|
3224
3512
|
this.showBib();
|
|
3225
3513
|
}
|
|
3226
3514
|
break;
|
|
3227
|
-
case
|
|
3515
|
+
case "mouseleave":
|
|
3228
3516
|
if (this.element.hoverToggle) {
|
|
3229
3517
|
this.hideBib("mouseleave");
|
|
3230
3518
|
}
|
|
3231
3519
|
break;
|
|
3232
|
-
case
|
|
3520
|
+
case "focus":
|
|
3233
3521
|
if (this.element.focusShow) {
|
|
3234
|
-
|
|
3235
3522
|
/*
|
|
3236
3523
|
This needs to better handle clicking that gives focus -
|
|
3237
3524
|
currently it shows and then immediately hides the bib
|
|
@@ -3239,12 +3526,12 @@ class AuroFloatingUI {
|
|
|
3239
3526
|
this.showBib();
|
|
3240
3527
|
}
|
|
3241
3528
|
break;
|
|
3242
|
-
case
|
|
3529
|
+
case "blur":
|
|
3243
3530
|
// send this task 100ms later queue to
|
|
3244
3531
|
// wait a frame in case focus moves within the floating element/bib
|
|
3245
3532
|
setTimeout(() => this.handleFocusLoss(), 0);
|
|
3246
3533
|
break;
|
|
3247
|
-
case
|
|
3534
|
+
case "click":
|
|
3248
3535
|
if (document.activeElement === document.body) {
|
|
3249
3536
|
event.currentTarget.focus();
|
|
3250
3537
|
}
|
|
@@ -3263,15 +3550,15 @@ class AuroFloatingUI {
|
|
|
3263
3550
|
*/
|
|
3264
3551
|
handleTriggerTabIndex() {
|
|
3265
3552
|
const focusableElementSelectors = [
|
|
3266
|
-
|
|
3267
|
-
|
|
3553
|
+
"a",
|
|
3554
|
+
"button",
|
|
3268
3555
|
'input:not([type="hidden"])',
|
|
3269
|
-
|
|
3270
|
-
|
|
3556
|
+
"select",
|
|
3557
|
+
"textarea",
|
|
3271
3558
|
'[tabindex]:not([tabindex="-1"])',
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3559
|
+
"auro-button",
|
|
3560
|
+
"auro-input",
|
|
3561
|
+
"auro-hyperlink",
|
|
3275
3562
|
];
|
|
3276
3563
|
|
|
3277
3564
|
const triggerNode = this.element.querySelectorAll('[slot="trigger"]')[0];
|
|
@@ -3299,10 +3586,10 @@ class AuroFloatingUI {
|
|
|
3299
3586
|
* @param {*} eventPrefix
|
|
3300
3587
|
*/
|
|
3301
3588
|
regenerateBibId() {
|
|
3302
|
-
this.id = this.element.getAttribute(
|
|
3589
|
+
this.id = this.element.getAttribute("id");
|
|
3303
3590
|
if (!this.id) {
|
|
3304
3591
|
this.id = window.crypto.randomUUID();
|
|
3305
|
-
this.element.setAttribute(
|
|
3592
|
+
this.element.setAttribute("id", this.id);
|
|
3306
3593
|
}
|
|
3307
3594
|
|
|
3308
3595
|
this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
|
|
@@ -3323,11 +3610,15 @@ class AuroFloatingUI {
|
|
|
3323
3610
|
if (this.element.trigger) {
|
|
3324
3611
|
this.disconnect();
|
|
3325
3612
|
}
|
|
3326
|
-
this.element.trigger =
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3613
|
+
this.element.trigger =
|
|
3614
|
+
this.element.triggerElement ||
|
|
3615
|
+
this.element.shadowRoot.querySelector("#trigger") ||
|
|
3616
|
+
this.element.trigger;
|
|
3617
|
+
this.element.bib =
|
|
3618
|
+
this.element.shadowRoot.querySelector("#bib") || this.element.bib;
|
|
3619
|
+
this.element.bibSizer = this.element.shadowRoot.querySelector("#bibSizer");
|
|
3620
|
+
this.element.triggerChevron =
|
|
3621
|
+
this.element.shadowRoot.querySelector("#showStateIcon");
|
|
3331
3622
|
|
|
3332
3623
|
if (this.element.floaterConfig) {
|
|
3333
3624
|
this.element.hoverToggle = this.element.floaterConfig.hoverToggle;
|
|
@@ -3338,12 +3629,12 @@ class AuroFloatingUI {
|
|
|
3338
3629
|
|
|
3339
3630
|
this.handleEvent = this.handleEvent.bind(this);
|
|
3340
3631
|
if (this.element.trigger) {
|
|
3341
|
-
this.element.trigger.addEventListener(
|
|
3342
|
-
this.element.trigger.addEventListener(
|
|
3343
|
-
this.element.trigger.addEventListener(
|
|
3344
|
-
this.element.trigger.addEventListener(
|
|
3345
|
-
this.element.trigger.addEventListener(
|
|
3346
|
-
this.element.trigger.addEventListener(
|
|
3632
|
+
this.element.trigger.addEventListener("keydown", this.handleEvent);
|
|
3633
|
+
this.element.trigger.addEventListener("click", this.handleEvent);
|
|
3634
|
+
this.element.trigger.addEventListener("mouseenter", this.handleEvent);
|
|
3635
|
+
this.element.trigger.addEventListener("mouseleave", this.handleEvent);
|
|
3636
|
+
this.element.trigger.addEventListener("focus", this.handleEvent);
|
|
3637
|
+
this.element.trigger.addEventListener("blur", this.handleEvent);
|
|
3347
3638
|
}
|
|
3348
3639
|
}
|
|
3349
3640
|
|
|
@@ -3358,12 +3649,18 @@ class AuroFloatingUI {
|
|
|
3358
3649
|
|
|
3359
3650
|
// Remove event & keyboard listeners
|
|
3360
3651
|
if (this.element?.trigger) {
|
|
3361
|
-
this.element.trigger.removeEventListener(
|
|
3362
|
-
this.element.trigger.removeEventListener(
|
|
3363
|
-
this.element.trigger.removeEventListener(
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3652
|
+
this.element.trigger.removeEventListener("keydown", this.handleEvent);
|
|
3653
|
+
this.element.trigger.removeEventListener("click", this.handleEvent);
|
|
3654
|
+
this.element.trigger.removeEventListener(
|
|
3655
|
+
"mouseenter",
|
|
3656
|
+
this.handleEvent,
|
|
3657
|
+
);
|
|
3658
|
+
this.element.trigger.removeEventListener(
|
|
3659
|
+
"mouseleave",
|
|
3660
|
+
this.handleEvent,
|
|
3661
|
+
);
|
|
3662
|
+
this.element.trigger.removeEventListener("focus", this.handleEvent);
|
|
3663
|
+
this.element.trigger.removeEventListener("blur", this.handleEvent);
|
|
3367
3664
|
}
|
|
3368
3665
|
}
|
|
3369
3666
|
}
|
|
@@ -3810,7 +4107,7 @@ let p$3 = class p{registerComponent(t,a){customElements.get(t)||customElements.d
|
|
|
3810
4107
|
|
|
3811
4108
|
var iconVersion$2 = '9.1.2';
|
|
3812
4109
|
|
|
3813
|
-
var styleCss$2$1 = css`:host{position:fixed;z-index:var(--depth-tooltip, 400);display:none;isolation:isolate}:host(:not([matchWidth])) .container{min-width:fit-content}:host([isfullscreen]){position:fixed;top:0;left:0}:host([isfullscreen]) .container{width:100dvw;max-width:none;height:100dvh;max-height:none;border-radius:unset;margin-top:0;box-shadow:unset;overscroll-behavior:contain}:host([data-show]){display:flex}:host([common]:not([isfullscreen])) .container,:host([rounded]:not([isfullscreen])) .container{border-radius:var(--ds-border-radius, 0.375rem)}:host([common][isfullscreen]) .container,:host([rounded][isfullscreen]) .container{border-radius:unset;box-shadow:unset}
|
|
4110
|
+
var styleCss$2$1 = css`:host{position:fixed;z-index:var(--depth-tooltip, 400);display:none;isolation:isolate}:host dialog{width:auto;max-width:none;height:auto;max-height:none;padding:0;border:none;margin:0;outline:none;transform:translateZ(0)}:host dialog::backdrop{background:transparent}:host(:not([isfullscreen])) dialog{position:relative;inset:unset}:host(:not([isfullscreen])) .container.shape-box{border-radius:unset}:host(:not([isfullscreen])) .container[class*=shape-pill],:host(:not([isfullscreen])) .container[class*=shape-snowflake]{border-radius:30px}:host(:not([isfullscreen])) .container[class*=shape-rounded]{border-radius:16px}:host(:not([matchWidth])) .container{min-width:fit-content}:host([isfullscreen]){position:fixed;top:0;left:0}:host([isfullscreen]) .container{width:100dvw;max-width:none;height:100dvh;max-height:none;border-radius:unset;margin-top:0;box-shadow:unset;overscroll-behavior:contain}:host([isfullscreen]) .container::backdrop{background:var(--ds-color-background-primary, #fff)}:host([data-show]){display:flex}:host([common]:not([isfullscreen])) .container,:host([rounded]:not([isfullscreen])) .container{border-radius:var(--ds-border-radius, 0.375rem)}:host([common][isfullscreen]) .container,:host([rounded][isfullscreen]) .container{border-radius:unset;box-shadow:unset}.container{display:inline-block;overflow:auto;box-sizing:border-box;border-radius:var(--ds-border-radius, 0.375rem);margin:var(--ds-size-50, 0.25rem) 0}.util_displayHiddenVisually{position:absolute;overflow:hidden;width:1px;height:1px;padding:0;border:0;margin:-1px;clip-path:inset(50%);white-space:nowrap}`;
|
|
3814
4111
|
|
|
3815
4112
|
var colorCss$2$1 = css`.container{background-color:var(--ds-auro-dropdownbib-container-color);box-shadow:var(--ds-auro-dropdownbib-boxshadow-color);color:var(--ds-auro-dropdownbib-text-color)}`;
|
|
3816
4113
|
|
|
@@ -3818,6 +4115,8 @@ var tokensCss$1$1 = css`:host(:not([ondark])),:host(:not([appearance=inverse])){
|
|
|
3818
4115
|
|
|
3819
4116
|
// Copyright (c) 2020 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
3820
4117
|
// See LICENSE in the project root for license information.
|
|
4118
|
+
/* eslint-disable max-lines */
|
|
4119
|
+
// ---------------------------------------------------------------------
|
|
3821
4120
|
|
|
3822
4121
|
|
|
3823
4122
|
const DESIGN_TOKEN_BREAKPOINT_PREFIX = '--ds-grid-breakpoint-';
|
|
@@ -3912,6 +4211,28 @@ class AuroDropdownBib extends LitElement {
|
|
|
3912
4211
|
shape: {
|
|
3913
4212
|
type: String,
|
|
3914
4213
|
reflect: true
|
|
4214
|
+
},
|
|
4215
|
+
|
|
4216
|
+
/**
|
|
4217
|
+
* Accessible label for the dialog element, used when displayed as a modal.
|
|
4218
|
+
* Applied via aria-labelledby on a visually hidden element rather than
|
|
4219
|
+
* aria-label because iOS VoiceOver does not reliably read aria-label
|
|
4220
|
+
* on <dialog> elements.
|
|
4221
|
+
* @private
|
|
4222
|
+
*/
|
|
4223
|
+
dialogLabel: {
|
|
4224
|
+
type: String
|
|
4225
|
+
},
|
|
4226
|
+
|
|
4227
|
+
/**
|
|
4228
|
+
* Overrides the native role of the dialog element.
|
|
4229
|
+
* For example, set to `"presentation"` on desktop combobox to prevent
|
|
4230
|
+
* VoiceOver from announcing "listbox inside of a dialog".
|
|
4231
|
+
* When `undefined`, the dialog keeps its native role.
|
|
4232
|
+
* @private
|
|
4233
|
+
*/
|
|
4234
|
+
dialogRole: {
|
|
4235
|
+
type: String
|
|
3915
4236
|
}
|
|
3916
4237
|
};
|
|
3917
4238
|
}
|
|
@@ -3979,7 +4300,10 @@ class AuroDropdownBib extends LitElement {
|
|
|
3979
4300
|
firstUpdated(changedProperties) {
|
|
3980
4301
|
super.firstUpdated(changedProperties);
|
|
3981
4302
|
|
|
3982
|
-
|
|
4303
|
+
const dialog = this.shadowRoot.querySelector('dialog');
|
|
4304
|
+
this._setupCancelHandler(dialog);
|
|
4305
|
+
this._setupKeyboardBridge(dialog);
|
|
4306
|
+
|
|
3983
4307
|
this.dispatchEvent(new CustomEvent('auro-dropdownbib-connected', {
|
|
3984
4308
|
bubbles: true,
|
|
3985
4309
|
composed: true,
|
|
@@ -3989,6 +4313,189 @@ class AuroDropdownBib extends LitElement {
|
|
|
3989
4313
|
}));
|
|
3990
4314
|
}
|
|
3991
4315
|
|
|
4316
|
+
/**
|
|
4317
|
+
* Forwards the dialog's native `cancel` event (fired on ESC) as
|
|
4318
|
+
* an `auro-bib-cancel` custom event so parent components can close.
|
|
4319
|
+
* @param {HTMLDialogElement} dialog
|
|
4320
|
+
* @private
|
|
4321
|
+
*/
|
|
4322
|
+
_setupCancelHandler(dialog) {
|
|
4323
|
+
dialog.addEventListener('cancel', (event) => {
|
|
4324
|
+
event.preventDefault();
|
|
4325
|
+
this.dispatchEvent(new CustomEvent('auro-bib-cancel', {
|
|
4326
|
+
bubbles: true,
|
|
4327
|
+
composed: true
|
|
4328
|
+
}));
|
|
4329
|
+
});
|
|
4330
|
+
}
|
|
4331
|
+
|
|
4332
|
+
/**
|
|
4333
|
+
* showModal() creates a closed focus scope — keyboard events inside
|
|
4334
|
+
* the dialog's shadow DOM do NOT bubble out to the combobox/select
|
|
4335
|
+
* keydown handlers in the parent shadow DOM. This handler bridges
|
|
4336
|
+
* that gap by re-dispatching navigation keys so they cross the
|
|
4337
|
+
* shadow boundary and reach the menu navigation logic in the parent
|
|
4338
|
+
* component.
|
|
4339
|
+
*
|
|
4340
|
+
* The trade-off: intercepting these keys means native keyboard
|
|
4341
|
+
* behaviors that would normally "just work" must be manually
|
|
4342
|
+
* re-implemented here:
|
|
4343
|
+
*
|
|
4344
|
+
* - Enter on buttons: Custom elements (auro-button) don't get the
|
|
4345
|
+
* native Enter→click that <button> provides, so we call .click()
|
|
4346
|
+
* directly when Enter is pressed on a button-like element.
|
|
4347
|
+
*
|
|
4348
|
+
* - Tab: Intercepted and re-dispatched so parent components
|
|
4349
|
+
* (select/combobox) can select the active option and close the
|
|
4350
|
+
* dialog. The <dialog> provides containment and isolation
|
|
4351
|
+
* (inert background, VoiceOver focus trapping, top layer), while
|
|
4352
|
+
* the content inside is a role="listbox" navigated via
|
|
4353
|
+
* aria-activedescendant (options are not focusable). Tab keyboard
|
|
4354
|
+
* behavior follows listbox conventions (select + close) because
|
|
4355
|
+
* the dialog's native Tab trap only cycles between the close
|
|
4356
|
+
* button and browser chrome.
|
|
4357
|
+
*
|
|
4358
|
+
* - Escape: The native <dialog> fires a `cancel` event on ESC
|
|
4359
|
+
* (handled by _setupCancelHandler), so the re-dispatched Escape
|
|
4360
|
+
* is a secondary path for parent components that also listen for
|
|
4361
|
+
* Escape keydown.
|
|
4362
|
+
*
|
|
4363
|
+
* @param {HTMLDialogElement} dialog
|
|
4364
|
+
* @private
|
|
4365
|
+
*/
|
|
4366
|
+
_setupKeyboardBridge(dialog) {
|
|
4367
|
+
const navKeys = new Set([
|
|
4368
|
+
'ArrowUp',
|
|
4369
|
+
'ArrowDown',
|
|
4370
|
+
'Enter',
|
|
4371
|
+
'Escape',
|
|
4372
|
+
'Tab'
|
|
4373
|
+
]);
|
|
4374
|
+
|
|
4375
|
+
dialog.addEventListener('keydown', (event) => {
|
|
4376
|
+
if (!navKeys.has(event.key)) {
|
|
4377
|
+
return;
|
|
4378
|
+
}
|
|
4379
|
+
|
|
4380
|
+
// Custom elements (auro-button) don't get the native Enter→click
|
|
4381
|
+
// behavior that <button> has. Find the button in the composed path
|
|
4382
|
+
// and click it directly.
|
|
4383
|
+
if (event.key === 'Enter') {
|
|
4384
|
+
const buttonSelector = 'button, [role="button"], auro-button, [auro-button]';
|
|
4385
|
+
const btn = event.composedPath().find((el) => el.matches && el.matches(buttonSelector));
|
|
4386
|
+
if (btn) {
|
|
4387
|
+
event.preventDefault();
|
|
4388
|
+
event.stopPropagation();
|
|
4389
|
+
btn.click();
|
|
4390
|
+
return;
|
|
4391
|
+
}
|
|
4392
|
+
}
|
|
4393
|
+
|
|
4394
|
+
event.preventDefault();
|
|
4395
|
+
event.stopPropagation();
|
|
4396
|
+
const newEvent = new KeyboardEvent('keydown', {
|
|
4397
|
+
key: event.key,
|
|
4398
|
+
code: event.code,
|
|
4399
|
+
shiftKey: event.shiftKey,
|
|
4400
|
+
altKey: event.altKey,
|
|
4401
|
+
ctrlKey: event.ctrlKey,
|
|
4402
|
+
metaKey: event.metaKey,
|
|
4403
|
+
bubbles: true,
|
|
4404
|
+
composed: true,
|
|
4405
|
+
cancelable: true
|
|
4406
|
+
});
|
|
4407
|
+
this.dispatchEvent(newEvent);
|
|
4408
|
+
});
|
|
4409
|
+
}
|
|
4410
|
+
|
|
4411
|
+
/**
|
|
4412
|
+
* Blocks touch-driven page scroll while a fullscreen modal dialog is open.
|
|
4413
|
+
*
|
|
4414
|
+
* The showModal() function places the dialog in the browser's **top layer**,
|
|
4415
|
+
* which is a separate rendering layer above the normal DOM. On mobile, the
|
|
4416
|
+
* compositor processes visual-viewport panning before top-layer touch
|
|
4417
|
+
* handling. This means the entire viewport — including the top-layer dialog
|
|
4418
|
+
* — can be panned by a touch gesture, causing the page behind the dialog to
|
|
4419
|
+
* scroll into view. To prevent this, we add a touchmove listener that cancels
|
|
4420
|
+
* the event if the touch started outside the dialog or any scrollable child within it.
|
|
4421
|
+
*
|
|
4422
|
+
* @private
|
|
4423
|
+
*/
|
|
4424
|
+
_lockTouchScroll() {
|
|
4425
|
+
const dialog = this.shadowRoot.querySelector('dialog');
|
|
4426
|
+
|
|
4427
|
+
this._touchMoveHandler = (event) => {
|
|
4428
|
+
// Walk the composed path (which crosses shadow DOM boundaries) to
|
|
4429
|
+
// check whether the touch started inside a scrollable element that
|
|
4430
|
+
// lives within the dialog. If so, allow the scroll.
|
|
4431
|
+
for (const el of event.composedPath()) {
|
|
4432
|
+
if (el === dialog) {
|
|
4433
|
+
// Reached the dialog boundary without finding a scrollable child.
|
|
4434
|
+
break;
|
|
4435
|
+
}
|
|
4436
|
+
if (el instanceof HTMLElement && el.scrollHeight > el.clientHeight) {
|
|
4437
|
+
const { overflowY } = getComputedStyle(el);
|
|
4438
|
+
if (overflowY === 'auto' || overflowY === 'scroll') {
|
|
4439
|
+
return;
|
|
4440
|
+
}
|
|
4441
|
+
}
|
|
4442
|
+
}
|
|
4443
|
+
|
|
4444
|
+
event.preventDefault();
|
|
4445
|
+
};
|
|
4446
|
+
|
|
4447
|
+
document.addEventListener('touchmove', this._touchMoveHandler, { passive: false });
|
|
4448
|
+
}
|
|
4449
|
+
|
|
4450
|
+
/**
|
|
4451
|
+
* Removes the touchmove listener added by _lockTouchScroll().
|
|
4452
|
+
* @private
|
|
4453
|
+
*/
|
|
4454
|
+
_unlockTouchScroll() {
|
|
4455
|
+
if (this._touchMoveHandler) {
|
|
4456
|
+
document.removeEventListener('touchmove', this._touchMoveHandler);
|
|
4457
|
+
this._touchMoveHandler = undefined;
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4460
|
+
|
|
4461
|
+
open(modal = true) {
|
|
4462
|
+
const dialog = this.shadowRoot.querySelector('dialog');
|
|
4463
|
+
if (dialog && !dialog.open) {
|
|
4464
|
+
if (modal) {
|
|
4465
|
+
// Prevent showModal() from scrolling the page to bring the dialog
|
|
4466
|
+
// into view. Locking overflow on <html> blocks the viewport scroll
|
|
4467
|
+
// that browsers perform natively; we release it immediately after
|
|
4468
|
+
// so it doesn't interfere with the modal's focus management.
|
|
4469
|
+
const { documentElement } = document;
|
|
4470
|
+
const prevOverflow = documentElement.style.overflow;
|
|
4471
|
+
documentElement.style.overflow = 'hidden';
|
|
4472
|
+
|
|
4473
|
+
dialog.showModal();
|
|
4474
|
+
|
|
4475
|
+
documentElement.style.overflow = prevOverflow;
|
|
4476
|
+
|
|
4477
|
+
this._lockTouchScroll();
|
|
4478
|
+
|
|
4479
|
+
} else {
|
|
4480
|
+
// Use setAttribute instead of dialog.show() to avoid the dialog
|
|
4481
|
+
// focusing steps which steal focus from the trigger and cause
|
|
4482
|
+
// the floater's handleFocusLoss() to immediately hide the bib.
|
|
4483
|
+
dialog.setAttribute('open', '');
|
|
4484
|
+
}
|
|
4485
|
+
}
|
|
4486
|
+
}
|
|
4487
|
+
|
|
4488
|
+
/**
|
|
4489
|
+
* Closes the dialog.
|
|
4490
|
+
*/
|
|
4491
|
+
close() {
|
|
4492
|
+
const dialog = this.shadowRoot.querySelector('dialog');
|
|
4493
|
+
if (dialog && dialog.open) {
|
|
4494
|
+
this._unlockTouchScroll();
|
|
4495
|
+
dialog.close();
|
|
4496
|
+
}
|
|
4497
|
+
}
|
|
4498
|
+
|
|
3992
4499
|
// function that renders the HTML and CSS into the scope of the component
|
|
3993
4500
|
render() {
|
|
3994
4501
|
const classes = {
|
|
@@ -4000,9 +4507,10 @@ class AuroDropdownBib extends LitElement {
|
|
|
4000
4507
|
classes[`shape-${this.shape}`] = true;
|
|
4001
4508
|
|
|
4002
4509
|
return html`
|
|
4003
|
-
<
|
|
4510
|
+
<dialog class="${classMap(classes)}" part="bibContainer" role="${ifDefined(this.dialogRole)}" aria-labelledby="${ifDefined(this.dialogLabel ? 'dialogLabel' : undefined)}">
|
|
4511
|
+
${this.dialogLabel ? html`<span id="dialogLabel" class="util_displayHiddenVisually" aria-hidden="true">${this.dialogLabel}</span>` : ''}
|
|
4004
4512
|
<slot></slot>
|
|
4005
|
-
</
|
|
4513
|
+
</dialog>
|
|
4006
4514
|
`;
|
|
4007
4515
|
}
|
|
4008
4516
|
}
|
|
@@ -4011,7 +4519,7 @@ var shapeSizeCss$1 = css`.shape-classic-xl,.shape-classic-lg,.shape-classic-md,.
|
|
|
4011
4519
|
|
|
4012
4520
|
var colorCss$1$1 = css`:host(:not([layout*=classic])){--ds-auro-dropdown-trigger-border-color: transparent}:host(:not([disabled],[onDark])) .wrapper:focus-within,:host(:not([disabled],[onDark])) .wrapper:active,:host(:not([disabled],[appearance=inverse])) .wrapper:focus-within,:host(:not([disabled],[appearance=inverse])) .wrapper:active{--ds-auro-dropdown-trigger-border-color: var(--ds-advanced-color-state-focused, #01426a);--ds-auro-dropdown-trigger-outline-color: var(--ds-advanced-color-state-focused, #01426a)}:host(:not([disabled],[onDark])) .wrapper:hover,:host(:not([disabled],[appearance=inverse])) .wrapper:hover{--ds-auro-dropdown-trigger-background-color: var(--ds-auro-dropdown-trigger-hover-background-color)}:host(:not([ondark])) .wrapper,:host(:not([appearance=inverse])) .wrapper{border-color:var(--ds-auro-dropdown-trigger-border-color);background-color:var(--ds-auro-dropdown-trigger-background-color);color:var(--ds-auro-dropdown-trigger-text-color)}:host(:not([onDark])[disabled]),:host(:not([appearance=inverse])[disabled]){--ds-auro-dropdown-trigger-text-color: var(--ds-basic-color-texticon-disabled, #d0d0d0);--ds-auro-dropdown-label-text-color: var(--ds-basic-color-texticon-disabled, #d0d0d0);--ds-auro-dropdown-trigger-border-color: var(--ds-basic-color-border-subtle, #dddddd)}:host(:not([onDark])[disabled]) #triggerLabel,:host(:not([appearance=inverse])[disabled]) #triggerLabel{cursor:default}:host(:not([ondark])[error]),:host(:not([appearance=inverse])[error]){--ds-auro-dropdown-trigger-border-color: var(--ds-basic-color-status-error, #e31f26)}:host(:not([disabled])[onDark]) .wrapper:focus-within,:host(:not([disabled])[onDark]) .wrapper:active,:host(:not([disabled])[appearance=inverse]) .wrapper:focus-within,:host(:not([disabled])[appearance=inverse]) .wrapper:active{--ds-auro-dropdown-trigger-border-color: var(--ds-advanced-color-state-focused-inverse, #ffffff);--ds-auro-dropdown-trigger-outline-color: var(--ds-advanced-color-state-focused-inverse, #ffffff)}:host(:not([disabled])[onDark]) .wrapper:hover,:host(:not([disabled])[appearance=inverse]) .wrapper:hover{--ds-auro-dropdown-trigger-background-color: var(--ds-auro-dropdown-trigger-hover-background-color)}:host([onDark]) .label,:host([onDark]) .helpText,:host([appearance=inverse]) .label,:host([appearance=inverse]) .helpText{color:var(--ds-auro-dropdown-label-text-color)}:host([onDark]) .wrapper,:host([appearance=inverse]) .wrapper{border-color:var(--ds-auro-dropdown-trigger-border-color);background-color:var(--ds-auro-dropdown-trigger-background-color);color:var(--ds-auro-dropdown-trigger-text-color)}:host([onDark][disabled]),:host([appearance=inverse][disabled]){--ds-auro-dropdown-trigger-text-color: var(--ds-basic-color-texticon-inverse-disabled, #7e8894);--ds-auro-dropdown-label-text-color: var(--ds-basic-color-texticon-inverse-disabled, #7e8894);--ds-auro-dropdown-trigger-container-color: var(--ds-advanced-color-shared-background-inverse-disabled, rgba(255, 255, 255, 0.1))}:host([onDark][disabled]) #triggerLabel,:host([appearance=inverse][disabled]) #triggerLabel{cursor:default}:host([ondark][error]),:host([appearance=inverse][error]){--ds-auro-dropdown-trigger-border-color: var(--ds-advanced-color-state-error-inverse, #f9a4a8)}`;
|
|
4013
4521
|
|
|
4014
|
-
var styleCss$1$2 = css`:host{position:relative;display:block;text-align:left}
|
|
4522
|
+
var styleCss$1$2 = css`:host{position:relative;display:block;text-align:left}:host([open]){z-index:var(--depth-tooltip, 400)}.wrapper{display:flex;flex:1;flex-direction:row;align-items:center;justify-content:center;outline:none}.triggerContentWrapper{display:flex;overflow:hidden;width:100%;flex:1;align-items:center;justify-content:center;text-overflow:ellipsis;white-space:nowrap}:host([matchwidth]) #bibSizer{width:100%}`;
|
|
4015
4523
|
|
|
4016
4524
|
var classicColorCss$1 = css``;
|
|
4017
4525
|
|
|
@@ -4249,7 +4757,7 @@ let AuroHelpText$2 = class AuroHelpText extends LitElement {
|
|
|
4249
4757
|
}
|
|
4250
4758
|
};
|
|
4251
4759
|
|
|
4252
|
-
var formkitVersion$2 = '
|
|
4760
|
+
var formkitVersion$2 = '202603102257';
|
|
4253
4761
|
|
|
4254
4762
|
let AuroElement$2 = class AuroElement extends LitElement {
|
|
4255
4763
|
static get properties() {
|
|
@@ -4363,7 +4871,7 @@ let AuroElement$2 = class AuroElement extends LitElement {
|
|
|
4363
4871
|
* The `auro-dropdown` element provides a way to place content in a bib that can be toggled.
|
|
4364
4872
|
* @customElement auro-dropdown
|
|
4365
4873
|
*
|
|
4366
|
-
* @slot - Default slot for the
|
|
4874
|
+
* @slot - Default slot for the dropdown bib content.
|
|
4367
4875
|
* @slot helpText - Defines the content of the helpText.
|
|
4368
4876
|
* @slot trigger - Defines the content of the trigger.
|
|
4369
4877
|
* @csspart trigger - The trigger content container.
|
|
@@ -4375,6 +4883,13 @@ let AuroElement$2 = class AuroElement extends LitElement {
|
|
|
4375
4883
|
* @event auroDropdown-idAdded - Notifies consumers that the unique ID for the dropdown bib has been generated.
|
|
4376
4884
|
*/
|
|
4377
4885
|
class AuroDropdown extends AuroElement$2 {
|
|
4886
|
+
static get shadowRootOptions() {
|
|
4887
|
+
return {
|
|
4888
|
+
...AuroElement$2.shadowRootOptions,
|
|
4889
|
+
delegatesFocus: true,
|
|
4890
|
+
};
|
|
4891
|
+
}
|
|
4892
|
+
|
|
4378
4893
|
constructor() {
|
|
4379
4894
|
super();
|
|
4380
4895
|
|
|
@@ -4440,15 +4955,6 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
4440
4955
|
this.shift = false;
|
|
4441
4956
|
this.autoPlacement = false;
|
|
4442
4957
|
|
|
4443
|
-
/**
|
|
4444
|
-
* @private
|
|
4445
|
-
* @property {boolean} delegatesFocus - Whether the shadow root delegates focus.
|
|
4446
|
-
*/
|
|
4447
|
-
this.constructor.shadowRootOptions = {
|
|
4448
|
-
...LitElement.shadowRootOptions,
|
|
4449
|
-
delegatesFocus: true,
|
|
4450
|
-
};
|
|
4451
|
-
|
|
4452
4958
|
/**
|
|
4453
4959
|
* @private
|
|
4454
4960
|
*/
|
|
@@ -4522,6 +5028,18 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
4522
5028
|
*/
|
|
4523
5029
|
show() {
|
|
4524
5030
|
this.floater.showBib();
|
|
5031
|
+
|
|
5032
|
+
// Open dialog synchronously so callers remain in the user gesture
|
|
5033
|
+
// chain. This is critical for mobile browsers (iOS Safari) to keep
|
|
5034
|
+
// the virtual keyboard open when transitioning from the trigger
|
|
5035
|
+
// input to an input inside the fullscreen dialog. Without this,
|
|
5036
|
+
// showModal() fires asynchronously via Lit's update cycle, which
|
|
5037
|
+
// falls outside the user activation window and causes iOS to
|
|
5038
|
+
// dismiss the keyboard.
|
|
5039
|
+
if (this.isBibFullscreen && this.bibElement && this.bibElement.value) {
|
|
5040
|
+
const useModal = !this.disableFocusTrap;
|
|
5041
|
+
this.bibElement.value.open(useModal);
|
|
5042
|
+
}
|
|
4525
5043
|
}
|
|
4526
5044
|
|
|
4527
5045
|
/**
|
|
@@ -4529,13 +5047,37 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
4529
5047
|
* If not, trigger element will get focus.
|
|
4530
5048
|
*/
|
|
4531
5049
|
focus() {
|
|
4532
|
-
if (this.isPopoverVisible && this.
|
|
4533
|
-
this.
|
|
5050
|
+
if (this.isPopoverVisible && this.bibContent) {
|
|
5051
|
+
const focusables = getFocusableElements(this.bibContent);
|
|
5052
|
+
if (focusables.length > 0) {
|
|
5053
|
+
focusables[0].focus();
|
|
5054
|
+
}
|
|
4534
5055
|
} else {
|
|
4535
5056
|
this.trigger.focus();
|
|
4536
5057
|
}
|
|
4537
5058
|
}
|
|
4538
5059
|
|
|
5060
|
+
/**
|
|
5061
|
+
* Sets the active descendant element for accessibility.
|
|
5062
|
+
* Uses ariaActiveDescendantElement to cross shadow DOM boundaries.
|
|
5063
|
+
* This function is used in components that contain `auro-dropdown` to set the active descendant.
|
|
5064
|
+
* @private
|
|
5065
|
+
* @param {HTMLElement|null} element - The element to set as the active descendant, or null to clear.
|
|
5066
|
+
* @returns {void}
|
|
5067
|
+
*/
|
|
5068
|
+
setActiveDescendant(element) {
|
|
5069
|
+
if (!this.trigger) {
|
|
5070
|
+
return;
|
|
5071
|
+
}
|
|
5072
|
+
|
|
5073
|
+
if (element) {
|
|
5074
|
+
this.trigger.ariaActiveDescendantElement = element;
|
|
5075
|
+
} else {
|
|
5076
|
+
this.trigger.ariaActiveDescendantElement = null;
|
|
5077
|
+
this.trigger.removeAttribute('aria-activedescendant');
|
|
5078
|
+
}
|
|
5079
|
+
}
|
|
5080
|
+
|
|
4539
5081
|
// function to define props used within the scope of this component
|
|
4540
5082
|
static get properties() {
|
|
4541
5083
|
return {
|
|
@@ -4793,6 +5335,16 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
4793
5335
|
*/
|
|
4794
5336
|
tabIndex: {
|
|
4795
5337
|
type: Number
|
|
5338
|
+
},
|
|
5339
|
+
|
|
5340
|
+
/**
|
|
5341
|
+
* Accessible label for the dropdown bib dialog element.
|
|
5342
|
+
* @private
|
|
5343
|
+
*/
|
|
5344
|
+
bibDialogLabel: {
|
|
5345
|
+
type: String,
|
|
5346
|
+
attribute: false,
|
|
5347
|
+
reflect: false
|
|
4796
5348
|
}
|
|
4797
5349
|
};
|
|
4798
5350
|
}
|
|
@@ -4844,7 +5396,10 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
4844
5396
|
|
|
4845
5397
|
disconnectedCallback() {
|
|
4846
5398
|
super.disconnectedCallback();
|
|
4847
|
-
this.floater
|
|
5399
|
+
if (this.floater) {
|
|
5400
|
+
this.floater.hideBib('disconnect');
|
|
5401
|
+
this.floater.disconnect();
|
|
5402
|
+
}
|
|
4848
5403
|
this.clearTriggerFocusEventBinding();
|
|
4849
5404
|
}
|
|
4850
5405
|
|
|
@@ -4866,11 +5421,22 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
4866
5421
|
|
|
4867
5422
|
if (changedProperties.has('isPopoverVisible') && this.bibElement.value) {
|
|
4868
5423
|
if (this.isPopoverVisible) {
|
|
4869
|
-
|
|
5424
|
+
// Fullscreen: use showModal() for native accessibility (inert outside, focus trap)
|
|
5425
|
+
// Desktop: use show() for Floating UI positioning + FocusTrap for focus management
|
|
5426
|
+
const useModal = this.isBibFullscreen && !this.disableFocusTrap;
|
|
5427
|
+
this.bibElement.value.open(useModal);
|
|
4870
5428
|
} else {
|
|
4871
|
-
this.bibElement.value.
|
|
5429
|
+
this.bibElement.value.close();
|
|
4872
5430
|
}
|
|
4873
5431
|
}
|
|
5432
|
+
|
|
5433
|
+
// When fullscreen strategy changes while open, re-open dialog with correct mode
|
|
5434
|
+
// (e.g. resizing from desktop → mobile while dropdown is open)
|
|
5435
|
+
if (changedProperties.has('isBibFullscreen') && this.isPopoverVisible && this.bibElement.value) {
|
|
5436
|
+
const useModal = this.isBibFullscreen && !this.disableFocusTrap;
|
|
5437
|
+
this.bibElement.value.close();
|
|
5438
|
+
this.bibElement.value.open(useModal);
|
|
5439
|
+
}
|
|
4874
5440
|
}
|
|
4875
5441
|
|
|
4876
5442
|
/**
|
|
@@ -4888,11 +5454,28 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
4888
5454
|
}
|
|
4889
5455
|
|
|
4890
5456
|
firstUpdated() {
|
|
4891
|
-
|
|
4892
5457
|
// Configure the floater to, this will generate the ID for the bib
|
|
4893
5458
|
this.floater.configure(this, 'auroDropdown');
|
|
5459
|
+
|
|
5460
|
+
// Prevent `contain: layout` on the dropdown host. Layout containment
|
|
5461
|
+
// creates a containing block for position:fixed descendants (the bib),
|
|
5462
|
+
// which clips the bib inside ancestor overflow contexts such as a
|
|
5463
|
+
// <dialog> element. Without it, the bib's position:fixed is relative
|
|
5464
|
+
// to the viewport, letting Floating UI's flip middleware detect
|
|
5465
|
+
// viewport boundaries and the bib escape overflow clipping.
|
|
5466
|
+
const origConfigureBibStrategy = this.floater.configureBibStrategy.bind(this.floater);
|
|
5467
|
+
this.floater.configureBibStrategy = (value) => {
|
|
5468
|
+
origConfigureBibStrategy(value);
|
|
5469
|
+
this.style.contain = '';
|
|
5470
|
+
};
|
|
5471
|
+
|
|
4894
5472
|
this.addEventListener('auroDropdown-toggled', this.handleDropdownToggle);
|
|
4895
5473
|
|
|
5474
|
+
// Handle ESC key from dialog's cancel event
|
|
5475
|
+
this.addEventListener('auro-bib-cancel', () => {
|
|
5476
|
+
this.floater.hideBib('keydown');
|
|
5477
|
+
});
|
|
5478
|
+
|
|
4896
5479
|
/**
|
|
4897
5480
|
* @description Let subscribers know that the dropdown ID ha been generated and added.
|
|
4898
5481
|
* @event auroDropdown-idAdded
|
|
@@ -4900,9 +5483,9 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
4900
5483
|
*/
|
|
4901
5484
|
this.dispatchEvent(new CustomEvent('auroDropdown-idAdded', {detail: {id: this.floater.element.id}}));
|
|
4902
5485
|
|
|
4903
|
-
// Set the bib ID locally
|
|
5486
|
+
// Set the bib ID locally for aria-controls (must be in the same shadow root as the trigger)
|
|
4904
5487
|
if (!this.triggerContentFocusable) {
|
|
4905
|
-
this.dropdownId = this.floater.element.id;
|
|
5488
|
+
this.dropdownId = this.floater.element.bib.id;
|
|
4906
5489
|
}
|
|
4907
5490
|
|
|
4908
5491
|
this.bibContent = this.floater.element.bib;
|
|
@@ -4962,21 +5545,20 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
4962
5545
|
* @private
|
|
4963
5546
|
*/
|
|
4964
5547
|
updateFocusTrap() {
|
|
4965
|
-
// If the dropdown is open, create a focus trap and focus the first element
|
|
4966
5548
|
if (this.isPopoverVisible && !this.disableFocusTrap) {
|
|
4967
|
-
|
|
4968
|
-
|
|
5549
|
+
if (!this.isBibFullscreen) {
|
|
5550
|
+
// Desktop: show() doesn't trap focus, so use FocusTrap
|
|
5551
|
+
this.focusTrap = new FocusTrap(this.bibContent);
|
|
5552
|
+
this.focusTrap.focusFirstElement();
|
|
5553
|
+
}
|
|
5554
|
+
// Fullscreen: showModal() provides native focus trapping
|
|
4969
5555
|
return;
|
|
4970
5556
|
}
|
|
4971
5557
|
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
5558
|
+
if (this.focusTrap) {
|
|
5559
|
+
this.focusTrap.disconnect();
|
|
5560
|
+
this.focusTrap = undefined;
|
|
4975
5561
|
}
|
|
4976
|
-
|
|
4977
|
-
// If the dropdown is not open, disconnect the focus trap if it exists
|
|
4978
|
-
this.focusTrap.disconnect();
|
|
4979
|
-
this.focusTrap = undefined;
|
|
4980
5562
|
}
|
|
4981
5563
|
|
|
4982
5564
|
/**
|
|
@@ -5192,13 +5774,14 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
5192
5774
|
<div
|
|
5193
5775
|
id="showStateIcon"
|
|
5194
5776
|
class="chevron"
|
|
5195
|
-
part="chevron"
|
|
5777
|
+
part="chevron"
|
|
5778
|
+
aria-hidden="true">
|
|
5196
5779
|
<${this.iconTag}
|
|
5197
5780
|
category="interface"
|
|
5198
5781
|
name="${this.isPopoverVisible ? 'chevron-up' : `chevron-down`}"
|
|
5199
5782
|
appearance="${this.onDark ? 'inverse' : this.appearance}"
|
|
5200
|
-
variant="${this.disabled ? 'disabled' : 'muted'}"
|
|
5201
|
-
>
|
|
5783
|
+
variant="${this.disabled ? 'disabled' : 'muted'}"
|
|
5784
|
+
ariaHidden="true">
|
|
5202
5785
|
</${this.iconTag}>
|
|
5203
5786
|
</div>
|
|
5204
5787
|
` : undefined }
|
|
@@ -5212,8 +5795,8 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
5212
5795
|
shape="${this.shape}"
|
|
5213
5796
|
?data-show="${this.isPopoverVisible}"
|
|
5214
5797
|
?isfullscreen="${this.isBibFullscreen}"
|
|
5798
|
+
.dialogLabel="${this.bibDialogLabel}"
|
|
5215
5799
|
${ref(this.bibElement)}
|
|
5216
|
-
popover="manual"
|
|
5217
5800
|
>
|
|
5218
5801
|
<div class="slotContent">
|
|
5219
5802
|
<slot @slotchange="${this.handleDefaultSlot}"></slot>
|
|
@@ -10127,7 +10710,7 @@ class AuroFormValidation {
|
|
|
10127
10710
|
}
|
|
10128
10711
|
}
|
|
10129
10712
|
|
|
10130
|
-
if (!hasValue && elem.required && elem.touched) {
|
|
10713
|
+
if (!hasValue && elem.required && (force || elem.touched)) {
|
|
10131
10714
|
elem.validity = 'valueMissing';
|
|
10132
10715
|
elem.errorMessage = elem.setCustomValidityValueMissing || elem.setCustomValidity || '';
|
|
10133
10716
|
} else if (hasValue && this.runtimeUtils.elementMatch(elem, 'auro-input')) {
|
|
@@ -10151,7 +10734,7 @@ class AuroFormValidation {
|
|
|
10151
10734
|
if (!isCombobox || isCombobox && !elem.persistInput) {
|
|
10152
10735
|
|
|
10153
10736
|
// run validation on all inputs since we're going to use them to set the validity of this component
|
|
10154
|
-
this.auroInputElements.forEach(input => input.validate());
|
|
10737
|
+
this.auroInputElements.forEach(input => input.validate(force));
|
|
10155
10738
|
|
|
10156
10739
|
// Reset element validity to the validity of the input
|
|
10157
10740
|
elem.validity = this.auroInputElements[0].validity;
|
|
@@ -10357,6 +10940,17 @@ let AuroElement$1 = class AuroElement extends LitElement {
|
|
|
10357
10940
|
*/
|
|
10358
10941
|
class BaseInput extends AuroElement$1 {
|
|
10359
10942
|
|
|
10943
|
+
// Delegate focus to the native <input> inside the shadow root so that
|
|
10944
|
+
// showModal()'s dialog focusing steps reach the input element.
|
|
10945
|
+
// This keeps the mobile virtual keyboard open when the fullscreen dialog
|
|
10946
|
+
// opens, because the browser sees an input-to-input focus transfer.
|
|
10947
|
+
static get shadowRootOptions() {
|
|
10948
|
+
return {
|
|
10949
|
+
...AuroElement$1.shadowRootOptions,
|
|
10950
|
+
delegatesFocus: true,
|
|
10951
|
+
};
|
|
10952
|
+
}
|
|
10953
|
+
|
|
10360
10954
|
constructor() {
|
|
10361
10955
|
super();
|
|
10362
10956
|
|
|
@@ -10374,6 +10968,7 @@ class BaseInput extends AuroElement$1 {
|
|
|
10374
10968
|
this.icon = false;
|
|
10375
10969
|
this.disabled = false;
|
|
10376
10970
|
this.dvInputOnly = false;
|
|
10971
|
+
this.hideLabelVisually = false;
|
|
10377
10972
|
this.max = undefined;
|
|
10378
10973
|
this.maxLength = undefined;
|
|
10379
10974
|
this.min = undefined;
|
|
@@ -10481,6 +11076,15 @@ class BaseInput extends AuroElement$1 {
|
|
|
10481
11076
|
reflect: true
|
|
10482
11077
|
},
|
|
10483
11078
|
|
|
11079
|
+
/**
|
|
11080
|
+
* The value for the aria-activedescendant attribute.
|
|
11081
|
+
* Points to the ID of the currently active/highlighted option in a listbox.
|
|
11082
|
+
*/
|
|
11083
|
+
a11yActivedescendant: {
|
|
11084
|
+
type: String,
|
|
11085
|
+
reflect: true
|
|
11086
|
+
},
|
|
11087
|
+
|
|
10484
11088
|
/**
|
|
10485
11089
|
* If set, the label will remain fixed in the active position.
|
|
10486
11090
|
*/
|
|
@@ -10587,6 +11191,16 @@ class BaseInput extends AuroElement$1 {
|
|
|
10587
11191
|
attribute: false
|
|
10588
11192
|
},
|
|
10589
11193
|
|
|
11194
|
+
/**
|
|
11195
|
+
* If set, the label will be hidden visually but still accessible to assistive technologies.
|
|
11196
|
+
* @private
|
|
11197
|
+
*/
|
|
11198
|
+
hideLabelVisually: {
|
|
11199
|
+
type: Boolean,
|
|
11200
|
+
reflect: true
|
|
11201
|
+
},
|
|
11202
|
+
|
|
11203
|
+
|
|
10590
11204
|
/**
|
|
10591
11205
|
* If set, will render an icon inside the input to the left of the value. Support is limited to auro-input instances with credit card format.
|
|
10592
11206
|
*/
|
|
@@ -11164,31 +11778,34 @@ class BaseInput extends AuroElement$1 {
|
|
|
11164
11778
|
// Process credit card type detection and formatting during input
|
|
11165
11779
|
if (this.type === 'credit-card') {
|
|
11166
11780
|
this.processCreditCard();
|
|
11167
|
-
|
|
11781
|
+
this.touched = true;
|
|
11782
|
+
this.validation.validate(this);
|
|
11783
|
+
} else {
|
|
11168
11784
|
|
|
11169
|
-
|
|
11170
|
-
|
|
11785
|
+
// Sets value property to value of element value (el.value).
|
|
11786
|
+
this.value = this.inputElement.value;
|
|
11171
11787
|
|
|
11172
|
-
|
|
11173
|
-
|
|
11788
|
+
// Determine if the value change was programmatic, including autofill.
|
|
11789
|
+
const inputWasProgrammatic = !this.matches(":focus") || event.isProgrammatic;
|
|
11174
11790
|
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11791
|
+
// Validation on input or programmatic value change (including autofill).
|
|
11792
|
+
if (this.validateOnInput || inputWasProgrammatic) {
|
|
11793
|
+
this.touched = true;
|
|
11794
|
+
this.validation.validate(this);
|
|
11795
|
+
}
|
|
11180
11796
|
|
|
11181
|
-
|
|
11182
|
-
|
|
11797
|
+
// Prevents cursor jumping in Safari.
|
|
11798
|
+
const { selectionStart } = this.inputElement;
|
|
11183
11799
|
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
|
|
11187
|
-
|
|
11188
|
-
|
|
11189
|
-
|
|
11190
|
-
|
|
11191
|
-
|
|
11800
|
+
if (this.setSelectionInputTypes.includes(this.type)) {
|
|
11801
|
+
this.updateComplete.then(() => {
|
|
11802
|
+
try {
|
|
11803
|
+
this.inputElement.setSelectionRange(selectionStart, selectionStart);
|
|
11804
|
+
} catch (error) { // eslint-disable-line
|
|
11805
|
+
// do nothing
|
|
11806
|
+
}
|
|
11807
|
+
});
|
|
11808
|
+
}
|
|
11192
11809
|
}
|
|
11193
11810
|
}
|
|
11194
11811
|
|
|
@@ -11221,6 +11838,11 @@ class BaseInput extends AuroElement$1 {
|
|
|
11221
11838
|
this.inputElement.scrollLeft = 100;
|
|
11222
11839
|
|
|
11223
11840
|
if (!this.noValidate) {
|
|
11841
|
+
// For credit card inputs with mask, ensure value is synced from mask instance
|
|
11842
|
+
if (this.type === 'credit-card' && this.maskInstance) {
|
|
11843
|
+
this.value = this.maskInstance.value;
|
|
11844
|
+
}
|
|
11845
|
+
|
|
11224
11846
|
this.validation.validate(this);
|
|
11225
11847
|
}
|
|
11226
11848
|
}
|
|
@@ -11245,6 +11867,20 @@ class BaseInput extends AuroElement$1 {
|
|
|
11245
11867
|
return activeEl;
|
|
11246
11868
|
}
|
|
11247
11869
|
|
|
11870
|
+
/**
|
|
11871
|
+
* Sets the active descendant element for accessibility.
|
|
11872
|
+
* Uses ariaActiveDescendantElement to cross shadow DOM boundaries.
|
|
11873
|
+
* This function is used in components that contain `auro-input` to set the active descendant.
|
|
11874
|
+
* @private
|
|
11875
|
+
* @param {HTMLElement|null} element - The element to set as the active descendant, or null to clear.
|
|
11876
|
+
* @returns {void}
|
|
11877
|
+
*/
|
|
11878
|
+
setActiveDescendant(element) {
|
|
11879
|
+
if (this.inputElement) {
|
|
11880
|
+
this.inputElement.ariaActiveDescendantElement = element;
|
|
11881
|
+
}
|
|
11882
|
+
}
|
|
11883
|
+
|
|
11248
11884
|
/**
|
|
11249
11885
|
* Validates value.
|
|
11250
11886
|
* @param {boolean} [force=false] - Whether to force validation.
|
|
@@ -11869,7 +12505,7 @@ let AuroHelpText$1 = class AuroHelpText extends LitElement {
|
|
|
11869
12505
|
}
|
|
11870
12506
|
};
|
|
11871
12507
|
|
|
11872
|
-
var formkitVersion$1 = '
|
|
12508
|
+
var formkitVersion$1 = '202603102257';
|
|
11873
12509
|
|
|
11874
12510
|
// Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
11875
12511
|
// See LICENSE in the project root for license information.
|
|
@@ -12051,7 +12687,7 @@ class AuroInput extends BaseInput {
|
|
|
12051
12687
|
return {
|
|
12052
12688
|
'is-disabled': this.disabled,
|
|
12053
12689
|
'withValue': this.hasValue,
|
|
12054
|
-
'util_displayHiddenVisually': this.labelHidden,
|
|
12690
|
+
'util_displayHiddenVisually': this.labelHidden || this.hideLabelVisually,
|
|
12055
12691
|
[this.labelFontClass]: true,
|
|
12056
12692
|
};
|
|
12057
12693
|
}
|
|
@@ -12223,6 +12859,7 @@ class AuroInput extends BaseInput {
|
|
|
12223
12859
|
?activeLabel="${this.activeLabel}"
|
|
12224
12860
|
?disabled="${this.disabled}"
|
|
12225
12861
|
?required="${this.required}"
|
|
12862
|
+
aria-activedescendant=${ifDefined(this.a11yActivedescendant)}
|
|
12226
12863
|
aria-controls=${ifDefined(this.a11yControls)}
|
|
12227
12864
|
aria-describedby="${this.uniqueId}"
|
|
12228
12865
|
aria-expanded=${ifDefined(this.a11yExpanded)}
|
|
@@ -12837,6 +13474,18 @@ class AuroBibtemplate extends LitElement {
|
|
|
12837
13474
|
this.removeEventListener('touchmove', this.preventBodyScroll, { passive: false });
|
|
12838
13475
|
}
|
|
12839
13476
|
|
|
13477
|
+
/**
|
|
13478
|
+
* Focuses the close button inside the bibtemplate's shadow DOM.
|
|
13479
|
+
* Used by parent components to set initial focus when the fullscreen dialog opens.
|
|
13480
|
+
* @returns {void}
|
|
13481
|
+
*/
|
|
13482
|
+
focusCloseButton() {
|
|
13483
|
+
const closeBtn = this.shadowRoot.querySelector('#closeButton');
|
|
13484
|
+
if (closeBtn) {
|
|
13485
|
+
closeBtn.focus();
|
|
13486
|
+
}
|
|
13487
|
+
}
|
|
13488
|
+
|
|
12840
13489
|
onCloseButtonClick() {
|
|
12841
13490
|
this.dispatchEvent(new Event("close-click", { bubbles: true,
|
|
12842
13491
|
composed: true }));
|
|
@@ -12895,7 +13544,7 @@ class AuroBibtemplate extends LitElement {
|
|
|
12895
13544
|
}
|
|
12896
13545
|
}
|
|
12897
13546
|
|
|
12898
|
-
var formkitVersion = '
|
|
13547
|
+
var formkitVersion = '202603102257';
|
|
12899
13548
|
|
|
12900
13549
|
var styleCss$1 = css`.util_displayInline{display:inline}.util_displayInlineBlock{display:inline-block}.util_displayBlock{display:block}.util_displayFlex{display:flex}.util_displayHidden{display:none}.util_displayHiddenVisually{position:absolute;overflow:hidden;clip:rect(1px, 1px, 1px, 1px);width:1px;height:1px;padding:0;border:0}:host{display:block;text-align:left}:host [auro-dropdown]{--ds-auro-dropdown-trigger-background-color: transparent}:host #inputInBib::part(wrapper){box-shadow:none}:host #inputInBib::part(accent-left){display:none}:host([layout*=classic]) [auro-input]{width:100%}:host([layout*=classic]) [auro-input]::part(helpText){display:none}:host([layout*=classic]) #slotHolder{display:none}`;
|
|
12901
13550
|
|
|
@@ -13311,6 +13960,9 @@ class AuroCombobox extends AuroElement {
|
|
|
13311
13960
|
this.availableOptions = [];
|
|
13312
13961
|
this.dropdownId = undefined;
|
|
13313
13962
|
this.dropdownOpen = false;
|
|
13963
|
+
this.triggerExpandedState = false;
|
|
13964
|
+
this._expandedTimeout = null;
|
|
13965
|
+
this._inFullscreenTransition = false;
|
|
13314
13966
|
this.errorMessage = null;
|
|
13315
13967
|
this.isHiddenWhileLoading = false;
|
|
13316
13968
|
this.largeFullscreenHeadline = false;
|
|
@@ -13331,7 +13983,7 @@ class AuroCombobox extends AuroElement {
|
|
|
13331
13983
|
|
|
13332
13984
|
/**
|
|
13333
13985
|
* Defines whether the component will be on lighter or darker backgrounds.
|
|
13334
|
-
* @property {'default' | 'inverse'}
|
|
13986
|
+
* @property {'default' | 'inverse'} appearance - The visual appearance of the component.
|
|
13335
13987
|
* @default 'default'
|
|
13336
13988
|
*/
|
|
13337
13989
|
appearance: {
|
|
@@ -13667,6 +14319,18 @@ class AuroCombobox extends AuroElement {
|
|
|
13667
14319
|
reflect: false,
|
|
13668
14320
|
attribute: false
|
|
13669
14321
|
},
|
|
14322
|
+
|
|
14323
|
+
/**
|
|
14324
|
+
* Deferred aria-expanded state for the trigger input.
|
|
14325
|
+
* Delays the "true" transition so VoiceOver finishes its character echo
|
|
14326
|
+
* before announcing "expanded".
|
|
14327
|
+
* @private
|
|
14328
|
+
*/
|
|
14329
|
+
triggerExpandedState: {
|
|
14330
|
+
type: Boolean,
|
|
14331
|
+
reflect: false,
|
|
14332
|
+
attribute: false
|
|
14333
|
+
},
|
|
13670
14334
|
};
|
|
13671
14335
|
}
|
|
13672
14336
|
|
|
@@ -13764,6 +14428,8 @@ class AuroCombobox extends AuroElement {
|
|
|
13764
14428
|
} else if (!option.hasAttribute('persistent')) {
|
|
13765
14429
|
// Hide all other non-persistent options
|
|
13766
14430
|
option.setAttribute('hidden', '');
|
|
14431
|
+
option.removeAttribute('aria-setsize');
|
|
14432
|
+
option.removeAttribute('aria-posinset');
|
|
13767
14433
|
}
|
|
13768
14434
|
});
|
|
13769
14435
|
|
|
@@ -13830,6 +14496,15 @@ class AuroCombobox extends AuroElement {
|
|
|
13830
14496
|
this.availableOptions = [];
|
|
13831
14497
|
this.updateFilter();
|
|
13832
14498
|
|
|
14499
|
+
// Set aria-setsize/aria-posinset on each visible option so screen readers
|
|
14500
|
+
// can announce position even when the listbox context is broken by
|
|
14501
|
+
// shadow DOM boundaries in fullscreen dialog mode.
|
|
14502
|
+
const optionCount = this.availableOptions.length;
|
|
14503
|
+
this.availableOptions.forEach((option, index) => {
|
|
14504
|
+
option.setAttribute('aria-setsize', optionCount);
|
|
14505
|
+
option.setAttribute('aria-posinset', index + 1);
|
|
14506
|
+
});
|
|
14507
|
+
|
|
13833
14508
|
if (this.value && this.input.value && !this.menu.value) {
|
|
13834
14509
|
this.syncValuesAndStates();
|
|
13835
14510
|
}
|
|
@@ -13863,7 +14538,7 @@ class AuroCombobox extends AuroElement {
|
|
|
13863
14538
|
* @returns {void}
|
|
13864
14539
|
*/
|
|
13865
14540
|
showBib() {
|
|
13866
|
-
if (!this.input.value) {
|
|
14541
|
+
if (!this.input.value && !this.dropdown.isBibFullscreen) {
|
|
13867
14542
|
this.dropdown.hide();
|
|
13868
14543
|
return;
|
|
13869
14544
|
}
|
|
@@ -13886,6 +14561,10 @@ class AuroCombobox extends AuroElement {
|
|
|
13886
14561
|
configureDropdown() {
|
|
13887
14562
|
this.dropdown.a11yRole = "combobox";
|
|
13888
14563
|
|
|
14564
|
+
// Prevent dropdown from closing on focus loss since menu content is slotted
|
|
14565
|
+
// from combobox's light DOM and won't be detected by dropdown's contains() check.
|
|
14566
|
+
this.dropdown.noHideOnThisFocusLoss = true;
|
|
14567
|
+
|
|
13889
14568
|
// Listen for the ID to be added to the dropdown so we can capture it and use it for accessibility.
|
|
13890
14569
|
this.dropdown.addEventListener('auroDropdown-idAdded', (event) => {
|
|
13891
14570
|
this.dropdownId = event.detail.id;
|
|
@@ -13896,12 +14575,80 @@ class AuroCombobox extends AuroElement {
|
|
|
13896
14575
|
this.dropdownOpen = ev.detail.expanded;
|
|
13897
14576
|
this.updateMenuShapeSize();
|
|
13898
14577
|
|
|
13899
|
-
//
|
|
13900
|
-
|
|
13901
|
-
|
|
13902
|
-
|
|
14578
|
+
// Defer aria-expanded "true" so VoiceOver finishes character echo
|
|
14579
|
+
// before announcing "expanded". Set "false" immediately on close.
|
|
14580
|
+
clearTimeout(this._expandedTimeout);
|
|
14581
|
+
if (this.dropdownOpen) {
|
|
14582
|
+
const expandedDelay = 150;
|
|
14583
|
+
this._expandedTimeout = setTimeout(() => {
|
|
14584
|
+
this.triggerExpandedState = true;
|
|
14585
|
+
}, expandedDelay);
|
|
14586
|
+
} else {
|
|
14587
|
+
this.triggerExpandedState = false;
|
|
14588
|
+
}
|
|
14589
|
+
|
|
14590
|
+
// Clear aria-activedescendant when dropdown closes
|
|
14591
|
+
if (!this.dropdownOpen && this.input) {
|
|
14592
|
+
this.input.setActiveDescendant(null);
|
|
14593
|
+
this.optionActive = null;
|
|
14594
|
+
|
|
14595
|
+
// Remove the highlighted state from all menu options so re-opening
|
|
14596
|
+
// the dropdown doesn't show a stale highlight.
|
|
14597
|
+
if (this.options) {
|
|
14598
|
+
this.options.forEach((opt) => {
|
|
14599
|
+
opt.active = false;
|
|
14600
|
+
opt.classList.remove('active');
|
|
14601
|
+
});
|
|
13903
14602
|
}
|
|
13904
|
-
|
|
14603
|
+
|
|
14604
|
+
// Restore pointer events on the menu in case they were disabled
|
|
14605
|
+
// during fullscreen open to prevent touch pass-through.
|
|
14606
|
+
this.menu.style.pointerEvents = '';
|
|
14607
|
+
|
|
14608
|
+
restoreTriggerAfterClose(this.dropdown, this.input);
|
|
14609
|
+
}
|
|
14610
|
+
|
|
14611
|
+
if (this.dropdownOpen) {
|
|
14612
|
+
// Suppress or restore dialog semantics based on mode.
|
|
14613
|
+
// On desktop, VoiceOver verbosely announces "listbox inside of a dialog"
|
|
14614
|
+
// which is disruptive for combobox usage. Fullscreen needs dialog semantics.
|
|
14615
|
+
this.updateBibDialogRole();
|
|
14616
|
+
|
|
14617
|
+
if (this.dropdown.isBibFullscreen) {
|
|
14618
|
+
// Guard against spurious validation during the focus transition
|
|
14619
|
+
// from trigger to bib input. Setting trigger.inert = true removes
|
|
14620
|
+
// focus, which fires focusout on the child auro-input before the
|
|
14621
|
+
// bib input receives focus. That focusout triggers the input's own
|
|
14622
|
+
// validate(), which dispatches a composed auroFormElement-validated
|
|
14623
|
+
// event. Because composed events are retargetted at each shadow DOM
|
|
14624
|
+
// boundary, the event appears to originate from the combobox itself
|
|
14625
|
+
// and its listener unconditionally sets this.validity — causing
|
|
14626
|
+
// premature validation. This flag suppresses all validation paths
|
|
14627
|
+
// (focusout handler, handleInputValueChange, validate(), and the
|
|
14628
|
+
// auroFormElement-validated listener) until focus settles in the bib.
|
|
14629
|
+
this._inFullscreenTransition = true;
|
|
14630
|
+
|
|
14631
|
+
// Hide the trigger from assistive technology so VoiceOver cannot reach it
|
|
14632
|
+
// behind the fullscreen dialog
|
|
14633
|
+
this.dropdown.trigger.inert = true;
|
|
14634
|
+
|
|
14635
|
+
guardTouchPassthrough(this.menu);
|
|
14636
|
+
|
|
14637
|
+
// Wait for the bibtemplate to fully render across
|
|
14638
|
+
// multiple Lit update cycles before moving focus into the bib
|
|
14639
|
+
doubleRaf(() => {
|
|
14640
|
+
this.setInputFocus();
|
|
14641
|
+
this._inFullscreenTransition = false;
|
|
14642
|
+
});
|
|
14643
|
+
} else {
|
|
14644
|
+
// wait a frame in case the bib gets hidden immediately after showing because there is no value
|
|
14645
|
+
setTimeout(() => {
|
|
14646
|
+
if (this.componentHasFocus) {
|
|
14647
|
+
this.setInputFocus();
|
|
14648
|
+
}
|
|
14649
|
+
}, 0);
|
|
14650
|
+
}
|
|
14651
|
+
}
|
|
13905
14652
|
});
|
|
13906
14653
|
|
|
13907
14654
|
this.dropdown.addEventListener('auroDropdown-triggerClick', () => {
|
|
@@ -13912,6 +14659,12 @@ class AuroCombobox extends AuroElement {
|
|
|
13912
14659
|
this.bibtemplate = this.dropdown.querySelector(this.bibtemplateTag._$litStatic$);
|
|
13913
14660
|
this.inputInBib = this.bibtemplate.querySelector(this.inputTag._$litStatic$);
|
|
13914
14661
|
|
|
14662
|
+
// Pass label text to the dropdown bib for accessible dialog naming
|
|
14663
|
+
const labelElement = this.querySelector('[slot="label"]');
|
|
14664
|
+
if (labelElement) {
|
|
14665
|
+
this.dropdown.bibDialogLabel = labelElement.textContent.trim() || undefined;
|
|
14666
|
+
}
|
|
14667
|
+
|
|
13915
14668
|
// Exposes the CSS parts from the bibtemplate for styling
|
|
13916
14669
|
this.bibtemplate.exposeCssParts();
|
|
13917
14670
|
|
|
@@ -13922,6 +14675,14 @@ class AuroCombobox extends AuroElement {
|
|
|
13922
14675
|
this.dropdown.addEventListener('auroDropdown-strategy-change', () => {
|
|
13923
14676
|
// event when the strategy(bib mode) is changed between fullscreen and floating
|
|
13924
14677
|
this.updateMenuShapeSize();
|
|
14678
|
+
this.updateBibDialogRole();
|
|
14679
|
+
|
|
14680
|
+
// When switching to fullscreen while open, hide trigger from assistive technology
|
|
14681
|
+
if (this.dropdown.isBibFullscreen && this.dropdown.isPopoverVisible) {
|
|
14682
|
+
this.dropdown.trigger.inert = true;
|
|
14683
|
+
} else if (!this.dropdown.isBibFullscreen) {
|
|
14684
|
+
this.dropdown.trigger.inert = false;
|
|
14685
|
+
}
|
|
13925
14686
|
|
|
13926
14687
|
setTimeout(() => {
|
|
13927
14688
|
this.setInputFocus();
|
|
@@ -13945,6 +14706,13 @@ class AuroCombobox extends AuroElement {
|
|
|
13945
14706
|
setInputFocus() {
|
|
13946
14707
|
if (this.dropdown.isBibFullscreen && this.dropdown.isPopoverVisible) {
|
|
13947
14708
|
this.inputInBib.focus();
|
|
14709
|
+
|
|
14710
|
+
// Place cursor at end of existing text so the user can continue editing
|
|
14711
|
+
const nativeInput = this.inputInBib.inputElement;
|
|
14712
|
+
if (nativeInput && nativeInput.value) {
|
|
14713
|
+
const len = nativeInput.value.length;
|
|
14714
|
+
nativeInput.setSelectionRange(len, len);
|
|
14715
|
+
}
|
|
13948
14716
|
} else if (!this.input.componentHasFocus) {
|
|
13949
14717
|
const focusedEl = this.querySelector(":focus");
|
|
13950
14718
|
this.input.focus();
|
|
@@ -13956,6 +14724,22 @@ class AuroCombobox extends AuroElement {
|
|
|
13956
14724
|
}
|
|
13957
14725
|
}
|
|
13958
14726
|
|
|
14727
|
+
/**
|
|
14728
|
+
* Suppresses or restores dialog semantics on the bib's dialog element.
|
|
14729
|
+
* On desktop (non-fullscreen), VoiceOver verbosely announces "listbox inside
|
|
14730
|
+
* of a dialog" which disrupts combobox usage. Setting role="presentation"
|
|
14731
|
+
* suppresses this. In fullscreen mode, dialog semantics are restored.
|
|
14732
|
+
* @private
|
|
14733
|
+
*/
|
|
14734
|
+
updateBibDialogRole() {
|
|
14735
|
+
const bibEl = this.dropdown.bibElement && this.dropdown.bibElement.value;
|
|
14736
|
+
if (!bibEl) {
|
|
14737
|
+
return;
|
|
14738
|
+
}
|
|
14739
|
+
|
|
14740
|
+
bibEl.dialogRole = this.dropdown.isBibFullscreen ? undefined : 'presentation';
|
|
14741
|
+
}
|
|
14742
|
+
|
|
13959
14743
|
/**
|
|
13960
14744
|
* Update menu to default for fullscreen bib, otherwise to this.size and this.shape.
|
|
13961
14745
|
* @private
|
|
@@ -14041,6 +14825,14 @@ class AuroCombobox extends AuroElement {
|
|
|
14041
14825
|
setTimeout(() => {
|
|
14042
14826
|
this.hideBib();
|
|
14043
14827
|
}, 0);
|
|
14828
|
+
|
|
14829
|
+
// Announce the selection after the dropdown closes so it isn't
|
|
14830
|
+
// overridden by VoiceOver's "collapsed" announcement from aria-expanded.
|
|
14831
|
+
const selectedValue = event.detail.stringValue;
|
|
14832
|
+
const announcementDelay = 300;
|
|
14833
|
+
setTimeout(() => {
|
|
14834
|
+
announceToScreenReader(this.shadowRoot, `${selectedValue}, selected`);
|
|
14835
|
+
}, announcementDelay);
|
|
14044
14836
|
}
|
|
14045
14837
|
});
|
|
14046
14838
|
|
|
@@ -14051,10 +14843,28 @@ class AuroCombobox extends AuroElement {
|
|
|
14051
14843
|
this.menu.addEventListener('auroMenu-activatedOption', (evt) => {
|
|
14052
14844
|
this.optionActive = evt.detail;
|
|
14053
14845
|
|
|
14846
|
+
if (this.input) {
|
|
14847
|
+
this.input.setActiveDescendant(this.optionActive);
|
|
14848
|
+
}
|
|
14849
|
+
|
|
14850
|
+
// Announce the active option for screen readers including position,
|
|
14851
|
+
// since shadow DOM boundaries prevent native reading of
|
|
14852
|
+
// aria-setsize/aria-posinset via aria-activedescendant.
|
|
14853
|
+
if (this.optionActive) {
|
|
14854
|
+
const optionText = this.optionActive.textContent.trim();
|
|
14855
|
+
const selectedState = this.optionActive.hasAttribute('selected') ? ', selected' : ', not selected';
|
|
14856
|
+
const optionIndex = this.availableOptions.indexOf(this.optionActive) + 1;
|
|
14857
|
+
const optionCount = this.availableOptions.length;
|
|
14858
|
+
announceToScreenReader(this.shadowRoot, `${optionText}${selectedState}, ${optionIndex} of ${optionCount}`);
|
|
14859
|
+
}
|
|
14860
|
+
|
|
14861
|
+
// Check if user prefers reduced motion for accessibility
|
|
14862
|
+
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
14863
|
+
|
|
14054
14864
|
this.optionActive.scrollIntoView({
|
|
14055
14865
|
alignToTop: false,
|
|
14056
14866
|
block: "nearest",
|
|
14057
|
-
behavior: "smooth"
|
|
14867
|
+
behavior: prefersReducedMotion ? "auto" : "smooth"
|
|
14058
14868
|
});
|
|
14059
14869
|
});
|
|
14060
14870
|
|
|
@@ -14073,7 +14883,7 @@ class AuroCombobox extends AuroElement {
|
|
|
14073
14883
|
* Validate every time we remove focus from the combo box.
|
|
14074
14884
|
*/
|
|
14075
14885
|
this.addEventListener('focusout', () => {
|
|
14076
|
-
if (!this.componentHasFocus) {
|
|
14886
|
+
if (!this.componentHasFocus && !this._inFullscreenTransition) {
|
|
14077
14887
|
this.validate();
|
|
14078
14888
|
}
|
|
14079
14889
|
});
|
|
@@ -14109,8 +14919,33 @@ class AuroCombobox extends AuroElement {
|
|
|
14109
14919
|
* @returns {void}
|
|
14110
14920
|
*/
|
|
14111
14921
|
handleInputValueChange(event) {
|
|
14922
|
+
// When the event comes from the fullscreen bib input, sync the value to
|
|
14923
|
+
// the trigger input. Setting trigger.value triggers Lit's updated()
|
|
14924
|
+
// (async, microtask) which fires notifyValueChanged() → another 'input'
|
|
14925
|
+
// event from the trigger. The _syncingBibValue guard persists across the
|
|
14926
|
+
// async boundary and prevents that re-entrant event from running the
|
|
14927
|
+
// non-fullscreen path (which would call clear() → hideBib()).
|
|
14928
|
+
// When the event comes from the fullscreen bib input, sync the value to
|
|
14929
|
+
// the trigger and run filtering, but suppress the re-entrant input event
|
|
14930
|
+
// that the trigger fires (via Lit updated() → notifyValueChanged()) so
|
|
14931
|
+
// the non-fullscreen hide/clear logic doesn't close the dialog.
|
|
14112
14932
|
if (event.target === this.inputInBib) {
|
|
14933
|
+
this._syncingBibValue = true;
|
|
14113
14934
|
this.input.value = this.inputInBib.value;
|
|
14935
|
+
this.input.updateComplete.then(() => {
|
|
14936
|
+
this._syncingBibValue = false;
|
|
14937
|
+
});
|
|
14938
|
+
|
|
14939
|
+
// Run filtering inline — the re-entrant event won't reach this code.
|
|
14940
|
+
this.menu.matchWord = this.inputInBib.value;
|
|
14941
|
+
this.optionActive = null;
|
|
14942
|
+
this.handleMenuOptions();
|
|
14943
|
+
this.dispatchEvent(new CustomEvent('inputValue', { detail: { value: this.inputValue } }));
|
|
14944
|
+
return;
|
|
14945
|
+
}
|
|
14946
|
+
|
|
14947
|
+
// Ignore re-entrant input events caused by the bib→trigger sync above.
|
|
14948
|
+
if (this._syncingBibValue) {
|
|
14114
14949
|
return;
|
|
14115
14950
|
}
|
|
14116
14951
|
|
|
@@ -14124,8 +14959,11 @@ class AuroCombobox extends AuroElement {
|
|
|
14124
14959
|
}
|
|
14125
14960
|
this.handleMenuOptions();
|
|
14126
14961
|
|
|
14127
|
-
// Validate only if the value was set programmatically
|
|
14128
|
-
|
|
14962
|
+
// Validate only if the value was set programmatically (not during user
|
|
14963
|
+
// interaction). In fullscreen dialog mode, componentHasFocus returns false
|
|
14964
|
+
// because focus is inside the top-layer dialog, so also check
|
|
14965
|
+
// dropdownOpen and the fullscreen transition flag.
|
|
14966
|
+
if (!this.componentHasFocus && !this.dropdownOpen && !this._inFullscreenTransition) {
|
|
14129
14967
|
this.validate();
|
|
14130
14968
|
}
|
|
14131
14969
|
|
|
@@ -14140,6 +14978,22 @@ class AuroCombobox extends AuroElement {
|
|
|
14140
14978
|
this.hideBib();
|
|
14141
14979
|
}
|
|
14142
14980
|
|
|
14981
|
+
// iOS virtual keyboard retention: when in fullscreen mode, ensure the
|
|
14982
|
+
// dialog opens and the bib input is focused synchronously within the
|
|
14983
|
+
// input event (user gesture) chain. Without this, Lit's async update
|
|
14984
|
+
// cycle delays showModal() past the user activation window, causing
|
|
14985
|
+
// iOS Safari to dismiss the virtual keyboard when the fullscreen
|
|
14986
|
+
// dialog opens — the user then has to tap the input again to resume
|
|
14987
|
+
// typing.
|
|
14988
|
+
if (this.dropdown.isBibFullscreen && this.input.value && this.input.value.length > 0) {
|
|
14989
|
+
if (!this.dropdown.isPopoverVisible) {
|
|
14990
|
+
this.showBib();
|
|
14991
|
+
}
|
|
14992
|
+
if (this.dropdown.isPopoverVisible) {
|
|
14993
|
+
this.setInputFocus();
|
|
14994
|
+
}
|
|
14995
|
+
}
|
|
14996
|
+
|
|
14143
14997
|
this.dispatchEvent(new CustomEvent('inputValue', { detail: { value: this.inputValue } }));
|
|
14144
14998
|
}
|
|
14145
14999
|
|
|
@@ -14149,61 +15003,7 @@ class AuroCombobox extends AuroElement {
|
|
|
14149
15003
|
* @returns {void}
|
|
14150
15004
|
*/
|
|
14151
15005
|
configureCombobox() {
|
|
14152
|
-
this
|
|
14153
|
-
if (evt.key === 'Enter') {
|
|
14154
|
-
if (this.dropdown.isPopoverVisible && this.optionActive) {
|
|
14155
|
-
this.menu.makeSelection();
|
|
14156
|
-
|
|
14157
|
-
await this.updateComplete;
|
|
14158
|
-
|
|
14159
|
-
evt.preventDefault();
|
|
14160
|
-
evt.stopPropagation();
|
|
14161
|
-
this.setClearBtnFocus();
|
|
14162
|
-
} else {
|
|
14163
|
-
this.showBib();
|
|
14164
|
-
}
|
|
14165
|
-
}
|
|
14166
|
-
|
|
14167
|
-
if (evt.key === 'Tab' && this.dropdown.isPopoverVisible) {
|
|
14168
|
-
if (this.dropdown.isBibFullscreen) {
|
|
14169
|
-
|
|
14170
|
-
// when focus is on the input, move focus back to close button with Tab key
|
|
14171
|
-
if (document.activeElement.shadowRoot.activeElement === this.inputInBib) {
|
|
14172
|
-
evt.preventDefault();
|
|
14173
|
-
this.dropdown.focus();
|
|
14174
|
-
}
|
|
14175
|
-
} else {
|
|
14176
|
-
if (this.menu.optionActive && this.menu.optionActive.value) {
|
|
14177
|
-
this.menu.value = this.menu.optionActive.value;
|
|
14178
|
-
}
|
|
14179
|
-
|
|
14180
|
-
setTimeout(() => {
|
|
14181
|
-
if (!this.componentHasFocus) {
|
|
14182
|
-
this.hideBib();
|
|
14183
|
-
}
|
|
14184
|
-
}, 0);
|
|
14185
|
-
}
|
|
14186
|
-
}
|
|
14187
|
-
|
|
14188
|
-
/**
|
|
14189
|
-
* Prevent moving the cursor position while navigating the menu options.
|
|
14190
|
-
*/
|
|
14191
|
-
if (evt.key === 'ArrowUp' || evt.key === 'ArrowDown') {
|
|
14192
|
-
if (this.availableOptions.length > 0) {
|
|
14193
|
-
this.showBib();
|
|
14194
|
-
}
|
|
14195
|
-
|
|
14196
|
-
if (this.dropdown.isPopoverVisible) {
|
|
14197
|
-
evt.preventDefault();
|
|
14198
|
-
|
|
14199
|
-
// navigate on menu only when the focus is on input
|
|
14200
|
-
if (!this.dropdown.isBibFullscreen || this.dropdown.isPopoverVisible) {
|
|
14201
|
-
const direction = evt.key.replace('Arrow', '').toLowerCase();
|
|
14202
|
-
this.menu.navigateOptions(direction);
|
|
14203
|
-
}
|
|
14204
|
-
}
|
|
14205
|
-
}
|
|
14206
|
-
});
|
|
15006
|
+
applyKeyboardStrategy(this, comboboxKeyboardStrategy);
|
|
14207
15007
|
|
|
14208
15008
|
this.addEventListener('focusin', () => {
|
|
14209
15009
|
this.touched = true;
|
|
@@ -14212,6 +15012,14 @@ class AuroCombobox extends AuroElement {
|
|
|
14212
15012
|
});
|
|
14213
15013
|
|
|
14214
15014
|
this.addEventListener('auroFormElement-validated', (evt) => {
|
|
15015
|
+
// During the fullscreen transition, child elements (auro-input) may fire
|
|
15016
|
+
// their own validation events when the trigger becomes inert and loses
|
|
15017
|
+
// focus. Those composed events bubble up through shadow DOM boundaries
|
|
15018
|
+
// and would incorrectly set combobox validity. Ignore them.
|
|
15019
|
+
if (this._inFullscreenTransition) {
|
|
15020
|
+
return;
|
|
15021
|
+
}
|
|
15022
|
+
|
|
14215
15023
|
this.input.validity = evt.detail.validity;
|
|
14216
15024
|
this.input.errorMessage = evt.detail.message;
|
|
14217
15025
|
this.validity = evt.detail.validity;
|
|
@@ -14238,6 +15046,11 @@ class AuroCombobox extends AuroElement {
|
|
|
14238
15046
|
}
|
|
14239
15047
|
}
|
|
14240
15048
|
|
|
15049
|
+
disconnectedCallback() {
|
|
15050
|
+
super.disconnectedCallback();
|
|
15051
|
+
this._inFullscreenTransition = false;
|
|
15052
|
+
}
|
|
15053
|
+
|
|
14241
15054
|
firstUpdated() {
|
|
14242
15055
|
// Add the tag name as an attribute if it is different than the component name
|
|
14243
15056
|
this.runtimeUtils.handleComponentTagRename(this, 'auro-combobox');
|
|
@@ -14315,6 +15128,9 @@ class AuroCombobox extends AuroElement {
|
|
|
14315
15128
|
* @param {boolean} [force=false] - Whether to force validation.
|
|
14316
15129
|
*/
|
|
14317
15130
|
validate(force = false) {
|
|
15131
|
+
if (this._inFullscreenTransition) {
|
|
15132
|
+
return;
|
|
15133
|
+
}
|
|
14318
15134
|
this.validation.validate(this, force);
|
|
14319
15135
|
}
|
|
14320
15136
|
|
|
@@ -14368,7 +15184,13 @@ class AuroCombobox extends AuroElement {
|
|
|
14368
15184
|
}
|
|
14369
15185
|
|
|
14370
15186
|
if (changedProperties.has('availableOptions')) {
|
|
14371
|
-
|
|
15187
|
+
// dropdownOpen is set synchronously by the auroDropdown-toggled event
|
|
15188
|
+
// handler during showBib() → floater.showBib() → dispatchEventDropdownToggle(),
|
|
15189
|
+
// so it's already true by the time updated() runs. This prevents the else
|
|
15190
|
+
// branch from calling hideBib() when the dropdown was just opened but
|
|
15191
|
+
// :focus-within hasn't propagated through the top-layer dialog's nested
|
|
15192
|
+
// shadow DOM boundaries.
|
|
15193
|
+
if ((this.availableOptions.length > 0 && (this.componentHasFocus || this.dropdownOpen)) || this.menu.loading || (this.availableOptions.length === 0 && this.noMatchOption)) {
|
|
14372
15194
|
this.showBib();
|
|
14373
15195
|
} else {
|
|
14374
15196
|
this.hideBib();
|
|
@@ -14485,14 +15307,7 @@ class AuroCombobox extends AuroElement {
|
|
|
14485
15307
|
|
|
14486
15308
|
return html`
|
|
14487
15309
|
<div>
|
|
14488
|
-
<
|
|
14489
|
-
${this.optionActive && this.availableOptions.length > 0
|
|
14490
|
-
? html`
|
|
14491
|
-
${`${this.optionActive.textContent}, selected, ${this.availableOptions.indexOf(this.optionActive) + 1} of ${this.availableOptions.length}`}
|
|
14492
|
-
`
|
|
14493
|
-
: undefined
|
|
14494
|
-
}
|
|
14495
|
-
</div>
|
|
15310
|
+
<span id="srAnnouncement" class="util_displayHiddenVisually" aria-live="polite" role="status"></span>
|
|
14496
15311
|
<${this.dropdownTag}
|
|
14497
15312
|
appearance="${this.onDark ? 'inverse' : this.appearance}"
|
|
14498
15313
|
.fullscreenBreakpoint="${this.fullscreenBreakpoint}"
|
|
@@ -14516,7 +15331,8 @@ class AuroCombobox extends AuroElement {
|
|
|
14516
15331
|
<${this.inputTag}
|
|
14517
15332
|
@input="${this.handleInputValueChange}"
|
|
14518
15333
|
appearance="${this.onDark ? 'inverse' : this.appearance}"
|
|
14519
|
-
.
|
|
15334
|
+
.a11yActivedescendant="${this.dropdownOpen && this.optionActive ? this.optionActive.id : undefined}"
|
|
15335
|
+
.a11yExpanded="${this.triggerExpandedState}"
|
|
14520
15336
|
.a11yControls="${this.dropdownId}"
|
|
14521
15337
|
.autocomplete="${this.autocomplete}"
|
|
14522
15338
|
.inputmode="${this.inputmode}"
|
|
@@ -14549,8 +15365,10 @@ class AuroCombobox extends AuroElement {
|
|
|
14549
15365
|
<slot @slotchange="${this.handleSlotChange}"></slot>
|
|
14550
15366
|
<${this.inputTag}
|
|
14551
15367
|
id="inputInBib"
|
|
15368
|
+
autofocus
|
|
14552
15369
|
@input="${this.handleInputValueChange}"
|
|
14553
|
-
.
|
|
15370
|
+
.a11yActivedescendant="${this.dropdownOpen && this.optionActive ? this.optionActive.id : undefined}"
|
|
15371
|
+
.a11yControls=${`${this.dropdownId}-floater-bib`}
|
|
14554
15372
|
.autocomplete="${this.autocomplete}"
|
|
14555
15373
|
.format="${this.format}"
|
|
14556
15374
|
.inputmode="${this.inputmode}"
|
|
@@ -14561,7 +15379,7 @@ class AuroCombobox extends AuroElement {
|
|
|
14561
15379
|
?icon="${this.triggerIcon}"
|
|
14562
15380
|
?required="${this.required}"
|
|
14563
15381
|
a11yRole="combobox"
|
|
14564
|
-
a11yExpanded="
|
|
15382
|
+
.a11yExpanded="${this.dropdownOpen}"
|
|
14565
15383
|
layout="classic"
|
|
14566
15384
|
noValidate="true"
|
|
14567
15385
|
shape="classic"
|