@atlaskit/emoji 70.7.2 → 70.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @atlaskit/emoji
2
2
 
3
+ ## 70.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`7bcc8a1cb49b5`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/7bcc8a1cb49b5) -
8
+ Add unicode + emoji utilities
9
+
3
10
  ## 70.7.2
4
11
 
5
12
  ### Patch Changes
@@ -163,5 +163,5 @@ var getHeight = function getHeight(fitToHeight) {
163
163
  return getPixelRatio() > 1 ? fitToHeight * 2 : fitToHeight;
164
164
  };
165
165
  var shouldUseAltRepresentation = exports.shouldUseAltRepresentation = function shouldUseAltRepresentation(emoji, fitToHeight) {
166
- return !!(fitToHeight && emoji.altRepresentation && getHeight(fitToHeight) > emoji.representation.height);
166
+ return !!(fitToHeight && emoji.altRepresentation && emoji.representation && 'height' in emoji.representation && getHeight(fitToHeight) > emoji.representation.height);
167
167
  };
@@ -148,11 +148,12 @@ var CachingMediaEmoji = exports.CachingMediaEmoji = function CachingMediaEmoji(p
148
148
  onLoadError: handleLoadError
149
149
  }));
150
150
  }
151
+ var imageRepresentation = representation && 'height' in representation ? representation : undefined;
151
152
  return /*#__PURE__*/_react.default.createElement(_EmojiPlaceholder.default, {
152
153
  size: fitToHeight || placeholderSize,
153
154
  shortName: shortName,
154
155
  showTooltip: showTooltip,
155
- representation: representation
156
+ representation: imageRepresentation
156
157
  });
157
158
  };
158
159
  var _default_1 = /*#__PURE__*/(0, _react.memo)(CachingEmoji);
@@ -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.7.1"
23
+ packageVersion: "70.7.2"
24
24
  }, attributes)
25
25
  };
26
26
  };
