@atlaskit/emoji 67.2.1 → 67.3.1

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 (99) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/cjs/api/EmojiResource.js +6 -0
  3. package/dist/cjs/components/common/DeletableEmojiTooltipContent.js +34 -0
  4. package/dist/cjs/components/common/DeleteButton.js +2 -1
  5. package/dist/cjs/components/common/Emoji.js +94 -81
  6. package/dist/cjs/components/common/EmojiActions.js +8 -6
  7. package/dist/cjs/components/common/EmojiDeletePreview.js +19 -6
  8. package/dist/cjs/components/common/EmojiErrorMessage.js +13 -5
  9. package/dist/cjs/components/common/EmojiRadioButton.js +1 -0
  10. package/dist/cjs/components/common/EmojiUploadPicker.js +30 -29
  11. package/dist/cjs/components/common/EmojiUploadPreview.js +12 -5
  12. package/dist/cjs/components/common/FileChooser.js +7 -1
  13. package/dist/cjs/components/common/RetryableButton.js +9 -3
  14. package/dist/cjs/components/common/ToolTipContentWithKeymap.js +25 -0
  15. package/dist/cjs/components/common/styles.js +50 -20
  16. package/dist/cjs/components/i18n.js +17 -2
  17. package/dist/cjs/components/picker/CategorySelector.js +2 -1
  18. package/dist/cjs/components/picker/CategoryTracker.js +5 -0
  19. package/dist/cjs/components/picker/EmojiPickerComponent.js +12 -6
  20. package/dist/cjs/components/picker/EmojiPickerList.js +49 -8
  21. package/dist/cjs/components/picker/EmojiPickerListSearch.js +4 -1
  22. package/dist/cjs/components/picker/VirtualList.js +8 -3
  23. package/dist/cjs/{util → hooks}/useInView.js +3 -2
  24. package/dist/cjs/util/browser-support.js +11 -3
  25. package/dist/cjs/util/constants.js +4 -1
  26. package/dist/cjs/util/keymaps.js +55 -0
  27. package/dist/cjs/version.json +1 -1
  28. package/dist/es2019/api/EmojiResource.js +6 -0
  29. package/dist/es2019/components/common/DeletableEmojiTooltipContent.js +27 -0
  30. package/dist/es2019/components/common/DeleteButton.js +2 -1
  31. package/dist/es2019/components/common/Emoji.js +90 -72
  32. package/dist/es2019/components/common/EmojiActions.js +9 -7
  33. package/dist/es2019/components/common/EmojiDeletePreview.js +17 -7
  34. package/dist/es2019/components/common/EmojiErrorMessage.js +10 -4
  35. package/dist/es2019/components/common/EmojiRadioButton.js +1 -0
  36. package/dist/es2019/components/common/EmojiUploadPicker.js +32 -27
  37. package/dist/es2019/components/common/EmojiUploadPreview.js +9 -5
  38. package/dist/es2019/components/common/FileChooser.js +7 -1
  39. package/dist/es2019/components/common/RetryableButton.js +9 -3
  40. package/dist/es2019/components/common/ToolTipContentWithKeymap.js +15 -0
  41. package/dist/es2019/components/common/styles.js +44 -16
  42. package/dist/es2019/components/i18n.js +17 -2
  43. package/dist/es2019/components/picker/CategorySelector.js +2 -1
  44. package/dist/es2019/components/picker/CategoryTracker.js +3 -0
  45. package/dist/es2019/components/picker/EmojiPickerComponent.js +12 -6
  46. package/dist/es2019/components/picker/EmojiPickerList.js +48 -8
  47. package/dist/es2019/components/picker/EmojiPickerListSearch.js +3 -1
  48. package/dist/es2019/components/picker/VirtualList.js +7 -3
  49. package/dist/es2019/{util → hooks}/useInView.js +2 -2
  50. package/dist/es2019/util/browser-support.js +9 -1
  51. package/dist/es2019/util/constants.js +2 -0
  52. package/dist/es2019/util/keymaps.js +43 -0
  53. package/dist/es2019/version.json +1 -1
  54. package/dist/esm/api/EmojiResource.js +6 -0
  55. package/dist/esm/components/common/DeletableEmojiTooltipContent.js +25 -0
  56. package/dist/esm/components/common/DeleteButton.js +2 -1
  57. package/dist/esm/components/common/Emoji.js +94 -82
  58. package/dist/esm/components/common/EmojiActions.js +9 -7
  59. package/dist/esm/components/common/EmojiDeletePreview.js +17 -7
  60. package/dist/esm/components/common/EmojiErrorMessage.js +11 -4
  61. package/dist/esm/components/common/EmojiRadioButton.js +1 -0
  62. package/dist/esm/components/common/EmojiUploadPicker.js +32 -31
  63. package/dist/esm/components/common/EmojiUploadPreview.js +9 -5
  64. package/dist/esm/components/common/FileChooser.js +7 -1
  65. package/dist/esm/components/common/RetryableButton.js +9 -3
  66. package/dist/esm/components/common/ToolTipContentWithKeymap.js +14 -0
  67. package/dist/esm/components/common/styles.js +43 -17
  68. package/dist/esm/components/i18n.js +17 -2
  69. package/dist/esm/components/picker/CategorySelector.js +2 -1
  70. package/dist/esm/components/picker/CategoryTracker.js +5 -0
  71. package/dist/esm/components/picker/EmojiPickerComponent.js +12 -6
  72. package/dist/esm/components/picker/EmojiPickerList.js +49 -8
  73. package/dist/esm/components/picker/EmojiPickerListSearch.js +4 -1
  74. package/dist/esm/components/picker/VirtualList.js +8 -3
  75. package/dist/esm/{util → hooks}/useInView.js +2 -2
  76. package/dist/esm/util/browser-support.js +9 -1
  77. package/dist/esm/util/constants.js +2 -0
  78. package/dist/esm/util/keymaps.js +43 -0
  79. package/dist/esm/version.json +1 -1
  80. package/dist/types/components/common/DeletableEmojiTooltipContent.d.ts +6 -0
  81. package/dist/types/components/common/Emoji.d.ts +6 -0
  82. package/dist/types/components/common/EmojiErrorMessage.d.ts +1 -0
  83. package/dist/types/components/common/FileChooser.d.ts +1 -0
  84. package/dist/types/components/common/RetryableButton.d.ts +2 -1
  85. package/dist/types/components/common/ToolTipContentWithKeymap.d.ts +9 -0
  86. package/dist/types/components/common/styles.d.ts +6 -2
  87. package/dist/types/components/i18n.d.ts +15 -0
  88. package/dist/types/components/picker/CategoryTracker.d.ts +1 -0
  89. package/dist/types/components/picker/EmojiPickerList.d.ts +8 -1
  90. package/dist/types/components/picker/EmojiPickerListSearch.d.ts +1 -0
  91. package/dist/types/components/picker/VirtualList.d.ts +21 -1
  92. package/dist/types/types.d.ts +1 -1
  93. package/dist/types/util/browser-support.d.ts +6 -1
  94. package/dist/types/util/constants.d.ts +3 -1
  95. package/dist/types/util/keymaps.d.ts +14 -0
  96. package/dist/types/util/type-helpers.d.ts +1 -1
  97. package/package.json +2 -2
  98. package/report.api.md +16 -1
  99. /package/dist/types/{util → hooks}/useInView.d.ts +0 -0
