@atlaskit/emoji 70.10.14 → 70.11.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 (32) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/components/common/Emoji.js +43 -2
  3. package/dist/cjs/components/common/EmojiPreviewComponent.js +4 -1
  4. package/dist/cjs/components/common/EmojiRadioButton.js +3 -1
  5. package/dist/cjs/components/common/EmojiUploadPicker.js +19 -0
  6. package/dist/cjs/components/common/TonePreviewButton.js +5 -2
  7. package/dist/cjs/components/i18n.js +5 -0
  8. package/dist/cjs/components/picker/EmojiPickerEmojiRow.js +3 -1
  9. package/dist/cjs/util/analytics/analytics.js +1 -1
  10. package/dist/es2019/components/common/Emoji.js +46 -3
  11. package/dist/es2019/components/common/EmojiPreviewComponent.js +4 -1
  12. package/dist/es2019/components/common/EmojiRadioButton.js +3 -1
  13. package/dist/es2019/components/common/EmojiUploadPicker.js +17 -0
  14. package/dist/es2019/components/common/TonePreviewButton.js +5 -2
  15. package/dist/es2019/components/i18n.js +5 -0
  16. package/dist/es2019/components/picker/EmojiPickerEmojiRow.js +3 -1
  17. package/dist/es2019/util/analytics/analytics.js +1 -1
  18. package/dist/esm/components/common/Emoji.js +44 -3
  19. package/dist/esm/components/common/EmojiPreviewComponent.js +4 -1
  20. package/dist/esm/components/common/EmojiRadioButton.js +3 -1
  21. package/dist/esm/components/common/EmojiUploadPicker.js +19 -0
  22. package/dist/esm/components/common/TonePreviewButton.js +5 -2
  23. package/dist/esm/components/i18n.js +5 -0
  24. package/dist/esm/components/picker/EmojiPickerEmojiRow.js +3 -1
  25. package/dist/esm/util/analytics/analytics.js +1 -1
  26. package/dist/types/components/common/Emoji.d.ts +2 -1
  27. package/dist/types/components/common/EmojiRadioButton.d.ts +1 -1
  28. package/dist/types/components/i18n.d.ts +5 -0
  29. package/dist/types-ts4.5/components/common/Emoji.d.ts +2 -1
  30. package/dist/types-ts4.5/components/common/EmojiRadioButton.d.ts +1 -1
  31. package/dist/types-ts4.5/components/i18n.d.ts +5 -0
  32. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @atlaskit/emoji
2
2
 
3
+ ## 70.11.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`f9457ee7bd8fc`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/f9457ee7bd8fc) -
8
+ Add file type validation to emoji picker.
9
+ - Updated dependencies
10
+
11
+ ## 70.11.0
12
+
13
+ ### Minor Changes
14
+
15
+ - [`447e1bfc88d10`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/447e1bfc88d10) -
16
+ Add UnicodeEmoji component for rendering emojis using Unicode representation. Update
17
+ EmojiNodeWrapper to support unicode type. Add fitToHeight support to EmojiPreviewComponent,
18
+ EmojiRadioButton, TonePreviewButton, and EmojiPickerEmojiRow.
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies
23
+
3
24
  ## 70.10.14
4
25
 
5
26
  ### Patch Changes
@@ -6,7 +6,7 @@ var _typeof = require("@babel/runtime/helpers/typeof");
6
6
  Object.defineProperty(exports, "__esModule", {
7
7
  value: true
8
8
  });
9
- exports.default = exports.SpriteEmoji = exports.ImageEmoji = exports.EmojiNodeWrapper = exports.Emoji = void 0;
9
+ exports.default = exports.UnicodeEmoji = exports.SpriteEmoji = exports.ImageEmoji = exports.EmojiNodeWrapper = exports.Emoji = void 0;
10
10
  require("./Emoji.compiled.css");
11
11
  var _runtime = require("@compiled/react/runtime");
12
12
  var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
@@ -36,6 +36,10 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbol
36
36
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
37
37
  var emojiSpriteContainer = null;
38
38
  var emojiImageContainer = null;
39
+
40
+ // Unicode emojis render as text inside a <span>, not an <img>, so they do not need
41
+ // borderRadius (which would clip a background on hover) or the img { display: block } rule.
42
+ var emojiUnicodeContainer = null;
39
43
  var handleMouseDown = function handleMouseDown(props, event) {
40
44
  // Clicked emoji delete button
41
45
  if (event.target instanceof Element && event.target.getAttribute('aria-label') === _constants.deleteEmojiLabel) {
@@ -145,6 +149,40 @@ var SpriteEmoji = exports.SpriteEmoji = function SpriteEmoji(props) {
145
149
  }))
146
150
  );
147
151
  };
152
+ var UnicodeEmoji = exports.UnicodeEmoji = function UnicodeEmoji(props) {
153
+ var emoji = props.emoji,
154
+ fitToHeight = props.fitToHeight,
155
+ selected = props.selected,
156
+ selectOnHover = props.selectOnHover,
157
+ className = props.className;
158
+ var classes = "".concat(_styles.emojiNodeStyles, " ").concat(selected ? _styles.commonSelectedStyles : '', " ").concat(selectOnHover ? _styles.selectOnHoverStyles : '', " ").concat(className ? className : '');
159
+ var emojiText = emoji.representation.unicodeEmoji;
160
+ var size = fitToHeight !== null && fitToHeight !== void 0 ? fitToHeight : _constants.defaultEmojiHeight;
161
+ var style = {
162
+ display: 'inline-block',
163
+ // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
164
+ fontSize: "max(1em, ".concat(size, "px)"),
165
+ width: "max(1em, ".concat(size, "px)"),
166
+ height: "max(1em, ".concat(size, "px)"),
167
+ textAlign: 'center',
168
+ alignContent: 'center',
169
+ alignSelf: 'center',
170
+ // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
171
+ lineHeight: '0',
172
+ margin: '0',
173
+ padding: '0'
174
+ };
175
+ return (
176
+ /*#__PURE__*/
177
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
178
+ _react.default.createElement(EmojiNodeWrapper, (0, _extends2.default)({}, props, {
179
+ type: "unicode",
180
+ className: classes
181
+ }), /*#__PURE__*/_react.default.createElement("span", {
182
+ style: style
183
+ }, emojiText))
184
+ );
185
+ };
148
186
 
149
187
  // Keep as pure functional component, see renderAsSprite.