@@ -4,9 +4,25 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.emojiIdToEmoji = emojiIdToEmoji;
7
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
7
8
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
8
9
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
9
10
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
11
+ var KEYCAP_COMBINING = 0x20e3;
12
+ var VARIATION_SELECTOR_16 = 0xfe0f;
13
+ var VARIATION_SELECTOR_15 = 0xfe0e;
14
+
15
+ // Text-presentation-default emoji: BMP characters (U+0000–U+FFFF) that are
16
+ // valid emoji but lack the Emoji_Presentation property render as text without
17
+ // U+FE0F. Supplementary-plane characters (U+10000+) always render as emoji
18
+ // regardless of the Emoji_Presentation property, so we skip those.
19
+ //
20
+ // This set is derived from Unicode 14.0 emoji-data.txt: all BMP code points
21
+ // that have the Emoji property but NOT the Emoji_Presentation property.
22
+ // Using an explicit lookup table avoids the \p{} Unicode property escape
23
+ // syntax (TS1501) which requires a specific TypeScript build target.
24
+ var TEXT_DEFAULT_EMOJI = new Set([0x0023, 0x002a, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x00a9, 0x00ae, 0x203c, 0x2049, 0x2122, 0x2139, 0x2194, 0x2195, 0x2196, 0x2197, 0x2198, 0x2199, 0x21a9, 0x21aa, 0x2328, 0x23cf, 0x23ed, 0x23ee, 0x23ef, 0x23f1, 0x23f2, 0x23f8, 0x23f9, 0x23fa, 0x24c2, 0x25aa, 0x25ab, 0x25b6, 0x25c0, 0x25fb, 0x25fc, 0x2600, 0x2601, 0x2602, 0x2603, 0x2604, 0x260e, 0x2611, 0x2618, 0x261d, 0x2620, 0x2622, 0x2623, 0x2626, 0x262a, 0x262e, 0x262f, 0x2638, 0x2639, 0x263a, 0x2640, 0x2642, 0x265f, 0x2660, 0x2663, 0x2665, 0x2666, 0x2668, 0x267b, 0x267e, 0x2692, 0x2694, 0x2695, 0x2696, 0x2697, 0x2699, 0x269b, 0x269c, 0x26a0, 0x26a7, 0x26b0, 0x26b1, 0x26c8, 0x26cf, 0x26d1, 0x26d3, 0x26e9, 0x26f0, 0x26f1, 0x26f4, 0x26f7, 0x26f8, 0x26f9, 0x2702, 0x2708, 0x2709, 0x270c, 0x270d, 0x270f, 0x2712, 0x2714, 0x2716, 0x271d, 0x2721, 0x2733, 0x2734, 0x2744, 0x2747, 0x2763, 0x2764, 0x27a1, 0x2934, 0x2935, 0x2b05, 0x2b06, 0x2b07, 0x3030, 0x303d, 0x3297, 0x3299]);
25
+
10
26
  /**
11
27
  * Converts an emoji ID (a hyphen-separated string of hex Unicode code points,
12
28
  * e.g. `"1f44d"`, `"1f44d-1f3fb"`, `"1f468-200d-1f469-200d-1f467"`) into its
@@ -50,22 +66,35 @@ function emojiIdToEmoji(id) {
50
66
  if (codePoints.length === 0) {
51
67
  return undefined;
52
68
  }
53
-
54
- // Keycap sequences: digit/# /* followed by U+20E3 need U+FE0F between them.
55
- // The keycap base characters are: 0x23 (#), 0x2A (*), 0x30–0x39 (0–9).
56
- var KEYCAP_COMBINING = 0x20e3;
57
- var VARIATION_SELECTOR_16 = 0xfe0f;
58
69
  var processedCodePoints = [];
59
70
  for (var i = 0; i < codePoints.length; i++) {
60
71
  var cp = codePoints[i];
61
72
  var next = codePoints[i + 1];
62
73
  processedCodePoints.push(cp);
63
74
 
64
- // Insert U+FE0F before U+20E3 if not already present
75
+ // Insert U+FE0F before U+20E3 if not already present.
76
+ // Keycap sequences: digit/# /* followed by U+20E3 need U+FE0F between them.
65
77
  if (next === KEYCAP_COMBINING && cp !== VARIATION_SELECTOR_16) {
66
78
  processedCodePoints.push(VARIATION_SELECTOR_16);
67
79
  }
68
80
  }
81
+
82
+ // Text-presentation-default emoji: characters that are valid emoji but whose
83
+ // default rendering is text (e.g. ☪ ☺ ☢ etc.) must be followed by
84
+ // U+FE0F (VARIATION SELECTOR-16) to force emoji presentation.
85
+ if ((0, _platformFeatureFlags.fg)('platform_twemoji_removal_unicode_emojis')) {
86
+ var lastCodePoint = processedCodePoints[processedCodePoints.length - 1];
87
+ var alreadyHasVariationSelector = lastCodePoint === VARIATION_SELECTOR_16 || lastCodePoint === VARIATION_SELECTOR_15 ||
88
+ // Keycap sequences end with U+20E3 — they already have U+FE0F inserted inline
89
+ // and must not have another variation selector appended at the end.
90
+ lastCodePoint === KEYCAP_COMBINING;
91
+ if (!alreadyHasVariationSelector) {
92
+ var baseCodePoint = codePoints[0];
93
+ if (codePoints.length === 1 && baseCodePoint <= 0xffff && TEXT_DEFAULT_EMOJI.has(baseCodePoint)) {
94
+ processedCodePoints.push(VARIATION_SELECTOR_16);
95
+ }
96
+ }
97
+ }
69
98
  try {
70
99
  return String.fromCodePoint.apply(String, processedCodePoints);
71
100
  } catch (_unused) {
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.toOptionalEmojiId = exports.toEmojiId = exports.isSpriteServiceRepresentation = exports.isSpriteRepresentation = exports.isPromise = exports.isMessagesKey = exports.isMediaRepresentation = exports.isMediaEmoji = exports.isLoadedMediaEmoji = exports.isImageRepresentation = exports.isEmojiVariationDescription = exports.isEmojiIdEqual = exports.isEmojiDescriptionWithVariations = exports.isEmojiDescription = exports.hasDataURLImage = exports.getCategoryId = exports.convertMediaToImageRepresentation = exports.convertMediaToImageEmoji = exports.convertImageToMediaRepresentation = exports.containsEmojiId = exports.buildEmojiDescriptionWithAltRepresentation = void 0;
7
+ exports.toOptionalEmojiId = exports.toEmojiId = exports.isUnicodeRepresentation = exports.isSpriteServiceRepresentation = exports.isSpriteRepresentation = exports.isPromise = exports.isMessagesKey = exports.isMediaRepresentation = exports.isMediaEmoji = exports.isLoadedMediaEmoji = exports.isImageRepresentation = exports.isEmojiVariationDescription = exports.isEmojiIdEqual = exports.isEmojiDescriptionWithVariations = exports.isEmojiDescription = exports.hasDataURLImage = exports.getCategoryId = exports.convertMediaToImageRepresentation = exports.convertMediaToImageEmoji = exports.convertImageToMediaRepresentation = exports.containsEmojiId = exports.buildEmojiDescriptionWithAltRepresentation = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
9
  var _i18n = require("../components/i18n");
10
10
  var _constants = require("./constants");
@@ -22,6 +22,9 @@ var isImageRepresentation = exports.isImageRepresentation = function isImageRepr
22
22
  var isMediaRepresentation = exports.isMediaRepresentation = function isMediaRepresentation(rep) {
23
23
  return !!(rep && rep.mediaPath);
24
24
  };
25
+ var isUnicodeRepresentation = exports.isUnicodeRepresentation = function isUnicodeRepresentation(rep) {
26
+ return !!(rep && rep.unicodeEmoji);
27
+ };
25
28
  var isPromise = exports.isPromise = function isPromise(p) {
26
29
  return !!(p && p.then);
27
30
  };
@@ -156,4 +156,4 @@ export const denormaliseEmojiServiceResponse = emojiData => {
156
156
  };
157
157
  };
158
158
  const getHeight = fitToHeight => getPixelRatio() > 1 ? fitToHeight * 2 : fitToHeight;
159
- export const shouldUseAltRepresentation = (emoji, fitToHeight) => !!(fitToHeight && emoji.altRepresentation && getHeight(fitToHeight) > emoji.representation.height);
159
+ export const shouldUseAltRepresentation = (emoji, fitToHeight) => !!(fitToHeight && emoji.altRepresentation && emoji.representation && 'height' in emoji.representation && getHeight(fitToHeight) > emoji.representation.height);
@@ -135,11 +135,12 @@ export const CachingMediaEmoji = props => {
135
135
  onLoadError: handleLoadError
136
136
  }));
137
137
  }
138
+ const imageRepresentation = representation && 'height' in representation ? representation : undefined;
138
139
  return /*#__PURE__*/React.createElement(EmojiPlaceholder, {
139
140
  size: fitToHeight || placeholderSize,
140
141
  shortName: shortName,
141
142
  showTooltip: showTooltip,
142
- representation: representation
143
+ representation: imageRepresentation
143
144
  });
