@atlassian/aui 9.4.6-0c8cd15d6 → 9.5.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.
@@ -1,4 +1,6 @@
1
1
  // JS components
2
+ export * from './aui.component.avatar'
3
+ export * from './aui.component.avatar-group'
2
4
  export * from './aui.component.banner'
3
5
  export * from './aui.component.button'
4
6
  export * from './aui.component.dialog2'
@@ -0,0 +1,4 @@
1
+ import './styles/aui.pattern.avatar';
2
+ import '@atlassian/aui/src/less/aui-avatars.less';
3
+ import { AvatarGroupEl } from '@atlassian/aui/src/js/aui/avatar-group';
4
+ export { AvatarGroupEl };
@@ -0,0 +1,5 @@
1
+ import './styles/aui.pattern.avatar';
2
+ import '@atlassian/aui/src/less/aui-avatars.less';
3
+ import { AvatarBadged } from '@atlassian/aui/src/js/aui/avatar-badged';
4
+ import { AvatarEl } from '@atlassian/aui/src/js/aui/avatar';
5
+ export { AvatarEl, AvatarBadged };
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.6-0c8cd15d6",
4
+ "version": "9.5.0",
5
5
  "author": "Atlassian Pty Ltd.",
6
6
  "homepage": "https://aui.atlassian.com",
7
7
  "license": "Apache-2.0",
@@ -35,27 +35,27 @@
35
35
  "dependencies": {
36
36
  "@atlassian/tipsy": "1.3.3",
37
37
  "@popperjs/core": "2.4.4",
38
- "backbone": "1.4.0",
39
- "css.escape": "1.5.0",
38
+ "backbone": "1.4.1",
39
+ "css.escape": "1.5.1",
40
40
  "fancy-file-input": "2.0.4",
41
- "jquery-ui": "1.13.0",
41
+ "jquery-ui": "1.13.1",
42
42
  "skatejs": "0.13.17",
43
43
  "skatejs-template-html": "0.0.0",
44
44
  "trim-extra-html-whitespace": "1.3.0",
45
- "underscore": "1.13.1"
45
+ "underscore": "1.13.4"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@atlassian/adg-server-iconfont": "3.1.0",
49
49
  "@atlassian/aui-webpack-config": "3.0.1",
50
- "@babel/core": "7.14.0",
51
- "@babel/preset-env": "7.14.1",
50
+ "@babel/core": "7.18.6",
51
+ "@babel/preset-env": "7.18.6",
52
52
  "bundlesize": "1.0.0-beta.2",
53
53
  "cross-env": "7.0.3",
54
- "eslint": "7.26.0",
55
- "glob": "7.1.6",
54
+ "eslint": "7.32.0",
55
+ "glob": "7.2.3",
56
56
  "ignore-emit-webpack-plugin": "2.0.6",
57
57
  "jquery": "3.5.1",
58
- "jquery-migrate": "3.3.2",
58
+ "jquery-migrate": "3.4.0",
59
59
  "less": "3.13.1"
60
60
  },
