@brightspace-ui/core 2.102.0 → 2.103.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/button/button-icon.js +0 -1
- package/components/button/button-move.js +245 -0
- package/components/button/demo/button-move.html +46 -0
- package/components/list/list-item-drag-handle.js +93 -125
- package/custom-elements.json +60 -0
- package/package.json +1 -1
- package/tools/dom-test-helpers.js +4 -3
|
@@ -167,7 +167,6 @@ class ButtonIcon extends ThemeMixin(ButtonMixin(VisibleOnAncestorMixin(RtlMixin(
|
|
|
167
167
|
aria-haspopup="${ifDefined(this.ariaHaspopup)}"
|
|
168
168
|
aria-label="${this.ariaLabel ? this.ariaLabel : ifDefined(this.text)}"
|
|
169
169
|
?autofocus="${this.autofocus}"
|
|
170
|
-
class="d2l-label-text"
|
|
171
170
|
?disabled="${this.disabled && !this.disabledTooltip}"
|
|
172
171
|
form="${ifDefined(this.form)}"
|
|
173
172
|
formaction="${ifDefined(this.formaction)}"
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import '../colors/colors.js';
|
|
2
|
+
import '../icons/icon.js';
|
|
3
|
+
import '../tooltip/tooltip.js';
|
|
4
|
+
import { css, html, LitElement } from 'lit';
|
|
5
|
+
import { buttonStyles } from './button-styles.js';
|
|
6
|
+
import { FocusMixin } from '../../mixins/focus-mixin.js';
|
|
7
|
+
import { getUniqueId } from '../../helpers/uniqueId.js';
|
|
8
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
9
|
+
import { RtlMixin } from '../../mixins/rtl-mixin.js';
|
|
10
|
+
|
|
11
|
+
const keyCodes = Object.freeze({
|
|
12
|
+
DOWN: 40,
|
|
13
|
+
END: 35,
|
|
14
|
+
HOME: 36,
|
|
15
|
+
LEFT: 37,
|
|
16
|
+
RIGHT: 39,
|
|
17
|
+
UP: 38
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export const moveActions = Object.freeze({
|
|
21
|
+
up: 'up',
|
|
22
|
+
down: 'down',
|
|
23
|
+
left: 'left',
|
|
24
|
+
right: 'right',
|
|
25
|
+
rootHome: 'root-home',
|
|
26
|
+
home: 'home',
|
|
27
|
+
rootEnd: 'root-end',
|
|
28
|
+
end: 'end'
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A button component that provides a move action via a single button.
|
|
33
|
+
*/
|
|
34
|
+
class ButtonMove extends FocusMixin(RtlMixin(LitElement)) {
|
|
35
|
+
|
|
36
|
+
static get properties() {
|
|
37
|
+
return {
|
|
38
|
+
/**
|
|
39
|
+
* @ignore
|
|
40
|
+
*/
|
|
41
|
+
autofocus: { type: Boolean, reflect: true },
|
|
42
|
+
/**
|
|
43
|
+
* A description to be added to the button for accessibility when text on button does not provide enough context
|
|
44
|
+
* @type {string}
|
|
45
|
+
*/
|
|
46
|
+
description: { type: String },
|
|
47
|
+
/**
|
|
48
|
+
* Disables the button
|
|
49
|
+
* @type {boolean}
|
|
50
|
+
*/
|
|
51
|
+
disabled: { type: Boolean, reflect: true },
|
|
52
|
+
/**
|
|
53
|
+
* Tooltip text when disabled
|
|
54
|
+
* @type {string}
|
|
55
|
+
*/
|
|
56
|
+
disabledTooltip: { type: String, attribute: 'disabled-tooltip' },
|
|
57
|
+
/**
|
|
58
|
+
* REQUIRED: Accessible text for the button
|
|
59
|
+
* @type {string}
|
|
60
|
+
*/
|
|
61
|
+
text: { type: String, reflect: true }
|
|
62
|
+
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static get styles() {
|
|
67
|
+
return [ buttonStyles,
|
|
68
|
+
css`
|
|
69
|
+
:host {
|
|
70
|
+
display: inline-block;
|
|
71
|
+
line-height: 0;
|
|
72
|
+
}
|
|
73
|
+
:host([hidden]) {
|
|
74
|
+
display: none;
|
|
75
|
+
}
|
|
76
|
+
button {
|
|
77
|
+
background-color: transparent;
|
|
78
|
+
display: flex;
|
|
79
|
+
flex-direction: column;
|
|
80
|
+
gap: 2px;
|
|
81
|
+
margin: 0;
|
|
82
|
+
min-height: 1.8rem;
|
|
83
|
+
padding: 0;
|
|
84
|
+
position: relative;
|
|
85
|
+
width: 0.9rem;
|
|
86
|
+
}
|
|
87
|
+
d2l-icon {
|
|
88
|
+
border-radius: 0.1rem;
|
|
89
|
+
height: 0.85rem;
|
|
90
|
+
width: 0.9rem;
|
|
91
|
+
}
|
|
92
|
+
button:focus {
|
|
93
|
+
background-color: #ffffff;
|
|
94
|
+
}
|
|
95
|
+
button:hover > d2l-icon,
|
|
96
|
+
button:focus > d2l-icon {
|
|
97
|
+
background-color: var(--d2l-color-mica);
|
|
98
|
+
}
|
|
99
|
+
.up-icon {
|
|
100
|
+
border-top-left-radius: 0.3rem;
|
|
101
|
+
border-top-right-radius: 0.3rem;
|
|
102
|
+
}
|
|
103
|
+
.down-icon {
|
|
104
|
+
border-bottom-left-radius: 0.3rem;
|
|
105
|
+
border-bottom-right-radius: 0.3rem;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.up-layer,
|
|
109
|
+
.down-layer {
|
|
110
|
+
height: 1.1rem;
|
|
111
|
+
left: -0.2rem;
|
|
112
|
+
position: absolute;
|
|
113
|
+
width: 1.3rem;
|
|
114
|
+
}
|
|
115
|
+
.up-layer {
|
|
116
|
+
top: -0.25rem;
|
|
117
|
+
}
|
|
118
|
+
.down-layer {
|
|
119
|
+
bottom: -0.25rem;
|
|
120
|
+
}
|
|
121
|
+
:host([dir="rtl"]) .up-layer,
|
|
122
|
+
:host([dir="rtl"]) .down-layer {
|
|
123
|
+
left: auto;
|
|
124
|
+
right: -0.2rem;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
/* Firefox includes a hidden border which messes up button dimensions */
|
|
129
|
+
button::-moz-focus-inner {
|
|
130
|
+
border: 0;
|
|
131
|
+
}
|
|
132
|
+
:host([disabled]) button {
|
|
133
|
+
cursor: default;
|
|
134
|
+
opacity: 0.5;
|
|
135
|
+
}
|
|
136
|
+
button[disabled]:hover > d2l-icon {
|
|
137
|
+
background-color: transparent;
|
|
138
|
+
}
|
|
139
|
+
`
|
|
140
|
+
];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
constructor() {
|
|
144
|
+
super();
|
|
145
|
+
this.disabled = false;
|
|
146
|
+
/** @ignore */
|
|
147
|
+
this.autofocus = false;
|
|
148
|
+
/** @internal */
|
|
149
|
+
this._buttonId = getUniqueId();
|
|
150
|
+
/** @internal */
|
|
151
|
+
this._describedById = getUniqueId();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
static get focusElementSelector() {
|
|
155
|
+
return 'button';
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
connectedCallback() {
|
|
159
|
+
super.connectedCallback();
|
|
160
|
+
this.addEventListener('click', this._handleClick, true);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
disconnectedCallback() {
|
|
164
|
+
super.disconnectedCallback();
|
|
165
|
+
this.removeEventListener('click', this._handleClick, true);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
render() {
|
|
169
|
+
return html`
|
|
170
|
+
<button
|
|
171
|
+
aria-describedby="${ifDefined(this.description ? this._describedById : undefined)}"
|
|
172
|
+
aria-disabled="${ifDefined(this.disabled && this.disabledTooltip ? 'true' : undefined)}"
|
|
173
|
+
aria-label="${ifDefined(this.text)}"
|
|
174
|
+
?autofocus="${this.autofocus}"
|
|
175
|
+
?disabled="${this.disabled && !this.disabledTooltip}"
|
|
176
|
+
id="${this._buttonId}"
|
|
177
|
+
@keydown="${this._handleKeydown}"
|
|
178
|
+
title="${ifDefined(this.text)}"
|
|
179
|
+
type="button">
|
|
180
|
+
<d2l-icon icon="tier1:arrow-toggle-up" class="up-icon"></d2l-icon>
|
|
181
|
+
<d2l-icon icon="tier1:arrow-toggle-down" class="down-icon"></d2l-icon>
|
|
182
|
+
<div class="up-layer" @click="${this._handleUpClick}"></div>
|
|
183
|
+
<div class="down-layer" @click="${this._handleDownClick}"></div>
|
|
184
|
+
</button>
|
|
185
|
+
${this.description ? html`<span id="${this._describedById}" hidden>${this.description}</span>` : null}
|
|
186
|
+
${this.disabled && this.disabledTooltip ? html`<d2l-tooltip for="${this._buttonId}">${this.disabledTooltip}</d2l-tooltip>` : ''}
|
|
187
|
+
`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
_dispatchAction(action) {
|
|
191
|
+
if (!action) return;
|
|
192
|
+
this.dispatchEvent(new CustomEvent('d2l-button-move-action', {
|
|
193
|
+
detail: { action },
|
|
194
|
+
bubbles: false
|
|
195
|
+
}));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
_handleClick(e) {
|
|
199
|
+
if (this.disabled) {
|
|
200
|
+
e.stopPropagation();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
_handleDownClick() {
|
|
205
|
+
this._dispatchAction(moveActions.down);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
_handleKeydown(e) {
|
|
209
|
+
let action;
|
|
210
|
+
switch (e.keyCode) {
|
|
211
|
+
case keyCodes.UP:
|
|
212
|
+
action = moveActions.up;
|
|
213
|
+
break;
|
|
214
|
+
case keyCodes.DOWN:
|
|
215
|
+
action = moveActions.down;
|
|
216
|
+
break;
|
|
217
|
+
case keyCodes.LEFT:
|
|
218
|
+
action = moveActions.left;
|
|
219
|
+
break;
|
|
220
|
+
case keyCodes.RIGHT:
|
|
221
|
+
action = moveActions.right;
|
|
222
|
+
break;
|
|
223
|
+
case keyCodes.HOME:
|
|
224
|
+
action = (e.ctrlKey ? moveActions.rootHome : moveActions.home);
|
|
225
|
+
break;
|
|
226
|
+
case keyCodes.END:
|
|
227
|
+
action = (e.ctrlKey ? moveActions.rootEnd : moveActions.end);
|
|
228
|
+
break;
|
|
229
|
+
default:
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
this._dispatchAction(action);
|
|
234
|
+
e.preventDefault();
|
|
235
|
+
e.stopPropagation();
|
|
236
|
+
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
_handleUpClick() {
|
|
240
|
+
this._dispatchAction(moveActions.up);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
customElements.define('d2l-button-move', ButtonMove);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<link rel="stylesheet" href="../../demo/styles.css" type="text/css">
|
|
7
|
+
<script type="module">
|
|
8
|
+
import '../../demo/demo-page.js';
|
|
9
|
+
import '../button-move.js';
|
|
10
|
+
</script>
|
|
11
|
+
</head>
|
|
12
|
+
<body unresolved>
|
|
13
|
+
|
|
14
|
+
<d2l-demo-page page-title="d2l-button-move">
|
|
15
|
+
|
|
16
|
+
<h2>Move Button</h2>
|
|
17
|
+
|
|
18
|
+
<d2l-demo-snippet>
|
|
19
|
+
<template>
|
|
20
|
+
<d2l-button-move id="move-button" text="Reorder Item"></d2l-button-move>
|
|
21
|
+
<script>
|
|
22
|
+
document.querySelector('#move-button').addEventListener('d2l-button-move-action', e => {
|
|
23
|
+
console.log('d2l-button-move-action', e.target, e.detail);
|
|
24
|
+
});
|
|
25
|
+
</script>
|
|
26
|
+
</template>
|
|
27
|
+
</d2l-demo-snippet>
|
|
28
|
+
|
|
29
|
+
<h2>Move Button Disabled</h2>
|
|
30
|
+
|
|
31
|
+
<d2l-demo-snippet>
|
|
32
|
+
<template>
|
|
33
|
+
<d2l-button-move text="Reorder Item" disabled></d2l-button-move>
|
|
34
|
+
</template>
|
|
35
|
+
</d2l-demo-snippet>
|
|
36
|
+
|
|
37
|
+
<h2>Move Button Disabled with Tooltip</h2>
|
|
38
|
+
|
|
39
|
+
<d2l-demo-snippet>
|
|
40
|
+
<template>
|
|
41
|
+
<d2l-button-move text="Reorder Item" disabled disabled-tooltip="Optional disabled tooltip"></d2l-button-move>
|
|
42
|
+
</template>
|
|
43
|
+
</d2l-demo-snippet>
|
|
44
|
+
|
|
45
|
+
</body>
|
|
46
|
+
</html>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import '../button/button-icon.js';
|
|
2
1
|
import '../icons/icon.js';
|
|
3
2
|
import '../tooltip/tooltip.js';
|
|
4
3
|
import { css, html, LitElement } from 'lit';
|
|
5
4
|
import { buttonStyles } from '../button/button-styles.js';
|
|
6
5
|
import { findComposedAncestor } from '../../helpers/dom.js';
|
|
7
|
-
import {
|
|
6
|
+
import { FocusMixin } from '../../mixins/focus-mixin.js';
|
|
8
7
|
import { getUniqueId } from '../../helpers/uniqueId.js';
|
|
9
8
|
import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
|
|
9
|
+
import { moveActions } from '../button/button-move.js';
|
|
10
10
|
import { RtlMixin } from '../../mixins/rtl-mixin.js';
|
|
11
11
|
|
|
12
12
|
const keyCodes = Object.freeze({
|
|
@@ -43,7 +43,7 @@ let hasDisplayedKeyboardTooltip = false;
|
|
|
43
43
|
/**
|
|
44
44
|
* @fires d2l-list-item-drag-handle-action - Dispatched when an action performed on the drag handle
|
|
45
45
|
*/
|
|
46
|
-
class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
46
|
+
class ListItemDragHandle extends LocalizeCoreElement(FocusMixin(RtlMixin(LitElement))) {
|
|
47
47
|
|
|
48
48
|
static get properties() {
|
|
49
49
|
return {
|
|
@@ -79,33 +79,6 @@ class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
79
79
|
.d2l-list-item-drag-handle-dragger-button {
|
|
80
80
|
background-color: unset;
|
|
81
81
|
display: block;
|
|
82
|
-
}
|
|
83
|
-
.d2l-list-item-drag-handle-keyboard-button {
|
|
84
|
-
display: grid;
|
|
85
|
-
gap: 2px;
|
|
86
|
-
grid-auto-rows: 1fr 1fr;
|
|
87
|
-
position: relative;
|
|
88
|
-
}
|
|
89
|
-
.d2l-list-item-drag-handle-keyboard-button-up,
|
|
90
|
-
.d2l-list-item-drag-handle-keyboard-button-down {
|
|
91
|
-
height: 1.1rem;
|
|
92
|
-
left: -0.2rem;
|
|
93
|
-
position: absolute;
|
|
94
|
-
width: 1.3rem;
|
|
95
|
-
}
|
|
96
|
-
.d2l-list-item-drag-handle-keyboard-button-up {
|
|
97
|
-
top: -0.25rem;
|
|
98
|
-
}
|
|
99
|
-
.d2l-list-item-drag-handle-keyboard-button-down {
|
|
100
|
-
bottom: -0.25rem;
|
|
101
|
-
}
|
|
102
|
-
:host([dir="rtl"]) .d2l-list-item-drag-handle-keyboard-button-up,
|
|
103
|
-
:host([dir="rtl"]) .d2l-list-item-drag-handle-keyboard-button-down {
|
|
104
|
-
left: auto;
|
|
105
|
-
right: -0.2rem;
|
|
106
|
-
}
|
|
107
|
-
.d2l-list-item-drag-handle-dragger-button,
|
|
108
|
-
.d2l-list-item-drag-handle-keyboard-button {
|
|
109
82
|
margin: 0;
|
|
110
83
|
min-height: 1.8rem;
|
|
111
84
|
padding: 0;
|
|
@@ -119,20 +92,6 @@ class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
119
92
|
height: 0.9rem;
|
|
120
93
|
width: 0.9rem;
|
|
121
94
|
}
|
|
122
|
-
.d2l-button-up-icon,
|
|
123
|
-
.d2l-button-down-icon {
|
|
124
|
-
border-radius: 0.1rem;
|
|
125
|
-
height: 0.85rem;
|
|
126
|
-
width: 0.9rem;
|
|
127
|
-
}
|
|
128
|
-
.d2l-button-up-icon {
|
|
129
|
-
border-top-left-radius: 0.3rem;
|
|
130
|
-
border-top-right-radius: 0.3rem;
|
|
131
|
-
}
|
|
132
|
-
.d2l-button-down-icon {
|
|
133
|
-
border-bottom-left-radius: 0.3rem;
|
|
134
|
-
border-bottom-right-radius: 0.3rem;
|
|
135
|
-
}
|
|
136
95
|
button,
|
|
137
96
|
button[disabled]:hover,
|
|
138
97
|
button[disabled]:focus {
|
|
@@ -143,14 +102,6 @@ class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
143
102
|
.d2l-list-item-drag-handle-dragger-button:focus {
|
|
144
103
|
background-color: var(--d2l-color-mica);
|
|
145
104
|
}
|
|
146
|
-
.d2l-list-item-drag-handle-keyboard-button:hover,
|
|
147
|
-
.d2l-list-item-drag-handle-keyboard-button:focus {
|
|
148
|
-
background-color: transparent;
|
|
149
|
-
}
|
|
150
|
-
.d2l-list-item-drag-handle-keyboard-button:hover > d2l-icon,
|
|
151
|
-
.d2l-list-item-drag-handle-keyboard-button:focus > d2l-icon {
|
|
152
|
-
background-color: var(--d2l-color-mica);
|
|
153
|
-
}
|
|
154
105
|
button[disabled] {
|
|
155
106
|
cursor: default;
|
|
156
107
|
opacity: 0.5;
|
|
@@ -178,6 +129,10 @@ class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
178
129
|
this._movingElement = false;
|
|
179
130
|
}
|
|
180
131
|
|
|
132
|
+
static get focusElementSelector() {
|
|
133
|
+
return '.d2l-list-item-drag-handle-button';
|
|
134
|
+
}
|
|
135
|
+
|
|
181
136
|
render() {
|
|
182
137
|
return this._keyboardActive && !this.disabled ? this._renderKeyboardDragging() : this._renderDragger();
|
|
183
138
|
}
|
|
@@ -192,11 +147,6 @@ class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
192
147
|
this._keyboardActive = true;
|
|
193
148
|
}
|
|
194
149
|
|
|
195
|
-
focus() {
|
|
196
|
-
const node = getFirstFocusableDescendant(this);
|
|
197
|
-
if (node) node.focus();
|
|
198
|
-
}
|
|
199
|
-
|
|
200
150
|
get _defaultLabel() {
|
|
201
151
|
const namespace = 'components.list-item-drag-handle';
|
|
202
152
|
const defaultLabel = this.localize(`${namespace}.${'default'}`, 'name', this.text);
|
|
@@ -212,37 +162,96 @@ class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
212
162
|
}));
|
|
213
163
|
}
|
|
214
164
|
|
|
215
|
-
|
|
216
|
-
this._dispatchAction(
|
|
165
|
+
async _doAction(action) {
|
|
166
|
+
this._dispatchAction(action);
|
|
167
|
+
const cell = findComposedAncestor(this, (parent) => parent.hasAttribute && parent.hasAttribute('draggable'));
|
|
168
|
+
if (cell) await cell.updateComplete;
|
|
169
|
+
await this.updateComplete;
|
|
170
|
+
this.focus();
|
|
171
|
+
this._movingElement = false;
|
|
217
172
|
}
|
|
218
173
|
|
|
219
|
-
|
|
220
|
-
this.
|
|
174
|
+
_onDraggerButtonClick() {
|
|
175
|
+
this.activateKeyboardMode();
|
|
221
176
|
}
|
|
222
177
|
|
|
223
|
-
|
|
224
|
-
if (
|
|
178
|
+
_onDraggerButtonKeydown(e) {
|
|
179
|
+
if (e.keyCode !== keyCodes.ENTER && e.keyCode !== keyCodes.SPACE) return;
|
|
180
|
+
e.preventDefault();
|
|
181
|
+
this.activateKeyboardMode();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
_onKeyboardButtonFocusIn() {
|
|
185
|
+
if (hasDisplayedKeyboardTooltip) return;
|
|
186
|
+
this._displayKeyboardTooltip = true;
|
|
187
|
+
hasDisplayedKeyboardTooltip = true;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
_onKeyboardButtonFocusOut(e) {
|
|
191
|
+
this._displayKeyboardTooltip = false;
|
|
192
|
+
if (this._movingElement) {
|
|
193
|
+
this._movingElement = false;
|
|
194
|
+
e.stopPropagation();
|
|
195
|
+
e.preventDefault();
|
|
225
196
|
return;
|
|
226
197
|
}
|
|
198
|
+
this._keyboardActive = false;
|
|
199
|
+
this._dispatchAction(dragActions.save);
|
|
200
|
+
e.stopPropagation();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async _onMoveButtonAction(e) {
|
|
204
|
+
|
|
227
205
|
let action = null;
|
|
228
|
-
switch (e.
|
|
229
|
-
case
|
|
206
|
+
switch (e.detail.action) {
|
|
207
|
+
case moveActions.up:
|
|
230
208
|
this._movingElement = true;
|
|
231
209
|
action = dragActions.up;
|
|
232
210
|
this.updateComplete.then(() => this.blur()); // tell screenreaders to refocus
|
|
233
211
|
break;
|
|
234
|
-
case
|
|
212
|
+
case moveActions.down:
|
|
235
213
|
this._movingElement = true;
|
|
236
214
|
action = dragActions.down;
|
|
237
215
|
break;
|
|
238
|
-
case
|
|
216
|
+
case moveActions.right:
|
|
217
|
+
this._movingElement = true;
|
|
218
|
+
action = (this.dir === 'rtl' ? dragActions.unnest : dragActions.nest);
|
|
219
|
+
break;
|
|
220
|
+
case moveActions.left:
|
|
221
|
+
this._movingElement = true;
|
|
222
|
+
action = (this.dir === 'rtl' ? dragActions.nest : dragActions.unnest) ;
|
|
223
|
+
break;
|
|
224
|
+
case moveActions.rootHome:
|
|
225
|
+
this._movingElement = true;
|
|
226
|
+
action = dragActions.rootFirst;
|
|
227
|
+
break;
|
|
228
|
+
case moveActions.home:
|
|
239
229
|
this._movingElement = true;
|
|
240
|
-
action =
|
|
230
|
+
action = dragActions.first;
|
|
241
231
|
break;
|
|
242
|
-
case
|
|
232
|
+
case moveActions.rootEnd:
|
|
243
233
|
this._movingElement = true;
|
|
244
|
-
action =
|
|
234
|
+
action = dragActions.rootLast;
|
|
245
235
|
break;
|
|
236
|
+
case moveActions.end:
|
|
237
|
+
this._movingElement = true;
|
|
238
|
+
action = dragActions.last;
|
|
239
|
+
break;
|
|
240
|
+
default:
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
this._doAction(action);
|
|
245
|
+
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async _onMoveButtonKeydown(e) {
|
|
249
|
+
if (!this._keyboardActive) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
let action = null;
|
|
254
|
+
switch (e.keyCode) {
|
|
246
255
|
case keyCodes.TAB:
|
|
247
256
|
action = e.shiftKey ? dragActions.previousElement : dragActions.nextElement;
|
|
248
257
|
break;
|
|
@@ -250,14 +259,6 @@ class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
250
259
|
action = dragActions.cancel;
|
|
251
260
|
this.updateComplete.then(() => this._keyboardActive = false);
|
|
252
261
|
break;
|
|
253
|
-
case keyCodes.RIGHT:
|
|
254
|
-
this._movingElement = true;
|
|
255
|
-
action = (this.dir === 'rtl' ? dragActions.unnest : dragActions.nest);
|
|
256
|
-
break;
|
|
257
|
-
case keyCodes.LEFT:
|
|
258
|
-
this._movingElement = true;
|
|
259
|
-
action = (this.dir === 'rtl' ? dragActions.nest : dragActions.unnest) ;
|
|
260
|
-
break;
|
|
261
262
|
case keyCodes.ENTER:
|
|
262
263
|
case keyCodes.SPACE:
|
|
263
264
|
action = dragActions.save;
|
|
@@ -266,49 +267,19 @@ class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
266
267
|
default:
|
|
267
268
|
return;
|
|
268
269
|
}
|
|
269
|
-
this._dispatchAction(action);
|
|
270
|
-
e.preventDefault();
|
|
271
|
-
e.stopPropagation();
|
|
272
|
-
const cell = findComposedAncestor(this, (parent) => parent.hasAttribute && parent.hasAttribute('draggable'));
|
|
273
|
-
if (cell) await cell.updateComplete;
|
|
274
|
-
await this.updateComplete;
|
|
275
|
-
this.focus();
|
|
276
|
-
this._movingElement = false;
|
|
277
|
-
}
|
|
278
270
|
|
|
279
|
-
|
|
280
|
-
if (hasDisplayedKeyboardTooltip) return;
|
|
281
|
-
this._displayKeyboardTooltip = true;
|
|
282
|
-
hasDisplayedKeyboardTooltip = true;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
_onFocusOutKeyboardButton(e) {
|
|
286
|
-
this._displayKeyboardTooltip = false;
|
|
287
|
-
if (this._movingElement) {
|
|
288
|
-
this._movingElement = false;
|
|
289
|
-
e.stopPropagation();
|
|
290
|
-
e.preventDefault();
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
this._keyboardActive = false;
|
|
294
|
-
this._dispatchAction(dragActions.save);
|
|
271
|
+
e.preventDefault();
|
|
295
272
|
e.stopPropagation();
|
|
296
|
-
|
|
273
|
+
this._doAction(action);
|
|
297
274
|
|
|
298
|
-
_onInactiveKeyboard(e) {
|
|
299
|
-
if (e.type === 'click' || e.keyCode === keyCodes.ENTER || e.keyCode === keyCodes.SPACE) {
|
|
300
|
-
this._dispatchAction(dragActions.active);
|
|
301
|
-
this._keyboardActive = true;
|
|
302
|
-
e.preventDefault();
|
|
303
|
-
}
|
|
304
275
|
}
|
|
305
276
|
|
|
306
277
|
_renderDragger() {
|
|
307
278
|
return html`
|
|
308
279
|
<button
|
|
309
|
-
class="d2l-list-item-drag-handle-dragger-button"
|
|
310
|
-
@click="${this.
|
|
311
|
-
@keydown="${this.
|
|
280
|
+
class="d2l-list-item-drag-handle-dragger-button d2l-list-item-drag-handle-button"
|
|
281
|
+
@click="${this._onDraggerButtonClick}"
|
|
282
|
+
@keydown="${this._onDraggerButtonKeydown}"
|
|
312
283
|
aria-label="${this._defaultLabel}"
|
|
313
284
|
?disabled="${this.disabled}">
|
|
314
285
|
<d2l-icon icon="tier1:dragger" class="d2l-button-dragger-icon"></d2l-icon>
|
|
@@ -318,19 +289,16 @@ class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
|
318
289
|
|
|
319
290
|
_renderKeyboardDragging() {
|
|
320
291
|
return html`
|
|
321
|
-
<button
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
@focusin="${this.
|
|
325
|
-
@focusout="${this.
|
|
292
|
+
<d2l-button-move
|
|
293
|
+
class="d2l-list-item-drag-handle-button"
|
|
294
|
+
@d2l-button-move-action="${this._onMoveButtonAction}"
|
|
295
|
+
@focusin="${this._onKeyboardButtonFocusIn}"
|
|
296
|
+
@focusout="${this._onKeyboardButtonFocusOut}"
|
|
326
297
|
id="${this._buttonId}"
|
|
327
|
-
@keydown="${this.
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
<div class="d2l-list-item-drag-handle-keyboard-button-down" @click="${this._dispatchActionDown}"></div>
|
|
332
|
-
</button>
|
|
333
|
-
${this._displayKeyboardTooltip ? html`<d2l-tooltip align="start" for="${this._buttonId}" for-type="descriptor">${this._renderTooltipContent()}</d2l-tooltip>` : ''}
|
|
298
|
+
@keydown="${this._onMoveButtonKeydown}"
|
|
299
|
+
text="${this._defaultLabel}">
|
|
300
|
+
</d2l-button-move>
|
|
301
|
+
${this._displayKeyboardTooltip ? html`<d2l-tooltip align="start" announced for="${this._buttonId}" for-type="descriptor">${this._renderTooltipContent()}</d2l-tooltip>` : ''}
|
|
334
302
|
`;
|
|
335
303
|
}
|
|
336
304
|
|
package/custom-elements.json
CHANGED
|
@@ -438,6 +438,66 @@
|
|
|
438
438
|
}
|
|
439
439
|
]
|
|
440
440
|
},
|
|
441
|
+
{
|
|
442
|
+
"name": "d2l-button-move",
|
|
443
|
+
"path": "./components/button/button-move.js",
|
|
444
|
+
"description": "A button component that provides a move action via a single button.",
|
|
445
|
+
"attributes": [
|
|
446
|
+
{
|
|
447
|
+
"name": "description",
|
|
448
|
+
"description": "A description to be added to the button for accessibility when text on button does not provide enough context",
|
|
449
|
+
"type": "string"
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
"name": "disabled-tooltip",
|
|
453
|
+
"description": "Tooltip text when disabled",
|
|
454
|
+
"type": "string"
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
"name": "text",
|
|
458
|
+
"description": "REQUIRED: Accessible text for the button",
|
|
459
|
+
"type": "string"
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
"name": "disabled",
|
|
463
|
+
"description": "Disables the button",
|
|
464
|
+
"type": "boolean",
|
|
465
|
+
"default": "false"
|
|
466
|
+
}
|
|
467
|
+
],
|
|
468
|
+
"properties": [
|
|
469
|
+
{
|
|
470
|
+
"name": "description",
|
|
471
|
+
"attribute": "description",
|
|
472
|
+
"description": "A description to be added to the button for accessibility when text on button does not provide enough context",
|
|
473
|
+
"type": "string"
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
"name": "disabledTooltip",
|
|
477
|
+
"attribute": "disabled-tooltip",
|
|
478
|
+
"description": "Tooltip text when disabled",
|
|
479
|
+
"type": "string"
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
"name": "text",
|
|
483
|
+
"attribute": "text",
|
|
484
|
+
"description": "REQUIRED: Accessible text for the button",
|
|
485
|
+
"type": "string"
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
"name": "disabled",
|
|
489
|
+
"attribute": "disabled",
|
|
490
|
+
"description": "Disables the button",
|
|
491
|
+
"type": "boolean",
|
|
492
|
+
"default": "false"
|
|
493
|
+
}
|
|
494
|
+
],
|
|
495
|
+
"events": [
|
|
496
|
+
{
|
|
497
|
+
"name": "d2l-button-move-action"
|
|
498
|
+
}
|
|
499
|
+
]
|
|
500
|
+
},
|
|
441
501
|
{
|
|
442
502
|
"name": "d2l-button-subtle",
|
|
443
503
|
"path": "./components/button/button-subtle.js",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brightspace-ui/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.103.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",
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { getComposedChildren } from '../helpers/dom.js';
|
|
2
2
|
|
|
3
|
-
export function keyDown(element,
|
|
3
|
+
export function keyDown(element, keyCode, ctrlKey) {
|
|
4
4
|
const event = new CustomEvent('keydown', {
|
|
5
5
|
detail: 0,
|
|
6
6
|
bubbles: true,
|
|
7
7
|
cancelable: true,
|
|
8
8
|
composed: true
|
|
9
9
|
});
|
|
10
|
-
event.keyCode =
|
|
11
|
-
event.code =
|
|
10
|
+
event.keyCode = keyCode;
|
|
11
|
+
event.code = keyCode;
|
|
12
|
+
if (ctrlKey !== undefined) event.ctrlKey = ctrlKey;
|
|
12
13
|
element.dispatchEvent(event);
|
|
13
14
|
}
|
|
14
15
|
|