@aurodesignsystem-dev/auro-formkit 0.0.0-pr1574.0 → 0.0.0-pr1576.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/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/dist/index.js +1 -1
- package/components/checkbox/dist/registered.js +1 -1
- package/components/combobox/demo/customize.md +40 -0
- package/components/combobox/demo/customize.min.js +256 -17
- package/components/combobox/demo/getting-started.min.js +256 -17
- package/components/combobox/demo/index.min.js +256 -17
- package/components/combobox/dist/index.js +3 -3
- package/components/combobox/dist/registered.js +3 -3
- package/components/counter/demo/customize.min.js +3 -3
- package/components/counter/demo/index.min.js +3 -3
- package/components/counter/dist/index.js +3 -3
- package/components/counter/dist/registered.js +3 -3
- package/components/datepicker/demo/customize.min.js +3 -3
- package/components/datepicker/demo/index.min.js +3 -3
- package/components/datepicker/dist/index.js +3 -3
- package/components/datepicker/dist/registered.js +3 -3
- package/components/dropdown/demo/customize.min.js +1 -1
- package/components/dropdown/demo/getting-started.min.js +1 -1
- package/components/dropdown/demo/index.min.js +1 -1
- package/components/dropdown/dist/index.js +1 -1
- package/components/dropdown/dist/registered.js +1 -1
- package/components/form/demo/customize.min.js +267 -28
- package/components/form/demo/getting-started.min.js +267 -28
- package/components/form/demo/index.min.js +267 -28
- package/components/form/demo/registerDemoDeps.min.js +267 -28
- 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/dist/index.js +1 -1
- package/components/input/dist/registered.js +1 -1
- package/components/menu/demo/index.min.js +253 -14
- package/components/menu/dist/auro-menu-utils.d.ts +30 -0
- package/components/menu/dist/auro-menu.d.ts +23 -0
- package/components/menu/dist/index.js +253 -14
- package/components/menu/dist/registered.js +253 -14
- package/components/radio/demo/customize.min.js +1 -1
- package/components/radio/demo/getting-started.min.js +1 -1
- package/components/radio/demo/index.min.js +1 -1
- package/components/radio/dist/index.js +1 -1
- package/components/radio/dist/registered.js +1 -1
- package/components/select/demo/customize.md +72 -0
- package/components/select/demo/customize.min.js +255 -16
- package/components/select/demo/getting-started.min.js +255 -16
- package/components/select/demo/index.min.js +255 -16
- package/components/select/dist/index.js +2 -2
- package/components/select/dist/registered.js +2 -2
- package/custom-elements.json +1617 -1513
- package/package.json +1 -1
|
@@ -1275,7 +1275,7 @@ class AuroHelpText extends i$2 {
|
|
|
1275
1275
|
}
|
|
1276
1276
|
}
|
|
1277
1277
|
|
|
1278
|
-
var formkitVersion = '
|
|
1278
|
+
var formkitVersion = '202608040326';
|
|
1279
1279
|
|
|
1280
1280
|
// Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
|
|
1281
1281
|
// See LICENSE in the project root for license information.
|
|
@@ -1275,7 +1275,7 @@ class AuroHelpText extends i$2 {
|
|
|
1275
1275
|
}
|
|
1276
1276
|
}
|
|
1277
1277
|
|
|
1278
|
-
var formkitVersion = '
|
|
1278
|
+
var formkitVersion = '202608040326';
|
|
1279
1279
|
|
|
1280
1280
|
// Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
|
|
1281
1281
|
// See LICENSE in the project root for license information.
|
|
@@ -1275,7 +1275,7 @@ class AuroHelpText extends i$2 {
|
|
|
1275
1275
|
}
|
|
1276
1276
|
}
|
|
1277
1277
|
|
|
1278
|
-
var formkitVersion = '
|
|
1278
|
+
var formkitVersion = '202608040326';
|
|
1279
1279
|
|
|
1280
1280
|
// Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
|
|
1281
1281
|
// See LICENSE in the project root for license information.
|
|
@@ -1228,7 +1228,7 @@ class AuroHelpText extends LitElement {
|
|
|
1228
1228
|
}
|
|
1229
1229
|
}
|
|
1230
1230
|
|
|
1231
|
-
var formkitVersion = '
|
|
1231
|
+
var formkitVersion = '202608040326';
|
|
1232
1232
|
|
|
1233
1233
|
// Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
|
|
1234
1234
|
// See LICENSE in the project root for license information.
|
|
@@ -1228,7 +1228,7 @@ class AuroHelpText extends LitElement {
|
|
|
1228
1228
|
}
|
|
1229
1229
|
}
|
|
1230
1230
|
|
|
1231
|
-
var formkitVersion = '
|
|
1231
|
+
var formkitVersion = '202608040326';
|
|
1232
1232
|
|
|
1233
1233
|
// Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
|
|
1234
1234
|
// See LICENSE in the project root for license information.
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
<auro-anchorlink fluid href="#noValidate" class="level2 body-xs">No Validation</auro-anchorlink>
|
|
30
30
|
<auro-anchorlink fluid href="#dynamicMenu" class="level2 body-xs">Dynamic Menu</auro-anchorlink>
|
|
31
31
|
<auro-anchorlink fluid href="#loading" class="level2 body-xs">Loading</auro-anchorlink>
|
|
32
|
+
<auro-anchorlink fluid href="#nonUniqueValues" class="level2 body-xs">Non-Unique Option Values</auro-anchorlink>
|
|
32
33
|
</auro-nav>
|
|
33
34
|
</nav>
|
|
34
35
|
<div class="mainContent">
|
|
@@ -1296,6 +1297,45 @@
|
|
|
1296
1297
|
</auro-combobox></code></pre>
|
|
1297
1298
|
<!-- AURO-GENERATED-CONTENT:END -->
|
|
1298
1299
|
</auro-accordion>
|
|
1300
|
+
<auro-header level="3" id="nonUniqueValues">Non-Unique Option Values</auro-header>
|
|
1301
|
+
<p>Two or more <code>auro-menuoption</code> elements may share the same <code>value</code>. This is common when the <code>value</code> represents a coarser grouping than the option label — for example, several airports that all serve the same city. When the user filters the list and selects one of several options that share a <code>value</code>, the combobox resolves to the exact option chosen, so the correct label is displayed even though the underlying <code>value</code> is duplicated.</p>
|
|
1302
|
+
<div class="exampleWrapper">
|
|
1303
|
+
<!-- AURO-GENERATED-CONTENT:START (FILE:src=./../apiExamples/duplicate-values.html) -->
|
|
1304
|
+
<!-- The below content is automatically added from ./../apiExamples/duplicate-values.html -->
|
|
1305
|
+
<auro-combobox>
|
|
1306
|
+
<span slot="ariaLabel.bib.close">Close combobox</span>
|
|
1307
|
+
<span slot="ariaLabel.input.clear">Clear All</span>
|
|
1308
|
+
<span slot="bib.fullscreen.headline">Choose an airport</span>
|
|
1309
|
+
<span slot="label">Departure airport</span>
|
|
1310
|
+
<auro-menu>
|
|
1311
|
+
<auro-menuoption value="seattle" suggest="seattle sea seatac tacoma">Seattle–Tacoma International (SEA)</auro-menuoption>
|
|
1312
|
+
<auro-menuoption value="seattle" suggest="seattle pae paine field everett">Seattle Paine Field (PAE)</auro-menuoption>
|
|
1313
|
+
<auro-menuoption value="portland" suggest="portland pdx oregon">Portland International (PDX)</auro-menuoption>
|
|
1314
|
+
<auro-menuoption value="spokane" suggest="spokane geg washington">Spokane International (GEG)</auro-menuoption>
|
|
1315
|
+
<auro-menuoption static nomatch>No matching airport</auro-menuoption>
|
|
1316
|
+
</auro-menu>
|
|
1317
|
+
</auro-combobox>
|
|
1318
|
+
<!-- AURO-GENERATED-CONTENT:END -->
|
|
1319
|
+
</div>
|
|
1320
|
+
<auro-accordion alignRight>
|
|
1321
|
+
<span slot="trigger">See code</span>
|
|
1322
|
+
<!-- AURO-GENERATED-CONTENT:START (CODE:src=./../apiExamples/duplicate-values.html) -->
|
|
1323
|
+
<!-- The below code snippet is automatically added from ./../apiExamples/duplicate-values.html -->
|
|
1324
|
+
<pre class="language-html"><code class="language-html"><auro-combobox>
|
|
1325
|
+
<span slot="ariaLabel.bib.close">Close combobox</span>
|
|
1326
|
+
<span slot="ariaLabel.input.clear">Clear All</span>
|
|
1327
|
+
<span slot="bib.fullscreen.headline">Choose an airport</span>
|
|
1328
|
+
<span slot="label">Departure airport</span>
|
|
1329
|
+
<auro-menu>
|
|
1330
|
+
<auro-menuoption value="seattle" suggest="seattle sea seatac tacoma">Seattle&ndash;Tacoma International (SEA)</auro-menuoption>
|
|
1331
|
+
<auro-menuoption value="seattle" suggest="seattle pae paine field everett">Seattle Paine Field (PAE)</auro-menuoption>
|
|
1332
|
+
<auro-menuoption value="portland" suggest="portland pdx oregon">Portland International (PDX)</auro-menuoption>
|
|
1333
|
+
<auro-menuoption value="spokane" suggest="spokane geg washington">Spokane International (GEG)</auro-menuoption>
|
|
1334
|
+
<auro-menuoption static nomatch>No matching airport</auro-menuoption>
|
|
1335
|
+
</auro-menu>
|
|
1336
|
+
</auro-combobox></code></pre>
|
|
1337
|
+
<!-- AURO-GENERATED-CONTENT:END -->
|
|
1338
|
+
</auro-accordion>
|
|
1299
1339
|
</section>
|
|
1300
1340
|
</div>
|
|
1301
1341
|
</div>
|
|
@@ -4977,7 +4977,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$3 {
|
|
|
4977
4977
|
}
|
|
4978
4978
|
};
|
|
4979
4979
|
|
|
4980
|
-
var formkitVersion$2 = '
|
|
4980
|
+
var formkitVersion$2 = '202608040326';
|
|
4981
4981
|
|
|
4982
4982
|
let AuroElement$2 = class AuroElement extends i$3 {
|
|
4983
4983
|
static get properties() {
|
|
@@ -18666,7 +18666,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$3 {
|
|
|
18666
18666
|
}
|
|
18667
18667
|
};
|
|
18668
18668
|
|
|
18669
|
-
var formkitVersion$1 = '
|
|
18669
|
+
var formkitVersion$1 = '202608040326';
|
|
18670
18670
|
|
|
18671
18671
|
// Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
18672
18672
|
// See LICENSE in the project root for license information.
|
|
@@ -19822,7 +19822,7 @@ class AuroBibtemplate extends i$3 {
|
|
|
19822
19822
|
}
|
|
19823
19823
|
}
|
|
19824
19824
|
|
|
19825
|
-
var formkitVersion = '
|
|
19825
|
+
var formkitVersion = '202608040326';
|
|
19826
19826
|
|
|
19827
19827
|
var styleCss$3 = i$6`.util_displayInline{display:inline}.util_displayInlineBlock{display:inline-block}.util_displayBlock{display:block}.util_displayFlex{display:flex}.util_displayHidden{display:none}.util_displayHiddenVisually{position:absolute;overflow:hidden;clip:rect(1px, 1px, 1px, 1px);width:1px;height:1px;padding:0;border:0}:host{display:block;text-align:left}:host [auro-dropdown]{--ds-auro-dropdown-trigger-background-color: transparent}:host #inputInBib::part(wrapper){box-shadow:none}:host #inputInBib::part(accent-left){display:none}:host([layout*=classic]) [auro-input]{width:100%}:host([layout*=classic]) [auro-input]::part(helpText){display:none}:host([layout*=classic]) #slotHolder{display:none}`;
|
|
19828
19828
|
|
|
@@ -22255,6 +22255,107 @@ function isSelectableByValue(option) {
|
|
|
22255
22255
|
!option.hasAttribute('static');
|
|
22256
22256
|
}
|
|
22257
22257
|
|
|
22258
|
+
/* eslint-disable no-underscore-dangle */
|
|
22259
|
+
/**
|
|
22260
|
+
* Resolves the single selected option for a given `value`, preferring the
|
|
22261
|
+
* option tracked by `selectedKey` (a user-initiated selection) over a
|
|
22262
|
+
* first-by-value match. When multiple options share the same `value`, matching
|
|
22263
|
+
* by `value` alone cannot distinguish which one the user picked; the key
|
|
22264
|
+
* disambiguates it.
|
|
22265
|
+
*
|
|
22266
|
+
* The key is trusted only when it still resolves to an option whose `value`
|
|
22267
|
+
* matches the requested `value`. If the key is stale (option removed) or the
|
|
22268
|
+
* value was changed programmatically, resolution falls back to value matching —
|
|
22269
|
+
* preserving backward-compatible behavior for preselection and `selectByValue`.
|
|
22270
|
+
* @private
|
|
22271
|
+
* @param {Array<HTMLElement>} items - The menu's flat option list.
|
|
22272
|
+
* @param {string} value - The value to resolve.
|
|
22273
|
+
* @param {string|undefined} selectedKey - The `_optionKey` of the user-selected option, if any.
|
|
22274
|
+
* @returns {HTMLElement|undefined} The resolved option, or undefined when none match.
|
|
22275
|
+
*/
|
|
22276
|
+
function resolveSelectedOption(items, value, selectedKey) {
|
|
22277
|
+
if (!items) {
|
|
22278
|
+
return undefined;
|
|
22279
|
+
}
|
|
22280
|
+
|
|
22281
|
+
if (selectedKey !== undefined) {
|
|
22282
|
+
const keyed = items.find((item) => item._optionKey === selectedKey);
|
|
22283
|
+
if (keyed && isSelectableByValue(keyed) && keyed.value === value) {
|
|
22284
|
+
return keyed;
|
|
22285
|
+
}
|
|
22286
|
+
// Key exists but the option is gone or its value no longer matches — fall
|
|
22287
|
+
// through to value-based matching.
|
|
22288
|
+
}
|
|
22289
|
+
|
|
22290
|
+
return items.find((item) => isSelectableByValue(item) && item.value === value);
|
|
22291
|
+
}
|
|
22292
|
+
|
|
22293
|
+
/**
|
|
22294
|
+
* Resolves the selected options for a multi-select `value` array, preferring
|
|
22295
|
+
* options tracked by `selectedKeys` (user-initiated selections) and falling
|
|
22296
|
+
* back to value matching for any values not resolved by key. The result is
|
|
22297
|
+
* always sorted into DOM order regardless of selection sequence.
|
|
22298
|
+
* @private
|
|
22299
|
+
* @param {Array<HTMLElement>} items - The menu's flat option list.
|
|
22300
|
+
* @param {Array<string>} valueArray - The selected values.
|
|
22301
|
+
* @param {Array<string>|undefined} selectedKeys - The `_optionKey`s of the user-selected options, if any.
|
|
22302
|
+
* @returns {Array<HTMLElement>} The resolved options in DOM order.
|
|
22303
|
+
*/
|
|
22304
|
+
function resolveSelectedOptions(items, valueArray, selectedKeys) {
|
|
22305
|
+
if (!items) {
|
|
22306
|
+
return [];
|
|
22307
|
+
}
|
|
22308
|
+
|
|
22309
|
+
const resolved = [];
|
|
22310
|
+
|
|
22311
|
+
// Track how many of each value are still available to resolve. A value that
|
|
22312
|
+
// appears N times in `valueArray` may be satisfied at most N times total across
|
|
22313
|
+
// the key pass and the value fallback below — matching by count, not presence,
|
|
22314
|
+
// on BOTH passes. This stops a duplicate value from being over-resolved: e.g.
|
|
22315
|
+
// two keyed options that both carry `SEA` cannot both match a single requested
|
|
22316
|
+
// `SEA` (which happens when `value` is set directly without clearing
|
|
22317
|
+
// `_selectedKey`, so more keys survive than the value set now asks for).
|
|
22318
|
+
const remaining = new Map();
|
|
22319
|
+
valueArray.forEach((val) => remaining.set(val, (remaining.get(val) || 0) + 1));
|
|
22320
|
+
|
|
22321
|
+
// Resolve by key first: trust a key only when its option is still selectable
|
|
22322
|
+
// and there is still an unmatched occurrence of its value in the request set.
|
|
22323
|
+
if (Array.isArray(selectedKeys)) {
|
|
22324
|
+
selectedKeys.forEach((key) => {
|
|
22325
|
+
const keyed = items.find((item) => item._optionKey === key);
|
|
22326
|
+
if (keyed && isSelectableByValue(keyed) && (remaining.get(keyed.value) || 0) > 0 && !resolved.includes(keyed)) {
|
|
22327
|
+
resolved.push(keyed);
|
|
22328
|
+
remaining.set(keyed.value, remaining.get(keyed.value) - 1);
|
|
22329
|
+
}
|
|
22330
|
+
});
|
|
22331
|
+
}
|
|
22332
|
+
|
|
22333
|
+
// Fall back to value matching for the occurrences not resolved by key. Iterate
|
|
22334
|
+
// the leftover per-value counts so a value that appears twice but was only
|
|
22335
|
+
// resolved once by key still matches its remaining occurrence(s).
|
|
22336
|
+
remaining.forEach((count, val) => {
|
|
22337
|
+
for (let occurrence = 0; occurrence < count; occurrence += 1) {
|
|
22338
|
+
const option = items.find((item) => isSelectableByValue(item) && item.value === val && !resolved.includes(item));
|
|
22339
|
+
if (option) {
|
|
22340
|
+
resolved.push(option);
|
|
22341
|
+
}
|
|
22342
|
+
}
|
|
22343
|
+
});
|
|
22344
|
+
|
|
22345
|
+
// Always return in DOM order so display is consistent regardless of the order
|
|
22346
|
+
// keys/values were selected. Every resolved option came from `items`, so an
|
|
22347
|
+
// O(1) index lookup mirrors `_sortSelectedByDomOrder` and avoids the O(n)
|
|
22348
|
+
// `items.indexOf` per comparison for large combobox option sets.
|
|
22349
|
+
const indexMap = new Map(items.map((item, index) => [
|
|
22350
|
+
item,
|
|
22351
|
+
index
|
|
22352
|
+
]));
|
|
22353
|
+
resolved.sort((optionA, optionB) => indexMap.get(optionA) - indexMap.get(optionB));
|
|
22354
|
+
|
|
22355
|
+
return resolved;
|
|
22356
|
+
}
|
|
22357
|
+
/* eslint-enable no-underscore-dangle */
|
|
22358
|
+
|
|
22258
22359
|
/**
|
|
22259
22360
|
* Helper method to dispatch custom events.
|
|
22260
22361
|
* @param {HTMLElement} element - Element to dispatch event from.
|
|
@@ -22280,6 +22381,14 @@ function dispatchMenuEvent(element, eventName, detail = null) {
|
|
|
22280
22381
|
// See LICENSE in the project root for license information.
|
|
22281
22382
|
|
|
22282
22383
|
|
|
22384
|
+
/**
|
|
22385
|
+
* Monotonically increasing counter used to give each menu instance a unique
|
|
22386
|
+
* `_menuInstanceId` prefix. Auto-generating the id (rather than using a random
|
|
22387
|
+
* string) keeps option keys deterministic and collision-free across menus.
|
|
22388
|
+
* @private
|
|
22389
|
+
*/
|
|
22390
|
+
let menuInstanceIdCounter = 0;
|
|
22391
|
+
|
|
22283
22392
|
|
|
22284
22393
|
/**
|
|
22285
22394
|
* The `auro-menu` element provides users a way to select from a list of options.
|
|
@@ -22354,6 +22463,8 @@ class AuroMenu extends AuroElement {
|
|
|
22354
22463
|
/**
|
|
22355
22464
|
* @private
|
|
22356
22465
|
*/
|
|
22466
|
+
menuInstanceIdCounter += 1;
|
|
22467
|
+
|
|
22357
22468
|
Object.assign(this, {
|
|
22358
22469
|
// Root-level menu (true) or a nested submenu (false)
|
|
22359
22470
|
rootMenu: true,
|
|
@@ -22363,6 +22474,21 @@ class AuroMenu extends AuroElement {
|
|
|
22363
22474
|
nestingSpacer: '<span class="nestingSpacer"></span>',
|
|
22364
22475
|
// Loading indicator for slot elements
|
|
22365
22476
|
loadingSlots: null,
|
|
22477
|
+
// Unique id for this menu instance; prefixes every auto-generated option
|
|
22478
|
+
// key so keys never collide across menus in the same document.
|
|
22479
|
+
_menuInstanceId: `menu-${menuInstanceIdCounter}`,
|
|
22480
|
+
// Monotonically increasing counter for option key generation. Never
|
|
22481
|
+
// resets, so a key is never reused within this instance's lifetime.
|
|
22482
|
+
_optionKeyCounter: 0,
|
|
22483
|
+
// Key(s) of the option(s) the user has actively selected. A single string
|
|
22484
|
+
// in single-select, an array in multi-select, undefined when nothing is
|
|
22485
|
+
// user-selected. Used to disambiguate options that share a `value`.
|
|
22486
|
+
_selectedKey: undefined,
|
|
22487
|
+
// True only for the one updated() cycle following a user selection, so
|
|
22488
|
+
// reconciliation trusts `_selectedKey`. A `value` change from a consumer's
|
|
22489
|
+
// direct property assignment leaves this false, dropping the stale key so
|
|
22490
|
+
// reconciliation falls back to first-by-value (see updated()).
|
|
22491
|
+
_valueChangeFromSelection: false,
|
|
22366
22492
|
});
|
|
22367
22493
|
}
|
|
22368
22494
|
|
|
@@ -22582,6 +22708,13 @@ class AuroMenu extends AuroElement {
|
|
|
22582
22708
|
return;
|
|
22583
22709
|
}
|
|
22584
22710
|
|
|
22711
|
+
// A programmatic value set carries no positional intent, so drop any
|
|
22712
|
+
// `_selectedKey` left over from a prior user click. This makes reconciliation
|
|
22713
|
+
// in updated() fall back to first-by-value (single) / value-in-DOM-order
|
|
22714
|
+
// (multi), matching the documented contract for programmatic selection even
|
|
22715
|
+
// when a stale key would still resolve to a duplicate-value option.
|
|
22716
|
+
this._selectedKey = undefined;
|
|
22717
|
+
|
|
22585
22718
|
// `value` is a String property; stringify arrays so attribute reflection and `formattedValue` parsing stay correct.
|
|
22586
22719
|
this.value = Array.isArray(value) ? JSON.stringify(value) : value;
|
|
22587
22720
|
}
|
|
@@ -22629,6 +22762,17 @@ class AuroMenu extends AuroElement {
|
|
|
22629
22762
|
updated(changedProperties) {
|
|
22630
22763
|
super.updated(changedProperties);
|
|
22631
22764
|
|
|
22765
|
+
// Consume the selection-driven flag for THIS cycle up front. Clearing it
|
|
22766
|
+
// unconditionally — not only inside the `value` branch below — prevents it
|
|
22767
|
+
// from lingering `true` when a selection produces a serialized `value`
|
|
22768
|
+
// byte-identical to the current one, in which case Lit schedules no
|
|
22769
|
+
// `value`-change cycle to consume it. A lingering flag would misclassify a
|
|
22770
|
+
// later consumer's programmatic `value` set as selection-driven and keep a
|
|
22771
|
+
// stale `_selectedKey`. The reconcile path below re-sets the instance flag
|
|
22772
|
+
// after this point, so its intentional cross-cycle hand-off still works.
|
|
22773
|
+
const valueChangeFromSelection = this._valueChangeFromSelection;
|
|
22774
|
+
this._valueChangeFromSelection = false;
|
|
22775
|
+
|
|
22632
22776
|
// Single source of truth for 'auroMenu-selectedOption'. Selection handlers
|
|
22633
22777
|
// mutate optionSelected and let Lit's update cycle dispatch here; the prior
|
|
22634
22778
|
// .value comparison missed multi-select array changes and combined with the
|
|
@@ -22652,6 +22796,17 @@ class AuroMenu extends AuroElement {
|
|
|
22652
22796
|
this.initItems();
|
|
22653
22797
|
}
|
|
22654
22798
|
|
|
22799
|
+
// Distinguish a selection-driven `value` change (a user click, which set
|
|
22800
|
+
// the flag in handleSelectState / _sortSelectedByDomOrder) from a
|
|
22801
|
+
// programmatic assignment by a consumer. A programmatic set carries no
|
|
22802
|
+
// positional intent, so drop any leftover `_selectedKey` and let
|
|
22803
|
+
// reconciliation fall back to first-by-value (single) / value-in-DOM-order
|
|
22804
|
+
// (multi) — the same contract selectByValue() guarantees, even when a
|
|
22805
|
+
// stale key would otherwise still resolve to a duplicate-value option.
|
|
22806
|
+
if (!valueChangeFromSelection) {
|
|
22807
|
+
this._selectedKey = undefined;
|
|
22808
|
+
}
|
|
22809
|
+
|
|
22655
22810
|
// Set when reconciliation reassigns `value` below. That reassignment schedules a
|
|
22656
22811
|
// second updated() cycle, so the `event`-attribute dispatch is deferred to that
|
|
22657
22812
|
// cycle to avoid firing option custom events twice on the same selection.
|
|
@@ -22669,7 +22824,10 @@ class AuroMenu extends AuroElement {
|
|
|
22669
22824
|
// Defensive default: `formattedValue` can be undefined for unexpected value types,
|
|
22670
22825
|
// and calling `.includes` on undefined would throw during reconciliation.
|
|
22671
22826
|
const valueArray = this.formattedValue || [];
|
|
22672
|
-
|
|
22827
|
+
// Resolve by key first (the user's exact picks), then fall back to
|
|
22828
|
+
// value matching for any values not resolved by key — so pre-selection
|
|
22829
|
+
// and programmatic value sets keep working. Result is DOM-ordered.
|
|
22830
|
+
const matchingOptions = resolveSelectedOptions(this.items, valueArray, this._selectedKey);
|
|
22673
22831
|
newSelected = matchingOptions.length > 0 ? matchingOptions : undefined;
|
|
22674
22832
|
|
|
22675
22833
|
// Reconcile `value` with the selectable set. Drop only entries whose option is
|
|
@@ -22682,6 +22840,12 @@ class AuroMenu extends AuroElement {
|
|
|
22682
22840
|
: [];
|
|
22683
22841
|
if (rejectedValues.length > 0) {
|
|
22684
22842
|
const reconciled = valueArray.filter((val) => !rejectedValues.includes(val));
|
|
22843
|
+
// This is an internal correction, not a consumer's programmatic set,
|
|
22844
|
+
// so preserve the selection-driven flag through the re-entrant
|
|
22845
|
+
// updated() cycle it schedules. Otherwise that cycle would treat the
|
|
22846
|
+
// reassignment as programmatic and drop `_selectedKey` mid-cascade,
|
|
22847
|
+
// flipping resolution and looping.
|
|
22848
|
+
this._valueChangeFromSelection = true;
|
|
22685
22849
|
this.value = serializeMultiSelectValue(reconciled);
|
|
22686
22850
|
valueReconciled = true;
|
|
22687
22851
|
}
|
|
@@ -22693,7 +22857,11 @@ class AuroMenu extends AuroElement {
|
|
|
22693
22857
|
// `hidden` is intentionally NOT excluded: the combobox toggles
|
|
22694
22858
|
// `hidden` as its type-ahead filter, so a filtered-out option is
|
|
22695
22859
|
// still a valid programmatic selection.
|
|
22696
|
-
|
|
22860
|
+
// Prefer the option the user actually selected (tracked by
|
|
22861
|
+
// `_selectedKey`) so a click on the second of two options sharing a
|
|
22862
|
+
// `value` resolves back to that exact element instead of the first
|
|
22863
|
+
// value match. Falls back to first-by-value for programmatic sets.
|
|
22864
|
+
const matchingOption = resolveSelectedOption(this.items, this.value, this._selectedKey);
|
|
22697
22865
|
|
|
22698
22866
|
if (matchingOption) {
|
|
22699
22867
|
newSelected = matchingOption;
|
|
@@ -22921,6 +23089,14 @@ class AuroMenu extends AuroElement {
|
|
|
22921
23089
|
}
|
|
22922
23090
|
});
|
|
22923
23091
|
|
|
23092
|
+
// Assign private keys once items are populated. Only the root menu assigns
|
|
23093
|
+
// keys: its `items` is a deep query that already includes nested submenu
|
|
23094
|
+
// options, so a single pass keys the entire tree. Nested menus skip this
|
|
23095
|
+
// and inherit keys from the root.
|
|
23096
|
+
if (this.rootMenu) {
|
|
23097
|
+
this._assignOptionKeys();
|
|
23098
|
+
}
|
|
23099
|
+
|
|
22924
23100
|
if (this.noCheckmark) {
|
|
22925
23101
|
this.updateItemsState(new Map([
|
|
22926
23102
|
[
|
|
@@ -22937,6 +23113,31 @@ class AuroMenu extends AuroElement {
|
|
|
22937
23113
|
}));
|
|
22938
23114
|
}
|
|
22939
23115
|
|
|
23116
|
+
/**
|
|
23117
|
+
* Assigns a private, auto-generated unique key (`_optionKey`) to each menu
|
|
23118
|
+
* option that does not already have one. Keys are internal state on the
|
|
23119
|
+
* element instance — never reflected as an attribute or exposed publicly —
|
|
23120
|
+
* and let selection tracking distinguish options that share the same `value`.
|
|
23121
|
+
*
|
|
23122
|
+
* The `_optionKey === undefined` guard makes this idempotent: options keep the
|
|
23123
|
+
* key they were first assigned across re-renders and slot changes, and if a
|
|
23124
|
+
* nested menu's lifecycle runs a pass before the root, options simply wait for
|
|
23125
|
+
* the root to key them (or keep whatever key they already hold).
|
|
23126
|
+
* @private
|
|
23127
|
+
*/
|
|
23128
|
+
_assignOptionKeys() {
|
|
23129
|
+
if (!this.items) {
|
|
23130
|
+
return;
|
|
23131
|
+
}
|
|
23132
|
+
|
|
23133
|
+
this.items.forEach((option) => {
|
|
23134
|
+
if (option._optionKey === undefined) {
|
|
23135
|
+
this._optionKeyCounter += 1;
|
|
23136
|
+
option._optionKey = `${this._menuInstanceId}-${this._optionKeyCounter}`;
|
|
23137
|
+
}
|
|
23138
|
+
});
|
|
23139
|
+
}
|
|
23140
|
+
|
|
22940
23141
|
// Logic Methods
|
|
22941
23142
|
|
|
22942
23143
|
/**
|
|
@@ -22946,24 +23147,28 @@ class AuroMenu extends AuroElement {
|
|
|
22946
23147
|
*/
|
|
22947
23148
|
handleSelectState(option) {
|
|
22948
23149
|
if (this.multiSelect) {
|
|
22949
|
-
const currentValue = this.formattedValue || [];
|
|
22950
23150
|
const currentSelected = this.optionSelected || [];
|
|
22951
23151
|
|
|
22952
|
-
if (!currentValue.includes(option.value)) {
|
|
22953
|
-
this.value = serializeMultiSelectValue([
|
|
22954
|
-
...currentValue,
|
|
22955
|
-
option.value
|
|
22956
|
-
]);
|
|
22957
|
-
}
|
|
22958
23152
|
if (!currentSelected.includes(option)) {
|
|
22959
23153
|
this.optionSelected = [
|
|
22960
23154
|
...currentSelected,
|
|
22961
23155
|
option
|
|
22962
23156
|
];
|
|
22963
23157
|
}
|
|
23158
|
+
|
|
23159
|
+
// Re-sort by DOM order and rebuild `_selectedKey`/`value` from the
|
|
23160
|
+
// selected set so display order stays consistent with the menu, not with
|
|
23161
|
+
// click order.
|
|
23162
|
+
this._sortSelectedByDomOrder();
|
|
22964
23163
|
} else {
|
|
22965
23164
|
this.value = option.value;
|
|
22966
23165
|
this.optionSelected = option;
|
|
23166
|
+
// Track the specific option the user selected so the value→option
|
|
23167
|
+
// reconciliation in updated() resolves back to this exact element even
|
|
23168
|
+
// when another option shares the same `value`.
|
|
23169
|
+
this._selectedKey = option._optionKey;
|
|
23170
|
+
// Mark this `value` change as selection-driven so updated() trusts the key.
|
|
23171
|
+
this._valueChangeFromSelection = true;
|
|
22967
23172
|
}
|
|
22968
23173
|
|
|
22969
23174
|
this._index = this.items.indexOf(option);
|
|
@@ -22976,18 +23181,22 @@ class AuroMenu extends AuroElement {
|
|
|
22976
23181
|
*/
|
|
22977
23182
|
handleDeselectState(option) {
|
|
22978
23183
|
if (this.multiSelect) {
|
|
22979
|
-
// Remove this
|
|
22980
|
-
|
|
22981
|
-
|
|
22982
|
-
|
|
22983
|
-
this.optionSelected = this.optionSelected.filter((val) => val !== option);
|
|
23184
|
+
// Remove this exact element from the selection (identity, not value — two
|
|
23185
|
+
// options can share a `value`), then rebuild `value`/`_selectedKey` from
|
|
23186
|
+
// the remaining set in DOM order. An empty result collapses to undefined.
|
|
23187
|
+
this.optionSelected = this.optionSelected.filter((selected) => selected !== option);
|
|
22984
23188
|
if (this.optionSelected.length === 0) {
|
|
22985
23189
|
this.optionSelected = undefined;
|
|
23190
|
+
this._selectedKey = undefined;
|
|
23191
|
+
this.value = undefined;
|
|
23192
|
+
} else {
|
|
23193
|
+
this._sortSelectedByDomOrder();
|
|
22986
23194
|
}
|
|
22987
23195
|
} else {
|
|
22988
23196
|
// For single-select: Back to undefined when deselected
|
|
22989
23197
|
this.value = undefined;
|
|
22990
23198
|
this.optionSelected = undefined;
|
|
23199
|
+
this._selectedKey = undefined;
|
|
22991
23200
|
}
|
|
22992
23201
|
|
|
22993
23202
|
// Update the index tracking
|
|
@@ -23011,9 +23220,38 @@ class AuroMenu extends AuroElement {
|
|
|
23011
23220
|
clearSelection() {
|
|
23012
23221
|
this.optionSelected = undefined;
|
|
23013
23222
|
this.value = undefined;
|
|
23223
|
+
this._selectedKey = undefined;
|
|
23014
23224
|
this._index = -1;
|
|
23015
23225
|
}
|
|
23016
23226
|
|
|
23227
|
+
/**
|
|
23228
|
+
* Re-sorts the multi-select selection into DOM order and rebuilds the derived
|
|
23229
|
+
* `_selectedKey` and `value` from `optionSelected`. Selection is always stored
|
|
23230
|
+
* and serialized in the order options appear in the menu, never in click
|
|
23231
|
+
* order — so selecting C then A yields `[A, C]`.
|
|
23232
|
+
* @private
|
|
23233
|
+
*/
|
|
23234
|
+
_sortSelectedByDomOrder() {
|
|
23235
|
+
if (!this.multiSelect || !Array.isArray(this.optionSelected) || !this.items) {
|
|
23236
|
+
return;
|
|
23237
|
+
}
|
|
23238
|
+
|
|
23239
|
+
const indexMap = new Map(this.items.map((item, index) => [
|
|
23240
|
+
item,
|
|
23241
|
+
index
|
|
23242
|
+
]));
|
|
23243
|
+
|
|
23244
|
+
// Sort any element no longer in `items` (a stale selection left over from a
|
|
23245
|
+
// dynamic rebuild that the consumer has not cleared) to the END rather than
|
|
23246
|
+
// the front, so it never displaces a live option to the head of the
|
|
23247
|
+
// serialized order. Value reconciliation drops it on the next updated() cycle.
|
|
23248
|
+
this.optionSelected.sort((optionA, optionB) => (indexMap.get(optionA) ?? this.items.length) - (indexMap.get(optionB) ?? this.items.length));
|
|
23249
|
+
this._selectedKey = this.optionSelected.map((option) => option._optionKey);
|
|
23250
|
+
this.value = serializeMultiSelectValue(this.optionSelected.map((option) => option.value));
|
|
23251
|
+
// Mark this `value` change as selection-driven so updated() trusts the keys.
|
|
23252
|
+
this._valueChangeFromSelection = true;
|
|
23253
|
+
}
|
|
23254
|
+
|
|
23017
23255
|
/**
|
|
23018
23256
|
* Resets the menu to its initial state.
|
|
23019
23257
|
* This is the only way to return value to undefined.
|
|
@@ -23023,6 +23261,7 @@ class AuroMenu extends AuroElement {
|
|
|
23023
23261
|
// Reset to undefined - initial state
|
|
23024
23262
|
this.value = undefined;
|
|
23025
23263
|
this.optionSelected = undefined;
|
|
23264
|
+
this._selectedKey = undefined;
|
|
23026
23265
|
this._index = -1;
|
|
23027
23266
|
|
|
23028
23267
|
// Clear active option state so a follow-up open/navigation starts fresh
|