@brightspace-ui/core 3.320.1 → 3.321.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/components/icons/icon.js
CHANGED
|
@@ -3,11 +3,12 @@ import { css, html, LitElement, noChange } from 'lit';
|
|
|
3
3
|
import { fixSvg } from './fix-svg.js';
|
|
4
4
|
import { guard } from 'lit/directives/guard.js';
|
|
5
5
|
import { iconStyles } from './icon-styles.js';
|
|
6
|
+
import { LoadingCompleteMixin } from '../../mixins/loading-complete/loading-complete-mixin.js';
|
|
6
7
|
import { loadSvg } from '../../generated/icons/presetIconLoader.js';
|
|
7
8
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
8
9
|
import { until } from 'lit/directives/until.js';
|
|
9
10
|
|
|
10
|
-
class Icon extends LitElement {
|
|
11
|
+
class Icon extends LoadingCompleteMixin(LitElement) {
|
|
11
12
|
|
|
12
13
|
static properties = {
|
|
13
14
|
icon: {
|
|
@@ -58,7 +59,13 @@ class Icon extends LitElement {
|
|
|
58
59
|
icon = icon.substring(4);
|
|
59
60
|
}
|
|
60
61
|
const svg = await loadSvg(icon);
|
|
61
|
-
|
|
62
|
+
const fixedSvg = this._fixSvg(svg ? svg.val : undefined);
|
|
63
|
+
|
|
64
|
+
this.updateComplete
|
|
65
|
+
.then(() => new Promise(resolve => requestAnimationFrame(resolve)))
|
|
66
|
+
.then(this.resolveLoadingComplete);
|
|
67
|
+
|
|
68
|
+
return fixedSvg;
|
|
62
69
|
}
|
|
63
70
|
}
|
|
64
71
|
|
package/components/tabs/tabs.js
CHANGED
|
@@ -906,7 +906,9 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
|
906
906
|
scrollVisibilityPromise,
|
|
907
907
|
scrollToPromise
|
|
908
908
|
]);
|
|
909
|
-
p.then(() => {
|
|
909
|
+
p.then(async() => {
|
|
910
|
+
await new Promise(resolve => requestAnimationFrame(resolve));
|
|
911
|
+
await new Promise(resolve => requestAnimationFrame(resolve));
|
|
910
912
|
if (this.#loadingCompleteResolve) {
|
|
911
913
|
this.#loadingCompleteResolve();
|
|
912
914
|
this.#loadingCompleteResolve = undefined;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { html, LitElement } from 'lit';
|
|
2
|
+
import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
|
|
3
|
+
import { PropertyRequiredMixin } from '../../mixins/property-required/property-required-mixin.js';
|
|
4
|
+
import { SlottedIconMixin } from '../icons/slotted-icon-mixin.js';
|
|
5
|
+
import { ThemeMixin } from '../../mixins/theme/theme-mixin.js';
|
|
6
|
+
import { toolbarButtonStyles } from './toolbar-item-styles.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A toolbar button that performs an action
|
|
10
|
+
*/
|
|
11
|
+
class ToolbarButton extends SlottedIconMixin(FocusMixin(ThemeMixin(PropertyRequiredMixin(LitElement)))) {
|
|
12
|
+
|
|
13
|
+
static properties = {
|
|
14
|
+
/**
|
|
15
|
+
* Disables the toolbar button
|
|
16
|
+
* @type {boolean}
|
|
17
|
+
*/
|
|
18
|
+
disabled: { type: Boolean },
|
|
19
|
+
/**
|
|
20
|
+
* ACCESSIBILITY: REQUIRED: Accessible text for the button
|
|
21
|
+
* @type {string}
|
|
22
|
+
*/
|
|
23
|
+
text: { type: String, required: true },
|
|
24
|
+
_activeFocusable: { state: true }
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
static styles = [super.styles, toolbarButtonStyles];
|
|
28
|
+
|
|
29
|
+
constructor() {
|
|
30
|
+
super();
|
|
31
|
+
this.disabled = false;
|
|
32
|
+
this.text = '';
|
|
33
|
+
this._activeFocusable = false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static get focusElementSelector() {
|
|
37
|
+
return 'button';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
render() {
|
|
41
|
+
return html`
|
|
42
|
+
<button
|
|
43
|
+
aria-disabled="${this.disabled ? 'true' : 'false'}"
|
|
44
|
+
aria-label="${this.text}"
|
|
45
|
+
@click="${this.#handleClick}"
|
|
46
|
+
tabindex="${this._activeFocusable ? 0 : -1}"
|
|
47
|
+
title="${this.text}"
|
|
48
|
+
type="button">
|
|
49
|
+
<div class="background"></div>
|
|
50
|
+
${this._renderIcon()}
|
|
51
|
+
</button>
|
|
52
|
+
`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
#handleClick(e) {
|
|
56
|
+
if (this.disabled) e.stopPropagation();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
customElements.define('d2l-toolbar-button', ToolbarButton);
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import '../colors/colors.js';
|
|
2
|
+
import { css } from 'lit';
|
|
3
|
+
import { getFocusRingStyles } from '../../helpers/focus.js';
|
|
4
|
+
|
|
5
|
+
export const toolbarButtonStyles = css`
|
|
6
|
+
:host {
|
|
7
|
+
display: inline-block;
|
|
8
|
+
}
|
|
9
|
+
:host([hidden]) {
|
|
10
|
+
display: none;
|
|
11
|
+
}
|
|
12
|
+
button {
|
|
13
|
+
--d2l-focus-ring-offset: 0;
|
|
14
|
+
align-items: center;
|
|
15
|
+
background-color: transparent;
|
|
16
|
+
border: none;
|
|
17
|
+
border-radius: 0.2rem;
|
|
18
|
+
box-sizing: border-box;
|
|
19
|
+
color: var(--d2l-theme-text-color-static-standard);
|
|
20
|
+
cursor: pointer;
|
|
21
|
+
display: flex;
|
|
22
|
+
fill: var(--d2l-theme-icon-color-standard);
|
|
23
|
+
font-family: inherit;
|
|
24
|
+
justify-content: center;
|
|
25
|
+
margin: 0;
|
|
26
|
+
min-height: 34px;
|
|
27
|
+
min-width: 34px;
|
|
28
|
+
outline: none;
|
|
29
|
+
padding: 0;
|
|
30
|
+
position: relative;
|
|
31
|
+
text-align: center;
|
|
32
|
+
-webkit-user-select: none;
|
|
33
|
+
-moz-user-select: none;
|
|
34
|
+
-ms-user-select: none;
|
|
35
|
+
user-select: none;
|
|
36
|
+
vertical-align: middle;
|
|
37
|
+
white-space: nowrap;
|
|
38
|
+
width: auto;
|
|
39
|
+
z-index: 0; /* create stacking context for the background so it can be animated */
|
|
40
|
+
}
|
|
41
|
+
button::-moz-focus-inner {
|
|
42
|
+
border: 0;
|
|
43
|
+
}
|
|
44
|
+
.background {
|
|
45
|
+
background-color: transparent;
|
|
46
|
+
border-radius: 4px;
|
|
47
|
+
height: 100%;
|
|
48
|
+
position: absolute;
|
|
49
|
+
transform: scale(0.1, 0.1);
|
|
50
|
+
transition: background-color 150ms linear, transform 150ms linear;
|
|
51
|
+
width: 100%;
|
|
52
|
+
z-index: -1;
|
|
53
|
+
}
|
|
54
|
+
${getFocusRingStyles('button')}
|
|
55
|
+
@supports not selector(:focus-visible) {
|
|
56
|
+
button:hover > .background,
|
|
57
|
+
button:focus > .background {
|
|
58
|
+
background-color: var(--d2l-theme-background-color-interactive-secondary-default);
|
|
59
|
+
transform: scale(1, 1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
@supports selector(:focus-visible) {
|
|
63
|
+
button:hover > .background,
|
|
64
|
+
button:focus-visible > .background {
|
|
65
|
+
background-color: var(--d2l-theme-background-color-interactive-secondary-default);
|
|
66
|
+
transform: scale(1, 1);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
button[disabled],
|
|
70
|
+
button[aria-disabled="true"] {
|
|
71
|
+
cursor: default;
|
|
72
|
+
opacity: var(--d2l-theme-opacity-disabled-control);
|
|
73
|
+
}
|
|
74
|
+
button[disabled]:hover,
|
|
75
|
+
button[disabled]:focus {
|
|
76
|
+
background-color: transparent;
|
|
77
|
+
fill: var(--d2l-theme-text-color-static-standard);
|
|
78
|
+
}
|
|
79
|
+
@media (prefers-reduced-motion: reduce) {
|
|
80
|
+
.background {
|
|
81
|
+
transition: none;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@supports not selector(:focus-visible) {
|
|
86
|
+
:host([theme="dark"]) button:hover > .background,
|
|
87
|
+
:host([theme="dark"]) button:focus > .background {
|
|
88
|
+
background-color: var(--d2l-color-tungsten);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
@supports selector(:focus-visible) {
|
|
92
|
+
:host([theme="dark"]) button:hover > .background,
|
|
93
|
+
:host([theme="dark"]) button:focus-visible > .background {
|
|
94
|
+
background-color: var(--d2l-color-tungsten);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
:host([theme="dark"]) button,
|
|
98
|
+
:host([theme="dark"]) ::slotted(d2l-icon-custom),
|
|
99
|
+
:host([theme="dark"]) d2l-icon {
|
|
100
|
+
color: var(--d2l-color-regolith);
|
|
101
|
+
fill: var(--d2l-color-regolith);
|
|
102
|
+
}
|
|
103
|
+
`;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import '../colors/colors.js';
|
|
2
|
+
import { createRef, ref } from 'lit/directives/ref.js';
|
|
3
|
+
import { css, html, LitElement } from 'lit';
|
|
4
|
+
import { PropertyRequiredMixin } from '../../mixins/property-required/property-required-mixin.js';
|
|
5
|
+
|
|
6
|
+
const keyCodes = Object.freeze({
|
|
7
|
+
END: 35,
|
|
8
|
+
HOME: 36,
|
|
9
|
+
LEFT: 37,
|
|
10
|
+
RIGHT: 39
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A toolbar that provides a slot for toolbar items
|
|
15
|
+
* @slot - Slot for toolbar items (ex. ``)
|
|
16
|
+
*/
|
|
17
|
+
class Toolbar extends PropertyRequiredMixin(LitElement) {
|
|
18
|
+
|
|
19
|
+
static properties = {
|
|
20
|
+
/**
|
|
21
|
+
* ACCESSIBILITY: REQUIRED: Accessible label for the toolbar
|
|
22
|
+
* @type {string}
|
|
23
|
+
*/
|
|
24
|
+
label: { type: String, required: true }
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
static styles = css`
|
|
28
|
+
:host {
|
|
29
|
+
display: inline-block;
|
|
30
|
+
}
|
|
31
|
+
:host([hidden]) {
|
|
32
|
+
display: none;
|
|
33
|
+
}
|
|
34
|
+
.container {
|
|
35
|
+
border-block-end: 1px solid var(--d2l-theme-border-color-standard);
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-wrap: wrap;
|
|
38
|
+
gap: 4px;
|
|
39
|
+
padding-block-end: 4px;
|
|
40
|
+
}
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
constructor() {
|
|
44
|
+
super();
|
|
45
|
+
this.label = '';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
render() {
|
|
49
|
+
return html`
|
|
50
|
+
<div
|
|
51
|
+
aria-label="${this.label}"
|
|
52
|
+
class="container"
|
|
53
|
+
@keydown="${this.#handleKeyDown}"
|
|
54
|
+
role="toolbar">
|
|
55
|
+
<slot ${ref(this.#slotRef)} @slotchange="${this.#handleSlotChange}"></slot>
|
|
56
|
+
</div>
|
|
57
|
+
`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
focus() {
|
|
61
|
+
const focusables = this.#getFocusables();
|
|
62
|
+
const item = focusables.find(item => item._activeFocusable);
|
|
63
|
+
if (!item) return;
|
|
64
|
+
item.focus();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
setActiveFocusable(focusable) {
|
|
68
|
+
const focusables = this.#getFocusables();
|
|
69
|
+
if (focusables.length === 0) return;
|
|
70
|
+
|
|
71
|
+
const focusableExists = !!focusables.find(item => item === focusable);
|
|
72
|
+
if (!focusableExists) return;
|
|
73
|
+
|
|
74
|
+
const currentFocusable = focusables.find(item => item._activeFocusable);
|
|
75
|
+
if (currentFocusable) currentFocusable._activeFocusable = false;
|
|
76
|
+
|
|
77
|
+
focusable._activeFocusable = true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
#slotRef = createRef();
|
|
81
|
+
|
|
82
|
+
#getFocusables() {
|
|
83
|
+
return this.#slotRef.value?.assignedElements({ flatten: true })
|
|
84
|
+
.filter(elem => elem.tagName === 'D2L-TOOLBAR-BUTTON') ?? [];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async #handleKeyDown(e) {
|
|
88
|
+
|
|
89
|
+
// todo: don't steal focus if arrow key originated from inside a dropdown
|
|
90
|
+
|
|
91
|
+
if (e.keyCode !== keyCodes.LEFT && e.keyCode !== keyCodes.RIGHT && e.keyCode !== keyCodes.HOME && e.keyCode !== keyCodes.END) return;
|
|
92
|
+
|
|
93
|
+
const isRtl = document.documentElement.getAttribute('dir') === 'rtl';
|
|
94
|
+
const focusables = this.#getFocusables();
|
|
95
|
+
if (focusables.length === 0) return;
|
|
96
|
+
|
|
97
|
+
const index = focusables.findIndex(item => item._activeFocusable);
|
|
98
|
+
focusables[index]._activeFocusable = false;
|
|
99
|
+
|
|
100
|
+
let focusable;
|
|
101
|
+
if (isRtl && e.keyCode === keyCodes.LEFT) {
|
|
102
|
+
if (index === focusables.length - 1) focusable = focusables[0];
|
|
103
|
+
else focusable = focusables[index + 1];
|
|
104
|
+
} else if (isRtl && e.keyCode === keyCodes.RIGHT) {
|
|
105
|
+
if (index === 0) focusable = focusables[focusables.length - 1];
|
|
106
|
+
else focusable = focusables[index - 1];
|
|
107
|
+
} else if (e.keyCode === keyCodes.LEFT) {
|
|
108
|
+
if (index === 0) focusable = focusables[focusables.length - 1];
|
|
109
|
+
else focusable = focusables[index - 1];
|
|
110
|
+
} else if (e.keyCode === keyCodes.RIGHT) {
|
|
111
|
+
if (index === focusables.length - 1) focusable = focusables[0];
|
|
112
|
+
else focusable = focusables[index + 1];
|
|
113
|
+
} else if (e.keyCode === keyCodes.HOME) {
|
|
114
|
+
focusable = focusables[0];
|
|
115
|
+
} else if (e.keyCode === keyCodes.END) {
|
|
116
|
+
focusable = focusables[focusables.length - 1];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// prevent default so page doesn't scroll when hitting HOME/END
|
|
120
|
+
e.preventDefault();
|
|
121
|
+
|
|
122
|
+
focusable._activeFocusable = true;
|
|
123
|
+
await focusable.updateComplete;
|
|
124
|
+
requestAnimationFrame(() => focusable.focus());
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
#handleSlotChange() {
|
|
128
|
+
const focusables = this.#getFocusables();
|
|
129
|
+
this.#resetActiveFocusable(focusables);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
#resetActiveFocusable(focusables) {
|
|
133
|
+
if (focusables.length === 0) return;
|
|
134
|
+
|
|
135
|
+
const item = focusables.find(item => item._activeFocusable);
|
|
136
|
+
if (item) item._activeFocusable = false;
|
|
137
|
+
|
|
138
|
+
focusables[0]._activeFocusable = true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
customElements.define('d2l-toolbar', Toolbar);
|
package/custom-elements.json
CHANGED
|
@@ -5862,6 +5862,14 @@
|
|
|
5862
5862
|
"name": "styles",
|
|
5863
5863
|
"type": "array",
|
|
5864
5864
|
"default": "[\"iconStyles\",null]"
|
|
5865
|
+
},
|
|
5866
|
+
{
|
|
5867
|
+
"name": "loadingComplete",
|
|
5868
|
+
"type": "Promise<any>"
|
|
5869
|
+
},
|
|
5870
|
+
{
|
|
5871
|
+
"name": "resolveLoadingComplete",
|
|
5872
|
+
"type": "() => void"
|
|
5865
5873
|
}
|
|
5866
5874
|
]
|
|
5867
5875
|
},
|
|
@@ -17173,6 +17181,89 @@
|
|
|
17173
17181
|
}
|
|
17174
17182
|
]
|
|
17175
17183
|
},
|
|
17184
|
+
{
|
|
17185
|
+
"name": "d2l-toolbar-button",
|
|
17186
|
+
"path": "./components/toolbar/toolbar-button.js",
|
|
17187
|
+
"description": "A toolbar button that performs an action",
|
|
17188
|
+
"attributes": [
|
|
17189
|
+
{
|
|
17190
|
+
"name": "disabled",
|
|
17191
|
+
"description": "Disables the toolbar button",
|
|
17192
|
+
"type": "boolean",
|
|
17193
|
+
"default": "false"
|
|
17194
|
+
},
|
|
17195
|
+
{
|
|
17196
|
+
"name": "text",
|
|
17197
|
+
"description": "ACCESSIBILITY: REQUIRED: Accessible text for the button",
|
|
17198
|
+
"type": "string",
|
|
17199
|
+
"default": "\"\""
|
|
17200
|
+
},
|
|
17201
|
+
{
|
|
17202
|
+
"name": "icon",
|
|
17203
|
+
"description": "Preset icon key (e.g. \"tier1:gear\")",
|
|
17204
|
+
"type": "string"
|
|
17205
|
+
}
|
|
17206
|
+
],
|
|
17207
|
+
"properties": [
|
|
17208
|
+
{
|
|
17209
|
+
"name": "styles",
|
|
17210
|
+
"type": "array",
|
|
17211
|
+
"default": "[[null],\"toolbarButtonStyles\"]"
|
|
17212
|
+
},
|
|
17213
|
+
{
|
|
17214
|
+
"name": "disabled",
|
|
17215
|
+
"attribute": "disabled",
|
|
17216
|
+
"description": "Disables the toolbar button",
|
|
17217
|
+
"type": "boolean",
|
|
17218
|
+
"default": "false"
|
|
17219
|
+
},
|
|
17220
|
+
{
|
|
17221
|
+
"name": "text",
|
|
17222
|
+
"attribute": "text",
|
|
17223
|
+
"description": "ACCESSIBILITY: REQUIRED: Accessible text for the button",
|
|
17224
|
+
"type": "string",
|
|
17225
|
+
"default": "\"\""
|
|
17226
|
+
},
|
|
17227
|
+
{
|
|
17228
|
+
"name": "icon",
|
|
17229
|
+
"attribute": "icon",
|
|
17230
|
+
"description": "Preset icon key (e.g. \"tier1:gear\")",
|
|
17231
|
+
"type": "string"
|
|
17232
|
+
}
|
|
17233
|
+
]
|
|
17234
|
+
},
|
|
17235
|
+
{
|
|
17236
|
+
"name": "d2l-toolbar",
|
|
17237
|
+
"path": "./components/toolbar/toolbar.js",
|
|
17238
|
+
"description": "A toolbar that provides a slot for toolbar items",
|
|
17239
|
+
"attributes": [
|
|
17240
|
+
{
|
|
17241
|
+
"name": "label",
|
|
17242
|
+
"description": "ACCESSIBILITY: REQUIRED: Accessible label for the toolbar",
|
|
17243
|
+
"type": "string",
|
|
17244
|
+
"default": "\"\""
|
|
17245
|
+
}
|
|
17246
|
+
],
|
|
17247
|
+
"properties": [
|
|
17248
|
+
{
|
|
17249
|
+
"name": "styles",
|
|
17250
|
+
"default": "\"css`\\n\\t\\t:host {\\n\\t\\t\\tdisplay: inline-block;\\n\\t\\t}\\n\\t\\t:host([hidden]) {\\n\\t\\t\\tdisplay: none;\\n\\t\\t}\\n\\t\\t.container {\\n\\t\\t\\tborder-block-end: 1px solid var(--d2l-theme-border-color-standard);\\n\\t\\t\\tdisplay: flex;\\n\\t\\t\\tflex-wrap: wrap;\\n\\t\\t\\tgap: 4px;\\n\\t\\t\\tpadding-block-end: 4px;\\n\\t\\t}\\n\\t`\""
|
|
17251
|
+
},
|
|
17252
|
+
{
|
|
17253
|
+
"name": "label",
|
|
17254
|
+
"attribute": "label",
|
|
17255
|
+
"description": "ACCESSIBILITY: REQUIRED: Accessible label for the toolbar",
|
|
17256
|
+
"type": "string",
|
|
17257
|
+
"default": "\"\""
|
|
17258
|
+
}
|
|
17259
|
+
],
|
|
17260
|
+
"slots": [
|
|
17261
|
+
{
|
|
17262
|
+
"name": "",
|
|
17263
|
+
"description": "Slot for toolbar items (ex. ``)"
|
|
17264
|
+
}
|
|
17265
|
+
]
|
|
17266
|
+
},
|
|
17176
17267
|
{
|
|
17177
17268
|
"name": "d2l-demo-tooltip-drag-and-drop-list",
|
|
17178
17269
|
"path": "./components/tooltip/demo/tooltip-drag-and-drop-list.js",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brightspace-ui/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.321.0",
|
|
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",
|