@@ -13,12 +13,15 @@ import { Component } from 'react';
13
13
  import { jsx } from '@emotion/react';
14
14
  import { FormattedMessage, injectIntl } from 'react-intl-next';
15
15
  import AkButton from '@atlaskit/button/custom-theme-button';
16
+ import FocusLock from 'react-focus-lock';
16
17
  import { messages } from '../i18n';
17
18
  import CachingEmoji from './CachingEmoji';
18
- import EmojiErrorMessage from './EmojiErrorMessage';
19
+ import EmojiErrorMessage, { emojiErrorScreenreaderTestId } from './EmojiErrorMessage';
19
20
  import RetryableButton from './RetryableButton';
20
- import { cancelButton, deleteFooter, deletePreview, deleteText, emojiDeleteErrorMessage, previewButtonGroup } from './styles';
21
+ import { cancelButton, deleteFooter, deletePreview, deleteText, emojiDeleteErrorMessage, headingH5, previewButtonGroup } from './styles';
22
+ import VisuallyHidden from '@atlaskit/visually-hidden';
21
23
  export var emojiDeletePreviewTestId = 'emoji-delete-preview';
24
+ var deleteEmojiLabelId = 'fabric.emoji.delete.label.id';
22
25
  var EmojiDeletePreview = /*#__PURE__*/function (_Component) {
23
26
  _inherits(EmojiDeletePreview, _Component);
24
27
  var _super = _createSuper(EmojiDeletePreview);
@@ -75,12 +78,16 @@ var EmojiDeletePreview = /*#__PURE__*/function (_Component) {
75
78
  loading = _this$state.loading,
76
79
  error = _this$state.error;
77
80
  var formatMessage = intl.formatMessage;
78
- return jsx("div", {
81
+ return jsx(FocusLock, {
82
+ noFocusGuards: true
83
+ }, jsx("div", {
79
84
  css: deletePreview,
80
85
  "data-testid": emojiDeletePreviewTestId
81
86
  }, jsx("div", {
82
87
  css: deleteText
83
- }, jsx("h5", null, jsx(FormattedMessage, messages.deleteEmojiTitle)), jsx(FormattedMessage, _extends({}, messages.deleteEmojiDescription, {
88
+ }, jsx("h2", {
89
+ css: headingH5
90
+ }, jsx(FormattedMessage, messages.deleteEmojiTitle)), jsx(FormattedMessage, _extends({}, messages.deleteEmojiDescription, {
84
91
  values: {
85
92
  emojiShortName: emoji.shortName
86
93
  }
@@ -94,17 +101,20 @@ var EmojiDeletePreview = /*#__PURE__*/function (_Component) {
94
101
  message: formatMessage(messages.deleteEmojiFailed),
95
102
  messageStyles: emojiDeleteErrorMessage,
96
103
  tooltip: true
97
- }) : null : null, jsx(RetryableButton, {
104
+ }) : null : null, jsx(VisuallyHidden, {
105
+ id: deleteEmojiLabelId
106
+ }, formatMessage(messages.deleteEmojiLabel)), jsx(RetryableButton, {
98
107
  label: formatMessage(messages.deleteEmojiLabel),
99
108
  onSubmit: this.onSubmit,
100
109
  appearance: "danger",
101
110
  loading: loading,
102
- error: error
111
+ error: error,
112
+ ariaLabelledBy: "".concat(emojiErrorScreenreaderTestId, " ").concat(deleteEmojiLabelId)
103
113
  }), jsx(AkButton, {
104
114
  appearance: "subtle",
105
115
  onClick: this.onCancel,
106
116
  css: cancelButton
107
- }, jsx(FormattedMessage, messages.cancelLabel)))));
117
+ }, jsx(FormattedMessage, messages.cancelLabel))))));
108
118
  }
109
119
  }]);