150
188
  var ImageEmoji = exports.ImageEmoji = function ImageEmoji(props) {
@@ -332,7 +370,7 @@ var EmojiNodeWrapper = exports.EmojiNodeWrapper = /*#__PURE__*/(0, _react.forwar
332
370
  "data-emoji-type": type,
333
371
  tabIndex: shouldBeInteractive ? tabIndex || 0 : undefined,
334
372
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
335
- className: (0, _runtime.ax)([type === 'sprite' ? "_19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _1e0c1o8l _jr50g2xd _ylp71o8l _pkaxgktf _1hdcgktf _109tnkob _tn8j1dpa _3naf1dpa _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc" : "_2rkofajl _19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _bfhk1j28 _1e0c1o8l _s7n4nkob _v4pn1ule _tn8j1dpa _3naf1dpa _160jewfl _1theewfl _1kogh2mm _qyp0ewfl _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc", className]),
373
+ className: (0, _runtime.ax)([type === 'sprite' ? "_19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _1e0c1o8l _jr50g2xd _ylp71o8l _pkaxgktf _1hdcgktf _109tnkob _tn8j1dpa _3naf1dpa _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc" : type === 'unicode' ? "_19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _bfhk1j28 _1e0c1o8l _s7n4nkob _tn8j1dpa _3naf1dpa _160jewfl _1theewfl _1kogh2mm _qyp0ewfl _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc" : "_2rkofajl _19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _bfhk1j28 _1e0c1o8l _s7n4nkob _v4pn1ule _tn8j1dpa _3naf1dpa _160jewfl _1theewfl _1kogh2mm _qyp0ewfl _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc", className]),
336
374
  onKeyDown: function onKeyDown(event) {
337
375
  return handleKeyDown(props, event);
338
376
  },
@@ -365,6 +403,9 @@ var Emoji = exports.Emoji = function Emoji(props) {
365
403
  }
366
404
  // eslint-disable-next-line react-hooks/exhaustive-deps
367
405
  }, []);
406
+ if ((0, _typeHelpers.isUnicodeRepresentation)(emoji.representation)) {
407
+ return /*#__PURE__*/_react.default.createElement(UnicodeEmoji, props);
408
+ }
368
409
  // TODO: We always prefer render as image as having accessibility issues with sprite representation
