@atlassian/aui 9.7.1 → 9.7.2
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-design-tokens-api.js +1 -1
- package/dist/aui/aui-prototyping.css +1 -1
- package/dist/aui/aui-prototyping.css.map +1 -1
- package/dist/aui/aui-prototyping.js +2 -2
- package/dist/aui/aui-prototyping.js.map +1 -1
- package/dist/aui/aui-prototyping.nodeps.css +1 -1
- package/dist/aui/aui-prototyping.nodeps.css.map +1 -1
- package/dist/aui/aui-prototyping.nodeps.js +2 -2
- package/dist/aui/aui-prototyping.nodeps.js.map +1 -1
- package/package.json +1 -1
- package/src/js/aui/avatar-badged.js +10 -17
- package/src/js/aui/avatar-group.js +16 -17
- package/src/js/aui/avatar.js +10 -6
- package/src/js/aui/form-notification.js +33 -2
- package/src/js/aui/form-validation.js +4 -0
- package/src/js/aui/select2.js +55 -4
package/package.json
CHANGED
|
@@ -1,37 +1,30 @@
|
|
|
1
1
|
import skate from './internal/skate';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
const DEFAULT_PLACEMENT_VALUE = 'bottom-end';
|
|
5
|
+
const PLACEMENT_OPTIONS = ['top-start', 'top-end', 'bottom-start', 'bottom-end'];
|
|
4
6
|
|
|
5
7
|
const setBadgedPlacement = (element, newValue, oldValue) => {
|
|
6
|
-
const
|
|
7
|
-
const newPlacementClass = placementOptions.includes(newValue) ? newValue : DEFAULT_VALUE;
|
|
8
|
+
const newPlacement = PLACEMENT_OPTIONS.includes(newValue) ? newValue : DEFAULT_PLACEMENT_VALUE;
|
|
8
9
|
|
|
9
|
-
if (oldValue
|
|
10
|
+
if (oldValue) {
|
|
10
11
|
element.classList.remove(`aui-avatar-badged-${oldValue}`);
|
|
11
12
|
}
|
|
12
|
-
element.classList.add(`aui-avatar-badged-${
|
|
13
|
+
element.classList.add(`aui-avatar-badged-${newPlacement}`);
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
const AvatarBadged = skate('aui-avatar-badged', {
|
|
16
|
-
attached(element) {
|
|
17
|
-
const value = element.getAttribute('placement');
|
|
18
|
-
if (value.length) {
|
|
19
|
-
setBadgedPlacement(element, value);
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
|
|
23
17
|
attributes: {
|
|
24
18
|
placement: {
|
|
25
|
-
value:
|
|
26
|
-
|
|
27
|
-
fallback: function(element, { newValue, oldValue}) {
|
|
19
|
+
value: DEFAULT_PLACEMENT_VALUE,
|
|
20
|
+
fallback(element, { newValue, oldValue}) {
|
|
28
21
|
setBadgedPlacement(element, newValue, oldValue);
|
|
29
22
|
},
|
|
30
|
-
}
|
|
23
|
+
},
|
|
31
24
|
},
|
|
32
25
|
|
|
33
26
|
created: function(element) {
|
|
34
|
-
element.
|
|
27
|
+
element.classList.add('aui-avatar-badged');
|
|
35
28
|
}
|
|
36
29
|
});
|
|
37
30
|
|
|
@@ -2,14 +2,16 @@ import skate from './internal/skate';
|
|
|
2
2
|
|
|
3
3
|
const DEFAULT_SIZE = 'medium';
|
|
4
4
|
const sizes = {xsmall: 16, small: 24, medium: 32, large: 48, xlarge: 64, xxlarge: 96, xxxlarge: 128};
|
|
5
|
-
let
|
|
5
|
+
let isButtonDropdownActive = false;
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const getAvatarGroupSize = (value) => {
|
|
8
8
|
return Object.keys(sizes).includes(value) ? value : DEFAULT_SIZE;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
const setAvatarGroupSize = (element, newValue, oldValue) => {
|
|
12
|
-
|
|
12
|
+
if (oldValue) {
|
|
13
|
+
element.classList.remove(`aui-avatar-group-${oldValue}`);
|
|
14
|
+
}
|
|
13
15
|
element.classList.add(`aui-avatar-group-${newValue}`);
|
|
14
16
|
}
|
|
15
17
|
|
|
@@ -29,9 +31,7 @@ const setBadgedDropdownItem = (element) => {
|
|
|
29
31
|
const badgedDropdown = element.parentNode.querySelector('.aui-avatar-group-dropdown')
|
|
30
32
|
const hiddenAvatarsList = [... avatars].slice(4);
|
|
31
33
|
|
|
32
|
-
if (
|
|
33
|
-
buttonDropdownIsActive = true;
|
|
34
|
-
|
|
34
|
+
if (isButtonDropdownActive) {
|
|
35
35
|
hiddenAvatarsList.forEach(avatar => {
|
|
36
36
|
const avatarItemSrc = avatar.getAttribute('src');
|
|
37
37
|
const avatarItemAlt = avatar.getAttribute('alt');
|
|
@@ -49,8 +49,6 @@ const setBadgedDropdownItem = (element) => {
|
|
|
49
49
|
badgedDropdown.appendChild(avatarWrapper);
|
|
50
50
|
});
|
|
51
51
|
} else {
|
|
52
|
-
buttonDropdownIsActive = false;
|
|
53
|
-
|
|
54
52
|
hiddenAvatarsList.forEach(()=> {
|
|
55
53
|
const dropdownItems = document.querySelector('.aui-avatar-group-dropdown-item');
|
|
56
54
|
if (dropdownItems) {dropdownItems.remove();}
|
|
@@ -60,8 +58,11 @@ const setBadgedDropdownItem = (element) => {
|
|
|
60
58
|
}
|
|
61
59
|
|
|
62
60
|
const handleClickOnBadged = (element) => {
|
|
63
|
-
const badgedDropdown = element.parentNode.querySelector('.aui-avatar-group-dropdown')
|
|
61
|
+
const badgedDropdown = element.parentNode.querySelector('.aui-avatar-group-dropdown');
|
|
64
62
|
badgedDropdown.classList.toggle('aui-avatar-group-dropdown-show');
|
|
63
|
+
|
|
64
|
+
isButtonDropdownActive = !isButtonDropdownActive;
|
|
65
|
+
element.setAttribute('aria-expanded', isButtonDropdownActive.toString());
|
|
65
66
|
|
|
66
67
|
setBadgedDropdownItem(element);
|
|
67
68
|
}
|
|
@@ -78,6 +79,8 @@ const createAvatarGroupBadged = (element, size, avatars, amount) => {
|
|
|
78
79
|
groupBadged.classList.add('aui-avatar-group-badged', 'aui-avatar-inner');
|
|
79
80
|
groupBadged.style.left = setLeftPosition(size, 4.5, multiplier);
|
|
80
81
|
groupBadged.innerText = `+${amount}`;
|
|
82
|
+
groupBadged.setAttribute('aria-expanded', isButtonDropdownActive.toString());
|
|
83
|
+
groupBadged.setAttribute('aria-haspopup', 'dialog')
|
|
81
84
|
element.appendChild(groupBadged);
|
|
82
85
|
|
|
83
86
|
groupBadged.addEventListener('click', () => handleClickOnBadged(groupBadged))
|
|
@@ -111,21 +114,17 @@ const AvatarGroupEl = skate('aui-avatar-group', {
|
|
|
111
114
|
value: DEFAULT_SIZE,
|
|
112
115
|
|
|
113
116
|
fallback(element, { newValue , oldValue }) {
|
|
114
|
-
|
|
117
|
+
const size = getAvatarGroupSize(newValue);
|
|
115
118
|
|
|
116
119
|
skate.init(element);
|
|
117
|
-
setAvatarGroupSize(element,
|
|
118
|
-
tidyUpAvatarGroup(element,
|
|
120
|
+
setAvatarGroupSize(element, size, oldValue);
|
|
121
|
+
tidyUpAvatarGroup(element, size);
|
|
119
122
|
}
|
|
120
123
|
}
|
|
121
124
|
},
|
|
122
125
|
|
|
123
126
|
created(element) {
|
|
124
|
-
|
|
125
|
-
const value = setDefaultSizeValue(avatarGroupSize);
|
|
126
|
-
|
|
127
|
-
element.className = 'aui-avatar-group';
|
|
128
|
-
setAvatarGroupSize(element, value);
|
|
127
|
+
element.classList.add('aui-avatar-group');
|
|
129
128
|
}
|
|
130
129
|
});
|
|
131
130
|
|
package/src/js/aui/avatar.js
CHANGED
|
@@ -9,6 +9,7 @@ const DEFAULT_AVATAR_IMAGES = new Map([
|
|
|
9
9
|
]);
|
|
10
10
|
|
|
11
11
|
const getElementWrapper = (element, elementFind) => element.querySelector(elementFind);
|
|
12
|
+
const containsBadge = (element) => element.querySelector('aui-avatar-badged') !== null;
|
|
12
13
|
|
|
13
14
|
const replaceClass = (element, newValue, oldValue) => {
|
|
14
15
|
const elementWrapper = getElementWrapper(element, '.aui-avatar');
|
|
@@ -48,20 +49,19 @@ const AvatarEl = skate('aui-avatar', {
|
|
|
48
49
|
size(element, { newValue , oldValue}) {
|
|
49
50
|
replaceClass(element, newValue, oldValue);
|
|
50
51
|
},
|
|
51
|
-
|
|
52
52
|
type(element, { newValue, oldValue}) {
|
|
53
53
|
replaceClass(element, newValue, oldValue);
|
|
54
54
|
setDefaultAvatarImage(element);
|
|
55
55
|
},
|
|
56
|
-
|
|
57
56
|
src(element, { newValue: value }) {
|
|
58
57
|
setImageSrc(element, value);
|
|
59
58
|
},
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
alt: {
|
|
60
|
+
value: '',
|
|
61
|
+
fallback(element, {newValue: value}) {
|
|
62
|
+
setImageAlt(element, value);
|
|
63
|
+
}
|
|
63
64
|
},
|
|
64
|
-
|
|
65
65
|
title(element, {newValue: value}) {
|
|
66
66
|
setImageTitle(element, value);
|
|
67
67
|
},
|
|
@@ -70,6 +70,10 @@ const AvatarEl = skate('aui-avatar', {
|
|
|
70
70
|
created: function(element) {
|
|
71
71
|
element.className = 'aui-avatar';
|
|
72
72
|
setDefaultAvatarImage(element);
|
|
73
|
+
|
|
74
|
+
if (containsBadge(element)) {
|
|
75
|
+
element.setAttribute('role', 'img')
|
|
76
|
+
}
|
|
73
77
|
}
|
|
74
78
|
});
|
|
75
79
|
|
|
@@ -119,7 +119,38 @@ function updateAriaInfo($field) {
|
|
|
119
119
|
labels.push(`${id}-${ARIA_DESCRIPTION_POSTFIX}`);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
$
|
|
122
|
+
const $ariaTarget = conditionallyGetFieldTarget($field);
|
|
123
|
+
|
|
124
|
+
$ariaTarget.attr(ARIA_INFO_ATTRIBUTE, !!labels.length ? labels.join(' ') : null);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* During the process of improving A11Y in the project,
|
|
129
|
+
* we discovered that for some form elements we need to
|
|
130
|
+
* make a shift of the target where aria-* attributes
|
|
131
|
+
* are to be applied.
|
|
132
|
+
*
|
|
133
|
+
* This function contains the mapping and returns
|
|
134
|
+
* the desired target, if it was found.
|
|
135
|
+
*
|
|
136
|
+
* If not - the same $field is returned back.
|
|
137
|
+
*/
|
|
138
|
+
function conditionallyGetFieldTarget($field) {
|
|
139
|
+
const modifiers = {
|
|
140
|
+
'aui-select': 'input[type="text"][role="combobox"]'
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
for (let [source, selector] of Object.entries(modifiers)) {
|
|
144
|
+
if ($field.is(source)) {
|
|
145
|
+
const $target = $field.find(selector);
|
|
146
|
+
|
|
147
|
+
if ($target.length) {
|
|
148
|
+
return $target;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return $field;
|
|
123
154
|
}
|
|
124
155
|
|
|
125
156
|
function isJqueryObject(el) {
|
|
@@ -132,7 +163,7 @@ function errorMessageTemplate($field, messages) {
|
|
|
132
163
|
.map(message => `<li><span class="aui-icon aui-icon-small aui-iconfont-error aui-icon-notification"></span>${message}</li>`)
|
|
133
164
|
.join('');
|
|
134
165
|
|
|
135
|
-
return `<div class="error" id="${id}-${ARIA_ERROR_POSTFIX}"><ul>${list}</ul></div>`;
|
|
166
|
+
return `<div class="error" role="alert" id="${id}-${ARIA_ERROR_POSTFIX}"><ul>${list}</ul></div>`;
|
|
136
167
|
}
|
|
137
168
|
|
|
138
169
|
function descriptionTemplate($field, messages) {
|
|
@@ -183,6 +183,7 @@ function createArgumentAccessorFunction($field) {
|
|
|
183
183
|
|
|
184
184
|
function changeFieldState($field, state, message) {
|
|
185
185
|
$field.attr('data-' + ATTRIBUTE_FIELD_STATE, state);
|
|
186
|
+
$field.attr('aria-invalid', false);
|
|
186
187
|
|
|
187
188
|
if (state === UNVALIDATED) {
|
|
188
189
|
return;
|
|
@@ -205,6 +206,9 @@ function changeFieldState($field, state, message) {
|
|
|
205
206
|
setFieldNotification($displayField, notificationType, message);
|
|
206
207
|
}
|
|
207
208
|
|
|
209
|
+
if (state === INVALID) {
|
|
210
|
+
$field.attr('aria-invalid', true);
|
|
211
|
+
}
|
|
208
212
|
}
|
|
209
213
|
|
|
210
214
|
function showSpinnerIfSlow($field) {
|
package/src/js/aui/select2.js
CHANGED
|
@@ -39,34 +39,85 @@ $.fn.auiSelect2 = function (first) {
|
|
|
39
39
|
updatedArgs = arguments;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
const options = updatedArgs[0];
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* AUI-5464: after the upgrade to select2 v3.5.4, custom error handling stopped
|
|
46
|
+
* working, as the `ajax.params.error` function is overriden by select2, and
|
|
47
|
+
* there is no alternative to this...
|
|
48
|
+
*
|
|
49
|
+
* This is a workaround for creating an array of ajax error handlers that will
|
|
50
|
+
* contain the default handler and the custom ones, which is supported starting
|
|
51
|
+
* from jQuery v1.5: http://api.jquery.com/jquery.ajax/
|
|
52
|
+
*
|
|
53
|
+
* Please note this issue is fixed starting from select2 v4, though the data format
|
|
54
|
+
* is different.
|
|
55
|
+
*
|
|
56
|
+
* @see https://atlassian.slack.com/archives/CFGN5350T/p1686741137056489
|
|
57
|
+
*/
|
|
58
|
+
if (options.ajax && options.ajax.params && options.ajax.params.error) {
|
|
59
|
+
let customErrorHandlers = options.ajax.params.error;
|
|
60
|
+
if (!Array.isArray(customErrorHandlers)) {
|
|
61
|
+
customErrorHandlers = [customErrorHandlers];
|
|
62
|
+
}
|
|
63
|
+
let originalTransport = options.ajax.transport;
|
|
64
|
+
if (!originalTransport) {
|
|
65
|
+
originalTransport = originalSelect2.ajaxDefaults.transport
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const newTransport = function(...args) {
|
|
69
|
+
args[0].error = [args[0].error, ...customErrorHandlers];
|
|
70
|
+
return originalTransport(...args);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
options.ajax.transport = newTransport;
|
|
74
|
+
}
|
|
75
|
+
|
|
42
76
|
const result = originalSelect2.apply(this, updatedArgs);
|
|
43
77
|
const select2Instance = this;
|
|
44
|
-
const searchLabel =
|
|
78
|
+
const searchLabel = options.searchLabel;
|
|
45
79
|
|
|
46
80
|
select2Instance.on('select2-open', function () {
|
|
47
81
|
const $selectInput = $(this);
|
|
48
82
|
|
|
49
|
-
if (
|
|
83
|
+
if (options.multiple || $selectInput.attr('multiple')) {
|
|
50
84
|
// This is a multi-select, exiting
|
|
51
85
|
return;
|
|
52
86
|
}
|
|
53
87
|
|
|
54
|
-
const $selectDropdown = $selectInput.select2('dropdown')
|
|
88
|
+
const $selectDropdown = $selectInput.select2('dropdown');
|
|
55
89
|
|
|
56
90
|
if (searchLabel) {
|
|
57
91
|
$selectDropdown.find('.select2-search label').text(searchLabel);
|
|
58
92
|
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
select2Instance.on('select2-close', function () {
|
|
96
|
+
const $selectInput = $(this);
|
|
97
|
+
$selectInput.removeData('was-ariadescribedby-cleared');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
select2Instance.on('select2-loaded', function () {
|
|
101
|
+
const $selectInput = $(this);
|
|
102
|
+
const wasAriaDescribedByCleared = $selectInput.data('was-ariadescribedby-cleared');
|
|
103
|
+
|
|
104
|
+
if (options.multiple || $selectInput.attr('multiple') || wasAriaDescribedByCleared) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const $selectDropdown = $selectInput.select2('dropdown');
|
|
59
109
|
|
|
60
110
|
// AUI-5461: when single select dropdown opens up, the first option is
|
|
61
111
|
// instantly focused, making SRs announce it, while skipping the search field
|
|
62
112
|
$selectDropdown.find('.select2-search .select2-input').attr('aria-activedescendant', '');
|
|
113
|
+
$selectInput.data('was-ariadescribedby-cleared', true);
|
|
63
114
|
});
|
|
64
115
|
|
|
65
116
|
select2Instance.on('select2-focus', function () {
|
|
66
117
|
const $selectInput = $(this);
|
|
67
118
|
const $container = $selectInput.parent().find('.select2-container');
|
|
68
119
|
|
|
69
|
-
if (
|
|
120
|
+
if (options.multiple || $selectInput.attr('multiple')) {
|
|
70
121
|
if (searchLabel) {
|
|
71
122
|
$container.find('.select2-search-field label').text(searchLabel);
|
|
72
123
|
}
|