@aurodesignsystem-dev/auro-formkit 0.0.0-pr1480.9 → 0.0.0-pr1482.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/bibtemplate/dist/auro-bibtemplate.d.ts +0 -7
- package/components/bibtemplate/dist/index.js +1 -9
- package/components/bibtemplate/dist/registered.js +1 -9
- package/components/checkbox/demo/customize.min.js +1 -1
- package/components/checkbox/demo/getting-started.min.js +1 -1
- package/components/checkbox/demo/index.min.js +1 -1
- package/components/checkbox/demo/pages.json +1 -1
- package/components/checkbox/dist/index.js +1 -1
- package/components/checkbox/dist/registered.js +1 -1
- package/components/combobox/demo/customize.md +7 -3
- package/components/combobox/demo/customize.min.js +1257 -1816
- package/components/combobox/demo/getting-started.min.js +1257 -1816
- package/components/combobox/demo/index.min.js +1257 -1816
- package/components/combobox/demo/keyboard-behavior.md +68 -8
- package/components/combobox/demo/pages.json +1 -1
- package/components/combobox/dist/auro-combobox.d.ts +5 -0
- package/components/combobox/dist/index.js +335 -319
- package/components/combobox/dist/registered.js +335 -319
- package/components/counter/demo/customize.min.js +15 -233
- package/components/counter/demo/index.min.js +15 -233
- package/components/counter/demo/keyboard-behavior.md +0 -1
- package/components/counter/demo/pages.json +1 -1
- package/components/counter/dist/index.js +5204 -208
- package/components/counter/dist/registered.js +5204 -208
- package/components/datepicker/demo/accessibility.md +3 -54
- package/components/datepicker/demo/api.md +2 -11
- package/components/datepicker/demo/customize.html +0 -2
- package/components/datepicker/demo/customize.md +8 -72
- package/components/datepicker/demo/design.md +1 -3
- package/components/datepicker/demo/index.js +1 -5
- package/components/datepicker/demo/index.md +2 -85
- package/components/datepicker/demo/index.min.js +183 -2288
- package/components/datepicker/demo/keyboard-behavior.md +2 -201
- package/components/datepicker/demo/pages.json +1 -1
- package/components/datepicker/demo/voiceover.md +12 -21
- package/components/datepicker/dist/index.js +156 -2174
- package/components/datepicker/dist/registered.js +156 -2174
- package/components/datepicker/dist/src/auro-calendar-cell.d.ts +11 -111
- package/components/datepicker/dist/src/auro-calendar-month.d.ts +0 -37
- package/components/datepicker/dist/src/auro-calendar.d.ts +0 -246
- package/components/datepicker/dist/src/auro-datepicker.d.ts +0 -88
- package/components/datepicker/dist/src/datepickerKeyboardStrategy.d.ts +3 -5
- package/components/dropdown/demo/accessibility.md +0 -11
- package/components/dropdown/demo/api.md +0 -1
- package/components/dropdown/demo/customize.md +0 -3
- package/components/dropdown/demo/customize.min.js +13 -223
- package/components/dropdown/demo/getting-started.min.js +13 -223
- package/components/dropdown/demo/index.min.js +13 -223
- package/components/dropdown/demo/keyboard-behavior.md +0 -1
- package/components/dropdown/demo/pages.json +1 -1
- package/components/dropdown/dist/auro-dropdown.d.ts +1 -33
- package/components/dropdown/dist/index.js +13 -223
- package/components/dropdown/dist/registered.js +13 -223
- package/components/form/demo/customize.min.js +7765 -10745
- package/components/form/demo/getting-started.min.js +7765 -10745
- package/components/form/demo/index.min.js +7765 -10745
- package/components/form/demo/pages.json +1 -1
- package/components/form/demo/registerDemoDeps.min.js +7764 -10744
- package/components/input/demo/customize.min.js +1 -1
- package/components/input/demo/getting-started.min.js +1 -1
- package/components/input/demo/index.min.js +1 -1
- package/components/input/demo/pages.json +1 -1
- package/components/input/dist/index.js +1 -1
- package/components/input/dist/registered.js +1 -1
- package/components/menu/demo/api.md +41 -45
- package/components/menu/demo/customize.md +0 -28
- package/components/menu/demo/index.min.js +779 -1354
- package/components/menu/demo/pages.json +1 -1
- package/components/menu/dist/auro-menu.d.ts +95 -110
- package/components/menu/dist/auro-menuoption.d.ts +32 -138
- package/components/menu/dist/index.js +753 -1308
- package/components/menu/dist/registered.js +765 -1308
- package/components/radio/demo/getting-started.js +1 -1
- package/components/radio/demo/getting-started.md +1 -1
- package/components/radio/demo/index.min.js +1 -1
- package/components/radio/demo/pages.json +1 -1
- package/components/radio/dist/index.js +1 -1
- package/components/radio/dist/registered.js +1 -1
- package/components/select/demo/customize.md +7 -3
- package/components/select/demo/customize.min.js +999 -1759
- package/components/select/demo/getting-started.min.js +999 -1759
- package/components/select/demo/index.min.js +999 -1759
- package/components/select/demo/keyboard-behavior.md +54 -9
- package/components/select/demo/pages.json +1 -1
- package/components/select/dist/index.js +76 -261
- package/components/select/dist/registered.js +76 -261
- package/components/select/dist/selectUtils.d.ts +12 -0
- package/custom-elements.json +2406 -4134
- package/package.json +4 -4
- package/components/checkbox/demo/why-checkbox.html +0 -57
- package/components/checkbox/demo/why-checkbox.md +0 -86
- package/components/combobox/demo/why-combobox.html +0 -57
- package/components/combobox/demo/why-combobox.md +0 -113
- package/components/counter/demo/why-counter.html +0 -57
- package/components/counter/demo/why-counter.md +0 -108
- package/components/datepicker/demo/customize.js +0 -19
- package/components/datepicker/demo/customize.min.js +0 -26655
- package/components/datepicker/demo/why-datepicker.html +0 -57
- package/components/datepicker/demo/why-datepicker.md +0 -133
- package/components/dropdown/demo/why-dropdown.html +0 -57
- package/components/dropdown/demo/why-dropdown.md +0 -97
- package/components/form/demo/why-form.html +0 -57
- package/components/form/demo/why-form.md +0 -101
- package/components/input/demo/why-input.html +0 -57
- package/components/input/demo/why-input.md +0 -121
- package/components/menu/demo/why-menu.html +0 -57
- package/components/menu/demo/why-menu.md +0 -104
- package/components/menu/dist/auro-menu.context.d.ts +0 -238
- package/components/radio/demo/customize.min.js +0 -2186
- package/components/radio/demo/demo-support.min.js +0 -55807
- package/components/radio/demo/getting-started.min.js +0 -2205
- package/components/radio/demo/why-radio.html +0 -57
- package/components/radio/demo/why-radio.md +0 -92
- package/components/select/demo/why-select.html +0 -57
- package/components/select/demo/why-select.md +0 -128
|
@@ -1219,6 +1219,21 @@ function isClearBtnFocused(ctx, clearBtn = getClearBtn(ctx)) {
|
|
|
1219
1219
|
return isFocused;
|
|
1220
1220
|
}
|
|
1221
1221
|
|
|
1222
|
+
/**
|
|
1223
|
+
* Reconcile the menu `_index` from `optionActive` so subsequent `makeSelection` calls find the correct option after async clearSelection has reset it.
|
|
1224
|
+
* @param {Object} menu - The menu component.
|
|
1225
|
+
*/
|
|
1226
|
+
function reconcileMenuIndex(menu) {
|
|
1227
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
1228
|
+
if (menu._index < 0 && menu.optionActive && menu.items) {
|
|
1229
|
+
const idx = menu.items.indexOf(menu.optionActive);
|
|
1230
|
+
if (idx >= 0) {
|
|
1231
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
1232
|
+
menu._index = idx;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1222
1237
|
const comboboxKeyboardStrategy = {
|
|
1223
1238
|
ArrowDown(component, evt, ctx) {
|
|
1224
1239
|
// If the clear button has focus, let the browser handle ArrowDown normally.
|
|
@@ -1232,7 +1247,7 @@ const comboboxKeyboardStrategy = {
|
|
|
1232
1247
|
|
|
1233
1248
|
// navigate if bib is open otherwise open it
|
|
1234
1249
|
if (component.dropdown.isPopoverVisible) {
|
|
1235
|
-
if (evt.altKey || evt.metaKey) {
|
|
1250
|
+
if (evt.altKey || evt.ctrlKey || evt.metaKey) {
|
|
1236
1251
|
component.activateLastEnabledAvailableOption();
|
|
1237
1252
|
} else {
|
|
1238
1253
|
navigateArrow(component, 'down');
|
|
@@ -1255,7 +1270,7 @@ const comboboxKeyboardStrategy = {
|
|
|
1255
1270
|
|
|
1256
1271
|
// navigate if bib is open otherwise open it
|
|
1257
1272
|
if (component.dropdown.isPopoverVisible) {
|
|
1258
|
-
if (evt.altKey || evt.metaKey) {
|
|
1273
|
+
if (evt.altKey || evt.ctrlKey || evt.metaKey) {
|
|
1259
1274
|
component.activateFirstEnabledAvailableOption();
|
|
1260
1275
|
} else {
|
|
1261
1276
|
navigateArrow(component, 'up');
|
|
@@ -1282,6 +1297,7 @@ const comboboxKeyboardStrategy = {
|
|
|
1282
1297
|
// block the browser's built-in "Enter activates focused button" behavior.
|
|
1283
1298
|
evt.stopPropagation();
|
|
1284
1299
|
} else if (ctx.isExpanded && component.menu.optionActive) {
|
|
1300
|
+
reconcileMenuIndex(component.menu);
|
|
1285
1301
|
component.menu.makeSelection();
|
|
1286
1302
|
|
|
1287
1303
|
if (ctx.isModal) {
|
|
@@ -1329,6 +1345,7 @@ const comboboxKeyboardStrategy = {
|
|
|
1329
1345
|
// When the clear button is focused, Tab events do not bubble out of
|
|
1330
1346
|
// its shadow DOM, so this handler only fires when the clear button
|
|
1331
1347
|
// is NOT focused. In that case, select the active option and close.
|
|
1348
|
+
reconcileMenuIndex(component.menu);
|
|
1332
1349
|
component.menu.makeSelection();
|
|
1333
1350
|
component.hideBib();
|
|
1334
1351
|
|
|
@@ -4580,7 +4597,7 @@ function applyKeyboardStrategy(component, strategy, options = {}) {
|
|
|
4580
4597
|
});
|
|
4581
4598
|
}
|
|
4582
4599
|
|
|
4583
|
-
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(
|
|
4600
|
+
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(:popover-open){position:fixed;overflow:visible;padding:0;border:none;margin:0;background:transparent;inset:unset;outline:none}: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}`;
|
|
4584
4601
|
|
|
4585
4602
|
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)}`;
|
|
4586
4603
|
|
|
@@ -5211,7 +5228,7 @@ let AuroHelpText$2 = class AuroHelpText extends LitElement {
|
|
|
5211
5228
|
}
|
|
5212
5229
|
};
|
|
5213
5230
|
|
|
5214
|
-
var formkitVersion$2 = '
|
|
5231
|
+
var formkitVersion$2 = '202606082059';
|
|
5215
5232
|
|
|
5216
5233
|
let AuroElement$2 = class AuroElement extends LitElement {
|
|
5217
5234
|
static get properties() {
|
|
@@ -5391,7 +5408,6 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
5391
5408
|
_intializeDefaults() {
|
|
5392
5409
|
this.appearance = 'default';
|
|
5393
5410
|
this.chevron = false;
|
|
5394
|
-
this.desktopModal = false;
|
|
5395
5411
|
this.disabled = false;
|
|
5396
5412
|
this.disableKeyboardHandling = false;
|
|
5397
5413
|
this.error = false;
|
|
@@ -5572,14 +5588,6 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
5572
5588
|
reflect: true
|
|
5573
5589
|
},
|
|
5574
5590
|
|
|
5575
|
-
/**
|
|
5576
|
-
* If declared, the dropdown will behave as a modal dialog when in a desktop viewport size.
|
|
5577
|
-
*/
|
|
5578
|
-
desktopModal: {
|
|
5579
|
-
type: Boolean,
|
|
5580
|
-
reflect: true
|
|
5581
|
-
},
|
|
5582
|
-
|
|
5583
5591
|
/**
|
|
5584
5592
|
* If declared, the dropdown will only show by calling the API .show() public method.
|
|
5585
5593
|
*/
|
|
@@ -5867,15 +5875,6 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
5867
5875
|
|
|
5868
5876
|
disconnectedCallback() {
|
|
5869
5877
|
super.disconnectedCallback();
|
|
5870
|
-
this._clearPageInert();
|
|
5871
|
-
if (this._bibTabHandler) {
|
|
5872
|
-
this.removeEventListener('keydown', this._bibTabHandler);
|
|
5873
|
-
this._bibTabHandler = undefined;
|
|
5874
|
-
}
|
|
5875
|
-
if (this.focusTrap) {
|
|
5876
|
-
this.focusTrap.disconnect();
|
|
5877
|
-
this.focusTrap = undefined;
|
|
5878
|
-
}
|
|
5879
5878
|
if (this.floater) {
|
|
5880
5879
|
this.floater.hideBib('disconnect');
|
|
5881
5880
|
this.floater.disconnect();
|
|
@@ -5903,45 +5902,19 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
5903
5902
|
if (this.isPopoverVisible) {
|
|
5904
5903
|
// Fullscreen: use showModal() for native accessibility (inert outside, focus trap)
|
|
5905
5904
|
// Desktop: use show() for Floating UI positioning + FocusTrap for focus management
|
|
5906
|
-
this.
|
|
5907
|
-
this.
|
|
5908
|
-
|
|
5909
|
-
// Desktop modal: make siblings inert so content outside is not interactive
|
|
5910
|
-
if (this.desktopModal && !this.isBibFullscreen) {
|
|
5911
|
-
this._setPageInert();
|
|
5912
|
-
}
|
|
5905
|
+
const useModal = this.isBibFullscreen;
|
|
5906
|
+
this.bibElement.value.open(useModal);
|
|
5913
5907
|
} else {
|
|
5914
5908
|
this.bibElement.value.close();
|
|
5915
|
-
this._clearPageInert();
|
|
5916
5909
|
}
|
|
5917
5910
|
}
|
|
5918
5911
|
|
|
5919
5912
|
// When fullscreen strategy changes while open, re-open dialog with correct mode
|
|
5920
5913
|
// (e.g. resizing from desktop → mobile while dropdown is open)
|
|
5921
5914
|
if (changedProperties.has('isBibFullscreen') && this.isPopoverVisible && this.bibElement.value) {
|
|
5915
|
+
const useModal = this.isBibFullscreen;
|
|
5922
5916
|
this.bibElement.value.close();
|
|
5923
|
-
this.bibElement.value.open(
|
|
5924
|
-
|
|
5925
|
-
// Re-initialize focus management for the new strategy
|
|
5926
|
-
this.updateFocusTrap();
|
|
5927
|
-
|
|
5928
|
-
// Toggle inert: desktop modal needs it, fullscreen showModal() handles it natively
|
|
5929
|
-
if (this.desktopModal && !this.isBibFullscreen) {
|
|
5930
|
-
this._setPageInert();
|
|
5931
|
-
} else {
|
|
5932
|
-
this._clearPageInert();
|
|
5933
|
-
}
|
|
5934
|
-
}
|
|
5935
|
-
|
|
5936
|
-
// Handle desktopModal toggled while the dropdown is already open.
|
|
5937
|
-
// Re-initialize focus trapping and page inert state to match the new mode.
|
|
5938
|
-
if (changedProperties.has('desktopModal') && this.isPopoverVisible && !this.isBibFullscreen) {
|
|
5939
|
-
this.updateFocusTrap();
|
|
5940
|
-
if (this.desktopModal) {
|
|
5941
|
-
this._setPageInert();
|
|
5942
|
-
} else {
|
|
5943
|
-
this._clearPageInert();
|
|
5944
|
-
}
|
|
5917
|
+
this.bibElement.value.open(useModal);
|
|
5945
5918
|
}
|
|
5946
5919
|
}
|
|
5947
5920
|
|
|
@@ -5951,14 +5924,8 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
5951
5924
|
* @param {CustomEvent} event - The custom event that contains the dropdown toggle information.
|
|
5952
5925
|
*/
|
|
5953
5926
|
handleDropdownToggle(event) {
|
|
5927
|
+
this.updateFocusTrap();
|
|
5954
5928
|
this.isPopoverVisible = event.detail.expanded;
|
|
5955
|
-
|
|
5956
|
-
// Tear down FocusTrap when closing. Creation happens in updated()
|
|
5957
|
-
// after the dialog is open so getFocusableElements can find content.
|
|
5958
|
-
if (!this.isPopoverVisible) {
|
|
5959
|
-
this.updateFocusTrap();
|
|
5960
|
-
}
|
|
5961
|
-
|
|
5962
5929
|
const eventType = event.detail.eventType || "unknown";
|
|
5963
5930
|
if (!this.isPopoverVisible && this.hasFocus && eventType === "keydown") {
|
|
5964
5931
|
this.trigger.focus();
|
|
@@ -6057,178 +6024,19 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
6057
6024
|
* @private
|
|
6058
6025
|
*/
|
|
6059
6026
|
updateFocusTrap() {
|
|
6060
|
-
// Always clean up existing handlers/traps before setting up new ones
|
|
6061
|
-
// to prevent duplicate listeners on repeated calls.
|
|
6062
|
-
if (this._bibTabHandler) {
|
|
6063
|
-
this.removeEventListener('keydown', this._bibTabHandler);
|
|
6064
|
-
this._bibTabHandler = undefined;
|
|
6065
|
-
}
|
|
6066
|
-
|
|
6067
|
-
if (this.focusTrap) {
|
|
6068
|
-
this.focusTrap.disconnect();
|
|
6069
|
-
this.focusTrap = undefined;
|
|
6070
|
-
}
|
|
6071
|
-
|
|
6072
6027
|
if (this.isPopoverVisible) {
|
|
6073
6028
|
if (!this.isBibFullscreen) {
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
// from slotted content bubble through the dropdown host (light DOM),
|
|
6078
|
-
// not through the bib (shadow projection target). Using FocusTrap
|
|
6079
|
-
// on the dropdown would include the trigger in the tab cycle.
|
|
6080
|
-
// Instead, listen for Tab on the dropdown and manually wrap focus
|
|
6081
|
-
// within the bib's focusable elements.
|
|
6082
|
-
this._bibTabHandler = (event) => {
|
|
6083
|
-
if (event.key !== 'Tab') {
|
|
6084
|
-
return;
|
|
6085
|
-
}
|
|
6086
|
-
|
|
6087
|
-
// Collect focusable elements from the bib content.
|
|
6088
|
-
const focusables = getFocusableElements(this.bibContent);
|
|
6089
|
-
|
|
6090
|
-
// Fallback: try from slotted content directly
|
|
6091
|
-
if (!focusables.length) {
|
|
6092
|
-
const slot = this.shadowRoot.querySelector('.slotContent slot');
|
|
6093
|
-
const assignedNodes = slot ? slot.assignedNodes({ flatten: true }) : [];
|
|
6094
|
-
|
|
6095
|
-
for (const node of assignedNodes) {
|
|
6096
|
-
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
6097
|
-
focusables.push(...getFocusableElements(node));
|
|
6098
|
-
}
|
|
6099
|
-
}
|
|
6100
|
-
}
|
|
6101
|
-
|
|
6102
|
-
if (!focusables.length) {
|
|
6103
|
-
return;
|
|
6104
|
-
}
|
|
6105
|
-
|
|
6106
|
-
event.preventDefault();
|
|
6107
|
-
|
|
6108
|
-
const direction = event.shiftKey ? -1 : 1; // eslint-disable-line no-magic-numbers
|
|
6109
|
-
|
|
6110
|
-
// Walk the active element chain through shadow roots
|
|
6111
|
-
const actives = this._getActiveElements();
|
|
6112
|
-
|
|
6113
|
-
let idx = focusables.findIndex((el) => actives.includes(el));
|
|
6114
|
-
|
|
6115
|
-
if (idx === -1) { // eslint-disable-line no-magic-numbers
|
|
6116
|
-
// Focus is not on a known element — move to first/last
|
|
6117
|
-
idx = direction === 1 ? -1 : focusables.length; // eslint-disable-line no-magic-numbers
|
|
6118
|
-
}
|
|
6119
|
-
|
|
6120
|
-
// Try each element in order, skipping any that can't receive focus
|
|
6121
|
-
// (e.g. hidden elements, elements in collapsed sections)
|
|
6122
|
-
for (let index = 0; index < focusables.length; index++) { // eslint-disable-line no-plusplus
|
|
6123
|
-
let nextIdx = idx + direction;
|
|
6124
|
-
|
|
6125
|
-
// Wrap around
|
|
6126
|
-
if (nextIdx < 0) {
|
|
6127
|
-
nextIdx = focusables.length - 1;
|
|
6128
|
-
} else if (nextIdx >= focusables.length) {
|
|
6129
|
-
nextIdx = 0;
|
|
6130
|
-
}
|
|
6131
|
-
|
|
6132
|
-
focusables[nextIdx].focus();
|
|
6133
|
-
|
|
6134
|
-
// Verify focus actually moved to the target
|
|
6135
|
-
const newActives = this._getActiveElements();
|
|
6136
|
-
|
|
6137
|
-
if (newActives.includes(focusables[nextIdx])) {
|
|
6138
|
-
return;
|
|
6139
|
-
}
|
|
6140
|
-
|
|
6141
|
-
// Focus didn't stick — skip this element and try the next
|
|
6142
|
-
idx = nextIdx;
|
|
6143
|
-
}
|
|
6144
|
-
};
|
|
6145
|
-
this.addEventListener('keydown', this._bibTabHandler);
|
|
6146
|
-
|
|
6147
|
-
// Move initial focus into the bib content, matching FocusTrap behavior
|
|
6148
|
-
requestAnimationFrame(() => {
|
|
6149
|
-
const focusables = getFocusableElements(this.bibContent);
|
|
6150
|
-
if (focusables.length) {
|
|
6151
|
-
focusables[0].focus();
|
|
6152
|
-
}
|
|
6153
|
-
});
|
|
6154
|
-
} else {
|
|
6155
|
-
// Normal desktop: use FocusTrap on the bib element
|
|
6156
|
-
this.focusTrap = new FocusTrap(this.bibContent);
|
|
6157
|
-
this.focusTrap.focusFirstElement();
|
|
6158
|
-
}
|
|
6029
|
+
// Desktop: show() doesn't trap focus, so use FocusTrap
|
|
6030
|
+
this.focusTrap = new FocusTrap(this.bibContent);
|
|
6031
|
+
this.focusTrap.focusFirstElement();
|
|
6159
6032
|
}
|
|
6160
6033
|
// Fullscreen: showModal() provides native focus trapping
|
|
6161
|
-
}
|
|
6162
|
-
}
|
|
6163
|
-
|
|
6164
|
-
/**
|
|
6165
|
-
* Returns the chain of active (focused) elements through shadow roots.
|
|
6166
|
-
* @private
|
|
6167
|
-
* @returns {Array<HTMLElement>}
|
|
6168
|
-
*/
|
|
6169
|
-
_getActiveElements() {
|
|
6170
|
-
let { activeElement } = document;
|
|
6171
|
-
const actives = [activeElement];
|
|
6172
|
-
|
|
6173
|
-
while (activeElement?.shadowRoot?.activeElement) {
|
|
6174
|
-
activeElement = activeElement.shadowRoot.activeElement;
|
|
6175
|
-
actives.push(activeElement);
|
|
6176
|
-
}
|
|
6177
|
-
|
|
6178
|
-
return actives;
|
|
6179
|
-
}
|
|
6180
|
-
|
|
6181
|
-
/**
|
|
6182
|
-
* Sets `inert` on sibling elements of the dropdown's top-level host
|
|
6183
|
-
* so that content outside the dropdown is not interactive while the modal is open.
|
|
6184
|
-
* Walks up through shadow DOM boundaries to find the outermost host element
|
|
6185
|
-
* in the light DOM, then sets `inert` on siblings at each ancestor level
|
|
6186
|
-
* to ensure all page content outside the host subtree is inert.
|
|
6187
|
-
* @private
|
|
6188
|
-
*/
|
|
6189
|
-
_setPageInert() {
|
|
6190
|
-
if (this._inertSiblings) {
|
|
6191
6034
|
return;
|
|
6192
6035
|
}
|
|
6193
6036
|
|
|
6194
|
-
this.
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
// element in the light DOM. For example, if this dropdown is inside
|
|
6198
|
-
// auro-datepicker's shadow DOM, we walk up to the datepicker element
|
|
6199
|
-
// so we set inert on its siblings — not on the datepicker itself.
|
|
6200
|
-
let host = this;
|
|
6201
|
-
while (host.getRootNode() instanceof ShadowRoot) {
|
|
6202
|
-
host = host.getRootNode().host;
|
|
6203
|
-
}
|
|
6204
|
-
|
|
6205
|
-
// Walk up the ancestor chain, inerting siblings at each level
|
|
6206
|
-
// to ensure the entire page outside the host subtree is inert.
|
|
6207
|
-
let current = host;
|
|
6208
|
-
while (current.parentElement) {
|
|
6209
|
-
const parent = current.parentElement;
|
|
6210
|
-
for (const sibling of parent.children) {
|
|
6211
|
-
if (sibling !== current) {
|
|
6212
|
-
this._inertSiblings.push({ element: sibling, wasInert: sibling.inert });
|
|
6213
|
-
sibling.inert = true;
|
|
6214
|
-
}
|
|
6215
|
-
}
|
|
6216
|
-
current = parent;
|
|
6217
|
-
}
|
|
6218
|
-
}
|
|
6219
|
-
|
|
6220
|
-
/**
|
|
6221
|
-
* Restores `inert` state on siblings that were tracked by `_setPageInert`.
|
|
6222
|
-
* Preserves the previous inert state so externally-inerted elements are
|
|
6223
|
-
* not inadvertently re-enabled.
|
|
6224
|
-
* @private
|
|
6225
|
-
*/
|
|
6226
|
-
_clearPageInert() {
|
|
6227
|
-
if (this._inertSiblings) {
|
|
6228
|
-
for (const entry of this._inertSiblings) {
|
|
6229
|
-
entry.element.inert = entry.wasInert;
|
|
6230
|
-
}
|
|
6231
|
-
this._inertSiblings = undefined;
|
|
6037
|
+
if (this.focusTrap) {
|
|
6038
|
+
this.focusTrap.disconnect();
|
|
6039
|
+
this.focusTrap = undefined;
|
|
6232
6040
|
}
|
|
6233
6041
|
}
|
|
6234
6042
|
|
|
@@ -6467,7 +6275,6 @@ class AuroDropdown extends AuroElement$2 {
|
|
|
6467
6275
|
shape="${this.shape}"
|
|
6468
6276
|
?data-show="${this.isPopoverVisible}"
|
|
6469
6277
|
?isfullscreen="${this.isBibFullscreen}"
|
|
6470
|
-
?desktopmodal="${this.desktopModal}"
|
|
6471
6278
|
.dialogLabel="${this.bibDialogLabel}"
|
|
6472
6279
|
${ref(this.bibElement)}
|
|
6473
6280
|
>
|
|
@@ -13166,7 +12973,7 @@ let AuroHelpText$1 = class AuroHelpText extends LitElement {
|
|
|
13166
12973
|
}
|
|
13167
12974
|
};
|
|
13168
12975
|
|
|
13169
|
-
var formkitVersion$1 = '
|
|
12976
|
+
var formkitVersion$1 = '202606082059';
|
|
13170
12977
|
|
|
13171
12978
|
// Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
13172
12979
|
// See LICENSE in the project root for license information.
|
|
@@ -14120,14 +13927,6 @@ class AuroBibtemplate extends LitElement {
|
|
|
14120
13927
|
large: {
|
|
14121
13928
|
type: Boolean,
|
|
14122
13929
|
reflect: true
|
|
14123
|
-
},
|
|
14124
|
-
|
|
14125
|
-
/**
|
|
14126
|
-
* If declared, the footer slot will be rendered even when not in fullscreen mode.
|
|
14127
|
-
*/
|
|
14128
|
-
showFooter: {
|
|
14129
|
-
type: Boolean,
|
|
14130
|
-
reflect: true
|
|
14131
13930
|
}
|
|
14132
13931
|
};
|
|
14133
13932
|
}
|
|
@@ -14230,7 +14029,7 @@ class AuroBibtemplate extends LitElement {
|
|
|
14230
14029
|
<slot></slot>
|
|
14231
14030
|
</div>
|
|
14232
14031
|
|
|
14233
|
-
${this.isFullscreen
|
|
14032
|
+
${this.isFullscreen ? html`
|
|
14234
14033
|
<div id="footerContainer">
|
|
14235
14034
|
<slot name="footer"></slot>
|
|
14236
14035
|
</div>` : null}
|
|
@@ -14239,7 +14038,7 @@ class AuroBibtemplate extends LitElement {
|
|
|
14239
14038
|
}
|
|
14240
14039
|
}
|
|
14241
14040
|
|
|
14242
|
-
var formkitVersion = '
|
|
14041
|
+
var formkitVersion = '202606082059';
|
|
14243
14042
|
|
|
14244
14043
|
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}`;
|
|
14245
14044
|
|
|
@@ -14596,6 +14395,25 @@ function normalizeFilterValue(value) {
|
|
|
14596
14395
|
return raw.trim() ? raw.trimEnd() : raw;
|
|
14597
14396
|
}
|
|
14598
14397
|
|
|
14398
|
+
/**
|
|
14399
|
+
* Returns the option's plain-text label suitable for input.value, with
|
|
14400
|
+
* HTML-indentation whitespace collapsed and the displayValue slot text
|
|
14401
|
+
* removed (the slot renders separately in the trigger).
|
|
14402
|
+
* @param {HTMLElement} option - An auro-menuoption element.
|
|
14403
|
+
* @returns {string} Normalized label.
|
|
14404
|
+
*/
|
|
14405
|
+
function getOptionLabel(option) {
|
|
14406
|
+
if (!option) {
|
|
14407
|
+
return '';
|
|
14408
|
+
}
|
|
14409
|
+
const clone = option.cloneNode(true);
|
|
14410
|
+
const displayValueEl = clone.querySelector('[slot="displayValue"]');
|
|
14411
|
+
if (displayValueEl) {
|
|
14412
|
+
displayValueEl.remove();
|
|
14413
|
+
}
|
|
14414
|
+
return (clone.textContent || '').replace(/\s+/gu, ' ').trim();
|
|
14415
|
+
}
|
|
14416
|
+
|
|
14599
14417
|
// See https://git.io/JJ6SJ for "How to document your components using JSDoc"
|
|
14600
14418
|
/**
|
|
14601
14419
|
* The `auro-combobox` element provides users with a way to select an option from a list of filtered or suggested options based on user input.
|
|
@@ -14723,7 +14541,19 @@ class AuroCombobox extends AuroElement {
|
|
|
14723
14541
|
availableOptions: {
|
|
14724
14542
|
state: true,
|
|
14725
14543
|
type: Array,
|
|
14726
|
-
reflect: false
|
|
14544
|
+
reflect: false,
|
|
14545
|
+
hasChanged(newVal, oldVal) {
|
|
14546
|
+
if (!oldVal && !newVal) {
|
|
14547
|
+
return false;
|
|
14548
|
+
}
|
|
14549
|
+
if (!oldVal || !newVal) {
|
|
14550
|
+
return true;
|
|
14551
|
+
}
|
|
14552
|
+
if (newVal.length !== oldVal.length) {
|
|
14553
|
+
return true;
|
|
14554
|
+
}
|
|
14555
|
+
return newVal.some((opt, idx) => opt !== oldVal[idx]);
|
|
14556
|
+
}
|
|
14727
14557
|
},
|
|
14728
14558
|
|
|
14729
14559
|
/**
|
|
@@ -15154,18 +14984,15 @@ class AuroCombobox extends AuroElement {
|
|
|
15154
14984
|
matchString = `${matchString} ${option.getAttribute('suggest')}`.toLowerCase();
|
|
15155
14985
|
}
|
|
15156
14986
|
|
|
15157
|
-
|
|
15158
|
-
|
|
15159
|
-
|
|
15160
|
-
|
|
15161
|
-
|
|
15162
|
-
|
|
15163
|
-
} else if (matchString.includes(filterValue) && !option.hasAttribute('static')) {
|
|
15164
|
-
// only count options that match the typed input value AND are not static
|
|
14987
|
+
if (!filterValue && option.hasAttribute('static')) {
|
|
14988
|
+
// Static options are shown when the input is empty so consumers can
|
|
14989
|
+
// surface headers / "add new" rows when no filter is active.
|
|
14990
|
+
option.removeAttribute('hidden');
|
|
14991
|
+
this.availableOptions.push(option);
|
|
14992
|
+
} else if (filterValue && matchString.includes(filterValue) && !option.hasAttribute('static')) {
|
|
15165
14993
|
option.removeAttribute('hidden');
|
|
15166
14994
|
this.availableOptions.push(option);
|
|
15167
14995
|
} else if (!option.hasAttribute('persistent')) {
|
|
15168
|
-
// Hide all other non-persistent options
|
|
15169
14996
|
option.setAttribute('hidden', '');
|
|
15170
14997
|
option.removeAttribute('aria-setsize');
|
|
15171
14998
|
option.removeAttribute('aria-posinset');
|
|
@@ -15173,7 +15000,9 @@ class AuroCombobox extends AuroElement {
|
|
|
15173
15000
|
});
|
|
15174
15001
|
|
|
15175
15002
|
if (this.availableOptions.length === 0) {
|
|
15176
|
-
|
|
15003
|
+
// Only surface the nomatch option once the user has actually typed
|
|
15004
|
+
// something. Empty input is handled by the bib being closed.
|
|
15005
|
+
if (this.noMatchOption && filterValue) {
|
|
15177
15006
|
this.noMatchOption.removeAttribute('hidden');
|
|
15178
15007
|
} else if (!this.menu.loading || this.isHiddenWhileLoading) {
|
|
15179
15008
|
this.hideBib();
|
|
@@ -15189,11 +15018,14 @@ class AuroCombobox extends AuroElement {
|
|
|
15189
15018
|
* @returns {void}
|
|
15190
15019
|
*/
|
|
15191
15020
|
syncValuesAndStates() {
|
|
15192
|
-
//
|
|
15021
|
+
// Do NOT call setMenuValue here — the caller (handleMenuOptions) already
|
|
15022
|
+
// guards setMenuValue with an option-match check. Calling it unconditionally
|
|
15023
|
+
// sets free-form values on the menu, triggering clearSelection which resets
|
|
15024
|
+
// _index and breaks subsequent makeSelection calls.
|
|
15193
15025
|
if (this.menu) {
|
|
15194
15026
|
this.menu.matchWord = normalizeFilterValue(this.input.value);
|
|
15195
15027
|
}
|
|
15196
|
-
const label = this.menu.currentLabel;
|
|
15028
|
+
const label = getOptionLabel(this.menu.optionSelected) || this.menu.currentLabel;
|
|
15197
15029
|
this.updateTriggerTextDisplay(label || this.value);
|
|
15198
15030
|
}
|
|
15199
15031
|
|
|
@@ -15208,7 +15040,39 @@ class AuroCombobox extends AuroElement {
|
|
|
15208
15040
|
const isInputFocusedWithNoSelection = !this.menu.value && (this.input.matches(':focus-within') || (this.inputInBib && this.inputInBib.matches(':focus-within')));
|
|
15209
15041
|
|
|
15210
15042
|
if (!this.persistInput && !(this.behavior === 'suggestion' && isInputFocusedWithNoSelection)) {
|
|
15211
|
-
|
|
15043
|
+
const nextValue = label || this.value;
|
|
15044
|
+
// Only set the flag when there's an actual write to suppress —
|
|
15045
|
+
// syncValuesAndStates re-enters here during typing when both inputs
|
|
15046
|
+
// already match, and a no-op flag flip would make the bib branch's
|
|
15047
|
+
// bail eat legitimate user-input events.
|
|
15048
|
+
const triggerNeedsSync = this.input.value !== nextValue;
|
|
15049
|
+
const bibNeedsSync = Boolean(this.inputInBib && this.inputInBib !== this.input && this.inputInBib.value !== nextValue);
|
|
15050
|
+
if (triggerNeedsSync || bibNeedsSync) {
|
|
15051
|
+
this._syncingDisplayValue = true;
|
|
15052
|
+
if (triggerNeedsSync) {
|
|
15053
|
+
this.input.value = nextValue;
|
|
15054
|
+
}
|
|
15055
|
+
if (bibNeedsSync) {
|
|
15056
|
+
this.inputInBib.value = nextValue;
|
|
15057
|
+
}
|
|
15058
|
+
const pending = [];
|
|
15059
|
+
if (triggerNeedsSync) {
|
|
15060
|
+
pending.push(this.input.updateComplete);
|
|
15061
|
+
}
|
|
15062
|
+
if (bibNeedsSync) {
|
|
15063
|
+
pending.push(this.inputInBib.updateComplete);
|
|
15064
|
+
}
|
|
15065
|
+
Promise.all(pending).then(() => {
|
|
15066
|
+
// imask reasserts otherwise, and handleBlur reverts to its stale value.
|
|
15067
|
+
if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
|
|
15068
|
+
this.input.maskInstance.updateValue();
|
|
15069
|
+
}
|
|
15070
|
+
if (bibNeedsSync && this.inputInBib && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
|
|
15071
|
+
this.inputInBib.maskInstance.updateValue();
|
|
15072
|
+
}
|
|
15073
|
+
this._syncingDisplayValue = false;
|
|
15074
|
+
});
|
|
15075
|
+
}
|
|
15212
15076
|
}
|
|
15213
15077
|
|
|
15214
15078
|
// update the displayValue in the trigger if displayValue slot content is present
|
|
@@ -15222,6 +15086,14 @@ class AuroCombobox extends AuroElement {
|
|
|
15222
15086
|
const displayValueEl = this.menu.optionSelected.querySelector("[slot='displayValue']");
|
|
15223
15087
|
if (displayValueEl) {
|
|
15224
15088
|
this.input.appendChild(displayValueEl.cloneNode(true));
|
|
15089
|
+
// auro-input's hasDisplayValueContent is non-reactive; nudge it to
|
|
15090
|
+
// re-evaluate the slot and re-render so the displayValue wrapper
|
|
15091
|
+
// gets its hasContent class. Without this, the apple/icon stays
|
|
15092
|
+
// hidden when input.value is set in the same tick as the append.
|
|
15093
|
+
if (typeof this.input.checkDisplayValueSlotChange === 'function') {
|
|
15094
|
+
this.input.checkDisplayValueSlotChange();
|
|
15095
|
+
this.input.requestUpdate();
|
|
15096
|
+
}
|
|
15225
15097
|
}
|
|
15226
15098
|
}
|
|
15227
15099
|
|
|
@@ -15255,7 +15127,10 @@ class AuroCombobox extends AuroElement {
|
|
|
15255
15127
|
this.syncValuesAndStates();
|
|
15256
15128
|
}
|
|
15257
15129
|
|
|
15258
|
-
|
|
15130
|
+
// Re-activate when optionActive is no longer visible, or when _index has
|
|
15131
|
+
// been reset (e.g. by clearSelection in an async update) so that
|
|
15132
|
+
// makeSelection() can find the correct option.
|
|
15133
|
+
if (!this.availableOptions.includes(this.menu.optionActive) || this.menu._index < 0) {
|
|
15259
15134
|
this.activateFirstEnabledAvailableOption();
|
|
15260
15135
|
}
|
|
15261
15136
|
}
|
|
@@ -15380,8 +15255,13 @@ class AuroCombobox extends AuroElement {
|
|
|
15380
15255
|
|
|
15381
15256
|
guardTouchPassthrough(this.menu);
|
|
15382
15257
|
|
|
15383
|
-
//
|
|
15384
|
-
//
|
|
15258
|
+
// The dialog's showModal() steals focus from the trigger.
|
|
15259
|
+
// A single rAF is enough for the dialog DOM to be painted and
|
|
15260
|
+
// focusable, then doubleRaf finalizes the transition.
|
|
15261
|
+
requestAnimationFrame(() => {
|
|
15262
|
+
this.setInputFocus();
|
|
15263
|
+
});
|
|
15264
|
+
|
|
15385
15265
|
doubleRaf(() => {
|
|
15386
15266
|
this.setInputFocus();
|
|
15387
15267
|
this._inFullscreenTransition = false;
|
|
@@ -15462,10 +15342,30 @@ class AuroCombobox extends AuroElement {
|
|
|
15462
15342
|
*/
|
|
15463
15343
|
setInputFocus() {
|
|
15464
15344
|
if (this.dropdown.isBibFullscreen && this.dropdown.isPopoverVisible) {
|
|
15465
|
-
|
|
15345
|
+
// Sync the native input value synchronously before focusing.
|
|
15346
|
+
// Lit's property-to-attribute sync is async (microtask), so the
|
|
15347
|
+
// native <input> inside inputInBib may still hold a stale value
|
|
15348
|
+
// when focus moves here during the fullscreen transition. Without
|
|
15349
|
+
// this, keystrokes (e.g. Backspace) operate on the wrong content.
|
|
15350
|
+
const nativeInput = this.inputInBib.inputElement;
|
|
15351
|
+
const triggerNativeInput = this.input.inputElement;
|
|
15352
|
+
if (nativeInput && triggerNativeInput && nativeInput.value !== triggerNativeInput.value) {
|
|
15353
|
+
this.inputInBib.skipNextProgrammaticInputEvent = true;
|
|
15354
|
+
nativeInput.value = triggerNativeInput.value || '';
|
|
15355
|
+
}
|
|
15356
|
+
|
|
15357
|
+
// Focus the native input directly to ensure it receives keystrokes
|
|
15358
|
+
// after the fullscreen dialog opens. The dialog's showModal() may
|
|
15359
|
+
// have moved focus to the dialog element itself; focusing the
|
|
15360
|
+
// auro-input custom element doesn't always reach the native input
|
|
15361
|
+
// when the dialog DOM isn't fully painted.
|
|
15362
|
+
if (nativeInput) {
|
|
15363
|
+
nativeInput.focus();
|
|
15364
|
+
} else {
|
|
15365
|
+
this.inputInBib.focus();
|
|
15366
|
+
}
|
|
15466
15367
|
|
|
15467
15368
|
// Place cursor at end of existing text so the user can continue editing
|
|
15468
|
-
const nativeInput = this.inputInBib.inputElement;
|
|
15469
15369
|
if (nativeInput && nativeInput.value) {
|
|
15470
15370
|
const len = nativeInput.value.length;
|
|
15471
15371
|
nativeInput.setSelectionRange(len, len);
|
|
@@ -15573,53 +15473,92 @@ class AuroCombobox extends AuroElement {
|
|
|
15573
15473
|
this.menu.setAttribute('nocheckmark', '');
|
|
15574
15474
|
}
|
|
15575
15475
|
|
|
15576
|
-
|
|
15577
|
-
|
|
15578
|
-
|
|
15476
|
+
// Handle menu option selection
|
|
15477
|
+
this.menu.addEventListener('auroMenu-selectedOption', (evt) => {
|
|
15478
|
+
// Capture before the consumption below — true means this event is the
|
|
15479
|
+
// echo of our own setMenuValue (programmatic value sync), false means
|
|
15480
|
+
// a fresh user selection.
|
|
15481
|
+
const isEcho = this._pendingMenuValueSync === true;
|
|
15579
15482
|
|
|
15580
|
-
|
|
15581
|
-
|
|
15582
|
-
// Update the optionSelected from the event details, not manually
|
|
15583
|
-
[this.optionSelected] = event.detail.options;
|
|
15483
|
+
if (this.menu.optionSelected) {
|
|
15484
|
+
const selected = this.menu.optionSelected;
|
|
15584
15485
|
|
|
15585
|
-
|
|
15586
|
-
|
|
15486
|
+
if (!this.optionSelected || this.optionSelected !== selected) {
|
|
15487
|
+
this.optionSelected = selected;
|
|
15488
|
+
}
|
|
15587
15489
|
|
|
15588
|
-
|
|
15589
|
-
|
|
15490
|
+
// Skip writeback when this event is the echo of our own setMenuValue —
|
|
15491
|
+
// otherwise it cascades against handleInputValueChange in suggestion mode.
|
|
15492
|
+
if (this._pendingMenuValueSync) {
|
|
15493
|
+
this._pendingMenuValueSync = false;
|
|
15494
|
+
} else if (!this.value || this.value !== this.optionSelected.value) {
|
|
15495
|
+
this.value = this.optionSelected.value;
|
|
15496
|
+
}
|
|
15590
15497
|
|
|
15591
|
-
|
|
15592
|
-
|
|
15593
|
-
if (this.menu.matchWord !== trimmedInput) {
|
|
15594
|
-
this.menu.matchWord = trimmedInput;
|
|
15595
|
-
}
|
|
15498
|
+
// Update display
|
|
15499
|
+
this.updateTriggerTextDisplay(getOptionLabel(this.optionSelected) || this.menu.value);
|
|
15596
15500
|
|
|
15597
|
-
|
|
15598
|
-
|
|
15501
|
+
// Update match word for filtering
|
|
15502
|
+
const trimmedInput = normalizeFilterValue(this.input.value);
|
|
15503
|
+
if (this.menu.matchWord !== trimmedInput) {
|
|
15504
|
+
this.menu.matchWord = trimmedInput;
|
|
15505
|
+
}
|
|
15506
|
+
}
|
|
15599
15507
|
|
|
15600
15508
|
// Hide dropdown on selection (except during slot changes)
|
|
15601
|
-
if (
|
|
15602
|
-
|
|
15603
|
-
|
|
15604
|
-
|
|
15605
|
-
|
|
15606
|
-
}
|
|
15607
|
-
}, 0);
|
|
15509
|
+
if (evt.detail && evt.detail.source !== 'slotchange') {
|
|
15510
|
+
// do not close while typing in suggestion mode with no value selected, to allow freeform input
|
|
15511
|
+
if (this.menu.value || this.behavior !== 'suggestion') {
|
|
15512
|
+
this.hideBib();
|
|
15513
|
+
}
|
|
15608
15514
|
|
|
15609
15515
|
// Announce the selection after the dropdown closes so it isn't
|
|
15610
15516
|
// overridden by VoiceOver's "collapsed" announcement from aria-expanded.
|
|
15611
|
-
const selectedValue =
|
|
15517
|
+
const selectedValue = this.menu.value;
|
|
15612
15518
|
const announcementDelay = 300;
|
|
15613
15519
|
setTimeout(() => {
|
|
15614
15520
|
announceToScreenReader(this._getAnnouncementRoot(), `${selectedValue}, selected`);
|
|
15615
15521
|
}, announcementDelay);
|
|
15616
15522
|
}
|
|
15523
|
+
|
|
15524
|
+
// Programmatic value syncs leave availableOptions stale because
|
|
15525
|
+
// updateTriggerTextDisplay sets input.value with _syncingDisplayValue
|
|
15526
|
+
// and handleInputValueChange bails. Refresh the filter on echo events
|
|
15527
|
+
// only — fresh user selections take the existing hideBib path.
|
|
15528
|
+
if (isEcho && this.menu.optionSelected) {
|
|
15529
|
+
this._programmaticFilterRefresh = true;
|
|
15530
|
+
this.handleMenuOptions();
|
|
15531
|
+
setTimeout(() => {
|
|
15532
|
+
this._programmaticFilterRefresh = false;
|
|
15533
|
+
}, 0);
|
|
15534
|
+
}
|
|
15535
|
+
|
|
15536
|
+
// base-input skips auto-validate when focus is inside its own shadow,
|
|
15537
|
+
// which it is after setTriggerInputFocus — re-run so prior tooShort
|
|
15538
|
+
// clears. processCreditCard reasserts errorMessage on every render.
|
|
15539
|
+
if (!isEcho && this.menu.optionSelected && this.input.validate) {
|
|
15540
|
+
this.input.updateComplete.then(() => {
|
|
15541
|
+
this.input.validate(true);
|
|
15542
|
+
if (this.input.validity === 'valid') {
|
|
15543
|
+
this.input.errorMessage = '';
|
|
15544
|
+
}
|
|
15545
|
+
});
|
|
15546
|
+
}
|
|
15617
15547
|
});
|
|
15618
15548
|
|
|
15619
15549
|
this.menu.addEventListener('auroMenu-customEventFired', () => {
|
|
15620
15550
|
this.hideBib();
|
|
15621
15551
|
});
|
|
15622
15552
|
|
|
15553
|
+
// When the menu cannot match a programmatic value to any option,
|
|
15554
|
+
// clear the combobox selection state so it doesn't reference a
|
|
15555
|
+
// stale option. Safe from re-entrancy because any resulting
|
|
15556
|
+
// input.value changes dispatch isProgrammatic events.
|
|
15557
|
+
this.menu.addEventListener('auroMenu-selectValueFailure', () => {
|
|
15558
|
+
this.value = undefined;
|
|
15559
|
+
this.optionSelected = undefined;
|
|
15560
|
+
});
|
|
15561
|
+
|
|
15623
15562
|
this.menu.addEventListener('auroMenu-activatedOption', (evt) => {
|
|
15624
15563
|
this.optionActive = evt.detail;
|
|
15625
15564
|
|
|
@@ -15720,11 +15659,12 @@ class AuroCombobox extends AuroElement {
|
|
|
15720
15659
|
// event from the trigger. The _syncingBibValue guard persists across the
|
|
15721
15660
|
// async boundary and prevents that re-entrant event from running the
|
|
15722
15661
|
// non-fullscreen path (which would call clear() → hideBib()).
|
|
15723
|
-
// When the event comes from the fullscreen bib input, sync the value to
|
|
15724
|
-
// the trigger and run filtering, but suppress the re-entrant input event
|
|
15725
|
-
// that the trigger fires (via Lit updated() → notifyValueChanged()) so
|
|
15726
|
-
// the non-fullscreen hide/clear logic doesn't close the dialog.
|
|
15727
15662
|
if (event.target === this.inputInBib) {
|
|
15663
|
+
// Mirror the trigger-branch bail below — programmatic inputInBib writes
|
|
15664
|
+
// notify back into this branch via Lit's notifyValueChanged.
|
|
15665
|
+
if (this._syncingDisplayValue) {
|
|
15666
|
+
return;
|
|
15667
|
+
}
|
|
15728
15668
|
this._syncingBibValue = true;
|
|
15729
15669
|
this.input.value = this.inputInBib.value;
|
|
15730
15670
|
this.input.updateComplete.then(() => {
|
|
@@ -15734,18 +15674,37 @@ class AuroCombobox extends AuroElement {
|
|
|
15734
15674
|
// Run filtering inline — the re-entrant event won't reach this code.
|
|
15735
15675
|
this.menu.matchWord = normalizeFilterValue(this.inputInBib.value);
|
|
15736
15676
|
this.optionActive = null;
|
|
15677
|
+
|
|
15678
|
+
// In suggestion mode, keep the combobox value in sync with the typed
|
|
15679
|
+
// text so that freeform values are captured (mirroring the non-fullscreen
|
|
15680
|
+
// path). Clear the selection when the input is emptied.
|
|
15681
|
+
if (this.behavior === 'suggestion') {
|
|
15682
|
+
this.value = this.inputInBib.value || undefined;
|
|
15683
|
+
}
|
|
15684
|
+
|
|
15737
15685
|
this.handleMenuOptions();
|
|
15738
15686
|
this.dispatchEvent(new CustomEvent('inputValue', { detail: { value: this.inputValue } }));
|
|
15739
15687
|
return;
|
|
15740
15688
|
}
|
|
15741
15689
|
|
|
15742
|
-
// Ignore re-entrant input events caused by
|
|
15743
|
-
if (this._syncingBibValue) {
|
|
15690
|
+
// Ignore re-entrant input events caused by programmatic value sets.
|
|
15691
|
+
if (this._syncingBibValue || this._syncingDisplayValue) {
|
|
15744
15692
|
return;
|
|
15745
15693
|
}
|
|
15746
15694
|
|
|
15747
15695
|
this.inputInBib.value = this.input.value;
|
|
15748
15696
|
|
|
15697
|
+
// Also sync the native input immediately so keystrokes arriving
|
|
15698
|
+
// before Lit's async update cycle (e.g. rapid Backspaces during a
|
|
15699
|
+
// fullscreen transition) operate on the correct content.
|
|
15700
|
+
// Skip the next programmatic input event to prevent the patched setter
|
|
15701
|
+
// from re-entering handleInputValueChange via the bib path.
|
|
15702
|
+
const bibNativeInput = this.inputInBib.inputElement;
|
|
15703
|
+
if (bibNativeInput && bibNativeInput.value !== this.input.value) {
|
|
15704
|
+
this.inputInBib.skipNextProgrammaticInputEvent = true;
|
|
15705
|
+
bibNativeInput.value = this.input.value || '';
|
|
15706
|
+
}
|
|
15707
|
+
|
|
15749
15708
|
this.menu.matchWord = normalizeFilterValue(this.input.value);
|
|
15750
15709
|
this.optionActive = null;
|
|
15751
15710
|
|
|
@@ -15753,7 +15712,7 @@ class AuroCombobox extends AuroElement {
|
|
|
15753
15712
|
this.value = this.input.value;
|
|
15754
15713
|
}
|
|
15755
15714
|
|
|
15756
|
-
if (!this.input.value) {
|
|
15715
|
+
if (!this.input.value && !this._clearing) {
|
|
15757
15716
|
this.clear();
|
|
15758
15717
|
}
|
|
15759
15718
|
this.handleMenuOptions();
|
|
@@ -15883,10 +15842,18 @@ class AuroCombobox extends AuroElement {
|
|
|
15883
15842
|
* @returns {void}
|
|
15884
15843
|
*/
|
|
15885
15844
|
setMenuValue(value) {
|
|
15886
|
-
if (!this.menu) {
|
|
15845
|
+
if (!this.menu || this.menu.value === value) {
|
|
15887
15846
|
return;
|
|
15888
15847
|
}
|
|
15848
|
+
// One-shot flag consumed by the auroMenu-selectedOption listener so the
|
|
15849
|
+
// echo of this sync doesn't propagate back to this.value.
|
|
15850
|
+
this._pendingMenuValueSync = true;
|
|
15889
15851
|
this.menu.value = value;
|
|
15852
|
+
// Backup clear: if menu.value === menu.optionSelected.value already, the
|
|
15853
|
+
// listener won't fire and the flag would swallow the next user click.
|
|
15854
|
+
setTimeout(() => {
|
|
15855
|
+
this._pendingMenuValueSync = false;
|
|
15856
|
+
}, 0);
|
|
15890
15857
|
}
|
|
15891
15858
|
|
|
15892
15859
|
/**
|
|
@@ -15908,16 +15875,24 @@ class AuroCombobox extends AuroElement {
|
|
|
15908
15875
|
* @returns {void}
|
|
15909
15876
|
*/
|
|
15910
15877
|
clear() {
|
|
15911
|
-
//
|
|
15912
|
-
|
|
15913
|
-
this.
|
|
15914
|
-
|
|
15915
|
-
// Then clear input and menu
|
|
15916
|
-
if (this.input.value) {
|
|
15917
|
-
this.input.clear();
|
|
15878
|
+
// input.clear() fires an input event that re-enters handleInputValueChange
|
|
15879
|
+
// → which calls clear() again on empty input. Guard against that loop.
|
|
15880
|
+
if (this._clearing) {
|
|
15881
|
+
return;
|
|
15918
15882
|
}
|
|
15919
|
-
|
|
15920
|
-
|
|
15883
|
+
this._clearing = true;
|
|
15884
|
+
try {
|
|
15885
|
+
this.optionSelected = undefined;
|
|
15886
|
+
this.value = undefined;
|
|
15887
|
+
|
|
15888
|
+
if (this.input.value) {
|
|
15889
|
+
this.input.clear();
|
|
15890
|
+
}
|
|
15891
|
+
if (this.menu.value || this.menu.optionSelected) {
|
|
15892
|
+
this.menu.reset();
|
|
15893
|
+
}
|
|
15894
|
+
} finally {
|
|
15895
|
+
this._clearing = false;
|
|
15921
15896
|
}
|
|
15922
15897
|
}
|
|
15923
15898
|
|
|
@@ -15945,29 +15920,64 @@ class AuroCombobox extends AuroElement {
|
|
|
15945
15920
|
this.input.value = this.value;
|
|
15946
15921
|
}
|
|
15947
15922
|
|
|
15948
|
-
|
|
15949
|
-
|
|
15950
|
-
|
|
15951
|
-
|
|
15952
|
-
|
|
15953
|
-
|
|
15954
|
-
|
|
15955
|
-
|
|
15956
|
-
|
|
15957
|
-
if (!this.menu.options || this.menu.options.length === 0) ; else if (this.menu.options.filter((opt) => opt.value === this.value).length > 0) {
|
|
15923
|
+
// Sync menu.value only when an option actually matches; otherwise clear it.
|
|
15924
|
+
if (this.menu.options && this.menu.options.length > 0) {
|
|
15925
|
+
if (this.menu.options.some((opt) => opt.value === this.value)) {
|
|
15926
|
+
this.setMenuValue(this.value);
|
|
15927
|
+
} else if (this.behavior === 'filter') {
|
|
15928
|
+
// In filter mode, freeform values aren't allowed. Push the unmatched
|
|
15929
|
+
// value through setMenuValue so menu dispatches auroMenu-selectValueFailure
|
|
15930
|
+
// and the listener at line 1206 clears combobox.value (mirrors select's
|
|
15931
|
+
// pattern). Bypassing setMenuValue here would skip the failure cascade.
|
|
15958
15932
|
this.setMenuValue(this.value);
|
|
15959
15933
|
} else {
|
|
15960
|
-
this.menu.value
|
|
15961
|
-
|
|
15962
|
-
|
|
15963
|
-
|
|
15964
|
-
|
|
15965
|
-
|
|
15966
|
-
|
|
15967
|
-
|
|
15968
|
-
this.
|
|
15934
|
+
if (this.menu.value) {
|
|
15935
|
+
this.menu.value = undefined;
|
|
15936
|
+
}
|
|
15937
|
+
// Sync the display for programmatic freeform value changes (e.g. the
|
|
15938
|
+
// swap-values pattern). Guard with _syncingDisplayValue so that the
|
|
15939
|
+
// re-entrant input event from base-input.notifyValueChanged() is
|
|
15940
|
+
// ignored by handleInputValueChange. Skip the sync when input already
|
|
15941
|
+
// matches to avoid spurious events during the normal typing path.
|
|
15942
|
+
const nextValue = this.value || '';
|
|
15943
|
+
const triggerNeedsSync = this.input.value !== nextValue;
|
|
15944
|
+
const bibNeedsSync = Boolean(this.inputInBib && this.inputInBib !== this.input && this.inputInBib.value !== nextValue);
|
|
15945
|
+
if (triggerNeedsSync || bibNeedsSync) {
|
|
15946
|
+
this._syncingDisplayValue = true;
|
|
15947
|
+
if (triggerNeedsSync) {
|
|
15948
|
+
this.input.value = nextValue;
|
|
15949
|
+
}
|
|
15950
|
+
if (bibNeedsSync) {
|
|
15951
|
+
this.inputInBib.value = nextValue;
|
|
15952
|
+
}
|
|
15953
|
+
const pending = [];
|
|
15954
|
+
if (triggerNeedsSync) {
|
|
15955
|
+
pending.push(this.input.updateComplete);
|
|
15956
|
+
}
|
|
15957
|
+
if (bibNeedsSync) {
|
|
15958
|
+
pending.push(this.inputInBib.updateComplete);
|
|
15959
|
+
}
|
|
15960
|
+
Promise.all(pending).then(() => {
|
|
15961
|
+
if (triggerNeedsSync && this.input.maskInstance && typeof this.input.maskInstance.updateValue === 'function') {
|
|
15962
|
+
this.input.maskInstance.updateValue();
|
|
15963
|
+
}
|
|
15964
|
+
if (bibNeedsSync && this.inputInBib && this.inputInBib.maskInstance && typeof this.inputInBib.maskInstance.updateValue === 'function') {
|
|
15965
|
+
this.inputInBib.maskInstance.updateValue();
|
|
15966
|
+
}
|
|
15967
|
+
this._syncingDisplayValue = false;
|
|
15968
|
+
// handleInputValueChange bailed on the flag — refresh the filter.
|
|
15969
|
+
this._programmaticFilterRefresh = true;
|
|
15970
|
+
this.handleMenuOptions();
|
|
15971
|
+
setTimeout(() => {
|
|
15972
|
+
this._programmaticFilterRefresh = false;
|
|
15973
|
+
}, 0);
|
|
15974
|
+
});
|
|
15975
|
+
}
|
|
15969
15976
|
}
|
|
15970
15977
|
}
|
|
15978
|
+
if (!this.value) {
|
|
15979
|
+
this.clear();
|
|
15980
|
+
}
|
|
15971
15981
|
if (this.value && !this.componentHasFocus) {
|
|
15972
15982
|
// If the value got set programmatically make sure we hide the bib
|
|
15973
15983
|
// when input is not taking the focus (input can be in dropdown.trigger or in bibtemplate)
|
|
@@ -16004,12 +16014,18 @@ class AuroCombobox extends AuroElement {
|
|
|
16004
16014
|
// branch from calling hideBib() when the dropdown was just opened but
|
|
16005
16015
|
// :focus-within hasn't propagated through the top-layer dialog's nested
|
|
16006
16016
|
// shadow DOM boundaries.
|
|
16007
|
-
|
|
16017
|
+
// Skip the show/hide side effects when the availableOptions change came
|
|
16018
|
+
// from a programmatic filter refresh after a value swap — the user
|
|
16019
|
+
// didn't interact, so we shouldn't auto-open the bib (especially for
|
|
16020
|
+
// the no-match path where the existing condition unconditionally fires).
|
|
16021
|
+
if (this._programmaticFilterRefresh) {
|
|
16022
|
+
this._programmaticFilterRefresh = false;
|
|
16023
|
+
} else if ((this.availableOptions.length > 0 && (this.componentHasFocus || this.dropdownOpen)) || (this.menu && this.menu.loading) || (this.availableOptions.length === 0 && this.noMatchOption)) {
|
|
16008
16024
|
this.showBib();
|
|
16009
16025
|
if (!this.availableOptions.includes(this.menu.optionActive)) {
|
|
16010
16026
|
this.activateFirstEnabledAvailableOption();
|
|
16011
16027
|
}
|
|
16012
|
-
} else {
|
|
16028
|
+
} else if (this.dropdown && this.dropdown.isPopoverVisible) {
|
|
16013
16029
|
this.hideBib();
|
|
16014
16030
|
}
|
|
16015
16031
|
}
|