110
120
  return EmojiDeletePreview;
@@ -4,6 +4,9 @@ import { jsx } from '@emotion/react';
4
4
  import Tooltip from '@atlaskit/tooltip';
5
5
  import ErrorIcon from '@atlaskit/icon/glyph/error';
6
6
  import VisuallyHidden from '@atlaskit/visually-hidden';
7
+ import { FormattedMessage, useIntl } from 'react-intl-next';
8
+ import { messages } from '../i18n';
9
+ export var emojiErrorScreenreaderTestId = 'emoji-error-screenreader-message';
7
10
  export var emojiErrorMessageTestId = 'emoji-error-message';
8
11
  export var emojiErrorMessageTooltipTestId = 'emoji-error-message-tooltip';
9
12
  export var emojiErrorIconTestId = 'emoji-error-icon';
@@ -11,6 +14,8 @@ var EmojiErrorMessage = function EmojiErrorMessage(props) {
11
14
  var messageStyles = props.messageStyles,
12
15
  message = props.message,
13
16
  tooltip = props.tooltip;
17
+ var _useIntl = useIntl(),
18
+ formatMessage = _useIntl.formatMessage;
14
19
  var visualContent = tooltip ? jsx("div", {
15
20
  css: messageStyles,
16
21
  "data-testid": emojiErrorMessageTestId
@@ -19,18 +24,20 @@ var EmojiErrorMessage = function EmojiErrorMessage(props) {
19
24
  position: "top",
20
25
  testId: emojiErrorMessageTooltipTestId
21
26
  }, jsx(ErrorIcon, {
22
- label: "Error",
27
+ label: formatMessage(messages.error),
23
28
  size: "medium",
24
29
  testId: emojiErrorIconTestId
25
30
  }))) : jsx("div", {
26
31
  css: messageStyles,
27
32
  "data-testid": emojiErrorMessageTestId
28
33
  }, jsx(ErrorIcon, {
29
- label: "Error",
34
+ label: formatMessage(messages.error),
30
35
  size: "small"
31
36
  }), message);
32
37
  return jsx(Fragment, null, jsx(VisuallyHidden, {
33
- role: "alert"
34
- }, message), visualContent);
38
+ id: emojiErrorScreenreaderTestId
39
+ }, jsx(FormattedMessage, messages.error, function (errMsg) {
40
+ return jsx("span", null, errMsg, " ", message, ".");
41
+ })), visualContent);
35
42
  };
36
43
  export default EmojiErrorMessage;
