@brightspace-ui/core 2.113.0 → 2.114.1
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/meter/README.md +8 -1
- package/components/meter/demo/meter.html +62 -23
- package/components/meter/meter-mixin.js +1 -1
- package/components/scroll-wrapper/demo/scroll-wrapper-test.js +41 -7
- package/components/scroll-wrapper/demo/scroll-wrapper.html +9 -0
- package/components/scroll-wrapper/scroll-wrapper.js +144 -28
- package/components/table/demo/table.html +10 -3
- package/components/table/table-wrapper.js +91 -22
- package/components/tag-list/tag-list-item-mixin.js +26 -13
- package/components/tag-list/tag-list.js +3 -2
- package/custom-elements.json +59 -6
- package/package.json +1 -1
|
@@ -41,7 +41,14 @@ Linear meters show a horizontal progress bar.
|
|
|
41
41
|
<script type="module">
|
|
42
42
|
import '@brightspace-ui/core/components/meter/meter-linear.js';
|
|
43
43
|
</script>
|
|
44
|
-
<
|
|
44
|
+
<style>
|
|
45
|
+
d2l-meter-linear {
|
|
46
|
+
width: 170px;
|
|
47
|
+
}
|
|
48
|
+
</style>
|
|
49
|
+
<d2l-meter-linear value="8" max="10" text="Activities"></d2l-meter-linear>
|
|
50
|
+
<d2l-meter-linear value="8" max="10" text="Activities: {x/y}" percent></d2l-meter-linear>
|
|
51
|
+
<d2l-meter-linear value="8" max="10" text-inline text="Activities"></d2l-meter-linear>
|
|
45
52
|
```
|
|
46
53
|
|
|
47
54
|
<!-- docs: start hidden content -->
|
|
@@ -10,6 +10,21 @@
|
|
|
10
10
|
import '../meter-radial.js';
|
|
11
11
|
import '../meter-circle.js';
|
|
12
12
|
</script>
|
|
13
|
+
<style>
|
|
14
|
+
d2l-demo-snippet > div > div {
|
|
15
|
+
padding: 1rem;
|
|
16
|
+
}
|
|
17
|
+
d2l-meter-linear {
|
|
18
|
+
width: 250px;
|
|
19
|
+
}
|
|
20
|
+
d2l-meter-linear, d2l-meter-radial, d2l-meter-circle {
|
|
21
|
+
margin-bottom: 1rem;
|
|
22
|
+
}
|
|
23
|
+
.dark-background {
|
|
24
|
+
background-color: var(--d2l-color-celestine);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
</style>
|
|
13
28
|
</head>
|
|
14
29
|
<body unresolved>
|
|
15
30
|
|
|
@@ -17,48 +32,72 @@
|
|
|
17
32
|
|
|
18
33
|
<h2>Meter Linear</h2>
|
|
19
34
|
|
|
20
|
-
<d2l-demo-snippet>
|
|
35
|
+
<d2l-demo-snippet no-padding>
|
|
21
36
|
<template>
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
<d2l-meter-linear value="2" max="15"
|
|
26
|
-
<d2l-meter-linear value="
|
|
37
|
+
<div>
|
|
38
|
+
<d2l-meter-linear value="2" max="15" text-inline></d2l-meter-linear>
|
|
39
|
+
<d2l-meter-linear value="2" max="15" text-inline percent></d2l-meter-linear>
|
|
40
|
+
<d2l-meter-linear value="2" max="15" text-inline text="Activities"></d2l-meter-linear>
|
|
41
|
+
<d2l-meter-linear value="2" max="15" text-inline text="Activities" percent></d2l-meter-linear>
|
|
42
|
+
<d2l-meter-linear value="3" max="6"></d2l-meter-linear>
|
|
43
|
+
<d2l-meter-linear value="3" max="6" percent></d2l-meter-linear>
|
|
44
|
+
<d2l-meter-linear value="3" max="6" text="Visited: {x/y}" percent></d2l-meter-linear>
|
|
45
|
+
<d2l-meter-linear value="3" max="6" text="Visited: {%}"></d2l-meter-linear>
|
|
46
|
+
<d2l-meter-linear value="3" max="6" text="You're doing great!" percent></d2l-meter-linear>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="dark-background">
|
|
49
|
+
<d2l-meter-linear value="2" max="15" foreground-light text-inline></d2l-meter-linear>
|
|
50
|
+
<d2l-meter-linear value="2" max="15" foreground-light text-inline percent></d2l-meter-linear>
|
|
51
|
+
<d2l-meter-linear value="2" max="15" foreground-light text-inline text="Activities"></d2l-meter-linear>
|
|
52
|
+
<d2l-meter-linear value="2" max="15" foreground-light text-inline text="Activities" percent></d2l-meter-linear>
|
|
53
|
+
<d2l-meter-linear value="3" max="6" foreground-light></d2l-meter-linear>
|
|
54
|
+
<d2l-meter-linear value="3" max="6" foreground-light percent></d2l-meter-linear>
|
|
55
|
+
<d2l-meter-linear value="3" max="6" foreground-light text="Visited: {x/y}" percent></d2l-meter-linear>
|
|
56
|
+
<d2l-meter-linear value="3" max="6" foreground-light text="Visited: {%}"></d2l-meter-linear>
|
|
57
|
+
<d2l-meter-linear value="3" max="6" foreground-light text="You're doing great!" percent></d2l-meter-linear>
|
|
27
58
|
</div>
|
|
28
59
|
</template>
|
|
29
60
|
</d2l-demo-snippet>
|
|
30
61
|
|
|
31
62
|
<h2>Meter Radial</h2>
|
|
32
63
|
|
|
33
|
-
<d2l-demo-snippet>
|
|
64
|
+
<d2l-demo-snippet no-padding>
|
|
34
65
|
<template>
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
66
|
+
<div>
|
|
67
|
+
<d2l-meter-radial value="0" max="10"></d2l-meter-radial>
|
|
68
|
+
<d2l-meter-radial value="5" max="13"></d2l-meter-radial>
|
|
69
|
+
<d2l-meter-radial value="5" max="13" percent></d2l-meter-radial>
|
|
70
|
+
<d2l-meter-radial value="10" max="10"></d2l-meter-radial>
|
|
71
|
+
<d2l-meter-radial value="5" max="10" text="Completed"></d2l-meter-radial>
|
|
72
|
+
<d2l-meter-radial value="19" max="26" style="width: 25%;"></d2l-meter-radial>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="dark-background">
|
|
75
|
+
<d2l-meter-radial value="0" max="10" foreground-light></d2l-meter-radial>
|
|
41
76
|
<d2l-meter-radial value="5" max="13" foreground-light></d2l-meter-radial>
|
|
77
|
+
<d2l-meter-radial value="5" max="13" percent foreground-light></d2l-meter-radial>
|
|
42
78
|
<d2l-meter-radial value="10" max="10" foreground-light></d2l-meter-radial>
|
|
43
|
-
<d2l-meter-radial value="0" max="10" foreground-light></d2l-meter-radial>
|
|
44
|
-
<d2l-meter-radial value="19" max="26" style="width: 25%;" foreground-light></d2l-meter-radial>
|
|
45
79
|
<d2l-meter-radial value="5" max="10" text="Completed" foreground-light></d2l-meter-radial>
|
|
80
|
+
<d2l-meter-radial value="19" max="26" style="width: 25%;" foreground-light></d2l-meter-radial>
|
|
46
81
|
</div>
|
|
47
82
|
</template>
|
|
48
83
|
</d2l-demo-snippet>
|
|
49
84
|
|
|
50
85
|
<h2>Meter Circle</h2>
|
|
51
86
|
|
|
52
|
-
<d2l-demo-snippet>
|
|
87
|
+
<d2l-demo-snippet no-padding>
|
|
53
88
|
<template>
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
<d2l-meter-circle value="
|
|
60
|
-
|
|
89
|
+
<div>
|
|
90
|
+
<d2l-meter-circle value="0" max="10"></d2l-meter-circle>
|
|
91
|
+
<d2l-meter-circle value="5" max="13"></d2l-meter-circle>
|
|
92
|
+
<d2l-meter-circle value="5" max="13" percent></d2l-meter-circle>
|
|
93
|
+
<d2l-meter-circle value="10" max="10"></d2l-meter-circle>
|
|
94
|
+
<d2l-meter-circle value="19" max="26" style="width: 25%;"></d2l-meter-circle>
|
|
95
|
+
</div>
|
|
96
|
+
<div class="dark-background">
|
|
61
97
|
<d2l-meter-circle value="0" max="10" foreground-light></d2l-meter-circle>
|
|
98
|
+
<d2l-meter-circle value="5" max="13" foreground-light></d2l-meter-circle>
|
|
99
|
+
<d2l-meter-circle value="5" max="13" percent foreground-light></d2l-meter-circle>
|
|
100
|
+
<d2l-meter-circle value="10" max="10" foreground-light></d2l-meter-circle>
|
|
62
101
|
<d2l-meter-circle value="19" max="26" style="width: 25%;" foreground-light></d2l-meter-circle>
|
|
63
102
|
</div>
|
|
64
103
|
</template>
|
|
@@ -17,7 +17,7 @@ export const MeterMixin = superclass => class extends LocalizeCoreElement(superc
|
|
|
17
17
|
*/
|
|
18
18
|
percent: { type: Boolean },
|
|
19
19
|
/**
|
|
20
|
-
* Context information for the meter
|
|
20
|
+
* Context information for the meter. If the text contains {%} or {x/y}, they will be replaced with a percentage or fraction respectively.
|
|
21
21
|
* @type {string}
|
|
22
22
|
*/
|
|
23
23
|
text: { type: String },
|
|
@@ -9,7 +9,9 @@ class TestScrollWrapper extends RtlMixin(LitElement) {
|
|
|
9
9
|
return {
|
|
10
10
|
hideActions: { attribute: 'hide-actions', type: Boolean },
|
|
11
11
|
scroll: { attribute: 'scroll', type: Number },
|
|
12
|
-
|
|
12
|
+
splitScrollers: { attribute: 'split-scrollers', type: Boolean },
|
|
13
|
+
width: { type: Number },
|
|
14
|
+
_customScrollers: { state: true }
|
|
13
15
|
};
|
|
14
16
|
}
|
|
15
17
|
|
|
@@ -22,6 +24,16 @@ class TestScrollWrapper extends RtlMixin(LitElement) {
|
|
|
22
24
|
background: linear-gradient(to right, #e66465, #9198e5);
|
|
23
25
|
height: 100px;
|
|
24
26
|
}
|
|
27
|
+
.d2l-scroll-wrapper-gradient-secondary {
|
|
28
|
+
background: linear-gradient(to left, #e66465, #9198e5);
|
|
29
|
+
height: 40px;
|
|
30
|
+
position: relative;
|
|
31
|
+
}
|
|
32
|
+
.d2l-scroll-wrapper-gradient-secondary button {
|
|
33
|
+
inset-inline-end: 0;
|
|
34
|
+
position: absolute;
|
|
35
|
+
top: 0;
|
|
36
|
+
}
|
|
25
37
|
`;
|
|
26
38
|
}
|
|
27
39
|
|
|
@@ -29,24 +41,46 @@ class TestScrollWrapper extends RtlMixin(LitElement) {
|
|
|
29
41
|
super();
|
|
30
42
|
this.hideActions = false;
|
|
31
43
|
this.scroll = 0;
|
|
44
|
+
this.splitScrollers = false;
|
|
32
45
|
this.width = 300;
|
|
46
|
+
this._customScrollers = {};
|
|
33
47
|
}
|
|
34
48
|
|
|
35
49
|
firstUpdated(changedProperties) {
|
|
36
50
|
super.firstUpdated(changedProperties);
|
|
37
|
-
if (this.scroll
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
if (this.scroll !== 0) {
|
|
52
|
+
requestAnimationFrame(() => this.shadowRoot.querySelector('d2l-scroll-wrapper').scrollDistance(this.scroll, false));
|
|
53
|
+
}
|
|
54
|
+
if (this.splitScrollers) {
|
|
55
|
+
this._customScrollers = { primary: this.shadowRoot.querySelector('.primary'), secondary: this.shadowRoot.querySelectorAll('.secondary') };
|
|
56
|
+
}
|
|
41
57
|
}
|
|
42
58
|
|
|
43
59
|
render() {
|
|
44
60
|
const style = {
|
|
45
61
|
width: `${this.width}px`
|
|
46
62
|
};
|
|
47
|
-
|
|
48
|
-
|
|
63
|
+
|
|
64
|
+
const secondaryScroller = html`
|
|
65
|
+
<div class="secondary">
|
|
66
|
+
<div class="d2l-scroll-wrapper-gradient-secondary" style="${styleMap(style)}">
|
|
67
|
+
Secondary scroller (No mouse scroll)
|
|
68
|
+
<button>Focus</button>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
const contents = this.splitScrollers ? html`
|
|
74
|
+
${secondaryScroller}
|
|
75
|
+
<div class="primary">
|
|
49
76
|
<div class="d2l-scroll-wrapper-gradient" style="${styleMap(style)}"></div>
|
|
77
|
+
</div>
|
|
78
|
+
${secondaryScroller}
|
|
79
|
+
` : html`<div class="d2l-scroll-wrapper-gradient" style="${styleMap(style)}"></div>`;
|
|
80
|
+
|
|
81
|
+
return html`
|
|
82
|
+
<d2l-scroll-wrapper ?hide-actions="${this.hideActions}" .customScrollers="${this._customScrollers}">
|
|
83
|
+
${contents}
|
|
50
84
|
</d2l-scroll-wrapper>
|
|
51
85
|
`;
|
|
52
86
|
}
|
|
@@ -31,6 +31,15 @@
|
|
|
31
31
|
</template>
|
|
32
32
|
</d2l-demo-snippet>
|
|
33
33
|
|
|
34
|
+
<h2>Split scrollers</h2>
|
|
35
|
+
<d2l-demo-snippet>
|
|
36
|
+
<template>
|
|
37
|
+
<div style="max-width: 700px;">
|
|
38
|
+
<d2l-test-scroll-wrapper width="1000" split-scrollers></d2l-test-scroll-wrapper>
|
|
39
|
+
</div>
|
|
40
|
+
</template>
|
|
41
|
+
</d2l-demo-snippet>
|
|
42
|
+
|
|
34
43
|
</d2l-demo-page>
|
|
35
44
|
</body>
|
|
36
45
|
</html>
|
|
@@ -2,12 +2,37 @@ import '../colors/colors.js';
|
|
|
2
2
|
import '../icons/icon.js';
|
|
3
3
|
import { css, html, LitElement, unsafeCSS } from 'lit';
|
|
4
4
|
import { getFocusPseudoClass } from '../../helpers/focus.js';
|
|
5
|
-
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
6
5
|
import ResizeObserver from 'resize-observer-polyfill/dist/ResizeObserver.es.js';
|
|
7
6
|
import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
|
|
8
7
|
|
|
9
8
|
const RTL_MULTIPLIER = navigator.userAgent.indexOf('Edge/') > 0 ? 1 : -1; /* legacy-Edge doesn't reverse scrolling in RTL */
|
|
10
9
|
const SCROLL_AMOUNT = 0.8;
|
|
10
|
+
const PRINT_MEDIA_QUERY_LIST = matchMedia('print');
|
|
11
|
+
|
|
12
|
+
let focusStyleSheet;
|
|
13
|
+
function getFocusStyleSheet() {
|
|
14
|
+
if (!focusStyleSheet) {
|
|
15
|
+
focusStyleSheet = new CSSStyleSheet();
|
|
16
|
+
focusStyleSheet.replaceSync(css`
|
|
17
|
+
.d2l-scroll-wrapper-focus:${unsafeCSS(getFocusPseudoClass())} {
|
|
18
|
+
box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px var(--d2l-color-celestine), 0 2px 12px 0 rgba(0, 0, 0, 0.15);
|
|
19
|
+
outline: none;
|
|
20
|
+
}`);
|
|
21
|
+
}
|
|
22
|
+
return focusStyleSheet;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getStyleSheetInsertionPoint(elem) {
|
|
26
|
+
if (elem.nodeType === Node.DOCUMENT_NODE || elem.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
27
|
+
if (elem.querySelector('.d2l-scroll-wrapper-focus') !== null) {
|
|
28
|
+
return elem;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (elem.parentNode) {
|
|
32
|
+
return getStyleSheetInsertionPoint(elem.parentNode);
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
11
36
|
|
|
12
37
|
/**
|
|
13
38
|
*
|
|
@@ -18,6 +43,14 @@ class ScrollWrapper extends RtlMixin(LitElement) {
|
|
|
18
43
|
|
|
19
44
|
static get properties() {
|
|
20
45
|
return {
|
|
46
|
+
/**
|
|
47
|
+
* An object containing custom primary/secondary scroll containers
|
|
48
|
+
* @type {Object}
|
|
49
|
+
*/
|
|
50
|
+
customScrollers: {
|
|
51
|
+
attribute: false,
|
|
52
|
+
type: Object
|
|
53
|
+
},
|
|
21
54
|
/**
|
|
22
55
|
* Whether to hide left/right scroll buttons
|
|
23
56
|
* @type {boolean}
|
|
@@ -31,6 +64,7 @@ class ScrollWrapper extends RtlMixin(LitElement) {
|
|
|
31
64
|
reflect: true,
|
|
32
65
|
type: Boolean
|
|
33
66
|
},
|
|
67
|
+
_printMode: { state: true },
|
|
34
68
|
_scrollbarLeft: {
|
|
35
69
|
attribute: 'scrollbar-left',
|
|
36
70
|
reflect: true,
|
|
@@ -55,13 +89,8 @@ class ScrollWrapper extends RtlMixin(LitElement) {
|
|
|
55
89
|
}
|
|
56
90
|
.d2l-scroll-wrapper-container {
|
|
57
91
|
box-sizing: border-box;
|
|
58
|
-
outline: none;
|
|
59
|
-
overflow-x: auto;
|
|
60
92
|
overflow-y: var(--d2l-scroll-wrapper-overflow-y, visible);
|
|
61
93
|
}
|
|
62
|
-
.d2l-scroll-wrapper-container:${unsafeCSS(getFocusPseudoClass())} {
|
|
63
|
-
box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px var(--d2l-color-celestine), 0 2px 12px 0 rgba(0, 0, 0, 0.15);
|
|
64
|
-
}
|
|
65
94
|
:host([h-scrollbar]) .d2l-scroll-wrapper-container {
|
|
66
95
|
border-left: 1px dashed var(--d2l-color-mica);
|
|
67
96
|
border-right: 1px dashed var(--d2l-color-mica);
|
|
@@ -121,47 +150,48 @@ class ScrollWrapper extends RtlMixin(LitElement) {
|
|
|
121
150
|
:host([scrollbar-left]) .d2l-scroll-wrapper-button-left {
|
|
122
151
|
display: none;
|
|
123
152
|
}
|
|
124
|
-
|
|
125
|
-
/* hide wrapper visuals from print view */
|
|
126
|
-
@media print {
|
|
127
|
-
.d2l-scroll-wrapper-actions {
|
|
128
|
-
display: none;
|
|
129
|
-
}
|
|
130
|
-
.d2l-scroll-wrapper-container {
|
|
131
|
-
overflow-x: visible;
|
|
132
|
-
}
|
|
133
|
-
:host([h-scrollbar]) .d2l-scroll-wrapper-container {
|
|
134
|
-
border-left: none;
|
|
135
|
-
border-right: none;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
153
|
`;
|
|
139
154
|
}
|
|
140
155
|
|
|
141
156
|
constructor() {
|
|
142
157
|
super();
|
|
158
|
+
this.customScrollers = {};
|
|
143
159
|
this.hideActions = false;
|
|
160
|
+
this._allScrollers = [];
|
|
161
|
+
this._baseContainer = null;
|
|
144
162
|
this._container = null;
|
|
145
163
|
this._hScrollbar = true;
|
|
146
|
-
this.
|
|
164
|
+
this._printMode = PRINT_MEDIA_QUERY_LIST.matches;
|
|
165
|
+
this._resizeObserver = new ResizeObserver(() => requestAnimationFrame(() => this.checkScrollbar()));
|
|
147
166
|
this._scrollbarLeft = false;
|
|
148
167
|
this._scrollbarRight = false;
|
|
168
|
+
this._syncDriver = null;
|
|
169
|
+
this._syncDriverTimeout = null;
|
|
170
|
+
this._checkScrollThresholds = this._checkScrollThresholds.bind(this);
|
|
171
|
+
this._handlePrintChange = this._handlePrintChange.bind(this);
|
|
172
|
+
this._synchronizeScroll = this._synchronizeScroll.bind(this);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
connectedCallback() {
|
|
176
|
+
super.connectedCallback();
|
|
177
|
+
PRINT_MEDIA_QUERY_LIST?.addEventListener('change', this._handlePrintChange);
|
|
149
178
|
}
|
|
150
179
|
|
|
151
180
|
disconnectedCallback() {
|
|
152
181
|
super.disconnectedCallback();
|
|
153
|
-
|
|
182
|
+
this._disconnectAll();
|
|
183
|
+
PRINT_MEDIA_QUERY_LIST?.removeEventListener('change', this._handlePrintChange);
|
|
154
184
|
}
|
|
155
185
|
|
|
156
186
|
firstUpdated(changedProperties) {
|
|
157
187
|
super.firstUpdated(changedProperties);
|
|
158
|
-
this.
|
|
159
|
-
this._resizeObserver = new ResizeObserver(() => requestAnimationFrame(() => this.checkScrollbar()));
|
|
160
|
-
this._resizeObserver.observe(this._container);
|
|
188
|
+
this._updateScrollTargets();
|
|
161
189
|
}
|
|
162
190
|
|
|
163
191
|
render() {
|
|
164
|
-
|
|
192
|
+
// when printing, just get scroll-wrapper out of the way
|
|
193
|
+
if (this._printMode) return html`<slot></slot>`;
|
|
194
|
+
|
|
165
195
|
const actions = !this.hideActions ? html`
|
|
166
196
|
<div class="d2l-scroll-wrapper-actions">
|
|
167
197
|
<div class="d2l-scroll-wrapper-button d2l-scroll-wrapper-button-left" @click="${this._scrollLeft}">
|
|
@@ -173,10 +203,17 @@ class ScrollWrapper extends RtlMixin(LitElement) {
|
|
|
173
203
|
</div>` : null;
|
|
174
204
|
return html`
|
|
175
205
|
${actions}
|
|
176
|
-
<div class="d2l-scroll-wrapper-container"
|
|
206
|
+
<div class="d2l-scroll-wrapper-container"><slot></slot></div>
|
|
177
207
|
`;
|
|
178
208
|
}
|
|
179
209
|
|
|
210
|
+
updated(changedProperties) {
|
|
211
|
+
super.updated(changedProperties);
|
|
212
|
+
|
|
213
|
+
if (changedProperties.has('customScrollers')) this._updateScrollTargets();
|
|
214
|
+
if (changedProperties.has('_hScrollbar')) this._updateTabIndex();
|
|
215
|
+
}
|
|
216
|
+
|
|
180
217
|
checkScrollbar() {
|
|
181
218
|
if (!this._container) return;
|
|
182
219
|
this._hScrollbar = this._container.offsetWidth !== this._container.scrollWidth;
|
|
@@ -201,12 +238,39 @@ class ScrollWrapper extends RtlMixin(LitElement) {
|
|
|
201
238
|
|
|
202
239
|
_checkScrollThresholds() {
|
|
203
240
|
if (!this._container) return;
|
|
204
|
-
const lowerScrollValue = this._container.scrollWidth - this.
|
|
241
|
+
const lowerScrollValue = this._container.scrollWidth - this._baseContainer.offsetWidth - Math.abs(this._container.scrollLeft);
|
|
205
242
|
this._scrollbarLeft = (this._container.scrollLeft === 0);
|
|
206
243
|
this._scrollbarRight = (lowerScrollValue <= 0);
|
|
207
244
|
|
|
208
245
|
}
|
|
209
246
|
|
|
247
|
+
_disconnectAll() {
|
|
248
|
+
this._resizeObserver?.disconnect();
|
|
249
|
+
|
|
250
|
+
if (this._container) {
|
|
251
|
+
this._container.style.removeProperty('overflow-x');
|
|
252
|
+
this._container.classList.remove('d2l-scroll-wrapper-focus');
|
|
253
|
+
this._container.removeAttribute('tabindex');
|
|
254
|
+
this._container.removeEventListener('scroll', this._synchronizeScroll);
|
|
255
|
+
this._container.removeEventListener('scroll', this._checkScrollThresholds);
|
|
256
|
+
this._secondaryScrollers.forEach(element => {
|
|
257
|
+
element.style.removeProperty('overflow-x');
|
|
258
|
+
element.removeEventListener('scroll', this._synchronizeScroll);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
async _handlePrintChange() {
|
|
264
|
+
if (!this._printMode) {
|
|
265
|
+
this._disconnectAll();
|
|
266
|
+
}
|
|
267
|
+
this._printMode = PRINT_MEDIA_QUERY_LIST.matches;
|
|
268
|
+
if (!this._printMode) {
|
|
269
|
+
await this.updateComplete;
|
|
270
|
+
this._updateScrollTargets();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
210
274
|
_scrollLeft() {
|
|
211
275
|
if (!this._container) return;
|
|
212
276
|
const scrollDistance = this._container.clientWidth * SCROLL_AMOUNT * -1;
|
|
@@ -219,6 +283,58 @@ class ScrollWrapper extends RtlMixin(LitElement) {
|
|
|
219
283
|
this.scrollDistance(scrollDistance, true);
|
|
220
284
|
}
|
|
221
285
|
|
|
286
|
+
_synchronizeScroll(e) {
|
|
287
|
+
if (this._syncDriver && e.target !== this._syncDriver) return;
|
|
288
|
+
if (this._syncDriverTimeout) clearTimeout(this._syncDriverTimeout);
|
|
289
|
+
|
|
290
|
+
this._syncDriver = e.target;
|
|
291
|
+
this._allScrollers.forEach(element => {
|
|
292
|
+
if (element && element !== e.target) element.scrollLeft = e.target.scrollLeft;
|
|
293
|
+
});
|
|
294
|
+
this._syncDriverTimeout = setTimeout(() => this._syncDriver = null, 100);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
_updateScrollTargets() {
|
|
298
|
+
this._disconnectAll();
|
|
299
|
+
|
|
300
|
+
if (this._printMode) return;
|
|
301
|
+
|
|
302
|
+
this._baseContainer = this.shadowRoot.querySelector('.d2l-scroll-wrapper-container');
|
|
303
|
+
this._container = this.customScrollers?.primary || this._baseContainer;
|
|
304
|
+
this._secondaryScrollers = this.customScrollers?.secondary || [];
|
|
305
|
+
if (this._secondaryScrollers.length === undefined) this._secondaryScrollers = [ this._secondaryScrollers ];
|
|
306
|
+
this._allScrollers = [ this._container, ...this._secondaryScrollers ];
|
|
307
|
+
|
|
308
|
+
if (this._container) {
|
|
309
|
+
this._container.classList.add('d2l-scroll-wrapper-focus');
|
|
310
|
+
const styleRoot = getStyleSheetInsertionPoint(this._container);
|
|
311
|
+
if (styleRoot && 'adoptedStyleSheets' in styleRoot) {
|
|
312
|
+
const sheet = getFocusStyleSheet();
|
|
313
|
+
if (styleRoot.adoptedStyleSheets.indexOf(sheet) === -1) {
|
|
314
|
+
styleRoot.adoptedStyleSheets = [...styleRoot.adoptedStyleSheets, sheet];
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
this._container.style.overflowX = 'auto';
|
|
318
|
+
this._resizeObserver.observe(this._container);
|
|
319
|
+
this._container.addEventListener('scroll', this._checkScrollThresholds);
|
|
320
|
+
this._updateTabIndex();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (this._secondaryScrollers.length) {
|
|
324
|
+
this._secondaryScrollers.forEach(element => {
|
|
325
|
+
element.style.overflowX = 'hidden';
|
|
326
|
+
element.addEventListener('scroll', this._synchronizeScroll);
|
|
327
|
+
});
|
|
328
|
+
this._container.addEventListener('scroll', this._synchronizeScroll);
|
|
329
|
+
this._synchronizeScroll({ target: this._container });
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
_updateTabIndex() {
|
|
334
|
+
if (!this._container) return;
|
|
335
|
+
if (this._hScrollbar) this._container.tabIndex = 0;
|
|
336
|
+
else this._container.removeAttribute('tabindex');
|
|
337
|
+
}
|
|
222
338
|
}
|
|
223
339
|
|
|
224
340
|
customElements.define('d2l-scroll-wrapper', ScrollWrapper);
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
<h2>Default, Sticky columns</h2>
|
|
59
59
|
<d2l-demo-snippet overflow-hidden>
|
|
60
60
|
<template>
|
|
61
|
-
<div style="overflow: auto; width:
|
|
61
|
+
<div style="overflow: auto; width: 400px;">
|
|
62
62
|
<d2l-test-table type="default" sticky-headers sticky-controls></d2l-test-table>
|
|
63
63
|
</div>
|
|
64
64
|
</template>
|
|
@@ -67,12 +67,19 @@
|
|
|
67
67
|
<h2>Default with Scroll-Wrapper (no sticky)</h2>
|
|
68
68
|
<d2l-demo-snippet overflow-hidden>
|
|
69
69
|
<template>
|
|
70
|
-
<div style="height:
|
|
71
|
-
<d2l-test-table type="default" sticky-controls style="width:
|
|
70
|
+
<div style="height: 400px; overflow: auto;">
|
|
71
|
+
<d2l-test-table type="default" sticky-controls style="width: 400px;"></d2l-test-table>
|
|
72
72
|
</div>
|
|
73
73
|
</template>
|
|
74
74
|
</d2l-demo-snippet>
|
|
75
75
|
|
|
76
|
+
<h2>Scroll-wrapper + sticky</h2>
|
|
77
|
+
<d2l-demo-snippet>
|
|
78
|
+
<template>
|
|
79
|
+
<d2l-test-table sticky-headers sticky-controls sticky-headers-scroll-wrapper style="width: 400px;"></d2l-test-table>
|
|
80
|
+
</template>
|
|
81
|
+
</d2l-demo-snippet>
|
|
82
|
+
|
|
76
83
|
<div style="margin-bottom: 1000px;"></div>
|
|
77
84
|
</d2l-demo-page>
|
|
78
85
|
</body>
|
|
@@ -2,6 +2,7 @@ import '../colors/colors.js';
|
|
|
2
2
|
import '../scroll-wrapper/scroll-wrapper.js';
|
|
3
3
|
import { css, html, LitElement, nothing } from 'lit';
|
|
4
4
|
import { PageableMixin } from '../paging/pageable-mixin.js';
|
|
5
|
+
import ResizeObserver from 'resize-observer-polyfill/dist/ResizeObserver.es.js';
|
|
5
6
|
import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
|
|
6
7
|
import { SelectionMixin } from '../selection/selection-mixin.js';
|
|
7
8
|
|
|
@@ -114,10 +115,35 @@ export const tableStyles = css`
|
|
|
114
115
|
|
|
115
116
|
/* sticky-headers */
|
|
116
117
|
|
|
118
|
+
/* all sticky cells */
|
|
119
|
+
d2l-table-wrapper[sticky-headers] .d2l-table > * > tr > .d2l-table-sticky-cell,
|
|
120
|
+
d2l-table-wrapper[sticky-headers] .d2l-table > * > tr > [sticky] {
|
|
121
|
+
position: -webkit-sticky;
|
|
122
|
+
position: sticky;
|
|
123
|
+
z-index: 1;
|
|
124
|
+
}
|
|
125
|
+
d2l-table-wrapper:not([dir="rtl"])[sticky-headers] .d2l-table > * > tr > .d2l-table-sticky-cell,
|
|
126
|
+
d2l-table-wrapper:not([dir="rtl"])[sticky-headers] .d2l-table > * > tr > [sticky] {
|
|
127
|
+
left: 0;
|
|
128
|
+
}
|
|
129
|
+
d2l-table-wrapper[dir="rtl"][sticky-headers] .d2l-table > * > tr > .d2l-table-sticky-cell,
|
|
130
|
+
d2l-table-wrapper[dir="rtl"][sticky-headers] .d2l-table > * > tr > [sticky] {
|
|
131
|
+
right: 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* non-header sticky cells */
|
|
135
|
+
d2l-table-wrapper[sticky-headers] .d2l-table > * > tr:not([selected]) {
|
|
136
|
+
background-color: inherit; /* white background so sticky cells layer on top of non-sticky cells */
|
|
137
|
+
}
|
|
138
|
+
d2l-table-wrapper[sticky-headers] .d2l-table > tbody > tr:not([header]):not(.d2l-table-header) > .d2l-table-sticky-cell,
|
|
139
|
+
d2l-table-wrapper[sticky-headers] .d2l-table > tbody > tr:not([header]):not(.d2l-table-header) > [sticky] {
|
|
140
|
+
background-color: inherit;
|
|
141
|
+
}
|
|
142
|
+
|
|
117
143
|
/* all header cells */
|
|
118
144
|
d2l-table-wrapper[sticky-headers] .d2l-table > thead > tr > th,
|
|
119
|
-
d2l-table-wrapper[sticky-headers] .d2l-table > * > tr.d2l-table-header > *,
|
|
120
|
-
d2l-table-wrapper[sticky-headers] .d2l-table > * > tr[header] > * {
|
|
145
|
+
d2l-table-wrapper[sticky-headers]:not([sticky-headers-scroll-wrapper]) .d2l-table > * > tr.d2l-table-header > *,
|
|
146
|
+
d2l-table-wrapper[sticky-headers]:not([sticky-headers-scroll-wrapper]) .d2l-table > * > tr[header] > * {
|
|
121
147
|
position: -webkit-sticky;
|
|
122
148
|
position: sticky;
|
|
123
149
|
z-index: 2;
|
|
@@ -126,17 +152,12 @@ export const tableStyles = css`
|
|
|
126
152
|
/* header cells that are also sticky */
|
|
127
153
|
d2l-table-wrapper[sticky-headers] .d2l-table > thead > tr > th.d2l-table-sticky-cell,
|
|
128
154
|
d2l-table-wrapper[sticky-headers] .d2l-table > thead > tr > th[sticky],
|
|
129
|
-
d2l-table-wrapper[sticky-headers] .d2l-table > * > tr.d2l-table-header > .d2l-table-sticky-cell,
|
|
130
|
-
d2l-table-wrapper[sticky-headers] .d2l-table > * > tr.d2l-table-header > [sticky],
|
|
131
|
-
d2l-table-wrapper[sticky-headers] .d2l-table > * > tr[header] > .d2l-table-sticky-cell,
|
|
132
|
-
d2l-table-wrapper[sticky-headers] .d2l-table > * > tr[header] > [sticky] {
|
|
133
|
-
left: 0;
|
|
155
|
+
d2l-table-wrapper[sticky-headers]:not([sticky-headers-scroll-wrapper]) .d2l-table > * > tr.d2l-table-header > .d2l-table-sticky-cell,
|
|
156
|
+
d2l-table-wrapper[sticky-headers]:not([sticky-headers-scroll-wrapper]) .d2l-table > * > tr.d2l-table-header > [sticky],
|
|
157
|
+
d2l-table-wrapper[sticky-headers]:not([sticky-headers-scroll-wrapper]) .d2l-table > * > tr[header] > .d2l-table-sticky-cell,
|
|
158
|
+
d2l-table-wrapper[sticky-headers]:not([sticky-headers-scroll-wrapper]) .d2l-table > * > tr[header] > [sticky] {
|
|
134
159
|
z-index: 3;
|
|
135
160
|
}
|
|
136
|
-
d2l-table-wrapper[dir="rtl"][sticky-headers] .d2l-table > * > tr > .d2l-table-sticky-cell,
|
|
137
|
-
d2l-table-wrapper[dir="rtl"][sticky-headers] .d2l-table > * > tr > [sticky] {
|
|
138
|
-
right: 0;
|
|
139
|
-
}
|
|
140
161
|
|
|
141
162
|
/* first column that's sticky: offset by size of border-radius so top/bottom border doesn't show through (default style only) */
|
|
142
163
|
d2l-table-wrapper[sticky-headers][type="default"]:not([dir="rtl"]) .d2l-table > * > tr > .d2l-table-sticky-cell.d2l-table-cell-first,
|
|
@@ -148,17 +169,20 @@ export const tableStyles = css`
|
|
|
148
169
|
right: var(--d2l-table-border-radius-sticky-offset, 0);
|
|
149
170
|
}
|
|
150
171
|
|
|
151
|
-
/*
|
|
152
|
-
d2l-table-wrapper[sticky-headers] .d2l-table
|
|
153
|
-
|
|
172
|
+
/* sticky + scroll-wrapper */
|
|
173
|
+
d2l-table-wrapper[sticky-headers][sticky-headers-scroll-wrapper] .d2l-table {
|
|
174
|
+
display: block;
|
|
154
175
|
}
|
|
155
|
-
|
|
156
|
-
d2l-table-wrapper[sticky-headers]
|
|
157
|
-
|
|
158
|
-
left: 0;
|
|
159
|
-
position: -webkit-sticky;
|
|
176
|
+
|
|
177
|
+
d2l-table-wrapper[sticky-headers][sticky-headers-scroll-wrapper] .d2l-table > thead {
|
|
178
|
+
display: block;
|
|
160
179
|
position: sticky;
|
|
161
|
-
|
|
180
|
+
top: calc(var(--d2l-table-sticky-top, 0px) + var(--d2l-table-border-radius-sticky-offset, 0px));
|
|
181
|
+
z-index: 2;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
d2l-table-wrapper[sticky-headers][sticky-headers-scroll-wrapper] .d2l-table > tbody {
|
|
185
|
+
display: block;
|
|
162
186
|
}
|
|
163
187
|
`;
|
|
164
188
|
|
|
@@ -190,6 +214,15 @@ export class TableWrapper extends RtlMixin(PageableMixin(SelectionMixin(LitEleme
|
|
|
190
214
|
reflect: true,
|
|
191
215
|
type: Boolean
|
|
192
216
|
},
|
|
217
|
+
/**
|
|
218
|
+
* When used in combo with `sticky-headers`, whether to additionally wrap the table in a scroll-wrapper. Requires sticky headers to be in a separate thead.
|
|
219
|
+
* @type {boolean}
|
|
220
|
+
*/
|
|
221
|
+
stickyHeadersScrollWrapper: {
|
|
222
|
+
attribute: 'sticky-headers-scroll-wrapper',
|
|
223
|
+
reflect: true,
|
|
224
|
+
type: Boolean
|
|
225
|
+
},
|
|
193
226
|
/**
|
|
194
227
|
* Type of table style to apply. The "light" style has fewer borders and tighter padding.
|
|
195
228
|
* @type {'default'|'light'}
|
|
@@ -257,6 +290,7 @@ export class TableWrapper extends RtlMixin(PageableMixin(SelectionMixin(LitEleme
|
|
|
257
290
|
super();
|
|
258
291
|
this.noColumnBorder = false;
|
|
259
292
|
this.stickyHeaders = false;
|
|
293
|
+
this.stickyHeadersScrollWrapper = false;
|
|
260
294
|
this.type = 'default';
|
|
261
295
|
|
|
262
296
|
this._controls = null;
|
|
@@ -266,6 +300,7 @@ export class TableWrapper extends RtlMixin(PageableMixin(SelectionMixin(LitEleme
|
|
|
266
300
|
this._table = null;
|
|
267
301
|
this._tableIntersectionObserver = null;
|
|
268
302
|
this._tableMutationObserver = null;
|
|
303
|
+
this._tableScrollers = {};
|
|
269
304
|
}
|
|
270
305
|
|
|
271
306
|
disconnectedCallback() {
|
|
@@ -275,14 +310,16 @@ export class TableWrapper extends RtlMixin(PageableMixin(SelectionMixin(LitEleme
|
|
|
275
310
|
this._controlsScrolledMutationObserver?.disconnect();
|
|
276
311
|
this._tableMutationObserver?.disconnect();
|
|
277
312
|
this._tableIntersectionObserver?.disconnect();
|
|
313
|
+
this._tableResizeObserver?.disconnect();
|
|
278
314
|
}
|
|
279
315
|
|
|
280
316
|
render() {
|
|
281
317
|
const slot = html`<slot @slotchange="${this._handleSlotChange}"></slot>`;
|
|
318
|
+
const useScrollWrapper = this.stickyHeadersScrollWrapper || !this.stickyHeaders;
|
|
282
319
|
return html`
|
|
283
320
|
<slot name="controls" @slotchange="${this._handleControlsSlotChange}"></slot>
|
|
284
321
|
${this.stickyHeaders && this._controlsScrolled ? html`<div class="d2l-sticky-headers-backdrop"></div>` : nothing}
|
|
285
|
-
${
|
|
322
|
+
${useScrollWrapper ? html`<d2l-scroll-wrapper .customScrollers="${this._tableScrollers}">${slot}</d2l-scroll-wrapper>` : slot}
|
|
286
323
|
${this._renderPagerContainer()}
|
|
287
324
|
`;
|
|
288
325
|
}
|
|
@@ -388,6 +425,10 @@ export class TableWrapper extends RtlMixin(PageableMixin(SelectionMixin(LitEleme
|
|
|
388
425
|
this._table = e.target.assignedNodes({ flatten: true }).find(
|
|
389
426
|
node => (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'TABLE' && node.classList.contains('d2l-table'))
|
|
390
427
|
);
|
|
428
|
+
this._tableScrollers = (this.stickyHeadersScrollWrapper && this.stickyHeaders) ? {
|
|
429
|
+
primary: this._table?.querySelector('tbody'),
|
|
430
|
+
secondary: this._table?.querySelector('thead'),
|
|
431
|
+
} : {};
|
|
391
432
|
|
|
392
433
|
// observes mutations to <table>'s direct children and also
|
|
393
434
|
// its subtree (rows or cells added/removed to any descendant)
|
|
@@ -397,6 +438,7 @@ export class TableWrapper extends RtlMixin(PageableMixin(SelectionMixin(LitEleme
|
|
|
397
438
|
childList: true,
|
|
398
439
|
subtree: true
|
|
399
440
|
});
|
|
441
|
+
this._tableResizeObserver?.disconnect();
|
|
400
442
|
|
|
401
443
|
if (!this._table) return;
|
|
402
444
|
|
|
@@ -418,6 +460,9 @@ export class TableWrapper extends RtlMixin(PageableMixin(SelectionMixin(LitEleme
|
|
|
418
460
|
this._tableIntersectionObserver.observe(this._table);
|
|
419
461
|
}
|
|
420
462
|
|
|
463
|
+
if (!this._tableResizeObserver) this._tableResizeObserver = new ResizeObserver(() => this._syncColumnWidths());
|
|
464
|
+
this._tableResizeObserver.observe(this._table);
|
|
465
|
+
|
|
421
466
|
this._handleTableChange();
|
|
422
467
|
}
|
|
423
468
|
|
|
@@ -426,6 +471,7 @@ export class TableWrapper extends RtlMixin(PageableMixin(SelectionMixin(LitEleme
|
|
|
426
471
|
|
|
427
472
|
this._updateItemShowingCount();
|
|
428
473
|
this._applyClassNames();
|
|
474
|
+
this._syncColumnWidths();
|
|
429
475
|
this._updateStickyTops();
|
|
430
476
|
}
|
|
431
477
|
|
|
@@ -438,12 +484,35 @@ export class TableWrapper extends RtlMixin(PageableMixin(SelectionMixin(LitEleme
|
|
|
438
484
|
if (target) this[observerName].observe(target, options);
|
|
439
485
|
}
|
|
440
486
|
|
|
487
|
+
_syncColumnWidths() {
|
|
488
|
+
if (!this._table || !this.stickyHeaders || !this.stickyHeadersScrollWrapper) return;
|
|
489
|
+
|
|
490
|
+
const head = this._table.querySelector('thead');
|
|
491
|
+
const body = this._table.querySelector('tbody');
|
|
492
|
+
if (!head || !body) return;
|
|
493
|
+
|
|
494
|
+
const firstRowHead = head.rows[0];
|
|
495
|
+
const firstRowBody = body.rows[0];
|
|
496
|
+
if (!firstRowHead || !firstRowBody || firstRowHead.cells.length !== firstRowBody.cells.length) return;
|
|
497
|
+
|
|
498
|
+
for (let i = 0; i < firstRowHead.cells.length; i++) {
|
|
499
|
+
const headCell = firstRowHead.cells[i];
|
|
500
|
+
const bodyCell = firstRowBody.cells[i];
|
|
501
|
+
|
|
502
|
+
if (headCell.clientWidth > bodyCell.clientWidth) {
|
|
503
|
+
bodyCell.style.minWidth = getComputedStyle(headCell).width;
|
|
504
|
+
} else if (headCell.clientWidth < bodyCell.clientWidth) {
|
|
505
|
+
headCell.style.minWidth = getComputedStyle(bodyCell).width;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
441
510
|
_updateStickyTops() {
|
|
442
511
|
const hasStickyControls = this._controls && !this._controls.noSticky;
|
|
443
512
|
let rowTop = hasStickyControls ? this._controls.offsetHeight + 6 : 0; // +6 for the internal `margin-bottom`.
|
|
444
513
|
this.style.setProperty('--d2l-table-sticky-top', `${rowTop}px`);
|
|
445
514
|
|
|
446
|
-
if (!this._table || !this.stickyHeaders) return;
|
|
515
|
+
if (!this._table || !this.stickyHeaders || this.stickyHeadersScrollWrapper) return;
|
|
447
516
|
|
|
448
517
|
const stickyRows = Array.from(this._table.querySelectorAll('tr.d2l-table-header, tr[header], thead tr'));
|
|
449
518
|
stickyRows.forEach(r => {
|
|
@@ -2,6 +2,7 @@ import '../button/button-icon.js';
|
|
|
2
2
|
import '../colors/colors.js';
|
|
3
3
|
import '../tooltip/tooltip.js';
|
|
4
4
|
import { css, html, nothing } from 'lit';
|
|
5
|
+
import { findComposedAncestor, isComposedAncestor } from '../../helpers/dom.js';
|
|
5
6
|
import { heading4Styles, labelStyles } from '../typography/styles.js';
|
|
6
7
|
import { announce } from '../../helpers/announce.js';
|
|
7
8
|
import { classMap } from 'lit/directives/class-map.js';
|
|
@@ -30,7 +31,10 @@ export const TagListItemMixin = superclass => class extends LocalizeCoreElement(
|
|
|
30
31
|
* @ignore
|
|
31
32
|
*/
|
|
32
33
|
keyboardTooltipItem: { type: Boolean, attribute: 'keyboard-tooltip-item' },
|
|
33
|
-
|
|
34
|
+
/**
|
|
35
|
+
* @ignore
|
|
36
|
+
*/
|
|
37
|
+
keyboardTooltipShown: { type: Boolean, attribute: 'keyboard-tooltip-shown' }
|
|
34
38
|
};
|
|
35
39
|
}
|
|
36
40
|
|
|
@@ -127,9 +131,8 @@ export const TagListItemMixin = superclass => class extends LocalizeCoreElement(
|
|
|
127
131
|
this.clearable = false;
|
|
128
132
|
/** @ignore */
|
|
129
133
|
this.keyboardTooltipItem = false;
|
|
130
|
-
this.
|
|
134
|
+
this.keyboardTooltipShown = false;
|
|
131
135
|
this._id = getUniqueId();
|
|
132
|
-
this._keyboardTooltipShown = false;
|
|
133
136
|
}
|
|
134
137
|
|
|
135
138
|
firstUpdated(changedProperties) {
|
|
@@ -140,17 +143,26 @@ export const TagListItemMixin = superclass => class extends LocalizeCoreElement(
|
|
|
140
143
|
this.addEventListener('focus', async(e) => {
|
|
141
144
|
// ignore focus events coming from inside the tag content
|
|
142
145
|
if (e.composedPath()[0] !== this) return;
|
|
146
|
+
const tagList = findComposedAncestor(this, elem => elem.tagName === 'D2L-TAG-LIST');
|
|
147
|
+
if (this.keyboardTooltipItem && this.keyboardTooltipShown && !isComposedAncestor(tagList, e.relatedTarget)) {
|
|
148
|
+
const arrows = this.localize('components.tag-list-item.tooltip-arrow-keys');
|
|
149
|
+
const arrowsDescription = this.localize('components.tag-list-item.tooltip-arrow-keys-desc');
|
|
150
|
+
|
|
151
|
+
let message = `${arrows} - ${arrowsDescription}`;
|
|
152
|
+
if (this.clearable) {
|
|
153
|
+
const del = this.localize('components.tag-list-item.tooltip-delete-key');
|
|
154
|
+
const delDescription = this.localize('components.tag-list-item.tooltip-delete-key-desc');
|
|
155
|
+
message += `; ${del} - ${delDescription}`;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
announce(message);
|
|
159
|
+
}
|
|
143
160
|
|
|
144
|
-
this._displayKeyboardTooltip = (this.keyboardTooltipItem && !this._keyboardTooltipShown);
|
|
145
161
|
await this.updateComplete;
|
|
146
162
|
|
|
147
163
|
container.focus();
|
|
148
164
|
});
|
|
149
165
|
|
|
150
|
-
this.addEventListener('blur', () => {
|
|
151
|
-
this._displayKeyboardTooltip = false;
|
|
152
|
-
});
|
|
153
|
-
|
|
154
166
|
this.addEventListener('keydown', this._handleKeydown);
|
|
155
167
|
}
|
|
156
168
|
|
|
@@ -167,11 +179,10 @@ export const TagListItemMixin = superclass => class extends LocalizeCoreElement(
|
|
|
167
179
|
}
|
|
168
180
|
|
|
169
181
|
_handleKeyboardTooltipHide() {
|
|
170
|
-
|
|
182
|
+
this.keyboardTooltipShown = true;
|
|
171
183
|
}
|
|
172
184
|
|
|
173
185
|
_handleKeyboardTooltipShow() {
|
|
174
|
-
this._keyboardTooltipShown = true;
|
|
175
186
|
/** @ignore */
|
|
176
187
|
this.dispatchEvent(new CustomEvent(
|
|
177
188
|
'd2l-tag-list-item-tooltip-show',
|
|
@@ -181,7 +192,7 @@ export const TagListItemMixin = superclass => class extends LocalizeCoreElement(
|
|
|
181
192
|
|
|
182
193
|
_handleKeydown(e) {
|
|
183
194
|
const openKeys = e.keyCode === keyCodes.SPACE || e.keyCode === keyCodes.ENTER;
|
|
184
|
-
if (this.
|
|
195
|
+
if (this.keyboardTooltipItem && !this.keyboardTooltipShown && openKeys) this.keyboardTooltipShown = true;
|
|
185
196
|
|
|
186
197
|
const clearKeys = e.keyCode === keyCodes.BACKSPACE || e.keyCode === keyCodes.DELETE;
|
|
187
198
|
if (!this.clearable || !clearKeys) return;
|
|
@@ -194,7 +205,9 @@ export const TagListItemMixin = superclass => class extends LocalizeCoreElement(
|
|
|
194
205
|
<div class="d2l-tag-list-item-tooltip-title-key">${this.localize('components.tag-list-item.tooltip-title')}</div>
|
|
195
206
|
<ul>
|
|
196
207
|
<li><span class="d2l-tag-list-item-tooltip-title-key">${this.localize('components.tag-list-item.tooltip-arrow-keys')}</span> - ${this.localize('components.tag-list-item.tooltip-arrow-keys-desc')}</li>
|
|
197
|
-
|
|
208
|
+
${this.clearable ? html`
|
|
209
|
+
<li><span class="d2l-tag-list-item-tooltip-title-key">${this.localize('components.tag-list-item.tooltip-delete-key')}</span> - ${this.localize('components.tag-list-item.tooltip-delete-key-desc')}</li>
|
|
210
|
+
` : nothing}
|
|
198
211
|
</ul>
|
|
199
212
|
`;
|
|
200
213
|
}
|
|
@@ -209,7 +222,7 @@ export const TagListItemMixin = superclass => class extends LocalizeCoreElement(
|
|
|
209
222
|
const hasDescription = !!options.description;
|
|
210
223
|
|
|
211
224
|
let tooltip = nothing;
|
|
212
|
-
if (this.
|
|
225
|
+
if (this.keyboardTooltipItem && !this.keyboardTooltipShown) {
|
|
213
226
|
tooltip = html`
|
|
214
227
|
<d2l-tooltip
|
|
215
228
|
align="start"
|
|
@@ -355,7 +355,7 @@ class TagList extends LocalizeCoreElement(InteractiveMixin(ArrowKeysMixin(LitEle
|
|
|
355
355
|
}
|
|
356
356
|
|
|
357
357
|
_handleKeyboardTooltipShown() {
|
|
358
|
-
this._hasShownKeyboardTooltip = true;
|
|
358
|
+
if (!this._hasShownKeyboardTooltip) this._hasShownKeyboardTooltip = true;
|
|
359
359
|
}
|
|
360
360
|
|
|
361
361
|
async _handleResize() {
|
|
@@ -398,7 +398,8 @@ class TagList extends LocalizeCoreElement(InteractiveMixin(ArrowKeysMixin(LitEle
|
|
|
398
398
|
this._chomp();
|
|
399
399
|
|
|
400
400
|
this._contentReady = true;
|
|
401
|
-
|
|
401
|
+
this._items[0].setAttribute('keyboard-tooltip-item', true);
|
|
402
|
+
if (this._hasShownKeyboardTooltip) this._items[0].setAttribute('keyboard-tooltip-shown', true);
|
|
402
403
|
}
|
|
403
404
|
|
|
404
405
|
async _toggleHiddenTagVisibility(e) {
|
package/custom-elements.json
CHANGED
|
@@ -9497,7 +9497,7 @@
|
|
|
9497
9497
|
"attributes": [
|
|
9498
9498
|
{
|
|
9499
9499
|
"name": "text",
|
|
9500
|
-
"description": "Context information for the meter",
|
|
9500
|
+
"description": "Context information for the meter. If the text contains {%} or {x/y}, they will be replaced with a percentage or fraction respectively.",
|
|
9501
9501
|
"type": "string"
|
|
9502
9502
|
},
|
|
9503
9503
|
{
|
|
@@ -9523,7 +9523,7 @@
|
|
|
9523
9523
|
{
|
|
9524
9524
|
"name": "text",
|
|
9525
9525
|
"attribute": "text",
|
|
9526
|
-
"description": "Context information for the meter",
|
|
9526
|
+
"description": "Context information for the meter. If the text contains {%} or {x/y}, they will be replaced with a percentage or fraction respectively.",
|
|
9527
9527
|
"type": "string"
|
|
9528
9528
|
},
|
|
9529
9529
|
{
|
|
@@ -9566,7 +9566,7 @@
|
|
|
9566
9566
|
},
|
|
9567
9567
|
{
|
|
9568
9568
|
"name": "text",
|
|
9569
|
-
"description": "Context information for the meter",
|
|
9569
|
+
"description": "Context information for the meter. If the text contains {%} or {x/y}, they will be replaced with a percentage or fraction respectively.",
|
|
9570
9570
|
"type": "string"
|
|
9571
9571
|
},
|
|
9572
9572
|
{
|
|
@@ -9599,7 +9599,7 @@
|
|
|
9599
9599
|
{
|
|
9600
9600
|
"name": "text",
|
|
9601
9601
|
"attribute": "text",
|
|
9602
|
-
"description": "Context information for the meter",
|
|
9602
|
+
"description": "Context information for the meter. If the text contains {%} or {x/y}, they will be replaced with a percentage or fraction respectively.",
|
|
9603
9603
|
"type": "string"
|
|
9604
9604
|
},
|
|
9605
9605
|
{
|
|
@@ -9636,7 +9636,7 @@
|
|
|
9636
9636
|
"attributes": [
|
|
9637
9637
|
{
|
|
9638
9638
|
"name": "text",
|
|
9639
|
-
"description": "Context information for the meter",
|
|
9639
|
+
"description": "Context information for the meter. If the text contains {%} or {x/y}, they will be replaced with a percentage or fraction respectively.",
|
|
9640
9640
|
"type": "string"
|
|
9641
9641
|
},
|
|
9642
9642
|
{
|
|
@@ -9662,7 +9662,7 @@
|
|
|
9662
9662
|
{
|
|
9663
9663
|
"name": "text",
|
|
9664
9664
|
"attribute": "text",
|
|
9665
|
-
"description": "Context information for the meter",
|
|
9665
|
+
"description": "Context information for the meter. If the text contains {%} or {x/y}, they will be replaced with a percentage or fraction respectively.",
|
|
9666
9666
|
"type": "string"
|
|
9667
9667
|
},
|
|
9668
9668
|
{
|
|
@@ -10168,6 +10168,11 @@
|
|
|
10168
10168
|
"type": "number",
|
|
10169
10169
|
"default": "0"
|
|
10170
10170
|
},
|
|
10171
|
+
{
|
|
10172
|
+
"name": "split-scrollers",
|
|
10173
|
+
"type": "boolean",
|
|
10174
|
+
"default": "false"
|
|
10175
|
+
},
|
|
10171
10176
|
{
|
|
10172
10177
|
"name": "width",
|
|
10173
10178
|
"type": "number",
|
|
@@ -10187,6 +10192,12 @@
|
|
|
10187
10192
|
"type": "number",
|
|
10188
10193
|
"default": "0"
|
|
10189
10194
|
},
|
|
10195
|
+
{
|
|
10196
|
+
"name": "splitScrollers",
|
|
10197
|
+
"attribute": "split-scrollers",
|
|
10198
|
+
"type": "boolean",
|
|
10199
|
+
"default": "false"
|
|
10200
|
+
},
|
|
10190
10201
|
{
|
|
10191
10202
|
"name": "width",
|
|
10192
10203
|
"attribute": "width",
|
|
@@ -10208,6 +10219,12 @@
|
|
|
10208
10219
|
}
|
|
10209
10220
|
],
|
|
10210
10221
|
"properties": [
|
|
10222
|
+
{
|
|
10223
|
+
"name": "customScrollers",
|
|
10224
|
+
"description": "An object containing custom primary/secondary scroll containers",
|
|
10225
|
+
"type": "Object",
|
|
10226
|
+
"default": "{}"
|
|
10227
|
+
},
|
|
10211
10228
|
{
|
|
10212
10229
|
"name": "hideActions",
|
|
10213
10230
|
"attribute": "hide-actions",
|
|
@@ -11525,6 +11542,12 @@
|
|
|
11525
11542
|
"type": "boolean",
|
|
11526
11543
|
"default": "false"
|
|
11527
11544
|
},
|
|
11545
|
+
{
|
|
11546
|
+
"name": "sticky-headers-scroll-wrapper",
|
|
11547
|
+
"description": "When used in combo with `sticky-headers`, whether to additionally wrap the table in a scroll-wrapper. Requires sticky headers to be in a separate thead.",
|
|
11548
|
+
"type": "boolean",
|
|
11549
|
+
"default": "false"
|
|
11550
|
+
},
|
|
11528
11551
|
{
|
|
11529
11552
|
"name": "type",
|
|
11530
11553
|
"description": "Type of table style to apply. The \"light\" style has fewer borders and tighter padding.",
|
|
@@ -11581,6 +11604,13 @@
|
|
|
11581
11604
|
"type": "boolean",
|
|
11582
11605
|
"default": "false"
|
|
11583
11606
|
},
|
|
11607
|
+
{
|
|
11608
|
+
"name": "stickyHeadersScrollWrapper",
|
|
11609
|
+
"attribute": "sticky-headers-scroll-wrapper",
|
|
11610
|
+
"description": "When used in combo with `sticky-headers`, whether to additionally wrap the table in a scroll-wrapper. Requires sticky headers to be in a separate thead.",
|
|
11611
|
+
"type": "boolean",
|
|
11612
|
+
"default": "false"
|
|
11613
|
+
},
|
|
11584
11614
|
{
|
|
11585
11615
|
"name": "type",
|
|
11586
11616
|
"attribute": "type",
|
|
@@ -11780,6 +11810,12 @@
|
|
|
11780
11810
|
"type": "boolean",
|
|
11781
11811
|
"default": "false"
|
|
11782
11812
|
},
|
|
11813
|
+
{
|
|
11814
|
+
"name": "sticky-headers-scroll-wrapper",
|
|
11815
|
+
"description": "When used in combo with `sticky-headers`, whether to additionally wrap the table in a scroll-wrapper. Requires sticky headers to be in a separate thead.",
|
|
11816
|
+
"type": "boolean",
|
|
11817
|
+
"default": "false"
|
|
11818
|
+
},
|
|
11783
11819
|
{
|
|
11784
11820
|
"name": "type",
|
|
11785
11821
|
"description": "Type of table style to apply. The \"light\" style has fewer borders and tighter padding.",
|
|
@@ -11818,6 +11854,13 @@
|
|
|
11818
11854
|
"type": "boolean",
|
|
11819
11855
|
"default": "false"
|
|
11820
11856
|
},
|
|
11857
|
+
{
|
|
11858
|
+
"name": "stickyHeadersScrollWrapper",
|
|
11859
|
+
"attribute": "sticky-headers-scroll-wrapper",
|
|
11860
|
+
"description": "When used in combo with `sticky-headers`, whether to additionally wrap the table in a scroll-wrapper. Requires sticky headers to be in a separate thead.",
|
|
11861
|
+
"type": "boolean",
|
|
11862
|
+
"default": "false"
|
|
11863
|
+
},
|
|
11821
11864
|
{
|
|
11822
11865
|
"name": "type",
|
|
11823
11866
|
"attribute": "type",
|
|
@@ -12089,6 +12132,11 @@
|
|
|
12089
12132
|
"type": "boolean",
|
|
12090
12133
|
"default": "false"
|
|
12091
12134
|
},
|
|
12135
|
+
{
|
|
12136
|
+
"name": "keyboardTooltipShown",
|
|
12137
|
+
"type": "boolean",
|
|
12138
|
+
"default": "false"
|
|
12139
|
+
},
|
|
12092
12140
|
{
|
|
12093
12141
|
"name": "documentLocaleSettings",
|
|
12094
12142
|
"default": "\"getDocumentLocaleSettings()\""
|
|
@@ -12194,6 +12242,11 @@
|
|
|
12194
12242
|
"type": "boolean",
|
|
12195
12243
|
"default": "false"
|
|
12196
12244
|
},
|
|
12245
|
+
{
|
|
12246
|
+
"name": "keyboardTooltipShown",
|
|
12247
|
+
"type": "boolean",
|
|
12248
|
+
"default": "false"
|
|
12249
|
+
},
|
|
12197
12250
|
{
|
|
12198
12251
|
"name": "documentLocaleSettings",
|
|
12199
12252
|
"default": "\"getDocumentLocaleSettings()\""
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brightspace-ui/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.114.1",
|
|
4
4
|
"description": "A collection of accessible, free, open-source web components for building Brightspace applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": "https://github.com/BrightspaceUI/core.git",
|