@brightspace-ui/core 3.139.0 → 3.140.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/button/button-icon.js +3 -3
- package/components/button/button-move.js +1 -1
- package/components/button/button-styles.js +3 -6
- package/components/button/floating-buttons.js +36 -48
- package/components/dialog/dialog-styles.js +2 -7
- package/components/empty-state/empty-state-styles.js +5 -7
- package/components/html-block/html-block.js +6 -7
- package/components/inputs/input-color.js +3 -10
- package/components/inputs/input-search.js +1 -1
- package/components/link/link.js +4 -8
- package/components/switch/switch-mixin.js +4 -5
- package/components/tabs/demo/tab-custom.js +7 -7
- package/components/tabs/tab.js +8 -6
- package/components/tooltip/tooltip-help.js +4 -11
- package/custom-elements.json +8 -0
- package/helpers/focus.js +15 -0
- package/mixins/interactive/interactive-mixin.js +5 -8
- package/package.json +1 -1
@@ -64,17 +64,17 @@ class ButtonIcon extends SlottedIconMixin(PropertyRequiredMixin(ThemeMixin(Butto
|
|
64
64
|
:host([translucent]) {
|
65
65
|
--d2l-button-icon-background-color: rgba(0, 0, 0, 0.5);
|
66
66
|
--d2l-button-icon-background-color-hover: var(--d2l-color-celestine);
|
67
|
-
--d2l-
|
68
|
-
--d2l-
|
67
|
+
--d2l-focus-ring-color: white;
|
68
|
+
--d2l-focus-ring-offset: -4px;
|
69
69
|
--d2l-button-icon-fill-color: white;
|
70
70
|
--d2l-button-icon-fill-color-hover: white;
|
71
71
|
}
|
72
72
|
:host([theme="dark"]) {
|
73
73
|
--d2l-button-icon-background-color: transparent;
|
74
74
|
--d2l-button-icon-background-color-hover: rgba(51, 53, 54, 0.9); /* tungsten @70% @90% */
|
75
|
-
--d2l-button-focus-color: var(--d2l-color-celestine-plus-1);
|
76
75
|
--d2l-button-icon-fill-color: var(--d2l-color-sylvite);
|
77
76
|
--d2l-button-icon-fill-color-hover: var(--d2l-color-sylvite);
|
77
|
+
--d2l-focus-ring-color: var(--d2l-color-celestine-plus-1);
|
78
78
|
}
|
79
79
|
|
80
80
|
button {
|
@@ -102,8 +102,8 @@ class ButtonMove extends ThemeMixin(FocusMixin(RtlMixin(LitElement))) {
|
|
102
102
|
:host([theme="dark"]) {
|
103
103
|
--d2l-button-move-background-color-focus: #000000;
|
104
104
|
--d2l-button-move-icon-background-color-hover: rgba(51, 53, 54, 0.9); /* tungsten @70% @90% */
|
105
|
-
--d2l-button-focus-color: var(--d2l-color-celestine-plus-1);
|
106
105
|
--d2l-icon-fill-color: var(--d2l-color-sylvite);
|
106
|
+
--d2l-focus-ring-color: var(--d2l-color-celestine-plus-1);
|
107
107
|
}
|
108
108
|
button {
|
109
109
|
background-color: transparent;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import '../colors/colors.js';
|
2
|
-
import { css
|
3
|
-
import {
|
2
|
+
import { css } from 'lit';
|
3
|
+
import { getFocusRingStyles } from '../../helpers/focus.js';
|
4
4
|
|
5
5
|
export const buttonStyles = css`
|
6
6
|
button {
|
@@ -24,10 +24,7 @@ export const buttonStyles = css`
|
|
24
24
|
white-space: nowrap;
|
25
25
|
width: auto;
|
26
26
|
}
|
27
|
-
|
28
|
-
outline: 2px solid var(--d2l-button-focus-color, var(--d2l-color-celestine));
|
29
|
-
outline-offset: var(--d2l-button-focus-offset, 2px);
|
30
|
-
}
|
27
|
+
${getFocusRingStyles('button')}
|
31
28
|
@media (prefers-contrast: more) {
|
32
29
|
button {
|
33
30
|
border: 2px solid transparent;
|
@@ -4,7 +4,7 @@ import { css, html, LitElement } from 'lit';
|
|
4
4
|
import { getBoundingAncestor, getComposedParent, isComposedAncestor } from '../../helpers/dom.js';
|
5
5
|
import { getComposedActiveElement } from '../../helpers/focus.js';
|
6
6
|
import { getLegacyOffsetParent } from '../../helpers/offsetParent-legacy.js';
|
7
|
-
import {
|
7
|
+
import { LoadingCompleteMixin } from '../../mixins/loading-complete/loading-complete-mixin.js';
|
8
8
|
import { styleMap } from 'lit/directives/style-map.js';
|
9
9
|
|
10
10
|
const mediaQueryList = window.matchMedia('(max-height: 500px)');
|
@@ -14,7 +14,7 @@ const MINIMUM_TARGET_SIZE = 24;
|
|
14
14
|
* A wrapper component to display floating workflow buttons. When the normal position of the workflow buttons is below the bottom edge of the viewport, they will dock at the bottom edge. When the normal position becomes visible, they will undock.
|
15
15
|
* @slot - Content to be displayed in the floating container
|
16
16
|
*/
|
17
|
-
class FloatingButtons extends
|
17
|
+
class FloatingButtons extends LoadingCompleteMixin(LitElement) {
|
18
18
|
|
19
19
|
static get properties() {
|
20
20
|
return {
|
@@ -26,8 +26,7 @@ class FloatingButtons extends RtlMixin(LitElement) {
|
|
26
26
|
_containerMarginLeft: { attribute: false, type: String },
|
27
27
|
_containerMarginRight: { attribute: false, type: String },
|
28
28
|
_floating: { type: Boolean, reflect: true },
|
29
|
-
_innerContainerLeft: { attribute: false, type: String }
|
30
|
-
_innerContainerRight: { attribute: false, type: String }
|
29
|
+
_innerContainerLeft: { attribute: false, type: String }
|
31
30
|
};
|
32
31
|
}
|
33
32
|
|
@@ -80,21 +79,14 @@ class FloatingButtons extends RtlMixin(LitElement) {
|
|
80
79
|
.d2l-floating-buttons-inner-container ::slotted(d2l-button),
|
81
80
|
.d2l-floating-buttons-inner-container ::slotted(button),
|
82
81
|
.d2l-floating-buttons-inner-container ::slotted(.d2l-button) {
|
82
|
+
margin-inline-end: 0.75rem !important;
|
83
83
|
margin-bottom: 0.75rem !important;
|
84
|
-
margin-right: 0.75rem !important;
|
85
84
|
}
|
86
85
|
|
87
86
|
.d2l-floating-buttons-inner-container ::slotted(d2l-overflow-group) {
|
88
87
|
padding-bottom: 0.75rem !important;
|
89
88
|
}
|
90
89
|
|
91
|
-
:host([dir="rtl"]) .d2l-floating-buttons-inner-container ::slotted(d2l-button),
|
92
|
-
:host([dir="rtl"]) .d2l-floating-buttons-inner-container ::slotted(button),
|
93
|
-
:host([dir="rtl"]) .d2l-floating-buttons-inner-container ::slotted(.d2l-button) {
|
94
|
-
margin-left: 0.75rem !important;
|
95
|
-
margin-right: 0 !important;
|
96
|
-
}
|
97
|
-
|
98
90
|
@media (prefers-reduced-motion: reduce) {
|
99
91
|
:host([_floating]:not([always-float])) .d2l-floating-buttons-container {
|
100
92
|
transition: none;
|
@@ -110,7 +102,6 @@ class FloatingButtons extends RtlMixin(LitElement) {
|
|
110
102
|
this._containerMarginRight = '';
|
111
103
|
this._floating = false;
|
112
104
|
this._innerContainerLeft = '';
|
113
|
-
this._innerContainerRight = '';
|
114
105
|
this._intersectionObserver = null;
|
115
106
|
this._isIntersecting = false;
|
116
107
|
this._recalculateFloating = this._recalculateFloating.bind(this);
|
@@ -125,13 +116,15 @@ class FloatingButtons extends RtlMixin(LitElement) {
|
|
125
116
|
// if browser doesn't support IntersectionObserver, we don't float
|
126
117
|
if (typeof(IntersectionObserver) !== 'function') {
|
127
118
|
this._isIntersecting = true;
|
119
|
+
this.resolveLoadingComplete();
|
128
120
|
return;
|
129
121
|
}
|
130
|
-
this._intersectionObserver = this._intersectionObserver || new IntersectionObserver((entries) => {
|
131
|
-
|
122
|
+
this._intersectionObserver = this._intersectionObserver || new IntersectionObserver(async(entries) => {
|
123
|
+
for (const entry of entries) {
|
132
124
|
this._isIntersecting = entry.isIntersecting;
|
133
|
-
this._recalculateFloating();
|
134
|
-
}
|
125
|
+
await this._recalculateFloating();
|
126
|
+
}
|
127
|
+
this.resolveLoadingComplete();
|
135
128
|
});
|
136
129
|
|
137
130
|
// observe intersection of a fake sibling element since host is sticky
|
@@ -164,13 +157,12 @@ class FloatingButtons extends RtlMixin(LitElement) {
|
|
164
157
|
|
165
158
|
render() {
|
166
159
|
const containerStyle = {
|
167
|
-
|
168
|
-
|
160
|
+
marginInlineStart: this._containerMarginLeft,
|
161
|
+
marginInlineEnd: this._containerMarginRight
|
169
162
|
};
|
170
163
|
|
171
164
|
const innerContainerStyle = {
|
172
|
-
|
173
|
-
marginRight: this._innerContainerRight
|
165
|
+
marginInlineStart: this._innerContainerLeft
|
174
166
|
};
|
175
167
|
|
176
168
|
return html`
|
@@ -193,7 +185,6 @@ class FloatingButtons extends RtlMixin(LitElement) {
|
|
193
185
|
this._containerMarginLeft = '';
|
194
186
|
this._containerMarginRight = '';
|
195
187
|
this._innerContainerLeft = '';
|
196
|
-
this._innerContainerRight = '';
|
197
188
|
|
198
189
|
if (!this._floating) return;
|
199
190
|
|
@@ -218,12 +209,8 @@ class FloatingButtons extends RtlMixin(LitElement) {
|
|
218
209
|
this._containerMarginRight = `-${containerRight}px`;
|
219
210
|
}
|
220
211
|
|
221
|
-
if (
|
222
|
-
|
223
|
-
this._innerContainerLeft = `${containerLeft}px`;
|
224
|
-
}
|
225
|
-
} else {
|
226
|
-
this._innerContainerRight = `${containerRight}px`;
|
212
|
+
if (containerLeft !== 0) {
|
213
|
+
this._innerContainerLeft = `${containerLeft}px`;
|
227
214
|
}
|
228
215
|
|
229
216
|
}
|
@@ -251,29 +238,30 @@ class FloatingButtons extends RtlMixin(LitElement) {
|
|
251
238
|
|
252
239
|
}
|
253
240
|
|
254
|
-
_recalculateFloating() {
|
255
|
-
|
256
|
-
|
257
|
-
if (this.alwaysFloat) {
|
258
|
-
this._floating = true;
|
259
|
-
this._calcContainerPosition();
|
260
|
-
return;
|
261
|
-
}
|
241
|
+
async _recalculateFloating() {
|
242
|
+
await new Promise(resolve => requestAnimationFrame(resolve));
|
262
243
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
244
|
+
if (this.alwaysFloat) {
|
245
|
+
this._floating = true;
|
246
|
+
this._calcContainerPosition();
|
247
|
+
await this.updateComplete;
|
248
|
+
return;
|
249
|
+
}
|
269
250
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
251
|
+
const viewportIsLessThanMinHeight = mediaQueryList.matches;
|
252
|
+
if (viewportIsLessThanMinHeight) {
|
253
|
+
this._floating = false;
|
254
|
+
this._calcContainerPosition();
|
255
|
+
await this.updateComplete;
|
256
|
+
return;
|
257
|
+
}
|
275
258
|
|
276
|
-
|
259
|
+
const shouldFloat = !this._isIntersecting;
|
260
|
+
if (shouldFloat !== this._floating) {
|
261
|
+
this._floating = shouldFloat;
|
262
|
+
this._calcContainerPosition();
|
263
|
+
await this.updateComplete;
|
264
|
+
}
|
277
265
|
}
|
278
266
|
|
279
267
|
_scrollIfFloatObsuringFocus() {
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import '../colors/colors.js';
|
2
2
|
import { css } from 'lit';
|
3
|
+
import { getFocusRingStyles } from '../../helpers/focus.js';
|
3
4
|
|
4
5
|
export const dialogStyles = css`
|
5
6
|
|
@@ -131,13 +132,7 @@ export const dialogStyles = css`
|
|
131
132
|
overflow: hidden; /* scrollbar is kept hidden while we update the scroll position to avoid scrollbar flash */
|
132
133
|
padding: 0 30px;
|
133
134
|
}
|
134
|
-
|
135
|
-
.d2l-dialog-content:focus-visible {
|
136
|
-
border-radius: 6px;
|
137
|
-
outline: 2px solid var(--d2l-color-celestine);
|
138
|
-
outline-offset: -2px;
|
139
|
-
}
|
140
|
-
|
135
|
+
${getFocusRingStyles('.d2l-dialog-content', { extraStyles: css`--d2l-focus-ring-offset: -2px; border-radius: 6px;` })}
|
141
136
|
.d2l-dialog-content > div {
|
142
137
|
position: relative; /* make this the positioned parent for absolute positioned elements like d2l-template-primary-secondary */
|
143
138
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import '../colors/colors.js';
|
2
|
-
import { css
|
3
|
-
import {
|
2
|
+
import { css } from 'lit';
|
3
|
+
import { getFocusRingStyles } from '../../helpers/focus.js';
|
4
4
|
|
5
5
|
export const emptyStateStyles = css`
|
6
6
|
|
@@ -20,13 +20,11 @@ export const emptyStateStyles = css`
|
|
20
20
|
.action-slot::slotted(d2l-empty-state-action-link:first-of-type) {
|
21
21
|
display: inline;
|
22
22
|
}
|
23
|
-
|
24
|
-
|
23
|
+
.d2l-empty-state-description {
|
24
|
+
--d2l-focus-ring-offset: 3px;
|
25
25
|
border-radius: 0.3rem;
|
26
|
-
outline: 2px solid var(--d2l-color-celestine);
|
27
|
-
outline-offset: 3px;
|
28
26
|
}
|
29
|
-
|
27
|
+
${getFocusRingStyles('.d2l-empty-state-description')}
|
30
28
|
`;
|
31
29
|
|
32
30
|
export const emptyStateSimpleStyles = css`
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import '../colors/colors.js';
|
2
2
|
import { codeStyles, createHtmlBlockRenderer as createCodeRenderer } from '../../helpers/prism.js';
|
3
|
-
import { css, html, LitElement
|
3
|
+
import { css, html, LitElement } from 'lit';
|
4
4
|
import { classMap } from 'lit/directives/class-map.js';
|
5
5
|
import { createHtmlBlockRenderer as createMathRenderer } from '../../helpers/mathjax.js';
|
6
|
-
import {
|
6
|
+
import { getFocusRingStyles } from '../../helpers/focus.js';
|
7
7
|
import { LoadingCompleteMixin } from '../../mixins/loading-complete/loading-complete-mixin.js';
|
8
8
|
import { renderEmbeds } from '../../helpers/embeds.js';
|
9
9
|
import { requestInstance } from '../../mixins/provider/provider-mixin.js';
|
@@ -108,12 +108,11 @@ export const htmlBlockContentStyles = css`
|
|
108
108
|
color: var(--d2l-color-celestine-minus-1, #004489);
|
109
109
|
text-decoration: underline;
|
110
110
|
}
|
111
|
-
a
|
112
|
-
|
113
|
-
|
114
|
-
outline-offset: 1px;
|
115
|
-
text-decoration: underline;
|
111
|
+
a {
|
112
|
+
--d2l-focus-ring-offset: 1px;
|
113
|
+
--d2l-focus-ring-color: var(--d2l-color-celestine, #006fbf);
|
116
114
|
}
|
115
|
+
${getFocusRingStyles('a', { extraStyles: css`border-radius: 2px; text-decoration: underline;` })}
|
117
116
|
@media print {
|
118
117
|
a,
|
119
118
|
a:visited,
|
@@ -1,12 +1,12 @@
|
|
1
1
|
import '../dropdown/dropdown.js';
|
2
2
|
import '../dropdown/dropdown-content.js';
|
3
3
|
import '../tooltip/tooltip.js';
|
4
|
-
import { css, html, LitElement, nothing
|
4
|
+
import { css, html, LitElement, nothing } from 'lit';
|
5
5
|
import { buttonStyles } from '../button/button-styles.js';
|
6
6
|
import { classMap } from 'lit/directives/class-map.js';
|
7
7
|
import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
|
8
8
|
import { FormElementMixin } from '../form/form-element-mixin.js';
|
9
|
-
import {
|
9
|
+
import { getFocusRingStyles } from '../../helpers/focus.js';
|
10
10
|
import { getUniqueId } from '../../helpers/uniqueId.js';
|
11
11
|
import { getValidHexColor } from '../../helpers/color.js';
|
12
12
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
@@ -226,14 +226,7 @@ class InputColor extends InputInlineHelpMixin(PropertyRequiredMixin(FocusMixin(F
|
|
226
226
|
outline: none;
|
227
227
|
width: 1.2rem;
|
228
228
|
}
|
229
|
-
.readonly-wrapper
|
230
|
-
outline: none;
|
231
|
-
}
|
232
|
-
.readonly-wrapper:${unsafeCSS(getFocusPseudoClass())} {
|
233
|
-
outline: 2px solid var(--d2l-color-celestine);
|
234
|
-
outline-offset: 2px;
|
235
|
-
}
|
236
|
-
|
229
|
+
${getFocusRingStyles('.readonly-wrapper')}
|
237
230
|
@media (prefers-contrast: more) {
|
238
231
|
.swatch {
|
239
232
|
border: 1px solid FieldText;
|
@@ -80,7 +80,7 @@ class InputSearch extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement)))
|
|
80
80
|
--d2l-button-icon-min-height: 1.5rem;
|
81
81
|
--d2l-button-icon-min-width: 1.5rem;
|
82
82
|
--d2l-button-icon-border-radius: 4px;
|
83
|
-
--d2l-
|
83
|
+
--d2l-focus-ring-offset: 1px;
|
84
84
|
margin-left: 0.3rem;
|
85
85
|
margin-right: 0.3rem;
|
86
86
|
}
|
package/components/link/link.js
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
import '../colors/colors.js';
|
2
2
|
import '../icons/icon.js';
|
3
|
-
import { css, html, LitElement, nothing
|
3
|
+
import { css, html, LitElement, nothing } from 'lit';
|
4
4
|
import { classMap } from 'lit/directives/class-map.js';
|
5
5
|
import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
|
6
|
-
import {
|
6
|
+
import { getFocusRingStyles } from '../../helpers/focus.js';
|
7
7
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
8
8
|
import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
|
9
9
|
import { offscreenStyles } from '../offscreen/offscreen.js';
|
@@ -11,6 +11,7 @@ import { styleMap } from 'lit/directives/style-map.js';
|
|
11
11
|
|
12
12
|
export const linkStyles = css`
|
13
13
|
.d2l-link, .d2l-link:visited, .d2l-link:active, .d2l-link:link {
|
14
|
+
--d2l-focus-ring-offset: 1px;
|
14
15
|
color: var(--d2l-color-celestine);
|
15
16
|
cursor: pointer;
|
16
17
|
outline-style: none;
|
@@ -24,12 +25,7 @@ export const linkStyles = css`
|
|
24
25
|
color: var(--d2l-color-celestine-minus-1);
|
25
26
|
text-decoration: underline;
|
26
27
|
}
|
27
|
-
.d2l-link
|
28
|
-
border-radius: 2px;
|
29
|
-
outline: 2px solid var(--d2l-color-celestine);
|
30
|
-
outline-offset: 1px;
|
31
|
-
text-decoration: underline;
|
32
|
-
}
|
28
|
+
${getFocusRingStyles('.d2l-link', { extraStyles: css`border-radius: 2px; text-decoration: underline;` })}
|
33
29
|
.d2l-link.d2l-link-main {
|
34
30
|
font-weight: 700;
|
35
31
|
}
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import '../colors/colors.js';
|
2
|
-
import { css, html
|
2
|
+
import { css, html } from 'lit';
|
3
3
|
import { classMap } from 'lit/directives/class-map.js';
|
4
4
|
import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
|
5
|
-
import {
|
5
|
+
import { getFocusRingStyles } from '../../helpers/focus.js';
|
6
6
|
import { getUniqueId } from '../../helpers/uniqueId.js';
|
7
7
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
8
8
|
import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
|
@@ -47,6 +47,7 @@ export const SwitchMixin = superclass => class extends FocusMixin(RtlMixin(super
|
|
47
47
|
}
|
48
48
|
|
49
49
|
.d2l-switch-container {
|
50
|
+
--d2l-focus-ring-offset: 0;
|
50
51
|
background-color: var(--d2l-switch-container-background-color, #ffffff);
|
51
52
|
border-radius: 1rem;
|
52
53
|
box-sizing: border-box;
|
@@ -58,9 +59,7 @@ export const SwitchMixin = superclass => class extends FocusMixin(RtlMixin(super
|
|
58
59
|
padding: 0.1rem;
|
59
60
|
vertical-align: middle;
|
60
61
|
}
|
61
|
-
.d2l-switch-container
|
62
|
-
outline: 2px solid var(--d2l-color-celestine);
|
63
|
-
}
|
62
|
+
${getFocusRingStyles('.d2l-switch-container')}
|
64
63
|
:host([disabled]) .d2l-switch-container {
|
65
64
|
cursor: default;
|
66
65
|
opacity: 0.5;
|
@@ -1,5 +1,5 @@
|
|
1
|
-
import { css, html, LitElement
|
2
|
-
import {
|
1
|
+
import { css, html, LitElement } from 'lit';
|
2
|
+
import { getFocusRingStyles } from '../../../helpers/focus.js';
|
3
3
|
import { TabMixin } from '../tab-mixin.js';
|
4
4
|
|
5
5
|
class TabCustom extends TabMixin(LitElement) {
|
@@ -7,6 +7,7 @@ class TabCustom extends TabMixin(LitElement) {
|
|
7
7
|
static get styles() {
|
8
8
|
const styles = [ css`
|
9
9
|
.d2l-tab-custom-content {
|
10
|
+
--d2l-focus-ring-offset: 0;
|
10
11
|
margin: 0.5rem;
|
11
12
|
overflow: hidden;
|
12
13
|
padding: 0.1rem;
|
@@ -15,11 +16,10 @@ class TabCustom extends TabMixin(LitElement) {
|
|
15
16
|
:host(:first-child) .d2l-tab-custom-content {
|
16
17
|
margin-inline-start: 0;
|
17
18
|
}
|
18
|
-
|
19
|
-
|
20
|
-
color: var(--d2l-color-celestine);
|
21
|
-
|
22
|
-
}
|
19
|
+
${getFocusRingStyles(
|
20
|
+
pseudoClass => `:host(:${pseudoClass}) .d2l-tab-custom-content`,
|
21
|
+
{ extraStyles: 'border-radius: 0.3rem; color: var(--d2l-color-celestine);' }
|
22
|
+
)}
|
23
23
|
`];
|
24
24
|
|
25
25
|
super.styles && styles.unshift(super.styles);
|
package/components/tabs/tab.js
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
import { css, html, LitElement, unsafeCSS } from 'lit';
|
2
|
+
import { getFocusPseudoClass, getFocusRingStyles } from '../../helpers/focus.js';
|
2
3
|
import { classMap } from 'lit/directives/class-map.js';
|
3
|
-
import { getFocusPseudoClass } from '../../helpers/focus.js';
|
4
4
|
import { TabMixin } from './tab-mixin.js';
|
5
5
|
|
6
|
+
const focusRingStyles = getFocusRingStyles(
|
7
|
+
pseudoClass => `:host(:${pseudoClass}) .d2l-tab-text-inner-content`,
|
8
|
+
{ extraStyles: css`border-radius: 0.3rem; color: var(--d2l-color-celestine);` }
|
9
|
+
);
|
10
|
+
|
6
11
|
/**
|
7
12
|
* @attr {string} id - REQUIRED: Unique identifier for the tab
|
8
13
|
* @fires d2l-tab-content-change - Dispatched when the text attribute is changed. Triggers virtual scrolling calculations in parent d2l-tabs.
|
@@ -24,14 +29,11 @@ class Tab extends TabMixin(LitElement) {
|
|
24
29
|
static get styles() {
|
25
30
|
const styles = [ css`
|
26
31
|
.d2l-tab-text-inner-content {
|
32
|
+
--d2l-focus-ring-offset: 0;
|
27
33
|
display: flex;
|
28
34
|
padding: 0.1rem;
|
29
35
|
}
|
30
|
-
|
31
|
-
border-radius: 0.3rem;
|
32
|
-
color: var(--d2l-color-celestine);
|
33
|
-
outline: 2px solid var(--d2l-color-celestine);
|
34
|
-
}
|
36
|
+
${focusRingStyles}
|
35
37
|
:host(:${unsafeCSS(getFocusPseudoClass())}) ::slotted(d2l-icon) {
|
36
38
|
color: var(--d2l-color-celestine);
|
37
39
|
}
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import '../colors/colors.js';
|
2
2
|
import '../tooltip/tooltip.js';
|
3
|
-
import { css, html, LitElement, nothing
|
3
|
+
import { css, html, LitElement, nothing } from 'lit';
|
4
4
|
import { bodySmallStyles } from '../typography/styles.js';
|
5
5
|
import { classMap } from 'lit/directives/class-map.js';
|
6
6
|
import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
|
7
|
-
import {
|
7
|
+
import { getFocusRingStyles } from '../../helpers/focus.js';
|
8
8
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
9
9
|
import { SkeletonMixin } from '../skeleton/skeleton-mixin.js';
|
10
10
|
import { SlottedIconMixin } from '../icons/slotted-icon-mixin.js';
|
@@ -48,6 +48,7 @@ class TooltipHelp extends SlottedIconMixin(SkeletonMixin(FocusMixin(LitElement))
|
|
48
48
|
display: none;
|
49
49
|
}
|
50
50
|
#d2l-tooltip-help-text {
|
51
|
+
--d2l-focus-ring-offset: 0.05rem;
|
51
52
|
align-items: baseline;
|
52
53
|
background: none;
|
53
54
|
border: none;
|
@@ -66,15 +67,7 @@ class TooltipHelp extends SlottedIconMixin(SkeletonMixin(FocusMixin(LitElement))
|
|
66
67
|
align-self: center;
|
67
68
|
}
|
68
69
|
|
69
|
-
#d2l-tooltip-help-text:
|
70
|
-
outline-style: none;
|
71
|
-
}
|
72
|
-
#d2l-tooltip-help-text:${unsafeCSS(getFocusPseudoClass())} {
|
73
|
-
border-radius: 0.05rem;
|
74
|
-
outline: 2px solid var(--d2l-color-celestine);
|
75
|
-
outline-offset: 0.05rem;
|
76
|
-
text-underline-offset: 0.1rem;
|
77
|
-
}
|
70
|
+
${getFocusRingStyles('#d2l-tooltip-help-text', { extraStyles: css`border-radius: 0.05rem; text-underline-offset: 0.1rem;` })}
|
78
71
|
:host([inherit-font-style]) #d2l-tooltip-help-text {
|
79
72
|
color: inherit;
|
80
73
|
font-size: inherit;
|
package/custom-elements.json
CHANGED
@@ -1039,6 +1039,14 @@
|
|
1039
1039
|
"description": "Indicates to display buttons as always floating",
|
1040
1040
|
"type": "boolean",
|
1041
1041
|
"default": "false"
|
1042
|
+
},
|
1043
|
+
{
|
1044
|
+
"name": "loadingComplete",
|
1045
|
+
"type": "Promise<any>"
|
1046
|
+
},
|
1047
|
+
{
|
1048
|
+
"name": "resolveLoadingComplete",
|
1049
|
+
"type": "() => void"
|
1042
1050
|
}
|
1043
1051
|
],
|
1044
1052
|
"slots": [
|
package/helpers/focus.js
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import { css, unsafeCSS } from 'lit';
|
1
2
|
import { getComposedChildren, getComposedParent, getNextAncestorSibling, getPreviousAncestorSibling, isVisible } from './dom.js';
|
2
3
|
|
3
4
|
const focusableElements = {
|
@@ -62,6 +63,20 @@ export function getFocusableDescendants(node, options) {
|
|
62
63
|
export function getFocusPseudoClass() {
|
63
64
|
return isFocusVisibleSupported() ? 'focus-visible' : 'focus';
|
64
65
|
}
|
66
|
+
export function getFocusRingStyles(selector, { applyOnHover = false, extraStyles = null } = {}) {
|
67
|
+
const selectorDelegate = typeof selector === 'string' ? pseudoClass => `${selector}:${pseudoClass}` : selector;
|
68
|
+
const cssSelector = unsafeCSS(`${selectorDelegate(getFocusPseudoClass())}${applyOnHover ? `, ${selectorDelegate('hover')}` : ''}`);
|
69
|
+
return css`${cssSelector} {
|
70
|
+
${extraStyles ?? css``}
|
71
|
+
outline: 2px solid var(--d2l-focus-ring-color, var(--d2l-color-celestine));
|
72
|
+
outline-offset: var(--d2l-focus-ring-offset, 2px);
|
73
|
+
}
|
74
|
+
@media (prefers-contrast: more) {
|
75
|
+
${cssSelector} {
|
76
|
+
outline-color: var(--d2l-focus-ring-color, Highlight);
|
77
|
+
}
|
78
|
+
}`;
|
79
|
+
}
|
65
80
|
|
66
81
|
export function getLastFocusableDescendant(node, includeHidden) {
|
67
82
|
const composedChildren = getComposedChildren(node);
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import { clearDismissible, setDismissible } from '../../helpers/dismissible.js';
|
2
2
|
import { css, html } from 'lit';
|
3
3
|
import { findComposedAncestor, isComposedAncestor } from '../../helpers/dom.js';
|
4
|
+
import { getFocusRingStyles, getNextFocusable } from '../../helpers/focus.js';
|
4
5
|
import { classMap } from 'lit/directives/class-map.js';
|
5
|
-
import { getNextFocusable } from '../../helpers/focus.js';
|
6
6
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
7
7
|
import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
|
8
8
|
import { offscreenStyles } from '../../components/offscreen/offscreen.js';
|
@@ -26,13 +26,10 @@ export const InteractiveMixin = superclass => class extends LocalizeCoreElement(
|
|
26
26
|
}
|
27
27
|
|
28
28
|
static get styles() {
|
29
|
-
return [offscreenStyles,
|
30
|
-
.interactive-focusing-toggle
|
31
|
-
|
32
|
-
|
33
|
-
outline-offset: 2px;
|
34
|
-
}
|
35
|
-
`];
|
29
|
+
return [offscreenStyles, getFocusRingStyles(
|
30
|
+
() => '.interactive-focusing-toggle',
|
31
|
+
{ extraStyles: css`border-radius: 6px;` }
|
32
|
+
)];
|
36
33
|
}
|
37
34
|
|
38
35
|
constructor() {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@brightspace-ui/core",
|
3
|
-
"version": "3.
|
3
|
+
"version": "3.140.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",
|