144
145
  };
145
146
  const _default_1 = /*#__PURE__*/memo(CachingEmoji);
@@ -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.7.1",
12
+ packageVersion: "70.7.2",
13
13
  ...attributes
14
14
  }
15
15
  });
@@ -1,3 +1,19 @@
1
+ import { fg } from '@atlaskit/platform-feature-flags';
2
+ const KEYCAP_COMBINING = 0x20e3;
3
+ const VARIATION_SELECTOR_16 = 0xfe0f;
4
+ const VARIATION_SELECTOR_15 = 0xfe0e;
5
+
6
+ // Text-presentation-default emoji: BMP characters (U+0000–U+FFFF) that are
7
+ // valid emoji but lack the Emoji_Presentation property render as text without
8
+ // U+FE0F. Supplementary-plane characters (U+10000+) always render as emoji
9
+ // regardless of the Emoji_Presentation property, so we skip those.
10
+ //
11
+ // This set is derived from Unicode 14.0 emoji-data.txt: all BMP code points
12
+ // that have the Emoji property but NOT the Emoji_Presentation property.
13
+ // Using an explicit lookup table avoids the \p{} Unicode property escape
14
+ // syntax (TS1501) which requires a specific TypeScript build target.
15
+ const TEXT_DEFAULT_EMOJI = new Set([0x0023, 0x002a, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x00a9, 0x00ae, 0x203c, 0x2049, 0x2122, 0x2139, 0x2194, 0x2195, 0x2196, 0x2197, 0x2198, 0x2199, 0x21a9, 0x21aa, 0x2328, 0x23cf, 0x23ed, 0x23ee, 0x23ef, 0x23f1, 0x23f2, 0x23f8, 0x23f9, 0x23fa, 0x24c2, 0x25aa, 0x25ab, 0x25b6, 0x25c0, 0x25fb, 0x25fc, 0x2600, 0x2601, 0x2602, 0x2603, 0x2604, 0x260e, 0x2611, 0x2618, 0x261d, 0x2620, 0x2622, 0x2623, 0x2626, 0x262a, 0x262e, 0x262f, 0x2638, 0x2639, 0x263a, 0x2640, 0x2642, 0x265f, 0x2660, 0x2663, 0x2665, 0x2666, 0x2668, 0x267b, 0x267e, 0x2692, 0x2694, 0x2695, 0x2696, 0x2697, 0x2699, 0x269b, 0x269c, 0x26a0, 0x26a7, 0x26b0, 0x26b1, 0x26c8, 0x26cf, 0x26d1, 0x26d3, 0x26e9, 0x26f0, 0x26f1, 0x26f4, 0x26f7, 0x26f8, 0x26f9, 0x2702, 0x2708, 0x2709, 0x270c, 0x270d, 0x270f, 0x2712, 0x2714, 0x2716, 0x271d, 0x2721, 0x2733, 0x2734, 0x2744, 0x2747, 0x2763, 0x2764, 0x27a1, 0x2934, 0x2935, 0x2b05, 0x2b06, 0x2b07, 0x3030, 0x303d, 0x3297, 0x3299]);
16
+
1
17
  /**
2
18
  * Converts an emoji ID (a hyphen-separated string of hex Unicode code points,
3
19
  * e.g. `"1f44d"`, `"1f44d-1f3fb"`, `"1f468-200d-1f469-200d-1f467"`) into its
@@ -32,22 +48,35 @@ export function emojiIdToEmoji(id) {
32
48
  if (codePoints.length === 0) {
33
49
  return undefined;
34
50
  }
35
-
36
- // Keycap sequences: digit/# /* followed by U+20E3 need U+FE0F between them.
37
- // The keycap base characters are: 0x23 (#), 0x2A (*), 0x30–0x39 (0–9).
38
- const KEYCAP_COMBINING = 0x20e3;
39
- const VARIATION_SELECTOR_16 = 0xfe0f;
40
51
  const processedCodePoints = [];
41
52
  for (let i = 0; i < codePoints.length; i++) {
42
53
  const cp = codePoints[i];
43
54
  const next = codePoints[i + 1];
44
55
  processedCodePoints.push(cp);
45
56
 
46
- // Insert U+FE0F before U+20E3 if not already present
57
+ // Insert U+FE0F before U+20E3 if not already present.
58
+ // Keycap sequences: digit/# /* followed by U+20E3 need U+FE0F between them.
47
59
  if (next === KEYCAP_COMBINING && cp !== VARIATION_SELECTOR_16) {
48
60
  processedCodePoints.push(VARIATION_SELECTOR_16);
49
61
  }
50
62
  }
63
+
64
+ // Text-presentation-default emoji: characters that are valid emoji but whose
65
+ // default rendering is text (e.g. ☪ ☺ ☢ etc.) must be followed by
66
+ // U+FE0F (VARIATION SELECTOR-16) to force emoji presentation.
67
+ if (fg('platform_twemoji_removal_unicode_emojis')) {
68
+ const lastCodePoint = processedCodePoints[processedCodePoints.length - 1];
69
+ const alreadyHasVariationSelector = lastCodePoint === VARIATION_SELECTOR_16 || lastCodePoint === VARIATION_SELECTOR_15 ||
70
+ // Keycap sequences end with U+20E3 — they already have U+FE0F inserted inline
71
+ // and must not have another variation selector appended at the end.
72
+ lastCodePoint === KEYCAP_COMBINING;
73
+ if (!alreadyHasVariationSelector) {
74
+ const baseCodePoint = codePoints[0];
75
+ if (codePoints.length === 1 && baseCodePoint <= 0xffff && TEXT_DEFAULT_EMOJI.has(baseCodePoint)) {
76
+ processedCodePoints.push(VARIATION_SELECTOR_16);
77
+ }
78
+ }
79
+ }
51
80
  try {
52
81
  return String.fromCodePoint(...processedCodePoints);
53
82
  } catch {
@@ -4,6 +4,7 @@ export const isSpriteServiceRepresentation = rep => !!(rep && rep.spriteRef);
4
4
  export const isSpriteRepresentation = rep => !!(rep && rep.sprite);
5
5
  export const isImageRepresentation = rep => !!(rep && rep.imagePath);
6
6
  export const isMediaRepresentation = rep => !!(rep && rep.mediaPath);
7
+ export const isUnicodeRepresentation = rep => !!(rep && rep.unicodeEmoji);
7
8
  export const isPromise = p => !!(p && p.then);
8
9
  export const isEmojiDescription = possibleEmojiDescription => possibleEmojiDescription && possibleEmojiDescription.shortName && possibleEmojiDescription.type;
9
10
  export const isMediaEmoji = emoji => isMediaRepresentation(emoji.representation);
@@ -156,5 +156,5 @@ var getHeight = function getHeight(fitToHeight) {
156
156
  return getPixelRatio() > 1 ? fitToHeight * 2 : fitToHeight;
157
157
  };
158
158
  export var shouldUseAltRepresentation = function shouldUseAltRepresentation(emoji, fitToHeight) {
159
- return !!(fitToHeight && emoji.altRepresentation && getHeight(fitToHeight) > emoji.representation.height);
159
+ return !!(fitToHeight && emoji.altRepresentation && emoji.representation && 'height' in emoji.representation && getHeight(fitToHeight) > emoji.representation.height);
160
160
  };
@@ -140,11 +140,12 @@ export var CachingMediaEmoji = function CachingMediaEmoji(props) {
140
140
  onLoadError: handleLoadError
141
141
  }));
142
142
  }
143
+ var imageRepresentation = representation && 'height' in representation ? representation : undefined;
143
144
  return /*#__PURE__*/React.createElement(EmojiPlaceholder, {
144
145
  size: fitToHeight || placeholderSize,
145
146
  shortName: shortName,
146
147
  showTooltip: showTooltip,
147
- representation: representation
148
+ representation: imageRepresentation
148
149
  });