61
61
  "scripts": {
@@ -0,0 +1,38 @@
1
+ import skate from './internal/skate';
2
+
3
+ const DEFAULT_VALUE = 'bottom-end'
4
+
5
+ const setBadgedPlacement = (element, newValue, oldValue) => {
6
+ const placementOptions = ['top-start', 'top-end', 'bottom-start', 'bottom-end'];
7
+ const newPlacementClass = placementOptions.includes(newValue) ? newValue : DEFAULT_VALUE;
8
+
9
+ if (oldValue !== null) {
10
+ element.classList.remove(`aui-avatar-badged-${oldValue}`);
11
+ }
12
+ element.classList.add(`aui-avatar-badged-${newPlacementClass}`);
13
+ }
14
+
15
+ 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
+ attributes: {
24
+ placement: {
25
+ value: DEFAULT_VALUE,
26
+
27
+ fallback: function(element, { newValue, oldValue}) {
28
+ setBadgedPlacement(element, newValue, oldValue);
29
+ },
30
+ }
31
+ },
32
+
33
+ created: function(element) {
34
+ element.className = 'aui-avatar-badged';
35
+ }
36
+ });
37
+
38
+ export { AvatarBadged };
@@ -0,0 +1,165 @@
1
+ import skate from './internal/skate';
2
+
3
+ const DEFAULT_SIZE = 'medium';
4
+ const sizes = {xsmall: 16, small: 24, medium: 32, large: 48, xlarge: 64, xxlarge: 96, xxxlarge: 128};
5
+ let buttonDropdownIsActive = false;
6
+
7
+ const setDefaultSizeValue = (value) => {
8
+ return Object.keys(sizes).includes(value) ? value : DEFAULT_SIZE;
9
+ }
10
+
11
+ const setAvatarGroupSize = (element, newValue, oldValue) => {
12
+ element.classList.remove(`aui-avatar-group-${oldValue}`);
13
+ element.classList.add(`aui-avatar-group-${newValue}`);
14
+ }
15
+
16
+ const setLeftPosition = (size, divisionNum, multiplyNum) => {
17
+ return `${(sizes[size] - sizes[size] / divisionNum) * multiplyNum}px`;
18
+ }
19
+
20
+ const addAvatarGroupStyle = (element, size, multiplyNum) => {
21
+ element.setAttribute('size', size);
22
+ element.classList.add('aui-avatar-group-item');
23
+ element.style.left = setLeftPosition(size, 4, multiplyNum);
24
+ element.style.zIndex = `${5 - multiplyNum}`;
25
+ }
26
+
27
+ const setBadgedDropdownItem = (element) => {
28
+ const avatars = element.parentNode.querySelectorAll('aui-avatar');
29
+ const badgedDropdown = element.parentNode.querySelector('.aui-avatar-group-dropdown')
30
+ const hiddenAvatarsList = [... avatars].slice(4);
31
+
32
+ if (!buttonDropdownIsActive) {
33
+ buttonDropdownIsActive = true;
34
+
35
+ hiddenAvatarsList.forEach(avatar => {
36
+ const avatarItemSrc = avatar.getAttribute('src');
37
+ const avatarItemAlt = avatar.getAttribute('alt');
38
+ const avatarItemTitle = avatar.getAttribute('title');
39
+
40
+ const avatarWrapper = document.createElement('span');
41
+ avatarWrapper.setAttribute('class', 'aui-avatar-group-dropdown-item');
42
+
43
+ if (avatarItemSrc) {
44
+ avatarWrapper.innerHTML = `<aui-avatar id="avatar-item" src=${avatarItemSrc} alt=${avatarItemAlt} title=${avatarItemTitle}></aui-avatar>`;
45
+ } else {
46
+ avatarWrapper.innerHTML = '<aui-avatar></aui-avatar>';
47
+ }
48
+
49
+ badgedDropdown.appendChild(avatarWrapper);
50
+ });
51
+ } else {
52
+ buttonDropdownIsActive = false;
53
+
54
+ hiddenAvatarsList.forEach(()=> {
55
+ const dropdownItems = document.querySelector('.aui-avatar-group-dropdown-item');
56
+ if (dropdownItems) {dropdownItems.remove();}
57
+ });
58
+ }
59
+
60
+ }
61
+
62
+ const handleClickOnBadged = (element) => {
63
+ const badgedDropdown = element.parentNode.querySelector('.aui-avatar-group-dropdown')
64
+ badgedDropdown.classList.toggle('aui-avatar-group-dropdown-show');
65
+
66
+ setBadgedDropdownItem(element);
67
+ }
68
+
69
+ const createAvatarGroupBadged = (element, size, avatars, amount) => {
70
+ const oldBadged = element.querySelector('.aui-avatar-group-badged');
71
+ if (oldBadged) {oldBadged.remove()};
72
+
73
+ const oldBadgedDropdown = element.querySelector('.aui-avatar-group-dropdown')
74
+ if (oldBadgedDropdown) {oldBadgedDropdown.remove()}
75
+ const multiplier = avatars.length - amount;
76
+
77
+ const groupBadged = document.createElement('button');
78
+ groupBadged.classList.add('aui-avatar-group-badged', 'aui-avatar-inner');
79
+ groupBadged.style.left = setLeftPosition(size, 4.5, multiplier);
80
+ groupBadged.innerText = `+${amount}`;
81
+ element.appendChild(groupBadged);
82
+
83
+ groupBadged.addEventListener('click', () => handleClickOnBadged(groupBadged))
84
+
85
+ const badgedDropdown = document.createElement('div');
86
+ badgedDropdown.classList.add('aui-avatar-group-dropdown');
87
+ badgedDropdown.style.left = setLeftPosition(size, 4.5, multiplier);
88
+ element.appendChild(badgedDropdown);
89
+ }
90
+
91
+ const tidyUpAvatarGroup = (element, size) => {
92
+ const avatars = element.querySelectorAll('aui-avatar');
93
+ let amountItems = avatars.length - 4;
94
+
95
+ avatars.forEach((avatar, index) => {
96
+ avatar.classList.toggle('aui-avatar-group-item-hidden', index >= 4);
97
+ addAvatarGroupStyle(avatar, size, index);
98
+ });
99
+
100
+ if (amountItems > 0) {
101
+ createAvatarGroupBadged(element, size, avatars, amountItems);
102
+ } else {
103
+ const badged = element.querySelector('.aui-avatar-group-badged');
104
+ if (badged) {badged.remove();}
105
+ }
106
+ }
107
+
108
+ const AvatarGroupEl = skate('aui-avatar-group', {
109
+ attributes: {
110
+ size: {
111
+ value: DEFAULT_SIZE,
112
+
113
+ fallback(element, { newValue , oldValue }) {
114
+ let value = setDefaultSizeValue(newValue);
115
+
116
+ skate.init(element);
117
+ setAvatarGroupSize(element, value, oldValue);
118
+ tidyUpAvatarGroup(element, value);
119
+ }
120
+ }
121
+ },
122
+
123
+ created(element) {
124
+ const avatarGroupSize = element.getAttribute('size')
125
+ const value = setDefaultSizeValue(avatarGroupSize);
126
+
127
+ element.className = 'aui-avatar-group';
128
+ setAvatarGroupSize(element, value);
129
+ }
130
+ });
131
+
132
+ const wasNodeRemoved = (mutation, target) => {
133
+ return mutation.removedNodes.length > 0 && target.classList.contains('aui-avatar-group') && mutation.removedNodes[0].classList.contains('aui-avatar-group-item');
134
+ }
135
+
136
+ const wasNodeAdded = (mutation, target) => {
137
+ return mutation.addedNodes.length > 0 && target.classList.contains('aui-avatar-group') && mutation.addedNodes[0].classList.contains('aui-avatar');
138
+ }
139
+
140
+ const mutationObserver = new MutationObserver(function(mutation) {
141
+ mutation.forEach(function(mutation) {
142
+ const target = mutation.target;
143
+
144
+ if (wasNodeRemoved(mutation, target)) {
145
+ tidyUpAvatarGroup(target, target.getAttribute('size'));
146
+ }
147
+
148
+ if (wasNodeAdded(mutation, target)) {
149
+ setTimeout(() => {
150
+ tidyUpAvatarGroup(target, target.getAttribute('size'));
151
+ }, 0);
152
+ }
153
+ });
154
+ });
155
+
156
+ mutationObserver.observe(document.documentElement, {
157
+ attributes: false,
158
+ characterData: true,
159
+ childList: true,
160
+ subtree: true,
161
+ attributeOldValue: false,
162
+ characterDataOldValue: false
163
+ });
164
+
165
+ export { AvatarGroupEl };
@@ -0,0 +1,76 @@
1
+ import template from 'skatejs-template-html';
2
+ import skate from './internal/skate';
3
+ import personImage from '../../../../../packages/docs/src/docs/images/avatar-person.svg';
4
+ import projectImage from '../../../../../packages/docs/src/docs/images/avatar-project.svg';
5
+
6
+ const DEFAULT_AVATAR_IMAGES = new Map([
7
+ ['project', projectImage],
8
+ ['user', personImage]
9
+ ]);
10
+
11
+ const getElementWrapper = (element, elementFind) => element.querySelector(elementFind);
12
+
13
+ const replaceClass = (element, newValue, oldValue) => {
14
+ const elementWrapper = getElementWrapper(element, '.aui-avatar');
15
+
16
+ elementWrapper.classList.remove(`aui-avatar-${oldValue}`);
17
+ elementWrapper.classList.add(`aui-avatar-${newValue}`);
18
+ }
19
+
20
+ const getAvatarType = (element) => element.getAttribute('type') === 'project' ? 'project' : 'user';
21
+
22
+ const setDefaultAvatarImage = (element) => {
23
+ if (element.hasAttribute('src')){
24
+ setImageSrc(element, element.getAttribute('src'));
25
+ } else {
26
+ const avatarType = getAvatarType(element);
27
+ const avatarSvg = DEFAULT_AVATAR_IMAGES.get(avatarType);
28
+ setImageSrc(element, avatarSvg);
29
+ }
30
+ }
31
+
32
+ const setImageAttr = (element, name, value) => getElementWrapper(element, 'img').setAttribute(name, value);
33
+ const setImageSrc = (element, src) => setImageAttr(element, 'src', src);
34
+ const setImageAlt = (element, alt) => setImageAttr(element, 'alt', alt);
35
+ const setImageTitle = (element, title) => setImageAttr(element, 'title', title);
36
+
37
+ const AvatarEl = skate('aui-avatar', {
38
+ template: template(`
39
+ <span class='aui-avatar'>
40
+ <span class='aui-avatar-inner'>
41
+ <img />
42
+ </span>
43
+ <content></content>
44
+ </span>
45
+ `),
46
+
47
+ attributes: {
48
+ size(element, { newValue , oldValue}) {
49
+ replaceClass(element, newValue, oldValue);
50
+ },
51
+
52
+ type(element, { newValue, oldValue}) {
53
+ replaceClass(element, newValue, oldValue);
54
+ setDefaultAvatarImage(element);
55
+ },
56
+
57
+ src(element, { newValue: value }) {
58
+ setImageSrc(element, value);
59
+ },
60
+
61
+ alt(element, {newValue: value}) {
62
+ setImageAlt(element, value);
63
+ },
64
+
65
+ title(element, {newValue: value}) {
66
+ setImageTitle(element, value);
67
+ },
68
+ },
69
+
70
+ created: function(element) {
71
+ element.className = 'aui-avatar';
72
+ setDefaultAvatarImage(element);
73
+ }
74
+ });
75
+
76
+ export { AvatarEl };
@@ -18,7 +18,7 @@ function dim (useShim, zIndex) {
18
18
  }
