@brightspace-ui/core 1.196.2 → 1.196.3
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/backdrop/README.md +5 -6
- package/components/backdrop/backdrop.js +3 -0
- package/components/breadcrumbs/breadcrumbs.js +2 -1
- package/components/button/button-icon.js +1 -0
- package/components/button/button-mixin.js +2 -0
- package/components/button/button-subtle.js +1 -0
- package/components/button/button.js +1 -0
- package/components/button/floating-buttons.js +1 -0
- package/components/calendar/calendar.js +1 -1
- package/components/card/card-footer-link.js +12 -2
- package/components/card/card-loading-shimmer.js +1 -0
- package/components/card/card.js +9 -0
- package/components/dialog/dialog-confirm.js +1 -2
- package/components/dialog/dialog-fullscreen.js +4 -5
- package/components/dialog/dialog-mixin.js +2 -0
- package/components/dialog/dialog.js +0 -2
- package/components/dropdown/dropdown-button-subtle.js +3 -3
- package/components/dropdown/dropdown-button.js +2 -0
- package/components/dropdown/dropdown-content-mixin.js +19 -0
- package/components/dropdown/dropdown-content.js +0 -3
- package/components/dropdown/dropdown-context-menu.js +2 -0
- package/components/dropdown/dropdown-menu.js +0 -3
- package/components/dropdown/dropdown-more.js +2 -0
- package/components/dropdown/dropdown-opener-mixin.js +2 -0
- package/components/dropdown/dropdown-tabs.js +0 -3
- package/components/list/demo/list-item-custom.js +7 -3
- package/components/list/demo/list-nested.html +6 -62
- package/components/list/list-item-generic-layout.js +85 -14
- package/components/list/list.js +16 -2
- package/components/selection/selection-mixin.js +1 -0
- package/components/switch/switch-mixin.js +1 -0
- package/custom-elements.json +33 -71
- package/helpers/focus.js +4 -2
- package/mixins/labelled-mixin.js +1 -0
- package/package.json +1 -1
|
@@ -8,6 +8,11 @@ The `d2l-backdrop` element is a web component to display a semi-transparent back
|
|
|
8
8
|
import '@brightspace-ui/core/components/button/button.js';
|
|
9
9
|
import '@brightspace-ui/core/components/backdrop/backdrop.js';
|
|
10
10
|
import '@brightspace-ui/core/components/switch/switch.js';
|
|
11
|
+
|
|
12
|
+
const backdrop = document.querySelector('d2l-backdrop');
|
|
13
|
+
document.querySelector('#target > d2l-button').addEventListener('click', () => {
|
|
14
|
+
backdrop.shown = !backdrop.shown;
|
|
15
|
+
});
|
|
11
16
|
</script>
|
|
12
17
|
<style>
|
|
13
18
|
#target { position: relative; z-index: 1000; margin: 40px; }
|
|
@@ -17,12 +22,6 @@ The `d2l-backdrop` element is a web component to display a semi-transparent back
|
|
|
17
22
|
<d2l-backdrop for-target="target"></d2l-backdrop>
|
|
18
23
|
</div>
|
|
19
24
|
<span>Background content</span>
|
|
20
|
-
<script>
|
|
21
|
-
const backdrop = document.querySelector('d2l-backdrop');
|
|
22
|
-
document.querySelector('#target > d2l-button').addEventListener('click', () => {
|
|
23
|
-
backdrop.shown = !backdrop.shown;
|
|
24
|
-
});
|
|
25
|
-
</script>
|
|
26
25
|
```
|
|
27
26
|
|
|
28
27
|
<!-- docs: start hidden content -->
|
|
@@ -17,16 +17,19 @@ class Backdrop extends LitElement {
|
|
|
17
17
|
return {
|
|
18
18
|
/**
|
|
19
19
|
* REQUIRED: id of the target element to display backdrop behind
|
|
20
|
+
* @type {string}
|
|
20
21
|
*/
|
|
21
22
|
forTarget: { type: String, attribute: 'for-target' },
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Disables the fade-out transition while the backdrop is being hidden
|
|
26
|
+
* @type {boolean}
|
|
25
27
|
*/
|
|
26
28
|
noAnimateHide: { type: Boolean, attribute: 'no-animate-hide' },
|
|
27
29
|
|
|
28
30
|
/**
|
|
29
31
|
* Used to control whether the backdrop is shown
|
|
32
|
+
* @type {boolean}
|
|
30
33
|
*/
|
|
31
34
|
shown: { type: Boolean },
|
|
32
35
|
_state: { type: String, reflect: true }
|
|
@@ -5,13 +5,14 @@ import { RtlMixin } from '../../mixins/rtl-mixin.js';
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Help users understand where they are within the application, and provide useful clues about how the space is organized. They also provide a convenient navigation mechanism.
|
|
8
|
-
* @slot -
|
|
8
|
+
* @slot - Breadcrumb items
|
|
9
9
|
*/
|
|
10
10
|
class Breadcrumbs extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
11
11
|
static get properties() {
|
|
12
12
|
return {
|
|
13
13
|
/**
|
|
14
14
|
* Renders in compact mode, displaying only the last item
|
|
15
|
+
* @type {boolean}
|
|
15
16
|
*/
|
|
16
17
|
compact: { type: Boolean, reflect: true }
|
|
17
18
|
};
|
|
@@ -22,10 +22,12 @@ export const ButtonMixin = superclass => class extends FocusVisiblePolyfillMixin
|
|
|
22
22
|
autofocus: { type: Boolean, reflect: true },
|
|
23
23
|
/**
|
|
24
24
|
* Disables the button
|
|
25
|
+
* @type {boolean}
|
|
25
26
|
*/
|
|
26
27
|
disabled: { type: Boolean, reflect: true },
|
|
27
28
|
/**
|
|
28
29
|
* Tooltip text when disabled
|
|
30
|
+
* @type {string}
|
|
29
31
|
*/
|
|
30
32
|
disabledTooltip: { type: String, attribute: 'disabled-tooltip' },
|
|
31
33
|
/**
|
|
@@ -17,6 +17,7 @@ class FloatingButtons extends RtlMixin(LitElement) {
|
|
|
17
17
|
return {
|
|
18
18
|
/**
|
|
19
19
|
* Indicates to display buttons as always floating
|
|
20
|
+
* @type {boolean}
|
|
20
21
|
*/
|
|
21
22
|
alwaysFloat: { type: Boolean, attribute: 'always-float', reflect: true },
|
|
22
23
|
_containerMarginLeft: { attribute: false, type: String },
|
|
@@ -132,7 +132,6 @@ export function getPrevMonth(month) {
|
|
|
132
132
|
/**
|
|
133
133
|
* A component can be used to display a responsively sized calendar that allows for date selection.
|
|
134
134
|
* @slot - Content displayed under the calendar (e.g., buttons)
|
|
135
|
-
* @fires d2l-calendar-selected - Dispatched when a date is selected through click, space, or enter. "e.detail.date" is in ISO 8601 calendar date format ("YYYY-MM-DD").
|
|
136
135
|
*/
|
|
137
136
|
class Calendar extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
138
137
|
|
|
@@ -620,6 +619,7 @@ class Calendar extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
620
619
|
composed: true,
|
|
621
620
|
detail: { date: this.selectedValue }
|
|
622
621
|
};
|
|
622
|
+
/** Dispatched when a date is selected through click, space, or enter. "e.detail.date" is in ISO 8601 calendar date format ("YYYY-MM-DD"). */
|
|
623
623
|
this.dispatchEvent(new CustomEvent('d2l-calendar-selected', eventDetails));
|
|
624
624
|
}
|
|
625
625
|
|
|
@@ -16,30 +16,37 @@ class CardFooterLink extends RtlMixin(LitElement) {
|
|
|
16
16
|
return {
|
|
17
17
|
/**
|
|
18
18
|
* Download a URL instead of navigating to it
|
|
19
|
+
* @type {boolean}
|
|
19
20
|
*/
|
|
20
21
|
download: { type: Boolean, reflect: true },
|
|
21
22
|
/**
|
|
22
23
|
* URL or URL fragment of the link
|
|
24
|
+
* @type {string}
|
|
23
25
|
*/
|
|
24
26
|
href: { type: String, reflect: true },
|
|
25
27
|
/**
|
|
26
28
|
* Indicates the human language of the linked resource; purely advisory, with no built-in functionality
|
|
29
|
+
* @type {string}
|
|
27
30
|
*/
|
|
28
31
|
hreflang: { type: String, reflect: true },
|
|
29
32
|
/**
|
|
30
33
|
* REQUIRED: Preset icon key (e.g. "tier1:gear"). Must be a tier 1 icon.
|
|
34
|
+
* @type {string}
|
|
31
35
|
*/
|
|
32
36
|
icon: { type: String, reflect: true },
|
|
33
37
|
/**
|
|
34
38
|
* Specifies the relationship of the target object to the link object
|
|
39
|
+
* @type {string}
|
|
35
40
|
*/
|
|
36
41
|
rel: { type: String, reflect: true },
|
|
37
42
|
/**
|
|
38
43
|
* Secondary count to display as a count bubble on the icon
|
|
44
|
+
* @type {number}
|
|
39
45
|
*/
|
|
40
46
|
secondaryCount: { type: Number, attribute: 'secondary-count', reflect: true },
|
|
41
47
|
/**
|
|
42
48
|
* Maximum digits to display in the secondary count. Defaults to no limit
|
|
49
|
+
* @type {string}
|
|
43
50
|
*/
|
|
44
51
|
secondaryCountMaxDigits: { type: String, attribute: 'secondary-count-max-digits' },
|
|
45
52
|
/**
|
|
@@ -49,14 +56,17 @@ class CardFooterLink extends RtlMixin(LitElement) {
|
|
|
49
56
|
secondaryCountType: { type: String, attribute: 'secondary-count-type', reflect: true },
|
|
50
57
|
/**
|
|
51
58
|
* Where to display the linked URL
|
|
59
|
+
* @type {string}
|
|
52
60
|
*/
|
|
53
61
|
target: { type: String, reflect: true },
|
|
54
62
|
/**
|
|
55
63
|
* REQUIRED: Accessible text for the link (not visible, gets announced when user focuses)
|
|
64
|
+
* @type {string}
|
|
56
65
|
*/
|
|
57
66
|
text: { type: String, reflect: true },
|
|
58
67
|
/**
|
|
59
68
|
* Specifies the media type in the form of a MIME type for the linked URL; purely advisory, with no built-in functionality
|
|
69
|
+
* @type {string}
|
|
60
70
|
*/
|
|
61
71
|
type: { type: String, reflect: true }
|
|
62
72
|
};
|
|
@@ -108,7 +118,7 @@ class CardFooterLink extends RtlMixin(LitElement) {
|
|
|
108
118
|
render() {
|
|
109
119
|
const noNumber = this.secondaryCount === undefined;
|
|
110
120
|
return html`
|
|
111
|
-
<a @focus="${this._onFocus}"
|
|
121
|
+
<a @focus="${this._onFocus}"
|
|
112
122
|
@blur="${this._onBlur}"
|
|
113
123
|
?download="${this.download}"
|
|
114
124
|
href="${ifDefined(this.href)}"
|
|
@@ -121,7 +131,7 @@ class CardFooterLink extends RtlMixin(LitElement) {
|
|
|
121
131
|
aria-hidden="true"
|
|
122
132
|
icon="${this.icon}"
|
|
123
133
|
max-digits="${ifDefined(this.secondaryCountMaxDigits ? this.secondaryCountMaxDigits : undefined)}"
|
|
124
|
-
number="${noNumber ? 0 : this.secondaryCount}"
|
|
134
|
+
number="${noNumber ? 0 : this.secondaryCount}"
|
|
125
135
|
?hide-zero="${noNumber}"
|
|
126
136
|
text="${this.text}"
|
|
127
137
|
type="${this._getType()}">
|
package/components/card/card.js
CHANGED
|
@@ -21,38 +21,47 @@ class Card extends RtlMixin(LitElement) {
|
|
|
21
21
|
return {
|
|
22
22
|
/**
|
|
23
23
|
* Style the card's content and footer as centered horizontally
|
|
24
|
+
* @type {boolean}
|
|
24
25
|
*/
|
|
25
26
|
alignCenter: { type: Boolean, attribute: 'align-center', reflect: true },
|
|
26
27
|
/**
|
|
27
28
|
* Download a URL instead of navigating to it
|
|
29
|
+
* @type {boolean}
|
|
28
30
|
*/
|
|
29
31
|
download: { type: Boolean, reflect: true },
|
|
30
32
|
/**
|
|
31
33
|
* Location for the primary action/navigation
|
|
34
|
+
* @type {string}
|
|
32
35
|
*/
|
|
33
36
|
href: { type: String, reflect: true },
|
|
34
37
|
/**
|
|
35
38
|
* Indicates the human language of the linked resource; purely advisory, with no built-in functionality
|
|
39
|
+
* @type {string}
|
|
36
40
|
*/
|
|
37
41
|
hreflang: { type: String, reflect: true },
|
|
38
42
|
/**
|
|
39
43
|
* Specifies the relationship of the target object to the link object
|
|
44
|
+
* @type {string}
|
|
40
45
|
*/
|
|
41
46
|
rel: { type: String, reflect: true },
|
|
42
47
|
/**
|
|
43
48
|
* Subtle aesthetic on non-white backgrounds
|
|
49
|
+
* @type {boolean}
|
|
44
50
|
*/
|
|
45
51
|
subtle: { type: Boolean, reflect: true },
|
|
46
52
|
/**
|
|
47
53
|
* Where to display the linked URL
|
|
54
|
+
* @type {string}
|
|
48
55
|
*/
|
|
49
56
|
target: { type: String, reflect: true },
|
|
50
57
|
/**
|
|
51
58
|
* Accessible text for the card (will be announced when AT user focuses)
|
|
59
|
+
* @type {string}
|
|
52
60
|
*/
|
|
53
61
|
text: { type: String, reflect: true },
|
|
54
62
|
/**
|
|
55
63
|
* Specifies the media type in the form of a MIME type for the linked URL; purely advisory, with no built-in functionality
|
|
64
|
+
* @type {string}
|
|
56
65
|
*/
|
|
57
66
|
type: { type: String, reflect: true },
|
|
58
67
|
_active: { type: Boolean, reflect: true },
|
|
@@ -8,8 +8,6 @@ import { heading3Styles } from '../typography/styles.js';
|
|
|
8
8
|
/**
|
|
9
9
|
* A simple confirmation dialog for prompting the user. Apply the "data-dialog-action" attribute to workflow buttons to automatically close the confirm dialog with the action value.
|
|
10
10
|
* @slot footer - Slot for footer content such as workflow buttons
|
|
11
|
-
* @fires d2l-dialog-open - Dispatched when the dialog is opened
|
|
12
|
-
* @fires d2l-dialog-close - Dispatched with the action value when the dialog is closed for any reason
|
|
13
11
|
*/
|
|
14
12
|
class DialogConfirm extends DialogMixin(LitElement) {
|
|
15
13
|
|
|
@@ -17,6 +15,7 @@ class DialogConfirm extends DialogMixin(LitElement) {
|
|
|
17
15
|
return {
|
|
18
16
|
/**
|
|
19
17
|
* REQUIRED: The text content for the confirmation dialog
|
|
18
|
+
* @type {string}
|
|
20
19
|
*/
|
|
21
20
|
text: { type: String }
|
|
22
21
|
};
|
|
@@ -16,8 +16,6 @@ const mediaQueryList = window.matchMedia('(max-width: 615px)');
|
|
|
16
16
|
* A generic fullscreen dialog that provides a slot for arbitrary content and a "footer" slot for workflow buttons. Apply the "data-dialog-action" attribute to workflow buttons to automatically close the dialog with the action value.
|
|
17
17
|
* @slot - Default slot for content inside dialog
|
|
18
18
|
* @slot footer - Slot for footer content such as workflow buttons
|
|
19
|
-
* @fires d2l-dialog-open - Dispatched when the dialog is opened
|
|
20
|
-
* @fires d2l-dialog-close - Dispatched with the action value when the dialog is closed for any reason
|
|
21
19
|
*/
|
|
22
20
|
class DialogFullscreen extends LocalizeCoreElement(AsyncContainerMixin(DialogMixin(LitElement))) {
|
|
23
21
|
|
|
@@ -25,6 +23,7 @@ class DialogFullscreen extends LocalizeCoreElement(AsyncContainerMixin(DialogMix
|
|
|
25
23
|
return {
|
|
26
24
|
/**
|
|
27
25
|
* Whether to render a loading-spinner and wait for state changes via AsyncContainerMixin
|
|
26
|
+
* @type {boolean}
|
|
28
27
|
*/
|
|
29
28
|
async: { type: Boolean },
|
|
30
29
|
_hasFooterContent: { type: Boolean, attribute: false },
|
|
@@ -45,7 +44,7 @@ class DialogFullscreen extends LocalizeCoreElement(AsyncContainerMixin(DialogMix
|
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
@media (min-width: 616px) {
|
|
48
|
-
|
|
47
|
+
|
|
49
48
|
.d2l-dialog-header {
|
|
50
49
|
border-bottom: 1px solid var(--d2l-color-gypsum);
|
|
51
50
|
padding-bottom: 0.9rem;
|
|
@@ -72,7 +71,7 @@ class DialogFullscreen extends LocalizeCoreElement(AsyncContainerMixin(DialogMix
|
|
|
72
71
|
:host([dir="rtl"]) .d2l-dialog-header > div > d2l-button-icon {
|
|
73
72
|
margin: -2px 0 0 -12px;
|
|
74
73
|
}
|
|
75
|
-
|
|
74
|
+
|
|
76
75
|
dialog.d2l-dialog-outer,
|
|
77
76
|
div.d2l-dialog-outer {
|
|
78
77
|
border-radius: 8px;
|
|
@@ -164,7 +163,7 @@ class DialogFullscreen extends LocalizeCoreElement(AsyncContainerMixin(DialogMix
|
|
|
164
163
|
margin-left: -13px;
|
|
165
164
|
margin-right: 15px;
|
|
166
165
|
}
|
|
167
|
-
|
|
166
|
+
|
|
168
167
|
dialog.d2l-dialog-outer,
|
|
169
168
|
div.d2l-dialog-outer {
|
|
170
169
|
margin: 0 !important;
|
|
@@ -244,6 +244,7 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
|
|
|
244
244
|
allowBodyScroll(this._bodyScrollKey);
|
|
245
245
|
this._bodyScrollKey = null;
|
|
246
246
|
if (this._action === undefined) this._action = abortAction;
|
|
247
|
+
/** Dispatched with the action value when the dialog is closed for any reason */
|
|
247
248
|
this.dispatchEvent(new CustomEvent(
|
|
248
249
|
'd2l-dialog-close', {
|
|
249
250
|
bubbles: true,
|
|
@@ -346,6 +347,7 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
|
|
|
346
347
|
}
|
|
347
348
|
|
|
348
349
|
if (!reduceMotion) await animPromise;
|
|
350
|
+
/** Dispatched when the dialog is opened */
|
|
349
351
|
this.dispatchEvent(new CustomEvent(
|
|
350
352
|
'd2l-dialog-open', { bubbles: true, composed: true }
|
|
351
353
|
));
|
|
@@ -17,8 +17,6 @@ const mediaQueryList = window.matchMedia('(max-width: 615px), (max-height: 420px
|
|
|
17
17
|
* A generic dialog that provides a slot for arbitrary content and a "footer" slot for workflow buttons. Apply the "data-dialog-action" attribute to workflow buttons to automatically close the dialog with the action value.
|
|
18
18
|
* @slot - Default slot for content inside dialog
|
|
19
19
|
* @slot footer - Slot for footer content such as workflow buttons
|
|
20
|
-
* @fires d2l-dialog-open - Dispatched when the dialog is opened
|
|
21
|
-
* @fires d2l-dialog-close - Dispatched with the action value when the dialog is closed for any reason
|
|
22
20
|
*/
|
|
23
21
|
class Dialog extends LocalizeCoreElement(AsyncContainerMixin(DialogMixin(LitElement))) {
|
|
24
22
|
|
|
@@ -14,14 +14,14 @@ class DropdownButtonSubtle extends DropdownOpenerMixin(LitElement) {
|
|
|
14
14
|
return {
|
|
15
15
|
/**
|
|
16
16
|
* A description to be added to the opener button for accessibility when text on button does not provide enough context
|
|
17
|
+
* @type {string}
|
|
17
18
|
*/
|
|
18
19
|
description: { type: String },
|
|
19
20
|
/**
|
|
20
21
|
* REQUIRED: Text for the button
|
|
22
|
+
* @type {string}
|
|
21
23
|
*/
|
|
22
|
-
text: {
|
|
23
|
-
type: String
|
|
24
|
-
}
|
|
24
|
+
text: { type: String }
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -15,6 +15,7 @@ class DropdownButton extends DropdownOpenerMixin(RtlMixin(LitElement)) {
|
|
|
15
15
|
return {
|
|
16
16
|
/**
|
|
17
17
|
* Optionally render button as primary button
|
|
18
|
+
* @type {boolean}
|
|
18
19
|
*/
|
|
19
20
|
primary: {
|
|
20
21
|
type: Boolean,
|
|
@@ -23,6 +24,7 @@ class DropdownButton extends DropdownOpenerMixin(RtlMixin(LitElement)) {
|
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* REQUIRED: Text for the button
|
|
27
|
+
* @type {string}
|
|
26
28
|
*/
|
|
27
29
|
text: {
|
|
28
30
|
type: String
|
|
@@ -29,12 +29,14 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
29
29
|
},
|
|
30
30
|
/**
|
|
31
31
|
* Optionally provide boundaries to where the dropdown will appear. Valid properties are "above", "below", "left", and "right".
|
|
32
|
+
* @type {object}
|
|
32
33
|
*/
|
|
33
34
|
boundary: {
|
|
34
35
|
type: Object,
|
|
35
36
|
},
|
|
36
37
|
/**
|
|
37
38
|
* Override default max-width (undefined). Specify a number that would be the px value.
|
|
39
|
+
* @type {number}
|
|
38
40
|
*/
|
|
39
41
|
maxWidth: {
|
|
40
42
|
type: Number,
|
|
@@ -43,6 +45,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
43
45
|
},
|
|
44
46
|
/**
|
|
45
47
|
* Override default min-width (undefined). Specify a number that would be the px value.
|
|
48
|
+
* @type {number}
|
|
46
49
|
*/
|
|
47
50
|
minWidth: {
|
|
48
51
|
type: Number,
|
|
@@ -51,6 +54,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
51
54
|
},
|
|
52
55
|
/**
|
|
53
56
|
* Override max-height. Note that the default behaviour is to be as tall as necessary within the viewport, so this property is usually not needed.
|
|
57
|
+
* @type {number}
|
|
54
58
|
*/
|
|
55
59
|
maxHeight: {
|
|
56
60
|
type: Number,
|
|
@@ -58,6 +62,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
58
62
|
},
|
|
59
63
|
/**
|
|
60
64
|
* Override the breakpoint at which mobile styling is used. Defaults to 616px.
|
|
65
|
+
* @type {number}
|
|
61
66
|
*/
|
|
62
67
|
mobileBreakpointOverride: {
|
|
63
68
|
type: Number,
|
|
@@ -65,6 +70,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
65
70
|
},
|
|
66
71
|
/**
|
|
67
72
|
* Override default height used for required space when `no-auto-fit` is true. Specify a number that would be the px value. Note that the default behaviour is to be as tall as necessary within the viewport, so this property is usually not needed.
|
|
73
|
+
* @type {number}
|
|
68
74
|
*/
|
|
69
75
|
minHeight: {
|
|
70
76
|
type: Number,
|
|
@@ -73,6 +79,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
73
79
|
},
|
|
74
80
|
/**
|
|
75
81
|
* Opt-out of showing a close button in the footer of tray-style mobile dropdowns.
|
|
82
|
+
* @type {boolean}
|
|
76
83
|
*/
|
|
77
84
|
noMobileCloseButton: {
|
|
78
85
|
type: Boolean,
|
|
@@ -90,6 +97,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
90
97
|
},
|
|
91
98
|
/**
|
|
92
99
|
* Opt out of automatically closing on focus or click outside of the dropdown content
|
|
100
|
+
* @type {boolean}
|
|
93
101
|
*/
|
|
94
102
|
noAutoClose: {
|
|
95
103
|
type: Boolean,
|
|
@@ -98,6 +106,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
98
106
|
},
|
|
99
107
|
/**
|
|
100
108
|
* Opt out of auto-sizing
|
|
109
|
+
* @type {boolean}
|
|
101
110
|
*/
|
|
102
111
|
noAutoFit: {
|
|
103
112
|
type: Boolean,
|
|
@@ -106,6 +115,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
106
115
|
},
|
|
107
116
|
/**
|
|
108
117
|
* Opt out of focus being automatically moved to the first focusable element in the dropdown when opened
|
|
118
|
+
* @type {boolean}
|
|
109
119
|
*/
|
|
110
120
|
noAutoFocus: {
|
|
111
121
|
type: Boolean,
|
|
@@ -114,6 +124,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
114
124
|
},
|
|
115
125
|
/**
|
|
116
126
|
* Render with no padding
|
|
127
|
+
* @type {boolean}
|
|
117
128
|
*/
|
|
118
129
|
noPadding: {
|
|
119
130
|
type: Boolean,
|
|
@@ -122,6 +133,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
122
133
|
},
|
|
123
134
|
/**
|
|
124
135
|
* Render the footer with no padding (if it has content)
|
|
136
|
+
* @type {boolean}
|
|
125
137
|
*/
|
|
126
138
|
noPaddingFooter: {
|
|
127
139
|
type: Boolean,
|
|
@@ -130,6 +142,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
130
142
|
},
|
|
131
143
|
/**
|
|
132
144
|
* Render the header with no padding (if it has content)
|
|
145
|
+
* @type {boolean}
|
|
133
146
|
*/
|
|
134
147
|
noPaddingHeader: {
|
|
135
148
|
type: Boolean,
|
|
@@ -138,6 +151,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
138
151
|
},
|
|
139
152
|
/**
|
|
140
153
|
* Render without a pointer
|
|
154
|
+
* @type {boolean}
|
|
141
155
|
*/
|
|
142
156
|
noPointer: {
|
|
143
157
|
type: Boolean,
|
|
@@ -162,6 +176,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
162
176
|
},
|
|
163
177
|
/**
|
|
164
178
|
* Optionally render a d2l-focus-trap around the dropdown content
|
|
179
|
+
* @type {boolean}
|
|
165
180
|
*/
|
|
166
181
|
trapFocus: {
|
|
167
182
|
type: Boolean,
|
|
@@ -170,6 +185,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
170
185
|
},
|
|
171
186
|
/**
|
|
172
187
|
* Provide custom offset, positive or negative
|
|
188
|
+
* @type {string}
|
|
173
189
|
*/
|
|
174
190
|
verticalOffset: {
|
|
175
191
|
type: String,
|
|
@@ -549,6 +565,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
549
565
|
this._showBackdrop = false;
|
|
550
566
|
await this.updateComplete;
|
|
551
567
|
|
|
568
|
+
/** Dispatched when the dropdown is closed */
|
|
552
569
|
this.dispatchEvent(new CustomEvent('d2l-dropdown-close', { bubbles: true, composed: true }));
|
|
553
570
|
|
|
554
571
|
}
|
|
@@ -656,6 +673,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
656
673
|
await this.updateComplete;
|
|
657
674
|
}
|
|
658
675
|
|
|
676
|
+
/** Dispatched when the dropdown position finishes adjusting */
|
|
659
677
|
this.dispatchEvent(new CustomEvent('d2l-dropdown-position', { bubbles: true, composed: true }));
|
|
660
678
|
};
|
|
661
679
|
|
|
@@ -1006,6 +1024,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
|
|
|
1006
1024
|
content.focus();
|
|
1007
1025
|
}
|
|
1008
1026
|
}
|
|
1027
|
+
/** Dispatched when user focus enters the dropdown content (trap-focus option only) */
|
|
1009
1028
|
this.dispatchEvent(new CustomEvent('d2l-dropdown-focus-enter'));
|
|
1010
1029
|
}
|
|
1011
1030
|
|
|
@@ -8,9 +8,6 @@ import { dropdownContentStyles } from './dropdown-content-styles.js';
|
|
|
8
8
|
* @slot header - Sticky container at the top of the dropdown
|
|
9
9
|
* @slot footer - Sticky container at the bottom of the dropdown
|
|
10
10
|
* @fires d2l-dropdown-open - Dispatched when the dropdown is opened
|
|
11
|
-
* @fires d2l-dropdown-close - Dispatched when the dropdown is closed
|
|
12
|
-
* @fires d2l-dropdown-focus-enter - Dispatched when user focus enters the dropdown content (trap-focus option only)
|
|
13
|
-
* @fires d2l-dropdown-position - Dispatched when the dropdown position finishes adjusting
|
|
14
11
|
*/
|
|
15
12
|
class DropdownContent extends DropdownContentMixin(LitElement) {
|
|
16
13
|
|
|
@@ -14,6 +14,7 @@ class DropdownContextMenu extends DropdownOpenerMixin(VisibleOnAncestorMixin(Lit
|
|
|
14
14
|
return {
|
|
15
15
|
/**
|
|
16
16
|
* REQUIRED: Label for the context-menu button
|
|
17
|
+
* @type {string}
|
|
17
18
|
*/
|
|
18
19
|
text: {
|
|
19
20
|
type: String
|
|
@@ -21,6 +22,7 @@ class DropdownContextMenu extends DropdownOpenerMixin(VisibleOnAncestorMixin(Lit
|
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Attribute for busy/rich backgrounds
|
|
25
|
+
* @type {boolean}
|
|
24
26
|
*/
|
|
25
27
|
translucent: {
|
|
26
28
|
type: Boolean
|
|
@@ -9,9 +9,6 @@ import { ThemeMixin } from '../../mixins/theme-mixin.js';
|
|
|
9
9
|
* @slot header - Sticky container at the top of the dropdown
|
|
10
10
|
* @slot footer - Sticky container at the bottom of the dropdown
|
|
11
11
|
* @fires d2l-dropdown-open - Dispatched when the dropdown is opened
|
|
12
|
-
* @fires d2l-dropdown-close - Dispatched when the dropdown is closed
|
|
13
|
-
* @fires d2l-dropdown-focus-enter - Dispatched when user focus enters the dropdown content (trap-focus option only)
|
|
14
|
-
* @fires d2l-dropdown-position - Dispatched when the dropdown position finishes adjusting
|
|
15
12
|
*/
|
|
16
13
|
class DropdownMenu extends ThemeMixin(DropdownContentMixin(LitElement)) {
|
|
17
14
|
|
|
@@ -14,6 +14,7 @@ class DropdownMore extends DropdownOpenerMixin(VisibleOnAncestorMixin(LitElement
|
|
|
14
14
|
return {
|
|
15
15
|
/**
|
|
16
16
|
* REQUIRED: Label for the more button
|
|
17
|
+
* @type {string}
|
|
17
18
|
*/
|
|
18
19
|
text: {
|
|
19
20
|
type: String
|
|
@@ -21,6 +22,7 @@ class DropdownMore extends DropdownOpenerMixin(VisibleOnAncestorMixin(LitElement
|
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Attribute for busy/rich backgrounds
|
|
25
|
+
* @type {boolean}
|
|
24
26
|
*/
|
|
25
27
|
translucent: {
|
|
26
28
|
type: Boolean
|
|
@@ -4,6 +4,7 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
|
4
4
|
return {
|
|
5
5
|
/**
|
|
6
6
|
* Disables the dropdown opener
|
|
7
|
+
* @type {boolean}
|
|
7
8
|
*/
|
|
8
9
|
disabled: {
|
|
9
10
|
type: Boolean,
|
|
@@ -19,6 +20,7 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
|
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Prevents the dropdown from opening automatically on or on key press
|
|
23
|
+
* @type {boolean}
|
|
22
24
|
*/
|
|
23
25
|
noAutoOpen: {
|
|
24
26
|
type: Boolean,
|
|
@@ -8,9 +8,6 @@ import { dropdownContentStyles } from './dropdown-content-styles.js';
|
|
|
8
8
|
* @slot header - Sticky container at the top of the dropdown
|
|
9
9
|
* @slot footer - Sticky container at the bottom of the dropdown
|
|
10
10
|
* @fires d2l-dropdown-open - Dispatched when the dropdown is opened
|
|
11
|
-
* @fires d2l-dropdown-close - Dispatched when the dropdown is closed
|
|
12
|
-
* @fires d2l-dropdown-focus-enter - Dispatched when user focus enters the dropdown content (trap-focus option only)
|
|
13
|
-
* @fires d2l-dropdown-position - Dispatched when the dropdown position finishes adjusting
|
|
14
11
|
*/
|
|
15
12
|
class DropdownTabs extends DropdownContentMixin(LitElement) {
|
|
16
13
|
|
|
@@ -32,7 +32,7 @@ const demoData = {
|
|
|
32
32
|
'L3-1': {
|
|
33
33
|
primaryText: 'Glaciation (L3)',
|
|
34
34
|
supportingText: 'Supporting Info',
|
|
35
|
-
nested: [ 'L4-1' ]
|
|
35
|
+
nested: [ 'L4-1', 'L4-2' ]
|
|
36
36
|
},
|
|
37
37
|
'L3-2': {
|
|
38
38
|
primaryText: 'Weathering (L3)',
|
|
@@ -45,7 +45,11 @@ const demoData = {
|
|
|
45
45
|
'L4-1': {
|
|
46
46
|
primaryText: 'Ice Sheets',
|
|
47
47
|
supportingText: 'Supporting Info',
|
|
48
|
-
nested: [ 'L5-1'
|
|
48
|
+
nested: [ /*'L5-1', 'L5-2', 'L5-3', 'L5-4', 'L5-5'*/ ]
|
|
49
|
+
},
|
|
50
|
+
'L4-2': {
|
|
51
|
+
primaryText: 'Alpine Glaciers',
|
|
52
|
+
supportingText: 'Supporting Info'
|
|
49
53
|
},
|
|
50
54
|
'L5-1': {
|
|
51
55
|
primaryText: 'Topic L5-1',
|
|
@@ -178,7 +182,7 @@ class DemoListItemCustom extends ListItemMixin(LitElement) {
|
|
|
178
182
|
|
|
179
183
|
if (demoData[this.key].nested && demoData[this.key].nested.length > 0) {
|
|
180
184
|
itemTemplates.nested = html`
|
|
181
|
-
<d2l-list separators="all">
|
|
185
|
+
<d2l-list grid separators="all">
|
|
182
186
|
${demoData[this.key].nested.map(itemKey => html`<d2l-demo-list-item-custom selectable key="${itemKey}"></d2l-demo-list-item-custom>`)}
|
|
183
187
|
</d2l-list>
|
|
184
188
|
`;
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
</head>
|
|
24
24
|
<body unresolved>
|
|
25
25
|
|
|
26
|
-
<d2l-demo-page page-title="d2l-list
|
|
26
|
+
<d2l-demo-page page-title="d2l-list (nested)">
|
|
27
27
|
|
|
28
28
|
<h2>Nested</h2>
|
|
29
29
|
|
|
30
30
|
<d2l-demo-snippet>
|
|
31
31
|
<template>
|
|
32
|
-
<d2l-list>
|
|
32
|
+
<d2l-list grid>
|
|
33
33
|
<d2l-list-header slot="header">
|
|
34
34
|
<d2l-selection-action icon="tier1:bookmark-hollow" text="Bookmark" requires-selection></d2l-selection-action>
|
|
35
35
|
<d2l-selection-action icon="tier1:gear" text="Settings"></d2l-selection-action>
|
|
@@ -39,80 +39,24 @@
|
|
|
39
39
|
<div>Earth Sciences (L1)</div>
|
|
40
40
|
<div slot="supporting-info">Earth science or geoscience includes all fields of natural science related to planet Earth. This is a branch of science dealing with the physical and chemical constitution of Earth and its atmosphere. Earth science can be considered to be a branch of planetary science, but with a much older history.</div>
|
|
41
41
|
</d2l-list-item-content>
|
|
42
|
-
<d2l-list slot="nested" separators="all">
|
|
42
|
+
<d2l-list slot="nested" grid separators="all">
|
|
43
43
|
<d2l-list-item selectable key="L2-1" label="Label for L2-1">
|
|
44
44
|
<d2l-list-item-content>
|
|
45
45
|
<div>Introductory Earth Sciences (L2)</div>
|
|
46
46
|
<div slot="supporting-info">This course explores the geological processes of the Earth's interior and surface. These include volcanism, earthquakes, mountain building, glaciation and weathering. Students will gain an appreciation of how these processes have controlled the evolution of our planet and the role of geology in meeting society's current and future demand for sustainable energy and mineral resources.</div>
|
|
47
47
|
</d2l-list-item-content>
|
|
48
|
-
<d2l-list slot="nested" separators="all">
|
|
48
|
+
<d2l-list slot="nested" grid separators="all">
|
|
49
49
|
<d2l-list-item selectable key="L3-1" label="Label for L3-1">
|
|
50
50
|
<d2l-list-item-content>
|
|
51
51
|
<div>Glaciation (L3)</div>
|
|
52
52
|
<div slot="supporting-info">Supporting Info</div>
|
|
53
53
|
</d2l-list-item-content>
|
|
54
|
-
<d2l-list slot="nested" separators="all">
|
|
54
|
+
<d2l-list slot="nested" grid separators="all">
|
|
55
55
|
<d2l-list-item selectable key="L4-1" label="Label for L4-1">
|
|
56
56
|
<d2l-list-item-content>
|
|
57
57
|
<div>Ice Sheets (L4)</div>
|
|
58
58
|
<div slot="supporting-info">Supporting Info</div>
|
|
59
59
|
</d2l-list-item-content>
|
|
60
|
-
<d2l-list slot="nested" separators="all">
|
|
61
|
-
<d2l-list-item selectable key="L5-1" label="Label for L5-1">
|
|
62
|
-
<d2l-list-item-content>
|
|
63
|
-
<div>Topic 1 (L5)</div>
|
|
64
|
-
<div slot="supporting-info">Supporting Info</div>
|
|
65
|
-
</d2l-list-item-content>
|
|
66
|
-
</d2l-list-item>
|
|
67
|
-
<d2l-list-item selectable key="L5-2" label="Label for L5-2">
|
|
68
|
-
<d2l-list-item-content>
|
|
69
|
-
<div>Topic 2 (L5)</div>
|
|
70
|
-
<div slot="supporting-info">Supporting Info</div>
|
|
71
|
-
</d2l-list-item-content>
|
|
72
|
-
<d2l-list slot="nested" separators="all">
|
|
73
|
-
<d2l-list-item selectable key="L6-1" label="Label for L6-1">
|
|
74
|
-
<d2l-list-item-content>
|
|
75
|
-
<div>Sub-Topic 1 (L6)</div>
|
|
76
|
-
<div slot="supporting-info">Supporting Info</div>
|
|
77
|
-
</d2l-list-item-content>
|
|
78
|
-
<d2l-list slot="nested" separators="all">
|
|
79
|
-
<d2l-list-item selectable key="L7-1" label="Label for L7-1">
|
|
80
|
-
<d2l-list-item-content>
|
|
81
|
-
<div>Sub-Topic 1 (L7)</div>
|
|
82
|
-
<div slot="supporting-info">Supporting Info</div>
|
|
83
|
-
</d2l-list-item-content>
|
|
84
|
-
<d2l-list slot="nested" separators="all">
|
|
85
|
-
<d2l-list-item selectable selected key="L8-1" label="Label for L8-1">
|
|
86
|
-
<d2l-list-item-content>
|
|
87
|
-
<div>Sub-Topic 1 (L8)</div>
|
|
88
|
-
<div slot="supporting-info">Supporting Info</div>
|
|
89
|
-
</d2l-list-item-content>
|
|
90
|
-
</d2l-list-item>
|
|
91
|
-
<d2l-list-item selectable key="L8-2" label="Label for L8-2">
|
|
92
|
-
<d2l-list-item-content>
|
|
93
|
-
<div>Sub-Topic 2 (L8)</div>
|
|
94
|
-
<div slot="supporting-info">Supporting Info</div>
|
|
95
|
-
</d2l-list-item-content>
|
|
96
|
-
</d2l-list-item>
|
|
97
|
-
</d2l-list>
|
|
98
|
-
</d2l-list-item>
|
|
99
|
-
<d2l-list-item selectable key="L7-2" label="Label for L7-2">
|
|
100
|
-
<d2l-list-item-content>
|
|
101
|
-
<div>Sub-Topic 2 (L7)</div>
|
|
102
|
-
<div slot="supporting-info">Supporting Info</div>
|
|
103
|
-
</d2l-list-item-content>
|
|
104
|
-
</d2l-list-item>
|
|
105
|
-
</d2l-list>
|
|
106
|
-
</d2l-list-item>
|
|
107
|
-
<d2l-list-item selectable key="L6-2" label="Label for L6-2">
|
|
108
|
-
<d2l-list-item-content>
|
|
109
|
-
<div>Sub-Topic 2 (L6)</div>
|
|
110
|
-
<div slot="supporting-info">Supporting Info</div>
|
|
111
|
-
</d2l-list-item-content>
|
|
112
|
-
</d2l-list-item>
|
|
113
|
-
</d2l-list>
|
|
114
|
-
</d2l-list-item>
|
|
115
|
-
</d2l-list>
|
|
116
60
|
</d2l-list-item>
|
|
117
61
|
<d2l-list-item selectable key="L4-2" label="Label for L4-2">
|
|
118
62
|
<d2l-list-item-content>
|
|
@@ -175,7 +119,7 @@
|
|
|
175
119
|
|
|
176
120
|
<d2l-demo-snippet>
|
|
177
121
|
<template>
|
|
178
|
-
<d2l-list>
|
|
122
|
+
<d2l-list grid>
|
|
179
123
|
<d2l-list-header slot="header">
|
|
180
124
|
<d2l-selection-action icon="tier1:bookmark-hollow" text="Bookmark" requires-selection></d2l-selection-action>
|
|
181
125
|
<d2l-selection-action icon="tier1:gear" text="Settings"></d2l-selection-action>
|
|
@@ -207,6 +207,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
|
207
207
|
_focusNextCell(num, forward = true) {
|
|
208
208
|
let cell = null;
|
|
209
209
|
let focusable = null;
|
|
210
|
+
|
|
210
211
|
do {
|
|
211
212
|
cell = this.shadowRoot.querySelector(`[data-cell-num="${num}"]`);
|
|
212
213
|
if (cell) {
|
|
@@ -215,26 +216,31 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
|
215
216
|
if (focusable) focusable.focus();
|
|
216
217
|
forward ? ++num : --num;
|
|
217
218
|
} while (cell && !focusable);
|
|
219
|
+
|
|
220
|
+
if (!cell) {
|
|
221
|
+
// wrap to first/last item
|
|
222
|
+
if (forward) this._focusNextCell(1);
|
|
223
|
+
else this._focusLastItem();
|
|
224
|
+
}
|
|
225
|
+
|
|
218
226
|
return focusable;
|
|
219
227
|
}
|
|
220
228
|
|
|
221
229
|
_focusNextRow(previous = false, num = 1) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
listItem = nextItem;
|
|
232
|
-
--num;
|
|
230
|
+
|
|
231
|
+
let listItem = findComposedAncestor(this, node => node.role === 'rowgroup');
|
|
232
|
+
|
|
233
|
+
while (num > 0) {
|
|
234
|
+
const tempListItem = (previous ? this._getPreviousFlattenedListItem(listItem) : this._getNextFlattenedListItem(listItem));
|
|
235
|
+
if (tempListItem) listItem = tempListItem;
|
|
236
|
+
else break;
|
|
237
|
+
num--;
|
|
233
238
|
}
|
|
234
|
-
const row = listItem.shadowRoot.querySelector('[role="gridrow"]');
|
|
235
|
-
if (!row) return;
|
|
236
239
|
|
|
237
|
-
|
|
240
|
+
if (!listItem) return;
|
|
241
|
+
const listItemRow = listItem.shadowRoot.querySelector('[role="gridrow"]');
|
|
242
|
+
listItemRow._focusCellItem(this._cellNum, this._cellFocusedItem);
|
|
243
|
+
|
|
238
244
|
}
|
|
239
245
|
|
|
240
246
|
_focusNextWithinCell(node, num = 1) {
|
|
@@ -280,6 +286,38 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
|
280
286
|
return position;
|
|
281
287
|
}
|
|
282
288
|
|
|
289
|
+
_getNextFlattenedListItem(listItem) {
|
|
290
|
+
|
|
291
|
+
// check for nested list first; this check needs to account for standard list-items as well as custom
|
|
292
|
+
const nestedList = listItem.querySelector('[slot="nested"]') || listItem.shadowRoot.querySelector('d2l-list');
|
|
293
|
+
if (nestedList) {
|
|
294
|
+
const nestedListItem = [...nestedList.children].find(node => node.role === 'rowgroup');
|
|
295
|
+
if (nestedListItem) return nestedListItem;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const getNextListItem = listItem => {
|
|
299
|
+
|
|
300
|
+
// check for sibling list-item
|
|
301
|
+
let nextElement = listItem.nextElementSibling;
|
|
302
|
+
while (nextElement) {
|
|
303
|
+
if (nextElement.role === 'rowgroup') return nextElement;
|
|
304
|
+
nextElement = nextElement.nextElementSibling;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// no sibling list-item was found so check for sibling of parent list-item if nested, recursively if necessary
|
|
308
|
+
const list = findComposedAncestor(listItem, node => node.tagName === 'D2L-LIST');
|
|
309
|
+
if (list.slot !== 'nested' && !(list.parentNode.tagName === 'SLOT' && list.parentNode.name === 'nested')) return;
|
|
310
|
+
|
|
311
|
+
const parentListItem = findComposedAncestor(list, node => node.role === 'rowgroup');
|
|
312
|
+
return getNextListItem(parentListItem);
|
|
313
|
+
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
// check for sibling list-item or ancestors sibling list-items
|
|
317
|
+
return getNextListItem(listItem);
|
|
318
|
+
|
|
319
|
+
}
|
|
320
|
+
|
|
283
321
|
_getNextSiblingInCell(node) {
|
|
284
322
|
const cell = findComposedAncestor(node, (parent) => parent.classList && parent.classList.contains('d2l-cell'));
|
|
285
323
|
if (!cell || cell.name === node.slot) return null;
|
|
@@ -289,6 +327,39 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
|
289
327
|
return isComposedAncestor(cell, sibling) ? sibling : null;
|
|
290
328
|
}
|
|
291
329
|
|
|
330
|
+
_getPreviousFlattenedListItem(listItem) {
|
|
331
|
+
|
|
332
|
+
let previousElement = listItem.previousElementSibling;
|
|
333
|
+
|
|
334
|
+
// try to get the previous list-item in the current list sub-tree including nested
|
|
335
|
+
while (previousElement) {
|
|
336
|
+
if (previousElement.role === 'rowgroup') {
|
|
337
|
+
|
|
338
|
+
// this check needs to account for standard list-items as well as custom
|
|
339
|
+
const nestedList = previousElement.querySelector('[slot="nested"]') || previousElement.shadowRoot.querySelector('d2l-list');
|
|
340
|
+
if (nestedList) {
|
|
341
|
+
const nestedListItems = [...nestedList.children].filter(node => node.role === 'rowgroup');
|
|
342
|
+
if (nestedListItems && nestedListItems.length > 0) {
|
|
343
|
+
return nestedListItems[nestedListItems.length - 1];
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return previousElement;
|
|
347
|
+
|
|
348
|
+
}
|
|
349
|
+
previousElement = previousElement.previousElementSibling;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// no previous list-item was found in the current list sub-tree so get the parent list item if currently in nested
|
|
353
|
+
const list = findComposedAncestor(listItem, node => node.tagName === 'D2L-LIST');
|
|
354
|
+
|
|
355
|
+
// this check needs to account for standard list-items as well as custom
|
|
356
|
+
if (list.slot === 'nested' || (list.parentNode.tagName === 'SLOT' && list.parentNode.name === 'nested')) {
|
|
357
|
+
const parentListItem = findComposedAncestor(list, node => node.role === 'rowgroup');
|
|
358
|
+
return parentListItem;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
}
|
|
362
|
+
|
|
292
363
|
_getPrevSiblingInCell(node) {
|
|
293
364
|
const cell = findComposedAncestor(node, (parent) => parent.classList && parent.classList.contains('d2l-cell'));
|
|
294
365
|
if (!cell || cell.name === node.slot) return null;
|
package/components/list/list.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { css, html, LitElement } from 'lit-element/lit-element.js';
|
|
2
|
+
import { getNextFocusable, getPreviousFocusable } from '../../helpers/focus.js';
|
|
2
3
|
import { SelectionInfo, SelectionMixin } from '../selection/selection-mixin.js';
|
|
3
4
|
|
|
5
|
+
const keyCodes = {
|
|
6
|
+
TAB: 9
|
|
7
|
+
};
|
|
8
|
+
|
|
4
9
|
export const listSelectionStates = SelectionInfo.states;
|
|
5
10
|
|
|
6
11
|
/**
|
|
7
12
|
* A container for a styled list of items ("d2l-list-item"). It provides the appropriate "list" semantics as well as options for displaying separators, etc.
|
|
8
13
|
* @slot - List content (e.g., `listitem`s)
|
|
9
|
-
* @fires d2l-list-selection-change - Dispatched when the selection state changes
|
|
10
14
|
*/
|
|
11
15
|
class List extends SelectionMixin(LitElement) {
|
|
12
16
|
|
|
@@ -54,6 +58,7 @@ class List extends SelectionMixin(LitElement) {
|
|
|
54
58
|
// batch the changes from select-all and nested lists
|
|
55
59
|
if (this._listItemChanges.length === 0) {
|
|
56
60
|
setTimeout(() => {
|
|
61
|
+
/** Dispatched once for a set of selection state changes (ex. select-all); event detail includes an array of objects where each object contains the `key` and `selected` state for each changed item */
|
|
57
62
|
this.dispatchEvent(new CustomEvent('d2l-list-selection-changes', {
|
|
58
63
|
detail: this._listItemChanges
|
|
59
64
|
}));
|
|
@@ -63,6 +68,7 @@ class List extends SelectionMixin(LitElement) {
|
|
|
63
68
|
this._listItemChanges.push(e.detail);
|
|
64
69
|
|
|
65
70
|
setTimeout(() => {
|
|
71
|
+
/** Dispatched when the selection state changes */
|
|
66
72
|
this.dispatchEvent(new CustomEvent('d2l-list-selection-change', {
|
|
67
73
|
bubbles: true,
|
|
68
74
|
composed: true,
|
|
@@ -78,7 +84,7 @@ class List extends SelectionMixin(LitElement) {
|
|
|
78
84
|
return html`
|
|
79
85
|
<div role="${role}" class="d2l-list-container">
|
|
80
86
|
<slot name="header"></slot>
|
|
81
|
-
<slot></slot>
|
|
87
|
+
<slot @keydown="${this._handleKeyDown}"></slot>
|
|
82
88
|
</div>
|
|
83
89
|
`;
|
|
84
90
|
}
|
|
@@ -114,6 +120,14 @@ class List extends SelectionMixin(LitElement) {
|
|
|
114
120
|
});
|
|
115
121
|
}
|
|
116
122
|
|
|
123
|
+
_handleKeyDown(e) {
|
|
124
|
+
if (!this.grid || this.slot === 'nested' || e.keyCode !== keyCodes.TAB) return;
|
|
125
|
+
e.preventDefault();
|
|
126
|
+
const focusable = (e.shiftKey ? getPreviousFocusable(this.shadowRoot.querySelector('slot:not([name])'))
|
|
127
|
+
: getNextFocusable(this, false, true, true));
|
|
128
|
+
if (focusable) focusable.focus();
|
|
129
|
+
}
|
|
130
|
+
|
|
117
131
|
}
|
|
118
132
|
|
|
119
133
|
customElements.define('d2l-list', List);
|
|
@@ -60,6 +60,7 @@ export const SelectionMixin = superclass => class extends RtlMixin(superclass) {
|
|
|
60
60
|
this.addEventListener('d2l-selection-observer-subscribe', this._handleSelectionObserverSubscribe);
|
|
61
61
|
this.addEventListener('d2l-selection-input-subscribe', this._handleSelectionInputSubscribe);
|
|
62
62
|
requestAnimationFrame(() => {
|
|
63
|
+
/** @ignore */
|
|
63
64
|
this.dispatchEvent(new CustomEvent('d2l-selection-provider-connected', { bubbles: true, composed: true }));
|
|
64
65
|
});
|
|
65
66
|
|
|
@@ -234,6 +234,7 @@ export const SwitchMixin = superclass => class extends RtlMixin(FocusVisiblePoly
|
|
|
234
234
|
_toggleState() {
|
|
235
235
|
if (this.disabled) return;
|
|
236
236
|
this.on = !this.on;
|
|
237
|
+
/** Dispatched when the `on` property is updated */
|
|
237
238
|
this.dispatchEvent(new CustomEvent('change', { bubbles: true }));
|
|
238
239
|
}
|
|
239
240
|
};
|
package/custom-elements.json
CHANGED
|
@@ -327,7 +327,7 @@
|
|
|
327
327
|
"slots": [
|
|
328
328
|
{
|
|
329
329
|
"name": "",
|
|
330
|
-
"description": "
|
|
330
|
+
"description": "Breadcrumb items"
|
|
331
331
|
}
|
|
332
332
|
]
|
|
333
333
|
},
|
|
@@ -1486,13 +1486,13 @@
|
|
|
1486
1486
|
}
|
|
1487
1487
|
],
|
|
1488
1488
|
"events": [
|
|
1489
|
-
{
|
|
1490
|
-
"name": "d2l-dialog-open",
|
|
1491
|
-
"description": "Dispatched when the dialog is opened"
|
|
1492
|
-
},
|
|
1493
1489
|
{
|
|
1494
1490
|
"name": "d2l-dialog-close",
|
|
1495
1491
|
"description": "Dispatched with the action value when the dialog is closed for any reason"
|
|
1492
|
+
},
|
|
1493
|
+
{
|
|
1494
|
+
"name": "d2l-dialog-open",
|
|
1495
|
+
"description": "Dispatched when the dialog is opened"
|
|
1496
1496
|
}
|
|
1497
1497
|
],
|
|
1498
1498
|
"slots": [
|
|
@@ -1557,13 +1557,13 @@
|
|
|
1557
1557
|
}
|
|
1558
1558
|
],
|
|
1559
1559
|
"events": [
|
|
1560
|
-
{
|
|
1561
|
-
"name": "d2l-dialog-open",
|
|
1562
|
-
"description": "Dispatched when the dialog is opened"
|
|
1563
|
-
},
|
|
1564
1560
|
{
|
|
1565
1561
|
"name": "d2l-dialog-close",
|
|
1566
1562
|
"description": "Dispatched with the action value when the dialog is closed for any reason"
|
|
1563
|
+
},
|
|
1564
|
+
{
|
|
1565
|
+
"name": "d2l-dialog-open",
|
|
1566
|
+
"description": "Dispatched when the dialog is opened"
|
|
1567
1567
|
}
|
|
1568
1568
|
],
|
|
1569
1569
|
"slots": [
|
|
@@ -1645,13 +1645,13 @@
|
|
|
1645
1645
|
}
|
|
1646
1646
|
],
|
|
1647
1647
|
"events": [
|
|
1648
|
-
{
|
|
1649
|
-
"name": "d2l-dialog-open",
|
|
1650
|
-
"description": "Dispatched when the dialog is opened"
|
|
1651
|
-
},
|
|
1652
1648
|
{
|
|
1653
1649
|
"name": "d2l-dialog-close",
|
|
1654
1650
|
"description": "Dispatched with the action value when the dialog is closed for any reason"
|
|
1651
|
+
},
|
|
1652
|
+
{
|
|
1653
|
+
"name": "d2l-dialog-open",
|
|
1654
|
+
"description": "Dispatched when the dialog is opened"
|
|
1655
1655
|
}
|
|
1656
1656
|
],
|
|
1657
1657
|
"slots": [
|
|
@@ -2041,13 +2041,13 @@
|
|
|
2041
2041
|
"name": "d2l-dropdown-close",
|
|
2042
2042
|
"description": "Dispatched when the dropdown is closed"
|
|
2043
2043
|
},
|
|
2044
|
-
{
|
|
2045
|
-
"name": "d2l-dropdown-focus-enter",
|
|
2046
|
-
"description": "Dispatched when user focus enters the dropdown content (trap-focus option only)"
|
|
2047
|
-
},
|
|
2048
2044
|
{
|
|
2049
2045
|
"name": "d2l-dropdown-position",
|
|
2050
2046
|
"description": "Dispatched when the dropdown position finishes adjusting"
|
|
2047
|
+
},
|
|
2048
|
+
{
|
|
2049
|
+
"name": "d2l-dropdown-focus-enter",
|
|
2050
|
+
"description": "Dispatched when user focus enters the dropdown content (trap-focus option only)"
|
|
2051
2051
|
}
|
|
2052
2052
|
],
|
|
2053
2053
|
"slots": [
|
|
@@ -2378,13 +2378,13 @@
|
|
|
2378
2378
|
"name": "d2l-dropdown-close",
|
|
2379
2379
|
"description": "Dispatched when the dropdown is closed"
|
|
2380
2380
|
},
|
|
2381
|
-
{
|
|
2382
|
-
"name": "d2l-dropdown-focus-enter",
|
|
2383
|
-
"description": "Dispatched when user focus enters the dropdown content (trap-focus option only)"
|
|
2384
|
-
},
|
|
2385
2381
|
{
|
|
2386
2382
|
"name": "d2l-dropdown-position",
|
|
2387
2383
|
"description": "Dispatched when the dropdown position finishes adjusting"
|
|
2384
|
+
},
|
|
2385
|
+
{
|
|
2386
|
+
"name": "d2l-dropdown-focus-enter",
|
|
2387
|
+
"description": "Dispatched when user focus enters the dropdown content (trap-focus option only)"
|
|
2388
2388
|
}
|
|
2389
2389
|
],
|
|
2390
2390
|
"slots": [
|
|
@@ -2715,13 +2715,13 @@
|
|
|
2715
2715
|
"name": "d2l-dropdown-close",
|
|
2716
2716
|
"description": "Dispatched when the dropdown is closed"
|
|
2717
2717
|
},
|
|
2718
|
-
{
|
|
2719
|
-
"name": "d2l-dropdown-focus-enter",
|
|
2720
|
-
"description": "Dispatched when user focus enters the dropdown content (trap-focus option only)"
|
|
2721
|
-
},
|
|
2722
2718
|
{
|
|
2723
2719
|
"name": "d2l-dropdown-position",
|
|
2724
2720
|
"description": "Dispatched when the dropdown position finishes adjusting"
|
|
2721
|
+
},
|
|
2722
|
+
{
|
|
2723
|
+
"name": "d2l-dropdown-focus-enter",
|
|
2724
|
+
"description": "Dispatched when user focus enters the dropdown content (trap-focus option only)"
|
|
2725
2725
|
}
|
|
2726
2726
|
],
|
|
2727
2727
|
"slots": [
|
|
@@ -4279,9 +4279,6 @@
|
|
|
4279
4279
|
{
|
|
4280
4280
|
"name": "change",
|
|
4281
4281
|
"description": "Dispatched when there is a change to selected date or selected time. \"value\" corresponds to the selected value and is formatted in ISO 8601 combined date and time format (\"YYYY-MM-DDTHH:mm:ss.sssZ\")."
|
|
4282
|
-
},
|
|
4283
|
-
{
|
|
4284
|
-
"name": "d2l-labelled-mixin-label-elem-change"
|
|
4285
4282
|
}
|
|
4286
4283
|
]
|
|
4287
4284
|
},
|
|
@@ -4437,9 +4434,6 @@
|
|
|
4437
4434
|
{
|
|
4438
4435
|
"name": "change",
|
|
4439
4436
|
"description": "Dispatched when there is a change to selected date. \"value\" corresponds to the selected value and is formatted in ISO 8601 calendar date format (\"YYYY-MM-DD\")."
|
|
4440
|
-
},
|
|
4441
|
-
{
|
|
4442
|
-
"name": "d2l-labelled-mixin-label-elem-change"
|
|
4443
4437
|
}
|
|
4444
4438
|
]
|
|
4445
4439
|
},
|
|
@@ -4768,9 +4762,6 @@
|
|
|
4768
4762
|
{
|
|
4769
4763
|
"name": "change",
|
|
4770
4764
|
"description": "Dispatched when an alteration to the value is committed (typically after focus is lost) by the user. The `value` attribute reflects a JavaScript Number which is parsed from the formatted input value."
|
|
4771
|
-
},
|
|
4772
|
-
{
|
|
4773
|
-
"name": "d2l-labelled-mixin-label-elem-change"
|
|
4774
4765
|
}
|
|
4775
4766
|
],
|
|
4776
4767
|
"slots": [
|
|
@@ -4958,9 +4949,6 @@
|
|
|
4958
4949
|
{
|
|
4959
4950
|
"name": "change",
|
|
4960
4951
|
"description": "Dispatched when an alteration to the value is committed (typically after focus is lost) by the user. The `value` attribute reflects a JavaScript Number which is parsed from the formatted input value."
|
|
4961
|
-
},
|
|
4962
|
-
{
|
|
4963
|
-
"name": "d2l-labelled-mixin-label-elem-change"
|
|
4964
4952
|
}
|
|
4965
4953
|
],
|
|
4966
4954
|
"slots": [
|
|
@@ -5430,9 +5418,6 @@
|
|
|
5430
5418
|
{
|
|
5431
5419
|
"name": "input",
|
|
5432
5420
|
"description": "Dispatched immediately after changes by the user"
|
|
5433
|
-
},
|
|
5434
|
-
{
|
|
5435
|
-
"name": "d2l-labelled-mixin-label-elem-change"
|
|
5436
5421
|
}
|
|
5437
5422
|
],
|
|
5438
5423
|
"slots": [
|
|
@@ -5661,9 +5646,6 @@
|
|
|
5661
5646
|
{
|
|
5662
5647
|
"name": "input",
|
|
5663
5648
|
"description": "Dispatched immediately after changes by the user"
|
|
5664
|
-
},
|
|
5665
|
-
{
|
|
5666
|
-
"name": "d2l-labelled-mixin-label-elem-change"
|
|
5667
5649
|
}
|
|
5668
5650
|
]
|
|
5669
5651
|
},
|
|
@@ -6047,9 +6029,6 @@
|
|
|
6047
6029
|
{
|
|
6048
6030
|
"name": "change",
|
|
6049
6031
|
"description": "Dispatched when there is a change to selected time. \"value\" corresponds to the selected value and is formatted in ISO 8601 time format (\"hh:mm:ss\")."
|
|
6050
|
-
},
|
|
6051
|
-
{
|
|
6052
|
-
"name": "d2l-labelled-mixin-label-elem-change"
|
|
6053
6032
|
}
|
|
6054
6033
|
]
|
|
6055
6034
|
},
|
|
@@ -6349,9 +6328,6 @@
|
|
|
6349
6328
|
},
|
|
6350
6329
|
{
|
|
6351
6330
|
"name": "d2l-list-item-selected"
|
|
6352
|
-
},
|
|
6353
|
-
{
|
|
6354
|
-
"name": "d2l-labelled-mixin-label-elem-change"
|
|
6355
6331
|
}
|
|
6356
6332
|
]
|
|
6357
6333
|
},
|
|
@@ -6545,9 +6521,6 @@
|
|
|
6545
6521
|
{
|
|
6546
6522
|
"name": "d2l-list-item-selected",
|
|
6547
6523
|
"description": "Dispatched when the component item is selected"
|
|
6548
|
-
},
|
|
6549
|
-
{
|
|
6550
|
-
"name": "d2l-labelled-mixin-label-elem-change"
|
|
6551
6524
|
}
|
|
6552
6525
|
],
|
|
6553
6526
|
"slots": [
|
|
@@ -6877,9 +6850,6 @@
|
|
|
6877
6850
|
{
|
|
6878
6851
|
"name": "d2l-list-item-selected",
|
|
6879
6852
|
"description": "Dispatched when the component item is selected"
|
|
6880
|
-
},
|
|
6881
|
-
{
|
|
6882
|
-
"name": "d2l-labelled-mixin-label-elem-change"
|
|
6883
6853
|
}
|
|
6884
6854
|
],
|
|
6885
6855
|
"slots": [
|
|
@@ -6959,14 +6929,12 @@
|
|
|
6959
6929
|
],
|
|
6960
6930
|
"events": [
|
|
6961
6931
|
{
|
|
6962
|
-
"name": "d2l-list-selection-
|
|
6963
|
-
"description": "Dispatched
|
|
6964
|
-
},
|
|
6965
|
-
{
|
|
6966
|
-
"name": "d2l-list-selection-changes"
|
|
6932
|
+
"name": "d2l-list-selection-changes",
|
|
6933
|
+
"description": "Dispatched once for a set of selection state changes (ex. select-all); event detail includes an array of objects where each object contains the `key` and `selected` state for each changed item"
|
|
6967
6934
|
},
|
|
6968
6935
|
{
|
|
6969
|
-
"name": "d2l-selection-
|
|
6936
|
+
"name": "d2l-list-selection-change",
|
|
6937
|
+
"description": "Dispatched when the selection state changes"
|
|
6970
6938
|
}
|
|
6971
6939
|
],
|
|
6972
6940
|
"slots": [
|
|
@@ -8132,9 +8100,6 @@
|
|
|
8132
8100
|
},
|
|
8133
8101
|
{
|
|
8134
8102
|
"name": "d2l-selection-input-subscribe"
|
|
8135
|
-
},
|
|
8136
|
-
{
|
|
8137
|
-
"name": "d2l-labelled-mixin-label-elem-change"
|
|
8138
8103
|
}
|
|
8139
8104
|
]
|
|
8140
8105
|
},
|
|
@@ -8253,11 +8218,6 @@
|
|
|
8253
8218
|
"type": "boolean",
|
|
8254
8219
|
"default": "false"
|
|
8255
8220
|
}
|
|
8256
|
-
],
|
|
8257
|
-
"events": [
|
|
8258
|
-
{
|
|
8259
|
-
"name": "d2l-selection-provider-connected"
|
|
8260
|
-
}
|
|
8261
8221
|
]
|
|
8262
8222
|
},
|
|
8263
8223
|
{
|
|
@@ -8594,7 +8554,8 @@
|
|
|
8594
8554
|
],
|
|
8595
8555
|
"events": [
|
|
8596
8556
|
{
|
|
8597
|
-
"name": "change"
|
|
8557
|
+
"name": "change",
|
|
8558
|
+
"description": "Dispatched when the `on` property is updated"
|
|
8598
8559
|
}
|
|
8599
8560
|
]
|
|
8600
8561
|
},
|
|
@@ -8681,7 +8642,8 @@
|
|
|
8681
8642
|
],
|
|
8682
8643
|
"events": [
|
|
8683
8644
|
{
|
|
8684
|
-
"name": "change"
|
|
8645
|
+
"name": "change",
|
|
8646
|
+
"description": "Dispatched when the `on` property is updated"
|
|
8685
8647
|
}
|
|
8686
8648
|
]
|
|
8687
8649
|
},
|
package/helpers/focus.js
CHANGED
|
@@ -98,11 +98,13 @@ export function getPreviousFocusable(node, includeHidden) {
|
|
|
98
98
|
return focusable;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
export function getNextFocusable(node, includeHidden) {
|
|
101
|
+
export function getNextFocusable(node, includeHidden, ignore, ignoreChildren) {
|
|
102
102
|
|
|
103
103
|
if (!node) return null;
|
|
104
104
|
|
|
105
105
|
if (includeHidden === undefined) includeHidden = false;
|
|
106
|
+
if (ignore === undefined) ignore = true;
|
|
107
|
+
if (ignoreChildren === undefined) ignoreChildren = false;
|
|
106
108
|
|
|
107
109
|
const _getNextFocusable = (node, ignore, ignoreChildren) => {
|
|
108
110
|
if (!ignore && isFocusable(node, includeHidden)) return node;
|
|
@@ -128,7 +130,7 @@ export function getNextFocusable(node, includeHidden) {
|
|
|
128
130
|
return null;
|
|
129
131
|
};
|
|
130
132
|
|
|
131
|
-
const focusable = _getNextFocusable(node,
|
|
133
|
+
const focusable = _getNextFocusable(node, ignore, ignoreChildren);
|
|
132
134
|
return focusable;
|
|
133
135
|
|
|
134
136
|
}
|
package/mixins/labelled-mixin.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brightspace-ui/core",
|
|
3
|
-
"version": "1.196.
|
|
3
|
+
"version": "1.196.3",
|
|
4
4
|
"description": "A collection of accessible, free, open-source web components for building Brightspace applications",
|
|
5
5
|
"repository": "https://github.com/BrightspaceUI/core.git",
|
|
6
6
|
"publishConfig": {
|