@brightspace-ui/core 3.88.3 → 3.89.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/dropdown/demo/dropdown-menu.html +7 -0
- package/components/dropdown/demo/dropdown-tabs.html +7 -0
- package/components/dropdown/demo/dropdown.html +7 -2
- package/components/dropdown/dropdown-content.js +32 -15
- package/components/dropdown/dropdown-menu.js +291 -116
- package/components/dropdown/dropdown-opener-mixin.js +21 -6
- package/components/dropdown/dropdown-popover-mixin.js +366 -0
- package/components/dropdown/dropdown-tabs.js +112 -48
- package/components/popover/demo/popover.html +2 -2
- package/components/popover/popover-mixin.js +120 -100
- package/components/tabs/tab-internal.js +3 -12
- package/components/tabs/tab-mixin.js +0 -1
- package/components/tabs/tab.js +0 -1
- package/components/tabs/tabs.js +21 -66
- package/custom-elements.json +17 -36
- package/helpers/flags.js +1 -0
- package/package.json +1 -1
@@ -5,6 +5,13 @@
|
|
5
5
|
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">
|
6
6
|
<meta charset="UTF-8">
|
7
7
|
<link rel="stylesheet" href="../../demo/styles.css" type="text/css">
|
8
|
+
<script>
|
9
|
+
const urlParams = new URLSearchParams(window.location.search);
|
10
|
+
window.D2L = { LP: { Web: { UI: { Flags: { Flag: (key) => {
|
11
|
+
if (key === 'GAUD-7472-dropdown-popover') return (urlParams.get('popover') === 'true');
|
12
|
+
return false;
|
13
|
+
} } } } } };
|
14
|
+
</script>
|
8
15
|
<script type="module">
|
9
16
|
import '../../demo/demo-page.js';
|
10
17
|
import '../../menu/menu.js';
|
@@ -5,6 +5,13 @@
|
|
5
5
|
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">
|
6
6
|
<meta charset="UTF-8">
|
7
7
|
<link rel="stylesheet" href="../../demo/styles.css" type="text/css">
|
8
|
+
<script>
|
9
|
+
const urlParams = new URLSearchParams(window.location.search);
|
10
|
+
window.D2L = { LP: { Web: { UI: { Flags: { Flag: (key) => {
|
11
|
+
if (key === 'GAUD-7472-dropdown-popover') return (urlParams.get('popover') === 'true');
|
12
|
+
return false;
|
13
|
+
} } } } } };
|
14
|
+
</script>
|
8
15
|
<script type="module">
|
9
16
|
import '../../demo/demo-page.js';
|
10
17
|
import '../../tabs/tabs.js';
|
@@ -1,10 +1,16 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html lang="en">
|
3
|
-
|
4
3
|
<head>
|
5
4
|
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">
|
6
5
|
<meta charset="UTF-8">
|
7
6
|
<link rel="stylesheet" href="../../demo/styles.css" type="text/css">
|
7
|
+
<script>
|
8
|
+
const urlParams = new URLSearchParams(window.location.search);
|
9
|
+
window.D2L = { LP: { Web: { UI: { Flags: { Flag: (key) => {
|
10
|
+
if (key === 'GAUD-7472-dropdown-popover') return (urlParams.get('popover') === 'true');
|
11
|
+
return false;
|
12
|
+
} } } } } };
|
13
|
+
</script>
|
8
14
|
<script type="module">
|
9
15
|
import '../../demo/demo-page.js';
|
10
16
|
import '../../button/button.js';
|
@@ -12,7 +18,6 @@
|
|
12
18
|
import '../dropdown-content.js';
|
13
19
|
</script>
|
14
20
|
</head>
|
15
|
-
|
16
21
|
<body unresolved>
|
17
22
|
|
18
23
|
<d2l-demo-page page-title="d2l-dropdown">
|
@@ -1,23 +1,40 @@
|
|
1
|
+
import { DropdownPopoverMixin, usePopoverMixin } from './dropdown-popover-mixin.js';
|
1
2
|
import { DropdownContentMixin } from './dropdown-content-mixin.js';
|
2
3
|
import { dropdownContentStyles } from './dropdown-content-styles.js';
|
3
4
|
import { LitElement } from 'lit';
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
6
|
+
if (usePopoverMixin) {
|
7
|
+
|
8
|
+
/**
|
9
|
+
* A generic container for dropdown content. It provides behavior such as sizing, positioning, and managing focus gain/loss.
|
10
|
+
* @slot - Anything inside of "d2l-dropdown-content" that isn't in the "header" or "footer" slots appears as regular content
|
11
|
+
* @slot header - Sticky container at the top of the dropdown
|
12
|
+
* @slot footer - Sticky container at the bottom of the dropdown
|
13
|
+
* @fires d2l-dropdown-open - Dispatched when the dropdown is opened
|
14
|
+
*/
|
15
|
+
class DropdownContent extends DropdownPopoverMixin(LitElement) { }
|
16
|
+
customElements.define('d2l-dropdown-content', DropdownContent);
|
17
|
+
|
18
|
+
} else {
|
19
|
+
|
20
|
+
/**
|
21
|
+
* A generic container for dropdown content. It provides behavior such as sizing, positioning, and managing focus gain/loss.
|
22
|
+
* @slot - Anything inside of "d2l-dropdown-content" that isn't in the "header" or "footer" slots appears as regular content
|
23
|
+
* @slot header - Sticky container at the top of the dropdown
|
24
|
+
* @slot footer - Sticky container at the bottom of the dropdown
|
25
|
+
* @fires d2l-dropdown-open - Dispatched when the dropdown is opened
|
26
|
+
*/
|
27
|
+
class DropdownContent extends DropdownContentMixin(LitElement) {
|
28
|
+
|
29
|
+
static get styles() {
|
30
|
+
return dropdownContentStyles;
|
31
|
+
}
|
32
|
+
|
33
|
+
render() {
|
34
|
+
return this._renderContent();
|
35
|
+
}
|
17
36
|
|
18
|
-
render() {
|
19
|
-
return this._renderContent();
|
20
37
|
}
|
38
|
+
customElements.define('d2l-dropdown-content', DropdownContent);
|
21
39
|
|
22
40
|
}
|
23
|
-
customElements.define('d2l-dropdown-content', DropdownContent);
|
@@ -1,33 +1,31 @@
|
|
1
1
|
import { css, LitElement } from 'lit';
|
2
|
+
import { DropdownPopoverMixin, usePopoverMixin } from './dropdown-popover-mixin.js';
|
2
3
|
import { DropdownContentMixin } from './dropdown-content-mixin.js';
|
3
4
|
import { dropdownContentStyles } from './dropdown-content-styles.js';
|
4
5
|
import { ThemeMixin } from '../../mixins/theme/theme-mixin.js';
|
5
6
|
|
6
7
|
const reduceMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
|
7
8
|
const dropdownDelay = 300;
|
8
|
-
/**
|
9
|
-
* A container for a "d2l-menu". It provides additional support on top of "d2l-dropdown-content" for closing the menu when menu items are selected, resetting to the root of nested menus when reopening and automatic resizing when the menu resizes.
|
10
|
-
* @slot - Anything inside of "d2l-dropdown-content" that isn't in the "header" or "footer" slots appears as regular content
|
11
|
-
* @slot header - Sticky container at the top of the dropdown
|
12
|
-
* @slot footer - Sticky container at the bottom of the dropdown
|
13
|
-
* @fires d2l-dropdown-open - Dispatched when the dropdown is opened
|
14
|
-
*/
|
15
|
-
class DropdownMenu extends ThemeMixin(DropdownContentMixin(LitElement)) {
|
16
|
-
|
17
|
-
static get properties() {
|
18
|
-
return {
|
19
|
-
_closeRadio: {
|
20
|
-
type: Boolean,
|
21
|
-
reflect: true,
|
22
|
-
attribute: '_close-radio'
|
23
|
-
},
|
24
|
-
};
|
25
|
-
}
|
26
9
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
10
|
+
if (usePopoverMixin) {
|
11
|
+
|
12
|
+
/**
|
13
|
+
* A container for a "d2l-menu". It provides additional support on top of "d2l-dropdown-content" for closing the menu when menu items are selected, resetting to the root of nested menus when reopening and automatic resizing when the menu resizes.
|
14
|
+
* @slot - Anything inside of "d2l-dropdown-content" that isn't in the "header" or "footer" slots appears as regular content
|
15
|
+
* @slot header - Sticky container at the top of the dropdown
|
16
|
+
* @slot footer - Sticky container at the bottom of the dropdown
|
17
|
+
* @fires d2l-dropdown-open - Dispatched when the dropdown is opened
|
18
|
+
*/
|
19
|
+
class DropdownMenu extends ThemeMixin(DropdownPopoverMixin(LitElement)) {
|
20
|
+
|
21
|
+
static get properties() {
|
22
|
+
return {
|
23
|
+
_closeRadio: { type: Boolean, reflect: true, attribute: '_close-radio' },
|
24
|
+
};
|
25
|
+
}
|
26
|
+
|
27
|
+
static get styles() {
|
28
|
+
return [super.styles, css`
|
31
29
|
:host {
|
32
30
|
--d2l-dropdown-close-animation-name: d2l-dropdown-close-animation;
|
33
31
|
}
|
@@ -55,134 +53,311 @@ class DropdownMenu extends ThemeMixin(DropdownContentMixin(LitElement)) {
|
|
55
53
|
0% { opacity: 0.9; transform: translate(0, 0); }
|
56
54
|
100% { opacity: 0; transform: translate(0, -10px); }
|
57
55
|
}
|
58
|
-
`
|
59
|
-
|
60
|
-
}
|
56
|
+
`];
|
57
|
+
}
|
61
58
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
59
|
+
constructor() {
|
60
|
+
super();
|
61
|
+
this.noAutoFocus = true;
|
62
|
+
this.noPadding = true;
|
63
|
+
|
64
|
+
this._closeRadio = false;
|
65
|
+
this.#initiallyOpenedSuppressFocus = false;
|
66
|
+
this.#maxHeightNonTray = this.maxHeight;
|
67
|
+
}
|
70
68
|
|
71
|
-
|
72
|
-
|
69
|
+
firstUpdated(changedProperties) {
|
70
|
+
super.firstUpdated(changedProperties);
|
73
71
|
|
74
|
-
|
72
|
+
if (this.opened) this.#initiallyOpenedSuppressFocus = true;
|
73
|
+
|
74
|
+
this.#maxHeightNonTray = this.maxHeight;
|
75
|
+
if (this._mobile && this.mobileTray) {
|
76
|
+
this.maxHeight = null;
|
77
|
+
} else {
|
78
|
+
this.maxHeight = this.#maxHeightNonTray;
|
79
|
+
}
|
75
80
|
|
76
|
-
|
77
|
-
|
78
|
-
this.
|
79
|
-
|
80
|
-
this.
|
81
|
+
this.addEventListener('animationend', this.#handleAnimationEnd);
|
82
|
+
this.addEventListener('d2l-dropdown-open', this.#handleOpen);
|
83
|
+
this.addEventListener('d2l-dropdown-close', this.#handleClose);
|
84
|
+
this.addEventListener('d2l-menu-resize', this.#handleMenuResize);
|
85
|
+
this.addEventListener('d2l-menu-item-select', this.#handleSelect);
|
86
|
+
this.addEventListener('d2l-selection-action-click', this.#handleSelect);
|
87
|
+
this.addEventListener('d2l-menu-item-change', this.#handleChange);
|
88
|
+
this.addEventListener('focus', this.#handleFocus);
|
81
89
|
}
|
82
90
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
this.addEventListener('d2l-menu-resize', this._onMenuResize);
|
87
|
-
this.addEventListener('d2l-menu-item-select', this._onSelect);
|
88
|
-
this.addEventListener('d2l-selection-action-click', this._onSelect);
|
89
|
-
this.addEventListener('d2l-menu-item-change', this._onChange);
|
90
|
-
this.addEventListener('focus', this._onFocus);
|
91
|
-
}
|
91
|
+
#initializingHeight;
|
92
|
+
#initiallyOpenedSuppressFocus;
|
93
|
+
#maxHeightNonTray;
|
92
94
|
|
93
|
-
|
94
|
-
|
95
|
-
|
95
|
+
#getMenuElement() {
|
96
|
+
return this.shadowRoot?.querySelector('.dropdown-content > slot')
|
97
|
+
.assignedNodes()
|
98
|
+
.filter(node => node.hasAttribute && (node.getAttribute('role') === 'menu' || node.getAttribute('role') === 'listbox'))[0];
|
99
|
+
}
|
96
100
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
.
|
101
|
-
|
102
|
-
}
|
101
|
+
#handleAnimationEnd() {
|
102
|
+
if (!this._closeRadio) return;
|
103
|
+
this._closeRadio = false;
|
104
|
+
this.close();
|
105
|
+
}
|
103
106
|
|
104
|
-
|
105
|
-
|
106
|
-
this._closeRadio = false;
|
107
|
-
this.close();
|
108
|
-
}
|
107
|
+
#handleChange(e) {
|
108
|
+
if (e.target.getAttribute('role') !== 'menuitemradio') return;
|
109
109
|
|
110
|
-
|
111
|
-
|
112
|
-
|
110
|
+
if (reduceMotion) {
|
111
|
+
// Don't trigger the animation but still wait before closing the dropdown
|
112
|
+
setTimeout(() => {
|
113
|
+
this.close();
|
114
|
+
}, dropdownDelay);
|
115
|
+
} else {
|
116
|
+
this._closeRadio = true;
|
117
|
+
}
|
113
118
|
}
|
114
119
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
this._closeRadio = true;
|
120
|
+
#handleClose(e) {
|
121
|
+
if (e.target !== this) return;
|
122
|
+
|
123
|
+
// reset to root view
|
124
|
+
const menu = this.#getMenuElement();
|
125
|
+
menu.show({ preventFocus: true });
|
122
126
|
}
|
123
|
-
}
|
124
127
|
|
125
|
-
|
128
|
+
#handleFocus(e) {
|
129
|
+
// ignore focus events originating from inside dropdown content,
|
130
|
+
// such as the mobile tray close button, as to not move focus
|
131
|
+
if (e.srcElement === this) return;
|
132
|
+
this.#getMenuElement().focus();
|
133
|
+
}
|
134
|
+
|
135
|
+
#handleMenuResize(e) {
|
136
|
+
|
137
|
+
if (this._mobile && this.mobileTray) {
|
138
|
+
this.maxHeight = null;
|
139
|
+
} else {
|
140
|
+
this.maxHeight = this.#maxHeightNonTray;
|
141
|
+
}
|
126
142
|
|
127
|
-
|
128
|
-
|
143
|
+
this.position(e.detail, { updateLocation: this.#initializingHeight });
|
144
|
+
this.#initializingHeight = false;
|
145
|
+
|
146
|
+
const menu = this.#getMenuElement();
|
147
|
+
if (menu.getMenuType() === 'menu-radio') {
|
148
|
+
const selected = menu.querySelector('[selected]');
|
149
|
+
if (selected !== null) {
|
150
|
+
setTimeout(() => selected.scrollIntoView({ block: 'nearest' }), 0);
|
151
|
+
}
|
152
|
+
}
|
129
153
|
}
|
130
154
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
155
|
+
#handleOpen(e) {
|
156
|
+
if (e.target !== this) return;
|
157
|
+
|
158
|
+
this.#initializingHeight = true;
|
159
|
+
this._closeRadio = false;
|
160
|
+
|
161
|
+
const menu = this.#getMenuElement();
|
162
|
+
menu.resize();
|
163
|
+
|
164
|
+
// If dropdown-menu is opened on first render, do not focus
|
165
|
+
if (this.#initiallyOpenedSuppressFocus) this.#initiallyOpenedSuppressFocus = false;
|
166
|
+
else menu.focus();
|
167
|
+
}
|
168
|
+
|
169
|
+
#handleSelect(e) {
|
170
|
+
if (['D2L-MENU-ITEM', 'D2L-MENU-ITEM-LINK', 'D2L-SELECTION-ACTION-MENU-ITEM'].indexOf(e.target.tagName) < 0) {
|
171
|
+
return;
|
172
|
+
}
|
173
|
+
this.close();
|
174
|
+
}
|
135
175
|
|
136
|
-
_onFocus(e) {
|
137
|
-
// ignore focus events originating from inside dropdown content,
|
138
|
-
// such as the mobile tray close button, as to not move focus
|
139
|
-
if (e.srcElement === this) return;
|
140
|
-
this.__getMenuElement().focus();
|
141
176
|
}
|
177
|
+
customElements.define('d2l-dropdown-menu', DropdownMenu);
|
178
|
+
|
179
|
+
} else {
|
180
|
+
|
181
|
+
/**
|
182
|
+
* A container for a "d2l-menu". It provides additional support on top of "d2l-dropdown-content" for closing the menu when menu items are selected, resetting to the root of nested menus when reopening and automatic resizing when the menu resizes.
|
183
|
+
* @slot - Anything inside of "d2l-dropdown-content" that isn't in the "header" or "footer" slots appears as regular content
|
184
|
+
* @slot header - Sticky container at the top of the dropdown
|
185
|
+
* @slot footer - Sticky container at the bottom of the dropdown
|
186
|
+
* @fires d2l-dropdown-open - Dispatched when the dropdown is opened
|
187
|
+
*/
|
188
|
+
class DropdownMenu extends ThemeMixin(DropdownContentMixin(LitElement)) {
|
189
|
+
|
190
|
+
static get properties() {
|
191
|
+
return {
|
192
|
+
_closeRadio: {
|
193
|
+
type: Boolean,
|
194
|
+
reflect: true,
|
195
|
+
attribute: '_close-radio'
|
196
|
+
},
|
197
|
+
};
|
198
|
+
}
|
199
|
+
|
200
|
+
static get styles() {
|
201
|
+
return [
|
202
|
+
dropdownContentStyles,
|
203
|
+
css`
|
204
|
+
:host {
|
205
|
+
--d2l-dropdown-close-animation-name: d2l-dropdown-close-animation;
|
206
|
+
}
|
207
|
+
|
208
|
+
:host([theme="dark"]) {
|
209
|
+
--d2l-dropdown-close-animation-name: d2l-dropdown-close-animation-dark;
|
210
|
+
}
|
211
|
+
|
212
|
+
:host([_close-radio]) {
|
213
|
+
animation: var(--d2l-dropdown-close-animation-name) ${dropdownDelay}ms ease-out;
|
214
|
+
animation-delay: 50ms;
|
215
|
+
}
|
216
|
+
|
217
|
+
@media (prefers-reduced-motion: reduce) {
|
218
|
+
:host([_close-radio]) {
|
219
|
+
animation: none !important;
|
220
|
+
}
|
221
|
+
}
|
222
|
+
@keyframes d2l-dropdown-close-animation {
|
223
|
+
0% { opacity: 1; transform: translate(0, 0); }
|
224
|
+
100% { opacity: 0; transform: translate(0, -10px); }
|
225
|
+
}
|
142
226
|
|
143
|
-
|
227
|
+
@keyframes d2l-dropdown-close-animation-dark {
|
228
|
+
0% { opacity: 0.9; transform: translate(0, 0); }
|
229
|
+
100% { opacity: 0; transform: translate(0, -10px); }
|
230
|
+
}
|
231
|
+
`
|
232
|
+
];
|
233
|
+
}
|
144
234
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
this.
|
235
|
+
constructor() {
|
236
|
+
super();
|
237
|
+
this.noAutoFocus = true;
|
238
|
+
this.noPadding = true;
|
239
|
+
this._closeRadio = false;
|
240
|
+
this._initiallyOpenedSuppressFocus = false;
|
241
|
+
this._maxHeightNonTray = this.maxHeight;
|
149
242
|
}
|
150
243
|
|
151
|
-
|
152
|
-
|
244
|
+
firstUpdated(changedProperties) {
|
245
|
+
super.firstUpdated(changedProperties);
|
246
|
+
|
247
|
+
if (this.opened) this._initiallyOpenedSuppressFocus = true;
|
153
248
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
249
|
+
this._maxHeightNonTray = this.maxHeight;
|
250
|
+
if (this._useMobileStyling && this.mobileTray) {
|
251
|
+
this.maxHeight = null;
|
252
|
+
} else {
|
253
|
+
this.maxHeight = this._maxHeightNonTray;
|
159
254
|
}
|
255
|
+
|
256
|
+
this.addEventListener('animationend', this._onAnimationEnd);
|
257
|
+
this.addEventListener('d2l-dropdown-open', this._onOpen);
|
258
|
+
this.addEventListener('d2l-dropdown-close', this._onClose);
|
259
|
+
this.addEventListener('d2l-menu-resize', this._onMenuResize);
|
260
|
+
this.addEventListener('d2l-menu-item-select', this._onSelect);
|
261
|
+
this.addEventListener('d2l-selection-action-click', this._onSelect);
|
262
|
+
this.addEventListener('d2l-menu-item-change', this._onChange);
|
263
|
+
this.addEventListener('focus', this._onFocus);
|
160
264
|
}
|
161
|
-
}
|
162
265
|
|
163
|
-
|
266
|
+
render() {
|
267
|
+
return this._renderContent();
|
268
|
+
}
|
164
269
|
|
165
|
-
|
166
|
-
return;
|
270
|
+
__getMenuElement() {
|
271
|
+
if (!this.shadowRoot) return undefined;
|
272
|
+
return this.shadowRoot.querySelector('.d2l-dropdown-content-slot')
|
273
|
+
.assignedNodes().filter(node => node.hasAttribute
|
274
|
+
&& (node.getAttribute('role') === 'menu' || node.getAttribute('role') === 'listbox'))[0];
|
167
275
|
}
|
168
|
-
this._initializingHeight = true;
|
169
|
-
this._closeRadio = false;
|
170
276
|
|
171
|
-
|
277
|
+
_onAnimationEnd() {
|
278
|
+
if (!this._closeRadio) return;
|
279
|
+
this._closeRadio = false;
|
280
|
+
this.close();
|
281
|
+
}
|
172
282
|
|
173
|
-
|
283
|
+
_onChange(e) {
|
284
|
+
if (e.target.getAttribute('role') !== 'menuitemradio') {
|
285
|
+
return;
|
286
|
+
}
|
174
287
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
288
|
+
if (reduceMotion) {
|
289
|
+
// Don't trigger the animation but still wait before closing the dropdown
|
290
|
+
setTimeout(() => {
|
291
|
+
this.close();
|
292
|
+
}, dropdownDelay);
|
293
|
+
} else {
|
294
|
+
this._closeRadio = true;
|
295
|
+
}
|
296
|
+
}
|
297
|
+
|
298
|
+
_onClose(e) {
|
299
|
+
|
300
|
+
if (e.target !== this) {
|
301
|
+
return;
|
302
|
+
}
|
303
|
+
|
304
|
+
// reset to root view
|
305
|
+
const menu = this.__getMenuElement();
|
306
|
+
menu.show({ preventFocus: true });
|
307
|
+
}
|
308
|
+
|
309
|
+
_onFocus(e) {
|
310
|
+
// ignore focus events originating from inside dropdown content,
|
311
|
+
// such as the mobile tray close button, as to not move focus
|
312
|
+
if (e.srcElement === this) return;
|
313
|
+
this.__getMenuElement().focus();
|
314
|
+
}
|
315
|
+
|
316
|
+
_onMenuResize(e) {
|
317
|
+
|
318
|
+
if (this._useMobileStyling && this.mobileTray) {
|
319
|
+
this.maxHeight = null;
|
320
|
+
} else {
|
321
|
+
this.maxHeight = this._maxHeightNonTray;
|
322
|
+
}
|
323
|
+
|
324
|
+
this.__position(e.detail, { updateAboveBelow: this._initializingHeight });
|
325
|
+
this._initializingHeight = false;
|
326
|
+
|
327
|
+
const menu = this.__getMenuElement();
|
328
|
+
if (menu.getMenuType() === 'menu-radio') {
|
329
|
+
const selected = menu.querySelector('[selected]');
|
330
|
+
if (selected !== null) {
|
331
|
+
setTimeout(() => selected.scrollIntoView({ block: 'nearest' }), 0);
|
332
|
+
}
|
333
|
+
}
|
334
|
+
}
|
335
|
+
|
336
|
+
_onOpen(e) {
|
337
|
+
|
338
|
+
if (e.target !== this) {
|
339
|
+
return;
|
340
|
+
}
|
341
|
+
this._initializingHeight = true;
|
342
|
+
this._closeRadio = false;
|
343
|
+
|
344
|
+
const menu = this.__getMenuElement();
|
179
345
|
|
180
|
-
|
181
|
-
|
182
|
-
|
346
|
+
menu.resize();
|
347
|
+
|
348
|
+
// If dropdown-menu is opened on first render, do not focus
|
349
|
+
if (this._initiallyOpenedSuppressFocus) this._initiallyOpenedSuppressFocus = false;
|
350
|
+
else menu.focus();
|
183
351
|
}
|
184
|
-
|
352
|
+
|
353
|
+
_onSelect(e) {
|
354
|
+
if (['D2L-MENU-ITEM', 'D2L-MENU-ITEM-LINK', 'D2L-SELECTION-ACTION-MENU-ITEM'].indexOf(e.target.tagName) < 0) {
|
355
|
+
return;
|
356
|
+
}
|
357
|
+
this.close();
|
358
|
+
}
|
359
|
+
|
185
360
|
}
|
361
|
+
customElements.define('d2l-dropdown-menu', DropdownMenu);
|
186
362
|
|
187
363
|
}
|
188
|
-
customElements.define('d2l-dropdown-menu', DropdownMenu);
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { getUniqueId } from '../../helpers/uniqueId.js';
|
2
2
|
import { isComposedAncestor } from '../../helpers/dom.js';
|
3
|
+
import { usePopoverMixin } from './dropdown-popover-mixin.js';
|
3
4
|
|
4
5
|
const intersectionObserver = new IntersectionObserver(entries => {
|
5
6
|
entries.forEach(entry => {
|
@@ -260,7 +261,10 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
260
261
|
if (!this.openOnHover) return;
|
261
262
|
// do not respond to hover events on mobile screens
|
262
263
|
const dropdownContent = this.__getContentElement();
|
263
|
-
|
264
|
+
|
265
|
+
if (usePopoverMixin && dropdownContent._mobile) return;
|
266
|
+
else if (!usePopoverMixin && dropdownContent._useMobileStyling) return; // Flag cleanup: GAUD-7472-dropdown-popover
|
267
|
+
|
264
268
|
clearTimeout(this._dismissTimerId);
|
265
269
|
if (!this.dropdownOpened) await this.openDropdown(false);
|
266
270
|
this._closeTimerStop();
|
@@ -271,7 +275,10 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
271
275
|
if (!this.openOnHover) return;
|
272
276
|
// do not respond to hover events on mobile screens
|
273
277
|
const dropdownContent = this.__getContentElement();
|
274
|
-
|
278
|
+
|
279
|
+
if (usePopoverMixin && dropdownContent._mobile) return;
|
280
|
+
else if (!usePopoverMixin && dropdownContent._useMobileStyling) return; // Flag cleanup: GAUD-7472-dropdown-popover
|
281
|
+
|
275
282
|
this._isHovering = false;
|
276
283
|
if (this._isOpenedViaClick) return;
|
277
284
|
//Wait before closing so we don't lose hover when we jump from opener to card
|
@@ -317,11 +324,15 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
317
324
|
this._isHovering = false;
|
318
325
|
this.openDropdown(false);
|
319
326
|
}
|
320
|
-
} else
|
327
|
+
} else {
|
328
|
+
this.toggleOpen(true);
|
329
|
+
}
|
321
330
|
}
|
322
331
|
|
323
332
|
__updateContentVisibility(visible) {
|
324
|
-
|
333
|
+
if (!usePopoverMixin) {
|
334
|
+
this.__getContentElement().offscreen = !visible; // Flag cleanup: GAUD-7472-dropdown-popover
|
335
|
+
}
|
325
336
|
}
|
326
337
|
|
327
338
|
/* used by open-on-hover option */
|
@@ -345,11 +356,15 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
345
356
|
/* used by open-on-hover option */
|
346
357
|
_onOutsideClick(e) {
|
347
358
|
if (!this.dropdownOpened) return;
|
348
|
-
const
|
359
|
+
const dropdownContent = this.__getContentElement();
|
360
|
+
const isWithinDropdown = isComposedAncestor(dropdownContent, e.composedPath()[0]);
|
349
361
|
const isWithinOpener = isComposedAncestor(this.getOpenerElement(), e.composedPath()[0]);
|
362
|
+
|
363
|
+
// Flag cleanup: GAUD-7472-dropdown-popover
|
350
364
|
const isBackdropClick = isWithinDropdown
|
351
|
-
&&
|
365
|
+
&& ((!usePopoverMixin && dropdownContent._useMobileStyling) || (usePopoverMixin && dropdownContent._mobile))
|
352
366
|
&& e.composedPath().find(node => node.nodeName === 'D2L-BACKDROP');
|
367
|
+
|
353
368
|
if (!isWithinOpener && (!isWithinDropdown || isBackdropClick)) {
|
354
369
|
this.closeDropdown();
|
355
370
|
}
|