@brightspace-ui/core 1.197.1 → 1.198.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/README.md +4 -0
- package/components/dropdown/demo/dropdown-button.html +30 -0
- package/components/dropdown/dropdown-content-styles.js +13 -0
- package/components/dropdown/dropdown-opener-mixin.js +221 -24
- package/components/filter/README.md +15 -6
- package/components/filter/screenshots/filter-mobile.png +0 -0
- package/components/filter/screenshots/filter-multi-dim.png +0 -0
- package/components/filter/screenshots/filter.png +0 -0
- package/components/html-block/html-block.js +8 -0
- package/components/inputs/docs/input-date-time.md +7 -7
- package/components/list/list-item-button-mixin.js +1 -0
- package/components/list/list-item-button.js +0 -3
- package/components/list/list-item-checkbox-mixin.js +1 -0
- package/components/list/list-item-drag-drop-mixin.js +2 -0
- package/components/list/list-item-link-mixin.js +1 -0
- package/components/list/list-item.js +0 -3
- package/components/list/list.js +2 -0
- package/components/menu/menu-item-checkbox.js +0 -4
- package/components/menu/menu-item-link.js +0 -2
- package/components/menu/menu-item-mixin.js +3 -0
- package/components/menu/menu-item-radio.js +0 -3
- package/components/menu/menu-item-selectable-mixin.js +2 -0
- package/components/menu/menu-item.js +0 -2
- package/components/overflow-group/overflow-group.js +4 -3
- package/components/scroll-wrapper/scroll-wrapper.js +1 -2
- package/components/selection/selection-action.js +4 -0
- package/components/selection/selection-input.js +5 -0
- package/components/selection/selection-mixin.js +2 -1
- package/components/selection/selection-observer-mixin.js +3 -1
- package/components/selection/selection-select-all.js +2 -0
- package/components/selection/selection-summary.js +3 -1
- package/components/skeleton/skeleton-mixin.js +1 -0
- package/components/status-indicator/status-indicator.js +2 -0
- package/components/switch/switch-visibility.js +3 -0
- package/components/switch/switch.js +3 -0
- package/components/table/table-col-sort-button.js +0 -2
- package/components/table/table-wrapper.js +0 -2
- package/components/tabs/tab-panel-mixin.js +2 -0
- package/components/tabs/tab-panel.js +0 -2
- package/custom-elements.json +104 -29
- package/lang/ar.js +7 -7
- package/lang/cy.js +7 -7
- package/lang/da.js +7 -7
- package/lang/de.js +7 -7
- package/lang/es-es.js +7 -7
- package/lang/es.js +8 -8
- package/lang/fr-fr.js +8 -8
- package/lang/fr.js +7 -7
- package/lang/ja.js +8 -8
- package/lang/ko.js +7 -7
- package/lang/nl.js +8 -8
- package/lang/pt.js +7 -7
- package/lang/sv.js +7 -7
- package/lang/tr.js +7 -7
- package/lang/zh-tw.js +7 -7
- package/lang/zh.js +8 -8
- package/package.json +1 -1
- package/templates/primary-secondary/primary-secondary.js +2 -0
|
@@ -117,6 +117,7 @@ If the dropdown is initially empty when it's opened, the dropdown pointer will n
|
|
|
117
117
|
| `disabled` | Boolean, default: `false` | Disables the dropdown opener |
|
|
118
118
|
| `no-auto-open` | Boolean, default: `false` | Prevents the dropdown from opening automatically on click or on key press |
|
|
119
119
|
| `primary` | Boolean, default: `false` | Optionally render button as primary button |
|
|
120
|
+
| `open-on-hover` | Boolean, default: `false` | Optionally open dropdown on click or hover action |
|
|
120
121
|
<!-- docs: end hidden content -->
|
|
121
122
|
|
|
122
123
|
## Opener: Button Subtle [d2l-dropdown-button-subtle]
|
|
@@ -160,6 +161,7 @@ If the dropdown is initially empty when it's opened, the dropdown pointer will n
|
|
|
160
161
|
| `description` | String | A description to be added to the inner `button` opener for accessibility |
|
|
161
162
|
| `disabled` | Boolean, default: `false` | Disables the dropdown opener |
|
|
162
163
|
| `no-auto-open` | Boolean, default: `false` | Prevents the dropdown from automatically on click or on key press |
|
|
164
|
+
| `open-on-hover` | Boolean, default: `false` | Optionally open dropdown on click or hover action |
|
|
163
165
|
<!-- docs: end hidden content -->
|
|
164
166
|
|
|
165
167
|
### Accessibility Properties
|
|
@@ -209,6 +211,7 @@ To make your `d2l-dropdown-button-subtle` accessible, use the following properti
|
|
|
209
211
|
|---|---|---|
|
|
210
212
|
| `disabled` | Boolean, default: `false` | Disables the dropdown opener |
|
|
211
213
|
| `no-auto-open` | Boolean, default: `false` | Prevents the dropdown from opening automatically on click or on key press |
|
|
214
|
+
| `open-on-hover` | Boolean, default: `false` | Optionally open dropdown on click or hover action |
|
|
212
215
|
| `text` | String | Used as `aria-label` for the button |
|
|
213
216
|
| `translucent` | Boolean, default: `false` | Attribute for busy/rich backgrounds |
|
|
214
217
|
| `visible-on-ancestor` | Boolean, default: `false` | See [visible-on-ancestor-mixin](../../mixins/visible-on-ancestor-mixin.md) for more details on configuring that behavior |
|
|
@@ -261,6 +264,7 @@ To make your usage of `d2l-dropdown-context-menu` accessible, use the following
|
|
|
261
264
|
|---|---|---|
|
|
262
265
|
| `disabled` | Boolean, default: `false` | Disables the dropdown opener |
|
|
263
266
|
| `no-auto-open` | Boolean, default: `false` | Prevents the dropdown from opening automatically on click or key press |
|
|
267
|
+
| `open-on-hover` | Boolean, default: `false` | Optionally open dropdown on click or hover action |
|
|
264
268
|
| `text` | String | Used as `aria-label` for the button |
|
|
265
269
|
| `translucent` | Boolean, default: `false` | Attribute for busy/rich backgrounds |
|
|
266
270
|
| `visible-on-ancestor` | Boolean, default: `false` | See [visible-on-ancestor-mixin](../../mixins/visible-on-ancestor-mixin.md) for more details on configuring that behavior |
|
|
@@ -65,6 +65,36 @@
|
|
|
65
65
|
</template>
|
|
66
66
|
</d2l-demo-snippet>
|
|
67
67
|
|
|
68
|
+
<h2>Dropdown Button Opener (open-on-hover Option)</h2>
|
|
69
|
+
<d2l-demo-snippet>
|
|
70
|
+
<template>
|
|
71
|
+
<d2l-dropdown-button text="Open!" open-on-hover>
|
|
72
|
+
<d2l-dropdown-content mobile-tray="right">
|
|
73
|
+
<div slot="header">
|
|
74
|
+
<h3>Scrolling is Fun</h3>
|
|
75
|
+
</div>
|
|
76
|
+
<a href="https://youtu.be/9ze87zQFSak">Google</a>
|
|
77
|
+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
|
|
78
|
+
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
|
79
|
+
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat
|
|
80
|
+
nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
|
|
81
|
+
anim id est laborum.Vestibulum vel sem non orci pretium fringilla sed eget augue. Vestibulum malesuada tortor
|
|
82
|
+
vitae odio elementum eleifend. Quisque ligula quam, ornare id malesuada ut, malesuada eleifend sem. Nulla porta
|
|
83
|
+
in arcu quis gravida. Duis ac sagittis felis, in condimentum libero. In dolor risus, semper vel iaculis vitae,
|
|
84
|
+
pellentesque efficitur lorem. Nunc a lacus malesuada, rhoncus risus aliquam, sodales nulla. Sed in varius elit.
|
|
85
|
+
Duis sagittis, turpis ut vehicula elementum, velit mi tincidunt turpis, sit amet sagittis quam urna ut justo.
|
|
86
|
+
Nunc interdum urna augue, ac pretium dui pulvinar eu. Proin vehicula placerat est, sed venenatis purus viverra
|
|
87
|
+
eget. Suspendisse imperdiet nulla eget velit sodales, sit amet tempus metus dignissim. Sed ac luctus leo, a
|
|
88
|
+
ornare nisl. Proin non sapien eu orci gravida aliquam. Praesent placerat auctor lacus sit amet faucibus.
|
|
89
|
+
Suspendisse sit amet dui sed turpis vestibulum dignissim.</p>
|
|
90
|
+
<div slot="footer">
|
|
91
|
+
<a href="http://www.desire2learn.com">D2L</a>
|
|
92
|
+
</div>
|
|
93
|
+
</d2l-dropdown-content>
|
|
94
|
+
</d2l-dropdown-button>
|
|
95
|
+
</template>
|
|
96
|
+
</d2l-demo-snippet>
|
|
97
|
+
|
|
68
98
|
</d2l-demo-page>
|
|
69
99
|
|
|
70
100
|
</body>
|
|
@@ -172,6 +172,19 @@ export const dropdownContentStyles = css`
|
|
|
172
172
|
text-align: right;
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
:host(.d2l-dropdown-content-fading) {
|
|
176
|
+
opacity: 0;
|
|
177
|
+
/* matches DropdownOpenerMixin _closeTimerStart function */
|
|
178
|
+
transition: opacity 0.4s ease-out 0.3s;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
@media (prefers-reduced-motion: reduce) {
|
|
182
|
+
:host(.d2l-dropdown-content-fading) {
|
|
183
|
+
opacity: 1;
|
|
184
|
+
transition: none;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
175
188
|
@media (prefers-reduced-motion: reduce) {
|
|
176
189
|
:host([opened]), :host([opened-above]) {
|
|
177
190
|
animation: none !important;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { getUniqueId } from '../../helpers/uniqueId.js';
|
|
2
|
+
import { isComposedAncestor } from '../../helpers/dom.js';
|
|
3
|
+
|
|
1
4
|
export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
2
5
|
|
|
3
6
|
static get properties() {
|
|
@@ -27,6 +30,19 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
|
27
30
|
reflect: true,
|
|
28
31
|
attribute: 'no-auto-open'
|
|
29
32
|
},
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Optionally open dropdown on click or hover action
|
|
36
|
+
* @type {boolean}
|
|
37
|
+
*/
|
|
38
|
+
openOnHover: {
|
|
39
|
+
type: Boolean,
|
|
40
|
+
attribute: 'open-on-hover'
|
|
41
|
+
},
|
|
42
|
+
_isHovering: { type: Boolean },
|
|
43
|
+
_isOpen: { type: Boolean },
|
|
44
|
+
_isOpenedViaClick: { type: Boolean },
|
|
45
|
+
_isFading: { type: Boolean }
|
|
30
46
|
};
|
|
31
47
|
}
|
|
32
48
|
|
|
@@ -34,36 +50,49 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
|
34
50
|
super();
|
|
35
51
|
this.dropdownOpener = true;
|
|
36
52
|
this.noAutoOpen = false;
|
|
53
|
+
this.openOnHover = false;
|
|
37
54
|
this.disabled = false;
|
|
38
55
|
|
|
39
|
-
|
|
56
|
+
// hover option
|
|
57
|
+
this._dismissTimerId = getUniqueId();
|
|
58
|
+
this._isOpen = false;
|
|
59
|
+
this._isOpenedViaClick = false;
|
|
60
|
+
this._isHovering = false;
|
|
61
|
+
this._isFading = false;
|
|
62
|
+
|
|
63
|
+
this.__onWholeKeypress = this.__onKeypress.bind(this);
|
|
40
64
|
this.__onMouseUp = this.__onMouseUp.bind(this);
|
|
65
|
+
this.__onMouseEnter = this.__onMouseEnter.bind(this);
|
|
66
|
+
this.__onMouseLeave = this.__onMouseLeave.bind(this);
|
|
67
|
+
this._contentRendered = null;
|
|
68
|
+
this._openerRendered = null;
|
|
41
69
|
}
|
|
42
70
|
|
|
43
71
|
connectedCallback() {
|
|
44
72
|
super.connectedCallback();
|
|
45
73
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
opener.setAttribute('aria-expanded', (content && content.opened || false).toString());
|
|
56
|
-
});
|
|
74
|
+
// listeners
|
|
75
|
+
this.addEventListener('keypress', this.__onKeypress);
|
|
76
|
+
this.addEventListener('mouseup', this.__onMouseUp);
|
|
77
|
+
this.addEventListener('mouseenter', this.__onMouseEnter);
|
|
78
|
+
this.addEventListener('mouseleave', this.__onMouseLeave);
|
|
79
|
+
|
|
80
|
+
if (this.openOnHover) {
|
|
81
|
+
document.body.addEventListener('mouseup', this._onOutsideClick);
|
|
82
|
+
}
|
|
57
83
|
}
|
|
58
84
|
|
|
59
85
|
disconnectedCallback() {
|
|
60
86
|
super.disconnectedCallback();
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
87
|
+
|
|
88
|
+
this.removeEventListener('keypress', this.__onKeypress);
|
|
89
|
+
this.removeEventListener('mouseup', this.__onMouseUp);
|
|
90
|
+
this.removeEventListener('mouseenter', this.__onMouseEnter);
|
|
91
|
+
this.removeEventListener('mouseleave', this.__onMouseLeave);
|
|
92
|
+
|
|
93
|
+
if (this.openOnHover) {
|
|
94
|
+
document.body.removeEventListener('mouseup', this._onOutsideClick);
|
|
64
95
|
}
|
|
65
|
-
opener.removeEventListener('keypress', this.__onKeyPress);
|
|
66
|
-
opener.removeEventListener('mouseup', this.__onMouseUp);
|
|
67
96
|
}
|
|
68
97
|
|
|
69
98
|
firstUpdated(changedProperties) {
|
|
@@ -71,6 +100,38 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
|
71
100
|
|
|
72
101
|
this.addEventListener('d2l-dropdown-open', this.__onOpened);
|
|
73
102
|
this.addEventListener('d2l-dropdown-close', this.__onClosed);
|
|
103
|
+
|
|
104
|
+
const opener = this.getOpenerElement();
|
|
105
|
+
const content = this.__getContentElement();
|
|
106
|
+
if (!opener) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
opener.setAttribute('aria-haspopup', 'true');
|
|
110
|
+
opener.setAttribute('aria-expanded', (content && content.opened || false).toString());
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
updated(changedProperties) {
|
|
114
|
+
super.updated(changedProperties);
|
|
115
|
+
if (!this.openOnHover || !changedProperties.has('_isFading')) return;
|
|
116
|
+
|
|
117
|
+
if (this._isFading) {
|
|
118
|
+
this.__getContentElement()?.classList.add('d2l-dropdown-content-fading');
|
|
119
|
+
} else {
|
|
120
|
+
this.__getContentElement()?.classList.remove('d2l-dropdown-content-fading');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* used by open-on-hover option */
|
|
125
|
+
async closeDropdown(fadeOut) {
|
|
126
|
+
this._isOpen = false;
|
|
127
|
+
this._isHovering = false;
|
|
128
|
+
this._isOpenedViaClick = false;
|
|
129
|
+
if (fadeOut) {
|
|
130
|
+
this._closeTimerStart();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const dropdownContent = this.__getContentElement();
|
|
134
|
+
await dropdownContent.close();
|
|
74
135
|
}
|
|
75
136
|
|
|
76
137
|
focus() {
|
|
@@ -89,6 +150,15 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
|
89
150
|
return this;
|
|
90
151
|
}
|
|
91
152
|
|
|
153
|
+
/* used by open-on-hover option */
|
|
154
|
+
async openDropdown(applyFocus) {
|
|
155
|
+
this._isOpen = true;
|
|
156
|
+
const dropdownContent = this.__getContentElement();
|
|
157
|
+
if (!dropdownContent) return;
|
|
158
|
+
await dropdownContent.open(applyFocus);
|
|
159
|
+
await dropdownContent.updateComplete;
|
|
160
|
+
}
|
|
161
|
+
|
|
92
162
|
toggleOpen(applyFocus) {
|
|
93
163
|
if (this.disabled) {
|
|
94
164
|
return;
|
|
@@ -99,6 +169,7 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
|
99
169
|
return;
|
|
100
170
|
}
|
|
101
171
|
content.toggleOpen(applyFocus);
|
|
172
|
+
this._isOpen = !this._isOpen;
|
|
102
173
|
}
|
|
103
174
|
|
|
104
175
|
__getContentElement() {
|
|
@@ -113,17 +184,61 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
|
113
184
|
}
|
|
114
185
|
opener.setAttribute('aria-expanded', 'false');
|
|
115
186
|
opener.removeAttribute('active');
|
|
187
|
+
this._isOpen = false;
|
|
188
|
+
this._isOpenedViaClick = false;
|
|
116
189
|
}
|
|
117
190
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
this.
|
|
191
|
+
/* used by open-on-hover option */
|
|
192
|
+
__onDropdownMouseEnter() {
|
|
193
|
+
this._isOpen = true;
|
|
194
|
+
this._isFading = false;
|
|
195
|
+
this._closeTimerStop();
|
|
122
196
|
}
|
|
123
197
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
this.
|
|
198
|
+
/* used by open-on-hover option */
|
|
199
|
+
__onDropdownMouseLeave(e) {
|
|
200
|
+
if (this.__getContentElement() !== e.target) return;
|
|
201
|
+
if (!this._isOpenedViaClick) this._isOpen = false;
|
|
202
|
+
this._closeTimerStart();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
__onDropdownMouseUp() {
|
|
206
|
+
this._isOpen = true;
|
|
207
|
+
this._isFading = false;
|
|
208
|
+
this._isOpenedViaClick = true;
|
|
209
|
+
this._closeTimerStop();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
__onKeypress(e) {
|
|
213
|
+
if (e.srcElement === this || isComposedAncestor(this.getOpenerElement(), e.srcElement)) {
|
|
214
|
+
this.__onOpenerKeyPress(e);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
__onMouseEnter(e) {
|
|
219
|
+
if (!this.openOnHover) return;
|
|
220
|
+
if (e.srcElement === this || isComposedAncestor(this.getOpenerElement(), e.srcElement)) {
|
|
221
|
+
this.__onOpenerMouseEnter(e);
|
|
222
|
+
} else if (isComposedAncestor(this.__getContentElement(), e.srcElement)) {
|
|
223
|
+
this.__onDropdownMouseEnter(e);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
__onMouseLeave(e) {
|
|
228
|
+
if (!this.openOnHover) return;
|
|
229
|
+
if (e.srcElement === this || isComposedAncestor(this.getOpenerElement(), e.srcElement)) {
|
|
230
|
+
this.__onOpenerMouseLeave(e);
|
|
231
|
+
} else if (isComposedAncestor(this.__getContentElement(), e.srcElement)) {
|
|
232
|
+
this.__onDropdownMouseLeave(e);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
__onMouseUp(e) {
|
|
237
|
+
if (e.srcElement === this || isComposedAncestor(this.getOpenerElement(), e.srcElement)) {
|
|
238
|
+
this.__onOpenerMouseUp(e);
|
|
239
|
+
} else if (this.openOnHover && isComposedAncestor(this.__getContentElement(), e.srcElement)) {
|
|
240
|
+
this.__onDropdownMouseUp();
|
|
241
|
+
}
|
|
127
242
|
}
|
|
128
243
|
|
|
129
244
|
__onOpened() {
|
|
@@ -133,6 +248,88 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
|
133
248
|
}
|
|
134
249
|
opener.setAttribute('aria-expanded', 'true');
|
|
135
250
|
opener.setAttribute('active', 'true');
|
|
251
|
+
this._isFading = false;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
__onOpenerKeyPress(e) {
|
|
255
|
+
if (e.keyCode !== 13 && e.keyCode !== 32) return;
|
|
256
|
+
if (this.noAutoOpen) return;
|
|
257
|
+
if (!this.openOnHover) {
|
|
258
|
+
this.toggleOpen(true);
|
|
259
|
+
} else {
|
|
260
|
+
this._closeTimerStop();
|
|
261
|
+
e.preventDefault();
|
|
262
|
+
this._isOpenedViaClick = true;
|
|
263
|
+
this.openDropdown(true);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* used by open-on-hover option */
|
|
268
|
+
async __onOpenerMouseEnter() {
|
|
269
|
+
// do not respond to hover events on mobile screens
|
|
270
|
+
const dropdownContent = this.__getContentElement();
|
|
271
|
+
if (dropdownContent._useMobileStyling) return;
|
|
272
|
+
clearTimeout(this._dismissTimerId);
|
|
273
|
+
if (!this._isOpen) await this.openDropdown(false);
|
|
274
|
+
this._closeTimerStop();
|
|
275
|
+
this._isHovering = true;
|
|
136
276
|
}
|
|
137
277
|
|
|
278
|
+
/* used by open-on-hover option */
|
|
279
|
+
async __onOpenerMouseLeave() {
|
|
280
|
+
// do not respond to hover events on mobile screens
|
|
281
|
+
const dropdownContent = this.__getContentElement();
|
|
282
|
+
if (dropdownContent._useMobileStyling) return;
|
|
283
|
+
this._isHovering = false;
|
|
284
|
+
if (this._isOpenedViaClick) return;
|
|
285
|
+
//Wait before closing so we don't lose hover when we jump from opener to card
|
|
286
|
+
clearTimeout(this._dismissTimerId);
|
|
287
|
+
await this.closeDropdown(true);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
__onOpenerMouseUp(e) {
|
|
291
|
+
if (this.noAutoOpen) return;
|
|
292
|
+
if (this.openOnHover) {
|
|
293
|
+
// prevent propogation to window and triggering _onOutsideClick
|
|
294
|
+
e?.stopPropagation();
|
|
295
|
+
this._closeTimerStop();
|
|
296
|
+
if (this._isOpen && !this._isHovering) {
|
|
297
|
+
this.closeDropdown();
|
|
298
|
+
} else {
|
|
299
|
+
this._isOpenedViaClick = true;
|
|
300
|
+
this._isHovering = false;
|
|
301
|
+
this.openDropdown(true);
|
|
302
|
+
}
|
|
303
|
+
} else this.toggleOpen(false);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/* used by open-on-hover option */
|
|
307
|
+
_closeTimerStart() {
|
|
308
|
+
if (this._isOpen) return;
|
|
309
|
+
clearTimeout(this._setTimeoutId);
|
|
310
|
+
this._isFading = true;
|
|
311
|
+
this._setTimeoutId = setTimeout(() => {
|
|
312
|
+
this.closeDropdown(false);
|
|
313
|
+
this._isFading = false;
|
|
314
|
+
// matches dropdownContentStyles CSS
|
|
315
|
+
}, 700);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/* used by open-on-hover option */
|
|
319
|
+
_closeTimerStop() {
|
|
320
|
+
clearTimeout(this._setTimeoutId);
|
|
321
|
+
this._isFading = false;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/* used by open-on-hover option */
|
|
325
|
+
_onOutsideClick(e) {
|
|
326
|
+
if (!this._isOpen) return;
|
|
327
|
+
const isWithinDropdown = isComposedAncestor(this.__getContentElement(), e.composedPath()[0]);
|
|
328
|
+
const isBackdropClick = isWithinDropdown
|
|
329
|
+
&& this.__getContentElement()._useMobileStyling
|
|
330
|
+
&& e.composedPath().find(node => node.nodeName === 'D2L-BACKDROP');
|
|
331
|
+
if (!isWithinDropdown || isBackdropClick) {
|
|
332
|
+
this.closeDropdown();
|
|
333
|
+
}
|
|
334
|
+
}
|
|
138
335
|
};
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# Filtering
|
|
2
2
|
|
|
3
|
-
**NOTE: This component is a work-in-progress and not ready for consumer use yet.**
|
|
4
|
-
|
|
5
3
|
Filter components are often used in conjuction with [tables](../../components/table) and allow users to select a subset of the presented data based on a set of parameters. Filter dimensions provide methods for entering parameters for a wide range of data types.
|
|
6
4
|
|
|
5
|
+
<!-- docs: start hidden content -->
|
|
6
|
+
Filter with multiple dimensions:
|
|
7
|
+

|
|
8
|
+
<!-- docs: end hidden content -->
|
|
9
|
+
|
|
7
10
|
<!-- docs: demo align:start autoSize:false size:large -->
|
|
8
11
|
```html
|
|
9
12
|
<script type="module">
|
|
@@ -47,10 +50,6 @@ Filter components are often used in conjuction with [tables](../../components/ta
|
|
|
47
50
|
|
|
48
51
|
The `d2l-filter` component allows a user to filter on one or more dimensions of data from a single dropdown.
|
|
49
52
|
|
|
50
|
-
<!-- docs: start hidden content -->
|
|
51
|
-
<!--  -->
|
|
52
|
-
<!-- docs: end hidden content -->
|
|
53
|
-
|
|
54
53
|
<!-- docs: demo live name:d2l-filter autoSize:false align:start size:large -->
|
|
55
54
|
```html
|
|
56
55
|
<script type="module">
|
|
@@ -96,6 +95,11 @@ The `d2l-filter` component allows a user to filter on one or more dimensions of
|
|
|
96
95
|
### Single Vs Multi Dimensional
|
|
97
96
|
A filter can be a single dimension (like picking from a list of courses) or offer multiple dimensions (filter by role, or department, or something else). Single-dimension filters can be used side-by-side to promote filters that are more commonly used, while tucking less-used filters into a multi-dimensional filter.
|
|
98
97
|
|
|
98
|
+
<!-- docs: start hidden content -->
|
|
99
|
+
Filter with a single dimension:
|
|
100
|
+

|
|
101
|
+
<!-- docs: end hidden content -->
|
|
102
|
+
|
|
99
103
|
<!-- docs: demo code autoSize:false align:start size:large -->
|
|
100
104
|
```html
|
|
101
105
|
<script type="module">
|
|
@@ -173,6 +177,11 @@ The filter will announce changes to filter selections, search results, and when
|
|
|
173
177
|
|
|
174
178
|
The `d2l-filter-dimension-set` component is the main dimension type that will work for most use cases. Used alongside the [d2l-filter-dimension-set-value](#filter-dimension%3A-set-value-%5Bd2l-filter-dimension-set-value%5D), this will give you a selectable list of filter values.
|
|
175
179
|
|
|
180
|
+
<!-- docs: start hidden content -->
|
|
181
|
+
Set dimension on mobile:
|
|
182
|
+

|
|
183
|
+
<!-- docs: end hidden content -->
|
|
184
|
+
|
|
176
185
|
<!-- docs: demo live name:d2l-filter-dimension-set align:start autoSize:false size:large -->
|
|
177
186
|
```html
|
|
178
187
|
<script type="module">
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -135,6 +135,14 @@ class HtmlBlock extends LitElement {
|
|
|
135
135
|
`];
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
connectedCallback() {
|
|
139
|
+
super.connectedCallback();
|
|
140
|
+
if (!this._templateObserver) return;
|
|
141
|
+
|
|
142
|
+
const template = this.querySelector('template');
|
|
143
|
+
if (template) this._templateObserver.observe(template.content, { attributes: true, childList: true, subtree: true });
|
|
144
|
+
}
|
|
145
|
+
|
|
138
146
|
disconnectedCallback() {
|
|
139
147
|
super.disconnectedCallback();
|
|
140
148
|
if (this._templateObserver) this._templateObserver.disconnect();
|
|
@@ -14,7 +14,7 @@ size:xlarge
|
|
|
14
14
|
</script>
|
|
15
15
|
<script>
|
|
16
16
|
window.addEventListener('load', function () {
|
|
17
|
-
|
|
17
|
+
var demoElem = document.querySelector('#demo-element');
|
|
18
18
|
if (!demoElem.hasAttribute('data-first-load')) return;
|
|
19
19
|
|
|
20
20
|
setTimeout(function() {
|
|
@@ -63,7 +63,7 @@ size:xlarge
|
|
|
63
63
|
<!-- docs: start hidden content -->
|
|
64
64
|
<script>
|
|
65
65
|
window.addEventListener('load', function () {
|
|
66
|
-
|
|
66
|
+
var demoElem = document.querySelector('#demo-element');
|
|
67
67
|
if (!demoElem.hasAttribute('data-first-load')) return;
|
|
68
68
|
|
|
69
69
|
setTimeout(function() {
|
|
@@ -131,7 +131,7 @@ size:xlarge
|
|
|
131
131
|
<!-- docs: start hidden content -->
|
|
132
132
|
<script>
|
|
133
133
|
window.addEventListener('load', function () {
|
|
134
|
-
|
|
134
|
+
var demoElem = document.querySelector('#demo-element');
|
|
135
135
|
if (!demoElem.hasAttribute('data-first-load')) return;
|
|
136
136
|
|
|
137
137
|
setTimeout(function() {
|
|
@@ -205,7 +205,7 @@ size:large
|
|
|
205
205
|
<!-- docs: start hidden content -->
|
|
206
206
|
<script>
|
|
207
207
|
window.addEventListener('load', function () {
|
|
208
|
-
|
|
208
|
+
var demoElem = document.querySelector('#demo-element');
|
|
209
209
|
if (!demoElem.hasAttribute('data-first-load')) return;
|
|
210
210
|
|
|
211
211
|
setTimeout(function() {
|
|
@@ -273,7 +273,7 @@ size:large
|
|
|
273
273
|
<!-- docs: start hidden content -->
|
|
274
274
|
<script>
|
|
275
275
|
window.addEventListener('load', function () {
|
|
276
|
-
|
|
276
|
+
var demoElem = document.querySelector('#demo-element');
|
|
277
277
|
if (!demoElem.hasAttribute('data-first-load')) return;
|
|
278
278
|
|
|
279
279
|
setTimeout(function() {
|
|
@@ -343,7 +343,7 @@ size:xlarge
|
|
|
343
343
|
<!-- docs: start hidden content -->
|
|
344
344
|
<script>
|
|
345
345
|
window.addEventListener('load', function () {
|
|
346
|
-
|
|
346
|
+
var demoElem = document.querySelector('#demo-element');
|
|
347
347
|
if (!demoElem.hasAttribute('data-first-load')) return;
|
|
348
348
|
|
|
349
349
|
setTimeout(function() {
|
|
@@ -412,7 +412,7 @@ size:xlarge
|
|
|
412
412
|
<!-- docs: start hidden content -->
|
|
413
413
|
<script>
|
|
414
414
|
window.addEventListener('load', function () {
|
|
415
|
-
|
|
415
|
+
var demoElem = document.querySelector('#demo-element');
|
|
416
416
|
if (!demoElem.hasAttribute('data-first-load')) return;
|
|
417
417
|
|
|
418
418
|
setTimeout(function() {
|
|
@@ -35,6 +35,7 @@ export const ListItemButtonMixin = superclass => class extends ListItemMixin(sup
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
_onButtonClick() {
|
|
38
|
+
/** Dispatched when the item's primary button action is clicked */
|
|
38
39
|
this.dispatchEvent(new CustomEvent('d2l-list-item-button-click', { bubbles: true }));
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -6,9 +6,6 @@ import { LitElement } from 'lit-element/lit-element.js';
|
|
|
6
6
|
* @slot - Default content placed inside of the component
|
|
7
7
|
* @slot illustration - Image associated with the list item located at the left of the item
|
|
8
8
|
* @slot actions - Actions (e.g., button icons) associated with the listen item located at the right of the item
|
|
9
|
-
* @fires d2l-list-item-button-click - Dispatched when the item's primary button action is clicked
|
|
10
|
-
* @fires d2l-list-item-position-change - Dispatched when a draggable list item's position changes in the list. See [Event Details: d2l-list-item-position-change](#event-details%3A-d2l-list-item-position-change).
|
|
11
|
-
* @fires d2l-list-item-selected - Dispatched when the component item is selected
|
|
12
9
|
*/
|
|
13
10
|
class ListItemButton extends ListItemButtonMixin(LitElement) {
|
|
14
11
|
|
|
@@ -105,6 +105,7 @@ export const ListItemCheckboxMixin = superclass => class extends SkeletonMixin(L
|
|
|
105
105
|
/* wait for internal state to be updated in case of action-click case so that a consumer
|
|
106
106
|
calling getSelectionInfo will get the correct state */
|
|
107
107
|
await this.updateComplete;
|
|
108
|
+
/** Dispatched when the component item is selected */
|
|
108
109
|
this.dispatchEvent(new CustomEvent('d2l-list-item-selected', {
|
|
109
110
|
detail: { key: this.key, selected: value },
|
|
110
111
|
composed: true,
|
|
@@ -265,6 +265,7 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
265
265
|
dragHandleText: { type: String, attribute: 'drag-handle-text' },
|
|
266
266
|
/**
|
|
267
267
|
* **Drag & drop:** Text to drag and drop
|
|
268
|
+
* @type {string}
|
|
268
269
|
*/
|
|
269
270
|
dropText: { type: String, attribute: 'drop-text' },
|
|
270
271
|
/**
|
|
@@ -351,6 +352,7 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
351
352
|
}
|
|
352
353
|
|
|
353
354
|
_annoucePositionChange(dragTargetKey, dropTargetKey, dropLocation) {
|
|
355
|
+
/** Dispatched when a draggable list item's position changes in the list. See [Event Details: d2l-list-item-position-change](#event-details%3A-d2l-list-item-position-change). */
|
|
354
356
|
this.dispatchEvent(new CustomEvent('d2l-list-item-position-change', {
|
|
355
357
|
detail: new NewPositionEventDetails({ dragTargetKey, dropTargetKey, dropLocation }),
|
|
356
358
|
bubbles: true
|
|
@@ -45,6 +45,7 @@ export const ListItemLinkMixin = superclass => class extends ListItemMixin(super
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
_handleLinkClick() {
|
|
48
|
+
/** Dispatched when the item's primary link action is clicked */
|
|
48
49
|
this.dispatchEvent(new CustomEvent('d2l-list-item-link-click', { bubbles: true }));
|
|
49
50
|
}
|
|
50
51
|
|
|
@@ -6,9 +6,6 @@ import { LitElement } from 'lit-element/lit-element.js';
|
|
|
6
6
|
* @slot - Default content placed inside of the component
|
|
7
7
|
* @slot illustration - Image associated with the list item located at the left of the item
|
|
8
8
|
* @slot actions - Actions (e.g., button icons) associated with the listen item located at the right of the item
|
|
9
|
-
* @fires d2l-list-item-link-click - Dispatched when the item's primary link action is clicked
|
|
10
|
-
* @fires d2l-list-item-position-change - Dispatched when a draggable list item's position changes in the list. See [Event Details: d2l-list-item-position-change](#event-details%3A-d2l-list-item-position-change).
|
|
11
|
-
* @fires d2l-list-item-selected - Dispatched when the component item is selected
|
|
12
9
|
*/
|
|
13
10
|
class ListItem extends ListItemLinkMixin(LitElement) {
|
|
14
11
|
|
package/components/list/list.js
CHANGED
|
@@ -18,10 +18,12 @@ class List extends SelectionMixin(LitElement) {
|
|
|
18
18
|
return {
|
|
19
19
|
/**
|
|
20
20
|
* Whether to extend the separators beyond the content's edge
|
|
21
|
+
* @type {boolean}
|
|
21
22
|
*/
|
|
22
23
|
extendSeparators: { type: Boolean, reflect: true, attribute: 'extend-separators' },
|
|
23
24
|
/**
|
|
24
25
|
* Use grid to manage focus with arrow keys. See [Accessibility](#accessibility).
|
|
26
|
+
* @type {boolean}
|
|
25
27
|
*/
|
|
26
28
|
grid: { type: Boolean },
|
|
27
29
|
/**
|
|
@@ -6,10 +6,6 @@ import { RtlMixin } from '../../mixins/rtl-mixin.js';
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* A menu item component used for selection. Multiple checkboxes can be selected at once.
|
|
9
|
-
* @fires click - Dispatched when the link is clicked
|
|
10
|
-
* @fires d2l-menu-item-change - Dispatched when the selected menu item changes
|
|
11
|
-
* @fires d2l-menu-item-select - Dispatched when the menu item is selected
|
|
12
|
-
* @fires d2l-menu-item-visibility-change - Dispatched when the visibility of the menu item changes
|
|
13
9
|
*/
|
|
14
10
|
class MenuItemCheckbox extends RtlMixin(MenuItemSelectableMixin(LitElement)) {
|
|
15
11
|
|
|
@@ -6,8 +6,6 @@ import { menuItemStyles } from './menu-item-styles.js';
|
|
|
6
6
|
/**
|
|
7
7
|
* A menu item component used for navigating.
|
|
8
8
|
* @fires click - Dispatched when the link is clicked
|
|
9
|
-
* @fires d2l-menu-item-select - Dispatched when the menu item is selected
|
|
10
|
-
* @fires d2l-menu-item-visibility-change - Dispatched when the visibility of the menu item changes
|
|
11
9
|
*/
|
|
12
10
|
class MenuItemLink extends MenuItemMixin(LitElement) {
|
|
13
11
|
|
|
@@ -4,6 +4,7 @@ export const MenuItemMixin = superclass => class extends superclass {
|
|
|
4
4
|
return {
|
|
5
5
|
/**
|
|
6
6
|
* Disables the menu item
|
|
7
|
+
* @type {boolean}
|
|
7
8
|
*/
|
|
8
9
|
disabled: { type: Boolean, reflect: true },
|
|
9
10
|
/**
|
|
@@ -100,6 +101,7 @@ export const MenuItemMixin = superclass => class extends superclass {
|
|
|
100
101
|
// assumption: single, focusable child view
|
|
101
102
|
this.__children[0].show();
|
|
102
103
|
} else {
|
|
104
|
+
/** Dispatched when the menu item is selected */
|
|
103
105
|
this.dispatchEvent(new CustomEvent('d2l-menu-item-select', { bubbles: true, composed: true }));
|
|
104
106
|
}
|
|
105
107
|
}
|
|
@@ -162,6 +164,7 @@ export const MenuItemMixin = superclass => class extends superclass {
|
|
|
162
164
|
}
|
|
163
165
|
|
|
164
166
|
_onHidden() {
|
|
167
|
+
/** Dispatched when the visibility of the menu item changes */
|
|
165
168
|
this.dispatchEvent(new CustomEvent('d2l-menu-item-visibility-change', { bubbles: true, composed: true }));
|
|
166
169
|
}
|
|
167
170
|
|