369
410
  if ((0, _typeHelpers.isSpriteRepresentation)(emoji.representation)) {
370
411
  return /*#__PURE__*/_react.default.createElement(SpriteEmoji, props);
@@ -10,6 +10,7 @@ exports.EmojiPreviewComponent = void 0;
10
10
  require("./EmojiPreviewComponent.compiled.css");
11
11
  var React = _interopRequireWildcard(require("react"));
12
12
  var _runtime = require("@compiled/react/runtime");
13
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
13
14
  var _CachingEmoji = _interopRequireDefault(require("./CachingEmoji"));
14
15
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
15
16
  var emojiName = null;
@@ -19,13 +20,15 @@ var previewImg = null;
19
20
  var previewText = null;
20
21
  var EmojiPreviewComponent = exports.EmojiPreviewComponent = function EmojiPreviewComponent(_ref) {
21
22
  var emoji = _ref.emoji;
23
+ var fitToHeight = (0, _platformFeatureFlags.fg)('platform_twemoji_removal_unicode_emojis') ? 32 : undefined;
22
24
  return /*#__PURE__*/React.createElement("div", {
23
25
  className: (0, _runtime.ax)(["_ca0q19bv _u5f319bv _n3td19bv _19bv19bv _1e0c1txw _2lx2vrvc _1n261q9c _4t3izwfg _4cvr1h6o"])
24
26
  }, /*#__PURE__*/React.createElement("span", {
25
27
  className: (0, _runtime.ax)(["_1e0c1o8l _1bsbzwfg _12s6idpf _1e4didpf _1dvqidpf _vwlxidpf _1gdiidpf _1f45idpf _pdfdidpf _mwo3idpf _5ilezwfg _boltzwfg _1pc7zwfg _u5wqzwfg _w7981kw7 _1vqe1kw7 _1l4xidpf _1l79idpf _118didpf _1pa4idpf _1pglh2mm _1vjf1ssb _1h6o1ssb _8fp6dbra _1os4zwfg _1e7azwfg _7mh21ule"])
26
28
  }, /*#__PURE__*/React.createElement(_CachingEmoji.default, {
27
29
  key: emoji.id || emoji.shortName,
28
- emoji: emoji
30
+ emoji: emoji,
31
+ fitToHeight: fitToHeight
29
32
  })), /*#__PURE__*/React.createElement("div", {
30
33
  className: (0, _runtime.ax)(["_1e0c1txw _2lx21bp4 _1wpz1h6o _19pk1i6y _18u019bv _p12f3sup _1bsb3sup _16jlkb7n _1o9zkb7n"])
31
34
  }, emoji.name && /*#__PURE__*/React.createElement("div", {
@@ -41,6 +41,7 @@ var EmojiRadioButton = exports.EmojiRadioButton = /*#__PURE__*/(0, _react.forwar
41
41
  selectOnHover = props.selectOnHover,
42
42
  ariaLabelText = props.ariaLabelText,
43
43
  defaultChecked = props.defaultChecked;
44
+ var fitToHeight = (0, _platformFeatureFlags.fg)('platform_twemoji_removal_unicode_emojis') ? 24 : undefined;
44
45
  return /*#__PURE__*/_react.default.createElement("label", {
45
46
  className: (0, _runtime.ax)(["_19itidpf _2rkofajl _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _bfhk1j28 _80omtlke _kqswh2mm _1e0c1o8l _lev4idpf _1cx6idpf _tyukidpf _2ewlidpf _11bcidpf _dqozglyw _1at812x7 _1cjo12x7 _1yg612x7 _hjaq12x7 _hlt21tcg _1s3c1tcg _1i911tcg _1ye71tcg"])
46
47
  }, /*#__PURE__*/_react.default.createElement(_visuallyHidden.default, null, ariaLabelText), /*#__PURE__*/_react.default.createElement("input", {
@@ -64,7 +65,8 @@ var EmojiRadioButton = exports.EmojiRadioButton = /*#__PURE__*/(0, _react.forwar
64
65
  emoji: emoji,
65
66
  selectOnHover: selectOnHover,
66
67
  shouldBeInteractive: false,
67
- "aria-hidden": true
68
+ "aria-hidden": true,
69
+ fitToHeight: fitToHeight
68
70
  }));
69
71
  });
70
72
  var _default_1 = /*#__PURE__*/(0, _react.memo)(EmojiRadioButton);
@@ -43,6 +43,8 @@ var uploadChooseFileEmojiName = null;
43
43
  var uploadChooseFileMessage = null;
44
44
  var uploadChooseFileRow = null;
45
45
  var uploadChooseFileRowNew = null;
46
+ var supportedEmojiUploadMimeTypes = new Set(['image/png', 'image/jpeg', 'image/gif']);
47
+ var supportedEmojiUploadExtensions = ['.png', '.jpg', '.jpeg', '.gif'];
46
48
  var uploadEmojiNameInputTestId = exports.uploadEmojiNameInputTestId = 'upload-emoji-name-input';
47
49
  var uploadEmojiComponentTestId = exports.uploadEmojiComponentTestId = 'upload-emoji-component';
48
50
  var cancelEmojiUploadPickerTestId = exports.cancelEmojiUploadPickerTestId = 'cancel-emoji-upload-picker';
@@ -59,6 +61,18 @@ var toEmojiName = function toEmojiName(uploadName) {
59
61
  var name = uploadName.split('_').join(' ');
60
62
  return "".concat(name.substr(0, 1).toLocaleUpperCase()).concat(name.substr(1));
61
63
  };
64
+ var isSupportedEmojiUploadFileType = function isSupportedEmojiUploadFileType(file) {
65
+ if (!(0, _platformFeatureFlags.fg)('platform_emoji_picker_refresh')) {
66
+ return true;
67
+ }
68
+ if (supportedEmojiUploadMimeTypes.has(file.type)) {
69
+ return true;
70
+ }
71
+ var lowerCaseFileName = file.name.toLowerCase();
72
+ return supportedEmojiUploadExtensions.some(function (extension) {
73
+ return lowerCaseFileName.endsWith(extension);
74
+ });
75
+ };
62
76
  var ChooseEmojiFile = /*#__PURE__*/(0, _react.memo)(function (props) {
63
77
  var _props$name = props.name,
64
78
  name = _props$name === void 0 ? '' : _props$name,
@@ -342,6 +356,11 @@ var EmojiUploadPicker = function EmojiUploadPicker(props) {
342
356
  if (files.length) {
343
357
  var reader = new FileReader();
344
358
  var file = files[0];
359
+ if (!isSupportedEmojiUploadFileType(file)) {
360
+ setChooseEmojiErrorMessage( /*#__PURE__*/React.createElement(_reactIntl.FormattedMessage, _i18n.messages.emojiUnsupportedFileType));
361
+ cancelChooseFile();
362
+ return;
363
+ }
345
364
  if (ImageUtil.hasFileExceededSize(file)) {
346
365
  setChooseEmojiErrorMessage( /*#__PURE__*/React.createElement(_reactIntl.FormattedMessage, _i18n.messages.emojiImageTooBig));
347
366
  cancelChooseFile();
@@ -26,6 +26,7 @@ var TonePreviewButton = exports.TonePreviewButton = /*#__PURE__*/(0, _react.forw
26
26
  onSelected = props.onSelected,
27
27
  _props$isVisible = props.isVisible,
28
28
  isVisible = _props$isVisible === void 0 ? true : _props$isVisible;
29
+ var fitToHeight = (0, _platformFeatureFlags.fg)('platform_twemoji_removal_unicode_emojis') ? 24 : undefined;
29
30
  return (0, _platformFeatureFlags.fg)('platform_emoji_picker_refresh') ? /*#__PURE__*/React.createElement("button", {
30
31
  ref: ref,
31
32
  onClick: onSelected,
@@ -44,7 +45,8 @@ var TonePreviewButton = exports.TonePreviewButton = /*#__PURE__*/(0, _react.forw
44
45
  emoji: emoji,
45
46
  selectOnHover: selectOnHover,
46
47
  shouldBeInteractive: false,
47
- "aria-hidden": true
48
+ "aria-hidden": true,
49
+ fitToHeight: fitToHeight
48
50
  })) : /*#__PURE__*/React.createElement("button", {
49
51
  ref: ref,
50
52
  onClick: onSelected,
@@ -63,7 +65,8 @@ var TonePreviewButton = exports.TonePreviewButton = /*#__PURE__*/(0, _react.forw
63
65
  emoji: emoji,
64
66
  selectOnHover: selectOnHover,
65
67
  shouldBeInteractive: false,
66
- "aria-hidden": true
68
+ "aria-hidden": true,
69
+ fitToHeight: fitToHeight
67
70
  }));
68
71
  });
69
72
  var _default_1 = /*#__PURE__*/(0, _react.memo)(TonePreviewButton);
@@ -221,6 +221,11 @@ var messages = exports.messages = (0, _reactIntl.defineMessages)({
221
221
  defaultMessage: 'Selected image is more than 1 MB',
222
222
  description: 'Error message for image too big, beyond the size limit'
223
223
  },
224
+ emojiUnsupportedFileType: {
225
+ id: 'fabric.emoji.error.unsupported.file.type',
226
+ defaultMessage: "This file type isn't supported. Select a PNG, JPEG, or GIF to create your emoji.",
227
+ description: 'Error message shown when the selected emoji upload file type is not supported'
228
+ },
224
229
  emojiDuplicateName: {
225
230
  id: 'fabric.emoji.error.duplicate.name',
226
231
  defaultMessage: 'An emoji with this name exists already',
@@ -37,6 +37,7 @@ var EmojiPickerEmojiRow = function EmojiPickerEmojiRow(_ref) {
37
37
  var rowIndex = (virtualItemContext === null || virtualItemContext === void 0 ? void 0 : virtualItemContext.index) || 0;
38
38
  var _useIntl = (0, _reactIntl.useIntl)(),
39
39
  formatMessage = _useIntl.formatMessage;
40
+ var fitToHeight = (0, _platformFeatureFlags.fg)('platform_twemoji_removal_unicode_emojis') ? 24 : undefined;
40
41
  var handleFocus = function handleFocus(index) {
41
42
  return function (emojiId, emoji, event) {
42
43
  setEmojisFocus({
@@ -103,7 +104,8 @@ var EmojiPickerEmojiRow = function EmojiPickerEmojiRow(_ref) {
103
104
  "data-focus-index": "".concat(rowIndex, "-").concat(index),
104
105
  tabIndex: focus ? 0 : -1,
105
106
  "aria-roledescription": formatMessage(_i18n.messages.emojiButtonRoleDescription),
106
- shouldBeInteractive: true
107
+ shouldBeInteractive: true,
108
+ fitToHeight: fitToHeight
107
109
  }));
108
110
  }));
109
111
  };
@@ -20,7 +20,7 @@ var createEvent = function createEvent(eventType, action, actionSubject, actionS
20
20
  actionSubjectId: actionSubjectId,
21
21
  attributes: _objectSpread({
22
22
  packageName: "@atlaskit/emoji",
23
- packageVersion: "70.10.13"
23
+ packageVersion: "70.11.0"
24
24
  }, attributes)
25
25
  };
26
26
  };
@@ -5,8 +5,8 @@ import { ax, ix } from "@compiled/react/runtime";
5
5
  import React, { useEffect, useCallback, useMemo, forwardRef } from 'react';
6
6
  import Tooltip from '@atlaskit/tooltip';
7
7
  import { shouldUseAltRepresentation } from '../../api/EmojiUtils';
8
- import { deleteEmojiLabel, EMOJI_KEYBOARD_KEYS_SUPPORTED, KeyboardKeys, SAMPLING_RATE_EMOJI_RENDERED_EXP } from '../../util/constants';
9
- import { isImageRepresentation, isMediaRepresentation, isSpriteRepresentation, toEmojiId } from '../../util/type-helpers';
8
+ import { defaultEmojiHeight, deleteEmojiLabel, EMOJI_KEYBOARD_KEYS_SUPPORTED, KeyboardKeys, SAMPLING_RATE_EMOJI_RENDERED_EXP } from '../../util/constants';
9
+ import { isImageRepresentation, isMediaRepresentation, isSpriteRepresentation, isUnicodeRepresentation, toEmojiId } from '../../util/type-helpers';
10
10
  import { UfoEmojiTimings } from '../../types';
11
11
  import { leftClick } from '../../util/mouse';
12
12
  import DeleteButton from './DeleteButton';
@@ -21,6 +21,10 @@ import { fg } from '@atlaskit/platform-feature-flags';
21
21
  import { messages } from '../i18n';
22
22
  const emojiSpriteContainer = null;
23
23
  const emojiImageContainer = null;
24
+
25
+ // Unicode emojis render as text inside a <span>, not an <img>, so they do not need
26
+ // borderRadius (which would clip a background on hover) or the img { display: block } rule.
27
+ const emojiUnicodeContainer = null;
24
28
  const handleMouseDown = (props, event) => {
25
29
  // Clicked emoji delete button
26
30
  if (event.target instanceof Element && event.target.getAttribute('aria-label') === deleteEmojiLabel) {
@@ -145,6 +149,42 @@ export const SpriteEmoji = props => {
145
149
  }))
146
150
  );
147
151
  };
152
+ export const UnicodeEmoji = props => {
153
+ const {
154
+ emoji,
155
+ fitToHeight,
156
+ selected,
157
+ selectOnHover,
158
+ className
159
+ } = props;
160
+ const classes = `${emojiNodeStyles} ${selected ? commonSelectedStyles : ''} ${selectOnHover ? selectOnHoverStyles : ''} ${className ? className : ''}`;
161
+ const emojiText = emoji.representation.unicodeEmoji;
162
+ const size = fitToHeight !== null && fitToHeight !== void 0 ? fitToHeight : defaultEmojiHeight;
163
+ const style = {
164
+ display: 'inline-block',
165
+ // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
166
+ fontSize: `max(1em, ${size}px)`,
167
+ width: `max(1em, ${size}px)`,
168
+ height: `max(1em, ${size}px)`,
169
+ textAlign: 'center',
170
+ alignContent: 'center',
171
+ alignSelf: 'center',
172
+ // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
173
+ lineHeight: '0',
174
+ margin: '0',
175
+ padding: '0'
176
+ };
177
+ return (
178
+ /*#__PURE__*/
179
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
180
+ React.createElement(EmojiNodeWrapper, _extends({}, props, {
181
+ type: "unicode",
182
+ className: classes
183
+ }), /*#__PURE__*/React.createElement("span", {
184
+ style: style
185
+ }, emojiText))
186
+ );
187
+ };
148
188
 
149
189
  // Keep as pure functional component, see renderAsSprite.
150
190
  export const ImageEmoji = props => {
@@ -324,7 +364,7 @@ export const EmojiNodeWrapper = /*#__PURE__*/forwardRef((props, ref) => {
324
364
  "data-emoji-type": type,
325
365
  tabIndex: shouldBeInteractive ? tabIndex || 0 : undefined,
326
366
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
327
- className: ax([type === 'sprite' ? "_19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _1e0c1o8l _jr50g2xd _ylp71o8l _pkaxgktf _1hdcgktf _109tnkob _tn8j1dpa _3naf1dpa _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc" : "_2rkofajl _19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _bfhk1j28 _1e0c1o8l _s7n4nkob _v4pn1ule _tn8j1dpa _3naf1dpa _160jewfl _1theewfl _1kogh2mm _qyp0ewfl _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc", className]),
367
+ className: ax([type === 'sprite' ? "_19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _1e0c1o8l _jr50g2xd _ylp71o8l _pkaxgktf _1hdcgktf _109tnkob _tn8j1dpa _3naf1dpa _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc" : type === 'unicode' ? "_19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _bfhk1j28 _1e0c1o8l _s7n4nkob _tn8j1dpa _3naf1dpa _160jewfl _1theewfl _1kogh2mm _qyp0ewfl _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc" : "_2rkofajl _19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _bfhk1j28 _1e0c1o8l _s7n4nkob _v4pn1ule _tn8j1dpa _3naf1dpa _160jewfl _1theewfl _1kogh2mm _qyp0ewfl _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc", className]),
328
368
  onKeyDown: event => handleKeyDown(props, event),
329
369
  onMouseDown: event => {
330
370
  handleMouseDown(props, event);
@@ -357,6 +397,9 @@ export const Emoji = props => {
357
397
  }
358
398
  // eslint-disable-next-line react-hooks/exhaustive-deps
359
399
  }, []);
400
+ if (isUnicodeRepresentation(emoji.representation)) {
401
+ return /*#__PURE__*/React.createElement(UnicodeEmoji, props);
402
+ }
360
403
  // TODO: We always prefer render as image as having accessibility issues with sprite representation
361
404
  if (isSpriteRepresentation(emoji.representation)) {
362
405
  return /*#__PURE__*/React.createElement(SpriteEmoji, props);
@@ -2,6 +2,7 @@
2
2
  import "./EmojiPreviewComponent.compiled.css";
3
3
  import * as React from 'react';
4
4
  import { ax, ix } from "@compiled/react/runtime";
5
+ import { fg } from '@atlaskit/platform-feature-flags';
5
6
  import CachingEmoji from './CachingEmoji';
6
7
  const emojiName = null;
7
8
  const emojiShortName = null;
@@ -11,13 +12,15 @@ const previewText = null;
11
12
  export const EmojiPreviewComponent = ({
12
13
  emoji
13
14
  }) => {
15
+ const fitToHeight = fg('platform_twemoji_removal_unicode_emojis') ? 32 : undefined;
14
16
  return /*#__PURE__*/React.createElement("div", {
15
17
  className: ax(["_ca0q19bv _u5f319bv _n3td19bv _19bv19bv _1e0c1txw _2lx2vrvc _1n261q9c _4t3izwfg _4cvr1h6o"])
16
18
  }, /*#__PURE__*/React.createElement("span", {
17
19
  className: ax(["_1e0c1o8l _1bsbzwfg _12s6idpf _1e4didpf _1dvqidpf _vwlxidpf _1gdiidpf _1f45idpf _pdfdidpf _mwo3idpf _5ilezwfg _boltzwfg _1pc7zwfg _u5wqzwfg _w7981kw7 _1vqe1kw7 _1l4xidpf _1l79idpf _118didpf _1pa4idpf _1pglh2mm _1vjf1ssb _1h6o1ssb _8fp6dbra _1os4zwfg _1e7azwfg _7mh21ule"])
18
20
  }, /*#__PURE__*/React.createElement(CachingEmoji, {
19
21
  key: emoji.id || emoji.shortName,
20
- emoji: emoji
22
+ emoji: emoji,
23
+ fitToHeight: fitToHeight
21
24
  })), /*#__PURE__*/React.createElement("div", {
22
25
  className: ax(["_1e0c1txw _2lx21bp4 _1wpz1h6o _19pk1i6y _18u019bv _p12f3sup _1bsb3sup _16jlkb7n _1o9zkb7n"])
23
26
  }, emoji.name && /*#__PURE__*/React.createElement("div", {
@@ -36,6 +36,7 @@ export const EmojiRadioButton = /*#__PURE__*/forwardRef((props, ref) => {
36
36
  ariaLabelText,
37
37
  defaultChecked
38
38
  } = props;
39
+ const fitToHeight = fg('platform_twemoji_removal_unicode_emojis') ? 24 : undefined;
39
40
  return /*#__PURE__*/React.createElement("label", {
40
41
  className: ax(["_19itidpf _2rkofajl _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _bfhk1j28 _80omtlke _kqswh2mm _1e0c1o8l _lev4idpf _1cx6idpf _tyukidpf _2ewlidpf _11bcidpf _dqozglyw _1at812x7 _1cjo12x7 _1yg612x7 _hjaq12x7 _hlt21tcg _1s3c1tcg _1i911tcg _1ye71tcg"])
41
42
  }, /*#__PURE__*/React.createElement(VisuallyHidden, null, ariaLabelText), /*#__PURE__*/React.createElement("input", {
@@ -55,7 +56,8 @@ export const EmojiRadioButton = /*#__PURE__*/forwardRef((props, ref) => {
55
56
  emoji: emoji,
56
57
  selectOnHover: selectOnHover,
57
58
  shouldBeInteractive: false,
58
- "aria-hidden": true
59
+ "aria-hidden": true,
60
+ fitToHeight: fitToHeight
59
61
  }));
60
62
  });
61
63
  const _default_1 = /*#__PURE__*/memo(EmojiRadioButton);
@@ -32,6 +32,8 @@ const uploadChooseFileEmojiName = null;
32
32
  const uploadChooseFileMessage = null;
33
33
  const uploadChooseFileRow = null;
34
34
  const uploadChooseFileRowNew = null;
35
+ const supportedEmojiUploadMimeTypes = new Set(['image/png', 'image/jpeg', 'image/gif']);
36
+ const supportedEmojiUploadExtensions = ['.png', '.jpg', '.jpeg', '.gif'];
35
37
  export const uploadEmojiNameInputTestId = 'upload-emoji-name-input';
36
38
  export const uploadEmojiComponentTestId = 'upload-emoji-component';
37
39
  export const cancelEmojiUploadPickerTestId = 'cancel-emoji-upload-picker';
@@ -48,6 +50,16 @@ const toEmojiName = uploadName => {
48
50
  const name = uploadName.split('_').join(' ');
49
51
  return `${name.substr(0, 1).toLocaleUpperCase()}${name.substr(1)}`;
50
52
  };
53
+ const isSupportedEmojiUploadFileType = file => {
54
+ if (!fg('platform_emoji_picker_refresh')) {
55
+ return true;
56
+ }
57
+ if (supportedEmojiUploadMimeTypes.has(file.type)) {
58
+ return true;
59
+ }
60
+ const lowerCaseFileName = file.name.toLowerCase();
61
+ return supportedEmojiUploadExtensions.some(extension => lowerCaseFileName.endsWith(extension));
62
+ };
51
63
  const ChooseEmojiFile = /*#__PURE__*/memo(props => {
52
64
  const {
53
65
  name = '',
@@ -297,6 +309,11 @@ const EmojiUploadPicker = props => {
297
309
  if (files.length) {
298
310
  const reader = new FileReader();
299
311
  const file = files[0];
312
+ if (!isSupportedEmojiUploadFileType(file)) {
313
+ setChooseEmojiErrorMessage( /*#__PURE__*/React.createElement(FormattedMessage, messages.emojiUnsupportedFileType));
314
+ cancelChooseFile();
315
+ return;
316
+ }
300
317
  if (ImageUtil.hasFileExceededSize(file)) {
301
318
  setChooseEmojiErrorMessage( /*#__PURE__*/React.createElement(FormattedMessage, messages.emojiImageTooBig));
302
319
  cancelChooseFile();
@@ -18,6 +18,7 @@ export const TonePreviewButton = /*#__PURE__*/forwardRef((props, ref) => {
18
18
  onSelected,
19
19
  isVisible = true
20
20
  } = props;
21
+ const fitToHeight = fg('platform_twemoji_removal_unicode_emojis') ? 24 : undefined;
21
22
  return fg('platform_emoji_picker_refresh') ? /*#__PURE__*/React.createElement("button", {
22
23
  ref: ref,
23
24
  onClick: onSelected,
@@ -36,7 +37,8 @@ export const TonePreviewButton = /*#__PURE__*/forwardRef((props, ref) => {
36
37
  emoji: emoji,
37
38
  selectOnHover: selectOnHover,
38
39
  shouldBeInteractive: false,
39
- "aria-hidden": true
40
+ "aria-hidden": true,
41
+ fitToHeight: fitToHeight
40
42
  })) : /*#__PURE__*/React.createElement("button", {
41
43
  ref: ref,
42
44
  onClick: onSelected,
@@ -55,7 +57,8 @@ export const TonePreviewButton = /*#__PURE__*/forwardRef((props, ref) => {
55
57
  emoji: emoji,
56
58
  selectOnHover: selectOnHover,
57
59
  shouldBeInteractive: false,
58
- "aria-hidden": true
60
+ "aria-hidden": true,
61
+ fitToHeight: fitToHeight
59
62
  }));
60
63
  });
61
64
  const _default_1 = /*#__PURE__*/memo(TonePreviewButton);
@@ -215,6 +215,11 @@ export const messages = defineMessages({
215
215
  defaultMessage: 'Selected image is more than 1 MB',
216
216
  description: 'Error message for image too big, beyond the size limit'
217
217
  },
218
+ emojiUnsupportedFileType: {
219
+ id: 'fabric.emoji.error.unsupported.file.type',
220
+ defaultMessage: "This file type isn't supported. Select a PNG, JPEG, or GIF to create your emoji.",
221
+ description: 'Error message shown when the selected emoji upload file type is not supported'
222
+ },
218
223
  emojiDuplicateName: {
219
224
  id: 'fabric.emoji.error.duplicate.name',
220
225
  defaultMessage: 'An emoji with this name exists already',
@@ -31,6 +31,7 @@ const EmojiPickerEmojiRow = ({
31
31
  const {
32
32
  formatMessage
33
33
  } = useIntl();
34
+ const fitToHeight = fg('platform_twemoji_removal_unicode_emojis') ? 24 : undefined;
34
35
  const handleFocus = index => (emojiId, emoji, event) => {
35
36
  setEmojisFocus({
36
37
  rowIndex,
@@ -99,7 +100,8 @@ const EmojiPickerEmojiRow = ({
99
100
  "data-focus-index": `${rowIndex}-${index}`,
100
101
  tabIndex: focus ? 0 : -1,
101
102
  "aria-roledescription": formatMessage(messages.emojiButtonRoleDescription),
102
- shouldBeInteractive: true
103
+ shouldBeInteractive: true,
104
+ fitToHeight: fitToHeight
103
105
  }));
104
106
  }));
105
107
  };
@@ -9,7 +9,7 @@ const createEvent = (eventType, action, actionSubject, actionSubjectId, attribut
9
9
  actionSubjectId,
10
10
  attributes: {
11
11
  packageName: "@atlaskit/emoji",
12
- packageVersion: "70.10.13",
12
+ packageVersion: "70.11.0",
13
13
  ...attributes
14
14
  }
15
15
  });
@@ -11,8 +11,8 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
11
11
  import React, { useEffect, useCallback, useMemo, forwardRef } from 'react';
12
12
  import Tooltip from '@atlaskit/tooltip';
13
13
  import { shouldUseAltRepresentation } from '../../api/EmojiUtils';
14
- import { deleteEmojiLabel, EMOJI_KEYBOARD_KEYS_SUPPORTED, KeyboardKeys, SAMPLING_RATE_EMOJI_RENDERED_EXP } from '../../util/constants';
15
- import { isImageRepresentation, isMediaRepresentation, isSpriteRepresentation, toEmojiId } from '../../util/type-helpers';
14
+ import { defaultEmojiHeight, deleteEmojiLabel, EMOJI_KEYBOARD_KEYS_SUPPORTED, KeyboardKeys, SAMPLING_RATE_EMOJI_RENDERED_EXP } from '../../util/constants';
15
+ import { isImageRepresentation, isMediaRepresentation, isSpriteRepresentation, isUnicodeRepresentation, toEmojiId } from '../../util/type-helpers';
16
16
  import { UfoEmojiTimings } from '../../types';
17
17
  import { leftClick } from '../../util/mouse';
18
18
  import DeleteButton from './DeleteButton';
@@ -27,6 +27,10 @@ import { fg } from '@atlaskit/platform-feature-flags';
27
27
  import { messages } from '../i18n';
28
28
  var emojiSpriteContainer = null;
29
29
  var emojiImageContainer = null;
30
+
31
+ // Unicode emojis render as text inside a <span>, not an <img>, so they do not need
32
+ // borderRadius (which would clip a background on hover) or the img { display: block } rule.
33
+ var emojiUnicodeContainer = null;
30
34
  var handleMouseDown = function handleMouseDown(props, event) {
31
35
  // Clicked emoji delete button
32
36
  if (event.target instanceof Element && event.target.getAttribute('aria-label') === deleteEmojiLabel) {
@@ -136,6 +140,40 @@ export var SpriteEmoji = function SpriteEmoji(props) {
136
140
  }))
137
141
  );
138
142
  };
143
+ export var UnicodeEmoji = function UnicodeEmoji(props) {
144
+ var emoji = props.emoji,
145
+ fitToHeight = props.fitToHeight,
146
+ selected = props.selected,
147
+ selectOnHover = props.selectOnHover,
148
+ className = props.className;
149
+ var classes = "".concat(emojiNodeStyles, " ").concat(selected ? commonSelectedStyles : '', " ").concat(selectOnHover ? selectOnHoverStyles : '', " ").concat(className ? className : '');
150
+ var emojiText = emoji.representation.unicodeEmoji;
151
+ var size = fitToHeight !== null && fitToHeight !== void 0 ? fitToHeight : defaultEmojiHeight;
152
+ var style = {
153
+ display: 'inline-block',
154
+ // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
155
+ fontSize: "max(1em, ".concat(size, "px)"),
156
+ width: "max(1em, ".concat(size, "px)"),
157
+ height: "max(1em, ".concat(size, "px)"),
158
+ textAlign: 'center',
159
+ alignContent: 'center',
160
+ alignSelf: 'center',
161
+ // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
162
+ lineHeight: '0',
163
+ margin: '0',
164
+ padding: '0'
165
+ };
166
+ return (
167
+ /*#__PURE__*/
168
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
169
+ React.createElement(EmojiNodeWrapper, _extends({}, props, {
170
+ type: "unicode",
171
+ className: classes
172
+ }), /*#__PURE__*/React.createElement("span", {
173
+ style: style
174
+ }, emojiText))
175
+ );
176
+ };
139
177
 
140
178
  // Keep as pure functional component, see renderAsSprite.
141
179
  export var ImageEmoji = function ImageEmoji(props) {
@@ -323,7 +361,7 @@ export var EmojiNodeWrapper = /*#__PURE__*/forwardRef(function (props, ref) {
323
361
  "data-emoji-type": type,
324
362
  tabIndex: shouldBeInteractive ? tabIndex || 0 : undefined,
325
363
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
326
- className: ax([type === 'sprite' ? "_19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _1e0c1o8l _jr50g2xd _ylp71o8l _pkaxgktf _1hdcgktf _109tnkob _tn8j1dpa _3naf1dpa _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc" : "_2rkofajl _19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _bfhk1j28 _1e0c1o8l _s7n4nkob _v4pn1ule _tn8j1dpa _3naf1dpa _160jewfl _1theewfl _1kogh2mm _qyp0ewfl _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc", className]),
364
+ className: ax([type === 'sprite' ? "_19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _1e0c1o8l _jr50g2xd _ylp71o8l _pkaxgktf _1hdcgktf _109tnkob _tn8j1dpa _3naf1dpa _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc" : type === 'unicode' ? "_19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _bfhk1j28 _1e0c1o8l _s7n4nkob _tn8j1dpa _3naf1dpa _160jewfl _1theewfl _1kogh2mm _qyp0ewfl _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc" : "_2rkofajl _19pk1n1a _2hwxidpf _otyr1n1a _18u0idpf _bfhk1j28 _1e0c1o8l _s7n4nkob _v4pn1ule _tn8j1dpa _3naf1dpa _160jewfl _1theewfl _1kogh2mm _qyp0ewfl _nt751r31 _49pcglyw _1hvw1o36 _7ehi1y54 _491113zc", className]),
327
365
  onKeyDown: function onKeyDown(event) {
328
366
  return handleKeyDown(props, event);
329
367
  },
@@ -356,6 +394,9 @@ export var Emoji = function Emoji(props) {
356
394
  }
357
395
  // eslint-disable-next-line react-hooks/exhaustive-deps
358
396
  }, []);
397
+ if (isUnicodeRepresentation(emoji.representation)) {
398
+ return /*#__PURE__*/React.createElement(UnicodeEmoji, props);
399
+ }
359
400
  // TODO: We always prefer render as image as having accessibility issues with sprite representation
360
401
  if (isSpriteRepresentation(emoji.representation)) {
361
402
  return /*#__PURE__*/React.createElement(SpriteEmoji, props);
@@ -2,6 +2,7 @@
2
2
  import "./EmojiPreviewComponent.compiled.css";
3
3
  import * as React from 'react';
4
4
  import { ax, ix } from "@compiled/react/runtime";
5
+ import { fg } from '@atlaskit/platform-feature-flags';
5
6
  import CachingEmoji from './CachingEmoji';
6
7
  var emojiName = null;
7
8
  var emojiShortName = null;
@@ -10,13 +11,15 @@ var previewImg = null;
10
11
  var previewText = null;
11
12
  export var EmojiPreviewComponent = function EmojiPreviewComponent(_ref) {
12
13
  var emoji = _ref.emoji;
14
+ var fitToHeight = fg('platform_twemoji_removal_unicode_emojis') ? 32 : undefined;
13
15
  return /*#__PURE__*/React.createElement("div", {
14
16
  className: ax(["_ca0q19bv _u5f319bv _n3td19bv _19bv19bv _1e0c1txw _2lx2vrvc _1n261q9c _4t3izwfg _4cvr1h6o"])
15
17
  }, /*#__PURE__*/React.createElement("span", {
16
18
  className: ax(["_1e0c1o8l _1bsbzwfg _12s6idpf _1e4didpf _1dvqidpf _vwlxidpf _1gdiidpf _1f45idpf _pdfdidpf _mwo3idpf _5ilezwfg _boltzwfg _1pc7zwfg _u5wqzwfg _w7981kw7 _1vqe1kw7 _1l4xidpf _1l79idpf _118didpf _1pa4idpf _1pglh2mm _1vjf1ssb _1h6o1ssb _8fp6dbra _1os4zwfg _1e7azwfg _7mh21ule"])
17
19
  }, /*#__PURE__*/React.createElement(CachingEmoji, {
18
20
  key: emoji.id || emoji.shortName,
19
- emoji: emoji
21
+ emoji: emoji,
22
+ fitToHeight: fitToHeight
20
23
  })), /*#__PURE__*/React.createElement("div", {
21
24
  className: ax(["_1e0c1txw _2lx21bp4 _1wpz1h6o _19pk1i6y _18u019bv _p12f3sup _1bsb3sup _16jlkb7n _1o9zkb7n"])
22
25
  }, emoji.name && /*#__PURE__*/React.createElement("div", {
@@ -32,6 +32,7 @@ export var EmojiRadioButton = /*#__PURE__*/forwardRef(function (props, ref) {
32
32
  selectOnHover = props.selectOnHover,
33
33
  ariaLabelText = props.ariaLabelText,
34
34
  defaultChecked = props.defaultChecked;
35
+ var fitToHeight = fg('platform_twemoji_removal_unicode_emojis') ? 24 : undefined;
35
36
  return /*#__PURE__*/React.createElement("label", {
36
37
  className: ax(["_19itidpf _2rkofajl _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _bfhk1j28 _80omtlke _kqswh2mm _1e0c1o8l _lev4idpf _1cx6idpf _tyukidpf _2ewlidpf _11bcidpf _dqozglyw _1at812x7 _1cjo12x7 _1yg612x7 _hjaq12x7 _hlt21tcg _1s3c1tcg _1i911tcg _1ye71tcg"])
37
38
  }, /*#__PURE__*/React.createElement(VisuallyHidden, null, ariaLabelText), /*#__PURE__*/React.createElement("input", {
@@ -55,7 +56,8 @@ export var EmojiRadioButton = /*#__PURE__*/forwardRef(function (props, ref) {
55
56
  emoji: emoji,
56
57
  selectOnHover: selectOnHover,
57
58
  shouldBeInteractive: false,
58
- "aria-hidden": true
59
+ "aria-hidden": true,
60
+ fitToHeight: fitToHeight
59
61
  }));
60
62
  });
61
63
  var _default_1 = /*#__PURE__*/memo(EmojiRadioButton);
@@ -35,6 +35,8 @@ var uploadChooseFileEmojiName = null;
35
35
  var uploadChooseFileMessage = null;
36
36
  var uploadChooseFileRow = null;
37
37
  var uploadChooseFileRowNew = null;
38
+ var supportedEmojiUploadMimeTypes = new Set(['image/png', 'image/jpeg', 'image/gif']);
39
+ var supportedEmojiUploadExtensions = ['.png', '.jpg', '.jpeg', '.gif'];
38
40
  export var uploadEmojiNameInputTestId = 'upload-emoji-name-input';
39
41
  export var uploadEmojiComponentTestId = 'upload-emoji-component';
40
42
  export var cancelEmojiUploadPickerTestId = 'cancel-emoji-upload-picker';
@@ -51,6 +53,18 @@ var toEmojiName = function toEmojiName(uploadName) {
51
53
  var name = uploadName.split('_').join(' ');
52
54
  return "".concat(name.substr(0, 1).toLocaleUpperCase()).concat(name.substr(1));
53
55
  };
56
+ var isSupportedEmojiUploadFileType = function isSupportedEmojiUploadFileType(file) {
57
+ if (!fg('platform_emoji_picker_refresh')) {
58
+ return true;
59
+ }
60
+ if (supportedEmojiUploadMimeTypes.has(file.type)) {
61
+ return true;
62
+ }
63
+ var lowerCaseFileName = file.name.toLowerCase();
64
+ return supportedEmojiUploadExtensions.some(function (extension) {
65
+ return lowerCaseFileName.endsWith(extension);
66
+ });
67
+ };
54
68
  var ChooseEmojiFile = /*#__PURE__*/memo(function (props) {
55
69
  var _props$name = props.name,
56
70
  name = _props$name === void 0 ? '' : _props$name,
@@ -334,6 +348,11 @@ var EmojiUploadPicker = function EmojiUploadPicker(props) {
334
348
  if (files.length) {
335
349
  var reader = new FileReader();
336
350
  var file = files[0];
351
+ if (!isSupportedEmojiUploadFileType(file)) {
352
+ setChooseEmojiErrorMessage( /*#__PURE__*/React.createElement(FormattedMessage, messages.emojiUnsupportedFileType));
353
+ cancelChooseFile();
354
+ return;
355
+ }
337
356
  if (ImageUtil.hasFileExceededSize(file)) {
338
357
  setChooseEmojiErrorMessage( /*#__PURE__*/React.createElement(FormattedMessage, messages.emojiImageTooBig));
339
358
  cancelChooseFile();
@@ -17,6 +17,7 @@ export var TonePreviewButton = /*#__PURE__*/forwardRef(function (props, ref) {
17
17
  onSelected = props.onSelected,
18
18
  _props$isVisible = props.isVisible,
19
19
  isVisible = _props$isVisible === void 0 ? true : _props$isVisible;
20
+ var fitToHeight = fg('platform_twemoji_removal_unicode_emojis') ? 24 : undefined;
20
21
  return fg('platform_emoji_picker_refresh') ? /*#__PURE__*/React.createElement("button", {
21
22
  ref: ref,
22
23
  onClick: onSelected,
@@ -35,7 +36,8 @@ export var TonePreviewButton = /*#__PURE__*/forwardRef(function (props, ref) {
35
36
  emoji: emoji,
36
37
  selectOnHover: selectOnHover,
37
38
  shouldBeInteractive: false,
38
- "aria-hidden": true
39
+ "aria-hidden": true,
40
+ fitToHeight: fitToHeight
39
41
  })) : /*#__PURE__*/React.createElement("button", {
40
42
  ref: ref,
41
43
  onClick: onSelected,
@@ -54,7 +56,8 @@ export var TonePreviewButton = /*#__PURE__*/forwardRef(function (props, ref) {
54
56
  emoji: emoji,
55
57
  selectOnHover: selectOnHover,
56
58
  shouldBeInteractive: false,
57
- "aria-hidden": true
59
+ "aria-hidden": true,
60
+ fitToHeight: fitToHeight
58
61
  }));
59
62
  });
60
63
  var _default_1 = /*#__PURE__*/memo(TonePreviewButton);
@@ -215,6 +215,11 @@ export var messages = defineMessages({
215
215
  defaultMessage: 'Selected image is more than 1 MB',
216
216
  description: 'Error message for image too big, beyond the size limit'
217
217
  },
218
+ emojiUnsupportedFileType: {
219
+ id: 'fabric.emoji.error.unsupported.file.type',
220
+ defaultMessage: "This file type isn't supported. Select a PNG, JPEG, or GIF to create your emoji.",
221
+ description: 'Error message shown when the selected emoji upload file type is not supported'
222
+ },
218
223
  emojiDuplicateName: {
219
224
  id: 'fabric.emoji.error.duplicate.name',
220
225
  defaultMessage: 'An emoji with this name exists already',
@@ -28,6 +28,7 @@ var EmojiPickerEmojiRow = function EmojiPickerEmojiRow(_ref) {
28
28
  var rowIndex = (virtualItemContext === null || virtualItemContext === void 0 ? void 0 : virtualItemContext.index) || 0;
29
29
  var _useIntl = useIntl(),
30
30
  formatMessage = _useIntl.formatMessage;
31
+ var fitToHeight = fg('platform_twemoji_removal_unicode_emojis') ? 24 : undefined;
31
32
  var handleFocus = function handleFocus(index) {
32
33
  return function (emojiId, emoji, event) {
33
34
  setEmojisFocus({
@@ -94,7 +95,8 @@ var EmojiPickerEmojiRow = function EmojiPickerEmojiRow(_ref) {
94
95
  "data-focus-index": "".concat(rowIndex, "-").concat(index),
95
96
  tabIndex: focus ? 0 : -1,
96
97
  "aria-roledescription": formatMessage(messages.emojiButtonRoleDescription),
97
- shouldBeInteractive: true
98
+ shouldBeInteractive: true,
99
+ fitToHeight: fitToHeight
98
100
  }));
99
101
  }));
100
102
  };
@@ -14,7 +14,7 @@ var createEvent = function createEvent(eventType, action, actionSubject, actionS
14
14
  actionSubjectId: actionSubjectId,
15
15
  attributes: _objectSpread({
16
16
  packageName: "@atlaskit/emoji",
17
- packageVersion: "70.10.13"
17
+ packageVersion: "70.11.0"
18
18
  }, attributes)
19
19
  };
20
20
  };
@@ -84,9 +84,10 @@ export interface Props extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'onMo
84
84
  showTooltip?: boolean;
85
85
  }
86
86
  export declare const SpriteEmoji: (props: Props) => JSX.Element;
87
+ export declare const UnicodeEmoji: (props: Props) => JSX.Element;
87
88
  export declare const ImageEmoji: (props: Props) => JSX.Element;
88
89
  interface EmojiNodeWrapperProps extends Props {
89
- type: 'sprite' | 'image';
90
+ type: 'sprite' | 'image' | 'unicode';
90
91
  }
91
92
  export declare const EmojiNodeWrapper: React.ForwardRefExoticComponent<EmojiNodeWrapperProps & {
92
93
  children?: React.ReactNode | undefined;
@@ -8,9 +8,9 @@ export interface Props {
8
8
  ariaLabelText?: string;
9
9
  defaultChecked?: boolean;
10
10
  emoji: EmojiDescription;
11
+ onArrowKey?: (direction: -1 | 1) => void;
11
12
  onSelected?: () => void;
12
13
  selectOnHover?: boolean;
13
- onArrowKey?: (direction: -1 | 1) => void;
14
14
  }
15
15
  export declare const EmojiRadioButton: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLInputElement>>;
16
16
  declare const _default_1: React.MemoExoticComponent<React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLInputElement>>>;
@@ -159,6 +159,11 @@ export declare const messages: {
159
159
  description: string;
160
160
  id: string;
161
161
  };
162
+ emojiUnsupportedFileType: {
163
+ defaultMessage: string;
164
+ description: string;
165
+ id: string;
166
+ };
162
167
  emojiUploadFailed: {
163
168
  defaultMessage: string;
164
169
  description: string;
@@ -84,9 +84,10 @@ export interface Props extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'onMo
84
84
  showTooltip?: boolean;
85
85
  }
86
86
  export declare const SpriteEmoji: (props: Props) => JSX.Element;
87
+ export declare const UnicodeEmoji: (props: Props) => JSX.Element;
87
88
  export declare const ImageEmoji: (props: Props) => JSX.Element;
88
89
  interface EmojiNodeWrapperProps extends Props {
89
- type: 'sprite' | 'image';
90
+ type: 'sprite' | 'image' | 'unicode';
90
91
  }
91
92
  export declare const EmojiNodeWrapper: React.ForwardRefExoticComponent<EmojiNodeWrapperProps & {
92
93
  children?: React.ReactNode | undefined;
@@ -8,9 +8,9 @@ export interface Props {
8
8
  ariaLabelText?: string;
9
9
  defaultChecked?: boolean;
10
10
  emoji: EmojiDescription;
11
+ onArrowKey?: (direction: -1 | 1) => void;
11
12
  onSelected?: () => void;
12
13
  selectOnHover?: boolean;
13
- onArrowKey?: (direction: -1 | 1) => void;
14
14
  }
15
15
  export declare const EmojiRadioButton: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLInputElement>>;
16
16
  declare const _default_1: React.MemoExoticComponent<React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLInputElement>>>;
@@ -159,6 +159,11 @@ export declare const messages: {
159
159
  description: string;
160
160
  id: string;
161
161
  };
162
+ emojiUnsupportedFileType: {
163
+ defaultMessage: string;
164
+ description: string;
165
+ id: string;
166
+ };
162
167
  emojiUploadFailed: {
163
168
  defaultMessage: string;
164
169
  description: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/emoji",
3
- "version": "70.10.14",
3
+ "version": "70.11.1",
4
4
  "description": "Fabric emoji React components",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -52,9 +52,9 @@
52
52
  "@atlaskit/primitives": "^19.0.0",
53
53
  "@atlaskit/spinner": "^19.1.0",
54
54
  "@atlaskit/textfield": "^8.3.0",
55
- "@atlaskit/tmp-editor-statsig": "^84.3.0",
55
+ "@atlaskit/tmp-editor-statsig": "^85.0.0",
56
56
  "@atlaskit/tokens": "^13.1.0",
57
- "@atlaskit/tooltip": "^22.4.0",
57
+ "@atlaskit/tooltip": "^22.5.0",
58
58
  "@atlaskit/ufo": "^0.5.0",
59
59
  "@atlaskit/util-service-support": "^6.4.0",
60
60
  "@atlaskit/visually-hidden": "^3.1.0",