19
19
 
20
20
  function isAuiLayer(element) {
21
- return element.classList.contains('aui-layer');
21
+ return element.classList && element.classList.contains('aui-layer');
22
22
  }
23
23
 
24
24
  Array.prototype.forEach.call(document.body.children, function (element) {
@@ -241,6 +241,8 @@ Header.prototype = {
241
241
  }
242
242
  };
243
243
 
244
+
245
+
244
246
  function createTriggerAndAssociate(dropdown) {
245
247
  var trigger = document.createElement('a');
246
248
  trigger.setAttribute('class', 'aui-dropdown2-trigger');
@@ -20,6 +20,7 @@ function createMessageConstructor(type) {
20
20
  * @param {String} [obj.title] - Plain-text title of the message. If provided, will appear above the message body.
21
21
  * @param {String} obj.body - Content of the message. Can be HTML content.
22
22
  * @param {boolean} [obj.closeable] - If true, the message can be manually closed by the end-user via the UI.
23
+ * @param {boolean} [obj.removeOnHide] - If true, the message will be removed from the DOM after hide.
23
24
  * @param {boolean} [obj.fadeout]
24
25
  * @param {boolean} [obj.duration]
25
26
  * @param {boolean} [obj.delay]
@@ -41,6 +42,10 @@ function createMessageConstructor(type) {
41
42
  insertMessageIntoContext($message, obj.insert, context);
42
43
 
43
44
  // Attach the optional extra behaviours
45
+ if (obj.removeOnHide) {
46
+ makeRemoveOnHide($message, obj.delay, obj.duration);
47
+ }
48
+
44
49
  if (obj.closeable) {
45
50
  makeCloseable($message);
46
51
  }
@@ -53,6 +58,13 @@ function createMessageConstructor(type) {
53
58
  };
54
59
  }
55
60
 
61
+ function makeRemoveOnHide(message, delay, duration) {
62
+ $(message || '.aui-message.aui-remove-on-hide').each(function () {
63
+ var $this = $(this);
64
+ makeFadeout($this, delay, duration)
65
+ })
66
+ }
67
+
56
68
  function makeCloseable(message) {
57
69
  $(message || 'div.aui-message.closeable').each(function () {
58
70
  var $this = $(this);
@@ -145,9 +157,11 @@ function makeFadeout(message, delay, duration) {
145
157
  */
146
158
  var messages = {
147
159
  setup: function () {
160
+ makeRemoveOnHide();
148
161
  makeCloseable();
149
162
  makeFadeout();
150
163
  },
164
+ makeRemoveOnHide: makeRemoveOnHide,
151
165
  makeCloseable: makeCloseable,
152
166
  makeFadeout: makeFadeout,
153
167
  createMessage: createMessageConstructor
@@ -178,7 +192,7 @@ function insertMessageIntoContext($message, insertWhere, context) {
178
192
  }
179
193
  }
180
194
 
181
- function renderMessageElement ({id, closeable, fadeout, title, body}, type) {
195
+ function renderMessageElement ({id, closeable, removeOnHide, fadeout, title, body}, type) {
182
196
  // Convert the options in to template values
183
197
  const titleHtml = title ? `<p class="title"><strong>${escapeHtml(title)}</strong></p>` : '';
184
198
  const html = `<div class="aui-message">${titleHtml}</div>`;
@@ -186,6 +200,7 @@ function renderMessageElement ({id, closeable, fadeout, title, body}, type) {
186
200
  // Construct the message element
187
201
  const $message = $(html)
188
202
  .append($.parseHTML(body || ''))
203
+ .addClass(removeOnHide ? 'aui-remove-on-hide' : '')
189
204
  .addClass(closeable ? 'closeable' : '')
190
205
  .addClass(fadeout ? 'fadeout' : '')
191
206
  .addClass(`aui-message-${type}`);
@@ -205,7 +220,7 @@ function renderMessageElement ({id, closeable, fadeout, title, body}, type) {
205
220
 
206
221
  $.fn.closeMessage = function () {
207
222
  var $message = $(this);
208
- if ($message.hasClass('aui-message') && $message.hasClass('closeable')) {
223
+ if ($message.hasClass('aui-message') && ($message.hasClass('closeable') || $message.hasClass('aui-remove-on-hide'))) {
209
224
  $message.stop(true); //Stop any running animation
210
225
  $message.trigger('messageClose', [this]); //messageClose event Deprecated as of 5.3
211
226
  $message.remove();
@@ -230,6 +245,7 @@ const MessageEl = skate('aui-message', {
230
245
  element.innerHTML = '';
231
246
  messages[type](element, {
232
247
  body: body,
248
+ removeOnHide: element.getAttribute('removeOnHide'),
233
249
  closeable: element.getAttribute('closeable'),
234
250
  delay: element.getAttribute('delay'),
235
251
  duration: element.getAttribute('duration'),
@@ -92,10 +92,8 @@ class Tooltip {
92
92
 
93
93
  buildTip(title) {
94
94
  const options = this.options;
95
- if ($sharedTip === undefined) {
96
- $sharedTip =
97
- $(`<div id="${AUI_TOOLTIP_ID}" class="${AUI_TOOLTIP_CLASS_NAME} assistive" role="tooltip"><p class="aui-tooltip-content"></p></div>`)
98
-
95
+ if ($sharedTip === undefined || $sharedTip.get(0) && !$sharedTip.get(0).isConnected) {
96
+ $sharedTip = $(`<div id="${AUI_TOOLTIP_ID}" class="${AUI_TOOLTIP_CLASS_NAME} assistive" role="tooltip"><p class="aui-tooltip-content"></p></div>`);
99
97
  $(document.body).append($sharedTip);
100
98
  }
101
99
 
@@ -497,14 +497,25 @@ whenIType.fromJSON = function (json, switchCtrlToMetaOnMac) {
497
497
  var shortcuts = [];
498
498
 
499
499
  if (json) {
500
+ var operation = null;
501
+ var param = null;
502
+ if (typeof json === 'object') {
503
+ operation = json.op;
504
+ param = json.param;
505
+ }
500
506
  $.each(json, function (i,item) {
501
- const operation = item.op;
502
- const param = item.param;
507
+ operation = (item.op) ? item.op : operation;
508
+ param = (item.param) ? item.param : param;
503
509
  let params;
504
510
 
505
511
  if (operation === 'execute' || operation === 'evaluate') {
506
512
  // need to turn function string into function object
507
- params = [new Function(param)];
513
+ // params = [new Function(param)];
514
+
515
+ // params = [(param) => JSON.parse(JSON.stringify(param))];
516
+ params = [function (param){
517
+ return param;
518
+ }];
508
519
 
509
520
  } else if (/^\[[^\]\[]*,[^\]\[]*\]$/.test(param)) {
510
521
  // pass in an array to send multiple params