149
150
  };
150
151
  var _default_1 = /*#__PURE__*/memo(CachingEmoji);
@@ -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.7.1"
17
+ packageVersion: "70.7.2"
18
18
  }, attributes)
19
19
  };
20
20
  };
@@ -1,6 +1,22 @@
1
1
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
2
2
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
3
3
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
4
+ import { fg } from '@atlaskit/platform-feature-flags';
5
+ var KEYCAP_COMBINING = 0x20e3;
6
+ var VARIATION_SELECTOR_16 = 0xfe0f;
7
+ var VARIATION_SELECTOR_15 = 0xfe0e;
8
+
9
+ // Text-presentation-default emoji: BMP characters (U+0000–U+FFFF) that are
10
+ // valid emoji but lack the Emoji_Presentation property render as text without
11
+ // U+FE0F. Supplementary-plane characters (U+10000+) always render as emoji
12
+ // regardless of the Emoji_Presentation property, so we skip those.
13
+ //
14
+ // This set is derived from Unicode 14.0 emoji-data.txt: all BMP code points
15
+ // that have the Emoji property but NOT the Emoji_Presentation property.
16
+ // Using an explicit lookup table avoids the \p{} Unicode property escape
17
+ // syntax (TS1501) which requires a specific TypeScript build target.
18
+ var TEXT_DEFAULT_EMOJI = new Set([0x0023, 0x002a, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x00a9, 0x00ae, 0x203c, 0x2049, 0x2122, 0x2139, 0x2194, 0x2195, 0x2196, 0x2197, 0x2198, 0x2199, 0x21a9, 0x21aa, 0x2328, 0x23cf, 0x23ed, 0x23ee, 0x23ef, 0x23f1, 0x23f2, 0x23f8, 0x23f9, 0x23fa, 0x24c2, 0x25aa, 0x25ab, 0x25b6, 0x25c0, 0x25fb, 0x25fc, 0x2600, 0x2601, 0x2602, 0x2603, 0x2604, 0x260e, 0x2611, 0x2618, 0x261d, 0x2620, 0x2622, 0x2623, 0x2626, 0x262a, 0x262e, 0x262f, 0x2638, 0x2639, 0x263a, 0x2640, 0x2642, 0x265f, 0x2660, 0x2663, 0x2665, 0x2666, 0x2668, 0x267b, 0x267e, 0x2692, 0x2694, 0x2695, 0x2696, 0x2697, 0x2699, 0x269b, 0x269c, 0x26a0, 0x26a7, 0x26b0, 0x26b1, 0x26c8, 0x26cf, 0x26d1, 0x26d3, 0x26e9, 0x26f0, 0x26f1, 0x26f4, 0x26f7, 0x26f8, 0x26f9, 0x2702, 0x2708, 0x2709, 0x270c, 0x270d, 0x270f, 0x2712, 0x2714, 0x2716, 0x271d, 0x2721, 0x2733, 0x2734, 0x2744, 0x2747, 0x2763, 0x2764, 0x27a1, 0x2934, 0x2935, 0x2b05, 0x2b06, 0x2b07, 0x3030, 0x303d, 0x3297, 0x3299]);
19
+
4
20
  /**
5
21
  * Converts an emoji ID (a hyphen-separated string of hex Unicode code points,
6
22
  * e.g. `"1f44d"`, `"1f44d-1f3fb"`, `"1f468-200d-1f469-200d-1f467"`) into its
@@ -44,22 +60,35 @@ export function emojiIdToEmoji(id) {
44
60
  if (codePoints.length === 0) {
45
61
  return undefined;
46
62
  }
47
-
48
- // Keycap sequences: digit/# /* followed by U+20E3 need U+FE0F between them.
49
- // The keycap base characters are: 0x23 (#), 0x2A (*), 0x30–0x39 (0–9).
50
- var KEYCAP_COMBINING = 0x20e3;
51
- var VARIATION_SELECTOR_16 = 0xfe0f;
52
63
  var processedCodePoints = [];
53
64
  for (var i = 0; i < codePoints.length; i++) {
54
65
  var cp = codePoints[i];
55
66
  var next = codePoints[i + 1];
56
67
  processedCodePoints.push(cp);
57
68
 
58
- // Insert U+FE0F before U+20E3 if not already present
69
+ // Insert U+FE0F before U+20E3 if not already present.
70
+ // Keycap sequences: digit/# /* followed by U+20E3 need U+FE0F between them.
59
71
  if (next === KEYCAP_COMBINING && cp !== VARIATION_SELECTOR_16) {
60
72
  processedCodePoints.push(VARIATION_SELECTOR_16);
61
73
  }
62
74
  }
75
+
76
+ // Text-presentation-default emoji: characters that are valid emoji but whose
77
+ // default rendering is text (e.g. ☪ ☺ ☢ etc.) must be followed by
78
+ // U+FE0F (VARIATION SELECTOR-16) to force emoji presentation.
79
+ if (fg('platform_twemoji_removal_unicode_emojis')) {
80
+ var lastCodePoint = processedCodePoints[processedCodePoints.length - 1];
81
+ var alreadyHasVariationSelector = lastCodePoint === VARIATION_SELECTOR_16 || lastCodePoint === VARIATION_SELECTOR_15 ||
82
+ // Keycap sequences end with U+20E3 — they already have U+FE0F inserted inline
83
+ // and must not have another variation selector appended at the end.
84
+ lastCodePoint === KEYCAP_COMBINING;
85
+ if (!alreadyHasVariationSelector) {
86
+ var baseCodePoint = codePoints[0];
87
+ if (codePoints.length === 1 && baseCodePoint <= 0xffff && TEXT_DEFAULT_EMOJI.has(baseCodePoint)) {
88
+ processedCodePoints.push(VARIATION_SELECTOR_16);
89
+ }
90
+ }
91
+ }
63
92
  try {
64
93
  return String.fromCodePoint.apply(String, processedCodePoints);
65
94
  } catch (_unused) {
@@ -15,6 +15,9 @@ export var isImageRepresentation = function isImageRepresentation(rep) {
15
15
  export var isMediaRepresentation = function isMediaRepresentation(rep) {
16
16
  return !!(rep && rep.mediaPath);
17
17
  };
18
+ export var isUnicodeRepresentation = function isUnicodeRepresentation(rep) {
19
+ return !!(rep && rep.unicodeEmoji);
20
+ };
18
21
  export var isPromise = function isPromise(p) {
19
22
  return !!(p && p.then);
20
23
  };
@@ -212,7 +212,10 @@ export interface ImageRepresentation extends EmojiImageRepresentation {
212
212
  export interface MediaApiRepresentation extends EmojiImageRepresentation {
213
213
  mediaPath: string;
214
214
  }
215
- export type EmojiRepresentation = SpriteRepresentation | ImageRepresentation | MediaApiRepresentation | undefined;
215
+ export interface UnicodeRepresentation {
216
+ unicodeEmoji: string;
217
+ }
218
+ export type EmojiRepresentation = SpriteRepresentation | ImageRepresentation | MediaApiRepresentation | UnicodeRepresentation | undefined;
216
219
  export interface EmojiDescription extends EmojiId {
217
220
  altRepresentation?: EmojiRepresentation;
218
221
  ascii?: string[];
@@ -1,10 +1,11 @@
1
1
  import { messages } from '../components/i18n';
2
2
  import type { CategoryId } from '../components/picker/categories';
3
- import type { EmojiDescription, EmojiDescriptionWithVariations, EmojiId, EmojiImageRepresentation, EmojiRepresentation, EmojiServiceRepresentation, EmojiVariationDescription, ImageRepresentation, MediaApiRepresentation, OptionalEmojiDescription, SpriteRepresentation, SpriteServiceRepresentation } from '../types';
3
+ import type { EmojiDescription, EmojiDescriptionWithVariations, EmojiId, EmojiImageRepresentation, EmojiRepresentation, EmojiServiceRepresentation, EmojiVariationDescription, ImageRepresentation, MediaApiRepresentation, OptionalEmojiDescription, SpriteRepresentation, SpriteServiceRepresentation, UnicodeRepresentation } from '../types';
4
4
  export declare const isSpriteServiceRepresentation: (rep: EmojiServiceRepresentation) => rep is SpriteServiceRepresentation;
5
5
  export declare const isSpriteRepresentation: (rep: EmojiRepresentation) => rep is SpriteRepresentation;
6
6
  export declare const isImageRepresentation: (rep: EmojiRepresentation | EmojiServiceRepresentation | EmojiImageRepresentation) => rep is ImageRepresentation;
7
7
  export declare const isMediaRepresentation: (rep: EmojiRepresentation | EmojiImageRepresentation) => rep is MediaApiRepresentation;
8
+ export declare const isUnicodeRepresentation: (rep: EmojiRepresentation) => rep is UnicodeRepresentation;
8
9
  export declare const isPromise: <T>(p: any) => p is Promise<T>;
9
10
  export declare const isEmojiDescription: (possibleEmojiDescription: any) => possibleEmojiDescription is EmojiDescription;
10
11
  export declare const isMediaEmoji: (emoji: EmojiDescription) => boolean;
@@ -212,7 +212,10 @@ export interface ImageRepresentation extends EmojiImageRepresentation {
212
212
  export interface MediaApiRepresentation extends EmojiImageRepresentation {
213
213
  mediaPath: string;
214
214
  }
215
- export type EmojiRepresentation = SpriteRepresentation | ImageRepresentation | MediaApiRepresentation | undefined;
215
+ export interface UnicodeRepresentation {
216
+ unicodeEmoji: string;
217
+ }
218
+ export type EmojiRepresentation = SpriteRepresentation | ImageRepresentation | MediaApiRepresentation | UnicodeRepresentation | undefined;
216
219
  export interface EmojiDescription extends EmojiId {
217
220
  altRepresentation?: EmojiRepresentation;
218
221
  ascii?: string[];
@@ -1,10 +1,11 @@
1
1
  import { messages } from '../components/i18n';
2
2
  import type { CategoryId } from '../components/picker/categories';
3
- import type { EmojiDescription, EmojiDescriptionWithVariations, EmojiId, EmojiImageRepresentation, EmojiRepresentation, EmojiServiceRepresentation, EmojiVariationDescription, ImageRepresentation, MediaApiRepresentation, OptionalEmojiDescription, SpriteRepresentation, SpriteServiceRepresentation } from '../types';
3
+ import type { EmojiDescription, EmojiDescriptionWithVariations, EmojiId, EmojiImageRepresentation, EmojiRepresentation, EmojiServiceRepresentation, EmojiVariationDescription, ImageRepresentation, MediaApiRepresentation, OptionalEmojiDescription, SpriteRepresentation, SpriteServiceRepresentation, UnicodeRepresentation } from '../types';
4
4
  export declare const isSpriteServiceRepresentation: (rep: EmojiServiceRepresentation) => rep is SpriteServiceRepresentation;
5
5
  export declare const isSpriteRepresentation: (rep: EmojiRepresentation) => rep is SpriteRepresentation;
6
6
  export declare const isImageRepresentation: (rep: EmojiRepresentation | EmojiServiceRepresentation | EmojiImageRepresentation) => rep is ImageRepresentation;
7
7
  export declare const isMediaRepresentation: (rep: EmojiRepresentation | EmojiImageRepresentation) => rep is MediaApiRepresentation;
8
+ export declare const isUnicodeRepresentation: (rep: EmojiRepresentation) => rep is UnicodeRepresentation;
8
9
  export declare const isPromise: <T>(p: any) => p is Promise<T>;
9
10
  export declare const isEmojiDescription: (possibleEmojiDescription: any) => possibleEmojiDescription is EmojiDescription;
10
11
  export declare const isMediaEmoji: (emoji: EmojiDescription) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/emoji",
3
- "version": "70.7.2",
3
+ "version": "70.8.0",
4
4
  "description": "Fabric emoji React components",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"