@aurodesignsystem/auro-formkit 2.0.0-beta.10 → 2.0.0-beta.12
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/.turbo/cache/0c8124a987c1cc05-meta.json +1 -1
- package/.turbo/cache/0cd512cdf86242c7-meta.json +1 -0
- package/.turbo/cache/0cd512cdf86242c7.tar.zst +0 -0
- package/.turbo/cache/123c83cd8727dff3-meta.json +1 -0
- package/.turbo/cache/123c83cd8727dff3.tar.zst +0 -0
- package/.turbo/cache/18129dba20f51b6b-meta.json +1 -1
- package/.turbo/cache/2787020e69f50af2-meta.json +1 -1
- package/.turbo/cache/2a5295c8f561ed84-meta.json +1 -0
- package/.turbo/cache/2c0d681132c153dd-meta.json +1 -1
- package/.turbo/cache/4006a206400d5c7b-meta.json +1 -1
- package/.turbo/cache/492dda333b8d15f1-meta.json +1 -1
- package/.turbo/cache/4e3619d9dfc86809-meta.json +1 -0
- package/.turbo/cache/4e3619d9dfc86809.tar.zst +0 -0
- package/.turbo/cache/50993de942ec15a9-meta.json +1 -1
- package/.turbo/cache/50cd7dcfc9f820c5-meta.json +1 -0
- package/.turbo/cache/50cd7dcfc9f820c5.tar.zst +0 -0
- package/.turbo/cache/51eaa58d5c167de8-meta.json +1 -1
- package/.turbo/cache/5a0d3e26da304c62-meta.json +1 -0
- package/.turbo/cache/5a0d3e26da304c62.tar.zst +0 -0
- package/.turbo/cache/5c960af698582835-meta.json +1 -0
- package/.turbo/cache/5c960af698582835.tar.zst +0 -0
- package/.turbo/cache/5dbbb71dffc3f542-meta.json +1 -0
- package/.turbo/cache/5dbbb71dffc3f542.tar.zst +0 -0
- package/.turbo/cache/6081837e8943b62e-meta.json +1 -1
- package/.turbo/cache/60ad74320c682a2b-meta.json +1 -1
- package/.turbo/cache/61e218aba69cff58-meta.json +1 -1
- package/.turbo/cache/77da375a012de9d0-meta.json +1 -1
- package/.turbo/cache/7964d1656e9e702a-meta.json +1 -0
- package/.turbo/cache/7964d1656e9e702a.tar.zst +0 -0
- package/.turbo/cache/7bf2b06a479d0b30-meta.json +1 -1
- package/.turbo/cache/7c9ca6163e61285c-meta.json +1 -1
- package/.turbo/cache/80aca269cd346fb4-meta.json +1 -0
- package/.turbo/cache/80aca269cd346fb4.tar.zst +0 -0
- package/.turbo/cache/8602fc2bb737a5cf-meta.json +1 -0
- package/.turbo/cache/89e0e7a6148e854f-meta.json +1 -0
- package/.turbo/cache/{83a167e135cb431a.tar.zst → 89e0e7a6148e854f.tar.zst} +0 -0
- package/.turbo/cache/8bb856bd31b5b479-meta.json +1 -1
- package/.turbo/cache/93c887fb93a10daa-meta.json +1 -0
- package/.turbo/cache/93c887fb93a10daa.tar.zst +0 -0
- package/.turbo/cache/94dae2a64e9d8356-meta.json +1 -0
- package/.turbo/cache/97f6fe83b54acf09-meta.json +1 -0
- package/.turbo/cache/97f6fe83b54acf09.tar.zst +0 -0
- package/.turbo/cache/98317b0d14d94df7-meta.json +1 -0
- package/.turbo/cache/98317b0d14d94df7.tar.zst +0 -0
- package/.turbo/cache/98fc8a56e3e13790-meta.json +1 -0
- package/.turbo/cache/98fc8a56e3e13790.tar.zst +0 -0
- package/.turbo/cache/9ae99e8e7bd83d06-meta.json +1 -1
- package/.turbo/cache/9cbcd13b1d031f63-meta.json +1 -0
- package/.turbo/cache/{8af27c076dc010c3.tar.zst → 9cbcd13b1d031f63.tar.zst} +0 -0
- package/.turbo/cache/afbbd49ed1a558b9-meta.json +1 -0
- package/.turbo/cache/b353ce8f6da43dea-meta.json +1 -0
- package/.turbo/cache/b5e6dc7fb9ae1a2f-meta.json +1 -1
- package/.turbo/cache/b6a202cc85cb61a0-meta.json +1 -1
- package/.turbo/cache/b8db059a9b9ccb5d-meta.json +1 -0
- package/.turbo/cache/bc24a38aa1b1a102-meta.json +1 -0
- package/.turbo/cache/be0b95293ea517cc-meta.json +1 -1
- package/.turbo/cache/c3a4f7a3565d6706-meta.json +1 -0
- package/.turbo/cache/c3a4f7a3565d6706.tar.zst +0 -0
- package/.turbo/cache/c44efc9e4ddd8a0e-meta.json +1 -1
- package/.turbo/cache/c6c6411199b68170-meta.json +1 -1
- package/.turbo/cache/c97b043e748e3580-meta.json +1 -0
- package/.turbo/cache/d5db503b2eaf239c-meta.json +1 -1
- package/.turbo/cache/d775555355d6b8fc-meta.json +1 -1
- package/.turbo/cache/d7c3007be148d2a1-meta.json +1 -1
- package/.turbo/cache/dad3d78b33edd9e4-meta.json +1 -1
- package/.turbo/cache/dc597b3ea4f61ec8-meta.json +1 -0
- package/.turbo/cache/dc597b3ea4f61ec8.tar.zst +0 -0
- package/.turbo/cache/df40b180126e5351-meta.json +1 -0
- package/.turbo/cache/{50a29c70b93c57dd.tar.zst → df40b180126e5351.tar.zst} +0 -0
- package/.turbo/cache/e5f217f77c32c93b-meta.json +1 -0
- package/.turbo/cache/e5f217f77c32c93b.tar.zst +0 -0
- package/.turbo/cache/e62cfee068e3ef36-meta.json +1 -1
- package/.turbo/cache/e9e36823f6c98f07-meta.json +1 -1
- package/.turbo/cache/ee1a3c1fe389da51-meta.json +1 -0
- package/.turbo/cache/f3c7b40f2c6a4094-meta.json +1 -0
- package/.turbo/cache/{b22ca87b2f7f9cc2.tar.zst → f3c7b40f2c6a4094.tar.zst} +0 -0
- package/.turbo/cache/f5958c3acb889631-meta.json +1 -0
- package/.turbo/cache/fb3809ac3f90e3b2-meta.json +1 -0
- package/.turbo/cache/{eb1dbe885532c1dc.tar.zst → fb3809ac3f90e3b2.tar.zst} +0 -0
- package/.turbo/cache/fd5ddfa43ebd8e5c-meta.json +1 -0
- package/.turbo/cache/fd5ddfa43ebd8e5c.tar.zst +0 -0
- package/CHANGELOG.md +25 -0
- package/components/checkbox/.turbo/turbo-build.log +3 -3
- package/components/checkbox/.turbo/turbo-bundler.log +3 -3
- package/components/checkbox/README.md +1 -1
- package/components/combobox/.turbo/turbo-build.log +3 -3
- package/components/combobox/README.md +4 -4
- package/components/combobox/demo/api.md +22 -21
- package/components/combobox/demo/api.min.js +2532 -655
- package/components/combobox/demo/index.min.js +2529 -652
- package/components/combobox/dist/auro-combobox.d.ts +70 -80
- package/components/combobox/dist/auro-combobox.d.ts.map +1 -1
- package/components/combobox/dist/index.js +1836 -274
- package/components/combobox/src/auro-combobox.js +156 -101
- package/components/counter/.turbo/turbo-build.log +3 -3
- package/components/counter/.turbo/turbo-bundler.log +3 -3
- package/components/counter/README.md +1 -1
- package/components/datepicker/.turbo/turbo-build.log +3 -3
- package/components/datepicker/README.md +4 -4
- package/components/dropdown/.turbo/turbo-build.log +3 -3
- package/components/dropdown/.turbo/turbo-bundler.log +3 -3
- package/components/dropdown/README.md +1 -1
- package/components/form/.turbo/turbo-build.log +3 -3
- package/components/form/.turbo/turbo-bundler.log +3 -3
- package/components/form/README.md +1 -1
- package/components/input/.turbo/turbo-build.log +3 -3
- package/components/input/.turbo/turbo-bundler.log +3 -3
- package/components/input/README.md +1 -1
- package/components/menu/.turbo/turbo-build.log +5 -3
- package/components/menu/.turbo/turbo-bundler.log +3 -3
- package/components/menu/README.md +1 -1
- package/components/menu/demo/api.md +57 -20
- package/components/menu/demo/api.min.js +620 -305
- package/components/menu/demo/index.min.js +618 -303
- package/components/menu/dist/auro-menu-utils.d.ts +43 -0
- package/components/menu/dist/auro-menu-utils.d.ts.map +1 -0
- package/components/menu/dist/auro-menu.d.ts +97 -81
- package/components/menu/dist/auro-menu.d.ts.map +1 -1
- package/components/menu/dist/index.d.ts +1 -0
- package/components/menu/dist/index.js +619 -304
- package/components/menu/src/auro-menu-utils.js +131 -0
- package/components/menu/src/auro-menu.js +493 -303
- package/components/menu/src/index.js +7 -0
- package/components/radio/.turbo/turbo-build.log +3 -3
- package/components/radio/.turbo/turbo-bundler.log +3 -3
- package/components/radio/README.md +1 -1
- package/components/select/.turbo/turbo-build.log +5 -3
- package/components/select/README.md +3 -3
- package/components/select/demo/api.md +46 -11
- package/components/select/demo/api.min.js +2336 -485
- package/components/select/demo/index.min.js +2337 -486
- package/components/select/dist/auro-select.d.ts +17 -6
- package/components/select/dist/auro-select.d.ts.map +1 -1
- package/components/select/dist/index.js +1706 -170
- package/components/select/src/auro-select.js +53 -24
- package/components/select/src/styles/style-css.js +1 -1
- package/components/select/src/styles/style.css +7 -0
- package/components/select/src/styles/style.scss +13 -0
- package/package.json +1 -1
- package/.turbo/cache/026e4d886ba97e63-meta.json +0 -1
- package/.turbo/cache/026e4d886ba97e63.tar.zst +0 -0
- package/.turbo/cache/080ca6155e637d5d-meta.json +0 -1
- package/.turbo/cache/080ca6155e637d5d.tar.zst +0 -0
- package/.turbo/cache/0b115e30ff606299-meta.json +0 -1
- package/.turbo/cache/0b115e30ff606299.tar.zst +0 -0
- package/.turbo/cache/1c630fb3411e4a41-meta.json +0 -1
- package/.turbo/cache/24b19ac5895e5dd6-meta.json +0 -1
- package/.turbo/cache/24b19ac5895e5dd6.tar.zst +0 -0
- package/.turbo/cache/29b72c73cbccb53d-meta.json +0 -1
- package/.turbo/cache/29b72c73cbccb53d.tar.zst +0 -0
- package/.turbo/cache/3e647c5863d32e6f-meta.json +0 -1
- package/.turbo/cache/3e647c5863d32e6f.tar.zst +0 -0
- package/.turbo/cache/43f5206cc4e69b44-meta.json +0 -1
- package/.turbo/cache/4a85ec226b585fd5-meta.json +0 -1
- package/.turbo/cache/50a29c70b93c57dd-meta.json +0 -1
- package/.turbo/cache/56455145cd768755-meta.json +0 -1
- package/.turbo/cache/56455145cd768755.tar.zst +0 -0
- package/.turbo/cache/5c06332cf9f132da-meta.json +0 -1
- package/.turbo/cache/5e613afc6868d0e2-meta.json +0 -1
- package/.turbo/cache/5e613afc6868d0e2.tar.zst +0 -0
- package/.turbo/cache/639dac15b979bedc-meta.json +0 -1
- package/.turbo/cache/664c2e08614fd212-meta.json +0 -1
- package/.turbo/cache/6c51b0ebfc086faa-meta.json +0 -1
- package/.turbo/cache/6c51b0ebfc086faa.tar.zst +0 -0
- package/.turbo/cache/7216d994164825fb-meta.json +0 -1
- package/.turbo/cache/7216d994164825fb.tar.zst +0 -0
- package/.turbo/cache/83a167e135cb431a-meta.json +0 -1
- package/.turbo/cache/8af27c076dc010c3-meta.json +0 -1
- package/.turbo/cache/953c8216249d3509-meta.json +0 -1
- package/.turbo/cache/95a5e76ffd8c5110-meta.json +0 -1
- package/.turbo/cache/95a5e76ffd8c5110.tar.zst +0 -0
- package/.turbo/cache/a8b0fa0a9aa707c5-meta.json +0 -1
- package/.turbo/cache/a8b0fa0a9aa707c5.tar.zst +0 -0
- package/.turbo/cache/b22ca87b2f7f9cc2-meta.json +0 -1
- package/.turbo/cache/b7bbe2e7d44b77f0-meta.json +0 -1
- package/.turbo/cache/b7bbe2e7d44b77f0.tar.zst +0 -0
- package/.turbo/cache/c2b51643f886a493-meta.json +0 -1
- package/.turbo/cache/c2b51643f886a493.tar.zst +0 -0
- package/.turbo/cache/c74d369a0475b124-meta.json +0 -1
- package/.turbo/cache/c7f5a276ddb73cf7-meta.json +0 -1
- package/.turbo/cache/c96933d40404e4c8-meta.json +0 -1
- package/.turbo/cache/c96933d40404e4c8.tar.zst +0 -0
- package/.turbo/cache/eb1dbe885532c1dc-meta.json +0 -1
- package/.turbo/cache/f1f6744948f1b18f-meta.json +0 -1
- package/.turbo/cache/f1f6744948f1b18f.tar.zst +0 -0
- package/.turbo/cache/feefbc25d550c1cd-meta.json +0 -1
- package/.turbo/cache/ff4dbfffc29255ab-meta.json +0 -1
- package/.turbo/cache/ff4dbfffc29255ab.tar.zst +0 -0
- /package/.turbo/cache/{639dac15b979bedc.tar.zst → 2a5295c8f561ed84.tar.zst} +0 -0
- /package/.turbo/cache/{1c630fb3411e4a41.tar.zst → 8602fc2bb737a5cf.tar.zst} +0 -0
- /package/.turbo/cache/{664c2e08614fd212.tar.zst → 94dae2a64e9d8356.tar.zst} +0 -0
- /package/.turbo/cache/{c7f5a276ddb73cf7.tar.zst → afbbd49ed1a558b9.tar.zst} +0 -0
- /package/.turbo/cache/{43f5206cc4e69b44.tar.zst → b353ce8f6da43dea.tar.zst} +0 -0
- /package/.turbo/cache/{c74d369a0475b124.tar.zst → b8db059a9b9ccb5d.tar.zst} +0 -0
- /package/.turbo/cache/{4a85ec226b585fd5.tar.zst → bc24a38aa1b1a102.tar.zst} +0 -0
- /package/.turbo/cache/{5c06332cf9f132da.tar.zst → c97b043e748e3580.tar.zst} +0 -0
- /package/.turbo/cache/{953c8216249d3509.tar.zst → ee1a3c1fe389da51.tar.zst} +0 -0
- /package/.turbo/cache/{feefbc25d550c1cd.tar.zst → f5958c3acb889631.tar.zst} +0 -0
|
@@ -10,23 +10,32 @@ import colorCss from "./styles/color-menu-css.js";
|
|
|
10
10
|
import tokensCss from "./styles/tokens-css.js";
|
|
11
11
|
|
|
12
12
|
import AuroLibraryRuntimeUtils from '@aurodesignsystem/auro-library/scripts/utils/runtimeUtils.mjs';
|
|
13
|
+
import {
|
|
14
|
+
arrayOrUndefinedHasChanged,
|
|
15
|
+
isOptionInteractive,
|
|
16
|
+
dispatchMenuEvent,
|
|
17
|
+
arrayConverter
|
|
18
|
+
} from './auro-menu-utils.js';
|
|
19
|
+
|
|
13
20
|
|
|
14
21
|
// See https://git.io/JJ6SJ for "How to document your components using JSDoc"
|
|
15
22
|
/**
|
|
16
23
|
* The auro-menu element provides users a way to select from a list of options.
|
|
17
|
-
* @attr {
|
|
18
|
-
* @attr {
|
|
19
|
-
* @attr {
|
|
20
|
-
* @attr {
|
|
21
|
-
* @attr {
|
|
22
|
-
* @attr {
|
|
23
|
-
* @
|
|
24
|
-
* @
|
|
25
|
-
* @
|
|
26
|
-
* @event auroMenu-
|
|
27
|
-
* @event auroMenu-
|
|
28
|
-
* @event auroMenu-
|
|
29
|
-
* @event auroMenu-
|
|
24
|
+
* @attr {Array<HTMLElement>|undefined} optionselected - An array of currently selected menu options. In single-select mode, the array will contain only one HTMLElement. `undefined` when no options are selected.
|
|
25
|
+
* @attr {object} optionactive - Specifies the current active menuOption.
|
|
26
|
+
* @attr {string} matchword - Specifies a string used to highlight matched string parts in options.
|
|
27
|
+
* @attr {boolean} disabled - When true, the entire menu and all options are disabled;
|
|
28
|
+
* @attr {boolean} nocheckmark - When true, selected option will not show the checkmark.
|
|
29
|
+
* @attr {boolean} loading - When true, displays a loading state using the loadingIcon and loadingText slots if provided.
|
|
30
|
+
* @attr {boolean} multiselect - When true, the selected option can be multiple options.
|
|
31
|
+
* @attr {Array<string>|undefined} value - Value selected for the menu. `undefined` when no selection has been made, otherwise an array of strings. In single-select mode, the array will contain only one value.
|
|
32
|
+
* @prop {boolean} hasLoadingPlaceholder - Indicates whether the menu has a loadingIcon or loadingText to render when in a loading state.
|
|
33
|
+
* @event {CustomEvent<Element>} auroMenu-activatedOption - Notifies that a menuoption has been made `active`.
|
|
34
|
+
* @event {CustomEvent<any>} auroMenu-customEventFired - Notifies that a custom event has been fired.
|
|
35
|
+
* @event {CustomEvent<{ loading: boolean; hasLoadingPlaceholder: boolean; }>} auroMenu-loadingChange - Notifies when the loading attribute is changed.
|
|
36
|
+
* @event {CustomEvent<any>} auroMenu-selectValueFailure - Notifies that an attempt to select a menuoption by matching a value has failed.
|
|
37
|
+
* @event {CustomEvent<any>} auroMenu-selectValueReset - Notifies that the component value has been reset.
|
|
38
|
+
* @event {CustomEvent<any>} auroMenu-selectedOption - Notifies that a new menuoption selection has been made.
|
|
30
39
|
* @slot loadingText - Text to show while loading attribute is set
|
|
31
40
|
* @slot loadingIcon - Icon to show while loading attribute is set
|
|
32
41
|
* @slot - Slot for insertion of menu options.
|
|
@@ -37,52 +46,104 @@ import AuroLibraryRuntimeUtils from '@aurodesignsystem/auro-library/scripts/util
|
|
|
37
46
|
export class AuroMenu extends LitElement {
|
|
38
47
|
constructor() {
|
|
39
48
|
super();
|
|
49
|
+
|
|
50
|
+
// State properties (reactive)
|
|
51
|
+
|
|
52
|
+
// Value of the selected options
|
|
40
53
|
this.value = undefined;
|
|
54
|
+
// Currently selected option
|
|
41
55
|
this.optionSelected = undefined;
|
|
56
|
+
// String used for highlighting/filtering
|
|
42
57
|
this.matchWord = undefined;
|
|
58
|
+
// Hide the checkmark icon on selected options
|
|
43
59
|
this.noCheckmark = false;
|
|
60
|
+
// Currently active option
|
|
44
61
|
this.optionActive = undefined;
|
|
62
|
+
// Loading state
|
|
45
63
|
this.loading = false;
|
|
64
|
+
// Multi-select mode
|
|
65
|
+
this.multiSelect = false;
|
|
66
|
+
|
|
67
|
+
// Event Bindings
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @private
|
|
71
|
+
*/
|
|
72
|
+
this.handleKeyDown = this.handleKeyDown.bind(this);
|
|
46
73
|
|
|
47
74
|
/**
|
|
48
75
|
* @private
|
|
49
76
|
*/
|
|
50
|
-
this.
|
|
77
|
+
this.handleMouseSelect = this.handleMouseSelect.bind(this);
|
|
51
78
|
|
|
52
79
|
/**
|
|
53
80
|
* @private
|
|
54
81
|
*/
|
|
55
|
-
this.
|
|
82
|
+
this.handleOptionHover = this.handleOptionHover.bind(this);
|
|
56
83
|
|
|
57
84
|
/**
|
|
58
85
|
* @private
|
|
59
86
|
*/
|
|
60
|
-
this.
|
|
87
|
+
this.handleSlotChange = this.handleSlotChange.bind(this);
|
|
88
|
+
|
|
89
|
+
// Instance properties (non-reactive)
|
|
61
90
|
|
|
62
91
|
/**
|
|
63
92
|
* @private
|
|
64
93
|
*/
|
|
65
|
-
this
|
|
94
|
+
Object.assign(this, {
|
|
95
|
+
// Root-level menu (true) or a nested submenu (false)
|
|
96
|
+
rootMenu: true,
|
|
97
|
+
// Currently focused/active menu item index
|
|
98
|
+
index: -1,
|
|
99
|
+
// Nested menu spacer
|
|
100
|
+
nestingSpacer: '<span class="nestingSpacer"></span>',
|
|
101
|
+
// Loading indicator for slot elements
|
|
102
|
+
loadingSlots: null,
|
|
103
|
+
// Store for menu items
|
|
104
|
+
items: [],
|
|
105
|
+
});
|
|
66
106
|
}
|
|
67
107
|
|
|
68
108
|
static get properties() {
|
|
69
109
|
return {
|
|
70
|
-
noCheckmark:
|
|
110
|
+
noCheckmark: {
|
|
71
111
|
type: Boolean,
|
|
72
|
-
reflect: true
|
|
112
|
+
reflect: true,
|
|
113
|
+
attribute: 'nocheckmark'
|
|
73
114
|
},
|
|
74
|
-
disabled:
|
|
115
|
+
disabled: {
|
|
75
116
|
type: Boolean,
|
|
76
117
|
reflect: true
|
|
77
118
|
},
|
|
78
|
-
loading:
|
|
119
|
+
loading: {
|
|
79
120
|
type: Boolean,
|
|
80
121
|
reflect: true
|
|
81
122
|
},
|
|
82
|
-
optionSelected: {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
123
|
+
optionSelected: {
|
|
124
|
+
// Allow HTMLElement[] arrays and undefined
|
|
125
|
+
converter: arrayConverter,
|
|
126
|
+
hasChanged: arrayOrUndefinedHasChanged
|
|
127
|
+
},
|
|
128
|
+
optionActive: {
|
|
129
|
+
type: Object,
|
|
130
|
+
attribute: 'optionactive'
|
|
131
|
+
},
|
|
132
|
+
matchWord: {
|
|
133
|
+
type: String,
|
|
134
|
+
attribute: 'matchword'
|
|
135
|
+
},
|
|
136
|
+
multiSelect: {
|
|
137
|
+
type: Boolean,
|
|
138
|
+
reflect: true,
|
|
139
|
+
attribute: 'multiselect'
|
|
140
|
+
},
|
|
141
|
+
value: {
|
|
142
|
+
// Allow string[] arrays and undefined
|
|
143
|
+
type: Object,
|
|
144
|
+
converter: arrayConverter,
|
|
145
|
+
hasChanged: arrayOrUndefinedHasChanged
|
|
146
|
+
}
|
|
86
147
|
};
|
|
87
148
|
}
|
|
88
149
|
|
|
@@ -106,198 +167,329 @@ export class AuroMenu extends LitElement {
|
|
|
106
167
|
AuroLibraryRuntimeUtils.prototype.registerComponent(name, AuroMenu);
|
|
107
168
|
}
|
|
108
169
|
|
|
109
|
-
|
|
110
|
-
* Passes the noCheckmark attribute to all nested auro-menuoptions.
|
|
111
|
-
* @private
|
|
112
|
-
* @returns {void}
|
|
113
|
-
*/
|
|
114
|
-
handleNoCheckmarkAttr() {
|
|
115
|
-
if (this.noCheckmark) {
|
|
116
|
-
const menus = this.querySelectorAll('auro-menu, [auro-menu]');
|
|
170
|
+
// Lifecycle Methods
|
|
117
171
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
});
|
|
172
|
+
connectedCallback() {
|
|
173
|
+
super.connectedCallback();
|
|
121
174
|
|
|
122
|
-
|
|
175
|
+
this.addEventListener('keydown', this.handleKeyDown);
|
|
176
|
+
this.addEventListener('mousedown', this.handleMouseSelect);
|
|
177
|
+
this.addEventListener('auroMenuOption-mouseover', this.handleOptionHover);
|
|
178
|
+
this.addEventListener('slotchange', this.handleSlotChange);
|
|
179
|
+
}
|
|
123
180
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
181
|
+
disconnectedCallback() {
|
|
182
|
+
this.removeEventListener('keydown', this.handleKeyDown);
|
|
183
|
+
this.removeEventListener('mousedown', this.handleMouseSelect);
|
|
184
|
+
this.removeEventListener('auroMenuOption-mouseover', this.handleOptionHover);
|
|
185
|
+
this.removeEventListener('slotchange', this.handleSlotChange);
|
|
186
|
+
|
|
187
|
+
super.disconnectedCallback();
|
|
128
188
|
}
|
|
129
189
|
|
|
130
190
|
firstUpdated() {
|
|
131
|
-
|
|
132
|
-
this.runtimeUtils.handleComponentTagRename(this, 'auro-menu');
|
|
133
|
-
|
|
134
|
-
this.addEventListener('keydown', this.handleKeyDown);
|
|
191
|
+
AuroLibraryRuntimeUtils.prototype.handleComponentTagRename(this, 'auro-menu');
|
|
135
192
|
|
|
136
193
|
this.loadingSlots = this.querySelectorAll("[slot='loadingText'], [slot='loadingIcon']");
|
|
194
|
+
this.initializeMenu();
|
|
137
195
|
}
|
|
138
196
|
|
|
139
197
|
updated(changedProperties) {
|
|
140
|
-
if (changedProperties.has('
|
|
141
|
-
|
|
198
|
+
if (changedProperties.has('value')) {
|
|
199
|
+
// Handle null/undefined case
|
|
200
|
+
if (this.value === undefined || this.value === null) {
|
|
201
|
+
this.optionSelected = undefined;
|
|
202
|
+
// Reset index tracking
|
|
203
|
+
this.index = -1;
|
|
204
|
+
} else {
|
|
205
|
+
// Convert single values to arrays
|
|
206
|
+
const valueArray = Array.isArray(this.value) ? this.value : [this.value];
|
|
207
|
+
|
|
208
|
+
// Find all matching options
|
|
209
|
+
const matchingOptions = this.items.filter((item) => valueArray.includes(item.value));
|
|
210
|
+
|
|
211
|
+
if (matchingOptions.length > 0) {
|
|
212
|
+
if (this.multiSelect) {
|
|
213
|
+
// For multiselect, keep all matching options
|
|
214
|
+
this.optionSelected = matchingOptions;
|
|
215
|
+
} else {
|
|
216
|
+
// For single select, only use the first match
|
|
217
|
+
this.optionSelected = [matchingOptions[0]];
|
|
218
|
+
this.index = this.items.indexOf(matchingOptions[0]);
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
// No matches found - trigger failure event
|
|
222
|
+
dispatchMenuEvent(this, 'auroMenu-selectValueFailure');
|
|
223
|
+
this.optionSelected = undefined;
|
|
224
|
+
this.index = -1;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Update UI state
|
|
229
|
+
this.updateItemsState(new Map([
|
|
230
|
+
[
|
|
231
|
+
'optionSelected',
|
|
232
|
+
true
|
|
233
|
+
]
|
|
234
|
+
]));
|
|
235
|
+
|
|
236
|
+
// Notify of changes
|
|
237
|
+
if (this.optionSelected !== undefined) {
|
|
238
|
+
this.notifySelectionChange();
|
|
239
|
+
}
|
|
142
240
|
}
|
|
143
241
|
|
|
144
|
-
|
|
145
|
-
|
|
242
|
+
// Process all other UI updates
|
|
243
|
+
this.updateItemsState(changedProperties);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Updates the UI state and appearance of menu items based on changed properties.
|
|
248
|
+
* @private
|
|
249
|
+
* @param {Map<string, boolean>} changedProperties - LitElement's changed properties map.
|
|
250
|
+
*/
|
|
251
|
+
updateItemsState(changedProperties) {
|
|
252
|
+
if (!this.items) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Handle noCheckmark propagation to all menus and options
|
|
257
|
+
if (changedProperties.has('noCheckmark') && this.noCheckmark) {
|
|
258
|
+
// Update both menus and options
|
|
259
|
+
this.querySelectorAll('auro-menu, [auro-menu], auro-menuoption, [auro-menuoption]').forEach((element) => element.setAttribute('noCheckmark', ''));
|
|
146
260
|
}
|
|
147
261
|
|
|
148
|
-
if
|
|
149
|
-
|
|
262
|
+
// Regex for matchWord if needed
|
|
263
|
+
let regexWord = null;
|
|
150
264
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
265
|
+
if (changedProperties.has('matchWord') && this.matchWord && this.matchWord.length) {
|
|
266
|
+
const escapedWord = this.matchWord.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
267
|
+
regexWord = new RegExp(escapedWord, 'giu');
|
|
154
268
|
}
|
|
155
269
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
270
|
+
// Handle direct item updates
|
|
271
|
+
this.items.forEach((option) => {
|
|
272
|
+
// Update selection if option or value changed
|
|
273
|
+
if (changedProperties.has('optionSelected') || changedProperties.has('value')) {
|
|
274
|
+
const isSelected = this.isOptionSelected(option);
|
|
275
|
+
option.classList.toggle('active', isSelected);
|
|
276
|
+
option.setAttribute('aria-selected', isSelected ? 'true' : 'false');
|
|
277
|
+
|
|
278
|
+
// Add/remove selected attribute based on state
|
|
279
|
+
if (isSelected) {
|
|
280
|
+
option.setAttribute('selected', '');
|
|
281
|
+
} else {
|
|
282
|
+
option.removeAttribute('selected');
|
|
162
283
|
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Update text highlighting if matchWord changed
|
|
287
|
+
if (changedProperties.has('matchWord') && regexWord &&
|
|
288
|
+
isOptionInteractive(option) && !option.hasAttribute('persistent')) {
|
|
289
|
+
const nested = option.querySelectorAll('.nestingSpacer');
|
|
290
|
+
// Create nested spacers
|
|
291
|
+
const nestingSpacerBundle = [...nested].map(() => this.nestingSpacer).join('');
|
|
292
|
+
|
|
293
|
+
// Update with spacers and matchWord
|
|
294
|
+
option.innerHTML = nestingSpacerBundle +
|
|
295
|
+
option.textContent.replace(
|
|
296
|
+
regexWord,
|
|
297
|
+
(match) => `<strong>${match}</strong>`
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Update disabled state
|
|
302
|
+
if (changedProperties.has('disabled')) {
|
|
303
|
+
option.disabled = this.disabled;
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// Handle loading state changes
|
|
308
|
+
if (changedProperties.has('loading')) {
|
|
309
|
+
this.setAttribute("aria-busy", this.loading);
|
|
310
|
+
dispatchMenuEvent(this, "auroMenu-loadingChange", {
|
|
311
|
+
loading: this.loading,
|
|
312
|
+
hasLoadingPlaceholder: this.hasLoadingPlaceholder
|
|
163
313
|
});
|
|
164
|
-
this.setAttribute("aria-busy", this.hasAttribute("loading"));
|
|
165
|
-
this.dispatchEvent(event);
|
|
166
314
|
}
|
|
167
315
|
}
|
|
168
316
|
|
|
317
|
+
// Init Methods
|
|
318
|
+
|
|
169
319
|
/**
|
|
320
|
+
* Initializes the menu's state and structure.
|
|
170
321
|
* @private
|
|
171
|
-
* @param {Object} option - The menuoption to check for interactive state.
|
|
172
|
-
* @returns {Boolean} Returns true if the option is interactive.
|
|
173
322
|
*/
|
|
174
|
-
|
|
175
|
-
|
|
323
|
+
initializeMenu() {
|
|
324
|
+
this.initItems();
|
|
325
|
+
if (this.rootMenu) {
|
|
326
|
+
this.setAttribute('role', 'listbox');
|
|
327
|
+
this.setAttribute('root', '');
|
|
328
|
+
this.handleNestedMenus(this);
|
|
329
|
+
}
|
|
176
330
|
}
|
|
177
331
|
|
|
178
332
|
/**
|
|
333
|
+
* Initializes menu items and their attributes.
|
|
179
334
|
* @private
|
|
180
|
-
* @returns {void} When called will update the DOM with visible suggest text matches.
|
|
181
335
|
*/
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
this.items.forEach((item) => {
|
|
192
|
-
if (this.optionInteractive(item) && !item.hasAttribute('persistent')) {
|
|
193
|
-
const nested = item.querySelectorAll('.nestingSpacer');
|
|
194
|
-
const nestingSpacerBundle = [...nested].map(() => this.nestingSpacer).join('');
|
|
195
|
-
|
|
196
|
-
item.innerHTML = nestingSpacerBundle + item.textContent.replace(regexWord, (match) => `<strong>${match}</strong>`);
|
|
197
|
-
}
|
|
198
|
-
});
|
|
336
|
+
initItems() {
|
|
337
|
+
this.items = Array.from(this.querySelectorAll('auro-menuoption, [auro-menuoption]'));
|
|
338
|
+
if (this.noCheckmark) {
|
|
339
|
+
this.updateItemsState(new Map([
|
|
340
|
+
[
|
|
341
|
+
'noCheckmark',
|
|
342
|
+
true
|
|
343
|
+
]
|
|
344
|
+
]));
|
|
199
345
|
}
|
|
200
346
|
}
|
|
201
347
|
|
|
348
|
+
// Logic Methods
|
|
349
|
+
|
|
202
350
|
/**
|
|
203
|
-
*
|
|
351
|
+
* Updates menu state when an option is selected.
|
|
352
|
+
* @private
|
|
353
|
+
* @param {HTMLElement} option - The option element to select.
|
|
204
354
|
*/
|
|
205
|
-
|
|
206
|
-
this.
|
|
207
|
-
|
|
208
|
-
this.
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
355
|
+
handleSelectState(option) {
|
|
356
|
+
if (this.multiSelect) {
|
|
357
|
+
const currentValue = this.value || [];
|
|
358
|
+
const currentSelected = this.optionSelected || [];
|
|
359
|
+
|
|
360
|
+
if (!currentValue.includes(option.value)) {
|
|
361
|
+
this.value = [
|
|
362
|
+
...currentValue,
|
|
363
|
+
option.value
|
|
364
|
+
];
|
|
365
|
+
}
|
|
366
|
+
if (!currentSelected.includes(option)) {
|
|
367
|
+
this.optionSelected = [
|
|
368
|
+
...currentSelected,
|
|
369
|
+
option
|
|
370
|
+
];
|
|
371
|
+
}
|
|
372
|
+
} else {
|
|
373
|
+
// Single select - use arrays with single values
|
|
374
|
+
this.value = [option.value];
|
|
375
|
+
this.optionSelected = [option];
|
|
212
376
|
}
|
|
377
|
+
|
|
378
|
+
this.index = this.items.indexOf(option);
|
|
213
379
|
}
|
|
214
380
|
|
|
215
381
|
/**
|
|
216
|
-
*
|
|
217
|
-
* @param {Object} option - The menuoption to be selected.
|
|
382
|
+
* Deselects a menu option and updates related state.
|
|
218
383
|
* @private
|
|
384
|
+
* @param {HTMLElement} option - The menuoption to be deselected.
|
|
219
385
|
*/
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
386
|
+
handleDeselectState(option) {
|
|
387
|
+
if (this.multiSelect && Array.isArray(this.value)) {
|
|
388
|
+
// Remove this option from array
|
|
389
|
+
this.value = this.value.filter((val) => val !== option.value);
|
|
390
|
+
|
|
391
|
+
// If array is empty after removal, set back to undefined
|
|
392
|
+
if (this.value.length === 0) {
|
|
393
|
+
this.value = undefined;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
this.optionSelected = this.optionSelected.filter((val) => val !== option);
|
|
397
|
+
if (this.optionSelected.length === 0) {
|
|
398
|
+
this.optionSelected = undefined;
|
|
399
|
+
}
|
|
400
|
+
} else {
|
|
401
|
+
// For single-select: Back to undefined when deselected
|
|
402
|
+
this.value = undefined;
|
|
403
|
+
this.optionSelected = undefined;
|
|
404
|
+
}
|
|
224
405
|
|
|
225
|
-
|
|
226
|
-
this.optionSelected = option;
|
|
406
|
+
// Update the index tracking
|
|
227
407
|
this.index = this.items.indexOf(option);
|
|
408
|
+
|
|
409
|
+
// Update UI to reflect changes
|
|
410
|
+
this.updateItemsState(new Map([
|
|
411
|
+
[
|
|
412
|
+
'optionSelected',
|
|
413
|
+
true
|
|
414
|
+
]
|
|
415
|
+
]));
|
|
416
|
+
|
|
417
|
+
// Notify of selection change
|
|
418
|
+
this.notifySelectionChange();
|
|
228
419
|
}
|
|
229
420
|
|
|
230
421
|
/**
|
|
231
|
-
*
|
|
422
|
+
* Resets all options to their default state.
|
|
232
423
|
* @private
|
|
233
|
-
* @return {void}
|
|
234
424
|
*/
|
|
235
|
-
|
|
236
|
-
this.
|
|
237
|
-
|
|
238
|
-
cancelable: false,
|
|
239
|
-
composed: true,
|
|
240
|
-
}));
|
|
425
|
+
clearSelection() {
|
|
426
|
+
this.optionSelected = undefined;
|
|
427
|
+
this.value = undefined;
|
|
241
428
|
}
|
|
242
429
|
|
|
243
430
|
/**
|
|
244
|
-
*
|
|
431
|
+
* Resets the menu to its initial state.
|
|
432
|
+
* This is the only way to return value to undefined.
|
|
433
|
+
* @public
|
|
245
434
|
*/
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
435
|
+
reset() {
|
|
436
|
+
// Reset to undefined - initial state
|
|
437
|
+
this.value = undefined;
|
|
438
|
+
this.optionSelected = undefined;
|
|
439
|
+
this.index = -1;
|
|
440
|
+
|
|
441
|
+
// Reset UI state
|
|
442
|
+
this.updateItemsState(new Map([
|
|
443
|
+
[
|
|
444
|
+
'optionSelected',
|
|
445
|
+
true
|
|
446
|
+
]
|
|
447
|
+
]));
|
|
448
|
+
|
|
449
|
+
// Dispatch reset event
|
|
450
|
+
dispatchMenuEvent(this, 'auroMenu-selectValueReset');
|
|
451
|
+
}
|
|
250
452
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
composed: true,
|
|
265
|
-
}));
|
|
266
|
-
|
|
267
|
-
this.dispatchEvent(new CustomEvent('auroMenu-customEventFired', {
|
|
268
|
-
bubbles: true,
|
|
269
|
-
cancelable: false,
|
|
270
|
-
composed: true,
|
|
271
|
-
}));
|
|
272
|
-
} else {
|
|
273
|
-
this.handleLocalSelectState(option);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
453
|
+
/**
|
|
454
|
+
* Handles nested menu structure.
|
|
455
|
+
* @private
|
|
456
|
+
* @param {HTMLElement} menu - Root menu element.
|
|
457
|
+
*/
|
|
458
|
+
handleNestedMenus(menu) {
|
|
459
|
+
const nestedMenus = menu.querySelectorAll('auro-menu, [auro-menu]');
|
|
460
|
+
|
|
461
|
+
nestedMenus.forEach((nestedMenu) => {
|
|
462
|
+
// role="listbox" only allows "role=group" for children.
|
|
463
|
+
nestedMenu.setAttribute('role', 'group');
|
|
464
|
+
if (!nestedMenu.hasAttribute('aria-label')) {
|
|
465
|
+
nestedMenu.setAttribute('aria-label', 'submenu');
|
|
276
466
|
}
|
|
277
|
-
}
|
|
278
467
|
|
|
279
|
-
|
|
468
|
+
const options = nestedMenu.querySelectorAll(':scope > auro-menuoption, :scope > [auro-menuoption]');
|
|
469
|
+
options.forEach((option) => {
|
|
470
|
+
option.innerHTML = this.nestingSpacer + option.innerHTML;
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
this.handleNestedMenus(nestedMenu);
|
|
474
|
+
});
|
|
280
475
|
}
|
|
281
476
|
|
|
477
|
+
// Event Handlers
|
|
478
|
+
|
|
282
479
|
/**
|
|
283
|
-
*
|
|
480
|
+
* Handles keyboard navigation.
|
|
284
481
|
* @private
|
|
285
|
-
* @param {
|
|
482
|
+
* @param {KeyboardEvent} event - Event object from the browser.
|
|
286
483
|
*/
|
|
287
484
|
handleKeyDown(event) {
|
|
288
485
|
event.preventDefault();
|
|
289
|
-
|
|
290
|
-
// With ArrowDown/ArrowUp events, pass new value to selectNextItem()
|
|
291
|
-
// With Enter event, set value and apply attrs
|
|
292
486
|
switch (event.key) {
|
|
293
487
|
case "ArrowDown":
|
|
294
|
-
this.
|
|
488
|
+
this.navigateOptions('down');
|
|
295
489
|
break;
|
|
296
|
-
|
|
297
490
|
case "ArrowUp":
|
|
298
|
-
this.
|
|
491
|
+
this.navigateOptions('up');
|
|
299
492
|
break;
|
|
300
|
-
|
|
301
493
|
case "Enter":
|
|
302
494
|
this.makeSelection();
|
|
303
495
|
break;
|
|
@@ -307,222 +499,218 @@ export class AuroMenu extends LitElement {
|
|
|
307
499
|
}
|
|
308
500
|
|
|
309
501
|
/**
|
|
310
|
-
*
|
|
502
|
+
* Makes a selection based on the current index or clicked option.
|
|
311
503
|
* @private
|
|
312
504
|
*/
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
505
|
+
makeSelection() {
|
|
506
|
+
if (!this.items) {
|
|
507
|
+
this.initItems();
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Get currently selected menu option based on index
|
|
511
|
+
const option = this.items[this.index];
|
|
512
|
+
|
|
513
|
+
// Return early if option is not interactive
|
|
514
|
+
if (!option || !isOptionInteractive(option)) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Handle custom events first
|
|
519
|
+
if (option.hasAttribute('event')) {
|
|
520
|
+
this.handleCustomEvent(option);
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (this.multiSelect) {
|
|
525
|
+
// In multiselect, toggle individual selections
|
|
526
|
+
this.toggleOption(option);
|
|
527
|
+
// In single select, only handle selection of new options
|
|
528
|
+
} else if (!this.isOptionSelected(option)) {
|
|
529
|
+
this.clearSelection();
|
|
530
|
+
this.handleSelectState(option);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
this.notifySelectionChange();
|
|
316
534
|
}
|
|
317
535
|
|
|
318
536
|
/**
|
|
319
|
-
*
|
|
537
|
+
* Toggle the selection state of the menuoption.
|
|
320
538
|
* @private
|
|
539
|
+
* @param {HTMLElement} option - The menuoption to toggle.
|
|
321
540
|
*/
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const index = this.items.findIndex((option) => option.hasAttribute('selected') && this.optionInteractive(option));
|
|
541
|
+
toggleOption(option) {
|
|
542
|
+
const isCurrentlySelected = this.isOptionSelected(option);
|
|
325
543
|
|
|
326
|
-
if (
|
|
327
|
-
this.
|
|
328
|
-
|
|
544
|
+
if (isCurrentlySelected) {
|
|
545
|
+
this.handleDeselectState(option);
|
|
546
|
+
} else if (option.value === undefined || option.value === '') {
|
|
547
|
+
dispatchMenuEvent(this, 'auroMenu-selectValueFailure');
|
|
548
|
+
} else {
|
|
549
|
+
this.handleSelectState(option);
|
|
329
550
|
}
|
|
330
551
|
}
|
|
331
552
|
|
|
332
553
|
/**
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
*
|
|
337
|
-
* The event.target is not used as the function needs to know where to go,
|
|
338
|
-
* versus knowing where it is.
|
|
339
|
-
* @param {String} moveDirection - Up or Down based on keyboard event.
|
|
554
|
+
* Handles option selection via mouse.
|
|
555
|
+
* @private
|
|
556
|
+
* @param {MouseEvent} event - Event object from the browser.
|
|
340
557
|
*/
|
|
341
|
-
|
|
342
|
-
if (
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
// calculate which is the selection we should focus next
|
|
346
|
-
let increment = 0;
|
|
347
|
-
|
|
348
|
-
if (moveDirection === 'down') {
|
|
349
|
-
increment = 1;
|
|
350
|
-
} else if (moveDirection === 'up') {
|
|
351
|
-
increment = -1;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
this.index += increment;
|
|
355
|
-
|
|
356
|
-
// keep looping inside the array of options
|
|
357
|
-
if (this.index > this.items.length - 1) {
|
|
358
|
-
this.index = 0;
|
|
359
|
-
} else if (this.index < 0) {
|
|
360
|
-
this.index = this.items.length - 1;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// check if new index is disabled, static or hidden, if so, execute again
|
|
364
|
-
if (!this.optionInteractive(this.items[this.index])) {
|
|
365
|
-
this.selectNextItem(moveDirection);
|
|
366
|
-
} else {
|
|
367
|
-
// apply focus to new index
|
|
368
|
-
this.updateActiveOption(this.index);
|
|
369
|
-
}
|
|
370
|
-
} else {
|
|
371
|
-
this.index = 0;
|
|
558
|
+
handleMouseSelect(event) {
|
|
559
|
+
if (event.target === this) {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
372
562
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
}
|
|
563
|
+
const option = event.target.closest('auro-menuoption, [auro-menuoption]');
|
|
564
|
+
if (option) {
|
|
565
|
+
this.index = this.items.indexOf(option);
|
|
566
|
+
this.makeSelection();
|
|
378
567
|
}
|
|
379
568
|
}
|
|
380
569
|
|
|
381
570
|
/**
|
|
382
|
-
*
|
|
571
|
+
* Handles option hover events.
|
|
383
572
|
* @private
|
|
384
|
-
* @param {
|
|
573
|
+
* @param {CustomEvent} event - Event object from the browser.
|
|
385
574
|
*/
|
|
386
|
-
|
|
387
|
-
const
|
|
575
|
+
handleOptionHover(event) {
|
|
576
|
+
const option = event.target;
|
|
577
|
+
this.index = this.items.indexOf(option);
|
|
578
|
+
this.updateActiveOption(this.index);
|
|
579
|
+
}
|
|
388
580
|
|
|
389
|
-
|
|
390
|
-
|
|
581
|
+
/**
|
|
582
|
+
* Handles slot change events.
|
|
583
|
+
* @private
|
|
584
|
+
*/
|
|
585
|
+
handleSlotChange() {
|
|
586
|
+
if (this.parentElement && this.parentElement.closest('auro-menu, [auro-menu]')) {
|
|
587
|
+
this.rootMenu = false;
|
|
391
588
|
}
|
|
392
589
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
590
|
+
if (this.rootMenu) {
|
|
591
|
+
this.initializeMenu();
|
|
592
|
+
} else if (this.noCheckmark) {
|
|
593
|
+
this.updateItemsState(new Map([
|
|
594
|
+
[
|
|
595
|
+
'noCheckmark',
|
|
596
|
+
true
|
|
597
|
+
]
|
|
598
|
+
]));
|
|
599
|
+
}
|
|
402
600
|
}
|
|
403
601
|
|
|
404
602
|
/**
|
|
405
|
-
*
|
|
603
|
+
* Navigates through options using keyboard.
|
|
406
604
|
* @private
|
|
407
|
-
* @param {
|
|
605
|
+
* @param {string} direction - 'up' or 'down'.
|
|
408
606
|
*/
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
if (!this.items) {
|
|
412
|
-
|
|
607
|
+
navigateOptions(direction) {
|
|
608
|
+
// Return early if no items exist
|
|
609
|
+
if (!this.items || !this.items.length) {
|
|
610
|
+
return;
|
|
413
611
|
}
|
|
414
612
|
|
|
415
|
-
this.index
|
|
613
|
+
let newIndex = this.index;
|
|
614
|
+
const increment = direction === 'down' ? 1 : -1;
|
|
615
|
+
const maxIterations = this.items.length;
|
|
616
|
+
let iterations = 0;
|
|
617
|
+
let foundInteractiveOption = false;
|
|
416
618
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
valueMatch = true;
|
|
421
|
-
this.index = index;
|
|
422
|
-
}
|
|
423
|
-
}
|
|
619
|
+
do {
|
|
620
|
+
newIndex = (newIndex + increment + this.items.length) % this.items.length;
|
|
621
|
+
iterations += 1;
|
|
424
622
|
|
|
425
|
-
if
|
|
426
|
-
|
|
427
|
-
|
|
623
|
+
// Check if current option is interactive
|
|
624
|
+
const currentOption = this.items[newIndex];
|
|
625
|
+
if (isOptionInteractive(currentOption)) {
|
|
626
|
+
foundInteractiveOption = true;
|
|
627
|
+
break;
|
|
628
|
+
}
|
|
428
629
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
composed: true,
|
|
433
|
-
}));
|
|
434
|
-
} else {
|
|
435
|
-
this.makeSelection();
|
|
630
|
+
// Break if all options were checked
|
|
631
|
+
if (iterations >= maxIterations) {
|
|
632
|
+
break;
|
|
436
633
|
}
|
|
437
|
-
}
|
|
438
|
-
this.resetOptionsStates();
|
|
634
|
+
} while (iterations < maxIterations);
|
|
439
635
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
636
|
+
// Handle the results of the search
|
|
637
|
+
if (foundInteractiveOption) {
|
|
638
|
+
// Update only if an interactive option was found
|
|
639
|
+
this.index = newIndex;
|
|
640
|
+
this.updateActiveOption(this.index);
|
|
641
|
+
} else {
|
|
642
|
+
// All options are disabled or non-interactive
|
|
643
|
+
// Keep the current index unchanged
|
|
644
|
+
dispatchMenuEvent(this, 'auroMenu-navigateFailure', {
|
|
645
|
+
reason: 'No interactive options available',
|
|
646
|
+
direction,
|
|
647
|
+
currentIndex: this.index
|
|
648
|
+
});
|
|
445
649
|
}
|
|
446
650
|
}
|
|
447
651
|
|
|
448
652
|
/**
|
|
449
|
-
*
|
|
450
|
-
* @param {Number} index - Index of the menuoption that will be made active.
|
|
653
|
+
* Updates the active option state and dispatches events.
|
|
451
654
|
* @private
|
|
655
|
+
* @param {number} index - Index of the option to make active.
|
|
452
656
|
*/
|
|
453
657
|
updateActiveOption(index) {
|
|
454
|
-
this.items.
|
|
455
|
-
|
|
456
|
-
}
|
|
658
|
+
if (!this.items || !this.items[index]) {
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
this.items.forEach((item) => item.classList.remove('active'));
|
|
457
663
|
this.items[index].classList.add('active');
|
|
458
664
|
this.optionActive = this.items[index];
|
|
459
665
|
|
|
460
|
-
this
|
|
461
|
-
bubbles: true,
|
|
462
|
-
cancelable: false,
|
|
463
|
-
composed: true,
|
|
464
|
-
detail: this.items[index]
|
|
465
|
-
}));
|
|
666
|
+
dispatchMenuEvent(this, 'auroMenu-activatedOption', this.items[index]);
|
|
466
667
|
}
|
|
467
668
|
|
|
468
669
|
/**
|
|
469
|
-
*
|
|
470
|
-
* @param {Event} evt - Mousedown event.
|
|
670
|
+
* Handles custom events defined on options.
|
|
471
671
|
* @private
|
|
672
|
+
* @param {HTMLElement} option - Option with custom event.
|
|
472
673
|
*/
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
674
|
+
handleCustomEvent(option) {
|
|
675
|
+
const eventName = option.getAttribute('event');
|
|
676
|
+
dispatchMenuEvent(this, eventName);
|
|
677
|
+
dispatchMenuEvent(this, 'auroMenu-customEventFired');
|
|
477
678
|
}
|
|
478
679
|
|
|
479
680
|
/**
|
|
480
|
-
*
|
|
481
|
-
*
|
|
482
|
-
* This getter evaluates the `loadingSlots` collection to determine if it contains any items.
|
|
483
|
-
* If the size of the collection is greater than zero, it indicates the presence of loading
|
|
484
|
-
* placeholders, returning true; otherwise, it returns false.
|
|
485
|
-
*
|
|
486
|
-
* @getter hasLoadingPlaceholder
|
|
487
|
-
* @type {boolean}
|
|
488
|
-
* @returns {boolean} Returns true if loading placeholders exist; false otherwise.
|
|
681
|
+
* Notifies selection change to parent components.
|
|
682
|
+
* @private
|
|
489
683
|
*/
|
|
490
|
-
|
|
491
|
-
|
|
684
|
+
notifySelectionChange() {
|
|
685
|
+
dispatchMenuEvent(this, 'auroMenu-selectedOption');
|
|
492
686
|
}
|
|
493
687
|
|
|
494
688
|
/**
|
|
495
|
-
*
|
|
689
|
+
* Checks if an option is currently selected.
|
|
496
690
|
* @private
|
|
691
|
+
* @param {HTMLElement} option - The option to check.
|
|
692
|
+
* @returns {boolean}
|
|
497
693
|
*/
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
this.rootMenu = false;
|
|
694
|
+
isOptionSelected(option) {
|
|
695
|
+
if (!this.optionSelected) {
|
|
696
|
+
return false;
|
|
502
697
|
}
|
|
698
|
+
// Always treat as array for both single and multi-select
|
|
699
|
+
return Array.isArray(this.optionSelected) && this.optionSelected.includes(option);
|
|
700
|
+
}
|
|
503
701
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
this.markOptions();
|
|
511
|
-
this.index = -1;
|
|
512
|
-
this.getSelectedIndex();
|
|
513
|
-
|
|
514
|
-
this.addEventListener('keydown', this.handleKeyDown);
|
|
515
|
-
this.addEventListener('mousedown', this.handleMenuMouseDown);
|
|
516
|
-
this.addEventListener('auroMenuOption-mouseover', (evt) => {
|
|
517
|
-
this.index = this.items.indexOf(evt.target);
|
|
518
|
-
this.updateActiveOption(this.index);
|
|
519
|
-
});
|
|
520
|
-
} else {
|
|
521
|
-
// make sure to update all menuoption noCheckmark attributes when the menu is dynamically changed
|
|
522
|
-
this.handleNoCheckmarkAttr();
|
|
523
|
-
}
|
|
702
|
+
/**
|
|
703
|
+
* Getter for loading placeholder state.
|
|
704
|
+
* @returns {boolean} - True if loading slots are present and non-empty.
|
|
705
|
+
*/
|
|
706
|
+
get hasLoadingPlaceholder() {
|
|
707
|
+
return this.loadingSlots && this.loadingSlots.length > 0;
|
|
524
708
|
}
|
|
525
709
|
|
|
710
|
+
/**
|
|
711
|
+
* Renders the component.
|
|
712
|
+
* @returns {boolean} - True if loading slots are present and non-empty.
|
|
713
|
+
*/
|
|
526
714
|
render() {
|
|
527
715
|
if (this.loading) {
|
|
528
716
|
return html`
|
|
@@ -534,6 +722,8 @@ export class AuroMenu extends LitElement {
|
|
|
534
722
|
</auro-menuoption>
|
|
535
723
|
`;
|
|
536
724
|
}
|
|
537
|
-
|
|
725
|
+
|
|
726
|
+
return html`<slot @slotchange=${this.handleSlotChange}></slot>`;
|
|
538
727
|
}
|
|
539
728
|
}
|
|
729
|
+
|