@atlassian/aui 9.4.7 → 9.4.9
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/dist/aui/aui-prototyping.css +3 -3
- package/dist/aui/aui-prototyping.css.map +1 -1
- package/dist/aui/aui-prototyping.js +8 -6
- package/dist/aui/aui-prototyping.js.map +1 -1
- package/dist/aui/aui-prototyping.nodeps.css +3 -3
- package/dist/aui/aui-prototyping.nodeps.css.map +1 -1
- package/dist/aui/aui-prototyping.nodeps.js +15 -13
- package/dist/aui/aui-prototyping.nodeps.js.map +1 -1
- package/package.json +2 -1
- package/src/js/aui/dropdown2.js +21 -2
- package/src/js/aui/forms/create-forms-component-body.js +37 -0
- package/src/js/aui/forms/custom-checkbox.js +6 -12
- package/src/js/aui/forms/custom-radio.js +6 -12
- package/src/js/aui/internal/detect-children-change.js +35 -0
- package/src/js/aui/sidebar.js +7 -0
- package/src/js/aui/tooltip.js +21 -5
- package/src/js/aui/when-i-type.js +33 -13
- package/src/less/aui-experimental-tooltip.less +1 -0
- package/src/less/forms-radios-and-checkboxes.less +19 -26
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlassian/aui",
|
|
3
3
|
"description": "Atlassian User Interface library",
|
|
4
|
-
"version": "9.4.
|
|
4
|
+
"version": "9.4.9",
|
|
5
5
|
"author": "Atlassian Pty Ltd.",
|
|
6
6
|
"homepage": "https://aui.atlassian.com",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"@popperjs/core": "2.4.4",
|
|
38
38
|
"backbone": "1.4.0",
|
|
39
39
|
"css.escape": "1.5.0",
|
|
40
|
+
"dompurify": "2.4.0",
|
|
40
41
|
"fancy-file-input": "2.0.4",
|
|
41
42
|
"jquery-ui": "1.13.0",
|
|
42
43
|
"skatejs": "0.13.17",
|
package/src/js/aui/dropdown2.js
CHANGED
|
@@ -35,8 +35,27 @@ function setDropdownTriggerActiveState(trigger, isActive) {
|
|
|
35
35
|
* @param {Event} [e] - the event that triggered the dropdown being shown
|
|
36
36
|
*/
|
|
37
37
|
function handleFocus(dropdown, e = {}) {
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
if (e && e.type) {
|
|
39
|
+
const isMouseEvent = e.type.indexOf('mouse') > -1 || e.type.indexOf('hover') > -1;
|
|
40
|
+
const isKeyDownEvent = e.type.indexOf('key') > -1;
|
|
41
|
+
if (dropdown.isSubmenu) {
|
|
42
|
+
!isMouseEvent ? dropdown.focusItem(0) : dropdown.focus();
|
|
43
|
+
} else if (isKeyDownEvent){
|
|
44
|
+
const isUpArrow = e.keyCode === keyCode.UP;
|
|
45
|
+
// set focus to last item in the menu to navigate bottom -> up
|
|
46
|
+
if (isUpArrow) {
|
|
47
|
+
const visibleItems = getVisibleDropdownItems(dropdown);
|
|
48
|
+
if (visibleItems && visibleItems.length) {
|
|
49
|
+
dropdown.focusItem(visibleItems.length - 1);
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
// if enter/space/downArrow than focus goes to the first item
|
|
53
|
+
dropdown.focusItem(0);
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
dropdown.focus();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
40
59
|
}
|
|
41
60
|
|
|
42
61
|
// LOADING STATES
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import skate from "skatejs";
|
|
2
|
+
import {onChildrenChange} from "../internal/detect-children-change";
|
|
3
|
+
import jQuery from "jquery";
|
|
4
|
+
|
|
5
|
+
export function createFormsComponentBody(type) {
|
|
6
|
+
|
|
7
|
+
let unsub;
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
type: skate.type.CLASSNAME,
|
|
11
|
+
attached: function(el) {
|
|
12
|
+
|
|
13
|
+
onChildrenChange(el,(unsubscribe) => {
|
|
14
|
+
|
|
15
|
+
// Store function that stops subscription
|
|
16
|
+
unsub = unsubscribe;
|
|
17
|
+
|
|
18
|
+
const innerCheckboxList = jQuery(`input[type=${type}]`, el);
|
|
19
|
+
|
|
20
|
+
innerCheckboxList.each(function (i, radio) {
|
|
21
|
+
jQuery('<span class="aui-form-glyph"></span>').insertAfter(radio);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const isInsertedAfterChange = innerCheckboxList.length > 0;
|
|
25
|
+
if (isInsertedAfterChange) {
|
|
26
|
+
unsub();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
detached: function(el) {
|
|
31
|
+
jQuery('.aui-form-glyph', el).remove();
|
|
32
|
+
if (unsub) {
|
|
33
|
+
unsub();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
import skate from 'skatejs';
|
|
2
|
-
import
|
|
2
|
+
import {createFormsComponentBody} from "./create-forms-component-body";
|
|
3
|
+
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Allows us to add a new DOM element for rendering ADG styled checkbox glyphs,
|
|
6
7
|
* so we can get our desired aesthetic without having to rely on a specific markup pattern.
|
|
7
8
|
*/
|
|
8
|
-
skate(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
jQuery('<span class="aui-form-glyph"></span>').insertAfter(checkbox);
|
|
13
|
-
});
|
|
14
|
-
},
|
|
15
|
-
detached: function(el) {
|
|
16
|
-
jQuery('.aui-form-glyph', el).remove();
|
|
17
|
-
}
|
|
18
|
-
});
|
|
9
|
+
skate(
|
|
10
|
+
'checkbox',
|
|
11
|
+
createFormsComponentBody('checkbox')
|
|
12
|
+
);
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
import skate from 'skatejs';
|
|
2
|
-
import
|
|
2
|
+
import {createFormsComponentBody} from "./create-forms-component-body";
|
|
3
|
+
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Allows us to add a new DOM element for rendering ADG styled radio glyphs,
|
|
6
7
|
* so we can get our desired aesthetic without having to rely on a specific markup pattern.
|
|
7
8
|
*/
|
|
8
|
-
skate(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
jQuery('<span class="aui-form-glyph"></span>').insertAfter(radio);
|
|
13
|
-
});
|
|
14
|
-
},
|
|
15
|
-
detached: function(el) {
|
|
16
|
-
jQuery('.aui-form-glyph', el).remove();
|
|
17
|
-
}
|
|
18
|
-
});
|
|
9
|
+
skate(
|
|
10
|
+
'radio',
|
|
11
|
+
createFormsComponentBody('radio')
|
|
12
|
+
);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
function isChildrenChanged(mutationList) {
|
|
2
|
+
for (const mutation of mutationList) {
|
|
3
|
+
if (mutation.type === 'childList') {
|
|
4
|
+
return true;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/***
|
|
11
|
+
* Executes callback every time element children change. Called once initially.
|
|
12
|
+
*
|
|
13
|
+
* ***Make sure to use unsubscribe callback to free resources occupied for detection***
|
|
14
|
+
*
|
|
15
|
+
* @param element Element whose children should be monitored
|
|
16
|
+
* @param callback Function to be called when children change happened. Gets unsubscribe function as argument.
|
|
17
|
+
*/
|
|
18
|
+
export function onChildrenChange(element, callback) {
|
|
19
|
+
|
|
20
|
+
let isCompleteOnInit = false;
|
|
21
|
+
|
|
22
|
+
callback(() => { isCompleteOnInit = true });
|
|
23
|
+
|
|
24
|
+
if (isCompleteOnInit) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const observer = new MutationObserver((mutationList) => {
|
|
29
|
+
if (isChildrenChanged(mutationList)) {
|
|
30
|
+
callback(() => observer.disconnect());
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
observer.observe(element, { childList: true });
|
|
35
|
+
}
|
package/src/js/aui/sidebar.js
CHANGED
|
@@ -265,8 +265,14 @@ Sidebar.prototype.reflow = function reflow(
|
|
|
265
265
|
Sidebar.prototype.toggle = function () {
|
|
266
266
|
if (this.isCollapsed()) {
|
|
267
267
|
this.expand();
|
|
268
|
+
this.$el
|
|
269
|
+
.find('.aui-sidebar-toggle')
|
|
270
|
+
.attr('aria-label', I18n.getText('aui.sidebar.collapse.tooltip'));
|
|
268
271
|
} else {
|
|
269
272
|
this.collapse();
|
|
273
|
+
this.$el
|
|
274
|
+
.find('.aui-sidebar-toggle')
|
|
275
|
+
.attr('aria-label', I18n.getText('aui.sidebar.expand.tooltip'));
|
|
270
276
|
}
|
|
271
277
|
return this;
|
|
272
278
|
};
|
|
@@ -618,6 +624,7 @@ function initializeHandlers(sidebar) {
|
|
|
618
624
|
|
|
619
625
|
sidebar.$el.tooltip({
|
|
620
626
|
...tooltipOptions,
|
|
627
|
+
aria: false,
|
|
621
628
|
live: sidebar.toggleSelector,
|
|
622
629
|
title: function () {
|
|
623
630
|
return sidebar.isCollapsed() ?
|
package/src/js/aui/tooltip.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import $ from './jquery';
|
|
2
2
|
import { createPopper } from '@popperjs/core';
|
|
3
|
+
import DOMPurify from 'dompurify';
|
|
3
4
|
|
|
4
5
|
const AUI_TOOLTIP_CLASS_NAME = 'aui-tooltip';
|
|
5
6
|
const AUI_TOOLTIP_ID = 'aui-tooltip';
|
|
@@ -32,7 +33,10 @@ const defaultOptions = {
|
|
|
32
33
|
html: false,
|
|
33
34
|
live: false,
|
|
34
35
|
enabled: true,
|
|
35
|
-
suppress: () => false
|
|
36
|
+
suppress: () => false,
|
|
37
|
+
aria: true,
|
|
38
|
+
sanitize: true,
|
|
39
|
+
maxWidth: 200
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
let $sharedTip;
|
|
@@ -70,7 +74,9 @@ class Tooltip {
|
|
|
70
74
|
|
|
71
75
|
$triggerElement.attr('title', function (_, originalTitle) {
|
|
72
76
|
tooltip.originalTitle = originalTitle;
|
|
73
|
-
|
|
77
|
+
if (tooltip.options.aria) {
|
|
78
|
+
$triggerElement.attr('aria-describedby', AUI_TOOLTIP_ID);
|
|
79
|
+
}
|
|
74
80
|
return null;
|
|
75
81
|
});
|
|
76
82
|
}
|
|
@@ -99,11 +105,21 @@ class Tooltip {
|
|
|
99
105
|
$(document.body).append($sharedTip);
|
|
100
106
|
}
|
|
101
107
|
|
|
108
|
+
const tooltipContentElement = $sharedTip.find('.aui-tooltip-content');
|
|
109
|
+
|
|
102
110
|
if (options.html) {
|
|
103
|
-
|
|
111
|
+
if (options.sanitize) {
|
|
112
|
+
title = DOMPurify.sanitize(title);
|
|
113
|
+
}
|
|
114
|
+
tooltipContentElement.html(title);
|
|
104
115
|
} else {
|
|
105
|
-
|
|
116
|
+
tooltipContentElement.text(title);
|
|
106
117
|
}
|
|
118
|
+
|
|
119
|
+
if (options.maxWidth) {
|
|
120
|
+
tooltipContentElement.css("max-width", options.maxWidth + "px");
|
|
121
|
+
}
|
|
122
|
+
|
|
107
123
|
return $sharedTip;
|
|
108
124
|
}
|
|
109
125
|
|
|
@@ -117,7 +133,7 @@ class Tooltip {
|
|
|
117
133
|
() => this.originalTitle || '';
|
|
118
134
|
|
|
119
135
|
let actualTitle = title.call(this.triggerElement);
|
|
120
|
-
return (actualTitle.trim().length
|
|
136
|
+
return (!actualTitle || !actualTitle.trim().length) ? undefined : actualTitle;
|
|
121
137
|
}
|
|
122
138
|
|
|
123
139
|
show() {
|
|
@@ -127,9 +127,13 @@ function whenIType (keys) {
|
|
|
127
127
|
var title = elem.attr('title') || '';
|
|
128
128
|
var keyCombos = boundKeyCombos.slice();
|
|
129
129
|
var existingCombos = elem.data('boundKeyCombos') || [];
|
|
130
|
-
var
|
|
131
|
-
var
|
|
132
|
-
var
|
|
130
|
+
var kbShortcutAppended = elem.data('kbShortcutAppended') || ''
|
|
131
|
+
var kbShortcutAppendedScreenReader = elem.data('kbShortcutAppendedScreenReader') || ''
|
|
132
|
+
var ariaLabel = elem.attr('aria-label');
|
|
133
|
+
var isFirstShortcut = !kbShortcutAppended;
|
|
134
|
+
var isFirstShortcutScreenReader = !kbShortcutAppendedScreenReader;
|
|
135
|
+
var originalTitle = isFirstShortcut ? title : title.substring(0, title.length - kbShortcutAppended.length);
|
|
136
|
+
var originalAriaLabel = isFirstShortcutScreenReader ? title : ariaLabel.substring(0, ariaLabel.length - kbShortcutAppendedScreenReader.length);
|
|
133
137
|
|
|
134
138
|
while (keyCombos.length) {
|
|
135
139
|
var keyCombo = keyCombos.shift();
|
|
@@ -137,19 +141,26 @@ function whenIType (keys) {
|
|
|
137
141
|
return isEqual(keyCombo, existingCombo);
|
|
138
142
|
});
|
|
139
143
|
if (!comboAlreadyExists) {
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
kbShortcutAppended = appendKeyComboInstructions(keyCombo.slice(), kbShortcutAppended, isFirstShortcut);
|
|
145
|
+
kbShortcutAppendedScreenReader = appendKeyComboInstructions(keyCombo.slice(), kbShortcutAppendedScreenReader, isFirstShortcutScreenReader, { workaroundJaws: true });
|
|
146
|
+
isFirstShortcut = false;
|
|
147
|
+
isFirstShortcutScreenReader = false;
|
|
142
148
|
}
|
|
143
149
|
}
|
|
144
150
|
|
|
145
151
|
if (isMac) {
|
|
146
|
-
|
|
152
|
+
kbShortcutAppended = kbShortcutAppended
|
|
153
|
+
.replace(/Meta/ig, '\u2318') //Apple cmd key
|
|
154
|
+
.replace(/Shift/ig, '\u21E7'); //Apple Shift symbol
|
|
155
|
+
kbShortcutAppendedScreenReader = kbShortcutAppendedScreenReader
|
|
147
156
|
.replace(/Meta/ig, '\u2318') //Apple cmd key
|
|
148
157
|
.replace(/Shift/ig, '\u21E7'); //Apple Shift symbol
|
|
149
158
|
}
|
|
150
159
|
|
|
151
|
-
elem.attr('title', originalTitle +
|
|
152
|
-
elem.
|
|
160
|
+
elem.attr('title', originalTitle + kbShortcutAppended);
|
|
161
|
+
elem.attr('aria-label', originalAriaLabel + kbShortcutAppendedScreenReader)
|
|
162
|
+
elem.data('kbShortcutAppended', kbShortcutAppended);
|
|
163
|
+
elem.data('kbShortcutAppendedScreenReader', kbShortcutAppendedScreenReader);
|
|
153
164
|
elem.data('boundKeyCombos', existingCombos.concat(boundKeyCombos));
|
|
154
165
|
}
|
|
155
166
|
|
|
@@ -163,23 +174,32 @@ function whenIType (keys) {
|
|
|
163
174
|
|
|
164
175
|
var title = elem.attr('title');
|
|
165
176
|
elem.attr('title', title.replace(shortcuts, ''));
|
|
177
|
+
elem.attr('aria-label', title.replace(shortcuts, ''));
|
|
166
178
|
elem.removeData('kbShortcutAppended');
|
|
179
|
+
elem.removeData('kbShortcutAppendedScreenReader');
|
|
167
180
|
elem.removeData('boundKeyCombos');
|
|
168
181
|
}
|
|
169
182
|
|
|
170
|
-
|
|
171
|
-
|
|
183
|
+
function appendKeyComboInstructions(keyCombo, title, isFirst, options) {
|
|
184
|
+
var openParenthesis = '(';
|
|
185
|
+
var closeParenthesis = ')';
|
|
186
|
+
|
|
187
|
+
if (options && options.workaroundJaws) {
|
|
188
|
+
openParenthesis = '';
|
|
189
|
+
closeParenthesis = '';
|
|
190
|
+
}
|
|
191
|
+
|
|
172
192
|
if (isFirst) {
|
|
173
|
-
title += '
|
|
193
|
+
title += ' ' + openParenthesis + I18n.getText('aui.keyboard.shortcut.type.x', keyCombo.shift());
|
|
174
194
|
} else {
|
|
175
195
|
title = title.replace(/\)$/, '');
|
|
176
|
-
title += I18n.getText('aui.keyboard.shortcut.or.x', keyCombo.shift());
|
|
196
|
+
title += ' ' + I18n.getText('aui.keyboard.shortcut.or.x', keyCombo.shift());
|
|
177
197
|
}
|
|
178
198
|
|
|
179
199
|
keyCombo.forEach(function (key) {
|
|
180
200
|
title += ' ' + I18n.getText('aui.keyboard.shortcut.then.x', key);
|
|
181
201
|
});
|
|
182
|
-
title +=
|
|
202
|
+
title += closeParenthesis;
|
|
183
203
|
|
|
184
204
|
return title;
|
|
185
205
|
}
|
|
@@ -200,6 +200,21 @@ form.aui:not(.aui-legacy-forms) {
|
|
|
200
200
|
.aui-checkbox-disabled-style();
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
|
+
|
|
204
|
+
&:focus + .aui-form-glyph::after {
|
|
205
|
+
.aui-radio-focus-size();
|
|
206
|
+
.aui-radio-focus-position();
|
|
207
|
+
|
|
208
|
+
content: "";
|
|
209
|
+
|
|
210
|
+
border: @button-focus-border;
|
|
211
|
+
border-radius: @aui-form-button-size;
|
|
212
|
+
background-color: transparent;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
&:focus + .aui-form-glyph::before {
|
|
216
|
+
border-color: @button-focus-border-color;
|
|
217
|
+
}
|
|
203
218
|
}
|
|
204
219
|
}
|
|
205
220
|
|
|
@@ -255,6 +270,10 @@ form.aui:not(.aui-legacy-forms) {
|
|
|
255
270
|
.aui-checkbox-disabled-style();
|
|
256
271
|
}
|
|
257
272
|
}
|
|
273
|
+
|
|
274
|
+
&:focus + .aui-form-glyph::before {
|
|
275
|
+
border-color: @button-focus-border-color;
|
|
276
|
+
}
|
|
258
277
|
}
|
|
259
278
|
}
|
|
260
279
|
|
|
@@ -273,30 +292,4 @@ form.aui:not(.aui-legacy-forms) {
|
|
|
273
292
|
top: @radio-offset-top - 1px;
|
|
274
293
|
}
|
|
275
294
|
|
|
276
|
-
.radio {
|
|
277
|
-
input {
|
|
278
|
-
&:focus + .aui-form-glyph::after {
|
|
279
|
-
.aui-radio-focus-size();
|
|
280
|
-
.aui-radio-focus-position();
|
|
281
|
-
|
|
282
|
-
content: "";
|
|
283
|
-
|
|
284
|
-
border: @button-focus-border;
|
|
285
|
-
border-radius: @aui-form-button-size;
|
|
286
|
-
background-color: transparent;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
&:focus + .aui-form-glyph::before {
|
|
290
|
-
border-color: @button-focus-border-color;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
.checkbox {
|
|
296
|
-
input {
|
|
297
|
-
&:focus + .aui-form-glyph::before {
|
|
298
|
-
border-color: @button-focus-border-color;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
295
|
}
|