@atlassian/aui 9.6.0 → 9.7.0-5d50c8a74

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.
Files changed (61) hide show
  1. package/README.md +1 -1
  2. package/dist/aui/@atlaskit-internal_atlassian-dark-iteration.js +2 -0
  3. package/dist/aui/@atlaskit-internal_atlassian-dark-iteration.js.map +1 -0
  4. package/dist/aui/@atlaskit-internal_atlassian-dark-new-input-border.js +2 -0
  5. package/dist/aui/@atlaskit-internal_atlassian-dark-new-input-border.js.map +1 -0
  6. package/dist/aui/@atlaskit-internal_atlassian-dark.js +2 -0
  7. package/dist/aui/@atlaskit-internal_atlassian-dark.js.map +1 -0
  8. package/dist/aui/@atlaskit-internal_atlassian-legacy-dark.js +2 -0
  9. package/dist/aui/@atlaskit-internal_atlassian-legacy-dark.js.map +1 -0
  10. package/dist/aui/@atlaskit-internal_atlassian-legacy-light.js +2 -0
  11. package/dist/aui/@atlaskit-internal_atlassian-legacy-light.js.map +1 -0
  12. package/dist/aui/@atlaskit-internal_atlassian-light-new-input-border.js +2 -0
  13. package/dist/aui/@atlaskit-internal_atlassian-light-new-input-border.js.map +1 -0
  14. package/dist/aui/@atlaskit-internal_atlassian-light.js +2 -0
  15. package/dist/aui/@atlaskit-internal_atlassian-light.js.map +1 -0
  16. package/dist/aui/@atlaskit-internal_atlassian-shape.js +2 -0
  17. package/dist/aui/@atlaskit-internal_atlassian-shape.js.map +1 -0
  18. package/dist/aui/@atlaskit-internal_atlassian-spacing.js +2 -0
  19. package/dist/aui/@atlaskit-internal_atlassian-spacing.js.map +1 -0
  20. package/dist/aui/@atlaskit-internal_atlassian-typography.js +2 -0
  21. package/dist/aui/@atlaskit-internal_atlassian-typography.js.map +1 -0
  22. package/dist/aui/aui-css-deprecations.js +1 -1
  23. package/dist/aui/aui-css-deprecations.js.map +1 -1
  24. package/dist/aui/aui-prototyping-browserfocus.css +532 -5
  25. package/dist/aui/aui-prototyping-darkmode.css +258 -5
  26. package/dist/aui/aui-prototyping-design-tokens-api.js +18 -0
  27. package/dist/aui/aui-prototyping-design-tokens-api.js.map +1 -0
  28. package/dist/aui/aui-prototyping.css +8 -8
  29. package/dist/aui/aui-prototyping.css.map +1 -1
  30. package/dist/aui/aui-prototyping.js +9 -9
  31. package/dist/aui/aui-prototyping.js.map +1 -1
  32. package/dist/aui/aui-prototyping.nodeps.css +8 -8
  33. package/dist/aui/aui-prototyping.nodeps.css.map +1 -1
  34. package/dist/aui/aui-prototyping.nodeps.js +14 -14
  35. package/dist/aui/aui-prototyping.nodeps.js.map +1 -1
  36. package/entry/aui.design-tokens-api.js +2 -0
  37. package/entry/styles/aui.page.design-tokens-mode.js +1 -0
  38. package/entry/styles/aui.page.reset.js +1 -0
  39. package/package.json +4 -2
  40. package/src/js/aui/design-tokens/design-tokens.js +104 -0
  41. package/src/js/aui/form-notification.js +44 -10
  42. package/src/js/aui/form-validation.js +8 -1
  43. package/src/js/aui/internal/globalize.js +1 -1
  44. package/src/js/aui/select2.js +58 -8
  45. package/src/js/aui/toggle.js +6 -6
  46. package/src/js/aui/tooltip.js +64 -26
  47. package/src/js/aui-css-deprecations.js +8 -0
  48. package/src/less/aui-banner.less +4 -5
  49. package/src/less/aui-close-button.less +1 -2
  50. package/src/less/aui-experimental-tooltip.less +1 -1
  51. package/src/less/aui-spinner.less +1 -1
  52. package/src/less/forms-radios-and-checkboxes.less +0 -2
  53. package/src/less/imports/aui-theme/components/buttons.less +1 -1
  54. package/src/less/imports/aui-theme/components/forms.less +0 -1
  55. package/src/less/imports/aui-theme/components/progress-tracker.less +0 -2
  56. package/src/less/imports/aui-theme/core/colors.less +337 -12
  57. package/src/less/imports/aui-theme/theme.less +16 -1
  58. package/src/less/messages.less +3 -4
  59. package/src/less/themes/design-tokens.aui-theme.less +5 -0
  60. package/src/less/themes/themes.less +2 -0
  61. /package/{LICENSE.md → LICENSE} +0 -0
