@aurodesignsystem-dev/auro-formkit 0.0.0-pr1582.0 → 0.0.0-pr1582.2
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 +400 -62
- package/components/combobox/demo/getting-started.min.js +400 -62
- package/components/combobox/demo/index.html +1 -1
- package/components/combobox/demo/index.min.js +400 -62
- package/components/combobox/dist/index.js +78 -35
- package/components/combobox/dist/registered.js +78 -35
- package/components/counter/demo/customize.min.js +2 -2
- package/components/counter/demo/index.min.js +2 -2
- package/components/counter/dist/index.js +2 -2
- package/components/counter/dist/registered.js +2 -2
- package/components/datepicker/demo/customize.min.js +22 -9
- package/components/datepicker/demo/index.min.js +22 -9
- package/components/datepicker/dist/index.js +22 -9
- package/components/datepicker/dist/registered.js +22 -9
- package/components/dropdown/demo/customize.min.js +1 -1
- package/components/dropdown/demo/getting-started.min.js +21 -8
- 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 +448 -84
- package/components/form/demo/getting-started.min.js +448 -84
- package/components/form/demo/index.min.js +448 -84
- package/components/form/demo/registerDemoDeps.min.js +448 -84
- package/components/input/demo/customize.min.js +20 -7
- package/components/input/demo/getting-started.min.js +20 -7
- package/components/input/demo/index.min.js +20 -7
- package/components/input/dist/auro-input.d.ts +8 -0
- package/components/input/dist/index.js +20 -7
- package/components/input/dist/registered.js +20 -7
- package/components/menu/demo/customize.md +50 -0
- package/components/menu/demo/index.min.js +322 -27
- 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 +322 -27
- package/components/menu/dist/registered.js +322 -27
- 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 +324 -29
- package/components/select/demo/getting-started.min.js +324 -29
- package/components/select/demo/index.min.js +324 -29
- package/components/select/dist/index.js +2 -2
- package/components/select/dist/registered.js +2 -2
- package/custom-elements.json +115 -0
- package/package.json +1 -1
|
@@ -4836,7 +4836,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$2 {
|
|
|
4836
4836
|
}
|
|
4837
4837
|
};
|
|
4838
4838
|
|
|
4839
|
-
var formkitVersion$1 = '
|
|
4839
|
+
var formkitVersion$1 = '202608111845';
|
|
4840
4840
|
|
|
4841
4841
|
class AuroElement extends i$2 {
|
|
4842
4842
|
static get properties() {
|
|
@@ -6947,7 +6947,7 @@ class AuroHelpText extends i$2 {
|
|
|
6947
6947
|
}
|
|
6948
6948
|
}
|
|
6949
6949
|
|
|
6950
|
-
var formkitVersion = '
|
|
6950
|
+
var formkitVersion = '202608111845';
|
|
6951
6951
|
|
|
6952
6952
|
var styleCss$2 = i$5`.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}.body-default{font-size:var(--wcss-body-default-font-size, 1rem);font-weight:var(--wcss-body-default-weight, );line-height:var(--wcss-body-default-line-height, 1.5rem)}.body-default,.body-default-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-default-emphasized{font-size:var(--wcss-body-default-emphasized-font-size, 1rem);font-weight:var(--wcss-body-default-emphasized-weight, );line-height:var(--wcss-body-default-emphasized-line-height, 1.5rem)}.body-lg{font-size:var(--wcss-body-lg-font-size, 1.125rem);font-weight:var(--wcss-body-lg-weight, );line-height:var(--wcss-body-lg-line-height, 1.625rem)}.body-lg,.body-lg-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-lg-emphasized{font-size:var(--wcss-body-lg-emphasized-font-size, 1.125rem);font-weight:var(--wcss-body-lg-emphasized-weight, );line-height:var(--wcss-body-lg-emphasized-line-height, 1.625rem)}.body-sm{font-size:var(--wcss-body-sm-font-size, 0.875rem);font-weight:var(--wcss-body-sm-weight, );line-height:var(--wcss-body-sm-line-height, 1.25rem)}.body-sm,.body-sm-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-sm-emphasized{font-size:var(--wcss-body-sm-emphasized-font-size, 0.875rem);font-weight:var(--wcss-body-sm-emphasized-weight, );line-height:var(--wcss-body-sm-emphasized-line-height, 1.25rem)}.body-xs{font-size:var(--wcss-body-xs-font-size, 0.75rem);font-weight:var(--wcss-body-xs-weight, );line-height:var(--wcss-body-xs-line-height, 1rem)}.body-xs,.body-xs-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-xs-emphasized{font-size:var(--wcss-body-xs-emphasized-font-size, 0.75rem);font-weight:var(--wcss-body-xs-emphasized-weight, );line-height:var(--wcss-body-xs-emphasized-line-height, 1rem)}.body-2xs{font-size:var(--wcss-body-2xs-font-size, 0.625rem);font-weight:var(--wcss-body-2xs-weight, );line-height:var(--wcss-body-2xs-line-height, 0.875rem)}.body-2xs,.body-2xs-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-2xs-emphasized{font-size:var(--wcss-body-2xs-emphasized-font-size, 0.625rem);font-weight:var(--wcss-body-2xs-emphasized-weight, );line-height:var(--wcss-body-2xs-emphasized-line-height, 0.875rem)}.display-2xl{font-family:var(--wcss-display-2xl-family, "AS Circular"),var(--wcss-display-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-2xl-font-size, clamp(3.5rem, 6vw, 5.375rem));font-weight:var(--wcss-display-2xl-weight, 300);letter-spacing:var(--wcss-display-2xl-letter-spacing, 0);line-height:var(--wcss-display-2xl-line-height, 1.3)}.display-xl{font-family:var(--wcss-display-xl-family, "AS Circular"),var(--wcss-display-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-xl-font-size, clamp(3rem, 5.3333333333vw, 4.5rem));font-weight:var(--wcss-display-xl-weight, 300);letter-spacing:var(--wcss-display-xl-letter-spacing, 0);line-height:var(--wcss-display-xl-line-height, 1.3)}.display-lg{font-family:var(--wcss-display-lg-family, "AS Circular"),var(--wcss-display-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-lg-font-size, clamp(2.75rem, 4.6666666667vw, 4rem));font-weight:var(--wcss-display-lg-weight, 300);letter-spacing:var(--wcss-display-lg-letter-spacing, 0);line-height:var(--wcss-display-lg-line-height, 1.3)}.display-md{font-family:var(--wcss-display-md-family, "AS Circular"),var(--wcss-display-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-md-font-size, clamp(2.5rem, 4vw, 3.5rem));font-weight:var(--wcss-display-md-weight, 300);letter-spacing:var(--wcss-display-md-letter-spacing, 0);line-height:var(--wcss-display-md-line-height, 1.3)}.display-sm{font-family:var(--wcss-display-sm-family, "AS Circular"),var(--wcss-display-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-sm-font-size, clamp(2rem, 3.6666666667vw, 3rem));font-weight:var(--wcss-display-sm-weight, 300);letter-spacing:var(--wcss-display-sm-letter-spacing, 0);line-height:var(--wcss-display-sm-line-height, 1.3)}.display-xs{font-family:var(--wcss-display-xs-family, "AS Circular"),var(--wcss-display-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-xs-font-size, clamp(1.75rem, 3vw, 2.375rem));font-weight:var(--wcss-display-xs-weight, 300);letter-spacing:var(--wcss-display-xs-letter-spacing, 0);line-height:var(--wcss-display-xs-line-height, 1.3)}.heading-xl{font-family:var(--wcss-heading-xl-family, "AS Circular"),var(--wcss-heading-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-xl-font-size, clamp(2rem, 3vw, 2.5rem));font-weight:var(--wcss-heading-xl-weight, 300);letter-spacing:var(--wcss-heading-xl-letter-spacing, 0);line-height:var(--wcss-heading-xl-line-height, 1.3)}.heading-lg{font-family:var(--wcss-heading-lg-family, "AS Circular"),var(--wcss-heading-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-lg-font-size, clamp(1.75rem, 2.6666666667vw, 2.25rem));font-weight:var(--wcss-heading-lg-weight, 300);letter-spacing:var(--wcss-heading-lg-letter-spacing, 0);line-height:var(--wcss-heading-lg-line-height, 1.3)}.heading-md{font-family:var(--wcss-heading-md-family, "AS Circular"),var(--wcss-heading-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-md-font-size, clamp(1.625rem, 2.3333333333vw, 1.75rem));font-weight:var(--wcss-heading-md-weight, 300);letter-spacing:var(--wcss-heading-md-letter-spacing, 0);line-height:var(--wcss-heading-md-line-height, 1.3)}.heading-sm{font-family:var(--wcss-heading-sm-family, "AS Circular"),var(--wcss-heading-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-sm-font-size, clamp(1.375rem, 2vw, 1.5rem));font-weight:var(--wcss-heading-sm-weight, 300);letter-spacing:var(--wcss-heading-sm-letter-spacing, 0);line-height:var(--wcss-heading-sm-line-height, 1.3)}.heading-xs{font-family:var(--wcss-heading-xs-family, "AS Circular"),var(--wcss-heading-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-xs-font-size, clamp(1.25rem, 1.6666666667vw, 1.25rem));font-weight:var(--wcss-heading-xs-weight, 300);letter-spacing:var(--wcss-heading-xs-letter-spacing, 0);line-height:var(--wcss-heading-xs-line-height, 1.3)}.heading-2xs{font-family:var(--wcss-heading-2xs-family, "AS Circular"),var(--wcss-heading-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-2xs-font-size, clamp(1.125rem, 1.5vw, 1.125rem));font-weight:var(--wcss-heading-2xs-weight, 300);letter-spacing:var(--wcss-heading-2xs-letter-spacing, 0);line-height:var(--wcss-heading-2xs-line-height, 1.3)}.accent-2xl{font-family:var(--wcss-accent-2xl-family, "Good OT"),var(--wcss-accent-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-2xl-font-size, clamp(2rem, 3.1666666667vw, 2.375rem));font-weight:var(--wcss-accent-2xl-weight, 450);letter-spacing:var(--wcss-accent-2xl-letter-spacing, 0.05em);line-height:var(--wcss-accent-2xl-line-height, 1)}.accent-2xl,.accent-xl{text-transform:uppercase}.accent-xl{font-family:var(--wcss-accent-xl-family, "Good OT"),var(--wcss-accent-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-xl-font-size, clamp(1.625rem, 2.3333333333vw, 2rem));font-weight:var(--wcss-accent-xl-weight, 450);letter-spacing:var(--wcss-accent-xl-letter-spacing, 0.05em);line-height:var(--wcss-accent-xl-line-height, 1.3)}.accent-lg{font-family:var(--wcss-accent-lg-family, "Good OT"),var(--wcss-accent-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-lg-font-size, clamp(1.5rem, 2.1666666667vw, 1.75rem));font-weight:var(--wcss-accent-lg-weight, 450);letter-spacing:var(--wcss-accent-lg-letter-spacing, 0.05em);line-height:var(--wcss-accent-lg-line-height, 1.3)}.accent-lg,.accent-md{text-transform:uppercase}.accent-md{font-family:var(--wcss-accent-md-family, "Good OT"),var(--wcss-accent-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-md-font-size, clamp(1.375rem, 1.8333333333vw, 1.5rem));font-weight:var(--wcss-accent-md-weight, 500);letter-spacing:var(--wcss-accent-md-letter-spacing, 0.05em);line-height:var(--wcss-accent-md-line-height, 1.3)}.accent-sm{font-family:var(--wcss-accent-sm-family, "Good OT"),var(--wcss-accent-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-sm-font-size, clamp(1.125rem, 1.5vw, 1.25rem));font-weight:var(--wcss-accent-sm-weight, 500);letter-spacing:var(--wcss-accent-sm-letter-spacing, 0.05em);line-height:var(--wcss-accent-sm-line-height, 1.3)}.accent-sm,.accent-xs{text-transform:uppercase}.accent-xs{font-family:var(--wcss-accent-xs-family, "Good OT"),var(--wcss-accent-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-xs-font-size, clamp(1rem, 1.3333333333vw, 1rem));font-weight:var(--wcss-accent-xs-weight, 500);letter-spacing:var(--wcss-accent-xs-letter-spacing, 0.1em);line-height:var(--wcss-accent-xs-line-height, 1.3)}.accent-2xs{font-family:var(--wcss-accent-2xs-family, "Good OT"),var(--wcss-accent-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-2xs-font-size, clamp(0.875rem, 1.1666666667vw, 0.875rem));font-weight:var(--wcss-accent-2xs-weight, 450);letter-spacing:var(--wcss-accent-2xs-letter-spacing, 0.1em);line-height:var(--wcss-accent-2xs-line-height, 1.3);text-transform:uppercase}[auro-dropdown]{--ds-auro-dropdown-trigger-border-color: var(--ds-auro-select-border-color);--ds-auro-dropdown-trigger-background-color: var(--ds-auro-select-background-color);--ds-auro-dropdown-trigger-container-color: var(--ds-auro-select-background-color);--ds-auro-dropdown-trigger-outline-color: var(--ds-auro-select-outline-color)}:host{display:inline-block;text-align:left;vertical-align:top}:host([layout*=emphasized]) [auro-dropdown],:host([layout*=snowflake]) [auro-dropdown]{--ds-auro-select-border-color: transparent}:host([layout*=emphasized]) .mainContent,:host([layout*=snowflake]) .mainContent{text-align:center}.mainContent{position:relative;display:flex;overflow:hidden;flex:1;flex-direction:column;align-items:center;justify-content:center}.valueContainer{max-width:100%}.accents{display:flex;flex-direction:row;align-items:center;justify-content:center}::slotted([slot=typeIcon]){margin-right:var(--ds-size-100, 0.5rem)}.displayValue{display:block}.displayValue:not(.force){display:none}.displayValue:not(.force).hasContent:is(.withValue):not(.hasFocus){display:block}.triggerContent{display:flex;width:100%;box-sizing:border-box;align-items:center;justify-content:center}:host([layout*=emphasized]) .triggerContent{padding:0 var(--ds-size-100, 0.5rem) 0 var(--ds-size-300, 1.5rem)}:host([layout*=snowflake]) .triggerContent{padding:0 var(--ds-size-100, 0.5rem) 0 var(--ds-size-200, 1rem)}:host([layout*=snowflake]) label{padding-block:var(--ds-size-25, 0.125rem)}:host([layout*=classic]) .triggerContent{padding:0 var(--ds-size-100, 0.5rem)}:host([layout*=classic]) .mainContent{align-items:start}:host([layout*=classic]) label{overflow:hidden;cursor:text;text-overflow:ellipsis;white-space:nowrap}:host([layout*=classic]) .value{overflow:hidden;height:auto;text-overflow:ellipsis;white-space:nowrap}label{color:var(--ds-auro-select-label-text-color)}:host(:is([validity]:not([validity=valid]))) [auro-dropdown]{--ds-auro-select-border-color: var(--ds-basic-color-status-error, #e31f26);--ds-auro-select-outline-color: var(--ds-basic-color-status-error, #e31f26);--ds-auro-dropdown-helptext-text-color: var(--ds-basic-color-texticon-default, #2a2a2a)}:host([ondark]:is([validity]:not([validity=valid]))) [auro-dropdown],:host([appearance=inverse]:is([validity]:not([validity=valid]))) [auro-dropdown]{--ds-auro-select-border-color: var(--ds-advanced-color-state-error-inverse, #f9a4a8);--ds-auro-select-outline-color: var(--ds-advanced-color-state-error-inverse, #f9a4a8);--ds-auro-dropdown-helptext-text-color: var(--ds-basic-color-texticon-inverse, #ffffff)}#slotHolder{display:none}:host([fluid]){width:100%}:host([disabled]){pointer-events:none;user-select:none}:host([disabled]:not([ondark])) [auro-dropdown],:host([disabled]:not([appearance=inverse])) [auro-dropdown]{--ds-auro-select-border-color: var(--ds-basic-color-border-subtle, #dddddd)}:host(:not([layout*=classic])[disabled][ondark]) [auro-dropdown],:host(:not([layout*=classic])[disabled][appearance=inverse]) [auro-dropdown]{--ds-auro-select-border-color: transparent}`;
|
|
6953
6953
|
|
|
@@ -8778,6 +8778,116 @@ function isSelectableByValue(option) {
|
|
|
8778
8778
|
!option.hasAttribute('static');
|
|
8779
8779
|
}
|
|
8780
8780
|
|
|
8781
|
+
/* eslint-disable no-underscore-dangle */
|
|
8782
|
+
/**
|
|
8783
|
+
* Resolves the single selected option for a given `value`, preferring the
|
|
8784
|
+
* option tracked by `selectedKey` (a user-initiated selection) over a
|
|
8785
|
+
* first-by-value match. When multiple options share the same `value`, matching
|
|
8786
|
+
* by `value` alone cannot distinguish which one the user picked; the key
|
|
8787
|
+
* disambiguates it.
|
|
8788
|
+
*
|
|
8789
|
+
* The key is trusted only when it still resolves to an option whose `value`
|
|
8790
|
+
* matches the requested `value`. If the key is stale (option removed) or the
|
|
8791
|
+
* value was changed programmatically, resolution falls back to value matching —
|
|
8792
|
+
* preserving backward-compatible behavior for preselection and `selectByValue`.
|
|
8793
|
+
* @private
|
|
8794
|
+
* @param {Array<HTMLElement>} items - The menu's flat option list.
|
|
8795
|
+
* @param {string} value - The value to resolve.
|
|
8796
|
+
* @param {string|undefined} selectedKey - The `_optionKey` of the user-selected option, if any.
|
|
8797
|
+
* @returns {HTMLElement|undefined} The resolved option, or undefined when none match.
|
|
8798
|
+
*/
|
|
8799
|
+
function resolveSelectedOption(items, value, selectedKey) {
|
|
8800
|
+
if (!items) {
|
|
8801
|
+
return undefined;
|
|
8802
|
+
}
|
|
8803
|
+
|
|
8804
|
+
if (selectedKey !== undefined) {
|
|
8805
|
+
const keyed = items.find((item) => item._optionKey === selectedKey);
|
|
8806
|
+
if (keyed && isSelectableByValue(keyed) && keyed.value === value) {
|
|
8807
|
+
return keyed;
|
|
8808
|
+
}
|
|
8809
|
+
// Key exists but the option is gone or its value no longer matches — fall
|
|
8810
|
+
// through to value-based matching.
|
|
8811
|
+
}
|
|
8812
|
+
|
|
8813
|
+
return items.find((item) => isSelectableByValue(item) && item.value === value);
|
|
8814
|
+
}
|
|
8815
|
+
|
|
8816
|
+
/**
|
|
8817
|
+
* Resolves the selected options for a multi-select `value` array, preferring
|
|
8818
|
+
* options tracked by `selectedKeys` (user-initiated selections) and falling
|
|
8819
|
+
* back to value matching for any values not resolved by key. The result is
|
|
8820
|
+
* always sorted into DOM order regardless of selection sequence.
|
|
8821
|
+
* @private
|
|
8822
|
+
* @param {Array<HTMLElement>} items - The menu's flat option list.
|
|
8823
|
+
* @param {Array<string>} valueArray - The selected values.
|
|
8824
|
+
* @param {Array<string>|undefined} selectedKeys - The `_optionKey`s of the user-selected options, if any.
|
|
8825
|
+
* @returns {Array<HTMLElement>} The resolved options in DOM order.
|
|
8826
|
+
*/
|
|
8827
|
+
function resolveSelectedOptions(items, valueArray, selectedKeys) {
|
|
8828
|
+
if (!items) {
|
|
8829
|
+
return [];
|
|
8830
|
+
}
|
|
8831
|
+
|
|
8832
|
+
const resolved = [];
|
|
8833
|
+
// Mirror `resolved` as a Set for O(1) membership checks below, matching the
|
|
8834
|
+
// indexMap optimization used for the sort rather than scanning `resolved`
|
|
8835
|
+
// on every candidate.
|
|
8836
|
+
const resolvedSet = new Set();
|
|
8837
|
+
|
|
8838
|
+
// Track how many of each value are still available to resolve. A value that
|
|
8839
|
+
// appears N times in `valueArray` may be satisfied at most N times total across
|
|
8840
|
+
// the key pass and the value fallback below — matching by count, not presence,
|
|
8841
|
+
// on BOTH passes. This stops a duplicate value from being over-resolved: e.g.
|
|
8842
|
+
// two keyed options that both carry `SEA` cannot both match a single requested
|
|
8843
|
+
// `SEA` (which happens when `value` is set directly without clearing
|
|
8844
|
+
// `_selectedKey`, so more keys survive than the value set now asks for).
|
|
8845
|
+
const remaining = new Map();
|
|
8846
|
+
valueArray.forEach((val) => remaining.set(val, (remaining.get(val) || 0) + 1));
|
|
8847
|
+
|
|
8848
|
+
// Resolve by key first: trust a key only when its option is still selectable
|
|
8849
|
+
// and there is still an unmatched occurrence of its value in the request set.
|
|
8850
|
+
if (Array.isArray(selectedKeys)) {
|
|
8851
|
+
selectedKeys.forEach((key) => {
|
|
8852
|
+
const keyed = items.find((item) => item._optionKey === key);
|
|
8853
|
+
if (keyed && isSelectableByValue(keyed) && (remaining.get(keyed.value) || 0) > 0 && !resolvedSet.has(keyed)) {
|
|
8854
|
+
resolved.push(keyed);
|
|
8855
|
+
resolvedSet.add(keyed);
|
|
8856
|
+
remaining.set(keyed.value, remaining.get(keyed.value) - 1);
|
|
8857
|
+
}
|
|
8858
|
+
});
|
|
8859
|
+
}
|
|
8860
|
+
|
|
8861
|
+
// Fall back to value matching for the occurrences not resolved by key. Iterate
|
|
8862
|
+
// the leftover per-value counts so a value that appears twice but was only
|
|
8863
|
+
// resolved once by key still matches its remaining occurrence(s).
|
|
8864
|
+
remaining.forEach((count, val) => {
|
|
8865
|
+
for (let occurrence = 0; occurrence < count; occurrence += 1) {
|
|
8866
|
+
const option = items.find((item) => isSelectableByValue(item) && item.value === val && !resolvedSet.has(item));
|
|
8867
|
+
if (option) {
|
|
8868
|
+
resolved.push(option);
|
|
8869
|
+
resolvedSet.add(option);
|
|
8870
|
+
}
|
|
8871
|
+
}
|
|
8872
|
+
});
|
|
8873
|
+
|
|
8874
|
+
// Always return in DOM order so display is consistent regardless of the order
|
|
8875
|
+
// keys/values were selected. Every resolved option came from `items`, so an
|
|
8876
|
+
// O(1) index lookup mirrors `_sortSelectedByDomOrder` and avoids the O(n)
|
|
8877
|
+
// `items.indexOf` per comparison for large combobox option sets. Any element
|
|
8878
|
+
// not in `items` (a stale snapshot from a future caller) sorts to the END via
|
|
8879
|
+
// `?? items.length`, matching `_sortSelectedByDomOrder` and avoiding NaN
|
|
8880
|
+
// comparisons.
|
|
8881
|
+
const indexMap = new Map(items.map((item, index) => [
|
|
8882
|
+
item,
|
|
8883
|
+
index
|
|
8884
|
+
]));
|
|
8885
|
+
resolved.sort((optionA, optionB) => (indexMap.get(optionA) ?? items.length) - (indexMap.get(optionB) ?? items.length));
|
|
8886
|
+
|
|
8887
|
+
return resolved;
|
|
8888
|
+
}
|
|
8889
|
+
/* eslint-enable no-underscore-dangle */
|
|
8890
|
+
|
|
8781
8891
|
/**
|
|
8782
8892
|
* Helper method to dispatch custom events.
|
|
8783
8893
|
* @param {HTMLElement} element - Element to dispatch event from.
|
|
@@ -8803,6 +8913,14 @@ function dispatchMenuEvent(element, eventName, detail = null) {
|
|
|
8803
8913
|
// See LICENSE in the project root for license information.
|
|
8804
8914
|
|
|
8805
8915
|
|
|
8916
|
+
/**
|
|
8917
|
+
* Monotonically increasing counter used to give each menu instance a unique
|
|
8918
|
+
* `_menuInstanceId` prefix. Auto-generating the id (rather than using a random
|
|
8919
|
+
* string) keeps option keys deterministic and collision-free across menus.
|
|
8920
|
+
* @private
|
|
8921
|
+
*/
|
|
8922
|
+
let menuInstanceIdCounter = 0;
|
|
8923
|
+
|
|
8806
8924
|
|
|
8807
8925
|
/**
|
|
8808
8926
|
* The `auro-menu` element provides users a way to select from a list of options.
|
|
@@ -8874,9 +8992,8 @@ class AuroMenu extends AuroElement$1 {
|
|
|
8874
8992
|
|
|
8875
8993
|
// Instance properties (non-reactive)
|
|
8876
8994
|
|
|
8877
|
-
|
|
8878
|
-
|
|
8879
|
-
*/
|
|
8995
|
+
menuInstanceIdCounter += 1;
|
|
8996
|
+
|
|
8880
8997
|
Object.assign(this, {
|
|
8881
8998
|
// Root-level menu (true) or a nested submenu (false)
|
|
8882
8999
|
rootMenu: true,
|
|
@@ -8886,6 +9003,21 @@ class AuroMenu extends AuroElement$1 {
|
|
|
8886
9003
|
nestingSpacer: '<span class="nestingSpacer"></span>',
|
|
8887
9004
|
// Loading indicator for slot elements
|
|
8888
9005
|
loadingSlots: null,
|
|
9006
|
+
// Unique id for this menu instance; prefixes every auto-generated option
|
|
9007
|
+
// key so keys never collide across menus in the same document.
|
|
9008
|
+
_menuInstanceId: `menu-${menuInstanceIdCounter}`,
|
|
9009
|
+
// Monotonically increasing counter for option key generation. Never
|
|
9010
|
+
// resets, so a key is never reused within this instance's lifetime.
|
|
9011
|
+
_optionKeyCounter: 0,
|
|
9012
|
+
// Key(s) of the option(s) the user has actively selected. A single string
|
|
9013
|
+
// in single-select, an array in multi-select, undefined when nothing is
|
|
9014
|
+
// user-selected. Used to disambiguate options that share a `value`.
|
|
9015
|
+
_selectedKey: undefined,
|
|
9016
|
+
// True only for the one updated() cycle following a user selection, so
|
|
9017
|
+
// reconciliation trusts `_selectedKey`. A `value` change from a consumer's
|
|
9018
|
+
// direct property assignment leaves this false, dropping the stale key so
|
|
9019
|
+
// reconciliation falls back to first-by-value (see updated()).
|
|
9020
|
+
_valueChangeFromSelection: false,
|
|
8889
9021
|
});
|
|
8890
9022
|
}
|
|
8891
9023
|
|
|
@@ -9105,6 +9237,13 @@ class AuroMenu extends AuroElement$1 {
|
|
|
9105
9237
|
return;
|
|
9106
9238
|
}
|
|
9107
9239
|
|
|
9240
|
+
// A programmatic value set carries no positional intent, so drop any
|
|
9241
|
+
// `_selectedKey` left over from a prior user click. This makes reconciliation
|
|
9242
|
+
// in updated() fall back to first-by-value (single) / value-in-DOM-order
|
|
9243
|
+
// (multi), matching the documented contract for programmatic selection even
|
|
9244
|
+
// when a stale key would still resolve to a duplicate-value option.
|
|
9245
|
+
this._selectedKey = undefined;
|
|
9246
|
+
|
|
9108
9247
|
// `value` is a String property; stringify arrays so attribute reflection and `formattedValue` parsing stay correct.
|
|
9109
9248
|
this.value = Array.isArray(value) ? JSON.stringify(value) : value;
|
|
9110
9249
|
}
|
|
@@ -9152,6 +9291,17 @@ class AuroMenu extends AuroElement$1 {
|
|
|
9152
9291
|
updated(changedProperties) {
|
|
9153
9292
|
super.updated(changedProperties);
|
|
9154
9293
|
|
|
9294
|
+
// Consume the selection-driven flag for THIS cycle up front. Clearing it
|
|
9295
|
+
// unconditionally — not only inside the `value` branch below — prevents it
|
|
9296
|
+
// from lingering `true` when a selection produces a serialized `value`
|
|
9297
|
+
// byte-identical to the current one, in which case Lit schedules no
|
|
9298
|
+
// `value`-change cycle to consume it. A lingering flag would misclassify a
|
|
9299
|
+
// later consumer's programmatic `value` set as selection-driven and keep a
|
|
9300
|
+
// stale `_selectedKey`. The reconcile path below re-sets the instance flag
|
|
9301
|
+
// after this point, so its intentional cross-cycle hand-off still works.
|
|
9302
|
+
const valueChangeFromSelection = this._valueChangeFromSelection;
|
|
9303
|
+
this._valueChangeFromSelection = false;
|
|
9304
|
+
|
|
9155
9305
|
// Single source of truth for 'auroMenu-selectedOption'. Selection handlers
|
|
9156
9306
|
// mutate optionSelected and let Lit's update cycle dispatch here; the prior
|
|
9157
9307
|
// .value comparison missed multi-select array changes and combined with the
|
|
@@ -9175,6 +9325,17 @@ class AuroMenu extends AuroElement$1 {
|
|
|
9175
9325
|
this.initItems();
|
|
9176
9326
|
}
|
|
9177
9327
|
|
|
9328
|
+
// Distinguish a selection-driven `value` change (a user click, which set
|
|
9329
|
+
// the flag in handleSelectState / _sortSelectedByDomOrder) from a
|
|
9330
|
+
// programmatic assignment by a consumer. A programmatic set carries no
|
|
9331
|
+
// positional intent, so drop any leftover `_selectedKey` and let
|
|
9332
|
+
// reconciliation fall back to first-by-value (single) / value-in-DOM-order
|
|
9333
|
+
// (multi) — the same contract selectByValue() guarantees, even when a
|
|
9334
|
+
// stale key would otherwise still resolve to a duplicate-value option.
|
|
9335
|
+
if (!valueChangeFromSelection) {
|
|
9336
|
+
this._selectedKey = undefined;
|
|
9337
|
+
}
|
|
9338
|
+
|
|
9178
9339
|
// Set when reconciliation reassigns `value` below. That reassignment schedules a
|
|
9179
9340
|
// second updated() cycle, so the `event`-attribute dispatch is deferred to that
|
|
9180
9341
|
// cycle to avoid firing option custom events twice on the same selection.
|
|
@@ -9192,19 +9353,55 @@ class AuroMenu extends AuroElement$1 {
|
|
|
9192
9353
|
// Defensive default: `formattedValue` can be undefined for unexpected value types,
|
|
9193
9354
|
// and calling `.includes` on undefined would throw during reconciliation.
|
|
9194
9355
|
const valueArray = this.formattedValue || [];
|
|
9195
|
-
|
|
9356
|
+
// Resolve by key first (the user's exact picks), then fall back to
|
|
9357
|
+
// value matching for any values not resolved by key — so pre-selection
|
|
9358
|
+
// and programmatic value sets keep working. Result is DOM-ordered.
|
|
9359
|
+
const matchingOptions = resolveSelectedOptions(this.items, valueArray, this._selectedKey);
|
|
9196
9360
|
newSelected = matchingOptions.length > 0 ? matchingOptions : undefined;
|
|
9197
9361
|
|
|
9198
|
-
// Reconcile `value` with the selectable set.
|
|
9199
|
-
// loaded but
|
|
9200
|
-
//
|
|
9201
|
-
//
|
|
9202
|
-
//
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
|
|
9206
|
-
|
|
9207
|
-
|
|
9362
|
+
// Reconcile `value` with the selectable set. An occurrence is dropped
|
|
9363
|
+
// only when it is loaded but no selectable option can satisfy it —
|
|
9364
|
+
// every loaded item sharing that value is non-selectable, or the value
|
|
9365
|
+
// recurs more often than it has selectable options (a duplicate value
|
|
9366
|
+
// whose extra siblings are disabled/static). This is count-based, not
|
|
9367
|
+
// presence-based, so an enabled option is kept even when a disabled
|
|
9368
|
+
// sibling shares its value — mirroring how `resolveSelectedOptions`
|
|
9369
|
+
// resolves the same set. Entries with no matching item yet are
|
|
9370
|
+
// preserved so async preselection still works, and the toggle handlers
|
|
9371
|
+
// rebuild `value` from `formattedValue`, so a rejected entry cannot
|
|
9372
|
+
// resurface on the next select/deselect.
|
|
9373
|
+
const selectableByValue = new Map();
|
|
9374
|
+
const loadedValues = new Set();
|
|
9375
|
+
if (this.items) {
|
|
9376
|
+
this.items.forEach((item) => {
|
|
9377
|
+
loadedValues.add(item.value);
|
|
9378
|
+
if (isSelectableByValue(item)) {
|
|
9379
|
+
selectableByValue.set(item.value, (selectableByValue.get(item.value) || 0) + 1);
|
|
9380
|
+
}
|
|
9381
|
+
});
|
|
9382
|
+
}
|
|
9383
|
+
|
|
9384
|
+
const reconciled = valueArray.filter((val) => {
|
|
9385
|
+
// Not loaded yet (async preselection) — keep for a later cycle.
|
|
9386
|
+
if (!loadedValues.has(val)) {
|
|
9387
|
+
return true;
|
|
9388
|
+
}
|
|
9389
|
+
// Consume one selectable option per occurrence; drop once exhausted.
|
|
9390
|
+
const remaining = selectableByValue.get(val) || 0;
|
|
9391
|
+
if (remaining > 0) {
|
|
9392
|
+
selectableByValue.set(val, remaining - 1);
|
|
9393
|
+
return true;
|
|
9394
|
+
}
|
|
9395
|
+
return false;
|
|
9396
|
+
});
|
|
9397
|
+
|
|
9398
|
+
if (reconciled.length !== valueArray.length) {
|
|
9399
|
+
// This is an internal correction, not a consumer's programmatic set,
|
|
9400
|
+
// so preserve the selection-driven flag through the re-entrant
|
|
9401
|
+
// updated() cycle it schedules. Otherwise that cycle would treat the
|
|
9402
|
+
// reassignment as programmatic and drop `_selectedKey` mid-cascade,
|
|
9403
|
+
// flipping resolution and looping.
|
|
9404
|
+
this._valueChangeFromSelection = true;
|
|
9208
9405
|
this.value = serializeMultiSelectValue(reconciled);
|
|
9209
9406
|
valueReconciled = true;
|
|
9210
9407
|
}
|
|
@@ -9216,7 +9413,11 @@ class AuroMenu extends AuroElement$1 {
|
|
|
9216
9413
|
// `hidden` is intentionally NOT excluded: the combobox toggles
|
|
9217
9414
|
// `hidden` as its type-ahead filter, so a filtered-out option is
|
|
9218
9415
|
// still a valid programmatic selection.
|
|
9219
|
-
|
|
9416
|
+
// Prefer the option the user actually selected (tracked by
|
|
9417
|
+
// `_selectedKey`) so a click on the second of two options sharing a
|
|
9418
|
+
// `value` resolves back to that exact element instead of the first
|
|
9419
|
+
// value match. Falls back to first-by-value for programmatic sets.
|
|
9420
|
+
const matchingOption = resolveSelectedOption(this.items, this.value, this._selectedKey);
|
|
9220
9421
|
|
|
9221
9422
|
if (matchingOption) {
|
|
9222
9423
|
newSelected = matchingOption;
|
|
@@ -9444,6 +9645,14 @@ class AuroMenu extends AuroElement$1 {
|
|
|
9444
9645
|
}
|
|
9445
9646
|
});
|
|
9446
9647
|
|
|
9648
|
+
// Assign private keys once items are populated. Only the root menu assigns
|
|
9649
|
+
// keys: its `items` is a deep query that already includes nested submenu
|
|
9650
|
+
// options, so a single pass keys the entire tree. Nested menus skip this
|
|
9651
|
+
// and inherit keys from the root.
|
|
9652
|
+
if (this.rootMenu) {
|
|
9653
|
+
this._assignOptionKeys();
|
|
9654
|
+
}
|
|
9655
|
+
|
|
9447
9656
|
if (this.noCheckmark) {
|
|
9448
9657
|
this.updateItemsState(new Map([
|
|
9449
9658
|
[
|
|
@@ -9460,6 +9669,31 @@ class AuroMenu extends AuroElement$1 {
|
|
|
9460
9669
|
}));
|
|
9461
9670
|
}
|
|
9462
9671
|
|
|
9672
|
+
/**
|
|
9673
|
+
* Assigns a private, auto-generated unique key (`_optionKey`) to each menu
|
|
9674
|
+
* option that does not already have one. Keys are internal state on the
|
|
9675
|
+
* element instance — never reflected as an attribute or exposed publicly —
|
|
9676
|
+
* and let selection tracking distinguish options that share the same `value`.
|
|
9677
|
+
*
|
|
9678
|
+
* The `_optionKey === undefined` guard makes this idempotent: options keep the
|
|
9679
|
+
* key they were first assigned across re-renders and slot changes, and if a
|
|
9680
|
+
* nested menu's lifecycle runs a pass before the root, options simply wait for
|
|
9681
|
+
* the root to key them (or keep whatever key they already hold).
|
|
9682
|
+
* @private
|
|
9683
|
+
*/
|
|
9684
|
+
_assignOptionKeys() {
|
|
9685
|
+
if (!this.items) {
|
|
9686
|
+
return;
|
|
9687
|
+
}
|
|
9688
|
+
|
|
9689
|
+
this.items.forEach((option) => {
|
|
9690
|
+
if (option._optionKey === undefined) {
|
|
9691
|
+
this._optionKeyCounter += 1;
|
|
9692
|
+
option._optionKey = `${this._menuInstanceId}-${this._optionKeyCounter}`;
|
|
9693
|
+
}
|
|
9694
|
+
});
|
|
9695
|
+
}
|
|
9696
|
+
|
|
9463
9697
|
// Logic Methods
|
|
9464
9698
|
|
|
9465
9699
|
/**
|
|
@@ -9469,24 +9703,28 @@ class AuroMenu extends AuroElement$1 {
|
|
|
9469
9703
|
*/
|
|
9470
9704
|
handleSelectState(option) {
|
|
9471
9705
|
if (this.multiSelect) {
|
|
9472
|
-
const currentValue = this.formattedValue || [];
|
|
9473
9706
|
const currentSelected = this.optionSelected || [];
|
|
9474
9707
|
|
|
9475
|
-
if (!currentValue.includes(option.value)) {
|
|
9476
|
-
this.value = serializeMultiSelectValue([
|
|
9477
|
-
...currentValue,
|
|
9478
|
-
option.value
|
|
9479
|
-
]);
|
|
9480
|
-
}
|
|
9481
9708
|
if (!currentSelected.includes(option)) {
|
|
9482
9709
|
this.optionSelected = [
|
|
9483
9710
|
...currentSelected,
|
|
9484
9711
|
option
|
|
9485
9712
|
];
|
|
9486
9713
|
}
|
|
9714
|
+
|
|
9715
|
+
// Re-sort by DOM order and rebuild `_selectedKey`/`value` from the
|
|
9716
|
+
// selected set so display order stays consistent with the menu, not with
|
|
9717
|
+
// click order.
|
|
9718
|
+
this._sortSelectedByDomOrder();
|
|
9487
9719
|
} else {
|
|
9488
9720
|
this.value = option.value;
|
|
9489
9721
|
this.optionSelected = option;
|
|
9722
|
+
// Track the specific option the user selected so the value→option
|
|
9723
|
+
// reconciliation in updated() resolves back to this exact element even
|
|
9724
|
+
// when another option shares the same `value`.
|
|
9725
|
+
this._selectedKey = option._optionKey;
|
|
9726
|
+
// Mark this `value` change as selection-driven so updated() trusts the key.
|
|
9727
|
+
this._valueChangeFromSelection = true;
|
|
9490
9728
|
}
|
|
9491
9729
|
|
|
9492
9730
|
this._index = this.items.indexOf(option);
|
|
@@ -9499,18 +9737,22 @@ class AuroMenu extends AuroElement$1 {
|
|
|
9499
9737
|
*/
|
|
9500
9738
|
handleDeselectState(option) {
|
|
9501
9739
|
if (this.multiSelect) {
|
|
9502
|
-
// Remove this
|
|
9503
|
-
|
|
9504
|
-
|
|
9505
|
-
|
|
9506
|
-
this.optionSelected = this.optionSelected.filter((val) => val !== option);
|
|
9740
|
+
// Remove this exact element from the selection (identity, not value — two
|
|
9741
|
+
// options can share a `value`), then rebuild `value`/`_selectedKey` from
|
|
9742
|
+
// the remaining set in DOM order. An empty result collapses to undefined.
|
|
9743
|
+
this.optionSelected = this.optionSelected.filter((selected) => selected !== option);
|
|
9507
9744
|
if (this.optionSelected.length === 0) {
|
|
9508
9745
|
this.optionSelected = undefined;
|
|
9746
|
+
this._selectedKey = undefined;
|
|
9747
|
+
this.value = undefined;
|
|
9748
|
+
} else {
|
|
9749
|
+
this._sortSelectedByDomOrder();
|
|
9509
9750
|
}
|
|
9510
9751
|
} else {
|
|
9511
9752
|
// For single-select: Back to undefined when deselected
|
|
9512
9753
|
this.value = undefined;
|
|
9513
9754
|
this.optionSelected = undefined;
|
|
9755
|
+
this._selectedKey = undefined;
|
|
9514
9756
|
}
|
|
9515
9757
|
|
|
9516
9758
|
// Update the index tracking
|
|
@@ -9534,9 +9776,46 @@ class AuroMenu extends AuroElement$1 {
|
|
|
9534
9776
|
clearSelection() {
|
|
9535
9777
|
this.optionSelected = undefined;
|
|
9536
9778
|
this.value = undefined;
|
|
9779
|
+
this._selectedKey = undefined;
|
|
9537
9780
|
this._index = -1;
|
|
9538
9781
|
}
|
|
9539
9782
|
|
|
9783
|
+
/**
|
|
9784
|
+
* Re-sorts the multi-select selection into DOM order and rebuilds the derived
|
|
9785
|
+
* `_selectedKey` and `value` from `optionSelected`. Selection is always stored
|
|
9786
|
+
* and serialized in the order options appear in the menu, never in click
|
|
9787
|
+
* order — so selecting C then A yields `[A, C]`.
|
|
9788
|
+
* @private
|
|
9789
|
+
*/
|
|
9790
|
+
_sortSelectedByDomOrder() {
|
|
9791
|
+
if (!this.multiSelect || !Array.isArray(this.optionSelected) || !this.items) {
|
|
9792
|
+
return;
|
|
9793
|
+
}
|
|
9794
|
+
|
|
9795
|
+
const indexMap = new Map(this.items.map((item, index) => [
|
|
9796
|
+
item,
|
|
9797
|
+
index
|
|
9798
|
+
]));
|
|
9799
|
+
|
|
9800
|
+
// Sorting in place mutates `optionSelected` without a new array reference,
|
|
9801
|
+
// which Lit's `===` change-detection cannot see on its own — but that is
|
|
9802
|
+
// intentional and safe: both callers (handleSelectState / handleDeselectState)
|
|
9803
|
+
// assign a fresh `optionSelected` array immediately before calling, so Lit
|
|
9804
|
+
// already has a changed reference to react to, and the `value` write below
|
|
9805
|
+
// schedules the updated() cycle that re-derives `optionSelected` in DOM order
|
|
9806
|
+
// via resolveSelectedOptions. Do not "fix" this into a new-array assignment.
|
|
9807
|
+
//
|
|
9808
|
+
// Sort any element no longer in `items` (a stale selection left over from a
|
|
9809
|
+
// dynamic rebuild that the consumer has not cleared) to the END rather than
|
|
9810
|
+
// the front, so it never displaces a live option to the head of the
|
|
9811
|
+
// serialized order. Value reconciliation drops it on the next updated() cycle.
|
|
9812
|
+
this.optionSelected.sort((optionA, optionB) => (indexMap.get(optionA) ?? this.items.length) - (indexMap.get(optionB) ?? this.items.length));
|
|
9813
|
+
this._selectedKey = this.optionSelected.map((option) => option._optionKey);
|
|
9814
|
+
this.value = serializeMultiSelectValue(this.optionSelected.map((option) => option.value));
|
|
9815
|
+
// Mark this `value` change as selection-driven so updated() trusts the keys.
|
|
9816
|
+
this._valueChangeFromSelection = true;
|
|
9817
|
+
}
|
|
9818
|
+
|
|
9540
9819
|
/**
|
|
9541
9820
|
* Resets the menu to its initial state.
|
|
9542
9821
|
* This is the only way to return value to undefined.
|
|
@@ -9546,6 +9825,7 @@ class AuroMenu extends AuroElement$1 {
|
|
|
9546
9825
|
// Reset to undefined - initial state
|
|
9547
9826
|
this.value = undefined;
|
|
9548
9827
|
this.optionSelected = undefined;
|
|
9828
|
+
this._selectedKey = undefined;
|
|
9549
9829
|
this._index = -1;
|
|
9550
9830
|
|
|
9551
9831
|
// Clear active option state so a follow-up open/navigation starts fresh
|
|
@@ -9607,6 +9887,21 @@ class AuroMenu extends AuroElement$1 {
|
|
|
9607
9887
|
this.initItems();
|
|
9608
9888
|
}
|
|
9609
9889
|
|
|
9890
|
+
// Recover `_index` from the highlighted option when it has been reset to -1.
|
|
9891
|
+
// The updated() reconciliation resets `_index = -1` whenever the value
|
|
9892
|
+
// collapses to undefined while `optionActive` still points at the highlighted
|
|
9893
|
+
// option — e.g. deselecting the last remaining option in multi-select, or a
|
|
9894
|
+
// programmatic clearSelection() in single-select while keyboard focus is on an
|
|
9895
|
+
// option. Without this, reading `items[-1]` returns undefined and the re-select
|
|
9896
|
+
// no-ops until the highlight is moved away and back. Mirrors auro-combobox's
|
|
9897
|
+
// reconcileMenuIndex.
|
|
9898
|
+
if (this._index < 0 && this.optionActive && this.items) {
|
|
9899
|
+
const activeIndex = this.items.indexOf(this.optionActive);
|
|
9900
|
+
if (activeIndex >= 0) {
|
|
9901
|
+
this._index = activeIndex;
|
|
9902
|
+
}
|
|
9903
|
+
}
|
|
9904
|
+
|
|
9610
9905
|
// Get currently selected menu option based on index
|
|
9611
9906
|
const option = this.items ? this.items[this._index] : undefined;
|
|
9612
9907
|
|