@@ -17,6 +17,7 @@ var handleKeyPress = function handleKeyPress(props, event) {
17
17
  if (TONESELECTOR_KEYBOARD_KEYS_SUPPORTED.includes(event.key)) {
18
18
  var onSelected = props.onSelected;
19
19
  event.preventDefault();
20
+ event.stopPropagation();
20
21
  if (onSelected) {
21
22
  onSelected();
22
23
  }
@@ -2,7 +2,7 @@ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
2
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
3
  import _regeneratorRuntime from "@babel/runtime/regenerator";
4
4
  /** @jsx jsx */
5
- import { Fragment, useEffect, useState, useRef, memo, useCallback, useMemo } from 'react';
5
+ import { Fragment, useEffect, useLayoutEffect, useState, useRef, memo, useCallback } from 'react';
6
6
  import { jsx } from '@emotion/react';
7
7
  import { FormattedMessage, injectIntl } from 'react-intl-next';
8
8
  import TextField from '@atlaskit/textfield';
@@ -12,14 +12,15 @@ import FocusLock from 'react-focus-lock';
12
12
  import * as ImageUtil from '../../util/image';
13
13
  import debug from '../../util/logger';
14
14
  import { messages } from '../i18n';
15
- import EmojiErrorMessage from './EmojiErrorMessage';
15
+ import EmojiErrorMessage, { emojiErrorScreenreaderTestId } from './EmojiErrorMessage';
16
16
  import EmojiUploadPreview from './EmojiUploadPreview';
17
17
  import FileChooser from './FileChooser';
18
18
  import { UploadStatus } from './internal-types';
19
- import { closeEmojiUploadButton, emojiChooseFileErrorMessage, emojiUpload, emojiUploadBottom, emojiUploadTop, uploadChooseFileBrowse, uploadChooseFileEmojiName, uploadChooseFileMessage, uploadChooseFileRow } from './styles';
19
+ import { closeEmojiUploadButton, emojiChooseFileErrorMessage, emojiUpload, emojiUploadBottom, emojiUploadTop, headingH5, requiredSymbol, uploadChooseFileBrowse, uploadChooseFileEmojiName, uploadChooseFileMessage, uploadChooseFileRow } from './styles';
20
20
  export var uploadEmojiNameInputTestId = 'upload-emoji-name-input';
21
21
  export var uploadEmojiComponentTestId = 'upload-emoji-component';
22
22
  export var cancelEmojiUploadPickerTestId = 'cancel-emoji-upload-picker';
23
+ var addCustomEmojiChooseFileScreenreaderId = 'fabric.emoji.choose.file.label.id';
23
24
  var disallowedReplacementsMap = new Map([[':', ''], ['!', ''], ['@', ''], ['#', ''], ['%', ''], ['^', ''], ['&', ''], ['*', ''], ['(', ''], [')', ''], [' ', '_']]);
24
25
  var sanitizeName = function sanitizeName(name) {
25
26
  // prevent / replace certain characters, allow others
@@ -51,18 +52,12 @@ var ChooseEmojiFile = /*#__PURE__*/memo(function (props) {
51
52
  onUploadCancelled();
52
53
  }
53
54
  }, [onUploadCancelled]);
54
- var setInputFocus = useCallback(function () {
55
- var _inputRef$current, _document$activeEleme, _inputRef$current2;
56
- (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.focus();
57
- if (((_document$activeEleme = document.activeElement) === null || _document$activeEleme === void 0 ? void 0 : _document$activeEleme.id) !== ((_inputRef$current2 = inputRef.current) === null || _inputRef$current2 === void 0 ? void 0 : _inputRef$current2.id)) {
58
- setInputFocus();
59
- }
55
+ useLayoutEffect(function () {
56
+ requestAnimationFrame(function () {
57
+ var _inputRef$current;
58
+ (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.focus();
59
+ });
60
60
  }, []);
61
-
62
- // make sure input has focus after update
63
- useEffect(function () {
64
- window.requestAnimationFrame(setInputFocus);
65
- }, [setInputFocus]);
66
61
  var cancelLabel = formatMessage(messages.cancelLabel);
67
62
  var emojiPlaceholder = formatMessage(messages.emojiPlaceholder);
68
63
  var emojiNameAriaLabel = formatMessage(messages.emojiNameAriaLabel);
@@ -72,11 +67,12 @@ var ChooseEmojiFile = /*#__PURE__*/memo(function (props) {
72
67
  "data-testid": uploadEmojiComponentTestId
73
68
  }, jsx("div", {
74
69
  css: emojiUploadTop
75
- }, jsx("span", {
76
- css: uploadChooseFileMessage
77
- }, jsx(FormattedMessage, messages.addCustomEmojiLabel, function (message) {
78
- return jsx("h5", null, message);
79
- })), jsx("div", {
70
+ }, jsx("h2", {
71
+ css: [uploadChooseFileMessage, headingH5]
72
+ }, jsx(FormattedMessage, messages.addCustomEmojiLabel), jsx("span", {
73
+ "aria-hidden": "true",
74
+ css: requiredSymbol
75
+ }, "*")), jsx("div", {
80
76
  css: closeEmojiUploadButton
81
77
  }, jsx(AkButton, {
82
78
  onClick: onUploadCancelled,
@@ -103,19 +99,24 @@ var ChooseEmojiFile = /*#__PURE__*/memo(function (props) {
103
99
  autoFocus: true,
104
100
  testId: uploadEmojiNameInputTestId,
105
101
  ref: inputRef,
106
- id: "new-emoji-name-input"
102
+ id: "new-emoji-name-input",
103
+ "aria-required": true
107
104
  })), jsx("span", {
108
105
  css: uploadChooseFileBrowse
109
106
  }, jsx(FormattedMessage, messages.emojiChooseFileScreenReaderDescription, function (screenReaderDescription) {
110
107
  return jsx(Fragment, null, jsx("span", {
111
108
  hidden: true,
112
109
  id: fileChooserButtonDescriptionId
113
- }, screenReaderDescription), jsx(FileChooser, {
110
+ }, screenReaderDescription), jsx("span", {
111
+ hidden: true,
112
+ id: addCustomEmojiChooseFileScreenreaderId
113
+ }, emojiChooseFileTitle), jsx(FileChooser, {
114
114
  label: emojiChooseFileTitle,
115
115
  onChange: onChooseFile,
116
116
  onClick: onClick,
117
117
  accept: "image/png,image/jpeg,image/gif",
118
118
  ariaDescribedBy: fileChooserButtonDescriptionId,
119
+ ariaLabelledBy: "".concat(emojiErrorScreenreaderTestId, " ").concat(addCustomEmojiChooseFileScreenreaderId),
119
120
  isDisabled: disableChooser
120
121
  }));
121
122
  }))), jsx("div", {
@@ -126,7 +127,7 @@ var ChooseEmojiFile = /*#__PURE__*/memo(function (props) {
126
127
  })));
127
128
  });
128
129
  var EmojiUploadPicker = function EmojiUploadPicker(props) {
129
- var _document$activeEleme2;
130
+ var _document$activeEleme;
130
131
  var errorMessage = props.errorMessage,
131
132
  initialUploadName = props.initialUploadName,
132
133
  onUploadEmoji = props.onUploadEmoji,
@@ -154,7 +155,7 @@ var EmojiUploadPicker = function EmojiUploadPicker(props) {
154
155
  previewImage = _useState10[0],
155
156
  setPreviewImage = _useState10[1];
156
157
  // document is undefined during ssr rendering and throws an error
157
- var lastFocusedElementId = useRef(typeof document !== 'undefined' ? (_document$activeEleme2 = document.activeElement) === null || _document$activeEleme2 === void 0 ? void 0 : _document$activeEleme2.id : '');
158
+ var lastFocusedElementId = useRef(typeof document !== 'undefined' ? (_document$activeEleme = document.activeElement) === null || _document$activeEleme === void 0 ? void 0 : _document$activeEleme.id : '');
158
159
  useEffect(function () {
159
160
  if (errorMessage) {
160
161
  setUploadStatus(UploadStatus.Error);
@@ -217,7 +218,7 @@ var EmojiUploadPicker = function EmojiUploadPicker(props) {
217
218
  }, []);
218
219
  var errorOnUpload = useCallback(function (event) {
219
220
  debug('File load error: ', event);
220
- setChooseEmojiErrorMessage(messages.emojiUploadFailed);
221
+ setChooseEmojiErrorMessage(jsx(FormattedMessage, messages.emojiUploadFailed));
221
222
  cancelChooseFile();
222
223
  }, [cancelChooseFile]);
223
224
  var onFileLoad = useCallback(function (file) {
@@ -238,7 +239,7 @@ var EmojiUploadPicker = function EmojiUploadPicker(props) {
238
239
  case 7:
239
240
  _context.prev = 7;
240
241
  _context.t0 = _context["catch"](0);
241
- setChooseEmojiErrorMessage(messages.emojiInvalidImage);
242
+ setChooseEmojiErrorMessage(jsx(FormattedMessage, messages.emojiInvalidImage));
242
243
  cancelChooseFile();
243
244
  case 11:
244
245
  case "end":
@@ -258,7 +259,7 @@ var EmojiUploadPicker = function EmojiUploadPicker(props) {
258
259
  var reader = new FileReader();
259
260
  var file = files[0];
260
261
  if (ImageUtil.hasFileExceededSize(file)) {
261
- setChooseEmojiErrorMessage(messages.emojiImageTooBig);
262
+ setChooseEmojiErrorMessage(jsx(FormattedMessage, messages.emojiImageTooBig));
262
263
  cancelChooseFile();
263
264
  return;
264
265
  }
@@ -282,9 +283,9 @@ var EmojiUploadPicker = function EmojiUploadPicker(props) {
282
283
  }
283
284
  }, 0, lastFocusedElementId.current);
284
285
  }, [clearUploadPicker, onUploadCancelled]);
285
- var chooseErrorMessage = useMemo(function () {
286
- return chooseEmojiErrorMessage ? jsx(FormattedMessage, chooseEmojiErrorMessage) : undefined;
287
- }, [chooseEmojiErrorMessage]);
286
+ var onChooseFileClicked = function onChooseFileClicked() {
287
+ onFileChooserClicked && onFileChooserClicked();
288
+ };
288
289
  return jsx(FocusLock, {
289
290
  noFocusGuards: true
290
291
  }, name && previewImage ? jsx(EmojiUploadPreview, {
@@ -297,10 +298,10 @@ var EmojiUploadPicker = function EmojiUploadPicker(props) {
297
298
  }) : jsx(ChooseEmojiFile, {
298
299
  name: name,
299
300
  onChooseFile: onChooseFile,
300
- onClick: onFileChooserClicked,
301
+ onClick: onChooseFileClicked,
301
302
  onNameChange: onNameChange,
302
303
  onUploadCancelled: cancelUpload,
303
- errorMessage: chooseErrorMessage,
304
+ errorMessage: chooseEmojiErrorMessage,
304
305
  intl: intl
305
306
  }));
306
307
  };
@@ -14,14 +14,15 @@ import { FormattedMessage, injectIntl } from 'react-intl-next';
14
14
  import { customCategory } from '../../util/constants';
15
15
  import { messages } from '../i18n';
16
16
  import Emoji from './Emoji';
17
- import EmojiErrorMessage from './EmojiErrorMessage';
17
+ import EmojiErrorMessage, { emojiErrorScreenreaderTestId } from './EmojiErrorMessage';
18
18
  import { UploadStatus } from './internal-types';
19
19
  import RetryableButton from './RetryableButton';
20
20
  import { bigEmojiPreview, cancelButton, emojiPreviewErrorMessage, uploadAddRow, uploadPreview, uploadPreviewFooter, uploadPreviewText } from './styles';
21
21
  import VisuallyHidden from '@atlaskit/visually-hidden';
22
22
  export var uploadPreviewTestId = 'upload-preview';
23
23
  export var cancelUploadButtonTestId = 'cancel-upload-button';
24
- var addEmojiButtonDescriptionId = 'add.emoji.button.screen.reader.description.id';
24
+ var addEmojiPreviewDescriptionId = 'fabric.emoji.preview.description.id';
25
+ var addEmojiButtonLabelId = 'fabric.emoji.add.label.id';
25
26
  var EmojiUploadPreview = /*#__PURE__*/function (_PureComponent) {
26
27
  _inherits(EmojiUploadPreview, _PureComponent);
27
28
  var _super = _createSuper(EmojiUploadPreview);
@@ -79,18 +80,21 @@ var EmojiUploadPreview = /*#__PURE__*/function (_PureComponent) {
79
80
  message: errorMessage,
80
81
  tooltip: true
81
82
  }) : null, !errorMessage && jsx(VisuallyHidden, {
82
- id: addEmojiButtonDescriptionId
83
+ id: addEmojiPreviewDescriptionId
83
84
  }, jsx(FormattedMessage, _extends({}, messages.emojiPreview, {
84
85
  values: {
85
86
  emoji: name
86
87
  }
87
- }))), jsx(RetryableButton, {
88
+ }))), jsx(VisuallyHidden, {
89
+ id: addEmojiButtonLabelId
90
+ }, errorMessage ? formatMessage(messages.retryLabel) : formatMessage(messages.addEmojiLabel)), jsx(RetryableButton, {
88
91
  label: formatMessage(messages.addEmojiLabel),
89
92
  onSubmit: onAddEmoji,
90
93
  appearance: "primary",
91
94
  loading: uploading,
92
95
  error: !!errorMessage,
93
- ariaDescribedby: addEmojiButtonDescriptionId
96
+ ariaDescribedBy: addEmojiPreviewDescriptionId,
97
+ ariaLabelledBy: "".concat(emojiErrorScreenreaderTestId, " ").concat(addEmojiButtonLabelId)
94
98
  }), jsx(AkButton, {
95
99
  onClick: onUploadCancelled,
96
100
  appearance: "subtle",
@@ -5,12 +5,15 @@ export var fileUploadInputTestId = 'file-upload';
5
5
  var FileChooser = function FileChooser(props) {
6
6
  var accept = props.accept,
7
7
  ariaDescribedBy = props.ariaDescribedBy,
8
+ ariaLabelledBy = props.ariaLabelledBy,
8
9
  isDisabled = props.isDisabled,
9
10
  label = props.label,
10
11
  onChange = props.onChange,
11
12
  onClick = props.onClick;
12
13
  var filePickerRef = useRef(null);
14
+ var fileButtonRef = useRef(null);
13
15
  var handleOnChooseFile = function handleOnChooseFile() {
16
+ var _fileButtonRef$curren;
14
17
  if (!filePickerRef.current) {
15
18
  return;
16
19
  }
@@ -18,12 +21,15 @@ var FileChooser = function FileChooser(props) {
18
21
  onClick();
19
22
  }
20
23
  filePickerRef.current.click();
24
+ (_fileButtonRef$curren = fileButtonRef.current) === null || _fileButtonRef$curren === void 0 ? void 0 : _fileButtonRef$curren.focus();
21
25
  };
22
26
  return /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(AkButton, {
23
27
  onClick: handleOnChooseFile,
24
28
  isDisabled: isDisabled,
25
29
  "aria-describedby": ariaDescribedBy,
26
- testId: chooseFileButtonTestId
30
+ "aria-labelledby": ariaLabelledBy,
31
+ testId: chooseFileButtonTestId,
32
+ ref: fileButtonRef
27
33
  }, label), /*#__PURE__*/React.createElement("input", {
28
34
  className: "emojiUploadFileInput",
29
35
  ref: filePickerRef,
@@ -14,13 +14,17 @@ var LoadingSpinner = function LoadingSpinner() {
14
14
  }, jsx(Spinner, null));
15
15
  };
16
16
  var RetryButton = function RetryButton(props) {
17
- var onSubmit = props.onSubmit;
17
+ var onSubmit = props.onSubmit,
18
+ ariaLabelledBy = props.ariaLabelledBy,
19
+ ariaDescribedBy = props.ariaDescribedBy;
18
20
  return jsx(FormattedMessage, messages.retryLabel, function (retryLabel) {
19
21
  return jsx(AkButton, {
20
22
  css: uploadRetryButton,
21
23
  appearance: "warning",
22
24
  onClick: onSubmit,
23
25
  testId: retryUploadButtonTestId,
26
+ "aria-describedby": ariaDescribedBy,
27
+ "aria-labelledby": ariaLabelledBy,
24
28
  autoFocus: true
25
29
  }, retryLabel);
26
30
  });
@@ -29,13 +33,15 @@ var UploadButton = function UploadButton(props) {
29
33
  var appearance = props.appearance,
30
34
  onSubmit = props.onSubmit,
31
35
  label = props.label,
32
- ariaDescribedby = props.ariaDescribedby;
36
+ ariaLabelledBy = props.ariaLabelledBy,
37
+ ariaDescribedBy = props.ariaDescribedBy;
33
38
  return jsx(AkButton, {
34
39
  css: uploadEmojiButton,
35
40
  appearance: appearance,
36
41
  onClick: onSubmit,
37
42
  testId: uploadEmojiButtonTestId,
38
- "aria-describedby": ariaDescribedby,
43
+ "aria-describedby": ariaDescribedBy,
44
+ "aria-labelledby": ariaLabelledBy,
39
45
  autoFocus: true
40
46
  }, label);
41
47
  };
@@ -0,0 +1,14 @@
1
+ /** @jsx jsx */
2
+ import React, { Fragment } from 'react';
3
+ import { jsx } from '@emotion/react';
4
+ import { formatShortcut } from '../../util/keymaps';
5
+ import { tooltipShortcutStyle } from './styles';
6
+ export var ToolTipContentWithKeymap = /*#__PURE__*/React.memo(function (_ref) {
7
+ var description = _ref.description,
8
+ shortcutOverride = _ref.shortcutOverride,
9
+ keymap = _ref.keymap;
10
+ var shortcut = shortcutOverride || keymap && formatShortcut(keymap);
11
+ return shortcut || description ? jsx(Fragment, null, description, shortcut && description && "\xA0", shortcut && jsx("span", {
12
+ css: tooltipShortcutStyle
13
+ }, shortcut)) : null;
14
+ });
@@ -4,7 +4,8 @@ var _css, _css2, _templateObject, _span, _css3, _css6, _input;
4
4
  import { css, keyframes } from '@emotion/react';
5
5
  import { defaultEmojiHeight } from '../../util/constants';
6
6
  import { akEmojiSelectedBackgroundColor } from '../../util/shared-styles';
7
- import { B100, N20, N200, N20A, N300, N900, R300, R400 } from '@atlaskit/theme/colors';
7
+ import { B100, N20, N200, N20A, N300, N400, N900, R300, R400 } from '@atlaskit/theme/colors';
8
+ import { fontFamily as getFontFamily, gridSize as getGridSize } from '@atlaskit/theme/constants';
8
9
  export var commonSelectedStyles = 'emoji-common-selected';
9
10
  export var selectOnHoverStyles = 'emoji-common-select-on-hover';
10
11
  export var emojiSprite = 'emoji-common-emoji-sprite';
@@ -12,18 +13,15 @@ export var emojiNodeStyles = 'emoji-common-node';
12
13
  export var emojiImage = 'emoji-common-emoji-image';
13
14
  export var emojiDeleteButton = 'emoji-common-deleteButton';
14
15
  export var emojiMainStyle = 'emoji-common-main-styles';
16
+ export var deletableEmoji = 'emoji-common-deletable';
15
17
  export var deleteButton = css({
16
18
  // hide by default
17
19
  visibility: 'hidden',
18
20
  display: 'flex',
19
- height: '0px',
20
- // 40px emoji width with 2px left offset
21
- width: '38px',
22
- alignItems: 'flex-end',
23
- justifyContent: 'flex-end',
24
- // vertically align button and prevent emoji offset
25
- paddingTop: '4px',
26
- marginBottom: '-4px'
21
+ position: 'absolute',
22
+ top: '-8px',
23
+ right: '-8px',
24
+ zIndex: 1
27
25
  });
28
26
  export var emojiToneSelectorContainer = css({
29
27
  flex: 1,
@@ -31,7 +29,7 @@ export var emojiToneSelectorContainer = css({
31
29
  justifyContent: 'flex-end',
32
30
  padding: '10px 10px 11px 0'
33
31
  });
34
- export var emojiStyles = css((_css = {
32
+ export var emojiImageContainer = css((_css = {
35
33
  borderRadius: "var(--ds-radius-100, 3px)",
36
34
  backgroundColor: 'transparent',
37
35
  display: 'inline-block',
@@ -39,20 +37,25 @@ export var emojiStyles = css((_css = {
39
37
  // Ensure along with vertical align middle, we don't increase the line height for p and some
40
38
  // headings. Smaller headings get a slight increase in height, cannot add more negative margin
41
39
  // as a "selected" emoji (e.g. in the editor) will not look good.
42
- margin: '-1px 0'
40
+ margin: '-1px 0',
41
+ img: {
42
+ display: 'block'
43
+ }
43
44
  }, _defineProperty(_css, "&.".concat(commonSelectedStyles, ",&.").concat(selectOnHoverStyles, ":hover"), {
44
45
  backgroundColor: akEmojiSelectedBackgroundColor
45
46
  }), _defineProperty(_css, "&.".concat(commonSelectedStyles, ",&.").concat(selectOnHoverStyles, ":hover .").concat(emojiDeleteButton), {
46
47
  // show delete button on hover
47
48
  visibility: 'visible'
48
- }), _defineProperty(_css, "img", {
49
- display: 'block'
49
+ }), _defineProperty(_css, "&.".concat(deletableEmoji), {
50
+ position: 'relative'
51
+ }), _defineProperty(_css, "&.".concat(deletableEmoji, ":focus-within .").concat(emojiDeleteButton), {
52
+ visibility: 'visible'
50
53
  }), _defineProperty(_css, '&:focus', {
51
54
  boxShadow: "0 0 0 2px ".concat("var(--ds-border-focused, ".concat(B100, ")")),
52
55
  transitionDuration: '0s, 0.2s',
53
56
  outline: 'none'
54
57
  }), _css));
55
- export var emojiContainer = css((_css2 = {
58
+ export var emojiSpriteContainer = css((_css2 = {
56
59
  display: 'inline-block',
57
60
  // Ensure along with vertical align middle, we don't increase the line height for h1..h6, and p
58
61
  margin: '-1px 0'
@@ -185,12 +188,12 @@ export var previewImg = css((_css6 = {
185
188
  display: 'inline-block',
186
189
  flex: 'initial',
187
190
  width: '32px'
188
- }, _defineProperty(_css6, "& .".concat(emojiSprite, ", > span"), {
191
+ }, _defineProperty(_css6, "& .".concat(emojiSprite, ", span[role=\"img\"]"), {
189
192
  width: '32px',
190
193
  height: '32px',
191
194
  padding: 0,
192
195
  maxHeight: 'inherit'
193
- }), _defineProperty(_css6, "& > span > img", {
196
+ }), _defineProperty(_css6, "& span[role=\"img\"] > img", {
194
197
  position: 'relative',
195
198
  left: '50%',
196
199
  top: '50%',
@@ -230,7 +233,9 @@ export var emojiUploadTop = css({
230
233
  fontSize: '12px'
231
234
  });
232
235
  export var uploadChooseFileMessage = css({
233
- color: "var(--ds-text-subtle, ".concat(N300, ")")
236
+ '&&': {
237
+ color: "var(--ds-text-subtle, ".concat(N300, ")")
238
+ }
234
239
  });
235
240
  export var closeEmojiUploadButton = css({
236
241
  display: 'flex'
@@ -321,6 +326,19 @@ export var deleteText = css({
321
326
  lineHeight: '16px'
322
327
  }
323
328
  });
329
+ export var headingH5 = css({
330
+ '&&': {
331
+ fontSize: "var(--ds-font-size-075, 12px)",
332
+ fontWeight: "var(--ds-font-weight-semibold, 600)",
333
+ letterSpacing: '-0.003em',
334
+ lineHeight: "var(--ds-font-lineHeight-100, 16px)"
335
+ }
336
+ });
337
+ export var requiredSymbol = css({
338
+ paddingLeft: "".concat(getGridSize() / 4, "px"),
339
+ color: "var(--ds-text-danger, ".concat(R400, ")"),
340
+ fontFamily: getFontFamily()
341
+ });
324
342
  export var previewButtonGroup = css({
325
343
  display: 'flex'
326
344
  });
@@ -390,4 +408,12 @@ export var emojiActionsWrapper = css({
390
408
  display: 'flex',
391
409
  justifyContent: 'flex-end',
392
410
  alignItems: 'center'
411
+ });
412
+ export var tooltipShortcutStyle = css({
413
+ borderRadius: '3px',
414
+ backgroundColor: "var(--ds-background-inverse-subtle, ".concat(N400, ")"),
415
+ padding: '0 2px',
416
+ /* TODO: fix in develop: https://atlassian.slack.com/archives/CFG3PSQ9E/p1647395052443259?thread_ts=1647394572.556029&cid=CFG3PSQ9E */
417
+ /* stylelint-disable-next-line */
418
+ label: 'tooltip-shortcut'
393
419
  });
@@ -1,5 +1,15 @@
1
1
  import { defineMessages } from 'react-intl-next';
2
2
  export var messages = defineMessages({
3
+ deleteEmojiTooltip: {
4
+ id: 'fabric.emoji.delete.tooltip',
5
+ defaultMessage: 'Delete',
6
+ description: 'Tooltip content for delete emoji when focus on deletable emoji'
7
+ },
8
+ deleteEmojiTooltipForScreenreader: {
9
+ id: 'fabric.emoji.delete.screenreader.tooltip',
10
+ defaultMessage: 'To delete {shortName} emoji, press Backspace',
11
+ description: 'Tooltip content for delete emoji when focus on deletable emoji'
12
+ },
3
13
  deleteEmojiTitle: {
4
14
  id: 'fabric.emoji.delete.title',
5
15
  defaultMessage: 'Remove emoji',
@@ -37,7 +47,7 @@ export var messages = defineMessages({
37
47
  },
38
48
  emojiChooseFileScreenReaderDescription: {
39
49
  id: 'fabric.emoji.choose.file.screenReaderDescription',
40
- defaultMessage: 'Choose a file for the emoji. JPG, PNG or GIF. Max size 1 MB.',
50
+ defaultMessage: 'Choose a file for the emoji. JPG, PNG or GIF. Max size 1 MB',
41
51
  description: 'Message indicating the purpose of choosing the file and requirements for the file'
42
52
  },
43
53
  emojiSelectSkinToneButtonAriaLabelText: {
@@ -102,7 +112,7 @@ export var messages = defineMessages({
102
112
  },
103
113
  categoriesSelectorLabel: {
104
114
  id: 'fabric.emoji.categories.label',
105
- defaultMessage: 'Choose a emoji category',
115
+ defaultMessage: 'Choose an emoji category',
106
116
  description: 'Aria label for Emoji categories selector at the top of emoji picker'
107
117
  },
108
118
  categoriesSearchResults: {
@@ -209,5 +219,10 @@ export var messages = defineMessages({
209
219
  id: 'fabric.emoji.emojipicker.emoi.roledescription',
210
220
  defaultMessage: 'emoji button',
211
221
  description: "Aria roledescription for emoji button, used in emoji picker."
222
+ },
223
+ error: {
224
+ id: 'fabric.emoji.emojipicker.error',
225
+ defaultMessage: 'Error!',
226
+ description: "Aria label for error icon, apperaed in emoji uploader screens and delete emoji screens of emoji picker"
212
227
  }
213
228
  });
@@ -62,6 +62,7 @@ var CategorySelector = function CategorySelector(props) {
62
62
  return;
63
63
  }
64
64
  e.preventDefault();
65
+ e.stopPropagation();
65
66
  var lastCategoryIndex = categories.length - 1;
66
67
  switch (e.key) {
67
68
  // navigate to the right category
@@ -123,7 +124,7 @@ var CategorySelector = function CategorySelector(props) {
123
124
  "data-focus-index": index,
124
125
  "aria-label": categoryName,
125
126
  "aria-controls": currentFocus === index ? RENDER_EMOJI_PICKER_LIST_TESTID : undefined,
126
- "aria-selected": currentFocus === index ? true : false,
127
+ "aria-selected": categoryId === activeCategoryId,
127
128
  css: categoryClasses,
128
129
  disabled: disableCategories,
129
130
  onClick: handleClick(categoryId, index),
@@ -30,6 +30,11 @@ var CategoryTracker = /*#__PURE__*/function () {
30
30
  value: function getRow(category) {
31
31
  return this.categoryToRow.get(category);
32
32
  }
33
+ }, {
34
+ key: "getFirstCategory",
35
+ value: function getFirstCategory() {
36
+ return this.rowToCategory.get(0);
37
+ }
33
38
  }]);
34
39
  return CategoryTracker;
35
40
  }();