@@ -0,0 +1,2 @@
1
+ // Enable design tokens themes
2
+ export * from '@atlassian/aui/src/js/aui/design-tokens/design-tokens';
@@ -0,0 +1 @@
1
+ import '@atlassian/aui/src/less/themes/design-tokens.aui-theme.less';
@@ -1 +1,2 @@
1
1
  import '@atlassian/aui/src/less/aui-reset.less';
2
+ import './aui.page.design-tokens-mode';
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.6.0",
4
+ "version": "9.7.0-5d50c8a74",
5
5
  "author": "Atlassian Pty Ltd.",
6
6
  "homepage": "https://aui.atlassian.com",
7
7
  "license": "Apache-2.0",
@@ -24,7 +24,7 @@
24
24
  "src",
25
25
  "CHANGELOG.md",
26
26
  "CONTRIBUTING.md",
27
- "LICENSE.md",
27
+ "LICENSE",
28
28
  "README.md",
29
29
  "yarn.lock"
30
30
  ],
@@ -33,6 +33,7 @@
33
33
  "jquery": "^2 || ^3"
34
34
  },
35
35
  "dependencies": {
36
+ "@atlaskit/tokens": "^1.2.11",
36
37
  "@atlassian/tipsy": "1.3.3",
37
38
  "@popperjs/core": "2.11.6",
38
39
  "backbone": "1.4.1",
@@ -54,6 +55,7 @@
54
55
  "cross-env": "7.0.3",
55
56
  "eslint": "7.32.0",
56
57
  "glob": "7.2.3",
58
+ "react": "^18.2.0",
57
59
  "ignore-emit-webpack-plugin": "2.0.6",
58
60
  "jquery": "3.5.1",
59
61
  "jquery-migrate": "3.4.1",
@@ -0,0 +1,104 @@
1
+ import * as Tokens from '@atlaskit/tokens';
2
+ import TokenNames from '@atlaskit/tokens/token-names';
3
+ import globalize from '../internal/globalize';
4
+
5
+
6
+
7
+ const testingColorVariableName = '--aui-theme-testing-color';
8
+ const defaultTestingColor = 'color(srgb 1 0.75 0.8 / 0.6)';
9
+ const testingThemeName = "aui-theme-testing";
10
+
11
+ /**
12
+ * Theme that replaces all the design tokens with single color, helping to visually identify custom colors on the page
13
+ *
14
+ * @param solidColor any valid CSS color, will be used to replace tokens
15
+ */
16
+ (function generateTestingTheme() {
17
+
18
+ const initialComment = "This theme is autogenerated using AJS.DesignTokens.generateTestingTheme()."
19
+
20
+ // If function called many times theme should be only added once
21
+ const isThemeAlreadyInitialised = !document.getElementById(testingThemeName)
22
+ if (!isThemeAlreadyInitialised) {
23
+ return;
24
+ }
25
+
26
+ // We use overridable test color declaration to make theme configurable
27
+ const colorDeclaration = `${testingColorVariableName}: ${defaultTestingColor};`
28
+ const themeCSSDeclarations = Object.values(TokenNames)
29
+ .map(token => `\t${token}: var(${testingColorVariableName});`);
30
+ const allDeclarations = [ colorDeclaration, ...themeCSSDeclarations ];
31
+
32
+
33
+ const themeCSS = `/* ${initialComment} */\nbody.${testingThemeName} {\n${allDeclarations.join('\n')}\n}`;
34
+
35
+ const themeElement = document.createElement('style');
36
+ themeElement.id = testingThemeName;
37
+ themeElement.innerText = themeCSS;
38
+
39
+ const head = document.querySelector('head');
40
+ if (head) {
41
+ head.appendChild(themeElement);
42
+ }
43
+ })();
44
+
45
+
46
+ /**
47
+ * Enables or disables testing theme for Design Tokens based on current state
48
+ * @param state Optional parameter. Allows to force specific state.
49
+ */
50
+ export function toggleTestingTheme(state) {
51
+
52
+ // If not passed, invert existing state
53
+ if (state == null) {
54
+ const currentState = document.body.classList.contains(testingThemeName);
55
+ state = !currentState;
56
+ }
57
+
58
+ state ? enableTestingTheme() : disableTestingTheme();
59
+ }
60
+
61
+ /**
62
+ * Overrides default testing color by setting css variable. If no color passed, will revert to default.
63
+ * @param color color to use for testing
64
+ */
65
+ export function setTestingThemeColor(color = defaultTestingColor) {
66
+ document.body.style.setProperty(testingColorVariableName, color);
67
+ }
68
+
69
+ export function enableTestingTheme() {
70
+ const isEnabled = document.body.classList.contains(testingThemeName);
71
+ if (!isEnabled) {
72
+ document.body.classList.add(testingThemeName);
73
+ }
74
+ }
75
+
76
+ export function disableTestingTheme() {
77
+ const isEnabled = document.body.classList.contains(testingThemeName);
78
+ if (isEnabled) {
79
+ document.body.classList.remove(testingThemeName);
80
+ document.body.style.removeProperty(testingColorVariableName);
81
+ }
82
+ }
83
+
84
+ // Export for NPM bundle, for which Webpack automatically puts those functions under AJS.DesignTokens
85
+ export const {
86
+ setGlobalTheme,
87
+ token,
88
+ themeObjectToString,
89
+ themeStringToObject,
90
+ getTokenValue
91
+ } = Tokens;
92
+
93
+ // Export for p2-plugin bundle, where we need to do put those functions under AJS.DesignTokens manually
94
+ globalize('DesignTokens', {
95
+ setGlobalTheme,
96
+ token,
97
+ themeObjectToString,
98
+ themeStringToObject,
99
+ getTokenValue,
100
+ toggleTestingTheme,
101
+ enableTestingTheme,
102
+ disableTestingTheme,
103
+ setTestingThemeColor
104
+ });
@@ -6,6 +6,10 @@ import {getMessageLogger} from './internal/deprecation'
6
6
 
7
7
  const CLASS_NOTIFICATION_INITIALISED = '_aui-form-notification-initialised';
8
8
 
9
+ const ARIA_INFO_ATTRIBUTE = 'aria-describedby';
10
+ const ARIA_DESCRIPTION_POSTFIX = 'description';
11
+ const ARIA_ERROR_POSTFIX = 'errors';
12
+
9
13
  const ATTRIBUTE_NOTIFICATION_PREFIX = 'data-aui-notification-';
10
14
  const ATTRIBUTE_NOTIFICATION_WAIT = ATTRIBUTE_NOTIFICATION_PREFIX + 'wait';
11
15
  const ATTRIBUTE_NOTIFICATION_INFO = ATTRIBUTE_NOTIFICATION_PREFIX + 'info';
@@ -37,9 +41,16 @@ function prepareFieldMarkup($field) {
37
41
 
38
42
  function appendDescription($field, message) {
39
43
  message = message ? message : getNotificationMessage($field);
44
+
40
45
  if (getFieldNotificationType($field) === ATTRIBUTE_NOTIFICATION_INFO) {
41
- $field.after(descriptionTemplate(message))
46
+ const existingDescription = $field.parent().find('.description');
47
+
48
+ if (!existingDescription.length) {
49
+ $field.after(descriptionTemplate($field, message))
50
+ }
42
51
  }
52
+
53
+ updateAriaInfo($field);
43
54
  }
44
55
 
45
56
  function getNotificationMessage($field) {
@@ -59,7 +70,7 @@ function jsonToArray(jsonOrString) {
59
70
  }
60
71
 
61
72
  function getFieldNotificationType($field) {
62
- var fieldNotificationType;
73
+ let fieldNotificationType;
63
74
  NOTIFICATION_PRIORITY.some(function (prioritisedNotification) {
64
75
  if ($field.is('[' + prioritisedNotification + ']')) {
65
76
  fieldNotificationType = prioritisedNotification;
@@ -94,25 +105,46 @@ function synchroniseNotificationDisplay(field) {
94
105
  }
95
106
  }
96
107
 
108
+ function updateAriaInfo($field) {
109
+ const labels = [];
110
+ const id = $field.attr('id') || $field.attr('name');
111
+ const type = getFieldNotificationType($field);
112
+ const message = getNotificationMessage($field);
113
+
114
+ if (message && type === ATTRIBUTE_NOTIFICATION_ERROR) {
115
+ labels.push(`${id}-${ARIA_ERROR_POSTFIX}`);
116
+ }
117
+
118
+ if (getMessageContainer($field, 'description').length) {
119
+ labels.push(`${id}-${ARIA_DESCRIPTION_POSTFIX}`);
120
+ }
121
+
122
+ $field.attr(ARIA_INFO_ATTRIBUTE, !!labels.length ? labels.join(' ') : null);
123
+ }
124
+
97
125
  function isJqueryObject(el) {
98
126
  return el.constructor.prototype.hasOwnProperty('jquery');
99
127
  }
100
128
 
101
- function errorMessageTemplate(messages) {
102
- let list = messages
103
- .map(message => `<li><span class="aui-icon aui-icon-small aui-iconfont-error aui-icon-notification">${message}</span>${message}</li>`)
129
+ function errorMessageTemplate($field, messages) {
130
+ const id = $field.attr('id') || $field.attr('name');
131
+ const list = messages
132
+ .map(message => `<li><span class="aui-icon aui-icon-small aui-iconfont-error aui-icon-notification"></span>${message}</li>`)
104
133
  .join('');
105
- return `<div class="error"><ul>${list}</ul></div>`;
134
+
135
+ return `<div class="error" id="${id}-${ARIA_ERROR_POSTFIX}"><ul>${list}</ul></div>`;
106
136
  }
107
137
 
108
- function descriptionTemplate(messages) {
138
+ function descriptionTemplate($field, messages) {
139
+ const id = $field.attr('id') || $field.attr('name');
140
+
109
141
  if (messages.length > 1) {
110
142
  let list = messages
111
143
  .map(message => `<li>${message}</li>`)
112
144
  .join('');
113
- return `<div class="description"><ul>${list}</ul></div>`;
145
+ return `<div class="description" id="${id}-${ARIA_DESCRIPTION_POSTFIX}"><ul>${list}</ul></div>`;
114
146
  }
115
- return `<div class="description">${messages}</div>`;
147
+ return `<div class="description" id="${id}-${ARIA_DESCRIPTION_POSTFIX}">${messages}</div>`;
116
148
  }
117
149
 
118
150
  function appendErrorMessages($field, messages) {
@@ -120,7 +152,8 @@ function appendErrorMessages($field, messages) {
120
152
  if (previousErrors.length > 0) {
121
153
  previousErrors.remove();
122
154
  }
123
- $field.after(errorMessageTemplate(messages));
155
+ $field.after(errorMessageTemplate($field, messages));
156
+ updateAriaInfo($field);
124
157
  }
125
158
 
126
159
  function getMessageContainer($field, type) {
@@ -165,6 +198,7 @@ export {
165
198
  getMessageContainer,
166
199
  appendErrorMessages,
167
200
  appendDescription,
201
+ updateAriaInfo,
168
202
  errorMessageTemplate,
169
203
  setFieldSpinner
170
204
  }
@@ -1,6 +1,12 @@
1
1
  import $ from './jquery';
2
2
  import './form-notification';
3
- import {appendDescription, appendErrorMessages, getMessageContainer, setFieldSpinner} from './form-notification';
3
+ import {
4
+ appendDescription,
5
+ appendErrorMessages,
6
+ getMessageContainer,
7
+ setFieldSpinner,
8
+ updateAriaInfo
9
+ } from './form-notification';
4
10
  import './form-validation/basic-validators';
5
11
  import amdify from './internal/amdify';
6
12
  import * as deprecate from './internal/deprecation';
@@ -241,6 +247,7 @@ function removeFieldNotification($field, type) {
241
247
  $field.removeAttr(ATTRIBUTE_NOTIFICATION_PREFIX + type);
242
248
  if (type === 'error') {
243
249
  getMessageContainer($field, type).remove();
250
+ updateAriaInfo($field);
244
251
  }
245
252
  }
246
253
 
@@ -8,7 +8,7 @@ function initNamespace() {
8
8
  }
9
9
 
10
10
  /**
11
- * Makes given value available globally under window[name] attribute.
11
+ * Makes given value available globally under window[NAMESPACE][name] attribute.
12
12
  * Keep in mind that this is needed for p2-plugin where chunks of AUI
13
13
  * can be loaded separately.
14
14
  *
@@ -12,19 +12,19 @@ import '../../js-vendor/jquery/plugins/jquery.select2';
12
12
  * way, calling code will be able to call $thing.select2() as if they were calling the original library,
13
13
  * and ADG styling will just magically happen.
14
14
  */
15
- var originalSelect2 = $.fn.select2;
15
+ const originalSelect2 = $.fn.select2;
16
16
 
17
17
  // AUI-specific classes
18
- var auiContainer = 'aui-select2-container';
19
- var auiDropdown = 'aui-select2-drop aui-dropdown2';
20
- var auiHasAvatar = 'aui-has-avatar';
18
+ const auiContainer = 'aui-select2-container';
19
+ const auiDropdown = 'aui-select2-drop aui-dropdown2';
20
+ const auiHasAvatar = 'aui-has-avatar';
21
21
 
22
22
  $.fn.auiSelect2 = function (first) {
23
- var updatedArgs;
23
+ let updatedArgs;
24
24
 
25
25
  if ($.isPlainObject(first)) {
26
- var auiOpts = $.extend({}, first);
27
- var auiAvatarClass = auiOpts.hasAvatar ? ' ' + auiHasAvatar : '';
26
+ const auiOpts = $.extend({}, first);
27
+ const auiAvatarClass = auiOpts.hasAvatar ? ' ' + auiHasAvatar : '';
28
28
  //add our classes in addition to those the caller specified
29
29
  auiOpts.containerCssClass = auiContainer + auiAvatarClass + (auiOpts.containerCssClass ? ' ' + auiOpts.containerCssClass : '');
30
30
  auiOpts.dropdownCssClass = auiDropdown + auiAvatarClass + (auiOpts.dropdownCssClass ? ' ' + auiOpts.dropdownCssClass : '');
@@ -39,5 +39,55 @@ $.fn.auiSelect2 = function (first) {
39
39
  updatedArgs = arguments;
40
40
  }
41
41
 
42
- return originalSelect2.apply(this, updatedArgs);
42
+ const result = originalSelect2.apply(this, updatedArgs);
43
+ const select2Instance = this;
44
+ const searchLabel = updatedArgs[0].searchLabel;
45
+
46
+ select2Instance.on('select2-open', function () {
47
+ const $selectInput = $(this);
48
+
49
+ if (updatedArgs[0].multiple || $selectInput.attr('multiple')) {
50
+ // This is a multi-select, exiting
51
+ return;
52
+ }
53
+
54
+ const $selectDropdown = $selectInput.select2('dropdown')
55
+
56
+ if (searchLabel) {
57
+ $selectDropdown.find('.select2-search label').text(searchLabel);
58
+ }
59
+
60
+ // AUI-5461: when single select dropdown opens up, the first option is
61
+ // instantly focused, making SRs announce it, while skipping the search field
62
+ $selectDropdown.find('.select2-search .select2-input').attr('aria-activedescendant', '');
63
+ });
64
+
65
+ select2Instance.on('select2-focus', function () {
66
+ const $selectInput = $(this);
67
+ const $container = $selectInput.parent().find('.select2-container');
68
+
69
+ if (updatedArgs[0].multiple || $selectInput.attr('multiple')) {
70
+ if (searchLabel) {
71
+ $container.find('.select2-search-field label').text(searchLabel);
72
+ }
73
+
74
+ return;
75
+ }
76
+
77
+ const $focusserLabel = $container.find('label');
78
+ if ($focusserLabel.attr('id')) {
79
+ // The id is already assigned, exiting
80
+ return;
81
+ }
82
+
83
+ // AUI-5462: when single select is initialized, the selected option container is
84
+ // linked to the button via aria-labelledby, preventing SRs from reading its label
85
+ const $focusserInput = $container.find('.select2-focusser');
86
+ const labelId = $focusserInput.attr('id') + '-label';
87
+ const ariaLabelledby = $focusserInput.attr('aria-labelledby');
88
+ $focusserLabel.attr('id', labelId);
89
+ $focusserInput.attr('aria-labelledby', labelId + ' ' + ariaLabelledby);
90
+ });
91
+
92
+ return result;
43
93
  };
@@ -52,7 +52,7 @@ const formAttributeHandler = {
52
52
  }
53
53
  };
54
54
 
55
- var idAttributeHandler = {
55
+ const idAttributeHandler = {
56
56
  removed: removedAttributeHandler.bind(this, 'id'),
57
57
  fallback: function (element, change) {
58
58
  const val = `${change.newValue}${INPUT_SUFFIX}`;
@@ -60,7 +60,7 @@ var idAttributeHandler = {
60
60
  }
61
61
  };
62
62
 
63
- var valueAttributeHandler = {
63
+ const valueAttributeHandler = {
64
64
  removed: function(element) {
65
65
  removedAttributeHandler.call(this, 'value', element);
66
66
  // Internet Explorer 11 has a bug where it doesn't clear out the previous value
@@ -72,7 +72,7 @@ var valueAttributeHandler = {
72
72
  }
73
73
  };
74
74
 
75
- var checkedAttributeHandler = {
75
+ const checkedAttributeHandler = {
76
76
  removed: function (element) {
77
77
  getInput(element).checked = false;
78
78
  },
@@ -81,7 +81,7 @@ var checkedAttributeHandler = {
81
81
  }
82
82
  };
83
83
 
84
- var labelHandler = {
84
+ const labelHandler = {
85
85
  removed: function (element) {
86
86
  getInput(element).removeAttribute('aria-label');
87
87
  },
@@ -91,7 +91,7 @@ var labelHandler = {
91
91
  };
92
92
 
93
93
  function clickHandler(element, e) {
94
- var input = getInput(element);
94
+ const input = getInput(element);
95
95
  if (!element.disabled && !element.busy && e.target !== input) {
96
96
  input.checked = !input.checked;
97
97
  fireChangeEvent(element);
@@ -140,7 +140,7 @@ const ToggleEl = skate('aui-toggle', {
140
140
  // (which prevents our click handler from being called),
141
141
  // while allow the element to still participate in the form.
142
142
  template: skateTemplateHtml(
143
- '<input type="checkbox" class="aui-toggle-input assistive">',
143
+ '<input type="checkbox" role="switch" class="aui-toggle-input assistive">',
144
144
  '<span class="aui-toggle-view">',
145
145
  '<span class="aui-toggle-tick aui-icon aui-icon-small aui-iconfont-success"></span>',
146
146
  '<span class="aui-toggle-cross aui-icon aui-icon-small aui-iconfont-close-dialog"></span>',
@@ -57,8 +57,9 @@ class Tooltip {
57
57
  this.triggerElement = triggerElement;
58
58
  this.$triggerElement = $(this.triggerElement);
59
59
  this.options = { ...defaultOptions, ...options };
60
- this.enabled = this.options.enabled
61
- this.moveTitleToTooltip()
60
+ this.enabled = this.options.enabled;
61
+ this.moveTitleToTooltip();
62
+ this.initContainer();
62
63
  }
63
64
 
64
65
  destroy() {
@@ -96,13 +97,15 @@ class Tooltip {
96
97
  this.$triggerElement.off(`.${pluginKey}`);
97
98
  }
98
99
 
99
- buildTip(title) {
100
- const options = this.options;
100
+ initContainer() {
101
101
  if ($sharedTip === undefined || $sharedTip.get(0) && !$sharedTip.get(0).isConnected) {
102
102
  $sharedTip = $(`<div id="${AUI_TOOLTIP_ID}" class="${AUI_TOOLTIP_CLASS_NAME} assistive" role="tooltip"><p class="aui-tooltip-content"></p></div>`);
103
103
  $(document.body).append($sharedTip);
104
104
  }
105
+ }
105
106
 
107
+ buildTip(title) {
108
+ const options = this.options;
106
109
  const tooltipContentElement = $sharedTip.find('.aui-tooltip-content');
107
110
 
108
111
  if (options.html) {
@@ -140,10 +143,14 @@ class Tooltip {
140
143
  return;
141
144
  }
142
145
 
143
- this.hide();
146
+ // In order to avoid flickering of the tooltip when we have the same content we need to skip hiding.
147
+ const isNewTooltip = $sharedTip && tipTitle !== $sharedTip.text();
148
+ if (isNewTooltip) {
149
+ this.hide();
150
+ }
151
+
144
152
  const triggerElement = this.triggerElement;
145
153
  const placement = GRAVITY_MAP[this.options.gravity];
146
- clearTimeout(this.popperTimeout);
147
154
 
148
155
  if (typeof this.options.suppress === 'function') {
149
156
  if (this.options.suppress.call(triggerElement) === true) {
@@ -152,34 +159,32 @@ class Tooltip {
152
159
  }
153
160
 
154
161
  const tipNode = this.buildTip(tipTitle).get(0);
155
- this.popperTimeout = setTimeout(() => {
156
- this.showTooltip();
157
-
158
- this.popperInstance = createPopper(triggerElement, tipNode, {
159
- placement,
160
- modifiers: [
161
- {
162
- name: 'offset',
163
- options: {
164
- offset: [0, 4],
165
- },
166
- },
167
- ],
168
- });
169
162
 
170
- $(window).on(`scroll.${pluginKey}`, () => this.hide());
171
- }, AUI_TOOLTIP_TIMEOUT);
163
+ this.showTooltip();
164
+
165
+ this.popperInstance = createPopper(triggerElement, tipNode, {
166
+ placement,
167
+ modifiers: [
168
+ {
169
+ name: 'offset',
170
+ options: {
171
+ offset: [0, 4],
172
+ },
173
+ },
174
+ ],
175
+ });
172
176
 
177
+ $(window).on(`scroll.${pluginKey}`, () => this.hide());
173
178
  }
174
179
 
175
180
  hide() {
176
181
  this.hideTooltip();
177
- clearTimeout(this.popperTimeout);
178
182
 
179
183
  if (this.popperInstance) {
180
184
  this.popperInstance.destroy();
181
185
  delete this.popperInstance;
182
186
  }
187
+
183
188
  $(window).off(`scroll.${pluginKey}`);
184
189
  }
185
190
 
@@ -221,6 +226,8 @@ const namespacify = events => events.map(event => `${event}.${pluginKey}`).join(
221
226
 
222
227
  const activationEvents = namespacify(['mouseenter', 'focus']);
223
228
  const deactivationEvents = namespacify(['click', 'mouseleave', 'blur']);
229
+ let showTimeoutId;
230
+ let hideTimeoutId;
224
231
 
225
232
  $.fn.tooltip = function (arg) {
226
233
  // We have an actual jQuery collection available under `this`
@@ -246,16 +253,47 @@ $.fn.tooltip = function (arg) {
246
253
  return $collection;
247
254
  }
248
255
 
249
- const options = arg || {}
256
+ const options = arg || {};
257
+
258
+ const clearAllTimers = function () {
259
+ clearTimeout(hideTimeoutId);
260
+ clearTimeout(showTimeoutId);
261
+ };
262
+
263
+ const updateTooltipEvents = function () {
264
+ $sharedTip.off(`mouseenter.${pluginKey}`);
265
+ $sharedTip.off(`mouseleave.${pluginKey}`);
266
+
267
+ $sharedTip.on(`mouseenter.${pluginKey}`, () => {
268
+ clearAllTimers();
269
+ });
270
+ $sharedTip.on(`mouseleave.${pluginKey}`, () => {
271
+ clearAllTimers();
272
+ hide();
273
+ });
274
+ }
250
275
 
251
276
  const show = function () {
277
+ // Stop all events that were triggered by different tooltip
278
+ clearAllTimers();
279
+
252
280
  const tooltip = getTooltipInstance(this, options);
253
- tooltip.show();
281
+ showTimeoutId = setTimeout(() => {
282
+ clearAllTimers();
283
+ tooltip.show();
284
+ $sharedTip && updateTooltipEvents();
285
+ }, AUI_TOOLTIP_TIMEOUT);
286
+
254
287
  }
255
288
 
256
289
  const hide = function () {
290
+ // Stop all events that were triggered by different tooltip
291
+ clearAllTimers();
292
+
257
293
  const tooltip = getTooltipInstance(this, options);
258
- tooltip.hide();
294
+ hideTimeoutId = setTimeout(() => {
295
+ tooltip.hide();
296
+ }, AUI_TOOLTIP_TIMEOUT);
259
297
  }
260
298
 
261
299
  const selector = options.live;
@@ -131,3 +131,11 @@ css('.aui-dropdown2-tailed', {
131
131
  removeInVersion: '10.0.0',
132
132
  extraInfo: 'ADGS does not include tails on layered components'
133
133
  })
134
+
135
+ // 9.7.0
136
+ css('form.aui .multi-select', {
137
+ sinceVersion: '9.7.0',
138
+ displayName: 'Multi-select',
139
+ removeInVersion: '11.0.0',
140
+ extraInfo: 'Default browser behavior for selecing items is non-intuitive and non-accessible. Use Select2 instead.'
141
+ });
@@ -28,11 +28,10 @@
28
28
  --aui-message-padding: 10px;
29
29
  --aui-message-gutter: 40px;
30
30
  --aui-message-isize: @aui-icon-size-small;
31
- // AUI-5192: currentColor is quoted to work around Edge 18 bug.
32
- --aui-focus: 'currentcolor';
33
- --aui-link-color: 'currentcolor';
34
- --aui-link-hover-color: 'currentcolor';
35
- --aui-link-active-color: 'currentcolor';
31
+ --aui-focus: currentcolor;
32
+ --aui-link-color: currentcolor;
33
+ --aui-link-hover-color: currentcolor;
34
+ --aui-link-active-color: currentcolor;
36
35
  border-radius: 0;
37
36
  box-shadow: none;
38
37
  margin-top: 0;
@@ -9,8 +9,7 @@
9
9
  border: 0;
10
10
  border-radius: @aui-border-radius-smallish;
11
11
  cursor: pointer;
12
- // AUI-5192: currentColor is quoted to work around Edge 18 bug.
13
- color: var(--aui-close-button-icon-color, 'currentcolor');
12
+ color: var(--aui-close-button-icon-color, currentcolor);
14
13
  height: @aui-close-button-size;
15
14
  width: @aui-close-button-size;
16
15
  line-height: 100%;
@@ -3,7 +3,7 @@
3
3
  .aui-tooltip {
4
4
  background-color: var(--aui-tooltip-bg-color);
5
5
  padding: 2px 6px;
6
- pointer-events: none;
6
+
7
7
  z-index: @aui-z-tooltip;
8
8
  border-radius: @aui-border-radius-small;
9
9
  font-size: @aui-font-size-small;
@@ -37,7 +37,7 @@ aui-spinner {
37
37
  left: 0;
38
38
  animation: 0.86s cubic-bezier(0.4, 0.15, 0.6, 0.85) infinite spinnerRotateAnimation;
39
39
  fill: none;
40
- stroke: currentColor;
40
+ stroke: currentcolor;
41
41
  stroke-dasharray: calc(@size * 2.8);
42
42
  stroke-dashoffset: calc(@size * 2.25);
43
43
  stroke-linecap: round;
@@ -31,8 +31,6 @@
31
31
 
32
32
  @radio-unchecked-bg-color: var(--aui-form-radio-unchecked-bg-color);
33
33
  @radio-unchecked-border-color: var(--aui-form-radio-unchecked-border-color);
34
- @radio-unchecked-hover-bg-color: var(--aui-form-radio-unchecked-hover-bg-color);
35
- @radio-unchecked-hover-border-color: var(--aui-form-radio-unchecked-hover-border-color);
36
34
  @radio-checked-bg-color: var(--aui-form-glyph-fill-color);
37
35
  @radio-disabled-bg-color: var(--aui-form-glyph-disabled-icon-color);
38
36
  @radio-disabled-border-color: var(--aui-form-glyph-disabled-fill-color);
@@ -116,7 +116,7 @@
116
116
  .aui-subtle-button-style(normal) {
117
117
  --aui-btn-bg: var(--aui-button-subtle-bg-color, transparent);
118
118
  --aui-btn-border: var(--aui-button-subtle-border-color, transparent);
119
- --aui-btn-text: var(--aui-button-subtle-text-color, currentColor);
119
+ --aui-btn-text: var(--aui-button-subtle-text-color, currentcolor);
120
120
  }
121
121
 
122
122
  .aui-link-button-style(normal) {
@@ -18,7 +18,6 @@
18
18
  @aui-form-select-bg-color: var(--aui-form-select-bg-color);
19
19
  @aui-form-select-border-color: var(--aui-form-select-border-color);
20
20
  @aui-form-select-hover-bg-color: var(--aui-form-select-hover-bg-color);
21
- @aui-form-checkbox-radio-hover-bg-color: var(--aui-form-checkbox-radio-hover-bg-color);
22
21
  @aui-form-checkbox-radio-active-bg-color: var(--aui-form-checkbox-radio-active-bg-color);
23
22
  @aui-form-optgroup-text-color: var(--aui-form-optgroup-text-color);
24
23
  @aui-form-optgroup-bg-color: var(--aui-form-optgroup-bg-color);